@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
package/base/Plugin.js ADDED
@@ -0,0 +1,176 @@
1
+ import Command from './Command.js';
2
+ import Editor from './Editor.js';
3
+ import Tag from './Tag.js';
4
+ import TagName from './TagName.js';
5
+ import { isOptString, isString } from './util.js';
6
+
7
+ export default class Plugin {
8
+ /**
9
+ * @type {Editor}
10
+ */
11
+ #editor;
12
+
13
+ /**
14
+ * @return {Editor}
15
+ */
16
+ get editor() {
17
+ return this.#editor;
18
+ }
19
+
20
+ /**
21
+ * @type {string}
22
+ */
23
+ static get name() {
24
+ throw new Error('Missing name');
25
+ }
26
+
27
+ /**
28
+ * @type {Plugin[]}
29
+ */
30
+ static get dependencies() {
31
+ return [];
32
+ }
33
+
34
+ /**
35
+ * Default configuration
36
+ *
37
+ * @type {Object.<string, any>}
38
+ */
39
+ static get config() {
40
+ return {};
41
+ }
42
+
43
+ /**
44
+ * @param {Editor} editor
45
+ */
46
+ constructor(editor) {
47
+ if (!(editor instanceof Editor)) {
48
+ throw new TypeError('Invalid argument');
49
+ }
50
+
51
+ this.#editor = editor;
52
+ }
53
+
54
+ /**
55
+ * @abstract
56
+ * @return {void}
57
+ */
58
+ init() {
59
+ throw new Error('Not implemented');
60
+ }
61
+
62
+ /**
63
+ * Translates given string
64
+ *
65
+ * @protected
66
+ * @param {string} key
67
+ * @return {string}
68
+ */
69
+ _(key) {
70
+ return this.editor.translate(key);
71
+ }
72
+
73
+ /**
74
+ * Registers i18n data for this plugin
75
+ *
76
+ * @protected
77
+ * @param {Object.<string, Object.<string, string>>} i18n
78
+ * @return {void}
79
+ */
80
+ _i18n(i18n) {
81
+ if (i18n[this.editor.config.base.lang]) {
82
+ this.editor.i18n = i18n[this.editor.config.base.lang];
83
+ }
84
+ }
85
+
86
+ /**
87
+ * Creates and registers a tag with given options
88
+ *
89
+ * @protected
90
+ * @param {Object} opts
91
+ * @return {void}
92
+ */
93
+ _tag(opts) {
94
+ this.editor.tags.set(new Tag(opts));
95
+ }
96
+
97
+ /**
98
+ * Registers a command with given parameters
99
+ *
100
+ * @protected
101
+ * @param {string} tagName
102
+ * @return {void}
103
+ */
104
+ _command(tagName) {
105
+ this.editor.commands.set(new Command(this.editor, this.constructor.name, tagName));
106
+ }
107
+
108
+ /**
109
+ * Adds a toolbar button
110
+ *
111
+ * @protected
112
+ * @param {string} label
113
+ * @param {string|undefined} [command = undefined]
114
+ * @return {void}
115
+ */
116
+ _toolbar(label, command = undefined) {
117
+ const l = this._(label);
118
+ this.editor.dom.insertLastChild(this.#button(l, l, undefined, command), this.editor.toolbar);
119
+ }
120
+
121
+ /**
122
+ * Adds a formatbar button
123
+ *
124
+ * @protected
125
+ * @param {string} label
126
+ * @param {string|undefined} [key = undefined]
127
+ * @param {string|undefined} [command = undefined]
128
+ * @return {void}
129
+ */
130
+ _formatbar(label, key = undefined, command = undefined) {
131
+ const l = this._(label);
132
+ const alt = this._('Alt');
133
+ const shift = this._('Shift');
134
+ const title = l + (key ? ` [${alt} + ${shift} + ${key}]` : '');
135
+
136
+ this.editor.dom.insertLastChild(this.#button(l, title, key, command), this.editor.formatbar);
137
+ }
138
+
139
+ /**
140
+ * Adds a focusbar button
141
+ *
142
+ * @protected
143
+ * @param {string} label
144
+ * @param {string|undefined} [command = undefined]
145
+ * @return {void}
146
+ */
147
+ _focusbar(label, command = undefined) {
148
+ const l = this._(label);
149
+ this.editor.dom.insertLastChild(this.#button(l, l, undefined, command), this.editor.focusbar);
150
+ }
151
+
152
+ /**
153
+ * Creates a button
154
+ *
155
+ * @param {string} html
156
+ * @param {string} title
157
+ * @param {string|undefined} [key = undefined]
158
+ * @param {string|undefined} [command = undefined]
159
+ * @return {HTMLButtonElement}
160
+ */
161
+ #button(html, title, key = undefined, command = undefined) {
162
+ if (!isString(html) || !isString(title) || !isOptString(key)) {
163
+ throw new TypeError('Invalid argument');
164
+ }
165
+
166
+ return this.editor.dom.createElement(TagName.BUTTON, {
167
+ attributes: {
168
+ type: 'button',
169
+ title,
170
+ 'data-command': command || this.constructor.name,
171
+ 'data-key': key,
172
+ },
173
+ html,
174
+ });
175
+ }
176
+ }
@@ -0,0 +1,51 @@
1
+ import Plugin from './Plugin.js';
2
+
3
+ export default class PluginManager {
4
+ /**
5
+ * @type {Map<string, Plugin>}
6
+ */
7
+ #items = new Map();
8
+
9
+ /**
10
+ * @param {Plugin[]} [plugins = []]
11
+ */
12
+ constructor(plugins = []) {
13
+ plugins.forEach((plugin) => this.set(plugin));
14
+ }
15
+
16
+ /**
17
+ * @param {string} name
18
+ * @return {Plugin|undefined}
19
+ */
20
+ get(name) {
21
+ return this.#items.get(name);
22
+ }
23
+
24
+ /**
25
+ * @param {Plugin} plugin
26
+ * @return {void}
27
+ */
28
+ set(plugin) {
29
+ if (!(plugin instanceof Plugin)) {
30
+ throw new TypeError('Invalid argument');
31
+ }
32
+
33
+ this.#items.set(plugin.constructor.name, plugin);
34
+ }
35
+
36
+ /**
37
+ * @return {void}
38
+ */
39
+ init() {
40
+ this.#items.forEach((plugin) => plugin.init());
41
+ }
42
+
43
+ /**
44
+ * @return {void}
45
+ */
46
+ freeze() {
47
+ this.#items.forEach((plugin) => Object.freeze(plugin));
48
+ Object.freeze(this.#items);
49
+ Object.freeze(this);
50
+ }
51
+ }
@@ -0,0 +1,40 @@
1
+ import Key from './Key.js';
2
+ import Listener from './Listener.js';
3
+ import TagName from './TagName.js';
4
+
5
+ export default class SlotableListener extends Listener {
6
+ /**
7
+ * @param {Editor} editor
8
+ */
9
+ constructor(editor) {
10
+ super(editor);
11
+ this.editor.root.addEventListener('insert', this);
12
+ }
13
+
14
+ /**
15
+ * @param {CustomEvent} event
16
+ * @param {HTMLElement} event.detail.element
17
+ * @return {void}
18
+ */
19
+ insert({ detail: { element } }) {
20
+ if (element instanceof HTMLSlotElement) {
21
+ element.addEventListener('keydown', this);
22
+ } else if (element.hasAttribute('data-slotable') && !element.querySelector(':scope > ' + TagName.SLOT)) {
23
+ this.editor.dom.insertLastChild(this.editor.dom.createElement(TagName.SLOT), element);
24
+ }
25
+ }
26
+
27
+ /**
28
+ * @param {KeyboardEvent} event
29
+ * @param {HTMLSlotElement} event.target
30
+ * @return {void}
31
+ */
32
+ keydown(event) {
33
+ if (Key.isEventFor(event, Key.BACKSPACE) && event.target.matches(':only-child')) {
34
+ this.editor.dom.delete(event.target.parentElement);
35
+ } else if (!Key.isEventFor(event, Key.TAB) && !Key.isEventFor(event, Key.TAB, { shift: true })) {
36
+ event.preventDefault();
37
+ event.stopPropagation();
38
+ }
39
+ }
40
+ }
@@ -0,0 +1,30 @@
1
+ import Command from './Command.js';
2
+ import Sorting from './Sorting.js';
3
+
4
+ export default class SortCommand extends Command {
5
+ /**
6
+ * @type {string}
7
+ */
8
+ #sorting;
9
+
10
+ /**
11
+ * @param {Editor} editor
12
+ * @param {string} sorting
13
+ */
14
+ constructor(editor, sorting) {
15
+ if (!Sorting.values().includes(sorting)) {
16
+ throw new TypeError('Invalid argument');
17
+ }
18
+
19
+ super(editor, 'sort-' + sorting);
20
+ this.#sorting = sorting;
21
+ }
22
+
23
+ /**
24
+ * @return {void}
25
+ */
26
+ execute() {
27
+ const element = this.editor.dom.getActiveElement();
28
+ element?.hasAttribute('data-sortable') && this.editor.dom.sort(element, this.#sorting);
29
+ }
30
+ }
@@ -0,0 +1,135 @@
1
+ import Key from './Key.js';
2
+ import Listener from './Listener.js';
3
+ import Sorting from './Sorting.js';
4
+ import TagName from './TagName.js';
5
+
6
+ export default class SortableListener extends Listener {
7
+ /**
8
+ * @param {Editor} editor
9
+ */
10
+ constructor(editor) {
11
+ super(editor);
12
+ this.editor.root.addEventListener('insert', this);
13
+ }
14
+
15
+ /**
16
+ * @param {CustomEvent} event
17
+ * @param {HTMLElement} event.detail.element
18
+ * @return {void}
19
+ */
20
+ insert({ detail: { element } }) {
21
+ if (element.hasAttribute('data-sortable')) {
22
+ element.addEventListener('keydown', this);
23
+ element.addEventListener('pointerdown', this);
24
+ element.addEventListener('pointermove', this);
25
+ element.addEventListener('pointerup', this);
26
+ }
27
+ }
28
+
29
+ /**
30
+ * @param {KeyboardEvent} event
31
+ * @param {HTMLElement} event.target
32
+ * @return {void}
33
+ */
34
+ keydown(event) {
35
+ const map = {
36
+ [Key.HOME]: Sorting.FIRST,
37
+ [Key.ARROWUP]: Sorting.PREV,
38
+ [Key.ARROWDOWN]: Sorting.NEXT,
39
+ [Key.END]: Sorting.LAST,
40
+ };
41
+
42
+ if (event.target === event.currentTarget && Key.isEventFor(event, Object.keys(map), { ctrl: true })) {
43
+ this.editor.dom.sort(event.target, map[event.key]);
44
+ event.preventDefault();
45
+ event.stopPropagation();
46
+ }
47
+ }
48
+
49
+ /**
50
+ * @param {PointerEvent} event
51
+ * @param {HTMLElement} event.target
52
+ * @return {void}
53
+ */
54
+ pointerdown(event) {
55
+ const target = event.target.closest('[data-sortable]');
56
+
57
+ if (target && this.editor.dom.contains(target)) {
58
+ target.setAttribute('data-sort', '');
59
+ target.setPointerCapture(event.pointerId);
60
+ }
61
+ }
62
+
63
+ /**
64
+ * @param {PointerEvent} event
65
+ * @param {HTMLElement} event.target
66
+ * @return {void}
67
+ */
68
+ pointermove(event) {
69
+ const target = event.target.closest('[data-sortable][data-sort]');
70
+ const element = this.editor.dom.document.elementFromPoint(event.x, event.y);
71
+ this.#sortover();
72
+
73
+ if (target && this.editor.dom.contains(target) && this.#droppable(target, element)) {
74
+ element.setAttribute('data-sortover', '');
75
+ }
76
+ }
77
+
78
+ /**
79
+ * @param {PointerEvent} event
80
+ * @param {HTMLElement} event.target
81
+ * @return {void}
82
+ */
83
+ pointerup(event) {
84
+ const target = event.target.closest('[data-sortable][data-sort]');
85
+
86
+ if (target && this.editor.dom.contains(target)) {
87
+ const element = this.editor.dom.document.elementFromPoint(event.x, event.y);
88
+ const parent = element.parentElement;
89
+ this.#sortover();
90
+ target.removeAttribute('data-sort');
91
+ target.releasePointerCapture(event.pointerId);
92
+
93
+ if (this.#droppable(target, element)) {
94
+ if (target.localName === TagName.COL && parent === target.parentElement) {
95
+ const t = Array.from(parent.children).indexOf(target);
96
+ const e = Array.from(parent.children).indexOf(element);
97
+ const table = parent.parentElement;
98
+ Array.from(table.rows).forEach((row) => this.editor.dom.insertBefore(row.cells[t], row.cells[e]));
99
+ }
100
+
101
+ this.editor.dom.insertBefore(target, element);
102
+ }
103
+ }
104
+ }
105
+
106
+ /**
107
+ * Removes editor sortover attribute
108
+ *
109
+ * @return {void}
110
+ */
111
+ #sortover() {
112
+ this.editor.root.querySelectorAll('[data-sortover]').forEach((item) => item.removeAttribute('data-sortover'));
113
+ }
114
+
115
+ /**
116
+ * Indicates if target element is a potential drop target for given element
117
+ *
118
+ * @param {HTMLElement} element
119
+ * @param {HTMLElement} target
120
+ * @return {boolean}
121
+ */
122
+ #droppable(element, target) {
123
+ return (
124
+ element instanceof HTMLElement &&
125
+ target instanceof HTMLElement &&
126
+ this.editor.dom.contains(target) &&
127
+ ![this.editor.root, element].includes(target) &&
128
+ target.hasAttribute('data-sortable') &&
129
+ (element.parentElement === target.parentElement ||
130
+ (this.editor.dom.arbitrary(element.parentElement) &&
131
+ this.editor.dom.arbitrary(target.parentElement))) &&
132
+ this.editor.tags.allowed(target.parentElement, element)
133
+ );
134
+ }
135
+ }
@@ -0,0 +1,36 @@
1
+ export default class Sorting {
2
+ /**
3
+ * @return {string}
4
+ */
5
+ static get FIRST() {
6
+ return 'first';
7
+ }
8
+
9
+ /**
10
+ * @return {string}
11
+ */
12
+ static get PREV() {
13
+ return 'prev';
14
+ }
15
+
16
+ /**
17
+ * @return {string}
18
+ */
19
+ static get NEXT() {
20
+ return 'next';
21
+ }
22
+
23
+ /**
24
+ * @return {string}
25
+ */
26
+ static get LAST() {
27
+ return 'last';
28
+ }
29
+
30
+ /**
31
+ * @return {string[]}
32
+ */
33
+ static values() {
34
+ return [this.FIRST, this.PREV, this.NEXT, this.LAST];
35
+ }
36
+ }
package/base/Tag.js ADDED
@@ -0,0 +1,113 @@
1
+ import { isOptArray, isOptString, isString } from './util.js';
2
+
3
+ export default class Tag {
4
+ /**
5
+ * @type {string}
6
+ */
7
+ name;
8
+
9
+ /**
10
+ * @type {string}
11
+ */
12
+ group;
13
+
14
+ /**
15
+ * @type {string[]}
16
+ */
17
+ children;
18
+
19
+ /**
20
+ * @type {string[]}
21
+ */
22
+ attributes;
23
+
24
+ /**
25
+ * @type {boolean}
26
+ */
27
+ alignable;
28
+
29
+ /**
30
+ * Does element allow arbitrary amount of child elements
31
+ *
32
+ * @type {boolean}
33
+ */
34
+ arbitrary;
35
+
36
+ /**
37
+ * @type {boolean}
38
+ */
39
+ deletable;
40
+
41
+ /**
42
+ * @type {boolean}
43
+ */
44
+ editable;
45
+
46
+ /**
47
+ * Is element empty or allowed to be empty
48
+ *
49
+ * @type {boolean}
50
+ */
51
+ empty;
52
+
53
+ /**
54
+ * @type {boolean}
55
+ */
56
+ focusable;
57
+
58
+ /**
59
+ * @type {boolean}
60
+ */
61
+ navigable;
62
+
63
+ /**
64
+ * Does element define a slot
65
+ *
66
+ * @type {boolean}
67
+ */
68
+ slotable;
69
+
70
+ /**
71
+ * @type {boolean}
72
+ */
73
+ sortable;
74
+
75
+ /**
76
+ * Element to insert when ENTER-key is pressed
77
+ *
78
+ * @type {string|undefined}
79
+ */
80
+ enter;
81
+
82
+ /**
83
+ * @param {string} name
84
+ * @param {string} group
85
+ * @param {Object.<string, any>} [opts = {}]
86
+ */
87
+ constructor({ name, group, ...opts } = {}) {
88
+ if (
89
+ !isString(name) ||
90
+ !isString(group) ||
91
+ !isOptArray(opts.children) ||
92
+ !isOptArray(opts.attributes) ||
93
+ !isOptString(opts.enter)
94
+ ) {
95
+ throw new TypeError('Invalid argument');
96
+ }
97
+
98
+ this.name = name;
99
+ this.group = group;
100
+ this.children = opts.children || [];
101
+ this.attributes = opts.attributes || [];
102
+ this.arbitrary = opts.arbitrary === true;
103
+ this.alignable = opts.alignable === true;
104
+ this.deletable = opts.deletable === true;
105
+ this.editable = opts.editable === true;
106
+ this.empty = opts.empty === true;
107
+ this.focusable = opts.focusable === true;
108
+ this.navigable = opts.navigable === true;
109
+ this.slotable = opts.slotable === true;
110
+ this.sortable = opts.sortable === true;
111
+ this.enter = opts.enter;
112
+ }
113
+ }