markupeditor 0.9.51 → 0.9.53
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/markup-editor.js +97 -19
- package/package.json +1 -1
package/dist/markup-editor.js
CHANGED
|
@@ -621,6 +621,40 @@ class MUError {
|
|
|
621
621
|
|
|
622
622
|
}
|
|
623
623
|
|
|
624
|
+
/**
|
|
625
|
+
* Return the slug for a heading's `text` the way GitHub makes it: lowercase, keep alphabetic
|
|
626
|
+
* characters, combining marks, decimal digits, connector punctuation (which includes `_`) and `-`,
|
|
627
|
+
* and replace blanks with `-`. The slug is cut to 40 characters, counting characters rather than
|
|
628
|
+
* UTF-16 units, just to avoid unwieldy IDs.
|
|
629
|
+
*
|
|
630
|
+
* @param {string} text The text content of a heading
|
|
631
|
+
* @returns {string} The slug, which is empty if nothing in `text` is kept
|
|
632
|
+
*/
|
|
633
|
+
function headingSlug(text) {
|
|
634
|
+
const slug = text.toLowerCase()
|
|
635
|
+
.replace(/[^\p{Alphabetic}\p{M}\p{Nd}\p{Pc} -]/gu, '')
|
|
636
|
+
.replaceAll(' ', '-');
|
|
637
|
+
return Array.from(slug).slice(0, 40).join('')
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
/**
|
|
641
|
+
* Return the slugs for the headings with the `texts` given in document order, numbering repeats
|
|
642
|
+
* the way GitHub does: the first heading with a slug gets it as-is, and later ones get `-1`, `-2`,
|
|
643
|
+
* and so on. Every heading counts, whether or not anything links to it.
|
|
644
|
+
*
|
|
645
|
+
* @param {string[]} texts The text content of every heading, in document order
|
|
646
|
+
* @returns {string[]} The slug for each of `texts`, in the same order
|
|
647
|
+
*/
|
|
648
|
+
function headingSlugs(texts) {
|
|
649
|
+
const seen = new Map();
|
|
650
|
+
return texts.map(text => {
|
|
651
|
+
const slug = headingSlug(text);
|
|
652
|
+
const count = seen.get(slug) ?? 0;
|
|
653
|
+
seen.set(slug, count + 1);
|
|
654
|
+
return count === 0 ? slug : slug + '-' + count.toString()
|
|
655
|
+
})
|
|
656
|
+
}
|
|
657
|
+
|
|
624
658
|
// ::- Persistent data structure representing an ordered mapping from
|
|
625
659
|
// strings to values, with some convenient update methods.
|
|
626
660
|
function OrderedMap(content) {
|
|
@@ -35495,8 +35529,27 @@ function getLinkAttributes() {
|
|
|
35495
35529
|
const linkMarks = selectedNode.marks.filter(mark => mark.type === schema.marks.link);
|
|
35496
35530
|
if (linkMarks.length === 1) {
|
|
35497
35531
|
return {href: linkMarks[0].attrs.href, link: selectedNode.text};
|
|
35532
|
+
} } // A linked image carries the link mark on the image node, which has no text to report as the link.
|
|
35533
|
+
const image = _selectedImageNode(view.state);
|
|
35534
|
+
if (image) {
|
|
35535
|
+
const linkMarks = image.marks.filter(mark => mark.type === schema.marks.link);
|
|
35536
|
+
if (linkMarks.length === 1) {
|
|
35537
|
+
return {href: linkMarks[0].attrs.href, link: image.attrs.alt ?? ''};
|
|
35498
35538
|
} } return {};
|
|
35499
35539
|
}
|
|
35540
|
+
function _selectedImageNode(state) {
|
|
35541
|
+
const {from, to} = state.selection;
|
|
35542
|
+
let image = null;
|
|
35543
|
+
let count = 0;
|
|
35544
|
+
state.doc.nodesBetween(from, to, node => {
|
|
35545
|
+
if (node.type === state.schema.nodes.image) {
|
|
35546
|
+
image = node;
|
|
35547
|
+
count++;
|
|
35548
|
+
}
|
|
35549
|
+
});
|
|
35550
|
+
return (count === 1) ? image : null
|
|
35551
|
+
}
|
|
35552
|
+
|
|
35500
35553
|
function _getImageAttributes() {
|
|
35501
35554
|
const view = activeView();
|
|
35502
35555
|
return getImageAttributes(view.state)
|
|
@@ -36228,12 +36281,10 @@ function idForInternalLinkCommand(hTag, index) {
|
|
|
36228
36281
|
}
|
|
36229
36282
|
|
|
36230
36283
|
/**
|
|
36231
|
-
* Return a unique identifier for the heading `node` by
|
|
36232
|
-
*
|
|
36233
|
-
* If the heading `node` has an id, then just
|
|
36234
|
-
*
|
|
36235
|
-
* Since the `node.textContent` can be arbitrarily large, we limit the id to 40 characters
|
|
36236
|
-
* just to avoid unwieldy IDs.
|
|
36284
|
+
* Return a unique identifier for the heading `node`: its slug as `headingSlugs` numbers it by its
|
|
36285
|
+
* position among all the headings in `state.doc`, as GitHub does. If another node already uses that
|
|
36286
|
+
* id, append `-1`, `-2`, and so on until it is unique. If the heading `node` has an id, then just
|
|
36287
|
+
* return it.
|
|
36237
36288
|
*
|
|
36238
36289
|
* @ignore
|
|
36239
36290
|
* @param {Node} node A ProseMirror Node that is of heading type
|
|
@@ -36242,15 +36293,20 @@ function idForInternalLinkCommand(hTag, index) {
|
|
|
36242
36293
|
*/
|
|
36243
36294
|
function idForHeader(node, state) {
|
|
36244
36295
|
if (node.attrs.id) return node.attrs.id
|
|
36245
|
-
|
|
36246
|
-
|
|
36247
|
-
|
|
36296
|
+
const texts = [];
|
|
36297
|
+
let position = -1;
|
|
36298
|
+
state.doc.descendants(child => {
|
|
36299
|
+
if (child.type !== state.schema.nodes.heading) return true
|
|
36300
|
+
if (child === node) position = texts.length;
|
|
36301
|
+
texts.push(child.textContent);
|
|
36302
|
+
return false
|
|
36303
|
+
});
|
|
36304
|
+
const base = (position >= 0) ? headingSlugs(texts)[position] : headingSlug(node.textContent);
|
|
36305
|
+
let id = base;
|
|
36248
36306
|
let index = 0;
|
|
36249
|
-
while (
|
|
36307
|
+
while (nodeWithId(id, state).node) {
|
|
36250
36308
|
index++;
|
|
36251
|
-
id =
|
|
36252
|
-
let {node} = nodeWithId(id, state);
|
|
36253
|
-
idNode = node;
|
|
36309
|
+
id = base + '-' + index.toString();
|
|
36254
36310
|
}
|
|
36255
36311
|
return id
|
|
36256
36312
|
}
|
|
@@ -36289,20 +36345,25 @@ function headerMatching(hTag, index, state) {
|
|
|
36289
36345
|
|
|
36290
36346
|
/**
|
|
36291
36347
|
* Return a JSON-stringified array describing every non-empty header in the document, in document
|
|
36292
|
-
* order within each level. Each entry is `{hTag, index, text, id}`, where `hTag` and `index` identify
|
|
36348
|
+
* order within each level. Each entry is `{hTag, index, text, id, slug}`, where `hTag` and `index` identify
|
|
36293
36349
|
* the header the same way `insertInternalLink(hTag, index)` and `idForInternalLinkCommand(hTag, index)`
|
|
36294
|
-
* do,
|
|
36350
|
+
* do, `id` is the header's current id attribute (null if it hasn't been assigned one yet), and `slug`
|
|
36351
|
+
* is the id a link to the header would give it, numbered by position among all the headers.
|
|
36295
36352
|
*
|
|
36296
36353
|
* An empty header is omitted -- it can't form a usable id, so there's nothing to link to -- but
|
|
36297
36354
|
* `index` still reflects its true position among ALL headers at that level (empty ones included),
|
|
36298
36355
|
* matching what `headerMatching` expects; it's only the reported entries that skip empty headers,
|
|
36299
36356
|
* not the numbering.
|
|
36300
36357
|
*
|
|
36301
|
-
* @returns {string} JSON-stringified array of `{hTag, index, text, id}`
|
|
36358
|
+
* @returns {string} JSON-stringified array of `{hTag, index, text, id, slug}`
|
|
36302
36359
|
*/
|
|
36303
36360
|
function getHeaders() {
|
|
36304
36361
|
const view = activeView();
|
|
36305
36362
|
const headersByLevel = headers(view.state);
|
|
36363
|
+
// Slugs are numbered by position among all the headings in the document
|
|
36364
|
+
const slugs = new Map();
|
|
36365
|
+
const all = Object.values(headersByLevel).flat().sort((a, b) => a.pos - b.pos);
|
|
36366
|
+
headingSlugs(all.map(h => h.node.textContent)).forEach((slug, i) => slugs.set(all[i].node, slug));
|
|
36306
36367
|
let result = [];
|
|
36307
36368
|
for (let level = 1; level < 7; level++) {
|
|
36308
36369
|
let hNodes = headersByLevel[level];
|
|
@@ -36310,7 +36371,7 @@ function getHeaders() {
|
|
|
36310
36371
|
hNodes.forEach((h, index) => {
|
|
36311
36372
|
const text = h.node.textContent;
|
|
36312
36373
|
if (text.trim().length === 0) return
|
|
36313
|
-
result.push({hTag: 'H' + level.toString(), index: index, text: text, id: h.node.attrs.id ?? null});
|
|
36374
|
+
result.push({hTag: 'H' + level.toString(), index: index, text: text, id: h.node.attrs.id ?? null, slug: slugs.get(h.node)});
|
|
36314
36375
|
});
|
|
36315
36376
|
}
|
|
36316
36377
|
}
|
|
@@ -42044,7 +42105,16 @@ const codeHighlightPlugin = new Plugin({
|
|
|
42044
42105
|
}
|
|
42045
42106
|
},
|
|
42046
42107
|
props: {
|
|
42047
|
-
|
|
42108
|
+
// The code_block holding the selection is left unhighlighted. Highlighting
|
|
42109
|
+
// wraps the text in spans that are rebuilt as it changes, which breaks the
|
|
42110
|
+
// system's inline predictions while typing. The block is highlighted again
|
|
42111
|
+
// when the selection leaves it.
|
|
42112
|
+
decorations(state) {
|
|
42113
|
+
const {decorations} = codeHighlightPlugin.getState(state);
|
|
42114
|
+
const editing = codeBlockAtSelection(state);
|
|
42115
|
+
if (!editing) return decorations
|
|
42116
|
+
return decorations.remove(decorations.find(editing.pos, editing.pos + editing.node.nodeSize))
|
|
42117
|
+
}
|
|
42048
42118
|
}
|
|
42049
42119
|
});
|
|
42050
42120
|
|
|
@@ -43324,7 +43394,13 @@ class Searcher {
|
|
|
43324
43394
|
* Create a new SearchQuery and highlight all the matches in the document.
|
|
43325
43395
|
*/
|
|
43326
43396
|
_buildQuery() {
|
|
43327
|
-
|
|
43397
|
+
// The search string has straight quotes and apostrophes. Match them against the straight and
|
|
43398
|
+
// curly forms in the document text, without changing the document.
|
|
43399
|
+
const pattern = this._searchString
|
|
43400
|
+
.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
43401
|
+
.replaceAll("'", "['‘’]")
|
|
43402
|
+
.replaceAll('"', '["“”]');
|
|
43403
|
+
this._searchQuery = new SearchQuery({search: pattern, regexp: true, caseSensitive: this._caseSensitive});
|
|
43328
43404
|
}
|
|
43329
43405
|
|
|
43330
43406
|
}
|
|
@@ -43580,6 +43656,8 @@ const MU = {
|
|
|
43580
43656
|
getLocalImages,
|
|
43581
43657
|
getHTML,
|
|
43582
43658
|
getHeaders,
|
|
43659
|
+
headingSlug,
|
|
43660
|
+
headingSlugs,
|
|
43583
43661
|
getHeight,
|
|
43584
43662
|
getImageAttributes,
|
|
43585
43663
|
getLinkAttributes,
|