@trafica/editor 1.0.15 → 1.0.17
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/index.d.mts +21 -13
- package/dist/index.d.ts +21 -13
- package/dist/index.js +343 -43
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +343 -44
- package/dist/index.mjs.map +1 -1
- package/dist/styles/editor.css +86 -0
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1653,10 +1653,14 @@ function serializeBlock(node, idCounts = /* @__PURE__ */ new Map()) {
|
|
|
1653
1653
|
case "list_item":
|
|
1654
1654
|
return `<li>${serializeChildren(node.children)}</li>`;
|
|
1655
1655
|
case "check_list":
|
|
1656
|
-
return `<ul data-type="checklist">${serializeChildren(node.children)}</ul>`;
|
|
1656
|
+
return `<ul class="todo-list" data-type="checklist">${serializeChildren(node.children)}</ul>`;
|
|
1657
1657
|
case "check_list_item": {
|
|
1658
|
-
const checked = ((_g = node.attrs) == null ? void 0 : _g.checked)
|
|
1659
|
-
|
|
1658
|
+
const checked = !!((_g = node.attrs) == null ? void 0 : _g.checked);
|
|
1659
|
+
const dataChecked = checked ? ' data-checked="true"' : "";
|
|
1660
|
+
const itemClass = `todo-list__item${checked ? " todo-list__item_checked" : ""}`;
|
|
1661
|
+
const checkedAttr = checked ? ' checked="checked"' : "";
|
|
1662
|
+
const innerContent = serializeChildren(node.children);
|
|
1663
|
+
return `<li class="${itemClass}"${dataChecked}><label class="todo-list__label"><input type="checkbox" disabled="disabled"${checkedAttr}><span class="todo-list__label__description">${innerContent}</span></label></li>`;
|
|
1660
1664
|
}
|
|
1661
1665
|
case "code_block": {
|
|
1662
1666
|
const lang = ((_h = node.attrs) == null ? void 0 : _h.language) ? ` class="language-${node.attrs.language}"` : "";
|
|
@@ -1929,6 +1933,7 @@ function parseInlineChildren(el) {
|
|
|
1929
1933
|
results.push({ type: "text", text: "\n", marks: [...marks] });
|
|
1930
1934
|
return;
|
|
1931
1935
|
}
|
|
1936
|
+
if (tag === "input") return;
|
|
1932
1937
|
const newMarks = [...marks, ...getMarksForTag(tag, elem)];
|
|
1933
1938
|
for (const child of Array.from(elem.childNodes)) {
|
|
1934
1939
|
walk(child, newMarks);
|
|
@@ -1978,10 +1983,16 @@ function getMarksForTag(tag, el) {
|
|
|
1978
1983
|
|
|
1979
1984
|
// src/editor/plugins/PastePlugin.ts
|
|
1980
1985
|
function createPastePlugin() {
|
|
1981
|
-
return {
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1986
|
+
return { name: "clipboard" };
|
|
1987
|
+
}
|
|
1988
|
+
function attachClipboardHandlers(container, engine) {
|
|
1989
|
+
const removeCopy = attachCopyOrCutHandler(container, engine, false);
|
|
1990
|
+
const removeCut = attachCopyOrCutHandler(container, engine, true);
|
|
1991
|
+
const removePaste = attachPasteHandler(container, engine);
|
|
1992
|
+
return () => {
|
|
1993
|
+
removeCopy();
|
|
1994
|
+
removeCut();
|
|
1995
|
+
removePaste();
|
|
1985
1996
|
};
|
|
1986
1997
|
}
|
|
1987
1998
|
function attachPasteHandler(container, engine) {
|
|
@@ -1997,11 +2008,9 @@ function attachPasteHandler(container, engine) {
|
|
|
1997
2008
|
if (file) {
|
|
1998
2009
|
const blobUrl = URL.createObjectURL(file);
|
|
1999
2010
|
const state2 = engine.getState();
|
|
2000
|
-
|
|
2011
|
+
const sel2 = state2.selection;
|
|
2012
|
+
const insertIdx = sel2 ? sel2.anchor.path[0] + 1 : state2.doc.children.length;
|
|
2001
2013
|
const tr2 = createTransaction();
|
|
2002
|
-
const sel = state2.selection;
|
|
2003
|
-
const blockPath = sel ? [sel.anchor.path[0]] : [state2.doc.children.length - 1];
|
|
2004
|
-
const insertIdx = blockPath[0] + 1;
|
|
2005
2014
|
tr2.steps.push({
|
|
2006
2015
|
type: "insert_node",
|
|
2007
2016
|
parentPath: [],
|
|
@@ -2014,56 +2023,346 @@ function attachPasteHandler(container, engine) {
|
|
|
2014
2023
|
}
|
|
2015
2024
|
const html = clipboardData.getData("text/html");
|
|
2016
2025
|
const plainText = clipboardData.getData("text/plain");
|
|
2017
|
-
let
|
|
2026
|
+
let pastedDoc;
|
|
2018
2027
|
if (html) {
|
|
2019
|
-
const
|
|
2020
|
-
|
|
2028
|
+
const normalized = normalizeHTML(html);
|
|
2029
|
+
pastedDoc = htmlSerializer.deserialize(normalized);
|
|
2021
2030
|
} else if (plainText) {
|
|
2022
|
-
|
|
2023
|
-
if (isURL(trimmed)) {
|
|
2024
|
-
const href = /^https?:\/\//i.test(trimmed) ? trimmed : `https://${trimmed}`;
|
|
2025
|
-
const escaped = escapeHTML2(trimmed);
|
|
2026
|
-
newDoc = htmlSerializer.deserialize(
|
|
2027
|
-
`<p><a href="${escapeAttr2(href)}">${escaped}</a></p>`
|
|
2028
|
-
);
|
|
2029
|
-
} else {
|
|
2030
|
-
newDoc = htmlSerializer.deserialize(`<p>${escapeHTML2(plainText)}</p>`);
|
|
2031
|
-
}
|
|
2031
|
+
pastedDoc = parsePlainText(plainText);
|
|
2032
2032
|
} else {
|
|
2033
2033
|
return;
|
|
2034
2034
|
}
|
|
2035
|
+
const pastedBlocks = pastedDoc.children.filter(
|
|
2036
|
+
(b) => !(b.type === "paragraph" && b.children.length === 0)
|
|
2037
|
+
);
|
|
2038
|
+
if (pastedBlocks.length === 0) return;
|
|
2035
2039
|
const state = engine.getState();
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
+
let sel = state.selection;
|
|
2041
|
+
if (sel && !sel.isCollapsed) {
|
|
2042
|
+
const { from, to } = normalizeRange(sel.anchor, sel.focus);
|
|
2043
|
+
const delTr = createTransaction();
|
|
2044
|
+
delTr.steps.push(tr_deleteRange(from, to));
|
|
2045
|
+
engine.dispatch(delTr);
|
|
2046
|
+
sel = engine.getState().selection;
|
|
2047
|
+
}
|
|
2048
|
+
const currentState = engine.getState();
|
|
2049
|
+
const { mergedDoc, cursorPos } = mergeAtCursor(
|
|
2050
|
+
currentState,
|
|
2051
|
+
{ children: pastedBlocks },
|
|
2052
|
+
sel
|
|
2053
|
+
);
|
|
2040
2054
|
const tr = createTransaction();
|
|
2041
|
-
tr.steps.push(tr_replaceDoc(
|
|
2055
|
+
tr.steps.push(tr_replaceDoc(mergedDoc));
|
|
2056
|
+
if (cursorPos) {
|
|
2057
|
+
tr.steps.push(tr_setSelection({ anchor: cursorPos, focus: cursorPos, isCollapsed: true }));
|
|
2058
|
+
}
|
|
2042
2059
|
engine.dispatch(tr);
|
|
2043
2060
|
};
|
|
2044
2061
|
container.addEventListener("paste", handler);
|
|
2045
2062
|
return () => container.removeEventListener("paste", handler);
|
|
2046
2063
|
}
|
|
2047
|
-
function
|
|
2064
|
+
function attachCopyOrCutHandler(container, engine, isCut) {
|
|
2065
|
+
const handler = (e) => {
|
|
2066
|
+
const state = engine.getState();
|
|
2067
|
+
const sel = state.selection;
|
|
2068
|
+
if (!sel || sel.isCollapsed) return;
|
|
2069
|
+
e.preventDefault();
|
|
2070
|
+
const selectedDoc = extractSelection(state);
|
|
2071
|
+
const selectedHTML = htmlSerializer.serialize(selectedDoc);
|
|
2072
|
+
const selectedText = docToPlainText(selectedDoc);
|
|
2073
|
+
try {
|
|
2074
|
+
e.clipboardData.setData("text/html", selectedHTML);
|
|
2075
|
+
e.clipboardData.setData("text/plain", selectedText);
|
|
2076
|
+
} catch (e2) {
|
|
2077
|
+
}
|
|
2078
|
+
if (isCut) {
|
|
2079
|
+
const { from, to } = normalizeRange(sel.anchor, sel.focus);
|
|
2080
|
+
const tr = createTransaction();
|
|
2081
|
+
tr.steps.push(tr_deleteRange(from, to));
|
|
2082
|
+
engine.dispatch(tr);
|
|
2083
|
+
}
|
|
2084
|
+
};
|
|
2085
|
+
const event = isCut ? "cut" : "copy";
|
|
2086
|
+
container.addEventListener(event, handler);
|
|
2087
|
+
return () => container.removeEventListener(event, handler);
|
|
2088
|
+
}
|
|
2089
|
+
function extractSelection(state) {
|
|
2090
|
+
var _a, _b;
|
|
2091
|
+
const sel = state.selection;
|
|
2092
|
+
if (!sel || sel.isCollapsed) return { type: "doc", children: [createParagraph()] };
|
|
2093
|
+
const { from, to } = normalizeRange(sel.anchor, sel.focus);
|
|
2094
|
+
const blocks = state.doc.children;
|
|
2095
|
+
const fromBlockIdx = (_a = from.path[0]) != null ? _a : 0;
|
|
2096
|
+
const toBlockIdx = (_b = to.path[0]) != null ? _b : 0;
|
|
2097
|
+
if (fromBlockIdx === toBlockIdx) {
|
|
2098
|
+
const sliced = sliceBlock(blocks[fromBlockIdx], from.path.slice(1), from.offset, to.path.slice(1), to.offset);
|
|
2099
|
+
return { type: "doc", children: sliced.length > 0 ? sliced : [createParagraph()] };
|
|
2100
|
+
}
|
|
2101
|
+
const firstBlock = sliceBlockFrom(blocks[fromBlockIdx], from.path.slice(1), from.offset);
|
|
2102
|
+
const middleBlocks = blocks.slice(fromBlockIdx + 1, toBlockIdx);
|
|
2103
|
+
const lastBlock = sliceBlockTo(blocks[toBlockIdx], to.path.slice(1), to.offset);
|
|
2104
|
+
return { type: "doc", children: [firstBlock, ...middleBlocks, lastBlock] };
|
|
2105
|
+
}
|
|
2106
|
+
function sliceBlock(block, fromRelPath, fromOffset, toRelPath, toOffset) {
|
|
2107
|
+
var _a, _b;
|
|
2108
|
+
const fromIdx = (_a = fromRelPath[0]) != null ? _a : 0;
|
|
2109
|
+
const toIdx = (_b = toRelPath[0]) != null ? _b : Math.max(0, block.children.length - 1);
|
|
2110
|
+
if (!block.children.every((c) => isTextNode(c))) {
|
|
2111
|
+
return [block];
|
|
2112
|
+
}
|
|
2113
|
+
const children = [];
|
|
2114
|
+
for (let i = fromIdx; i <= toIdx && i < block.children.length; i++) {
|
|
2115
|
+
const t = block.children[i];
|
|
2116
|
+
const s = i === fromIdx ? fromOffset : 0;
|
|
2117
|
+
const end = i === toIdx ? toOffset : t.text.length;
|
|
2118
|
+
const slice = t.text.slice(s, end);
|
|
2119
|
+
if (slice) children.push({ type: "text", text: slice, marks: t.marks });
|
|
2120
|
+
}
|
|
2121
|
+
return children.length > 0 ? [{ ...block, children }] : [];
|
|
2122
|
+
}
|
|
2123
|
+
function sliceBlockFrom(block, relPath, offset) {
|
|
2124
|
+
var _a;
|
|
2125
|
+
const fromIdx = (_a = relPath[0]) != null ? _a : 0;
|
|
2126
|
+
if (!block.children.every((c) => isTextNode(c))) return block;
|
|
2127
|
+
const children = [];
|
|
2128
|
+
for (let i = fromIdx; i < block.children.length; i++) {
|
|
2129
|
+
const t = block.children[i];
|
|
2130
|
+
const s = i === fromIdx ? offset : 0;
|
|
2131
|
+
const slice = t.text.slice(s);
|
|
2132
|
+
if (slice) children.push({ type: "text", text: slice, marks: t.marks });
|
|
2133
|
+
}
|
|
2134
|
+
return { ...block, children };
|
|
2135
|
+
}
|
|
2136
|
+
function sliceBlockTo(block, relPath, offset) {
|
|
2137
|
+
var _a;
|
|
2138
|
+
const toIdx = (_a = relPath[0]) != null ? _a : Math.max(0, block.children.length - 1);
|
|
2139
|
+
if (!block.children.every((c) => isTextNode(c))) return block;
|
|
2140
|
+
const children = [];
|
|
2141
|
+
for (let i = 0; i <= toIdx && i < block.children.length; i++) {
|
|
2142
|
+
const t = block.children[i];
|
|
2143
|
+
const end = i === toIdx ? offset : t.text.length;
|
|
2144
|
+
const slice = t.text.slice(0, end);
|
|
2145
|
+
if (slice) children.push({ type: "text", text: slice, marks: t.marks });
|
|
2146
|
+
}
|
|
2147
|
+
return { ...block, children };
|
|
2148
|
+
}
|
|
2149
|
+
function mergeAtCursor(state, pastedDoc, sel) {
|
|
2150
|
+
var _a, _b;
|
|
2151
|
+
const pasted = pastedDoc.children;
|
|
2152
|
+
if (pasted.length === 0) return { mergedDoc: state.doc, cursorPos: (_a = sel == null ? void 0 : sel.anchor) != null ? _a : null };
|
|
2153
|
+
const existingBlocks = state.doc.children;
|
|
2154
|
+
if (!sel) {
|
|
2155
|
+
const mergedDoc = { ...state.doc, children: [...existingBlocks, ...pasted] };
|
|
2156
|
+
const lastIdx = mergedDoc.children.length - 1;
|
|
2157
|
+
const cursorPos = endOfBlock(mergedDoc.children[lastIdx], lastIdx);
|
|
2158
|
+
return { mergedDoc, cursorPos };
|
|
2159
|
+
}
|
|
2160
|
+
const blockIdx = (_b = sel.anchor.path[0]) != null ? _b : 0;
|
|
2161
|
+
const relPath = sel.anchor.path.slice(1);
|
|
2162
|
+
const charOffset = sel.anchor.offset;
|
|
2163
|
+
const currentBlock = existingBlocks[blockIdx];
|
|
2164
|
+
if (!currentBlock) {
|
|
2165
|
+
const mergedDoc = { ...state.doc, children: [...existingBlocks, ...pasted] };
|
|
2166
|
+
const lastIdx = mergedDoc.children.length - 1;
|
|
2167
|
+
return { mergedDoc, cursorPos: endOfBlock(mergedDoc.children[lastIdx], lastIdx) };
|
|
2168
|
+
}
|
|
2169
|
+
const [beforeChildren, afterChildren] = splitBlockChildren(currentBlock, relPath, charOffset);
|
|
2170
|
+
let newBlocks;
|
|
2171
|
+
let cursorBlockOffset;
|
|
2172
|
+
let cursorInBlock;
|
|
2173
|
+
if (pasted.length === 1) {
|
|
2174
|
+
const pastedChildren = pasted[0].children;
|
|
2175
|
+
const mergedChildren2 = [...beforeChildren, ...pastedChildren, ...afterChildren];
|
|
2176
|
+
const cleanChildren = mergedChildren2.length > 0 ? mergedChildren2 : [{ type: "text", text: "", marks: [] }];
|
|
2177
|
+
newBlocks = [{ ...currentBlock, children: cleanChildren }];
|
|
2178
|
+
cursorBlockOffset = 0;
|
|
2179
|
+
const cursorChildIdx = beforeChildren.length + pastedChildren.length;
|
|
2180
|
+
const nodeBeforeCursor = cleanChildren[cursorChildIdx - 1];
|
|
2181
|
+
if (nodeBeforeCursor && isTextNode(nodeBeforeCursor)) {
|
|
2182
|
+
cursorInBlock = {
|
|
2183
|
+
path: [blockIdx, cursorChildIdx - 1],
|
|
2184
|
+
offset: nodeBeforeCursor.text.length
|
|
2185
|
+
};
|
|
2186
|
+
} else {
|
|
2187
|
+
cursorInBlock = { path: [blockIdx], offset: 0 };
|
|
2188
|
+
}
|
|
2189
|
+
} else {
|
|
2190
|
+
const firstPasted = pasted[0];
|
|
2191
|
+
const lastPasted = pasted[pasted.length - 1];
|
|
2192
|
+
const middleBlocks = pasted.slice(1, -1);
|
|
2193
|
+
const firstMerged = {
|
|
2194
|
+
...currentBlock,
|
|
2195
|
+
children: [...beforeChildren, ...firstPasted.children]
|
|
2196
|
+
};
|
|
2197
|
+
const lastMerged = {
|
|
2198
|
+
type: lastPasted.type,
|
|
2199
|
+
attrs: lastPasted.attrs,
|
|
2200
|
+
children: [...lastPasted.children, ...afterChildren]
|
|
2201
|
+
};
|
|
2202
|
+
newBlocks = [firstMerged, ...middleBlocks, lastMerged];
|
|
2203
|
+
cursorBlockOffset = newBlocks.length - 1;
|
|
2204
|
+
const lpChildren = lastPasted.children;
|
|
2205
|
+
const absoluteLastBlockIdx = blockIdx + cursorBlockOffset;
|
|
2206
|
+
if (lpChildren.length > 0) {
|
|
2207
|
+
const lastNode = lpChildren[lpChildren.length - 1];
|
|
2208
|
+
cursorInBlock = {
|
|
2209
|
+
path: [absoluteLastBlockIdx, lpChildren.length - 1],
|
|
2210
|
+
offset: isTextNode(lastNode) ? lastNode.text.length : 0
|
|
2211
|
+
};
|
|
2212
|
+
} else {
|
|
2213
|
+
cursorInBlock = { path: [absoluteLastBlockIdx], offset: 0 };
|
|
2214
|
+
}
|
|
2215
|
+
}
|
|
2216
|
+
const mergedChildren = [
|
|
2217
|
+
...existingBlocks.slice(0, blockIdx),
|
|
2218
|
+
...newBlocks,
|
|
2219
|
+
...existingBlocks.slice(blockIdx + 1)
|
|
2220
|
+
];
|
|
2221
|
+
return {
|
|
2222
|
+
mergedDoc: { ...state.doc, children: mergedChildren },
|
|
2223
|
+
cursorPos: cursorInBlock
|
|
2224
|
+
};
|
|
2225
|
+
}
|
|
2226
|
+
function splitBlockChildren(block, relPath, offset) {
|
|
2227
|
+
const children = block.children;
|
|
2228
|
+
if (children.length === 0) return [[], []];
|
|
2229
|
+
if (relPath.length === 0) return [[], [...children]];
|
|
2230
|
+
const textIdx = relPath[0];
|
|
2231
|
+
if (textIdx >= children.length) return [[...children], []];
|
|
2232
|
+
const node = children[textIdx];
|
|
2233
|
+
if (!isTextNode(node)) {
|
|
2234
|
+
return [[...children.slice(0, textIdx)], [...children.slice(textIdx)]];
|
|
2235
|
+
}
|
|
2236
|
+
const textNode = node;
|
|
2237
|
+
const before = [
|
|
2238
|
+
...children.slice(0, textIdx),
|
|
2239
|
+
...offset > 0 ? [{ type: "text", text: textNode.text.slice(0, offset), marks: textNode.marks }] : []
|
|
2240
|
+
];
|
|
2241
|
+
const after = [
|
|
2242
|
+
...offset < textNode.text.length ? [{ type: "text", text: textNode.text.slice(offset), marks: textNode.marks }] : [],
|
|
2243
|
+
...children.slice(textIdx + 1)
|
|
2244
|
+
];
|
|
2245
|
+
return [before, after];
|
|
2246
|
+
}
|
|
2247
|
+
function endOfBlock(block, blockIdx) {
|
|
2248
|
+
const children = block.children;
|
|
2249
|
+
for (let i = children.length - 1; i >= 0; i--) {
|
|
2250
|
+
const n = children[i];
|
|
2251
|
+
if (isTextNode(n)) {
|
|
2252
|
+
return { path: [blockIdx, i], offset: n.text.length };
|
|
2253
|
+
}
|
|
2254
|
+
}
|
|
2255
|
+
return { path: [blockIdx], offset: 0 };
|
|
2256
|
+
}
|
|
2257
|
+
function parsePlainText(text) {
|
|
2258
|
+
const normalized = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").trim();
|
|
2259
|
+
if (isURL(normalized)) {
|
|
2260
|
+
const href = /^https?:\/\//i.test(normalized) ? normalized : `https://${normalized}`;
|
|
2261
|
+
return htmlSerializer.deserialize(
|
|
2262
|
+
`<p><a href="${escapeAttr2(href)}">${escapeHTML2(normalized)}</a></p>`
|
|
2263
|
+
);
|
|
2264
|
+
}
|
|
2265
|
+
const paragraphs = normalized.split(/\n{2,}/);
|
|
2266
|
+
if (paragraphs.length === 1) {
|
|
2267
|
+
const lines = normalized.split("\n");
|
|
2268
|
+
if (lines.length === 1) {
|
|
2269
|
+
return htmlSerializer.deserialize(`<p>${escapeHTML2(normalized)}</p>`);
|
|
2270
|
+
}
|
|
2271
|
+
const html2 = lines.map((l) => escapeHTML2(l)).join("<br>");
|
|
2272
|
+
return htmlSerializer.deserialize(`<p>${html2}</p>`);
|
|
2273
|
+
}
|
|
2274
|
+
const html = paragraphs.map((p) => `<p>${p.split("\n").map((l) => escapeHTML2(l)).join("<br>")}</p>`).join("");
|
|
2275
|
+
return htmlSerializer.deserialize(html);
|
|
2276
|
+
}
|
|
2277
|
+
function normalizeHTML(html) {
|
|
2278
|
+
let out = html.replace(/<!--[\s\S]*?-->/g, "");
|
|
2279
|
+
out = out.replace(/<!\[if[^\]]*\]>[\s\S]*?<!\[endif\]>/gi, "");
|
|
2280
|
+
out = out.replace(/<\/?(?:o|w|m|v|st\d?|x):[^>]*>/gi, "");
|
|
2048
2281
|
const parser = new DOMParser();
|
|
2049
|
-
const doc = parser.parseFromString(
|
|
2050
|
-
|
|
2051
|
-
"script, style, iframe, object, embed, form,
|
|
2052
|
-
);
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
const
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2282
|
+
const doc = parser.parseFromString(out, "text/html");
|
|
2283
|
+
doc.querySelectorAll(
|
|
2284
|
+
"script, style, iframe, object, embed, form, button, select, textarea, meta, link"
|
|
2285
|
+
).forEach((el) => el.remove());
|
|
2286
|
+
doc.querySelectorAll("input").forEach((el) => {
|
|
2287
|
+
var _a;
|
|
2288
|
+
const isCheckbox = ((_a = el.getAttribute("type")) == null ? void 0 : _a.toLowerCase()) === "checkbox";
|
|
2289
|
+
const inTodoList = !!el.closest('ul[data-type="checklist"], ul.todo-list, li.todo-list__item, li[data-checked]');
|
|
2290
|
+
if (!isCheckbox || !inTodoList) el.remove();
|
|
2291
|
+
});
|
|
2292
|
+
doc.querySelectorAll("b").forEach((el) => {
|
|
2293
|
+
const fw = el.style.fontWeight;
|
|
2294
|
+
if (fw === "normal" || fw === "400" || fw === "inherit" || fw === "") {
|
|
2295
|
+
const parent = el.parentNode;
|
|
2296
|
+
if (!parent) return;
|
|
2297
|
+
while (el.firstChild) parent.insertBefore(el.firstChild, el);
|
|
2298
|
+
el.remove();
|
|
2299
|
+
}
|
|
2300
|
+
});
|
|
2301
|
+
doc.querySelectorAll("*").forEach((node) => {
|
|
2302
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
2303
|
+
const el = node;
|
|
2304
|
+
const tag = el.tagName.toLowerCase();
|
|
2305
|
+
const fontSize = (_b = (_a = el.style) == null ? void 0 : _a.fontSize) != null ? _b : "";
|
|
2306
|
+
const fontFamily = (_d = (_c = el.style) == null ? void 0 : _c.fontFamily) != null ? _d : "";
|
|
2307
|
+
const color = (_f = (_e = el.style) == null ? void 0 : _e.color) != null ? _f : "";
|
|
2308
|
+
const bgColor = (_h = (_g = el.style) == null ? void 0 : _g.backgroundColor) != null ? _h : "";
|
|
2061
2309
|
el.removeAttribute("style");
|
|
2310
|
+
const safeStyle = [];
|
|
2311
|
+
if (fontSize) safeStyle.push(`font-size:${fontSize}`);
|
|
2312
|
+
if (fontFamily) safeStyle.push(`font-family:${fontFamily}`);
|
|
2313
|
+
if (color) safeStyle.push(`color:${color}`);
|
|
2314
|
+
if (bgColor && !["transparent", "rgba(0, 0, 0, 0)", "white", "rgb(255, 255, 255)", "#ffffff", "#fff"].includes(
|
|
2315
|
+
bgColor.toLowerCase().replace(/\s/g, "")
|
|
2316
|
+
)) {
|
|
2317
|
+
safeStyle.push(`background-color:${bgColor}`);
|
|
2318
|
+
}
|
|
2319
|
+
if (safeStyle.length > 0) el.setAttribute("style", safeStyle.join(";"));
|
|
2062
2320
|
el.removeAttribute("class");
|
|
2063
2321
|
el.removeAttribute("id");
|
|
2322
|
+
Array.from(el.attributes).forEach((attr) => {
|
|
2323
|
+
if (attr.name.startsWith("on")) el.removeAttribute(attr.name);
|
|
2324
|
+
});
|
|
2325
|
+
Array.from(el.attributes).forEach((attr) => {
|
|
2326
|
+
if (attr.name.startsWith("data-") && !["data-align", "data-type", "data-checked"].includes(attr.name)) {
|
|
2327
|
+
el.removeAttribute(attr.name);
|
|
2328
|
+
}
|
|
2329
|
+
});
|
|
2330
|
+
if (tag === "a") {
|
|
2331
|
+
const href = (_i = el.getAttribute("href")) != null ? _i : "";
|
|
2332
|
+
const isUnsafe = /^(javascript:|vbscript:|data:)/i.test(href.trim());
|
|
2333
|
+
Array.from(el.attributes).forEach((attr) => {
|
|
2334
|
+
if (!["href", "target", "rel", "style"].includes(attr.name)) el.removeAttribute(attr.name);
|
|
2335
|
+
});
|
|
2336
|
+
if (isUnsafe) el.removeAttribute("href");
|
|
2337
|
+
}
|
|
2338
|
+
if (tag === "img") {
|
|
2339
|
+
Array.from(el.attributes).forEach((attr) => {
|
|
2340
|
+
if (!["src", "alt", "width", "height", "style"].includes(attr.name)) el.removeAttribute(attr.name);
|
|
2341
|
+
});
|
|
2342
|
+
}
|
|
2343
|
+
if (tag === "td" || tag === "th") {
|
|
2344
|
+
Array.from(el.attributes).forEach((attr) => {
|
|
2345
|
+
if (!["colspan", "rowspan", "style"].includes(attr.name)) el.removeAttribute(attr.name);
|
|
2346
|
+
});
|
|
2347
|
+
}
|
|
2348
|
+
if (tag === "code") {
|
|
2349
|
+
Array.from(el.attributes).forEach((attr) => {
|
|
2350
|
+
if (!["class", "style"].includes(attr.name)) el.removeAttribute(attr.name);
|
|
2351
|
+
});
|
|
2352
|
+
}
|
|
2064
2353
|
});
|
|
2065
2354
|
return doc.body.innerHTML;
|
|
2066
2355
|
}
|
|
2356
|
+
function docToPlainText(doc) {
|
|
2357
|
+
return doc.children.map(blockToPlainText).join("\n\n");
|
|
2358
|
+
}
|
|
2359
|
+
function blockToPlainText(block) {
|
|
2360
|
+
if (block.children.length === 0) return "";
|
|
2361
|
+
return block.children.map((c) => {
|
|
2362
|
+
if (isTextNode(c)) return c.text;
|
|
2363
|
+
return blockToPlainText(c);
|
|
2364
|
+
}).join("");
|
|
2365
|
+
}
|
|
2067
2366
|
function escapeHTML2(str) {
|
|
2068
2367
|
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
2069
2368
|
}
|
|
@@ -7583,7 +7882,7 @@ function EditorCore({
|
|
|
7583
7882
|
useEffect(() => {
|
|
7584
7883
|
const container = containerRef.current;
|
|
7585
7884
|
if (!container || readOnly) return;
|
|
7586
|
-
return
|
|
7885
|
+
return attachClipboardHandlers(container, engine);
|
|
7587
7886
|
}, [engine, readOnly]);
|
|
7588
7887
|
useEffect(() => {
|
|
7589
7888
|
const container = containerRef.current;
|
|
@@ -8717,6 +9016,6 @@ var Editor = forwardRef(function Editor2(props, ref) {
|
|
|
8717
9016
|
);
|
|
8718
9017
|
});
|
|
8719
9018
|
|
|
8720
|
-
export { BASIC_TOOLBAR, DEFAULT_TOOLBAR, Editor, EditorCore, EditorEngine, MINIMAL_TOOLBAR, TablePlugin, Toolbar, addColumnLeft, addColumnRight, addMarkToNode, addRowAbove, addRowBelow, applyMarkToRange, applySearchHighlights, applyTransaction, attachPasteHandler, captureSelection, clearSearchHighlights, collectText, comparePaths, comparePositions, createEmptyDocument, createHistoryManager, createHistoryPlugin, createParagraph, createPastePlugin, createTableCell, createTableNode, createTransaction, deleteColumn, deleteImageAtPath, deleteRange, deleteRow, deleteTable, deleteTableColumn, deleteTableRow, deleteTextAtPath, execCommand, findCellPosition, findContentBlockPath, findMatches, findTablePath, getActiveAlignment, getActiveBlockType, getActiveFontFamily, getActiveFontSize, getActiveHighlightColor, getActiveLinkHref, getActiveLinkRange, getActiveMarks, getActiveTextColor, getCellFirstPosition, getCellLastPosition, getDocumentLength, getDocumentMarkAttrValues, getNodeAtPath, getTableDimensions, getTextNodesBetween, htmlSerializer, insertImage, insertLink, insertTable, insertTableColumnAfter, insertTableColumnBefore, insertTableRowAfter, insertTableRowBefore, insertText, insertTextAtPath, isBlockNode, isContainerBlock, isSelectionInContainer, isTextNode, joinBlocks, jsonSerializer, makeCollapsedSelection, makePosition, markdownSerializer, marksEqual, mergeAdjacentTextNodesInDoc, mergeCells, mergeTableCells, normalizeRange, redo, registerCommand, removeMarkFromNode, removeMarkFromRange, renderDocument, replaceAllMatches, replaceMatch, restoreSelection, scrollMatchIntoView, setAlignment, setBlockType2 as setBlockType, setCodeBlockLanguage, setColumnWidth, setFontFamily, setFontSize, setHighlightColor, setImageAttr, setMarkOnRange, setTextColor, splitBlock, splitCell, splitTableCell, toggleCheckItemAt, toggleHeaderRow, toggleMark, undo, updateColumnWidth, useEditorEngine, useEditorState, walkDocument };
|
|
9019
|
+
export { BASIC_TOOLBAR, DEFAULT_TOOLBAR, Editor, EditorCore, EditorEngine, MINIMAL_TOOLBAR, TablePlugin, Toolbar, addColumnLeft, addColumnRight, addMarkToNode, addRowAbove, addRowBelow, applyMarkToRange, applySearchHighlights, applyTransaction, attachClipboardHandlers, attachPasteHandler, captureSelection, clearSearchHighlights, collectText, comparePaths, comparePositions, createEmptyDocument, createHistoryManager, createHistoryPlugin, createParagraph, createPastePlugin, createTableCell, createTableNode, createTransaction, deleteColumn, deleteImageAtPath, deleteRange, deleteRow, deleteTable, deleteTableColumn, deleteTableRow, deleteTextAtPath, execCommand, findCellPosition, findContentBlockPath, findMatches, findTablePath, getActiveAlignment, getActiveBlockType, getActiveFontFamily, getActiveFontSize, getActiveHighlightColor, getActiveLinkHref, getActiveLinkRange, getActiveMarks, getActiveTextColor, getCellFirstPosition, getCellLastPosition, getDocumentLength, getDocumentMarkAttrValues, getNodeAtPath, getTableDimensions, getTextNodesBetween, htmlSerializer, insertImage, insertLink, insertTable, insertTableColumnAfter, insertTableColumnBefore, insertTableRowAfter, insertTableRowBefore, insertText, insertTextAtPath, isBlockNode, isContainerBlock, isSelectionInContainer, isTextNode, joinBlocks, jsonSerializer, makeCollapsedSelection, makePosition, markdownSerializer, marksEqual, mergeAdjacentTextNodesInDoc, mergeCells, mergeTableCells, normalizeRange, redo, registerCommand, removeMarkFromNode, removeMarkFromRange, renderDocument, replaceAllMatches, replaceMatch, restoreSelection, scrollMatchIntoView, setAlignment, setBlockType2 as setBlockType, setCodeBlockLanguage, setColumnWidth, setFontFamily, setFontSize, setHighlightColor, setImageAttr, setMarkOnRange, setTextColor, splitBlock, splitCell, splitTableCell, toggleCheckItemAt, toggleHeaderRow, toggleMark, undo, updateColumnWidth, useEditorEngine, useEditorState, walkDocument };
|
|
8721
9020
|
//# sourceMappingURL=index.mjs.map
|
|
8722
9021
|
//# sourceMappingURL=index.mjs.map
|