119 lines
3.3 KiB
JavaScript
119 lines
3.3 KiB
JavaScript
import Delta from 'quill-delta';
|
|
import Parchment from 'parchment';
|
|
import Block from '../blots/block';
|
|
import Inline from '../blots/inline';
|
|
import TextBlot from '../blots/text';
|
|
|
|
|
|
class Code extends Inline {}
|
|
Code.blotName = 'code';
|
|
Code.tagName = 'CODE';
|
|
|
|
|
|
class CodeBlock extends Block {
|
|
static create(value) {
|
|
let domNode = super.create(value);
|
|
domNode.setAttribute('spellcheck', false);
|
|
return domNode;
|
|
}
|
|
|
|
static formats() {
|
|
return true;
|
|
}
|
|
|
|
delta() {
|
|
let text = this.domNode.textContent;
|
|
if (text.endsWith('\n')) { // Should always be true
|
|
text = text.slice(0, -1);
|
|
}
|
|
return text.split('\n').reduce((delta, frag) => {
|
|
return delta.insert(frag).insert('\n', this.formats());
|
|
}, new Delta());
|
|
}
|
|
|
|
format(name, value) {
|
|
if (name === this.statics.blotName && value) return;
|
|
let [text, ] = this.descendant(TextBlot, this.length() - 1);
|
|
if (text != null) {
|
|
text.deleteAt(text.length() - 1, 1);
|
|
}
|
|
super.format(name, value);
|
|
}
|
|
|
|
formatAt(index, length, name, value) {
|
|
if (length === 0) return;
|
|
if (Parchment.query(name, Parchment.Scope.BLOCK) == null ||
|
|
(name === this.statics.blotName && value === this.statics.formats(this.domNode))) {
|
|
return;
|
|
}
|
|
let nextNewline = this.newlineIndex(index);
|
|
if (nextNewline < 0 || nextNewline >= index + length) return;
|
|
let prevNewline = this.newlineIndex(index, true) + 1;
|
|
let isolateLength = nextNewline - prevNewline + 1;
|
|
let blot = this.isolate(prevNewline, isolateLength);
|
|
let next = blot.next;
|
|
blot.format(name, value);
|
|
if (next instanceof CodeBlock) {
|
|
next.formatAt(0, index - prevNewline + length - isolateLength, name, value);
|
|
}
|
|
}
|
|
|
|
insertAt(index, value, def) {
|
|
if (def != null) return;
|
|
let [text, offset] = this.descendant(TextBlot, index);
|
|
text.insertAt(offset, value);
|
|
}
|
|
|
|
length() {
|
|
let length = this.domNode.textContent.length;
|
|
if (!this.domNode.textContent.endsWith('\n')) {
|
|
return length + 1;
|
|
}
|
|
return length;
|
|
}
|
|
|
|
newlineIndex(searchIndex, reverse = false) {
|
|
if (!reverse) {
|
|
let offset = this.domNode.textContent.slice(searchIndex).indexOf('\n');
|
|
return offset > -1 ? searchIndex + offset : -1;
|
|
} else {
|
|
return this.domNode.textContent.slice(0, searchIndex).lastIndexOf('\n');
|
|
}
|
|
}
|
|
|
|
optimize(context) {
|
|
if (!this.domNode.textContent.endsWith('\n')) {
|
|
this.appendChild(Parchment.create('text', '\n'));
|
|
}
|
|
super.optimize(context);
|
|
let next = this.next;
|
|
if (next != null && next.prev === this &&
|
|
next.statics.blotName === this.statics.blotName &&
|
|
this.statics.formats(this.domNode) === next.statics.formats(next.domNode)) {
|
|
next.optimize(context);
|
|
next.moveChildren(this);
|
|
next.remove();
|
|
}
|
|
}
|
|
|
|
replace(target) {
|
|
super.replace(target);
|
|
[].slice.call(this.domNode.querySelectorAll('*')).forEach(function(node) {
|
|
let blot = Parchment.find(node);
|
|
if (blot == null) {
|
|
node.parentNode.removeChild(node);
|
|
} else if (blot instanceof Parchment.Embed) {
|
|
blot.remove();
|
|
} else {
|
|
blot.unwrap();
|
|
}
|
|
});
|
|
}
|
|
}
|
|
CodeBlock.blotName = 'code-block';
|
|
CodeBlock.tagName = 'PRE';
|
|
CodeBlock.TAB = ' ';
|
|
|
|
|
|
export { Code, CodeBlock as default };
|