eleven / ocho Public
File too large to show in full — download it above (showing a truncated preview below).
| 1 | // π€ ProseMirror (MIT, prosemirror.net, Marijn Haverbeke et al.) β vendored |
| 2 | // single-file ESM bundle backing the rich composer (#531). One bundle, not |
| 3 | // per-package files: ProseMirror relies on class identity across packages |
| 4 | // (Fragment/Slice instanceof checks), which separate bundles would duplicate |
| 5 | // and break. markdown-it is deliberately NOT bundled β the import below is |
| 6 | // rewritten to ./markdown-it.js so the page holds exactly ONE Markdown parser |
| 7 | // (the feed's), and feed-only/embed loads never pay for the editor. |
| 8 | // |
| 9 | // Packages: prosemirror-model@1.25.11 state@1.4.4 view@1.42.1 |
| 10 | // transform@1.12.0 commands@1.7.1 keymap@1.2.3 history@1.5.0 |
| 11 | // inputrules@1.5.1 schema-list@1.5.1 markdown@1.13.5 |
| 12 | // (deps: orderedmap, w3c-keyname, rope-sequence β all MIT). |
| 13 | // |
| 14 | // Regenerate on any machine with node: |
| 15 | // mkdir /tmp/pm && cd /tmp/pm && npm init -y |
| 16 | // npm install prosemirror-model@1.25.11 prosemirror-state@1.4.4 \ |
| 17 | // prosemirror-view@1.42.1 prosemirror-transform@1.12.0 \ |
| 18 | // prosemirror-commands@1.7.1 prosemirror-keymap@1.2.3 \ |
| 19 | // prosemirror-history@1.5.0 prosemirror-inputrules@1.5.1 \ |
| 20 | // prosemirror-schema-list@1.5.1 prosemirror-markdown@1.13.5 esbuild |
| 21 | // cat > entry.mjs <<'E' |
| 22 | // export * from "prosemirror-model"; export * from "prosemirror-state"; |
| 23 | // export * from "prosemirror-view"; export * from "prosemirror-transform"; |
| 24 | // export * from "prosemirror-commands"; export * from "prosemirror-keymap"; |
| 25 | // export * from "prosemirror-history"; export * from "prosemirror-inputrules"; |
| 26 | // export * from "prosemirror-schema-list"; |
| 27 | // export { MarkdownParser, MarkdownSerializer, MarkdownSerializerState } from "prosemirror-markdown"; |
| 28 | // E |
| 29 | // npx esbuild entry.mjs --bundle --format=esm --external:markdown-it \ |
| 30 | // --legal-comments=inline --outfile=prosemirror.js |
| 31 | // sed -i '' 's|from "markdown-it"|from "./markdown-it.js"|' prosemirror.js |
| 32 | // |
| 33 | // then re-add this header. Unminified on purpose (CLAUDE.md: human-manageable; |
| 34 | // version bumps diff reviewably). |
| 35 | // node_modules/orderedmap/dist/index.js |
| 36 | function OrderedMap(content) { |
| 37 | this.content = content; |
| 38 | } |
| 39 | OrderedMap.prototype = { |
| 40 | constructor: OrderedMap, |
| 41 | find: function(key) { |
| 42 | for (var i2 = 0; i2 < this.content.length; i2 += 2) |
| 43 | if (this.content[i2] === key) return i2; |
| 44 | return -1; |
| 45 | }, |
| 46 | // :: (string) β ?any |
| 47 | // Retrieve the value stored under `key`, or return undefined when |
| 48 | // no such key exists. |
| 49 | get: function(key) { |
| 50 | var found2 = this.find(key); |
| 51 | return found2 == -1 ? void 0 : this.content[found2 + 1]; |
| 52 | }, |
| 53 | // :: (string, any, ?string) β OrderedMap |
| 54 | // Create a new map by replacing the value of `key` with a new |
| 55 | // value, or adding a binding to the end of the map. If `newKey` is |
| 56 | // given, the key of the binding will be replaced with that key. |
| 57 | update: function(key, value, newKey) { |
| 58 | var self = newKey && newKey != key ? this.remove(newKey) : this; |
| 59 | var found2 = self.find(key), content = self.content.slice(); |
| 60 | if (found2 == -1) { |
| 61 | content.push(newKey || key, value); |
| 62 | } else { |
| 63 | content[found2 + 1] = value; |
| 64 | if (newKey) content[found2] = newKey; |
| 65 | } |
| 66 | return new OrderedMap(content); |
| 67 | }, |
| 68 | // :: (string) β OrderedMap |
| 69 | // Return a map with the given key removed, if it existed. |
| 70 | remove: function(key) { |
| 71 | var found2 = this.find(key); |
| 72 | if (found2 == -1) return this; |
| 73 | var content = this.content.slice(); |
| 74 | content.splice(found2, 2); |
| 75 | return new OrderedMap(content); |
| 76 | }, |
| 77 | // :: (string, any) β OrderedMap |
| 78 | // Add a new key to the start of the map. |
| 79 | addToStart: function(key, value) { |
| 80 | return new OrderedMap([key, value].concat(this.remove(key).content)); |
| 81 | }, |
| 82 | // :: (string, any) β OrderedMap |
| 83 | // Add a new key to the end of the map. |
| 84 | addToEnd: function(key, value) { |
| 85 | var content = this.remove(key).content.slice(); |
| 86 | content.push(key, value); |
| 87 | return new OrderedMap(content); |
| 88 | }, |
| 89 | // :: (string, string, any) β OrderedMap |
| 90 | // Add a key after the given key. If `place` is not found, the new |
| 91 | // key is added to the end. |
| 92 | addBefore: function(place, key, value) { |
| 93 | var without = this.remove(key), content = without.content.slice(); |
| 94 | var found2 = without.find(place); |
| 95 | content.splice(found2 == -1 ? content.length : found2, 0, key, value); |
| 96 | return new OrderedMap(content); |
| 97 | }, |
| 98 | // :: ((key: string, value: any)) |
| 99 | // Call the given function for each key/value pair in the map, in |
| 100 | // order. |
| 101 | forEach: function(f) { |
| 102 | for (var i2 = 0; i2 < this.content.length; i2 += 2) |
| 103 | f(this.content[i2], this.content[i2 + 1]); |
| 104 | }, |
| 105 | // :: (union<Object, OrderedMap>) β OrderedMap |
| 106 | // Create a new map by prepending the keys in this map that don't |
| 107 | // appear in `map` before the keys in `map`. |
| 108 | prepend: function(map2) { |
| 109 | map2 = OrderedMap.from(map2); |
| 110 | if (!map2.size) return this; |
| 111 | return new OrderedMap(map2.content.concat(this.subtract(map2).content)); |
| 112 | }, |
| 113 | // :: (union<Object, OrderedMap>) β OrderedMap |
| 114 | // Create a new map by appending the keys in this map that don't |
| 115 | // appear in `map` after the keys in `map`. |
| 116 | append: function(map2) { |
| 117 | map2 = OrderedMap.from(map2); |
| 118 | if (!map2.size) return this; |
| 119 | return new OrderedMap(this.subtract(map2).content.concat(map2.content)); |
| 120 | }, |
| 121 | // :: (union<Object, OrderedMap>) β OrderedMap |
| 122 | // Create a map containing all the keys in this map that don't |
| 123 | // appear in `map`. |
| 124 | subtract: function(map2) { |
| 125 | var result = this; |
| 126 | map2 = OrderedMap.from(map2); |
| 127 | for (var i2 = 0; i2 < map2.content.length; i2 += 2) |
| 128 | result = result.remove(map2.content[i2]); |
| 129 | return result; |
| 130 | }, |
| 131 | // :: () β Object |
| 132 | // Turn ordered map into a plain object. |
| 133 | toObject: function() { |
| 134 | var result = {}; |
| 135 | this.forEach(function(key, value) { |
| 136 | result[key] = value; |
| 137 | }); |
| 138 | return result; |
| 139 | }, |
| 140 | // :: number |
| 141 | // The amount of keys in this map. |
| 142 | get size() { |
| 143 | return this.content.length >> 1; |
| 144 | } |
| 145 | }; |
| 146 | OrderedMap.from = function(value) { |
| 147 | if (value instanceof OrderedMap) return value; |
| 148 | var content = []; |
| 149 | if (value) for (var prop in value) content.push(prop, value[prop]); |
| 150 | return new OrderedMap(content); |
| 151 | }; |
| 152 | var dist_default = OrderedMap; |
| 153 | |
| 154 | // node_modules/prosemirror-model/dist/index.js |
| 155 | function findDiffStart(a, b, pos) { |
| 156 | for (let i2 = 0; ; i2++) { |
| 157 | if (i2 == a.childCount || i2 == b.childCount) |
| 158 | return a.childCount == b.childCount ? null : pos; |
| 159 | let childA = a.child(i2), childB = b.child(i2); |
| 160 | if (childA == childB) { |
| 161 | pos += childA.nodeSize; |
| 162 | continue; |
| 163 | } |
| 164 | if (!childA.sameMarkup(childB)) |
| 165 | return pos; |
| 166 | if (childA.isText && childA.text != childB.text) { |
| 167 | let tA = childA.text, tB = childB.text, j = 0; |
| 168 | for (; tA[j] == tB[j]; j++) |
| 169 | pos++; |
| 170 | if (j && j < tA.length && j < tB.length && surrogateHigh(tA.charCodeAt(j - 1)) && surrogateLow(tA.charCodeAt(j))) |
| 171 | pos--; |
| 172 | return pos; |
| 173 | } |
| 174 | if (childA.content.size || childB.content.size) { |
| 175 | let inner = findDiffStart(childA.content, childB.content, pos + 1); |
| 176 | if (inner != null) |
| 177 | return inner; |
| 178 | } |
| 179 | pos += childA.nodeSize; |
| 180 | } |
| 181 | } |
| 182 | function findDiffEnd(a, b, posA, posB) { |
| 183 | for (let iA = a.childCount, iB = b.childCount; ; ) { |
| 184 | if (iA == 0 || iB == 0) |
| 185 | return iA == iB ? null : { a: posA, b: posB }; |
| 186 | let childA = a.child(--iA), childB = b.child(--iB), size = childA.nodeSize; |
| 187 | if (childA == childB) { |
| 188 | posA -= size; |
| 189 | posB -= size; |
| 190 | continue; |
| 191 | } |
| 192 | if (!childA.sameMarkup(childB)) |
| 193 | return { a: posA, b: posB }; |
| 194 | if (childA.isText && childA.text != childB.text) { |
| 195 | let tA = childA.text, tB = childB.text, iA2 = tA.length, iB2 = tB.length; |
| 196 | while (iA2 > 0 && iB2 > 0 && tA[iA2 - 1] == tB[iB2 - 1]) { |
| 197 | iA2--; |
| 198 | iB2--; |
| 199 | posA--; |
| 200 | posB--; |
| 201 | } |
| 202 | if (iA2 && iB2 && iA2 < tA.length && surrogateHigh(tA.charCodeAt(iA2 - 1)) && surrogateLow(tA.charCodeAt(iA2))) { |
| 203 | posA++; |
| 204 | posB++; |
| 205 | } |
| 206 | return { a: posA, b: posB }; |
| 207 | } |
| 208 | if (childA.content.size || childB.content.size) { |
| 209 | let inner = findDiffEnd(childA.content, childB.content, posA - 1, posB - 1); |
| 210 | if (inner) |
| 211 | return inner; |
| 212 | } |
| 213 | posA -= size; |
| 214 | posB -= size; |
| 215 | } |
| 216 | } |
| 217 | function surrogateLow(ch) { |
| 218 | return ch >= 56320 && ch < 57344; |
| 219 | } |
| 220 | function surrogateHigh(ch) { |
| 221 | return ch >= 55296 && ch < 56320; |
| 222 | } |
| 223 | var Fragment = class _Fragment { |
| 224 | /** |
| 225 | @internal |
| 226 | */ |
| 227 | constructor(content, size) { |
| 228 | this.content = content; |
| 229 | this.size = size || 0; |
| 230 | if (size == null) |
| 231 | for (let i2 = 0; i2 < content.length; i2++) |
| 232 | this.size += content[i2].nodeSize; |
| 233 | } |
| 234 | /** |
| 235 | Invoke a callback for all descendant nodes between the given two |
| 236 | positions (relative to start of this fragment). Doesn't descend |
| 237 | into a node when the callback returns `false`. |
| 238 | */ |
| 239 | nodesBetween(from2, to, f, nodeStart = 0, parent) { |
| 240 | for (let i2 = 0, pos = 0; pos < to; i2++) { |
| 241 | let child = this.content[i2], end = pos + child.nodeSize; |
| 242 | if (end > from2 && f(child, nodeStart + pos, parent || null, i2) !== false && child.content.size) { |
| 243 | let start = pos + 1; |
| 244 | child.nodesBetween(Math.max(0, from2 - start), Math.min(child.content.size, to - start), f, nodeStart + start); |
| 245 | } |
| 246 | pos = end; |
| 247 | } |
| 248 | } |
| 249 | /** |
| 250 | Call the given callback for every descendant node. `pos` will be |
| 251 | relative to the start of the fragment. The callback may return |
| 252 | `false` to prevent traversal of a given node's children. |
| 253 | */ |
| 254 | descendants(f) { |
| 255 | this.nodesBetween(0, this.size, f); |
| 256 | } |
| 257 | /** |
| 258 | Extract the text between `from` and `to`. See the same method on |
| 259 | [`Node`](https://prosemirror.net/docs/ref/#model.Node.textBetween). |
| 260 | */ |
| 261 | textBetween(from2, to, blockSeparator, leafText) { |
| 262 | let text = "", first = true; |
| 263 | this.nodesBetween(from2, to, (node, pos) => { |
| 264 | let nodeText = node.isText ? node.text.slice(Math.max(from2, pos) - pos, to - pos) : !node.isLeaf ? "" : leafText ? typeof leafText === "function" ? leafText(node) : leafText : node.type.spec.leafText ? node.type.spec.leafText(node) : ""; |
| 265 | if (node.isBlock && (node.isLeaf && nodeText || node.isTextblock) && blockSeparator) { |
| 266 | if (first) |
| 267 | first = false; |
| 268 | else |
| 269 | text += blockSeparator; |
| 270 | } |
| 271 | text += nodeText; |
| 272 | }, 0); |
| 273 | return text; |
| 274 | } |
| 275 | /** |
| 276 | Create a new fragment containing the combined content of this |
| 277 | fragment and the other. |
| 278 | */ |
| 279 | append(other) { |
| 280 | if (!other.size) |
| 281 | return this; |
| 282 | if (!this.size) |
| 283 | return other; |
| 284 | let last = this.lastChild, first = other.firstChild, content = this.content.slice(), i2 = 0; |
| 285 | if (last.isText && last.sameMarkup(first)) { |
| 286 | content[content.length - 1] = last.withText(last.text + first.text); |
| 287 | i2 = 1; |
| 288 | } |
| 289 | for (; i2 < other.content.length; i2++) |
| 290 | content.push(other.content[i2]); |
| 291 | return new _Fragment(content, this.size + other.size); |
| 292 | } |
| 293 | /** |
| 294 | Cut out the sub-fragment between the two given positions. |
| 295 | */ |
| 296 | cut(from2, to = this.size) { |
| 297 | if (from2 == 0 && to == this.size) |
| 298 | return this; |
| 299 | let result = [], size = 0; |
| 300 | if (to > from2) |
| 301 | for (let i2 = 0, pos = 0; pos < to; i2++) { |
| 302 | let child = this.content[i2], end = pos + child.nodeSize; |
| 303 | if (end > from2) { |
| 304 | if (pos < from2 || end > to) { |
| 305 | if (child.isText) |
| 306 | child = child.cut(Math.max(0, from2 - pos), Math.min(child.text.length, to - pos)); |
| 307 | else |
| 308 | child = child.cut(Math.max(0, from2 - pos - 1), Math.min(child.content.size, to - pos - 1)); |
| 309 | } |
| 310 | result.push(child); |
| 311 | size += child.nodeSize; |
| 312 | } |
| 313 | pos = end; |
| 314 | } |
| 315 | return new _Fragment(result, size); |
| 316 | } |
| 317 | /** |
| 318 | @internal |
| 319 | */ |
| 320 | cutByIndex(from2, to) { |
| 321 | if (from2 == to) |
| 322 | return _Fragment.empty; |
| 323 | if (from2 == 0 && to == this.content.length) |
| 324 | return this; |
| 325 | return new _Fragment(this.content.slice(from2, to)); |
| 326 | } |
| 327 | /** |
| 328 | Create a new fragment in which the node at the given index is |
| 329 | replaced by the given node. |
| 330 | */ |
| 331 | replaceChild(index, node) { |
| 332 | let current = this.content[index]; |
| 333 | if (current == node) |
| 334 | return this; |
| 335 | let copy2 = this.content.slice(); |
| 336 | let size = this.size + node.nodeSize - current.nodeSize; |
| 337 | copy2[index] = node; |
| 338 | return new _Fragment(copy2, size); |
| 339 | } |
| 340 | /** |
| 341 | Create a new fragment by prepending the given node to this |
| 342 | fragment. |
| 343 | */ |
| 344 | addToStart(node) { |
| 345 | return new _Fragment([node].concat(this.content), this.size + node.nodeSize); |
| 346 | } |
| 347 | /** |
| 348 | Create a new fragment by appending the given node to this |
| 349 | fragment. |
| 350 | */ |
| 351 | addToEnd(node) { |
| 352 | return new _Fragment(this.content.concat(node), this.size + node.nodeSize); |
| 353 | } |
| 354 | /** |
| 355 | Compare this fragment to another one. |
| 356 | */ |
| 357 | eq(other) { |
| 358 | if (this.content.length != other.content.length) |
| 359 | return false; |
| 360 | for (let i2 = 0; i2 < this.content.length; i2++) |
| 361 | if (!this.content[i2].eq(other.content[i2])) |
| 362 | return false; |
| 363 | return true; |
| 364 | } |
| 365 | /** |
| 366 | The first child of the fragment, or `null` if it is empty. |
| 367 | */ |
| 368 | get firstChild() { |
| 369 | return this.content.length ? this.content[0] : null; |
| 370 | } |
| 371 | /** |
| 372 | The last child of the fragment, or `null` if it is empty. |
| 373 | */ |
| 374 | get lastChild() { |
| 375 | return this.content.length ? this.content[this.content.length - 1] : null; |
| 376 | } |
| 377 | /** |
| 378 | The number of child nodes in this fragment. |
| 379 | */ |
| 380 | get childCount() { |
| 381 | return this.content.length; |
| 382 | } |
| 383 | /** |
| 384 | Get the child node at the given index. Raise an error when the |
| 385 | index is out of range. |
| 386 | */ |
| 387 | child(index) { |
| 388 | let found2 = this.content[index]; |
| 389 | if (!found2) |
| 390 | throw new RangeError("Index " + index + " out of range for " + this); |
| 391 | return found2; |
| 392 | } |
| 393 | /** |
| 394 | Get the child node at the given index, if it exists. |
| 395 | */ |
| 396 | maybeChild(index) { |
| 397 | return this.content[index] || null; |
| 398 | } |
| 399 | /** |
| 400 | Call `f` for every child node, passing the node, its offset |
| 401 | into this parent node, and its index. |
| 402 | */ |
| 403 | forEach(f) { |
| 404 | for (let i2 = 0, p = 0; i2 < this.content.length; i2++) { |
| 405 | let child = this.content[i2]; |
| 406 | f(child, p, i2); |
| 407 | p += child.nodeSize; |
| 408 | } |
| 409 | } |
| 410 | /** |
| 411 | Find the first position at which this fragment and another |
| 412 | fragment differ, or `null` if they are the same. |
| 413 | */ |
| 414 | findDiffStart(other, pos = 0) { |
| 415 | return findDiffStart(this, other, pos); |
| 416 | } |
| 417 | /** |
| 418 | Find the first position, searching from the end, at which this |
| 419 | fragment and the given fragment differ, or `null` if they are |
| 420 | the same. Since this position will not be the same in both |
| 421 | nodes, an object with two separate positions is returned. |
| 422 | */ |
| 423 | findDiffEnd(other, pos = this.size, otherPos = other.size) { |
| 424 | return findDiffEnd(this, other, pos, otherPos); |
| 425 | } |
| 426 | /** |
| 427 | Find the index and inner offset corresponding to a given relative |
| 428 | position in this fragment. The result object will be reused |
| 429 | (overwritten) the next time the function is called. @internal |
| 430 | */ |
| 431 | findIndex(pos) { |
| 432 | if (pos == 0) |
| 433 | return retIndex(0, pos); |
| 434 | if (pos == this.size) |
| 435 | return retIndex(this.content.length, pos); |
| 436 | if (pos > this.size || pos < 0) |
| 437 | throw new RangeError(`Position ${pos} outside of fragment (${this})`); |
| 438 | for (let i2 = 0, curPos = 0; ; i2++) { |
| 439 | let cur = this.child(i2), end = curPos + cur.nodeSize; |
| 440 | if (end >= pos) { |
| 441 | if (end == pos) |
| 442 | return retIndex(i2 + 1, end); |
| 443 | return retIndex(i2, curPos); |
| 444 | } |
| 445 | curPos = end; |
| 446 | } |
| 447 | } |
| 448 | /** |
| 449 | Return a debugging string that describes this fragment. |
| 450 | */ |
| 451 | toString() { |
| 452 | return "<" + this.toStringInner() + ">"; |
| 453 | } |
| 454 | /** |
| 455 | @internal |
| 456 | */ |
| 457 | toStringInner() { |
| 458 | return this.content.join(", "); |
| 459 | } |
| 460 | /** |
| 461 | Create a JSON-serializeable representation of this fragment. |
| 462 | */ |
| 463 | toJSON() { |
| 464 | return this.content.length ? this.content.map((n) => n.toJSON()) : null; |
| 465 | } |
| 466 | /** |
| 467 | Deserialize a fragment from its JSON representation. |
| 468 | */ |
| 469 | static fromJSON(schema2, value) { |
| 470 | if (!value) |
| 471 | return _Fragment.empty; |
| 472 | if (!Array.isArray(value)) |
| 473 | throw new RangeError("Invalid input for Fragment.fromJSON"); |
| 474 | return _Fragment.fromArray(value.map(schema2.nodeFromJSON)); |
| 475 | } |
| 476 | /** |
| 477 | Build a fragment from an array of nodes. Ensures that adjacent |
| 478 | text nodes with the same marks are joined together. |
| 479 | */ |
| 480 | static fromArray(array) { |
| 481 | if (!array.length) |
| 482 | return _Fragment.empty; |
| 483 | let joined, size = 0; |
| 484 | for (let i2 = 0; i2 < array.length; i2++) { |
| 485 | let node = array[i2]; |
| 486 | size += node.nodeSize; |
| 487 | if (i2 && node.isText && array[i2 - 1].sameMarkup(node)) { |
| 488 | if (!joined) |
| 489 | joined = array.slice(0, i2); |
| 490 | joined[joined.length - 1] = node.withText(joined[joined.length - 1].text + node.text); |
| 491 | } else if (joined) { |
| 492 | joined.push(node); |
| 493 | } |
| 494 | } |
| 495 | return new _Fragment(joined || array, size); |
| 496 | } |
| 497 | /** |
| 498 | Create a fragment from something that can be interpreted as a |
| 499 | set of nodes. For `null`, it returns the empty fragment. For a |
| 500 | fragment, the fragment itself. For a node or array of nodes, a |
| 501 | fragment containing those nodes. |
| 502 | */ |
| 503 | static from(nodes) { |
| 504 | if (!nodes) |
| 505 | return _Fragment.empty; |
| 506 | if (nodes instanceof _Fragment) |
| 507 | return nodes; |
| 508 | if (Array.isArray(nodes)) |
| 509 | return this.fromArray(nodes); |
| 510 | if (nodes.attrs) |
| 511 | return new _Fragment([nodes], nodes.nodeSize); |
| 512 | throw new RangeError("Can not convert " + nodes + " to a Fragment" + (nodes.nodesBetween ? " (looks like multiple versions of prosemirror-model were loaded)" : "")); |
| 513 | } |
| 514 | }; |
| 515 | Fragment.empty = new Fragment([], 0); |
| 516 | var found = { index: 0, offset: 0 }; |
| 517 | function retIndex(index, offset) { |
| 518 | found.index = index; |
| 519 | found.offset = offset; |
| 520 | return found; |
| 521 | } |
| 522 | function compareDeep(a, b) { |
| 523 | if (a === b) |
| 524 | return true; |
| 525 | if (!(a && typeof a == "object") || !(b && typeof b == "object")) |
| 526 | return false; |
| 527 | let array = Array.isArray(a); |
| 528 | if (Array.isArray(b) != array) |
| 529 | return false; |
| 530 | if (array) { |
| 531 | if (a.length != b.length) |
| 532 | return false; |
| 533 | for (let i2 = 0; i2 < a.length; i2++) |
| 534 | if (!compareDeep(a[i2], b[i2])) |
| 535 | return false; |
| 536 | } else { |
| 537 | for (let p in a) |
| 538 | if (!(p in b) || !compareDeep(a[p], b[p])) |
| 539 | return false; |
| 540 | for (let p in b) |
| 541 | if (!(p in a)) |
| 542 | return false; |
| 543 | } |
| 544 | return true; |
| 545 | } |
| 546 | var Mark = class _Mark { |
| 547 | /** |
| 548 | @internal |
| 549 | */ |
| 550 | constructor(type, attrs2) { |
| 551 | this.type = type; |
| 552 | this.attrs = attrs2; |
| 553 | } |
| 554 | /** |
| 555 | Given a set of marks, create a new set which contains this one as |
| 556 | well, in the right position. If this mark is already in the set, |
| 557 | the set itself is returned. If any marks that are set to be |
| 558 | [exclusive](https://prosemirror.net/docs/ref/#model.MarkSpec.excludes) with this mark are present, |
| 559 | those are replaced by this one. |
| 560 | */ |
| 561 | addToSet(set) { |
| 562 | let copy2, placed = false; |
| 563 | for (let i2 = 0; i2 < set.length; i2++) { |
| 564 | let other = set[i2]; |
| 565 | if (this.eq(other)) |
| 566 | return set; |
| 567 | if (this.type.excludes(other.type)) { |
| 568 | if (!copy2) |
| 569 | copy2 = set.slice(0, i2); |
| 570 | } else if (other.type.excludes(this.type)) { |
| 571 | return set; |
| 572 | } else { |
| 573 | if (!placed && other.type.rank > this.type.rank) { |
| 574 | if (!copy2) |
| 575 | copy2 = set.slice(0, i2); |
| 576 | copy2.push(this); |
| 577 | placed = true; |
| 578 | } |
| 579 | if (copy2) |
| 580 | copy2.push(other); |
| 581 | } |
| 582 | } |
| 583 | if (!copy2) |
| 584 | copy2 = set.slice(); |
| 585 | if (!placed) |
| 586 | copy2.push(this); |
| 587 | return copy2; |
| 588 | } |
| 589 | /** |
| 590 | Remove this mark from the given set, returning a new set. If this |
| 591 | mark is not in the set, the set itself is returned. |
| 592 | */ |
| 593 | removeFromSet(set) { |
| 594 | for (let i2 = 0; i2 < set.length; i2++) |
| 595 | if (this.eq(set[i2])) |
| 596 | return set.slice(0, i2).concat(set.slice(i2 + 1)); |
| 597 | return set; |
| 598 | } |
| 599 | /** |
| 600 | Test whether this mark is in the given set of marks. |
| 601 | */ |
| 602 | isInSet(set) { |
| 603 | for (let i2 = 0; i2 < set.length; i2++) |
| 604 | if (this.eq(set[i2])) |
| 605 | return true; |
| 606 | return false; |
| 607 | } |
| 608 | /** |
| 609 | Test whether this mark has the same type and attributes as |
| 610 | another mark. |
| 611 | */ |
| 612 | eq(other) { |
| 613 | return this == other || this.type == other.type && compareDeep(this.attrs, other.attrs); |
| 614 | } |
| 615 | /** |
| 616 | Convert this mark to a JSON-serializeable representation. |
| 617 | */ |
| 618 | toJSON() { |
| 619 | let obj = { type: this.type.name }; |
| 620 | for (let _ in this.attrs) { |
| 621 | obj.attrs = this.attrs; |
| 622 | break; |
| 623 | } |
| 624 | return obj; |
| 625 | } |
| 626 | /** |
| 627 | Deserialize a mark from JSON. |
| 628 | */ |
| 629 | static fromJSON(schema2, json) { |
| 630 | if (!json) |
| 631 | throw new RangeError("Invalid input for Mark.fromJSON"); |
| 632 | let type = schema2.marks[json.type]; |
| 633 | if (!type) |
| 634 | throw new RangeError(`There is no mark type ${json.type} in this schema`); |
| 635 | let mark = type.create(json.attrs); |
| 636 | type.checkAttrs(mark.attrs); |
| 637 | return mark; |
| 638 | } |
| 639 | /** |
| 640 | Test whether two sets of marks are identical. |
| 641 | */ |
| 642 | static sameSet(a, b) { |
| 643 | if (a == b) |
| 644 | return true; |
| 645 | if (a.length != b.length) |
| 646 | return false; |
| 647 | for (let i2 = 0; i2 < a.length; i2++) |
| 648 | if (!a[i2].eq(b[i2])) |
| 649 | return false; |
| 650 | return true; |
| 651 | } |
| 652 | /** |
| 653 | Create a properly sorted mark set from null, a single mark, or an |
| 654 | unsorted array of marks. |
| 655 | */ |
| 656 | static setFrom(marks) { |
| 657 | if (!marks || Array.isArray(marks) && marks.length == 0) |
| 658 | return _Mark.none; |
| 659 | if (marks instanceof _Mark) |
| 660 | return [marks]; |
| 661 | let copy2 = marks.slice(); |
| 662 | copy2.sort((a, b) => a.type.rank - b.type.rank); |
| 663 | return copy2; |
| 664 | } |
| 665 | }; |
| 666 | Mark.none = []; |
| 667 | var ReplaceError = class extends Error { |
| 668 | }; |
| 669 | var Slice = class _Slice { |
| 670 | /** |
| 671 | Create a slice. When specifying a non-zero open depth, you must |
| 672 | make sure that there are nodes of at least that depth at the |
| 673 | appropriate side of the fragmentβi.e. if the fragment is an |
| 674 | empty paragraph node, `openStart` and `openEnd` can't be greater |
| 675 | than 1. |
| 676 | |
| 677 | It is not necessary for the content of open nodes to conform to |
| 678 | the schema's content constraints, though it should be a valid |
| 679 | start/end/middle for such a node, depending on which sides are |
| 680 | open. |
| 681 | */ |
| 682 | constructor(content, openStart, openEnd) { |
| 683 | this.content = content; |
| 684 | this.openStart = openStart; |
| 685 | this.openEnd = openEnd; |
| 686 | } |
| 687 | /** |
| 688 | The size this slice would add when inserted into a document. |
| 689 | */ |
| 690 | get size() { |
| 691 | return this.content.size - this.openStart - this.openEnd; |
| 692 | } |
| 693 | /** |
| 694 | @internal |
| 695 | */ |
| 696 | insertAt(pos, fragment) { |
| 697 | let content = insertInto(this.content, pos + this.openStart, fragment, this.openStart + 1, this.openEnd + 1); |
| 698 | return content && new _Slice(content, this.openStart, this.openEnd); |
| 699 | } |
| 700 | /** |
| 701 | @internal |
| 702 | */ |
| 703 | removeBetween(from2, to) { |
| 704 | return new _Slice(removeRange(this.content, from2 + this.openStart, to + this.openStart), this.openStart, this.openEnd); |
| 705 | } |
| 706 | /** |
| 707 | Tests whether this slice is equal to another slice. |
| 708 | */ |
| 709 | eq(other) { |
| 710 | return this.content.eq(other.content) && this.openStart == other.openStart && this.openEnd == other.openEnd; |
| 711 | } |
| 712 | /** |
| 713 | @internal |
| 714 | */ |
| 715 | toString() { |
| 716 | return this.content + "(" + this.openStart + "," + this.openEnd + ")"; |
| 717 | } |
| 718 | /** |
| 719 | Convert a slice to a JSON-serializable representation. |
| 720 | */ |
| 721 | toJSON() { |
| 722 | if (!this.content.size) |
| 723 | return null; |
| 724 | let json = { content: this.content.toJSON() }; |
| 725 | if (this.openStart > 0) |
| 726 | json.openStart = this.openStart; |
| 727 | if (this.openEnd > 0) |
| 728 | json.openEnd = this.openEnd; |
| 729 | return json; |
| 730 | } |
| 731 | /** |
| 732 | Deserialize a slice from its JSON representation. |
| 733 | */ |
| 734 | static fromJSON(schema2, json) { |
| 735 | if (!json) |
| 736 | return _Slice.empty; |
| 737 | let openStart = json.openStart || 0, openEnd = json.openEnd || 0; |
| 738 | if (typeof openStart != "number" || typeof openEnd != "number") |
| 739 | throw new RangeError("Invalid input for Slice.fromJSON"); |
| 740 | return new _Slice(Fragment.fromJSON(schema2, json.content), openStart, openEnd); |
| 741 | } |
| 742 | /** |
| 743 | Create a slice from a fragment by taking the maximum possible |
| 744 | open value on both side of the fragment. |
| 745 | */ |
| 746 | static maxOpen(fragment, openIsolating = true) { |
| 747 | let openStart = 0, openEnd = 0; |
| 748 | for (let n = fragment.firstChild; n && !n.isLeaf && (openIsolating || !n.type.spec.isolating); n = n.firstChild) |
| 749 | openStart++; |
| 750 | for (let n = fragment.lastChild; n && !n.isLeaf && (openIsolating || !n.type.spec.isolating); n = n.lastChild) |
| 751 | openEnd++; |
| 752 | return new _Slice(fragment, openStart, openEnd); |
| 753 | } |
| 754 | }; |
| 755 | Slice.empty = new Slice(Fragment.empty, 0, 0); |
| 756 | function removeRange(content, from2, to) { |
| 757 | let { index, offset } = content.findIndex(from2), child = content.maybeChild(index); |
| 758 | let { index: indexTo, offset: offsetTo } = content.findIndex(to); |
| 759 | if (offset == from2 || child.isText) { |
| 760 | if (offsetTo != to && !content.child(indexTo).isText) |
| 761 | throw new RangeError("Removing non-flat range"); |
| 762 | return content.cut(0, from2).append(content.cut(to)); |
| 763 | } |
| 764 | if (index != indexTo) |
| 765 | throw new RangeError("Removing non-flat range"); |
| 766 | return content.replaceChild(index, child.copy(removeRange(child.content, from2 - offset - 1, to - offset - 1))); |
| 767 | } |
| 768 | function insertInto(content, dist, insert, openStart, openEnd, parent) { |
| 769 | let { index, offset } = content.findIndex(dist), child = content.maybeChild(index); |
| 770 | if (offset == dist || child.isText) { |
| 771 | if (parent && openStart <= 0 && openEnd <= 0 && !parent.canReplace(index, index, insert)) |
| 772 | return null; |
| 773 | return content.cut(0, dist).append(insert).append(content.cut(dist)); |
| 774 | } |
| 775 | let inner = insertInto(child.content, dist - offset - 1, insert, index == 0 ? openStart - 1 : 0, index == content.childCount - 1 ? openEnd - 1 : 0, child); |
| 776 | return inner && content.replaceChild(index, child.copy(inner)); |
| 777 | } |
| 778 | function replace($from, $to, slice2) { |
| 779 | if (slice2.openStart > $from.depth) |
| 780 | throw new ReplaceError("Inserted content deeper than insertion position"); |
| 781 | if ($from.depth - slice2.openStart != $to.depth - slice2.openEnd) |
| 782 | throw new ReplaceError("Inconsistent open depths"); |
| 783 | return replaceOuter($from, $to, slice2, 0); |
| 784 | } |
| 785 | function replaceOuter($from, $to, slice2, depth) { |
| 786 | let index = $from.index(depth), node = $from.node(depth); |
| 787 | if (index == $to.index(depth) && depth < $from.depth - slice2.openStart) { |
| 788 | let inner = replaceOuter($from, $to, slice2, depth + 1); |
| 789 | return node.copy(node.content.replaceChild(index, inner)); |
| 790 | } else if (!slice2.content.size) { |
| 791 | return close(node, replaceTwoWay($from, $to, depth)); |
| 792 | } else if (!slice2.openStart && !slice2.openEnd && $from.depth == depth && $to.depth == depth) { |
| 793 | let parent = $from.parent, content = parent.content; |
| 794 | return close(parent, content.cut(0, $from.parentOffset).append(slice2.content).append(content.cut($to.parentOffset))); |
| 795 | } else { |
| 796 | let { start, end } = prepareSliceForReplace(slice2, $from); |
| 797 | return close(node, replaceThreeWay($from, start, end, $to, depth)); |
| 798 | } |
| 799 | } |
| 800 | function checkJoin(main, sub) { |
| 801 | if (!sub.type.compatibleContent(main.type)) |
| 802 | throw new ReplaceError("Cannot join " + sub.type.name + " onto " + main.type.name); |
| 803 | } |
| 804 | function joinable($before, $after, depth) { |
| 805 | let node = $before.node(depth); |
| 806 | checkJoin(node, $after.node(depth)); |
| 807 | return node; |
| 808 | } |
| 809 | function addNode(child, target) { |
| 810 | let last = target.length - 1; |
| 811 | if (last >= 0 && child.isText && child.sameMarkup(target[last])) |
| 812 | target[last] = child.withText(target[last].text + child.text); |
| 813 | else |
| 814 | target.push(child); |
| 815 | } |
| 816 | function addRange($start, $end, depth, target) { |
| 817 | let node = ($end || $start).node(depth); |
| 818 | let startIndex = 0, endIndex = $end ? $end.index(depth) : node.childCount; |
| 819 | if ($start) { |
| 820 | startIndex = $start.index(depth); |
| 821 | if ($start.depth > depth) { |
| 822 | startIndex++; |
| 823 | } else if ($start.textOffset) { |
| 824 | addNode($start.nodeAfter, target); |
| 825 | startIndex++; |
| 826 | } |
| 827 | } |
| 828 | for (let i2 = startIndex; i2 < endIndex; i2++) |
| 829 | addNode(node.child(i2), target); |
| 830 | if ($end && $end.depth == depth && $end.textOffset) |
| 831 | addNode($end.nodeBefore, target); |
| 832 | } |
| 833 | function close(node, content) { |
| 834 | if (!node.type.validContent(content)) |
| 835 | throw new ReplaceError("Invalid content for node " + node.type.name); |
| 836 | return node.copy(content); |
| 837 | } |
| 838 | function replaceThreeWay($from, $start, $end, $to, depth) { |
| 839 | let openStart = $from.depth > depth && joinable($from, $start, depth + 1); |
| 840 | let openEnd = $to.depth > depth && joinable($end, $to, depth + 1); |
| 841 | let content = []; |
| 842 | addRange(null, $from, depth, content); |
| 843 | if (openStart && openEnd && $start.index(depth) == $end.index(depth)) { |
| 844 | checkJoin(openStart, openEnd); |
| 845 | addNode(close(openStart, replaceThreeWay($from, $start, $end, $to, depth + 1)), content); |
| 846 | } else { |
| 847 | if (openStart) |
| 848 | addNode(close(openStart, replaceTwoWay($from, $start, depth + 1)), content); |
| 849 | addRange($start, $end, depth, content); |
| 850 | if (openEnd) |
| 851 | addNode(close(openEnd, replaceTwoWay($end, $to, depth + 1)), content); |
| 852 | } |
| 853 | addRange($to, null, depth, content); |
| 854 | return new Fragment(content); |
| 855 | } |
| 856 | function replaceTwoWay($from, $to, depth) { |
| 857 | let content = []; |
| 858 | addRange(null, $from, depth, content); |
| 859 | if ($from.depth > depth) { |
| 860 | let type = joinable($from, $to, depth + 1); |
| 861 | addNode(close(type, replaceTwoWay($from, $to, depth + 1)), content); |
| 862 | } |
| 863 | addRange($to, null, depth, content); |
| 864 | return new Fragment(content); |
| 865 | } |
| 866 | function prepareSliceForReplace(slice2, $along) { |
| 867 | let extra = $along.depth - slice2.openStart, parent = $along.node(extra); |
| 868 | let node = parent.copy(slice2.content); |
| 869 | for (let i2 = extra - 1; i2 >= 0; i2--) |
| 870 | node = $along.node(i2).copy(Fragment.from(node)); |
| 871 | return { |
| 872 | start: node.resolveNoCache(slice2.openStart + extra), |
| 873 | end: node.resolveNoCache(node.content.size - slice2.openEnd - extra) |
| 874 | }; |
| 875 | } |
| 876 | var ResolvedPos = class _ResolvedPos { |
| 877 | /** |
| 878 | @internal |
| 879 | */ |
| 880 | constructor(pos, path, parentOffset) { |
| 881 | this.pos = pos; |
| 882 | this.path = path; |
| 883 | this.parentOffset = parentOffset; |
| 884 | this.depth = path.length / 3 - 1; |
| 885 | } |
| 886 | /** |
| 887 | @internal |
| 888 | */ |
| 889 | resolveDepth(val) { |
| 890 | if (val == null) |
| 891 | return this.depth; |
| 892 | if (val < 0) |
| 893 | return this.depth + val; |
| 894 | return val; |
| 895 | } |
| 896 | /** |
| 897 | The parent node that the position points into. Note that even if |
| 898 | a position points into a text node, that node is not considered |
| 899 | the parentβtext nodes are βflatβ in this model, and have no content. |
| 900 | */ |
| 901 | get parent() { |
| 902 | return this.node(this.depth); |
| 903 | } |
| 904 | /** |
| 905 | The root node in which the position was resolved. |
| 906 | */ |
| 907 | get doc() { |
| 908 | return this.node(0); |
| 909 | } |
| 910 | /** |
| 911 | The ancestor node at the given level. `p.node(p.depth)` is the |
| 912 | same as `p.parent`. |
| 913 | */ |
| 914 | node(depth) { |
| 915 | return this.path[this.resolveDepth(depth) * 3]; |
| 916 | } |
| 917 | /** |
| 918 | The index into the ancestor at the given level. If this points |
| 919 | at the 3rd node in the 2nd paragraph on the top level, for |
| 920 | example, `p.index(0)` is 1 and `p.index(1)` is 2. |
| 921 | */ |
| 922 | index(depth) { |
| 923 | return this.path[this.resolveDepth(depth) * 3 + 1]; |
| 924 | } |
| 925 | /** |
| 926 | The index pointing after this position into the ancestor at the |
| 927 | given level. |
| 928 | */ |
| 929 | indexAfter(depth) { |
| 930 | depth = this.resolveDepth(depth); |
| 931 | return this.index(depth) + (depth == this.depth && !this.textOffset ? 0 : 1); |
| 932 | } |
| 933 | /** |
| 934 | The (absolute) position at the start of the node at the given |
| 935 | level. |
| 936 | */ |
| 937 | start(depth) { |
| 938 | depth = this.resolveDepth(depth); |
| 939 | return depth == 0 ? 0 : this.path[depth * 3 - 1] + 1; |
| 940 | } |
| 941 | /** |
| 942 | The (absolute) position at the end of the node at the given |
| 943 | level. |
| 944 | */ |
| 945 | end(depth) { |
| 946 | depth = this.resolveDepth(depth); |
| 947 | return this.start(depth) + this.node(depth).content.size; |
| 948 | } |
| 949 | /** |
| 950 | The (absolute) position directly before the wrapping node at the |
| 951 | given level, or, when `depth` is `this.depth + 1`, the original |
| 952 | position. |
| 953 | */ |
| 954 | before(depth) { |
| 955 | depth = this.resolveDepth(depth); |
| 956 | if (!depth) |
| 957 | throw new RangeError("There is no position before the top-level node"); |
| 958 | return depth == this.depth + 1 ? this.pos : this.path[depth * 3 - 1]; |
| 959 | } |
| 960 | /** |
| 961 | The (absolute) position directly after the wrapping node at the |
| 962 | given level, or the original position when `depth` is `this.depth + 1`. |
| 963 | */ |
| 964 | after(depth) { |
| 965 | depth = this.resolveDepth(depth); |
| 966 | if (!depth) |
| 967 | throw new RangeError("There is no position after the top-level node"); |
| 968 | return depth == this.depth + 1 ? this.pos : this.path[depth * 3 - 1] + this.path[depth * 3].nodeSize; |
| 969 | } |
| 970 | /** |
| 971 | When this position points into a text node, this returns the |
| 972 | distance between the position and the start of the text node. |
| 973 | Will be zero for positions that point between nodes. |
| 974 | */ |
| 975 | get textOffset() { |
| 976 | return this.pos - this.path[this.path.length - 1]; |
| 977 | } |
| 978 | /** |
| 979 | Get the node directly after the position, if any. If the position |
| 980 | points into a text node, only the part of that node after the |
| 981 | position is returned. |
| 982 | */ |
| 983 | get nodeAfter() { |
| 984 | let parent = this.parent, index = this.index(this.depth); |
| 985 | if (index == parent.childCount) |
| 986 | return null; |
| 987 | let dOff = this.pos - this.path[this.path.length - 1], child = parent.child(index); |
| 988 | return dOff ? parent.child(index).cut(dOff) : child; |
| 989 | } |
| 990 | /** |
| 991 | Get the node directly before the position, if any. If the |
| 992 | position points into a text node, only the part of that node |
| 993 | before the position is returned. |
| 994 | */ |
| 995 | get nodeBefore() { |
| 996 | let index = this.index(this.depth); |
| 997 | let dOff = this.pos - this.path[this.path.length - 1]; |
| 998 | if (dOff) |
| 999 | return this.parent.child(index).cut(0, dOff); |
| 1000 | return index == 0 ? null : this.parent.child(index - 1); |
| 1001 | } |
| 1002 | /** |
| 1003 | Get the position at the given index in the parent node at the |
| 1004 | given depth (which defaults to `this.depth`). |
| 1005 | */ |
| 1006 | posAtIndex(index, depth) { |
| 1007 | depth = this.resolveDepth(depth); |
| 1008 | let node = this.path[depth * 3], pos = depth == 0 ? 0 : this.path[depth * 3 - 1] + 1; |
| 1009 | for (let i2 = 0; i2 < index; i2++) |
| 1010 | pos += node.child(i2).nodeSize; |
| 1011 | return pos; |
| 1012 | } |
| 1013 | /** |
| 1014 | Get the marks at this position, factoring in the surrounding |
| 1015 | marks' [`inclusive`](https://prosemirror.net/docs/ref/#model.MarkSpec.inclusive) property. If the |
| 1016 | position is at the start of a non-empty node, the marks of the |
| 1017 | node after it (if any) are returned. |
| 1018 | */ |
| 1019 | marks() { |
| 1020 | let parent = this.parent, index = this.index(); |
| 1021 | if (parent.content.size == 0) |
| 1022 | return Mark.none; |
| 1023 | if (this.textOffset) |
| 1024 | return parent.child(index).marks; |
| 1025 | let main = parent.maybeChild(index - 1), other = parent.maybeChild(index); |
| 1026 | if (!main) { |
| 1027 | let tmp = main; |
| 1028 | main = other; |
| 1029 | other = tmp; |
| 1030 | } |
| 1031 | let marks = main.marks; |
| 1032 | for (var i2 = 0; i2 < marks.length; i2++) |
| 1033 | if (marks[i2].type.spec.inclusive === false && (!other || !marks[i2].isInSet(other.marks))) |
| 1034 | marks = marks[i2--].removeFromSet(marks); |
| 1035 | return marks; |
| 1036 | } |
| 1037 | /** |
| 1038 | Get the marks after the current position, if any, except those |
| 1039 | that are non-inclusive and not present at position `$end`. This |
| 1040 | is mostly useful for getting the set of marks to preserve after a |
| 1041 | deletion. Will return `null` if this position is at the end of |
| 1042 | its parent node or its parent node isn't a textblock (in which |
| 1043 | case no marks should be preserved). |
| 1044 | */ |
| 1045 | marksAcross($end) { |
| 1046 | let after = this.parent.maybeChild(this.index()); |
| 1047 | if (!after || !after.isInline) |
| 1048 | return null; |
| 1049 | let marks = after.marks, next = $end.parent.maybeChild($end.index()); |
| 1050 | for (var i2 = 0; i2 < marks.length; i2++) |
| 1051 | if (marks[i2].type.spec.inclusive === false && (!next || !marks[i2].isInSet(next.marks))) |
| 1052 | marks = marks[i2--].removeFromSet(marks); |
| 1053 | return marks; |
| 1054 | } |
| 1055 | /** |
| 1056 | The depth up to which this position and the given (non-resolved) |
| 1057 | position share the same parent nodes. |
| 1058 | */ |
| 1059 | sharedDepth(pos) { |
| 1060 | for (let depth = this.depth; depth > 0; depth--) |
| 1061 | if (this.start(depth) <= pos && this.end(depth) >= pos) |
| 1062 | return depth; |
| 1063 | return 0; |
| 1064 | } |
| 1065 | /** |
| 1066 | Returns a range based on the place where this position and the |
| 1067 | given position diverge around block content. If both point into |
| 1068 | the same textblock, for example, a range around that textblock |
| 1069 | will be returned. If they point into different blocks, the range |
| 1070 | around those blocks in their shared ancestor is returned. You can |
| 1071 | pass in an optional predicate that will be called with a parent |
| 1072 | node to see if a range into that parent is acceptable. |
| 1073 | */ |
| 1074 | blockRange(other = this, pred) { |
| 1075 | if (other.pos < this.pos) |
| 1076 | return other.blockRange(this); |
| 1077 | for (let d = this.depth - (this.parent.inlineContent || this.pos == other.pos ? 1 : 0); d >= 0; d--) |
| 1078 | if (other.pos <= this.end(d) && (!pred || pred(this.node(d)))) |
| 1079 | return new NodeRange(this, other, d); |
| 1080 | return null; |
| 1081 | } |
| 1082 | /** |
| 1083 | Query whether the given position shares the same parent node. |
| 1084 | */ |
| 1085 | sameParent(other) { |
| 1086 | return this.pos - this.parentOffset == other.pos - other.parentOffset; |
| 1087 | } |
| 1088 | /** |
| 1089 | Return the greater of this and the given position. |
| 1090 | */ |
| 1091 | max(other) { |
| 1092 | return other.pos > this.pos ? other : this; |
| 1093 | } |
| 1094 | /** |
| 1095 | Return the smaller of this and the given position. |
| 1096 | */ |
| 1097 | min(other) { |
| 1098 | return other.pos < this.pos ? other : this; |
| 1099 | } |
| 1100 | /** |
| 1101 | @internal |
| 1102 | */ |
| 1103 | toString() { |
| 1104 | let str = ""; |
| 1105 | for (let i2 = 1; i2 <= this.depth; i2++) |
| 1106 | str += (str ? "/" : "") + this.node(i2).type.name + "_" + this.index(i2 - 1); |
| 1107 | return str + ":" + this.parentOffset; |
| 1108 | } |
| 1109 | /** |
| 1110 | @internal |
| 1111 | */ |
| 1112 | static resolve(doc3, pos) { |
| 1113 | if (!(pos >= 0 && pos <= doc3.content.size)) |
| 1114 | throw new RangeError("Position " + pos + " out of range"); |
| 1115 | let path = []; |
| 1116 | let start = 0, parentOffset = pos; |
| 1117 | for (let node = doc3; ; ) { |
| 1118 | let { index, offset } = node.content.findIndex(parentOffset); |
| 1119 | let rem = parentOffset - offset; |
| 1120 | path.push(node, index, start + offset); |
| 1121 | if (!rem) |
| 1122 | break; |
| 1123 | node = node.child(index); |
| 1124 | if (node.isText) |
| 1125 | break; |
| 1126 | parentOffset = rem - 1; |
| 1127 | start += offset + 1; |
| 1128 | } |
| 1129 | return new _ResolvedPos(pos, path, parentOffset); |
| 1130 | } |
| 1131 | /** |
| 1132 | @internal |
| 1133 | */ |
| 1134 | static resolveCached(doc3, pos) { |
| 1135 | let cache = resolveCache.get(doc3); |
| 1136 | if (cache) { |
| 1137 | for (let i2 = 0; i2 < cache.elts.length; i2++) { |
| 1138 | let elt = cache.elts[i2]; |
| 1139 | if (elt.pos == pos) |
| 1140 | return elt; |
| 1141 | } |
| 1142 | } else { |
| 1143 | resolveCache.set(doc3, cache = new ResolveCache()); |
| 1144 | } |
| 1145 | let result = cache.elts[cache.i] = _ResolvedPos.resolve(doc3, pos); |
| 1146 | cache.i = (cache.i + 1) % resolveCacheSize; |
| 1147 | return result; |
| 1148 | } |
| 1149 | }; |
| 1150 | var ResolveCache = class { |
| 1151 | constructor() { |
| 1152 | this.elts = []; |
| 1153 | this.i = 0; |
| 1154 | } |
| 1155 | }; |
| 1156 | var resolveCacheSize = 12; |
| 1157 | var resolveCache = /* @__PURE__ */ new WeakMap(); |
| 1158 | var NodeRange = class { |
| 1159 | /** |
| 1160 | Construct a node range. `$from` and `$to` should point into the |
| 1161 | same node until at least the given `depth`, since a node range |
| 1162 | denotes an adjacent set of nodes in a single parent node. |
| 1163 | */ |
| 1164 | constructor($from, $to, depth) { |
| 1165 | this.$from = $from; |
| 1166 | this.$to = $to; |
| 1167 | this.depth = depth; |
| 1168 | } |
| 1169 | /** |
| 1170 | The position at the start of the range. |
| 1171 | */ |
| 1172 | get start() { |
| 1173 | return this.$from.before(this.depth + 1); |
| 1174 | } |
| 1175 | /** |
| 1176 | The position at the end of the range. |
| 1177 | */ |
| 1178 | get end() { |
| 1179 | return this.$to.after(this.depth + 1); |
| 1180 | } |
| 1181 | /** |
| 1182 | The parent node that the range points into. |
| 1183 | */ |
| 1184 | get parent() { |
| 1185 | return this.$from.node(this.depth); |
| 1186 | } |
| 1187 | /** |
| 1188 | The start index of the range in the parent node. |
| 1189 | */ |
| 1190 | get startIndex() { |
| 1191 | return this.$from.index(this.depth); |
| 1192 | } |
| 1193 | /** |
| 1194 | The end index of the range in the parent node. |
| 1195 | */ |
| 1196 | get endIndex() { |
| 1197 | return this.$to.indexAfter(this.depth); |
| 1198 | } |
| 1199 | }; |
| 1200 | var emptyAttrs = /* @__PURE__ */ Object.create(null); |
| 1201 | var Node = class _Node { |
| 1202 | /** |
| 1203 | @internal |
| 1204 | */ |
| 1205 | constructor(type, attrs2, content, marks = Mark.none) { |
| 1206 | this.type = type; |
| 1207 | this.attrs = attrs2; |
| 1208 | this.marks = marks; |
| 1209 | this.content = content || Fragment.empty; |
| 1210 | } |
| 1211 | /** |
| 1212 | The array of this node's child nodes. |
| 1213 | */ |
| 1214 | get children() { |
| 1215 | return this.content.content; |
| 1216 | } |
| 1217 | /** |
| 1218 | The size of this node, as defined by the integer-based [indexing |
| 1219 | scheme](https://prosemirror.net/docs/guide/#doc.indexing). For text nodes, this is the |
| 1220 | amount of characters. For other leaf nodes, it is one. For |
| 1221 | non-leaf nodes, it is the size of the content plus two (the |
| 1222 | start and end token). |
| 1223 | */ |
| 1224 | get nodeSize() { |
| 1225 | return this.isLeaf ? 1 : 2 + this.content.size; |
| 1226 | } |
| 1227 | /** |
| 1228 | The number of children that the node has. |
| 1229 | */ |
| 1230 | get childCount() { |
| 1231 | return this.content.childCount; |
| 1232 | } |
| 1233 | /** |
| 1234 | Get the child node at the given index. Raises an error when the |
| 1235 | index is out of range. |
| 1236 | */ |
| 1237 | child(index) { |
| 1238 | return this.content.child(index); |
| 1239 | } |
| 1240 | /** |
| 1241 | Get the child node at the given index, if it exists. |
| 1242 | */ |
| 1243 | maybeChild(index) { |
| 1244 | return this.content.maybeChild(index); |
| 1245 | } |
| 1246 | /** |
| 1247 | Call `f` for every child node, passing the node, its offset |
| 1248 | into this parent node, and its index. |
| 1249 | */ |
| 1250 | forEach(f) { |
| 1251 | this.content.forEach(f); |
| 1252 | } |
| 1253 | /** |
| 1254 | Invoke a callback for all descendant nodes recursively overlapping |
| 1255 | the given two positions that are relative to start of this |
| 1256 | node's content. This includes all ancestors of the nodes |
| 1257 | containing the two positions. The callback is invoked with the |
| 1258 | node, its position relative to the original node (method receiver), |
| 1259 | its parent node, and its child index. When the callback returns |
| 1260 | false for a given node, that node's children will not be |
| 1261 | recursed over. The last parameter can be used to specify a |
| 1262 | starting position to count from. |
| 1263 | */ |
| 1264 | nodesBetween(from2, to, f, startPos = 0) { |
| 1265 | this.content.nodesBetween(from2, to, f, startPos, this); |
| 1266 | } |
| 1267 | /** |
| 1268 | Call the given callback for every descendant node. Doesn't |
| 1269 | descend into a node when the callback returns `false`. |
| 1270 | */ |
| 1271 | descendants(f) { |
| 1272 | this.nodesBetween(0, this.content.size, f); |
| 1273 | } |
| 1274 | /** |
| 1275 | Concatenates all the text nodes found in this fragment and its |
| 1276 | children. |
| 1277 | */ |
| 1278 | get textContent() { |
| 1279 | return this.isLeaf && this.type.spec.leafText ? this.type.spec.leafText(this) : this.textBetween(0, this.content.size, ""); |
| 1280 | } |
| 1281 | /** |
| 1282 | Get all text between positions `from` and `to`. When |
| 1283 | `blockSeparator` is given, it will be inserted to separate text |
| 1284 | from different block nodes. If `leafText` is given, it'll be |
| 1285 | inserted for every non-text leaf node encountered, otherwise |
| 1286 | [`leafText`](https://prosemirror.net/docs/ref/#model.NodeSpec.leafText) will be used. |
| 1287 | */ |
| 1288 | textBetween(from2, to, blockSeparator, leafText) { |
| 1289 | return this.content.textBetween(from2, to, blockSeparator, leafText); |
| 1290 | } |
| 1291 | /** |
| 1292 | Returns this node's first child, or `null` if there are no |
| 1293 | children. |
| 1294 | */ |
| 1295 | get firstChild() { |
| 1296 | return this.content.firstChild; |
| 1297 | } |
| 1298 | /** |
| 1299 | Returns this node's last child, or `null` if there are no |
| 1300 | children. |
| 1301 | */ |
| 1302 | get lastChild() { |
| 1303 | return this.content.lastChild; |
| 1304 | } |
| 1305 | /** |
| 1306 | Test whether two nodes represent the same piece of document. |
| 1307 | */ |
| 1308 | eq(other) { |
| 1309 | return this == other || this.sameMarkup(other) && this.content.eq(other.content); |
| 1310 | } |
| 1311 | /** |
| 1312 | Compare the markup (type, attributes, and marks) of this node to |
| 1313 | those of another. Returns `true` if both have the same markup. |
| 1314 | */ |
| 1315 | sameMarkup(other) { |
| 1316 | return this.hasMarkup(other.type, other.attrs, other.marks); |
| 1317 | } |
| 1318 | /** |
| 1319 | Check whether this node's markup correspond to the given type, |
| 1320 | attributes, and marks. |
| 1321 | */ |
| 1322 | hasMarkup(type, attrs2, marks) { |
| 1323 | return this.type == type && compareDeep(this.attrs, attrs2 || type.defaultAttrs || emptyAttrs) && Mark.sameSet(this.marks, marks || Mark.none); |
| 1324 | } |
| 1325 | /** |
| 1326 | Create a new node with the same markup as this node, containing |
| 1327 | the given content (or empty, if no content is given). |
| 1328 | */ |
| 1329 | copy(content = null) { |
| 1330 | if (content == this.content) |
| 1331 | return this; |
| 1332 | return new _Node(this.type, this.attrs, content, this.marks); |
| 1333 | } |
| 1334 | /** |
| 1335 | Create a copy of this node, with the given set of marks instead |
| 1336 | of the node's own marks. |
| 1337 | */ |
| 1338 | mark(marks) { |
| 1339 | return marks == this.marks ? this : new _Node(this.type, this.attrs, this.content, marks); |
| 1340 | } |
| 1341 | /** |
| 1342 | Create a copy of this node with only the content between the |
| 1343 | given positions. If `to` is not given, it defaults to the end of |
| 1344 | the node. |
| 1345 | */ |
| 1346 | cut(from2, to = this.content.size) { |
| 1347 | if (from2 == 0 && to == this.content.size) |
| 1348 | return this; |
| 1349 | return this.copy(this.content.cut(from2, to)); |
| 1350 | } |
| 1351 | /** |
| 1352 | Cut out the part of the document between the given positions, and |
| 1353 | return it as a `Slice` object. |
| 1354 | */ |
| 1355 | slice(from2, to = this.content.size, includeParents = false) { |
| 1356 | if (from2 == to) |
| 1357 | return Slice.empty; |
| 1358 | let $from = this.resolve(from2), $to = this.resolve(to); |
| 1359 | let depth = includeParents ? 0 : $from.sharedDepth(to); |
| 1360 | let start = $from.start(depth), node = $from.node(depth); |
| 1361 | let content = node.content.cut($from.pos - start, $to.pos - start); |
| 1362 | return new Slice(content, $from.depth - depth, $to.depth - depth); |
| 1363 | } |
| 1364 | /** |
| 1365 | Replace the part of the document between the given positions with |
| 1366 | the given slice. The slice must 'fit', meaning its open sides |
| 1367 | must be able to connect to the surrounding content, and its |
| 1368 | content nodes must be valid children for the node they are placed |
| 1369 | into. If any of this is violated, an error of type |
| 1370 | [`ReplaceError`](https://prosemirror.net/docs/ref/#model.ReplaceError) is thrown. |
| 1371 | */ |
| 1372 | replace(from2, to, slice2) { |
| 1373 | return replace(this.resolve(from2), this.resolve(to), slice2); |
| 1374 | } |
| 1375 | /** |
| 1376 | Find the node directly after the given position. |
| 1377 | */ |
| 1378 | nodeAt(pos) { |
| 1379 | for (let node = this; ; ) { |
| 1380 | let { index, offset } = node.content.findIndex(pos); |
| 1381 | node = node.maybeChild(index); |
| 1382 | if (!node) |
| 1383 | return null; |
| 1384 | if (offset == pos || node.isText) |
| 1385 | return node; |
| 1386 | pos -= offset + 1; |
| 1387 | } |
| 1388 | } |
| 1389 | /** |
| 1390 | Find the (direct) child node after the given offset, if any, |
| 1391 | and return it along with its index and offset relative to this |
| 1392 | node. |
| 1393 | */ |
| 1394 | childAfter(pos) { |
| 1395 | let { index, offset } = this.content.findIndex(pos); |
| 1396 | return { node: this.content.maybeChild(index), index, offset }; |
| 1397 | } |
| 1398 | /** |
| 1399 | Find the (direct) child node before the given offset, if any, |
| 1400 | and return it along with its index and offset relative to this |
| 1401 | node. |
| 1402 | */ |
| 1403 | childBefore(pos) { |
| 1404 | if (pos == 0) |
| 1405 | return { node: null, index: 0, offset: 0 }; |
| 1406 | let { index, offset } = this.content.findIndex(pos); |
| 1407 | if (offset < pos) |
| 1408 | return { node: this.content.child(index), index, offset }; |
| 1409 | let node = this.content.child(index - 1); |
| 1410 | return { node, index: index - 1, offset: offset - node.nodeSize }; |
| 1411 | } |
| 1412 | /** |
| 1413 | Resolve the given position in the document, returning an |
| 1414 | [object](https://prosemirror.net/docs/ref/#model.ResolvedPos) with information about its context. |
| 1415 | */ |
| 1416 | resolve(pos) { |
| 1417 | return ResolvedPos.resolveCached(this, pos); |
| 1418 | } |
| 1419 | /** |
| 1420 | @internal |
| 1421 | */ |
| 1422 | resolveNoCache(pos) { |
| 1423 | return ResolvedPos.resolve(this, pos); |
| 1424 | } |
| 1425 | /** |
| 1426 | Test whether a given mark or mark type occurs in this document |
| 1427 | between the two given positions. |
| 1428 | */ |
| 1429 | rangeHasMark(from2, to, type) { |
| 1430 | let found2 = false; |
| 1431 | if (to > from2) |
| 1432 | this.nodesBetween(from2, to, (node) => { |
| 1433 | if (type.isInSet(node.marks)) |
| 1434 | found2 = true; |
| 1435 | return !found2; |
| 1436 | }); |
| 1437 | return found2; |
| 1438 | } |
| 1439 | /** |
| 1440 | True when this is a block (non-inline node) |
| 1441 | */ |
| 1442 | get isBlock() { |
| 1443 | return this.type.isBlock; |
| 1444 | } |
| 1445 | /** |
| 1446 | True when this is a textblock node, a block node with inline |
| 1447 | content. |
| 1448 | */ |
| 1449 | get isTextblock() { |
| 1450 | return this.type.isTextblock; |
| 1451 | } |
| 1452 | /** |
| 1453 | True when this node allows inline content. |
| 1454 | */ |
| 1455 | get inlineContent() { |
| 1456 | return this.type.inlineContent; |
| 1457 | } |
| 1458 | /** |
| 1459 | True when this is an inline node (a text node or a node that can |
| 1460 | appear among text). |
| 1461 | */ |
| 1462 | get isInline() { |
| 1463 | return this.type.isInline; |
| 1464 | } |
| 1465 | /** |
| 1466 | True when this is a text node. |
| 1467 | */ |
| 1468 | get isText() { |
| 1469 | return this.type.isText; |
| 1470 | } |
| 1471 | /** |
| 1472 | True when this is a leaf node. |
| 1473 | */ |
| 1474 | get isLeaf() { |
| 1475 | return this.type.isLeaf; |
| 1476 | } |
| 1477 | /** |
| 1478 | True when this is an atom, i.e. when it does not have directly |
| 1479 | editable content. This is usually the same as `isLeaf`, but can |
| 1480 | be configured with the [`atom` property](https://prosemirror.net/docs/ref/#model.NodeSpec.atom) |
| 1481 | on a node's spec (typically used when the node is displayed as |
| 1482 | an uneditable [node view](https://prosemirror.net/docs/ref/#view.NodeView)). |
| 1483 | */ |
| 1484 | get isAtom() { |
| 1485 | return this.type.isAtom; |
| 1486 | } |
| 1487 | /** |
| 1488 | Return a string representation of this node for debugging |
| 1489 | purposes. |
| 1490 | */ |
| 1491 | toString() { |
| 1492 | if (this.type.spec.toDebugString) |
| 1493 | return this.type.spec.toDebugString(this); |
| 1494 | let name = this.type.name; |
| 1495 | if (this.content.size) |
| 1496 | name += "(" + this.content.toStringInner() + ")"; |
| 1497 | return wrapMarks(this.marks, name); |
| 1498 | } |
| 1499 | /** |
| 1500 | Get the content match in this node at the given index. |
| 1501 | */ |
| 1502 | contentMatchAt(index) { |
| 1503 | let match = this.type.contentMatch.matchFragment(this.content, 0, index); |
| 1504 | if (!match) |
| 1505 | throw new Error("Called contentMatchAt on a node with invalid content"); |
| 1506 | return match; |
| 1507 | } |
| 1508 | /** |
| 1509 | Test whether replacing the range between `from` and `to` (by |
| 1510 | child index) with the given replacement fragment (which defaults |
| 1511 | to the empty fragment) would leave the node's content valid. You |
| 1512 | can optionally pass `start` and `end` indices into the |
| 1513 | replacement fragment. |
| 1514 | */ |
| 1515 | canReplace(from2, to, replacement = Fragment.empty, start = 0, end = replacement.childCount) { |
| 1516 | let one = this.contentMatchAt(from2).matchFragment(replacement, start, end); |
| 1517 | let two = one && one.matchFragment(this.content, to); |
| 1518 | if (!two || !two.validEnd) |
| 1519 | return false; |
| 1520 | for (let i2 = start; i2 < end; i2++) |
| 1521 | if (!this.type.allowsMarks(replacement.child(i2).marks)) |
| 1522 | return false; |
| 1523 | return true; |
| 1524 | } |
| 1525 | /** |
| 1526 | Test whether replacing the range `from` to `to` (by index) with |
| 1527 | a node of the given type would leave the node's content valid. |
| 1528 | */ |
| 1529 | canReplaceWith(from2, to, type, marks) { |
| 1530 | if (marks && !this.type.allowsMarks(marks)) |
| 1531 | return false; |
| 1532 | let start = this.contentMatchAt(from2).matchType(type); |
| 1533 | let end = start && start.matchFragment(this.content, to); |
| 1534 | return end ? end.validEnd : false; |
| 1535 | } |
| 1536 | /** |
| 1537 | Test whether the given node's content could be appended to this |
| 1538 | node. If that node is empty, this will only return true if there |
| 1539 | is at least one node type that can appear in both nodes (to avoid |
| 1540 | merging completely incompatible nodes). |
| 1541 | */ |
| 1542 | canAppend(other) { |
| 1543 | if (other.content.size) |
| 1544 | return this.canReplace(this.childCount, this.childCount, other.content); |
| 1545 | else |
| 1546 | return this.type.compatibleContent(other.type); |
| 1547 | } |
| 1548 | /** |
| 1549 | Check whether this node and its descendants conform to the |
| 1550 | schema, and raise an exception when they do not. |
| 1551 | */ |
| 1552 | check() { |
| 1553 | this.type.checkContent(this.content); |
| 1554 | this.type.checkAttrs(this.attrs); |
| 1555 | let copy2 = Mark.none; |
| 1556 | for (let i2 = 0; i2 < this.marks.length; i2++) { |
| 1557 | let mark = this.marks[i2]; |
| 1558 | mark.type.checkAttrs(mark.attrs); |
| 1559 | copy2 = mark.addToSet(copy2); |
| 1560 | } |
| 1561 | if (!Mark.sameSet(copy2, this.marks)) |
| 1562 | throw new RangeError(`Invalid collection of marks for node ${this.type.name}: ${this.marks.map((m) => m.type.name)}`); |
| 1563 | this.content.forEach((node) => node.check()); |
| 1564 | } |
| 1565 | /** |
| 1566 | Return a JSON-serializeable representation of this node. |
| 1567 | */ |
| 1568 | toJSON() { |
| 1569 | let obj = { type: this.type.name }; |
| 1570 | for (let _ in this.attrs) { |
| 1571 | obj.attrs = this.attrs; |
| 1572 | break; |
| 1573 | } |
| 1574 | if (this.content.size) |
| 1575 | obj.content = this.content.toJSON(); |
| 1576 | if (this.marks.length) |
| 1577 | obj.marks = this.marks.map((n) => n.toJSON()); |
| 1578 | return obj; |
| 1579 | } |
| 1580 | /** |
| 1581 | Deserialize a node from its JSON representation. |
| 1582 | */ |
| 1583 | static fromJSON(schema2, json) { |
| 1584 | if (!json) |
| 1585 | throw new RangeError("Invalid input for Node.fromJSON"); |
| 1586 | let marks = void 0; |
| 1587 | if (json.marks) { |
| 1588 | if (!Array.isArray(json.marks)) |
| 1589 | throw new RangeError("Invalid mark data for Node.fromJSON"); |
| 1590 | marks = json.marks.map(schema2.markFromJSON); |
| 1591 | } |
| 1592 | if (json.type == "text") { |
| 1593 | if (typeof json.text != "string") |
| 1594 | throw new RangeError("Invalid text node in JSON"); |
| 1595 | return schema2.text(json.text, marks); |
| 1596 | } |
| 1597 | let content = Fragment.fromJSON(schema2, json.content); |
| 1598 | let node = schema2.nodeType(json.type).create(json.attrs, content, marks); |
| 1599 | node.type.checkAttrs(node.attrs); |
| 1600 | return node; |
| 1601 | } |
| 1602 | }; |
| 1603 | Node.prototype.text = void 0; |
| 1604 | var TextNode = class _TextNode extends Node { |
| 1605 | /** |
| 1606 | @internal |
| 1607 | */ |
| 1608 | constructor(type, attrs2, content, marks) { |
| 1609 | super(type, attrs2, null, marks); |
| 1610 | if (!content) |
| 1611 | throw new RangeError("Empty text nodes are not allowed"); |
| 1612 | this.text = content; |
| 1613 | } |
| 1614 | toString() { |
| 1615 | if (this.type.spec.toDebugString) |
| 1616 | return this.type.spec.toDebugString(this); |
| 1617 | return wrapMarks(this.marks, JSON.stringify(this.text)); |
| 1618 | } |
| 1619 | get textContent() { |
| 1620 | return this.text; |
| 1621 | } |
| 1622 | textBetween(from2, to) { |
| 1623 | return this.text.slice(from2, to); |
| 1624 | } |
| 1625 | get nodeSize() { |
| 1626 | return this.text.length; |
| 1627 | } |
| 1628 | mark(marks) { |
| 1629 | return marks == this.marks ? this : new _TextNode(this.type, this.attrs, this.text, marks); |
| 1630 | } |
| 1631 | withText(text) { |
| 1632 | if (text == this.text) |
| 1633 | return this; |
| 1634 | return new _TextNode(this.type, this.attrs, text, this.marks); |
| 1635 | } |
| 1636 | cut(from2 = 0, to = this.text.length) { |
| 1637 | if (from2 == 0 && to == this.text.length) |
| 1638 | return this; |
| 1639 | return this.withText(this.text.slice(from2, to)); |
| 1640 | } |
| 1641 | eq(other) { |
| 1642 | return this.sameMarkup(other) && this.text == other.text; |
| 1643 | } |
| 1644 | toJSON() { |
| 1645 | let base2 = super.toJSON(); |
| 1646 | base2.text = this.text; |
| 1647 | return base2; |
| 1648 | } |
| 1649 | }; |
| 1650 | function wrapMarks(marks, str) { |
| 1651 | for (let i2 = marks.length - 1; i2 >= 0; i2--) |
| 1652 | str = marks[i2].type.name + "(" + str + ")"; |
| 1653 | return str; |
| 1654 | } |
| 1655 | var ContentMatch = class _ContentMatch { |
| 1656 | /** |
| 1657 | @internal |
| 1658 | */ |
| 1659 | constructor(validEnd) { |
| 1660 | this.validEnd = validEnd; |
| 1661 | this.next = []; |
| 1662 | this.wrapCache = []; |
| 1663 | } |
| 1664 | /** |
| 1665 | @internal |
| 1666 | */ |
| 1667 | static parse(string, nodeTypes) { |
| 1668 | let stream = new TokenStream(string, nodeTypes); |
| 1669 | if (stream.next == null) |
| 1670 | return _ContentMatch.empty; |
| 1671 | let expr = parseExpr(stream); |
| 1672 | if (stream.next) |
| 1673 | stream.err("Unexpected trailing text"); |
| 1674 | let match = dfa(nfa(expr)); |
| 1675 | checkForDeadEnds(match, stream); |
| 1676 | return match; |
| 1677 | } |
| 1678 | /** |
| 1679 | Match a node type, returning a match after that node if |
| 1680 | successful. |
| 1681 | */ |
| 1682 | matchType(type) { |
| 1683 | for (let i2 = 0; i2 < this.next.length; i2++) |
| 1684 | if (this.next[i2].type == type) |
| 1685 | return this.next[i2].next; |
| 1686 | return null; |
| 1687 | } |
| 1688 | /** |
| 1689 | Try to match a fragment. Returns the resulting match when |
| 1690 | successful. |
| 1691 | */ |
| 1692 | matchFragment(frag, start = 0, end = frag.childCount) { |
| 1693 | let cur = this; |
| 1694 | for (let i2 = start; cur && i2 < end; i2++) |
| 1695 | cur = cur.matchType(frag.child(i2).type); |
| 1696 | return cur; |
| 1697 | } |
| 1698 | /** |
| 1699 | @internal |
| 1700 | */ |
| 1701 | get inlineContent() { |
| 1702 | return this.next.length != 0 && this.next[0].type.isInline; |
| 1703 | } |
| 1704 | /** |
| 1705 | Get the first matching node type at this match position that can |
| 1706 | be generated. |
| 1707 | */ |
| 1708 | get defaultType() { |
| 1709 | for (let i2 = 0; i2 < this.next.length; i2++) { |
| 1710 | let { type } = this.next[i2]; |
| 1711 | if (!(type.isText || type.hasRequiredAttrs())) |
| 1712 | return type; |
| 1713 | } |
| 1714 | return null; |
| 1715 | } |
| 1716 | /** |
| 1717 | @internal |
| 1718 | */ |
| 1719 | compatible(other) { |
| 1720 | for (let i2 = 0; i2 < this.next.length; i2++) |
| 1721 | for (let j = 0; j < other.next.length; j++) |
| 1722 | if (this.next[i2].type == other.next[j].type) |
| 1723 | return true; |
| 1724 | return false; |
| 1725 | } |
| 1726 | /** |
| 1727 | Try to match the given fragment, and if that fails, see if it can |
| 1728 | be made to match by inserting nodes in front of it. When |
| 1729 | successful, return a fragment of inserted nodes (which may be |
| 1730 | empty if nothing had to be inserted). When `toEnd` is true, only |
| 1731 | return a fragment if the resulting match goes to the end of the |
| 1732 | content expression. |
| 1733 | */ |
| 1734 | fillBefore(after, toEnd = false, startIndex = 0) { |
| 1735 | let seen = [this]; |
| 1736 | function search(match, types) { |
| 1737 | let finished = match.matchFragment(after, startIndex); |
| 1738 | if (finished && (!toEnd || finished.validEnd)) |
| 1739 | return Fragment.from(types.map((tp) => tp.createAndFill())); |
| 1740 | for (let i2 = 0; i2 < match.next.length; i2++) { |
| 1741 | let { type, next } = match.next[i2]; |
| 1742 | if (!(type.isText || type.hasRequiredAttrs()) && seen.indexOf(next) == -1) { |
| 1743 | seen.push(next); |
| 1744 | let found2 = search(next, types.concat(type)); |
| 1745 | if (found2) |
| 1746 | return found2; |
| 1747 | } |
| 1748 | } |
| 1749 | return null; |
| 1750 | } |
| 1751 | return search(this, []); |
| 1752 | } |
| 1753 | /** |
| 1754 | Find a set of wrapping node types that would allow a node of the |
| 1755 | given type to appear at this position. The result may be empty |
| 1756 | (when it fits directly) and will be null when no such wrapping |
| 1757 | exists. |
| 1758 | */ |
| 1759 | findWrapping(target) { |
| 1760 | for (let i2 = 0; i2 < this.wrapCache.length; i2 += 2) |
| 1761 | if (this.wrapCache[i2] == target) |
| 1762 | return this.wrapCache[i2 + 1]; |
| 1763 | let computed = this.computeWrapping(target); |
| 1764 | this.wrapCache.push(target, computed); |
| 1765 | return computed; |
| 1766 | } |
| 1767 | /** |
| 1768 | @internal |
| 1769 | */ |
| 1770 | computeWrapping(target) { |
| 1771 | let seen = /* @__PURE__ */ Object.create(null), active = [{ match: this, type: null, via: null }]; |
| 1772 | while (active.length) { |
| 1773 | let current = active.shift(), match = current.match; |
| 1774 | if (match.matchType(target)) { |
| 1775 | let result = []; |
| 1776 | for (let obj = current; obj.type; obj = obj.via) |
| 1777 | result.push(obj.type); |
| 1778 | return result.reverse(); |
| 1779 | } |
| 1780 | for (let i2 = 0; i2 < match.next.length; i2++) { |
| 1781 | let { type, next } = match.next[i2]; |
| 1782 | if (!type.isLeaf && !type.hasRequiredAttrs() && !(type.name in seen) && (!current.type || next.validEnd)) { |
| 1783 | active.push({ match: type.contentMatch, type, via: current }); |
| 1784 | seen[type.name] = true; |
| 1785 | } |
| 1786 | } |
| 1787 | } |
| 1788 | return null; |
| 1789 | } |
| 1790 | /** |
| 1791 | The number of outgoing edges this node has in the finite |
| 1792 | automaton that describes the content expression. |
| 1793 | */ |
| 1794 | get edgeCount() { |
| 1795 | return this.next.length; |
| 1796 | } |
| 1797 | /** |
| 1798 | Get the _n_βth outgoing edge from this node in the finite |
| 1799 | automaton that describes the content expression. |
| 1800 | */ |
| 1801 | edge(n) { |
| 1802 | if (n >= this.next.length) |
| 1803 | throw new RangeError(`There's no ${n}th edge in this content match`); |
| 1804 | return this.next[n]; |
| 1805 | } |
| 1806 | /** |
| 1807 | @internal |
| 1808 | */ |
| 1809 | toString() { |
| 1810 | let seen = []; |
| 1811 | function scan(m) { |
| 1812 | seen.push(m); |
| 1813 | for (let i2 = 0; i2 < m.next.length; i2++) |
| 1814 | if (seen.indexOf(m.next[i2].next) == -1) |
| 1815 | scan(m.next[i2].next); |
| 1816 | } |
| 1817 | scan(this); |
| 1818 | return seen.map((m, i2) => { |
| 1819 | let out = i2 + (m.validEnd ? "*" : " ") + " "; |
| 1820 | for (let i3 = 0; i3 < m.next.length; i3++) |
| 1821 | out += (i3 ? ", " : "") + m.next[i3].type.name + "->" + seen.indexOf(m.next[i3].next); |
| 1822 | return out; |
| 1823 | }).join("\n"); |
| 1824 | } |
| 1825 | }; |
| 1826 | ContentMatch.empty = new ContentMatch(true); |
| 1827 | var TokenStream = class { |
| 1828 | constructor(string, nodeTypes) { |
| 1829 | this.string = string; |
| 1830 | this.nodeTypes = nodeTypes; |
| 1831 | this.inline = null; |
| 1832 | this.pos = 0; |
| 1833 | this.tokens = string.split(/\s*(?=\b|\W|$)/); |
| 1834 | if (this.tokens[this.tokens.length - 1] == "") |
| 1835 | this.tokens.pop(); |
| 1836 | if (this.tokens[0] == "") |
| 1837 | this.tokens.shift(); |
| 1838 | } |
| 1839 | get next() { |
| 1840 | return this.tokens[this.pos]; |
| 1841 | } |
| 1842 | eat(tok) { |
| 1843 | return this.next == tok && (this.pos++ || true); |
| 1844 | } |
| 1845 | err(str) { |
| 1846 | throw new SyntaxError(str + " (in content expression '" + this.string + "')"); |
| 1847 | } |
| 1848 | }; |
| 1849 | function parseExpr(stream) { |
| 1850 | let exprs = []; |
| 1851 | do { |
| 1852 | exprs.push(parseExprSeq(stream)); |
| 1853 | } while (stream.eat("|")); |
| 1854 | return exprs.length == 1 ? exprs[0] : { type: "choice", exprs }; |
| 1855 | } |
| 1856 | function parseExprSeq(stream) { |
| 1857 | let exprs = []; |
| 1858 | do { |
| 1859 | exprs.push(parseExprSubscript(stream)); |
| 1860 | } while (stream.next && stream.next != ")" && stream.next != "|"); |
| 1861 | return exprs.length == 1 ? exprs[0] : { type: "seq", exprs }; |
| 1862 | } |
| 1863 | function parseExprSubscript(stream) { |
| 1864 | let expr = parseExprAtom(stream); |
| 1865 | for (; ; ) { |
| 1866 | if (stream.eat("+")) |
| 1867 | expr = { type: "plus", expr }; |
| 1868 | else if (stream.eat("*")) |
| 1869 | expr = { type: "star", expr }; |
| 1870 | else if (stream.eat("?")) |
| 1871 | expr = { type: "opt", expr }; |
| 1872 | else if (stream.eat("{")) |
| 1873 | expr = parseExprRange(stream, expr); |
| 1874 | else |
| 1875 | break; |
| 1876 | } |
| 1877 | return expr; |
| 1878 | } |
| 1879 | function parseNum(stream) { |
| 1880 | if (/\D/.test(stream.next)) |
| 1881 | stream.err("Expected number, got '" + stream.next + "'"); |
| 1882 | let result = Number(stream.next); |
| 1883 | stream.pos++; |
| 1884 | return result; |
| 1885 | } |
| 1886 | function parseExprRange(stream, expr) { |
| 1887 | let min = parseNum(stream), max = min; |
| 1888 | if (stream.eat(",")) { |
| 1889 | if (stream.next != "}") |
| 1890 | max = parseNum(stream); |
| 1891 | else |
| 1892 | max = -1; |
| 1893 | } |
| 1894 | if (!stream.eat("}")) |
| 1895 | stream.err("Unclosed braced range"); |
| 1896 | return { type: "range", min, max, expr }; |
| 1897 | } |
| 1898 | function resolveName(stream, name) { |
| 1899 | let types = stream.nodeTypes, type = types[name]; |
| 1900 | if (type) |
| 1901 | return [type]; |
| 1902 | let result = []; |
| 1903 | for (let typeName in types) { |
| 1904 | let type2 = types[typeName]; |
| 1905 | if (type2.isInGroup(name)) |
| 1906 | result.push(type2); |
| 1907 | } |
| 1908 | if (result.length == 0) |
| 1909 | stream.err("No node type or group '" + name + "' found"); |
| 1910 | return result; |
| 1911 | } |
| 1912 | function parseExprAtom(stream) { |
| 1913 | if (stream.eat("(")) { |
| 1914 | let expr = parseExpr(stream); |
| 1915 | if (!stream.eat(")")) |
| 1916 | stream.err("Missing closing paren"); |
| 1917 | return expr; |
| 1918 | } else if (!/\W/.test(stream.next)) { |
| 1919 | let exprs = resolveName(stream, stream.next).map((type) => { |
| 1920 | if (stream.inline == null) |
| 1921 | stream.inline = type.isInline; |
| 1922 | else if (stream.inline != type.isInline) |
| 1923 | stream.err("Mixing inline and block content"); |
| 1924 | return { type: "name", value: type }; |
| 1925 | }); |
| 1926 | stream.pos++; |
| 1927 | return exprs.length == 1 ? exprs[0] : { type: "choice", exprs }; |
| 1928 | } else { |
| 1929 | stream.err("Unexpected token '" + stream.next + "'"); |
| 1930 | } |
| 1931 | } |
| 1932 | function nfa(expr) { |
| 1933 | let nfa2 = [[]]; |
| 1934 | connect(compile(expr, 0), node()); |
| 1935 | return nfa2; |
| 1936 | function node() { |
| 1937 | return nfa2.push([]) - 1; |
| 1938 | } |
| 1939 | function edge(from2, to, term) { |
| 1940 | let edge2 = { term, to }; |
| 1941 | nfa2[from2].push(edge2); |
| 1942 | return edge2; |
| 1943 | } |
| 1944 | function connect(edges, to) { |
| 1945 | edges.forEach((edge2) => edge2.to = to); |
| 1946 | } |
| 1947 | function compile(expr2, from2) { |
| 1948 | if (expr2.type == "choice") { |
| 1949 | return expr2.exprs.reduce((out, expr3) => out.concat(compile(expr3, from2)), []); |
| 1950 | } else if (expr2.type == "seq") { |
| 1951 | for (let i2 = 0; ; i2++) { |
| 1952 | let next = compile(expr2.exprs[i2], from2); |
| 1953 | if (i2 == expr2.exprs.length - 1) |
| 1954 | return next; |
| 1955 | connect(next, from2 = node()); |
| 1956 | } |
| 1957 | } else if (expr2.type == "star") { |
| 1958 | let loop = node(); |
| 1959 | edge(from2, loop); |
| 1960 | connect(compile(expr2.expr, loop), loop); |
| 1961 | return [edge(loop)]; |
| 1962 | } else if (expr2.type == "plus") { |
| 1963 | let loop = node(); |
| 1964 | connect(compile(expr2.expr, from2), loop); |
| 1965 | connect(compile(expr2.expr, loop), loop); |
| 1966 | return [edge(loop)]; |
| 1967 | } else if (expr2.type == "opt") { |
| 1968 | return [edge(from2)].concat(compile(expr2.expr, from2)); |
| 1969 | } else if (expr2.type == "range") { |
| 1970 | let cur = from2; |
| 1971 | for (let i2 = 0; i2 < expr2.min; i2++) { |
| 1972 | let next = node(); |
| 1973 | connect(compile(expr2.expr, cur), next); |
| 1974 | cur = next; |
| 1975 | } |
| 1976 | if (expr2.max == -1) { |
| 1977 | connect(compile(expr2.expr, cur), cur); |
| 1978 | } else { |
| 1979 | for (let i2 = expr2.min; i2 < expr2.max; i2++) { |
| 1980 | let next = node(); |
| 1981 | edge(cur, next); |
| 1982 | connect(compile(expr2.expr, cur), next); |
| 1983 | cur = next; |
| 1984 | } |
| 1985 | } |
| 1986 | return [edge(cur)]; |
| 1987 | } else if (expr2.type == "name") { |
| 1988 | return [edge(from2, void 0, expr2.value)]; |
| 1989 | } else { |
| 1990 | throw new Error("Unknown expr type"); |
| 1991 | } |
| 1992 | } |
| 1993 | } |
| 1994 | function cmp(a, b) { |
| 1995 | return b - a; |
| 1996 | } |
| 1997 | function nullFrom(nfa2, node) { |
| 1998 | let result = []; |
| 1999 | scan(node); |
| 2000 | return result.sort(cmp); |
| 2001 | function scan(node2) { |
| 2002 | let edges = nfa2[node2]; |
| 2003 | if (edges.length == 1 && !edges[0].term) |
| 2004 | return scan(edges[0].to); |
| 2005 | result.push(node2); |
| 2006 | for (let i2 = 0; i2 < edges.length; i2++) { |
| 2007 | let { term, to } = edges[i2]; |
| 2008 | if (!term && result.indexOf(to) == -1) |
| 2009 | scan(to); |
| 2010 | } |
| 2011 | } |
| 2012 | } |
| 2013 | function dfa(nfa2) { |
| 2014 | let labeled = /* @__PURE__ */ Object.create(null); |
| 2015 | return explore(nullFrom(nfa2, 0)); |
| 2016 | function explore(states) { |
| 2017 | let out = []; |
| 2018 | states.forEach((node) => { |
| 2019 | nfa2[node].forEach(({ term, to }) => { |
| 2020 | if (!term) |
| 2021 | return; |
| 2022 | let set; |
| 2023 | for (let i2 = 0; i2 < out.length; i2++) |
| 2024 | if (out[i2][0] == term) |
| 2025 | set = out[i2][1]; |
| 2026 | nullFrom(nfa2, to).forEach((node2) => { |
| 2027 | if (!set) |
| 2028 | out.push([term, set = []]); |
| 2029 | if (set.indexOf(node2) == -1) |
| 2030 | set.push(node2); |
| 2031 | }); |
| 2032 | }); |
| 2033 | }); |
| 2034 | let state = labeled[states.join(",")] = new ContentMatch(states.indexOf(nfa2.length - 1) > -1); |
| 2035 | for (let i2 = 0; i2 < out.length; i2++) { |
| 2036 | let states2 = out[i2][1].sort(cmp); |
| 2037 | state.next.push({ type: out[i2][0], next: labeled[states2.join(",")] || explore(states2) }); |
| 2038 | } |
| 2039 | return state; |
| 2040 | } |
| 2041 | } |
| 2042 | function checkForDeadEnds(match, stream) { |
| 2043 | for (let i2 = 0, work = [match]; i2 < work.length; i2++) { |
| 2044 | let state = work[i2], dead = !state.validEnd, nodes = []; |
| 2045 | for (let j = 0; j < state.next.length; j++) { |
| 2046 | let { type, next } = state.next[j]; |
| 2047 | nodes.push(type.name); |
| 2048 | if (dead && !(type.isText || type.hasRequiredAttrs())) |
| 2049 | dead = false; |
| 2050 | if (work.indexOf(next) == -1) |
| 2051 | work.push(next); |
| 2052 | } |
| 2053 | if (dead) |
| 2054 | stream.err("Only non-generatable nodes (" + nodes.join(", ") + ") in a required position (see https://prosemirror.net/docs/guide/#generatable)"); |
| 2055 | } |
| 2056 | } |
| 2057 | function defaultAttrs(attrs2) { |
| 2058 | let defaults = /* @__PURE__ */ Object.create(null); |
| 2059 | for (let attrName in attrs2) { |
| 2060 | let attr = attrs2[attrName]; |
| 2061 | if (!attr.hasDefault) |
| 2062 | return null; |
| 2063 | defaults[attrName] = attr.default; |
| 2064 | } |
| 2065 | return defaults; |
| 2066 | } |
| 2067 | function computeAttrs(attrs2, value) { |
| 2068 | let built = /* @__PURE__ */ Object.create(null); |
| 2069 | for (let name in attrs2) { |
| 2070 | let given = value && value[name]; |
| 2071 | if (given === void 0) { |
| 2072 | let attr = attrs2[name]; |
| 2073 | if (attr.hasDefault) |
| 2074 | given = attr.default; |
| 2075 | else |
| 2076 | throw new RangeError("No value supplied for attribute " + name); |
| 2077 | } |
| 2078 | built[name] = given; |
| 2079 | } |
| 2080 | return built; |
| 2081 | } |
| 2082 | function checkAttrs(attrs2, values, type, name) { |
| 2083 | for (let attr in values) |
| 2084 | if (!(attr in attrs2)) |
| 2085 | throw new RangeError(`Unsupported attribute ${attr} for ${type} of type ${name}`); |
| 2086 | for (let attr in attrs2) { |
| 2087 | if (attrs2[attr].validate) |
| 2088 | attrs2[attr].validate(values[attr]); |
| 2089 | } |
| 2090 | } |
| 2091 | function initAttrs(typeName, attrs2) { |
| 2092 | let result = /* @__PURE__ */ Object.create(null); |
| 2093 | if (attrs2) |
| 2094 | for (let name in attrs2) |
| 2095 | result[name] = new Attribute(typeName, name, attrs2[name]); |
| 2096 | return result; |
| 2097 | } |
| 2098 | var NodeType = class _NodeType { |
| 2099 | /** |
| 2100 | @internal |
| 2101 | */ |
| 2102 | constructor(name, schema2, spec) { |
| 2103 | this.name = name; |
| 2104 | this.schema = schema2; |
| 2105 | this.spec = spec; |
| 2106 | this.markSet = null; |
| 2107 | this.groups = spec.group ? spec.group.split(" ") : []; |
| 2108 | this.attrs = initAttrs(name, spec.attrs); |
| 2109 | this.defaultAttrs = defaultAttrs(this.attrs); |
| 2110 | this.contentMatch = null; |
| 2111 | this.inlineContent = null; |
| 2112 | this.isBlock = !(spec.inline || name == "text"); |
| 2113 | this.isText = name == "text"; |
| 2114 | } |
| 2115 | /** |
| 2116 | True if this is an inline type. |
| 2117 | */ |
| 2118 | get isInline() { |
| 2119 | return !this.isBlock; |
| 2120 | } |
| 2121 | /** |
| 2122 | True if this is a textblock type, a block that contains inline |
| 2123 | content. |
| 2124 | */ |
| 2125 | get isTextblock() { |
| 2126 | return this.isBlock && this.inlineContent; |
| 2127 | } |
| 2128 | /** |
| 2129 | True for node types that allow no content. |
| 2130 | */ |
| 2131 | get isLeaf() { |
| 2132 | return this.contentMatch == ContentMatch.empty; |
| 2133 | } |
| 2134 | /** |
| 2135 | True when this node is an atom, i.e. when it does not have |
| 2136 | directly editable content. |
| 2137 | */ |
| 2138 | get isAtom() { |
| 2139 | return this.isLeaf || !!this.spec.atom; |
| 2140 | } |
| 2141 | /** |
| 2142 | Return true when this node type is part of the given |
| 2143 | [group](https://prosemirror.net/docs/ref/#model.NodeSpec.group). |
| 2144 | */ |
| 2145 | isInGroup(group) { |
| 2146 | return this.groups.indexOf(group) > -1; |
| 2147 | } |
| 2148 | /** |
| 2149 | The node type's [whitespace](https://prosemirror.net/docs/ref/#model.NodeSpec.whitespace) option. |
| 2150 | */ |
| 2151 | get whitespace() { |
| 2152 | return this.spec.whitespace || (this.spec.code ? "pre" : "normal"); |
| 2153 | } |
| 2154 | /** |
| 2155 | Tells you whether this node type has any required attributes. |
| 2156 | */ |
| 2157 | hasRequiredAttrs() { |
| 2158 | for (let n in this.attrs) |
| 2159 | if (this.attrs[n].isRequired) |
| 2160 | return true; |
| 2161 | return false; |
| 2162 | } |
| 2163 | /** |
| 2164 | Indicates whether this node allows some of the same content as |
| 2165 | the given node type. |
| 2166 | */ |
| 2167 | compatibleContent(other) { |
| 2168 | return this == other || this.contentMatch.compatible(other.contentMatch); |
| 2169 | } |
| 2170 | /** |
| 2171 | @internal |
| 2172 | */ |
| 2173 | computeAttrs(attrs2) { |
| 2174 | if (!attrs2 && this.defaultAttrs) |
| 2175 | return this.defaultAttrs; |
| 2176 | else |
| 2177 | return computeAttrs(this.attrs, attrs2); |
| 2178 | } |
| 2179 | /** |
| 2180 | Create a `Node` of this type. The given attributes are |
| 2181 | checked and defaulted (you can pass `null` to use the type's |
| 2182 | defaults entirely, if no required attributes exist). `content` |
| 2183 | may be a `Fragment`, a node, an array of nodes, or |
| 2184 | `null`. Similarly `marks` may be `null` to default to the empty |
| 2185 | set of marks. |
| 2186 | */ |
| 2187 | create(attrs2 = null, content, marks) { |
| 2188 | if (this.isText) |
| 2189 | throw new Error("NodeType.create can't construct text nodes"); |
| 2190 | return new Node(this, this.computeAttrs(attrs2), Fragment.from(content), Mark.setFrom(marks)); |
| 2191 | } |
| 2192 | /** |
| 2193 | Like [`create`](https://prosemirror.net/docs/ref/#model.NodeType.create), but check the given content |
| 2194 | against the node type's content restrictions, and throw an error |
| 2195 | if it doesn't match. |
| 2196 | */ |
| 2197 | createChecked(attrs2 = null, content, marks) { |
| 2198 | content = Fragment.from(content); |
| 2199 | this.checkContent(content); |
| 2200 | return new Node(this, this.computeAttrs(attrs2), content, Mark.setFrom(marks)); |
| 2201 | } |
| 2202 | /** |
| 2203 | Like [`create`](https://prosemirror.net/docs/ref/#model.NodeType.create), but see if it is |
| 2204 | necessary to add nodes to the start or end of the given fragment |
| 2205 | to make it fit the node. If no fitting wrapping can be found, |
| 2206 | return null. Note that, due to the fact that required nodes can |
| 2207 | always be created, this will always succeed if you pass null or |
| 2208 | `Fragment.empty` as content. |
| 2209 | */ |
| 2210 | createAndFill(attrs2 = null, content, marks) { |
| 2211 | attrs2 = this.computeAttrs(attrs2); |
| 2212 | content = Fragment.from(content); |
| 2213 | if (content.size) { |
| 2214 | let before = this.contentMatch.fillBefore(content); |
| 2215 | if (!before) |
| 2216 | return null; |
| 2217 | content = before.append(content); |
| 2218 | } |
| 2219 | let matched = this.contentMatch.matchFragment(content); |
| 2220 | let after = matched && matched.fillBefore(Fragment.empty, true); |
| 2221 | if (!after) |
| 2222 | return null; |
| 2223 | return new Node(this, attrs2, content.append(after), Mark.setFrom(marks)); |
| 2224 | } |
| 2225 | /** |
| 2226 | Returns true if the given fragment is valid content for this node |
| 2227 | type. |
| 2228 | */ |
| 2229 | validContent(content) { |
| 2230 | let result = this.contentMatch.matchFragment(content); |
| 2231 | if (!result || !result.validEnd) |
| 2232 | return false; |
| 2233 | for (let i2 = 0; i2 < content.childCount; i2++) |
| 2234 | if (!this.allowsMarks(content.child(i2).marks)) |
| 2235 | return false; |
| 2236 | return true; |
| 2237 | } |
| 2238 | /** |
| 2239 | Throws a RangeError if the given fragment is not valid content for this |
| 2240 | node type. |
| 2241 | @internal |
| 2242 | */ |
| 2243 | checkContent(content) { |
| 2244 | if (!this.validContent(content)) |
| 2245 | throw new RangeError(`Invalid content for node ${this.name}: ${content.toString().slice(0, 50)}`); |
| 2246 | } |
| 2247 | /** |
| 2248 | @internal |
| 2249 | */ |
| 2250 | checkAttrs(attrs2) { |
| 2251 | checkAttrs(this.attrs, attrs2, "node", this.name); |
| 2252 | } |
| 2253 | /** |
| 2254 | Check whether the given mark type is allowed in this node. |
| 2255 | */ |
| 2256 | allowsMarkType(markType) { |
| 2257 | return this.markSet == null || this.markSet.indexOf(markType) > -1; |
| 2258 | } |
| 2259 | /** |
| 2260 | Test whether the given set of marks are allowed in this node. |
| 2261 | */ |
| 2262 | allowsMarks(marks) { |
| 2263 | if (this.markSet == null) |
| 2264 | return true; |
| 2265 | for (let i2 = 0; i2 < marks.length; i2++) |
| 2266 | if (!this.allowsMarkType(marks[i2].type)) |
| 2267 | return false; |
| 2268 | return true; |
| 2269 | } |
| 2270 | /** |
| 2271 | Removes the marks that are not allowed in this node from the given set. |
| 2272 | */ |
| 2273 | allowedMarks(marks) { |
| 2274 | if (this.markSet == null) |
| 2275 | return marks; |
| 2276 | let copy2; |
| 2277 | for (let i2 = 0; i2 < marks.length; i2++) { |
| 2278 | if (!this.allowsMarkType(marks[i2].type)) { |
| 2279 | if (!copy2) |
| 2280 | copy2 = marks.slice(0, i2); |
| 2281 | } else if (copy2) { |
| 2282 | copy2.push(marks[i2]); |
| 2283 | } |
| 2284 | } |
| 2285 | return !copy2 ? marks : copy2.length ? copy2 : Mark.none; |
| 2286 | } |
| 2287 | /** |
| 2288 | @internal |
| 2289 | */ |
| 2290 | static compile(nodes, schema2) { |
| 2291 | let result = /* @__PURE__ */ Object.create(null); |
| 2292 | nodes.forEach((name, spec) => result[name] = new _NodeType(name, schema2, spec)); |
| 2293 | let topType = schema2.spec.topNode || "doc"; |
| 2294 | if (!result[topType]) |
| 2295 | throw new RangeError("Schema is missing its top node type ('" + topType + "')"); |
| 2296 | if (!result.text) |
| 2297 | throw new RangeError("Every schema needs a 'text' type"); |
| 2298 | for (let _ in result.text.attrs) |
| 2299 | throw new RangeError("The text node type should not have attributes"); |
| 2300 | return result; |
| 2301 | } |
| 2302 | }; |
| 2303 | function validateType(typeName, attrName, type) { |
| 2304 | let types = type.split("|"); |
| 2305 | return (value) => { |
| 2306 | let name = value === null ? "null" : typeof value; |
| 2307 | if (types.indexOf(name) < 0) |
| 2308 | throw new RangeError(`Expected value of type ${types} for attribute ${attrName} on type ${typeName}, got ${name}`); |
| 2309 | }; |
| 2310 | } |
| 2311 | var Attribute = class { |
| 2312 | constructor(typeName, attrName, options) { |
| 2313 | this.hasDefault = Object.prototype.hasOwnProperty.call(options, "default"); |
| 2314 | this.default = options.default; |
| 2315 | this.validate = typeof options.validate == "string" ? validateType(typeName, attrName, options.validate) : options.validate; |
| 2316 | } |
| 2317 | get isRequired() { |
| 2318 | return !this.hasDefault; |
| 2319 | } |
| 2320 | }; |
| 2321 | var MarkType = class _MarkType { |
| 2322 | /** |
| 2323 | @internal |
| 2324 | */ |
| 2325 | constructor(name, rank, schema2, spec) { |
| 2326 | this.name = name; |
| 2327 | this.rank = rank; |
| 2328 | this.schema = schema2; |
| 2329 | this.spec = spec; |
| 2330 | this.attrs = initAttrs(name, spec.attrs); |
| 2331 | this.excluded = null; |
| 2332 | let defaults = defaultAttrs(this.attrs); |
| 2333 | this.instance = defaults ? new Mark(this, defaults) : null; |
| 2334 | } |
| 2335 | /** |
| 2336 | Create a mark of this type. `attrs` may be `null` or an object |
| 2337 | containing only some of the mark's attributes. The others, if |
| 2338 | they have defaults, will be added. |
| 2339 | */ |
| 2340 | create(attrs2 = null) { |
| 2341 | if (!attrs2 && this.instance) |
| 2342 | return this.instance; |
| 2343 | return new Mark(this, computeAttrs(this.attrs, attrs2)); |
| 2344 | } |
| 2345 | /** |
| 2346 | @internal |
| 2347 | */ |
| 2348 | static compile(marks, schema2) { |
| 2349 | let result = /* @__PURE__ */ Object.create(null), rank = 0; |
| 2350 | marks.forEach((name, spec) => result[name] = new _MarkType(name, rank++, schema2, spec)); |
| 2351 | return result; |
| 2352 | } |
| 2353 | /** |
| 2354 | When there is a mark of this type in the given set, a new set |
| 2355 | without it is returned. Otherwise, the input set is returned. |
| 2356 | */ |
| 2357 | removeFromSet(set) { |
| 2358 | for (var i2 = 0; i2 < set.length; i2++) |
| 2359 | if (set[i2].type == this) { |
| 2360 | set = set.slice(0, i2).concat(set.slice(i2 + 1)); |
| 2361 | i2--; |
| 2362 | } |
| 2363 | return set; |
| 2364 | } |
| 2365 | /** |
| 2366 | Tests whether there is a mark of this type in the given set. |
| 2367 | */ |
| 2368 | isInSet(set) { |
| 2369 | for (let i2 = 0; i2 < set.length; i2++) |
| 2370 | if (set[i2].type == this) |
| 2371 | return set[i2]; |
| 2372 | } |
| 2373 | /** |
| 2374 | @internal |
| 2375 | */ |
| 2376 | checkAttrs(attrs2) { |
| 2377 | checkAttrs(this.attrs, attrs2, "mark", this.name); |
| 2378 | } |
| 2379 | /** |
| 2380 | Queries whether a given mark type is |
| 2381 | [excluded](https://prosemirror.net/docs/ref/#model.MarkSpec.excludes) by this one. |
| 2382 | */ |
| 2383 | excludes(other) { |
| 2384 | return this.excluded.indexOf(other) > -1; |
| 2385 | } |
| 2386 | }; |
| 2387 | var Schema = class { |
| 2388 | /** |
| 2389 | Construct a schema from a schema [specification](https://prosemirror.net/docs/ref/#model.SchemaSpec). |
| 2390 | */ |
| 2391 | constructor(spec) { |
| 2392 | this.linebreakReplacement = null; |
| 2393 | this.cached = /* @__PURE__ */ Object.create(null); |
| 2394 | let instanceSpec = this.spec = {}; |
| 2395 | for (let prop in spec) |
| 2396 | instanceSpec[prop] = spec[prop]; |
| 2397 | instanceSpec.nodes = dist_default.from(spec.nodes), instanceSpec.marks = dist_default.from(spec.marks || {}), this.nodes = NodeType.compile(this.spec.nodes, this); |
| 2398 | this.marks = MarkType.compile(this.spec.marks, this); |
| 2399 | let contentExprCache = /* @__PURE__ */ Object.create(null); |
| 2400 | for (let prop in this.nodes) { |
| 2401 | if (prop in this.marks) |
| 2402 | throw new RangeError(prop + " can not be both a node and a mark"); |
| 2403 | let type = this.nodes[prop], contentExpr = type.spec.content || "", markExpr = type.spec.marks; |
| 2404 | type.contentMatch = contentExprCache[contentExpr] || (contentExprCache[contentExpr] = ContentMatch.parse(contentExpr, this.nodes)); |
| 2405 | type.inlineContent = type.contentMatch.inlineContent; |
| 2406 | if (type.spec.linebreakReplacement) { |
| 2407 | if (this.linebreakReplacement) |
| 2408 | throw new RangeError("Multiple linebreak nodes defined"); |
| 2409 | if (!type.isInline || !type.isLeaf) |
| 2410 | throw new RangeError("Linebreak replacement nodes must be inline leaf nodes"); |
| 2411 | this.linebreakReplacement = type; |
| 2412 | } |
| 2413 | type.markSet = markExpr == "_" ? null : markExpr ? gatherMarks(this, markExpr.split(" ")) : markExpr == "" || !type.inlineContent ? [] : null; |
| 2414 | } |
| 2415 | for (let prop in this.marks) { |
| 2416 | let type = this.marks[prop], excl = type.spec.excludes; |
| 2417 | type.excluded = excl == null ? [type] : excl == "" ? [] : gatherMarks(this, excl.split(" ")); |
| 2418 | } |
| 2419 | this.nodeFromJSON = (json) => Node.fromJSON(this, json); |
| 2420 | this.markFromJSON = (json) => Mark.fromJSON(this, json); |
| 2421 | this.topNodeType = this.nodes[this.spec.topNode || "doc"]; |
| 2422 | this.cached.wrappings = /* @__PURE__ */ Object.create(null); |
| 2423 | } |
| 2424 | /** |
| 2425 | Create a node in this schema. The `type` may be a string or a |
| 2426 | `NodeType` instance. Attributes will be extended with defaults, |
| 2427 | `content` may be a `Fragment`, `null`, a `Node`, or an array of |
| 2428 | nodes. |
| 2429 | */ |
| 2430 | node(type, attrs2 = null, content, marks) { |
| 2431 | if (typeof type == "string") |
| 2432 | type = this.nodeType(type); |
| 2433 | else if (!(type instanceof NodeType)) |
| 2434 | throw new RangeError("Invalid node type: " + type); |
| 2435 | else if (type.schema != this) |
| 2436 | throw new RangeError("Node type from different schema used (" + type.name + ")"); |
| 2437 | return type.createChecked(attrs2, content, marks); |
| 2438 | } |
| 2439 | /** |
| 2440 | Create a text node in the schema. Empty text nodes are not |
| 2441 | allowed. |
| 2442 | */ |
| 2443 | text(text, marks) { |
| 2444 | let type = this.nodes.text; |
| 2445 | return new TextNode(type, type.defaultAttrs, text, Mark.setFrom(marks)); |
| 2446 | } |
| 2447 | /** |
| 2448 | Create a mark with the given type and attributes. |
| 2449 | */ |
| 2450 | mark(type, attrs2) { |
| 2451 | if (typeof type == "string") |
| 2452 | type = this.marks[type]; |
| 2453 | return type.create(attrs2); |
| 2454 | } |
| 2455 | /** |
| 2456 | @internal |
| 2457 | */ |
| 2458 | nodeType(name) { |
| 2459 | let found2 = this.nodes[name]; |
| 2460 | if (!found2) |
| 2461 | throw new RangeError("Unknown node type: " + name); |
| 2462 | return found2; |
| 2463 | } |
| 2464 | }; |
| 2465 | function gatherMarks(schema2, marks) { |
| 2466 | let found2 = []; |
| 2467 | for (let i2 = 0; i2 < marks.length; i2++) { |
| 2468 | let name = marks[i2], mark = schema2.marks[name], ok = mark; |
| 2469 | if (mark) { |
| 2470 | found2.push(mark); |
| 2471 | } else { |
| 2472 | for (let prop in schema2.marks) { |
| 2473 | let mark2 = schema2.marks[prop]; |
| 2474 | if (name == "_" || mark2.spec.group && mark2.spec.group.split(" ").indexOf(name) > -1) |
| 2475 | found2.push(ok = mark2); |
| 2476 | } |
| 2477 | } |
| 2478 | if (!ok) |
| 2479 | throw new SyntaxError("Unknown mark type: '" + marks[i2] + "'"); |
| 2480 | } |
| 2481 | return found2; |
| 2482 | } |
| 2483 | function isTagRule(rule) { |
| 2484 | return rule.tag != null; |
| 2485 | } |
| 2486 | function isStyleRule(rule) { |
| 2487 | return rule.style != null; |
| 2488 | } |
| 2489 | var DOMParser = class _DOMParser { |
| 2490 | /** |
| 2491 | Create a parser that targets the given schema, using the given |
| 2492 | parsing rules. |
| 2493 | */ |
| 2494 | constructor(schema2, rules) { |
| 2495 | this.schema = schema2; |
| 2496 | this.rules = rules; |
| 2497 | this.tags = []; |
| 2498 | this.styles = []; |
| 2499 | let matchedStyles = this.matchedStyles = []; |
| 2500 | rules.forEach((rule) => { |
| 2501 | if (isTagRule(rule)) { |
| 2502 | this.tags.push(rule); |
| 2503 | } else if (isStyleRule(rule)) { |
| 2504 | let prop = /[^=]*/.exec(rule.style)[0]; |
| 2505 | if (matchedStyles.indexOf(prop) < 0) |
| 2506 | matchedStyles.push(prop); |
| 2507 | this.styles.push(rule); |
| 2508 | } |
| 2509 | }); |
| 2510 | this.normalizeLists = !this.tags.some((r) => { |
| 2511 | if (!/^(ul|ol)\b/.test(r.tag) || !r.node) |
| 2512 | return false; |
| 2513 | let node = schema2.nodes[r.node]; |
| 2514 | return node.contentMatch.matchType(node); |
| 2515 | }); |
| 2516 | } |
| 2517 | /** |
| 2518 | Parse a document from the content of a DOM node. |
| 2519 | */ |
| 2520 | parse(dom, options = {}) { |
| 2521 | let context = new ParseContext(this, options, false); |
| 2522 | context.addAll(dom, Mark.none, options.from, options.to); |
| 2523 | return context.finish(); |
| 2524 | } |
| 2525 | /** |
| 2526 | Parses the content of the given DOM node, like |
| 2527 | [`parse`](https://prosemirror.net/docs/ref/#model.DOMParser.parse), and takes the same set of |
| 2528 | options. But unlike that method, which produces a whole node, |
| 2529 | this one returns a slice that is open at the sides, meaning that |
| 2530 | the schema constraints aren't applied to the start of nodes to |
| 2531 | the left of the input and the end of nodes at the end. |
| 2532 | */ |
| 2533 | parseSlice(dom, options = {}) { |
| 2534 | let context = new ParseContext(this, options, true); |
| 2535 | context.addAll(dom, Mark.none, options.from, options.to); |
| 2536 | return Slice.maxOpen(context.finish()); |
| 2537 | } |
| 2538 | /** |
| 2539 | @internal |
| 2540 | */ |
| 2541 | matchTag(dom, context, after) { |
| 2542 | for (let i2 = after ? this.tags.indexOf(after) + 1 : 0; i2 < this.tags.length; i2++) { |
| 2543 | let rule = this.tags[i2]; |
| 2544 | if (matches(dom, rule.tag) && (rule.namespace === void 0 || dom.namespaceURI == rule.namespace) && (!rule.context || context.matchesContext(rule.context))) { |
| 2545 | if (rule.getAttrs) { |
| 2546 | let result = rule.getAttrs(dom); |
| 2547 | if (result === false) |
| 2548 | continue; |
| 2549 | rule.attrs = result || void 0; |
| 2550 | } |
| 2551 | return rule; |
| 2552 | } |
| 2553 | } |
| 2554 | } |
| 2555 | /** |
| 2556 | @internal |
| 2557 | */ |
| 2558 | matchStyle(prop, value, context, after) { |
| 2559 | for (let i2 = after ? this.styles.indexOf(after) + 1 : 0; i2 < this.styles.length; i2++) { |
| 2560 | let rule = this.styles[i2], style = rule.style; |
| 2561 | if (style.indexOf(prop) != 0 || rule.context && !context.matchesContext(rule.context) || // Test that the style string either precisely matches the prop, |
| 2562 | // or has an '=' sign after the prop, followed by the given |
| 2563 | // value. |
| 2564 | style.length > prop.length && (style.charCodeAt(prop.length) != 61 || style.slice(prop.length + 1) != value)) |
| 2565 | continue; |
| 2566 | if (rule.getAttrs) { |
| 2567 | let result = rule.getAttrs(value); |
| 2568 | if (result === false) |
| 2569 | continue; |
| 2570 | rule.attrs = result || void 0; |
| 2571 | } |
| 2572 | return rule; |
| 2573 | } |
| 2574 | } |
| 2575 | /** |
| 2576 | @internal |
| 2577 | */ |
| 2578 | static schemaRules(schema2) { |
| 2579 | let result = []; |
| 2580 | function insert(rule) { |
| 2581 | let priority = rule.priority == null ? 50 : rule.priority, i2 = 0; |
| 2582 | for (; i2 < result.length; i2++) { |
| 2583 | let next = result[i2], nextPriority = next.priority == null ? 50 : next.priority; |
| 2584 | if (nextPriority < priority) |
| 2585 | break; |
| 2586 | } |
| 2587 | result.splice(i2, 0, rule); |
| 2588 | } |
| 2589 | for (let name in schema2.marks) { |
| 2590 | let rules = schema2.marks[name].spec.parseDOM; |
| 2591 | if (rules) |
| 2592 | rules.forEach((rule) => { |
| 2593 | insert(rule = copy(rule)); |
| 2594 | if (!(rule.mark || rule.ignore || rule.clearMark)) |
| 2595 | rule.mark = name; |
| 2596 | }); |
| 2597 | } |
| 2598 | for (let name in schema2.nodes) { |
| 2599 | let rules = schema2.nodes[name].spec.parseDOM; |
| 2600 | if (rules) |
| 2601 | rules.forEach((rule) => { |
| 2602 | insert(rule = copy(rule)); |
| 2603 | if (!(rule.node || rule.ignore || rule.mark)) |
| 2604 | rule.node = name; |
| 2605 | }); |
| 2606 | } |
| 2607 | return result; |
| 2608 | } |
| 2609 | /** |
| 2610 | Construct a DOM parser using the parsing rules listed in a |
| 2611 | schema's [node specs](https://prosemirror.net/docs/ref/#model.NodeSpec.parseDOM), reordered by |
| 2612 | [priority](https://prosemirror.net/docs/ref/#model.GenericParseRule.priority). |
| 2613 | */ |
| 2614 | static fromSchema(schema2) { |
| 2615 | return schema2.cached.domParser || (schema2.cached.domParser = new _DOMParser(schema2, _DOMParser.schemaRules(schema2))); |
| 2616 | } |
| 2617 | }; |
| 2618 | var blockTags = { |
| 2619 | address: true, |
| 2620 | article: true, |
| 2621 | aside: true, |
| 2622 | blockquote: true, |
| 2623 | body: true, |
| 2624 | canvas: true, |
| 2625 | dd: true, |
| 2626 | div: true, |
| 2627 | dl: true, |
| 2628 | fieldset: true, |
| 2629 | figcaption: true, |
| 2630 | figure: true, |
| 2631 | footer: true, |
| 2632 | form: true, |
| 2633 | h1: true, |
| 2634 | h2: true, |
| 2635 | h3: true, |
| 2636 | h4: true, |
| 2637 | h5: true, |
| 2638 | h6: true, |
| 2639 | header: true, |
| 2640 | hgroup: true, |
| 2641 | hr: true, |
| 2642 | li: true, |
| 2643 | noscript: true, |
| 2644 | ol: true, |
| 2645 | output: true, |
| 2646 | p: true, |
| 2647 | pre: true, |
| 2648 | section: true, |
| 2649 | table: true, |
| 2650 | tfoot: true, |
| 2651 | ul: true |
| 2652 | }; |
| 2653 | var ignoreTags = { |
| 2654 | head: true, |
| 2655 | noscript: true, |
| 2656 | object: true, |
| 2657 | script: true, |
| 2658 | style: true, |
| 2659 | title: true |
| 2660 | }; |
| 2661 | var listTags = { ol: true, ul: true }; |
| 2662 | var OPT_PRESERVE_WS = 1; |
| 2663 | var OPT_PRESERVE_WS_FULL = 2; |
| 2664 | var OPT_OPEN_LEFT = 4; |
| 2665 | function wsOptionsFor(type, preserveWhitespace, base2) { |
| 2666 | if (preserveWhitespace != null) |
| 2667 | return (preserveWhitespace ? OPT_PRESERVE_WS : 0) | (preserveWhitespace === "full" ? OPT_PRESERVE_WS_FULL : 0); |
| 2668 | return type && type.whitespace == "pre" ? OPT_PRESERVE_WS | OPT_PRESERVE_WS_FULL : base2 & ~OPT_OPEN_LEFT; |
| 2669 | } |
| 2670 | var NodeContext = class { |
| 2671 | constructor(type, attrs2, marks, solid, match, options) { |
| 2672 | this.type = type; |
| 2673 | this.attrs = attrs2; |
| 2674 | this.marks = marks; |
| 2675 | this.solid = solid; |
| 2676 | this.options = options; |
| 2677 | this.content = []; |
| 2678 | this.activeMarks = Mark.none; |
| 2679 | this.match = match || (options & OPT_OPEN_LEFT ? null : type.contentMatch); |
| 2680 | } |
| 2681 | findWrapping(node) { |
| 2682 | if (!this.match) { |
| 2683 | if (!this.type) |
| 2684 | return []; |
| 2685 | let fill = this.type.contentMatch.fillBefore(Fragment.from(node)); |
| 2686 | if (fill) { |
| 2687 | this.match = this.type.contentMatch.matchFragment(fill); |
| 2688 | } else { |
| 2689 | let start = this.type.contentMatch, wrap2; |
| 2690 | if (wrap2 = start.findWrapping(node.type)) { |
| 2691 | this.match = start; |
| 2692 | return wrap2; |
| 2693 | } else { |
| 2694 | return null; |
| 2695 | } |
| 2696 | } |
| 2697 | } |
| 2698 | return this.match.findWrapping(node.type); |
| 2699 | } |
| 2700 | finish(openEnd) { |
| 2701 | if (!(this.options & OPT_PRESERVE_WS)) { |
| 2702 | let last = this.content[this.content.length - 1], m; |
| 2703 | if (last && last.isText && (m = /[ \t\r\n\u000c]+$/.exec(last.text))) { |
| 2704 | let text = last; |
| 2705 | if (last.text.length == m[0].length) |
| 2706 | this.content.pop(); |
| 2707 | else |
| 2708 | this.content[this.content.length - 1] = text.withText(text.text.slice(0, text.text.length - m[0].length)); |
| 2709 | } |
| 2710 | } |
| 2711 | let content = Fragment.from(this.content); |
| 2712 | if (!openEnd && this.match) |
| 2713 | content = content.append(this.match.fillBefore(Fragment.empty, true)); |
| 2714 | return this.type ? this.type.create(this.attrs, content, this.marks) : content; |
| 2715 | } |
| 2716 | inlineContext(node) { |
| 2717 | if (this.type) |
| 2718 | return this.type.inlineContent; |
| 2719 | if (this.content.length) |
| 2720 | return this.content[0].isInline; |
| 2721 | return node.parentNode && !blockTags.hasOwnProperty(node.parentNode.nodeName.toLowerCase()); |
| 2722 | } |
| 2723 | }; |
| 2724 | var ParseContext = class { |
| 2725 | constructor(parser, options, isOpen) { |
| 2726 | this.parser = parser; |
| 2727 | this.options = options; |
| 2728 | this.isOpen = isOpen; |
| 2729 | this.open = 0; |
| 2730 | this.localPreserveWS = false; |
| 2731 | let topNode = options.topNode, topContext; |
| 2732 | let topOptions = wsOptionsFor(null, options.preserveWhitespace, 0) | (isOpen ? OPT_OPEN_LEFT : 0); |
| 2733 | if (topNode) |
| 2734 | topContext = new NodeContext(topNode.type, topNode.attrs, Mark.none, true, options.topMatch || topNode.type.contentMatch, topOptions); |
| 2735 | else if (isOpen) |
| 2736 | topContext = new NodeContext(null, null, Mark.none, true, null, topOptions); |
| 2737 | else |
| 2738 | topContext = new NodeContext(parser.schema.topNodeType, null, Mark.none, true, null, topOptions); |
| 2739 | this.nodes = [topContext]; |
| 2740 | this.find = options.findPositions; |
| 2741 | this.needsBlock = false; |
| 2742 | } |
| 2743 | get top() { |
| 2744 | return this.nodes[this.open]; |
| 2745 | } |
| 2746 | // Add a DOM node to the content. Text is inserted as text node, |
| 2747 | // otherwise, the node is passed to `addElement` or, if it has a |
| 2748 | // `style` attribute, `addElementWithStyles`. |
| 2749 | addDOM(dom, marks) { |
| 2750 | if (dom.nodeType == 3) |
| 2751 | this.addTextNode(dom, marks); |
| 2752 | else if (dom.nodeType == 1) |
| 2753 | this.addElement(dom, marks); |
| 2754 | } |
| 2755 | addTextNode(dom, marks) { |
| 2756 | let value = dom.nodeValue; |
| 2757 | let top = this.top, preserveWS = top.options & OPT_PRESERVE_WS_FULL ? "full" : this.localPreserveWS || (top.options & OPT_PRESERVE_WS) > 0; |
| 2758 | let { schema: schema2 } = this.parser; |
| 2759 | if (preserveWS === "full" || top.inlineContext(dom) || /[^ \t\r\n\u000c]/.test(value)) { |
| 2760 | if (!preserveWS) { |
| 2761 | value = value.replace(/[ \t\r\n\u000c]+/g, " "); |
| 2762 | if (/^[ \t\r\n\u000c]/.test(value) && this.open == this.nodes.length - 1) { |
| 2763 | let nodeBefore = top.content[top.content.length - 1]; |
| 2764 | let domNodeBefore = dom.previousSibling; |
| 2765 | if (!nodeBefore || domNodeBefore && domNodeBefore.nodeName == "BR" || nodeBefore.isText && /[ \t\r\n\u000c]$/.test(nodeBefore.text)) |
| 2766 | value = value.slice(1); |
| 2767 | } |
| 2768 | } else if (preserveWS === "full") { |
| 2769 | value = value.replace(/\r\n?/g, "\n"); |
| 2770 | } else if (schema2.linebreakReplacement && /[\r\n]/.test(value) && this.top.findWrapping(schema2.linebreakReplacement.create())) { |
| 2771 | let lines = value.split(/\r?\n|\r/); |
| 2772 | for (let i2 = 0; i2 < lines.length; i2++) { |
| 2773 | if (i2) |
| 2774 | this.insertNode(schema2.linebreakReplacement.create(), marks, true); |
| 2775 | if (lines[i2]) |
| 2776 | this.insertNode(schema2.text(lines[i2]), marks, !/\S/.test(lines[i2])); |
| 2777 | } |
| 2778 | value = ""; |
| 2779 | } else { |
| 2780 | value = value.replace(/\r?\n|\r/g, " "); |
| 2781 | } |
| 2782 | if (value) |
| 2783 | this.insertNode(schema2.text(value), marks, !/\S/.test(value)); |
| 2784 | this.findInText(dom); |
| 2785 | } else { |
| 2786 | this.findInside(dom); |
| 2787 | } |
| 2788 | } |
| 2789 | // Try to find a handler for the given tag and use that to parse. If |
| 2790 | // none is found, the element's content nodes are added directly. |
| 2791 | addElement(dom, marks, matchAfter) { |
| 2792 | let outerWS = this.localPreserveWS, top = this.top; |
| 2793 | if (dom.tagName == "PRE" || /pre/.test(dom.style && dom.style.whiteSpace)) |
| 2794 | this.localPreserveWS = true; |
| 2795 | let name = dom.nodeName.toLowerCase(), ruleID; |
| 2796 | if (listTags.hasOwnProperty(name) && this.parser.normalizeLists) |
| 2797 | normalizeList(dom); |
| 2798 | let rule = this.options.ruleFromNode && this.options.ruleFromNode(dom) || (ruleID = this.parser.matchTag(dom, this, matchAfter)); |
| 2799 | out: if (rule ? rule.ignore : ignoreTags.hasOwnProperty(name)) { |
| 2800 | this.findInside(dom); |
| 2801 | this.ignoreFallback(dom, marks); |
| 2802 | } else if (!rule || rule.skip || rule.closeParent) { |
| 2803 | if (rule && rule.closeParent) |
| 2804 | this.open = Math.max(0, this.open - 1); |
| 2805 | else if (rule && rule.skip.nodeType) |
| 2806 | dom = rule.skip; |
| 2807 | let sync, oldNeedsBlock = this.needsBlock; |
| 2808 | if (blockTags.hasOwnProperty(name)) { |
| 2809 | if (top.content.length && top.content[0].isInline && this.open) { |
| 2810 | this.open--; |
| 2811 | top = this.top; |
| 2812 | } |
| 2813 | sync = true; |
| 2814 | if (!top.type) |
| 2815 | this.needsBlock = true; |
| 2816 | } else if (!dom.firstChild) { |
| 2817 | this.leafFallback(dom, marks); |
| 2818 | break out; |
| 2819 | } |
| 2820 | let innerMarks = rule && rule.skip ? marks : this.readStyles(dom, marks); |
| 2821 | if (innerMarks) |
| 2822 | this.addAll(dom, innerMarks); |
| 2823 | if (sync) |
| 2824 | this.sync(top); |
| 2825 | this.needsBlock = oldNeedsBlock; |
| 2826 | } else { |
| 2827 | let innerMarks = this.readStyles(dom, marks); |
| 2828 | if (innerMarks) |
| 2829 | this.addElementByRule(dom, rule, innerMarks, rule.consuming === false ? ruleID : void 0); |
| 2830 | } |
| 2831 | this.localPreserveWS = outerWS; |
| 2832 | } |
| 2833 | // Called for leaf DOM nodes that would otherwise be ignored |
| 2834 | leafFallback(dom, marks) { |
| 2835 | if (dom.nodeName == "BR" && this.top.type && this.top.type.inlineContent) |
| 2836 | this.addTextNode(dom.ownerDocument.createTextNode("\n"), marks); |
| 2837 | } |
| 2838 | // Called for ignored nodes |
| 2839 | ignoreFallback(dom, marks) { |
| 2840 | if (dom.nodeName == "BR" && (!this.top.type || !this.top.type.inlineContent)) |
| 2841 | this.findPlace(this.parser.schema.text("-"), marks, true); |
| 2842 | } |
| 2843 | // Run any style parser associated with the node's styles. Either |
| 2844 | // return an updated array of marks, or null to indicate some of the |
| 2845 | // styles had a rule with `ignore` set. |
| 2846 | readStyles(dom, marks) { |
| 2847 | let styles = dom.style; |
| 2848 | if (styles && styles.length) |
| 2849 | for (let i2 = 0; i2 < this.parser.matchedStyles.length; i2++) { |
| 2850 | let name = this.parser.matchedStyles[i2], value = styles.getPropertyValue(name); |
| 2851 | if (value) |
| 2852 | for (let after = void 0; ; ) { |
| 2853 | let rule = this.parser.matchStyle(name, value, this, after); |
| 2854 | if (!rule) |
| 2855 | break; |
| 2856 | if (rule.ignore) |
| 2857 | return null; |
| 2858 | if (rule.clearMark) |
| 2859 | marks = marks.filter((m) => !rule.clearMark(m)); |
| 2860 | else |
| 2861 | marks = marks.concat(this.parser.schema.marks[rule.mark].create(rule.attrs)); |
| 2862 | if (rule.consuming === false) |
| 2863 | after = rule; |
| 2864 | else |
| 2865 | break; |
| 2866 | } |
| 2867 | } |
| 2868 | return marks; |
| 2869 | } |
| 2870 | // Look up a handler for the given node. If none are found, return |
| 2871 | // false. Otherwise, apply it, use its return value to drive the way |
| 2872 | // the node's content is wrapped, and return true. |
| 2873 | addElementByRule(dom, rule, marks, continueAfter) { |
| 2874 | let sync, nodeType; |
| 2875 | if (rule.node) { |
| 2876 | nodeType = this.parser.schema.nodes[rule.node]; |
| 2877 | if (!nodeType.isLeaf) { |
| 2878 | let inner = this.enter(nodeType, rule.attrs || null, marks, rule.preserveWhitespace); |
| 2879 | if (inner) { |
| 2880 | sync = true; |
| 2881 | marks = inner; |
| 2882 | } |
| 2883 | } else if (!this.insertNode(nodeType.create(rule.attrs), marks, dom.nodeName == "BR")) { |
| 2884 | this.leafFallback(dom, marks); |
| 2885 | } |
| 2886 | } else { |
| 2887 | let markType = this.parser.schema.marks[rule.mark]; |
| 2888 | marks = marks.concat(markType.create(rule.attrs)); |
| 2889 | } |
| 2890 | let startIn = this.top; |
| 2891 | if (nodeType && nodeType.isLeaf) { |
| 2892 | this.findInside(dom); |
| 2893 | } else if (continueAfter) { |
| 2894 | this.addElement(dom, marks, continueAfter); |
| 2895 | } else if (rule.getContent) { |
| 2896 | this.findInside(dom); |
| 2897 | rule.getContent(dom, this.parser.schema).forEach((node) => this.insertNode(node, marks, false)); |
| 2898 | } else { |
| 2899 | let contentDOM = dom; |
| 2900 | if (typeof rule.contentElement == "string") |
| 2901 | contentDOM = dom.querySelector(rule.contentElement); |
| 2902 | else if (typeof rule.contentElement == "function") |
| 2903 | contentDOM = rule.contentElement(dom); |
| 2904 | else if (rule.contentElement) |
| 2905 | contentDOM = rule.contentElement; |
| 2906 | this.findAround(dom, contentDOM, true); |
| 2907 | this.addAll(contentDOM, marks); |
| 2908 | this.findAround(dom, contentDOM, false); |
| 2909 | } |
| 2910 | if (sync && this.sync(startIn)) |
| 2911 | this.open--; |
| 2912 | } |
| 2913 | // Add all child nodes between `startIndex` and `endIndex` (or the |
| 2914 | // whole node, if not given). If `sync` is passed, use it to |
| 2915 | // synchronize after every block element. |
| 2916 | addAll(parent, marks, startIndex, endIndex) { |
| 2917 | let index = startIndex || 0; |
| 2918 | for (let dom = startIndex ? parent.childNodes[startIndex] : parent.firstChild, end = endIndex == null ? null : parent.childNodes[endIndex]; dom != end; dom = dom.nextSibling, ++index) { |
| 2919 | this.findAtPoint(parent, index); |
| 2920 | this.addDOM(dom, marks); |
| 2921 | } |
| 2922 | this.findAtPoint(parent, index); |
| 2923 | } |
| 2924 | // Try to find a way to fit the given node type into the current |
| 2925 | // context. May add intermediate wrappers and/or leave non-solid |
| 2926 | // nodes that we're in. |
| 2927 | findPlace(node, marks, cautious) { |
| 2928 | let route, sync; |
| 2929 | for (let depth = this.open, penalty = 0; depth >= 0; depth--) { |
| 2930 | let cx = this.nodes[depth]; |
| 2931 | let found2 = cx.findWrapping(node); |
| 2932 | if (found2 && (!route || route.length > found2.length + penalty)) { |
| 2933 | route = found2; |
| 2934 | sync = cx; |
| 2935 | if (!found2.length) |
| 2936 | break; |
| 2937 | } |
| 2938 | if (cx.solid) { |
| 2939 | if (cautious) |
| 2940 | break; |
| 2941 | penalty += 2; |
| 2942 | } |
| 2943 | } |
| 2944 | if (!route) |
| 2945 | return null; |
| 2946 | this.sync(sync); |
| 2947 | for (let i2 = 0; i2 < route.length; i2++) |
| 2948 | marks = this.enterInner(route[i2], null, marks, false); |
| 2949 | return marks; |
| 2950 | } |
| 2951 | // Try to insert the given node, adjusting the context when needed. |
| 2952 | insertNode(node, marks, cautious) { |
| 2953 | if (node.isInline && this.needsBlock && !this.top.type) { |
| 2954 | let block = this.textblockFromContext(); |
| 2955 | if (block) |
| 2956 | marks = this.enterInner(block, null, marks); |
| 2957 | } |
| 2958 | let innerMarks = this.findPlace(node, marks, cautious); |
| 2959 | if (innerMarks) { |
| 2960 | this.closeExtra(); |
| 2961 | let top = this.top; |
| 2962 | if (top.match) |
| 2963 | top.match = top.match.matchType(node.type); |
| 2964 | let nodeMarks = Mark.none; |
| 2965 | for (let m of innerMarks.concat(node.marks)) |
| 2966 | if (top.type ? top.type.allowsMarkType(m.type) : markMayApply(m.type, node.type)) |
| 2967 | nodeMarks = m.addToSet(nodeMarks); |
| 2968 | top.content.push(node.mark(nodeMarks)); |
| 2969 | return true; |
| 2970 | } |
| 2971 | return false; |
| 2972 | } |
| 2973 | // Try to start a node of the given type, adjusting the context when |
| 2974 | // necessary. |
| 2975 | enter(type, attrs2, marks, preserveWS) { |
| 2976 | let innerMarks = this.findPlace(type.create(attrs2), marks, false); |
| 2977 | if (innerMarks) |
| 2978 | innerMarks = this.enterInner(type, attrs2, marks, true, preserveWS); |
| 2979 | return innerMarks; |
| 2980 | } |
| 2981 | // Open a node of the given type |
| 2982 | enterInner(type, attrs2, marks, solid = false, preserveWS) { |
| 2983 | this.closeExtra(); |
| 2984 | let top = this.top; |
| 2985 | top.match = top.match && top.match.matchType(type); |
| 2986 | let options = wsOptionsFor(type, preserveWS, top.options); |
| 2987 | if (top.options & OPT_OPEN_LEFT && top.content.length == 0) |
| 2988 | options |= OPT_OPEN_LEFT; |
| 2989 | let applyMarks = Mark.none; |
| 2990 | marks = marks.filter((m) => { |
| 2991 | if (top.type ? top.type.allowsMarkType(m.type) : markMayApply(m.type, type)) { |
| 2992 | applyMarks = m.addToSet(applyMarks); |
| 2993 | return false; |
| 2994 | } |
| 2995 | return true; |
| 2996 | }); |
| 2997 | this.nodes.push(new NodeContext(type, attrs2, applyMarks, solid, null, options)); |
| 2998 | this.open++; |
| 2999 | return marks; |
| 3000 | } |
| 3001 | // Make sure all nodes above this.open are finished and added to |
| 3002 | // their parents |
| 3003 | closeExtra(openEnd = false) { |
| 3004 | let i2 = this.nodes.length - 1; |
| 3005 | if (i2 > this.open) { |
| 3006 | for (; i2 > this.open; i2--) |
| 3007 | this.nodes[i2 - 1].content.push(this.nodes[i2].finish(openEnd)); |
| 3008 | this.nodes.length = this.open + 1; |
| 3009 | } |
| 3010 | } |
| 3011 | finish() { |
| 3012 | this.open = 0; |
| 3013 | this.closeExtra(this.isOpen); |
| 3014 | return this.nodes[0].finish(!!(this.isOpen || this.options.topOpen)); |
| 3015 | } |
| 3016 | sync(to) { |
| 3017 | for (let i2 = this.open; i2 >= 0; i2--) { |
| 3018 | if (this.nodes[i2] == to) { |
| 3019 | this.open = i2; |
| 3020 | return true; |
| 3021 | } else if (this.localPreserveWS) { |
| 3022 | this.nodes[i2].options |= OPT_PRESERVE_WS; |
| 3023 | } |
| 3024 | } |
| 3025 | return false; |
| 3026 | } |
| 3027 | get currentPos() { |
| 3028 | this.closeExtra(); |
| 3029 | let pos = 0; |
| 3030 | for (let i2 = this.open; i2 >= 0; i2--) { |
| 3031 | let content = this.nodes[i2].content; |
| 3032 | for (let j = content.length - 1; j >= 0; j--) |
| 3033 | pos += content[j].nodeSize; |
| 3034 | if (i2) |
| 3035 | pos++; |
| 3036 | } |
| 3037 | return pos; |
| 3038 | } |
| 3039 | findAtPoint(parent, offset) { |
| 3040 | if (this.find) |
| 3041 | for (let i2 = 0; i2 < this.find.length; i2++) { |
| 3042 | if (this.find[i2].node == parent && this.find[i2].offset == offset) |
| 3043 | this.find[i2].pos = this.currentPos; |
| 3044 | } |
| 3045 | } |
| 3046 | findInside(parent) { |
| 3047 | if (this.find) |
| 3048 | for (let i2 = 0; i2 < this.find.length; i2++) { |
| 3049 | if (this.find[i2].pos == null && parent.nodeType == 1 && parent.contains(this.find[i2].node)) |
| 3050 | this.find[i2].pos = this.currentPos; |
| 3051 | } |
| 3052 | } |
| 3053 | findAround(parent, content, before) { |
| 3054 | if (parent != content && this.find) |
| 3055 | for (let i2 = 0; i2 < this.find.length; i2++) { |
| 3056 | if (this.find[i2].pos == null && parent.nodeType == 1 && parent.contains(this.find[i2].node)) { |
| 3057 | let pos = content.compareDocumentPosition(this.find[i2].node); |
| 3058 | if (pos & (before ? 2 : 4)) |
| 3059 | this.find[i2].pos = this.currentPos; |
| 3060 | } |
| 3061 | } |
| 3062 | } |
| 3063 | findInText(textNode) { |
| 3064 | if (this.find) |
| 3065 | for (let i2 = 0; i2 < this.find.length; i2++) { |
| 3066 | if (this.find[i2].node == textNode) |
| 3067 | this.find[i2].pos = this.currentPos - (textNode.nodeValue.length - this.find[i2].offset); |
| 3068 | } |
| 3069 | } |
| 3070 | // Determines whether the given context string matches this context. |
| 3071 | matchesContext(context) { |
| 3072 | if (context.indexOf("|") > -1) |
| 3073 | return context.split(/\s*\|\s*/).some(this.matchesContext, this); |
| 3074 | let parts = context.split("/"); |
| 3075 | let option = this.options.context; |
| 3076 | let useRoot = !this.isOpen && (!option || option.parent.type == this.nodes[0].type); |
| 3077 | let minDepth = -(option ? option.depth + 1 : 0) + (useRoot ? 0 : 1); |
| 3078 | let match = (i2, depth) => { |
| 3079 | for (; i2 >= 0; i2--) { |
| 3080 | let part = parts[i2]; |
| 3081 | if (part == "") { |
| 3082 | if (i2 == parts.length - 1 || i2 == 0) |
| 3083 | continue; |
| 3084 | for (; depth >= minDepth; depth--) |
| 3085 | if (match(i2 - 1, depth)) |
| 3086 | return true; |
| 3087 | return false; |
| 3088 | } else { |
| 3089 | let next = depth > 0 || depth == 0 && useRoot ? this.nodes[depth].type : option && depth >= minDepth ? option.node(depth - minDepth).type : null; |
| 3090 | if (!next || next.name != part && !next.isInGroup(part)) |
| 3091 | return false; |
| 3092 | depth--; |
| 3093 | } |
| 3094 | } |
| 3095 | return true; |
| 3096 | }; |
| 3097 | return match(parts.length - 1, this.open); |
| 3098 | } |
| 3099 | textblockFromContext() { |
| 3100 | let $context = this.options.context; |
| 3101 | if ($context) |
| 3102 | for (let d = $context.depth; d >= 0; d--) { |
| 3103 | let deflt = $context.node(d).contentMatchAt($context.indexAfter(d)).defaultType; |
| 3104 | if (deflt && deflt.isTextblock && deflt.defaultAttrs) |
| 3105 | return deflt; |
| 3106 | } |
| 3107 | for (let name in this.parser.schema.nodes) { |
| 3108 | let type = this.parser.schema.nodes[name]; |
| 3109 | if (type.isTextblock && type.defaultAttrs) |
| 3110 | return type; |
| 3111 | } |
| 3112 | } |
| 3113 | }; |
| 3114 | function normalizeList(dom) { |
| 3115 | for (let child = dom.firstChild, prevItem = null; child; child = child.nextSibling) { |
| 3116 | let name = child.nodeType == 1 ? child.nodeName.toLowerCase() : null; |
| 3117 | if (name && listTags.hasOwnProperty(name) && prevItem) { |
| 3118 | prevItem.appendChild(child); |
| 3119 | child = prevItem; |
| 3120 | } else if (name == "li") { |
| 3121 | prevItem = child; |
| 3122 | } else if (name) { |
| 3123 | prevItem = null; |
| 3124 | } |
| 3125 | } |
| 3126 | } |
| 3127 | function matches(dom, selector) { |
| 3128 | return (dom.matches || dom.msMatchesSelector || dom.webkitMatchesSelector || dom.mozMatchesSelector).call(dom, selector); |
| 3129 | } |
| 3130 | function copy(obj) { |
| 3131 | let copy2 = {}; |
| 3132 | for (let prop in obj) |
| 3133 | copy2[prop] = obj[prop]; |
| 3134 | return copy2; |
| 3135 | } |
| 3136 | function markMayApply(markType, nodeType) { |
| 3137 | let nodes = nodeType.schema.nodes; |
| 3138 | for (let name in nodes) { |
| 3139 | let parent = nodes[name]; |
| 3140 | if (!parent.allowsMarkType(markType)) |
| 3141 | continue; |
| 3142 | let seen = [], scan = (match) => { |
| 3143 | seen.push(match); |
| 3144 | for (let i2 = 0; i2 < match.edgeCount; i2++) { |
| 3145 | let { type, next } = match.edge(i2); |
| 3146 | if (type == nodeType) |
| 3147 | return true; |
| 3148 | if (seen.indexOf(next) < 0 && scan(next)) |
| 3149 | return true; |
| 3150 | } |
| 3151 | }; |
| 3152 | if (scan(parent.contentMatch)) |
| 3153 | return true; |
| 3154 | } |
| 3155 | } |
| 3156 | var DOMSerializer = class _DOMSerializer { |
| 3157 | /** |
| 3158 | Create a serializer. `nodes` should map node names to functions |
| 3159 | that take a node and return a description of the corresponding |
| 3160 | DOM. `marks` does the same for mark names, but also gets an |
| 3161 | argument that tells it whether the mark's content is block or |
| 3162 | inline content (for typical use, it'll always be inline). A mark |
| 3163 | serializer may be `null` to indicate that marks of that type |
| 3164 | should not be serialized. |
| 3165 | */ |
| 3166 | constructor(nodes, marks) { |
| 3167 | this.nodes = nodes; |
| 3168 | this.marks = marks; |
| 3169 | } |
| 3170 | /** |
| 3171 | Serialize the content of this fragment to a DOM fragment. When |
| 3172 | not in the browser, the `document` option, containing a DOM |
| 3173 | document, should be passed so that the serializer can create |
| 3174 | nodes. |
| 3175 | */ |
| 3176 | serializeFragment(fragment, options = {}, target) { |
| 3177 | if (!target) |
| 3178 | target = doc(options).createDocumentFragment(); |
| 3179 | let top = target, active = []; |
| 3180 | fragment.forEach((node) => { |
| 3181 | if (active.length || node.marks.length) { |
| 3182 | let keep = 0, rendered = 0; |
| 3183 | while (keep < active.length && rendered < node.marks.length) { |
| 3184 | let next = node.marks[rendered]; |
| 3185 | if (!this.marks[next.type.name]) { |
| 3186 | rendered++; |
| 3187 | continue; |
| 3188 | } |
| 3189 | if (!next.eq(active[keep][0]) || next.type.spec.spanning === false) |
| 3190 | break; |
| 3191 | keep++; |
| 3192 | rendered++; |
| 3193 | } |
| 3194 | while (keep < active.length) |
| 3195 | top = active.pop()[1]; |
| 3196 | while (rendered < node.marks.length) { |
| 3197 | let add2 = node.marks[rendered++]; |
| 3198 | let markDOM = this.serializeMark(add2, node.isInline, options); |
| 3199 | if (markDOM) { |
| 3200 | active.push([add2, top]); |
| 3201 | top.appendChild(markDOM.dom); |
| 3202 | top = markDOM.contentDOM || markDOM.dom; |
| 3203 | } |
| 3204 | } |
| 3205 | } |
| 3206 | top.appendChild(this.serializeNodeInner(node, options)); |
| 3207 | }); |
| 3208 | return target; |
| 3209 | } |
| 3210 | /** |
| 3211 | @internal |
| 3212 | */ |
| 3213 | serializeNodeInner(node, options) { |
| 3214 | if (node.isText) |
| 3215 | return doc(options).createTextNode(node.text); |
| 3216 | let { dom, contentDOM } = renderSpec(doc(options), this.nodes[node.type.name](node), null, node.attrs); |
| 3217 | if (contentDOM) { |
| 3218 | if (node.isLeaf) |
| 3219 | throw new RangeError("Content hole not allowed in a leaf node spec"); |
| 3220 | this.serializeFragment(node.content, options, contentDOM); |
| 3221 | } |
| 3222 | return dom; |
| 3223 | } |
| 3224 | /** |
| 3225 | Serialize this node to a DOM node. This can be useful when you |
| 3226 | need to serialize a part of a document, as opposed to the whole |
| 3227 | document. To serialize a whole document, use |
| 3228 | [`serializeFragment`](https://prosemirror.net/docs/ref/#model.DOMSerializer.serializeFragment) on |
| 3229 | its [content](https://prosemirror.net/docs/ref/#model.Node.content). |
| 3230 | */ |
| 3231 | serializeNode(node, options = {}) { |
| 3232 | let dom = this.serializeNodeInner(node, options); |
| 3233 | for (let i2 = node.marks.length - 1; i2 >= 0; i2--) { |
| 3234 | let wrap2 = this.serializeMark(node.marks[i2], node.isInline, options); |
| 3235 | if (wrap2) { |
| 3236 | (wrap2.contentDOM || wrap2.dom).appendChild(dom); |
| 3237 | dom = wrap2.dom; |
| 3238 | } |
| 3239 | } |
| 3240 | return dom; |
| 3241 | } |
| 3242 | /** |
| 3243 | @internal |
| 3244 | */ |
| 3245 | serializeMark(mark, inline, options = {}) { |
| 3246 | let toDOM = this.marks[mark.type.name]; |
| 3247 | return toDOM && renderSpec(doc(options), toDOM(mark, inline), null, mark.attrs); |
| 3248 | } |
| 3249 | static renderSpec(doc3, structure, xmlNS = null, blockArraysIn) { |
| 3250 | if (typeof structure == "string") |
| 3251 | return { dom: doc3.createTextNode(structure) }; |
| 3252 | return renderSpec(doc3, structure, xmlNS, blockArraysIn); |
| 3253 | } |
| 3254 | /** |
| 3255 | Build a serializer using the [`toDOM`](https://prosemirror.net/docs/ref/#model.NodeSpec.toDOM) |
| 3256 | properties in a schema's node and mark specs. |
| 3257 | */ |
| 3258 | static fromSchema(schema2) { |
| 3259 | return schema2.cached.domSerializer || (schema2.cached.domSerializer = new _DOMSerializer(this.nodesFromSchema(schema2), this.marksFromSchema(schema2))); |
| 3260 | } |
| 3261 | /** |
| 3262 | Gather the serializers in a schema's node specs into an object. |
| 3263 | This can be useful as a base to build a custom serializer from. |
| 3264 | */ |
| 3265 | static nodesFromSchema(schema2) { |
| 3266 | let result = gatherToDOM(schema2.nodes); |
| 3267 | if (!result.text) |
| 3268 | result.text = (node) => node.text; |
| 3269 | return result; |
| 3270 | } |
| 3271 | /** |
| 3272 | Gather the serializers in a schema's mark specs into an object. |
| 3273 | */ |
| 3274 | static marksFromSchema(schema2) { |
| 3275 | return gatherToDOM(schema2.marks); |
| 3276 | } |
| 3277 | }; |
| 3278 | function gatherToDOM(obj) { |
| 3279 | let result = {}; |
| 3280 | for (let name in obj) { |
| 3281 | let toDOM = obj[name].spec.toDOM; |
| 3282 | if (toDOM) |
| 3283 | result[name] = toDOM; |
| 3284 | } |
| 3285 | return result; |
| 3286 | } |
| 3287 | function doc(options) { |
| 3288 | return options.document || window.document; |
| 3289 | } |
| 3290 | var suspiciousAttributeCache = /* @__PURE__ */ new WeakMap(); |
| 3291 | function suspiciousAttributes(attrs2) { |
| 3292 | let value = suspiciousAttributeCache.get(attrs2); |
| 3293 | if (value === void 0) |
| 3294 | suspiciousAttributeCache.set(attrs2, value = suspiciousAttributesInner(attrs2)); |
| 3295 | return value; |
| 3296 | } |
| 3297 | function suspiciousAttributesInner(attrs2) { |
| 3298 | let result = null; |
| 3299 | function scan(value) { |
| 3300 | if (value && typeof value == "object") { |
| 3301 | if (Array.isArray(value)) { |
| 3302 | if (typeof value[0] == "string") { |
| 3303 | if (!result) |
| 3304 | result = []; |
| 3305 | result.push(value); |
| 3306 | } else { |
| 3307 | for (let i2 = 0; i2 < value.length; i2++) |
| 3308 | scan(value[i2]); |
| 3309 | } |
| 3310 | } else { |
| 3311 | for (let prop in value) |
| 3312 | scan(value[prop]); |
| 3313 | } |
| 3314 | } |
| 3315 | } |
| 3316 | scan(attrs2); |
| 3317 | return result; |
| 3318 | } |
| 3319 | function renderSpec(doc3, structure, xmlNS, blockArraysIn) { |
| 3320 | if (structure.nodeType == 1) |
| 3321 | return { dom: structure }; |
| 3322 | if (structure.dom && structure.dom.nodeType == 1) |
| 3323 | return structure; |
| 3324 | let tagName = structure[0], suspicious; |
| 3325 | if (typeof tagName != "string") |
| 3326 | throw new RangeError("Invalid array passed to renderSpec"); |
| 3327 | if (blockArraysIn && (suspicious = suspiciousAttributes(blockArraysIn)) && suspicious.indexOf(structure) > -1) |
| 3328 | throw new RangeError("Using an array from an attribute object as a DOM spec. This may be an attempted cross site scripting attack."); |
| 3329 | let space = tagName.indexOf(" "); |
| 3330 | if (space > 0) { |
| 3331 | xmlNS = tagName.slice(0, space); |
| 3332 | tagName = tagName.slice(space + 1); |
| 3333 | } |
| 3334 | let contentDOM; |
| 3335 | let dom = xmlNS ? doc3.createElementNS(xmlNS, tagName) : doc3.createElement(tagName); |
| 3336 | let attrs2 = structure[1], start = 1; |
| 3337 | if (attrs2 && typeof attrs2 == "object" && attrs2.nodeType == null && !Array.isArray(attrs2)) { |
| 3338 | start = 2; |
| 3339 | for (let name in attrs2) |
| 3340 | if (attrs2[name] != null) { |
| 3341 | let space2 = name.indexOf(" "); |
| 3342 | if (space2 > 0) |
| 3343 | dom.setAttributeNS(name.slice(0, space2), name.slice(space2 + 1), attrs2[name]); |
| 3344 | else if (name == "style" && dom.style) |
| 3345 | dom.style.cssText = attrs2[name]; |
| 3346 | else |
| 3347 | dom.setAttribute(name, attrs2[name]); |
| 3348 | } |
| 3349 | } |
| 3350 | for (let i2 = start; i2 < structure.length; i2++) { |
| 3351 | let child = structure[i2]; |
| 3352 | if (child === 0) { |
| 3353 | if (i2 < structure.length - 1 || i2 > start) |
| 3354 | throw new RangeError("Content hole must be the only child of its parent node"); |
| 3355 | return { dom, contentDOM: dom }; |
| 3356 | } else if (typeof child == "string") { |
| 3357 | dom.appendChild(doc3.createTextNode(child)); |
| 3358 | } else { |
| 3359 | let { dom: inner, contentDOM: innerContent } = renderSpec(doc3, child, xmlNS, blockArraysIn); |
| 3360 | dom.appendChild(inner); |
| 3361 | if (innerContent) { |
| 3362 | if (contentDOM) |
| 3363 | throw new RangeError("Multiple content holes"); |
| 3364 | contentDOM = innerContent; |
| 3365 | } |
| 3366 | } |
| 3367 | } |
| 3368 | return { dom, contentDOM }; |
| 3369 | } |
| 3370 | |
| 3371 | // node_modules/prosemirror-transform/dist/index.js |
| 3372 | var lower16 = 65535; |
| 3373 | var factor16 = Math.pow(2, 16); |
| 3374 | function makeRecover(index, offset) { |
| 3375 | return index + offset * factor16; |
| 3376 | } |
| 3377 | function recoverIndex(value) { |
| 3378 | return value & lower16; |
| 3379 | } |
| 3380 | function recoverOffset(value) { |
| 3381 | return (value - (value & lower16)) / factor16; |
| 3382 | } |
| 3383 | var DEL_BEFORE = 1; |
| 3384 | var DEL_AFTER = 2; |
| 3385 | var DEL_ACROSS = 4; |
| 3386 | var DEL_SIDE = 8; |
| 3387 | var MapResult = class { |
| 3388 | /** |
| 3389 | @internal |
| 3390 | */ |
| 3391 | constructor(pos, delInfo, recover) { |
| 3392 | this.pos = pos; |
| 3393 | this.delInfo = delInfo; |
| 3394 | this.recover = recover; |
| 3395 | } |
| 3396 | /** |
| 3397 | Tells you whether the position was deleted, that is, whether the |
| 3398 | step removed the token on the side queried (via the `assoc`) |
| 3399 | argument from the document. |
| 3400 | */ |
| 3401 | get deleted() { |
| 3402 | return (this.delInfo & DEL_SIDE) > 0; |
| 3403 | } |
| 3404 | /** |
| 3405 | Tells you whether the token before the mapped position was deleted. |
| 3406 | */ |
| 3407 | get deletedBefore() { |
| 3408 | return (this.delInfo & (DEL_BEFORE | DEL_ACROSS)) > 0; |
| 3409 | } |
| 3410 | /** |
| 3411 | True when the token after the mapped position was deleted. |
| 3412 | */ |
| 3413 | get deletedAfter() { |
| 3414 | return (this.delInfo & (DEL_AFTER | DEL_ACROSS)) > 0; |
| 3415 | } |
| 3416 | /** |
| 3417 | Tells whether any of the steps mapped through deletes across the |
| 3418 | position (including both the token before and after the |
| 3419 | position). |
| 3420 | */ |
| 3421 | get deletedAcross() { |
| 3422 | return (this.delInfo & DEL_ACROSS) > 0; |
| 3423 | } |
| 3424 | }; |
| 3425 | var StepMap = class _StepMap { |
| 3426 | /** |
| 3427 | Create a position map. The modifications to the document are |
| 3428 | represented as an array of numbers, in which each group of three |
| 3429 | represents a modified chunk as `[start, oldSize, newSize]`. |
| 3430 | */ |
| 3431 | constructor(ranges, inverted = false) { |
| 3432 | this.ranges = ranges; |
| 3433 | this.inverted = inverted; |
| 3434 | if (!ranges.length && _StepMap.empty) |
| 3435 | return _StepMap.empty; |
| 3436 | } |
| 3437 | /** |
| 3438 | @internal |
| 3439 | */ |
| 3440 | recover(value) { |
| 3441 | let diff = 0, index = recoverIndex(value); |
| 3442 | if (!this.inverted) |
| 3443 | for (let i2 = 0; i2 < index; i2++) |
| 3444 | diff += this.ranges[i2 * 3 + 2] - this.ranges[i2 * 3 + 1]; |
| 3445 | return this.ranges[index * 3] + diff + recoverOffset(value); |
| 3446 | } |
| 3447 | mapResult(pos, assoc = 1) { |
| 3448 | return this._map(pos, assoc, false); |
| 3449 | } |
| 3450 | map(pos, assoc = 1) { |
| 3451 | return this._map(pos, assoc, true); |
| 3452 | } |
| 3453 | /** |
| 3454 | @internal |
| 3455 | */ |
| 3456 | _map(pos, assoc, simple) { |
| 3457 | let diff = 0, oldIndex = this.inverted ? 2 : 1, newIndex = this.inverted ? 1 : 2; |
| 3458 | for (let i2 = 0; i2 < this.ranges.length; i2 += 3) { |
| 3459 | let start = this.ranges[i2] - (this.inverted ? diff : 0); |
| 3460 | if (start > pos) |
| 3461 | break; |
| 3462 | let oldSize = this.ranges[i2 + oldIndex], newSize = this.ranges[i2 + newIndex], end = start + oldSize; |
| 3463 | if (pos <= end) { |
| 3464 | let side = !oldSize ? assoc : pos == start ? -1 : pos == end ? 1 : assoc; |
| 3465 | let result = start + diff + (side < 0 ? 0 : newSize); |
| 3466 | if (simple) |
| 3467 | return result; |
| 3468 | let recover = pos == (assoc < 0 ? start : end) ? null : makeRecover(i2 / 3, pos - start); |
| 3469 | let del2 = pos == start ? DEL_AFTER : pos == end ? DEL_BEFORE : DEL_ACROSS; |
| 3470 | if (assoc < 0 ? pos != start : pos != end) |
| 3471 | del2 |= DEL_SIDE; |
| 3472 | return new MapResult(result, del2, recover); |
| 3473 | } |
| 3474 | diff += newSize - oldSize; |
| 3475 | } |
| 3476 | return simple ? pos + diff : new MapResult(pos + diff, 0, null); |
| 3477 | } |
| 3478 | /** |
| 3479 | @internal |
| 3480 | */ |
| 3481 | touches(pos, recover) { |
| 3482 | let diff = 0, index = recoverIndex(recover); |
| 3483 | let oldIndex = this.inverted ? 2 : 1, newIndex = this.inverted ? 1 : 2; |
| 3484 | for (let i2 = 0; i2 < this.ranges.length; i2 += 3) { |
| 3485 | let start = this.ranges[i2] - (this.inverted ? diff : 0); |
| 3486 | if (start > pos) |
| 3487 | break; |
| 3488 | let oldSize = this.ranges[i2 + oldIndex], end = start + oldSize; |
| 3489 | if (pos <= end && i2 == index * 3) |
| 3490 | return true; |
| 3491 | diff += this.ranges[i2 + newIndex] - oldSize; |
| 3492 | } |
| 3493 | return false; |
| 3494 | } |
| 3495 | /** |
| 3496 | Calls the given function on each of the changed ranges included in |
| 3497 | this map. |
| 3498 | */ |
| 3499 | forEach(f) { |
| 3500 | let oldIndex = this.inverted ? 2 : 1, newIndex = this.inverted ? 1 : 2; |
| 3501 | for (let i2 = 0, diff = 0; i2 < this.ranges.length; i2 += 3) { |
| 3502 | let start = this.ranges[i2], oldStart = start - (this.inverted ? diff : 0), newStart = start + (this.inverted ? 0 : diff); |
| 3503 | let oldSize = this.ranges[i2 + oldIndex], newSize = this.ranges[i2 + newIndex]; |
| 3504 | f(oldStart, oldStart + oldSize, newStart, newStart + newSize); |
| 3505 | diff += newSize - oldSize; |
| 3506 | } |
| 3507 | } |
| 3508 | /** |
| 3509 | Create an inverted version of this map. The result can be used to |
| 3510 | map positions in the post-step document to the pre-step document. |
| 3511 | */ |
| 3512 | invert() { |
| 3513 | return new _StepMap(this.ranges, !this.inverted); |
| 3514 | } |
| 3515 | /** |
| 3516 | @internal |
| 3517 | */ |
| 3518 | toString() { |
| 3519 | return (this.inverted ? "-" : "") + JSON.stringify(this.ranges); |
| 3520 | } |
| 3521 | /** |
| 3522 | Create a map that moves all positions by offset `n` (which may be |
| 3523 | negative). This can be useful when applying steps meant for a |
| 3524 | sub-document to a larger document, or vice-versa. |
| 3525 | */ |
| 3526 | static offset(n) { |
| 3527 | return n == 0 ? _StepMap.empty : new _StepMap(n < 0 ? [0, -n, 0] : [0, 0, n]); |
| 3528 | } |
| 3529 | }; |
| 3530 | StepMap.empty = new StepMap([]); |
| 3531 | var Mapping = class _Mapping { |
| 3532 | /** |
| 3533 | Create a new mapping with the given position maps. |
| 3534 | */ |
| 3535 | constructor(maps, mirror, from2 = 0, to = maps ? maps.length : 0) { |
| 3536 | this.mirror = mirror; |
| 3537 | this.from = from2; |
| 3538 | this.to = to; |
| 3539 | this._maps = maps || []; |
| 3540 | this.ownData = !(maps || mirror); |
| 3541 | } |
| 3542 | /** |
| 3543 | The step maps in this mapping. |
| 3544 | */ |
| 3545 | get maps() { |
| 3546 | return this._maps; |
| 3547 | } |
| 3548 | /** |
| 3549 | Create a mapping that maps only through a part of this one. |
| 3550 | */ |
| 3551 | slice(from2 = 0, to = this.maps.length) { |
| 3552 | return new _Mapping(this._maps, this.mirror, from2, to); |
| 3553 | } |
| 3554 | /** |
| 3555 | Add a step map to the end of this mapping. If `mirrors` is |
| 3556 | given, it should be the index of the step map that is the mirror |
| 3557 | image of this one. |
| 3558 | */ |
| 3559 | appendMap(map2, mirrors) { |
| 3560 | if (!this.ownData) { |
| 3561 | this._maps = this._maps.slice(); |
| 3562 | this.mirror = this.mirror && this.mirror.slice(); |
| 3563 | this.ownData = true; |
| 3564 | } |
| 3565 | this.to = this._maps.push(map2); |
| 3566 | if (mirrors != null) |
| 3567 | this.setMirror(this._maps.length - 1, mirrors); |
| 3568 | } |
| 3569 | /** |
| 3570 | Add all the step maps in a given mapping to this one (preserving |
| 3571 | mirroring information). |
| 3572 | */ |
| 3573 | appendMapping(mapping) { |
| 3574 | for (let i2 = 0, startSize = this._maps.length; i2 < mapping._maps.length; i2++) { |
| 3575 | let mirr = mapping.getMirror(i2); |
| 3576 | this.appendMap(mapping._maps[i2], mirr != null && mirr < i2 ? startSize + mirr : void 0); |
| 3577 | } |
| 3578 | } |
| 3579 | /** |
| 3580 | Finds the offset of the step map that mirrors the map at the |
| 3581 | given offset, in this mapping (as per the second argument to |
| 3582 | `appendMap`). |
| 3583 | */ |
| 3584 | getMirror(n) { |
| 3585 | if (this.mirror) { |
| 3586 | for (let i2 = 0; i2 < this.mirror.length; i2++) |
| 3587 | if (this.mirror[i2] == n) |
| 3588 | return this.mirror[i2 + (i2 % 2 ? -1 : 1)]; |
| 3589 | } |
| 3590 | } |
| 3591 | /** |
| 3592 | @internal |
| 3593 | */ |
| 3594 | setMirror(n, m) { |
| 3595 | if (!this.mirror) |
| 3596 | this.mirror = []; |
| 3597 | this.mirror.push(n, m); |
| 3598 | } |
| 3599 | /** |
| 3600 | Append the inverse of the given mapping to this one. |
| 3601 | */ |
| 3602 | appendMappingInverted(mapping) { |
| 3603 | for (let i2 = mapping.maps.length - 1, totalSize = this._maps.length + mapping._maps.length; i2 >= 0; i2--) { |
| 3604 | let mirr = mapping.getMirror(i2); |
| 3605 | this.appendMap(mapping._maps[i2].invert(), mirr != null && mirr > i2 ? totalSize - mirr - 1 : void 0); |
| 3606 | } |
| 3607 | } |
| 3608 | /** |
| 3609 | Create an inverted version of this mapping. |
| 3610 | */ |
| 3611 | invert() { |
| 3612 | let inverse = new _Mapping(); |
| 3613 | inverse.appendMappingInverted(this); |
| 3614 | return inverse; |
| 3615 | } |
| 3616 | /** |
| 3617 | Map a position through this mapping. |
| 3618 | */ |
| 3619 | map(pos, assoc = 1) { |
| 3620 | if (this.mirror) |
| 3621 | return this._map(pos, assoc, true); |
| 3622 | for (let i2 = this.from; i2 < this.to; i2++) |
| 3623 | pos = this._maps[i2].map(pos, assoc); |
| 3624 | return pos; |
| 3625 | } |
| 3626 | /** |
| 3627 | Map a position through this mapping, returning a mapping |
| 3628 | result. |
| 3629 | */ |
| 3630 | mapResult(pos, assoc = 1) { |
| 3631 | return this._map(pos, assoc, false); |
| 3632 | } |
| 3633 | /** |
| 3634 | @internal |
| 3635 | */ |
| 3636 | _map(pos, assoc, simple) { |
| 3637 | let delInfo = 0; |
| 3638 | for (let i2 = this.from; i2 < this.to; i2++) { |
| 3639 | let map2 = this._maps[i2], result = map2.mapResult(pos, assoc); |
| 3640 | if (result.recover != null) { |
| 3641 | let corr = this.getMirror(i2); |
| 3642 | if (corr != null && corr > i2 && corr < this.to) { |
| 3643 | i2 = corr; |
| 3644 | pos = this._maps[corr].recover(result.recover); |
| 3645 | continue; |
| 3646 | } |
| 3647 | } |
| 3648 | delInfo |= result.delInfo; |
| 3649 | pos = result.pos; |
| 3650 | } |
| 3651 | return simple ? pos : new MapResult(pos, delInfo, null); |
| 3652 | } |
| 3653 | }; |
| 3654 | var stepsByID = /* @__PURE__ */ Object.create(null); |
| 3655 | var Step = class { |
| 3656 | /** |
| 3657 | Get the step map that represents the changes made by this step, |
| 3658 | and which can be used to transform between positions in the old |
| 3659 | and the new document. |
| 3660 | */ |
| 3661 | getMap() { |
| 3662 | return StepMap.empty; |
| 3663 | } |
| 3664 | /** |
| 3665 | Try to merge this step with another one, to be applied directly |
| 3666 | after it. Returns the merged step when possible, null if the |
| 3667 | steps can't be merged. |
| 3668 | */ |
| 3669 | merge(other) { |
| 3670 | return null; |
| 3671 | } |
| 3672 | /** |
| 3673 | Deserialize a step from its JSON representation. Will call |
| 3674 | through to the step class' own implementation of this method. |
| 3675 | */ |
| 3676 | static fromJSON(schema2, json) { |
| 3677 | if (!json || !json.stepType) |
| 3678 | throw new RangeError("Invalid input for Step.fromJSON"); |
| 3679 | let type = stepsByID[json.stepType]; |
| 3680 | if (!type) |
| 3681 | throw new RangeError(`No step type ${json.stepType} defined`); |
| 3682 | return type.fromJSON(schema2, json); |
| 3683 | } |
| 3684 | /** |
| 3685 | To be able to serialize steps to JSON, each step needs a string |
| 3686 | ID to attach to its JSON representation. Use this method to |
| 3687 | register an ID for your step classes. Try to pick something |
| 3688 | that's unlikely to clash with steps from other modules. |
| 3689 | */ |
| 3690 | static jsonID(id, stepClass) { |
| 3691 | if (id in stepsByID) |
| 3692 | throw new RangeError("Duplicate use of step JSON ID " + id); |
| 3693 | stepsByID[id] = stepClass; |
| 3694 | stepClass.prototype.jsonID = id; |
| 3695 | return stepClass; |
| 3696 | } |
| 3697 | }; |
| 3698 | var StepResult = class _StepResult { |
| 3699 | /** |
| 3700 | @internal |
| 3701 | */ |
| 3702 | constructor(doc3, failed) { |
| 3703 | this.doc = doc3; |
| 3704 | this.failed = failed; |
| 3705 | } |
| 3706 | /** |
| 3707 | Create a successful step result. |
| 3708 | */ |
| 3709 | static ok(doc3) { |
| 3710 | return new _StepResult(doc3, null); |
| 3711 | } |
| 3712 | /** |
| 3713 | Create a failed step result. |
| 3714 | */ |
| 3715 | static fail(message) { |
| 3716 | return new _StepResult(null, message); |
| 3717 | } |
| 3718 | /** |
| 3719 | Call [`Node.replace`](https://prosemirror.net/docs/ref/#model.Node.replace) with the given |
| 3720 | arguments. Create a successful result if it succeeds, and a |
| 3721 | failed one if it throws a `ReplaceError`. |
| 3722 | */ |
| 3723 | static fromReplace(doc3, from2, to, slice2) { |
| 3724 | try { |
| 3725 | return _StepResult.ok(doc3.replace(from2, to, slice2)); |
| 3726 | } catch (e) { |
| 3727 | if (e instanceof ReplaceError) |
| 3728 | return _StepResult.fail(e.message); |
| 3729 | throw e; |
| 3730 | } |
| 3731 | } |
| 3732 | }; |
| 3733 | function mapFragment(fragment, f, parent) { |
| 3734 | let mapped = []; |
| 3735 | for (let i2 = 0; i2 < fragment.childCount; i2++) { |
| 3736 | let child = fragment.child(i2); |
| 3737 | if (child.content.size) |
| 3738 | child = child.copy(mapFragment(child.content, f, child)); |
| 3739 | if (child.isInline) |
| 3740 | child = f(child, parent, i2); |
| 3741 | mapped.push(child); |
| 3742 | } |
| 3743 | return Fragment.fromArray(mapped); |
| 3744 | } |
| 3745 | var AddMarkStep = class _AddMarkStep extends Step { |
| 3746 | /** |
| 3747 | Create a mark step. |
| 3748 | */ |
| 3749 | constructor(from2, to, mark) { |
| 3750 | super(); |
| 3751 | this.from = from2; |
| 3752 | this.to = to; |
| 3753 | this.mark = mark; |
| 3754 | } |
| 3755 | apply(doc3) { |
| 3756 | let oldSlice = doc3.slice(this.from, this.to), $from = doc3.resolve(this.from); |
| 3757 | let parent = $from.node($from.sharedDepth(this.to)); |
| 3758 | let slice2 = new Slice(mapFragment(oldSlice.content, (node, parent2) => { |
| 3759 | if (!node.isAtom || !parent2.type.allowsMarkType(this.mark.type)) |
| 3760 | return node; |
| 3761 | return node.mark(this.mark.addToSet(node.marks)); |
| 3762 | }, parent), oldSlice.openStart, oldSlice.openEnd); |
| 3763 | return StepResult.fromReplace(doc3, this.from, this.to, slice2); |
| 3764 | } |
| 3765 | invert() { |
| 3766 | return new RemoveMarkStep(this.from, this.to, this.mark); |
| 3767 | } |
| 3768 | map(mapping) { |
| 3769 | let from2 = mapping.mapResult(this.from, 1), to = mapping.mapResult(this.to, -1); |
| 3770 | if (from2.deleted && to.deleted || from2.pos >= to.pos) |
| 3771 | return null; |
| 3772 | return new _AddMarkStep(from2.pos, to.pos, this.mark); |
| 3773 | } |
| 3774 | merge(other) { |
| 3775 | if (other instanceof _AddMarkStep && other.mark.eq(this.mark) && this.from <= other.to && this.to >= other.from) |
| 3776 | return new _AddMarkStep(Math.min(this.from, other.from), Math.max(this.to, other.to), this.mark); |
| 3777 | return null; |
| 3778 | } |
| 3779 | toJSON() { |
| 3780 | return { |
| 3781 | stepType: "addMark", |
| 3782 | mark: this.mark.toJSON(), |
| 3783 | from: this.from, |
| 3784 | to: this.to |
| 3785 | }; |
| 3786 | } |
| 3787 | /** |
| 3788 | @internal |
| 3789 | */ |
| 3790 | static fromJSON(schema2, json) { |
| 3791 | if (typeof json.from != "number" || typeof json.to != "number") |
| 3792 | throw new RangeError("Invalid input for AddMarkStep.fromJSON"); |
| 3793 | return new _AddMarkStep(json.from, json.to, schema2.markFromJSON(json.mark)); |
| 3794 | } |
| 3795 | }; |
| 3796 | Step.jsonID("addMark", AddMarkStep); |
| 3797 | var RemoveMarkStep = class _RemoveMarkStep extends Step { |
| 3798 | /** |
| 3799 | Create a mark-removing step. |
| 3800 | */ |
| 3801 | constructor(from2, to, mark) { |
| 3802 | super(); |
| 3803 | this.from = from2; |
| 3804 | this.to = to; |
| 3805 | this.mark = mark; |
| 3806 | } |
| 3807 | apply(doc3) { |
| 3808 | let oldSlice = doc3.slice(this.from, this.to); |
| 3809 | let slice2 = new Slice(mapFragment(oldSlice.content, (node) => { |
| 3810 | return node.mark(this.mark.removeFromSet(node.marks)); |
| 3811 | }, doc3), oldSlice.openStart, oldSlice.openEnd); |
| 3812 | return StepResult.fromReplace(doc3, this.from, this.to, slice2); |
| 3813 | } |
| 3814 | invert() { |
| 3815 | return new AddMarkStep(this.from, this.to, this.mark); |
| 3816 | } |
| 3817 | map(mapping) { |
| 3818 | let from2 = mapping.mapResult(this.from, 1), to = mapping.mapResult(this.to, -1); |
| 3819 | if (from2.deleted && to.deleted || from2.pos >= to.pos) |
| 3820 | return null; |
| 3821 | return new _RemoveMarkStep(from2.pos, to.pos, this.mark); |
| 3822 | } |
| 3823 | merge(other) { |
| 3824 | if (other instanceof _RemoveMarkStep && other.mark.eq(this.mark) && this.from <= other.to && this.to >= other.from) |
| 3825 | return new _RemoveMarkStep(Math.min(this.from, other.from), Math.max(this.to, other.to), this.mark); |
| 3826 | return null; |
| 3827 | } |
| 3828 | toJSON() { |
| 3829 | return { |
| 3830 | stepType: "removeMark", |
| 3831 | mark: this.mark.toJSON(), |
| 3832 | from: this.from, |
| 3833 | to: this.to |
| 3834 | }; |
| 3835 | } |
| 3836 | /** |
| 3837 | @internal |
| 3838 | */ |
| 3839 | static fromJSON(schema2, json) { |
| 3840 | if (typeof json.from != "number" || typeof json.to != "number") |
| 3841 | throw new RangeError("Invalid input for RemoveMarkStep.fromJSON"); |
| 3842 | return new _RemoveMarkStep(json.from, json.to, schema2.markFromJSON(json.mark)); |
| 3843 | } |
| 3844 | }; |
| 3845 | Step.jsonID("removeMark", RemoveMarkStep); |
| 3846 | var AddNodeMarkStep = class _AddNodeMarkStep extends Step { |
| 3847 | /** |
| 3848 | Create a node mark step. |
| 3849 | */ |
| 3850 | constructor(pos, mark) { |
| 3851 | super(); |
| 3852 | this.pos = pos; |
| 3853 | this.mark = mark; |
| 3854 | } |
| 3855 | apply(doc3) { |
| 3856 | let node = doc3.nodeAt(this.pos); |
| 3857 | if (!node) |
| 3858 | return StepResult.fail("No node at mark step's position"); |
| 3859 | let updated = node.type.create(node.attrs, null, this.mark.addToSet(node.marks)); |
| 3860 | return StepResult.fromReplace(doc3, this.pos, this.pos + 1, new Slice(Fragment.from(updated), 0, node.isLeaf ? 0 : 1)); |
| 3861 | } |
| 3862 | invert(doc3) { |
| 3863 | let node = doc3.nodeAt(this.pos); |
| 3864 | if (node) { |
| 3865 | let newSet = this.mark.addToSet(node.marks); |
| 3866 | if (newSet.length == node.marks.length) { |
| 3867 | for (let i2 = 0; i2 < node.marks.length; i2++) |
| 3868 | if (!node.marks[i2].isInSet(newSet)) |
| 3869 | return new _AddNodeMarkStep(this.pos, node.marks[i2]); |
| 3870 | return new _AddNodeMarkStep(this.pos, this.mark); |
| 3871 | } |
| 3872 | } |
| 3873 | return new RemoveNodeMarkStep(this.pos, this.mark); |
| 3874 | } |
| 3875 | map(mapping) { |
| 3876 | let pos = mapping.mapResult(this.pos, 1); |
| 3877 | return pos.deletedAfter ? null : new _AddNodeMarkStep(pos.pos, this.mark); |
| 3878 | } |
| 3879 | toJSON() { |
| 3880 | return { stepType: "addNodeMark", pos: this.pos, mark: this.mark.toJSON() }; |
| 3881 | } |
| 3882 | /** |
| 3883 | @internal |
| 3884 | */ |
| 3885 | static fromJSON(schema2, json) { |
| 3886 | if (typeof json.pos != "number") |
| 3887 | throw new RangeError("Invalid input for AddNodeMarkStep.fromJSON"); |
| 3888 | return new _AddNodeMarkStep(json.pos, schema2.markFromJSON(json.mark)); |
| 3889 | } |
| 3890 | }; |
| 3891 | Step.jsonID("addNodeMark", AddNodeMarkStep); |
| 3892 | var RemoveNodeMarkStep = class _RemoveNodeMarkStep extends Step { |
| 3893 | /** |
| 3894 | Create a mark-removing step. |
| 3895 | */ |
| 3896 | constructor(pos, mark) { |
| 3897 | super(); |
| 3898 | this.pos = pos; |
| 3899 | this.mark = mark; |
| 3900 | } |
| 3901 | apply(doc3) { |
| 3902 | let node = doc3.nodeAt(this.pos); |
| 3903 | if (!node) |
| 3904 | return StepResult.fail("No node at mark step's position"); |
| 3905 | let updated = node.type.create(node.attrs, null, this.mark.removeFromSet(node.marks)); |
| 3906 | return StepResult.fromReplace(doc3, this.pos, this.pos + 1, new Slice(Fragment.from(updated), 0, node.isLeaf ? 0 : 1)); |
| 3907 | } |
| 3908 | invert(doc3) { |
| 3909 | let node = doc3.nodeAt(this.pos); |
| 3910 | if (!node || !this.mark.isInSet(node.marks)) |
| 3911 | return this; |
| 3912 | return new AddNodeMarkStep(this.pos, this.mark); |
| 3913 | } |
| 3914 | map(mapping) { |
| 3915 | let pos = mapping.mapResult(this.pos, 1); |
| 3916 | return pos.deletedAfter ? null : new _RemoveNodeMarkStep(pos.pos, this.mark); |
| 3917 | } |
| 3918 | toJSON() { |
| 3919 | return { stepType: "removeNodeMark", pos: this.pos, mark: this.mark.toJSON() }; |
| 3920 | } |
| 3921 | /** |
| 3922 | @internal |
| 3923 | */ |
| 3924 | static fromJSON(schema2, json) { |
| 3925 | if (typeof json.pos != "number") |
| 3926 | throw new RangeError("Invalid input for RemoveNodeMarkStep.fromJSON"); |
| 3927 | return new _RemoveNodeMarkStep(json.pos, schema2.markFromJSON(json.mark)); |
| 3928 | } |
| 3929 | }; |
| 3930 | Step.jsonID("removeNodeMark", RemoveNodeMarkStep); |
| 3931 | var ReplaceStep = class _ReplaceStep extends Step { |
| 3932 | /** |
| 3933 | The given `slice` should fit the 'gap' between `from` and |
| 3934 | `to`βthe depths must line up, and the surrounding nodes must be |
| 3935 | able to be joined with the open sides of the slice. When |
| 3936 | `structure` is true, the step will fail if the content between |
| 3937 | from and to is not just a sequence of closing and then opening |
| 3938 | tokens (this is to guard against rebased replace steps |
| 3939 | overwriting something they weren't supposed to). |
| 3940 | */ |
| 3941 | constructor(from2, to, slice2, structure = false) { |
| 3942 | super(); |
| 3943 | this.from = from2; |
| 3944 | this.to = to; |
| 3945 | this.slice = slice2; |
| 3946 | this.structure = structure; |
| 3947 | } |
| 3948 | apply(doc3) { |
| 3949 | if (this.structure && contentBetween(doc3, this.from, this.to)) |
| 3950 | return StepResult.fail("Structure replace would overwrite content"); |
| 3951 | return StepResult.fromReplace(doc3, this.from, this.to, this.slice); |
| 3952 | } |
| 3953 | getMap() { |
| 3954 | return new StepMap([this.from, this.to - this.from, this.slice.size]); |
| 3955 | } |
| 3956 | invert(doc3) { |
| 3957 | return new _ReplaceStep(this.from, this.from + this.slice.size, doc3.slice(this.from, this.to)); |
| 3958 | } |
| 3959 | map(mapping) { |
| 3960 | let to = mapping.mapResult(this.to, -1); |
| 3961 | let from2 = this.from == this.to && _ReplaceStep.MAP_BIAS < 0 ? to : mapping.mapResult(this.from, 1); |
| 3962 | if (from2.deletedAcross && to.deletedAcross) |
| 3963 | return null; |
| 3964 | return new _ReplaceStep(from2.pos, Math.max(from2.pos, to.pos), this.slice, this.structure); |
| 3965 | } |
| 3966 | merge(other) { |
| 3967 | if (!(other instanceof _ReplaceStep) || other.structure || this.structure) |
| 3968 | return null; |
| 3969 | if (this.from + this.slice.size == other.from && !this.slice.openEnd && !other.slice.openStart) { |
| 3970 | let slice2 = this.slice.size + other.slice.size == 0 ? Slice.empty : new Slice(this.slice.content.append(other.slice.content), this.slice.openStart, other.slice.openEnd); |
| 3971 | return new _ReplaceStep(this.from, this.to + (other.to - other.from), slice2, this.structure); |
| 3972 | } else if (other.to == this.from && !this.slice.openStart && !other.slice.openEnd) { |
| 3973 | let slice2 = this.slice.size + other.slice.size == 0 ? Slice.empty : new Slice(other.slice.content.append(this.slice.content), other.slice.openStart, this.slice.openEnd); |
| 3974 | return new _ReplaceStep(other.from, this.to, slice2, this.structure); |
| 3975 | } else { |
| 3976 | return null; |
| 3977 | } |
| 3978 | } |
| 3979 | toJSON() { |
| 3980 | let json = { stepType: "replace", from: this.from, to: this.to }; |
| 3981 | if (this.slice.size) |
| 3982 | json.slice = this.slice.toJSON(); |
| 3983 | if (this.structure) |
| 3984 | json.structure = true; |
| 3985 | return json; |
| 3986 | } |
| 3987 | /** |
| 3988 | @internal |
| 3989 | */ |
| 3990 | static fromJSON(schema2, json) { |
| 3991 | if (typeof json.from != "number" || typeof json.to != "number") |
| 3992 | throw new RangeError("Invalid input for ReplaceStep.fromJSON"); |
| 3993 | return new _ReplaceStep(json.from, json.to, Slice.fromJSON(schema2, json.slice), !!json.structure); |
| 3994 | } |
| 3995 | }; |
| 3996 | ReplaceStep.MAP_BIAS = 1; |
| 3997 | Step.jsonID("replace", ReplaceStep); |
| 3998 | var ReplaceAroundStep = class _ReplaceAroundStep extends Step { |
| 3999 | /** |
| 4000 | Create a replace-around step with the given range and gap. |
| 4001 | `insert` should be the point in the slice into which the content |
| 4002 | of the gap should be moved. `structure` has the same meaning as |
| 4003 | it has in the [`ReplaceStep`](https://prosemirror.net/docs/ref/#transform.ReplaceStep) class. |
| 4004 | */ |
| 4005 | constructor(from2, to, gapFrom, gapTo, slice2, insert, structure = false) { |
| 4006 | super(); |
| 4007 | this.from = from2; |
| 4008 | this.to = to; |
| 4009 | this.gapFrom = gapFrom; |
| 4010 | this.gapTo = gapTo; |
| 4011 | this.slice = slice2; |
| 4012 | this.insert = insert; |
| 4013 | this.structure = structure; |
| 4014 | } |
| 4015 | apply(doc3) { |
| 4016 | if (this.structure && (contentBetween(doc3, this.from, this.gapFrom) || contentBetween(doc3, this.gapTo, this.to))) |
| 4017 | return StepResult.fail("Structure gap-replace would overwrite content"); |
| 4018 | let gap = doc3.slice(this.gapFrom, this.gapTo); |
| 4019 | if (gap.openStart || gap.openEnd) |
| 4020 | return StepResult.fail("Gap is not a flat range"); |
| 4021 | let inserted = this.slice.insertAt(this.insert, gap.content); |
| 4022 | if (!inserted) |
| 4023 | return StepResult.fail("Content does not fit in gap"); |
| 4024 | return StepResult.fromReplace(doc3, this.from, this.to, inserted); |
| 4025 | } |
| 4026 | getMap() { |
| 4027 | return new StepMap([ |
| 4028 | this.from, |
| 4029 | this.gapFrom - this.from, |
| 4030 | this.insert, |
| 4031 | this.gapTo, |
| 4032 | this.to - this.gapTo, |
| 4033 | this.slice.size - this.insert |
| 4034 | ]); |
| 4035 | } |
| 4036 | invert(doc3) { |
| 4037 | let gap = this.gapTo - this.gapFrom; |
| 4038 | return new _ReplaceAroundStep(this.from, this.from + this.slice.size + gap, this.from + this.insert, this.from + this.insert + gap, doc3.slice(this.from, this.to).removeBetween(this.gapFrom - this.from, this.gapTo - this.from), this.gapFrom - this.from, this.structure); |
| 4039 | } |
| 4040 | map(mapping) { |
| 4041 | let from2 = mapping.mapResult(this.from, 1), to = mapping.mapResult(this.to, -1); |
| 4042 | let gapFrom = this.from == this.gapFrom ? from2.pos : mapping.map(this.gapFrom, -1); |
| 4043 | let gapTo = this.to == this.gapTo ? to.pos : mapping.map(this.gapTo, 1); |
| 4044 | if (from2.deletedAcross && to.deletedAcross || gapFrom < from2.pos || gapTo > to.pos) |
| 4045 | return null; |
| 4046 | return new _ReplaceAroundStep(from2.pos, to.pos, gapFrom, gapTo, this.slice, this.insert, this.structure); |
| 4047 | } |
| 4048 | toJSON() { |
| 4049 | let json = { |
| 4050 | stepType: "replaceAround", |
| 4051 | from: this.from, |
| 4052 | to: this.to, |
| 4053 | gapFrom: this.gapFrom, |
| 4054 | gapTo: this.gapTo, |
| 4055 | insert: this.insert |
| 4056 | }; |
| 4057 | if (this.slice.size) |
| 4058 | json.slice = this.slice.toJSON(); |
| 4059 | if (this.structure) |
| 4060 | json.structure = true; |
| 4061 | return json; |
| 4062 | } |
| 4063 | /** |
| 4064 | @internal |
| 4065 | */ |
| 4066 | static fromJSON(schema2, json) { |
| 4067 | if (typeof json.from != "number" || typeof json.to != "number" || typeof json.gapFrom != "number" || typeof json.gapTo != "number" || typeof json.insert != "number") |
| 4068 | throw new RangeError("Invalid input for ReplaceAroundStep.fromJSON"); |
| 4069 | return new _ReplaceAroundStep(json.from, json.to, json.gapFrom, json.gapTo, Slice.fromJSON(schema2, json.slice), json.insert, !!json.structure); |
| 4070 | } |
| 4071 | }; |
| 4072 | Step.jsonID("replaceAround", ReplaceAroundStep); |
| 4073 | function contentBetween(doc3, from2, to) { |
| 4074 | let $from = doc3.resolve(from2), dist = to - from2, depth = $from.depth; |
| 4075 | while (dist > 0 && depth > 0 && $from.indexAfter(depth) == $from.node(depth).childCount) { |
| 4076 | depth--; |
| 4077 | dist--; |
| 4078 | } |
| 4079 | if (dist > 0) { |
| 4080 | let next = $from.node(depth).maybeChild($from.indexAfter(depth)); |
| 4081 | while (dist > 0) { |
| 4082 | if (!next || next.isLeaf) |
| 4083 | return true; |
| 4084 | next = next.firstChild; |
| 4085 | dist--; |
| 4086 | } |
| 4087 | } |
| 4088 | return false; |
| 4089 | } |
| 4090 | function addMark(tr, from2, to, mark) { |
| 4091 | let removed = [], added = []; |
| 4092 | let removing, adding; |
| 4093 | tr.doc.nodesBetween(from2, to, (node, pos, parent) => { |
| 4094 | if (!node.isInline) |
| 4095 | return; |
| 4096 | let marks = node.marks; |
| 4097 | if (!mark.isInSet(marks) && parent.type.allowsMarkType(mark.type)) { |
| 4098 | let start = Math.max(pos, from2), end = Math.min(pos + node.nodeSize, to); |
| 4099 | let newSet = mark.addToSet(marks); |
| 4100 | for (let i2 = 0; i2 < marks.length; i2++) { |
| 4101 | if (!marks[i2].isInSet(newSet)) { |
| 4102 | if (removing && removing.to == start && removing.mark.eq(marks[i2])) |
| 4103 | removing.to = end; |
| 4104 | else |
| 4105 | removed.push(removing = new RemoveMarkStep(start, end, marks[i2])); |
| 4106 | } |
| 4107 | } |
| 4108 | if (adding && adding.to == start) |
| 4109 | adding.to = end; |
| 4110 | else |
| 4111 | added.push(adding = new AddMarkStep(start, end, mark)); |
| 4112 | } |
| 4113 | }); |
| 4114 | removed.forEach((s) => tr.step(s)); |
| 4115 | added.forEach((s) => tr.step(s)); |
| 4116 | } |
| 4117 | function removeMark(tr, from2, to, mark) { |
| 4118 | let matched = [], step = 0; |
| 4119 | tr.doc.nodesBetween(from2, to, (node, pos) => { |
| 4120 | if (!node.isInline) |
| 4121 | return; |
| 4122 | step++; |
| 4123 | let toRemove = null; |
| 4124 | if (mark instanceof MarkType) { |
| 4125 | let set = node.marks, found2; |
| 4126 | while (found2 = mark.isInSet(set)) { |
| 4127 | (toRemove || (toRemove = [])).push(found2); |
| 4128 | set = found2.removeFromSet(set); |
| 4129 | } |
| 4130 | } else if (mark) { |
| 4131 | if (mark.isInSet(node.marks)) |
| 4132 | toRemove = [mark]; |
| 4133 | } else { |
| 4134 | toRemove = node.marks; |
| 4135 | } |
| 4136 | if (toRemove && toRemove.length) { |
| 4137 | let end = Math.min(pos + node.nodeSize, to); |
| 4138 | for (let i2 = 0; i2 < toRemove.length; i2++) { |
| 4139 | let style = toRemove[i2], found2; |
| 4140 | for (let j = 0; j < matched.length; j++) { |
| 4141 | let m = matched[j]; |
| 4142 | if (m.step == step - 1 && style.eq(matched[j].style)) |
| 4143 | found2 = m; |
| 4144 | } |
| 4145 | if (found2) { |
| 4146 | found2.to = end; |
| 4147 | found2.step = step; |
| 4148 | } else { |
| 4149 | matched.push({ style, from: Math.max(pos, from2), to: end, step }); |
| 4150 | } |
| 4151 | } |
| 4152 | } |
| 4153 | }); |
| 4154 | matched.forEach((m) => tr.step(new RemoveMarkStep(m.from, m.to, m.style))); |
| 4155 | } |
| 4156 | function clearIncompatible(tr, pos, parentType, match = parentType.contentMatch, clearNewlines = true) { |
| 4157 | let node = tr.doc.nodeAt(pos); |
| 4158 | let replSteps = [], cur = pos + 1; |
| 4159 | for (let i2 = 0; i2 < node.childCount; i2++) { |
| 4160 | let child = node.child(i2), end = cur + child.nodeSize; |
| 4161 | let allowed = match.matchType(child.type); |
| 4162 | if (!allowed) { |
| 4163 | replSteps.push(new ReplaceStep(cur, end, Slice.empty)); |
| 4164 | } else { |
| 4165 | match = allowed; |
| 4166 | for (let j = 0; j < child.marks.length; j++) |
| 4167 | if (!parentType.allowsMarkType(child.marks[j].type)) |
| 4168 | tr.step(new RemoveMarkStep(cur, end, child.marks[j])); |
| 4169 | if (clearNewlines && child.isText && parentType.whitespace != "pre") { |
| 4170 | let m, newline = /\r?\n|\r/g, slice2; |
| 4171 | while (m = newline.exec(child.text)) { |
| 4172 | if (!slice2) |
| 4173 | slice2 = new Slice(Fragment.from(parentType.schema.text(" ", parentType.allowedMarks(child.marks))), 0, 0); |
| 4174 | replSteps.push(new ReplaceStep(cur + m.index, cur + m.index + m[0].length, slice2)); |
| 4175 | } |
| 4176 | } |
| 4177 | } |
| 4178 | cur = end; |
| 4179 | } |
| 4180 | if (!match.validEnd) { |
| 4181 | let fill = match.fillBefore(Fragment.empty, true); |
| 4182 | tr.replace(cur, cur, new Slice(fill, 0, 0)); |
| 4183 | } |
| 4184 | for (let i2 = replSteps.length - 1; i2 >= 0; i2--) |
| 4185 | tr.step(replSteps[i2]); |
| 4186 | } |
| 4187 | function canCut(node, start, end) { |
| 4188 | return (start == 0 || node.canReplace(start, node.childCount)) && (end == node.childCount || node.canReplace(0, end)); |
| 4189 | } |
| 4190 | function liftTarget(range) { |
| 4191 | let parent = range.parent; |
| 4192 | let content = parent.content.cutByIndex(range.startIndex, range.endIndex); |
| 4193 | for (let depth = range.depth, contentBefore = 0, contentAfter = 0; ; --depth) { |
| 4194 | let node = range.$from.node(depth); |
| 4195 | let index = range.$from.index(depth) + contentBefore, endIndex = range.$to.indexAfter(depth) - contentAfter; |
| 4196 | if (depth < range.depth && node.canReplace(index, endIndex, content)) |
| 4197 | return depth; |
| 4198 | if (depth == 0 || node.type.spec.isolating || !canCut(node, index, endIndex)) |
| 4199 | break; |
| 4200 | if (index) |
| 4201 | contentBefore = 1; |
| 4202 | if (endIndex < node.childCount) |
| 4203 | contentAfter = 1; |
| 4204 | } |
| 4205 | return null; |
| 4206 | } |
| 4207 | function lift(tr, range, target) { |
| 4208 | let { $from, $to, depth } = range; |
| 4209 | let gapStart = $from.before(depth + 1), gapEnd = $to.after(depth + 1); |
| 4210 | let start = gapStart, end = gapEnd; |
| 4211 | let before = Fragment.empty, openStart = 0; |
| 4212 | for (let d = depth, splitting = false; d > target; d--) |
| 4213 | if (splitting || $from.index(d) > 0) { |
| 4214 | splitting = true; |
| 4215 | before = Fragment.from($from.node(d).copy(before)); |
| 4216 | openStart++; |
| 4217 | } else { |
| 4218 | start--; |
| 4219 | } |
| 4220 | let after = Fragment.empty, openEnd = 0; |
| 4221 | for (let d = depth, splitting = false; d > target; d--) |
| 4222 | if (splitting || $to.after(d + 1) < $to.end(d)) { |
| 4223 | splitting = true; |
| 4224 | after = Fragment.from($to.node(d).copy(after)); |
| 4225 | openEnd++; |
| 4226 | } else { |
| 4227 | end++; |
| 4228 | } |
| 4229 | tr.step(new ReplaceAroundStep(start, end, gapStart, gapEnd, new Slice(before.append(after), openStart, openEnd), before.size - openStart, true)); |
| 4230 | } |
| 4231 | function findWrapping(range, nodeType, attrs2 = null, innerRange = range) { |
| 4232 | let around = findWrappingOutside(range, nodeType); |
| 4233 | let inner = around && findWrappingInside(innerRange, nodeType); |
| 4234 | if (!inner) |
| 4235 | return null; |
| 4236 | return around.map(withAttrs).concat({ type: nodeType, attrs: attrs2 }).concat(inner.map(withAttrs)); |
| 4237 | } |
| 4238 | function withAttrs(type) { |
| 4239 | return { type, attrs: null }; |
| 4240 | } |
| 4241 | function findWrappingOutside(range, type) { |
| 4242 | let { parent, startIndex, endIndex } = range; |
| 4243 | let around = parent.contentMatchAt(startIndex).findWrapping(type); |
| 4244 | if (!around) |
| 4245 | return null; |
| 4246 | let outer = around.length ? around[0] : type; |
| 4247 | return parent.canReplaceWith(startIndex, endIndex, outer) ? around : null; |
| 4248 | } |
| 4249 | function findWrappingInside(range, type) { |
| 4250 | let { parent, startIndex, endIndex } = range; |
| 4251 | let inner = parent.child(startIndex); |
| 4252 | let inside = type.contentMatch.findWrapping(inner.type); |
| 4253 | if (!inside) |
| 4254 | return null; |
| 4255 | let lastType = inside.length ? inside[inside.length - 1] : type; |
| 4256 | let innerMatch = lastType.contentMatch; |
| 4257 | for (let i2 = startIndex; innerMatch && i2 < endIndex; i2++) |
| 4258 | innerMatch = innerMatch.matchType(parent.child(i2).type); |
| 4259 | if (!innerMatch || !innerMatch.validEnd) |
| 4260 | return null; |
| 4261 | return inside; |
| 4262 | } |
| 4263 | function wrap(tr, range, wrappers) { |
| 4264 | let content = Fragment.empty; |
| 4265 | for (let i2 = wrappers.length - 1; i2 >= 0; i2--) { |
| 4266 | if (content.size) { |
| 4267 | let match = wrappers[i2].type.contentMatch.matchFragment(content); |
| 4268 | if (!match || !match.validEnd) |
| 4269 | throw new RangeError("Wrapper type given to Transform.wrap does not form valid content of its parent wrapper"); |
| 4270 | } |
| 4271 | content = Fragment.from(wrappers[i2].type.create(wrappers[i2].attrs, content)); |
| 4272 | } |
| 4273 | let start = range.start, end = range.end; |
| 4274 | tr.step(new ReplaceAroundStep(start, end, start, end, new Slice(content, 0, 0), wrappers.length, true)); |
| 4275 | } |
| 4276 | function setBlockType(tr, from2, to, type, attrs2) { |
| 4277 | if (!type.isTextblock) |
| 4278 | throw new RangeError("Type given to setBlockType should be a textblock"); |
| 4279 | let mapFrom = tr.steps.length; |
| 4280 | tr.doc.nodesBetween(from2, to, (node, pos) => { |
| 4281 | let attrsHere = typeof attrs2 == "function" ? attrs2(node) : attrs2; |
| 4282 | if (node.isTextblock && !node.hasMarkup(type, attrsHere) && canChangeType(tr.doc, tr.mapping.slice(mapFrom).map(pos), type)) { |
| 4283 | let convertNewlines = null; |
| 4284 | if (type.schema.linebreakReplacement) { |
| 4285 | let pre = type.whitespace == "pre", supportLinebreak = !!type.contentMatch.matchType(type.schema.linebreakReplacement); |
| 4286 | if (pre && !supportLinebreak) |
| 4287 | convertNewlines = false; |
| 4288 | else if (!pre && supportLinebreak) |
| 4289 | convertNewlines = true; |
| 4290 | } |
| 4291 | if (convertNewlines === false) |
| 4292 | replaceLinebreaks(tr, node, pos, mapFrom); |
| 4293 | clearIncompatible(tr, tr.mapping.slice(mapFrom).map(pos, 1), type, void 0, convertNewlines === null); |
| 4294 | let mapping = tr.mapping.slice(mapFrom); |
| 4295 | let startM = mapping.map(pos, 1), endM = mapping.map(pos + node.nodeSize, 1); |
| 4296 | tr.step(new ReplaceAroundStep(startM, endM, startM + 1, endM - 1, new Slice(Fragment.from(type.create(attrsHere, null, node.marks)), 0, 0), 1, true)); |
| 4297 | if (convertNewlines === true) |
| 4298 | replaceNewlines(tr, node, pos, mapFrom); |
| 4299 | return false; |
| 4300 | } |
| 4301 | }); |
| 4302 | } |
| 4303 | function replaceNewlines(tr, node, pos, mapFrom) { |
| 4304 | node.forEach((child, offset) => { |
| 4305 | if (child.isText) { |
| 4306 | let m, newline = /\r?\n|\r/g; |
| 4307 | while (m = newline.exec(child.text)) { |
| 4308 | let start = tr.mapping.slice(mapFrom).map(pos + 1 + offset + m.index); |
| 4309 | tr.replaceWith(start, start + 1, node.type.schema.linebreakReplacement.create()); |
| 4310 | } |
| 4311 | } |
| 4312 | }); |
| 4313 | } |
| 4314 | function replaceLinebreaks(tr, node, pos, mapFrom) { |
| 4315 | node.forEach((child, offset) => { |
| 4316 | if (child.type == child.type.schema.linebreakReplacement) { |
| 4317 | let start = tr.mapping.slice(mapFrom).map(pos + 1 + offset); |
| 4318 | tr.replaceWith(start, start + 1, node.type.schema.text("\n")); |
| 4319 | } |
| 4320 | }); |
| 4321 | } |
| 4322 | function canChangeType(doc3, pos, type) { |
| 4323 | let $pos = doc3.resolve(pos), index = $pos.index(); |
| 4324 | return $pos.parent.canReplaceWith(index, index + 1, type); |
| 4325 | } |
| 4326 | function setNodeMarkup(tr, pos, type, attrs2, marks) { |
| 4327 | let node = tr.doc.nodeAt(pos); |
| 4328 | if (!node) |
| 4329 | throw new RangeError("No node at given position"); |
| 4330 | if (!type) |
| 4331 | type = node.type; |
| 4332 | let newNode = type.create(attrs2, null, marks || node.marks); |
| 4333 | if (node.isLeaf) |
| 4334 | return tr.replaceWith(pos, pos + node.nodeSize, newNode); |
| 4335 | if (!type.validContent(node.content)) |
| 4336 | throw new RangeError("Invalid content for node type " + type.name); |
| 4337 | tr.step(new ReplaceAroundStep(pos, pos + node.nodeSize, pos + 1, pos + node.nodeSize - 1, new Slice(Fragment.from(newNode), 0, 0), 1, true)); |
| 4338 | } |
| 4339 | function canSplit(doc3, pos, depth = 1, typesAfter) { |
| 4340 | let $pos = doc3.resolve(pos), base2 = $pos.depth - depth; |
| 4341 | let innerType = typesAfter && typesAfter[typesAfter.length - 1] || $pos.parent; |
| 4342 | if (base2 < 0 || $pos.parent.type.spec.isolating || !$pos.parent.canReplace($pos.index(), $pos.parent.childCount) || !innerType.type.validContent($pos.parent.content.cutByIndex($pos.index(), $pos.parent.childCount))) |
| 4343 | return false; |
| 4344 | for (let d = $pos.depth - 1, i2 = depth - 2; d > base2; d--, i2--) { |
| 4345 | let node = $pos.node(d), index2 = $pos.index(d); |
| 4346 | if (node.type.spec.isolating) |
| 4347 | return false; |
| 4348 | let rest = node.content.cutByIndex(index2, node.childCount); |
| 4349 | let overrideChild = typesAfter && typesAfter[i2 + 1]; |
| 4350 | if (overrideChild) |
| 4351 | rest = rest.replaceChild(0, overrideChild.type.create(overrideChild.attrs)); |
| 4352 | let after = typesAfter && typesAfter[i2] || node; |
| 4353 | if (!node.canReplace(index2 + 1, node.childCount) || !after.type.validContent(rest)) |
| 4354 | return false; |
| 4355 | } |
| 4356 | let index = $pos.indexAfter(base2); |
| 4357 | let baseType = typesAfter && typesAfter[0]; |
| 4358 | return $pos.node(base2).canReplaceWith(index, index, baseType ? baseType.type : $pos.node(base2 + 1).type); |
| 4359 | } |
| 4360 | function split(tr, pos, depth = 1, typesAfter) { |
| 4361 | let $pos = tr.doc.resolve(pos), before = Fragment.empty, after = Fragment.empty; |
| 4362 | for (let d = $pos.depth, e = $pos.depth - depth, i2 = depth - 1; d > e; d--, i2--) { |
| 4363 | before = Fragment.from($pos.node(d).copy(before)); |
| 4364 | let typeAfter = typesAfter && typesAfter[i2]; |
| 4365 | after = Fragment.from(typeAfter ? typeAfter.type.create(typeAfter.attrs, after) : $pos.node(d).copy(after)); |
| 4366 | } |
| 4367 | tr.step(new ReplaceStep(pos, pos, new Slice(before.append(after), depth, depth), true)); |
| 4368 | } |
| 4369 | function canJoin(doc3, pos) { |
| 4370 | let $pos = doc3.resolve(pos), index = $pos.index(); |
| 4371 | return joinable2($pos.nodeBefore, $pos.nodeAfter) && $pos.parent.canReplace(index, index + 1); |
| 4372 | } |
| 4373 | function canAppendWithSubstitutedLinebreaks(a, b) { |
| 4374 | if (!b.content.size) |
| 4375 | a.type.compatibleContent(b.type); |
| 4376 | let match = a.contentMatchAt(a.childCount); |
| 4377 | let { linebreakReplacement } = a.type.schema; |
| 4378 | for (let i2 = 0; i2 < b.childCount; i2++) { |
| 4379 | let child = b.child(i2); |
| 4380 | let type = child.type == linebreakReplacement ? a.type.schema.nodes.text : child.type; |
| 4381 | match = match.matchType(type); |
| 4382 | if (!match) |
| 4383 | return false; |
| 4384 | if (!a.type.allowsMarks(child.marks)) |
| 4385 | return false; |
| 4386 | } |
| 4387 | return match.validEnd; |
| 4388 | } |
| 4389 | function joinable2(a, b) { |
| 4390 | return !!(a && b && !a.isLeaf && canAppendWithSubstitutedLinebreaks(a, b)); |
| 4391 | } |
| 4392 | function joinPoint(doc3, pos, dir = -1) { |
| 4393 | let $pos = doc3.resolve(pos); |
| 4394 | for (let d = $pos.depth; ; d--) { |
| 4395 | let before, after, index = $pos.index(d); |
| 4396 | if (d == $pos.depth) { |
| 4397 | before = $pos.nodeBefore; |
| 4398 | after = $pos.nodeAfter; |
| 4399 | } else if (dir > 0) { |
| 4400 | before = $pos.node(d + 1); |
| 4401 | index++; |
| 4402 | after = $pos.node(d).maybeChild(index); |
| 4403 | } else { |
| 4404 | before = $pos.node(d).maybeChild(index - 1); |
| 4405 | after = $pos.node(d + 1); |
| 4406 | } |
| 4407 | if (before && !before.isTextblock && joinable2(before, after) && $pos.node(d).canReplace(index, index + 1)) |
| 4408 | return pos; |
| 4409 | if (d == 0) |
| 4410 | break; |
| 4411 | pos = dir < 0 ? $pos.before(d) : $pos.after(d); |
| 4412 | } |
| 4413 | } |
| 4414 | function join(tr, pos, depth) { |
| 4415 | let convertNewlines = null; |
| 4416 | let { linebreakReplacement } = tr.doc.type.schema; |
| 4417 | let $before = tr.doc.resolve(pos - depth), beforeType = $before.node().type; |
| 4418 | if (linebreakReplacement && beforeType.inlineContent) { |
| 4419 | let pre = beforeType.whitespace == "pre"; |
| 4420 | let supportLinebreak = !!beforeType.contentMatch.matchType(linebreakReplacement); |
| 4421 | if (pre && !supportLinebreak) |
| 4422 | convertNewlines = false; |
| 4423 | else if (!pre && supportLinebreak) |
| 4424 | convertNewlines = true; |
| 4425 | } |
| 4426 | let mapFrom = tr.steps.length; |
| 4427 | if (convertNewlines === false) { |
| 4428 | let $after = tr.doc.resolve(pos + depth); |
| 4429 | replaceLinebreaks(tr, $after.node(), $after.before(), mapFrom); |
| 4430 | } |
| 4431 | if (beforeType.inlineContent) |
| 4432 | clearIncompatible(tr, pos + depth - 1, beforeType, $before.node().contentMatchAt($before.index()), convertNewlines == null); |
| 4433 | let mapping = tr.mapping.slice(mapFrom), start = mapping.map(pos - depth); |
| 4434 | tr.step(new ReplaceStep(start, mapping.map(pos + depth, -1), Slice.empty, true)); |
| 4435 | if (convertNewlines === true) { |
| 4436 | let $full = tr.doc.resolve(start); |
| 4437 | replaceNewlines(tr, $full.node(), $full.before(), tr.steps.length); |
| 4438 | } |
| 4439 | return tr; |
| 4440 | } |
| 4441 | function insertPoint(doc3, pos, nodeType) { |
| 4442 | let $pos = doc3.resolve(pos); |
| 4443 | if ($pos.parent.canReplaceWith($pos.index(), $pos.index(), nodeType)) |
| 4444 | return pos; |
| 4445 | if ($pos.parentOffset == 0) |
| 4446 | for (let d = $pos.depth - 1; d >= 0; d--) { |
| 4447 | let index = $pos.index(d); |
| 4448 | if ($pos.node(d).canReplaceWith(index, index, nodeType)) |
| 4449 | return $pos.before(d + 1); |
| 4450 | if (index > 0) |
| 4451 | return null; |
| 4452 | } |
| 4453 | if ($pos.parentOffset == $pos.parent.content.size) |
| 4454 | for (let d = $pos.depth - 1; d >= 0; d--) { |
| 4455 | let index = $pos.indexAfter(d); |
| 4456 | if ($pos.node(d).canReplaceWith(index, index, nodeType)) |
| 4457 | return $pos.after(d + 1); |
| 4458 | if (index < $pos.node(d).childCount) |
| 4459 | return null; |
| 4460 | } |
| 4461 | return null; |
| 4462 | } |
| 4463 | function dropPoint(doc3, pos, slice2) { |
| 4464 | let $pos = doc3.resolve(pos); |
| 4465 | if (!slice2.content.size) |
| 4466 | return pos; |
| 4467 | let content = slice2.content; |
| 4468 | for (let i2 = 0; i2 < slice2.openStart; i2++) |
| 4469 | content = content.firstChild.content; |
| 4470 | for (let pass = 1; pass <= (slice2.openStart == 0 && slice2.size ? 2 : 1); pass++) { |
| 4471 | for (let d = $pos.depth; d >= 0; d--) { |
| 4472 | let bias = d == $pos.depth ? 0 : $pos.pos <= ($pos.start(d + 1) + $pos.end(d + 1)) / 2 ? -1 : 1; |
| 4473 | let insertPos = $pos.index(d) + (bias > 0 ? 1 : 0); |
| 4474 | let parent = $pos.node(d), fits = false; |
| 4475 | if (pass == 1) { |
| 4476 | fits = parent.canReplace(insertPos, insertPos, content); |
| 4477 | } else { |
| 4478 | let wrapping = parent.contentMatchAt(insertPos).findWrapping(content.firstChild.type); |
| 4479 | fits = wrapping && parent.canReplaceWith(insertPos, insertPos, wrapping[0]); |
| 4480 | } |
| 4481 | if (fits) |
| 4482 | return bias == 0 ? $pos.pos : bias < 0 ? $pos.before(d + 1) : $pos.after(d + 1); |
| 4483 | } |
| 4484 | } |
| 4485 | return null; |
| 4486 | } |
| 4487 | function replaceStep(doc3, from2, to = from2, slice2 = Slice.empty) { |
| 4488 | if (from2 == to && !slice2.size) |
| 4489 | return null; |
| 4490 | let $from = doc3.resolve(from2), $to = doc3.resolve(to); |
| 4491 | if (fitsTrivially($from, $to, slice2)) |
| 4492 | return new ReplaceStep(from2, to, slice2); |
| 4493 | return new Fitter($from, $to, slice2).fit(); |
| 4494 | } |
| 4495 | function fitsTrivially($from, $to, slice2) { |
| 4496 | return !slice2.openStart && !slice2.openEnd && $from.start() == $to.start() && $from.parent.canReplace($from.index(), $to.index(), slice2.content); |
| 4497 | } |
| 4498 | var Fitter = class { |
| 4499 | constructor($from, $to, unplaced) { |
| 4500 | this.$from = $from; |
| 4501 | this.$to = $to; |
| 4502 | this.unplaced = unplaced; |
| 4503 | this.frontier = []; |
| 4504 | this.placed = Fragment.empty; |
| 4505 | for (let i2 = 0; i2 <= $from.depth; i2++) { |
| 4506 | let node = $from.node(i2); |
| 4507 | this.frontier.push({ |
| 4508 | type: node.type, |
| 4509 | match: node.contentMatchAt($from.indexAfter(i2)) |
| 4510 | }); |
| 4511 | } |
| 4512 | for (let i2 = $from.depth; i2 > 0; i2--) |
| 4513 | this.placed = Fragment.from($from.node(i2).copy(this.placed)); |
| 4514 | } |
| 4515 | get depth() { |
| 4516 | return this.frontier.length - 1; |
| 4517 | } |
| 4518 | fit() { |
| 4519 | while (this.unplaced.size) { |
| 4520 | let fit = this.findFittable(); |
| 4521 | if (fit) |
| 4522 | this.placeNodes(fit); |
| 4523 | else |
| 4524 | this.openMore() || this.dropNode(); |
| 4525 | } |
| 4526 | let moveInline = this.mustMoveInline(), placedSize = this.placed.size - this.depth - this.$from.depth; |
| 4527 | let $from = this.$from, $to = this.close(moveInline < 0 ? this.$to : $from.doc.resolve(moveInline)); |
| 4528 | if (!$to) |
| 4529 | return null; |
| 4530 | let content = this.placed, openStart = $from.depth, openEnd = $to.depth; |
| 4531 | while (openStart && openEnd && content.childCount == 1) { |
| 4532 | content = content.firstChild.content; |
| 4533 | openStart--; |
| 4534 | openEnd--; |
| 4535 | } |
| 4536 | let slice2 = new Slice(content, openStart, openEnd); |
| 4537 | if (moveInline > -1) |
| 4538 | return new ReplaceAroundStep($from.pos, moveInline, this.$to.pos, this.$to.end(), slice2, placedSize); |
| 4539 | if (slice2.size || $from.pos != this.$to.pos) |
| 4540 | return new ReplaceStep($from.pos, $to.pos, slice2); |
| 4541 | return null; |
| 4542 | } |
| 4543 | // Find a position on the start spine of `this.unplaced` that has |
| 4544 | // content that can be moved somewhere on the frontier. Returns two |
| 4545 | // depths, one for the slice and one for the frontier. |
| 4546 | findFittable() { |
| 4547 | let startDepth = this.unplaced.openStart; |
| 4548 | for (let cur = this.unplaced.content, d = 0, openEnd = this.unplaced.openEnd; d < startDepth; d++) { |
| 4549 | let node = cur.firstChild; |
| 4550 | if (cur.childCount > 1) |
| 4551 | openEnd = 0; |
| 4552 | if (node.type.spec.isolating && openEnd <= d) { |
| 4553 | startDepth = d; |
| 4554 | break; |
| 4555 | } |
| 4556 | cur = node.content; |
| 4557 | } |
| 4558 | for (let pass = 1; pass <= 2; pass++) { |
| 4559 | for (let sliceDepth = pass == 1 ? startDepth : this.unplaced.openStart; sliceDepth >= 0; sliceDepth--) { |
| 4560 | let fragment, parent = null; |
| 4561 | if (sliceDepth) { |
| 4562 | parent = contentAt(this.unplaced.content, sliceDepth - 1).firstChild; |
| 4563 | fragment = parent.content; |
| 4564 | } else { |
| 4565 | fragment = this.unplaced.content; |
| 4566 | } |
| 4567 | let first = fragment.firstChild; |
| 4568 | for (let frontierDepth = this.depth; frontierDepth >= 0; frontierDepth--) { |
| 4569 | let { type, match } = this.frontier[frontierDepth], wrap2, inject = null; |
| 4570 | if (pass == 1 && (first ? match.matchType(first.type) || (inject = match.fillBefore(Fragment.from(first), false)) : parent && type.compatibleContent(parent.type))) |
| 4571 | return { sliceDepth, frontierDepth, parent, inject }; |
| 4572 | else if (pass == 2 && first && (wrap2 = match.findWrapping(first.type))) |
| 4573 | return { sliceDepth, frontierDepth, parent, wrap: wrap2 }; |
| 4574 | if (parent && match.matchType(parent.type)) |
| 4575 | break; |
| 4576 | } |
| 4577 | } |
| 4578 | } |
| 4579 | } |
| 4580 | openMore() { |
| 4581 | let { content, openStart, openEnd } = this.unplaced; |
| 4582 | let inner = contentAt(content, openStart); |
| 4583 | if (!inner.childCount || inner.firstChild.isLeaf) |
| 4584 | return false; |
| 4585 | this.unplaced = new Slice(content, openStart + 1, Math.max(openEnd, inner.size + openStart >= content.size - openEnd ? openStart + 1 : 0)); |
| 4586 | return true; |
| 4587 | } |
| 4588 | dropNode() { |
| 4589 | let { content, openStart, openEnd } = this.unplaced; |
| 4590 | let inner = contentAt(content, openStart); |
| 4591 | if (inner.childCount <= 1 && openStart > 0) { |
| 4592 | let openAtEnd = content.size - openStart <= openStart + inner.size; |
| 4593 | this.unplaced = new Slice(dropFromFragment(content, openStart - 1, 1), openStart - 1, openAtEnd ? openStart - 1 : openEnd); |
| 4594 | } else { |
| 4595 | this.unplaced = new Slice(dropFromFragment(content, openStart, 1), openStart, openEnd); |
| 4596 | } |
| 4597 | } |
| 4598 | // Move content from the unplaced slice at `sliceDepth` to the |
| 4599 | // frontier node at `frontierDepth`. Close that frontier node when |
| 4600 | // applicable. |
| 4601 | placeNodes({ sliceDepth, frontierDepth, parent, inject, wrap: wrap2 }) { |
| 4602 | while (this.depth > frontierDepth) |
| 4603 | this.closeFrontierNode(); |
| 4604 | if (wrap2) |
| 4605 | for (let i2 = 0; i2 < wrap2.length; i2++) |
| 4606 | this.openFrontierNode(wrap2[i2]); |
| 4607 | let slice2 = this.unplaced, fragment = parent ? parent.content : slice2.content; |
| 4608 | let openStart = slice2.openStart - sliceDepth; |
| 4609 | let taken = 0, add2 = []; |
| 4610 | let { match, type } = this.frontier[frontierDepth]; |
| 4611 | if (inject) { |
| 4612 | for (let i2 = 0; i2 < inject.childCount; i2++) |
| 4613 | add2.push(inject.child(i2)); |
| 4614 | match = match.matchFragment(inject); |
| 4615 | } |
| 4616 | let openEndCount = fragment.size + sliceDepth - (slice2.content.size - slice2.openEnd); |
| 4617 | while (taken < fragment.childCount) { |
| 4618 | let next = fragment.child(taken), matches2 = match.matchType(next.type); |
| 4619 | if (!matches2) |
| 4620 | break; |
| 4621 | taken++; |
| 4622 | if (taken > 1 || openStart == 0 || next.content.size) { |
| 4623 | match = matches2; |
| 4624 | add2.push(closeNodeStart(next.mark(type.allowedMarks(next.marks)), taken == 1 ? openStart : 0, taken == fragment.childCount ? openEndCount : -1)); |
| 4625 | } |
| 4626 | } |
| 4627 | let toEnd = taken == fragment.childCount; |
| 4628 | if (!toEnd) |
| 4629 | openEndCount = -1; |
| 4630 | this.placed = addToFragment(this.placed, frontierDepth, Fragment.from(add2)); |
| 4631 | this.frontier[frontierDepth].match = match; |
| 4632 | if (toEnd && openEndCount < 0 && parent && parent.type == this.frontier[this.depth].type && this.frontier.length > 1) |
| 4633 | this.closeFrontierNode(); |
| 4634 | for (let i2 = 0, cur = fragment; i2 < openEndCount; i2++) { |
| 4635 | let node = cur.lastChild; |
| 4636 | this.frontier.push({ type: node.type, match: node.contentMatchAt(node.childCount) }); |
| 4637 | cur = node.content; |
| 4638 | } |
| 4639 | this.unplaced = !toEnd ? new Slice(dropFromFragment(slice2.content, sliceDepth, taken), slice2.openStart, slice2.openEnd) : sliceDepth == 0 ? Slice.empty : new Slice(dropFromFragment(slice2.content, sliceDepth - 1, 1), sliceDepth - 1, openEndCount < 0 ? slice2.openEnd : sliceDepth - 1); |
| 4640 | } |
| 4641 | mustMoveInline() { |
| 4642 | if (!this.$to.parent.isTextblock) |
| 4643 | return -1; |
| 4644 | let top = this.frontier[this.depth], level; |
| 4645 | if (!top.type.isTextblock || !contentAfterFits(this.$to, this.$to.depth, top.type, top.match, false) || this.$to.depth == this.depth && (level = this.findCloseLevel(this.$to)) && level.depth == this.depth) |
| 4646 | return -1; |
| 4647 | let { depth } = this.$to, after = this.$to.after(depth); |
| 4648 | while (depth > 1 && after == this.$to.end(--depth)) |
| 4649 | ++after; |
| 4650 | return after; |
| 4651 | } |
| 4652 | findCloseLevel($to) { |
| 4653 | scan: for (let i2 = Math.min(this.depth, $to.depth); i2 >= 0; i2--) { |
| 4654 | let { match, type } = this.frontier[i2]; |
| 4655 | let dropInner = i2 < $to.depth && $to.end(i2 + 1) == $to.pos + ($to.depth - (i2 + 1)); |
| 4656 | let fit = contentAfterFits($to, i2, type, match, dropInner); |
| 4657 | if (!fit) |
| 4658 | continue; |
| 4659 | for (let d = i2 - 1; d >= 0; d--) { |
| 4660 | let { match: match2, type: type2 } = this.frontier[d]; |
| 4661 | let matches2 = contentAfterFits($to, d, type2, match2, true); |
| 4662 | if (!matches2 || matches2.childCount) |
| 4663 | continue scan; |
| 4664 | } |
| 4665 | return { depth: i2, fit, move: dropInner ? $to.doc.resolve($to.after(i2 + 1)) : $to }; |
| 4666 | } |
| 4667 | } |
| 4668 | close($to) { |
| 4669 | let close2 = this.findCloseLevel($to); |
| 4670 | if (!close2) |
| 4671 | return null; |
| 4672 | while (this.depth > close2.depth) |
| 4673 | this.closeFrontierNode(); |
| 4674 | if (close2.fit.childCount) |
| 4675 | this.placed = addToFragment(this.placed, close2.depth, close2.fit); |
| 4676 | $to = close2.move; |
| 4677 | for (let d = close2.depth + 1; d <= $to.depth; d++) { |
| 4678 | let node = $to.node(d), add2 = node.type.contentMatch.fillBefore(node.content, true, $to.index(d)); |
| 4679 | this.openFrontierNode(node.type, node.attrs, add2); |
| 4680 | } |
| 4681 | return $to; |
| 4682 | } |
| 4683 | openFrontierNode(type, attrs2 = null, content) { |
| 4684 | let top = this.frontier[this.depth]; |
| 4685 | top.match = top.match.matchType(type); |
| 4686 | this.placed = addToFragment(this.placed, this.depth, Fragment.from(type.create(attrs2, content))); |
| 4687 | this.frontier.push({ type, match: type.contentMatch }); |
| 4688 | } |
| 4689 | closeFrontierNode() { |
| 4690 | let open = this.frontier.pop(); |
| 4691 | let add2 = open.match.fillBefore(Fragment.empty, true); |
| 4692 | if (add2.childCount) |
| 4693 | this.placed = addToFragment(this.placed, this.frontier.length, add2); |
| 4694 | } |
| 4695 | }; |
| 4696 | function dropFromFragment(fragment, depth, count) { |
| 4697 | if (depth == 0) |
| 4698 | return fragment.cutByIndex(count, fragment.childCount); |
| 4699 | return fragment.replaceChild(0, fragment.firstChild.copy(dropFromFragment(fragment.firstChild.content, depth - 1, count))); |
| 4700 | } |
| 4701 | function addToFragment(fragment, depth, content) { |
| 4702 | if (depth == 0) |
| 4703 | return fragment.append(content); |
| 4704 | return fragment.replaceChild(fragment.childCount - 1, fragment.lastChild.copy(addToFragment(fragment.lastChild.content, depth - 1, content))); |
| 4705 | } |
| 4706 | function contentAt(fragment, depth) { |
| 4707 | for (let i2 = 0; i2 < depth; i2++) |
| 4708 | fragment = fragment.firstChild.content; |
| 4709 | return fragment; |
| 4710 | } |
| 4711 | function closeNodeStart(node, openStart, openEnd) { |
| 4712 | if (openStart <= 0) |
| 4713 | return node; |
| 4714 | let frag = node.content; |
| 4715 | if (openStart > 1) |
| 4716 | frag = frag.replaceChild(0, closeNodeStart(frag.firstChild, openStart - 1, frag.childCount == 1 ? openEnd - 1 : 0)); |
| 4717 | if (openStart > 0) { |
| 4718 | frag = node.type.contentMatch.fillBefore(frag).append(frag); |
| 4719 | if (openEnd <= 0) |
| 4720 | frag = frag.append(node.type.contentMatch.matchFragment(frag).fillBefore(Fragment.empty, true)); |
| 4721 | } |
| 4722 | return node.copy(frag); |
| 4723 | } |
| 4724 | function contentAfterFits($to, depth, type, match, open) { |
| 4725 | let node = $to.node(depth), index = open ? $to.indexAfter(depth) : $to.index(depth); |
| 4726 | if (index == node.childCount && !type.compatibleContent(node.type)) |
| 4727 | return null; |
| 4728 | let fit = match.fillBefore(node.content, true, index); |
| 4729 | return fit && !invalidMarks(type, node.content, index) ? fit : null; |
| 4730 | } |
| 4731 | function invalidMarks(type, fragment, start) { |
| 4732 | for (let i2 = start; i2 < fragment.childCount; i2++) |
| 4733 | if (!type.allowsMarks(fragment.child(i2).marks)) |
| 4734 | return true; |
| 4735 | return false; |
| 4736 | } |
| 4737 | function definesContent(type) { |
| 4738 | return type.spec.defining || type.spec.definingForContent; |
| 4739 | } |
| 4740 | function replaceRange(tr, from2, to, slice2) { |
| 4741 | if (!slice2.size) |
| 4742 | return tr.deleteRange(from2, to); |
| 4743 | let $from = tr.doc.resolve(from2), $to = tr.doc.resolve(to); |
| 4744 | if (fitsTrivially($from, $to, slice2)) |
| 4745 | return tr.step(new ReplaceStep(from2, to, slice2)); |
| 4746 | let targetDepths = coveredDepths($from, $to); |
| 4747 | if (targetDepths[targetDepths.length - 1] == 0) |
| 4748 | targetDepths.pop(); |
| 4749 | let preferredTarget = -($from.depth + 1); |
| 4750 | targetDepths.unshift(preferredTarget); |
| 4751 | for (let d = $from.depth, pos = $from.pos - 1; d > 0; d--, pos--) { |
| 4752 | let spec = $from.node(d).type.spec; |
| 4753 | if (spec.defining || spec.definingAsContext || spec.isolating) |
| 4754 | break; |
| 4755 | if (targetDepths.indexOf(d) > -1) |
| 4756 | preferredTarget = d; |
| 4757 | else if ($from.before(d) == pos) |
| 4758 | targetDepths.splice(1, 0, -d); |
| 4759 | } |
| 4760 | let preferredTargetIndex = targetDepths.indexOf(preferredTarget); |
| 4761 | let leftNodes = [], preferredDepth = slice2.openStart; |
| 4762 | for (let content = slice2.content, i2 = 0; ; i2++) { |
| 4763 | let node = content.firstChild; |
| 4764 | leftNodes.push(node); |
| 4765 | if (i2 == slice2.openStart) |
| 4766 | break; |
| 4767 | content = node.content; |
| 4768 | } |
| 4769 | for (let d = preferredDepth - 1; d >= 0; d--) { |
| 4770 | let leftNode = leftNodes[d], def = definesContent(leftNode.type); |
| 4771 | if (def && !leftNode.sameMarkup($from.node(Math.abs(preferredTarget) - 1))) |
| 4772 | preferredDepth = d; |
| 4773 | else if (def || !leftNode.type.isTextblock) |
| 4774 | break; |
| 4775 | } |
| 4776 | for (let j = slice2.openStart; j >= 0; j--) { |
| 4777 | let openDepth = (j + preferredDepth + 1) % (slice2.openStart + 1); |
| 4778 | let insert = leftNodes[openDepth]; |
| 4779 | if (!insert) |
| 4780 | continue; |
| 4781 | for (let i2 = 0; i2 < targetDepths.length; i2++) { |
| 4782 | let targetDepth = targetDepths[(i2 + preferredTargetIndex) % targetDepths.length], expand = true; |
| 4783 | if (targetDepth < 0) { |
| 4784 | expand = false; |
| 4785 | targetDepth = -targetDepth; |
| 4786 | } |
| 4787 | let parent = $from.node(targetDepth - 1), index = $from.index(targetDepth - 1); |
| 4788 | if (parent.canReplaceWith(index, index, insert.type, insert.marks)) |
| 4789 | return tr.replace($from.before(targetDepth), expand ? $to.after(targetDepth) : to, new Slice(closeFragment(slice2.content, 0, slice2.openStart, openDepth), openDepth, slice2.openEnd)); |
| 4790 | } |
| 4791 | } |
| 4792 | let startSteps = tr.steps.length; |
| 4793 | for (let i2 = targetDepths.length - 1; i2 >= 0; i2--) { |
| 4794 | tr.replace(from2, to, slice2); |
| 4795 | if (tr.steps.length > startSteps) |
| 4796 | break; |
| 4797 | let depth = targetDepths[i2]; |
| 4798 | if (depth < 0) |
| 4799 | continue; |
| 4800 | from2 = $from.before(depth); |
| 4801 | to = $to.after(depth); |
| 4802 | } |
| 4803 | } |
| 4804 | function closeFragment(fragment, depth, oldOpen, newOpen, parent) { |
| 4805 | if (depth < oldOpen) { |
| 4806 | let first = fragment.firstChild; |
| 4807 | fragment = fragment.replaceChild(0, first.copy(closeFragment(first.content, depth + 1, oldOpen, newOpen, first))); |
| 4808 | } |
| 4809 | if (depth > newOpen) { |
| 4810 | let match = parent.contentMatchAt(0); |
| 4811 | let start = match.fillBefore(fragment).append(fragment); |
| 4812 | fragment = start.append(match.matchFragment(start).fillBefore(Fragment.empty, true)); |
| 4813 | } |
| 4814 | return fragment; |
| 4815 | } |
| 4816 | function replaceRangeWith(tr, from2, to, node) { |
| 4817 | if (!node.isInline && from2 == to && tr.doc.resolve(from2).parent.content.size) { |
| 4818 | let point = insertPoint(tr.doc, from2, node.type); |
| 4819 | if (point != null) |
| 4820 | from2 = to = point; |
| 4821 | } |
| 4822 | tr.replaceRange(from2, to, new Slice(Fragment.from(node), 0, 0)); |
| 4823 | } |
| 4824 | function deleteRange(tr, from2, to) { |
| 4825 | let $from = tr.doc.resolve(from2), $to = tr.doc.resolve(to); |
| 4826 | if ($from.parent.isTextblock && $to.parent.isTextblock && $from.start() != $to.start() && $from.parentOffset == 0 && $to.parentOffset == 0) { |
| 4827 | let shared = $from.sharedDepth(to), isolated = false; |
| 4828 | for (let d = $from.depth; d > shared; d--) |
| 4829 | if ($from.node(d).type.spec.isolating) |
| 4830 | isolated = true; |
| 4831 | for (let d = $to.depth; d > shared; d--) |
| 4832 | if ($to.node(d).type.spec.isolating) |
| 4833 | isolated = true; |
| 4834 | if (!isolated) { |
| 4835 | for (let d = $from.depth; d > 0 && from2 == $from.start(d); d--) |
| 4836 | from2 = $from.before(d); |
| 4837 | for (let d = $to.depth; d > 0 && to == $to.start(d); d--) |
| 4838 | to = $to.before(d); |
| 4839 | $from = tr.doc.resolve(from2); |
| 4840 | $to = tr.doc.resolve(to); |
| 4841 | } |
| 4842 | } |
| 4843 | let covered = coveredDepths($from, $to); |
| 4844 | for (let i2 = 0; i2 < covered.length; i2++) { |
| 4845 | let depth = covered[i2], last = i2 == covered.length - 1; |
| 4846 | if (last && depth == 0 || $from.node(depth).type.contentMatch.validEnd) |
| 4847 | return tr.delete($from.start(depth), $to.end(depth)); |
| 4848 | if (depth > 0 && (last || $from.node(depth - 1).canReplace($from.index(depth - 1), $to.indexAfter(depth - 1)))) |
| 4849 | return tr.delete($from.before(depth), $to.after(depth)); |
| 4850 | } |
| 4851 | for (let d = 1; d <= $from.depth && d <= $to.depth; d++) { |
| 4852 | if (from2 - $from.start(d) == $from.depth - d && to > $from.end(d) && $to.end(d) - to != $to.depth - d && $from.start(d - 1) == $to.start(d - 1) && $from.node(d - 1).canReplace($from.index(d - 1), $to.index(d - 1))) |
| 4853 | return tr.delete($from.before(d), to); |
| 4854 | } |
| 4855 | tr.delete(from2, to); |
| 4856 | } |
| 4857 | function coveredDepths($from, $to) { |
| 4858 | let result = [], minDepth = Math.min($from.depth, $to.depth); |
| 4859 | for (let d = minDepth; d >= 0; d--) { |
| 4860 | let start = $from.start(d); |
| 4861 | if (start < $from.pos - ($from.depth - d) || $to.end(d) > $to.pos + ($to.depth - d) || $from.node(d).type.spec.isolating || $to.node(d).type.spec.isolating) |
| 4862 | break; |
| 4863 | if (start == $to.start(d) || d == $from.depth && d == $to.depth && $from.parent.inlineContent && $to.parent.inlineContent && d && $to.start(d - 1) == start - 1) |
| 4864 | result.push(d); |
| 4865 | } |
| 4866 | return result; |
| 4867 | } |
| 4868 | var AttrStep = class _AttrStep extends Step { |
| 4869 | /** |
| 4870 | Construct an attribute step. |
| 4871 | */ |
| 4872 | constructor(pos, attr, value) { |
| 4873 | super(); |
| 4874 | this.pos = pos; |
| 4875 | this.attr = attr; |
| 4876 | this.value = value; |
| 4877 | } |
| 4878 | apply(doc3) { |
| 4879 | let node = doc3.nodeAt(this.pos); |
| 4880 | if (!node) |
| 4881 | return StepResult.fail("No node at attribute step's position"); |
| 4882 | let attrs2 = /* @__PURE__ */ Object.create(null); |
| 4883 | for (let name in node.attrs) |
| 4884 | attrs2[name] = node.attrs[name]; |
| 4885 | attrs2[this.attr] = this.value; |
| 4886 | let updated = node.type.create(attrs2, null, node.marks); |
| 4887 | return StepResult.fromReplace(doc3, this.pos, this.pos + 1, new Slice(Fragment.from(updated), 0, node.isLeaf ? 0 : 1)); |
| 4888 | } |
| 4889 | getMap() { |
| 4890 | return StepMap.empty; |
| 4891 | } |
| 4892 | invert(doc3) { |
| 4893 | return new _AttrStep(this.pos, this.attr, doc3.nodeAt(this.pos).attrs[this.attr]); |
| 4894 | } |
| 4895 | map(mapping) { |
| 4896 | let pos = mapping.mapResult(this.pos, 1); |
| 4897 | return pos.deletedAfter ? null : new _AttrStep(pos.pos, this.attr, this.value); |
| 4898 | } |
| 4899 | toJSON() { |
| 4900 | return { stepType: "attr", pos: this.pos, attr: this.attr, value: this.value }; |
| 4901 | } |
| 4902 | static fromJSON(schema2, json) { |
| 4903 | if (typeof json.pos != "number" || typeof json.attr != "string") |
| 4904 | throw new RangeError("Invalid input for AttrStep.fromJSON"); |
| 4905 | return new _AttrStep(json.pos, json.attr, json.value); |
| 4906 | } |
| 4907 | }; |
| 4908 | Step.jsonID("attr", AttrStep); |
| 4909 | var DocAttrStep = class _DocAttrStep extends Step { |
| 4910 | /** |
| 4911 | Construct an attribute step. |
| 4912 | */ |
| 4913 | constructor(attr, value) { |
| 4914 | super(); |
| 4915 | this.attr = attr; |
| 4916 | this.value = value; |
| 4917 | } |
| 4918 | apply(doc3) { |
| 4919 | let attrs2 = /* @__PURE__ */ Object.create(null); |
| 4920 | for (let name in doc3.attrs) |
| 4921 | attrs2[name] = doc3.attrs[name]; |
| 4922 | attrs2[this.attr] = this.value; |
| 4923 | let updated = doc3.type.create(attrs2, doc3.content, doc3.marks); |
| 4924 | return StepResult.ok(updated); |
| 4925 | } |
| 4926 | getMap() { |
| 4927 | return StepMap.empty; |
| 4928 | } |
| 4929 | invert(doc3) { |
| 4930 | return new _DocAttrStep(this.attr, doc3.attrs[this.attr]); |
| 4931 | } |
| 4932 | map(mapping) { |
| 4933 | return this; |
| 4934 | } |
| 4935 | toJSON() { |
| 4936 | return { stepType: "docAttr", attr: this.attr, value: this.value }; |
| 4937 | } |
| 4938 | static fromJSON(schema2, json) { |
| 4939 | if (typeof json.attr != "string") |
| 4940 | throw new RangeError("Invalid input for DocAttrStep.fromJSON"); |
| 4941 | return new _DocAttrStep(json.attr, json.value); |
| 4942 | } |
| 4943 | }; |
| 4944 | Step.jsonID("docAttr", DocAttrStep); |
| 4945 | var TransformError = class extends Error { |
| 4946 | }; |
| 4947 | TransformError = function TransformError2(message) { |
| 4948 | let err = Error.call(this, message); |
| 4949 | err.__proto__ = TransformError2.prototype; |
| 4950 | return err; |
| 4951 | }; |
| 4952 | TransformError.prototype = Object.create(Error.prototype); |
| 4953 | TransformError.prototype.constructor = TransformError; |
| 4954 | TransformError.prototype.name = "TransformError"; |
| 4955 | var Transform = class { |
| 4956 | /** |
| 4957 | Create a transform that starts with the given document. |
| 4958 | */ |
| 4959 | constructor(doc3) { |
| 4960 | this.doc = doc3; |
| 4961 | this.steps = []; |
| 4962 | this.docs = []; |
| 4963 | this.mapping = new Mapping(); |
| 4964 | } |
| 4965 | /** |
| 4966 | The starting document. |
| 4967 | */ |
| 4968 | get before() { |
| 4969 | return this.docs.length ? this.docs[0] : this.doc; |
| 4970 | } |
| 4971 | /** |
| 4972 | Apply a new step in this transform, saving the result. Throws an |
| 4973 | error when the step fails. |
| 4974 | */ |
| 4975 | step(step) { |
| 4976 | let result = this.maybeStep(step); |
| 4977 | if (result.failed) |
| 4978 | throw new TransformError(result.failed); |
| 4979 | return this; |
| 4980 | } |
| 4981 | /** |
| 4982 | Try to apply a step in this transformation, ignoring it if it |
| 4983 | fails. Returns the step result. |
| 4984 | */ |
| 4985 | maybeStep(step) { |
| 4986 | let result = step.apply(this.doc); |
| 4987 | if (!result.failed) |
| 4988 | this.addStep(step, result.doc); |
| 4989 | return result; |
| 4990 | } |
| 4991 | /** |
| 4992 | True when the document has been changed (when there are any |
| 4993 | steps). |
| 4994 | */ |
| 4995 | get docChanged() { |
| 4996 | return this.steps.length > 0; |
| 4997 | } |
| 4998 | /** |
| 4999 | Return a single range, in post-transform document positions, |
| 5000 | that covers all content changed by this transform. Returns null |
| 5001 | if no replacements are made. Note that this will ignore changes |
| 5002 | that add/remove marks without replacing the underlying content. |
| 5003 | */ |
| 5004 | changedRange() { |
| 5005 | let from2 = 1e9, to = -1e9; |
| 5006 | for (let i2 = 0; i2 < this.mapping.maps.length; i2++) { |
| 5007 | let map2 = this.mapping.maps[i2]; |
| 5008 | if (i2) { |
| 5009 | from2 = map2.map(from2, 1); |
| 5010 | to = map2.map(to, -1); |
| 5011 | } |
| 5012 | map2.forEach((_f, _t, fromB, toB) => { |
| 5013 | from2 = Math.min(from2, fromB); |
| 5014 | to = Math.max(to, toB); |
| 5015 | }); |
| 5016 | } |
| 5017 | return from2 == 1e9 ? null : { from: from2, to }; |
| 5018 | } |
| 5019 | /** |
| 5020 | @internal |
| 5021 | */ |
| 5022 | addStep(step, doc3) { |
| 5023 | this.docs.push(this.doc); |
| 5024 | this.steps.push(step); |
| 5025 | this.mapping.appendMap(step.getMap()); |
| 5026 | this.doc = doc3; |
| 5027 | } |
| 5028 | /** |
| 5029 | Replace the part of the document between `from` and `to` with the |
| 5030 | given `slice`. |
| 5031 | */ |
| 5032 | replace(from2, to = from2, slice2 = Slice.empty) { |
| 5033 | let step = replaceStep(this.doc, from2, to, slice2); |
| 5034 | if (step) |
| 5035 | this.step(step); |
| 5036 | return this; |
| 5037 | } |
| 5038 | /** |
| 5039 | Replace the given range with the given content, which may be a |
| 5040 | fragment, node, or array of nodes. |
| 5041 | */ |
| 5042 | replaceWith(from2, to, content) { |
| 5043 | return this.replace(from2, to, new Slice(Fragment.from(content), 0, 0)); |
| 5044 | } |
| 5045 | /** |
| 5046 | Delete the content between the given positions. |
| 5047 | */ |
| 5048 | delete(from2, to) { |
| 5049 | return this.replace(from2, to, Slice.empty); |
| 5050 | } |
| 5051 | /** |
| 5052 | Insert the given content at the given position. |
| 5053 | */ |
| 5054 | insert(pos, content) { |
| 5055 | return this.replaceWith(pos, pos, content); |
| 5056 | } |
| 5057 | /** |
| 5058 | Replace a range of the document with a given slice, using |
| 5059 | `from`, `to`, and the slice's |
| 5060 | [`openStart`](https://prosemirror.net/docs/ref/#model.Slice.openStart) property as hints, rather |
| 5061 | than fixed start and end points. This method may grow the |
| 5062 | replaced area or close open nodes in the slice in order to get a |
| 5063 | fit that is more in line with WYSIWYG expectations, by dropping |
| 5064 | fully covered parent nodes of the replaced region when they are |
| 5065 | marked [non-defining as |
| 5066 | context](https://prosemirror.net/docs/ref/#model.NodeSpec.definingAsContext), or including an |
| 5067 | open parent node from the slice that _is_ marked as [defining |
| 5068 | its content](https://prosemirror.net/docs/ref/#model.NodeSpec.definingForContent). |
| 5069 | |
| 5070 | This is the method, for example, to handle paste. The similar |
| 5071 | [`replace`](https://prosemirror.net/docs/ref/#transform.Transform.replace) method is a more |
| 5072 | primitive tool which will _not_ move the start and end of its given |
| 5073 | range, and is useful in situations where you need more precise |
| 5074 | control over what happens. |
| 5075 | */ |
| 5076 | replaceRange(from2, to, slice2) { |
| 5077 | replaceRange(this, from2, to, slice2); |
| 5078 | return this; |
| 5079 | } |
| 5080 | /** |
| 5081 | Replace the given range with a node, but use `from` and `to` as |
| 5082 | hints, rather than precise positions. When from and to are the same |
| 5083 | and are at the start or end of a parent node in which the given |
| 5084 | node doesn't fit, this method may _move_ them out towards a parent |
| 5085 | that does allow the given node to be placed. When the given range |
| 5086 | completely covers a parent node, this method may completely replace |
| 5087 | that parent node. |
| 5088 | */ |
| 5089 | replaceRangeWith(from2, to, node) { |
| 5090 | replaceRangeWith(this, from2, to, node); |
| 5091 | return this; |
| 5092 | } |
| 5093 | /** |
| 5094 | Delete the given range, expanding it to cover fully covered |
| 5095 | parent nodes until a valid replace is found. |
| 5096 | */ |
| 5097 | deleteRange(from2, to) { |
| 5098 | deleteRange(this, from2, to); |
| 5099 | return this; |
| 5100 | } |
| 5101 | /** |
| 5102 | Split the content in the given range off from its parent, if there |
| 5103 | is sibling content before or after it, and move it up the tree to |
| 5104 | the depth specified by `target`. You'll probably want to use |
| 5105 | [`liftTarget`](https://prosemirror.net/docs/ref/#transform.liftTarget) to compute `target`, to make |
| 5106 | sure the lift is valid. |
| 5107 | */ |
| 5108 | lift(range, target) { |
| 5109 | lift(this, range, target); |
| 5110 | return this; |
| 5111 | } |
| 5112 | /** |
| 5113 | Join the blocks around the given position. If depth is 2, their |
| 5114 | last and first siblings are also joined, and so on. |
| 5115 | */ |
| 5116 | join(pos, depth = 1) { |
| 5117 | join(this, pos, depth); |
| 5118 | return this; |
| 5119 | } |
| 5120 | /** |
| 5121 | Wrap the given [range](https://prosemirror.net/docs/ref/#model.NodeRange) in the given set of wrappers. |
| 5122 | The wrappers are assumed to be valid in this position, and should |
| 5123 | probably be computed with [`findWrapping`](https://prosemirror.net/docs/ref/#transform.findWrapping). |
| 5124 | */ |
| 5125 | wrap(range, wrappers) { |
| 5126 | wrap(this, range, wrappers); |
| 5127 | return this; |
| 5128 | } |
| 5129 | /** |
| 5130 | Set the type of all textblocks (partly) between `from` and `to` to |
| 5131 | the given node type with the given attributes. |
| 5132 | */ |
| 5133 | setBlockType(from2, to = from2, type, attrs2 = null) { |
| 5134 | setBlockType(this, from2, to, type, attrs2); |
| 5135 | return this; |
| 5136 | } |
| 5137 | /** |
| 5138 | Change the type, attributes, and/or marks of the node at `pos`. |
| 5139 | When `type` isn't given, the existing node type is preserved, |
| 5140 | */ |
| 5141 | setNodeMarkup(pos, type, attrs2 = null, marks) { |
| 5142 | setNodeMarkup(this, pos, type, attrs2, marks); |
| 5143 | return this; |
| 5144 | } |
| 5145 | /** |
| 5146 | Set a single attribute on a given node to a new value. |
| 5147 | The `pos` addresses the document content. Use `setDocAttribute` |
| 5148 | to set attributes on the document itself. |
| 5149 | */ |
| 5150 | setNodeAttribute(pos, attr, value) { |
| 5151 | this.step(new AttrStep(pos, attr, value)); |
| 5152 | return this; |
| 5153 | } |
| 5154 | /** |
| 5155 | Set a single attribute on the document to a new value. |
| 5156 | */ |
| 5157 | setDocAttribute(attr, value) { |
| 5158 | this.step(new DocAttrStep(attr, value)); |
| 5159 | return this; |
| 5160 | } |
| 5161 | /** |
| 5162 | Add a mark to the node at position `pos`. |
| 5163 | */ |
| 5164 | addNodeMark(pos, mark) { |
| 5165 | this.step(new AddNodeMarkStep(pos, mark)); |
| 5166 | return this; |
| 5167 | } |
| 5168 | /** |
| 5169 | Remove a mark (or all marks of the given type) from the node at |
| 5170 | position `pos`. |
| 5171 | */ |
| 5172 | removeNodeMark(pos, mark) { |
| 5173 | let node = this.doc.nodeAt(pos); |
| 5174 | if (!node) |
| 5175 | throw new RangeError("No node at position " + pos); |
| 5176 | if (mark instanceof Mark) { |
| 5177 | if (mark.isInSet(node.marks)) |
| 5178 | this.step(new RemoveNodeMarkStep(pos, mark)); |
| 5179 | } else { |
| 5180 | let set = node.marks, found2, steps = []; |
| 5181 | while (found2 = mark.isInSet(set)) { |
| 5182 | steps.push(new RemoveNodeMarkStep(pos, found2)); |
| 5183 | set = found2.removeFromSet(set); |
| 5184 | } |
| 5185 | for (let i2 = steps.length - 1; i2 >= 0; i2--) |
| 5186 | this.step(steps[i2]); |
| 5187 | } |
| 5188 | return this; |
| 5189 | } |
| 5190 | /** |
| 5191 | Split the node at the given position, and optionally, if `depth` is |
| 5192 | greater than one, any number of nodes above that. By default, the |
| 5193 | parts split off will inherit the node type of the original node. |
| 5194 | This can be changed by passing an array of types and attributes to |
| 5195 | use after the split (with the outermost nodes coming first). |
| 5196 | */ |
| 5197 | split(pos, depth = 1, typesAfter) { |
| 5198 | split(this, pos, depth, typesAfter); |
| 5199 | return this; |
| 5200 | } |
| 5201 | /** |
| 5202 | Add the given mark to the inline content between `from` and `to`. |
| 5203 | */ |
| 5204 | addMark(from2, to, mark) { |
| 5205 | addMark(this, from2, to, mark); |
| 5206 | return this; |
| 5207 | } |
| 5208 | /** |
| 5209 | Remove marks from inline nodes between `from` and `to`. When |
| 5210 | `mark` is a single mark, remove precisely that mark. When it is |
| 5211 | a mark type, remove all marks of that type. When it is null, |
| 5212 | remove all marks of any type. |
| 5213 | */ |
| 5214 | removeMark(from2, to, mark) { |
| 5215 | removeMark(this, from2, to, mark); |
| 5216 | return this; |
| 5217 | } |
| 5218 | /** |
| 5219 | Removes all marks and nodes from the content of the node at |
| 5220 | `pos` that don't match the given new parent node type. Accepts |
| 5221 | an optional starting [content match](https://prosemirror.net/docs/ref/#model.ContentMatch) as |
| 5222 | third argument. |
| 5223 | */ |
| 5224 | clearIncompatible(pos, parentType, match) { |
| 5225 | clearIncompatible(this, pos, parentType, match); |
| 5226 | return this; |
| 5227 | } |
| 5228 | }; |
| 5229 | |
| 5230 | // node_modules/prosemirror-state/dist/index.js |
| 5231 | var classesById = /* @__PURE__ */ Object.create(null); |
| 5232 | var Selection = class { |
| 5233 | /** |
| 5234 | Initialize a selection with the head and anchor and ranges. If no |
| 5235 | ranges are given, constructs a single range across `$anchor` and |
| 5236 | `$head`. |
| 5237 | */ |
| 5238 | constructor($anchor, $head, ranges) { |
| 5239 | this.$anchor = $anchor; |
| 5240 | this.$head = $head; |
| 5241 | this.ranges = ranges || [new SelectionRange($anchor.min($head), $anchor.max($head))]; |
| 5242 | } |
| 5243 | /** |
| 5244 | The selection's anchor, as an unresolved position. |
| 5245 | */ |
| 5246 | get anchor() { |
| 5247 | return this.$anchor.pos; |
| 5248 | } |
| 5249 | /** |
| 5250 | The selection's head. |
| 5251 | */ |
| 5252 | get head() { |
| 5253 | return this.$head.pos; |
| 5254 | } |
| 5255 | /** |
| 5256 | The lower bound of the selection's main range. |
| 5257 | */ |
| 5258 | get from() { |
| 5259 | return this.$from.pos; |
| 5260 | } |
| 5261 | /** |
| 5262 | The upper bound of the selection's main range. |
| 5263 | */ |
| 5264 | get to() { |
| 5265 | return this.$to.pos; |
| 5266 | } |
| 5267 | /** |
| 5268 | The resolved lower bound of the selection's main range. |
| 5269 | */ |
| 5270 | get $from() { |
| 5271 | return this.ranges[0].$from; |
| 5272 | } |
| 5273 | /** |
| 5274 | The resolved upper bound of the selection's main range. |
| 5275 | */ |
| 5276 | get $to() { |
| 5277 | return this.ranges[0].$to; |
| 5278 | } |
| 5279 | /** |
| 5280 | Indicates whether the selection contains any content. |
| 5281 | */ |
| 5282 | get empty() { |
| 5283 | let ranges = this.ranges; |
| 5284 | for (let i2 = 0; i2 < ranges.length; i2++) |
| 5285 | if (ranges[i2].$from.pos != ranges[i2].$to.pos) |
| 5286 | return false; |
| 5287 | return true; |
| 5288 | } |
| 5289 | /** |
| 5290 | Get the content of this selection as a slice. |
| 5291 | */ |
| 5292 | content() { |
| 5293 | return this.$from.doc.slice(this.from, this.to, true); |
| 5294 | } |
| 5295 | /** |
| 5296 | Replace the selection with a slice or, if no slice is given, |
| 5297 | delete the selection. Will append to the given transaction. |
| 5298 | */ |
| 5299 | replace(tr, content = Slice.empty) { |
| 5300 | let lastNode = content.content.lastChild, lastParent = null; |
| 5301 | for (let i2 = 0; i2 < content.openEnd; i2++) { |
| 5302 | lastParent = lastNode; |
| 5303 | lastNode = lastNode.lastChild; |
| 5304 | } |
| 5305 | let mapFrom = tr.steps.length, ranges = this.ranges; |
| 5306 | for (let i2 = 0; i2 < ranges.length; i2++) { |
| 5307 | let { $from, $to } = ranges[i2], mapping = tr.mapping.slice(mapFrom); |
| 5308 | tr.replaceRange(mapping.map($from.pos), mapping.map($to.pos), i2 ? Slice.empty : content); |
| 5309 | if (i2 == 0) |
| 5310 | selectionToInsertionEnd(tr, mapFrom, (lastNode ? lastNode.isInline : lastParent && lastParent.isTextblock) ? -1 : 1); |
| 5311 | } |
| 5312 | } |
| 5313 | /** |
| 5314 | Replace the selection with the given node, appending the changes |
| 5315 | to the given transaction. |
| 5316 | */ |
| 5317 | replaceWith(tr, node) { |
| 5318 | let mapFrom = tr.steps.length, ranges = this.ranges; |
| 5319 | for (let i2 = 0; i2 < ranges.length; i2++) { |
| 5320 | let { $from, $to } = ranges[i2], mapping = tr.mapping.slice(mapFrom); |
| 5321 | let from2 = mapping.map($from.pos), to = mapping.map($to.pos); |
| 5322 | if (i2) { |
| 5323 | tr.deleteRange(from2, to); |
| 5324 | } else { |
| 5325 | tr.replaceRangeWith(from2, to, node); |
| 5326 | selectionToInsertionEnd(tr, mapFrom, node.isInline ? -1 : 1); |
| 5327 | } |
| 5328 | } |
| 5329 | } |
| 5330 | /** |
| 5331 | Find a valid cursor or leaf node selection starting at the given |
| 5332 | position and searching back if `dir` is negative, and forward if |
| 5333 | positive. When `textOnly` is true, only consider cursor |
| 5334 | selections. Will return null when no valid selection position is |
| 5335 | found. |
| 5336 | */ |
| 5337 | static findFrom($pos, dir, textOnly = false) { |
| 5338 | let inner = $pos.parent.inlineContent ? new TextSelection($pos) : findSelectionIn($pos.node(0), $pos.parent, $pos.pos, $pos.index(), dir, textOnly); |
| 5339 | if (inner) |
| 5340 | return inner; |
| 5341 | for (let depth = $pos.depth - 1; depth >= 0; depth--) { |
| 5342 | let found2 = dir < 0 ? findSelectionIn($pos.node(0), $pos.node(depth), $pos.before(depth + 1), $pos.index(depth), dir, textOnly) : findSelectionIn($pos.node(0), $pos.node(depth), $pos.after(depth + 1), $pos.index(depth) + 1, dir, textOnly); |
| 5343 | if (found2) |
| 5344 | return found2; |
| 5345 | } |
| 5346 | return null; |
| 5347 | } |
| 5348 | /** |
| 5349 | Find a valid cursor or leaf node selection near the given |
| 5350 | position. Searches forward first by default, but if `bias` is |
| 5351 | negative, it will search backwards first. |
| 5352 | */ |
| 5353 | static near($pos, bias = 1) { |
| 5354 | return this.findFrom($pos, bias) || this.findFrom($pos, -bias) || new AllSelection($pos.node(0)); |
| 5355 | } |
| 5356 | /** |
| 5357 | Find the cursor or leaf node selection closest to the start of |
| 5358 | the given document. Will return an |
| 5359 | [`AllSelection`](https://prosemirror.net/docs/ref/#state.AllSelection) if no valid position |
| 5360 | exists. |
| 5361 | */ |
| 5362 | static atStart(doc3) { |
| 5363 | return findSelectionIn(doc3, doc3, 0, 0, 1) || new AllSelection(doc3); |
| 5364 | } |
| 5365 | /** |
| 5366 | Find the cursor or leaf node selection closest to the end of the |
| 5367 | given document. |
| 5368 | */ |
| 5369 | static atEnd(doc3) { |
| 5370 | return findSelectionIn(doc3, doc3, doc3.content.size, doc3.childCount, -1) || new AllSelection(doc3); |
| 5371 | } |
| 5372 | /** |
| 5373 | Deserialize the JSON representation of a selection. Must be |
| 5374 | implemented for custom classes (as a static class method). |
| 5375 | */ |
| 5376 | static fromJSON(doc3, json) { |
| 5377 | if (!json || !json.type) |
| 5378 | throw new RangeError("Invalid input for Selection.fromJSON"); |
| 5379 | let cls = classesById[json.type]; |
| 5380 | if (!cls) |
| 5381 | throw new RangeError(`No selection type ${json.type} defined`); |
| 5382 | return cls.fromJSON(doc3, json); |
| 5383 | } |
| 5384 | /** |
| 5385 | To be able to deserialize selections from JSON, custom selection |
| 5386 | classes must register themselves with an ID string, so that they |
| 5387 | can be disambiguated. Try to pick something that's unlikely to |
| 5388 | clash with classes from other modules. |
| 5389 | */ |
| 5390 | static jsonID(id, selectionClass) { |
| 5391 | if (id in classesById) |
| 5392 | throw new RangeError("Duplicate use of selection JSON ID " + id); |
| 5393 | classesById[id] = selectionClass; |
| 5394 | selectionClass.prototype.jsonID = id; |
| 5395 | return selectionClass; |
| 5396 | } |
| 5397 | /** |
| 5398 | Get a [bookmark](https://prosemirror.net/docs/ref/#state.SelectionBookmark) for this selection, |
| 5399 | which is a value that can be mapped without having access to a |
| 5400 | current document, and later resolved to a real selection for a |
| 5401 | given document again. (This is used mostly by the history to |
| 5402 | track and restore old selections.) The default implementation of |
| 5403 | this method just converts the selection to a text selection and |
| 5404 | returns the bookmark for that. |
| 5405 | */ |
| 5406 | getBookmark() { |
| 5407 | return TextSelection.between(this.$anchor, this.$head).getBookmark(); |
| 5408 | } |
| 5409 | }; |
| 5410 | Selection.prototype.visible = true; |
| 5411 | var SelectionRange = class { |
| 5412 | /** |
| 5413 | Create a range. |
| 5414 | */ |
| 5415 | constructor($from, $to) { |
| 5416 | this.$from = $from; |
| 5417 | this.$to = $to; |
| 5418 | } |
| 5419 | }; |
| 5420 | var warnedAboutTextSelection = false; |
| 5421 | function checkTextSelection($pos) { |
| 5422 | if (!warnedAboutTextSelection && !$pos.parent.inlineContent) { |
| 5423 | warnedAboutTextSelection = true; |
| 5424 | console["warn"]("TextSelection endpoint not pointing into a node with inline content (" + $pos.parent.type.name + ")"); |
| 5425 | } |
| 5426 | } |
| 5427 | var TextSelection = class _TextSelection extends Selection { |
| 5428 | /** |
| 5429 | Construct a text selection between the given points. |
| 5430 | */ |
| 5431 | constructor($anchor, $head = $anchor) { |
| 5432 | checkTextSelection($anchor); |
| 5433 | checkTextSelection($head); |
| 5434 | super($anchor, $head); |
| 5435 | } |
| 5436 | /** |
| 5437 | Returns a resolved position if this is a cursor selection (an |
| 5438 | empty text selection), and null otherwise. |
| 5439 | */ |
| 5440 | get $cursor() { |
| 5441 | return this.$anchor.pos == this.$head.pos ? this.$head : null; |
| 5442 | } |
| 5443 | map(doc3, mapping) { |
| 5444 | let $head = doc3.resolve(mapping.map(this.head)); |
| 5445 | if (!$head.parent.inlineContent) |
| 5446 | return Selection.near($head); |
| 5447 | let $anchor = doc3.resolve(mapping.map(this.anchor)); |
| 5448 | return new _TextSelection($anchor.parent.inlineContent ? $anchor : $head, $head); |
| 5449 | } |
| 5450 | replace(tr, content = Slice.empty) { |
| 5451 | super.replace(tr, content); |
| 5452 | if (content == Slice.empty) { |
| 5453 | let marks = this.$from.marksAcross(this.$to); |
| 5454 | if (marks) |
| 5455 | tr.ensureMarks(marks); |
| 5456 | } |
| 5457 | } |
| 5458 | eq(other) { |
| 5459 | return other instanceof _TextSelection && other.anchor == this.anchor && other.head == this.head; |
| 5460 | } |
| 5461 | getBookmark() { |
| 5462 | return new TextBookmark(this.anchor, this.head); |
| 5463 | } |
| 5464 | toJSON() { |
| 5465 | return { type: "text", anchor: this.anchor, head: this.head }; |
| 5466 | } |
| 5467 | /** |
| 5468 | @internal |
| 5469 | */ |
| 5470 | static fromJSON(doc3, json) { |
| 5471 | if (typeof json.anchor != "number" || typeof json.head != "number") |
| 5472 | throw new RangeError("Invalid input for TextSelection.fromJSON"); |
| 5473 | return new _TextSelection(doc3.resolve(json.anchor), doc3.resolve(json.head)); |
| 5474 | } |
| 5475 | /** |
| 5476 | Create a text selection from non-resolved positions. |
| 5477 | */ |
| 5478 | static create(doc3, anchor, head = anchor) { |
| 5479 | let $anchor = doc3.resolve(anchor); |
| 5480 | return new this($anchor, head == anchor ? $anchor : doc3.resolve(head)); |
| 5481 | } |
| 5482 | /** |
| 5483 | Return a text selection that spans the given positions or, if |
| 5484 | they aren't text positions, find a text selection near them. |
| 5485 | `bias` determines whether the method searches forward (default) |
| 5486 | or backwards (negative number) first. Will fall back to calling |
| 5487 | [`Selection.near`](https://prosemirror.net/docs/ref/#state.Selection^near) when the document |
| 5488 | doesn't contain a valid text position. |
| 5489 | */ |
| 5490 | static between($anchor, $head, bias) { |
| 5491 | let dPos = $anchor.pos - $head.pos; |
| 5492 | if (!bias || dPos) |
| 5493 | bias = dPos >= 0 ? 1 : -1; |
| 5494 | if (!$head.parent.inlineContent) { |
| 5495 | let found2 = Selection.findFrom($head, bias, true) || Selection.findFrom($head, -bias, true); |
| 5496 | if (found2) |
| 5497 | $head = found2.$head; |
| 5498 | else |
| 5499 | return Selection.near($head, bias); |
| 5500 | } |
| 5501 | if (!$anchor.parent.inlineContent) { |
| 5502 | if (dPos == 0) { |
| 5503 | $anchor = $head; |
| 5504 | } else { |
| 5505 | $anchor = (Selection.findFrom($anchor, -bias, true) || Selection.findFrom($anchor, bias, true)).$anchor; |
| 5506 | if ($anchor.pos < $head.pos != dPos < 0) |
| 5507 | $anchor = $head; |
| 5508 | } |
| 5509 | } |
| 5510 | return new _TextSelection($anchor, $head); |
| 5511 | } |
| 5512 | }; |
| 5513 | Selection.jsonID("text", TextSelection); |
| 5514 | var TextBookmark = class _TextBookmark { |
| 5515 | constructor(anchor, head) { |
| 5516 | this.anchor = anchor; |
| 5517 | this.head = head; |
| 5518 | } |
| 5519 | map(mapping) { |
| 5520 | return new _TextBookmark(mapping.map(this.anchor), mapping.map(this.head)); |
| 5521 | } |
| 5522 | resolve(doc3) { |
| 5523 | return TextSelection.between(doc3.resolve(this.anchor), doc3.resolve(this.head)); |
| 5524 | } |
| 5525 | }; |
| 5526 | var NodeSelection = class _NodeSelection extends Selection { |
| 5527 | /** |
| 5528 | Create a node selection. Does not verify the validity of its |
| 5529 | argument. |
| 5530 | */ |
| 5531 | constructor($pos) { |
| 5532 | let node = $pos.nodeAfter; |
| 5533 | let $end = $pos.node(0).resolve($pos.pos + node.nodeSize); |
| 5534 | super($pos, $end); |
| 5535 | this.node = node; |
| 5536 | } |
| 5537 | map(doc3, mapping) { |
| 5538 | let { deleted, pos } = mapping.mapResult(this.anchor); |
| 5539 | let $pos = doc3.resolve(pos); |
| 5540 | if (deleted) |
| 5541 | return Selection.near($pos); |
| 5542 | return new _NodeSelection($pos); |
| 5543 | } |
| 5544 | content() { |
| 5545 | return new Slice(Fragment.from(this.node), 0, 0); |
| 5546 | } |
| 5547 | eq(other) { |
| 5548 | return other instanceof _NodeSelection && other.anchor == this.anchor; |
| 5549 | } |
| 5550 | toJSON() { |
| 5551 | return { type: "node", anchor: this.anchor }; |
| 5552 | } |
| 5553 | getBookmark() { |
| 5554 | return new NodeBookmark(this.anchor); |
| 5555 | } |
| 5556 | /** |
| 5557 | @internal |
| 5558 | */ |
| 5559 | static fromJSON(doc3, json) { |
| 5560 | if (typeof json.anchor != "number") |
| 5561 | throw new RangeError("Invalid input for NodeSelection.fromJSON"); |
| 5562 | return new _NodeSelection(doc3.resolve(json.anchor)); |
| 5563 | } |
| 5564 | /** |
| 5565 | Create a node selection from non-resolved positions. |
| 5566 | */ |
| 5567 | static create(doc3, from2) { |
| 5568 | return new _NodeSelection(doc3.resolve(from2)); |
| 5569 | } |
| 5570 | /** |
| 5571 | Determines whether the given node may be selected as a node |
| 5572 | selection. |
| 5573 | */ |
| 5574 | static isSelectable(node) { |
| 5575 | return !node.isText && node.type.spec.selectable !== false; |
| 5576 | } |
| 5577 | }; |
| 5578 | NodeSelection.prototype.visible = false; |
| 5579 | Selection.jsonID("node", NodeSelection); |
| 5580 | var NodeBookmark = class _NodeBookmark { |
| 5581 | constructor(anchor) { |
| 5582 | this.anchor = anchor; |
| 5583 | } |
| 5584 | map(mapping) { |
| 5585 | let { deleted, pos } = mapping.mapResult(this.anchor); |
| 5586 | return deleted ? new TextBookmark(pos, pos) : new _NodeBookmark(pos); |
| 5587 | } |
| 5588 | resolve(doc3) { |
| 5589 | let $pos = doc3.resolve(this.anchor), node = $pos.nodeAfter; |
| 5590 | if (node && NodeSelection.isSelectable(node)) |
| 5591 | return new NodeSelection($pos); |
| 5592 | return Selection.near($pos); |
| 5593 | } |
| 5594 | }; |
| 5595 | var AllSelection = class _AllSelection extends Selection { |
| 5596 | /** |
| 5597 | Create an all-selection over the given document. |
| 5598 | */ |
| 5599 | constructor(doc3) { |
| 5600 | super(doc3.resolve(0), doc3.resolve(doc3.content.size)); |
| 5601 | } |
| 5602 | replace(tr, content = Slice.empty) { |
| 5603 | if (content == Slice.empty) { |
| 5604 | tr.delete(0, tr.doc.content.size); |
| 5605 | let sel = Selection.atStart(tr.doc); |
| 5606 | if (!sel.eq(tr.selection)) |
| 5607 | tr.setSelection(sel); |
| 5608 | } else { |
| 5609 | super.replace(tr, content); |
| 5610 | } |
| 5611 | } |
| 5612 | toJSON() { |
| 5613 | return { type: "all" }; |
| 5614 | } |
| 5615 | /** |
| 5616 | @internal |
| 5617 | */ |
| 5618 | static fromJSON(doc3) { |
| 5619 | return new _AllSelection(doc3); |
| 5620 | } |
| 5621 | map(doc3) { |
| 5622 | return new _AllSelection(doc3); |
| 5623 | } |
| 5624 | eq(other) { |
| 5625 | return other instanceof _AllSelection; |
| 5626 | } |
| 5627 | getBookmark() { |
| 5628 | return AllBookmark; |
| 5629 | } |
| 5630 | }; |
| 5631 | Selection.jsonID("all", AllSelection); |
| 5632 | var AllBookmark = { |
| 5633 | map() { |
| 5634 | return this; |
| 5635 | }, |
| 5636 | resolve(doc3) { |
| 5637 | return new AllSelection(doc3); |
| 5638 | } |
| 5639 | }; |
| 5640 | function findSelectionIn(doc3, node, pos, index, dir, text = false) { |
| 5641 | if (node.inlineContent) |
| 5642 | return TextSelection.create(doc3, pos); |
| 5643 | for (let i2 = index - (dir > 0 ? 0 : 1); dir > 0 ? i2 < node.childCount : i2 >= 0; i2 += dir) { |
| 5644 | let child = node.child(i2); |
| 5645 | if (!child.isAtom) { |
| 5646 | let inner = findSelectionIn(doc3, child, pos + dir, dir < 0 ? child.childCount : 0, dir, text); |
| 5647 | if (inner) |
| 5648 | return inner; |
| 5649 | } else if (!text && NodeSelection.isSelectable(child)) { |
| 5650 | return NodeSelection.create(doc3, pos - (dir < 0 ? child.nodeSize : 0)); |
| 5651 | } |
| 5652 | pos += child.nodeSize * dir; |
| 5653 | } |
| 5654 | return null; |
| 5655 | } |
| 5656 | function selectionToInsertionEnd(tr, startLen, bias) { |
| 5657 | let last = tr.steps.length - 1; |
| 5658 | if (last < startLen) |
| 5659 | return; |
| 5660 | let step = tr.steps[last]; |
| 5661 | if (!(step instanceof ReplaceStep || step instanceof ReplaceAroundStep)) |
| 5662 | return; |
| 5663 | let map2 = tr.mapping.maps[last], end; |
| 5664 | map2.forEach((_from, _to, _newFrom, newTo) => { |
| 5665 | if (end == null) |
| 5666 | end = newTo; |
| 5667 | }); |
| 5668 | tr.setSelection(Selection.near(tr.doc.resolve(end), bias)); |
| 5669 | } |
| 5670 | var UPDATED_SEL = 1; |
| 5671 | var UPDATED_MARKS = 2; |
| 5672 | var UPDATED_SCROLL = 4; |
| 5673 | var Transaction = class extends Transform { |
| 5674 | /** |
| 5675 | @internal |
| 5676 | */ |
| 5677 | constructor(state) { |
| 5678 | super(state.doc); |
| 5679 | this.curSelectionFor = 0; |
| 5680 | this.updated = 0; |
| 5681 | this.meta = /* @__PURE__ */ Object.create(null); |
| 5682 | this.time = Date.now(); |
| 5683 | this.curSelection = state.selection; |
| 5684 | this.storedMarks = state.storedMarks; |
| 5685 | } |
| 5686 | /** |
| 5687 | The transaction's current selection. This defaults to the editor |
| 5688 | selection [mapped](https://prosemirror.net/docs/ref/#state.Selection.map) through the steps in the |
| 5689 | transaction, but can be overwritten with |
| 5690 | [`setSelection`](https://prosemirror.net/docs/ref/#state.Transaction.setSelection). |
| 5691 | */ |
| 5692 | get selection() { |
| 5693 | if (this.curSelectionFor < this.steps.length) { |
| 5694 | this.curSelection = this.curSelection.map(this.doc, this.mapping.slice(this.curSelectionFor)); |
| 5695 | this.curSelectionFor = this.steps.length; |
| 5696 | } |
| 5697 | return this.curSelection; |
| 5698 | } |
| 5699 | /** |
| 5700 | Update the transaction's current selection. Will determine the |
| 5701 | selection that the editor gets when the transaction is applied. |
| 5702 | */ |
| 5703 | setSelection(selection) { |
| 5704 | if (selection.$from.doc != this.doc) |
| 5705 | throw new RangeError("Selection passed to setSelection must point at the current document"); |
| 5706 | this.curSelection = selection; |
| 5707 | this.curSelectionFor = this.steps.length; |
| 5708 | this.updated = (this.updated | UPDATED_SEL) & ~UPDATED_MARKS; |
| 5709 | this.storedMarks = null; |
| 5710 | return this; |
| 5711 | } |
| 5712 | /** |
| 5713 | Whether the selection was explicitly updated by this transaction. |
| 5714 | */ |
| 5715 | get selectionSet() { |
| 5716 | return (this.updated & UPDATED_SEL) > 0; |
| 5717 | } |
| 5718 | /** |
| 5719 | Set the current stored marks. |
| 5720 | */ |
| 5721 | setStoredMarks(marks) { |
| 5722 | this.storedMarks = marks; |
| 5723 | this.updated |= UPDATED_MARKS; |
| 5724 | return this; |
| 5725 | } |
| 5726 | /** |
| 5727 | Make sure the current stored marks or, if that is null, the marks |
| 5728 | at the selection, match the given set of marks. Does nothing if |
| 5729 | this is already the case. |
| 5730 | */ |
| 5731 | ensureMarks(marks) { |
| 5732 | if (!Mark.sameSet(this.storedMarks || this.selection.$from.marks(), marks)) |
| 5733 | this.setStoredMarks(marks); |
| 5734 | return this; |
| 5735 | } |
| 5736 | /** |
| 5737 | Add a mark to the set of stored marks. |
| 5738 | */ |
| 5739 | addStoredMark(mark) { |
| 5740 | return this.ensureMarks(mark.addToSet(this.storedMarks || this.selection.$head.marks())); |
| 5741 | } |
| 5742 | /** |
| 5743 | Remove a mark or mark type from the set of stored marks. |
| 5744 | */ |
| 5745 | removeStoredMark(mark) { |
| 5746 | return this.ensureMarks(mark.removeFromSet(this.storedMarks || this.selection.$head.marks())); |
| 5747 | } |
| 5748 | /** |
| 5749 | Whether the stored marks were explicitly set for this transaction. |
| 5750 | */ |
| 5751 | get storedMarksSet() { |
| 5752 | return (this.updated & UPDATED_MARKS) > 0; |
| 5753 | } |
| 5754 | /** |
| 5755 | @internal |
| 5756 | */ |
| 5757 | addStep(step, doc3) { |
| 5758 | super.addStep(step, doc3); |
| 5759 | this.updated = this.updated & ~UPDATED_MARKS; |
| 5760 | this.storedMarks = null; |
| 5761 | } |
| 5762 | /** |
| 5763 | Update the timestamp for the transaction. |
| 5764 | */ |
| 5765 | setTime(time) { |
| 5766 | this.time = time; |
| 5767 | return this; |
| 5768 | } |
| 5769 | /** |
| 5770 | Replace the current selection with the given slice. |
| 5771 | */ |
| 5772 | replaceSelection(slice2) { |
| 5773 | this.selection.replace(this, slice2); |
| 5774 | return this; |
| 5775 | } |
| 5776 | /** |
| 5777 | Replace the selection with the given node. When `inheritMarks` is |
| 5778 | true and the content is inline, it inherits the marks from the |
| 5779 | place where it is inserted. |
| 5780 | */ |
| 5781 | replaceSelectionWith(node, inheritMarks = true) { |
| 5782 | let selection = this.selection; |
| 5783 | if (inheritMarks) |
| 5784 | node = node.mark(this.storedMarks || (selection.empty ? selection.$from.marks() : selection.$from.marksAcross(selection.$to) || Mark.none)); |
| 5785 | selection.replaceWith(this, node); |
| 5786 | return this; |
| 5787 | } |
| 5788 | /** |
| 5789 | Delete the selection. |
| 5790 | */ |
| 5791 | deleteSelection() { |
| 5792 | this.selection.replace(this); |
| 5793 | return this; |
| 5794 | } |
| 5795 | /** |
| 5796 | Replace the given range, or the selection if no range is given, |
| 5797 | with a text node containing the given string. |
| 5798 | */ |
| 5799 | insertText(text, from2, to) { |
| 5800 | let schema2 = this.doc.type.schema; |
| 5801 | if (from2 == null) { |
| 5802 | if (!text) |
| 5803 | return this.deleteSelection(); |
| 5804 | return this.replaceSelectionWith(schema2.text(text), true); |
| 5805 | } else { |
| 5806 | if (to == null) |
| 5807 | to = from2; |
| 5808 | if (!text) |
| 5809 | return this.deleteRange(from2, to); |
| 5810 | let marks = this.storedMarks; |
| 5811 | if (!marks) { |
| 5812 | let $from = this.doc.resolve(from2); |
| 5813 | marks = to == from2 ? $from.marks() : $from.marksAcross(this.doc.resolve(to)); |
| 5814 | } |
| 5815 | this.replaceRangeWith(from2, to, schema2.text(text, marks)); |
| 5816 | if (!this.selection.empty && this.selection.to == from2 + text.length) |
| 5817 | this.setSelection(Selection.near(this.selection.$to)); |
| 5818 | return this; |
| 5819 | } |
| 5820 | } |
| 5821 | /** |
| 5822 | Store a metadata property in this transaction, keyed either by |
| 5823 | name or by plugin. |
| 5824 | */ |
| 5825 | setMeta(key, value) { |
| 5826 | this.meta[typeof key == "string" ? key : key.key] = value; |
| 5827 | return this; |
| 5828 | } |
| 5829 | /** |
| 5830 | Retrieve a metadata property for a given name or plugin. |
| 5831 | */ |
| 5832 | getMeta(key) { |
| 5833 | return this.meta[typeof key == "string" ? key : key.key]; |
| 5834 | } |
| 5835 | /** |
| 5836 | Returns true if this transaction doesn't contain any metadata, |
| 5837 | and can thus safely be extended. |
| 5838 | */ |
| 5839 | get isGeneric() { |
| 5840 | for (let _ in this.meta) |
| 5841 | return false; |
| 5842 | return true; |
| 5843 | } |
| 5844 | /** |
| 5845 | Indicate that the editor should scroll the selection into view |
| 5846 | when updated to the state produced by this transaction. |
| 5847 | */ |
| 5848 | scrollIntoView() { |
| 5849 | this.updated |= UPDATED_SCROLL; |
| 5850 | return this; |
| 5851 | } |
| 5852 | /** |
| 5853 | True when this transaction has had `scrollIntoView` called on it. |
| 5854 | */ |
| 5855 | get scrolledIntoView() { |
| 5856 | return (this.updated & UPDATED_SCROLL) > 0; |
| 5857 | } |
| 5858 | }; |
| 5859 | function bind(f, self) { |
| 5860 | return !self || !f ? f : f.bind(self); |
| 5861 | } |
| 5862 | var FieldDesc = class { |
| 5863 | constructor(name, desc, self) { |
| 5864 | this.name = name; |
| 5865 | this.init = bind(desc.init, self); |
| 5866 | this.apply = bind(desc.apply, self); |
| 5867 | } |
| 5868 | }; |
| 5869 | var baseFields = [ |
| 5870 | new FieldDesc("doc", { |
| 5871 | init(config) { |
| 5872 | return config.doc || config.schema.topNodeType.createAndFill(); |
| 5873 | }, |
| 5874 | apply(tr) { |
| 5875 | return tr.doc; |
| 5876 | } |
| 5877 | }), |
| 5878 | new FieldDesc("selection", { |
| 5879 | init(config, instance) { |
| 5880 | return config.selection || Selection.atStart(instance.doc); |
| 5881 | }, |
| 5882 | apply(tr) { |
| 5883 | return tr.selection; |
| 5884 | } |
| 5885 | }), |
| 5886 | new FieldDesc("storedMarks", { |
| 5887 | init(config) { |
| 5888 | return config.storedMarks || null; |
| 5889 | }, |
| 5890 | apply(tr, _marks, _old, state) { |
| 5891 | return state.selection.$cursor ? tr.storedMarks : null; |
| 5892 | } |
| 5893 | }), |
| 5894 | new FieldDesc("scrollToSelection", { |
| 5895 | init() { |
| 5896 | return 0; |
| 5897 | }, |
| 5898 | apply(tr, prev) { |
| 5899 | return tr.scrolledIntoView ? prev + 1 : prev; |
| 5900 | } |
| 5901 | }) |
| 5902 | ]; |
| 5903 | var Configuration = class { |
| 5904 | constructor(schema2, plugins) { |
| 5905 | this.schema = schema2; |
| 5906 | this.plugins = []; |
| 5907 | this.pluginsByKey = /* @__PURE__ */ Object.create(null); |
| 5908 | this.fields = baseFields.slice(); |
| 5909 | if (plugins) |
| 5910 | plugins.forEach((plugin) => { |
| 5911 | if (this.pluginsByKey[plugin.key]) |
| 5912 | throw new RangeError("Adding different instances of a keyed plugin (" + plugin.key + ")"); |
| 5913 | this.plugins.push(plugin); |
| 5914 | this.pluginsByKey[plugin.key] = plugin; |
| 5915 | if (plugin.spec.state) |
| 5916 | this.fields.push(new FieldDesc(plugin.key, plugin.spec.state, plugin)); |
| 5917 | }); |
| 5918 | } |
| 5919 | }; |
| 5920 | var EditorState = class _EditorState { |
| 5921 | /** |
| 5922 | @internal |
| 5923 | */ |
| 5924 | constructor(config) { |
| 5925 | this.config = config; |
| 5926 | } |
| 5927 | /** |
| 5928 | The schema of the state's document. |
| 5929 | */ |
| 5930 | get schema() { |
| 5931 | return this.config.schema; |
| 5932 | } |
| 5933 | /** |
| 5934 | The plugins that are active in this state. |
| 5935 | */ |
| 5936 | get plugins() { |
| 5937 | return this.config.plugins; |
| 5938 | } |
| 5939 | /** |
| 5940 | Apply the given transaction to produce a new state. |
| 5941 | */ |
| 5942 | apply(tr) { |
| 5943 | return this.applyTransaction(tr).state; |
| 5944 | } |
| 5945 | /** |
| 5946 | @internal |
| 5947 | */ |
| 5948 | filterTransaction(tr, ignore = -1) { |
| 5949 | for (let i2 = 0; i2 < this.config.plugins.length; i2++) |
| 5950 | if (i2 != ignore) { |
| 5951 | let plugin = this.config.plugins[i2]; |
| 5952 | if (plugin.spec.filterTransaction && !plugin.spec.filterTransaction.call(plugin, tr, this)) |
| 5953 | return false; |
| 5954 | } |
| 5955 | return true; |
| 5956 | } |
| 5957 | /** |
| 5958 | Verbose variant of [`apply`](https://prosemirror.net/docs/ref/#state.EditorState.apply) that |
| 5959 | returns the precise transactions that were applied (which might |
| 5960 | be influenced by the [transaction |
| 5961 | hooks](https://prosemirror.net/docs/ref/#state.PluginSpec.filterTransaction) of |
| 5962 | plugins) along with the new state. |
| 5963 | */ |
| 5964 | applyTransaction(rootTr) { |
| 5965 | if (!this.filterTransaction(rootTr)) |
| 5966 | return { state: this, transactions: [] }; |
| 5967 | let trs = [rootTr], newState = this.applyInner(rootTr), seen = null; |
| 5968 | for (; ; ) { |
| 5969 | let haveNew = false; |
| 5970 | for (let i2 = 0; i2 < this.config.plugins.length; i2++) { |
| 5971 | let plugin = this.config.plugins[i2]; |
| 5972 | if (plugin.spec.appendTransaction) { |
| 5973 | let n = seen ? seen[i2].n : 0, oldState = seen ? seen[i2].state : this; |
| 5974 | let tr = n < trs.length && plugin.spec.appendTransaction.call(plugin, n ? trs.slice(n) : trs, oldState, newState); |
| 5975 | if (tr && newState.filterTransaction(tr, i2)) { |
| 5976 | tr.setMeta("appendedTransaction", rootTr); |
| 5977 | if (!seen) { |
| 5978 | seen = []; |
| 5979 | for (let j = 0; j < this.config.plugins.length; j++) |
| 5980 | seen.push(j < i2 ? { state: newState, n: trs.length } : { state: this, n: 0 }); |
| 5981 | } |
| 5982 | trs.push(tr); |
| 5983 | newState = newState.applyInner(tr); |
| 5984 | haveNew = true; |
| 5985 | } |
| 5986 | if (seen) |
| 5987 | seen[i2] = { state: newState, n: trs.length }; |
| 5988 | } |
| 5989 | } |
| 5990 | if (!haveNew) |
| 5991 | return { state: newState, transactions: trs }; |
| 5992 | } |
| 5993 | } |
| 5994 | /** |
| 5995 | @internal |
| 5996 | */ |
| 5997 | applyInner(tr) { |
| 5998 | if (!tr.before.eq(this.doc)) |
| 5999 | throw new RangeError("Applying a mismatched transaction"); |
| 6000 | let newInstance = new _EditorState(this.config), fields = this.config.fields; |
| 6001 | for (let i2 = 0; i2 < fields.length; i2++) { |
| 6002 | let field = fields[i2]; |
| 6003 | newInstance[field.name] = field.apply(tr, this[field.name], this, newInstance); |
| 6004 | } |
| 6005 | return newInstance; |
| 6006 | } |
| 6007 | /** |
| 6008 | Accessor that constructs and returns a new [transaction](https://prosemirror.net/docs/ref/#state.Transaction) from this state. |
| 6009 | */ |
| 6010 | get tr() { |
| 6011 | return new Transaction(this); |
| 6012 | } |
| 6013 | /** |
| 6014 | Create a new state. |
| 6015 | */ |
| 6016 | static create(config) { |
| 6017 | let $config = new Configuration(config.doc ? config.doc.type.schema : config.schema, config.plugins); |
| 6018 | let instance = new _EditorState($config); |
| 6019 | for (let i2 = 0; i2 < $config.fields.length; i2++) |
| 6020 | instance[$config.fields[i2].name] = $config.fields[i2].init(config, instance); |
| 6021 | return instance; |
| 6022 | } |
| 6023 | /** |
| 6024 | Create a new state based on this one, but with an adjusted set |
| 6025 | of active plugins. State fields that exist in both sets of |
| 6026 | plugins are kept unchanged. Those that no longer exist are |
| 6027 | dropped, and those that are new are initialized using their |
| 6028 | [`init`](https://prosemirror.net/docs/ref/#state.StateField.init) method, passing in the new |
| 6029 | configuration object.. |
| 6030 | */ |
| 6031 | reconfigure(config) { |
| 6032 | let $config = new Configuration(this.schema, config.plugins); |
| 6033 | let fields = $config.fields, instance = new _EditorState($config); |
| 6034 | for (let i2 = 0; i2 < fields.length; i2++) { |
| 6035 | let name = fields[i2].name; |
| 6036 | instance[name] = this.hasOwnProperty(name) ? this[name] : fields[i2].init(config, instance); |
| 6037 | } |
| 6038 | return instance; |
| 6039 | } |
| 6040 | /** |
| 6041 | Serialize this state to JSON. If you want to serialize the state |
| 6042 | of plugins, pass an object mapping property names to use in the |
| 6043 | resulting JSON object to plugin objects. The argument may also be |
| 6044 | a string or number, in which case it is ignored, to support the |
| 6045 | way `JSON.stringify` calls `toString` methods. |
| 6046 | */ |
| 6047 | toJSON(pluginFields) { |
| 6048 | let result = { doc: this.doc.toJSON(), selection: this.selection.toJSON() }; |
| 6049 | if (this.storedMarks) |
| 6050 | result.storedMarks = this.storedMarks.map((m) => m.toJSON()); |
| 6051 | if (pluginFields && typeof pluginFields == "object") |
| 6052 | for (let prop in pluginFields) { |
| 6053 | if (prop == "doc" || prop == "selection") |
| 6054 | throw new RangeError("The JSON fields `doc` and `selection` are reserved"); |
| 6055 | let plugin = pluginFields[prop], state = plugin.spec.state; |
| 6056 | if (state && state.toJSON) |
| 6057 | result[prop] = state.toJSON.call(plugin, this[plugin.key]); |
| 6058 | } |
| 6059 | return result; |
| 6060 | } |
| 6061 | /** |
| 6062 | Deserialize a JSON representation of a state. `config` should |
| 6063 | have at least a `schema` field, and should contain array of |
| 6064 | plugins to initialize the state with. `pluginFields` can be used |
| 6065 | to deserialize the state of plugins, by associating plugin |
| 6066 | instances with the property names they use in the JSON object. |
| 6067 | */ |
| 6068 | static fromJSON(config, json, pluginFields) { |
| 6069 | if (!json) |
| 6070 | throw new RangeError("Invalid input for EditorState.fromJSON"); |
| 6071 | if (!config.schema) |
| 6072 | throw new RangeError("Required config field 'schema' missing"); |
| 6073 | let $config = new Configuration(config.schema, config.plugins); |
| 6074 | let instance = new _EditorState($config); |
| 6075 | $config.fields.forEach((field) => { |
| 6076 | if (field.name == "doc") { |
| 6077 | instance.doc = Node.fromJSON(config.schema, json.doc); |
| 6078 | } else if (field.name == "selection") { |
| 6079 | instance.selection = Selection.fromJSON(instance.doc, json.selection); |
| 6080 | } else if (field.name == "storedMarks") { |
| 6081 | if (json.storedMarks) |
| 6082 | instance.storedMarks = json.storedMarks.map(config.schema.markFromJSON); |
| 6083 | } else { |
| 6084 | if (pluginFields) |
| 6085 | for (let prop in pluginFields) { |
| 6086 | let plugin = pluginFields[prop], state = plugin.spec.state; |
| 6087 | if (plugin.key == field.name && state && state.fromJSON && Object.prototype.hasOwnProperty.call(json, prop)) { |
| 6088 | instance[field.name] = state.fromJSON.call(plugin, config, json[prop], instance); |
| 6089 | return; |
| 6090 | } |
| 6091 | } |
| 6092 | instance[field.name] = field.init(config, instance); |
| 6093 | } |
| 6094 | }); |
| 6095 | return instance; |
| 6096 | } |
| 6097 | }; |
| 6098 | function bindProps(obj, self, target) { |
| 6099 | for (let prop in obj) { |
| 6100 | let val = obj[prop]; |
| 6101 | if (val instanceof Function) |
| 6102 | val = val.bind(self); |
| 6103 | else if (prop == "handleDOMEvents") |
| 6104 | val = bindProps(val, self, {}); |
| 6105 | target[prop] = val; |
| 6106 | } |
| 6107 | return target; |
| 6108 | } |
| 6109 | var Plugin = class { |
| 6110 | /** |
| 6111 | Create a plugin. |
| 6112 | */ |
| 6113 | constructor(spec) { |
| 6114 | this.spec = spec; |
| 6115 | this.props = {}; |
| 6116 | if (spec.props) |
| 6117 | bindProps(spec.props, this, this.props); |
| 6118 | this.key = spec.key ? spec.key.key : createKey("plugin"); |
| 6119 | } |
| 6120 | /** |
| 6121 | Extract the plugin's state field from an editor state. |
| 6122 | */ |
| 6123 | getState(state) { |
| 6124 | return state[this.key]; |
| 6125 | } |
| 6126 | }; |
| 6127 | var keys = /* @__PURE__ */ Object.create(null); |
| 6128 | function createKey(name) { |
| 6129 | if (name in keys) |
| 6130 | return name + "$" + ++keys[name]; |
| 6131 | keys[name] = 0; |
| 6132 | return name + "$"; |
| 6133 | } |
| 6134 | var PluginKey = class { |
| 6135 | /** |
| 6136 | Create a plugin key. |
| 6137 | */ |
| 6138 | constructor(name = "key") { |
| 6139 | this.key = createKey(name); |
| 6140 | } |
| 6141 | /** |
| 6142 | Get the active plugin with this key, if any, from an editor |
| 6143 | state. |
| 6144 | */ |
| 6145 | get(state) { |
| 6146 | return state.config.pluginsByKey[this.key]; |
| 6147 | } |
| 6148 | /** |
| 6149 | Get the plugin's state from an editor state. |
| 6150 | */ |
| 6151 | getState(state) { |
| 6152 | return state[this.key]; |
| 6153 | } |
| 6154 | }; |
| 6155 | |
| 6156 | // node_modules/prosemirror-view/dist/index.js |
| 6157 | var domIndex = function(node) { |
| 6158 | for (var index = 0; ; index++) { |
| 6159 | node = node.previousSibling; |
| 6160 | if (!node) |
| 6161 | return index; |
| 6162 | } |
| 6163 | }; |
| 6164 | var parentNode = function(node) { |
| 6165 | let parent = node.assignedSlot || node.parentNode; |
| 6166 | return parent && parent.nodeType == 11 ? parent.host : parent; |
| 6167 | }; |
| 6168 | var reusedRange = null; |
| 6169 | var textRange = function(node, from2, to) { |
| 6170 | let range = reusedRange || (reusedRange = document.createRange()); |
| 6171 | range.setEnd(node, to == null ? node.nodeValue.length : to); |
| 6172 | range.setStart(node, from2 || 0); |
| 6173 | return range; |
| 6174 | }; |
| 6175 | var clearReusedRange = function() { |
| 6176 | reusedRange = null; |
| 6177 | }; |
| 6178 | var isEquivalentPosition = function(node, off, targetNode, targetOff) { |
| 6179 | return targetNode && (scanFor(node, off, targetNode, targetOff, -1) || scanFor(node, off, targetNode, targetOff, 1)); |
| 6180 | }; |
| 6181 | var atomElements = /^(img|br|input|textarea|hr)$/i; |
| 6182 | function scanFor(node, off, targetNode, targetOff, dir) { |
| 6183 | var _a; |
| 6184 | for (; ; ) { |
| 6185 | if (node == targetNode && off == targetOff) |
| 6186 | return true; |
| 6187 | if (off == (dir < 0 ? 0 : nodeSize(node))) { |
| 6188 | let parent = node.parentNode; |
| 6189 | if (!parent || parent.nodeType != 1 || hasBlockDesc(node) || atomElements.test(node.nodeName) || node.contentEditable == "false") |
| 6190 | return false; |
| 6191 | off = domIndex(node) + (dir < 0 ? 0 : 1); |
| 6192 | node = parent; |
| 6193 | } else if (node.nodeType == 1) { |
| 6194 | let child = node.childNodes[off + (dir < 0 ? -1 : 0)]; |
| 6195 | if (child.nodeType == 1 && child.contentEditable == "false") { |
| 6196 | if ((_a = child.pmViewDesc) === null || _a === void 0 ? void 0 : _a.ignoreForSelection) |
| 6197 | off += dir; |
| 6198 | else |
| 6199 | return false; |
| 6200 | } else { |
| 6201 | node = child; |
| 6202 | off = dir < 0 ? nodeSize(node) : 0; |
| 6203 | } |
| 6204 | } else { |
| 6205 | return false; |
| 6206 | } |
| 6207 | } |
| 6208 | } |
| 6209 | function nodeSize(node) { |
| 6210 | return node.nodeType == 3 ? node.nodeValue.length : node.childNodes.length; |
| 6211 | } |
| 6212 | function textNodeBefore$1(node, offset) { |
| 6213 | for (; ; ) { |
| 6214 | if (node.nodeType == 3 && offset) |
| 6215 | return node; |
| 6216 | if (node.nodeType == 1 && offset > 0) { |
| 6217 | if (node.contentEditable == "false") |
| 6218 | return null; |
| 6219 | node = node.childNodes[offset - 1]; |
| 6220 | offset = nodeSize(node); |
| 6221 | } else if (node.parentNode && !hasBlockDesc(node)) { |
| 6222 | offset = domIndex(node); |
| 6223 | node = node.parentNode; |
| 6224 | } else { |
| 6225 | return null; |
| 6226 | } |
| 6227 | } |
| 6228 | } |
| 6229 | function textNodeAfter$1(node, offset) { |
| 6230 | for (; ; ) { |
| 6231 | if (node.nodeType == 3 && offset < node.nodeValue.length) |
| 6232 | return node; |
| 6233 | if (node.nodeType == 1 && offset < node.childNodes.length) { |
| 6234 | if (node.contentEditable == "false") |
| 6235 | return null; |
| 6236 | node = node.childNodes[offset]; |
| 6237 | offset = 0; |
| 6238 | } else if (node.parentNode && !hasBlockDesc(node)) { |
| 6239 | offset = domIndex(node) + 1; |
| 6240 | node = node.parentNode; |
| 6241 | } else { |
| 6242 | return null; |
| 6243 | } |
| 6244 | } |
| 6245 | } |
| 6246 | function isOnEdge(node, offset, parent) { |
| 6247 | for (let atStart = offset == 0, atEnd = offset == nodeSize(node); atStart || atEnd; ) { |
| 6248 | if (node == parent) |
| 6249 | return true; |
| 6250 | let index = domIndex(node); |
| 6251 | node = node.parentNode; |
| 6252 | if (!node) |
| 6253 | return false; |
| 6254 | atStart = atStart && index == 0; |
| 6255 | atEnd = atEnd && index == nodeSize(node); |
| 6256 | } |
| 6257 | } |
| 6258 | function hasBlockDesc(dom) { |
| 6259 | let desc; |
| 6260 | for (let cur = dom; cur; cur = cur.parentNode) |
| 6261 | if (desc = cur.pmViewDesc) |
| 6262 | break; |
| 6263 | return desc && desc.node && desc.node.isBlock && (desc.dom == dom || desc.contentDOM == dom); |
| 6264 | } |
| 6265 | var selectionCollapsed = function(domSel) { |
| 6266 | return domSel.focusNode && isEquivalentPosition(domSel.focusNode, domSel.focusOffset, domSel.anchorNode, domSel.anchorOffset); |
| 6267 | }; |
| 6268 | function keyEvent(keyCode, key) { |
| 6269 | let event = document.createEvent("Event"); |
| 6270 | event.initEvent("keydown", true, true); |
| 6271 | event.keyCode = keyCode; |
| 6272 | event.key = event.code = key; |
| 6273 | return event; |
| 6274 | } |
| 6275 | function deepActiveElement(doc3) { |
| 6276 | let elt = doc3.activeElement; |
| 6277 | while (elt && elt.shadowRoot) |
| 6278 | elt = elt.shadowRoot.activeElement; |
| 6279 | return elt; |
| 6280 | } |
| 6281 | function caretFromPoint(doc3, x, y) { |
| 6282 | if (doc3.caretPositionFromPoint) { |
| 6283 | try { |
| 6284 | let pos = doc3.caretPositionFromPoint(x, y); |
| 6285 | if (pos) |
| 6286 | return { node: pos.offsetNode, offset: Math.min(nodeSize(pos.offsetNode), pos.offset) }; |
| 6287 | } catch (_) { |
| 6288 | } |
| 6289 | } |
| 6290 | if (doc3.caretRangeFromPoint) { |
| 6291 | let range = doc3.caretRangeFromPoint(x, y); |
| 6292 | if (range) |
| 6293 | return { node: range.startContainer, offset: Math.min(nodeSize(range.startContainer), range.startOffset) }; |
| 6294 | } |
| 6295 | } |
| 6296 | var nav = typeof navigator != "undefined" ? navigator : null; |
| 6297 | var doc2 = typeof document != "undefined" ? document : null; |
| 6298 | var agent = nav && nav.userAgent || ""; |
| 6299 | var ie_edge = /Edge\/(\d+)/.exec(agent); |
| 6300 | var ie_upto10 = /MSIE \d/.exec(agent); |
| 6301 | var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(agent); |
| 6302 | var ie = !!(ie_upto10 || ie_11up || ie_edge); |
| 6303 | var ie_version = ie_upto10 ? document.documentMode : ie_11up ? +ie_11up[1] : ie_edge ? +ie_edge[1] : 0; |
| 6304 | var gecko = !ie && /gecko\/(\d+)/i.test(agent); |
| 6305 | gecko && +(/Firefox\/(\d+)/.exec(agent) || [0, 0])[1]; |
| 6306 | var _chrome = !ie && /Chrome\/(\d+)/.exec(agent); |
| 6307 | var chrome = !!_chrome; |
| 6308 | var chrome_version = _chrome ? +_chrome[1] : 0; |
| 6309 | var safari = !ie && !!nav && /Apple Computer/.test(nav.vendor); |
| 6310 | var ios = safari && (/Mobile\/\w+/.test(agent) || !!nav && nav.maxTouchPoints > 2); |
| 6311 | var mac = ios || (nav ? /Mac/.test(nav.platform) : false); |
| 6312 | var windows = nav ? /Win/.test(nav.platform) : false; |
| 6313 | var android = /Android \d/.test(agent); |
| 6314 | var webkit = !!doc2 && "webkitFontSmoothing" in doc2.documentElement.style; |
| 6315 | var webkit_version = webkit ? +(/\bAppleWebKit\/(\d+)/.exec(navigator.userAgent) || [0, 0])[1] : 0; |
| 6316 | function windowRect(doc3) { |
| 6317 | let vp = doc3.defaultView && doc3.defaultView.visualViewport; |
| 6318 | if (vp) |
| 6319 | return { |
| 6320 | left: 0, |
| 6321 | right: vp.width, |
| 6322 | top: 0, |
| 6323 | bottom: vp.height |
| 6324 | }; |
| 6325 | return { |
| 6326 | left: 0, |
| 6327 | right: doc3.documentElement.clientWidth, |
| 6328 | top: 0, |
| 6329 | bottom: doc3.documentElement.clientHeight |
| 6330 | }; |
| 6331 | } |
| 6332 | function getSide(value, side) { |
| 6333 | return typeof value == "number" ? value : value[side]; |
| 6334 | } |
| 6335 | function clientRect(node) { |
| 6336 | let rect = node.getBoundingClientRect(); |
| 6337 | let scaleX = rect.width / node.offsetWidth || 1; |
| 6338 | let scaleY = rect.height / node.offsetHeight || 1; |
| 6339 | return { |
| 6340 | left: rect.left, |
| 6341 | right: rect.left + node.clientWidth * scaleX, |
| 6342 | top: rect.top, |
| 6343 | bottom: rect.top + node.clientHeight * scaleY |
| 6344 | }; |
| 6345 | } |
| 6346 | function scrollRectIntoView(view, rect, startDOM) { |
| 6347 | if (!nonZero(rect) && rect.left == 0) |
| 6348 | return; |
| 6349 | let scrollThreshold = view.someProp("scrollThreshold") || 0, scrollMargin = view.someProp("scrollMargin") || 5; |
| 6350 | let doc3 = view.dom.ownerDocument; |
| 6351 | for (let parent = startDOM || view.dom; ; ) { |
| 6352 | if (!parent) |
| 6353 | break; |
| 6354 | if (parent.nodeType != 1) { |
| 6355 | parent = parentNode(parent); |
| 6356 | continue; |
| 6357 | } |
| 6358 | let elt = parent; |
| 6359 | let atTop = elt == doc3.body; |
| 6360 | let bounding = atTop ? windowRect(doc3) : clientRect(elt); |
| 6361 | let moveX = 0, moveY = 0; |
| 6362 | if (rect.top < bounding.top + getSide(scrollThreshold, "top")) |
| 6363 | moveY = -(bounding.top - rect.top + getSide(scrollMargin, "top")); |
| 6364 | else if (rect.bottom > bounding.bottom - getSide(scrollThreshold, "bottom")) |
| 6365 | moveY = rect.bottom - rect.top > bounding.bottom - bounding.top ? rect.top + getSide(scrollMargin, "top") - bounding.top : rect.bottom - bounding.bottom + getSide(scrollMargin, "bottom"); |
| 6366 | if (rect.left < bounding.left + getSide(scrollThreshold, "left")) |
| 6367 | moveX = -(bounding.left - rect.left + getSide(scrollMargin, "left")); |
| 6368 | else if (rect.right > bounding.right - getSide(scrollThreshold, "right")) |
| 6369 | moveX = rect.right - bounding.right + getSide(scrollMargin, "right"); |
| 6370 | if (moveX || moveY) { |
| 6371 | if (atTop) { |
| 6372 | doc3.defaultView.scrollBy(moveX, moveY); |
| 6373 | } else { |
| 6374 | let startX = elt.scrollLeft, startY = elt.scrollTop; |
| 6375 | if (moveY) |
| 6376 | elt.scrollTop += moveY; |
| 6377 | if (moveX) |
| 6378 | elt.scrollLeft += moveX; |
| 6379 | let dX = elt.scrollLeft - startX, dY = elt.scrollTop - startY; |
| 6380 | rect = { left: rect.left - dX, top: rect.top - dY, right: rect.right - dX, bottom: rect.bottom - dY }; |
| 6381 | } |
| 6382 | } |
| 6383 | let pos = atTop ? "fixed" : getComputedStyle(parent).position; |
| 6384 | if (/^(fixed|sticky)$/.test(pos)) |
| 6385 | break; |
| 6386 | parent = pos == "absolute" ? parent.offsetParent : parentNode(parent); |
| 6387 | } |
| 6388 | } |
| 6389 | function storeScrollPos(view) { |
| 6390 | let rect = view.dom.getBoundingClientRect(), startY = Math.max(0, rect.top); |
| 6391 | let refDOM, refTop; |
| 6392 | for (let x = (rect.left + rect.right) / 2, y = startY + 1; y < Math.min(innerHeight, rect.bottom); y += 5) { |
| 6393 | let dom = view.root.elementFromPoint(x, y); |
| 6394 | if (!dom || dom == view.dom || !view.dom.contains(dom)) |
| 6395 | continue; |
| 6396 | let localRect = dom.getBoundingClientRect(); |
| 6397 | if (localRect.top >= startY - 20) { |
| 6398 | refDOM = dom; |
| 6399 | refTop = localRect.top; |
| 6400 | break; |
| 6401 | } |
| 6402 | } |
| 6403 | return { refDOM, refTop, stack: scrollStack(view.dom) }; |
| 6404 | } |
| 6405 | function scrollStack(dom) { |
| 6406 | let stack = [], doc3 = dom.ownerDocument; |
| 6407 | for (let cur = dom; cur; cur = parentNode(cur)) { |
| 6408 | stack.push({ dom: cur, top: cur.scrollTop, left: cur.scrollLeft }); |
| 6409 | if (dom == doc3) |
| 6410 | break; |
| 6411 | } |
| 6412 | return stack; |
| 6413 | } |
| 6414 | function resetScrollPos({ refDOM, refTop, stack }) { |
| 6415 | let newRefTop = refDOM ? refDOM.getBoundingClientRect().top : 0; |
| 6416 | restoreScrollStack(stack, newRefTop == 0 ? 0 : newRefTop - refTop); |
| 6417 | } |
| 6418 | function restoreScrollStack(stack, dTop) { |
| 6419 | for (let i2 = 0; i2 < stack.length; i2++) { |
| 6420 | let { dom, top, left } = stack[i2]; |
| 6421 | if (dom.scrollTop != top + dTop) |
| 6422 | dom.scrollTop = top + dTop; |
| 6423 | if (dom.scrollLeft != left) |
| 6424 | dom.scrollLeft = left; |
| 6425 | } |
| 6426 | } |
| 6427 | var preventScrollSupported = null; |
| 6428 | function focusPreventScroll(dom) { |
| 6429 | if (dom.setActive) |
| 6430 | return dom.setActive(); |
| 6431 | if (preventScrollSupported) |
| 6432 | return dom.focus(preventScrollSupported); |
| 6433 | let stored = scrollStack(dom); |
| 6434 | dom.focus(preventScrollSupported == null ? { |
| 6435 | get preventScroll() { |
| 6436 | preventScrollSupported = { preventScroll: true }; |
| 6437 | return true; |
| 6438 | } |
| 6439 | } : void 0); |
| 6440 | if (!preventScrollSupported) { |
| 6441 | preventScrollSupported = false; |
| 6442 | restoreScrollStack(stored, 0); |
| 6443 | } |
| 6444 | } |
| 6445 | function findOffsetInNode(node, coords) { |
| 6446 | let closest, dxClosest = 2e8, coordsClosest, offset = 0; |
| 6447 | let rowBot = coords.top, rowTop = coords.top; |
| 6448 | let firstBelow, coordsBelow; |
| 6449 | for (let child = node.firstChild, childIndex = 0; child; child = child.nextSibling, childIndex++) { |
| 6450 | let rects; |
| 6451 | if (child.nodeType == 1) |
| 6452 | rects = child.getClientRects(); |
| 6453 | else if (child.nodeType == 3) |
| 6454 | rects = textRange(child).getClientRects(); |
| 6455 | else |
| 6456 | continue; |
| 6457 | for (let i2 = 0; i2 < rects.length; i2++) { |
| 6458 | let rect = rects[i2]; |
| 6459 | if (rect.top <= rowBot && rect.bottom >= rowTop) { |
| 6460 | rowBot = Math.max(rect.bottom, rowBot); |
| 6461 | rowTop = Math.min(rect.top, rowTop); |
| 6462 | let dx = rect.left > coords.left ? rect.left - coords.left : rect.right < coords.left ? coords.left - rect.right : 0; |
| 6463 | if (dx < dxClosest) { |
| 6464 | closest = child; |
| 6465 | dxClosest = dx; |
| 6466 | coordsClosest = dx && closest.nodeType == 3 ? { |
| 6467 | left: rect.right < coords.left ? rect.right : rect.left, |
| 6468 | top: coords.top |
| 6469 | } : coords; |
| 6470 | if (child.nodeType == 1 && dx) |
| 6471 | offset = childIndex + (coords.left >= (rect.left + rect.right) / 2 ? 1 : 0); |
| 6472 | continue; |
| 6473 | } |
| 6474 | } else if (rect.top > coords.top && !firstBelow && rect.left <= coords.left && rect.right >= coords.left) { |
| 6475 | firstBelow = child; |
| 6476 | coordsBelow = { left: Math.max(rect.left, Math.min(rect.right, coords.left)), top: rect.top }; |
| 6477 | } |
| 6478 | if (!closest && (coords.left >= rect.right && coords.top >= rect.top || coords.left >= rect.left && coords.top >= rect.bottom)) |
| 6479 | offset = childIndex + 1; |
| 6480 | } |
| 6481 | } |
| 6482 | if (!closest && firstBelow) { |
| 6483 | closest = firstBelow; |
| 6484 | coordsClosest = coordsBelow; |
| 6485 | dxClosest = 0; |
| 6486 | } |
| 6487 | if (closest && closest.nodeType == 3) |
| 6488 | return findOffsetInText(closest, coordsClosest); |
| 6489 | if (!closest || dxClosest && closest.nodeType == 1) |
| 6490 | return { node, offset }; |
| 6491 | return findOffsetInNode(closest, coordsClosest); |
| 6492 | } |
| 6493 | function findOffsetInText(node, coords) { |
| 6494 | let len = node.nodeValue.length; |
| 6495 | let range = document.createRange(), result; |
| 6496 | for (let i2 = 0; i2 < len; i2++) { |
| 6497 | range.setEnd(node, i2 + 1); |
| 6498 | range.setStart(node, i2); |
| 6499 | let rect = singleRect(range, 1); |
| 6500 | if (rect.top == rect.bottom) |
| 6501 | continue; |
| 6502 | if (inRect(coords, rect)) { |
| 6503 | result = { node, offset: i2 + (coords.left >= (rect.left + rect.right) / 2 ? 1 : 0) }; |
| 6504 | break; |
| 6505 | } |
| 6506 | } |
| 6507 | range.detach(); |
| 6508 | return result || { node, offset: 0 }; |
| 6509 | } |
| 6510 | function inRect(coords, rect) { |
| 6511 | return coords.left >= rect.left - 1 && coords.left <= rect.right + 1 && coords.top >= rect.top - 1 && coords.top <= rect.bottom + 1; |
| 6512 | } |
| 6513 | function targetKludge(dom, coords) { |
| 6514 | let parent = dom.parentNode; |
| 6515 | if (parent && /^li$/i.test(parent.nodeName) && coords.left < dom.getBoundingClientRect().left) |
| 6516 | return parent; |
| 6517 | return dom; |
| 6518 | } |
| 6519 | function posFromElement(view, elt, coords) { |
| 6520 | let { node, offset } = findOffsetInNode(elt, coords), bias = -1; |
| 6521 | if (node.nodeType == 1 && !node.firstChild) { |
| 6522 | let rect = node.getBoundingClientRect(); |
| 6523 | bias = rect.left != rect.right && coords.left > (rect.left + rect.right) / 2 ? 1 : -1; |
| 6524 | } |
| 6525 | return view.docView.posFromDOM(node, offset, bias); |
| 6526 | } |
| 6527 | function posFromCaret(view, node, offset, coords) { |
| 6528 | let outsideBlock = -1; |
| 6529 | for (let cur = node, sawBlock = false; ; ) { |
| 6530 | if (cur == view.dom) |
| 6531 | break; |
| 6532 | let desc = view.docView.nearestDesc(cur, true), rect; |
| 6533 | if (!desc) |
| 6534 | return null; |
| 6535 | if (desc.dom.nodeType == 1 && (desc.node.isBlock && desc.parent || !desc.contentDOM) && // Ignore elements with zero-size bounding rectangles |
| 6536 | ((rect = desc.dom.getBoundingClientRect()).width || rect.height)) { |
| 6537 | if (desc.node.isBlock && desc.parent && !/^T(R|BODY|HEAD|FOOT)$/.test(desc.dom.nodeName)) { |
| 6538 | if (!sawBlock && rect.left > coords.left || rect.top > coords.top) |
| 6539 | outsideBlock = desc.posBefore; |
| 6540 | else if (!sawBlock && rect.right < coords.left || rect.bottom < coords.top) |
| 6541 | outsideBlock = desc.posAfter; |
| 6542 | sawBlock = true; |
| 6543 | } |
| 6544 | if (!desc.contentDOM && outsideBlock < 0 && !desc.node.isText) { |
| 6545 | let before = desc.node.isBlock ? coords.top < (rect.top + rect.bottom) / 2 : coords.left < (rect.left + rect.right) / 2; |
| 6546 | return before ? desc.posBefore : desc.posAfter; |
| 6547 | } |
| 6548 | } |
| 6549 | cur = desc.dom.parentNode; |
| 6550 | } |
| 6551 | return outsideBlock > -1 ? outsideBlock : view.docView.posFromDOM(node, offset, -1); |
| 6552 | } |
| 6553 | function elementFromPoint(element, coords, box) { |
| 6554 | let len = element.childNodes.length; |
| 6555 | if (len && box.top < box.bottom) { |
| 6556 | for (let startI = Math.max(0, Math.min(len - 1, Math.floor(len * (coords.top - box.top) / (box.bottom - box.top)) - 2)), i2 = startI; ; ) { |
| 6557 | let child = element.childNodes[i2]; |
| 6558 | if (child.nodeType == 1) { |
| 6559 | let rects = child.getClientRects(); |
| 6560 | for (let j = 0; j < rects.length; j++) { |
| 6561 | let rect = rects[j]; |
| 6562 | if (inRect(coords, rect)) |
| 6563 | return elementFromPoint(child, coords, rect); |
| 6564 | } |
| 6565 | } |
| 6566 | if ((i2 = (i2 + 1) % len) == startI) |
| 6567 | break; |
| 6568 | } |
| 6569 | } |
| 6570 | return element; |
| 6571 | } |
| 6572 | function posAtCoords(view, coords) { |
| 6573 | let doc3 = view.dom.ownerDocument, node, offset = 0; |
| 6574 | let caret = caretFromPoint(doc3, coords.left, coords.top); |
| 6575 | if (caret) |
| 6576 | ({ node, offset } = caret); |
| 6577 | let elt = (view.root.elementFromPoint ? view.root : doc3).elementFromPoint(coords.left, coords.top); |
| 6578 | let pos; |
| 6579 | if (!elt || !view.dom.contains(elt.nodeType != 1 ? elt.parentNode : elt)) { |
| 6580 | let box = view.dom.getBoundingClientRect(); |
| 6581 | if (!inRect(coords, box)) |
| 6582 | return null; |
| 6583 | elt = elementFromPoint(view.dom, coords, box); |
| 6584 | if (!elt) |
| 6585 | return null; |
| 6586 | } |
| 6587 | if (safari) { |
| 6588 | for (let p = elt; node && p; p = parentNode(p)) |
| 6589 | if (p.draggable) |
| 6590 | node = void 0; |
| 6591 | } |
| 6592 | elt = targetKludge(elt, coords); |
| 6593 | if (node) { |
| 6594 | if (gecko && node.nodeType == 1) { |
| 6595 | offset = Math.min(offset, node.childNodes.length); |
| 6596 | if (offset < node.childNodes.length) { |
| 6597 | let next = node.childNodes[offset], box; |
| 6598 | if (next.nodeName == "IMG" && (box = next.getBoundingClientRect()).right <= coords.left && box.bottom > coords.top) |
| 6599 | offset++; |
| 6600 | } |
| 6601 | } |
| 6602 | let prev; |
| 6603 | if (webkit && offset && node.nodeType == 1 && (prev = node.childNodes[offset - 1]).nodeType == 1 && prev.contentEditable == "false" && prev.getBoundingClientRect().top >= coords.top) |
| 6604 | offset--; |
| 6605 | if (node == view.dom && offset == node.childNodes.length - 1 && node.lastChild.nodeType == 1 && coords.top > node.lastChild.getBoundingClientRect().bottom) |
| 6606 | pos = view.state.doc.content.size; |
| 6607 | else if (offset == 0 || node.nodeType != 1 || node.childNodes[offset - 1].nodeName != "BR") |
| 6608 | pos = posFromCaret(view, node, offset, coords); |
| 6609 | } |
| 6610 | if (pos == null) |
| 6611 | pos = posFromElement(view, elt, coords); |
| 6612 | let desc = view.docView.nearestDesc(elt, true); |
| 6613 | return { pos, inside: desc ? desc.posAtStart - desc.border : -1 }; |
| 6614 | } |
| 6615 | function nonZero(rect) { |
| 6616 | return rect.top < rect.bottom || rect.left < rect.right; |
| 6617 | } |
| 6618 | function singleRect(target, bias) { |
| 6619 | let rects = target.getClientRects(); |
| 6620 | if (rects.length) { |
| 6621 | let first = rects[bias < 0 ? 0 : rects.length - 1]; |
| 6622 | if (nonZero(first)) |
| 6623 | return first; |
| 6624 | } |
| 6625 | return Array.prototype.find.call(rects, nonZero) || target.getBoundingClientRect(); |
| 6626 | } |
| 6627 | var BIDI = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/; |
| 6628 | function coordsAtPos(view, pos, side) { |
| 6629 | let { node, offset, atom } = view.docView.domFromPos(pos, side < 0 ? -1 : 1); |
| 6630 | let supportEmptyRange = webkit || gecko; |
| 6631 | if (node.nodeType == 3) { |
| 6632 | if (supportEmptyRange && (BIDI.test(node.nodeValue) || (side < 0 ? !offset : offset == node.nodeValue.length))) { |
| 6633 | let rect = singleRect(textRange(node, offset, offset), side); |
| 6634 | if (gecko && offset && /\s/.test(node.nodeValue[offset - 1]) && offset < node.nodeValue.length) { |
| 6635 | let rectBefore = singleRect(textRange(node, offset - 1, offset - 1), -1); |
| 6636 | if (rectBefore.top == rect.top) { |
| 6637 | let rectAfter = singleRect(textRange(node, offset, offset + 1), -1); |
| 6638 | if (rectAfter.top != rect.top) |
| 6639 | return flattenV(rectAfter, rectAfter.left < rectBefore.left); |
| 6640 | } |
| 6641 | } |
| 6642 | return rect; |
| 6643 | } else { |
| 6644 | let from2 = offset, to = offset, takeSide = side < 0 ? 1 : -1; |
| 6645 | if (side < 0 && !offset) { |
| 6646 | to++; |
| 6647 | takeSide = -1; |
| 6648 | } else if (side >= 0 && offset == node.nodeValue.length) { |
| 6649 | from2--; |
| 6650 | takeSide = 1; |
| 6651 | } else if (side < 0) { |
| 6652 | from2--; |
| 6653 | } else { |
| 6654 | to++; |
| 6655 | } |
| 6656 | return flattenV(singleRect(textRange(node, from2, to), takeSide), takeSide < 0); |
| 6657 | } |
| 6658 | } |
| 6659 | let $dom = view.state.doc.resolve(pos - (atom || 0)); |
| 6660 | if (!$dom.parent.inlineContent) { |
| 6661 | if (atom == null && offset && (side < 0 || offset == nodeSize(node))) { |
| 6662 | let before = node.childNodes[offset - 1]; |
| 6663 | if (before.nodeType == 1) |
| 6664 | return flattenH(before.getBoundingClientRect(), false); |
| 6665 | } |
| 6666 | if (atom == null && offset < nodeSize(node)) { |
| 6667 | let after = node.childNodes[offset]; |
| 6668 | if (after.nodeType == 1) |
| 6669 | return flattenH(after.getBoundingClientRect(), true); |
| 6670 | } |
| 6671 | return flattenH(node.getBoundingClientRect(), side >= 0); |
| 6672 | } |
| 6673 | if (atom == null && offset && (side < 0 || offset == nodeSize(node))) { |
| 6674 | let before = node.childNodes[offset - 1]; |
| 6675 | let target = before.nodeType == 3 ? textRange(before, nodeSize(before) - (supportEmptyRange ? 0 : 1)) : before.nodeType == 1 && (before.nodeName != "BR" || !before.nextSibling) ? before : null; |
| 6676 | if (target) |
| 6677 | return flattenV(singleRect(target, 1), false); |
| 6678 | } |
| 6679 | if (atom == null && offset < nodeSize(node)) { |
| 6680 | let after = node.childNodes[offset]; |
| 6681 | while (after.pmViewDesc && after.pmViewDesc.ignoreForCoords) |
| 6682 | after = after.nextSibling; |
| 6683 | let target = !after ? null : after.nodeType == 3 ? textRange(after, 0, supportEmptyRange ? 0 : 1) : after.nodeType == 1 ? after : null; |
| 6684 | if (target) |
| 6685 | return flattenV(singleRect(target, -1), true); |
| 6686 | } |
| 6687 | return flattenV(singleRect(node.nodeType == 3 ? textRange(node) : node, -side), side >= 0); |
| 6688 | } |
| 6689 | function flattenV(rect, left) { |
| 6690 | if (rect.width == 0) |
| 6691 | return rect; |
| 6692 | let x = left ? rect.left : rect.right; |
| 6693 | return { top: rect.top, bottom: rect.bottom, left: x, right: x }; |
| 6694 | } |
| 6695 | function flattenH(rect, top) { |
| 6696 | if (rect.height == 0) |
| 6697 | return rect; |
| 6698 | let y = top ? rect.top : rect.bottom; |
| 6699 | return { top: y, bottom: y, left: rect.left, right: rect.right }; |
| 6700 | } |
| 6701 | function withFlushedState(view, state, f) { |
| 6702 | let viewState = view.state, active = view.root.activeElement; |
| 6703 | if (viewState != state) |
| 6704 | view.updateState(state); |
| 6705 | if (active != view.dom) |
| 6706 | view.focus(); |
| 6707 | try { |
| 6708 | return f(); |
| 6709 | } finally { |
| 6710 | if (viewState != state) |
| 6711 | view.updateState(viewState); |
| 6712 | if (active != view.dom && active) |
| 6713 | active.focus(); |
| 6714 | } |
| 6715 | } |
| 6716 | function endOfTextblockVertical(view, state, dir) { |
| 6717 | let sel = state.selection; |
| 6718 | let $pos = dir == "up" ? sel.$from : sel.$to; |
| 6719 | return withFlushedState(view, state, () => { |
| 6720 | let { node: dom } = view.docView.domFromPos($pos.pos, dir == "up" ? -1 : 1); |
| 6721 | for (; ; ) { |
| 6722 | let nearest = view.docView.nearestDesc(dom, true); |
| 6723 | if (!nearest) |
| 6724 | break; |
| 6725 | if (nearest.node.isBlock) { |
| 6726 | dom = nearest.contentDOM || nearest.dom; |
| 6727 | break; |
| 6728 | } |
| 6729 | dom = nearest.dom.parentNode; |
| 6730 | } |
| 6731 | let coords = coordsAtPos(view, $pos.pos, 1); |
| 6732 | for (let child = dom.firstChild; child; child = child.nextSibling) { |
| 6733 | let boxes; |
| 6734 | if (child.nodeType == 1) |
| 6735 | boxes = child.getClientRects(); |
| 6736 | else if (child.nodeType == 3) |
| 6737 | boxes = textRange(child, 0, child.nodeValue.length).getClientRects(); |
| 6738 | else |
| 6739 | continue; |
| 6740 | for (let i2 = 0; i2 < boxes.length; i2++) { |
| 6741 | let box = boxes[i2]; |
| 6742 | if (box.bottom > box.top + 1 && (dir == "up" ? coords.top - box.top > (box.bottom - coords.top) * 2 : box.bottom - coords.bottom > (coords.bottom - box.top) * 2)) |
| 6743 | return false; |
| 6744 | } |
| 6745 | } |
| 6746 | return true; |
| 6747 | }); |
| 6748 | } |
| 6749 | var maybeRTL = /[\u0590-\u08ac]/; |
| 6750 | function endOfTextblockHorizontal(view, state, dir) { |
| 6751 | let { $head } = state.selection; |
| 6752 | if (!$head.parent.isTextblock) |
| 6753 | return false; |
| 6754 | let offset = $head.parentOffset, atStart = !offset, atEnd = offset == $head.parent.content.size; |
| 6755 | let sel = view.domSelection(); |
| 6756 | if (!sel) |
| 6757 | return $head.pos == $head.start() || $head.pos == $head.end(); |
| 6758 | if (!maybeRTL.test($head.parent.textContent) || !sel.modify) |
| 6759 | return dir == "left" || dir == "backward" ? atStart : atEnd; |
| 6760 | return withFlushedState(view, state, () => { |
| 6761 | let { focusNode: oldNode, focusOffset: oldOff, anchorNode, anchorOffset } = view.domSelectionRange(); |
| 6762 | let oldBidiLevel = sel.caretBidiLevel; |
| 6763 | sel.modify("move", dir, "character"); |
| 6764 | let parentDOM = $head.depth ? view.docView.domAfterPos($head.before()) : view.dom; |
| 6765 | let { focusNode: newNode, focusOffset: newOff } = view.domSelectionRange(); |
| 6766 | let result = newNode && !parentDOM.contains(newNode.nodeType == 1 ? newNode : newNode.parentNode) || oldNode == newNode && oldOff == newOff; |
| 6767 | try { |
| 6768 | sel.collapse(anchorNode, anchorOffset); |
| 6769 | if (oldNode && (oldNode != anchorNode || oldOff != anchorOffset) && sel.extend) |
| 6770 | sel.extend(oldNode, oldOff); |
| 6771 | } catch (_) { |
| 6772 | } |
| 6773 | if (oldBidiLevel != null) |
| 6774 | sel.caretBidiLevel = oldBidiLevel; |
| 6775 | return result; |
| 6776 | }); |
| 6777 | } |
| 6778 | var cachedState = null; |
| 6779 | var cachedDir = null; |
| 6780 | var cachedResult = false; |
| 6781 | function endOfTextblock(view, state, dir) { |
| 6782 | if (cachedState == state && cachedDir == dir) |
| 6783 | return cachedResult; |
| 6784 | cachedState = state; |
| 6785 | cachedDir = dir; |
| 6786 | return cachedResult = dir == "up" || dir == "down" ? endOfTextblockVertical(view, state, dir) : endOfTextblockHorizontal(view, state, dir); |
| 6787 | } |
| 6788 | var NOT_DIRTY = 0; |
| 6789 | var CHILD_DIRTY = 1; |
| 6790 | var CONTENT_DIRTY = 2; |
| 6791 | var NODE_DIRTY = 3; |
| 6792 | var ViewDesc = class { |
| 6793 | constructor(parent, children, dom, contentDOM) { |
| 6794 | this.parent = parent; |
| 6795 | this.children = children; |
| 6796 | this.dom = dom; |
| 6797 | this.contentDOM = contentDOM; |
| 6798 | this.dirty = NOT_DIRTY; |
| 6799 | dom.pmViewDesc = this; |
| 6800 | } |
| 6801 | // Used to check whether a given description corresponds to a |
| 6802 | // widget/mark/node. |
| 6803 | matchesWidget(widget) { |
| 6804 | return false; |
| 6805 | } |
| 6806 | matchesMark(mark) { |
| 6807 | return false; |
| 6808 | } |
| 6809 | matchesNode(node, outerDeco, innerDeco) { |
| 6810 | return false; |
| 6811 | } |
| 6812 | matchesHack(nodeName) { |
| 6813 | return false; |
| 6814 | } |
| 6815 | // When parsing in-editor content (in domchange.js), we allow |
| 6816 | // descriptions to determine the parse rules that should be used to |
| 6817 | // parse them. |
| 6818 | parseRule() { |
| 6819 | return null; |
| 6820 | } |
| 6821 | // Used by the editor's event handler to ignore events that come |
| 6822 | // from certain descs. |
| 6823 | stopEvent(event) { |
| 6824 | return false; |
| 6825 | } |
| 6826 | // The size of the content represented by this desc. |
| 6827 | get size() { |
| 6828 | let size = 0; |
| 6829 | for (let i2 = 0; i2 < this.children.length; i2++) |
| 6830 | size += this.children[i2].size; |
| 6831 | return size; |
| 6832 | } |
| 6833 | // For block nodes, this represents the space taken up by their |
| 6834 | // start/end tokens. |
| 6835 | get border() { |
| 6836 | return 0; |
| 6837 | } |
| 6838 | destroy() { |
| 6839 | this.parent = void 0; |
| 6840 | if (this.dom.pmViewDesc == this) |
| 6841 | this.dom.pmViewDesc = void 0; |
| 6842 | for (let i2 = 0; i2 < this.children.length; i2++) |
| 6843 | this.children[i2].destroy(); |
| 6844 | } |
| 6845 | posBeforeChild(child) { |
| 6846 | for (let i2 = 0, pos = this.posAtStart; ; i2++) { |
| 6847 | let cur = this.children[i2]; |
| 6848 | if (cur == child) |
| 6849 | return pos; |
| 6850 | pos += cur.size; |
| 6851 | } |
| 6852 | } |
| 6853 | get posBefore() { |
| 6854 | return this.parent.posBeforeChild(this); |
| 6855 | } |
| 6856 | get posAtStart() { |
| 6857 | return this.parent ? this.parent.posBeforeChild(this) + this.border : 0; |
| 6858 | } |
| 6859 | get posAfter() { |
| 6860 | return this.posBefore + this.size; |
| 6861 | } |
| 6862 | get posAtEnd() { |
| 6863 | return this.posAtStart + this.size - 2 * this.border; |
| 6864 | } |
| 6865 | localPosFromDOM(dom, offset, bias) { |
| 6866 | if (this.contentDOM && this.contentDOM.contains(dom.nodeType == 1 ? dom : dom.parentNode)) { |
| 6867 | if (bias < 0) { |
| 6868 | let domBefore, desc; |
| 6869 | if (dom == this.contentDOM) { |
| 6870 | domBefore = dom.childNodes[offset - 1]; |
| 6871 | } else { |
| 6872 | while (dom.parentNode != this.contentDOM) |
| 6873 | dom = dom.parentNode; |
| 6874 | domBefore = dom.previousSibling; |
| 6875 | } |
| 6876 | while (domBefore && !((desc = domBefore.pmViewDesc) && desc.parent == this)) |
| 6877 | domBefore = domBefore.previousSibling; |
| 6878 | return domBefore ? this.posBeforeChild(desc) + desc.size : this.posAtStart; |
| 6879 | } else { |
| 6880 | let domAfter, desc; |
| 6881 | if (dom == this.contentDOM) { |
| 6882 | domAfter = dom.childNodes[offset]; |
| 6883 | } else { |
| 6884 | while (dom.parentNode != this.contentDOM) |
| 6885 | dom = dom.parentNode; |
| 6886 | domAfter = dom.nextSibling; |
| 6887 | } |
| 6888 | while (domAfter && !((desc = domAfter.pmViewDesc) && desc.parent == this)) |
| 6889 | domAfter = domAfter.nextSibling; |
| 6890 | return domAfter ? this.posBeforeChild(desc) : this.posAtEnd; |
| 6891 | } |
| 6892 | } |
| 6893 | let atEnd; |
| 6894 | if (dom == this.dom && this.contentDOM) { |
| 6895 | atEnd = offset > domIndex(this.contentDOM); |
| 6896 | } else if (this.contentDOM && this.contentDOM != this.dom && this.dom.contains(this.contentDOM)) { |
| 6897 | atEnd = dom.compareDocumentPosition(this.contentDOM) & 2; |
| 6898 | } else if (this.dom.firstChild) { |
| 6899 | if (offset == 0) |
| 6900 | for (let search = dom; ; search = search.parentNode) { |
| 6901 | if (search == this.dom) { |
| 6902 | atEnd = false; |
| 6903 | break; |
| 6904 | } |
| 6905 | if (search.previousSibling) |
| 6906 | break; |
| 6907 | } |
| 6908 | if (atEnd == null && offset == dom.childNodes.length) |
| 6909 | for (let search = dom; ; search = search.parentNode) { |
| 6910 | if (search == this.dom) { |
| 6911 | atEnd = true; |
| 6912 | break; |
| 6913 | } |
| 6914 | if (search.nextSibling) |
| 6915 | break; |
| 6916 | } |
| 6917 | } |
| 6918 | return (atEnd == null ? bias > 0 : atEnd) ? this.posAtEnd : this.posAtStart; |
| 6919 | } |
| 6920 | nearestDesc(dom, onlyNodes = false) { |
| 6921 | for (let first = true, cur = dom; cur; cur = cur.parentNode) { |
| 6922 | let desc = this.getDesc(cur), nodeDOM; |
| 6923 | if (desc && (!onlyNodes || desc.node)) { |
| 6924 | if (first && (nodeDOM = desc.nodeDOM) && !(nodeDOM.nodeType == 1 ? nodeDOM.contains(dom.nodeType == 1 ? dom : dom.parentNode) : nodeDOM == dom)) |
| 6925 | first = false; |
| 6926 | else |
| 6927 | return desc; |
| 6928 | } |
| 6929 | } |
| 6930 | } |
| 6931 | getDesc(dom) { |
| 6932 | let desc = dom.pmViewDesc; |
| 6933 | for (let cur = desc; cur; cur = cur.parent) |
| 6934 | if (cur == this) |
| 6935 | return desc; |
| 6936 | } |
| 6937 | posFromDOM(dom, offset, bias) { |
| 6938 | for (let scan = dom; scan; scan = scan.parentNode) { |
| 6939 | let desc = this.getDesc(scan); |
| 6940 | if (desc) |
| 6941 | return desc.localPosFromDOM(dom, offset, bias); |
| 6942 | } |
| 6943 | return -1; |
| 6944 | } |
| 6945 | // Find the desc for the node after the given pos, if any. (When a |
| 6946 | // parent node overrode rendering, there might not be one.) |
| 6947 | descAt(pos) { |
| 6948 | for (let i2 = 0, offset = 0; i2 < this.children.length; i2++) { |
| 6949 | let child = this.children[i2], end = offset + child.size; |
| 6950 | if (offset == pos && end != offset) { |
| 6951 | while (!child.border && child.children.length) { |
| 6952 | for (let i3 = 0; i3 < child.children.length; i3++) { |
| 6953 | let inner = child.children[i3]; |
| 6954 | if (inner.size) { |
| 6955 | child = inner; |
| 6956 | break; |
| 6957 | } |
| 6958 | } |
| 6959 | } |
| 6960 | return child; |
| 6961 | } |
| 6962 | if (pos < end) |
| 6963 | return child.descAt(pos - offset - child.border); |
| 6964 | offset = end; |
| 6965 | } |
| 6966 | } |
| 6967 | domFromPos(pos, side) { |
| 6968 | if (!this.contentDOM) |
| 6969 | return { node: this.dom, offset: 0, atom: pos + 1 }; |
| 6970 | let i2 = 0, offset = 0; |
| 6971 | for (let curPos = 0; i2 < this.children.length; i2++) { |
| 6972 | let child = this.children[i2], end = curPos + child.size; |
| 6973 | if (end > pos || child instanceof TrailingHackViewDesc) { |
| 6974 | offset = pos - curPos; |
| 6975 | break; |
| 6976 | } |
| 6977 | curPos = end; |
| 6978 | } |
| 6979 | if (offset) |
| 6980 | return this.children[i2].domFromPos(offset - this.children[i2].border, side); |
| 6981 | for (let prev; i2 && !(prev = this.children[i2 - 1]).size && prev instanceof WidgetViewDesc && prev.side >= 0; i2--) { |
| 6982 | } |
| 6983 | if (side <= 0) { |
| 6984 | let prev, enter = true; |
| 6985 | for (; ; i2--, enter = false) { |
| 6986 | prev = i2 ? this.children[i2 - 1] : null; |
| 6987 | if (!prev || prev.dom.parentNode == this.contentDOM) |
| 6988 | break; |
| 6989 | } |
| 6990 | if (prev && side && enter && !prev.border && !prev.domAtom) |
| 6991 | return prev.domFromPos(prev.size, side); |
| 6992 | return { node: this.contentDOM, offset: prev ? domIndex(prev.dom) + 1 : 0 }; |
| 6993 | } else { |
| 6994 | let next, enter = true; |
| 6995 | for (; ; i2++, enter = false) { |
| 6996 | next = i2 < this.children.length ? this.children[i2] : null; |
| 6997 | if (!next || next.dom.parentNode == this.contentDOM) |
| 6998 | break; |
| 6999 | } |
| 7000 | if (next && enter && !next.border && !next.domAtom) |
| 7001 | return next.domFromPos(0, side); |
| 7002 | return { node: this.contentDOM, offset: next ? domIndex(next.dom) : this.contentDOM.childNodes.length }; |
| 7003 | } |
| 7004 | } |
| 7005 | // Used to find a DOM range in a single parent for a given changed |
| 7006 | // range. |
| 7007 | parseRange(from2, to, base2 = 0) { |
| 7008 | if (this.children.length == 0) |
| 7009 | return { node: this.contentDOM, from: from2, to, fromOffset: 0, toOffset: this.contentDOM.childNodes.length }; |
| 7010 | let fromOffset = -1, toOffset = -1; |
| 7011 | for (let offset = base2, i2 = 0; ; i2++) { |
| 7012 | let child = this.children[i2], end = offset + child.size; |
| 7013 | if (fromOffset == -1 && from2 <= end) { |
| 7014 | let childBase = offset + child.border; |
| 7015 | if (from2 >= childBase && to <= end - child.border && child.node && child.contentDOM && this.contentDOM.contains(child.contentDOM)) |
| 7016 | return child.parseRange(from2, to, childBase); |
| 7017 | from2 = offset; |
| 7018 | for (let j = i2; j > 0; j--) { |
| 7019 | let prev = this.children[j - 1]; |
| 7020 | if (prev.size && prev.dom.parentNode == this.contentDOM && !prev.emptyChildAt(1)) { |
| 7021 | fromOffset = domIndex(prev.dom) + 1; |
| 7022 | break; |
| 7023 | } |
| 7024 | from2 -= prev.size; |
| 7025 | } |
| 7026 | if (fromOffset == -1) |
| 7027 | fromOffset = 0; |
| 7028 | } |
| 7029 | if (fromOffset > -1 && (end > to || i2 == this.children.length - 1)) { |
| 7030 | to = end; |
| 7031 | for (let j = i2 + 1; j < this.children.length; j++) { |
| 7032 | let next = this.children[j]; |
| 7033 | if (next.size && next.dom.parentNode == this.contentDOM && !next.emptyChildAt(-1)) { |
| 7034 | toOffset = domIndex(next.dom); |
| 7035 | break; |
| 7036 | } |
| 7037 | to += next.size; |
| 7038 | } |
| 7039 | if (toOffset == -1) |
| 7040 | toOffset = this.contentDOM.childNodes.length; |
| 7041 | break; |
| 7042 | } |
| 7043 | offset = end; |
| 7044 | } |
| 7045 | return { node: this.contentDOM, from: from2, to, fromOffset, toOffset }; |
| 7046 | } |
| 7047 | emptyChildAt(side) { |
| 7048 | if (this.border || !this.contentDOM || !this.children.length) |
| 7049 | return false; |
| 7050 | let child = this.children[side < 0 ? 0 : this.children.length - 1]; |
| 7051 | return child.size == 0 || child.emptyChildAt(side); |
| 7052 | } |
| 7053 | domAfterPos(pos) { |
| 7054 | let { node, offset } = this.domFromPos(pos, 0); |
| 7055 | if (node.nodeType != 1 || offset == node.childNodes.length) |
| 7056 | throw new RangeError("No node after pos " + pos); |
| 7057 | return node.childNodes[offset]; |
| 7058 | } |
| 7059 | // View descs are responsible for setting any selection that falls |
| 7060 | // entirely inside of them, so that custom implementations can do |
| 7061 | // custom things with the selection. Note that this falls apart when |
| 7062 | // a selection starts in such a node and ends in another, in which |
| 7063 | // case we just use whatever domFromPos produces as a best effort. |
| 7064 | setSelection(anchor, head, view, force = false) { |
| 7065 | let from2 = Math.min(anchor, head), to = Math.max(anchor, head); |
| 7066 | for (let i2 = 0, offset = 0; i2 < this.children.length; i2++) { |
| 7067 | let child = this.children[i2], end = offset + child.size; |
| 7068 | if (from2 > offset && to < end) |
| 7069 | return child.setSelection(anchor - offset - child.border, head - offset - child.border, view, force); |
| 7070 | offset = end; |
| 7071 | } |
| 7072 | let anchorDOM = this.domFromPos(anchor, anchor ? -1 : 1); |
| 7073 | let headDOM = head == anchor ? anchorDOM : this.domFromPos(head, head ? -1 : 1); |
| 7074 | let domSel = view.root.getSelection(); |
| 7075 | let selRange = view.domSelectionRange(); |
| 7076 | let brKludge = false; |
| 7077 | if ((gecko || safari) && anchor == head) { |
| 7078 | let { node, offset } = anchorDOM; |
| 7079 | if (node.nodeType == 3) { |
| 7080 | brKludge = !!(offset && node.nodeValue[offset - 1] == "\n"); |
| 7081 | if (brKludge && offset == node.nodeValue.length) { |
| 7082 | for (let scan = node, after; scan; scan = scan.parentNode) { |
| 7083 | if (after = scan.nextSibling) { |
| 7084 | if (after.nodeName == "BR") |
| 7085 | anchorDOM = headDOM = { node: after.parentNode, offset: domIndex(after) + 1 }; |
| 7086 | break; |
| 7087 | } |
| 7088 | let desc = scan.pmViewDesc; |
| 7089 | if (desc && desc.node && desc.node.isBlock) |
| 7090 | break; |
| 7091 | } |
| 7092 | } |
| 7093 | } else { |
| 7094 | let prev = node.childNodes[offset - 1]; |
| 7095 | brKludge = prev && (prev.nodeName == "BR" || prev.contentEditable == "false"); |
| 7096 | } |
| 7097 | } |
| 7098 | if (gecko && selRange.focusNode && selRange.focusNode != headDOM.node && selRange.focusNode.nodeType == 1) { |
| 7099 | let after = selRange.focusNode.childNodes[selRange.focusOffset]; |
| 7100 | if (after && after.contentEditable == "false") |
| 7101 | force = true; |
| 7102 | } |
| 7103 | if (!(force || brKludge && safari) && isEquivalentPosition(anchorDOM.node, anchorDOM.offset, selRange.anchorNode, selRange.anchorOffset) && isEquivalentPosition(headDOM.node, headDOM.offset, selRange.focusNode, selRange.focusOffset)) |
| 7104 | return; |
| 7105 | let domSelExtended = false; |
| 7106 | if ((domSel.extend || anchor == head) && !(brKludge && gecko)) { |
| 7107 | domSel.collapse(anchorDOM.node, anchorDOM.offset); |
| 7108 | try { |
| 7109 | if (anchor != head) |
| 7110 | domSel.extend(headDOM.node, headDOM.offset); |
| 7111 | domSelExtended = true; |
| 7112 | } catch (_) { |
| 7113 | } |
| 7114 | } |
| 7115 | if (!domSelExtended) { |
| 7116 | if (anchor > head) { |
| 7117 | let tmp = anchorDOM; |
| 7118 | anchorDOM = headDOM; |
| 7119 | headDOM = tmp; |
| 7120 | } |
| 7121 | let range = document.createRange(); |
| 7122 | range.setEnd(headDOM.node, headDOM.offset); |
| 7123 | range.setStart(anchorDOM.node, anchorDOM.offset); |
| 7124 | domSel.removeAllRanges(); |
| 7125 | domSel.addRange(range); |
| 7126 | } |
| 7127 | } |
| 7128 | ignoreMutation(mutation) { |
| 7129 | return !this.contentDOM && mutation.type != "selection"; |
| 7130 | } |
| 7131 | get contentLost() { |
| 7132 | return this.contentDOM && this.contentDOM != this.dom && !this.dom.contains(this.contentDOM); |
| 7133 | } |
| 7134 | // Remove a subtree of the element tree that has been touched |
| 7135 | // by a DOM change, so that the next update will redraw it. |
| 7136 | markDirty(from2, to) { |
| 7137 | for (let offset = 0, i2 = 0; i2 < this.children.length; i2++) { |
| 7138 | let child = this.children[i2], end = offset + child.size; |
| 7139 | if (offset == end ? from2 <= end && to >= offset : from2 < end && to > offset) { |
| 7140 | let startInside = offset + child.border, endInside = end - child.border; |
| 7141 | if (from2 >= startInside && to <= endInside) { |
| 7142 | this.dirty = from2 == offset || to == end ? CONTENT_DIRTY : CHILD_DIRTY; |
| 7143 | if (from2 == startInside && to == endInside && (child.contentLost || child.dom.parentNode != this.contentDOM)) |
| 7144 | child.dirty = NODE_DIRTY; |
| 7145 | else |
| 7146 | child.markDirty(from2 - startInside, to - startInside); |
| 7147 | return; |
| 7148 | } else { |
| 7149 | child.dirty = child.dom == child.contentDOM && child.dom.parentNode == this.contentDOM && !child.children.length ? CONTENT_DIRTY : NODE_DIRTY; |
| 7150 | } |
| 7151 | } |
| 7152 | offset = end; |
| 7153 | } |
| 7154 | this.dirty = CONTENT_DIRTY; |
| 7155 | } |
| 7156 | markParentsDirty() { |
| 7157 | let level = 1; |
| 7158 | for (let node = this.parent; node; node = node.parent, level++) { |
| 7159 | let dirty = level == 1 ? CONTENT_DIRTY : CHILD_DIRTY; |
| 7160 | if (node.dirty < dirty) |
| 7161 | node.dirty = dirty; |
| 7162 | } |
| 7163 | } |
| 7164 | get domAtom() { |
| 7165 | return false; |
| 7166 | } |
| 7167 | get ignoreForCoords() { |
| 7168 | return false; |
| 7169 | } |
| 7170 | get ignoreForSelection() { |
| 7171 | return false; |
| 7172 | } |
| 7173 | isText(text) { |
| 7174 | return false; |
| 7175 | } |
| 7176 | }; |
| 7177 | var WidgetViewDesc = class extends ViewDesc { |
| 7178 | constructor(parent, widget, view, pos) { |
| 7179 | let self, dom = widget.type.toDOM; |
| 7180 | if (typeof dom == "function") |
| 7181 | dom = dom(view, () => { |
| 7182 | if (!self) |
| 7183 | return pos; |
| 7184 | if (self.parent) |
| 7185 | return self.parent.posBeforeChild(self); |
| 7186 | }); |
| 7187 | if (!widget.type.spec.raw) { |
| 7188 | if (dom.nodeType != 1) { |
| 7189 | let wrap2 = document.createElement("span"); |
| 7190 | wrap2.appendChild(dom); |
| 7191 | dom = wrap2; |
| 7192 | } |
| 7193 | dom.contentEditable = "false"; |
| 7194 | dom.classList.add("ProseMirror-widget"); |
| 7195 | } |
| 7196 | super(parent, [], dom, null); |
| 7197 | this.widget = widget; |
| 7198 | this.widget = widget; |
| 7199 | self = this; |
| 7200 | } |
| 7201 | matchesWidget(widget) { |
| 7202 | return this.dirty == NOT_DIRTY && widget.type.eq(this.widget.type); |
| 7203 | } |
| 7204 | parseRule() { |
| 7205 | return { ignore: true }; |
| 7206 | } |
| 7207 | stopEvent(event) { |
| 7208 | let stop = this.widget.spec.stopEvent; |
| 7209 | return stop ? stop(event) : false; |
| 7210 | } |
| 7211 | ignoreMutation(mutation) { |
| 7212 | return mutation.type != "selection" || this.widget.spec.ignoreSelection; |
| 7213 | } |
| 7214 | destroy() { |
| 7215 | this.widget.type.destroy(this.dom); |
| 7216 | super.destroy(); |
| 7217 | } |
| 7218 | get domAtom() { |
| 7219 | return true; |
| 7220 | } |
| 7221 | get ignoreForSelection() { |
| 7222 | return !!this.widget.type.spec.relaxedSide; |
| 7223 | } |
| 7224 | get side() { |
| 7225 | return this.widget.type.side; |
| 7226 | } |
| 7227 | }; |
| 7228 | var CompositionViewDesc = class extends ViewDesc { |
| 7229 | constructor(parent, dom, textDOM, text) { |
| 7230 | super(parent, [], dom, null); |
| 7231 | this.textDOM = textDOM; |
| 7232 | this.text = text; |
| 7233 | } |
| 7234 | get size() { |
| 7235 | return this.text.length; |
| 7236 | } |
| 7237 | localPosFromDOM(dom, offset) { |
| 7238 | if (dom != this.textDOM) |
| 7239 | return this.posAtStart + (offset ? this.size : 0); |
| 7240 | return this.posAtStart + offset; |
| 7241 | } |
| 7242 | domFromPos(pos) { |
| 7243 | return { node: this.textDOM, offset: pos }; |
| 7244 | } |
| 7245 | ignoreMutation(mut) { |
| 7246 | return mut.type === "characterData" && mut.target.nodeValue == mut.oldValue; |
| 7247 | } |
| 7248 | }; |
| 7249 | var MarkViewDesc = class _MarkViewDesc extends ViewDesc { |
| 7250 | constructor(parent, mark, dom, contentDOM, spec) { |
| 7251 | super(parent, [], dom, contentDOM); |
| 7252 | this.mark = mark; |
| 7253 | this.spec = spec; |
| 7254 | } |
| 7255 | static create(parent, mark, inline, view) { |
| 7256 | let custom = view.nodeViews[mark.type.name]; |
| 7257 | let spec = custom && custom(mark, view, inline); |
| 7258 | if (!spec || !spec.dom) |
| 7259 | spec = DOMSerializer.renderSpec(document, mark.type.spec.toDOM(mark, inline), null, mark.attrs); |
| 7260 | return new _MarkViewDesc(parent, mark, spec.dom, spec.contentDOM || spec.dom, spec); |
| 7261 | } |
| 7262 | parseRule() { |
| 7263 | if (this.dirty & NODE_DIRTY || this.mark.type.spec.reparseInView) |
| 7264 | return null; |
| 7265 | return { mark: this.mark.type.name, attrs: this.mark.attrs, contentElement: this.contentDOM }; |
| 7266 | } |
| 7267 | matchesMark(mark) { |
| 7268 | return this.dirty != NODE_DIRTY && this.mark.eq(mark); |
| 7269 | } |
| 7270 | markDirty(from2, to) { |
| 7271 | super.markDirty(from2, to); |
| 7272 | if (this.dirty != NOT_DIRTY) { |
| 7273 | let parent = this.parent; |
| 7274 | while (!parent.node) |
| 7275 | parent = parent.parent; |
| 7276 | if (parent.dirty < this.dirty) |
| 7277 | parent.dirty = this.dirty; |
| 7278 | this.dirty = NOT_DIRTY; |
| 7279 | } |
| 7280 | } |
| 7281 | slice(from2, to, view) { |
| 7282 | let copy2 = _MarkViewDesc.create(this.parent, this.mark, true, view); |
| 7283 | let nodes = this.children, size = this.size; |
| 7284 | if (to < size) |
| 7285 | nodes = replaceNodes(nodes, to, size, view); |
| 7286 | if (from2 > 0) |
| 7287 | nodes = replaceNodes(nodes, 0, from2, view); |
| 7288 | for (let i2 = 0; i2 < nodes.length; i2++) |
| 7289 | nodes[i2].parent = copy2; |
| 7290 | copy2.children = nodes; |
| 7291 | return copy2; |
| 7292 | } |
| 7293 | ignoreMutation(mutation) { |
| 7294 | return this.spec.ignoreMutation ? this.spec.ignoreMutation(mutation) : super.ignoreMutation(mutation); |
| 7295 | } |
| 7296 | destroy() { |
| 7297 | if (this.spec.destroy) |
| 7298 | this.spec.destroy(); |
| 7299 | super.destroy(); |
| 7300 | } |
| 7301 | }; |
| 7302 | var NodeViewDesc = class _NodeViewDesc extends ViewDesc { |
| 7303 | constructor(parent, node, outerDeco, innerDeco, dom, contentDOM, nodeDOM) { |
| 7304 | super(parent, [], dom, contentDOM); |
| 7305 | this.node = node; |
| 7306 | this.outerDeco = outerDeco; |
| 7307 | this.innerDeco = innerDeco; |
| 7308 | this.nodeDOM = nodeDOM; |
| 7309 | } |
| 7310 | // By default, a node is rendered using the `toDOM` method from the |
| 7311 | // node type spec. But client code can use the `nodeViews` spec to |
| 7312 | // supply a custom node view, which can influence various aspects of |
| 7313 | // the way the node works. |
| 7314 | // |
| 7315 | // (Using subclassing for this was intentionally decided against, |
| 7316 | // since it'd require exposing a whole slew of finicky |
| 7317 | // implementation details to the user code that they probably will |
| 7318 | // never need.) |
| 7319 | static create(parent, node, outerDeco, innerDeco, view, pos) { |
| 7320 | let custom = view.nodeViews[node.type.name], descObj; |
| 7321 | let spec = custom && custom(node, view, () => { |
| 7322 | if (!descObj) |
| 7323 | return pos; |
| 7324 | if (descObj.parent) |
| 7325 | return descObj.parent.posBeforeChild(descObj); |
| 7326 | }, outerDeco, innerDeco); |
| 7327 | let dom = spec && spec.dom, contentDOM = spec && spec.contentDOM; |
| 7328 | if (node.isText) { |
| 7329 | if (!dom) |
| 7330 | dom = document.createTextNode(node.text); |
| 7331 | else if (dom.nodeType != 3) |
| 7332 | throw new RangeError("Text must be rendered as a DOM text node"); |
| 7333 | } else if (!dom) { |
| 7334 | let spec2 = DOMSerializer.renderSpec(document, node.type.spec.toDOM(node), null, node.attrs); |
| 7335 | ({ dom, contentDOM } = spec2); |
| 7336 | } |
| 7337 | if (!contentDOM && !node.isText && dom.nodeName != "BR") { |
| 7338 | if (!dom.hasAttribute("contenteditable")) |
| 7339 | dom.contentEditable = "false"; |
| 7340 | if (node.type.spec.draggable) |
| 7341 | dom.draggable = true; |
| 7342 | } |
| 7343 | let nodeDOM = dom; |
| 7344 | dom = applyOuterDeco(dom, outerDeco, node); |
| 7345 | if (spec) |
| 7346 | return descObj = new CustomNodeViewDesc(parent, node, outerDeco, innerDeco, dom, contentDOM || null, nodeDOM, spec); |
| 7347 | else if (node.isText) |
| 7348 | return new TextViewDesc(parent, node, outerDeco, innerDeco, dom, nodeDOM); |
| 7349 | else |
| 7350 | return new _NodeViewDesc(parent, node, outerDeco, innerDeco, dom, contentDOM || null, nodeDOM); |
| 7351 | } |
| 7352 | parseRule() { |
| 7353 | if (this.node.type.spec.reparseInView) |
| 7354 | return null; |
| 7355 | let rule = { node: this.node.type.name, attrs: this.node.attrs }; |
| 7356 | if (this.node.type.whitespace == "pre") |
| 7357 | rule.preserveWhitespace = "full"; |
| 7358 | if (!this.contentDOM) { |
| 7359 | rule.getContent = () => this.node.content; |
| 7360 | } else if (!this.contentLost) { |
| 7361 | rule.contentElement = this.contentDOM; |
| 7362 | } else { |
| 7363 | for (let i2 = this.children.length - 1; i2 >= 0; i2--) { |
| 7364 | let child = this.children[i2]; |
| 7365 | if (this.dom.contains(child.dom.parentNode)) { |
| 7366 | rule.contentElement = child.dom.parentNode; |
| 7367 | break; |
| 7368 | } |
| 7369 | } |
| 7370 | if (!rule.contentElement) |
| 7371 | rule.getContent = () => Fragment.empty; |
| 7372 | } |
| 7373 | return rule; |
| 7374 | } |
| 7375 | matchesNode(node, outerDeco, innerDeco) { |
| 7376 | return this.dirty == NOT_DIRTY && node.eq(this.node) && sameOuterDeco(outerDeco, this.outerDeco) && innerDeco.eq(this.innerDeco); |
| 7377 | } |
| 7378 | get size() { |
| 7379 | return this.node.nodeSize; |
| 7380 | } |
| 7381 | get border() { |
| 7382 | return this.node.isLeaf ? 0 : 1; |
| 7383 | } |
| 7384 | // Syncs `this.children` to match `this.node.content` and the local |
| 7385 | // decorations, possibly introducing nesting for marks. Then, in a |
| 7386 | // separate step, syncs the DOM inside `this.contentDOM` to |
| 7387 | // `this.children`. |
| 7388 | updateChildren(view, pos) { |
| 7389 | let inline = this.node.inlineContent, off = pos; |
| 7390 | let composition = view.composing ? this.localCompositionInfo(view, pos) : null; |
| 7391 | let localComposition = composition && composition.pos > -1 ? composition : null; |
| 7392 | let compositionInChild = composition && composition.pos < 0; |
| 7393 | let updater = new ViewTreeUpdater(this, localComposition && localComposition.node, view); |
| 7394 | iterDeco(this.node, this.innerDeco, (widget, i2, insideNode) => { |
| 7395 | if (widget.spec.marks) |
| 7396 | updater.syncToMarks(widget.spec.marks, inline, view, i2); |
| 7397 | else if (widget.type.side >= 0 && !insideNode) |
| 7398 | updater.syncToMarks(i2 == this.node.childCount ? Mark.none : this.node.child(i2).marks, inline, view, i2); |
| 7399 | updater.placeWidget(widget, view, off); |
| 7400 | }, (child, outerDeco, innerDeco, i2) => { |
| 7401 | updater.syncToMarks(child.marks, inline, view, i2); |
| 7402 | let compIndex; |
| 7403 | if (updater.findNodeMatch(child, outerDeco, innerDeco, i2)) ; |
| 7404 | else if (compositionInChild && view.state.selection.from > off && view.state.selection.to < off + child.nodeSize && (compIndex = updater.findIndexWithChild(composition.node)) > -1 && updater.updateNodeAt(child, outerDeco, innerDeco, compIndex, view)) ; |
| 7405 | else if (updater.updateNextNode(child, outerDeco, innerDeco, view, i2, off)) ; |
| 7406 | else { |
| 7407 | updater.addNode(child, outerDeco, innerDeco, view, off); |
| 7408 | } |
| 7409 | off += child.nodeSize; |
| 7410 | }); |
| 7411 | updater.syncToMarks([], inline, view, 0); |
| 7412 | if (this.node.isTextblock) |
| 7413 | updater.addTextblockHacks(); |
| 7414 | updater.destroyRest(); |
| 7415 | if (updater.changed || this.dirty == CONTENT_DIRTY) { |
| 7416 | if (localComposition) |
| 7417 | this.protectLocalComposition(view, localComposition); |
| 7418 | renderDescs(this.contentDOM, this.children, view); |
| 7419 | if (ios) |
| 7420 | iosHacks(this.dom); |
| 7421 | } |
| 7422 | } |
| 7423 | localCompositionInfo(view, pos) { |
| 7424 | let { from: from2, to } = view.state.selection; |
| 7425 | if (!(view.state.selection instanceof TextSelection) || from2 < pos || to > pos + this.node.content.size) |
| 7426 | return null; |
| 7427 | let textNode = view.input.compositionNode; |
| 7428 | if (!textNode || !this.dom.contains(textNode.parentNode)) |
| 7429 | return null; |
| 7430 | if (this.node.inlineContent) { |
| 7431 | let text = textNode.nodeValue; |
| 7432 | let textPos = findTextInFragment(this.node.content, text, from2 - pos, to - pos); |
| 7433 | return textPos < 0 ? null : { node: textNode, pos: textPos, text }; |
| 7434 | } else { |
| 7435 | return { node: textNode, pos: -1, text: "" }; |
| 7436 | } |
| 7437 | } |
| 7438 | protectLocalComposition(view, { node, pos, text }) { |
| 7439 | if (this.getDesc(node)) |
| 7440 | return; |
| 7441 | let topNode = node; |
| 7442 | for (; ; topNode = topNode.parentNode) { |
| 7443 | if (topNode.parentNode == this.contentDOM) |
| 7444 | break; |
| 7445 | while (topNode.previousSibling) |
| 7446 | topNode.parentNode.removeChild(topNode.previousSibling); |
| 7447 | while (topNode.nextSibling) |
| 7448 | topNode.parentNode.removeChild(topNode.nextSibling); |
| 7449 | if (topNode.pmViewDesc) |
| 7450 | topNode.pmViewDesc = void 0; |
| 7451 | } |
| 7452 | let desc = new CompositionViewDesc(this, topNode, node, text); |
| 7453 | view.input.compositionNodes.push(desc); |
| 7454 | this.children = replaceNodes(this.children, pos, pos + text.length, view, desc); |
| 7455 | } |
| 7456 | // If this desc must be updated to match the given node decoration, |
| 7457 | // do so and return true. |
| 7458 | update(node, outerDeco, innerDeco, view) { |
| 7459 | if (this.dirty == NODE_DIRTY || !node.sameMarkup(this.node)) |
| 7460 | return false; |
| 7461 | this.updateInner(node, outerDeco, innerDeco, view); |
| 7462 | return true; |
| 7463 | } |
| 7464 | updateInner(node, outerDeco, innerDeco, view) { |
| 7465 | this.updateOuterDeco(outerDeco); |
| 7466 | this.node = node; |
| 7467 | this.innerDeco = innerDeco; |
| 7468 | if (this.contentDOM) |
| 7469 | this.updateChildren(view, this.posAtStart); |
| 7470 | this.dirty = NOT_DIRTY; |
| 7471 | } |
| 7472 | updateOuterDeco(outerDeco) { |
| 7473 | if (sameOuterDeco(outerDeco, this.outerDeco)) |
| 7474 | return; |
| 7475 | let needsWrap = this.nodeDOM.nodeType != 1; |
| 7476 | let oldDOM = this.dom; |
| 7477 | this.dom = patchOuterDeco(this.dom, this.nodeDOM, computeOuterDeco(this.outerDeco, this.node, needsWrap), computeOuterDeco(outerDeco, this.node, needsWrap)); |
| 7478 | if (this.dom != oldDOM) { |
| 7479 | oldDOM.pmViewDesc = void 0; |
| 7480 | this.dom.pmViewDesc = this; |
| 7481 | } |
| 7482 | this.outerDeco = outerDeco; |
| 7483 | } |
| 7484 | // Mark this node as being the selected node. |
| 7485 | selectNode() { |
| 7486 | if (this.nodeDOM.nodeType == 1) { |
| 7487 | this.nodeDOM.classList.add("ProseMirror-selectednode"); |
| 7488 | if (this.contentDOM || !this.node.type.spec.draggable) |
| 7489 | this.nodeDOM.draggable = true; |
| 7490 | } |
| 7491 | } |
| 7492 | // Remove selected node marking from this node. |
| 7493 | deselectNode() { |
| 7494 | if (this.nodeDOM.nodeType == 1) { |
| 7495 | this.nodeDOM.classList.remove("ProseMirror-selectednode"); |
| 7496 | if (this.contentDOM || !this.node.type.spec.draggable) |
| 7497 | this.nodeDOM.removeAttribute("draggable"); |
| 7498 | } |
| 7499 | } |
| 7500 | get domAtom() { |
| 7501 | return this.node.isAtom; |
| 7502 | } |
| 7503 | }; |
| 7504 | function docViewDesc(doc3, outerDeco, innerDeco, dom, view) { |
| 7505 | applyOuterDeco(dom, outerDeco, doc3); |
| 7506 | let docView = new NodeViewDesc(void 0, doc3, outerDeco, innerDeco, dom, dom, dom); |
| 7507 | if (docView.contentDOM) |
| 7508 | docView.updateChildren(view, 0); |
| 7509 | return docView; |
| 7510 | } |
| 7511 | var TextViewDesc = class _TextViewDesc extends NodeViewDesc { |
| 7512 | constructor(parent, node, outerDeco, innerDeco, dom, nodeDOM) { |
| 7513 | super(parent, node, outerDeco, innerDeco, dom, null, nodeDOM); |
| 7514 | } |
| 7515 | parseRule() { |
| 7516 | let skip = this.nodeDOM.parentNode; |
| 7517 | while (skip && skip != this.dom && !skip.pmIsDeco) |
| 7518 | skip = skip.parentNode; |
| 7519 | return { skip: skip || true }; |
| 7520 | } |
| 7521 | update(node, outerDeco, innerDeco, view) { |
| 7522 | if (this.dirty == NODE_DIRTY || this.dirty != NOT_DIRTY && !this.inParent() || !node.sameMarkup(this.node)) |
| 7523 | return false; |
| 7524 | this.updateOuterDeco(outerDeco); |
| 7525 | if ((this.dirty != NOT_DIRTY || node.text != this.node.text) && node.text != this.nodeDOM.nodeValue) { |
| 7526 | this.nodeDOM.nodeValue = node.text; |
| 7527 | if (view.trackWrites == this.nodeDOM) |
| 7528 | view.trackWrites = null; |
| 7529 | } |
| 7530 | this.node = node; |
| 7531 | this.dirty = NOT_DIRTY; |
| 7532 | return true; |
| 7533 | } |
| 7534 | inParent() { |
| 7535 | let parentDOM = this.parent.contentDOM; |
| 7536 | for (let n = this.nodeDOM; n; n = n.parentNode) |
| 7537 | if (n == parentDOM) |
| 7538 | return true; |
| 7539 | return false; |
| 7540 | } |
| 7541 | domFromPos(pos) { |
| 7542 | return { node: this.nodeDOM, offset: pos }; |
| 7543 | } |
| 7544 | localPosFromDOM(dom, offset, bias) { |
| 7545 | if (dom == this.nodeDOM) |
| 7546 | return this.posAtStart + Math.min(offset, this.node.text.length); |
| 7547 | return super.localPosFromDOM(dom, offset, bias); |
| 7548 | } |
| 7549 | ignoreMutation(mutation) { |
| 7550 | return mutation.type != "characterData" && mutation.type != "selection"; |
| 7551 | } |
| 7552 | slice(from2, to, _view) { |
| 7553 | let node = this.node.cut(from2, to), dom = document.createTextNode(node.text); |
| 7554 | return new _TextViewDesc(this.parent, node, this.outerDeco, this.innerDeco, dom, dom); |
| 7555 | } |
| 7556 | markDirty(from2, to) { |
| 7557 | super.markDirty(from2, to); |
| 7558 | if (this.dom != this.nodeDOM && (from2 == 0 || to == this.nodeDOM.nodeValue.length)) |
| 7559 | this.dirty = NODE_DIRTY; |
| 7560 | } |
| 7561 | get domAtom() { |
| 7562 | return false; |
| 7563 | } |
| 7564 | isText(text) { |
| 7565 | return this.node.text == text; |
| 7566 | } |
| 7567 | }; |
| 7568 | var TrailingHackViewDesc = class extends ViewDesc { |
| 7569 | parseRule() { |
| 7570 | return { ignore: true }; |
| 7571 | } |
| 7572 | matchesHack(nodeName) { |
| 7573 | return this.dirty == NOT_DIRTY && this.dom.nodeName == nodeName; |
| 7574 | } |
| 7575 | get domAtom() { |
| 7576 | return true; |
| 7577 | } |
| 7578 | get ignoreForCoords() { |
| 7579 | return this.dom.nodeName == "IMG"; |
| 7580 | } |
| 7581 | }; |
| 7582 | var CustomNodeViewDesc = class extends NodeViewDesc { |
| 7583 | constructor(parent, node, outerDeco, innerDeco, dom, contentDOM, nodeDOM, spec) { |
| 7584 | super(parent, node, outerDeco, innerDeco, dom, contentDOM, nodeDOM); |
| 7585 | this.spec = spec; |
| 7586 | } |
| 7587 | // A custom `update` method gets to decide whether the update goes |
| 7588 | // through. If it does, and there's a `contentDOM` node, our logic |
| 7589 | // updates the children. |
| 7590 | update(node, outerDeco, innerDeco, view) { |
| 7591 | if (this.dirty == NODE_DIRTY) |
| 7592 | return false; |
| 7593 | if (this.spec.update && (this.node.type == node.type || this.spec.multiType)) { |
| 7594 | let result = this.spec.update(node, outerDeco, innerDeco); |
| 7595 | if (result) |
| 7596 | this.updateInner(node, outerDeco, innerDeco, view); |
| 7597 | return result; |
| 7598 | } else if (!this.contentDOM && !node.isLeaf) { |
| 7599 | return false; |
| 7600 | } else { |
| 7601 | return super.update(node, outerDeco, innerDeco, view); |
| 7602 | } |
| 7603 | } |
| 7604 | selectNode() { |
| 7605 | this.spec.selectNode ? this.spec.selectNode() : super.selectNode(); |
| 7606 | } |
| 7607 | deselectNode() { |
| 7608 | this.spec.deselectNode ? this.spec.deselectNode() : super.deselectNode(); |
| 7609 | } |
| 7610 | setSelection(anchor, head, view, force) { |
| 7611 | this.spec.setSelection ? this.spec.setSelection(anchor, head, view.root) : super.setSelection(anchor, head, view, force); |
| 7612 | } |
| 7613 | destroy() { |
| 7614 | if (this.spec.destroy) |
| 7615 | this.spec.destroy(); |
| 7616 | super.destroy(); |
| 7617 | } |
| 7618 | stopEvent(event) { |
| 7619 | return this.spec.stopEvent ? this.spec.stopEvent(event) : false; |
| 7620 | } |
| 7621 | ignoreMutation(mutation) { |
| 7622 | return this.spec.ignoreMutation ? this.spec.ignoreMutation(mutation) : super.ignoreMutation(mutation); |
| 7623 | } |
| 7624 | }; |
| 7625 | function renderDescs(parentDOM, descs, view) { |
| 7626 | let dom = parentDOM.firstChild, written = false; |
| 7627 | for (let i2 = 0; i2 < descs.length; i2++) { |
| 7628 | let desc = descs[i2], childDOM = desc.dom; |
| 7629 | if (childDOM.parentNode == parentDOM) { |
| 7630 | while (childDOM != dom) { |
| 7631 | dom = rm(dom); |
| 7632 | written = true; |
| 7633 | } |
| 7634 | dom = dom.nextSibling; |
| 7635 | } else { |
| 7636 | written = true; |
| 7637 | parentDOM.insertBefore(childDOM, dom); |
| 7638 | } |
| 7639 | if (desc instanceof MarkViewDesc) { |
| 7640 | let pos = dom ? dom.previousSibling : parentDOM.lastChild; |
| 7641 | renderDescs(desc.contentDOM, desc.children, view); |
| 7642 | dom = pos ? pos.nextSibling : parentDOM.firstChild; |
| 7643 | } |
| 7644 | } |
| 7645 | while (dom) { |
| 7646 | dom = rm(dom); |
| 7647 | written = true; |
| 7648 | } |
| 7649 | if (written && view.trackWrites == parentDOM) |
| 7650 | view.trackWrites = null; |
| 7651 | } |
| 7652 | var OuterDecoLevel = function(nodeName) { |
| 7653 | if (nodeName) |
| 7654 | this.nodeName = nodeName; |
| 7655 | }; |
| 7656 | OuterDecoLevel.prototype = /* @__PURE__ */ Object.create(null); |
| 7657 | var noDeco = [new OuterDecoLevel()]; |
| 7658 | function computeOuterDeco(outerDeco, node, needsWrap) { |
| 7659 | if (outerDeco.length == 0) |
| 7660 | return noDeco; |
| 7661 | let top = needsWrap ? noDeco[0] : new OuterDecoLevel(), result = [top]; |
| 7662 | for (let i2 = 0; i2 < outerDeco.length; i2++) { |
| 7663 | let attrs2 = outerDeco[i2].type.attrs; |
| 7664 | if (!attrs2) |
| 7665 | c |