@akilli/editor-src 5.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/abbreviation/Abbreviation.js +32 -0
  2. package/abbreviation/AbbreviationDialog.js +21 -0
  3. package/audio/Audio.js +47 -0
  4. package/audio/AudioDialog.js +18 -0
  5. package/audio/AudioListener.js +50 -0
  6. package/base/AlignCommand.js +34 -0
  7. package/base/AlignableListener.js +45 -0
  8. package/base/Alignment.js +36 -0
  9. package/base/BarListener.js +95 -0
  10. package/base/Base.js +127 -0
  11. package/base/Command.js +139 -0
  12. package/base/CommandManager.js +60 -0
  13. package/base/ContentFilter.js +109 -0
  14. package/base/DeletableListener.js +36 -0
  15. package/base/DeleteCommand.js +18 -0
  16. package/base/Dialog.js +153 -0
  17. package/base/DialogManager.js +44 -0
  18. package/base/Dispatcher.js +88 -0
  19. package/base/Dom.js +790 -0
  20. package/base/EditableListener.js +82 -0
  21. package/base/Editor.js +448 -0
  22. package/base/Filter.js +35 -0
  23. package/base/FilterManager.js +44 -0
  24. package/base/FocusableListener.js +22 -0
  25. package/base/FocusbarListener.js +99 -0
  26. package/base/FormCreator.js +162 -0
  27. package/base/FormatbarListener.js +32 -0
  28. package/base/Key.js +258 -0
  29. package/base/Listener.js +51 -0
  30. package/base/NavigableListener.js +81 -0
  31. package/base/Plugin.js +176 -0
  32. package/base/PluginManager.js +51 -0
  33. package/base/SlotableListener.js +40 -0
  34. package/base/SortCommand.js +30 -0
  35. package/base/SortableListener.js +135 -0
  36. package/base/Sorting.js +36 -0
  37. package/base/Tag.js +113 -0
  38. package/base/TagGroup.js +183 -0
  39. package/base/TagListener.js +34 -0
  40. package/base/TagManager.js +61 -0
  41. package/base/TagName.js +470 -0
  42. package/base/ToolbarListener.js +11 -0
  43. package/base/util.js +59 -0
  44. package/block/Block.js +51 -0
  45. package/block/BlockDialog.js +11 -0
  46. package/block/BlockElement.js +21 -0
  47. package/block/BlockListener.js +60 -0
  48. package/blockquote/Blockquote.js +43 -0
  49. package/blockquote/BlockquoteFilter.js +22 -0
  50. package/blockquote/BlockquoteListener.js +34 -0
  51. package/bold/Bold.js +30 -0
  52. package/break/Break.js +33 -0
  53. package/break/BreakFilter.js +24 -0
  54. package/build/BuildEditor.js +97 -0
  55. package/build/editor.css +548 -0
  56. package/build/editor.woff2 +0 -0
  57. package/cite/Cite.js +30 -0
  58. package/code/Code.js +30 -0
  59. package/data/Data.js +32 -0
  60. package/data/DataDialog.js +13 -0
  61. package/definition/Definition.js +32 -0
  62. package/definition/DefinitionDialog.js +13 -0
  63. package/deletion/Deletion.js +30 -0
  64. package/details/Details.js +63 -0
  65. package/details/DetailsFilter.js +17 -0
  66. package/details/DetailsListener.js +102 -0
  67. package/division/Division.js +53 -0
  68. package/division/DivisionDialog.js +13 -0
  69. package/emphasis/Emphasis.js +30 -0
  70. package/figure/Figure.js +58 -0
  71. package/figure/FigureFilter.js +14 -0
  72. package/figure/FigureListener.js +23 -0
  73. package/heading/Heading.js +38 -0
  74. package/horizontalrule/HorizontalRule.js +37 -0
  75. package/i18n/I18n.js +26 -0
  76. package/i18n/de.js +167 -0
  77. package/iframe/Iframe.js +49 -0
  78. package/iframe/IframeDialog.js +20 -0
  79. package/iframe/IframeListener.js +48 -0
  80. package/image/Image.js +47 -0
  81. package/image/ImageDialog.js +23 -0
  82. package/image/ImageListener.js +47 -0
  83. package/insertion/Insertion.js +30 -0
  84. package/italic/Italic.js +30 -0
  85. package/keyboard/Keyboard.js +30 -0
  86. package/link/Link.js +34 -0
  87. package/link/LinkDialog.js +14 -0
  88. package/link/LinkListener.js +45 -0
  89. package/list/List.js +40 -0
  90. package/list/ListListener.js +91 -0
  91. package/mark/Mark.js +30 -0
  92. package/orderedlist/OrderedList.js +39 -0
  93. package/package.json +24 -0
  94. package/paragraph/Paragraph.js +42 -0
  95. package/paragraph/ParagraphListener.js +40 -0
  96. package/preformat/Preformat.js +43 -0
  97. package/preformat/PreformatFilter.js +22 -0
  98. package/preformat/PreformatListener.js +34 -0
  99. package/quote/Quote.js +30 -0
  100. package/sample/Sample.js +30 -0
  101. package/section/Section.js +55 -0
  102. package/section/SectionDialog.js +13 -0
  103. package/small/Small.js +30 -0
  104. package/strikethrough/Strikethrough.js +30 -0
  105. package/strong/Strong.js +30 -0
  106. package/subheading/Subheading.js +38 -0
  107. package/subscript/Subscript.js +30 -0
  108. package/superscript/Superscript.js +30 -0
  109. package/table/Table.js +113 -0
  110. package/table/TableCellListener.js +125 -0
  111. package/table/TableColumnAddCommand.js +19 -0
  112. package/table/TableColumnListener.js +34 -0
  113. package/table/TableCommand.js +23 -0
  114. package/table/TableDialog.js +14 -0
  115. package/table/TableFilter.js +35 -0
  116. package/table/TableListener.js +39 -0
  117. package/table/TableRowAddCommand.js +18 -0
  118. package/table/TableRowListener.js +34 -0
  119. package/time/Time.js +32 -0
  120. package/time/TimeDialog.js +13 -0
  121. package/underline/Underline.js +30 -0
  122. package/unorderedlist/UnorderedList.js +39 -0
  123. package/variable/Variable.js +30 -0
  124. package/video/Video.js +47 -0
  125. package/video/VideoDialog.js +20 -0
  126. package/video/VideoListener.js +48 -0
@@ -0,0 +1,99 @@
1
+ import BarListener from './BarListener.js';
2
+
3
+ export default class FocusbarListener extends BarListener {
4
+ /**
5
+ * @param {Editor} editor
6
+ */
7
+ constructor(editor) {
8
+ super(editor);
9
+ this.editor.focusbar.addEventListener('insertbutton', this);
10
+ this.editor.root.addEventListener('focusin', this);
11
+ this.editor.root.addEventListener('focusout', this);
12
+ this.editor.dom.document.addEventListener('selectionchange', this);
13
+ }
14
+
15
+ /**
16
+ * @param {CustomEvent} event
17
+ * @param {HTMLButtonElement} event.detail.element
18
+ * @return {void}
19
+ */
20
+ insertbutton(event) {
21
+ super.insertbutton(event);
22
+
23
+ if (event.detail.element.getAttribute('data-command')) {
24
+ event.detail.element.addEventListener('mousedown', this);
25
+ }
26
+ }
27
+
28
+ /**
29
+ * @param {MouseEvent} event
30
+ * @return {void}
31
+ */
32
+ mousedown(event) {
33
+ event.preventDefault();
34
+ event.stopPropagation();
35
+ }
36
+
37
+ /**
38
+ * Shows the focusbar on focusin if element is focusable
39
+ *
40
+ * @param {FocusEvent} event
41
+ * @param {HTMLElement} event.target
42
+ * @return {void}
43
+ */
44
+ focusin({ target }) {
45
+ if (target instanceof HTMLElement && target.hasAttribute('data-focusable')) {
46
+ this.#show(target);
47
+ }
48
+ }
49
+
50
+ /**
51
+ * Hides the focusbar on focusout
52
+ *
53
+ * @return {void}
54
+ */
55
+ focusout() {
56
+ this.#hide();
57
+ }
58
+
59
+ /**
60
+ * Hides focusbar if current selection is not collapsed
61
+ *
62
+ * @return {void}
63
+ */
64
+ selectionchange() {
65
+ const element = this.editor.dom.getActiveElement();
66
+
67
+ if (!this.editor.dom.getSelection().isCollapsed || !element) {
68
+ this.#hide();
69
+ } else if (element instanceof HTMLElement && element.hasAttribute('data-focusable')) {
70
+ this.#show(element);
71
+ }
72
+ }
73
+
74
+ /**
75
+ * Shows the focusbar
76
+ *
77
+ * @param {HTMLElement} element
78
+ * @return {void}
79
+ */
80
+ #show(element) {
81
+ if (!this.editor.focusbar.children.length) {
82
+ return;
83
+ }
84
+
85
+ Object.keys(element.dataset).forEach((key) => (this.editor.focusbar.dataset[key] = element.dataset[key]));
86
+ this.editor.focusbar.dataset.tag = element.localName;
87
+ this._show(this.editor.focusbar, element);
88
+ }
89
+
90
+ /**
91
+ * Hides the focusbar
92
+ *
93
+ * @return {void}
94
+ */
95
+ #hide() {
96
+ this._hide(this.editor.focusbar);
97
+ Object.keys(this.editor.focusbar.dataset).forEach((key) => delete this.editor.focusbar.dataset[key]);
98
+ }
99
+ }
@@ -0,0 +1,162 @@
1
+ import Editor from './Editor.js';
2
+ import TagName from './TagName.js';
3
+ import { isString } from './util.js';
4
+
5
+ export default class FormCreator {
6
+ /**
7
+ * @type {Editor}
8
+ */
9
+ #editor;
10
+
11
+ /**
12
+ * @return {Editor}
13
+ */
14
+ get editor() {
15
+ return this.#editor;
16
+ }
17
+
18
+ /**
19
+ * @type {HTMLFormElement}
20
+ */
21
+ #form;
22
+
23
+ /**
24
+ * @return {HTMLFormElement}
25
+ */
26
+ get form() {
27
+ return this.#form;
28
+ }
29
+
30
+ /**
31
+ * Current fieldset
32
+ *
33
+ * @type {HTMLFieldSetElement}
34
+ */
35
+ #fieldset;
36
+
37
+ /**
38
+ * @param {Editor} editor
39
+ */
40
+ constructor(editor) {
41
+ if (!(editor instanceof Editor)) {
42
+ throw new TypeError('Invalid argument');
43
+ }
44
+
45
+ this.#editor = editor;
46
+ this.#form = this.editor.dom.createElement(TagName.FORM, { attributes: { method: 'dialog' } });
47
+ this.addFieldset().#addCancelButton().#addSubmitButton();
48
+ }
49
+
50
+ /**
51
+ * @return {this}
52
+ */
53
+ addFieldset() {
54
+ const fieldset = this.editor.dom.createElement(TagName.FIELDSET);
55
+
56
+ if (this.#fieldset) {
57
+ this.editor.dom.insertAfter(fieldset, this.#fieldset);
58
+ } else {
59
+ this.editor.dom.insertFirstChild(fieldset, this.#form);
60
+ }
61
+
62
+ this.#fieldset = fieldset;
63
+
64
+ return this;
65
+ }
66
+
67
+ /**
68
+ * @param {string} html
69
+ * @return {this}
70
+ */
71
+ addLegend(html) {
72
+ if (!isString(html)) {
73
+ throw new TypeError('Invalid argument');
74
+ }
75
+
76
+ this.editor.dom.insertLastChild(this.editor.dom.createElement(TagName.LEGEND, { html }), this.#fieldset);
77
+
78
+ return this;
79
+ }
80
+
81
+ /**
82
+ * Adds a wrapped text input element with label
83
+ *
84
+ * @param {string} name
85
+ * @param {string} label
86
+ * @param {Object.<string, string>} [attributes = {}]
87
+ * @return {this}
88
+ */
89
+ addTextInput(name, label, attributes = {}) {
90
+ return this.addInput(name, label, attributes, 'text');
91
+ }
92
+
93
+ /**
94
+ * Adds a wrapped number input element with label
95
+ *
96
+ * @param {string} name
97
+ * @param {string} label
98
+ * @param {Object.<string, string>} [attributes = {}]
99
+ * @return {this}
100
+ */
101
+ addNumberInput(name, label, attributes = {}) {
102
+ return this.addInput(name, label, attributes, 'number');
103
+ }
104
+
105
+ /**
106
+ * Adds a wrapped input element with label
107
+ *
108
+ * @param {string} name
109
+ * @param {string} label
110
+ * @param {Object.<string, string>} [attributes = {}]
111
+ * @param {string} [type = 'text']
112
+ * @return {this}
113
+ */
114
+ addInput(name, label, attributes = {}, type = 'text') {
115
+ if (!isString(name) || !isString(label) || !isString(type)) {
116
+ throw new TypeError('Invalid argument');
117
+ }
118
+
119
+ Object.assign(attributes, { id: `editor-${name}`, name, type });
120
+ const div = this.editor.dom.createElement(TagName.DIV);
121
+ this.editor.dom.insertLastChild(
122
+ this.editor.dom.createElement(TagName.LABEL, { attributes: { for: attributes.id }, html: label }),
123
+ div
124
+ );
125
+ this.editor.dom.insertLastChild(this.editor.dom.createElement(TagName.INPUT, { attributes }), div);
126
+ attributes.required && div.setAttribute('data-required', '');
127
+ this.editor.dom.insertLastChild(div, this.#fieldset);
128
+
129
+ return this;
130
+ }
131
+
132
+ /**
133
+ * @return {this}
134
+ */
135
+ #addCancelButton() {
136
+ const html = this.#t('Cancel');
137
+ const button = this.editor.dom.createElement(TagName.BUTTON, { attributes: { type: 'reset' }, html });
138
+ this.editor.dom.insertLastChild(button, this.#form);
139
+
140
+ return this;
141
+ }
142
+
143
+ /**
144
+ * @return {this}
145
+ */
146
+ #addSubmitButton() {
147
+ const button = this.editor.dom.createElement(TagName.BUTTON, { html: this.#t('Save') });
148
+ this.editor.dom.insertLastChild(button, this.#form);
149
+
150
+ return this;
151
+ }
152
+
153
+ /**
154
+ * Translates given string
155
+ *
156
+ * @param {string} key
157
+ * @return {string}
158
+ */
159
+ #t(key) {
160
+ return this.editor.translate(key);
161
+ }
162
+ }
@@ -0,0 +1,32 @@
1
+ import BarListener from './BarListener.js';
2
+ import TagGroup from './TagGroup.js';
3
+
4
+ export default class FormatbarListener extends BarListener {
5
+ /**
6
+ * @param {Editor} editor
7
+ */
8
+ constructor(editor) {
9
+ super(editor);
10
+ this.editor.formatbar.addEventListener('insertbutton', this);
11
+ this.editor.dom.document.addEventListener('selectionchange', this);
12
+ }
13
+
14
+ /**
15
+ * Shows or hides formatbar depending on current selection
16
+ *
17
+ * @return {void}
18
+ */
19
+ selectionchange() {
20
+ const editable = this.editor.dom.getSelectedEditable();
21
+
22
+ if (
23
+ editable &&
24
+ !this.editor.dom.getSelection().isCollapsed &&
25
+ this.editor.tags.allowed(editable, TagGroup.FORMAT, true)
26
+ ) {
27
+ this._show(this.editor.formatbar, editable);
28
+ } else {
29
+ this._hide(this.editor.formatbar);
30
+ }
31
+ }
32
+ }
package/base/Key.js ADDED
@@ -0,0 +1,258 @@
1
+ export default class Key {
2
+ /**
3
+ * @return {string}
4
+ */
5
+ static get A() {
6
+ return 'a';
7
+ }
8
+
9
+ /**
10
+ * @return {string}
11
+ */
12
+ static get ARROWDOWN() {
13
+ return 'ArrowDown';
14
+ }
15
+
16
+ /**
17
+ * @return {string}
18
+ */
19
+ static get ARROWLEFT() {
20
+ return 'ArrowLeft';
21
+ }
22
+
23
+ /**
24
+ * @return {string}
25
+ */
26
+ static get ARROWRIGHT() {
27
+ return 'ArrowRight';
28
+ }
29
+
30
+ /**
31
+ * @return {string}
32
+ */
33
+ static get ARROWUP() {
34
+ return 'ArrowUp';
35
+ }
36
+
37
+ /**
38
+ * @return {string}
39
+ */
40
+ static get B() {
41
+ return 'b';
42
+ }
43
+
44
+ /**
45
+ * @return {string}
46
+ */
47
+ static get BACKSPACE() {
48
+ return 'Backspace';
49
+ }
50
+
51
+ /**
52
+ * @return {string}
53
+ */
54
+ static get C() {
55
+ return 'c';
56
+ }
57
+
58
+ /**
59
+ * @return {string}
60
+ */
61
+ static get D() {
62
+ return 'd';
63
+ }
64
+
65
+ /**
66
+ * @return {string}
67
+ */
68
+ static get DEL() {
69
+ return 'Delete';
70
+ }
71
+
72
+ /**
73
+ * @return {string}
74
+ */
75
+ static get E() {
76
+ return 'e';
77
+ }
78
+
79
+ /**
80
+ * @return {string}
81
+ */
82
+ static get END() {
83
+ return 'End';
84
+ }
85
+
86
+ /**
87
+ * @return {string}
88
+ */
89
+ static get ENTER() {
90
+ return 'Enter';
91
+ }
92
+
93
+ /**
94
+ * @return {string}
95
+ */
96
+ static get F() {
97
+ return 'f';
98
+ }
99
+
100
+ /**
101
+ * @return {string}
102
+ */
103
+ static get G() {
104
+ return 'g';
105
+ }
106
+
107
+ /**
108
+ * @return {string}
109
+ */
110
+ static get HOME() {
111
+ return 'Home';
112
+ }
113
+
114
+ /**
115
+ * @return {string}
116
+ */
117
+ static get I() {
118
+ return 'i';
119
+ }
120
+
121
+ /**
122
+ * @return {string}
123
+ */
124
+ static get J() {
125
+ return 'j';
126
+ }
127
+
128
+ /**
129
+ * @return {string}
130
+ */
131
+ static get K() {
132
+ return 'k';
133
+ }
134
+
135
+ /**
136
+ * @return {string}
137
+ */
138
+ static get L() {
139
+ return 'l';
140
+ }
141
+
142
+ /**
143
+ * @return {string}
144
+ */
145
+ static get M() {
146
+ return 'm';
147
+ }
148
+
149
+ /**
150
+ * @return {string}
151
+ */
152
+ static get O() {
153
+ return 'o';
154
+ }
155
+
156
+ /**
157
+ * @return {string}
158
+ */
159
+ static get Q() {
160
+ return 'q';
161
+ }
162
+
163
+ /**
164
+ * @return {string}
165
+ */
166
+ static get R() {
167
+ return 'r';
168
+ }
169
+
170
+ /**
171
+ * @return {string}
172
+ */
173
+ static get S() {
174
+ return 's';
175
+ }
176
+
177
+ /**
178
+ * @return {string}
179
+ */
180
+ static get SPACE() {
181
+ return ' ';
182
+ }
183
+
184
+ /**
185
+ * @return {string}
186
+ */
187
+ static get T() {
188
+ return 't';
189
+ }
190
+
191
+ /**
192
+ * @return {string}
193
+ */
194
+ static get TAB() {
195
+ return 'Tab';
196
+ }
197
+
198
+ /**
199
+ * @return {string}
200
+ */
201
+ static get U() {
202
+ return 'u';
203
+ }
204
+
205
+ /**
206
+ * @return {string}
207
+ */
208
+ static get V() {
209
+ return 'v';
210
+ }
211
+
212
+ /**
213
+ * @return {string}
214
+ */
215
+ static get W() {
216
+ return 'w';
217
+ }
218
+
219
+ /**
220
+ * @return {string}
221
+ */
222
+ static get X() {
223
+ return 'x';
224
+ }
225
+
226
+ /**
227
+ * @return {string}
228
+ */
229
+ static get Y() {
230
+ return 'y';
231
+ }
232
+
233
+ /**
234
+ * @return {string}
235
+ */
236
+ static get Z() {
237
+ return 'z';
238
+ }
239
+
240
+ /**
241
+ * Indicates if keyboard event was triggered for given key combination
242
+ *
243
+ * @param {KeyboardEvent} event
244
+ * @param {string|string[]} key
245
+ * @param {boolean} alt
246
+ * @param {boolean} ctrl
247
+ * @param {boolean} shift
248
+ * @return {boolean}
249
+ */
250
+ static isEventFor(event, key, { alt = false, ctrl = false, shift = false } = {}) {
251
+ return (
252
+ ((Array.isArray(key) && key.includes(event.key)) || event.key === key) &&
253
+ event.altKey === alt &&
254
+ event.ctrlKey === ctrl &&
255
+ event.shiftKey === shift
256
+ );
257
+ }
258
+ }
@@ -0,0 +1,51 @@
1
+ import Editor from './Editor.js';
2
+ import { isFunction } from './util.js';
3
+
4
+ /**
5
+ * @abstract
6
+ * @implements EventListener
7
+ */
8
+ export default class Listener {
9
+ /**
10
+ * @type {Editor}
11
+ */
12
+ #editor;
13
+
14
+ /**
15
+ * @return {Editor}
16
+ */
17
+ get editor() {
18
+ return this.#editor;
19
+ }
20
+
21
+ /**
22
+ * @borrows handleEvent
23
+ * @param {Editor} editor
24
+ */
25
+ constructor(editor) {
26
+ if (!(editor instanceof Editor)) {
27
+ throw new TypeError('Invalid argument');
28
+ }
29
+
30
+ this.#editor = editor;
31
+ }
32
+
33
+ /**
34
+ * @param {Event} event
35
+ * @return {void}
36
+ */
37
+ handleEvent(event) {
38
+ isFunction(this[event.type]) && this[event.type](event);
39
+ }
40
+
41
+ /**
42
+ * Translates given string
43
+ *
44
+ * @protected
45
+ * @param {string} key
46
+ * @return {string}
47
+ */
48
+ _(key) {
49
+ return this.editor.translate(key);
50
+ }
51
+ }
@@ -0,0 +1,81 @@
1
+ import Key from './Key.js';
2
+ import Listener from './Listener.js';
3
+
4
+ export default class NavigableListener extends Listener {
5
+ /**
6
+ * @param {Editor} editor
7
+ */
8
+ constructor(editor) {
9
+ super(editor);
10
+ this.editor.root.addEventListener('insert', this);
11
+ }
12
+
13
+ /**
14
+ * @param {CustomEvent} event
15
+ * @param {HTMLElement} event.detail.element
16
+ * @return {void}
17
+ */
18
+ insert({ detail: { element } }) {
19
+ if (element.hasAttribute('data-navigable')) {
20
+ element.tabIndex = 0;
21
+ element.addEventListener('keydown', this);
22
+ }
23
+ }
24
+
25
+ /**
26
+ * @param {KeyboardEvent} event
27
+ * @param {HTMLElement} event.target
28
+ * @return {void}
29
+ */
30
+ keydown(event) {
31
+ if (
32
+ event.target === event.currentTarget &&
33
+ Key.isEventFor(event, [Key.ARROWUP, Key.ARROWDOWN, Key.HOME, Key.END]) &&
34
+ this.#enabled(event.target)
35
+ ) {
36
+ const prev = event.target.previousElementSibling;
37
+ const next = event.target.nextElementSibling;
38
+ const first = event.target.parentElement.firstElementChild;
39
+ const last = event.target.parentElement.lastElementChild;
40
+ const isFirst = event.target === first;
41
+ const isLast = event.target === last;
42
+
43
+ if (event.key === Key.ARROWUP && !isFirst && prev.hasAttribute('data-navigable')) {
44
+ prev.focus();
45
+ } else if (event.key === Key.ARROWDOWN && !isLast && next.hasAttribute('data-navigable')) {
46
+ next.focus();
47
+ } else if (
48
+ (event.key === Key.HOME || (event.key === Key.ARROWDOWN && isLast)) &&
49
+ first.hasAttribute('data-navigable')
50
+ ) {
51
+ first.focus();
52
+ } else if (
53
+ (event.key === Key.END || (event.key === Key.ARROWUP && isFirst)) &&
54
+ last.hasAttribute('data-navigable')
55
+ ) {
56
+ last.focus();
57
+ }
58
+
59
+ event.preventDefault();
60
+ event.stopPropagation();
61
+ }
62
+ }
63
+
64
+ /**
65
+ * Indicates if navigation is enabled for element
66
+ *
67
+ * @param {HTMLElement} element
68
+ * @return {boolean}
69
+ */
70
+ #enabled(element) {
71
+ if (element.contentEditable !== 'true') {
72
+ return true;
73
+ }
74
+
75
+ const sel = this.editor.dom.getSelection();
76
+ const editable = this.editor.dom.getSelectedEditable();
77
+ const selected = this.editor.dom.getSelectedElement();
78
+
79
+ return sel.isCollapsed && sel.anchorOffset === 0 && [editable, element.firstChild].includes(selected);
80
+ }
81
+ }