@rathkit/rte-core 0.1.0-alpha.3 → 0.1.0-alpha.5
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/README.md +1 -1
- package/dist/autoformat/autoformat.js +18 -3
- package/dist/base64.js +5 -1
- package/dist/dom/index.d.ts +1 -1
- package/dist/dom/render.js +26 -15
- package/dist/dom/view.d.ts +59 -6
- package/dist/dom/view.js +195 -38
- package/dist/edit.d.ts +6 -0
- package/dist/edit.js +101 -11
- package/dist/engine.d.ts +26 -4
- package/dist/engine.js +113 -23
- package/dist/export.d.ts +2 -2
- package/dist/export.js +22 -6
- package/dist/footnotes/index.d.ts +2 -0
- package/dist/footnotes/index.js +2 -0
- package/dist/footnotes/plugin.d.ts +6 -0
- package/dist/footnotes/plugin.js +130 -0
- package/dist/footnotes/reconcile.d.ts +4 -0
- package/dist/footnotes/reconcile.js +155 -0
- package/dist/html/parse.d.ts +8 -2
- package/dist/html/parse.js +6 -2
- package/dist/images/images.js +4 -3
- package/dist/images/index.d.ts +5 -1
- package/dist/images/index.js +3 -1
- package/dist/images/plugin.js +2 -1
- package/dist/{dom/imageview.d.ts → images/view.d.ts} +9 -6
- package/dist/{dom/imageview.js → images/view.js} +20 -14
- package/dist/import.d.ts +18 -2
- package/dist/import.js +87 -42
- package/dist/index.d.ts +4 -1
- package/dist/index.js +3 -1
- package/dist/lists/lists.js +55 -30
- package/dist/markdown/detect.d.ts +1 -0
- package/dist/markdown/detect.js +81 -0
- package/dist/markdown/export.d.ts +10 -0
- package/dist/markdown/export.js +252 -0
- package/dist/markdown/index.d.ts +5 -0
- package/dist/markdown/index.js +4 -0
- package/dist/markdown/inline.d.ts +37 -0
- package/dist/markdown/inline.js +604 -0
- package/dist/markdown/parse.d.ts +4 -0
- package/dist/markdown/parse.js +586 -0
- package/dist/markdown/plugin.d.ts +20 -0
- package/dist/markdown/plugin.js +56 -0
- package/dist/model.d.ts +30 -2
- package/dist/model.js +2 -0
- package/dist/notes.d.ts +6 -0
- package/dist/notes.js +49 -0
- package/dist/ops.d.ts +6 -1
- package/dist/ops.js +5 -4
- package/dist/paste.js +9 -2
- package/dist/path.d.ts +10 -1
- package/dist/path.js +110 -11
- package/dist/plugin.d.ts +53 -2
- package/dist/policy.d.ts +41 -0
- package/dist/policy.js +40 -0
- package/dist/standard/index.d.ts +5 -3
- package/dist/standard/index.js +6 -5
- package/dist/stats.js +1 -1
- package/dist/svg/svg.js +9 -1
- package/dist/{dom/tableview.d.ts → tables/cells.d.ts} +7 -6
- package/dist/{dom/tableview.js → tables/cells.js} +16 -12
- package/dist/{dom/tablegrips.d.ts → tables/grips.d.ts} +5 -4
- package/dist/{dom/tablegrips.js → tables/grips.js} +10 -9
- package/dist/tables/index.d.ts +5 -1
- package/dist/tables/index.js +3 -1
- package/dist/tables/view.d.ts +2 -0
- package/dist/tables/view.js +15 -0
- package/dist/warning.d.ts +16 -0
- package/dist/warning.js +5 -0
- package/package.json +23 -1
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
const MAX_KEPT = 64;
|
|
2
|
+
export function createReconciler(ops) {
|
|
3
|
+
const kept = new Map();
|
|
4
|
+
const keep = (id, item) => {
|
|
5
|
+
kept.delete(id);
|
|
6
|
+
kept.set(id, item);
|
|
7
|
+
if (kept.size > MAX_KEPT)
|
|
8
|
+
kept.delete(kept.keys().next().value);
|
|
9
|
+
};
|
|
10
|
+
const paragraph = { type: "br", paragraph: true };
|
|
11
|
+
const join = (a, b) => {
|
|
12
|
+
if (a.children.length > 0 && b.content.length > 0) {
|
|
13
|
+
const text = { type: "p", content: b.content };
|
|
14
|
+
return { item: { ...a, children: [...a.children, text, ...b.children] }, add: 0, childAdd: a.children.length };
|
|
15
|
+
}
|
|
16
|
+
const both = a.content.length > 0;
|
|
17
|
+
return {
|
|
18
|
+
item: { ...a, content: ops.normalizeInline([...a.content, ...(both ? [paragraph] : []), ...b.content]), children: [...a.children, ...b.children] },
|
|
19
|
+
add: both ? ops.inlineLength(a.content) + 1 : ops.inlineLength(a.content), childAdd: a.children.length,
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
return (doc, sel) => {
|
|
23
|
+
let current = doc;
|
|
24
|
+
const found = ops.noteIds(current);
|
|
25
|
+
const lists = current.blocks.flatMap((block, b) => (ops.isNotes(block) ? [b] : []));
|
|
26
|
+
if (found.length === 0 && lists.length === 0)
|
|
27
|
+
return { doc, selection: sel };
|
|
28
|
+
const copies = new Map();
|
|
29
|
+
if (new Set(found).size !== found.length) {
|
|
30
|
+
const used = new Set(found);
|
|
31
|
+
const seen = new Set();
|
|
32
|
+
const fresh = () => { for (let n = used.size + 1;; n++)
|
|
33
|
+
if (!used.has(`n${n}`)) {
|
|
34
|
+
used.add(`n${n}`);
|
|
35
|
+
return `n${n}`;
|
|
36
|
+
} };
|
|
37
|
+
for (const path of ops.containerPaths(current)) {
|
|
38
|
+
if (lists.includes(path[0]))
|
|
39
|
+
continue;
|
|
40
|
+
const content = ops.getContent(current, path);
|
|
41
|
+
if (!content.some((n) => n.type === "note" && seen.has(n.id))) {
|
|
42
|
+
for (const n of content)
|
|
43
|
+
if (n.type === "note")
|
|
44
|
+
seen.add(n.id);
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
current = ops.setContent(current, path, content.map((n) => {
|
|
48
|
+
if (n.type !== "note")
|
|
49
|
+
return n;
|
|
50
|
+
if (!seen.has(n.id)) {
|
|
51
|
+
seen.add(n.id);
|
|
52
|
+
return n;
|
|
53
|
+
}
|
|
54
|
+
const id = fresh();
|
|
55
|
+
copies.set(id, n.id);
|
|
56
|
+
return { type: "note", id };
|
|
57
|
+
}));
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
const ids = ops.noteIds(current);
|
|
61
|
+
const groups = new Map();
|
|
62
|
+
const moved = new Map();
|
|
63
|
+
let lead;
|
|
64
|
+
const leading = [];
|
|
65
|
+
let last;
|
|
66
|
+
let flat = 0;
|
|
67
|
+
const order = ids.filter((id, i) => ids.indexOf(id) === i);
|
|
68
|
+
for (const b of lists) {
|
|
69
|
+
current.blocks[b].items.forEach((item) => {
|
|
70
|
+
const id = item.id;
|
|
71
|
+
if (id !== undefined && !groups.has(id)) {
|
|
72
|
+
const joined = lead ? join(lead, item) : { item, add: 0, childAdd: 0 };
|
|
73
|
+
groups.set(id, joined.item === item ? item : { ...joined.item, id });
|
|
74
|
+
last = id;
|
|
75
|
+
for (const n of leading)
|
|
76
|
+
moved.set(n, { index: order.indexOf(id), add: moved.get(n)?.add ?? 0, childAdd: 0 });
|
|
77
|
+
moved.set(flat, { index: order.indexOf(id), add: joined.add, childAdd: joined.childAdd });
|
|
78
|
+
lead = undefined;
|
|
79
|
+
leading.length = 0;
|
|
80
|
+
}
|
|
81
|
+
else if (last !== undefined) {
|
|
82
|
+
const { item: next, add, childAdd } = join(groups.get(last), item);
|
|
83
|
+
groups.set(last, next);
|
|
84
|
+
moved.set(flat, { index: order.indexOf(last), add, childAdd });
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
const joined = lead ? join(lead, item) : { item, add: 0, childAdd: 0 };
|
|
88
|
+
lead = joined.item;
|
|
89
|
+
moved.set(flat, { index: -1, add: joined.add, childAdd: joined.childAdd });
|
|
90
|
+
leading.push(flat);
|
|
91
|
+
}
|
|
92
|
+
flat++;
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
if (lead && order[0] !== undefined) {
|
|
96
|
+
const target = order[0];
|
|
97
|
+
groups.set(target, groups.has(target) ? join(lead, groups.get(target)).item : { ...lead, id: target });
|
|
98
|
+
for (const n of leading)
|
|
99
|
+
moved.set(n, { index: 0, add: moved.get(n)?.add ?? 0, childAdd: 0 });
|
|
100
|
+
}
|
|
101
|
+
for (const [id, item] of groups)
|
|
102
|
+
if (!order.includes(id))
|
|
103
|
+
keep(id, item);
|
|
104
|
+
const wanted = order.map((id) => {
|
|
105
|
+
const have = groups.get(id);
|
|
106
|
+
if (have)
|
|
107
|
+
return have.id === id ? have : { ...have, id };
|
|
108
|
+
const source = copies.get(id);
|
|
109
|
+
const old = kept.get(id) ?? (source !== undefined ? groups.get(source) : undefined);
|
|
110
|
+
kept.delete(id);
|
|
111
|
+
return { ...(old ?? { content: [], children: [] }), id };
|
|
112
|
+
});
|
|
113
|
+
const first = lists[0];
|
|
114
|
+
const only = first !== undefined ? current.blocks[first] : undefined;
|
|
115
|
+
if (lists.length === 1 && only && only.items.length === wanted.length && only.items.every((item, i) => item === wanted[i]) && current === doc)
|
|
116
|
+
return { doc, selection: sel };
|
|
117
|
+
const block = wanted.length > 0 ? { ...(only ?? { type: "ol" }), type: "ol", notes: true, items: wanted } : undefined;
|
|
118
|
+
const blocks = [];
|
|
119
|
+
const newIndex = new Map();
|
|
120
|
+
current.blocks.forEach((b, i) => {
|
|
121
|
+
if (i === first) {
|
|
122
|
+
if (block) {
|
|
123
|
+
newIndex.set(i, blocks.length);
|
|
124
|
+
blocks.push(block);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
else if (!lists.includes(i)) {
|
|
128
|
+
newIndex.set(i, blocks.length);
|
|
129
|
+
blocks.push(b);
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
const at = first === undefined && block ? blocks.length : (newIndex.get(first) ?? 0);
|
|
133
|
+
if (first === undefined && block)
|
|
134
|
+
blocks.push(block);
|
|
135
|
+
let offsetOf = 0;
|
|
136
|
+
const flatStart = new Map();
|
|
137
|
+
for (const b of lists) {
|
|
138
|
+
flatStart.set(b, offsetOf);
|
|
139
|
+
offsetOf += current.blocks[b].items.length;
|
|
140
|
+
}
|
|
141
|
+
const next = { blocks };
|
|
142
|
+
const map = (pos) => {
|
|
143
|
+
const [b, i, ...rest] = pos.path;
|
|
144
|
+
if (lists.includes(b)) {
|
|
145
|
+
const to = moved.get(flatStart.get(b) + i);
|
|
146
|
+
if (!to || !block)
|
|
147
|
+
return ops.clampPos(next, { path: [Math.min(at, blocks.length - 1)], offset: 0 });
|
|
148
|
+
const [k, ...deeper] = rest;
|
|
149
|
+
return { path: k === undefined ? [at, to.index] : [at, to.index, k + to.childAdd, ...deeper], offset: pos.offset + (rest.length === 0 ? to.add : 0) };
|
|
150
|
+
}
|
|
151
|
+
return ops.clampPos(next, { path: [newIndex.get(b) ?? b, ...pos.path.slice(1)], offset: pos.offset });
|
|
152
|
+
};
|
|
153
|
+
return { doc: next, selection: { anchor: map(sel.anchor), focus: map(sel.focus) } };
|
|
154
|
+
};
|
|
155
|
+
}
|
package/dist/html/parse.d.ts
CHANGED
|
@@ -9,6 +9,12 @@ export interface HText {
|
|
|
9
9
|
readonly text: string;
|
|
10
10
|
}
|
|
11
11
|
export type HNode = HElement | HText;
|
|
12
|
-
/**
|
|
13
|
-
export declare
|
|
12
|
+
/** Deepest nesting read when the caller does not say. */
|
|
13
|
+
export declare const DEFAULT_MAX_DEPTH = 100;
|
|
14
|
+
/**
|
|
15
|
+
* Parses markup into nodes. Tag and attribute names are lower-cased and entities in text and values are decoded. An element
|
|
16
|
+
* that would nest deeper than `maxDepth` is left out and what is inside it stays in the deepest element allowed, so the tree is
|
|
17
|
+
* never deeper than that however the markup is written.
|
|
18
|
+
*/
|
|
19
|
+
export declare function parseHtml(source: string, maxDepth?: number): HNode[];
|
|
14
20
|
export declare function findAll(nodes: readonly HNode[], tag: string, out?: HElement[]): HElement[];
|
package/dist/html/parse.js
CHANGED
|
@@ -7,7 +7,8 @@ const BLOCKS_CLOSING_P = new Set([
|
|
|
7
7
|
]);
|
|
8
8
|
const TAG_NAME = /[A-Za-z][^\s/>]*/y;
|
|
9
9
|
const ATTRIBUTE = /([^\s"'<>/=]+)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'=<>`]+)))?/y;
|
|
10
|
-
export
|
|
10
|
+
export const DEFAULT_MAX_DEPTH = 100;
|
|
11
|
+
export function parseHtml(source, maxDepth = DEFAULT_MAX_DEPTH) {
|
|
11
12
|
const root = { type: "el", tag: "#root", attrs: {}, children: [] };
|
|
12
13
|
const stack = [root];
|
|
13
14
|
const top = () => stack[stack.length - 1];
|
|
@@ -123,9 +124,12 @@ export function parseHtml(source) {
|
|
|
123
124
|
closeWithin(new Set(["thead", "tbody", "tfoot"]), new Set(["table"]));
|
|
124
125
|
if (BLOCKS_CLOSING_P.has(tag))
|
|
125
126
|
closeWithin(new Set(["p"]), new Set(["li", "td", "th", "table", "blockquote", "div", "ul", "ol"]));
|
|
127
|
+
const void_ = VOID.has(tag);
|
|
128
|
+
if (!void_ && stack.length > maxDepth)
|
|
129
|
+
continue;
|
|
126
130
|
const el = { type: "el", tag, attrs, children: [] };
|
|
127
131
|
top().children.push(el);
|
|
128
|
-
if (!
|
|
132
|
+
if (!void_)
|
|
129
133
|
stack.push(el);
|
|
130
134
|
}
|
|
131
135
|
return root.children;
|
package/dist/images/images.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { decodeBase64 } from "../base64.js";
|
|
2
|
+
import { asChildren } from "../path.js";
|
|
2
3
|
export function dataImageBytes(src) {
|
|
3
4
|
const comma = src.indexOf(",");
|
|
4
5
|
if (!/^data:/i.test(src) || comma === -1 || !/;base64$/i.test(src.slice(0, comma)))
|
|
@@ -26,8 +27,8 @@ export function mapImages(blocks, fn) {
|
|
|
26
27
|
const list = (l) => {
|
|
27
28
|
const items = l.items.flatMap((item) => {
|
|
28
29
|
const { content, emptied } = inline(item.content);
|
|
29
|
-
const
|
|
30
|
-
return emptied &&
|
|
30
|
+
const children = asChildren(walk(item.children));
|
|
31
|
+
return emptied && children.length === 0 ? [] : [{ ...item, content, children }];
|
|
31
32
|
});
|
|
32
33
|
return items.length > 0 || l.items.length === 0 ? { ...l, items } : undefined;
|
|
33
34
|
};
|
|
@@ -74,7 +75,7 @@ export function collectImages(blocks) {
|
|
|
74
75
|
const inline = (content) => { for (const node of content)
|
|
75
76
|
if (node.type === "image")
|
|
76
77
|
found.push(node); };
|
|
77
|
-
const list = (l) => l.items.forEach((item) => { inline(item.content); item.
|
|
78
|
+
const list = (l) => l.items.forEach((item) => { inline(item.content); walk(item.children); });
|
|
78
79
|
const walk = (bs) => {
|
|
79
80
|
for (const block of bs) {
|
|
80
81
|
if (block.type === "p" || block.type === "h")
|
package/dist/images/index.d.ts
CHANGED
|
@@ -1,2 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
import { type ImagesOptions } from "./plugin.ts";
|
|
2
|
+
import type { Plugin } from "../plugin.ts";
|
|
3
|
+
export type { ImagesOptions };
|
|
4
|
+
/** The images plugin, with the part that selects and resizes images in a browser. (`./plugin.ts` is the same without it.) */
|
|
5
|
+
export declare const images: (options?: ImagesOptions) => Plugin;
|
|
2
6
|
export { collectImages, dataImageBytes, isDataImage, mapImages, readDataImage, rewriteImages } from "./images.ts";
|
package/dist/images/index.js
CHANGED
|
@@ -1,2 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
import { images as engineOnly } from "./plugin.js";
|
|
2
|
+
import { imagesView } from "./view.js";
|
|
3
|
+
export const images = (options) => ({ ...engineOnly(options), view: imagesView });
|
|
2
4
|
export { collectImages, dataImageBytes, isDataImage, mapImages, readDataImage, rewriteImages } from "./images.js";
|
package/dist/images/plugin.js
CHANGED
|
@@ -21,7 +21,8 @@ export function images(options = {}) {
|
|
|
21
21
|
const checked = url ? checkImageSrc(url) : undefined;
|
|
22
22
|
return checked ?? reject("unsupported", file.type, file.size);
|
|
23
23
|
}
|
|
24
|
-
catch {
|
|
24
|
+
catch (error) {
|
|
25
|
+
host.editor.report({ code: "upload-failed", message: `Uploading an image failed: ${error instanceof Error ? error.message : String(error)}`, error });
|
|
25
26
|
return reject("upload-failed", file.type, file.size);
|
|
26
27
|
}
|
|
27
28
|
};
|
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ViewExtension, ViewHost } from "../plugin.ts";
|
|
2
2
|
/** The attribute on the selected image, for styling. */
|
|
3
|
-
export declare const SELECTED_IMAGE = "data-
|
|
3
|
+
export declare const SELECTED_IMAGE = "data-rte-image-selected";
|
|
4
4
|
export declare class ImageSelection {
|
|
5
|
-
private readonly
|
|
6
|
-
private readonly engine;
|
|
7
|
-
private readonly quiet;
|
|
5
|
+
private readonly host;
|
|
8
6
|
private marked;
|
|
9
7
|
private handle;
|
|
10
8
|
private drag;
|
|
11
9
|
private readonly stops;
|
|
12
|
-
|
|
10
|
+
private readonly root;
|
|
11
|
+
private readonly engine;
|
|
12
|
+
private readonly quiet;
|
|
13
|
+
constructor(host: ViewHost);
|
|
13
14
|
/** The drawn element of the selected image, or undefined. */
|
|
14
15
|
private find;
|
|
15
16
|
update(): void;
|
|
@@ -19,3 +20,5 @@ export declare class ImageSelection {
|
|
|
19
20
|
private start;
|
|
20
21
|
destroy(): void;
|
|
21
22
|
}
|
|
23
|
+
/** Images in the page: a click selects one, and its corner can be dragged to resize it. Comes with the images plugin. */
|
|
24
|
+
export declare const imagesView: ViewExtension;
|
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
import { imageSelection, selectedImage } from "../imageselect.js";
|
|
2
|
-
|
|
3
|
-
export const SELECTED_IMAGE = "data-rk-image-selected";
|
|
2
|
+
export const SELECTED_IMAGE = "data-rte-image-selected";
|
|
4
3
|
const MIN = 16;
|
|
5
4
|
export class ImageSelection {
|
|
6
|
-
|
|
7
|
-
engine;
|
|
8
|
-
quiet;
|
|
5
|
+
host;
|
|
9
6
|
marked;
|
|
10
7
|
handle;
|
|
11
8
|
drag;
|
|
12
9
|
stops = [];
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
10
|
+
root;
|
|
11
|
+
engine;
|
|
12
|
+
quiet;
|
|
13
|
+
constructor(host) {
|
|
14
|
+
this.host = host;
|
|
15
|
+
this.root = host.element;
|
|
16
|
+
this.engine = host.engine;
|
|
17
|
+
this.quiet = () => host.quiet();
|
|
17
18
|
const reposition = () => this.place();
|
|
18
19
|
window.addEventListener("scroll", reposition, true);
|
|
19
20
|
window.addEventListener("resize", reposition);
|
|
@@ -22,7 +23,7 @@ export class ImageSelection {
|
|
|
22
23
|
const target = e.target;
|
|
23
24
|
if (!(target instanceof HTMLImageElement) || !this.root.contains(target) || this.engine.readOnly)
|
|
24
25
|
return;
|
|
25
|
-
const at = posFromDom(
|
|
26
|
+
const at = this.host.posFromDom(target.parentNode, [...target.parentNode.childNodes].indexOf(target));
|
|
26
27
|
if (at)
|
|
27
28
|
this.engine.setSelection(imageSelection(at.path, at.offset));
|
|
28
29
|
};
|
|
@@ -34,12 +35,12 @@ export class ImageSelection {
|
|
|
34
35
|
const picked = selectedImage(this.engine.document, this.engine.selection);
|
|
35
36
|
if (!picked)
|
|
36
37
|
return undefined;
|
|
37
|
-
const at = domFromPos(
|
|
38
|
+
const at = this.host.domFromPos({ path: picked.path, offset: picked.offset + 1 });
|
|
38
39
|
const el = !at ? undefined : at.node.nodeType === Node.TEXT_NODE ? at.node.previousSibling : at.node.childNodes[at.offset - 1];
|
|
39
40
|
return el instanceof HTMLImageElement ? el : undefined;
|
|
40
41
|
}
|
|
41
42
|
update() {
|
|
42
|
-
const img = this.find();
|
|
43
|
+
const img = this.engine.readOnly ? undefined : this.find();
|
|
43
44
|
if (img === this.marked) {
|
|
44
45
|
this.place();
|
|
45
46
|
return;
|
|
@@ -59,7 +60,7 @@ export class ImageSelection {
|
|
|
59
60
|
}
|
|
60
61
|
if (!this.handle) {
|
|
61
62
|
const handle = document.createElement("div");
|
|
62
|
-
handle.setAttribute("data-
|
|
63
|
+
handle.setAttribute("data-rte-resize-handle", "");
|
|
63
64
|
handle.style.cssText = "position:fixed;z-index:2147483646;width:12px;height:12px;background:#17408b;border:2px solid #fff;border-radius:3px;cursor:nwse-resize;touch-action:none;box-sizing:border-box";
|
|
64
65
|
handle.addEventListener("pointerdown", (e) => this.start(e));
|
|
65
66
|
document.body.appendChild(handle);
|
|
@@ -79,7 +80,7 @@ export class ImageSelection {
|
|
|
79
80
|
event.preventDefault();
|
|
80
81
|
const box = img.getBoundingClientRect();
|
|
81
82
|
const guide = document.createElement("div");
|
|
82
|
-
guide.setAttribute("data-
|
|
83
|
+
guide.setAttribute("data-rte-resize-line", "");
|
|
83
84
|
guide.style.cssText = `position:fixed;z-index:2147483645;pointer-events:none;border:2px dashed #17408b;left:${box.left}px;top:${box.top}px;width:${box.width}px;height:${box.height}px;box-sizing:border-box`;
|
|
84
85
|
document.body.appendChild(guide);
|
|
85
86
|
this.drag = { startX: event.clientX, startWidth: box.width, width: box.width, guide };
|
|
@@ -120,3 +121,8 @@ export class ImageSelection {
|
|
|
120
121
|
this.marked?.removeAttribute(SELECTED_IMAGE);
|
|
121
122
|
}
|
|
122
123
|
}
|
|
124
|
+
export const imagesView = (host) => {
|
|
125
|
+
const selection = new ImageSelection(host);
|
|
126
|
+
const stop = host.onChange(() => selection.update());
|
|
127
|
+
return () => { stop(); selection.destroy(); };
|
|
128
|
+
};
|
package/dist/import.d.ts
CHANGED
|
@@ -49,8 +49,24 @@ export interface ImportOptions {
|
|
|
49
49
|
readonly linkSchemes?: readonly string[];
|
|
50
50
|
/** Keep empty paragraphs. Content that is loaded keeps them; pasted content does not. */
|
|
51
51
|
readonly keepEmptyBlocks?: boolean;
|
|
52
|
-
/** Largest `data:` image address, in characters. */
|
|
52
|
+
/** Largest `data:` image address, in characters. 0 refuses every `data:` image. Default 12 million. */
|
|
53
53
|
readonly maxDataImageLength?: number;
|
|
54
|
+
/** Longest markup read, in characters. Longer markup is refused whole: nothing is read, `onLimit` is told. Default 50 million. */
|
|
55
|
+
readonly maxInputLength?: number;
|
|
56
|
+
/** Keep an image whose address is relative (`a.png`, `/a.png`). Default true; pasting turns it off (see `pasteRelativeImages`). */
|
|
57
|
+
readonly relativeImages?: boolean;
|
|
58
|
+
/** Keep relative image addresses when pasting. Default false: a pasted `/path` would be fetched from the page's own origin. */
|
|
59
|
+
readonly pasteRelativeImages?: boolean;
|
|
60
|
+
/** Deepest element nesting read; deeper elements are left out and their content kept. Default 100. */
|
|
61
|
+
readonly maxDepth?: number;
|
|
62
|
+
/** Told when reading failed for a reason in the reader or a recognizer: the content is then left out and nothing is thrown. */
|
|
63
|
+
readonly onError?: (error: unknown) => void;
|
|
64
|
+
/** Told when markup was refused for being longer than `maxInputLength`. */
|
|
65
|
+
readonly onLimit?: (info: {
|
|
66
|
+
readonly limit: "maxInputLength";
|
|
67
|
+
readonly max: number;
|
|
68
|
+
readonly length: number;
|
|
69
|
+
}) => void;
|
|
54
70
|
}
|
|
55
71
|
export declare function parseStyle(style: string | undefined): Map<string, string>;
|
|
56
72
|
/** Returns the address when its scheme is allowed, otherwise undefined. Obfuscation with spaces, tabs or entities does not help. */
|
|
@@ -62,4 +78,4 @@ export declare function importHtml(html: string, options?: ImportOptions): Doc;
|
|
|
62
78
|
export declare function importText(value: string): Block[];
|
|
63
79
|
export { decodeEntities };
|
|
64
80
|
/** Checks an image address the same way the importer does: remote, or a raster image whose bytes match its type. */
|
|
65
|
-
export declare const checkImageSrc: (src: string, maxDataLength?: number, sanitizeSvg?: ImportOptions["sanitizeSvg"]) => string | undefined;
|
|
81
|
+
export declare const checkImageSrc: (src: string, maxDataLength?: number, sanitizeSvg?: ImportOptions["sanitizeSvg"], relative?: boolean) => string | undefined;
|