UNPKG

node-quill-converter

Version:

Convert HTML to Delta or Delta to HTML

221 lines (155 loc) 6.17 kB
## OBJECTIVE Recreate memory issue refactor: prevent hanging execution Instantiating a Quill instance at the module scope caused execution of the module to hang indefinitely. Prior to Quill v1 there was a destroy method to clean up instances however it was removed. Removing the node in JSDOM did not resolve the issue. # OBJECTIVE Option to import katex. # OBJECTIVE Does including KaTeX enable formulas to go from Delta to HTML? TASKS * Hard code KaTeX same as quill * Set up test https://github.com/KillerCodeMonkey/ngx-quill/issues/80 # OBJECTIVE How do we optionally include formula library? Currently JSDOM_TEMPLATE is formed on require, not inside a function call. This is to avoid creating a JSDOM instance on each function call. TODO: cache DOM TODO: cache quill editor TODO: Use local versioned scripts rather than CDN Problem 1: We don't know why Quill isn't available after instantiation Possible: External scripts Any way to get ride of setTimeout/polling? localScripts? # FLOX ## OBJECTIVE Inline of quill doesn't work in package require('').resolve etc etc --- # FLOX setText set's text not HTML https://quilljs.com/docs/modules/clipboard/#dangerouslypastehtml ALTERNATIVE All we are trying to do is create a delta from HTML. Quill has implented this is their dangerouslyPasteHtml method. We can't use JSDOM because they don't support getRange APIs. Therefore we may be able to tease out their algorithm for converting HTML to a delta and drop all the selection crap. This is good because we could then potentially drop JSDOM all together. https://github.com/quilljs/quill/blob/f83ae57131e3c3abd3913acf57c045bdb3340bfa/modules/clipboard.js#L75 # Flox ## OBJECTIVE Passing non string to function throws error Error: [Parchment] Unable to create html blot at new e (about:blank:7:3081) at Object.r [as create] (about:blank:7:1278) convertHtmlToDelta(html, [options] # FLOX ## OBJECTIVE What the hell is this s { ops: []} # FLOX ## OBJECTIVE Tests for convertHtmlToDelta # FLOX ## OBJECTIVE Tests for convertDeltaToHtml # FLOX ## OBJECTIVE Comment by document.getSelected, document.execCommand are needed # FLOX ## OBJECTIVE Spread the word! // https://github.com/zenoamaro/react-quill/blob/af34e52d8574737bb768e1517dc4610bee65db33/src/mixin.js#L68 // TODO: Add quill-delta // TODO: Import Delta import Delta from 'quill-delta' // TODO: Convert this.prepareMatching to pure function // TODO: DOM tree library -> Cheerio? function convert(html) { // IF STRING convert to DOM tree if (typeof html === 'string') { this.container.innerHTML = html.replace(/\>\r?\n +\</g, '><'); // Remove spaces between tags return this.convert(); } // IF CODE BLOCK, create simple delta and return const formats = this.quill.getFormat(this.quill.selection.savedRange.index); if (formats[CodeBlock.blotName]) { const text = this.container.innerText; this.container.innerHTML = ''; return new Delta().insert(text, { [CodeBlock.blotName]: formats[CodeBlock.blotName] }); } // Parse DOM tree (this.container is your DOM tree) and create delta let [elementMatchers, textMatchers] = this.prepareMatching(); let delta = traverse(this.container, elementMatchers, textMatchers); // Remove trailing newline from delta if (deltaEndsWith(delta, '\n') && delta.ops[delta.ops.length - 1].attributes == null) { delta = delta.compose(new Delta().retain(delta.length() - 1).delete(1)); } // Empty Quill container which was used as temp holding for DOM tree this.container.innerHTML = ''; return delta; } // TODO: Understand this.prepareMatching // What is this.matchers // What is Node.TEXT_NODE // What is this.container.querySelectorAll function prepareMatching() { let elementMatchers = [], textMatchers = []; this.matchers.forEach((pair) => { let [selector, matcher] = pair; switch (selector) { case Node.TEXT_NODE: textMatchers.push(matcher); break; case Node.ELEMENT_NODE: elementMatchers.push(matcher); break; default: [].forEach.call(this.container.querySelectorAll(selector), (node) => { // TODO use weakmap node[DOM_KEY] = node[DOM_KEY] || []; node[DOM_KEY].push(matcher); }); break; } }); return [elementMatchers, textMatchers]; } // THESE TWO ARE pure functions should be good to co as long as we get args right // https://github.com/quilljs/quill/blob/f83ae57131e3c3abd3913acf57c045bdb3340bfa/modules/clipboard.js#L176 function deltaEndsWith(delta, text) { let endText = ""; for (let i = delta.ops.length - 1; i >= 0 && endText.length < text.length; --i) { let op = delta.ops[i]; if (typeof op.insert !== 'string') break; endText = op.insert + endText; } return endText.slice(-1*text.length) === text; } // https://github.com/quilljs/quill/blob/f83ae57131e3c3abd3913acf57c045bdb3340bfa/modules/clipboard.js#L192 function traverse(node, elementMatchers, textMatchers) { // Post-order if (node.nodeType === node.TEXT_NODE) { return textMatchers.reduce(function(delta, matcher) { return matcher(node, delta); }, new Delta()); } else if (node.nodeType === node.ELEMENT_NODE) { return [].reduce.call(node.childNodes || [], (delta, childNode) => { let childrenDelta = traverse(childNode, elementMatchers, textMatchers); if (childNode.nodeType === node.ELEMENT_NODE) { childrenDelta = elementMatchers.reduce(function(childrenDelta, matcher) { return matcher(childNode, childrenDelta); }, childrenDelta); childrenDelta = (childNode[DOM_KEY] || []).reduce(function(childrenDelta, matcher) { return matcher(childNode, childrenDelta); }, childrenDelta); } return delta.concat(childrenDelta); }, new Delta()); } else { return new Delta(); } } I put together a node package to convert html/plain text to and from a Quill delta. See [node-quill-converter](https://www.npmjs.com/package/node-quill-converter). The package uses JSDOM similar to a previous comments example however it uses JSDOMs latest API