1 | import Delta from 'quill-delta';
|
2 | import Parchment from 'parchment';
|
3 | import Block from '../blots/block';
|
4 | import Inline from '../blots/inline';
|
5 | import TextBlot from '../blots/text';
|
6 |
|
7 |
|
8 | class Code extends Inline {}
|
9 | Code.blotName = 'code';
|
10 | Code.tagName = 'CODE';
|
11 |
|
12 |
|
13 | class CodeBlock extends Block {
|
14 | static create(value) {
|
15 | let domNode = super.create(value);
|
16 | domNode.setAttribute('spellcheck', false);
|
17 | return domNode;
|
18 | }
|
19 |
|
20 | static formats() {
|
21 | return true;
|
22 | }
|
23 |
|
24 | delta() {
|
25 | let text = this.domNode.textContent;
|
26 | if (text.endsWith('\n')) {
|
27 | text = text.slice(0, -1);
|
28 | }
|
29 | return text.split('\n').reduce((delta, frag) => {
|
30 | return delta.insert(frag).insert('\n', this.formats());
|
31 | }, new Delta());
|
32 | }
|
33 |
|
34 | format(name, value) {
|
35 | if (name === this.statics.blotName && value) return;
|
36 | let [text, ] = this.descendant(TextBlot, this.length() - 1);
|
37 | if (text != null) {
|
38 | text.deleteAt(text.length() - 1, 1);
|
39 | }
|
40 | super.format(name, value);
|
41 | }
|
42 |
|
43 | formatAt(index, length, name, value) {
|
44 | if (length === 0) return;
|
45 | if (Parchment.query(name, Parchment.Scope.BLOCK) == null ||
|
46 | (name === this.statics.blotName && value === this.statics.formats(this.domNode))) {
|
47 | return;
|
48 | }
|
49 | let nextNewline = this.newlineIndex(index);
|
50 | if (nextNewline < 0 || nextNewline >= index + length) return;
|
51 | let prevNewline = this.newlineIndex(index, true) + 1;
|
52 | let isolateLength = nextNewline - prevNewline + 1;
|
53 | let blot = this.isolate(prevNewline, isolateLength);
|
54 | let next = blot.next;
|
55 | blot.format(name, value);
|
56 | if (next instanceof CodeBlock) {
|
57 | next.formatAt(0, index - prevNewline + length - isolateLength, name, value);
|
58 | }
|
59 | }
|
60 |
|
61 | insertAt(index, value, def) {
|
62 | if (def != null) return;
|
63 | let [text, offset] = this.descendant(TextBlot, index);
|
64 | text.insertAt(offset, value);
|
65 | }
|
66 |
|
67 | length() {
|
68 | let length = this.domNode.textContent.length;
|
69 | if (!this.domNode.textContent.endsWith('\n')) {
|
70 | return length + 1;
|
71 | }
|
72 | return length;
|
73 | }
|
74 |
|
75 | newlineIndex(searchIndex, reverse = false) {
|
76 | if (!reverse) {
|
77 | let offset = this.domNode.textContent.slice(searchIndex).indexOf('\n');
|
78 | return offset > -1 ? searchIndex + offset : -1;
|
79 | } else {
|
80 | return this.domNode.textContent.slice(0, searchIndex).lastIndexOf('\n');
|
81 | }
|
82 | }
|
83 |
|
84 | optimize(context) {
|
85 | if (!this.domNode.textContent.endsWith('\n')) {
|
86 | this.appendChild(Parchment.create('text', '\n'));
|
87 | }
|
88 | super.optimize(context);
|
89 | let next = this.next;
|
90 | if (next != null && next.prev === this &&
|
91 | next.statics.blotName === this.statics.blotName &&
|
92 | this.statics.formats(this.domNode) === next.statics.formats(next.domNode)) {
|
93 | next.optimize(context);
|
94 | next.moveChildren(this);
|
95 | next.remove();
|
96 | }
|
97 | }
|
98 |
|
99 | replace(target) {
|
100 | super.replace(target);
|
101 | [].slice.call(this.domNode.querySelectorAll('*')).forEach(function(node) {
|
102 | let blot = Parchment.find(node);
|
103 | if (blot == null) {
|
104 | node.parentNode.removeChild(node);
|
105 | } else if (blot instanceof Parchment.Embed) {
|
106 | blot.remove();
|
107 | } else {
|
108 | blot.unwrap();
|
109 | }
|
110 | });
|
111 | }
|
112 | }
|
113 | CodeBlock.blotName = 'code-block';
|
114 | CodeBlock.tagName = 'PRE';
|
115 | CodeBlock.TAB = ' ';
|
116 |
|
117 |
|
118 | export { Code, CodeBlock as default };
|