slab / quill

Quill is a modern WYSIWYG editor built for compatibility and extensibility
https://quilljs.com
BSD 3-Clause "New" or "Revised" License
43.16k stars 3.35k forks source link

Render quill delta without instantiating an editor #993

Open yourGuy opened 7 years ago

yourGuy commented 7 years ago

What do people use to render quill content in a non editor context? Does quill exposes a method for that, or is the a basic rendering library? I use quill as part of a templating app. I save the different editable blocks in the delta format later I'd like to render that content without instantiating the editor. And preferably with loading a much smaller lib then quill if anybody can recommend one. Thanx

EricGrange commented 7 years ago

This is something that I have been wondering about.

The guide mentions https://github.com/ottypes/rich-text/ but it does not seem to include any renderer.

I have found this project https://github.com/casetext/quill-render but it looks outdated and no longer maintained, and it also involves a DOM.

The Quill Delta format is yet-another-custom-rich-text-format, which even if open, would turn problematic to use for persistence of content (in a db, etc.), because well, it is non-standard.

Finally while the format is simple, it is non-trivial to render as it is an action log, so the rendering engine needs to be 1:1 with the editing engine (including edge case bugs). Rolling out an engine (or a third party) would thus face all the usual problems of "code rot", because the expected render is not defined by the format, but by what the user saw during edition.

jhchen commented 7 years ago

@EricGrange Deltas are JSON and should save fine in many databases, such as Postgres or MongoDB. Are you encountering issues?

EricGrange commented 7 years ago

The problem is not saving JSON itself but saving user content in custom (as in "non standard") format. It would tie the data in the database very strongly to quilljs.

If there was a renderer to html available, there would be no such issue: delta could be used over the wire, to protect from xss and keep all other advantages, and then rendered to html server-side and used in database persistence (possibly alongside the delta).

This way user content and db are not strongly tied to quilljs and its custom format.

At the moment it is my understanding that rendering a delta to html involves reproducing all the quilljs interpretation of deltas 1:1, with deltas thus being closer to a script than to a document format (as in html, rtf, etc.), as they list operations/instructions rather than an expected state and visual aspect (correct me if I'm wrong). Notably the delete and retain ops mean the final state cannot be known without "correct" interpretation of all ops in a delta (with "correct" as in "reproducing bugs as well")

Le 24 sept. 2016 17:03, "Jason Chen" notifications@github.com a écrit :

@EricGrange https://github.com/EricGrange Deltas are JSON and should save fine in many databases, such as Postgres or MongoDB. Are you encountering issues?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/quilljs/quill/issues/993#issuecomment-249369201, or mute the thread https://github.com/notifications/unsubscribe-auth/ACGG2lxcsy70tIeDZpBhudcLcKyJ-OvUks5qtTvNgaJpZM4KCQEe .

jhchen commented 7 years ago

If the scope is the particular JSON Quill produces then we should similarly scope to the particular HTML Quill produces. Through those lenses, HTML has the same issue.

If you stored the HTML Quill produced in a database and one day wanted to switch to another editor, that editor will produce different HTML for the same content expressed by Quill through HTML. Now you could do some fuzzy matching with HTML parsers and libraries are out there to do this but this is much more complicated than a JSON array. HTML is undisputedly a more complex and expressive of a format, and, stored a string, requires a parser to even begin interpreting.

benbro commented 7 years ago

You can convert Quill Delta to HTML on the server with node.js and jsdom without using a real browser. Demo: https://runkit.com/57e6d4ebaaf7d01400559d04/57e6d4ebc63d1e1400b586fc

jsdom is a javascript implementation of the DOM. MutationObserver support in jsdom - https://github.com/tmpvar/jsdom/issues/639 getSelection support in jsdom - https://github.com/tmpvar/jsdom/issues/317

All the issues with HTML that jhchen raised are obviously still valid.

var jsdom = require("jsdom");

jsdom.env({
    html: '<div id="editor-container"></div>',
    scripts: [
        'https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/0.7.22/MutationObserver.js',
        'https://cdn.quilljs.com/1.0.4/quill.js'],
    onload: function (window) {
        var document = window.document;
        // fake getSelection
        // https://github.com/tmpvar/jsdom/issues/317
        document.getSelection = function() { 
            return { 
                getRangeAt: function() {}
            };
        }; 

        var container = window.document.getElementById("editor-container");
        var quill = new window.Quill(container, {});

        var delta = {
          ops: [
            { insert: 'Gandalf', attributes: { bold: true } },
            { insert: ' the ' },
            { insert: 'Grey', attributes: { color: '#ccc' } }
          ]
        };
        quill.setContents(delta);

        console.log(document.querySelector(".ql-editor").innerHTML);
    }
});
EricGrange commented 7 years ago

The issue with html is actually completely different, because it's standard, it will be possible to display, manipulate and edit on any target in any reasonable future.

I am not sure what you mean with fuzzy matching: the content for me is meant to be edited and read by humans, so the actual html does not matter as long as the visual aspect is fine enough.

For example if someone enters content that contains the sentence "the document is not approved", what matters is that this sentence is what will be displayed. Whether there are spurious whitespaces or span tags in the html is purely technical efficiency (or lack of).

But if the same content is described by deltas, and because of some bug a particular delete OP is ignored in v1 (or snips whitespace, etc.), but handled properly in a bugfixed v2, it is possible that the same delta would be rendered by v2 with the sentence "the document is approved", with the fixed delete OP snipping the "not", and changing the human meaning of the content.

The same issue exists with alternative rendering engines from delta to html, which may render to a different content in terms of human semantic if there is just one bug.

When html or text is stored, displaying it may be technically complex if you look at the full stack involved, but it's quite foolproof because it's a standard with well established tools. Its complexity is as relevant as the complexity of the Operating System or the video driver used to push the actual pixels. There will be differences, but as long as the human visual aspect is good, it's fine.

Stored deltas on the other hand need to be fully executed (as it is a script) before you get a valid html/text/dom, and that delta execution engine is not a well established standard. And while the format itself is simple, its execution is not (involves a dom, and bugs can affect the output drastically in terms of human semantic, even if you only want a text output).

Or in other words, the risk that in 5 years rendering current quill deltas means going through legacy hoops and hacks is much higher than the risk of having to do that for html content. Which is why I would rather have html stored in the database: the data for any application is likely to outlive its UI components.

All that said, the execution trouble with deltas come from delete & retain ops: with only insert, delta becomes a state more than a script. So returning a "baseline" or "pre-processed" delta with (guaranteed) only insert OPs could be another solution. A renderer for an insert-only delta is simple AFAICT and safe in terms of human semantic content. The quilljs editor content could be reset to that baselined delta during a preview step (at editing time).

Le 24 sept. 2016 19:38, "Jason Chen" notifications@github.com a écrit :

If the scope is the particular JSON Quill produces then we should similarly scope to the particular HTML Quill produces. Through those lenses, HTML has the same issue.

If you stored the HTML Quill produced in a database and one day wanted to switch to another editor, that editor will produce different HTML for the same content expressed by Quill through HTML. Now you could do some fuzzy matching with HTML parsers and libraries are out there to do this but this is much more complicated than a JSON array. HTML is undisputedly a more complex and expressive of a format, and, stored a string, requires a parser to even begin interpreting.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/quilljs/quill/issues/993#issuecomment-249377396, or mute the thread https://github.com/notifications/unsubscribe-auth/ACGG2qyQW2BkN9N4lJmp_xcF3ohgV3vCks5qtV_8gaJpZM4KCQEe .

jhchen commented 7 years ago

@EricGrange Sounds like we disagree on the guarantees and implications of a standard.

Less open to opinion is that by design Deltas used to represent documents will only ever have insert operations.

All that said, the execution trouble with deltas come from delete & retain ops: with only insert, delta becomes a state more than a script. So returning a "baseline" or "pre-processed" delta with (guaranteed) only insert OPs could be another solution.

So as you say, most of the concerns are moot.

yourGuy commented 7 years ago

@jhchen I think the point me and @EricGrange are getting at is that it seems that the rendering of deltas is coupled to quill itself and wondering what are our options when it comes to displaying the content outside of an editor context (quill or other) I'm aware of the readonly option in quill, but in my application 280k is a heavy price to pay plus the unnecessary marckup. I'm wondering if a simple small renderer module can be extracted from quill.

jhchen commented 7 years ago

@yourGuy Deltas are implemented it its own library in which you can use on its own. In the end it is just JSON so if you don't care about the methods Delta implements (which may or may not be useful depending on your use case) you are free to use the data structure in vanilla Javascript, which can be as easy as something like this:

html = delta.slice(0, 500).ops.map(function(op) {
   if (typeof op.insert !== 'string') return '';
   let html = op.insert;
   if (op.attributes.bold) {
      html = '<strong>' + html + '</strong>';
   }
   return html;
}).join('');

I assume this issue is more about the particular HTML Quill chooses to generate from Deltas. That by definition has ties to Quill. This is not a detachable piece at the moment, which is why this Issue is still open.

artaommahe commented 7 years ago

@jhchen there is one problem with separate lib for converting Delta to HTML - it requires to pass all common and custom formats that already registered in Quill instance due to editing usage. So if we could have method to get HTML from Delta via Quill instance, this will reduce formats registering/passing duplication. Currently i have to use Quill editor readonly instance for proper Delta -> HTML rendering with all registered custom formats.

yourGuy commented 7 years ago

I think the renderer, and I hope there is a plan to make one, should include the custom module registration, but again just the rendering part.

timeswind commented 7 years ago

+1

kxgio commented 7 years ago

The reason why I do not choose to use Quill editor currently is that I got stuck while trying to convert delta to pure HTML for display purpose

fightingtheboss commented 7 years ago

Quill is an amazing piece of tech, really so impressed the further I dive into it.

As with other people, though, my main stumbling block for using it is that there are actually no guides or demos showing how to use it where the use-case is to have editors create content and have that content rendered in HTML for reading by consumers.

The path from editing to rendering isn't clear. I believe the implicit way of rendering content is creating a Quill editor with no toolbar and readOnly: true. This seems a little heavy handed and not the simplest use case since rendering content shouldn't rely on JS, in my opinion.

There needs to be an option that allows developers to access the rendered HTML rather than the Delta JSON. This would allow developers to save the rendered HTML for later use in addition to saving Deltas for further parsing.

Perhaps this is simply an add-on module that needs to be written or already exists? I'm definitely not yet an expert in Quill so perhaps what I'm suggesting already exists. I can see how the rendering of HTML from a Delta document can be subjective and potentially customizable per app, but there's just no word on the normal use case for rendering Quill documents anywhere so it's hard to dive in.

EricGrange commented 7 years ago

HTML needs to be sanitized and protected against various things, and you also no longer have any change history, ability to merge simultaneous edits, undo edits, etc.

The delta format allows merge & history, and also naturally provides a degree of protection vs style, script and other injections. So it has many advantages over raw html, the only disadvantage it has is the one mentioned here: as it cannot be displayed directly, it needs to be rendered.

On Tue, Nov 15, 2016 at 7:05 PM, Jerry Orr notifications@github.com wrote:

I feel like I'm missing something here. Why would you want to save the Deltas and later render them as HTML? Why wouldn't you just save the HTML that's already been rendered?

editor.root.innerHTML

or

document.getElementsByClassName('ql-editor')[0].innerHTML

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/quilljs/quill/issues/993#issuecomment-260718450, or mute the thread https://github.com/notifications/unsubscribe-auth/ACGG2jhHTozz7GvozOtuwV3bkNN0uhTRks5q-fSGgaJpZM4KCQEe .

benallfree commented 7 years ago

To build on what @fightingtheboss said, editor.root.innerHTML is not an adequate solution because some custom blots, particularly embeds, may have different design-time and run-time renderings.

Here is a Codepen of how I'm using Quill to show design-time previews of dynamic run-time HTML: http://codepen.io/benallfree/pen/aBmjjv. Click on the far-right icon to insert another form. Mouse over to alter state and remove elements.

I have a content rendering engine with a feature similar to WordPress's shortcode API. At page load, shortcodes such as [foo id=42] are replaced with HTML by whatever service handles the [foo] shortcode.

I use Quill as a visual editor where the user sees a visual preview or sample of what [foo] will look like when rendered. It's just a nonfunctional sample since the actual rendering takes run-time inputs to determine. In this use case, [foo id=42] is what needs to be saved back to the database, not the visual preview placeholder. So edit.root.innerHTML will not work.

In my case, I save both the deltas and the rendered output back to the database. That means blots need to know how to render themselves. innerHTML works for all the native blots, but custom blots are different. I created a RenderableBlot as follows:

class RenderableBlot extends BlockEmbed
{
  static create(options)
  {
    let node = super.create(node);
    $(node).addClass('ql-component');
    $(node).attr('contenteditable', false);
    $(node).attr('component-type', this.name);
    return node;
  }

  static render(node)
  {
    throw new TypeError('render() must be implemented');
  }

  static renderAll(quill)
  {
    let rendered = $('<div>').append($(quill.root.innerHTML));
    rendered.find('.ql-component').each((idx,e)=>{
      let $e = $(e);
      let t = $e.attr('component-type');
      let js = `${t}.render(e)`;
      $(e).replaceWith(eval(js));
    });
    return rendered.html();
  }
}
RenderableBlot.tagName = 'div';

There's more to it, but that is the essence of a renderable base class. Subclasses must implement the render(e), where e is the root DOM element for the .ql-component.

All of this leads me to the conclusion that blots should know how to return rendered versions of themselves. Right now, I am getting by with a subclass that replaces innerHTML with what I want, but ideally this would be built into Quill somehow.

If we do this, I can envision a plugin ecosystem of rich visual design interfaces that know how to render their own output. Imagine an editable video embed that lets the user search YouTube/Vimeo/Vine by keyword and select a suitable video. The uses cases of design-time edit interfaces for blots are incredible (to me).

fabiosussetto commented 7 years ago

Very surprised this hasn't been implemented yet. Don't get me wrong, Quill looks amazing, just surprised this wasn't considered a very basic requirement for 1.0

I appreciate the benefits of the delta formats over storing html inside the db, but without a built-in way to render the content without creating an editor full instance, how do you use the editor in a real scenario? Imagine I want to build a simple list of comments. Are you saying I need to create 20 instances of Quill to display the formatted comments posted by the users through Quill?

benallfree commented 7 years ago

@fabiosussetto Save the editor.root.innerHTML to the database when the user posts a comment.

artaommahe commented 7 years ago

@benallfree this breaks a lot of cool things like updating display format for image/video or all formats markup, cause old HTML will not update. And also requires a lot of sanitizing before displaying plain HTML received from back-end

benallfree commented 7 years ago

@artaommahe I generally agree. I was proposing a solution specifically to @fabiosussetto's desire to display the HTML without loading Quill.

I think your suggestion is to render a page from stored Quill deltas instead of the stored HTML, right? That would require a server-side rendering library of some kind. There are a few nodejs-based rendering libs, but anyone outside Node is out of luck as far as I know. I started to write a Delta renderer in PHP, but then I elected to just store the HTML instead. I agree that sanitizing Deltas would be easier than sanitizing HTML.

Ultimately, I abandoned Quill on my project because allowing users to have rich editing control is just too fraught with problems. In my case, since my users won't know Markdown or any other safer language, I elected to build a drag-and-drop component designer where the component layout is fixed and the user is only allowed to edit specific data rather than the layout/markup. I still save the HTML back to the server because it is a trusted environment, but if I wanted to be safer I could use Vue.js on the server side to render the content from the data. So I'd still be tied to Node.js for server-side rendering, but I vastly prefer that strategy over rendering Quill deltas.

artaommahe commented 7 years ago

I think your suggestion is to render a page from stored Quill deltas instead of the stored HTML, right?

yes, this is my current usecase

That would require a server-side rendering library of some kind

nope. Server side rendering forced to duplicate formats between front-end quill editor and back-end renderer that is awful. I prefer front-end rendering from Delta before displaying without instantiating full quill editor in readonly mode.

benallfree commented 7 years ago

I prefer front-end rendering from Delta before displaying without instantiating full quill editor in readonly mode.

Is search engine indexing an issue in your use case?

artaommahe commented 7 years ago

Is search engine indexing an issue in your use case?

there is no issues with google search engine, it runs all js and then analyze (we'r using angular). Other search engines does not matter for us.

rquast commented 7 years ago

Please excuse my ignorance on this topic, but I haven't been able to find an answer for this anywhere else yet.

If a malicious user were to put html inside of a delta json (say in a sentence), would the html be displayed on the front-end when read back from the server? In that case, do we have to build a sophisticated sanitizer on the backend to parse the json delta format before saving? Or does quill filter out this stuff automatically? I don't fully understand the implications of something like dangerouslyPasteHTML ... does that mean deltas can contain html, or is there a special node in the delta for this? It would help to know this before using quill for rendering, or converting to html and sanitizing it server (or client) side display. Need more info.

benallfree commented 7 years ago

@rquast Think of it this way: a very malicious user could post something to the server that looks like it came from Quill but was actually hand-crafted for evil purposes :)

So regardless of what Quill or any client-side technology does, the server code should never trust what it receives. @EricGrange's comment above about sanitization was (I think) just to mention that sanitizing a Quill delta format is easier than trying to sanitize HTML. I don't have an opinion on that statement, but I think that's what he was trying to say.

rquast commented 7 years ago

@benallfree if something malicious was sent back from the server, and you used quill to render the delta, then if quill sanitized that on the frontend, then you wouldn't have to worry? It's just that otherwise, you have to sanitize all of strings inside of the delta json on the server side. That's not straight forward.. means you have to hard code the format of the delta json into something that can sanitize it on the server side. Either that or render html (getHTML) before sanitizing on either client or server sides. I don't believe it's necessarily wrong for a database to store XSS code. It's up to the developer to prevent the browser from parsing that code (be it before it goes into the database, or before it gets sent, or before it gets displayed).

benallfree commented 7 years ago

@rquast I think it comes down to preference and use case, but for me, storing malware in my database and trusting a client-side tool to remove it feels too brittle. I don't want garbage in my database in the first place. I think I would go out of my way to avoid an architecture like that. So, my architecture would be as follows:

I mentioned in a comment above - even this architecture seemed too brittle for my use case. Giving the user control over layout and formatting is just disastrous in my experience. There is a reason, for example, that Facebook doesn't allow rich edits on posts and comments. But they do allow emojis and @ tags which produce consistently formatted embellishments. Github uses Markdown in favor of allowing rich editing, I think for the same reason. Quill and rich editors in general have a really narrow set of use cases when long-term user experience is taken into consideration.

rquast commented 7 years ago

@benallfree starting to think the same. It would be good if JSON Schema was used so you could validate the structure both client and server side as well as check for xss using regex in the schema. Without something like that, you can't trust the integrity. Like you said, rendering the HTML on the server side and running it through a strong sanitizer is also another layer to prevent xss coming through.

Fortunately, my use case is for site admins, so they are less likely to muck things up or try any XSS (hopefully).

edit like what this guy did (but include xss checks).. https://github.com/dnephin/quill-data-format

benallfree commented 7 years ago

@rquast Yep I agree, if the use case is internal or backend, Quill probably works fine and the security considerations are nil. For public use...a different story! :)

jhchen commented 7 years ago

Quill treats Deltas like data, and does not execute it like code. A key component to (all?) malicious code execution exploits is breaching this barrier between data into code. This can be trivially done with things like eval and innerHTML, which is why they are very dangerous to work with.

Quill's APIs treat data like data, with the notable exception of dangerouslyPasteHTML. If you call insertText(0, someString), it's not going to treat the contents on someString like code just because it looks like code and decide to execute it. Similarly if you create a Delta that has an insert value that looks like HTML, updateContents will not just decide to execute some string that looks like HTML (it doesn't even know what HTML is!).

Now Quill also in general does not protect you from layers above and below it. For example formatText(0, 4, 'link', 'http://somephishingsite.com') will be treated like any formatText call to any old URL. Similarly insertEmbed(0, 'image', 'http://pixel-ad-tracker.com') will also not be treated specially.

Where the principles start to get tricky is something like formatText(0, 4, 'link', 'javascript: alert("Ha!")'). This is something Quill treats specially, since it whitelists protocols, even though in principle it should not interfere with abstraction layers below it. In principle security conscious web developers should be using CSP, but it is somewhat new and not everyone has yet and so for now this whitelisting is a "helpful" thing Quill does.

rquast commented 7 years ago

@jhchen so dangerouslyPasteHTML converts the html to the quill document model and saves no html? If it does that, and there is nowhere in quill that does an innerHTML when it restores a document, then all seems okay except for what you mentioned.

jhchen commented 7 years ago

In order for Quill to convert from HTML to a Delta, it uses innerHTML, so dangerouslyPasteHTML is indeed dangerous. This is because Quill does not and should not implement a full HTML and CSS parser and relies on the DOM to resolve these complexities.

ergo commented 7 years ago

So, if I'm understanding this correctly for every backend we want to use we need to write delta rendering implementation basicly?

Using the editor in read-only mode seems like a no-go option since it will create issues with search engines other than google and also requires adding a lot of js with little benefit - that is important for mobile clients.

What about providing API that would get HTML that quill provides in read only mode? That is something that could be stored in the db for rendering in templates - would that be a reasonable solution?

ergo commented 7 years ago

To add something on top - I guess the solution would be to store the delta as the source of truth in the db, but still have the representation available for us to provide without rendering - what about text html clients or readers for disabled people? I understand the technical explanation why html is not ideal solution, but alternative ie. requirement for me to implement renderer for every backend that would consume quill seems problematic, because it adds serious moving target to update.

kay999 commented 7 years ago

The current linear deltas are quite hard to render to HTML. So I think a good solution would be to have a renderer which makes a hierachical "DOM-like" JSON-structure from the content.

It would be quite simple to render such a structure to HTML (or wharever) then and there would be no need for complex html sanitation etc.

chuckh commented 7 years ago

I created a web component <polymer-quill-html-render> which renders Quill HTML. I save both the HTML and deltas to my database when using Quill. I use <polymer-quill-html-render> to render content read only.

Learn more about Quill HTML render at https://chuckh.github.io/polymer-quill/components/polymer-quill/#polymer-quill-html-render.

Learn about the web component Quill Editor at : https://beta.webcomponents.org/element/chuckh/polymer-quill.

Quill HTML Render screenshot

image

dphunct commented 7 years ago

I will throw in my $.02. I am just starting with Quill, so please forgive my ignorance.

I think the deltas are neat and see a great value in them. I think it will be very useful, especially when we support collaborative documents. However, I still have a legacy system to support, that works across several web and mobile platforms. I have to persist all data in a subset of HTML.

I am interested in Quill because I like what it can provide as far as flexibility. I need to be able to show certain mark-up in a specific way inside the text editor just as we do outside of the text editor. I think I can use Quill to do that. (for example, an anchor with a specific class or linked to a specific file type needs to display differently than a general hyperlink)

However, it would be nice to have a built in function that can return the formatted text, minus the rendered components that are UI specific, in order to save to the server. It would also be nice to have a separate function that can dynamically load an HTML block and return a Delta without having to reinitialize the component. (At least I didn't see a way to do that). If nothing else, this workflow that several people are asking for would greatly help the initial conversion from other classic RTEs to Quill. From there, they can start to utilize other features.

@chuckh, your polymer-quill looks like it may work.

cjaoude commented 7 years ago

My take on it...

...is to save both the Delta and the innerHTML. When the user is in an edit view, hydrate the editor with the Delta. When the user saves, the Delta is saved but also the innerHTML is saved in its own separate Db field. Sanitize the HTML. The HTML is used only in the show content views.

This gets rid of the need to use Quill in readOnly mode in a show view.

Seems like the best way. But I've been using Quill for like an hour, so... :)

Users will mess up rich text editing. Keep it down to the bare minimum formatting: Bold, Italic, Large Font, and Bullets.

gnemtsov commented 7 years ago

Well, I am also new to quill and I decided to arrange the following workflow. I will implement quill in outosaving manner. I'll send quill delta via ajax to server every 3 seconds. On the server I am going to use node.js and jsdom to apply coming deltas to the stored HTML. In node.js server-side I create a quill editor, load previously saved HTML content, apply delta and store new HTML in my storage. I don't want to store content in delta format, since I need to not only show content in browser, but also send it via email to users.

Do I have to worry about sanitizing delta before appling it in my node.js code?

nozer commented 7 years ago

I created a quill delta to html converter and it allows this. It also cleans urls and escapes the content for html. It is located at https://github.com/nozer/quill-delta-to-html

gnemtsov commented 7 years ago

I gave up with idea to apply deltas server-side. JSDom was too slow actually! So I send content HTML to server instead of deltas. I store only HTML server-side. I also had to change default quill behavior about storing base64 encoded pics in the src attribute in order to lower content size. I made my own pics paste/drop handler which uploads pic to s3 using CORS and then sets src as url. Now it works pretty cool, I think. Everybody may have a look at the result here: https://demo.ab-tasks.ru/task.php?t_id=5. Just press blue button at the bottom of the page to add new message. Sorry, the task management system, we are working on, is only in Russian for now!

WriterStat commented 7 years ago

Hi! I'm interested in this where it pertains to exporting to other document types and standards driven renderers. We aren't using node.js on the server side. But instead PHP or Rails etc...

I found this. https://packagist.org/packages/deanblackborough/php-quill-renderer

Building a renderer that is somewhat future proof seems to be hard for most. Which is why people are using root and using innerHTML and saving html instead of the Deltas.

Until there is a decent renderer for each of the standard programming languages, this debate is going to continue to rage on. Having a Delta is way cool. But only if you can get it out into other things. Else it's a closed system.

People like open systems.

Adoptance of Deltas would go way up if there were standard renderers for it.

In a best case world I'd like to save a Delta and have a renderer for html or markdown.

Could be it's time to spend some time on renderers. And rendering guides.

nozer commented 7 years ago

@gnemtsov Sorry for the delay in response; I got caught up with things. I am not using JSDom or any external library to convert delta to HTML. I will send deltas to server and convert to html safely (converter escapes HTML and scrubs the urls) and save to db as HTML. The reason I want to convert to HTML myself is to have control over HTML output. Right now, nested lists are not generated properly (a nested list must be child of the li it is listed under) and what quill generates both semantically and W3C recommendation-wise is wrong. Also, consecutive blocks with same kind (such as blockquotes) that have same align, direction, and indent values should be combined instead of rendering in its own block. That drop handler for image embed is a great idea; I will surely implement something like that.

nozer commented 7 years ago

@WriterStat Delta is really cool. I think what would be a great idea is to have delta object structure versions so that the renderers could target the delta versions to prevent issues down the line; this would also help its openness.

bux commented 6 years ago

+1

brianolson commented 6 years ago

Quill is a cool editor, but at some point I'm done editing and want to just display the results , and it seems there's currently no good way to go from Quill-Delta to HTML outside of a Quill editor context; and that's sad and could be a dealbreaker. The server should not trust what the client says was the content of Quill.root.innerHTML. If the server stores that and turns around and puts it into a page that would be an easy vector for a script attack. Fully parsing and sanitizing HTML is a drag. It would be so much nicer to render Quill-Delta to HTML; but it seems the only good library for that is the Quill editor. :-/

brianolson commented 6 years ago

Here's a basic renderer in Python that handles bold, italic, underline, OL, UL, H1-H6 https://github.com/brianolson/render_quill BUT I know that's not the whole of the Quill document language, and I didn't find a specification for the Quill document language other than what Quill.js outputs. It would be nice if Quill.js docs had a more formal spec for what goes into the Delta language in terms of what attributes are possible, how lists and nested lists are structured, other elements, etc.

Risto-Stevcev commented 6 years ago

I wanted to add another data point here. For some reason having contenteditable=false (with the readOnly: true option) and a draggable element will crash both chrome and the x-server when it gets accidentally or intentionally dragged.

I hope this becomes a feature so quill could just render the content as HTML without any contenteditable anywhere (or anything else), because it's causing some show stopping bugs

ericeslinger commented 6 years ago

as a different data point, I would not use this feature, were it available.

I've written a couple of different converters from Delta format to rendered-out HTML, and in all cases I find that it is a tricky enough process that I really want to have a lot of control over it. For example: in link-formatted text, I conditionally add target="_blank" to some links in some contexts to force new-tab behavior (some users complained about opening in-tab). I don't want to muck around with the link format renderer in the editor (where the affordances are different), but in my rendered area, I do. I also like being able to decide if I want <br>, <p>, or some other tags as the top-level paragraph organizing structures.

Furthermore, there's just some plain differences between display and edit - when you're editing an atmention, for example, it's not urgent that username changes propagate into the editor (which is ephemeral in lifecycle), but you do want them to propagate into the rendered delta, and that kind of data binding is a lot better handled by your framework of choice (angular, react, etc) than by hacking it in to a custom quill element. Maybe images display differently, with different controls on them, for example.

Ultimately, converting from an insert-only delta (e.g., the canonical form) is mostly a matter of iterating through an array and outputting relevant HTML strings. This is pretty much the job of angular, react, vue, and so on, who make it easy with stuff like *ngFor doing a lot of the heavy lifting, or a small library for converting from deltas to an HTML string isn't terrible, and then you have a lot more control of stuff that happens outside of the purview of Quill.

laukaichung commented 6 years ago

I'm very satisfied with https://github.com/nozer/quill-delta-to-html. I use it to render react components in reactjs. It does not use any dependencies. It should work in react-native as well.