1 | import extend from 'extend';
|
2 | import Delta from 'quill-delta';
|
3 | import Parchment from 'parchment';
|
4 | import Break from './break';
|
5 | import Inline from './inline';
|
6 | import TextBlot from './text';
|
7 |
|
8 |
|
9 | const NEWLINE_LENGTH = 1;
|
10 |
|
11 |
|
12 | class BlockEmbed extends Parchment.Embed {
|
13 | attach() {
|
14 | super.attach();
|
15 | this.attributes = new Parchment.Attributor.Store(this.domNode);
|
16 | }
|
17 |
|
18 | delta() {
|
19 | return new Delta().insert(this.value(), extend(this.formats(), this.attributes.values()));
|
20 | }
|
21 |
|
22 | format(name, value) {
|
23 | let attribute = Parchment.query(name, Parchment.Scope.BLOCK_ATTRIBUTE);
|
24 | if (attribute != null) {
|
25 | this.attributes.attribute(attribute, value);
|
26 | }
|
27 | }
|
28 |
|
29 | formatAt(index, length, name, value) {
|
30 | this.format(name, value);
|
31 | }
|
32 |
|
33 | insertAt(index, value, def) {
|
34 | if (typeof value === 'string' && value.endsWith('\n')) {
|
35 | let block = Parchment.create(Block.blotName);
|
36 | this.parent.insertBefore(block, index === 0 ? this : this.next);
|
37 | block.insertAt(0, value.slice(0, -1));
|
38 | } else {
|
39 | super.insertAt(index, value, def);
|
40 | }
|
41 | }
|
42 | }
|
43 | BlockEmbed.scope = Parchment.Scope.BLOCK_BLOT;
|
44 |
|
45 |
|
46 |
|
47 | class Block extends Parchment.Block {
|
48 | constructor(domNode) {
|
49 | super(domNode);
|
50 | this.cache = {};
|
51 | }
|
52 |
|
53 | delta() {
|
54 | if (this.cache.delta == null) {
|
55 | this.cache.delta = this.descendants(Parchment.Leaf).reduce((delta, leaf) => {
|
56 | if (leaf.length() === 0) {
|
57 | return delta;
|
58 | } else {
|
59 | return delta.insert(leaf.value(), bubbleFormats(leaf));
|
60 | }
|
61 | }, new Delta()).insert('\n', bubbleFormats(this));
|
62 | }
|
63 | return this.cache.delta;
|
64 | }
|
65 |
|
66 | deleteAt(index, length) {
|
67 | super.deleteAt(index, length);
|
68 | this.cache = {};
|
69 | }
|
70 |
|
71 | formatAt(index, length, name, value) {
|
72 | if (length <= 0) return;
|
73 | if (Parchment.query(name, Parchment.Scope.BLOCK)) {
|
74 | if (index + length === this.length()) {
|
75 | this.format(name, value);
|
76 | }
|
77 | } else {
|
78 | super.formatAt(index, Math.min(length, this.length() - index - 1), name, value);
|
79 | }
|
80 | this.cache = {};
|
81 | }
|
82 |
|
83 | insertAt(index, value, def) {
|
84 | if (def != null) return super.insertAt(index, value, def);
|
85 | if (value.length === 0) return;
|
86 | let lines = value.split('\n');
|
87 | let text = lines.shift();
|
88 | if (text.length > 0) {
|
89 | if (index < this.length() - 1 || this.children.tail == null) {
|
90 | super.insertAt(Math.min(index, this.length() - 1), text);
|
91 | } else {
|
92 | this.children.tail.insertAt(this.children.tail.length(), text);
|
93 | }
|
94 | this.cache = {};
|
95 | }
|
96 | let block = this;
|
97 | lines.reduce(function(index, line) {
|
98 | block = block.split(index, true);
|
99 | block.insertAt(0, line);
|
100 | return line.length;
|
101 | }, index + text.length);
|
102 | }
|
103 |
|
104 | insertBefore(blot, ref) {
|
105 | let head = this.children.head;
|
106 | super.insertBefore(blot, ref);
|
107 | if (head instanceof Break) {
|
108 | head.remove();
|
109 | }
|
110 | this.cache = {};
|
111 | }
|
112 |
|
113 | length() {
|
114 | if (this.cache.length == null) {
|
115 | this.cache.length = super.length() + NEWLINE_LENGTH;
|
116 | }
|
117 | return this.cache.length;
|
118 | }
|
119 |
|
120 | moveChildren(target, ref) {
|
121 | super.moveChildren(target, ref);
|
122 | this.cache = {};
|
123 | }
|
124 |
|
125 | optimize(context) {
|
126 | super.optimize(context);
|
127 | this.cache = {};
|
128 | }
|
129 |
|
130 | path(index) {
|
131 | return super.path(index, true);
|
132 | }
|
133 |
|
134 | removeChild(child) {
|
135 | super.removeChild(child);
|
136 | this.cache = {};
|
137 | }
|
138 |
|
139 | split(index, force = false) {
|
140 | if (force && (index === 0 || index >= this.length() - NEWLINE_LENGTH)) {
|
141 | let clone = this.clone();
|
142 | if (index === 0) {
|
143 | this.parent.insertBefore(clone, this);
|
144 | return this;
|
145 | } else {
|
146 | this.parent.insertBefore(clone, this.next);
|
147 | return clone;
|
148 | }
|
149 | } else {
|
150 | let next = super.split(index, force);
|
151 | this.cache = {};
|
152 | return next;
|
153 | }
|
154 | }
|
155 | }
|
156 | Block.blotName = 'block';
|
157 | Block.tagName = 'P';
|
158 | Block.defaultChild = 'break';
|
159 | Block.allowedChildren = [Inline, Parchment.Embed, TextBlot];
|
160 |
|
161 |
|
162 | function bubbleFormats(blot, formats = {}) {
|
163 | if (blot == null) return formats;
|
164 | if (typeof blot.formats === 'function') {
|
165 | formats = extend(formats, blot.formats());
|
166 | }
|
167 | if (blot.parent == null || blot.parent.blotName == 'scroll' || blot.parent.statics.scope !== blot.statics.scope) {
|
168 | return formats;
|
169 | }
|
170 | return bubbleFormats(blot.parent, formats);
|
171 | }
|
172 |
|
173 |
|
174 | export { bubbleFormats, BlockEmbed, Block as default };
|