Skip to content

Commit

Permalink
add converting to semantic html
Browse files Browse the repository at this point in the history
  • Loading branch information
jhchen committed Jun 18, 2018
1 parent 9a6d3dc commit 1fab592
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 11 deletions.
71 changes: 71 additions & 0 deletions core/editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { LeafBlot } from 'parchment';
import CursorBlot from '../blots/cursor';
import Block, { bubbleFormats } from '../blots/block';
import Break from '../blots/break';
import ScrollBlot from '../blots/scroll';
import TextBlot from '../blots/text';

const ASCII = /^[ -~]*$/;

Expand Down Expand Up @@ -131,6 +133,10 @@ class Editor {
return extend.apply(extend, formatsArr);
}

getHTML(index, length) {
return convertHTML(this.scroll, index, length);
}

getText(index, length) {
return this.getContents(index, length)
.filter(op => typeof op.insert === 'string')
Expand Down Expand Up @@ -214,6 +220,71 @@ class Editor {
}
}

function convertListHTML(items, lastIndent) {
if (items.length === 0) {
if (lastIndent <= 0) {
return '</li></ol>';
}
return `</li></ol>${convertListHTML([], lastIndent - 1)}`;
}
const [{ child, offset, length, indent }, ...rest] = items;
if (indent > lastIndent) {
return `<ol><li>${convertHTML(child, offset, length)}${convertListHTML(
rest,
indent,
)}`;
} else if (indent === lastIndent) {
return `</li><li>${convertHTML(child, offset, length)}${convertListHTML(
rest,
indent,
)}`;
} else if (indent === lastIndent - 1) {
return `</li></ol></li><li>${convertHTML(
child,
offset,
length,
)}${convertListHTML(rest, indent)}`;
}
return `</li></ol>${convertListHTML(items, lastIndent - 1)}`;
}

function convertHTML(blot, index, length) {
if (typeof blot.html === 'function') {
return blot.html(index, length);
} else if (blot instanceof TextBlot) {
return blot.value().slice(index, index + length);
} else if (blot.children) {
// TODO fix API
if (blot.statics.blotName === 'list-container') {
const items = [];
blot.children.forEachAt(index, length, (child, offset, childLength) => {
const formats = child.formats();
items.push({
child,
offset,
length: childLength,
indent: formats.indent || 0,
});
});
return convertListHTML(items, -1);
}
const parts = [];
const { outerHTML, innerHTML } = blot.domNode;
const strIndex = outerHTML.lastIndexOf(innerHTML);
let startTag = outerHTML.slice(0, strIndex);
let endTag = outerHTML.slice(strIndex + innerHTML.length);
if (blot instanceof ScrollBlot || blot.statics.blotName === 'list') {
startTag = '';
endTag = '';
}
blot.children.forEachAt(index, length, (child, offset, childLength) => {
parts.push(convertHTML(child, offset, childLength));
});
return `${startTag}${parts.join('')}${endTag}`;
}
return blot.domNode.outerHTML;
}

function combineFormats(formats, combined) {
return Object.keys(combined).reduce((merged, name) => {
if (formats[name] == null) return merged;
Expand Down
5 changes: 5 additions & 0 deletions core/quill.js
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,11 @@ class Quill {
return this.selection.getRange()[0];
}

getSemanticHTML(index = 0, length = this.getLength() - index) {
[index, length] = overload(index, length);
return this.editor.getHTML(index, length);
}

getText(index = 0, length = this.getLength() - index) {
[index, length] = overload(index, length);
return this.editor.getText(index, length);
Expand Down
5 changes: 5 additions & 0 deletions formats/code.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ class CodeBlockContainer extends Container {
domNode.setAttribute('spellcheck', false);
return domNode;
}

html(index, length) {
const html = this.domNode.innerText.slice(index, index + length);
return `<pre>${html}</pre>`;
}
}

class CodeBlock extends Block {
Expand Down
5 changes: 5 additions & 0 deletions formats/formula.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ class Formula extends Embed {
static value(domNode) {
return domNode.getAttribute('data-value');
}

html() {
const { formula } = this.value();
return `<span>${formula}</span>`;
}
}
Formula.blotName = 'formula';
Formula.className = 'ql-formula';
Expand Down
5 changes: 5 additions & 0 deletions formats/video.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ class Video extends BlockEmbed {
super.format(name, value);
}
}

html() {
const { video } = this.value();
return `<a href="${video}">${video}</a>`;
}
}
Video.blotName = 'video';
Video.className = 'ql-video';
Expand Down
16 changes: 5 additions & 11 deletions modules/clipboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,8 @@ class Clipboard extends Module {
onCaptureCopy(e) {
if (e.defaultPrevented) return;
this.quill.update();
const [range, native] = this.quill.selection.getRange();
this.onCopy(e, range, native);
const [range] = this.quill.selection.getRange();
this.onCopy(e, range);
e.preventDefault();
}

Expand All @@ -143,17 +143,11 @@ class Clipboard extends Module {
e.preventDefault();
}

onCopy(e, range, nativeRange) {
onCopy(e, range) {
const text = this.quill.getText(range);
const fragment = nativeRange.native.cloneContents();
Array.from(fragment.querySelectorAll('select')).forEach(select => {
select.parentNode.removeChild(select);
});
const div = this.quill.root.ownerDocument.createElement('div');
div.style.whiteSpace = 'pre-wrap';
div.appendChild(fragment);
const html = this.quill.getSemanticHTML(range);
e.clipboardData.setData('text/plain', text);
e.clipboardData.setData('text/html', div.outerHTML);
e.clipboardData.setData('text/html', html);
}

onPaste(e, range) {
Expand Down

0 comments on commit 1fab592

Please sign in to comment.