@openleaf-editor/core 0.1.0-beta.1 → 0.1.0-beta.3

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 (101) hide show
  1. package/README.md +115 -0
  2. package/dist/autolink.d.ts +12 -0
  3. package/dist/autolink.d.ts.map +1 -0
  4. package/dist/autolink.js +136 -0
  5. package/dist/autolink.js.map +1 -0
  6. package/dist/command-helpers.d.ts +8 -0
  7. package/dist/command-helpers.d.ts.map +1 -0
  8. package/dist/command-helpers.js +36 -0
  9. package/dist/command-helpers.js.map +1 -0
  10. package/dist/commands.d.ts +43 -22
  11. package/dist/commands.d.ts.map +1 -1
  12. package/dist/commands.js +513 -115
  13. package/dist/commands.js.map +1 -1
  14. package/dist/css.d.ts +1 -123
  15. package/dist/css.d.ts.map +1 -1
  16. package/dist/css.js +1 -214
  17. package/dist/css.js.map +1 -1
  18. package/dist/disclosure.d.ts +21 -0
  19. package/dist/disclosure.d.ts.map +1 -0
  20. package/dist/disclosure.js +144 -0
  21. package/dist/disclosure.js.map +1 -0
  22. package/dist/elements.d.ts +2 -0
  23. package/dist/elements.d.ts.map +1 -0
  24. package/dist/elements.js +2 -0
  25. package/dist/elements.js.map +1 -0
  26. package/dist/embed.d.ts +2 -0
  27. package/dist/embed.d.ts.map +1 -0
  28. package/dist/embed.js +2 -0
  29. package/dist/embed.js.map +1 -0
  30. package/dist/errors.d.ts +38 -0
  31. package/dist/errors.d.ts.map +1 -0
  32. package/dist/errors.js +40 -0
  33. package/dist/errors.js.map +1 -0
  34. package/dist/extensions.d.ts +46 -5
  35. package/dist/extensions.d.ts.map +1 -1
  36. package/dist/extensions.js +292 -65
  37. package/dist/extensions.js.map +1 -1
  38. package/dist/formats.d.ts +44 -0
  39. package/dist/formats.d.ts.map +1 -0
  40. package/dist/formats.js +123 -0
  41. package/dist/formats.js.map +1 -0
  42. package/dist/html.d.ts +32 -2
  43. package/dist/html.d.ts.map +1 -1
  44. package/dist/html.js +185 -31
  45. package/dist/html.js.map +1 -1
  46. package/dist/index.d.ts +27 -6
  47. package/dist/index.d.ts.map +1 -1
  48. package/dist/index.js +44 -10
  49. package/dist/index.js.map +1 -1
  50. package/dist/insert-commands.d.ts +172 -0
  51. package/dist/insert-commands.d.ts.map +1 -0
  52. package/dist/insert-commands.js +560 -0
  53. package/dist/insert-commands.js.map +1 -0
  54. package/dist/isolating-selection.d.ts +41 -0
  55. package/dist/isolating-selection.d.ts.map +1 -0
  56. package/dist/isolating-selection.js +162 -0
  57. package/dist/isolating-selection.js.map +1 -0
  58. package/dist/keymap.d.ts.map +1 -1
  59. package/dist/keymap.js +6 -3
  60. package/dist/keymap.js.map +1 -1
  61. package/dist/noneditable.d.ts +14 -0
  62. package/dist/noneditable.d.ts.map +1 -0
  63. package/dist/noneditable.js +107 -0
  64. package/dist/noneditable.js.map +1 -0
  65. package/dist/plugins.d.ts +20 -2
  66. package/dist/plugins.d.ts.map +1 -1
  67. package/dist/plugins.js +27 -2
  68. package/dist/plugins.js.map +1 -1
  69. package/dist/preserve.d.ts +76 -0
  70. package/dist/preserve.d.ts.map +1 -1
  71. package/dist/preserve.js +308 -58
  72. package/dist/preserve.js.map +1 -1
  73. package/dist/schema.d.ts +15 -0
  74. package/dist/schema.d.ts.map +1 -1
  75. package/dist/schema.js +356 -76
  76. package/dist/schema.js.map +1 -1
  77. package/dist/structure.d.ts +76 -0
  78. package/dist/structure.d.ts.map +1 -0
  79. package/dist/structure.js +422 -0
  80. package/dist/structure.js.map +1 -0
  81. package/dist/tables.d.ts +60 -1
  82. package/dist/tables.d.ts.map +1 -1
  83. package/dist/tables.js +617 -35
  84. package/dist/tables.js.map +1 -1
  85. package/dist/testing.d.ts +3 -0
  86. package/dist/testing.d.ts.map +1 -0
  87. package/dist/testing.js +3 -0
  88. package/dist/testing.js.map +1 -0
  89. package/dist/tokens.d.ts +36 -0
  90. package/dist/tokens.d.ts.map +1 -0
  91. package/dist/tokens.js +116 -0
  92. package/dist/tokens.js.map +1 -0
  93. package/dist/url.d.ts +1 -25
  94. package/dist/url.d.ts.map +1 -1
  95. package/dist/url.js +1 -77
  96. package/dist/url.js.map +1 -1
  97. package/dist/visual-aids.d.ts +20 -0
  98. package/dist/visual-aids.d.ts.map +1 -0
  99. package/dist/visual-aids.js +149 -0
  100. package/dist/visual-aids.js.map +1 -0
  101. package/package.json +16 -1
package/dist/preserve.js CHANGED
@@ -26,8 +26,9 @@
26
26
  * element carries an attribute we cannot represent, it becomes opaque
27
27
  * and is preserved intact.
28
28
  */
29
- import { isFullyModelledStyle } from './css.js';
30
- import { URL_ATTRIBUTES, isEventHandlerAttribute, isSafeUrl } from './url.js';
29
+ import { isFullyModelledStyle, safeLang } from './css.js';
30
+ import { DROP_WITH_CONTENT } from './elements.js';
31
+ import { URL_ATTRIBUTES, isEventHandlerAttribute, isNeverCarriedAttribute, isSafeUrl, } from './url.js';
31
32
  /**
32
33
  * Elements that are never preserved, and whose contents are discarded with them.
33
34
  *
@@ -45,42 +46,111 @@ import { URL_ATTRIBUTES, isEventHandlerAttribute, isSafeUrl } from './url.js';
45
46
  * `ignore` rather than `skip`: the element AND its contents go. Skipping would
46
47
  * unwrap `<script>alert(1)</script>` into the literal text "alert(1)" appearing
47
48
  * in the document, which is a different kind of wrong.
49
+ *
50
+ * Spread from `@openleaf-editor/content-policy` rather than written out here.
51
+ * This list and the sanitize policy's `dropWithContent` are the same decision
52
+ * made in two packages, they were maintained by hand, and they drifted: `<svg>`
53
+ * and `<math>` were on the sanitizer's list and missing from this one, so the
54
+ * editor stored exactly the markup the server was configured to delete. Sharing
55
+ * the constant is what makes that drift impossible rather than merely unlikely.
56
+ *
57
+ * Exported so the divergence can be asserted in a test as well as prevented by
58
+ * construction. Not re-exported from the package index: it is an internal
59
+ * invariant, and the shared list itself is public in content-policy.
48
60
  */
49
- const NEVER_PRESERVE = [
50
- 'script',
51
- 'style',
52
- 'iframe',
53
- 'frame',
54
- 'frameset',
55
- 'object',
56
- 'embed',
57
- 'applet',
58
- 'form',
59
- 'input',
60
- 'button',
61
- 'select',
62
- 'textarea',
63
- 'option',
64
- 'link',
65
- 'meta',
66
- 'base',
67
- 'noscript',
68
- 'template',
69
- ];
61
+ export const NEVER_PRESERVE = [...DROP_WITH_CONTENT];
62
+ /**
63
+ * Tags that must not survive *inside* a preserved subtree either.
64
+ *
65
+ * `iframe` is here and not in `NEVER_PRESERVE` because the two answer different
66
+ * questions. At the top level an iframe is claimed by the modelled embed node
67
+ * when its `src` is an allowlisted player, and ignored otherwise -- a
68
+ * priority-100 drop rule would outrank the embed node and delete legitimate
69
+ * players. Inside preserved markup there is no such question: the subtree is
70
+ * stored as an opaque string and re-emitted verbatim, so nothing re-checks the
71
+ * frame on the way out.
72
+ *
73
+ * That gap was the bypass. `<iframe src="https://evil.example/">` on its own was
74
+ * dropped; wrapped in a `<div class="c">` it round-tripped byte-identical, with
75
+ * `allow="camera; microphone; geolocation"` intact. One attribute on a wrapper
76
+ * defeated both the host allowlist and the permissions filter.
77
+ */
78
+ const NEVER_INSIDE_PRESERVED = new Set([...NEVER_PRESERVE, 'iframe']);
70
79
  /** Parse rules that drop dangerous elements before any other rule sees them. */
71
80
  const dropRules = NEVER_PRESERVE.map((tag) => ({ tag, ignore: true, priority: 100 }));
81
+ /**
82
+ * `<source>` and `<track>`: media children the schema stores as markup rather
83
+ * than as nodes, so they do not count as content when deciding what to keep.
84
+ *
85
+ * Lives here because this module owns the "keep it whole or claim it" decision,
86
+ * and `structure.ts` asks the same question when it reads a media element.
87
+ */
88
+ export const MEDIA_FURNITURE_TAGS = new Set(['source', 'track']);
89
+ /**
90
+ * True when a media element holds content its node cannot carry.
91
+ *
92
+ * Video and audio are atoms whose only modelled children are `<source>` and
93
+ * `<track>`, so fallback content -- "Download <a href=...>the video</a>", shown
94
+ * by a browser that cannot play the file -- has nowhere to live on the node.
95
+ */
96
+ export function hasMediaFallback(el) {
97
+ for (const child of Array.from(el.childNodes)) {
98
+ if (child.nodeType === 1) {
99
+ if (!MEDIA_FURNITURE_TAGS.has(child.nodeName.toLowerCase()))
100
+ return true;
101
+ continue;
102
+ }
103
+ // Whitespace between the <source> children is layout, not fallback: the
104
+ // element still models cleanly and still round-trips.
105
+ if (child.nodeType === 3 && (child.textContent ?? '').trim() !== '')
106
+ return true;
107
+ }
108
+ return false;
109
+ }
110
+ /**
111
+ * Media whose fallback content the node cannot hold, kept whole.
112
+ *
113
+ * Priority 45 sits below the schema's own rules (50) and above the drop rule
114
+ * (40): a video with a safe `src` is still claimed as a node first, and an
115
+ * unsafe iframe is still dropped rather than preserved, but a `<video>` carrying
116
+ * a download link is preserved instead of being deleted along with it.
117
+ */
118
+ const preserveMediaWithFallback = ['video', 'audio'].map((tag) => ({
119
+ tag,
120
+ priority: 45,
121
+ getAttrs(dom) {
122
+ if (!hasMediaFallback(dom))
123
+ return false;
124
+ return { html: scrub(dom), tag: dom.nodeName.toLowerCase() };
125
+ },
126
+ }));
127
+ /**
128
+ * Media the schema declined. Priority 40 is below the schema's default (50),
129
+ * so an allowlisted iframe or a video with a safe `src` is claimed first;
130
+ * anything left is ignored rather than preserved as an atom. Preserving an
131
+ * arbitrary iframe would be a nested page the author never asked to keep.
132
+ */
133
+ const dropDeclinedMedia = ['iframe', 'video', 'audio'].map((tag) => ({
134
+ tag,
135
+ ignore: true,
136
+ priority: 40,
137
+ }));
72
138
  /**
73
139
  * Scrub markup before it is stored for preservation.
74
140
  *
75
141
  * Preserving an element verbatim means preserving its attributes verbatim, and
76
142
  * `<div class="callout" onclick="steal()">` is not something an author needs
77
143
  * kept. Works on a clone so the live parse tree is untouched.
144
+ *
145
+ * Exported because the table schema stores `<caption>` and `<colgroup>` the same
146
+ * way, for the same reason, and a second scrubber that drifted from this one
147
+ * would be a hole in exactly the code path that exists to close holes.
78
148
  */
79
- function scrub(el) {
149
+ export function scrub(el) {
80
150
  const clone = el.cloneNode(true);
81
151
  const visit = (node) => {
82
152
  for (const child of Array.from(node.children)) {
83
- if (NEVER_PRESERVE.includes(child.nodeName.toLowerCase())) {
153
+ if (NEVER_INSIDE_PRESERVED.has(child.nodeName.toLowerCase())) {
84
154
  child.remove();
85
155
  continue;
86
156
  }
@@ -91,6 +161,13 @@ function scrub(el) {
91
161
  node.removeAttribute(attr.name);
92
162
  continue;
93
163
  }
164
+ // Before the URL question, not as a case of it: `srcdoc` is a document
165
+ // rather than a URL, and asking a scheme checker about a document gets
166
+ // "no scheme, therefore relative, therefore safe".
167
+ if (isNeverCarriedAttribute(attr.name)) {
168
+ node.removeAttribute(attr.name);
169
+ continue;
170
+ }
94
171
  if (URL_ATTRIBUTES.has(attr.name.toLowerCase()) && !isSafeUrl(attr.value)) {
95
172
  node.removeAttribute(attr.name);
96
173
  }
@@ -137,51 +214,97 @@ export function isLosslesslyUnwrappable(el) {
137
214
  return false;
138
215
  if (el.attributes.length === 0)
139
216
  return true;
140
- /*
141
- * One exception, and it is deliberately the narrowest one that works: a
142
- * `<span>` whose only attribute is a style the colour marks fully model.
143
- *
144
- * Without it, colour is a fidelity regression dressed as a feature. Every
145
- * `<span style="color:#c00">` in an inherited archive is preserved as an
146
- * opaque atom -- a grey card where a sentence used to be, its text
147
- * unselectable and unspellcheckable. Declining the rule here lets the span
148
- * unwrap, and ProseMirror's style rules then re-apply the colour as a mark on
149
- * the text inside, which is both editable and byte-identical on the way out.
150
- *
151
- * `text-align` is not in the accepted set, because unwrapping the element that
152
- * carries it would drop it: it is a property of the block, and the block here
153
- * is somebody else. Two attributes, or one attribute the marks cannot fully
154
- * express, and the element stays preserved exactly as it does today.
155
- */
156
- if (el.attributes.length !== 1 || name !== 'span')
217
+ if (name !== 'span')
157
218
  return false;
158
219
  /*
159
- * Unwrap only if the marks will actually pick the declarations up.
220
+ * A `<span>` whose attributes are fully modelled as marks: colour, font, and
221
+ * `lang`. Without this, those runs become opaque atoms -- a grey card where a
222
+ * sentence used to be. Declining the catch-all lets the span unwrap so the
223
+ * mark rules can re-apply formatting on the text inside.
160
224
  *
161
- * ProseMirror matches mark style rules through the CSSOM, and there are two
162
- * situations where the CSSOM reports nothing for a style attribute that is
163
- * plainly there: the declaration is invalid, and -- the one that matters -- a
164
- * Content-Security-Policy with no `unsafe-inline` in `style-src`, under which
165
- * the browser leaves the attribute in the DOM and refuses to parse it.
225
+ * Any other attribute, or a style the marks cannot fully express, and the
226
+ * element stays preserved exactly as it does today.
166
227
  *
167
- * Unwrapping in that case destroys the colour: the span goes, no mark replaces
168
- * it, and the author's red text is black on the next save. An empty CSSOM is
169
- * therefore a reason to leave the element to the preservation layer, where it
170
- * stays verbatim and uneditable -- exactly what happened before colour was
171
- * modelled at all. Degrading to the old behaviour is acceptable; losing content
172
- * is not.
228
+ * ProseMirror matches mark style rules through the CSSOM. Under a CSP with
229
+ * no `unsafe-inline` in `style-src`, the browser leaves the attribute in the
230
+ * DOM and refuses to parse it, so unwrapping would destroy the formatting.
231
+ * An empty CSSOM is therefore a reason to leave the element to the
232
+ * preservation layer.
173
233
  */
174
- if (el.style?.length === 0)
234
+ for (const attr of Array.from(el.attributes)) {
235
+ if (attr.name === 'lang') {
236
+ if (safeLang(attr.value) === null)
237
+ return false;
238
+ continue;
239
+ }
240
+ if (attr.name === 'style') {
241
+ if (el.style?.length === 0)
242
+ return false;
243
+ if (!isFullyModelledStyle(attr.value))
244
+ return false;
245
+ continue;
246
+ }
175
247
  return false;
176
- return isFullyModelledStyle(el.getAttribute('style'));
248
+ }
249
+ return true;
177
250
  }
251
+ /**
252
+ * Parsed preserved markup, per Document, keyed on the exact stored string.
253
+ *
254
+ * `toDOM` runs on every render of every preserved atom, and an HTML parse is the
255
+ * most expensive thing in it: a document that is half preserved markup spent
256
+ * roughly 4x as long serializing as the same document in plain paragraphs.
257
+ *
258
+ * Caching one is only sound because the key is the whole input. `html` is a node
259
+ * attribute, ProseMirror nodes are immutable, and the string was produced by
260
+ * `scrub` before it was ever stored -- so two calls with the same string must
261
+ * produce the same element, and there is no edit that can invalidate an entry
262
+ * without changing the key.
263
+ *
264
+ * Three properties this must keep, none of them optional:
265
+ *
266
+ * A CLONE every time. Handing out the cached node would let one caller's
267
+ * mutation -- ProseMirror appending it, a decoration setting an attribute --
268
+ * poison every later render of that markup.
269
+ *
270
+ * PER DOCUMENT. Serialization can target a Document that is not the global
271
+ * one, and a node has to be owned by the document it is going into. Scoping by
272
+ * Document also means the entries die with it, so a throwaway serialization
273
+ * document is still collectable.
274
+ *
275
+ * BOUNDED. The keys are document content, so an unbounded map is a leak that
276
+ * grows with what the user pastes. A cap with clear-on-overflow keeps it flat;
277
+ * very large strings are not cached at all, because they are both the least
278
+ * likely to repeat and the most expensive to hold.
279
+ */
280
+ const PARSE_CACHE_ENTRIES = 256;
281
+ const PARSE_CACHE_MAX_LENGTH = 4096;
282
+ const parseCaches = new WeakMap();
178
283
  /** Rebuild a DOM element from stored markup. `<template>` is used because
179
284
  * its parsing context permits otherwise-illegal fragments such as a bare
180
285
  * `<tr>`, which a `<div>` container would silently discard. */
181
286
  function elementFromHtml(html, doc) {
287
+ let cache = parseCaches.get(doc);
288
+ const hit = cache?.get(html);
289
+ if (hit)
290
+ return hit.cloneNode(true);
182
291
  const tpl = doc.createElement('template');
183
292
  tpl.innerHTML = html;
184
- return tpl.content.firstElementChild;
293
+ const parsed = tpl.content.firstElementChild;
294
+ if (!parsed)
295
+ return null;
296
+ if (html.length > PARSE_CACHE_MAX_LENGTH)
297
+ return parsed;
298
+ if (!cache) {
299
+ cache = new Map();
300
+ parseCaches.set(doc, cache);
301
+ }
302
+ if (cache.size >= PARSE_CACHE_ENTRIES)
303
+ cache.clear();
304
+ // The master copy is the clone, so the element handed back is the freshly
305
+ // parsed one and the cache holds something no caller has ever touched.
306
+ cache.set(html, parsed.cloneNode(true));
307
+ return parsed;
185
308
  }
186
309
  /**
187
310
  * ProseMirror's `toDOM` does not receive the `document` passed to
@@ -281,6 +404,8 @@ export const unknownBlock = {
281
404
  },
282
405
  parseDOM: [
283
406
  ...dropRules,
407
+ ...preserveMediaWithFallback,
408
+ ...dropDeclinedMedia,
284
409
  {
285
410
  tag: '*',
286
411
  // Lowest priority: every real rule in the schema gets first refusal.
@@ -300,6 +425,114 @@ export const unknownBlock = {
300
425
  return rebuildOrCarry(node.attrs['html'], 'div');
301
426
  },
302
427
  };
428
+ /**
429
+ * Where the inline catch-all is allowed to fire.
430
+ *
431
+ * ProseMirror matches `context` against the parent node the content is being
432
+ * parsed INTO, and the naive list -- paragraph and heading -- described the
433
+ * wrong thing. It named the nodes that hold inline content, when what the rule
434
+ * needs to name is every node that can END UP holding it.
435
+ *
436
+ * `list_item` is `paragraph block*`, so its implicit paragraph does not exist
437
+ * until some inline content arrives to force it. An unknown element that is the
438
+ * FIRST child of an `<li>` therefore sees a context of `.../list_item/`, the
439
+ * inline rule declines, and `unknownBlock` claims a block-level atom inside a
440
+ * container whose content expression cannot hold one. ProseMirror's recovery is
441
+ * to close the list and emit the atom as a sibling, so
442
+ * `<ol><li><ins>a</ins></li><li>b</li></ol>` came back as an emptied `<ol>`, an
443
+ * escaped `<ins>`, and a `<ul>` -- the list's contents gone and its very type
444
+ * changed. The identical element with a single character of text before it
445
+ * round-tripped perfectly, which is what kept this invisible: position was the
446
+ * whole trigger.
447
+ *
448
+ * `summary` and `figcaption` fail the same way for the same reason, and
449
+ * `blockquote`, `table_cell` and `table_header` are listed so that a first-child
450
+ * unknown *inline* element is wrapped in a paragraph exactly as it is when text
451
+ * precedes it. Those three can also hold a block atom legally. Wrapping a
452
+ * p-closing element (`div`, `section`, …) in that paragraph is the other
453
+ * failure: the HTML parser closes the `<p>` on the next parse, leaves empty
454
+ * paragraphs on both sides, and the document grows by two blanks on every save.
455
+ * `unknownInline` declines those tags so `unknownBlock` claims them instead.
456
+ *
457
+ * Naming containers explicitly rather than dropping the context altogether:
458
+ * without it the inline rule would outrank `unknownBlock` everywhere, and a
459
+ * genuinely block-level unknown element at the top of the document would become
460
+ * an inline atom inside a paragraph the author never had.
461
+ */
462
+ const INLINE_CONTEXT = [
463
+ 'paragraph/',
464
+ 'heading/',
465
+ 'summary/',
466
+ 'figcaption/',
467
+ 'list_item/',
468
+ 'table_cell/',
469
+ 'table_header/',
470
+ 'blockquote/',
471
+ ].join('|');
472
+ /**
473
+ * Start tags that close an open `<p>` in the HTML "in body" insertion mode.
474
+ *
475
+ * Serializing one of these as an inline atom wraps it in `<p>…</p>`. The next
476
+ * parse cannot keep it there, so it splits into an empty paragraph, the
477
+ * element, and another empty paragraph -- and the following save wraps it
478
+ * again. The same unbounded growth `<plaintext>` caused by having no end tag.
479
+ *
480
+ * Shared with anything else that must not claim a p-closing element as inline
481
+ * (`figcaption` being inline is the other door into this). Custom elements are
482
+ * not on the list: they do not close a `<p>`, so `<drupal-media>` inside a
483
+ * blockquote is correctly an inline atom.
484
+ *
485
+ * Source: WHATWG HTML parsing, "in body" -- every start tag that runs
486
+ * "if the stack of open elements has a p element in button scope, then close
487
+ * a p element" before inserting.
488
+ */
489
+ export const CLOSES_OPEN_P = new Set([
490
+ 'address',
491
+ 'article',
492
+ 'aside',
493
+ 'blockquote',
494
+ 'center',
495
+ 'details',
496
+ 'dialog',
497
+ 'dir',
498
+ 'div',
499
+ 'dl',
500
+ 'dt',
501
+ 'dd',
502
+ 'fieldset',
503
+ 'figcaption',
504
+ 'figure',
505
+ 'footer',
506
+ 'header',
507
+ 'hgroup',
508
+ 'main',
509
+ 'menu',
510
+ 'nav',
511
+ 'ol',
512
+ 'p',
513
+ 'search',
514
+ 'section',
515
+ 'summary',
516
+ 'ul',
517
+ 'h1',
518
+ 'h2',
519
+ 'h3',
520
+ 'h4',
521
+ 'h5',
522
+ 'h6',
523
+ 'listing',
524
+ 'plaintext',
525
+ 'pre',
526
+ 'form',
527
+ 'li',
528
+ 'button',
529
+ 'table',
530
+ 'hr',
531
+ 'xmp',
532
+ 'applet',
533
+ 'marquee',
534
+ 'object',
535
+ ]);
303
536
  /**
304
537
  * Inline preserved content, for unrecognised markup appearing inside a
305
538
  * paragraph -- the `<o:p>` and `<w:sdt>` debris of a Word paste, custom
@@ -316,17 +549,34 @@ export const unknownInline = {
316
549
  },
317
550
  parseDOM: [
318
551
  ...dropRules,
552
+ ...preserveMediaWithFallback,
553
+ ...dropDeclinedMedia,
319
554
  {
320
555
  tag: '*',
321
556
  // Higher than unknownBlock's catch-all: inline gets first refusal so
322
557
  // the block rule cannot claim inline debris and split the paragraph
323
558
  // that contained it.
324
559
  priority: 1,
325
- context: 'paragraph/|heading/',
560
+ context: INLINE_CONTEXT,
326
561
  getAttrs(dom) {
327
562
  const el = dom;
328
563
  if (isLosslesslyUnwrappable(el))
329
564
  return false;
565
+ // A block-level element inside a paragraph-holding container must not
566
+ // become an inline atom: emitting it inside `<p>` is markup the HTML
567
+ // parser will not re-parse as itself. Declining lets unknownBlock
568
+ // claim it, which blockquote (`block+`) and list_item (`paragraph
569
+ // block*`) can hold. `<ins>` and custom elements stay on this path.
570
+ // `figcaption` is on CLOSES_OPEN_P, but declining it in summary/heading
571
+ // sends it to unknownBlock, which those containers cannot hold.
572
+ const tag = el.nodeName.toLowerCase();
573
+ if (tag === 'figcaption') {
574
+ if (el.parentElement?.nodeName.toLowerCase() === 'p')
575
+ return false;
576
+ }
577
+ else if (CLOSES_OPEN_P.has(tag)) {
578
+ return false;
579
+ }
330
580
  return { html: scrub(el), tag: el.nodeName.toLowerCase() };
331
581
  },
332
582
  },
@@ -1 +1 @@
1
- {"version":3,"file":"preserve.js","sourceRoot":"","sources":["../src/preserve.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"preserve.js","sourceRoot":"","sources":["../src/preserve.ts"],"names":[],"mappings":"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"}
package/dist/schema.d.ts CHANGED
@@ -8,6 +8,21 @@
8
8
  * there rather than at the package boundary.
9
9
  */
10
10
  import { Schema, type MarkSpec, type NodeSpec } from 'prosemirror-model';
11
+ /**
12
+ * The `start` of an ordered list, or null when the attribute is not a number.
13
+ *
14
+ * `Number('abc')` is `NaN`, and `NaN` is a perfectly good value to store on a
15
+ * node -- so `<ol start="abc">` was stored as `NaN` and serialized as the string
16
+ * `start="NaN"`, turning a value the browser ignores into one it still ignores
17
+ * but that is now in the customer's database with our fingerprints on it.
18
+ * Returning null instead lets extensions.ts carry the original spelling as
19
+ * residue, so the attribute survives without being interpreted.
20
+ *
21
+ * Exported so that the carry mechanism asks the same question this does. Two
22
+ * copies of "is this a valid start" is how they would disagree and emit the
23
+ * attribute twice, or neither time.
24
+ */
25
+ export declare function listStart(value: string | null | undefined): number | null;
11
26
  /** The base node specs. Extensions are appended to these. */
12
27
  export declare const coreNodes: Record<string, NodeSpec>;
13
28
  /** The base mark specs. */
@@ -1 +1 @@
1
- {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,MAAM,EAAkC,KAAK,QAAQ,EAAE,KAAK,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAiExG,6DAA6D;AAC7D,eAAO,MAAM,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAmL9C,CAAA;AAED,2BAA2B;AAC3B,eAAO,MAAM,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAoI9C,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,UAAU,wBAAqD,CAAA"}
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,MAAM,EAAkC,KAAK,QAAQ,EAAE,KAAK,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAqHxG;;;;;;;;;;;;;GAaG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAIzE;AA8BD,6DAA6D;AAC7D,eAAO,MAAM,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CA4L9C,CAAA;AAgDD,2BAA2B;AAC3B,eAAO,MAAM,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAwQ9C,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,UAAU,wBAAqD,CAAA"}