UNPKG

3.23 kBJavaScriptView Raw
1import Parchment from 'parchment';
2import TextBlot from './text';
3
4
5class Cursor extends Parchment.Embed {
6 static value() {
7 return undefined;
8 }
9
10 constructor(domNode, selection) {
11 super(domNode);
12 this.selection = selection;
13 this.textNode = document.createTextNode(Cursor.CONTENTS);
14 this.domNode.appendChild(this.textNode);
15 this._length = 0;
16 }
17
18 detach() {
19 // super.detach() will also clear domNode.__blot
20 if (this.parent != null) this.parent.removeChild(this);
21 }
22
23 format(name, value) {
24 if (this._length !== 0) {
25 return super.format(name, value);
26 }
27 let target = this, index = 0;
28 while (target != null && target.statics.scope !== Parchment.Scope.BLOCK_BLOT) {
29 index += target.offset(target.parent);
30 target = target.parent;
31 }
32 if (target != null) {
33 this._length = Cursor.CONTENTS.length;
34 target.optimize();
35 target.formatAt(index, Cursor.CONTENTS.length, name, value);
36 this._length = 0;
37 }
38 }
39
40 index(node, offset) {
41 if (node === this.textNode) return 0;
42 return super.index(node, offset);
43 }
44
45 length() {
46 return this._length;
47 }
48
49 position() {
50 return [this.textNode, this.textNode.data.length];
51 }
52
53 remove() {
54 super.remove();
55 this.parent = null;
56 }
57
58 restore() {
59 if (this.selection.composing || this.parent == null) return;
60 let textNode = this.textNode;
61 let range = this.selection.getNativeRange();
62 let restoreText, start, end;
63 if (range != null && range.start.node === textNode && range.end.node === textNode) {
64 [restoreText, start, end] = [textNode, range.start.offset, range.end.offset];
65 }
66 // Link format will insert text outside of anchor tag
67 while (this.domNode.lastChild != null && this.domNode.lastChild !== this.textNode) {
68 this.domNode.parentNode.insertBefore(this.domNode.lastChild, this.domNode);
69 }
70 if (this.textNode.data !== Cursor.CONTENTS) {
71 let text = this.textNode.data.split(Cursor.CONTENTS).join('');
72 if (this.next instanceof TextBlot) {
73 restoreText = this.next.domNode;
74 this.next.insertAt(0, text);
75 this.textNode.data = Cursor.CONTENTS;
76 } else {
77 this.textNode.data = text;
78 this.parent.insertBefore(Parchment.create(this.textNode), this);
79 this.textNode = document.createTextNode(Cursor.CONTENTS);
80 this.domNode.appendChild(this.textNode);
81 }
82 }
83 this.remove();
84 if (start != null) {
85 [start, end] = [start, end].map(function(offset) {
86 return Math.max(0, Math.min(restoreText.data.length, offset - 1));
87 });
88 return {
89 startNode: restoreText,
90 startOffset: start,
91 endNode: restoreText,
92 endOffset: end
93 };
94 }
95 }
96
97 update(mutations, context) {
98 if (mutations.some((mutation) => {
99 return mutation.type === 'characterData' && mutation.target === this.textNode;
100 })) {
101 let range = this.restore();
102 if (range) context.range = range;
103 }
104 }
105
106 value() {
107 return '';
108 }
109}
110Cursor.blotName = 'cursor';
111Cursor.className = 'ql-cursor';
112Cursor.tagName = 'span';
113Cursor.CONTENTS = "\uFEFF"; // Zero width no break space
114
115
116export default Cursor;