UNPKG

3.48 kBJavaScriptView Raw
1import Parchment from 'parchment';
2import Block from '../blots/block';
3import Container from '../blots/container';
4
5
6class ListItem extends Block {
7 static formats(domNode) {
8 return domNode.tagName === this.tagName ? undefined : super.formats(domNode);
9 }
10
11 format(name, value) {
12 if (name === List.blotName && !value) {
13 this.replaceWith(Parchment.create(this.statics.scope));
14 } else {
15 super.format(name, value);
16 }
17 }
18
19 remove() {
20 if (this.prev == null && this.next == null) {
21 this.parent.remove();
22 } else {
23 super.remove();
24 }
25 }
26
27 replaceWith(name, value) {
28 this.parent.isolate(this.offset(this.parent), this.length());
29 if (name === this.parent.statics.blotName) {
30 this.parent.replaceWith(name, value);
31 return this;
32 } else {
33 this.parent.unwrap();
34 return super.replaceWith(name, value);
35 }
36 }
37}
38ListItem.blotName = 'list-item';
39ListItem.tagName = 'LI';
40
41
42class List extends Container {
43 static create(value) {
44 let tagName = value === 'ordered' ? 'OL' : 'UL';
45 let node = super.create(tagName);
46 if (value === 'checked' || value === 'unchecked') {
47 node.setAttribute('data-checked', value === 'checked');
48 }
49 return node;
50 }
51
52 static formats(domNode) {
53 if (domNode.tagName === 'OL') return 'ordered';
54 if (domNode.tagName === 'UL') {
55 if (domNode.hasAttribute('data-checked')) {
56 return domNode.getAttribute('data-checked') === 'true' ? 'checked' : 'unchecked';
57 } else {
58 return 'bullet';
59 }
60 }
61 return undefined;
62 }
63
64 constructor(domNode) {
65 super(domNode);
66 const listEventHandler = (e) => {
67 if (e.target.parentNode !== domNode) return;
68 let format = this.statics.formats(domNode);
69 let blot = Parchment.find(e.target);
70 if (format === 'checked') {
71 blot.format('list', 'unchecked');
72 } else if(format === 'unchecked') {
73 blot.format('list', 'checked');
74 }
75 }
76
77 domNode.addEventListener('touchstart', listEventHandler);
78 domNode.addEventListener('mousedown', listEventHandler);
79 }
80
81 format(name, value) {
82 if (this.children.length > 0) {
83 this.children.tail.format(name, value);
84 }
85 }
86
87 formats() {
88 // We don't inherit from FormatBlot
89 return { [this.statics.blotName]: this.statics.formats(this.domNode) };
90 }
91
92 insertBefore(blot, ref) {
93 if (blot instanceof ListItem) {
94 super.insertBefore(blot, ref);
95 } else {
96 let index = ref == null ? this.length() : ref.offset(this);
97 let after = this.split(index);
98 after.parent.insertBefore(blot, after);
99 }
100 }
101
102 optimize(context) {
103 super.optimize(context);
104 let next = this.next;
105 if (next != null && next.prev === this &&
106 next.statics.blotName === this.statics.blotName &&
107 next.domNode.tagName === this.domNode.tagName &&
108 next.domNode.getAttribute('data-checked') === this.domNode.getAttribute('data-checked')) {
109 next.moveChildren(this);
110 next.remove();
111 }
112 }
113
114 replace(target) {
115 if (target.statics.blotName !== this.statics.blotName) {
116 let item = Parchment.create(this.statics.defaultChild);
117 target.moveChildren(item);
118 this.appendChild(item);
119 }
120 super.replace(target);
121 }
122}
123List.blotName = 'list';
124List.scope = Parchment.Scope.BLOCK_BLOT;
125List.tagName = ['OL', 'UL'];
126List.defaultChild = 'list-item';
127List.allowedChildren = [ListItem];
128
129
130export { ListItem, List as default };