u2ui 1.5.2 → 1.5.4

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 (144) hide show
  1. package/el/ico/ico.js +5 -5
  2. package/el/rte/README.md +53 -13
  3. package/el/rte/manifest.json +19 -4
  4. package/el/rte/rte.css +31 -6
  5. package/el/rte/rte.js +174 -44
  6. package/el/rte0/README.md +37 -0
  7. package/el/rte0/manifest.json +33 -0
  8. package/el/rte0/rte0.css +9 -0
  9. package/el/rte0/rte0.js +56 -0
  10. package/el/system/styler.js +2 -0
  11. package/el/tooltip/tooltip.css +2 -2
  12. package/js/Placer/Placer.js +2 -1
  13. package/js/rte/AGENTS.md +142 -0
  14. package/js/rte/PLAN.md +488 -0
  15. package/js/rte/README.md +319 -25
  16. package/js/rte/blocks.js +7 -0
  17. package/js/rte/breaks.js +6 -0
  18. package/js/rte/classes.js +7 -0
  19. package/js/rte/docs/usage.md +845 -0
  20. package/js/rte/images.js +7 -0
  21. package/js/rte/link.js +8 -0
  22. package/js/rte/playground/README.md +95 -0
  23. package/js/rte/playground/hosts.html +518 -0
  24. package/js/rte/playground/index.html +824 -0
  25. package/js/rte/rte.js +56 -5
  26. package/js/rte/source.js +12 -0
  27. package/js/rte/src/browser/README.md +40 -0
  28. package/js/rte/src/browser/range-rect.js +82 -0
  29. package/js/rte/src/client/README.md +378 -0
  30. package/js/rte/src/client/blocks.js +38 -0
  31. package/js/rte/src/client/breaks.js +212 -0
  32. package/js/rte/src/client/classes.js +48 -0
  33. package/js/rte/src/client/editor.js +461 -0
  34. package/js/rte/src/client/external-input.js +47 -0
  35. package/js/rte/src/client/history.js +13 -0
  36. package/js/rte/src/client/images.js +275 -0
  37. package/js/rte/src/client/link.js +572 -0
  38. package/js/rte/src/client/marks.js +25 -0
  39. package/js/rte/src/client/source.js +182 -0
  40. package/js/rte/src/client/structure.js +27 -0
  41. package/js/rte/src/client/tables.js +162 -0
  42. package/js/rte/src/client/unstyle.js +32 -0
  43. package/js/rte/src/command/README.md +517 -0
  44. package/js/rte/src/command/block-boundary.js +43 -0
  45. package/js/rte/src/command/block-style.js +120 -0
  46. package/js/rte/src/command/commands.js +158 -0
  47. package/js/rte/src/command/delete.js +112 -0
  48. package/js/rte/src/command/edit.js +72 -0
  49. package/js/rte/src/command/element.js +45 -0
  50. package/js/rte/src/command/enter.js +175 -0
  51. package/js/rte/src/command/fragment.js +76 -0
  52. package/js/rte/src/command/insert.js +52 -0
  53. package/js/rte/src/command/list.js +284 -0
  54. package/js/rte/src/command/mark.js +583 -0
  55. package/js/rte/src/command/pending-marks.js +216 -0
  56. package/js/rte/src/command/table.js +207 -0
  57. package/js/rte/src/command/unstyle.js +248 -0
  58. package/js/rte/src/config/README.md +96 -0
  59. package/js/rte/src/config/config.js +127 -0
  60. package/js/rte/src/core/README.md +41 -0
  61. package/js/rte/src/core/core.js +156 -0
  62. package/js/rte/src/history/README.md +83 -0
  63. package/js/rte/src/history/history.js +283 -0
  64. package/js/rte/src/input/README.md +155 -0
  65. package/js/rte/src/input/external-input.js +130 -0
  66. package/js/rte/src/input/input-pipeline.js +414 -0
  67. package/js/rte/src/mark/README.md +219 -0
  68. package/js/rte/src/mark/dom-adapter.js +100 -0
  69. package/js/rte/src/mark/mark.js +133 -0
  70. package/js/rte/src/mark/standard.js +76 -0
  71. package/js/rte/src/model/README.md +71 -0
  72. package/js/rte/src/model/content-model.js +213 -0
  73. package/js/rte/src/model/html/README.md +51 -0
  74. package/js/rte/src/model/html/html-model.js +90 -0
  75. package/js/rte/src/normalize/execute/README.md +33 -0
  76. package/js/rte/src/normalize/execute/repair-executor.js +129 -0
  77. package/js/rte/src/normalize/normalizer/README.md +48 -0
  78. package/js/rte/src/normalize/normalizer/normalizer.js +141 -0
  79. package/js/rte/src/normalize/repair/README.md +70 -0
  80. package/js/rte/src/normalize/repair/repair-planner.js +208 -0
  81. package/js/rte/src/sanitize/README.md +105 -0
  82. package/js/rte/src/sanitize/native.js +43 -0
  83. package/js/rte/src/sanitize/policy.js +202 -0
  84. package/js/rte/src/selection/README.md +39 -0
  85. package/js/rte/src/selection/map/README.md +53 -0
  86. package/js/rte/src/selection/map/point-map.js +307 -0
  87. package/js/rte/src/selection/ownership/README.md +32 -0
  88. package/js/rte/src/selection/ownership/ownership.js +42 -0
  89. package/js/rte/src/selection/point/README.md +34 -0
  90. package/js/rte/src/selection/point/point.js +83 -0
  91. package/js/rte/src/selection/range/README.md +38 -0
  92. package/js/rte/src/selection/range/edit-range.js +223 -0
  93. package/js/rte/src/selection/snapshot.js +64 -0
  94. package/js/rte/src/source/README.md +64 -0
  95. package/js/rte/src/source/source.js +193 -0
  96. package/js/rte/src/surface/README.md +36 -0
  97. package/js/rte/src/surface/content.js +16 -0
  98. package/js/rte/src/surface/surface.js +87 -0
  99. package/js/rte/src/transaction/README.md +35 -0
  100. package/js/rte/src/transaction/transaction.js +56 -0
  101. package/js/rte/src/ui/README.md +255 -0
  102. package/js/rte/src/ui/chrome.js +214 -0
  103. package/js/rte/src/ui/handles.js +179 -0
  104. package/js/rte/src/ui/place.js +25 -0
  105. package/js/rte/src/ui/toolbar.js +283 -0
  106. package/js/rte/src/unstyle/README.md +103 -0
  107. package/js/rte/src/unstyle/unstyle.js +140 -0
  108. package/js/rte/tables.js +7 -0
  109. package/js/rte/unstyle.js +8 -0
  110. package/js/rte0/README.md +37 -0
  111. package/js/rte0/rte.js +7 -0
  112. package/js/{rte → rte0}/src/behavior.js +0 -1
  113. package/js/{rte → rte0}/src/events.js +0 -1
  114. package/js/{rte → rte0}/src/range.js +0 -2
  115. package/js/{rte → rte0}/src/ui.items.js +0 -2
  116. package/js/{rte → rte0}/src/ui.js +0 -1
  117. package/package.json +1 -1
  118. package/u2/Element.js +16 -4
  119. package/u2/enhance.js +2 -1
  120. package/u2/plan-scoped-refactoring.md +133 -304
  121. package/u2/projects.json +18 -2
  122. package/u2/tools/update.repos.json.js +1 -1
  123. package/u2/utils.js +0 -16
  124. package/el/qrcode/package.json +0 -22
  125. /package/js/{rte → rte0}/old/NodeCleaner.js +0 -0
  126. /package/js/{rte → rte0}/old/Rte/Rte.mjs +0 -0
  127. /package/js/{rte → rte0}/old/Rte/Rte.ui.items.mjs +0 -0
  128. /package/js/{rte → rte0}/old/Rte/Rte.ui.mjs +0 -0
  129. /package/js/{rte → rte0}/old/Rte/crossbrowser.mjs +0 -0
  130. /package/js/{rte → rte0}/old/Rte/font/tinymce.svg +0 -0
  131. /package/js/{rte → rte0}/old/Rte/font/tinymce.woff +0 -0
  132. /package/js/{rte → rte0}/old/Rte/helpers.mjs +0 -0
  133. /package/js/{rte → rte0}/old/Rte/htmlparser.mjs +0 -0
  134. /package/js/{rte → rte0}/old/Rte/index.mjs +0 -0
  135. /package/js/{rte → rte0}/old/Rte/main.css +0 -0
  136. /package/js/{rte → rte0}/old/old.rte.js +0 -0
  137. /package/js/{rte → rte0}/old/range-selection.old.js +0 -0
  138. /package/js/{rte → rte0}/src/fixes.js +0 -0
  139. /package/js/{rte → rte0}/src/rte.js +0 -0
  140. /package/js/{rte → rte0}/src/ui/items/ai.js +0 -0
  141. /package/js/{rte → rte0}/src/ui/items/code.js +0 -0
  142. /package/js/{rte → rte0}/src/ui/items/undo.js +0 -0
  143. /package/js/{rte → rte0}/src/util/htmlparser.js +0 -0
  144. /package/js/{rte → rte0}/src/util/indentHtml.js +0 -0
@@ -0,0 +1,583 @@
1
+ import {Edit} from './edit.js';
2
+ import {MarkAdapter} from '../mark/dom-adapter.js';
3
+ import {elementOf, isEditingBoundary} from '../selection/ownership/ownership.js';
4
+ import {Mark, markSet} from '../mark/mark.js';
5
+ import {EditRange} from '../selection/range/edit-range.js';
6
+ import {Point} from '../selection/point/point.js';
7
+
8
+ export function applyMark(adapter, value) {
9
+ const mark = concrete(adapter, arguments.length > 1 ? value : true);
10
+ return applyCommand(adapter, mark);
11
+ }
12
+
13
+ export function removeMark(adapter, value) {
14
+ const mark = concrete(adapter, arguments.length > 1 ? value : true);
15
+ return removeCommand(adapter, mark);
16
+ }
17
+
18
+ export function toggleMark(adapter, value) {
19
+ const mark = concrete(adapter, arguments.length > 1 ? value : true);
20
+ const apply = applyCommand(adapter, mark);
21
+ const remove = removeCommand(adapter, mark);
22
+ return {
23
+ enabled: edit => {
24
+ if (!selected(edit)) return false;
25
+ return markState(edit, adapter, mark) === true || canApply(edit, adapter, mark);
26
+ },
27
+ state: apply.state,
28
+ run(edit) {
29
+ return (markState(edit, adapter, mark) === true ? remove : apply).run(edit);
30
+ },
31
+ };
32
+ }
33
+
34
+ // One command for a mark whose value is decided per execution: `edit.value`
35
+ // carries it, and a null value removes whatever mark of that type is there.
36
+ // A link needs this — its value is content, not a fixed choice — so a single
37
+ // control can create, change, and remove one without a command per URL.
38
+ export function valueMark(adapter) {
39
+ return {
40
+ enabled(edit) {
41
+ const scope = whole(edit, adapter);
42
+ if (scope.value == null) return current(scope, adapter).length > 0;
43
+ return selected(scope) && canApply(scope, adapter, concrete(adapter, scope.value));
44
+ },
45
+ state(edit) {
46
+ const marks = current(edit, adapter);
47
+ if (!marks.length) return null;
48
+ if (marks.length > 1) return 'mixed';
49
+ return markState(edit, adapter, marks[0]) === true ? marks[0].value : 'mixed';
50
+ },
51
+ run(edit) {
52
+ const scope = whole(edit, adapter);
53
+ if (scope.value == null) {
54
+ return change(scope, current(scope, adapter).map(mark => [adapter, mark]));
55
+ }
56
+ return applyCommand(adapter, concrete(adapter, scope.value)).run(scope);
57
+ },
58
+ };
59
+ }
60
+
61
+ // A caret carries no range to mark, but it does sit on one: a value command at
62
+ // a caret inside a mark acts on that whole mark, which is what makes editing an
63
+ // existing link's value possible without selecting it first.
64
+ function whole(edit, adapter) {
65
+ if (!edit.range?.collapsed) return edit;
66
+ const element = carrier(edit, adapter);
67
+ if (!element) return edit;
68
+ const range = edit.document.createRange();
69
+ range.selectNodeContents(element);
70
+ return new Edit(edit.surface, edit.transaction, {
71
+ model: edit.model,
72
+ range,
73
+ value: edit.value,
74
+ inputType: edit.inputType,
75
+ data: edit.data,
76
+ });
77
+ }
78
+
79
+ function carrier(edit, adapter) {
80
+ for (let element = elementOf(edit.range.start.node);
81
+ element && element !== edit.element; element = element.parentElement) {
82
+ if (isEditingBoundary(element) || edit.model.block(element)) return null;
83
+ if (adapter.parse(element)) return element;
84
+ }
85
+ return null;
86
+ }
87
+
88
+ // The marks of one type the edit actually sits on, at a caret or across a range.
89
+ function current(edit, adapter) {
90
+ if (!edit.range) return [];
91
+ return edit.range.collapsed
92
+ ? [...marksAt(edit, [adapter], edit.range.start.node)]
93
+ : marksIn(edit, adapter);
94
+ }
95
+
96
+ export function setMarks(adapters) {
97
+ const known = adapterSet(adapters);
98
+ return {
99
+ enabled(edit) {
100
+ const target = targetSet(edit.value, known);
101
+ return selected(edit) && !!target && target.every(mark => {
102
+ const adapter = known.get(mark.type);
103
+ return markState(edit, adapter, mark) === true || canApply(edit, adapter, mark);
104
+ });
105
+ },
106
+ state: edit => setState(edit, [...known.values()]),
107
+ run(edit) {
108
+ const target = targetSet(edit.value, known);
109
+ if (!target) return [];
110
+ const removals = [];
111
+ for (const adapter of known.values()) {
112
+ const kept = target.filter(mark => mark.type === adapter.type);
113
+ for (const mark of marksIn(edit, adapter)) {
114
+ if (!kept.some(item => item.equals(mark))) removals.push([adapter, mark]);
115
+ }
116
+ }
117
+ return change(edit, removals, target.map(mark => [known.get(mark.type), mark]));
118
+ },
119
+ };
120
+ }
121
+
122
+ function applyCommand(adapter, mark) {
123
+ return {
124
+ enabled: edit => selected(edit)
125
+ && (markState(edit, adapter, mark) === true || canApply(edit, adapter, mark)),
126
+ state: edit => markState(edit, adapter, mark),
127
+ run(edit) {
128
+ const removals = marksIn(edit, adapter)
129
+ .filter(current => !current.equals(mark) && current.conflicts(mark))
130
+ .map(current => [adapter, current]);
131
+ return change(edit, removals, [[adapter, mark]]);
132
+ },
133
+ };
134
+ }
135
+
136
+ function removeCommand(adapter, mark) {
137
+ if (!adapter.removable) throw new TypeError('Removing a mark requires a clear policy');
138
+ return {
139
+ enabled: edit => selected(edit) && markState(edit, adapter, mark) !== false,
140
+ state: edit => markState(edit, adapter, mark),
141
+ run: edit => change(edit, [[adapter, mark]]),
142
+ };
143
+ }
144
+
145
+ function change(edit, removals = [], applications = []) {
146
+ const state = prepare(edit);
147
+ const changed = new Set();
148
+ for (const [adapter, mark] of removals) {
149
+ isolate(edit, adapter, mark, state);
150
+ state.range = mappedRange(edit, state);
151
+ for (const element of remove(edit, adapter, mark, state.range)) changed.add(element);
152
+ state.range = mappedRange(edit, state);
153
+ }
154
+ for (const [adapter, mark] of applications) {
155
+ for (const element of apply(edit, adapter, mark, state.range)) changed.add(element);
156
+ state.range = mappedRange(edit, state);
157
+ }
158
+ canonicalize(edit, applications, state, changed);
159
+ restore(edit, state);
160
+ return [...changed];
161
+ }
162
+
163
+ function canonicalize(edit, applications, state, changed) {
164
+ const entries = applications.map(([adapter, mark], order) => ({
165
+ adapter,
166
+ mark,
167
+ order,
168
+ pattern: adapter.render(mark, edit.document),
169
+ }));
170
+ while (entries.length) {
171
+ state.range = mappedRange(edit, state);
172
+ if (dedupe(edit, entries, state.range, changed) || reorder(edit, entries, state.range, changed)) continue;
173
+ let merged = false;
174
+ for (const {adapter, mark, pattern} of entries) {
175
+ for (const [left, right] of merge(edit, adapter, mark, pattern, state.range)) {
176
+ changed.delete(right);
177
+ changed.add(left);
178
+ merged = true;
179
+ }
180
+ }
181
+ if (!merged) break;
182
+ }
183
+ }
184
+
185
+ function selected(edit) {
186
+ return !!edit.range && !edit.range.collapsed;
187
+ }
188
+
189
+ function canApply(edit, adapter, mark) {
190
+ if (!selected(edit)) return false;
191
+ const wrapper = adapter.render(mark, edit.document);
192
+ for (const node of edit.range.textNodes()) {
193
+ if (!node.data || blocked(edit, node) || has(edit, adapter, mark, node)) continue;
194
+ for (let element = node.parentElement; element && element !== edit.element; element = element.parentElement) {
195
+ if (edit.model.block(element) || isEditingBoundary(element)) break;
196
+ const current = adapter.parse(element);
197
+ if (current && current.conflicts(mark) && allowsAfterClear(edit, adapter, current, element, wrapper)) return true;
198
+ if (covered(edit.range, element) && reusable(edit, adapter, element)) return true;
199
+ }
200
+ if (edit.model.allows(node.parentNode, wrapper)) return true;
201
+ }
202
+ return false;
203
+ }
204
+
205
+ function allowsAfterClear(edit, adapter, mark, element, wrapper) {
206
+ if (!adapter.removable) return false;
207
+ const cleared = element.cloneNode(false);
208
+ const unwrap = adapter.clear(cleared, mark);
209
+ let parent = cleared;
210
+ if (unwrap && cleared.attributes.length && cleared.localName !== 'span') {
211
+ parent = edit.document.createElement('span');
212
+ for (const attribute of cleared.attributes) parent.setAttribute(attribute.name, attribute.value);
213
+ } else if (unwrap && !cleared.attributes.length) {
214
+ parent = element.parentNode;
215
+ }
216
+ return edit.model.allows(parent, wrapper);
217
+ }
218
+
219
+ function markState(edit, adapter, mark) {
220
+ if (!edit.range) return null;
221
+ if (edit.range.collapsed) {
222
+ const node = edit.range.start.node;
223
+ return !blocked(edit, node) && has(edit, adapter, mark, node);
224
+ }
225
+ let active = false;
226
+ let inactive = false;
227
+ for (const node of edit.range.textNodes()) {
228
+ if (!node.data || blocked(edit, node)) continue;
229
+ has(edit, adapter, mark, node) ? active = true : inactive = true;
230
+ if (active && inactive) return 'mixed';
231
+ }
232
+ return active;
233
+ }
234
+
235
+ function setState(edit, adapters) {
236
+ if (!edit.range) return null;
237
+ if (edit.range.collapsed) return marksAt(edit, adapters, edit.range.start.node);
238
+ let state = null;
239
+ for (const node of edit.range.textNodes()) {
240
+ if (!node.data || blocked(edit, node)) continue;
241
+ const marks = marksAt(edit, adapters, node);
242
+ if (state && !sameSet(state, marks)) return 'mixed';
243
+ state = marks;
244
+ }
245
+ return state;
246
+ }
247
+
248
+ function marksAt(edit, adapters, node) {
249
+ if (blocked(edit, node)) return markSet([]);
250
+ const elements = [];
251
+ for (let element = elementOf(node); element && element !== edit.element; element = element.parentElement) {
252
+ if (isEditingBoundary(element) || edit.model.block(element)) break;
253
+ elements.push(element);
254
+ }
255
+ const marks = [];
256
+ for (const element of elements.reverse()) {
257
+ for (const adapter of adapters) {
258
+ const mark = adapter.parse(element);
259
+ if (mark) marks.push(mark);
260
+ }
261
+ }
262
+ return markSet(marks);
263
+ }
264
+
265
+ function marksIn(edit, adapter) {
266
+ const marks = [];
267
+ if (!edit.range) return marks;
268
+ for (const node of edit.range.textNodes()) {
269
+ if (!node.data || blocked(edit, node)) continue;
270
+ for (let element = node.parentElement; element && element !== edit.element; element = element.parentElement) {
271
+ if (isEditingBoundary(element) || edit.model.block(element)) break;
272
+ const mark = adapter.parse(element);
273
+ if (mark && !marks.some(item => item.equals(mark))) marks.push(mark);
274
+ }
275
+ }
276
+ return marks;
277
+ }
278
+
279
+ function apply(edit, adapter, mark, range) {
280
+ const changed = [];
281
+ const visit = parent => {
282
+ for (const node of [...parent.childNodes]) {
283
+ if (!range.intersects(node)) continue;
284
+ if (node.nodeType === Node.TEXT_NODE) {
285
+ if (!node.data || !range.contains(node) || has(edit, adapter, mark, node)) continue;
286
+ const wrapper = adapter.render(mark, edit.document);
287
+ if (!edit.model.allows(parent, wrapper)) continue;
288
+ edit.map.wrap([node], wrapper);
289
+ edit.transaction.touch(wrapper);
290
+ changed.push(wrapper);
291
+ continue;
292
+ }
293
+ if (node.nodeType !== Node.ELEMENT_NODE || isEditingBoundary(node) || edit.model.atomic(node)) continue;
294
+ if (covered(range, node) && reusable(edit, adapter, node)) {
295
+ const current = adapter.parse(node);
296
+ if (current && !current.conflicts(mark)) {
297
+ visit(node);
298
+ continue;
299
+ }
300
+ if (!current?.equals(mark)) {
301
+ if (current?.type === mark.type && adapter.removable) adapter.clear(node, current);
302
+ adapter.apply(node, mark);
303
+ edit.transaction.touch(node);
304
+ changed.push(node);
305
+ }
306
+ continue;
307
+ }
308
+ visit(node);
309
+ }
310
+ };
311
+ visit(edit.element);
312
+ return changed;
313
+ }
314
+
315
+ function remove(edit, adapter, mark, range) {
316
+ const matches = [];
317
+ const visit = parent => {
318
+ for (const node of parent.children) {
319
+ if (isEditingBoundary(node) || !range.intersects(node)) continue;
320
+ const current = adapter.parse(node);
321
+ if (current?.equals(mark) && covered(range, node) && inline(edit, node)) matches.push(node);
322
+ visit(node);
323
+ }
324
+ };
325
+ visit(edit.element);
326
+ const changed = [];
327
+ for (const element of matches.reverse()) {
328
+ const parent = element.parentNode;
329
+ const unwrap = adapter.clear(element, mark);
330
+ if (unwrap && element.attributes.length && element.localName !== 'span') {
331
+ const replacement = edit.document.createElement('span');
332
+ for (const attribute of element.attributes) replacement.setAttribute(attribute.name, attribute.value);
333
+ edit.map.replaceWrapper(element, replacement);
334
+ edit.transaction.touch(replacement).touch(parent);
335
+ } else if (unwrap && !element.attributes.length) {
336
+ edit.map.unwrap(element);
337
+ edit.transaction.touch(parent);
338
+ } else {
339
+ edit.transaction.touch(element);
340
+ }
341
+ changed.push(element);
342
+ }
343
+ return changed;
344
+ }
345
+
346
+ function merge(edit, adapter, mark, pattern, range) {
347
+ const changed = [];
348
+ const visit = parent => {
349
+ for (const child of [...parent.children]) {
350
+ if (!isEditingBoundary(child) && !edit.model.atomic(child) && range.intersects(child)) visit(child);
351
+ }
352
+ for (let left = parent.firstChild; left;) {
353
+ const right = left.nextSibling;
354
+ if (!right) break;
355
+ if (canonical(adapter, mark, pattern, left)
356
+ && canonical(adapter, mark, pattern, right)
357
+ && (range.intersects(left) || range.intersects(right))) {
358
+ join(edit, left, right);
359
+ changed.push([left, right]);
360
+ } else {
361
+ left = right;
362
+ }
363
+ }
364
+ };
365
+ visit(edit.element);
366
+ return changed;
367
+ }
368
+
369
+ function dedupe(edit, entries, range, changed) {
370
+ for (const element of elements(edit)) {
371
+ if (!range.intersects(element) || isEditingBoundary(element) || edit.model.atomic(element)) continue;
372
+ const entry = representation(entries, element);
373
+ if (!entry || !marked(edit, entry.adapter, entry.mark, element.parentNode)) continue;
374
+ const parent = element.parentNode;
375
+ edit.map.unwrap(element);
376
+ joinText(edit, parent);
377
+ edit.transaction.touch(parent);
378
+ changed.delete(element);
379
+ changed.add(parent);
380
+ return true;
381
+ }
382
+ return false;
383
+ }
384
+
385
+ function reorder(edit, entries, range, changed) {
386
+ for (const parent of elements(edit)) {
387
+ if (!range.intersects(parent) || isEditingBoundary(parent) || edit.model.atomic(parent)) continue;
388
+ if (parent.childNodes.length !== 1 || parent.firstChild.nodeType !== Node.ELEMENT_NODE) continue;
389
+ const child = parent.firstChild;
390
+ const outer = representation(entries, parent);
391
+ const inner = representation(entries, child);
392
+ if (!outer || !inner || outer.order <= inner.order || !swappable(edit, parent, child)) continue;
393
+ const grand = parent.parentNode;
394
+ edit.map.unwrap(parent);
395
+ edit.map.wrap([...child.childNodes], parent);
396
+ edit.transaction.touch(grand).touch(child).touch(parent);
397
+ changed.add(child).add(parent);
398
+ return true;
399
+ }
400
+ return false;
401
+ }
402
+
403
+ function representation(entries, element) {
404
+ let found = null;
405
+ for (const entry of entries) {
406
+ if (!canonical(entry.adapter, entry.mark, entry.pattern, element)) continue;
407
+ if (found) return null;
408
+ found = entry;
409
+ }
410
+ return found;
411
+ }
412
+
413
+ function swappable(edit, parent, child) {
414
+ return inline(edit, parent)
415
+ && inline(edit, child)
416
+ && edit.model.allows(parent.parentNode, child)
417
+ && edit.model.allows(child, parent)
418
+ && [...child.childNodes].every(node => edit.model.allows(parent, node));
419
+ }
420
+
421
+ function elements(edit) {
422
+ const found = [];
423
+ const visit = parent => {
424
+ for (const child of parent.children) {
425
+ found.push(child);
426
+ if (!isEditingBoundary(child) && !edit.model.atomic(child)) visit(child);
427
+ }
428
+ };
429
+ visit(edit.element);
430
+ return found;
431
+ }
432
+
433
+ function joinText(edit, parent) {
434
+ for (let node = parent.firstChild; node;) {
435
+ const next = node.nextSibling;
436
+ if (node.nodeType === Node.TEXT_NODE && next?.nodeType === Node.TEXT_NODE) edit.map.mergeText(node, next);
437
+ else node = next;
438
+ }
439
+ }
440
+
441
+ function canonical(adapter, mark, pattern, element) {
442
+ return element.nodeType === Node.ELEMENT_NODE
443
+ && adapter.parse(element)?.equals(mark)
444
+ && element.cloneNode(false).isEqualNode(pattern);
445
+ }
446
+
447
+ function join(edit, left, right) {
448
+ const before = left.lastChild;
449
+ while (right.firstChild) edit.map.move(right.firstChild, left, left.childNodes.length);
450
+ edit.map.remove(right);
451
+ const after = before?.nextSibling;
452
+ if (before?.nodeType === Node.TEXT_NODE && after?.nodeType === Node.TEXT_NODE) edit.map.mergeText(before, after);
453
+ edit.transaction.touch(left).touch(left.parentNode);
454
+ }
455
+
456
+ function prepare(edit) {
457
+ const start = new Point(edit.range.start.node, edit.range.start.offset, 'forward');
458
+ const end = new Point(edit.range.end.node, edit.range.end.offset, 'backward');
459
+ edit.map.add(start).add(end);
460
+ splitText(edit, end);
461
+ splitText(edit, start);
462
+ return {start, end, backward: !!edit.surface.selection?.backward, range: mappedRange(edit, {start, end})};
463
+ }
464
+
465
+ function splitText(edit, point) {
466
+ const current = edit.map.get(point);
467
+ if (current.node.nodeType === Node.TEXT_NODE && current.offset > 0 && current.offset < current.node.length) {
468
+ edit.map.splitText(current.node, current.offset);
469
+ }
470
+ }
471
+
472
+ function isolate(edit, adapter, mark, state) {
473
+ splitMark(edit, adapter, mark, state.end);
474
+ splitMark(edit, adapter, mark, state.start);
475
+ }
476
+
477
+ function splitMark(edit, adapter, mark, point) {
478
+ const current = edit.map.get(point);
479
+ const wrapper = marked(edit, adapter, mark, current.node);
480
+ if (!wrapper || !inside(current, wrapper)) return;
481
+ edit.transaction.touch(wrapper.parentNode);
482
+ edit.map.split(wrapper.parentNode, current.node, current.offset);
483
+ }
484
+
485
+ function marked(edit, adapter, mark, node) {
486
+ let found = null;
487
+ for (let element = elementOf(node); element && element !== edit.element; element = element.parentElement) {
488
+ if (isEditingBoundary(element) || edit.model.block(element)) break;
489
+ if (adapter.parse(element)?.equals(mark)) found = element;
490
+ }
491
+ return found;
492
+ }
493
+
494
+ function has(edit, adapter, mark, node) {
495
+ for (let element = elementOf(node); element && element !== edit.element; element = element.parentElement) {
496
+ if (isEditingBoundary(element) || edit.model.block(element)) return false;
497
+ if (adapter.parse(element)?.equals(mark)) return true;
498
+ }
499
+ return false;
500
+ }
501
+
502
+ function blocked(edit, node) {
503
+ for (let element = elementOf(node); element && element !== edit.element; element = element.parentElement) {
504
+ if (isEditingBoundary(element) || edit.model.atomic(element)) return true;
505
+ }
506
+ return false;
507
+ }
508
+
509
+ function reusable(edit, adapter, element) {
510
+ return adapter.canReuse(element) && inline(edit, element);
511
+ }
512
+
513
+ function inline(edit, element) {
514
+ return element !== edit.element
515
+ && !isEditingBoundary(element)
516
+ && (typeof edit.model.allowed !== 'function' || edit.model.allowed(element))
517
+ && edit.model.is(element, 'phrasing')
518
+ && !edit.model.block(element)
519
+ && !edit.model.atomic(element);
520
+ }
521
+
522
+ function covered(range, element) {
523
+ if (!element.childNodes.length) return range.contains(element);
524
+ return [...element.childNodes].every(node => {
525
+ if (node.nodeType === Node.TEXT_NODE) return !node.data || range.contains(node);
526
+ if (node.nodeType !== Node.ELEMENT_NODE || !node.childNodes.length) return range.contains(node);
527
+ return covered(range, node);
528
+ });
529
+ }
530
+
531
+ function inside(point, element) {
532
+ return point.within(element) && !atEdge(point, element, 'start') && !atEdge(point, element, 'end');
533
+ }
534
+
535
+ function atEdge(point, element, edge) {
536
+ let node = point.node;
537
+ let offset = point.offset;
538
+ while (node !== element) {
539
+ const length = typeof node.length === 'number' ? node.length : node.childNodes.length;
540
+ if (offset !== (edge === 'start' ? 0 : length)) return false;
541
+ const parent = node.parentNode;
542
+ offset = Array.prototype.indexOf.call(parent.childNodes, node) + (edge === 'end' ? 1 : 0);
543
+ node = parent;
544
+ }
545
+ return offset === (edge === 'start' ? 0 : element.childNodes.length);
546
+ }
547
+
548
+ function mappedRange(edit, {start, end}) {
549
+ return EditRange.fromPoints(edit.map.get(start), edit.map.get(end), edit.element);
550
+ }
551
+
552
+ function restore(edit, state) {
553
+ edit.select(edit.map.get(state.start), edit.map.get(state.end), state.backward);
554
+ }
555
+
556
+ function concrete(adapter, value) {
557
+ if (!(adapter instanceof MarkAdapter)) throw new TypeError('A mark command requires a mark adapter');
558
+ const mark = value instanceof Mark ? value : adapter.type.create(value);
559
+ if (mark.type !== adapter.type) throw new TypeError('A mark command requires the adapter\'s mark type');
560
+ return mark;
561
+ }
562
+
563
+ function adapterSet(adapters) {
564
+ if (!Array.isArray(adapters) || !adapters.length) throw new TypeError('A mark set command requires adapters');
565
+ const known = new Map();
566
+ for (const adapter of adapters) {
567
+ if (!(adapter instanceof MarkAdapter)) throw new TypeError('A mark set command requires mark adapters');
568
+ if (!adapter.removable) throw new TypeError('A mark set adapter requires a clear policy');
569
+ if (known.has(adapter.type)) throw new RangeError('A mark set command requires one adapter per mark type');
570
+ known.set(adapter.type, adapter);
571
+ }
572
+ return known;
573
+ }
574
+
575
+ function targetSet(value, adapters) {
576
+ if (!Array.isArray(value) || value.some(mark => !(mark instanceof Mark) || !adapters.has(mark.type))) return null;
577
+ return markSet(value);
578
+ }
579
+
580
+ function sameSet(left, right) {
581
+ return left.length === right.length && left.every((mark, index) => mark.equals(right[index]));
582
+ }
583
+