@aicayzer/inkkit 0.3.0 → 0.3.2
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/chunks/{core-DrVCeBzK.js → core-DTew7k7c.js} +1577 -358
- package/dist/chunks/{highlight-D6evOlOs.js → highlight-LB7Mkd5W.js} +1 -1
- package/dist/core.js +1 -1
- package/dist/editor.d.ts +32 -7
- package/dist/index.js +1 -1
- package/dist/style.css +85 -57
- package/dist/types.d.ts +7 -1
- package/package.json +2 -2
|
@@ -2214,7 +2214,7 @@ function tokenizeCharacterEscape(effects, ok, nok) {
|
|
|
2214
2214
|
* } from 'micromark-util-types'
|
|
2215
2215
|
*/
|
|
2216
2216
|
/** @type {Construct} */
|
|
2217
|
-
var characterReference = {
|
|
2217
|
+
var characterReference$1 = {
|
|
2218
2218
|
name: "characterReference",
|
|
2219
2219
|
tokenize: tokenizeCharacterReference
|
|
2220
2220
|
};
|
|
@@ -7349,7 +7349,7 @@ var flow = {
|
|
|
7349
7349
|
};
|
|
7350
7350
|
/** @satisfies {Extension['string']} */
|
|
7351
7351
|
var string = {
|
|
7352
|
-
[38]: characterReference,
|
|
7352
|
+
[38]: characterReference$1,
|
|
7353
7353
|
[92]: characterEscape
|
|
7354
7354
|
};
|
|
7355
7355
|
/** @satisfies {Extension['text']} */
|
|
@@ -7358,7 +7358,7 @@ var text$4 = {
|
|
|
7358
7358
|
[-4]: lineEnding$1,
|
|
7359
7359
|
[-3]: lineEnding$1,
|
|
7360
7360
|
[33]: labelStartImage,
|
|
7361
|
-
[38]: characterReference,
|
|
7361
|
+
[38]: characterReference$1,
|
|
7362
7362
|
[42]: attention$2,
|
|
7363
7363
|
[60]: [autolink$1, htmlText],
|
|
7364
7364
|
[91]: labelStartLink,
|
|
@@ -7916,7 +7916,7 @@ function postprocess(events) {
|
|
|
7916
7916
|
* @returns {Array<Chunk>}
|
|
7917
7917
|
* Chunks.
|
|
7918
7918
|
*/
|
|
7919
|
-
var search$
|
|
7919
|
+
var search$2 = /[\0\t\n\r]/g;
|
|
7920
7920
|
/**
|
|
7921
7921
|
* @returns {Preprocessor}
|
|
7922
7922
|
* Preprocess a value.
|
|
@@ -7941,8 +7941,8 @@ function preprocess() {
|
|
|
7941
7941
|
start = void 0;
|
|
7942
7942
|
}
|
|
7943
7943
|
while (startPosition < value.length) {
|
|
7944
|
-
search$
|
|
7945
|
-
const match = search$
|
|
7944
|
+
search$2.lastIndex = startPosition;
|
|
7945
|
+
const match = search$2.exec(value);
|
|
7946
7946
|
const endPosition = match && match.index !== void 0 ? match.index : value.length;
|
|
7947
7947
|
const code = value.charCodeAt(endPosition);
|
|
7948
7948
|
if (!match) {
|
|
@@ -22734,7 +22734,7 @@ var SerializerState = class extends Stack {
|
|
|
22734
22734
|
#closeMark;
|
|
22735
22735
|
};
|
|
22736
22736
|
//#endregion
|
|
22737
|
-
//#region node_modules/.pnpm/prosemirror-view@1.42.6_patch_hash=
|
|
22737
|
+
//#region node_modules/.pnpm/prosemirror-view@1.42.6_patch_hash=f2853b430244e6a0ce28d0ee793854c199c3f40279a807cb6690af21fae2d25e/node_modules/prosemirror-view/dist/index.js
|
|
22738
22738
|
var domIndex = function(node) {
|
|
22739
22739
|
for (var index = 0;; index++) {
|
|
22740
22740
|
node = node.previousSibling;
|
|
@@ -23907,7 +23907,7 @@ var NodeViewDesc = class NodeViewDesc extends ViewDesc {
|
|
|
23907
23907
|
this.children = replaceNodes(this.children, pos, pos + text.length, view, desc);
|
|
23908
23908
|
}
|
|
23909
23909
|
update(node, outerDeco, innerDeco, view) {
|
|
23910
|
-
if (this.dirty == NODE_DIRTY || !node.sameMarkup(this.node)) return false;
|
|
23910
|
+
if (this.dirty == NODE_DIRTY || (this.parent ? !node.sameMarkup(this.node) : node.type != this.node.type)) return false;
|
|
23911
23911
|
this.updateInner(node, outerDeco, innerDeco, view);
|
|
23912
23912
|
return true;
|
|
23913
23913
|
}
|
|
@@ -31817,21 +31817,51 @@ var linkSchemes = /* @__PURE__ */ new Set([
|
|
|
31817
31817
|
"mailto",
|
|
31818
31818
|
"tel"
|
|
31819
31819
|
]);
|
|
31820
|
+
/** Schemes a host may never add: each runs code or reads local data. */
|
|
31821
|
+
var refusedSchemes = /* @__PURE__ */ new Set([
|
|
31822
|
+
"javascript",
|
|
31823
|
+
"data",
|
|
31824
|
+
"vbscript",
|
|
31825
|
+
"file"
|
|
31826
|
+
]);
|
|
31827
|
+
var noSchemes = /* @__PURE__ */ new Set();
|
|
31820
31828
|
/**
|
|
31821
31829
|
* Whether a link address may be kept. Relative paths, queries and fragments
|
|
31822
31830
|
* pass, and so does an address whose scheme is listed, in any letter case.
|
|
31823
|
-
*
|
|
31824
|
-
*
|
|
31825
|
-
*
|
|
31826
|
-
* the
|
|
31827
|
-
* scheme is
|
|
31828
|
-
|
|
31829
|
-
|
|
31831
|
+
* `extra` holds the lower-case schemes one editor's host added. Spaces, tabs
|
|
31832
|
+
* and line breaks at the ends are ignored, as in a browser. Any other control
|
|
31833
|
+
* character makes the address unsafe, because a browser may skip it while it
|
|
31834
|
+
* reads the scheme. The scheme is the text before the first `:` in the part
|
|
31835
|
+
* before the first `/`, `?`, `#` or `\`, so an unknown or malformed scheme is
|
|
31836
|
+
* refused.
|
|
31837
|
+
*/
|
|
31838
|
+
function isSafeLinkTarget(value, extra = noSchemes) {
|
|
31830
31839
|
const target = value.replace(/^[ \t\n\f\r]+|[ \t\n\f\r]+$/g, "");
|
|
31831
31840
|
if (/[\u0000-\u001f\u007f]/.test(target)) return false;
|
|
31832
31841
|
const head = target.slice(0, target.search(/[/?#\\]|$/));
|
|
31833
31842
|
const colon = head.indexOf(":");
|
|
31834
|
-
|
|
31843
|
+
if (colon < 0) return true;
|
|
31844
|
+
const scheme = head.slice(0, colon).toLowerCase();
|
|
31845
|
+
return linkSchemes.has(scheme) || extra.has(scheme);
|
|
31846
|
+
}
|
|
31847
|
+
/**
|
|
31848
|
+
* Checks the host's `linkSchemes` option and returns its entries in lower
|
|
31849
|
+
* case. An entry is a scheme name, and `javascript`, `data`, `vbscript` and
|
|
31850
|
+
* `file` are never accepted.
|
|
31851
|
+
*/
|
|
31852
|
+
function extraLinkSchemes(value, name) {
|
|
31853
|
+
if (!Array.isArray(value)) throw invalidArgument(`${name} must be a list`);
|
|
31854
|
+
return value.map((entry, index) => {
|
|
31855
|
+
if (typeof entry !== "string" || !/^[a-z][a-z0-9+.-]*$/i.test(entry)) throw invalidArgument(`${name}[${index}] must be a scheme name of letters, digits, +, - and ., starting with a letter`);
|
|
31856
|
+
const scheme = entry.toLowerCase();
|
|
31857
|
+
if (refusedSchemes.has(scheme)) throw invalidArgument(`${name}[${index}] cannot be ${scheme}`);
|
|
31858
|
+
return scheme;
|
|
31859
|
+
});
|
|
31860
|
+
}
|
|
31861
|
+
/** The extra schemes of one editor, so that two editors on a page keep their own. */
|
|
31862
|
+
var linkSchemesCtx = $ctx(noSchemes, "inkkitLinkSchemes");
|
|
31863
|
+
function editorLinkSchemes(ctx) {
|
|
31864
|
+
return ctx.isInjected(linkSchemesCtx.key) ? ctx.get(linkSchemesCtx.key) : noSchemes;
|
|
31835
31865
|
}
|
|
31836
31866
|
/**
|
|
31837
31867
|
* Whether an image source would run script if a renderer treated it as an
|
|
@@ -34914,6 +34944,7 @@ var referenceLinks = linkSchema.extendSchema((base) => (ctx) => {
|
|
|
34914
34944
|
const schema = base(ctx);
|
|
34915
34945
|
return {
|
|
34916
34946
|
...schema,
|
|
34947
|
+
inclusive: false,
|
|
34917
34948
|
priority: 40,
|
|
34918
34949
|
attrs: {
|
|
34919
34950
|
...schema.attrs,
|
|
@@ -34942,7 +34973,9 @@ var referenceLinks = linkSchema.extendSchema((base) => (ctx) => {
|
|
|
34942
34973
|
}],
|
|
34943
34974
|
toDOM(mark) {
|
|
34944
34975
|
const attrs = { ...schema.toDOM(mark, false)[1] };
|
|
34945
|
-
|
|
34976
|
+
const href = String(mark.attrs.href ?? "");
|
|
34977
|
+
if (!isSafeLinkTarget(href, editorLinkSchemes(ctx))) attrs.href = "";
|
|
34978
|
+
else if (!attrs.href) attrs.href = href.trim();
|
|
34946
34979
|
delete attrs.label;
|
|
34947
34980
|
delete attrs.identifier;
|
|
34948
34981
|
delete attrs.referenceType;
|
|
@@ -35387,6 +35420,10 @@ var undoSmartPunctuation = (state, dispatch) => {
|
|
|
35387
35420
|
//#region src/linked-syntax.ts
|
|
35388
35421
|
var fromTable = (raw) => raw.replace(/(\\*)\|/g, (_match, escapes) => `${"\\".repeat(Math.floor(escapes.length / 2))}|`);
|
|
35389
35422
|
var toTable = (raw) => raw.replace(/(\\*)\|/g, (_match, escapes) => `${"\\".repeat(escapes.length * 2 + 1)}|`);
|
|
35423
|
+
function pathTableForm(raw, inTable) {
|
|
35424
|
+
if (!inTable) return raw;
|
|
35425
|
+
return raw.replace(/(\\*)\|/g, (_match, escapes) => escapes.length % 2 ? escapes + "|" : escapes + "\\|");
|
|
35426
|
+
}
|
|
35390
35427
|
function parseLinkedSyntax(raw, inTable = false) {
|
|
35391
35428
|
const source = inTable ? fromTable(raw) : raw;
|
|
35392
35429
|
const embed = source.startsWith("!");
|
|
@@ -35473,7 +35510,25 @@ function tableForm(raw, authoredInTable, outputInTable) {
|
|
|
35473
35510
|
if (authoredInTable === outputInTable) return raw;
|
|
35474
35511
|
return outputInTable ? toTable(raw) : fromTable(raw);
|
|
35475
35512
|
}
|
|
35513
|
+
function wikiMarkdown(node, inTable = false) {
|
|
35514
|
+
return tableForm(String(node.attrs.raw), Boolean(node.attrs.inTable), inTable);
|
|
35515
|
+
}
|
|
35516
|
+
function wikiReference(node) {
|
|
35517
|
+
return {
|
|
35518
|
+
raw: wikiMarkdown(node, Boolean(node.attrs.inTable)),
|
|
35519
|
+
target: String(node.attrs.target),
|
|
35520
|
+
...node.attrs.fragment != null ? { fragment: String(node.attrs.fragment) } : {},
|
|
35521
|
+
label: String(node.attrs.label)
|
|
35522
|
+
};
|
|
35523
|
+
}
|
|
35476
35524
|
function fileReference(node) {
|
|
35525
|
+
return {
|
|
35526
|
+
...fileFields(node),
|
|
35527
|
+
raw: fileSource(node)
|
|
35528
|
+
};
|
|
35529
|
+
}
|
|
35530
|
+
/** `fileReference` without the embed's text, which takes writing it. */
|
|
35531
|
+
function fileFields(node) {
|
|
35477
35532
|
const reference = String(node.attrs.src ?? "");
|
|
35478
35533
|
const named = node.attrs.inkkitFileRaw != null;
|
|
35479
35534
|
const alt = String(node.attrs.alt ?? "");
|
|
@@ -35492,11 +35547,49 @@ function fileReference(node) {
|
|
|
35492
35547
|
...width != null ? { width } : {}
|
|
35493
35548
|
};
|
|
35494
35549
|
}
|
|
35550
|
+
var writers = /* @__PURE__ */ new WeakMap();
|
|
35551
|
+
/** Sets how an image of `schema` is written when it has no authored text. */
|
|
35552
|
+
function setImageWriter(schema, write) {
|
|
35553
|
+
writers.set(schema, write);
|
|
35554
|
+
}
|
|
35555
|
+
/**
|
|
35556
|
+
* A file embed's Markdown as the document holds it: its authored text while
|
|
35557
|
+
* the embed is unchanged, otherwise the text InkKit writes for it.
|
|
35558
|
+
*/
|
|
35559
|
+
function fileSource(node) {
|
|
35560
|
+
if (node.attrs.inkkitFileRaw != null) return namedFileMarkdown(node, Boolean(node.attrs.inkkitFileInTable)) ?? "";
|
|
35561
|
+
const authored = authoredFileSource(node);
|
|
35562
|
+
if (authored != null) return authored;
|
|
35563
|
+
const write = writers.get(node.type.schema);
|
|
35564
|
+
if (!write) throw new InkKitError("internal", "The image writer is not set");
|
|
35565
|
+
return pathTableForm(write(node), Boolean(node.attrs.inkkitFileInTable));
|
|
35566
|
+
}
|
|
35567
|
+
/** Only reuse authored spelling while it still describes the image. */
|
|
35568
|
+
function authoredFileSource(node) {
|
|
35569
|
+
const authored = node.attrs.inkkitFileSource;
|
|
35570
|
+
return authored && authored.src === node.attrs.src && authored.alt === node.attrs.alt && authored.title === node.attrs.title ? authored.text : null;
|
|
35571
|
+
}
|
|
35572
|
+
/** Records each path image's Markdown as written, for `FileReference.raw`. */
|
|
35573
|
+
function remarkFileSources() {
|
|
35574
|
+
return (tree, file) => {
|
|
35575
|
+
const source = String(file.value ?? "").replace(/^\uFEFF/, "");
|
|
35576
|
+
const visit = (node, inTable = false) => {
|
|
35577
|
+
if (node.type === "image" && node.inkkitFileRaw == null) {
|
|
35578
|
+
const start = node.position?.start.offset;
|
|
35579
|
+
const end = node.position?.end.offset;
|
|
35580
|
+
if (start != null && end != null) node.inkkitFileSource = source.slice(start, end);
|
|
35581
|
+
node.inkkitFileInTable = inTable;
|
|
35582
|
+
}
|
|
35583
|
+
if ("children" in node) node.children.forEach((child) => visit(child, inTable || node.type === "tableCell"));
|
|
35584
|
+
};
|
|
35585
|
+
visit(tree);
|
|
35586
|
+
};
|
|
35587
|
+
}
|
|
35495
35588
|
function namedFileMarkdown(node, inTable = false) {
|
|
35496
35589
|
if (node.attrs.inkkitFileRaw == null) return void 0;
|
|
35497
35590
|
let raw = String(node.attrs.inkkitFileRaw);
|
|
35498
35591
|
const authoredInTable = Boolean(node.attrs.inkkitFileInTable);
|
|
35499
|
-
const width =
|
|
35592
|
+
const width = fileFields(node).width ?? null;
|
|
35500
35593
|
const original = node.attrs.inkkitFileWidth ?? null;
|
|
35501
35594
|
if (width !== original) {
|
|
35502
35595
|
if (authoredInTable) raw = fromTable(raw);
|
|
@@ -35608,6 +35701,54 @@ var wikiLinkComposition = $prose(() => new Plugin({
|
|
|
35608
35701
|
} } }
|
|
35609
35702
|
}));
|
|
35610
35703
|
/**
|
|
35704
|
+
* A pasted or moved atom retains its original attributes. Stores the spelling
|
|
35705
|
+
* its new context saves before preservation and node views observe it, so
|
|
35706
|
+
* adapter references and clipboard metadata agree.
|
|
35707
|
+
*/
|
|
35708
|
+
var referenceTableContext = $prose(() => new Plugin({
|
|
35709
|
+
key: new PluginKey("inkkitReferenceTableContext"),
|
|
35710
|
+
appendTransaction(transactions, _before, state) {
|
|
35711
|
+
if (!transactions.some((tr) => tr.docChanged)) return null;
|
|
35712
|
+
let ranges = [];
|
|
35713
|
+
for (const transaction of transactions) for (const map of transaction.mapping.maps) {
|
|
35714
|
+
ranges = ranges.map(([from, to]) => [map.map(from, -1), map.map(to)]);
|
|
35715
|
+
map.forEach((_from, _to, from, to) => ranges.push([from, to]));
|
|
35716
|
+
}
|
|
35717
|
+
const tr = state.tr;
|
|
35718
|
+
const seen = /* @__PURE__ */ new Set();
|
|
35719
|
+
for (const [from, to] of ranges) state.doc.nodesBetween(from, to, (node, pos) => {
|
|
35720
|
+
if (![
|
|
35721
|
+
"inkkit_wiki_link",
|
|
35722
|
+
"image",
|
|
35723
|
+
"image_block"
|
|
35724
|
+
].includes(node.type.name) || seen.has(pos)) return;
|
|
35725
|
+
seen.add(pos);
|
|
35726
|
+
const $pos = state.doc.resolve(pos);
|
|
35727
|
+
let inTable = false;
|
|
35728
|
+
for (let depth = $pos.depth; depth > 0; depth--) if (["table_cell", "table_header"].includes($pos.node(depth).type.name)) inTable = true;
|
|
35729
|
+
if (node.type.name === "inkkit_wiki_link") {
|
|
35730
|
+
if (inTable !== Boolean(node.attrs.inTable)) tr.setNodeMarkup(pos, void 0, {
|
|
35731
|
+
...node.attrs,
|
|
35732
|
+
raw: wikiMarkdown(node, inTable),
|
|
35733
|
+
inTable
|
|
35734
|
+
});
|
|
35735
|
+
} else if (inTable !== Boolean(node.attrs.inkkitFileInTable)) {
|
|
35736
|
+
const authored = node.attrs.inkkitFileSource;
|
|
35737
|
+
tr.setNodeMarkup(pos, void 0, {
|
|
35738
|
+
...node.attrs,
|
|
35739
|
+
inkkitFileRaw: namedFileMarkdown(node, inTable) ?? null,
|
|
35740
|
+
inkkitFileSource: authored ? {
|
|
35741
|
+
...authored,
|
|
35742
|
+
text: pathTableForm(authored.text, inTable)
|
|
35743
|
+
} : null,
|
|
35744
|
+
inkkitFileInTable: inTable
|
|
35745
|
+
});
|
|
35746
|
+
}
|
|
35747
|
+
});
|
|
35748
|
+
return tr.steps.length ? tr : null;
|
|
35749
|
+
}
|
|
35750
|
+
}));
|
|
35751
|
+
/**
|
|
35611
35752
|
* Turns `[[target]]`, as the person types its last bracket, into the wiki link
|
|
35612
35753
|
* it reads as when the note is opened, so the note keeps the characters that
|
|
35613
35754
|
* were typed. Left as text, the brackets save as `\[\[target]]`, which no
|
|
@@ -35695,6 +35836,7 @@ function linkedSyntax(wikiLinks, files) {
|
|
|
35695
35836
|
const wiki = (node, _parent, state) => tableForm(String(node.raw), Boolean(node.inTable), state.stack.includes("tableCell"));
|
|
35696
35837
|
const named = (node, parent, state, info) => {
|
|
35697
35838
|
if (node.inkkitFileRaw != null) return tableForm(String(node.inkkitFileRaw), Boolean(node.inkkitFileInTable), state.stack.includes("tableCell"));
|
|
35839
|
+
if (node.inkkitFileSource != null) return pathTableForm(node.inkkitFileSource, state.stack.includes("tableCell"));
|
|
35698
35840
|
return handle.image(node, parent, state, info);
|
|
35699
35841
|
};
|
|
35700
35842
|
return $remark("inkkitLinkedSyntax", () => function() {
|
|
@@ -35719,13 +35861,22 @@ function validName(value) {
|
|
|
35719
35861
|
}
|
|
35720
35862
|
function wikiSuggestionNode(state, name) {
|
|
35721
35863
|
if (!validName(name)) throw invalidArgument("A note suggestion must be a supported note name");
|
|
35722
|
-
|
|
35864
|
+
const { $from } = state.selection;
|
|
35865
|
+
let inTable = false;
|
|
35866
|
+
for (let depth = $from.depth; depth > 0; depth--) if (["table_cell", "table_header"].includes($from.node(depth).type.name)) inTable = true;
|
|
35867
|
+
const node = state.schema.nodes.inkkit_wiki_link.create({
|
|
35723
35868
|
raw: rawName(name),
|
|
35724
35869
|
target: name,
|
|
35725
35870
|
label: name,
|
|
35726
35871
|
fragment: null,
|
|
35727
35872
|
inTable: false
|
|
35728
|
-
}, void 0,
|
|
35873
|
+
}, void 0, $from.marks());
|
|
35874
|
+
if (!inTable) return node;
|
|
35875
|
+
return node.type.create({
|
|
35876
|
+
...node.attrs,
|
|
35877
|
+
raw: wikiMarkdown(node, true),
|
|
35878
|
+
inTable
|
|
35879
|
+
}, void 0, node.marks);
|
|
35729
35880
|
}
|
|
35730
35881
|
function wikiSuggestionTransaction(view, session, name) {
|
|
35731
35882
|
const { state } = view;
|
|
@@ -43197,17 +43348,28 @@ var imageAttrs = {
|
|
|
43197
43348
|
validate: "string"
|
|
43198
43349
|
},
|
|
43199
43350
|
inkkitFileRaw: { default: null },
|
|
43351
|
+
inkkitFileSource: { default: null },
|
|
43200
43352
|
inkkitFileTarget: { default: null },
|
|
43201
43353
|
inkkitFileFragment: { default: null },
|
|
43202
43354
|
inkkitFileWidth: { default: null },
|
|
43203
43355
|
inkkitFileInTable: { default: false }
|
|
43204
43356
|
};
|
|
43205
43357
|
function markdownImageAttrs(node) {
|
|
43358
|
+
const src = String(node.url ?? "");
|
|
43359
|
+
const alt = String(node.alt ?? "");
|
|
43360
|
+
const title = String(node.title ?? "");
|
|
43361
|
+
const source = typeof node.inkkitFileSource === "string" ? {
|
|
43362
|
+
text: node.inkkitFileSource,
|
|
43363
|
+
src,
|
|
43364
|
+
alt,
|
|
43365
|
+
title
|
|
43366
|
+
} : null;
|
|
43206
43367
|
return {
|
|
43207
|
-
src
|
|
43208
|
-
alt
|
|
43209
|
-
title
|
|
43368
|
+
src,
|
|
43369
|
+
alt,
|
|
43370
|
+
title,
|
|
43210
43371
|
inkkitFileRaw: node.inkkitFileRaw ?? null,
|
|
43372
|
+
inkkitFileSource: source,
|
|
43211
43373
|
inkkitFileTarget: node.inkkitFileTarget ?? null,
|
|
43212
43374
|
inkkitFileFragment: node.inkkitFileFragment ?? null,
|
|
43213
43375
|
inkkitFileWidth: node.inkkitFileWidth ?? null,
|
|
@@ -43603,14 +43765,15 @@ var from = {
|
|
|
43603
43765
|
}
|
|
43604
43766
|
}
|
|
43605
43767
|
};
|
|
43768
|
+
var onThreeLines = (isBlock, block, value) => isBlock ? block !== false || /[\r\n]/.test(value) : Boolean(block);
|
|
43606
43769
|
function commentSource(node) {
|
|
43607
43770
|
const body = node.textContent;
|
|
43608
|
-
return node.attrs.syntax === "html" ? `<!--${body}-->` : node.type.name === "comment_block"
|
|
43771
|
+
return node.attrs.syntax === "html" ? `<!--${body}-->` : onThreeLines(node.type.name === "comment_block", node.attrs.block, body) ? `%%\n${body}\n%%` : `%%${body}%%`;
|
|
43609
43772
|
}
|
|
43610
43773
|
var handler = (node) => {
|
|
43611
43774
|
const comment = node;
|
|
43612
43775
|
const value = comment.value ?? "";
|
|
43613
|
-
return comment.syntax === "html" ? `<!--${value}-->` : comment.type === "inkkitCommentBlock"
|
|
43776
|
+
return comment.syntax === "html" ? `<!--${value}-->` : onThreeLines(comment.type === "inkkitCommentBlock", comment.block, value) ? `%%\n${value}\n%%` : `%%${value}%%`;
|
|
43614
43777
|
};
|
|
43615
43778
|
function htmlSpans(value) {
|
|
43616
43779
|
const spans = [];
|
|
@@ -43700,6 +43863,7 @@ function remarkComments() {
|
|
|
43700
43863
|
if (node.type === "paragraph" && parentType !== "listItem" && node.children.length === 1 && node.children[0]?.type === "inkkitCommentInline") return {
|
|
43701
43864
|
...node.children[0],
|
|
43702
43865
|
type: "inkkitCommentBlock",
|
|
43866
|
+
block: false,
|
|
43703
43867
|
position: node.position
|
|
43704
43868
|
};
|
|
43705
43869
|
return node;
|
|
@@ -43739,7 +43903,7 @@ function commentNode(inline) {
|
|
|
43739
43903
|
runner: (state, node, type) => {
|
|
43740
43904
|
state.addNode(type, {
|
|
43741
43905
|
syntax: node.syntax,
|
|
43742
|
-
block: inline ? Boolean(node.block) :
|
|
43906
|
+
block: inline ? Boolean(node.block) : node.block !== false
|
|
43743
43907
|
}, node.value ? [state.schema.text(String(node.value))] : void 0);
|
|
43744
43908
|
}
|
|
43745
43909
|
},
|
|
@@ -43963,50 +44127,116 @@ async function resolveFile(adapter, reference, context) {
|
|
|
43963
44127
|
].includes(presentation.kind)) throw new TypeError("File presentation needs a resource URL");
|
|
43964
44128
|
return Object.freeze({ ...presentation });
|
|
43965
44129
|
}
|
|
44130
|
+
/** The event every reference view hears when the editor's media policy or references change. */
|
|
44131
|
+
var mediaPolicyEvent = "inkkit-media-policy";
|
|
44132
|
+
function requestRefresh(dom, refresh) {
|
|
44133
|
+
dom.dispatchEvent(new CustomEvent(mediaPolicyEvent, { detail: { refresh } }));
|
|
44134
|
+
}
|
|
44135
|
+
/** The refresh a policy event carries. A plain event, such as a host's, carries none. */
|
|
44136
|
+
function refreshOf(event) {
|
|
44137
|
+
const detail = event instanceof CustomEvent ? event.detail : null;
|
|
44138
|
+
return detail && typeof detail === "object" && "refresh" in detail ? detail.refresh : void 0;
|
|
44139
|
+
}
|
|
44140
|
+
function refreshes(refresh, target) {
|
|
44141
|
+
return !refresh.targets || refresh.targets.has(target);
|
|
44142
|
+
}
|
|
44143
|
+
function samePresentation(a, b) {
|
|
44144
|
+
const left = a;
|
|
44145
|
+
const right = b;
|
|
44146
|
+
const keys = Object.keys(left);
|
|
44147
|
+
return keys.length === Object.keys(right).length && keys.every((key) => left[key] === right[key]);
|
|
44148
|
+
}
|
|
43966
44149
|
var FileResolution = class {
|
|
43967
44150
|
runtime;
|
|
43968
44151
|
changed;
|
|
44152
|
+
cache;
|
|
43969
44153
|
state = { status: "idle" };
|
|
43970
44154
|
reference;
|
|
43971
44155
|
key = "";
|
|
43972
44156
|
request;
|
|
43973
44157
|
dead = false;
|
|
43974
|
-
constructor(runtime, changed) {
|
|
44158
|
+
constructor(runtime, changed, cache) {
|
|
43975
44159
|
this.runtime = runtime;
|
|
43976
44160
|
this.changed = changed;
|
|
44161
|
+
this.cache = cache;
|
|
43977
44162
|
}
|
|
43978
44163
|
update(reference) {
|
|
43979
44164
|
const key = JSON.stringify([
|
|
44165
|
+
reference.raw,
|
|
43980
44166
|
reference.reference,
|
|
43981
44167
|
reference.kind,
|
|
43982
44168
|
reference.fragment
|
|
43983
44169
|
]);
|
|
43984
44170
|
this.reference = Object.freeze({ ...reference });
|
|
43985
44171
|
if (this.key === key && this.request?.isCurrent()) return;
|
|
44172
|
+
if (this.key !== key) this.cache?.release(this, this.key);
|
|
43986
44173
|
this.key = key;
|
|
44174
|
+
this.cache?.retain(this, key);
|
|
44175
|
+
const cached = this.cache?.get(key);
|
|
44176
|
+
if (cached) {
|
|
44177
|
+
if (this.request?.pending) this.request.controller.abort();
|
|
44178
|
+
this.request = {
|
|
44179
|
+
controller: cached.controller,
|
|
44180
|
+
pending: false,
|
|
44181
|
+
isCurrent: cached.isCurrent
|
|
44182
|
+
};
|
|
44183
|
+
this.state = {
|
|
44184
|
+
status: "resolved",
|
|
44185
|
+
presentation: cached.presentation
|
|
44186
|
+
};
|
|
44187
|
+
this.changed();
|
|
44188
|
+
return;
|
|
44189
|
+
}
|
|
43987
44190
|
this.retry();
|
|
43988
44191
|
}
|
|
44192
|
+
/** Resolves again from a blank loading card. */
|
|
43989
44193
|
retry() {
|
|
44194
|
+
this.cache?.delete(this.key);
|
|
43990
44195
|
this.cancel();
|
|
44196
|
+
this.start(true);
|
|
44197
|
+
}
|
|
44198
|
+
/**
|
|
44199
|
+
* Resolves again behind the current card, which stays until the answer differs, so a card that
|
|
44200
|
+
* the host's change doesn't affect neither blanks nor moves.
|
|
44201
|
+
*/
|
|
44202
|
+
refresh() {
|
|
44203
|
+
this.cache?.delete(this.key);
|
|
44204
|
+
if (this.dead || !this.runtime.active()) return;
|
|
44205
|
+
if (this.state.status === "idle") this.retry();
|
|
44206
|
+
else this.start(false);
|
|
44207
|
+
}
|
|
44208
|
+
start(blank) {
|
|
44209
|
+
if (!this.cache || this.request?.pending) this.request?.controller.abort();
|
|
44210
|
+
this.request = void 0;
|
|
43991
44211
|
if (this.dead || !this.reference || !this.runtime.active()) return;
|
|
43992
44212
|
const captured = this.runtime.capture();
|
|
43993
44213
|
const request = {
|
|
43994
44214
|
controller: new AbortController(),
|
|
44215
|
+
pending: true,
|
|
43995
44216
|
isCurrent: captured.isCurrent
|
|
43996
44217
|
};
|
|
43997
44218
|
this.request = request;
|
|
43998
|
-
|
|
43999
|
-
|
|
44219
|
+
if (blank) {
|
|
44220
|
+
this.state = { status: "loading" };
|
|
44221
|
+
this.changed();
|
|
44222
|
+
}
|
|
44000
44223
|
resolveFile(this.runtime.adapter, this.reference, {
|
|
44001
44224
|
...captured.context,
|
|
44002
44225
|
signal: request.controller.signal
|
|
44003
44226
|
}).then((presentation) => {
|
|
44004
44227
|
if (!this.current(request)) return;
|
|
44228
|
+
const before = this.state;
|
|
44229
|
+
request.pending = false;
|
|
44005
44230
|
this.state = {
|
|
44006
44231
|
status: "resolved",
|
|
44007
44232
|
presentation
|
|
44008
44233
|
};
|
|
44009
|
-
this.
|
|
44234
|
+
this.cache?.set(this.key, {
|
|
44235
|
+
presentation,
|
|
44236
|
+
isCurrent: request.isCurrent,
|
|
44237
|
+
controller: request.controller
|
|
44238
|
+
});
|
|
44239
|
+
if (before.status !== "resolved" || !samePresentation(before.presentation, presentation)) this.changed();
|
|
44010
44240
|
}, (failure) => {
|
|
44011
44241
|
if (!this.current(request)) return;
|
|
44012
44242
|
const error = coded(failure, "file-unavailable");
|
|
@@ -44026,9 +44256,63 @@ var FileResolution = class {
|
|
|
44026
44256
|
this.request = void 0;
|
|
44027
44257
|
this.state = { status: "idle" };
|
|
44028
44258
|
}
|
|
44259
|
+
/** Hidden views keep an answer for this document, but never accept a late answer. */
|
|
44260
|
+
suspend() {
|
|
44261
|
+
if (this.request?.pending || this.state.status === "idle") this.cancel();
|
|
44262
|
+
}
|
|
44263
|
+
invalidate() {
|
|
44264
|
+
this.cache?.delete(this.key);
|
|
44265
|
+
this.cancel();
|
|
44266
|
+
}
|
|
44029
44267
|
destroy() {
|
|
44030
44268
|
this.dead = true;
|
|
44031
|
-
this.
|
|
44269
|
+
this.cache?.release(this, this.key);
|
|
44270
|
+
if (!this.cache || this.request?.pending || this.state.status !== "resolved") this.cancel();
|
|
44271
|
+
}
|
|
44272
|
+
};
|
|
44273
|
+
/** A source commit may replace a node view without changing its authored reference. */
|
|
44274
|
+
var FilePresentationCache = class {
|
|
44275
|
+
entries = /* @__PURE__ */ new Map();
|
|
44276
|
+
retain(owner, key) {
|
|
44277
|
+
let entry = this.entries.get(key);
|
|
44278
|
+
if (!entry) this.entries.set(key, entry = {
|
|
44279
|
+
owners: /* @__PURE__ */ new Set(),
|
|
44280
|
+
controllers: /* @__PURE__ */ new Set()
|
|
44281
|
+
});
|
|
44282
|
+
entry.owners.add(owner);
|
|
44283
|
+
}
|
|
44284
|
+
release(owner, key) {
|
|
44285
|
+
const entry = this.entries.get(key);
|
|
44286
|
+
if (!entry) return;
|
|
44287
|
+
entry.owners.delete(owner);
|
|
44288
|
+
queueMicrotask(() => {
|
|
44289
|
+
if (this.entries.get(key) === entry && !entry.owners.size) {
|
|
44290
|
+
for (const controller of entry.controllers) controller.abort();
|
|
44291
|
+
this.entries.delete(key);
|
|
44292
|
+
}
|
|
44293
|
+
});
|
|
44294
|
+
}
|
|
44295
|
+
get(key) {
|
|
44296
|
+
const value = this.entries.get(key)?.value;
|
|
44297
|
+
if (value && !value.isCurrent()) {
|
|
44298
|
+
this.delete(key);
|
|
44299
|
+
return;
|
|
44300
|
+
}
|
|
44301
|
+
return value;
|
|
44302
|
+
}
|
|
44303
|
+
set(key, value) {
|
|
44304
|
+
const entry = this.entries.get(key);
|
|
44305
|
+
if (!entry) return;
|
|
44306
|
+
entry.value = value;
|
|
44307
|
+
entry.controllers.add(value.controller);
|
|
44308
|
+
}
|
|
44309
|
+
delete(key) {
|
|
44310
|
+
const entry = this.entries.get(key);
|
|
44311
|
+
if (entry) {
|
|
44312
|
+
for (const controller of entry.controllers) controller.abort();
|
|
44313
|
+
entry.controllers.clear();
|
|
44314
|
+
entry.value = void 0;
|
|
44315
|
+
}
|
|
44032
44316
|
}
|
|
44033
44317
|
};
|
|
44034
44318
|
//#endregion
|
|
@@ -44117,7 +44401,7 @@ function nodeText(node, missingImages, fileDescriptions) {
|
|
|
44117
44401
|
if (node.type.name === "image") {
|
|
44118
44402
|
const description = fileDescriptions.get(node.attrs);
|
|
44119
44403
|
if (description != null) return description;
|
|
44120
|
-
const alt =
|
|
44404
|
+
const alt = fileFields(node).label || "Image";
|
|
44121
44405
|
return missingImages.has(String(node.attrs.src ?? "")) ? `[${alt}: image unavailable]` : alt;
|
|
44122
44406
|
}
|
|
44123
44407
|
if (node.type.name === "table") {
|
|
@@ -44131,7 +44415,9 @@ function nodeText(node, missingImages, fileDescriptions) {
|
|
|
44131
44415
|
}
|
|
44132
44416
|
return clipboardText(node.content, missingImages, fileDescriptions);
|
|
44133
44417
|
}
|
|
44134
|
-
|
|
44418
|
+
/** `linkSchemes` are the schemes beyond the built-in ones that a copied link keeps. Print and paste
|
|
44419
|
+
* leave it out, so they keep only the built-in ones. */
|
|
44420
|
+
function clipboardDOM(content, schema, linkSchemes) {
|
|
44135
44421
|
content = shareableFragment(content);
|
|
44136
44422
|
const container = document.createElement("div");
|
|
44137
44423
|
const serializer = DOMSerializer.fromSchema(schema);
|
|
@@ -44144,7 +44430,7 @@ function clipboardDOM(content, schema) {
|
|
|
44144
44430
|
}]
|
|
44145
44431
|
}, {
|
|
44146
44432
|
...serializer.marks,
|
|
44147
|
-
link: (mark, inline) => isSafeLinkTarget(String(mark.attrs.href ?? "")) ? serializer.marks.link(mark, inline) : ["span", 0]
|
|
44433
|
+
link: (mark, inline) => isSafeLinkTarget(String(mark.attrs.href ?? ""), linkSchemes) ? serializer.marks.link(mark, inline) : ["span", 0]
|
|
44148
44434
|
});
|
|
44149
44435
|
container.append(safe.serializeFragment(content));
|
|
44150
44436
|
if (!onlyDefinitions(content)) for (const definition of container.querySelectorAll("[data-inkkit-reference-definition]")) definition.remove();
|
|
@@ -44163,18 +44449,18 @@ function clipboardDOM(content, schema) {
|
|
|
44163
44449
|
}
|
|
44164
44450
|
return container;
|
|
44165
44451
|
}
|
|
44166
|
-
function clipboardContent(content, schema) {
|
|
44452
|
+
function clipboardContent(content, schema, linkSchemes) {
|
|
44167
44453
|
return {
|
|
44168
44454
|
text: clipboardText(content),
|
|
44169
|
-
html: clipboardDOM(content, schema).innerHTML
|
|
44455
|
+
html: clipboardDOM(content, schema, linkSchemes).innerHTML
|
|
44170
44456
|
};
|
|
44171
44457
|
}
|
|
44172
|
-
function clipboardSerializer(schema) {
|
|
44458
|
+
function clipboardSerializer(schema, linkSchemes) {
|
|
44173
44459
|
const serializer = DOMSerializer.fromSchema(schema);
|
|
44174
44460
|
const safe = new DOMSerializer(serializer.nodes, serializer.marks);
|
|
44175
44461
|
safe.serializeFragment = (content, options = {}, target) => {
|
|
44176
44462
|
const output = target ?? (options.document ?? document).createDocumentFragment();
|
|
44177
|
-
output.append(...clipboardDOM(content, schema).childNodes);
|
|
44463
|
+
output.append(...clipboardDOM(content, schema, linkSchemes).childNodes);
|
|
44178
44464
|
return output;
|
|
44179
44465
|
};
|
|
44180
44466
|
return safe;
|
|
@@ -44182,15 +44468,15 @@ function clipboardSerializer(schema) {
|
|
|
44182
44468
|
var visibleClipboard = $prose((ctx) => new Plugin({
|
|
44183
44469
|
key: new PluginKey("visibleClipboard"),
|
|
44184
44470
|
props: {
|
|
44185
|
-
clipboardSerializer: clipboardSerializer(ctx.get(schemaCtx)),
|
|
44471
|
+
clipboardSerializer: clipboardSerializer(ctx.get(schemaCtx), editorLinkSchemes(ctx)),
|
|
44186
44472
|
clipboardTextSerializer: (slice) => clipboardText(slice.content)
|
|
44187
44473
|
}
|
|
44188
44474
|
}));
|
|
44189
44475
|
/** Export a frozen document fragment; presentation URLs never enter the clipboard. */
|
|
44190
|
-
async function portableClipboard(content, schema, markdown, adapter, context, completeDiagrams, files, signal = new AbortController().signal) {
|
|
44476
|
+
async function portableClipboard(content, schema, markdown, adapter, context, completeDiagrams, files, signal = new AbortController().signal, linkSchemes) {
|
|
44191
44477
|
signal.throwIfAborted();
|
|
44192
44478
|
content = shareableFragment(content);
|
|
44193
|
-
const base = clipboardContent(content, schema);
|
|
44479
|
+
const base = clipboardContent(content, schema, linkSchemes);
|
|
44194
44480
|
const container = document.createElement("div");
|
|
44195
44481
|
container.innerHTML = base.html;
|
|
44196
44482
|
const images = [];
|
|
@@ -44202,7 +44488,7 @@ async function portableClipboard(content, schema, markdown, adapter, context, co
|
|
|
44202
44488
|
const captured = [...container.querySelectorAll("img")].map((element, index) => {
|
|
44203
44489
|
const node = references[index];
|
|
44204
44490
|
const reference = String(node?.attrs.src ?? "");
|
|
44205
|
-
const { label: authoredAlt, width } =
|
|
44491
|
+
const { label: authoredAlt, width } = fileFields(node);
|
|
44206
44492
|
const alt = authoredAlt || "Image";
|
|
44207
44493
|
if (width != null && width > 0) element.setAttribute("width", String(Math.min(4096, width)));
|
|
44208
44494
|
element.removeAttribute("src");
|
|
@@ -44805,10 +45091,82 @@ var cursor = [
|
|
|
44805
45091
|
//#endregion
|
|
44806
45092
|
//#region src/text-input.ts
|
|
44807
45093
|
var isInputRules = (plugin) => plugin.spec.isInputRules === true;
|
|
45094
|
+
function heldLink(doc, from, to) {
|
|
45095
|
+
const type = doc.type.schema.marks.link;
|
|
45096
|
+
if (!type) return void 0;
|
|
45097
|
+
let link;
|
|
45098
|
+
let whole = true;
|
|
45099
|
+
doc.nodesBetween(from, to, (node) => {
|
|
45100
|
+
if (!node.isInline) return true;
|
|
45101
|
+
const own = type.isInSet(node.marks);
|
|
45102
|
+
if (!own || link && !own.eq(link)) whole = false;
|
|
45103
|
+
link ??= own;
|
|
45104
|
+
return false;
|
|
45105
|
+
});
|
|
45106
|
+
return whole ? link : void 0;
|
|
45107
|
+
}
|
|
44808
45108
|
/**
|
|
44809
|
-
*
|
|
44810
|
-
*
|
|
44811
|
-
*
|
|
45109
|
+
* The marks that text put in place of `from` to `to` takes. Links are not
|
|
45110
|
+
* inclusive, so text typed at either end of a link stays outside it, but text
|
|
45111
|
+
* that replaces part or all of one link's text stays in that link. Marks
|
|
45112
|
+
* stored for the selection, such as a link started at the caret, come first.
|
|
45113
|
+
*/
|
|
45114
|
+
function replacementMarks(state, from, to) {
|
|
45115
|
+
const { doc, selection, storedMarks } = state;
|
|
45116
|
+
if (storedMarks && selection.from === from && selection.to === to) return storedMarks;
|
|
45117
|
+
const $from = doc.resolve(from);
|
|
45118
|
+
if (from === to) return $from.marks();
|
|
45119
|
+
const $to = doc.resolve(to);
|
|
45120
|
+
const marks = $from.marksAcross($to) ?? $from.marks();
|
|
45121
|
+
const link = $from.sameParent($to) ? heldLink(doc, from, to) : void 0;
|
|
45122
|
+
return link && !link.isInSet(marks) ? link.addToSet(marks) : marks;
|
|
45123
|
+
}
|
|
45124
|
+
/**
|
|
45125
|
+
* The link that typing over its end continues, after typing replaced the end
|
|
45126
|
+
* or all of its text. Its stored marks keep it for the next keystrokes until
|
|
45127
|
+
* the caret moves or another edit clears them.
|
|
45128
|
+
*/
|
|
45129
|
+
var typingKey = new PluginKey("inkkitTextInput");
|
|
45130
|
+
var typingState = {
|
|
45131
|
+
init: () => null,
|
|
45132
|
+
apply(tr, link, _old, state) {
|
|
45133
|
+
const meta = tr.getMeta(typingKey);
|
|
45134
|
+
if (meta !== void 0) return meta;
|
|
45135
|
+
return link && link.isInSet(state.storedMarks ?? []) ? link : null;
|
|
45136
|
+
}
|
|
45137
|
+
};
|
|
45138
|
+
function linkTyping(state, from, to, text) {
|
|
45139
|
+
const type = state.schema.marks.link;
|
|
45140
|
+
if (!type) return void 0;
|
|
45141
|
+
const marks = replacementMarks(state, from, to);
|
|
45142
|
+
const link = type.isInSet(marks);
|
|
45143
|
+
if (!link) return void 0;
|
|
45144
|
+
const stored = type.isInSet(state.storedMarks ?? []);
|
|
45145
|
+
const continued = typingKey.getState(state);
|
|
45146
|
+
const retyped = stored !== void 0 && continued?.eq(stored) || from < to && !type.isInSet(state.doc.resolve(from).marksAcross(state.doc.resolve(to)) ?? []);
|
|
45147
|
+
if (!retyped && !stored) return void 0;
|
|
45148
|
+
const space = retyped ? -1 : text.search(/\s/);
|
|
45149
|
+
const linked = space < 0 ? text.length : space;
|
|
45150
|
+
const address = link.attrs.form != null;
|
|
45151
|
+
return {
|
|
45152
|
+
marks,
|
|
45153
|
+
link,
|
|
45154
|
+
linked,
|
|
45155
|
+
stored: address ? null : linked < text.length ? link.removeFromSet(marks) : marks,
|
|
45156
|
+
retyped: retyped && !address
|
|
45157
|
+
};
|
|
45158
|
+
}
|
|
45159
|
+
function continueLink(tr, from, text, typing) {
|
|
45160
|
+
const linked = Math.min(typing.linked, text.length);
|
|
45161
|
+
tr.removeMark(from, from + text.length, typing.link.type);
|
|
45162
|
+
if (linked) tr.addMark(from, from + linked, typing.link);
|
|
45163
|
+
if (typing.stored) tr.setStoredMarks(typing.stored);
|
|
45164
|
+
return tr.setMeta(typingKey, typing.retyped ? typing.link : null);
|
|
45165
|
+
}
|
|
45166
|
+
/**
|
|
45167
|
+
* Inserts typed text at `from` to `to`, and returns whether it did. It handles
|
|
45168
|
+
* text that arrives in one piece, such as buffered native typing, dictation or
|
|
45169
|
+
* a text replacement, and typing that continues a link.
|
|
44812
45170
|
*
|
|
44813
45171
|
* Input rules are written for one typed character: Milkdown's take their
|
|
44814
45172
|
* positions from the document before the text goes in, so given more than
|
|
@@ -44816,19 +45174,25 @@ var isInputRules = (plugin) => plugin.spec.isInputRules === true;
|
|
|
44816
45174
|
* in except for its last character, and the input rules see that character
|
|
44817
45175
|
* typed after the rest, all in one transaction.
|
|
44818
45176
|
*/
|
|
44819
|
-
function
|
|
45177
|
+
function insertTypedText(view, from, to, text, deflt) {
|
|
44820
45178
|
const characters = Array.from(text);
|
|
44821
|
-
if (characters.length
|
|
45179
|
+
if (!characters.length || view.composing || /[\r\n]/.test(text)) return false;
|
|
44822
45180
|
const { state } = view;
|
|
44823
|
-
const
|
|
44824
|
-
|
|
45181
|
+
const typing = linkTyping(state, from, to, text);
|
|
45182
|
+
if (characters.length < 2 && !typing) return false;
|
|
45183
|
+
const fallback = () => {
|
|
45184
|
+
const plain = deflt();
|
|
45185
|
+
return typing ? continueLink(plain, from, text, typing) : plain;
|
|
45186
|
+
};
|
|
45187
|
+
const marks = typing?.marks ?? replacementMarks(state, from, to);
|
|
44825
45188
|
const last = characters.at(-1);
|
|
44826
45189
|
const rest = text.slice(0, -last.length);
|
|
44827
|
-
const tr = state.tr.insertText(rest, from, to);
|
|
45190
|
+
const tr = rest ? state.tr.setStoredMarks(marks).insertText(rest, from, to) : state.tr.delete(from, to);
|
|
45191
|
+
if (typing) continueLink(tr, from, rest, typing);
|
|
44828
45192
|
const $at = Selection.near(tr.doc.resolve(tr.mapping.map(to)), -1).$head;
|
|
44829
45193
|
const at = $at.pos;
|
|
44830
45194
|
if (!$at.parent.inlineContent || $at.parent.type.spec.code || $at.parentOffset < rest.length || $at.parent.textBetween($at.parentOffset - rest.length, $at.parentOffset) !== rest) {
|
|
44831
|
-
view.dispatch(
|
|
45195
|
+
view.dispatch(fallback().scrollIntoView());
|
|
44832
45196
|
return true;
|
|
44833
45197
|
}
|
|
44834
45198
|
const rules = state.plugins.filter(isInputRules);
|
|
@@ -44836,7 +45200,7 @@ function insertTextChunk(view, from, to, text, deflt) {
|
|
|
44836
45200
|
schema: state.schema,
|
|
44837
45201
|
doc: tr.doc,
|
|
44838
45202
|
selection: TextSelection.create(tr.doc, at),
|
|
44839
|
-
storedMarks:
|
|
45203
|
+
storedMarks: typing && typing.linked < text.length ? typing.link.removeFromSet(marks) : marks
|
|
44840
45204
|
}, rest);
|
|
44841
45205
|
let ruled;
|
|
44842
45206
|
const preparedView = Object.create(view, {
|
|
@@ -44846,7 +45210,7 @@ function insertTextChunk(view, from, to, text, deflt) {
|
|
|
44846
45210
|
} }
|
|
44847
45211
|
});
|
|
44848
45212
|
if (!rules.some((rule) => rule.props.handleTextInput?.call(rule, preparedView, at, at, last, () => prepared.tr.insertText(last, at)))) {
|
|
44849
|
-
const plain =
|
|
45213
|
+
const plain = fallback().scrollIntoView();
|
|
44850
45214
|
view.dispatch(last === "-" ? insertedHyphen(plain) : plain);
|
|
44851
45215
|
return true;
|
|
44852
45216
|
}
|
|
@@ -44854,6 +45218,7 @@ function insertTextChunk(view, from, to, text, deflt) {
|
|
|
44854
45218
|
for (const step of ruled.steps) tr.step(step);
|
|
44855
45219
|
tr.setSelection(ruled.selection.map(tr.doc, StepMap.empty));
|
|
44856
45220
|
if (ruled.storedMarksSet) tr.setStoredMarks(ruled.storedMarks);
|
|
45221
|
+
else if (typing?.stored) tr.setStoredMarks(typing.stored);
|
|
44857
45222
|
for (const rule of rules) {
|
|
44858
45223
|
const meta = ruled.getMeta(rule);
|
|
44859
45224
|
if (meta !== void 0) tr.setMeta(rule, meta);
|
|
@@ -44862,6 +45227,65 @@ function insertTextChunk(view, from, to, text, deflt) {
|
|
|
44862
45227
|
view.dispatch(tr.scrollIntoView());
|
|
44863
45228
|
return true;
|
|
44864
45229
|
}
|
|
45230
|
+
function finishComposition(view, composing) {
|
|
45231
|
+
const { state } = view;
|
|
45232
|
+
const { start, link, retyped } = composing;
|
|
45233
|
+
const end = state.selection.head;
|
|
45234
|
+
if (view.isDestroyed || view.composing || state.doc !== composing.doc || !state.selection.empty || end <= start || !state.doc.resolve(start).sameParent(state.selection.$head)) return;
|
|
45235
|
+
const text = state.doc.textBetween(start, end);
|
|
45236
|
+
if (text.length !== end - start) return;
|
|
45237
|
+
const space = retyped ? -1 : text.search(/\s/);
|
|
45238
|
+
const linked = start + (space < 0 ? text.length : space);
|
|
45239
|
+
const tr = state.tr;
|
|
45240
|
+
if (linked > start) tr.addMark(start, linked, link);
|
|
45241
|
+
const marks = link.type.removeFromSet(tr.doc.resolve(end).marks());
|
|
45242
|
+
tr.setStoredMarks(linked === end ? link.addToSet(marks) : marks).setMeta(typingKey, retyped && linked === end ? link : null).setMeta("composition", composing.composition);
|
|
45243
|
+
view.dispatch(tr);
|
|
45244
|
+
}
|
|
45245
|
+
var controlCharacters = /^[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F]+$/;
|
|
45246
|
+
/** Typed text: chunks, control characters, and the link rule for typing and composition. */
|
|
45247
|
+
function textInputPlugin() {
|
|
45248
|
+
let composing;
|
|
45249
|
+
return new Plugin({
|
|
45250
|
+
key: typingKey,
|
|
45251
|
+
state: typingState,
|
|
45252
|
+
props: {
|
|
45253
|
+
handleTextInput: (view, from, to, text, deflt) => controlCharacters.test(text) || insertTypedText(view, from, to, text, deflt),
|
|
45254
|
+
handleDOMEvents: {
|
|
45255
|
+
compositionstart(view) {
|
|
45256
|
+
if (view.composing) return false;
|
|
45257
|
+
const { state } = view;
|
|
45258
|
+
const { from, to } = state.selection;
|
|
45259
|
+
const typing = linkTyping(state, from, to, "");
|
|
45260
|
+
composing = typing?.stored && !view.isDestroyed ? {
|
|
45261
|
+
link: typing.link,
|
|
45262
|
+
retyped: typing.retyped,
|
|
45263
|
+
start: from,
|
|
45264
|
+
doc: state.doc
|
|
45265
|
+
} : void 0;
|
|
45266
|
+
return false;
|
|
45267
|
+
},
|
|
45268
|
+
compositionend(view) {
|
|
45269
|
+
const ended = composing;
|
|
45270
|
+
if (ended) setTimeout(() => {
|
|
45271
|
+
if (composing !== ended) return;
|
|
45272
|
+
composing = void 0;
|
|
45273
|
+
finishComposition(view, ended);
|
|
45274
|
+
});
|
|
45275
|
+
return false;
|
|
45276
|
+
}
|
|
45277
|
+
}
|
|
45278
|
+
},
|
|
45279
|
+
appendTransaction(transactions, _old, state) {
|
|
45280
|
+
if (composing && transactions.some((tr) => tr.docChanged)) for (const tr of transactions) {
|
|
45281
|
+
composing.start = tr.mapping.map(composing.start, -1);
|
|
45282
|
+
composing.composition ??= tr.getMeta("composition");
|
|
45283
|
+
}
|
|
45284
|
+
if (composing) composing.doc = state.doc;
|
|
45285
|
+
return null;
|
|
45286
|
+
}
|
|
45287
|
+
});
|
|
45288
|
+
}
|
|
44865
45289
|
//#endregion
|
|
44866
45290
|
//#region src/drop-placement.ts
|
|
44867
45291
|
/**
|
|
@@ -44977,6 +45401,95 @@ function caretAfterInsertion(tr, view) {
|
|
|
44977
45401
|
return tr.setSelection($end.parent.inlineContent ? TextSelection.create(tr.doc, end) : caretAfter(tr.doc, end, view && calloutFolds(view, tr)));
|
|
44978
45402
|
}
|
|
44979
45403
|
//#endregion
|
|
45404
|
+
//#region src/parser.ts
|
|
45405
|
+
/**
|
|
45406
|
+
* Milkdown's parser state, except that it throws where Milkdown would drop content. Milkdown
|
|
45407
|
+
* catches the failure to build a node (`createNodeInParserFail`), logs it and carries on without
|
|
45408
|
+
* the node and everything inside it, so the document it returns can silently lack part of its
|
|
45409
|
+
* source.
|
|
45410
|
+
*/
|
|
45411
|
+
var CheckedParserState = class extends ParserState {
|
|
45412
|
+
constructor(schema) {
|
|
45413
|
+
super(schema);
|
|
45414
|
+
const closeNode = this.closeNode;
|
|
45415
|
+
const addNode = this.addNode;
|
|
45416
|
+
const unbuildable = (type, attrs, content) => {
|
|
45417
|
+
try {
|
|
45418
|
+
return !type.createAndFill(attrs, content);
|
|
45419
|
+
} catch {
|
|
45420
|
+
return true;
|
|
45421
|
+
}
|
|
45422
|
+
};
|
|
45423
|
+
this.closeNode = () => {
|
|
45424
|
+
const element = this.top();
|
|
45425
|
+
if (!element || this.size() < 2 || unbuildable(element.type, element.attrs, element.content)) throw new Error(`Cannot build ${element?.type.name ?? "a node"}`);
|
|
45426
|
+
return closeNode();
|
|
45427
|
+
};
|
|
45428
|
+
this.addNode = (type, attrs, content) => {
|
|
45429
|
+
if (!this.top() || unbuildable(type, attrs, content)) throw new Error(`Cannot build ${type.name}`);
|
|
45430
|
+
return addNode(type, attrs, content);
|
|
45431
|
+
};
|
|
45432
|
+
}
|
|
45433
|
+
};
|
|
45434
|
+
/** The document, or undefined when Milkdown cannot build all of it. */
|
|
45435
|
+
function build(schema, tree) {
|
|
45436
|
+
try {
|
|
45437
|
+
return new CheckedParserState(schema).next(tree).toDoc();
|
|
45438
|
+
} catch {
|
|
45439
|
+
return;
|
|
45440
|
+
}
|
|
45441
|
+
}
|
|
45442
|
+
/**
|
|
45443
|
+
* Parses Markdown as Milkdown does, but never returns a document that lacks part of its source.
|
|
45444
|
+
* A top-level block that cannot be built is kept as its literal source, as unsupported syntax is,
|
|
45445
|
+
* so the rest of the document stays editable; when that is not enough, it throws `preservation`.
|
|
45446
|
+
*/
|
|
45447
|
+
function parseMarkdown(schema, remark, markdown, parsedTree) {
|
|
45448
|
+
const tree = parsedTree ?? remark.runSync(remark.parse(markdown), markdown);
|
|
45449
|
+
const doc = build(schema, tree);
|
|
45450
|
+
if (doc) return doc;
|
|
45451
|
+
const source = markdown.replace(/^\uFEFF/, "");
|
|
45452
|
+
tree.children = tree.children.map((node) => {
|
|
45453
|
+
if (build(schema, {
|
|
45454
|
+
type: "root",
|
|
45455
|
+
children: [node]
|
|
45456
|
+
})) return node;
|
|
45457
|
+
const start = node.position?.start.offset;
|
|
45458
|
+
const end = node.position?.end.offset;
|
|
45459
|
+
if (start == null || end == null) return node;
|
|
45460
|
+
const value = source.slice(start, end);
|
|
45461
|
+
return {
|
|
45462
|
+
type: "inkkitLiteral",
|
|
45463
|
+
value,
|
|
45464
|
+
comments: literalCommentSpans(value),
|
|
45465
|
+
position: node.position
|
|
45466
|
+
};
|
|
45467
|
+
});
|
|
45468
|
+
const kept = build(schema, tree);
|
|
45469
|
+
if (kept) return kept;
|
|
45470
|
+
throw new InkKitError("preservation", "The Markdown cannot be shown without losing part of it");
|
|
45471
|
+
}
|
|
45472
|
+
/** Replaces Milkdown's parser with `parseMarkdown`, for every caller of `parserCtx`. */
|
|
45473
|
+
var checkedParser = (ctx) => async () => {
|
|
45474
|
+
await ctx.wait(ParserReady);
|
|
45475
|
+
const schema = ctx.get(schemaCtx);
|
|
45476
|
+
ctx.set(parserCtx, (markdown) => parseMarkdown(schema, ctx.get(remarkCtx), markdown));
|
|
45477
|
+
};
|
|
45478
|
+
//#endregion
|
|
45479
|
+
//#region src/gutter.ts
|
|
45480
|
+
var listMarker = /(?:[-*+]|\d{1,9}[.)])(?=[ \t])/g;
|
|
45481
|
+
/**
|
|
45482
|
+
* What the lines of a block repeat before it: the quote markers and
|
|
45483
|
+
* indentation that open the line `offset` is on, up to `offset`, with a list
|
|
45484
|
+
* marker as the spaces it takes, which is how the lines after the item's first
|
|
45485
|
+
* are indented. Anything else before `offset` on its line is content, and ends
|
|
45486
|
+
* the gutter.
|
|
45487
|
+
*/
|
|
45488
|
+
function gutterAt(text, offset) {
|
|
45489
|
+
const line = text.slice(text.lastIndexOf("\n", offset - 1) + 1, offset);
|
|
45490
|
+
return /^(?:[ \t]|>|(?:[-*+]|\d{1,9}[.)])(?=[ \t]))*/.exec(line)[0].replace(listMarker, (marker) => " ".repeat(marker.length));
|
|
45491
|
+
}
|
|
45492
|
+
//#endregion
|
|
44980
45493
|
//#region src/code-fences.ts
|
|
44981
45494
|
function readFence(value) {
|
|
44982
45495
|
if (typeof value !== "object" || value == null) return null;
|
|
@@ -45368,10 +45881,11 @@ var formatting = /* @__PURE__ */ new Set([
|
|
|
45368
45881
|
"delete",
|
|
45369
45882
|
"highlight"
|
|
45370
45883
|
]);
|
|
45884
|
+
var linkTypes = /* @__PURE__ */ new Set(["link", "linkReference"]);
|
|
45371
45885
|
function ordered(node) {
|
|
45372
45886
|
let current = node;
|
|
45373
45887
|
const inner = current.children?.[0];
|
|
45374
|
-
if (current.type
|
|
45888
|
+
if (linkTypes.has(current.type) && current.children.length === 1 && formatting.has(inner.type)) current = {
|
|
45375
45889
|
...inner,
|
|
45376
45890
|
children: [{
|
|
45377
45891
|
...current,
|
|
@@ -45383,6 +45897,32 @@ function ordered(node) {
|
|
|
45383
45897
|
children: current.children.map(ordered)
|
|
45384
45898
|
} : current;
|
|
45385
45899
|
}
|
|
45900
|
+
function wrappers$1(node) {
|
|
45901
|
+
const chain = [];
|
|
45902
|
+
for (let at = node; at && (linkTypes.has(at.type) || formatting.has(at.type)); at = at.children?.length === 1 ? at.children[0] : void 0) chain.push(at);
|
|
45903
|
+
return chain;
|
|
45904
|
+
}
|
|
45905
|
+
function authoredNesting(before, after) {
|
|
45906
|
+
if (before.type === after.type || !formatting.has(before.type)) return after;
|
|
45907
|
+
const authored = wrappers$1(before);
|
|
45908
|
+
const written = wrappers$1(after);
|
|
45909
|
+
const types = (chain) => chain.map((node) => node.type).sort().join();
|
|
45910
|
+
const linksIn = (chain) => chain.filter((node) => linkTypes.has(node.type));
|
|
45911
|
+
const shape = (node) => ownShape({
|
|
45912
|
+
...node,
|
|
45913
|
+
children: []
|
|
45914
|
+
});
|
|
45915
|
+
const [authoredLink] = linksIn(authored);
|
|
45916
|
+
const [writtenLink] = linksIn(written);
|
|
45917
|
+
if (linksIn(authored).length !== 1 || linksIn(written).length !== 1 || types(authored) !== types(written) || shape(authoredLink) !== shape(writtenLink) || authored.at(-1).children?.length !== written.at(-1).children?.length) return after;
|
|
45918
|
+
const inner = written.at(-1).children;
|
|
45919
|
+
const byType = new Map(written.map((node) => [node.type, node]));
|
|
45920
|
+
return authored.reduceRight((child, node, level) => ({
|
|
45921
|
+
...byType.get(node.type),
|
|
45922
|
+
...level === 0 && { position: after.position },
|
|
45923
|
+
children: child ? [child] : inner
|
|
45924
|
+
}), void 0);
|
|
45925
|
+
}
|
|
45386
45926
|
/** Where the delimiter row ends, given where the header row before it ends. */
|
|
45387
45927
|
function delimiterRowEnd(text, headerEnd) {
|
|
45388
45928
|
const next = text.indexOf("\n", headerEnd);
|
|
@@ -45391,15 +45931,17 @@ function delimiterRowEnd(text, headerEnd) {
|
|
|
45391
45931
|
ending.lastIndex = next + 1;
|
|
45392
45932
|
return ending.exec(text)?.index ?? text.length;
|
|
45393
45933
|
}
|
|
45394
|
-
function ownShape(node) {
|
|
45934
|
+
function ownShape(node, spreadless = false) {
|
|
45395
45935
|
return JSON.stringify(ordered(node), (key, value) => [
|
|
45396
45936
|
"position",
|
|
45397
45937
|
"data",
|
|
45398
45938
|
"children",
|
|
45399
45939
|
"value",
|
|
45400
45940
|
"marker"
|
|
45401
|
-
].includes(key) ? void 0 : value);
|
|
45941
|
+
].includes(key) || spreadless && key === "spread" ? void 0 : value);
|
|
45402
45942
|
}
|
|
45943
|
+
var holdsLiteralBlock = (node) => (node.type === "listItem" || node.type === "list") && !!node.children?.some((child) => child.type === "inkkitLiteral" || literals$1.has(child) || holdsLiteralBlock(child));
|
|
45944
|
+
var sameShape = (before, after) => ownShape(before) === ownShape(after) || (holdsLiteralBlock(before) || holdsLiteralBlock(after)) && ownShape(before, true) === ownShape(after, true);
|
|
45403
45945
|
var matchShape = (node) => ownShape({
|
|
45404
45946
|
...node,
|
|
45405
45947
|
checked: void 0
|
|
@@ -45456,10 +45998,25 @@ function authoredMarker(list, source) {
|
|
|
45456
45998
|
return at == null ? void 0 : markerAt(source, at)?.marker;
|
|
45457
45999
|
}
|
|
45458
46000
|
var sameList = (before, after) => before.type === "list" && after.type === "list" && before.ordered === after.ordered;
|
|
45459
|
-
function
|
|
46001
|
+
function childGutters(before, after, source, canonical, fromStart = false) {
|
|
46002
|
+
if (inlineParents.has(before.type) || before.type === "table") return void 0;
|
|
46003
|
+
const [first, now] = [before, after].map((node) => fromStart ? node.position?.start.offset : node.children?.[0]?.position?.start.offset);
|
|
46004
|
+
return first == null || now == null ? void 0 : [gutterAt(source, first), gutterAt(canonical, now)];
|
|
46005
|
+
}
|
|
46006
|
+
function regutter(text, gutters, open = false) {
|
|
46007
|
+
if (!gutters || gutters[0] === gutters[1]) return text;
|
|
46008
|
+
const [authored, canonical] = gutters;
|
|
46009
|
+
const bare = canonical.trimEnd();
|
|
46010
|
+
return text.replace(/(\r?\n)([^\r\n]*)/g, (match, ending, line, at) => {
|
|
46011
|
+
if (open && at + match.length === text.length && (line === bare || line === canonical)) return ending + authored;
|
|
46012
|
+
if (line === bare) return ending + authored.trimEnd();
|
|
46013
|
+
return line.startsWith(canonical) ? ending + authored + line.slice(canonical.length) : match;
|
|
46014
|
+
});
|
|
46015
|
+
}
|
|
46016
|
+
function canonicalSlice(marker, children, canonical, from, to, previous, next, gutters, open = false, inherited) {
|
|
45460
46017
|
let text = canonical.slice(from, to);
|
|
45461
46018
|
const offsets = (list) => (list.children ?? []).map((item) => item.position.start.offset - from);
|
|
45462
|
-
if (marker) return relabel(text, children.map((item) => item.position.start.offset - from), marker);
|
|
46019
|
+
if (marker) return regutter(relabel(text, children.map((item) => item.position.start.offset - from), marker), gutters, open);
|
|
45463
46020
|
children.forEach((child, index) => {
|
|
45464
46021
|
if (child.type !== "list") {
|
|
45465
46022
|
previous = void 0;
|
|
@@ -45467,19 +46024,24 @@ function canonicalSlice(marker, children, canonical, from, to, previous, next) {
|
|
|
45467
46024
|
}
|
|
45468
46025
|
const avoid = [previous, index === children.length - 1 ? next : void 0].filter((neighbour) => neighbour?.ordered === child.ordered).map((neighbour) => neighbour.marker);
|
|
45469
46026
|
const own = markerAt(canonical, child.children[0].position.start.offset)?.marker;
|
|
45470
|
-
const choice = [
|
|
45471
|
-
|
|
45472
|
-
|
|
45473
|
-
"
|
|
45474
|
-
|
|
46027
|
+
const choice = [
|
|
46028
|
+
inherited && /[.)]/.test(inherited) === !!child.ordered ? inherited : void 0,
|
|
46029
|
+
own,
|
|
46030
|
+
...child.ordered ? [".", ")"] : [
|
|
46031
|
+
"-",
|
|
46032
|
+
"*",
|
|
46033
|
+
"+"
|
|
46034
|
+
]
|
|
46035
|
+
].find((candidate) => candidate && !avoid.includes(candidate));
|
|
45475
46036
|
if (choice) text = relabel(text, offsets(child), choice);
|
|
45476
46037
|
previous = {
|
|
45477
46038
|
ordered: child.ordered,
|
|
45478
46039
|
marker: choice ?? own ?? ""
|
|
45479
46040
|
};
|
|
45480
46041
|
});
|
|
45481
|
-
return text;
|
|
46042
|
+
return regutter(text, gutters, open);
|
|
45482
46043
|
}
|
|
46044
|
+
var itemMarker = (item, source) => item.type === "listItem" ? markerAt(source, item.position.start.offset)?.marker : void 0;
|
|
45483
46045
|
function authoredNeighbour(before, after, source) {
|
|
45484
46046
|
if (!before || !after || !sameList(before, after)) return void 0;
|
|
45485
46047
|
const marker = authoredMarker(before, source);
|
|
@@ -45579,35 +46141,90 @@ function retainSplit(candidates, after, source, canonical, lineEnding, taken) {
|
|
|
45579
46141
|
text: retainSource(part, after, source, canonical, lineEnding)
|
|
45580
46142
|
};
|
|
45581
46143
|
}
|
|
45582
|
-
function
|
|
45583
|
-
|
|
46144
|
+
function liftedSource(blocks, after, source) {
|
|
46145
|
+
if (after.type === "list" || after.type === "blockquote") return void 0;
|
|
46146
|
+
const wanted = signature(after);
|
|
46147
|
+
const found = [];
|
|
46148
|
+
const visit = (node) => {
|
|
46149
|
+
for (const child of node.children ?? []) if (child.type === "list" || child.type === "listItem" || child.type === "blockquote") visit(child);
|
|
46150
|
+
else if ((node.type === "blockquote" || node.type === "listItem" && node.checked == null) && signature(child) === wanted) found.push(child);
|
|
46151
|
+
};
|
|
46152
|
+
blocks.forEach(visit);
|
|
46153
|
+
if (found.length !== 1) return void 0;
|
|
46154
|
+
const start = found[0].position?.start.offset;
|
|
46155
|
+
const end = found[0].position?.end.offset;
|
|
46156
|
+
if (start == null || end == null) return void 0;
|
|
46157
|
+
return regutter(source.slice(start, end), ["", gutterAt(source, start)]);
|
|
46158
|
+
}
|
|
46159
|
+
function strayRun(strays, wanted, source, opening) {
|
|
46160
|
+
const keys = wanted.map(opening);
|
|
46161
|
+
for (const [at, stray] of strays.entries()) {
|
|
46162
|
+
if (opening(stray) !== keys[0]) continue;
|
|
46163
|
+
const run = [stray];
|
|
46164
|
+
for (const next of strays.slice(at + 1)) {
|
|
46165
|
+
if (opening(next) !== keys[run.length] || !/^[ \t>]*(\r?\n[ \t>]*)+$/.test(source.slice(run.at(-1).position.end.offset, next.position.start.offset))) break;
|
|
46166
|
+
run.push(next);
|
|
46167
|
+
}
|
|
46168
|
+
return run;
|
|
46169
|
+
}
|
|
46170
|
+
return [];
|
|
46171
|
+
}
|
|
46172
|
+
function retainParts(marker, before, after, source, canonical, from, to, lineEnding, previous, next, gutters, open = false, inherited) {
|
|
45584
46173
|
const taken = /* @__PURE__ */ new Set();
|
|
45585
46174
|
const opening = (item) => item.children?.length ? matchShape(item) + signature(item.children[0]) : void 0;
|
|
45586
|
-
const
|
|
46175
|
+
const items = /* @__PURE__ */ new Map();
|
|
46176
|
+
for (let row = before; row.length;) {
|
|
46177
|
+
const deeper = [];
|
|
46178
|
+
for (const node of row) {
|
|
46179
|
+
if (node.type !== "listItem") continue;
|
|
46180
|
+
const key = opening(node);
|
|
46181
|
+
if (key) {
|
|
46182
|
+
const same = items.get(key);
|
|
46183
|
+
if (same) same.push(node);
|
|
46184
|
+
else items.set(key, [node]);
|
|
46185
|
+
}
|
|
46186
|
+
for (const child of node.children ?? []) if (child.type === "list") deeper.push(...child.children ?? []);
|
|
46187
|
+
}
|
|
46188
|
+
row = deeper;
|
|
46189
|
+
}
|
|
46190
|
+
const isNumbered = (item) => /[.)]/.test(itemMarker(item, source) ?? "");
|
|
46191
|
+
const originals = after.map((child) => {
|
|
46192
|
+
const original = child.type === "listItem" ? items.get(opening(child) ?? "")?.shift() : void 0;
|
|
46193
|
+
return original && marker && isNumbered(original) !== /[.)]/.test(marker) ? void 0 : original;
|
|
46194
|
+
});
|
|
46195
|
+
const ownLevel = new Set(before);
|
|
46196
|
+
const strays = [...items.values()].flat().sort((left, right) => left.position.start.offset - right.position.start.offset);
|
|
46197
|
+
const pieces = after.map((child, index) => {
|
|
45587
46198
|
const end = child.position.end.offset;
|
|
45588
46199
|
if (child.type === "list" || child.type === "blockquote") {
|
|
45589
46200
|
const part = retainSplit(before, child, source, canonical, lineEnding, taken);
|
|
45590
46201
|
if (part) return part.text + canonical.slice(child.children.at(-1).position.end.offset, end);
|
|
45591
46202
|
const lists = before.filter((node) => node.type === "list" && node.ordered === child.ordered);
|
|
45592
|
-
|
|
45593
|
-
|
|
45594
|
-
|
|
45595
|
-
|
|
45596
|
-
|
|
45597
|
-
|
|
45598
|
-
|
|
45599
|
-
|
|
45600
|
-
|
|
45601
|
-
|
|
45602
|
-
|
|
46203
|
+
if (child.type === "list" && !lists.length) {
|
|
46204
|
+
const run = strayRun(strays, child.children, source, opening);
|
|
46205
|
+
if (!run.length) return void 0;
|
|
46206
|
+
const first = run[0].position.start.offset;
|
|
46207
|
+
return regutter(retainSource({
|
|
46208
|
+
type: "list",
|
|
46209
|
+
ordered: child.ordered,
|
|
46210
|
+
start: child.ordered ? Number(/^\d+/.exec(source.slice(first))[0]) : null,
|
|
46211
|
+
spread: false,
|
|
46212
|
+
children: run,
|
|
46213
|
+
position: {
|
|
46214
|
+
start: { offset: first },
|
|
46215
|
+
end: { offset: run.at(-1).position.end.offset }
|
|
46216
|
+
}
|
|
46217
|
+
}, child, source, canonical, lineEnding), gutters && [gutters[0], gutterAt(source, first)]) + canonical.slice(child.children.at(-1).position.end.offset, end);
|
|
45603
46218
|
}
|
|
46219
|
+
return child.type === "list" && lists.length ? retainParts(authoredMarker(lists[0], source), lists.flatMap((list) => list.children ?? []), child.children, source, canonical, child.position.start.offset, end, lineEnding, void 0, void 0, childGutters(lists[0], child, source, canonical)) : void 0;
|
|
45604
46220
|
}
|
|
45605
|
-
|
|
45606
|
-
const
|
|
46221
|
+
if (child.type !== "listItem") return void 0;
|
|
46222
|
+
const original = originals[index];
|
|
46223
|
+
const text = original ? regutter(retainSource(original, child, source, canonical, lineEnding, false, void 0, void 0, strays), gutters && [gutters[0], gutterAt(source, original.position.start.offset)]) : child.children?.some((node) => node.type === "list" || node.type === "blockquote") ? retainParts(void 0, before.flatMap((node) => node.type === "listItem" ? node.children ?? [] : []), child.children, source, canonical, child.position.start.offset, end, lineEnding, void 0, void 0, childGutters(before.find((node) => node.type === "listItem"), child, source, canonical)) : void 0;
|
|
45607
46224
|
return text !== void 0 && marker ? relabel(text, [0], marker) : text;
|
|
45608
46225
|
});
|
|
45609
46226
|
if (pieces.every((piece) => piece === void 0)) return void 0;
|
|
45610
|
-
let text = "", at = from;
|
|
46227
|
+
let text = "", at = from, lastNumber;
|
|
45611
46228
|
after.forEach((child, index) => {
|
|
45612
46229
|
const childStart = child.position.start.offset;
|
|
45613
46230
|
const childEnd = child.position.end.offset;
|
|
@@ -45615,15 +46232,18 @@ function retainParts(marker, before, after, source, canonical, from, to, lineEnd
|
|
|
45615
46232
|
let piece = pieces[index];
|
|
45616
46233
|
const own = piece && markerAt(piece, 0)?.marker;
|
|
45617
46234
|
if (child.type === "list" && [previous, following].some((neighbour) => neighbour?.ordered === child.ordered && neighbour?.marker === own)) piece = void 0;
|
|
45618
|
-
|
|
46235
|
+
const number = /^\d+/.exec(piece ?? "")?.[0];
|
|
46236
|
+
if (piece && number && marker && lastNumber !== void 0 && originals[index] && !ownLevel.has(originals[index]) && String(lastNumber + 1).length === number.length) piece = String(lastNumber + 1) + piece.slice(number.length);
|
|
46237
|
+
piece ??= canonicalSlice(marker, [child], canonical, childStart, childEnd, previous, following, gutters, false, inherited);
|
|
46238
|
+
lastNumber = child.type === "listItem" && /^\d/.test(piece) ? Number(/^\d+/.exec(piece)[0]) : void 0;
|
|
45619
46239
|
previous = child.type === "list" ? {
|
|
45620
46240
|
ordered: child.ordered,
|
|
45621
46241
|
marker: markerAt(piece, /^[ \t]*/.exec(piece)[0].length)?.marker ?? ""
|
|
45622
46242
|
} : void 0;
|
|
45623
|
-
text += canonical.slice(at, childStart) + piece;
|
|
46243
|
+
text += regutter(canonical.slice(at, childStart), gutters, true) + piece;
|
|
45624
46244
|
at = childEnd;
|
|
45625
46245
|
});
|
|
45626
|
-
return text + canonical.slice(at, to);
|
|
46246
|
+
return text + regutter(canonical.slice(at, to), gutters, open);
|
|
45627
46247
|
}
|
|
45628
46248
|
function decodedOffsets(raw, lines = false) {
|
|
45629
46249
|
const offsets = [0];
|
|
@@ -45631,7 +46251,7 @@ function decodedOffsets(raw, lines = false) {
|
|
|
45631
46251
|
for (let index = 0; index < raw.length;) {
|
|
45632
46252
|
const rest = raw.slice(index);
|
|
45633
46253
|
const line = /[ \t]/.test(raw[index - 1] ?? "") && /[ \t]/.test(raw[index]) ? void 0 : /^[ \t]*(?:\r\n?|\n)(?:[ \t]*>)*[ \t]*/.exec(rest)?.[0];
|
|
45634
|
-
|
|
46254
|
+
let token = line ?? /^\\[!"#$%&'()*+,\-./:;<=>?@[\]\\^_`{|}~]/.exec(rest)?.[0] ?? /^&(?:#[xX][\da-fA-F]+|#\d+|[A-Za-z][A-Za-z\d]+);/.exec(rest)?.[0];
|
|
45635
46255
|
let value = raw[index];
|
|
45636
46256
|
if (line) {
|
|
45637
46257
|
if (!lines) return void 0;
|
|
@@ -45640,7 +46260,8 @@ function decodedOffsets(raw, lines = false) {
|
|
|
45640
46260
|
else if (token) {
|
|
45641
46261
|
const element = document.createElement("textarea");
|
|
45642
46262
|
element.innerHTML = token;
|
|
45643
|
-
value =
|
|
46263
|
+
if (element.value === token) token = void 0;
|
|
46264
|
+
else value = element.value;
|
|
45644
46265
|
}
|
|
45645
46266
|
index += token?.length ?? 1;
|
|
45646
46267
|
decoded += value;
|
|
@@ -45757,7 +46378,10 @@ function retainRun(before, after, source, canonical, [from, to], [newFrom, newTo
|
|
|
45757
46378
|
}
|
|
45758
46379
|
return source.slice(from, old.offsets[prefix]) + canonical.slice(now.offsets[prefix], now.offsets[b.length - suffix]) + (now.breaks.has(b.length - suffix - 1) ? retainBoundaryText(source.slice(old.offsets[a.length - suffix], to), canonical.slice(now.offsets[b.length - suffix], newTo), true) : source.slice(old.offsets[a.length - suffix], to));
|
|
45759
46380
|
}
|
|
45760
|
-
function retainText(raw, before, after, inTable = false, written, beside = [false, false]) {
|
|
46381
|
+
function retainText(raw, before, after, inTable = false, written, beside = [false, false], readGutters) {
|
|
46382
|
+
let found;
|
|
46383
|
+
const gutters = () => found ??= readGutters?.();
|
|
46384
|
+
const guttered = (text) => text.includes("\n") ? regutter(text, gutters()) : text;
|
|
45761
46385
|
before = lf(before);
|
|
45762
46386
|
after = lf(after);
|
|
45763
46387
|
let prefix = 0;
|
|
@@ -45775,19 +46399,34 @@ function retainText(raw, before, after, inTable = false, written, beside = [fals
|
|
|
45775
46399
|
const marker = /^(?:\d+)?\\[#+.\->)]/.exec(opening)?.[0];
|
|
45776
46400
|
if (marker && prefix - lineStart <= decodedOffsets(marker).decoded.length) {
|
|
45777
46401
|
prefix = lineStart;
|
|
45778
|
-
return raw.slice(0, offsets[prefix]) + written.slice(canonical.offsets[prefix], canonical.offsets[after.length - suffix]) + raw.slice(offsets[before.length - suffix]);
|
|
46402
|
+
return raw.slice(0, offsets[prefix]) + guttered(written.slice(canonical.offsets[prefix], canonical.offsets[after.length - suffix])) + raw.slice(offsets[before.length - suffix]);
|
|
45779
46403
|
}
|
|
45780
46404
|
}
|
|
45781
46405
|
}
|
|
45782
46406
|
if (written !== void 0 && (beside[0] && prefix === 0 || beside[1] && suffix === 0)) {
|
|
45783
46407
|
const writtenOffsets = decodedOffsets(written);
|
|
45784
|
-
if (writtenOffsets && writtenOffsets.decoded === after) return raw.slice(0, offsets[prefix]) + written.slice(writtenOffsets.offsets[prefix], writtenOffsets.offsets[after.length - suffix]) + raw.slice(offsets[before.length - suffix]);
|
|
46408
|
+
if (writtenOffsets && writtenOffsets.decoded === after) return raw.slice(0, offsets[prefix]) + guttered(written.slice(writtenOffsets.offsets[prefix], writtenOffsets.offsets[after.length - suffix])) + raw.slice(offsets[before.length - suffix]);
|
|
45785
46409
|
}
|
|
45786
46410
|
const inserted = after.slice(prefix, after.length - suffix).split("").map((character, index) => {
|
|
45787
46411
|
const at = prefix + index;
|
|
45788
|
-
return (character === "%" || character === "=") && (after[at - 1] === character || after[at + 1] === character) || /[\\`*_[\]<>]/.test(character) || inTable && character === "|" ? `\\${character}` : character;
|
|
46412
|
+
return (character === "%" || character === "=") && (after[at - 1] === character || after[at + 1] === character) || /[\\`*_[\]<>]/.test(character) || inTable && character === "|" ? `\\${character}` : character === "\n" ? character + (gutters()?.[0] ?? "") : character;
|
|
45789
46413
|
}).join("");
|
|
45790
|
-
return raw.slice(0, offsets[prefix])
|
|
46414
|
+
return escapeReferences(raw.slice(0, offsets[prefix]), inserted, raw.slice(offsets[before.length - suffix]));
|
|
46415
|
+
}
|
|
46416
|
+
var characterReference = /&(?:#[xX][\da-fA-F]+|#\d+|[A-Za-z][A-Za-z\d]*);/g;
|
|
46417
|
+
function escapeReferences(head, inserted, tail) {
|
|
46418
|
+
const text = head + inserted + tail;
|
|
46419
|
+
const from = head.length;
|
|
46420
|
+
const to = from + inserted.length;
|
|
46421
|
+
let output = "", at = 0;
|
|
46422
|
+
for (const match of text.matchAll(characterReference)) {
|
|
46423
|
+
const start = match.index;
|
|
46424
|
+
const end = start + match[0].length;
|
|
46425
|
+
if (start >= to || end <= from || (/\\*$/.exec(text.slice(0, start))[0].length & 1) === 1) continue;
|
|
46426
|
+
output += text.slice(at, end - 1) + "\\";
|
|
46427
|
+
at = end - 1;
|
|
46428
|
+
}
|
|
46429
|
+
return output + text.slice(at);
|
|
45791
46430
|
}
|
|
45792
46431
|
function retainBoundaryText(raw, canonical, afterBreak = false) {
|
|
45793
46432
|
if (afterBreak) {
|
|
@@ -45984,6 +46623,7 @@ function markLiterals(raw, transformed, blocks = []) {
|
|
|
45984
46623
|
raw.children.forEach(mark);
|
|
45985
46624
|
}
|
|
45986
46625
|
function retainSource(before, after, source, canonical, lineEnding, inTable = false, width, beside = [false, false], joined = [], reorder, afterBreak = false) {
|
|
46626
|
+
after = authoredNesting(before, after);
|
|
45987
46627
|
if (literals$1.has(after)) return withEnding(retainLiteral(source.slice(before.position.start.offset, before.position.end.offset), literalForms.get(before), lf(canonical.slice(after.position.start.offset, after.position.end.offset))), lineEnding);
|
|
45988
46628
|
if (before.type === "list" && after.type === "list" && before.ordered && after.ordered && !numbered.has(before) && before.position?.start.offset != null) {
|
|
45989
46629
|
const own = {
|
|
@@ -46080,15 +46720,20 @@ function retainSource(before, after, source, canonical, lineEnding, inTable = fa
|
|
|
46080
46720
|
const to = first.position.end.offset - start;
|
|
46081
46721
|
return retained.startsWith(source.slice(start, before.children[1].position.start.offset)) ? retained.slice(0, from) + "<br />" + retained.slice(to) : retained;
|
|
46082
46722
|
}
|
|
46083
|
-
if (before.type === "text" && after.type === "text") return retainBoundaryText(withEnding(retainText(raw, before.value, after.value, inTable, canonical.slice(newStart, newEnd), beside), lineEnding), canonical.slice(newStart, newEnd), afterBreak);
|
|
46723
|
+
if (before.type === "text" && after.type === "text") return retainBoundaryText(withEnding(retainText(raw, before.value, after.value, inTable, canonical.slice(newStart, newEnd), beside, () => [gutterAt(source, start), gutterAt(canonical, newStart)]), lineEnding), canonical.slice(newStart, newEnd), afterBreak);
|
|
46084
46724
|
if (signature(before) === signature(after) && ownShape(before) === ownShape(after) && !holdsLiteral(after) && !reorderedWithin(before, reorder)) return raw;
|
|
46725
|
+
if (before.type !== after.type) {
|
|
46726
|
+
const lifted = liftedSource([before], after, source);
|
|
46727
|
+
if (lifted !== void 0) return lifted;
|
|
46728
|
+
}
|
|
46085
46729
|
const marker = sameList(before, after) ? authoredMarker(before, source) : void 0;
|
|
46086
46730
|
const located = (nodes) => nodes.every((node) => node.position?.start.offset != null);
|
|
46087
|
-
if (before.type === after.type &&
|
|
46731
|
+
if (before.type === after.type && sameShape(before, after) && before.children && after.children && before.children.length === after.children.length && located(before.children) && located(after.children)) {
|
|
46088
46732
|
let output = "", at = start;
|
|
46089
46733
|
let previous;
|
|
46090
46734
|
const same = (candidate, incoming) => signature(candidate) === signature(incoming) && ownShape(candidate) === ownShape(incoming);
|
|
46091
46735
|
const reorderable = before.type === "table" || before.type === "tableRow";
|
|
46736
|
+
const gutters = childGutters(before, after, source, canonical);
|
|
46092
46737
|
const moves = reorder?.get(parentKey(before));
|
|
46093
46738
|
const retained = new Set(reorderable ? before.children.flatMap((child, index) => same(child, after.children[index]) ? [index] : []) : []);
|
|
46094
46739
|
before.children.forEach((child, index) => {
|
|
@@ -46099,7 +46744,7 @@ function retainSource(before, after, source, canonical, lineEnding, inTable = fa
|
|
|
46099
46744
|
if (movedIndex >= 0) retained.add(movedIndex);
|
|
46100
46745
|
const childStart = child.position?.start.offset, childEnd = child.position?.end.offset;
|
|
46101
46746
|
if (childStart == null || childEnd == null) throw new PreservationError("A source token has no location");
|
|
46102
|
-
let retainedSource = rewrittenAddress(before.type, before.children, movedIndex < 0 ? index : movedIndex, after.children, index, source, canonical) ? canonical.slice(incoming.position.start.offset, incoming.position.end.offset) : incoming.type === "list" && !sameList(original, incoming) ? withEnding(canonicalSlice(void 0, [incoming], canonical, incoming.position.start.offset, incoming.position.end.offset, previous, authoredNeighbour(before.children[index + 1], after.children[index + 1], source)), lineEnding) : retainSource(original, incoming, source, canonical, lineEnding, inTable || before.type === "tableCell", before.type === "table" ? before.children[0]?.children?.length : void 0, [after.children[index - 1]?.type === "link", after.children[index + 1]?.type === "link"],
|
|
46747
|
+
let retainedSource = rewrittenAddress(before.type, before.children, movedIndex < 0 ? index : movedIndex, after.children, index, source, canonical) ? regutter(canonical.slice(incoming.position.start.offset, incoming.position.end.offset), gutters) : incoming.type === "list" && !sameList(original, incoming) ? withEnding(canonicalSlice(void 0, [incoming], canonical, incoming.position.start.offset, incoming.position.end.offset, previous, authoredNeighbour(before.children[index + 1], after.children[index + 1], source), gutters), lineEnding) : retainSource(original, incoming, source, canonical, lineEnding, inTable || before.type === "tableCell", before.type === "table" ? before.children[0]?.children?.length : void 0, [after.children[index - 1]?.type === "link", after.children[index + 1]?.type === "link"], joined, reorder, after.children[index - 1]?.type === "break");
|
|
46103
46748
|
if (before.type === "tableRow" && movedIndex >= 0 && movedIndex !== index) {
|
|
46104
46749
|
const originalFrom = original.children?.[0]?.position?.start.offset;
|
|
46105
46750
|
const originalTo = original.children?.at(-1)?.position?.end.offset;
|
|
@@ -46118,7 +46763,7 @@ function retainSource(before, after, source, canonical, lineEnding, inTable = fa
|
|
|
46118
46763
|
});
|
|
46119
46764
|
return output + source.slice(at, end);
|
|
46120
46765
|
}
|
|
46121
|
-
if (before.type === after.type &&
|
|
46766
|
+
if (before.type === after.type && sameShape(before, after) && before.children && after.children) {
|
|
46122
46767
|
let prefix = 0, suffix = 0;
|
|
46123
46768
|
while (prefix < before.children.length && prefix < after.children.length && signature(before.children[prefix]) === signature(after.children[prefix])) prefix++;
|
|
46124
46769
|
while (suffix < before.children.length - prefix && suffix < after.children.length - prefix && signature(before.children[before.children.length - 1 - suffix]) === signature(after.children[after.children.length - 1 - suffix])) suffix++;
|
|
@@ -46143,13 +46788,15 @@ function retainSource(before, after, source, canonical, lineEnding, inTable = fa
|
|
|
46143
46788
|
const changes = after.children.slice(prefix, after.children.length - suffix);
|
|
46144
46789
|
const previous = authoredNeighbour(before.children[prefix - 1], after.children[prefix - 1], source);
|
|
46145
46790
|
const next = authoredNeighbour(before.children[before.children.length - suffix], after.children[after.children.length - suffix], source);
|
|
46146
|
-
|
|
46791
|
+
const gutters = childGutters(before, after, source, canonical, !prefix);
|
|
46792
|
+
const inherited = itemMarker(before, source);
|
|
46793
|
+
return source.slice(start, first) + retainBoundaryText(source.slice(first, from) + withEnding((inlineParents.has(before.type) ? retainRun(changed, changes, source, canonical, [from, to], [newFrom, newTo]) : retainParts(marker, [...changed, ...joined], changes, source, canonical, newFrom, newTo, lineEnding, previous, next, gutters, suffix > 0, inherited)) ?? canonicalSlice(marker, changes, canonical, newFrom, newTo, previous, next, gutters, suffix > 0, inherited), lineEnding) + (inlineParents.has(before.type) ? retainBoundaryText(source.slice(to, last), canonical.slice(newTo, newLast), after.children[after.children.length - suffix - 1]?.type === "break") : source.slice(to, last)), canonical.slice(newFirst, newLast)) + source.slice(last, end);
|
|
46147
46794
|
}
|
|
46148
46795
|
}
|
|
46149
46796
|
const lastAfter = after.children?.at(-1)?.position?.end.offset;
|
|
46150
46797
|
const lastBefore = before.children?.at(-1)?.position?.end.offset;
|
|
46151
46798
|
const trailing = marker != null && lastAfter != null && lastBefore != null && loose(before, source) === loose(after, canonical);
|
|
46152
|
-
return withEnding(canonicalSlice(marker, after.children ?? [], canonical, newStart, trailing ? lastAfter : newEnd), lineEnding) + (trailing ? source.slice(lastBefore, end) : "");
|
|
46799
|
+
return withEnding(canonicalSlice(marker, after.children ?? [], canonical, newStart, trailing ? lastAfter : newEnd, void 0, void 0, childGutters(before, after, source, canonical, true), false, itemMarker(before, source)), lineEnding) + (trailing ? source.slice(lastBefore, end) : "");
|
|
46153
46800
|
}
|
|
46154
46801
|
function loose(list, text) {
|
|
46155
46802
|
const blank = (from, to) => from != null && to != null && /\n[ \t>]*\r?\n/.test(text.slice(from, to));
|
|
@@ -46246,6 +46893,13 @@ function semanticSignature(doc) {
|
|
|
46246
46893
|
attrs
|
|
46247
46894
|
};
|
|
46248
46895
|
}
|
|
46896
|
+
if (value.type === "comment_block" && value.attrs) {
|
|
46897
|
+
const { block: _block, ...attrs } = value.attrs;
|
|
46898
|
+
value = {
|
|
46899
|
+
...value,
|
|
46900
|
+
attrs
|
|
46901
|
+
};
|
|
46902
|
+
}
|
|
46249
46903
|
const content = value.content;
|
|
46250
46904
|
if (!content) return value;
|
|
46251
46905
|
const tokens = [];
|
|
@@ -46288,6 +46942,7 @@ function semanticSignature(doc) {
|
|
|
46288
46942
|
"authoredFence",
|
|
46289
46943
|
"form",
|
|
46290
46944
|
"inkkitFileRaw",
|
|
46945
|
+
"inkkitFileSource",
|
|
46291
46946
|
"inkkitFileWidth",
|
|
46292
46947
|
"inkkitFileInTable"
|
|
46293
46948
|
].includes(key) ? void 0 : value));
|
|
@@ -46476,6 +47131,18 @@ var nothingCarried = {
|
|
|
46476
47131
|
var Preservation = class Preservation {
|
|
46477
47132
|
ctx;
|
|
46478
47133
|
source;
|
|
47134
|
+
static recent = /* @__PURE__ */ new WeakMap();
|
|
47135
|
+
processor;
|
|
47136
|
+
rawTree;
|
|
47137
|
+
sourceTree;
|
|
47138
|
+
static read(ctx, source) {
|
|
47139
|
+
const cached = this.recent.get(ctx);
|
|
47140
|
+
const previous = cached?.processor === ctx.get(remarkCtx) ? cached : void 0;
|
|
47141
|
+
if (previous?.source === source) return previous;
|
|
47142
|
+
const next = new Preservation(ctx, source, previous);
|
|
47143
|
+
this.recent.set(ctx, next);
|
|
47144
|
+
return next;
|
|
47145
|
+
}
|
|
46479
47146
|
/** The document as loaded from `source`. */
|
|
46480
47147
|
baseline;
|
|
46481
47148
|
blocks = [];
|
|
@@ -46493,18 +47160,22 @@ var Preservation = class Preservation {
|
|
|
46493
47160
|
nestedLiterals = /* @__PURE__ */ new Set();
|
|
46494
47161
|
literalsRead = /* @__PURE__ */ new WeakSet();
|
|
46495
47162
|
definitionSources;
|
|
46496
|
-
constructor(ctx, source) {
|
|
47163
|
+
constructor(ctx, source, previous) {
|
|
46497
47164
|
this.ctx = ctx;
|
|
46498
47165
|
this.source = source;
|
|
46499
47166
|
try {
|
|
46500
47167
|
const parse = (text) => parseDoc(ctx, text);
|
|
46501
|
-
this.
|
|
46502
|
-
|
|
46503
|
-
const processor = ctx.get(remarkCtx);
|
|
47168
|
+
this.lineEnding = !source.includes("\n") ? source.includes("\r") ? "\r" : "\n" : source.includes("\r\n") && !source.replaceAll("\r\n", "").includes("\n") ? "\r\n" : "\n";
|
|
47169
|
+
const processor = this.processor = ctx.get(remarkCtx);
|
|
46504
47170
|
const offset = source.startsWith("") ? 1 : 0;
|
|
46505
47171
|
const body = source.slice(offset);
|
|
46506
|
-
const
|
|
46507
|
-
const
|
|
47172
|
+
const incremental = previous?.readEditedSource(source);
|
|
47173
|
+
const rawTree = incremental?.raw ?? parseTree(ctx, source);
|
|
47174
|
+
const tree = incremental?.tree ?? processor.runSync(structuredClone(rawTree), { value: body });
|
|
47175
|
+
this.rawTree = rawTree;
|
|
47176
|
+
this.sourceTree = tree;
|
|
47177
|
+
this.baseline = incremental?.doc ?? parseMarkdown(ctx.get(schemaCtx), processor, source, structuredClone(tree));
|
|
47178
|
+
const positions = new Map(rawTree.children.map((node) => [`${node.position?.start.offset}:${node.position?.end.offset}`, node]));
|
|
46508
47179
|
for (const [index, node] of tree.children.entries()) {
|
|
46509
47180
|
let start = node.position?.start.offset;
|
|
46510
47181
|
const end = node.position?.end.offset;
|
|
@@ -46516,9 +47187,9 @@ var Preservation = class Preservation {
|
|
|
46516
47187
|
const text = source.slice(start, sourceEnd);
|
|
46517
47188
|
const own = this.baseline.childCount === tree.children.length;
|
|
46518
47189
|
const parsed = own ? this.baseline.type.create(null, [this.baseline.child(index)]) : parse(text);
|
|
46519
|
-
const blockText = parsed.childCount === 1 ? blockForm(ctx, parsed.firstChild) : form(write(ctx, parsed));
|
|
47190
|
+
const blockText = previous?.forms.get(parsed.firstChild) ?? (parsed.childCount === 1 ? blockForm(ctx, parsed.firstChild) : form(write(ctx, parsed)));
|
|
46520
47191
|
if (own) this.forms.set(this.baseline.child(index), blockText);
|
|
46521
|
-
const ast =
|
|
47192
|
+
const ast = positions.get(`${node.position?.start.offset}:${node.position?.end.offset}`) ?? node;
|
|
46522
47193
|
if (parsed.childCount === 1 && parsed.firstChild.type.name === "literal_markdown") literalForms.set(ast, blockText);
|
|
46523
47194
|
this.blocks.push({
|
|
46524
47195
|
start,
|
|
@@ -46555,6 +47226,66 @@ var Preservation = class Preservation {
|
|
|
46555
47226
|
throw new PreservationError("Cannot read Markdown for preservation", { cause });
|
|
46556
47227
|
}
|
|
46557
47228
|
}
|
|
47229
|
+
readEditedSource(source) {
|
|
47230
|
+
if (this.source.startsWith("") || source.startsWith("") || /[\[\]<>%]/.test(this.source) || /[\[\]<>%]/.test(source) || this.blocks.length !== this.baseline.childCount || this.blocks.some((_, index) => !["paragraph", "heading"].includes(this.baseline.child(index).type.name))) return;
|
|
47231
|
+
let prefix = 0, suffix = 0;
|
|
47232
|
+
while (prefix < source.length && prefix < this.source.length && source[prefix] === this.source[prefix]) prefix++;
|
|
47233
|
+
while (suffix < source.length - prefix && suffix < this.source.length - prefix && source[source.length - suffix - 1] === this.source[this.source.length - suffix - 1]) suffix++;
|
|
47234
|
+
const first = Math.max(0, this.blocks.findIndex((block) => block.end >= prefix) - 1);
|
|
47235
|
+
let last = this.blocks.findIndex((block) => block.start > this.source.length - suffix);
|
|
47236
|
+
if (last < 0) last = this.blocks.length - 1;
|
|
47237
|
+
else last = Math.min(this.blocks.length - 1, last + 1);
|
|
47238
|
+
if (!this.blocks[first] || !this.blocks[last]) return;
|
|
47239
|
+
const start = this.blocks[first].start;
|
|
47240
|
+
const end = this.blocks[last].end;
|
|
47241
|
+
const delta = source.length - this.source.length;
|
|
47242
|
+
const nextEnd = end + delta;
|
|
47243
|
+
if (nextEnd < start || prefix < start || this.source.length - suffix > end) return;
|
|
47244
|
+
const part = new Preservation(this.ctx, source.slice(start, nextEnd));
|
|
47245
|
+
if (part.blocks.length !== part.baseline.childCount || part.blocks.some((_, index) => !["paragraph", "heading"].includes(part.baseline.child(index).type.name))) return;
|
|
47246
|
+
const lines = [0];
|
|
47247
|
+
for (const match of source.matchAll(/\r\n|\r|\n/g)) lines.push(match.index + match[0].length);
|
|
47248
|
+
const point = (offset) => {
|
|
47249
|
+
let low = 0, high = lines.length;
|
|
47250
|
+
while (low + 1 < high) {
|
|
47251
|
+
const middle = low + high >> 1;
|
|
47252
|
+
if (lines[middle] <= offset) low = middle;
|
|
47253
|
+
else high = middle;
|
|
47254
|
+
}
|
|
47255
|
+
return {
|
|
47256
|
+
offset,
|
|
47257
|
+
line: low + 1,
|
|
47258
|
+
column: offset - lines[low] + 1
|
|
47259
|
+
};
|
|
47260
|
+
};
|
|
47261
|
+
const shifted = (node, amount) => {
|
|
47262
|
+
const visit = (value) => {
|
|
47263
|
+
if (Array.isArray(value)) return value.map(visit);
|
|
47264
|
+
if (!value || typeof value !== "object") return value;
|
|
47265
|
+
if ("offset" in value && typeof value.offset === "number") return point(value.offset + amount);
|
|
47266
|
+
return Object.fromEntries(Object.entries(value).map(([key, child]) => [key, visit(child)]));
|
|
47267
|
+
};
|
|
47268
|
+
return visit(node);
|
|
47269
|
+
};
|
|
47270
|
+
const splice = (old, fresh) => ({
|
|
47271
|
+
type: "root",
|
|
47272
|
+
children: [
|
|
47273
|
+
...old.children.slice(0, first),
|
|
47274
|
+
...fresh.children.map((node) => shifted(node, start)),
|
|
47275
|
+
...old.children.slice(last + 1).map((node) => shifted(node, delta))
|
|
47276
|
+
]
|
|
47277
|
+
});
|
|
47278
|
+
const children = [];
|
|
47279
|
+
this.baseline.forEach((node, _offset, index) => {
|
|
47280
|
+
if (index === first) part.baseline.forEach((child) => children.push(child));
|
|
47281
|
+
if (index < first || index > last) children.push(node);
|
|
47282
|
+
});
|
|
47283
|
+
return {
|
|
47284
|
+
raw: splice(this.rawTree, part.rawTree),
|
|
47285
|
+
tree: splice(this.sourceTree, part.sourceTree),
|
|
47286
|
+
doc: this.baseline.copy(Fragment.fromArray(children))
|
|
47287
|
+
};
|
|
47288
|
+
}
|
|
46558
47289
|
retainBlock(block, after, canonical, joined = [], reorder) {
|
|
46559
47290
|
const offset = this.source.startsWith("") ? 1 : 0;
|
|
46560
47291
|
const start = block.ast.position?.start.offset;
|
|
@@ -46594,6 +47325,9 @@ var Preservation = class Preservation {
|
|
|
46594
47325
|
const indent = source.slice(source.lastIndexOf("\n", part.from - 1) + 1, part.from);
|
|
46595
47326
|
return (/^[ \t]*$/.test(indent) ? indent : "") + part.text;
|
|
46596
47327
|
}
|
|
47328
|
+
retainLifted(positions, index, after) {
|
|
47329
|
+
return liftedSource(this.around(positions, index).map((block) => block.ast), after, this.source.slice(this.source.startsWith("") ? 1 : 0));
|
|
47330
|
+
}
|
|
46597
47331
|
localEdits(doc) {
|
|
46598
47332
|
if (this.baseline.childCount !== this.blocks.length || doc.childCount !== this.blocks.length || !doc.sameMarkup(this.baseline)) return void 0;
|
|
46599
47333
|
let output = "", previous = 0;
|
|
@@ -46688,7 +47422,7 @@ var Preservation = class Preservation {
|
|
|
46688
47422
|
static plainInline(node) {
|
|
46689
47423
|
let plain = true;
|
|
46690
47424
|
node.descendants((child) => {
|
|
46691
|
-
if (child.isInline && !child.isText && child.type.name
|
|
47425
|
+
if (child.isInline && !child.isText && !["hardbreak", "footnote_reference"].includes(child.type.name)) plain = false;
|
|
46692
47426
|
return plain;
|
|
46693
47427
|
});
|
|
46694
47428
|
return plain;
|
|
@@ -46972,6 +47706,12 @@ var Preservation = class Preservation {
|
|
|
46972
47706
|
const block = position == null ? void 0 : this.blocks[position];
|
|
46973
47707
|
if (index === 0) return position === 0 && block ? this.source.slice(0, block.start) : this.source.startsWith("") ? "" : "";
|
|
46974
47708
|
const previous = positions[index - 1];
|
|
47709
|
+
if (previous === this.blocks.length - 1 && position == null) {
|
|
47710
|
+
const ending = this.source.slice(this.blocks[previous].end);
|
|
47711
|
+
const lines = ending.replace(/\r\n?/g, "\n");
|
|
47712
|
+
if (/\n[ \t]*\n/.test(lines)) return ending + (lines.endsWith("\n") ? "" : this.lineEnding);
|
|
47713
|
+
return ending + this.lineEnding.repeat(lines.endsWith("\n") ? 1 : 2);
|
|
47714
|
+
}
|
|
46975
47715
|
return previous != null && position === previous + 1 && block ? this.source.slice(this.blocks[previous].end, block.start) : this.lineEnding.repeat(2);
|
|
46976
47716
|
}
|
|
46977
47717
|
build(doc, positions, current, carried, from, to, canonical, tree) {
|
|
@@ -47008,7 +47748,7 @@ var Preservation = class Preservation {
|
|
|
47008
47748
|
const kind = block && block.form === text && !carried.within.has(index) ? position == null ? "moved" : "unchanged" : block && tree && position != null ? "edited" : "canonical";
|
|
47009
47749
|
kept.push(kind);
|
|
47010
47750
|
const node = tree ? positionalNode(tree.raw, transformed(index)) : void 0;
|
|
47011
|
-
pieces.push(kind === "unchanged" || kind === "moved" ? this.source.slice(block.start, block.end) : kind === "edited" ? this.retainingForms(block, doc.child(index), () => this.retainBlock(block, node, canonical, this.around(positions, index).filter((other) => !paired.has(other) && other.ast.type === block.ast.type).flatMap((other) => other.ast.children ?? []), carried.children ? this.carriedChildren(doc.child(index), position) : void 0)) : (node && this.retainPart(positions, index, node, canonical, taken)) ?? restoreCodeEndings(this.ctx, doc.type.create(null, [doc.child(index)]), withEnding(text, this.lineEnding)));
|
|
47751
|
+
pieces.push(kind === "unchanged" || kind === "moved" ? this.source.slice(block.start, block.end) : kind === "edited" ? this.retainingForms(block, doc.child(index), () => this.retainBlock(block, node, canonical, this.around(positions, index).filter((other) => !paired.has(other) && other.ast.type === block.ast.type).flatMap((other) => other.ast.children ?? []), carried.children ? this.carriedChildren(doc.child(index), position) : void 0)) : (node && (this.retainPart(positions, index, node, canonical, taken) ?? this.retainLifted(positions, index, node))) ?? restoreCodeEndings(this.ctx, doc.type.create(null, [doc.child(index)]), withEnding(text, this.lineEnding)));
|
|
47012
47752
|
}
|
|
47013
47753
|
return {
|
|
47014
47754
|
gaps,
|
|
@@ -47544,23 +48284,6 @@ function completedAngle(tr, chars, from, to) {
|
|
|
47544
48284
|
form: "angle"
|
|
47545
48285
|
})).removeStoredMark(tr.doc.type.schema.marks.link);
|
|
47546
48286
|
}
|
|
47547
|
-
function closeAngleEnds(tr, transactions) {
|
|
47548
|
-
const steps = transactions.flatMap((transaction) => transaction.steps.map((step, index) => ({
|
|
47549
|
-
doc: transaction.docs[index],
|
|
47550
|
-
map: step.getMap()
|
|
47551
|
-
})));
|
|
47552
|
-
steps.forEach(({ doc, map }, index) => {
|
|
47553
|
-
const remaining = new Mapping(steps.slice(index + 1).map(({ map }) => map));
|
|
47554
|
-
map.forEach((from, to, start, end) => {
|
|
47555
|
-
if (from !== to || start === end) return;
|
|
47556
|
-
const at = doc.resolve(from);
|
|
47557
|
-
const before = at.nodeBefore?.marks.find((mark) => mark.attrs.form === "angle");
|
|
47558
|
-
const after = at.nodeAfter?.marks.find((mark) => mark.attrs.form === "angle");
|
|
47559
|
-
if (before && after && before.eq(after)) return;
|
|
47560
|
-
for (const mark of [before, after]) if (mark) tr.removeMark(remaining.map(start, 1), remaining.map(end, -1), mark);
|
|
47561
|
-
});
|
|
47562
|
-
});
|
|
47563
|
-
}
|
|
47564
48287
|
function codeAngles(tr, edited) {
|
|
47565
48288
|
const spans = [];
|
|
47566
48289
|
for (const block of edited) tr.doc.nodesBetween(block.pos, block.pos + block.block.nodeSize, (node, pos) => {
|
|
@@ -47769,10 +48492,7 @@ var autolinkLiterals = $prose((ctx) => new Plugin({
|
|
|
47769
48492
|
if (!transactions.some((tr) => tr.docChanged)) return null;
|
|
47770
48493
|
const base = newState.tr;
|
|
47771
48494
|
const written = transactions.every(isWrittenEdit);
|
|
47772
|
-
if (written)
|
|
47773
|
-
closeAngleEnds(base, transactions);
|
|
47774
|
-
codeAngles(base, editedBlocks(oldState.doc, base.doc));
|
|
47775
|
-
}
|
|
48495
|
+
if (written) codeAngles(base, editedBlocks(oldState.doc, base.doc));
|
|
47776
48496
|
let edited = editedBlocks(oldState.doc, base.doc);
|
|
47777
48497
|
if (written && edited.length === 1) {
|
|
47778
48498
|
const { pos, block, from, to } = edited[0];
|
|
@@ -48024,81 +48744,6 @@ function normalizeTableColumnAlignment(element) {
|
|
|
48024
48744
|
return normalizeTableAlignment(header ?? element);
|
|
48025
48745
|
}
|
|
48026
48746
|
//#endregion
|
|
48027
|
-
//#region src/parser.ts
|
|
48028
|
-
/**
|
|
48029
|
-
* Milkdown's parser state, except that it throws where Milkdown would drop content. Milkdown
|
|
48030
|
-
* catches the failure to build a node (`createNodeInParserFail`), logs it and carries on without
|
|
48031
|
-
* the node and everything inside it, so the document it returns can silently lack part of its
|
|
48032
|
-
* source.
|
|
48033
|
-
*/
|
|
48034
|
-
var CheckedParserState = class extends ParserState {
|
|
48035
|
-
constructor(schema) {
|
|
48036
|
-
super(schema);
|
|
48037
|
-
const closeNode = this.closeNode;
|
|
48038
|
-
const addNode = this.addNode;
|
|
48039
|
-
const unbuildable = (type, attrs, content) => {
|
|
48040
|
-
try {
|
|
48041
|
-
return !type.createAndFill(attrs, content);
|
|
48042
|
-
} catch {
|
|
48043
|
-
return true;
|
|
48044
|
-
}
|
|
48045
|
-
};
|
|
48046
|
-
this.closeNode = () => {
|
|
48047
|
-
const element = this.top();
|
|
48048
|
-
if (!element || this.size() < 2 || unbuildable(element.type, element.attrs, element.content)) throw new Error(`Cannot build ${element?.type.name ?? "a node"}`);
|
|
48049
|
-
return closeNode();
|
|
48050
|
-
};
|
|
48051
|
-
this.addNode = (type, attrs, content) => {
|
|
48052
|
-
if (!this.top() || unbuildable(type, attrs, content)) throw new Error(`Cannot build ${type.name}`);
|
|
48053
|
-
return addNode(type, attrs, content);
|
|
48054
|
-
};
|
|
48055
|
-
}
|
|
48056
|
-
};
|
|
48057
|
-
/** The document, or undefined when Milkdown cannot build all of it. */
|
|
48058
|
-
function build(schema, tree) {
|
|
48059
|
-
try {
|
|
48060
|
-
return new CheckedParserState(schema).next(tree).toDoc();
|
|
48061
|
-
} catch {
|
|
48062
|
-
return;
|
|
48063
|
-
}
|
|
48064
|
-
}
|
|
48065
|
-
/**
|
|
48066
|
-
* Parses Markdown as Milkdown does, but never returns a document that lacks part of its source.
|
|
48067
|
-
* A top-level block that cannot be built is kept as its literal source, as unsupported syntax is,
|
|
48068
|
-
* so the rest of the document stays editable; when that is not enough, it throws `preservation`.
|
|
48069
|
-
*/
|
|
48070
|
-
function parseMarkdown(schema, remark, markdown) {
|
|
48071
|
-
const tree = remark.runSync(remark.parse(markdown), markdown);
|
|
48072
|
-
const doc = build(schema, tree);
|
|
48073
|
-
if (doc) return doc;
|
|
48074
|
-
const source = markdown.replace(/^\uFEFF/, "");
|
|
48075
|
-
tree.children = tree.children.map((node) => {
|
|
48076
|
-
if (build(schema, {
|
|
48077
|
-
type: "root",
|
|
48078
|
-
children: [node]
|
|
48079
|
-
})) return node;
|
|
48080
|
-
const start = node.position?.start.offset;
|
|
48081
|
-
const end = node.position?.end.offset;
|
|
48082
|
-
if (start == null || end == null) return node;
|
|
48083
|
-
const value = source.slice(start, end);
|
|
48084
|
-
return {
|
|
48085
|
-
type: "inkkitLiteral",
|
|
48086
|
-
value,
|
|
48087
|
-
comments: literalCommentSpans(value),
|
|
48088
|
-
position: node.position
|
|
48089
|
-
};
|
|
48090
|
-
});
|
|
48091
|
-
const kept = build(schema, tree);
|
|
48092
|
-
if (kept) return kept;
|
|
48093
|
-
throw new InkKitError("preservation", "The Markdown cannot be shown without losing part of it");
|
|
48094
|
-
}
|
|
48095
|
-
/** Replaces Milkdown's parser with `parseMarkdown`, for every caller of `parserCtx`. */
|
|
48096
|
-
var checkedParser = (ctx) => async () => {
|
|
48097
|
-
await ctx.wait(ParserReady);
|
|
48098
|
-
const schema = ctx.get(schemaCtx);
|
|
48099
|
-
ctx.set(parserCtx, (markdown) => parseMarkdown(schema, ctx.get(remarkCtx), markdown));
|
|
48100
|
-
};
|
|
48101
|
-
//#endregion
|
|
48102
48747
|
//#region src/callouts.ts
|
|
48103
48748
|
var kinds = /* @__PURE__ */ new Set([
|
|
48104
48749
|
"NOTE",
|
|
@@ -48141,7 +48786,8 @@ function remarkCallouts() {
|
|
|
48141
48786
|
const visit = (node) => {
|
|
48142
48787
|
if (node.type === "blockquote") {
|
|
48143
48788
|
const start = node.position?.start.offset, end = node.position?.end.offset;
|
|
48144
|
-
const
|
|
48789
|
+
const gutter = start == null ? "" : gutterAt(source, start);
|
|
48790
|
+
const raw = start == null || end == null ? "" : source.slice(start, end).replace(/(\r?\n)([^\r\n]*)/g, (line, eol, text) => gutter && text.startsWith(gutter) ? eol + text.slice(gutter.length) : line);
|
|
48145
48791
|
const header = /^>[ \t]*([\s\S]*?)(?:\r?\n|$)/.exec(raw)?.[1] ?? "";
|
|
48146
48792
|
if (header.startsWith("[!")) {
|
|
48147
48793
|
const match = /^(\[!([A-Za-z]+)\])([+-]?)(?:[ \t]+([^\r\n]*))?$/.exec(header);
|
|
@@ -48313,7 +48959,7 @@ var calloutView = $prose((ctx) => new Plugin({
|
|
|
48313
48959
|
const render = () => {
|
|
48314
48960
|
title.textContent = node.attrs.title || String(node.attrs.kind).toLowerCase().replace(/^./, (letter) => letter.toUpperCase());
|
|
48315
48961
|
dom.setAttribute("data-inkkit-folded", String(folded));
|
|
48316
|
-
view.dom.dispatchEvent(new Event(
|
|
48962
|
+
view.dom.dispatchEvent(new Event(mediaPolicyEvent));
|
|
48317
48963
|
button.hidden = !node.attrs.fold;
|
|
48318
48964
|
button.setAttribute("aria-expanded", String(!folded));
|
|
48319
48965
|
button.setAttribute("aria-label", `${folded ? editorLabels(ctx).expandCallout : editorLabels(ctx).collapseCallout} ${title.textContent}`);
|
|
@@ -50080,12 +50726,50 @@ function writesBare(node, index, ancestors) {
|
|
|
50080
50726
|
return side(-1) && side(1);
|
|
50081
50727
|
}
|
|
50082
50728
|
var bareLinks = /* @__PURE__ */ new WeakSet();
|
|
50729
|
+
function linkFormatting(node) {
|
|
50730
|
+
const plain = node.type === "link" && !formOf(node) || node.type === "linkReference" && node.referenceType === "full";
|
|
50731
|
+
const [inner] = plain ? node.children : [];
|
|
50732
|
+
return plain && node.children.length === 1 && inner && wrappers.has(inner.type) ? inner : void 0;
|
|
50733
|
+
}
|
|
50734
|
+
function shareFormatting(children) {
|
|
50735
|
+
const same = (left, right) => {
|
|
50736
|
+
const { children: _left, position: _a, ...leftRest } = left;
|
|
50737
|
+
const { children: _right, position: _b, ...rightRest } = right;
|
|
50738
|
+
return JSON.stringify(leftRest) === JSON.stringify(rightRest);
|
|
50739
|
+
};
|
|
50740
|
+
for (let index = 0; index < children.length; index++) {
|
|
50741
|
+
const child = children[index];
|
|
50742
|
+
const formatting = linkFormatting(child);
|
|
50743
|
+
if (!formatting) continue;
|
|
50744
|
+
const link = {
|
|
50745
|
+
...child,
|
|
50746
|
+
children: formatting.children
|
|
50747
|
+
};
|
|
50748
|
+
const previous = children[index - 1];
|
|
50749
|
+
const next = children[index + 1];
|
|
50750
|
+
const before = previous && same(previous, formatting);
|
|
50751
|
+
const after = next && same(next, formatting);
|
|
50752
|
+
if (!before && !after) continue;
|
|
50753
|
+
const merged = {
|
|
50754
|
+
...formatting,
|
|
50755
|
+
children: [
|
|
50756
|
+
...before ? previous.children : [],
|
|
50757
|
+
link,
|
|
50758
|
+
...after ? next.children : []
|
|
50759
|
+
]
|
|
50760
|
+
};
|
|
50761
|
+
const from = before ? index - 1 : index;
|
|
50762
|
+
children.splice(from, 1 + Number(before) + Number(after), merged);
|
|
50763
|
+
index = from - 1;
|
|
50764
|
+
}
|
|
50765
|
+
}
|
|
50083
50766
|
var root = (node, parent, state, info) => {
|
|
50084
50767
|
bareLinks = /* @__PURE__ */ new WeakSet();
|
|
50085
50768
|
const empty = (child) => child.type === "text" && child.value === "" || wrappers.has(child.type) && "children" in child && child.children.every(empty);
|
|
50086
50769
|
const visit = (current, ancestors) => {
|
|
50087
50770
|
if (current.children.some((child) => empty(child))) current.children = current.children.filter((child) => !empty(child));
|
|
50088
50771
|
const children = current.children;
|
|
50772
|
+
shareFormatting(children);
|
|
50089
50773
|
children.forEach((child, index) => {
|
|
50090
50774
|
if (child.type === "link" && formOf(child)) {
|
|
50091
50775
|
const outside = formattedOutside(child);
|
|
@@ -50306,6 +50990,16 @@ var breaksWithoutMarks = $prose((ctx) => new Plugin({
|
|
|
50306
50990
|
}
|
|
50307
50991
|
}));
|
|
50308
50992
|
var remarkLinkFormsPlugin = $remark("inkkitLinkForms", () => remarkLinkForms);
|
|
50993
|
+
var remarkFileSourcesPlugin = $remark("inkkitFileSources", () => remarkFileSources);
|
|
50994
|
+
var imageWriter = (ctx) => async () => {
|
|
50995
|
+
await ctx.wait(SerializerReady);
|
|
50996
|
+
const schema = ctx.get(schemaCtx);
|
|
50997
|
+
setImageWriter(schema, (node) => {
|
|
50998
|
+
node = node.mark([]);
|
|
50999
|
+
const block = node.isBlock ? node : schema.nodes.paragraph.create(null, node);
|
|
51000
|
+
return ctx.get(serializerCtx)(schema.topNodeType.create(null, block)).replace(/\n+$/, "");
|
|
51001
|
+
});
|
|
51002
|
+
};
|
|
50309
51003
|
var preserveSpacerParagraphs = paragraphSchema.extendSchema((base) => (ctx) => {
|
|
50310
51004
|
const schema = base(ctx);
|
|
50311
51005
|
return {
|
|
@@ -50436,7 +51130,16 @@ var normalizedImages = imageSchema.extendSchema((base) => (ctx) => {
|
|
|
50436
51130
|
...schema.toMarkdown,
|
|
50437
51131
|
runner(state, node) {
|
|
50438
51132
|
const raw = namedFileMarkdown(node, Boolean(node.attrs.inkkitFileInTable));
|
|
50439
|
-
if (raw == null)
|
|
51133
|
+
if (raw == null) {
|
|
51134
|
+
state.addNode("image", void 0, void 0, {
|
|
51135
|
+
url: node.attrs.src,
|
|
51136
|
+
alt: node.attrs.alt,
|
|
51137
|
+
title: node.attrs.title || null,
|
|
51138
|
+
inkkitFileSource: authoredFileSource(node),
|
|
51139
|
+
inkkitFileInTable: node.attrs.inkkitFileInTable
|
|
51140
|
+
});
|
|
51141
|
+
return;
|
|
51142
|
+
}
|
|
50440
51143
|
state.addNode("image", void 0, void 0, {
|
|
50441
51144
|
url: node.attrs.src,
|
|
50442
51145
|
alt: node.attrs.alt,
|
|
@@ -50444,7 +51147,7 @@ var normalizedImages = imageSchema.extendSchema((base) => (ctx) => {
|
|
|
50444
51147
|
inkkitFileRaw: raw,
|
|
50445
51148
|
inkkitFileTarget: node.attrs.inkkitFileTarget,
|
|
50446
51149
|
inkkitFileFragment: node.attrs.inkkitFileFragment,
|
|
50447
|
-
inkkitFileWidth:
|
|
51150
|
+
inkkitFileWidth: fileFields(node).width ?? null,
|
|
50448
51151
|
inkkitFileInTable: node.attrs.inkkitFileInTable
|
|
50449
51152
|
});
|
|
50450
51153
|
}
|
|
@@ -50557,6 +51260,7 @@ function createDialect(images, wikiLinks = false, files = false) {
|
|
|
50557
51260
|
remarkCodeFences,
|
|
50558
51261
|
remarkReferencesPlugin,
|
|
50559
51262
|
remarkLinkFormsPlugin,
|
|
51263
|
+
remarkFileSourcesPlugin,
|
|
50560
51264
|
remarkCalloutsPlugin,
|
|
50561
51265
|
remarkCommentsPlugin,
|
|
50562
51266
|
wikiLinks || files ? linkedSyntax(wikiLinks, files) : [],
|
|
@@ -50576,6 +51280,7 @@ function createDialect(images, wikiLinks = false, files = false) {
|
|
|
50576
51280
|
wikiLinkComposition,
|
|
50577
51281
|
wikiLinkInputRule
|
|
50578
51282
|
] : [],
|
|
51283
|
+
wikiLinks || files ? referenceTableContext : [],
|
|
50579
51284
|
callouts,
|
|
50580
51285
|
comments,
|
|
50581
51286
|
hiddenCommentEditing,
|
|
@@ -50603,7 +51308,8 @@ function createDialect(images, wikiLinks = false, files = false) {
|
|
|
50603
51308
|
remarkDialectPlugin,
|
|
50604
51309
|
tables,
|
|
50605
51310
|
literalBlock,
|
|
50606
|
-
checkedParser
|
|
51311
|
+
checkedParser,
|
|
51312
|
+
imageWriter
|
|
50607
51313
|
].flat();
|
|
50608
51314
|
}
|
|
50609
51315
|
createDialect(false);
|
|
@@ -51106,8 +51812,7 @@ function modeSelectionMap(ctx, source, doc) {
|
|
|
51106
51812
|
if (at >= 0) append(value, Array.from({ length: value.length + 1 }, (_, index) => start + bom + at + index));
|
|
51107
51813
|
}
|
|
51108
51814
|
};
|
|
51109
|
-
|
|
51110
|
-
processor.runSync(processor.parse(source), { value: source }).children.forEach((node) => visit(node));
|
|
51815
|
+
Preservation.read(ctx, source).sourceTree.children.forEach((node) => visit(node));
|
|
51111
51816
|
let cursor = 0;
|
|
51112
51817
|
doc.descendants((node, position) => {
|
|
51113
51818
|
if ([
|
|
@@ -51315,7 +52020,7 @@ var ImageView = class {
|
|
|
51315
52020
|
view;
|
|
51316
52021
|
getPos;
|
|
51317
52022
|
adapter;
|
|
51318
|
-
|
|
52023
|
+
host;
|
|
51319
52024
|
canMutate;
|
|
51320
52025
|
dom;
|
|
51321
52026
|
/** The card or picture, which a standalone image's block row holds. */
|
|
@@ -51327,22 +52032,31 @@ var ImageView = class {
|
|
|
51327
52032
|
stopResize;
|
|
51328
52033
|
resolution;
|
|
51329
52034
|
previewFailed = false;
|
|
51330
|
-
|
|
52035
|
+
suspended = false;
|
|
52036
|
+
/** Present when the host sets `files`, which then shows every image. */
|
|
52037
|
+
runtime;
|
|
52038
|
+
constructor(node, view, getPos, adapter, host, files, cache, canMutate = () => true) {
|
|
51331
52039
|
this.node = node;
|
|
51332
52040
|
this.view = view;
|
|
51333
52041
|
this.getPos = getPos;
|
|
51334
52042
|
this.adapter = adapter;
|
|
51335
|
-
this.
|
|
52043
|
+
this.host = host;
|
|
51336
52044
|
this.canMutate = canMutate;
|
|
52045
|
+
const runtime = files && host && {
|
|
52046
|
+
...host,
|
|
52047
|
+
adapter: files
|
|
52048
|
+
};
|
|
52049
|
+
this.runtime = runtime;
|
|
51337
52050
|
this.element = document.createElement("span");
|
|
51338
52051
|
this.element.className = "inkkit-image";
|
|
52052
|
+
this.element.addEventListener("contextmenu", this.contextMenu);
|
|
51339
52053
|
if (node.isBlock) {
|
|
51340
52054
|
this.dom = document.createElement("div");
|
|
51341
52055
|
this.dom.className = "inkkit-image-block";
|
|
51342
52056
|
this.dom.append(this.element);
|
|
51343
52057
|
} else this.dom = this.element;
|
|
51344
52058
|
this.view.dom.addEventListener("inkkit-cancel-resize", this.cancelResize);
|
|
51345
|
-
this.view.dom.addEventListener(
|
|
52059
|
+
this.view.dom.addEventListener(mediaPolicyEvent, this.mediaPolicy);
|
|
51346
52060
|
if (runtime) {
|
|
51347
52061
|
this.resolution = new FileResolution({
|
|
51348
52062
|
...runtime,
|
|
@@ -51350,7 +52064,7 @@ var ImageView = class {
|
|
|
51350
52064
|
}, () => {
|
|
51351
52065
|
this.previewFailed = false;
|
|
51352
52066
|
this.render();
|
|
51353
|
-
});
|
|
52067
|
+
}, cache);
|
|
51354
52068
|
this.resolution.update(this.reference());
|
|
51355
52069
|
}
|
|
51356
52070
|
this.render();
|
|
@@ -51379,15 +52093,37 @@ var ImageView = class {
|
|
|
51379
52093
|
ignoreMutation() {
|
|
51380
52094
|
return true;
|
|
51381
52095
|
}
|
|
51382
|
-
mediaPolicy = () => {
|
|
52096
|
+
mediaPolicy = (event) => {
|
|
51383
52097
|
if (!this.runtime) return;
|
|
52098
|
+
const refresh = refreshOf(event);
|
|
52099
|
+
if (refresh) {
|
|
52100
|
+
if (!refreshes(refresh, this.reference().target)) return;
|
|
52101
|
+
if (!this.active()) {
|
|
52102
|
+
this.resolution?.invalidate();
|
|
52103
|
+
return;
|
|
52104
|
+
}
|
|
52105
|
+
if (this.previewFailed) this.resolution?.retry();
|
|
52106
|
+
else this.resolution?.refresh();
|
|
52107
|
+
return;
|
|
52108
|
+
}
|
|
51384
52109
|
if (!this.active()) {
|
|
52110
|
+
if (this.suspended) return;
|
|
52111
|
+
this.suspended = true;
|
|
51385
52112
|
this.stopResize?.();
|
|
51386
52113
|
this.stopResize = void 0;
|
|
51387
|
-
this.resolution?.
|
|
51388
|
-
this.
|
|
51389
|
-
|
|
51390
|
-
|
|
52114
|
+
this.resolution?.suspend();
|
|
52115
|
+
if (this.media || this.pdf) this.render();
|
|
52116
|
+
} else {
|
|
52117
|
+
const suspended = this.suspended;
|
|
52118
|
+
this.suspended = false;
|
|
52119
|
+
this.resolution?.update(this.reference());
|
|
52120
|
+
const state = this.resolution?.state;
|
|
52121
|
+
if (suspended && state?.status === "resolved" && [
|
|
52122
|
+
"audio",
|
|
52123
|
+
"video",
|
|
52124
|
+
"pdf"
|
|
52125
|
+
].includes(state.presentation.kind)) this.render();
|
|
52126
|
+
}
|
|
51391
52127
|
};
|
|
51392
52128
|
cancelResize = () => {
|
|
51393
52129
|
if (!this.stopResize) return;
|
|
@@ -51408,7 +52144,7 @@ var ImageView = class {
|
|
|
51408
52144
|
}
|
|
51409
52145
|
destroy() {
|
|
51410
52146
|
this.view.dom.removeEventListener("inkkit-cancel-resize", this.cancelResize);
|
|
51411
|
-
this.view.dom.removeEventListener(
|
|
52147
|
+
this.view.dom.removeEventListener(mediaPolicyEvent, this.mediaPolicy);
|
|
51412
52148
|
this.stopResize?.();
|
|
51413
52149
|
this.stopResize = void 0;
|
|
51414
52150
|
this.resolution?.destroy();
|
|
@@ -51437,6 +52173,37 @@ var ImageView = class {
|
|
|
51437
52173
|
report(error) {
|
|
51438
52174
|
this.runtime?.error?.(coded(error, "file-unavailable"));
|
|
51439
52175
|
}
|
|
52176
|
+
/** Hands the request to the host's hook, which replaces the web view's own menu. A file card
|
|
52177
|
+
* uses `FileAdapter.contextMenu`; any other image selects itself and uses
|
|
52178
|
+
* `ImageAdapter.contextMenu`. */
|
|
52179
|
+
contextMenu = (event) => {
|
|
52180
|
+
const { host, runtime, adapter } = this;
|
|
52181
|
+
if (!host?.active() || !(runtime ? runtime.adapter.contextMenu : adapter?.contextMenu)) return;
|
|
52182
|
+
const captured = host.capture();
|
|
52183
|
+
if (!captured.isCurrent()) return;
|
|
52184
|
+
event.preventDefault();
|
|
52185
|
+
const point = {
|
|
52186
|
+
clientX: event.clientX,
|
|
52187
|
+
clientY: event.clientY
|
|
52188
|
+
};
|
|
52189
|
+
try {
|
|
52190
|
+
if (runtime) runtime.adapter.contextMenu?.(this.reference(), point, captured.context);
|
|
52191
|
+
else {
|
|
52192
|
+
this.select();
|
|
52193
|
+
adapter?.contextMenu?.(String(this.node.attrs.src ?? ""), point, captured.context);
|
|
52194
|
+
}
|
|
52195
|
+
} catch (error) {
|
|
52196
|
+
if (runtime) this.report(error);
|
|
52197
|
+
else host.error?.(coded(error, "image-unavailable"));
|
|
52198
|
+
}
|
|
52199
|
+
};
|
|
52200
|
+
select() {
|
|
52201
|
+
const pos = this.getPos();
|
|
52202
|
+
if (pos == null || this.view.composing) return;
|
|
52203
|
+
const { state } = this.view;
|
|
52204
|
+
const selection = NodeSelection.create(state.doc, pos);
|
|
52205
|
+
if (!state.selection.eq(selection)) this.view.dispatch(state.tr.setSelection(selection));
|
|
52206
|
+
}
|
|
51440
52207
|
card(label, status, retry = false) {
|
|
51441
52208
|
const footer = document.createElement("span");
|
|
51442
52209
|
footer.className = "inkkit-file-footer";
|
|
@@ -51485,20 +52252,6 @@ var ImageView = class {
|
|
|
51485
52252
|
this.image = void 0;
|
|
51486
52253
|
if (this.runtime) {
|
|
51487
52254
|
this.element.classList.add("inkkit-file");
|
|
51488
|
-
this.element.oncontextmenu = (event) => {
|
|
51489
|
-
if (!this.runtime?.adapter.contextMenu || !this.active()) return;
|
|
51490
|
-
const captured = this.runtime.capture();
|
|
51491
|
-
if (!captured.isCurrent()) return;
|
|
51492
|
-
event.preventDefault();
|
|
51493
|
-
try {
|
|
51494
|
-
this.runtime.adapter.contextMenu(this.reference(), {
|
|
51495
|
-
clientX: event.clientX,
|
|
51496
|
-
clientY: event.clientY
|
|
51497
|
-
}, captured.context);
|
|
51498
|
-
} catch (error) {
|
|
51499
|
-
this.report(error);
|
|
51500
|
-
}
|
|
51501
|
-
};
|
|
51502
52255
|
const state = this.resolution.state;
|
|
51503
52256
|
const label = state.status === "resolved" ? state.presentation.label || alt || reference.reference : alt || reference.reference;
|
|
51504
52257
|
this.element.setAttribute("role", "group");
|
|
@@ -51518,6 +52271,14 @@ var ImageView = class {
|
|
|
51518
52271
|
return;
|
|
51519
52272
|
}
|
|
51520
52273
|
const presentation = state.presentation;
|
|
52274
|
+
if (!this.active() && [
|
|
52275
|
+
"audio",
|
|
52276
|
+
"video",
|
|
52277
|
+
"pdf"
|
|
52278
|
+
].includes(presentation.kind)) {
|
|
52279
|
+
this.card(label);
|
|
52280
|
+
return;
|
|
52281
|
+
}
|
|
51521
52282
|
if (presentation.kind === "missing") this.card(label, this.runtime.labels.fileMissing, true);
|
|
51522
52283
|
else if (presentation.kind === "error") this.card(label, presentation.message || this.runtime.labels.fileError, true);
|
|
51523
52284
|
else if (presentation.kind === "image") {
|
|
@@ -51647,8 +52408,9 @@ function openArrow() {
|
|
|
51647
52408
|
icon.append(path);
|
|
51648
52409
|
return icon;
|
|
51649
52410
|
}
|
|
51650
|
-
function imageView(adapter,
|
|
51651
|
-
const
|
|
52411
|
+
function imageView(adapter, host, files, canMutate = () => true) {
|
|
52412
|
+
const cache = new FilePresentationCache();
|
|
52413
|
+
const view = (schema) => $view(schema.node, () => (node, view, getPos) => new ImageView(node, view, getPos, adapter, host, files, cache, canMutate));
|
|
51652
52414
|
return [view(imageSchema), view(imageBlockSchema)];
|
|
51653
52415
|
}
|
|
51654
52416
|
//#endregion
|
|
@@ -51660,26 +52422,29 @@ function wikiLinkView(adapter, runtime) {
|
|
|
51660
52422
|
dom.className = "inkkit-wiki-link";
|
|
51661
52423
|
dom.setAttribute("role", "link");
|
|
51662
52424
|
dom.tabIndex = 0;
|
|
51663
|
-
const reference = () => (
|
|
51664
|
-
target: String(current.attrs.target),
|
|
51665
|
-
...current.attrs.fragment ? { fragment: String(current.attrs.fragment) } : {},
|
|
51666
|
-
label: String(current.attrs.label)
|
|
51667
|
-
});
|
|
52425
|
+
const reference = () => wikiReference(current);
|
|
51668
52426
|
const report = (error) => runtime.error?.(coded(error, "file-unavailable"));
|
|
51669
52427
|
const render = () => {
|
|
51670
|
-
|
|
51671
|
-
dom.
|
|
51672
|
-
|
|
51673
|
-
if (
|
|
51674
|
-
|
|
51675
|
-
|
|
51676
|
-
|
|
51677
|
-
|
|
51678
|
-
|
|
51679
|
-
|
|
52428
|
+
const { label } = reference();
|
|
52429
|
+
if (dom.textContent !== label) dom.textContent = label;
|
|
52430
|
+
let missing = false;
|
|
52431
|
+
if (runtime.active()) {
|
|
52432
|
+
const captured = runtime.capture();
|
|
52433
|
+
try {
|
|
52434
|
+
const result = adapter.resolve?.(reference(), captured.context);
|
|
52435
|
+
missing = captured.isCurrent() && Boolean(result?.missing);
|
|
52436
|
+
} catch (error) {
|
|
52437
|
+
report(error);
|
|
51680
52438
|
}
|
|
51681
|
-
}
|
|
51682
|
-
|
|
52439
|
+
}
|
|
52440
|
+
if (missing) {
|
|
52441
|
+
dom.dataset.missing = "true";
|
|
52442
|
+
dom.title = runtime.labels.wikiMissing;
|
|
52443
|
+
dom.setAttribute("aria-description", runtime.labels.wikiMissing);
|
|
52444
|
+
} else {
|
|
52445
|
+
dom.removeAttribute("data-missing");
|
|
52446
|
+
dom.removeAttribute("title");
|
|
52447
|
+
dom.removeAttribute("aria-description");
|
|
51683
52448
|
}
|
|
51684
52449
|
};
|
|
51685
52450
|
const open = (event) => {
|
|
@@ -51698,7 +52463,11 @@ function wikiLinkView(adapter, runtime) {
|
|
|
51698
52463
|
dom.addEventListener("keydown", (event) => {
|
|
51699
52464
|
if (event.key === "Enter" || event.key === " ") open(event);
|
|
51700
52465
|
});
|
|
51701
|
-
|
|
52466
|
+
const policy = (event) => {
|
|
52467
|
+
const refresh = refreshOf(event);
|
|
52468
|
+
if (!refresh || refreshes(refresh, String(current.attrs.target))) render();
|
|
52469
|
+
};
|
|
52470
|
+
view.dom.addEventListener(mediaPolicyEvent, policy);
|
|
51702
52471
|
render();
|
|
51703
52472
|
return {
|
|
51704
52473
|
dom,
|
|
@@ -51713,7 +52482,7 @@ function wikiLinkView(adapter, runtime) {
|
|
|
51713
52482
|
},
|
|
51714
52483
|
ignoreMutation: () => true,
|
|
51715
52484
|
destroy() {
|
|
51716
|
-
view.dom.removeEventListener(
|
|
52485
|
+
view.dom.removeEventListener(mediaPolicyEvent, policy);
|
|
51717
52486
|
}
|
|
51718
52487
|
};
|
|
51719
52488
|
});
|
|
@@ -52784,7 +53553,7 @@ function readableProjection(doc) {
|
|
|
52784
53553
|
}
|
|
52785
53554
|
if (name === "image_block") {
|
|
52786
53555
|
block(position);
|
|
52787
|
-
append(
|
|
53556
|
+
append(fileFields(node).label || "Image", position, position + node.nodeSize, "embed");
|
|
52788
53557
|
return false;
|
|
52789
53558
|
}
|
|
52790
53559
|
if (node.isTextblock) {
|
|
@@ -52801,7 +53570,7 @@ function readableProjection(doc) {
|
|
|
52801
53570
|
return false;
|
|
52802
53571
|
}
|
|
52803
53572
|
if (name === "image" || name === "footnote_reference" || name === "inkkit_wiki_link") {
|
|
52804
|
-
append(name === "image" ?
|
|
53573
|
+
append(name === "image" ? fileFields(node).label || "Image" : name === "inkkit_wiki_link" ? String(node.attrs.label || node.attrs.target || "Link") : `[${node.attrs.label}]`, position, position + node.nodeSize, "embed");
|
|
52805
53574
|
return false;
|
|
52806
53575
|
}
|
|
52807
53576
|
return true;
|
|
@@ -54053,6 +54822,96 @@ function htmlGrid(schema, html) {
|
|
|
54053
54822
|
};
|
|
54054
54823
|
}
|
|
54055
54824
|
//#endregion
|
|
54825
|
+
//#region src/image-identity.ts
|
|
54826
|
+
var pngSignature = [
|
|
54827
|
+
137,
|
|
54828
|
+
80,
|
|
54829
|
+
78,
|
|
54830
|
+
71,
|
|
54831
|
+
13,
|
|
54832
|
+
10,
|
|
54833
|
+
26,
|
|
54834
|
+
10
|
|
54835
|
+
];
|
|
54836
|
+
function format(bytes) {
|
|
54837
|
+
if (bytes.length >= 8 && pngSignature.every((value, index) => bytes[index] === value)) return "png";
|
|
54838
|
+
if (bytes.length >= 8 && (bytes[0] === 73 && bytes[1] === 73 && bytes[2] === 42 && bytes[3] === 0 || bytes[0] === 77 && bytes[1] === 77 && bytes[2] === 0 && bytes[3] === 42)) return "tiff";
|
|
54839
|
+
}
|
|
54840
|
+
/** The pixel size in the header of a PNG or the first image of a TIFF. Nothing is decoded, so a
|
|
54841
|
+
* truncated or unusual file gives `undefined` and is never treated as a match. */
|
|
54842
|
+
function size(bytes, kind) {
|
|
54843
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
54844
|
+
if (kind === "png") {
|
|
54845
|
+
if (bytes.length < 24 || view.getUint32(12) !== 1229472850) return void 0;
|
|
54846
|
+
return {
|
|
54847
|
+
width: view.getUint32(16),
|
|
54848
|
+
height: view.getUint32(20)
|
|
54849
|
+
};
|
|
54850
|
+
}
|
|
54851
|
+
const little = bytes[0] === 73;
|
|
54852
|
+
const directory = view.getUint32(4, little);
|
|
54853
|
+
if (directory + 2 > bytes.length) return void 0;
|
|
54854
|
+
const entries = view.getUint16(directory, little);
|
|
54855
|
+
let width;
|
|
54856
|
+
let height;
|
|
54857
|
+
for (let index = 0; index < entries; index++) {
|
|
54858
|
+
const entry = directory + 2 + index * 12;
|
|
54859
|
+
if (entry + 12 > bytes.length) return void 0;
|
|
54860
|
+
const tag = view.getUint16(entry, little);
|
|
54861
|
+
if (tag !== 256 && tag !== 257) continue;
|
|
54862
|
+
const type = view.getUint16(entry + 2, little);
|
|
54863
|
+
const value = type === 3 ? view.getUint16(entry + 8, little) : type === 4 ? view.getUint32(entry + 8, little) : void 0;
|
|
54864
|
+
if (tag === 256) width = value;
|
|
54865
|
+
else height = value;
|
|
54866
|
+
}
|
|
54867
|
+
return width && height ? {
|
|
54868
|
+
width,
|
|
54869
|
+
height
|
|
54870
|
+
} : void 0;
|
|
54871
|
+
}
|
|
54872
|
+
function identical(a, b) {
|
|
54873
|
+
if (a.length !== b.length) return false;
|
|
54874
|
+
for (let index = 0; index < a.length; index++) if (a[index] !== b[index]) return false;
|
|
54875
|
+
return true;
|
|
54876
|
+
}
|
|
54877
|
+
function stem(filename) {
|
|
54878
|
+
const name = (filename ?? "").split(/[\\/]/).pop() ?? "";
|
|
54879
|
+
const dot = name.lastIndexOf(".");
|
|
54880
|
+
return (dot > 0 ? name.slice(0, dot) : name).normalize("NFC").toLowerCase();
|
|
54881
|
+
}
|
|
54882
|
+
/** Whether two captured images are one picture in two representations. */
|
|
54883
|
+
function sameImage(a, b) {
|
|
54884
|
+
if ((a.source ?? "") !== (b.source ?? "")) return false;
|
|
54885
|
+
if (identical(a.bytes, b.bytes)) return true;
|
|
54886
|
+
const kindA = format(a.bytes);
|
|
54887
|
+
const kindB = format(b.bytes);
|
|
54888
|
+
if (!kindA || !kindB || kindA === kindB) return false;
|
|
54889
|
+
const nameA = stem(a.filename);
|
|
54890
|
+
const nameB = stem(b.filename);
|
|
54891
|
+
if (nameA && nameB && nameA !== nameB) return false;
|
|
54892
|
+
const sizeA = size(a.bytes, kindA);
|
|
54893
|
+
const sizeB = size(b.bytes, kindB);
|
|
54894
|
+
return !!sizeA && !!sizeB && sizeA.width === sizeB.width && sizeA.height === sizeB.height;
|
|
54895
|
+
}
|
|
54896
|
+
/** Keeps one image for each picture in a single paste or drop. A clipboard can hold a picture
|
|
54897
|
+
* more than once, such as a screenshot as PNG and as TIFF, and each copy would be stored and
|
|
54898
|
+
* inserted separately.
|
|
54899
|
+
*
|
|
54900
|
+
* Two images are one picture when their bytes are identical, or when one is a PNG and the other a
|
|
54901
|
+
* TIFF with the same pixel size and compatible names (the same name without its extension, or a
|
|
54902
|
+
* name missing). Anything else is a different image, including a copy that was resized, re-encoded
|
|
54903
|
+
* as JPEG or renamed. The first image keeps its place; a PNG replaces a TIFF of the same picture
|
|
54904
|
+
* because every web view can show it. */
|
|
54905
|
+
function distinctImages(images) {
|
|
54906
|
+
const kept = [];
|
|
54907
|
+
for (const image of images) {
|
|
54908
|
+
const index = kept.findIndex((other) => sameImage(other, image));
|
|
54909
|
+
if (index < 0) kept.push(image);
|
|
54910
|
+
else if (format(kept[index].bytes) === "tiff" && format(image.bytes) === "png") kept[index] = image;
|
|
54911
|
+
}
|
|
54912
|
+
return kept;
|
|
54913
|
+
}
|
|
54914
|
+
//#endregion
|
|
54056
54915
|
//#region src/paste.ts
|
|
54057
54916
|
var PasteController = class {
|
|
54058
54917
|
options;
|
|
@@ -54214,12 +55073,12 @@ var PasteController = class {
|
|
|
54214
55073
|
this.active = operation;
|
|
54215
55074
|
this.options.onPendingChanged?.();
|
|
54216
55075
|
try {
|
|
54217
|
-
const
|
|
54218
|
-
for (const file of files) images.push({
|
|
55076
|
+
const fromFiles = files.length ? distinctImages(await Promise.all(files.map(async (file) => ({
|
|
54219
55077
|
bytes: new Uint8Array(await file.arrayBuffer()),
|
|
54220
55078
|
mimeType: file.type,
|
|
54221
55079
|
filename: file.name
|
|
54222
|
-
});
|
|
55080
|
+
})))) : [];
|
|
55081
|
+
const images = distinctImages([...input.images ?? [], ...fromFiles]);
|
|
54223
55082
|
this.assertContext(context, operation);
|
|
54224
55083
|
const schema = view.state.schema;
|
|
54225
55084
|
let slice;
|
|
@@ -54238,8 +55097,7 @@ var PasteController = class {
|
|
|
54238
55097
|
}
|
|
54239
55098
|
const anchor = this.anchor(operation);
|
|
54240
55099
|
const start = view.state.doc.resolve(anchor.from);
|
|
54241
|
-
const
|
|
54242
|
-
const marks = view.state.storedMarks ?? (anchor.from === anchor.to ? start.marks() : start.marksAcross(end)) ?? [];
|
|
55100
|
+
const marks = replacementMarks(view.state, anchor.from, anchor.to);
|
|
54243
55101
|
const nodes = literalTextNodes(schema, input.text, marks, htmlBreakAt(start));
|
|
54244
55102
|
slice = new Slice(Fragment.from(schema.nodes.paragraph.create(null, nodes)), 1, 1);
|
|
54245
55103
|
} else if (input.html) {
|
|
@@ -54247,7 +55105,7 @@ var PasteController = class {
|
|
|
54247
55105
|
const imported = /* @__PURE__ */ new Map();
|
|
54248
55106
|
const elements = [...container.querySelectorAll("img")];
|
|
54249
55107
|
const uniqueSources = new Set(elements.map((element) => element.getAttribute("src") ?? ""));
|
|
54250
|
-
const positional = (
|
|
55108
|
+
const positional = (fromFiles.length === 0 || fromFiles.length === 1 && uniqueSources.size === 1 ? images : input.images ?? []).filter((image) => !image.source);
|
|
54251
55109
|
let index = 0;
|
|
54252
55110
|
for (const element of elements) {
|
|
54253
55111
|
const source = element.getAttribute("src") ?? "";
|
|
@@ -54744,60 +55602,259 @@ var DocumentSession = class {
|
|
|
54744
55602
|
//#region src/selection.ts
|
|
54745
55603
|
/** The stylesheet paints the selection under this name. */
|
|
54746
55604
|
var name = "inkkit-selection";
|
|
54747
|
-
var
|
|
55605
|
+
var activeClass = "inkkit-selection-active";
|
|
54748
55606
|
/** The selected text within each block. */
|
|
54749
55607
|
function covered(state) {
|
|
54750
55608
|
const { from, to, empty, visible } = state.selection;
|
|
54751
|
-
if (empty || !visible) return
|
|
55609
|
+
if (empty || !visible) return [];
|
|
54752
55610
|
const text = [];
|
|
54753
|
-
|
|
55611
|
+
let index = 0;
|
|
55612
|
+
state.doc.descendants((node, pos) => {
|
|
54754
55613
|
if (!node.isTextblock) return true;
|
|
54755
55614
|
const start = Math.max(from, pos + 1);
|
|
54756
55615
|
const end = Math.min(to, pos + node.nodeSize - 1);
|
|
54757
55616
|
if (end > start) text.push({
|
|
54758
55617
|
from: start,
|
|
54759
|
-
to: end
|
|
55618
|
+
to: end,
|
|
55619
|
+
start: pos + 1,
|
|
55620
|
+
end: pos + node.nodeSize - 1,
|
|
55621
|
+
index
|
|
54760
55622
|
});
|
|
55623
|
+
index++;
|
|
54761
55624
|
return false;
|
|
54762
55625
|
});
|
|
54763
55626
|
return text;
|
|
54764
55627
|
}
|
|
55628
|
+
function blockContents(view) {
|
|
55629
|
+
return Array.from(view.dom.querySelectorAll("p,h1,h2,h3,h4,h5,h6,pre,.inkkit-comment-block")).filter((element) => {
|
|
55630
|
+
const excluded = element.closest(".ProseMirror-widget,[contenteditable=\"false\"]");
|
|
55631
|
+
return !excluded || excluded === view.dom;
|
|
55632
|
+
}).map((element) => element.tagName === "PRE" && !element.classList.contains("inkkit-literal-markdown") ? element.querySelector(":scope > code") ?? element : element);
|
|
55633
|
+
}
|
|
55634
|
+
function matchesBlock(node, content) {
|
|
55635
|
+
if (!content) return false;
|
|
55636
|
+
switch (node.type.name) {
|
|
55637
|
+
case "paragraph": return content.tagName === "P";
|
|
55638
|
+
case "heading": return content.tagName === `H${node.attrs.level}`;
|
|
55639
|
+
case "code_block": return content.tagName === "CODE" && content.parentElement?.tagName === "PRE";
|
|
55640
|
+
case "literal_markdown": return content.classList.contains("inkkit-literal-markdown");
|
|
55641
|
+
case "comment_block": return content.classList.contains("inkkit-comment-block");
|
|
55642
|
+
default: return false;
|
|
55643
|
+
}
|
|
55644
|
+
}
|
|
55645
|
+
function blockRange(view, span, content) {
|
|
55646
|
+
const range = view.dom.ownerDocument.createRange();
|
|
55647
|
+
range.selectNodeContents(content);
|
|
55648
|
+
const children = Array.from(content.childNodes);
|
|
55649
|
+
const decoration = (node) => node instanceof Element && (node.classList.contains("ProseMirror-widget") || node.classList.contains("ProseMirror-trailingBreak"));
|
|
55650
|
+
const first = children.find((node) => !decoration(node));
|
|
55651
|
+
const last = [...children].reverse().find((node) => !decoration(node));
|
|
55652
|
+
if (first) range.setStartBefore(first);
|
|
55653
|
+
if (last) range.setEndAfter(last);
|
|
55654
|
+
if (span.from !== span.start) {
|
|
55655
|
+
const start = view.domAtPos(span.from);
|
|
55656
|
+
range.setStart(start.node, start.offset);
|
|
55657
|
+
}
|
|
55658
|
+
if (span.to !== span.end) {
|
|
55659
|
+
const end = view.domAtPos(span.to);
|
|
55660
|
+
range.setEnd(end.node, end.offset);
|
|
55661
|
+
}
|
|
55662
|
+
return range;
|
|
55663
|
+
}
|
|
55664
|
+
function addBlockRanges(highlight, view, spans, contents) {
|
|
55665
|
+
let first;
|
|
55666
|
+
let last;
|
|
55667
|
+
const flush = () => {
|
|
55668
|
+
if (!first || !last) return;
|
|
55669
|
+
const range = view.dom.ownerDocument.createRange();
|
|
55670
|
+
range.setStart(first.content.firstChild, first.span.from - first.span.start);
|
|
55671
|
+
range.setEnd(last.content.firstChild, last.span.to - last.span.start);
|
|
55672
|
+
highlight.add(range);
|
|
55673
|
+
first = last = void 0;
|
|
55674
|
+
};
|
|
55675
|
+
for (const span of spans) {
|
|
55676
|
+
const content = contents[span.index];
|
|
55677
|
+
if (!(/^(P|H[1-6])$/.test(content.tagName) && content.childNodes.length === 1 && content.firstChild?.nodeType === Node.TEXT_NODE)) {
|
|
55678
|
+
flush();
|
|
55679
|
+
highlight.add(blockRange(view, span, content));
|
|
55680
|
+
continue;
|
|
55681
|
+
}
|
|
55682
|
+
if (last && last.content.nextSibling !== content) flush();
|
|
55683
|
+
first ??= {
|
|
55684
|
+
span,
|
|
55685
|
+
content
|
|
55686
|
+
};
|
|
55687
|
+
last = {
|
|
55688
|
+
span,
|
|
55689
|
+
content
|
|
55690
|
+
};
|
|
55691
|
+
}
|
|
55692
|
+
flush();
|
|
55693
|
+
}
|
|
55694
|
+
function setSelectionHostActive(view, active) {
|
|
55695
|
+
Painter.of(view.dom.ownerDocument).hostActive(view, active);
|
|
55696
|
+
}
|
|
54765
55697
|
function domRange(view, span) {
|
|
54766
55698
|
const start = view.domAtPos(span.from);
|
|
54767
55699
|
const end = view.domAtPos(span.to);
|
|
54768
|
-
const range =
|
|
55700
|
+
const range = view.dom.ownerDocument.createRange();
|
|
54769
55701
|
range.setStart(start.node, start.offset);
|
|
54770
55702
|
range.setEnd(end.node, end.offset);
|
|
54771
55703
|
return range;
|
|
54772
55704
|
}
|
|
54773
|
-
|
|
54774
|
-
ranges.set(view, (covered(view.state) ?? []).map((span) => domRange(view, span)));
|
|
54775
|
-
refresh();
|
|
54776
|
-
}
|
|
54777
|
-
function refresh() {
|
|
54778
|
-
if (ranges.size === 0) {
|
|
54779
|
-
CSS.highlights.delete(name);
|
|
54780
|
-
return;
|
|
54781
|
-
}
|
|
54782
|
-
const highlight = new Highlight();
|
|
54783
|
-
for (const selection of ranges.values()) for (const range of selection) highlight.add(range);
|
|
54784
|
-
CSS.highlights.set(name, highlight);
|
|
54785
|
-
}
|
|
55705
|
+
var rootOf = (view) => view.dom.closest(".inkkit-root");
|
|
54786
55706
|
var paintable = () => typeof Highlight === "function" && "highlights" in CSS && CSS.supports(`selector(::highlight(${name}))`);
|
|
54787
|
-
|
|
54788
|
-
|
|
54789
|
-
|
|
54790
|
-
|
|
54791
|
-
|
|
54792
|
-
|
|
54793
|
-
|
|
54794
|
-
|
|
54795
|
-
|
|
54796
|
-
|
|
54797
|
-
|
|
55707
|
+
/**
|
|
55708
|
+
* Whether the view holds the user's input: its formatted surface, or the source or TXT
|
|
55709
|
+
* textarea beside it, has focus, or, in a read-only editor that takes no focus, the
|
|
55710
|
+
* document selection is inside it.
|
|
55711
|
+
*/
|
|
55712
|
+
function focused(view) {
|
|
55713
|
+
const doc = view.dom.ownerDocument;
|
|
55714
|
+
const surface = doc.activeElement;
|
|
55715
|
+
if (surface === view.dom || view.dom.contains(surface) || surface instanceof HTMLTextAreaElement && surface.classList.contains("inkkit-plain") && rootOf(view).contains(surface)) return true;
|
|
55716
|
+
const anchor = doc.getSelection()?.anchorNode;
|
|
55717
|
+
return !view.editable && !!anchor && view.dom.contains(anchor);
|
|
55718
|
+
}
|
|
55719
|
+
/** Whether the focused element takes typing, so a selection kept elsewhere is still what the host is working on. */
|
|
55720
|
+
function takesText(element) {
|
|
55721
|
+
return element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement || element instanceof HTMLSelectElement || element instanceof HTMLElement && element.isContentEditable;
|
|
55722
|
+
}
|
|
55723
|
+
/**
|
|
55724
|
+
* One document has one selection, so the editors on it share one painter and one highlight.
|
|
55725
|
+
* The owner is the editor that most recently held the selection. Its selection is painted
|
|
55726
|
+
* in the active colour while it has focus in a focused window, and in the inactive colour
|
|
55727
|
+
* otherwise, so a host that selects a range from its search field, or blurs the editor,
|
|
55728
|
+
* still shows what is selected. Anything that takes the selection elsewhere releases it.
|
|
55729
|
+
*/
|
|
55730
|
+
var Painter = class Painter {
|
|
55731
|
+
doc;
|
|
55732
|
+
static all = /* @__PURE__ */ new WeakMap();
|
|
55733
|
+
views = /* @__PURE__ */ new Map();
|
|
55734
|
+
win;
|
|
55735
|
+
custom = paintable();
|
|
55736
|
+
owner = null;
|
|
55737
|
+
windowFocused;
|
|
55738
|
+
hostActivation = /* @__PURE__ */ new WeakMap();
|
|
55739
|
+
painted;
|
|
55740
|
+
hostActive(view, active) {
|
|
55741
|
+
if (active === null) this.hostActivation.delete(view);
|
|
55742
|
+
else this.hostActivation.set(view, active);
|
|
55743
|
+
this.sync();
|
|
55744
|
+
}
|
|
55745
|
+
static of(doc) {
|
|
55746
|
+
let painter = Painter.all.get(doc);
|
|
55747
|
+
if (!painter) Painter.all.set(doc, painter = new Painter(doc));
|
|
55748
|
+
return painter;
|
|
55749
|
+
}
|
|
55750
|
+
constructor(doc) {
|
|
55751
|
+
this.doc = doc;
|
|
55752
|
+
this.win = doc.defaultView;
|
|
55753
|
+
this.windowFocused = doc.hasFocus();
|
|
55754
|
+
}
|
|
55755
|
+
add(view) {
|
|
55756
|
+
if (!this.views.size) this.listen("add");
|
|
55757
|
+
this.views.set(view, rootOf(view));
|
|
55758
|
+
this.sync();
|
|
55759
|
+
}
|
|
55760
|
+
remove(view) {
|
|
55761
|
+
this.views.get(view)?.classList.remove(activeClass);
|
|
55762
|
+
this.views.delete(view);
|
|
55763
|
+
if (this.owner === view) this.owner = null;
|
|
55764
|
+
this.sync();
|
|
55765
|
+
if (!this.views.size) {
|
|
55766
|
+
this.listen("remove");
|
|
55767
|
+
Painter.all.delete(this.doc);
|
|
55768
|
+
}
|
|
55769
|
+
}
|
|
55770
|
+
/** A transaction gave this view a selection. A focused owner is not taken over by an editor that is not. */
|
|
55771
|
+
take(view) {
|
|
55772
|
+
if (!this.owner || this.owner === view || focused(view) || !focused(this.owner)) this.owner = view;
|
|
55773
|
+
this.sync();
|
|
55774
|
+
}
|
|
55775
|
+
/** The owner's document changed, or its selection moved with it. */
|
|
55776
|
+
changed(view) {
|
|
55777
|
+
if (this.owner === view) this.sync();
|
|
55778
|
+
}
|
|
55779
|
+
onFocusIn = () => {
|
|
55780
|
+
for (const view of this.views.keys()) if (focused(view)) this.owner = view;
|
|
55781
|
+
this.sync();
|
|
55782
|
+
};
|
|
55783
|
+
onFocusOut = () => this.sync();
|
|
55784
|
+
onWindow = (event) => {
|
|
55785
|
+
this.windowFocused = event.type === "focus";
|
|
55786
|
+
this.sync();
|
|
55787
|
+
};
|
|
55788
|
+
onSelectionChange = () => {
|
|
55789
|
+
const owner = this.owner;
|
|
55790
|
+
if (!owner || focused(owner)) return;
|
|
55791
|
+
const selection = this.doc.getSelection();
|
|
55792
|
+
if (!selection?.rangeCount || owner.dom.contains(selection.anchorNode)) return;
|
|
55793
|
+
if (selection.isCollapsed && takesText(this.doc.activeElement)) return;
|
|
55794
|
+
this.owner = null;
|
|
55795
|
+
this.sync();
|
|
55796
|
+
};
|
|
55797
|
+
listen(action) {
|
|
55798
|
+
const method = `${action}EventListener`;
|
|
55799
|
+
this.doc[method]("focusin", this.onFocusIn);
|
|
55800
|
+
this.doc[method]("focusout", this.onFocusOut);
|
|
55801
|
+
this.doc[method]("selectionchange", this.onSelectionChange);
|
|
55802
|
+
this.win[method]("focus", this.onWindow);
|
|
55803
|
+
this.win[method]("blur", this.onWindow);
|
|
55804
|
+
}
|
|
55805
|
+
sync() {
|
|
55806
|
+
for (const [view, root] of this.views) root.classList.toggle(activeClass, (this.hostActivation.get(view) ?? this.windowFocused) && focused(view));
|
|
55807
|
+
if (!this.custom) return;
|
|
55808
|
+
const { owner } = this;
|
|
55809
|
+
if (owner && this.painted?.owner === owner && this.painted.doc === owner.state.doc && this.painted.selection.eq(owner.state.selection)) return;
|
|
55810
|
+
const spans = owner ? covered(owner.state) : [];
|
|
55811
|
+
if (!owner || !spans.length) {
|
|
55812
|
+
CSS.highlights.delete(name);
|
|
55813
|
+
this.painted = void 0;
|
|
55814
|
+
return;
|
|
55815
|
+
}
|
|
55816
|
+
const highlight = new Highlight();
|
|
55817
|
+
const contents = blockContents(owner);
|
|
55818
|
+
let blocks = 0;
|
|
55819
|
+
let mapped = true;
|
|
55820
|
+
owner.state.doc.descendants((node) => {
|
|
55821
|
+
if (!node.isTextblock) return true;
|
|
55822
|
+
if (!matchesBlock(node, contents[blocks])) mapped = false;
|
|
55823
|
+
blocks++;
|
|
55824
|
+
return false;
|
|
55825
|
+
});
|
|
55826
|
+
if (mapped && contents.length === blocks) addBlockRanges(highlight, owner, spans, contents);
|
|
55827
|
+
else for (const span of spans) highlight.add(domRange(owner, span));
|
|
55828
|
+
CSS.highlights.set(name, highlight);
|
|
55829
|
+
this.painted = {
|
|
55830
|
+
owner,
|
|
55831
|
+
doc: owner.state.doc,
|
|
55832
|
+
selection: owner.state.selection
|
|
54798
55833
|
};
|
|
54799
55834
|
}
|
|
54800
|
-
}
|
|
55835
|
+
};
|
|
55836
|
+
var selectionPlugin = $prose(() => {
|
|
55837
|
+
const key = new PluginKey("selection");
|
|
55838
|
+
return new Plugin({
|
|
55839
|
+
key,
|
|
55840
|
+
state: {
|
|
55841
|
+
init: () => 0,
|
|
55842
|
+
apply: (tr, count) => tr.selectionSet ? count + 1 : count
|
|
55843
|
+
},
|
|
55844
|
+
props: paintable() ? { attributes: { class: "inkkit-painted-selection" } } : {},
|
|
55845
|
+
view(view) {
|
|
55846
|
+
const painter = Painter.of(view.dom.ownerDocument);
|
|
55847
|
+
painter.add(view);
|
|
55848
|
+
return {
|
|
55849
|
+
update(view, previous) {
|
|
55850
|
+
if (key.getState(view.state) !== key.getState(previous)) painter.take(view);
|
|
55851
|
+
else painter.changed(view);
|
|
55852
|
+
},
|
|
55853
|
+
destroy: () => painter.remove(view)
|
|
55854
|
+
};
|
|
55855
|
+
}
|
|
55856
|
+
});
|
|
55857
|
+
});
|
|
54801
55858
|
//#endregion
|
|
54802
55859
|
//#region node_modules/.pnpm/prosemirror-search@1.1.1/node_modules/prosemirror-search/dist/index.js
|
|
54803
55860
|
var SearchQuery = class {
|
|
@@ -55095,7 +56152,7 @@ var searchKey = new PluginKey("search");
|
|
|
55095
56152
|
Returns a plugin that stores a current search query and searched
|
|
55096
56153
|
range, and highlights matches of the query.
|
|
55097
56154
|
*/
|
|
55098
|
-
function search(options = {}) {
|
|
56155
|
+
function search$1(options = {}) {
|
|
55099
56156
|
return new Plugin({
|
|
55100
56157
|
key: searchKey,
|
|
55101
56158
|
state: {
|
|
@@ -55144,6 +56201,56 @@ function setSearchState(tr, query, range = null) {
|
|
|
55144
56201
|
}
|
|
55145
56202
|
//#endregion
|
|
55146
56203
|
//#region src/search.ts
|
|
56204
|
+
function search() {
|
|
56205
|
+
const original = search$1();
|
|
56206
|
+
return new Plugin({
|
|
56207
|
+
...original.spec,
|
|
56208
|
+
state: {
|
|
56209
|
+
init: original.spec.state.init,
|
|
56210
|
+
apply(tr, current, oldState, state) {
|
|
56211
|
+
if (tr.getMeta(original) || current.range) return original.spec.state.apply.call(this, tr, current, oldState, state);
|
|
56212
|
+
if (!current.query.valid || !tr.docChanged && !tr.selectionSet) return current;
|
|
56213
|
+
let deco = tr.docChanged ? current.deco.map(tr.mapping, tr.doc) : current.deco;
|
|
56214
|
+
let from = tr.doc.content.size, to = 0;
|
|
56215
|
+
if (tr.docChanged) {
|
|
56216
|
+
tr.mapping.maps.forEach((map, index) => map.forEach((_a, _b, start, end) => {
|
|
56217
|
+
const rest = tr.mapping.slice(index + 1);
|
|
56218
|
+
from = Math.min(from, rest.map(start, -1));
|
|
56219
|
+
to = Math.max(to, rest.map(end, 1));
|
|
56220
|
+
}));
|
|
56221
|
+
if (from <= to) {
|
|
56222
|
+
const left = tr.doc.resolve(Math.max(0, from - 1));
|
|
56223
|
+
const right = tr.doc.resolve(Math.min(tr.doc.content.size, to + 1));
|
|
56224
|
+
from = left.depth ? left.before(1) : left.pos;
|
|
56225
|
+
to = right.depth ? right.after(1) : right.pos;
|
|
56226
|
+
deco = deco.remove(deco.find(from, to));
|
|
56227
|
+
const added = [];
|
|
56228
|
+
for (let position = from; position < to;) {
|
|
56229
|
+
const match = current.query.findNext(state, position, to);
|
|
56230
|
+
if (!match) break;
|
|
56231
|
+
added.push(Decoration.inline(match.from, match.to, { class: "ProseMirror-search-match" }));
|
|
56232
|
+
position = Math.max(match.to, position + 1);
|
|
56233
|
+
}
|
|
56234
|
+
deco = deco.add(state.doc, added);
|
|
56235
|
+
}
|
|
56236
|
+
}
|
|
56237
|
+
const previous = {
|
|
56238
|
+
from: tr.mapping.map(oldState.selection.from),
|
|
56239
|
+
to: tr.mapping.map(oldState.selection.to)
|
|
56240
|
+
};
|
|
56241
|
+
for (const [selection, active] of [[previous, false], [state.selection, true]]) {
|
|
56242
|
+
const matches = deco.find(selection.from, selection.to).filter((item) => item.from === selection.from && item.to === selection.to);
|
|
56243
|
+
const replacements = matches.map((item) => Decoration.inline(item.from, item.to, { class: active ? "ProseMirror-active-search-match" : "ProseMirror-search-match" }));
|
|
56244
|
+
deco = deco.remove(matches).add(state.doc, replacements);
|
|
56245
|
+
}
|
|
56246
|
+
return {
|
|
56247
|
+
...current,
|
|
56248
|
+
deco
|
|
56249
|
+
};
|
|
56250
|
+
}
|
|
56251
|
+
}
|
|
56252
|
+
});
|
|
56253
|
+
}
|
|
55147
56254
|
function escapedPattern(text) {
|
|
55148
56255
|
return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
55149
56256
|
}
|
|
@@ -55227,8 +56334,8 @@ function findFormatted(view, text) {
|
|
|
55227
56334
|
return found;
|
|
55228
56335
|
}
|
|
55229
56336
|
function replacementSlice(state, from, to, value) {
|
|
55230
|
-
const start = state.doc.resolve(from)
|
|
55231
|
-
const marks =
|
|
56337
|
+
const start = state.doc.resolve(from);
|
|
56338
|
+
const marks = replacementMarks(state, from, to);
|
|
55232
56339
|
const nodes = [];
|
|
55233
56340
|
if (start.parent.type.spec.code) {
|
|
55234
56341
|
if (value) nodes.push(state.schema.text(value, marks));
|
|
@@ -55305,8 +56412,10 @@ function formattedLocations(doc) {
|
|
|
55305
56412
|
return headings;
|
|
55306
56413
|
}
|
|
55307
56414
|
function sourceLocations(ctx, source) {
|
|
55308
|
-
const
|
|
55309
|
-
|
|
56415
|
+
const cached = sourceOutlines.get(ctx);
|
|
56416
|
+
if (cached?.source === source) return cached.headings;
|
|
56417
|
+
const preservation = Preservation.read(ctx, source);
|
|
56418
|
+
const tree = preservation.sourceTree;
|
|
55310
56419
|
const positions = [];
|
|
55311
56420
|
const bom = source.startsWith("") ? 1 : 0;
|
|
55312
56421
|
const visit = (node) => {
|
|
@@ -55317,13 +56426,19 @@ function sourceLocations(ctx, source) {
|
|
|
55317
56426
|
node.children?.forEach(visit);
|
|
55318
56427
|
};
|
|
55319
56428
|
visit(tree);
|
|
55320
|
-
const parsed = formattedLocations(
|
|
56429
|
+
const parsed = formattedLocations(preservation.baseline);
|
|
55321
56430
|
if (positions.length !== parsed.length || positions.some((item, index) => item.level !== parsed[index].node.attrs.level)) throw new InkKitError("preservation", "The current Markdown headings cannot be located safely");
|
|
55322
|
-
|
|
56431
|
+
const headings = parsed.map((heading, index) => ({
|
|
55323
56432
|
...heading,
|
|
55324
56433
|
position: positions[index].position
|
|
55325
56434
|
}));
|
|
56435
|
+
sourceOutlines.set(ctx, {
|
|
56436
|
+
source,
|
|
56437
|
+
headings
|
|
56438
|
+
});
|
|
56439
|
+
return headings;
|
|
55326
56440
|
}
|
|
56441
|
+
var sourceOutlines = /* @__PURE__ */ new WeakMap();
|
|
55327
56442
|
function entry(heading, context) {
|
|
55328
56443
|
return Object.freeze({
|
|
55329
56444
|
id: `heading:${context.key}:${heading.position}`,
|
|
@@ -55845,6 +56960,8 @@ var shortcutNames = [
|
|
|
55845
56960
|
"redo",
|
|
55846
56961
|
"moveBlockUp",
|
|
55847
56962
|
"moveBlockDown",
|
|
56963
|
+
"indent",
|
|
56964
|
+
"outdent",
|
|
55848
56965
|
...tableCommands.map(tableShortcut)
|
|
55849
56966
|
];
|
|
55850
56967
|
/** Checks a keymap and drops omitted entries, so a `null` binding keeps its default. */
|
|
@@ -55896,6 +57013,7 @@ function editorOptions(value) {
|
|
|
55896
57013
|
"textInput",
|
|
55897
57014
|
"labels",
|
|
55898
57015
|
"keymap",
|
|
57016
|
+
"linkSchemes",
|
|
55899
57017
|
"rendering",
|
|
55900
57018
|
"slashMenu"
|
|
55901
57019
|
]) ?? {};
|
|
@@ -55905,6 +57023,7 @@ function editorOptions(value) {
|
|
|
55905
57023
|
optionalBoolean(options.editable, "options.editable");
|
|
55906
57024
|
if (!isOmitted(options.textInput)) textInputPreferences(options.textInput, "options.textInput");
|
|
55907
57025
|
if (!isOmitted(options.keymap)) keymapBindings(options.keymap, "options.keymap");
|
|
57026
|
+
const linkSchemes = isOmitted(options.linkSchemes) ? void 0 : extraLinkSchemes(options.linkSchemes, "options.linkSchemes");
|
|
55908
57027
|
const rendering = optionalRecord(options.rendering, "options.rendering", ["codeHighlighting", "diagramPreview"]);
|
|
55909
57028
|
optionalBoolean(rendering?.codeHighlighting, "options.rendering.codeHighlighting");
|
|
55910
57029
|
optionalBoolean(rendering?.diagramPreview, "options.rendering.diagramPreview");
|
|
@@ -55912,6 +57031,7 @@ function editorOptions(value) {
|
|
|
55912
57031
|
return {
|
|
55913
57032
|
...options,
|
|
55914
57033
|
slashMenu: slashMenuOptions(options.slashMenu),
|
|
57034
|
+
linkSchemes,
|
|
55915
57035
|
labels: labels && Object.fromEntries(Object.entries(labels).filter(([, label]) => !isOmitted(label)).map(([key, label]) => [key, expectString(label, `options.labels.${key}`)]))
|
|
55916
57036
|
};
|
|
55917
57037
|
}
|
|
@@ -56108,6 +57228,18 @@ function blockAt(parent, $from) {
|
|
|
56108
57228
|
return { type: "paragraph" };
|
|
56109
57229
|
}
|
|
56110
57230
|
var quotes = /* @__PURE__ */ new Set(["blockquote", "inkkit_callout"]);
|
|
57231
|
+
function liftQuote(state, range, target) {
|
|
57232
|
+
const tr = state.tr.lift(range, target);
|
|
57233
|
+
const { depth } = range;
|
|
57234
|
+
const item = range.$from.node(depth - 1);
|
|
57235
|
+
const spacer = item.firstChild;
|
|
57236
|
+
if (item.type.name === "list_item" && range.$from.index(depth - 1) === 1 && spacer?.type.name === "paragraph" && spacer.content.size === 0) {
|
|
57237
|
+
const from = range.$from.start(depth - 1);
|
|
57238
|
+
if (tr.doc.nodeAt(from + spacer.nodeSize)?.type === spacer.type) tr.delete(from, from + spacer.nodeSize);
|
|
57239
|
+
}
|
|
57240
|
+
return tr;
|
|
57241
|
+
}
|
|
57242
|
+
var undoTypedRule = $prose(() => keymap$3({ Backspace: undoInputRule }));
|
|
56111
57243
|
var quoteBackspace = $prose(() => keymap$3({ Backspace: (state, dispatch) => {
|
|
56112
57244
|
const { $from, empty } = state.selection;
|
|
56113
57245
|
if (!empty || $from.parentOffset > 0 || $from.depth < 2) return false;
|
|
@@ -56117,7 +57249,7 @@ var quoteBackspace = $prose(() => keymap$3({ Backspace: (state, dispatch) => {
|
|
|
56117
57249
|
const range = $from.blockRange($from, (node) => quotes.has(node.type.name));
|
|
56118
57250
|
const target = range && liftTarget(range);
|
|
56119
57251
|
if (!range || target == null) return false;
|
|
56120
|
-
dispatch?.(state
|
|
57252
|
+
dispatch?.(liftQuote(state, range, target).scrollIntoView());
|
|
56121
57253
|
return true;
|
|
56122
57254
|
} }));
|
|
56123
57255
|
var calloutEnter = $prose(() => keymap$3({ Enter: (state, dispatch) => {
|
|
@@ -56159,7 +57291,6 @@ var liftItem = (state, dispatch) => {
|
|
|
56159
57291
|
dispatch(lifted);
|
|
56160
57292
|
return true;
|
|
56161
57293
|
};
|
|
56162
|
-
var listItemShiftTab = $prose(() => keymap$3({ "Shift-Tab": liftItem }));
|
|
56163
57294
|
var rejoinLists = $prose(() => keymap$3({ Backspace: (state, dispatch) => {
|
|
56164
57295
|
const { $from, empty } = state.selection;
|
|
56165
57296
|
if (!empty || $from.parent.type.name !== "paragraph" || $from.parent.content.size > 0) return false;
|
|
@@ -56252,11 +57383,7 @@ var movedListItems = $prose(() => new Plugin({
|
|
|
56252
57383
|
return tr.docChanged ? tr : null;
|
|
56253
57384
|
}
|
|
56254
57385
|
}));
|
|
56255
|
-
var
|
|
56256
|
-
var textInputPolicy = $prose(() => new Plugin({
|
|
56257
|
-
key: new PluginKey("inkkitTextInput"),
|
|
56258
|
-
props: { handleTextInput: (view, from, to, text, deflt) => controlCharacters.test(text) || insertTextChunk(view, from, to, text, deflt) }
|
|
56259
|
-
}));
|
|
57386
|
+
var textInputPolicy = $prose(() => textInputPlugin());
|
|
56260
57387
|
function outermostListDepth($pos) {
|
|
56261
57388
|
for (let depth = 1; depth <= $pos.depth; depth++) if (isList($pos.node(depth))) return depth;
|
|
56262
57389
|
return null;
|
|
@@ -56381,6 +57508,7 @@ var InkKitEditor = class InkKitEditor {
|
|
|
56381
57508
|
inputPreferences = {};
|
|
56382
57509
|
literalKeys = () => false;
|
|
56383
57510
|
configuredKeys = {};
|
|
57511
|
+
indentKeys = () => false;
|
|
56384
57512
|
readOnlyKeys = () => false;
|
|
56385
57513
|
suggestions;
|
|
56386
57514
|
suggestionBase;
|
|
@@ -56407,7 +57535,7 @@ var InkKitEditor = class InkKitEditor {
|
|
|
56407
57535
|
const anchor = view.state.doc.attrs[sourceAttribute];
|
|
56408
57536
|
const from = anchor?.from ?? this.plain.selectionStart;
|
|
56409
57537
|
const to = anchor?.to ?? this.plain.selectionEnd;
|
|
56410
|
-
if (!this.plainComposing) this.
|
|
57538
|
+
if (!this.plainComposing) this.setSourceValue(markdown);
|
|
56411
57539
|
if (!this.plainComposing) {
|
|
56412
57540
|
this.plain.setSelectionRange(Math.min(from, this.plain.value.length), Math.min(to, this.plain.value.length));
|
|
56413
57541
|
this.revealLiteralSelection();
|
|
@@ -56420,6 +57548,8 @@ var InkKitEditor = class InkKitEditor {
|
|
|
56420
57548
|
}));
|
|
56421
57549
|
keys = () => false;
|
|
56422
57550
|
events;
|
|
57551
|
+
/** The host's extra link schemes, in lower case. */
|
|
57552
|
+
linkSchemes;
|
|
56423
57553
|
/** How many of each state event the host has been sent. */
|
|
56424
57554
|
sentEvents = /* @__PURE__ */ new Map();
|
|
56425
57555
|
constructor(events, options) {
|
|
@@ -56439,6 +57569,7 @@ var InkKitEditor = class InkKitEditor {
|
|
|
56439
57569
|
else send();
|
|
56440
57570
|
};
|
|
56441
57571
|
} });
|
|
57572
|
+
this.linkSchemes = new Set(options.linkSchemes);
|
|
56442
57573
|
this.writable = options.editable ?? true;
|
|
56443
57574
|
this.inputPreferences = textInputPreferences(options.textInput ?? {}, "options.textInput");
|
|
56444
57575
|
}
|
|
@@ -56499,7 +57630,7 @@ var InkKitEditor = class InkKitEditor {
|
|
|
56499
57630
|
};
|
|
56500
57631
|
}
|
|
56501
57632
|
mediaPolicy() {
|
|
56502
|
-
if (this.editor && this.root) this.editor.ctx.get(editorViewCtx).dom.dispatchEvent(new Event(
|
|
57633
|
+
if (this.editor && this.root) this.editor.ctx.get(editorViewCtx).dom.dispatchEvent(new Event(mediaPolicyEvent));
|
|
56503
57634
|
}
|
|
56504
57635
|
assertAlive() {
|
|
56505
57636
|
if (this.destroyed) throw new InkKitError("destroyed", "The editor has been destroyed");
|
|
@@ -56653,6 +57784,12 @@ var InkKitEditor = class InkKitEditor {
|
|
|
56653
57784
|
}
|
|
56654
57785
|
this.publishCommandState();
|
|
56655
57786
|
}
|
|
57787
|
+
/** Supplies native host activation for selection presentation. Null restores browser detection. */
|
|
57788
|
+
setHostActive(active) {
|
|
57789
|
+
this.assertAlive();
|
|
57790
|
+
if (active !== null) expectBoolean(active, "active");
|
|
57791
|
+
setSelectionHostActive(this.editor.ctx.get(editorViewCtx), active);
|
|
57792
|
+
}
|
|
56656
57793
|
/** Replaces the input preferences. A field left out takes its default. Throws `composition`
|
|
56657
57794
|
* during text composition. */
|
|
56658
57795
|
setTextInputPreferences(preferences) {
|
|
@@ -56671,11 +57808,13 @@ var InkKitEditor = class InkKitEditor {
|
|
|
56671
57808
|
}
|
|
56672
57809
|
applyInputPolicy() {
|
|
56673
57810
|
const view = this.editor.ctx.get(editorViewCtx);
|
|
56674
|
-
const
|
|
57811
|
+
const inputAttributes = { ...typeof view.props.attributes === "function" ? view.props.attributes(view.state) : view.props.attributes };
|
|
57812
|
+
delete inputAttributes["aria-readonly"];
|
|
57813
|
+
if (!this.writable) inputAttributes["aria-readonly"] = "true";
|
|
56675
57814
|
view.setProps({
|
|
56676
57815
|
editable: () => this.writable && !this.literalSurface,
|
|
56677
57816
|
attributes: {
|
|
56678
|
-
...
|
|
57817
|
+
...inputAttributes,
|
|
56679
57818
|
role: "textbox",
|
|
56680
57819
|
"aria-multiline": "true",
|
|
56681
57820
|
"aria-label": this.options.labels?.formattedEditor ?? defaultLabels.formattedEditor
|
|
@@ -56750,6 +57889,7 @@ var InkKitEditor = class InkKitEditor {
|
|
|
56750
57889
|
replace: mutable,
|
|
56751
57890
|
replaceSource: mutable,
|
|
56752
57891
|
insertImages: formatted && this.canInsertImages,
|
|
57892
|
+
appendImages: formatted && this.canInsertImages,
|
|
56753
57893
|
insertPaths: mutable,
|
|
56754
57894
|
insertFootnote: formatted,
|
|
56755
57895
|
editReferenceDefinition: formatted && referenceDefinitions(state.doc).size > 0,
|
|
@@ -56839,7 +57979,7 @@ var InkKitEditor = class InkKitEditor {
|
|
|
56839
57979
|
if (provenance) {
|
|
56840
57980
|
preservation = this.sourcePreservations.get(provenance);
|
|
56841
57981
|
if (!preservation) {
|
|
56842
|
-
preservation =
|
|
57982
|
+
preservation = Preservation.read(this.editor.ctx, provenance.text);
|
|
56843
57983
|
this.sourcePreservations.set(provenance, preservation);
|
|
56844
57984
|
}
|
|
56845
57985
|
}
|
|
@@ -56881,7 +58021,7 @@ var InkKitEditor = class InkKitEditor {
|
|
|
56881
58021
|
this.plainSearch = "";
|
|
56882
58022
|
this.literalMatch = void 0;
|
|
56883
58023
|
if (mode === "source") {
|
|
56884
|
-
this.
|
|
58024
|
+
this.setSourceValue(text);
|
|
56885
58025
|
this.plain.setSelectionRange(Math.min(anchor, head), Math.max(anchor, head), anchor > head ? "backward" : "forward");
|
|
56886
58026
|
} else view.dispatch(view.state.tr.setSelection(TextSelection.between(view.state.doc.resolve(Math.min(anchor, view.state.doc.content.size)), view.state.doc.resolve(Math.min(head, view.state.doc.content.size)))).setMeta("addToHistory", false));
|
|
56887
58027
|
const suppressed = this.reportingSuppressed;
|
|
@@ -56966,10 +58106,27 @@ var InkKitEditor = class InkKitEditor {
|
|
|
56966
58106
|
if (this.typedSteps.length > sourceStepLimit) this.typedSteps.shift();
|
|
56967
58107
|
}
|
|
56968
58108
|
showTypedSource(text, from, to) {
|
|
56969
|
-
this.
|
|
58109
|
+
this.setSourceValue(text);
|
|
56970
58110
|
this.plain.setSelectionRange(Math.min(from, this.plain.value.length), Math.min(to, this.plain.value.length));
|
|
56971
58111
|
this.revealLiteralSelection();
|
|
56972
58112
|
}
|
|
58113
|
+
setSourceValue(text) {
|
|
58114
|
+
const plain = this.plain;
|
|
58115
|
+
if (text.length < 65536 || !plain.isConnected || this.plainComposing) {
|
|
58116
|
+
plain.value = text;
|
|
58117
|
+
return;
|
|
58118
|
+
}
|
|
58119
|
+
const focused = plain.ownerDocument.activeElement === plain;
|
|
58120
|
+
const { selectionStart, selectionEnd, selectionDirection, scrollTop, scrollLeft } = plain;
|
|
58121
|
+
const marker = plain.ownerDocument.createComment("source");
|
|
58122
|
+
plain.replaceWith(marker);
|
|
58123
|
+
plain.value = text;
|
|
58124
|
+
marker.replaceWith(plain);
|
|
58125
|
+
plain.setSelectionRange(selectionStart, selectionEnd, selectionDirection);
|
|
58126
|
+
if (focused) plain.focus({ preventScroll: true });
|
|
58127
|
+
plain.scrollTop = scrollTop;
|
|
58128
|
+
plain.scrollLeft = scrollLeft;
|
|
58129
|
+
}
|
|
56973
58130
|
/**
|
|
56974
58131
|
* Undoes or redoes typed source that the formatted document has not taken
|
|
56975
58132
|
* in, on the text alone. Returns whether there was a step to take.
|
|
@@ -57041,7 +58198,7 @@ var InkKitEditor = class InkKitEditor {
|
|
|
57041
58198
|
try {
|
|
57042
58199
|
if (this.formatType === "txt") parsed = view.state.schema.topNodeType.create(null, view.state.schema.nodes.paragraph.create(null, text ? view.state.schema.text(text) : void 0));
|
|
57043
58200
|
else {
|
|
57044
|
-
const preservation =
|
|
58201
|
+
const preservation = Preservation.read(this.editor.ctx, text);
|
|
57045
58202
|
this.sourcePreservations.set(provenance, preservation);
|
|
57046
58203
|
parsed = preservation.baseline;
|
|
57047
58204
|
}
|
|
@@ -57205,11 +58362,11 @@ var InkKitEditor = class InkKitEditor {
|
|
|
57205
58362
|
const valid = content.firstChild?.isInline ? Fragment.from(schema.nodes.paragraph.create(null, content)) : content;
|
|
57206
58363
|
let markdown;
|
|
57207
58364
|
try {
|
|
57208
|
-
markdown = selectedSource ? selectedSource.markdown : all ? snapshot.text : completeDiagrams.size ?
|
|
58365
|
+
markdown = selectedSource ? selectedSource.markdown : all ? snapshot.text : completeDiagrams.size ? Preservation.read(this.editor.ctx, snapshot.text).serialize(doc.type.create(null, selectionContent(doc, valid))) : selectionMarkdown(this.editor.ctx, doc, valid);
|
|
57209
58366
|
} catch (error) {
|
|
57210
58367
|
throw coded(error, "preservation");
|
|
57211
58368
|
}
|
|
57212
|
-
const result = await this.exportContent(captured, (signal) => portableClipboard(all || selectedDoc ? content : selectionContent(doc, content), schema, markdown, this.options.images, this.context(), completeDiagrams, this.options.files, signal));
|
|
58369
|
+
const result = await this.exportContent(captured, (signal) => portableClipboard(all || selectedDoc ? content : selectionContent(doc, content), schema, markdown, this.options.images, this.context(), completeDiagrams, this.options.files, signal, this.linkSchemes));
|
|
57213
58370
|
const metadata = referenceMetadata(this.editor.ctx, selectedDoc ?? doc, content);
|
|
57214
58371
|
if (metadata != null) result.html = withReferenceMetadata(result.html, metadata);
|
|
57215
58372
|
this.assertCaptured(captured);
|
|
@@ -57260,7 +58417,8 @@ var InkKitEditor = class InkKitEditor {
|
|
|
57260
58417
|
if (view.state.selection.$from.parent.type.spec.code && !inHiddenComment) view.dispatch(view.state.tr.insertText(text.replace(/\r\n?/g, "\n")).scrollIntoView());
|
|
57261
58418
|
else {
|
|
57262
58419
|
const { schema } = view.state;
|
|
57263
|
-
const
|
|
58420
|
+
const { from, to } = view.state.selection;
|
|
58421
|
+
const marks = replacementMarks(view.state, from, to);
|
|
57264
58422
|
const isHTML = !inHiddenComment && htmlBreakAt(view.state.selection.$from);
|
|
57265
58423
|
const lines = text.replace(/\r\n?/g, "\n").split("\n");
|
|
57266
58424
|
const children = literalTextNodes(schema, text, marks, isHTML);
|
|
@@ -57336,6 +58494,10 @@ var InkKitEditor = class InkKitEditor {
|
|
|
57336
58494
|
return this.keys(view, event);
|
|
57337
58495
|
} }
|
|
57338
58496
|
}));
|
|
58497
|
+
indentPlugin = new Plugin({
|
|
58498
|
+
key: new PluginKey("listIndent"),
|
|
58499
|
+
props: { handleKeyDown: (view, event) => this.indentKeys(view, event) }
|
|
58500
|
+
});
|
|
57339
58501
|
copySourceSelection(event) {
|
|
57340
58502
|
event.preventDefault();
|
|
57341
58503
|
event.stopPropagation();
|
|
@@ -57361,7 +58523,7 @@ var InkKitEditor = class InkKitEditor {
|
|
|
57361
58523
|
}
|
|
57362
58524
|
}).catch((error) => this.report(error));
|
|
57363
58525
|
else {
|
|
57364
|
-
const output = clipboardContent(parsed.content, parsed.type.schema);
|
|
58526
|
+
const output = clipboardContent(parsed.content, parsed.type.schema, this.linkSchemes);
|
|
57365
58527
|
if (!event.clipboardData) return;
|
|
57366
58528
|
this.rememberCopy(output, selected.markdown, parsed.content, selected.markdown !== selected.shareable, true);
|
|
57367
58529
|
event.clipboardData.setData("text/plain", output.text);
|
|
@@ -57427,6 +58589,7 @@ var InkKitEditor = class InkKitEditor {
|
|
|
57427
58589
|
ctx.set(rootCtx, root);
|
|
57428
58590
|
ctx.set(authoredSourcesCtx.key, (doc, positions) => instance.authoredSources(doc, positions));
|
|
57429
58591
|
ctx.set(smartPunctuationCtx.key, () => instance.inputPreferences.smartPunctuation === true);
|
|
58592
|
+
ctx.set(linkSchemesCtx.key, instance.linkSchemes);
|
|
57430
58593
|
ctx.update(labelsCtx.key, () => ({
|
|
57431
58594
|
...defaultLabels,
|
|
57432
58595
|
...options.labels
|
|
@@ -57441,9 +58604,16 @@ var InkKitEditor = class InkKitEditor {
|
|
|
57441
58604
|
}), false));
|
|
57442
58605
|
ctx.set(defaultValueCtx, "");
|
|
57443
58606
|
ctx.set(remarkStringifyOptionsCtx, stringifyOptions);
|
|
58607
|
+
ctx.update(editorStateOptionsCtx, (override) => (options) => {
|
|
58608
|
+
const next = override(options);
|
|
58609
|
+
return {
|
|
58610
|
+
...next,
|
|
58611
|
+
plugins: [...next.plugins ?? [], instance.indentPlugin]
|
|
58612
|
+
};
|
|
58613
|
+
});
|
|
57444
58614
|
ctx.update(listItemKeymap.key, (keys) => ({
|
|
57445
58615
|
...keys,
|
|
57446
|
-
SinkListItem: { shortcuts:
|
|
58616
|
+
SinkListItem: { shortcuts: [] },
|
|
57447
58617
|
LiftListItem: { shortcuts: [] }
|
|
57448
58618
|
}));
|
|
57449
58619
|
const unbind = (keymap, keep = []) => ctx.update(keymap.key, (keys) => {
|
|
@@ -57507,7 +58677,7 @@ var InkKitEditor = class InkKitEditor {
|
|
|
57507
58677
|
return true;
|
|
57508
58678
|
}
|
|
57509
58679
|
}));
|
|
57510
|
-
}).use(labelsCtx).use(instance.pasteController.plugin).use(visibleClipboard).use($prose(() => instance.suggestions.plugin())).use(instance.keymapPlugin).use(createDialect(Boolean(options.images || options.files), Boolean(options.wikiLinks), Boolean(options.files))).use(codeControlCtx).use(codeControlsPlugin(() => instance.viewport().rect)).use(tablePlugins).use(tableBlock).use(instance.changePlugin).use(instance.historyInputPlugin).use(history).use(clipboard).use(cursor).use(taskListPlugin).use(quoteBackspace).use(calloutEnter).use(literalEnter).use(literalReread).use(listItemBackspace).use(
|
|
58680
|
+
}).use(labelsCtx).use(linkSchemesCtx).use(instance.pasteController.plugin).use(visibleClipboard).use($prose(() => instance.suggestions.plugin())).use(instance.keymapPlugin).use(createDialect(Boolean(options.images || options.files), Boolean(options.wikiLinks), Boolean(options.files))).use(codeControlCtx).use(codeControlsPlugin(() => instance.viewport().rect)).use(tablePlugins).use(tableBlock).use(instance.changePlugin).use(instance.historyInputPlugin).use(history).use(clipboard).use(cursor).use(taskListPlugin).use(undoTypedRule).use(quoteBackspace).use(calloutEnter).use(literalEnter).use(literalReread).use(listItemBackspace).use(nestedItemEnter).use(rejoinLists).use(movedListItems).use(textInputPolicy).use(events.copy ? codeCopyPlugin((text) => events.copy?.(text)) : []).use(placeholderPlugin).use(options.rendering?.codeHighlighting === false ? [] : (await import("./highlight-LB7Mkd5W.js")).highlightPlugin).use(options.rendering?.diagramPreview === false || !diagramsAvailable() ? [] : mermaidPreview((error) => instance.report(error))).use(selectionPlugin).use($prose(() => search())).use(instance.policyPlugin).use(options.wikiLinks ? wikiLinkView(options.wikiLinks, {
|
|
57511
58681
|
capture: () => instance.adapterCapture(),
|
|
57512
58682
|
active: () => instance.ready && !instance.destroyed && !instance.literalSurface,
|
|
57513
58683
|
labels: {
|
|
@@ -57515,8 +58685,7 @@ var InkKitEditor = class InkKitEditor {
|
|
|
57515
58685
|
...options.labels
|
|
57516
58686
|
},
|
|
57517
58687
|
error: (error) => instance.report(error)
|
|
57518
|
-
}) : []).use(options.images || options.files ? imageView(options.images,
|
|
57519
|
-
adapter: options.files,
|
|
58688
|
+
}) : []).use(options.images || options.files ? imageView(options.images, {
|
|
57520
58689
|
capture: () => instance.adapterCapture(),
|
|
57521
58690
|
active: () => instance.ready && !instance.destroyed && !instance.literalSurface,
|
|
57522
58691
|
labels: {
|
|
@@ -57524,7 +58693,7 @@ var InkKitEditor = class InkKitEditor {
|
|
|
57524
58693
|
...options.labels
|
|
57525
58694
|
},
|
|
57526
58695
|
error: (error) => instance.report(error)
|
|
57527
|
-
}
|
|
58696
|
+
}, options.files, () => {
|
|
57528
58697
|
try {
|
|
57529
58698
|
instance.assertMutation();
|
|
57530
58699
|
return true;
|
|
@@ -57558,7 +58727,7 @@ var InkKitEditor = class InkKitEditor {
|
|
|
57558
58727
|
instance.plain.addEventListener("input", () => {
|
|
57559
58728
|
if (!instance.ready || !instance.literalSurface) return;
|
|
57560
58729
|
if (!instance.writable) {
|
|
57561
|
-
instance.
|
|
58730
|
+
instance.setSourceValue(instance.currentText());
|
|
57562
58731
|
return;
|
|
57563
58732
|
}
|
|
57564
58733
|
try {
|
|
@@ -57658,7 +58827,7 @@ var InkKitEditor = class InkKitEditor {
|
|
|
57658
58827
|
const content = expanded;
|
|
57659
58828
|
const valid = fragment.firstChild?.isInline ? Fragment.from(view.state.schema.nodes.paragraph.create(null, fragment)) : fragment;
|
|
57660
58829
|
const markdown = selectionMarkdown(instance.editor.ctx, view.state.doc, valid);
|
|
57661
|
-
const output = clipboardContent(content, view.state.schema);
|
|
58830
|
+
const output = clipboardContent(content, view.state.schema, instance.linkSchemes);
|
|
57662
58831
|
const metadata = referenceMetadata(instance.editor.ctx, view.state.doc, valid);
|
|
57663
58832
|
if (metadata != null) output.html = withReferenceMetadata(output.html, metadata);
|
|
57664
58833
|
instance.rememberCopy(output, markdown, fragment, false, true);
|
|
@@ -57709,7 +58878,7 @@ var InkKitEditor = class InkKitEditor {
|
|
|
57709
58878
|
const markdown = input.format === "txt" ? "" : input.text;
|
|
57710
58879
|
let preservation;
|
|
57711
58880
|
try {
|
|
57712
|
-
preservation =
|
|
58881
|
+
preservation = Preservation.read(this.editor.ctx, markdown);
|
|
57713
58882
|
} catch (error) {
|
|
57714
58883
|
throw new InkKitError("preservation", "The document was not loaded because its Markdown could not be shown without losing part of it", { cause: error });
|
|
57715
58884
|
}
|
|
@@ -57734,7 +58903,7 @@ var InkKitEditor = class InkKitEditor {
|
|
|
57734
58903
|
this.plainSearch = "";
|
|
57735
58904
|
this.literalMatch = void 0;
|
|
57736
58905
|
this.formatType = input.format;
|
|
57737
|
-
this.
|
|
58906
|
+
this.setSourceValue(input.text);
|
|
57738
58907
|
this.plain.setSelectionRange(this.plain.value.length, this.plain.value.length);
|
|
57739
58908
|
this.load(markdown, preservation);
|
|
57740
58909
|
this.originalSource = input.text;
|
|
@@ -58311,10 +59480,23 @@ var InkKitEditor = class InkKitEditor {
|
|
|
58311
59480
|
this.assertReady(expectedGeneration);
|
|
58312
59481
|
this.releaseFocus();
|
|
58313
59482
|
}
|
|
59483
|
+
/**
|
|
59484
|
+
* Resolves wiki links and file embeds again, all of them or those whose `target` is named, after
|
|
59485
|
+
* something they point to changed. A file keeps its card until the new answer differs. Changes no
|
|
59486
|
+
* document state, so it works in a read-only editor and during composition. Source and TXT modes
|
|
59487
|
+
* draw no references; named file answers are invalidated and resolved when formatted mode returns.
|
|
59488
|
+
*/
|
|
59489
|
+
refreshReferences(targets, expectedGeneration) {
|
|
59490
|
+
this.assertAlive();
|
|
59491
|
+
const names = isOmitted(targets) ? void 0 : new Set(expectArray(targets, "targets").map((target) => expectString(target, "targets entry")));
|
|
59492
|
+
this.assertReady(expectedGeneration);
|
|
59493
|
+
requestRefresh(this.editor.ctx.get(editorViewCtx).dom, { ...names && { targets: names } });
|
|
59494
|
+
}
|
|
58314
59495
|
/** Replaces every binding. Keys are in ProseMirror's notation. A key given to two shortcuts goes
|
|
58315
59496
|
* to the later one, in the order history, formatting, block moves, tables, so it lands the same
|
|
58316
59497
|
* way every time. A table binding passes a key it shares with a block move to the move outside
|
|
58317
|
-
* a table.
|
|
59498
|
+
* a table. List indentation keys apply after all of these, and after the table keys the editor
|
|
59499
|
+
* keeps for itself. */
|
|
58318
59500
|
setKeymap(keymap) {
|
|
58319
59501
|
this.assertAlive();
|
|
58320
59502
|
keymap = keymapBindings(keymap, "keymap");
|
|
@@ -58324,6 +59506,8 @@ var InkKitEditor = class InkKitEditor {
|
|
|
58324
59506
|
moveBlockUp: ["Alt-ArrowUp"],
|
|
58325
59507
|
moveBlockDown: ["Alt-ArrowDown"],
|
|
58326
59508
|
tableExit: ["Mod-Enter", "Enter"],
|
|
59509
|
+
indent: ["Tab"],
|
|
59510
|
+
outdent: ["Shift-Tab"],
|
|
58327
59511
|
...keymap
|
|
58328
59512
|
};
|
|
58329
59513
|
const bindings = {};
|
|
@@ -58350,6 +59534,9 @@ var InkKitEditor = class InkKitEditor {
|
|
|
58350
59534
|
if (move === "move" && !this.composing && !this.pasteController.pending) this.forPerson(() => this.moveBlock(direction), false);
|
|
58351
59535
|
return true;
|
|
58352
59536
|
};
|
|
59537
|
+
const indents = {};
|
|
59538
|
+
const sink = (state, dispatch) => sinkListItem(state.schema.nodes.list_item)(state, dispatch);
|
|
59539
|
+
for (const [name, command] of [["indent", sink], ["outdent", liftItem]]) for (const key of this.configuredKeys[name] ?? []) indents[key] = (state, dispatch, view) => this.ready && this.writable && !this.literalSurface ? command(state, dispatch, view) : false;
|
|
58353
59540
|
for (const command of tableCommands) for (const key of this.configuredKeys[tableShortcut(command)] ?? []) bindings[key] = (state, dispatch, view) => {
|
|
58354
59541
|
if (!this.ready || !this.commandState().commands.table[command]) return moves[key]?.(state, dispatch, view) ?? false;
|
|
58355
59542
|
return this.forPerson(() => this.table(command), true);
|
|
@@ -58358,6 +59545,7 @@ var InkKitEditor = class InkKitEditor {
|
|
|
58358
59545
|
throw new InkKitError("read-only", "The editor is read-only");
|
|
58359
59546
|
}])));
|
|
58360
59547
|
this.keys = keydownHandler(bindings);
|
|
59548
|
+
this.indentKeys = keydownHandler(indents);
|
|
58361
59549
|
this.literalKeys = keydownHandler(historyBindings);
|
|
58362
59550
|
}
|
|
58363
59551
|
/** Dropped files land as one paragraph per path at the drop point: in place of an empty block, after
|
|
@@ -58385,17 +59573,12 @@ var InkKitEditor = class InkKitEditor {
|
|
|
58385
59573
|
this.assertMutation(expectedGeneration);
|
|
58386
59574
|
if (!images.length || !this.canInsertImages || this.literalSurface) return false;
|
|
58387
59575
|
const view = this.editor.ctx.get(editorViewCtx);
|
|
58388
|
-
const { schema } = view.state;
|
|
58389
59576
|
const placement = point ? void 0 : imagePlacement(view.state);
|
|
58390
59577
|
if (placement?.kind === "inline") {
|
|
58391
59578
|
this.insertInline(images);
|
|
58392
59579
|
return true;
|
|
58393
59580
|
}
|
|
58394
|
-
const blocks =
|
|
58395
|
-
src: image.reference,
|
|
58396
|
-
alt: image.alt,
|
|
58397
|
-
title: image.title ?? ""
|
|
58398
|
-
})));
|
|
59581
|
+
const blocks = this.imageBlocks(images);
|
|
58399
59582
|
if (point) {
|
|
58400
59583
|
this.insertBlocks(blocks, point);
|
|
58401
59584
|
return true;
|
|
@@ -58411,6 +59594,31 @@ var InkKitEditor = class InkKitEditor {
|
|
|
58411
59594
|
view.dispatch(tr.scrollIntoView());
|
|
58412
59595
|
return true;
|
|
58413
59596
|
}
|
|
59597
|
+
/** Adds images as the last blocks of the document and leaves everything else as it is: no focus,
|
|
59598
|
+
* no scrolling, and the selection stays on the text it covered. For a host that attaches images
|
|
59599
|
+
* to a document the person is not editing at that moment. Returns false when it does nothing. */
|
|
59600
|
+
appendImages(images, expectedGeneration) {
|
|
59601
|
+
this.assertAlive();
|
|
59602
|
+
images = imageInsertions(images);
|
|
59603
|
+
this.assertMutation(expectedGeneration);
|
|
59604
|
+
if (!images.length || !this.canInsertImages || this.literalSurface) return false;
|
|
59605
|
+
const view = this.editor.ctx.get(editorViewCtx);
|
|
59606
|
+
const { doc, tr } = view.state;
|
|
59607
|
+
const blocks = this.imageBlocks(images);
|
|
59608
|
+
if (doc.childCount === 1 && doc.firstChild.type.name === "paragraph" && doc.firstChild.content.size === 0 && this.currentText().trim() === "") tr.replaceWith(0, doc.content.size, blocks);
|
|
59609
|
+
else tr.insert(doc.content.size, blocks);
|
|
59610
|
+
view.dispatch(closeHistory(tr));
|
|
59611
|
+
view.dispatch(closeHistory(view.state.tr).setMeta("addToHistory", false));
|
|
59612
|
+
return true;
|
|
59613
|
+
}
|
|
59614
|
+
imageBlocks(images) {
|
|
59615
|
+
const { schema } = this.editor.ctx.get(editorViewCtx).state;
|
|
59616
|
+
return images.map((image) => schema.nodes.paragraph.create(null, schema.nodes.image.create({
|
|
59617
|
+
src: image.reference,
|
|
59618
|
+
alt: image.alt,
|
|
59619
|
+
title: image.title ?? ""
|
|
59620
|
+
})));
|
|
59621
|
+
}
|
|
58414
59622
|
insertInline(images) {
|
|
58415
59623
|
const view = this.editor.ctx.get(editorViewCtx);
|
|
58416
59624
|
const { state } = view;
|
|
@@ -58528,7 +59736,7 @@ var InkKitEditor = class InkKitEditor {
|
|
|
58528
59736
|
if (!range) return;
|
|
58529
59737
|
const target = liftTarget(range);
|
|
58530
59738
|
if (target == null) return;
|
|
58531
|
-
view.dispatch(view.state
|
|
59739
|
+
view.dispatch(liftQuote(view.state, range, target));
|
|
58532
59740
|
}
|
|
58533
59741
|
/** Changes the selected textblocks' type, keeping everything they hold. */
|
|
58534
59742
|
textblockType(type, attr) {
|
|
@@ -58613,25 +59821,27 @@ var InkKitEditor = class InkKitEditor {
|
|
|
58613
59821
|
commit(command);
|
|
58614
59822
|
return;
|
|
58615
59823
|
}
|
|
59824
|
+
const onHostError = (error) => {
|
|
59825
|
+
if (!this.destroyed) this.report(coded(error, "slash-command-failed"));
|
|
59826
|
+
};
|
|
59827
|
+
const insert = (markdown) => {
|
|
59828
|
+
if (this.destroyed) return;
|
|
59829
|
+
if (markdown === void 0) return;
|
|
59830
|
+
if (typeof markdown !== "string") {
|
|
59831
|
+
this.report(invalidArgument("A slash command must return Markdown text"));
|
|
59832
|
+
return;
|
|
59833
|
+
}
|
|
59834
|
+
commit({ markdown });
|
|
59835
|
+
};
|
|
59836
|
+
let result;
|
|
58616
59837
|
try {
|
|
58617
|
-
|
|
58618
|
-
const insert = (markdown) => {
|
|
58619
|
-
if (this.destroyed) return;
|
|
58620
|
-
if (markdown === void 0) return;
|
|
58621
|
-
if (typeof markdown !== "string") {
|
|
58622
|
-
this.report(invalidArgument("A slash command must return Markdown text"));
|
|
58623
|
-
return;
|
|
58624
|
-
}
|
|
58625
|
-
commit({ markdown });
|
|
58626
|
-
};
|
|
58627
|
-
if (result instanceof Promise) result.then(insert).catch((error) => {
|
|
58628
|
-
if (this.destroyed) return;
|
|
58629
|
-
this.report(error);
|
|
58630
|
-
});
|
|
58631
|
-
else insert(result);
|
|
59838
|
+
result = command.action(this.context());
|
|
58632
59839
|
} catch (error) {
|
|
58633
|
-
|
|
59840
|
+
onHostError(error);
|
|
59841
|
+
return;
|
|
58634
59842
|
}
|
|
59843
|
+
if (result instanceof Promise) result.then(insert, onHostError);
|
|
59844
|
+
else insert(result);
|
|
58635
59845
|
}
|
|
58636
59846
|
/** Returns whether the document or the marks the next typed text takes changed. */
|
|
58637
59847
|
format(command, options, expectedGeneration) {
|
|
@@ -58692,12 +59902,13 @@ var InkKitEditor = class InkKitEditor {
|
|
|
58692
59902
|
return !after.doc.eq(before.doc) || !Mark.sameSet(marks(after), marks(before));
|
|
58693
59903
|
}
|
|
58694
59904
|
/**
|
|
58695
|
-
* Refuses a link destination that is empty, that opens anything but a web, mail or phone address
|
|
58696
|
-
* or that the Markdown writer cannot save so that it reads back the
|
|
59905
|
+
* Refuses a link destination that is empty, that opens anything but a web, mail or phone address
|
|
59906
|
+
* or a scheme the host listed, or that the Markdown writer cannot save so that it reads back the
|
|
59907
|
+
* same.
|
|
58697
59908
|
*/
|
|
58698
59909
|
checkDestination(destination, name) {
|
|
58699
59910
|
if (destination.trim() === "") throw invalidArgument(`${name} must not be empty`);
|
|
58700
|
-
if (!isSafeLinkTarget(destination)) throw invalidArgument(`${name} must be relative, or an http, https, mailto or
|
|
59911
|
+
if (!isSafeLinkTarget(destination, this.linkSchemes)) throw invalidArgument(`${name} must be relative, or an address with an allowed scheme (http, https, mailto, tel or one of linkSchemes), with no control characters`);
|
|
58701
59912
|
const { schema } = this.editor.ctx.get(editorViewCtx).state;
|
|
58702
59913
|
const written = serialize(this.editor.ctx, schema.node("doc", null, [schema.node("paragraph", null, [schema.text("x", [schema.marks.link.create({ href: destination })])])]));
|
|
58703
59914
|
let read;
|
|
@@ -58719,13 +59930,18 @@ var InkKitEditor = class InkKitEditor {
|
|
|
58719
59930
|
const { selection, storedMarks } = state;
|
|
58720
59931
|
const { from, to, empty } = selection;
|
|
58721
59932
|
const stored = empty ? type.isInSet(storedMarks ?? []) : void 0;
|
|
58722
|
-
|
|
59933
|
+
const beside = empty ? selection.$from.nodeBefore?.marks ?? [] : [];
|
|
59934
|
+
if (stored && !stored.isInSet(selection.$from.marks()) && !stored.isInSet(beside)) {
|
|
58723
59935
|
const tr = state.tr.removeStoredMark(type);
|
|
58724
59936
|
if (destination !== void 0) tr.addStoredMark(type.create({ href: destination }));
|
|
58725
59937
|
view.dispatch(tr);
|
|
58726
59938
|
return;
|
|
58727
59939
|
}
|
|
58728
|
-
const mark = type.isInSet(empty ? [
|
|
59940
|
+
const mark = type.isInSet(empty ? [
|
|
59941
|
+
...selection.$from.marks(),
|
|
59942
|
+
...beside,
|
|
59943
|
+
...state.doc.nodeAt(from)?.marks ?? []
|
|
59944
|
+
] : state.doc.nodeAt(from)?.marks ?? []);
|
|
58729
59945
|
const extent = mark && markRun(state.doc, mark, from, to);
|
|
58730
59946
|
const keepStored = (tr, link) => {
|
|
58731
59947
|
if (!storedMarks) return tr;
|
|
@@ -58857,6 +60073,7 @@ var InkKitEditor = class InkKitEditor {
|
|
|
58857
60073
|
"pasteAsPlainText",
|
|
58858
60074
|
"commandState",
|
|
58859
60075
|
"setEditable",
|
|
60076
|
+
"setHostActive",
|
|
58860
60077
|
"setTextInputPreferences",
|
|
58861
60078
|
"setEditingMode",
|
|
58862
60079
|
"replaceSource",
|
|
@@ -58872,12 +60089,14 @@ var InkKitEditor = class InkKitEditor {
|
|
|
58872
60089
|
"keyDown",
|
|
58873
60090
|
"insertPaths",
|
|
58874
60091
|
"insertImages",
|
|
60092
|
+
"appendImages",
|
|
58875
60093
|
"insertFootnote",
|
|
58876
60094
|
"navigateFootnote",
|
|
58877
60095
|
"editReferenceDefinition",
|
|
58878
60096
|
"setCommentsVisible",
|
|
58879
60097
|
"focus",
|
|
58880
60098
|
"blur",
|
|
60099
|
+
"refreshReferences",
|
|
58881
60100
|
"setKeymap",
|
|
58882
60101
|
"textSnapshot",
|
|
58883
60102
|
"selectTextRange",
|