@mdaemon/html-editor 1.1.0 → 1.2.0
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 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +384 -1
- package/dist/index.mjs +384 -1
- package/package.json +19 -19
package/README.md
CHANGED
|
@@ -103,6 +103,7 @@ const editor = new HTMLEditor(container, {
|
|
|
103
103
|
| `entity_encoding` | 'raw' \| 'named' \| 'numeric' | 'raw' | HTML entity encoding mode |
|
|
104
104
|
| `convert_unsafe_embeds` | boolean | true | Sanitize embedded content |
|
|
105
105
|
| `format_empty_lines` | boolean | true | Format empty lines |
|
|
106
|
+
| `paste_from_office` | boolean | true | Clean and preserve formatting when pasting from Microsoft Word and Excel |
|
|
106
107
|
| `setup` | (editor) => void | - | Callback invoked before init — use to register custom buttons |
|
|
107
108
|
|
|
108
109
|
### Toolbar Toggle
|
package/dist/index.d.ts
CHANGED
|
@@ -138,6 +138,7 @@ export declare interface EditorConfig {
|
|
|
138
138
|
quickbars_selection_toolbar?: string;
|
|
139
139
|
quickbars_image_toolbar?: boolean;
|
|
140
140
|
quickbars_insert_toolbar?: boolean;
|
|
141
|
+
paste_from_office?: boolean;
|
|
141
142
|
browser_spellcheck?: boolean;
|
|
142
143
|
elementpath?: boolean;
|
|
143
144
|
entity_encoding?: 'raw' | 'named' | 'numeric';
|
|
@@ -373,6 +374,16 @@ export declare interface MDHTMLEditor {
|
|
|
373
374
|
|
|
374
375
|
export declare const Mention: Node_2<any, any>;
|
|
375
376
|
|
|
377
|
+
export declare const PasteFromOffice: Extension<PasteFromOfficeOptions, any>;
|
|
378
|
+
|
|
379
|
+
export declare interface PasteFromOfficeOptions {
|
|
380
|
+
/**
|
|
381
|
+
* Enable/disable paste-from-office cleaning.
|
|
382
|
+
* When false, pasted content passes through unchanged.
|
|
383
|
+
*/
|
|
384
|
+
enabled: boolean;
|
|
385
|
+
}
|
|
386
|
+
|
|
376
387
|
/**
|
|
377
388
|
* Reset the global translation function to the default identity function.
|
|
378
389
|
* This also clears the customized flag so that the next editor created
|
package/dist/index.js
CHANGED
|
@@ -44033,6 +44033,384 @@ const Mention = Node3.create({
|
|
|
44033
44033
|
];
|
|
44034
44034
|
}
|
|
44035
44035
|
});
|
|
44036
|
+
const WORD_MARKERS = [
|
|
44037
|
+
'xmlns:o="urn:schemas-microsoft-com:office:office"',
|
|
44038
|
+
'xmlns:w="urn:schemas-microsoft-com:office:word"',
|
|
44039
|
+
'class="Mso',
|
|
44040
|
+
"class=Mso",
|
|
44041
|
+
'style="mso-',
|
|
44042
|
+
"style='mso-"
|
|
44043
|
+
];
|
|
44044
|
+
const EXCEL_MARKERS = [
|
|
44045
|
+
'xmlns:x="urn:schemas-microsoft-com:office:excel"',
|
|
44046
|
+
"ProgId content=Excel.Sheet",
|
|
44047
|
+
'ProgId content="Excel.Sheet"'
|
|
44048
|
+
];
|
|
44049
|
+
function isWordContent(html) {
|
|
44050
|
+
return WORD_MARKERS.some((marker) => html.includes(marker));
|
|
44051
|
+
}
|
|
44052
|
+
function isExcelContent(html) {
|
|
44053
|
+
return EXCEL_MARKERS.some((marker) => html.includes(marker));
|
|
44054
|
+
}
|
|
44055
|
+
function isOfficeContent(html) {
|
|
44056
|
+
return isWordContent(html) || isExcelContent(html);
|
|
44057
|
+
}
|
|
44058
|
+
function removeConditionalComments(html) {
|
|
44059
|
+
return html.replace(/<!--\[if[^\]]*\]>[\s\S]*?<!\[endif\]-->/gi, "");
|
|
44060
|
+
}
|
|
44061
|
+
const OFFICE_NS_TAG_PATTERN = /(?:<\/?)(?:o|w|v|m|x|st\d):/i;
|
|
44062
|
+
function removeOfficeElements(doc2) {
|
|
44063
|
+
const allElements = Array.from(doc2.body.querySelectorAll("*"));
|
|
44064
|
+
for (const el2 of allElements) {
|
|
44065
|
+
const tagName = el2.tagName.toLowerCase();
|
|
44066
|
+
if (OFFICE_NS_TAG_PATTERN.test(`<${tagName}`)) {
|
|
44067
|
+
const parent = el2.parentNode;
|
|
44068
|
+
if (parent) {
|
|
44069
|
+
while (el2.firstChild) {
|
|
44070
|
+
parent.insertBefore(el2.firstChild, el2);
|
|
44071
|
+
}
|
|
44072
|
+
parent.removeChild(el2);
|
|
44073
|
+
}
|
|
44074
|
+
}
|
|
44075
|
+
}
|
|
44076
|
+
const remaining = Array.from(doc2.body.querySelectorAll("*"));
|
|
44077
|
+
for (const el2 of remaining) {
|
|
44078
|
+
const attrs = Array.from(el2.attributes);
|
|
44079
|
+
for (const attr of attrs) {
|
|
44080
|
+
if (attr.name.startsWith("xmlns:") || attr.name === "xmlns") {
|
|
44081
|
+
el2.removeAttribute(attr.name);
|
|
44082
|
+
}
|
|
44083
|
+
}
|
|
44084
|
+
}
|
|
44085
|
+
}
|
|
44086
|
+
function parseListStyles(doc2) {
|
|
44087
|
+
const styleMap = /* @__PURE__ */ new Map();
|
|
44088
|
+
const styleEls = doc2.querySelectorAll("style");
|
|
44089
|
+
for (const styleEl of Array.from(styleEls)) {
|
|
44090
|
+
const css2 = styleEl.textContent ?? "";
|
|
44091
|
+
const listRulePattern = /@list\s+(l\d+):level(\d+)\s*\{([^}]*)\}/gi;
|
|
44092
|
+
let match;
|
|
44093
|
+
while ((match = listRulePattern.exec(css2)) !== null) {
|
|
44094
|
+
const listId = match[1];
|
|
44095
|
+
const level = match[2];
|
|
44096
|
+
const body = match[3];
|
|
44097
|
+
const key = `${listId}:level${level}`;
|
|
44098
|
+
const formatMatch = /mso-level-number-format:\s*([^;]+)/i.exec(body);
|
|
44099
|
+
if (formatMatch) {
|
|
44100
|
+
const format = formatMatch[1].trim().toLowerCase();
|
|
44101
|
+
styleMap.set(key, format !== "bullet");
|
|
44102
|
+
} else {
|
|
44103
|
+
styleMap.set(key, true);
|
|
44104
|
+
}
|
|
44105
|
+
}
|
|
44106
|
+
}
|
|
44107
|
+
return styleMap;
|
|
44108
|
+
}
|
|
44109
|
+
function parseListStyle(style2) {
|
|
44110
|
+
const match = /mso-list:\s*(l\d+)\s+level(\d+)\s+/i.exec(style2);
|
|
44111
|
+
if (!match) return null;
|
|
44112
|
+
return {
|
|
44113
|
+
listId: match[1],
|
|
44114
|
+
level: parseInt(match[2], 10),
|
|
44115
|
+
isOrdered: false
|
|
44116
|
+
// Will be resolved from style rules
|
|
44117
|
+
};
|
|
44118
|
+
}
|
|
44119
|
+
function convertWordLists(doc2) {
|
|
44120
|
+
const listStyles = parseListStyles(doc2);
|
|
44121
|
+
const listParagraphs = Array.from(doc2.body.querySelectorAll('[class*="MsoList"]'));
|
|
44122
|
+
if (listParagraphs.length === 0) return;
|
|
44123
|
+
const groups = [];
|
|
44124
|
+
let currentGroup = [];
|
|
44125
|
+
for (const p of listParagraphs) {
|
|
44126
|
+
const el2 = p;
|
|
44127
|
+
const style2 = el2.getAttribute("style") ?? "";
|
|
44128
|
+
if (!parseListStyle(style2)) continue;
|
|
44129
|
+
if (currentGroup.length > 0) {
|
|
44130
|
+
const lastEl = currentGroup[currentGroup.length - 1];
|
|
44131
|
+
let nextSibling = lastEl.nextElementSibling;
|
|
44132
|
+
while (nextSibling && nextSibling !== el2 && nextSibling.textContent?.trim() === "") {
|
|
44133
|
+
nextSibling = nextSibling.nextElementSibling;
|
|
44134
|
+
}
|
|
44135
|
+
if (nextSibling !== el2) {
|
|
44136
|
+
groups.push(currentGroup);
|
|
44137
|
+
currentGroup = [];
|
|
44138
|
+
}
|
|
44139
|
+
}
|
|
44140
|
+
currentGroup.push(el2);
|
|
44141
|
+
}
|
|
44142
|
+
if (currentGroup.length > 0) {
|
|
44143
|
+
groups.push(currentGroup);
|
|
44144
|
+
}
|
|
44145
|
+
for (const group of groups) {
|
|
44146
|
+
convertListGroup(doc2, group, listStyles);
|
|
44147
|
+
}
|
|
44148
|
+
}
|
|
44149
|
+
function convertListGroup(doc2, paragraphs, listStyles) {
|
|
44150
|
+
if (paragraphs.length === 0) return;
|
|
44151
|
+
const rootInfo = parseListStyle(paragraphs[0].getAttribute("style") ?? "");
|
|
44152
|
+
if (!rootInfo) return;
|
|
44153
|
+
const parent = paragraphs[0].parentNode;
|
|
44154
|
+
if (!parent) return;
|
|
44155
|
+
const rootKey = `${rootInfo.listId}:level${rootInfo.level}`;
|
|
44156
|
+
const isRootOrdered = listStyles.get(rootKey) ?? false;
|
|
44157
|
+
const rootList = doc2.createElement(isRootOrdered ? "ol" : "ul");
|
|
44158
|
+
const stack = [{ element: rootList, level: rootInfo.level }];
|
|
44159
|
+
for (const p of paragraphs) {
|
|
44160
|
+
const style2 = p.getAttribute("style") ?? "";
|
|
44161
|
+
const info = parseListStyle(style2);
|
|
44162
|
+
if (!info) continue;
|
|
44163
|
+
const key = `${info.listId}:level${info.level}`;
|
|
44164
|
+
const isOrdered = listStyles.get(key) ?? false;
|
|
44165
|
+
while (stack.length > 1 && stack[stack.length - 1].level >= info.level) {
|
|
44166
|
+
stack.pop();
|
|
44167
|
+
}
|
|
44168
|
+
if (info.level > stack[stack.length - 1].level) {
|
|
44169
|
+
const currentList = stack[stack.length - 1].element;
|
|
44170
|
+
let lastLi = currentList.lastElementChild;
|
|
44171
|
+
if (!lastLi || lastLi.tagName.toLowerCase() !== "li") {
|
|
44172
|
+
lastLi = doc2.createElement("li");
|
|
44173
|
+
currentList.appendChild(lastLi);
|
|
44174
|
+
}
|
|
44175
|
+
const subList = doc2.createElement(isOrdered ? "ol" : "ul");
|
|
44176
|
+
lastLi.appendChild(subList);
|
|
44177
|
+
stack.push({ element: subList, level: info.level });
|
|
44178
|
+
}
|
|
44179
|
+
const li = doc2.createElement("li");
|
|
44180
|
+
removeListMarkers(p);
|
|
44181
|
+
while (p.firstChild) {
|
|
44182
|
+
li.appendChild(p.firstChild);
|
|
44183
|
+
}
|
|
44184
|
+
const cleanedStyle = cleanMsoStyles(style2);
|
|
44185
|
+
if (cleanedStyle) {
|
|
44186
|
+
li.setAttribute("style", cleanedStyle);
|
|
44187
|
+
}
|
|
44188
|
+
stack[stack.length - 1].element.appendChild(li);
|
|
44189
|
+
}
|
|
44190
|
+
parent.insertBefore(rootList, paragraphs[0]);
|
|
44191
|
+
for (const p of paragraphs) {
|
|
44192
|
+
p.remove();
|
|
44193
|
+
}
|
|
44194
|
+
}
|
|
44195
|
+
function removeListMarkers(el2) {
|
|
44196
|
+
const spans = Array.from(el2.querySelectorAll("span"));
|
|
44197
|
+
for (const span of spans) {
|
|
44198
|
+
const style2 = span.getAttribute("style") ?? "";
|
|
44199
|
+
if (/mso-list:\s*Ignore/i.test(style2)) {
|
|
44200
|
+
span.remove();
|
|
44201
|
+
}
|
|
44202
|
+
}
|
|
44203
|
+
}
|
|
44204
|
+
const MSO_PROPERTY_PATTERN = /\bmso-[^:]+:[^;]+;?\s*/gi;
|
|
44205
|
+
const MSO_CLASS_PATTERN = /\bMso\w*|\bxl\d+/g;
|
|
44206
|
+
function cleanMsoStyles(style2) {
|
|
44207
|
+
let cleaned = style2.replace(MSO_PROPERTY_PATTERN, "");
|
|
44208
|
+
cleaned = cleaned.replace(/;\s*;/g, ";").replace(/^\s*;\s*/, "").replace(/\s*;\s*$/, "").trim();
|
|
44209
|
+
return cleaned || "";
|
|
44210
|
+
}
|
|
44211
|
+
function cleanFontFamily(value) {
|
|
44212
|
+
const first2 = value.split(",")[0].trim();
|
|
44213
|
+
return first2.replace(/^["']|["']$/g, "");
|
|
44214
|
+
}
|
|
44215
|
+
function cleanElementStyles(doc2) {
|
|
44216
|
+
const allElements = Array.from(doc2.body.querySelectorAll("*"));
|
|
44217
|
+
for (const el2 of allElements) {
|
|
44218
|
+
const className = el2.getAttribute("class");
|
|
44219
|
+
if (className) {
|
|
44220
|
+
const cleaned = className.replace(MSO_CLASS_PATTERN, "").trim();
|
|
44221
|
+
if (cleaned) {
|
|
44222
|
+
el2.setAttribute("class", cleaned);
|
|
44223
|
+
} else {
|
|
44224
|
+
el2.removeAttribute("class");
|
|
44225
|
+
}
|
|
44226
|
+
}
|
|
44227
|
+
const style2 = el2.getAttribute("style");
|
|
44228
|
+
if (style2) {
|
|
44229
|
+
let cleaned = cleanMsoStyles(style2);
|
|
44230
|
+
const fontFamilyMatch = /font-family:\s*([^;]+)/i.exec(cleaned);
|
|
44231
|
+
if (fontFamilyMatch) {
|
|
44232
|
+
const cleanedFont = cleanFontFamily(fontFamilyMatch[1]);
|
|
44233
|
+
cleaned = cleaned.replace(fontFamilyMatch[0], `font-family: ${cleanedFont}`);
|
|
44234
|
+
}
|
|
44235
|
+
if (cleaned) {
|
|
44236
|
+
el2.setAttribute("style", cleaned);
|
|
44237
|
+
} else {
|
|
44238
|
+
el2.removeAttribute("style");
|
|
44239
|
+
}
|
|
44240
|
+
}
|
|
44241
|
+
const attrsToRemove = Array.from(el2.attributes).filter(
|
|
44242
|
+
(attr) => attr.name.startsWith("v:") || attr.name.startsWith("o:") || attr.name === "lang"
|
|
44243
|
+
);
|
|
44244
|
+
for (const attr of attrsToRemove) {
|
|
44245
|
+
el2.removeAttribute(attr.name);
|
|
44246
|
+
}
|
|
44247
|
+
}
|
|
44248
|
+
}
|
|
44249
|
+
function removeEmptyWrappers(doc2) {
|
|
44250
|
+
let changed = true;
|
|
44251
|
+
while (changed) {
|
|
44252
|
+
changed = false;
|
|
44253
|
+
const spans = Array.from(doc2.body.querySelectorAll("span"));
|
|
44254
|
+
for (const span of spans) {
|
|
44255
|
+
if (span.attributes.length === 0) {
|
|
44256
|
+
const parent = span.parentNode;
|
|
44257
|
+
if (parent) {
|
|
44258
|
+
while (span.firstChild) {
|
|
44259
|
+
parent.insertBefore(span.firstChild, span);
|
|
44260
|
+
}
|
|
44261
|
+
parent.removeChild(span);
|
|
44262
|
+
changed = true;
|
|
44263
|
+
}
|
|
44264
|
+
}
|
|
44265
|
+
}
|
|
44266
|
+
}
|
|
44267
|
+
const emptyParas = Array.from(doc2.body.querySelectorAll("p"));
|
|
44268
|
+
for (const p of emptyParas) {
|
|
44269
|
+
if (p.innerHTML.trim() === "" && doc2.body.children.length > 1) {
|
|
44270
|
+
p.remove();
|
|
44271
|
+
}
|
|
44272
|
+
}
|
|
44273
|
+
}
|
|
44274
|
+
function normalizeExcelTables(doc2) {
|
|
44275
|
+
const tables = Array.from(doc2.body.querySelectorAll("table"));
|
|
44276
|
+
for (const table of tables) {
|
|
44277
|
+
removeExcelAttributes(table);
|
|
44278
|
+
const cells = Array.from(table.querySelectorAll("td, th"));
|
|
44279
|
+
for (const cell of cells) {
|
|
44280
|
+
removeExcelAttributes(cell);
|
|
44281
|
+
const style2 = cell.getAttribute("style");
|
|
44282
|
+
if (style2) {
|
|
44283
|
+
const cleaned = cleanMsoStyles(style2);
|
|
44284
|
+
if (cleaned) {
|
|
44285
|
+
cell.setAttribute("style", cleaned);
|
|
44286
|
+
} else {
|
|
44287
|
+
cell.removeAttribute("style");
|
|
44288
|
+
}
|
|
44289
|
+
}
|
|
44290
|
+
}
|
|
44291
|
+
const rows = Array.from(table.querySelectorAll("tr"));
|
|
44292
|
+
for (const row of rows) {
|
|
44293
|
+
removeExcelAttributes(row);
|
|
44294
|
+
}
|
|
44295
|
+
}
|
|
44296
|
+
}
|
|
44297
|
+
const EXCEL_ATTRS = [
|
|
44298
|
+
"x:num",
|
|
44299
|
+
"x:str",
|
|
44300
|
+
"x:fmla",
|
|
44301
|
+
"x:autofilter",
|
|
44302
|
+
"mso-number-format"
|
|
44303
|
+
];
|
|
44304
|
+
function removeExcelAttributes(el2) {
|
|
44305
|
+
for (const attr of EXCEL_ATTRS) {
|
|
44306
|
+
el2.removeAttribute(attr);
|
|
44307
|
+
}
|
|
44308
|
+
const className = el2.getAttribute("class");
|
|
44309
|
+
if (className) {
|
|
44310
|
+
const cleaned = className.replace(MSO_CLASS_PATTERN, "").trim();
|
|
44311
|
+
if (cleaned) {
|
|
44312
|
+
el2.setAttribute("class", cleaned);
|
|
44313
|
+
} else {
|
|
44314
|
+
el2.removeAttribute("class");
|
|
44315
|
+
}
|
|
44316
|
+
}
|
|
44317
|
+
}
|
|
44318
|
+
const DANGEROUS_TAGS = [
|
|
44319
|
+
"script",
|
|
44320
|
+
"iframe",
|
|
44321
|
+
"object",
|
|
44322
|
+
"embed",
|
|
44323
|
+
"applet",
|
|
44324
|
+
"form",
|
|
44325
|
+
"input",
|
|
44326
|
+
"textarea",
|
|
44327
|
+
"select",
|
|
44328
|
+
"button"
|
|
44329
|
+
];
|
|
44330
|
+
const EVENT_ATTR_PATTERN = /^on/i;
|
|
44331
|
+
const DANGEROUS_URL_PATTERN = /^\s*(javascript|vbscript|data\s*:(?!image))/i;
|
|
44332
|
+
function sanitize(doc2) {
|
|
44333
|
+
for (const tag of DANGEROUS_TAGS) {
|
|
44334
|
+
const elements = Array.from(doc2.body.querySelectorAll(tag));
|
|
44335
|
+
for (const el2 of elements) {
|
|
44336
|
+
el2.remove();
|
|
44337
|
+
}
|
|
44338
|
+
}
|
|
44339
|
+
const allElements = Array.from(doc2.body.querySelectorAll("*"));
|
|
44340
|
+
for (const el2 of allElements) {
|
|
44341
|
+
const attrs = Array.from(el2.attributes);
|
|
44342
|
+
for (const attr of attrs) {
|
|
44343
|
+
if (EVENT_ATTR_PATTERN.test(attr.name)) {
|
|
44344
|
+
el2.removeAttribute(attr.name);
|
|
44345
|
+
continue;
|
|
44346
|
+
}
|
|
44347
|
+
if ((attr.name === "href" || attr.name === "src" || attr.name === "action") && DANGEROUS_URL_PATTERN.test(attr.value)) {
|
|
44348
|
+
el2.removeAttribute(attr.name);
|
|
44349
|
+
}
|
|
44350
|
+
}
|
|
44351
|
+
const src = el2.getAttribute("src");
|
|
44352
|
+
if (src && src.startsWith("file://")) {
|
|
44353
|
+
el2.removeAttribute("src");
|
|
44354
|
+
}
|
|
44355
|
+
const href = el2.getAttribute("href");
|
|
44356
|
+
if (href && href.startsWith("file://")) {
|
|
44357
|
+
el2.removeAttribute("href");
|
|
44358
|
+
}
|
|
44359
|
+
}
|
|
44360
|
+
}
|
|
44361
|
+
function removeStyleBlocks(doc2) {
|
|
44362
|
+
const styles = Array.from(doc2.querySelectorAll("style"));
|
|
44363
|
+
for (const s of styles) {
|
|
44364
|
+
s.remove();
|
|
44365
|
+
}
|
|
44366
|
+
}
|
|
44367
|
+
function removeHeadElements(doc2) {
|
|
44368
|
+
const selectors = ["meta", "link", "title", "xml"];
|
|
44369
|
+
for (const selector of selectors) {
|
|
44370
|
+
const elements = Array.from(doc2.body.querySelectorAll(selector));
|
|
44371
|
+
for (const el2 of elements) {
|
|
44372
|
+
el2.remove();
|
|
44373
|
+
}
|
|
44374
|
+
}
|
|
44375
|
+
}
|
|
44376
|
+
function transformOfficeHTML(html) {
|
|
44377
|
+
if (!isOfficeContent(html)) {
|
|
44378
|
+
return html;
|
|
44379
|
+
}
|
|
44380
|
+
let cleaned = removeConditionalComments(html);
|
|
44381
|
+
const parser = new DOMParser();
|
|
44382
|
+
const doc2 = parser.parseFromString(cleaned, "text/html");
|
|
44383
|
+
removeHeadElements(doc2);
|
|
44384
|
+
if (isWordContent(html)) {
|
|
44385
|
+
convertWordLists(doc2);
|
|
44386
|
+
}
|
|
44387
|
+
removeOfficeElements(doc2);
|
|
44388
|
+
if (isExcelContent(html)) {
|
|
44389
|
+
normalizeExcelTables(doc2);
|
|
44390
|
+
}
|
|
44391
|
+
cleanElementStyles(doc2);
|
|
44392
|
+
removeStyleBlocks(doc2);
|
|
44393
|
+
removeEmptyWrappers(doc2);
|
|
44394
|
+
sanitize(doc2);
|
|
44395
|
+
return doc2.body.innerHTML;
|
|
44396
|
+
}
|
|
44397
|
+
const PasteFromOffice = Extension.create({
|
|
44398
|
+
name: "pasteFromOffice",
|
|
44399
|
+
addOptions() {
|
|
44400
|
+
return {
|
|
44401
|
+
enabled: true
|
|
44402
|
+
};
|
|
44403
|
+
},
|
|
44404
|
+
addStorage() {
|
|
44405
|
+
return {};
|
|
44406
|
+
},
|
|
44407
|
+
transformPastedHTML(html) {
|
|
44408
|
+
if (!this.options.enabled) {
|
|
44409
|
+
return html;
|
|
44410
|
+
}
|
|
44411
|
+
return transformOfficeHTML(html);
|
|
44412
|
+
}
|
|
44413
|
+
});
|
|
44036
44414
|
const en = {
|
|
44037
44415
|
"Bold": "Bold",
|
|
44038
44416
|
"Italic": "Italic",
|
|
@@ -46403,7 +46781,8 @@ class HTMLEditor {
|
|
|
46403
46781
|
convert_unsafe_embeds: config.convert_unsafe_embeds ?? true,
|
|
46404
46782
|
format_empty_lines: config.format_empty_lines ?? true,
|
|
46405
46783
|
toolbar_narrow_breakpoint: config.toolbar_narrow_breakpoint,
|
|
46406
|
-
toolbar_priority: config.toolbar_priority
|
|
46784
|
+
toolbar_priority: config.toolbar_priority,
|
|
46785
|
+
paste_from_office: config.paste_from_office ?? true
|
|
46407
46786
|
};
|
|
46408
46787
|
}
|
|
46409
46788
|
createEditor() {
|
|
@@ -46606,6 +46985,9 @@ class HTMLEditor {
|
|
|
46606
46985
|
}),
|
|
46607
46986
|
TextDirection
|
|
46608
46987
|
];
|
|
46988
|
+
if (this.config.paste_from_office !== false) {
|
|
46989
|
+
extensions.push(PasteFromOffice);
|
|
46990
|
+
}
|
|
46609
46991
|
if (!this.config.basicEditor) {
|
|
46610
46992
|
extensions.push(
|
|
46611
46993
|
Image.configure({
|
|
@@ -46830,6 +47212,7 @@ exports.HTMLEditor = HTMLEditor;
|
|
|
46830
47212
|
exports.LineHeight = LineHeight;
|
|
46831
47213
|
exports.LinkEditor = LinkEditor;
|
|
46832
47214
|
exports.Mention = Mention;
|
|
47215
|
+
exports.PasteFromOffice = PasteFromOffice;
|
|
46833
47216
|
exports.SearchReplace = SearchReplace;
|
|
46834
47217
|
exports.SignatureBlock = SignatureBlock;
|
|
46835
47218
|
exports.SourceEditor = SourceEditor;
|
package/dist/index.mjs
CHANGED
|
@@ -44031,6 +44031,384 @@ const Mention = Node3.create({
|
|
|
44031
44031
|
];
|
|
44032
44032
|
}
|
|
44033
44033
|
});
|
|
44034
|
+
const WORD_MARKERS = [
|
|
44035
|
+
'xmlns:o="urn:schemas-microsoft-com:office:office"',
|
|
44036
|
+
'xmlns:w="urn:schemas-microsoft-com:office:word"',
|
|
44037
|
+
'class="Mso',
|
|
44038
|
+
"class=Mso",
|
|
44039
|
+
'style="mso-',
|
|
44040
|
+
"style='mso-"
|
|
44041
|
+
];
|
|
44042
|
+
const EXCEL_MARKERS = [
|
|
44043
|
+
'xmlns:x="urn:schemas-microsoft-com:office:excel"',
|
|
44044
|
+
"ProgId content=Excel.Sheet",
|
|
44045
|
+
'ProgId content="Excel.Sheet"'
|
|
44046
|
+
];
|
|
44047
|
+
function isWordContent(html) {
|
|
44048
|
+
return WORD_MARKERS.some((marker) => html.includes(marker));
|
|
44049
|
+
}
|
|
44050
|
+
function isExcelContent(html) {
|
|
44051
|
+
return EXCEL_MARKERS.some((marker) => html.includes(marker));
|
|
44052
|
+
}
|
|
44053
|
+
function isOfficeContent(html) {
|
|
44054
|
+
return isWordContent(html) || isExcelContent(html);
|
|
44055
|
+
}
|
|
44056
|
+
function removeConditionalComments(html) {
|
|
44057
|
+
return html.replace(/<!--\[if[^\]]*\]>[\s\S]*?<!\[endif\]-->/gi, "");
|
|
44058
|
+
}
|
|
44059
|
+
const OFFICE_NS_TAG_PATTERN = /(?:<\/?)(?:o|w|v|m|x|st\d):/i;
|
|
44060
|
+
function removeOfficeElements(doc2) {
|
|
44061
|
+
const allElements = Array.from(doc2.body.querySelectorAll("*"));
|
|
44062
|
+
for (const el2 of allElements) {
|
|
44063
|
+
const tagName = el2.tagName.toLowerCase();
|
|
44064
|
+
if (OFFICE_NS_TAG_PATTERN.test(`<${tagName}`)) {
|
|
44065
|
+
const parent = el2.parentNode;
|
|
44066
|
+
if (parent) {
|
|
44067
|
+
while (el2.firstChild) {
|
|
44068
|
+
parent.insertBefore(el2.firstChild, el2);
|
|
44069
|
+
}
|
|
44070
|
+
parent.removeChild(el2);
|
|
44071
|
+
}
|
|
44072
|
+
}
|
|
44073
|
+
}
|
|
44074
|
+
const remaining = Array.from(doc2.body.querySelectorAll("*"));
|
|
44075
|
+
for (const el2 of remaining) {
|
|
44076
|
+
const attrs = Array.from(el2.attributes);
|
|
44077
|
+
for (const attr of attrs) {
|
|
44078
|
+
if (attr.name.startsWith("xmlns:") || attr.name === "xmlns") {
|
|
44079
|
+
el2.removeAttribute(attr.name);
|
|
44080
|
+
}
|
|
44081
|
+
}
|
|
44082
|
+
}
|
|
44083
|
+
}
|
|
44084
|
+
function parseListStyles(doc2) {
|
|
44085
|
+
const styleMap = /* @__PURE__ */ new Map();
|
|
44086
|
+
const styleEls = doc2.querySelectorAll("style");
|
|
44087
|
+
for (const styleEl of Array.from(styleEls)) {
|
|
44088
|
+
const css2 = styleEl.textContent ?? "";
|
|
44089
|
+
const listRulePattern = /@list\s+(l\d+):level(\d+)\s*\{([^}]*)\}/gi;
|
|
44090
|
+
let match;
|
|
44091
|
+
while ((match = listRulePattern.exec(css2)) !== null) {
|
|
44092
|
+
const listId = match[1];
|
|
44093
|
+
const level = match[2];
|
|
44094
|
+
const body = match[3];
|
|
44095
|
+
const key = `${listId}:level${level}`;
|
|
44096
|
+
const formatMatch = /mso-level-number-format:\s*([^;]+)/i.exec(body);
|
|
44097
|
+
if (formatMatch) {
|
|
44098
|
+
const format = formatMatch[1].trim().toLowerCase();
|
|
44099
|
+
styleMap.set(key, format !== "bullet");
|
|
44100
|
+
} else {
|
|
44101
|
+
styleMap.set(key, true);
|
|
44102
|
+
}
|
|
44103
|
+
}
|
|
44104
|
+
}
|
|
44105
|
+
return styleMap;
|
|
44106
|
+
}
|
|
44107
|
+
function parseListStyle(style2) {
|
|
44108
|
+
const match = /mso-list:\s*(l\d+)\s+level(\d+)\s+/i.exec(style2);
|
|
44109
|
+
if (!match) return null;
|
|
44110
|
+
return {
|
|
44111
|
+
listId: match[1],
|
|
44112
|
+
level: parseInt(match[2], 10),
|
|
44113
|
+
isOrdered: false
|
|
44114
|
+
// Will be resolved from style rules
|
|
44115
|
+
};
|
|
44116
|
+
}
|
|
44117
|
+
function convertWordLists(doc2) {
|
|
44118
|
+
const listStyles = parseListStyles(doc2);
|
|
44119
|
+
const listParagraphs = Array.from(doc2.body.querySelectorAll('[class*="MsoList"]'));
|
|
44120
|
+
if (listParagraphs.length === 0) return;
|
|
44121
|
+
const groups = [];
|
|
44122
|
+
let currentGroup = [];
|
|
44123
|
+
for (const p of listParagraphs) {
|
|
44124
|
+
const el2 = p;
|
|
44125
|
+
const style2 = el2.getAttribute("style") ?? "";
|
|
44126
|
+
if (!parseListStyle(style2)) continue;
|
|
44127
|
+
if (currentGroup.length > 0) {
|
|
44128
|
+
const lastEl = currentGroup[currentGroup.length - 1];
|
|
44129
|
+
let nextSibling = lastEl.nextElementSibling;
|
|
44130
|
+
while (nextSibling && nextSibling !== el2 && nextSibling.textContent?.trim() === "") {
|
|
44131
|
+
nextSibling = nextSibling.nextElementSibling;
|
|
44132
|
+
}
|
|
44133
|
+
if (nextSibling !== el2) {
|
|
44134
|
+
groups.push(currentGroup);
|
|
44135
|
+
currentGroup = [];
|
|
44136
|
+
}
|
|
44137
|
+
}
|
|
44138
|
+
currentGroup.push(el2);
|
|
44139
|
+
}
|
|
44140
|
+
if (currentGroup.length > 0) {
|
|
44141
|
+
groups.push(currentGroup);
|
|
44142
|
+
}
|
|
44143
|
+
for (const group of groups) {
|
|
44144
|
+
convertListGroup(doc2, group, listStyles);
|
|
44145
|
+
}
|
|
44146
|
+
}
|
|
44147
|
+
function convertListGroup(doc2, paragraphs, listStyles) {
|
|
44148
|
+
if (paragraphs.length === 0) return;
|
|
44149
|
+
const rootInfo = parseListStyle(paragraphs[0].getAttribute("style") ?? "");
|
|
44150
|
+
if (!rootInfo) return;
|
|
44151
|
+
const parent = paragraphs[0].parentNode;
|
|
44152
|
+
if (!parent) return;
|
|
44153
|
+
const rootKey = `${rootInfo.listId}:level${rootInfo.level}`;
|
|
44154
|
+
const isRootOrdered = listStyles.get(rootKey) ?? false;
|
|
44155
|
+
const rootList = doc2.createElement(isRootOrdered ? "ol" : "ul");
|
|
44156
|
+
const stack = [{ element: rootList, level: rootInfo.level }];
|
|
44157
|
+
for (const p of paragraphs) {
|
|
44158
|
+
const style2 = p.getAttribute("style") ?? "";
|
|
44159
|
+
const info = parseListStyle(style2);
|
|
44160
|
+
if (!info) continue;
|
|
44161
|
+
const key = `${info.listId}:level${info.level}`;
|
|
44162
|
+
const isOrdered = listStyles.get(key) ?? false;
|
|
44163
|
+
while (stack.length > 1 && stack[stack.length - 1].level >= info.level) {
|
|
44164
|
+
stack.pop();
|
|
44165
|
+
}
|
|
44166
|
+
if (info.level > stack[stack.length - 1].level) {
|
|
44167
|
+
const currentList = stack[stack.length - 1].element;
|
|
44168
|
+
let lastLi = currentList.lastElementChild;
|
|
44169
|
+
if (!lastLi || lastLi.tagName.toLowerCase() !== "li") {
|
|
44170
|
+
lastLi = doc2.createElement("li");
|
|
44171
|
+
currentList.appendChild(lastLi);
|
|
44172
|
+
}
|
|
44173
|
+
const subList = doc2.createElement(isOrdered ? "ol" : "ul");
|
|
44174
|
+
lastLi.appendChild(subList);
|
|
44175
|
+
stack.push({ element: subList, level: info.level });
|
|
44176
|
+
}
|
|
44177
|
+
const li = doc2.createElement("li");
|
|
44178
|
+
removeListMarkers(p);
|
|
44179
|
+
while (p.firstChild) {
|
|
44180
|
+
li.appendChild(p.firstChild);
|
|
44181
|
+
}
|
|
44182
|
+
const cleanedStyle = cleanMsoStyles(style2);
|
|
44183
|
+
if (cleanedStyle) {
|
|
44184
|
+
li.setAttribute("style", cleanedStyle);
|
|
44185
|
+
}
|
|
44186
|
+
stack[stack.length - 1].element.appendChild(li);
|
|
44187
|
+
}
|
|
44188
|
+
parent.insertBefore(rootList, paragraphs[0]);
|
|
44189
|
+
for (const p of paragraphs) {
|
|
44190
|
+
p.remove();
|
|
44191
|
+
}
|
|
44192
|
+
}
|
|
44193
|
+
function removeListMarkers(el2) {
|
|
44194
|
+
const spans = Array.from(el2.querySelectorAll("span"));
|
|
44195
|
+
for (const span of spans) {
|
|
44196
|
+
const style2 = span.getAttribute("style") ?? "";
|
|
44197
|
+
if (/mso-list:\s*Ignore/i.test(style2)) {
|
|
44198
|
+
span.remove();
|
|
44199
|
+
}
|
|
44200
|
+
}
|
|
44201
|
+
}
|
|
44202
|
+
const MSO_PROPERTY_PATTERN = /\bmso-[^:]+:[^;]+;?\s*/gi;
|
|
44203
|
+
const MSO_CLASS_PATTERN = /\bMso\w*|\bxl\d+/g;
|
|
44204
|
+
function cleanMsoStyles(style2) {
|
|
44205
|
+
let cleaned = style2.replace(MSO_PROPERTY_PATTERN, "");
|
|
44206
|
+
cleaned = cleaned.replace(/;\s*;/g, ";").replace(/^\s*;\s*/, "").replace(/\s*;\s*$/, "").trim();
|
|
44207
|
+
return cleaned || "";
|
|
44208
|
+
}
|
|
44209
|
+
function cleanFontFamily(value) {
|
|
44210
|
+
const first2 = value.split(",")[0].trim();
|
|
44211
|
+
return first2.replace(/^["']|["']$/g, "");
|
|
44212
|
+
}
|
|
44213
|
+
function cleanElementStyles(doc2) {
|
|
44214
|
+
const allElements = Array.from(doc2.body.querySelectorAll("*"));
|
|
44215
|
+
for (const el2 of allElements) {
|
|
44216
|
+
const className = el2.getAttribute("class");
|
|
44217
|
+
if (className) {
|
|
44218
|
+
const cleaned = className.replace(MSO_CLASS_PATTERN, "").trim();
|
|
44219
|
+
if (cleaned) {
|
|
44220
|
+
el2.setAttribute("class", cleaned);
|
|
44221
|
+
} else {
|
|
44222
|
+
el2.removeAttribute("class");
|
|
44223
|
+
}
|
|
44224
|
+
}
|
|
44225
|
+
const style2 = el2.getAttribute("style");
|
|
44226
|
+
if (style2) {
|
|
44227
|
+
let cleaned = cleanMsoStyles(style2);
|
|
44228
|
+
const fontFamilyMatch = /font-family:\s*([^;]+)/i.exec(cleaned);
|
|
44229
|
+
if (fontFamilyMatch) {
|
|
44230
|
+
const cleanedFont = cleanFontFamily(fontFamilyMatch[1]);
|
|
44231
|
+
cleaned = cleaned.replace(fontFamilyMatch[0], `font-family: ${cleanedFont}`);
|
|
44232
|
+
}
|
|
44233
|
+
if (cleaned) {
|
|
44234
|
+
el2.setAttribute("style", cleaned);
|
|
44235
|
+
} else {
|
|
44236
|
+
el2.removeAttribute("style");
|
|
44237
|
+
}
|
|
44238
|
+
}
|
|
44239
|
+
const attrsToRemove = Array.from(el2.attributes).filter(
|
|
44240
|
+
(attr) => attr.name.startsWith("v:") || attr.name.startsWith("o:") || attr.name === "lang"
|
|
44241
|
+
);
|
|
44242
|
+
for (const attr of attrsToRemove) {
|
|
44243
|
+
el2.removeAttribute(attr.name);
|
|
44244
|
+
}
|
|
44245
|
+
}
|
|
44246
|
+
}
|
|
44247
|
+
function removeEmptyWrappers(doc2) {
|
|
44248
|
+
let changed = true;
|
|
44249
|
+
while (changed) {
|
|
44250
|
+
changed = false;
|
|
44251
|
+
const spans = Array.from(doc2.body.querySelectorAll("span"));
|
|
44252
|
+
for (const span of spans) {
|
|
44253
|
+
if (span.attributes.length === 0) {
|
|
44254
|
+
const parent = span.parentNode;
|
|
44255
|
+
if (parent) {
|
|
44256
|
+
while (span.firstChild) {
|
|
44257
|
+
parent.insertBefore(span.firstChild, span);
|
|
44258
|
+
}
|
|
44259
|
+
parent.removeChild(span);
|
|
44260
|
+
changed = true;
|
|
44261
|
+
}
|
|
44262
|
+
}
|
|
44263
|
+
}
|
|
44264
|
+
}
|
|
44265
|
+
const emptyParas = Array.from(doc2.body.querySelectorAll("p"));
|
|
44266
|
+
for (const p of emptyParas) {
|
|
44267
|
+
if (p.innerHTML.trim() === "" && doc2.body.children.length > 1) {
|
|
44268
|
+
p.remove();
|
|
44269
|
+
}
|
|
44270
|
+
}
|
|
44271
|
+
}
|
|
44272
|
+
function normalizeExcelTables(doc2) {
|
|
44273
|
+
const tables = Array.from(doc2.body.querySelectorAll("table"));
|
|
44274
|
+
for (const table of tables) {
|
|
44275
|
+
removeExcelAttributes(table);
|
|
44276
|
+
const cells = Array.from(table.querySelectorAll("td, th"));
|
|
44277
|
+
for (const cell of cells) {
|
|
44278
|
+
removeExcelAttributes(cell);
|
|
44279
|
+
const style2 = cell.getAttribute("style");
|
|
44280
|
+
if (style2) {
|
|
44281
|
+
const cleaned = cleanMsoStyles(style2);
|
|
44282
|
+
if (cleaned) {
|
|
44283
|
+
cell.setAttribute("style", cleaned);
|
|
44284
|
+
} else {
|
|
44285
|
+
cell.removeAttribute("style");
|
|
44286
|
+
}
|
|
44287
|
+
}
|
|
44288
|
+
}
|
|
44289
|
+
const rows = Array.from(table.querySelectorAll("tr"));
|
|
44290
|
+
for (const row of rows) {
|
|
44291
|
+
removeExcelAttributes(row);
|
|
44292
|
+
}
|
|
44293
|
+
}
|
|
44294
|
+
}
|
|
44295
|
+
const EXCEL_ATTRS = [
|
|
44296
|
+
"x:num",
|
|
44297
|
+
"x:str",
|
|
44298
|
+
"x:fmla",
|
|
44299
|
+
"x:autofilter",
|
|
44300
|
+
"mso-number-format"
|
|
44301
|
+
];
|
|
44302
|
+
function removeExcelAttributes(el2) {
|
|
44303
|
+
for (const attr of EXCEL_ATTRS) {
|
|
44304
|
+
el2.removeAttribute(attr);
|
|
44305
|
+
}
|
|
44306
|
+
const className = el2.getAttribute("class");
|
|
44307
|
+
if (className) {
|
|
44308
|
+
const cleaned = className.replace(MSO_CLASS_PATTERN, "").trim();
|
|
44309
|
+
if (cleaned) {
|
|
44310
|
+
el2.setAttribute("class", cleaned);
|
|
44311
|
+
} else {
|
|
44312
|
+
el2.removeAttribute("class");
|
|
44313
|
+
}
|
|
44314
|
+
}
|
|
44315
|
+
}
|
|
44316
|
+
const DANGEROUS_TAGS = [
|
|
44317
|
+
"script",
|
|
44318
|
+
"iframe",
|
|
44319
|
+
"object",
|
|
44320
|
+
"embed",
|
|
44321
|
+
"applet",
|
|
44322
|
+
"form",
|
|
44323
|
+
"input",
|
|
44324
|
+
"textarea",
|
|
44325
|
+
"select",
|
|
44326
|
+
"button"
|
|
44327
|
+
];
|
|
44328
|
+
const EVENT_ATTR_PATTERN = /^on/i;
|
|
44329
|
+
const DANGEROUS_URL_PATTERN = /^\s*(javascript|vbscript|data\s*:(?!image))/i;
|
|
44330
|
+
function sanitize(doc2) {
|
|
44331
|
+
for (const tag of DANGEROUS_TAGS) {
|
|
44332
|
+
const elements = Array.from(doc2.body.querySelectorAll(tag));
|
|
44333
|
+
for (const el2 of elements) {
|
|
44334
|
+
el2.remove();
|
|
44335
|
+
}
|
|
44336
|
+
}
|
|
44337
|
+
const allElements = Array.from(doc2.body.querySelectorAll("*"));
|
|
44338
|
+
for (const el2 of allElements) {
|
|
44339
|
+
const attrs = Array.from(el2.attributes);
|
|
44340
|
+
for (const attr of attrs) {
|
|
44341
|
+
if (EVENT_ATTR_PATTERN.test(attr.name)) {
|
|
44342
|
+
el2.removeAttribute(attr.name);
|
|
44343
|
+
continue;
|
|
44344
|
+
}
|
|
44345
|
+
if ((attr.name === "href" || attr.name === "src" || attr.name === "action") && DANGEROUS_URL_PATTERN.test(attr.value)) {
|
|
44346
|
+
el2.removeAttribute(attr.name);
|
|
44347
|
+
}
|
|
44348
|
+
}
|
|
44349
|
+
const src = el2.getAttribute("src");
|
|
44350
|
+
if (src && src.startsWith("file://")) {
|
|
44351
|
+
el2.removeAttribute("src");
|
|
44352
|
+
}
|
|
44353
|
+
const href = el2.getAttribute("href");
|
|
44354
|
+
if (href && href.startsWith("file://")) {
|
|
44355
|
+
el2.removeAttribute("href");
|
|
44356
|
+
}
|
|
44357
|
+
}
|
|
44358
|
+
}
|
|
44359
|
+
function removeStyleBlocks(doc2) {
|
|
44360
|
+
const styles = Array.from(doc2.querySelectorAll("style"));
|
|
44361
|
+
for (const s of styles) {
|
|
44362
|
+
s.remove();
|
|
44363
|
+
}
|
|
44364
|
+
}
|
|
44365
|
+
function removeHeadElements(doc2) {
|
|
44366
|
+
const selectors = ["meta", "link", "title", "xml"];
|
|
44367
|
+
for (const selector of selectors) {
|
|
44368
|
+
const elements = Array.from(doc2.body.querySelectorAll(selector));
|
|
44369
|
+
for (const el2 of elements) {
|
|
44370
|
+
el2.remove();
|
|
44371
|
+
}
|
|
44372
|
+
}
|
|
44373
|
+
}
|
|
44374
|
+
function transformOfficeHTML(html) {
|
|
44375
|
+
if (!isOfficeContent(html)) {
|
|
44376
|
+
return html;
|
|
44377
|
+
}
|
|
44378
|
+
let cleaned = removeConditionalComments(html);
|
|
44379
|
+
const parser = new DOMParser();
|
|
44380
|
+
const doc2 = parser.parseFromString(cleaned, "text/html");
|
|
44381
|
+
removeHeadElements(doc2);
|
|
44382
|
+
if (isWordContent(html)) {
|
|
44383
|
+
convertWordLists(doc2);
|
|
44384
|
+
}
|
|
44385
|
+
removeOfficeElements(doc2);
|
|
44386
|
+
if (isExcelContent(html)) {
|
|
44387
|
+
normalizeExcelTables(doc2);
|
|
44388
|
+
}
|
|
44389
|
+
cleanElementStyles(doc2);
|
|
44390
|
+
removeStyleBlocks(doc2);
|
|
44391
|
+
removeEmptyWrappers(doc2);
|
|
44392
|
+
sanitize(doc2);
|
|
44393
|
+
return doc2.body.innerHTML;
|
|
44394
|
+
}
|
|
44395
|
+
const PasteFromOffice = Extension.create({
|
|
44396
|
+
name: "pasteFromOffice",
|
|
44397
|
+
addOptions() {
|
|
44398
|
+
return {
|
|
44399
|
+
enabled: true
|
|
44400
|
+
};
|
|
44401
|
+
},
|
|
44402
|
+
addStorage() {
|
|
44403
|
+
return {};
|
|
44404
|
+
},
|
|
44405
|
+
transformPastedHTML(html) {
|
|
44406
|
+
if (!this.options.enabled) {
|
|
44407
|
+
return html;
|
|
44408
|
+
}
|
|
44409
|
+
return transformOfficeHTML(html);
|
|
44410
|
+
}
|
|
44411
|
+
});
|
|
44034
44412
|
const en = {
|
|
44035
44413
|
"Bold": "Bold",
|
|
44036
44414
|
"Italic": "Italic",
|
|
@@ -46401,7 +46779,8 @@ class HTMLEditor {
|
|
|
46401
46779
|
convert_unsafe_embeds: config.convert_unsafe_embeds ?? true,
|
|
46402
46780
|
format_empty_lines: config.format_empty_lines ?? true,
|
|
46403
46781
|
toolbar_narrow_breakpoint: config.toolbar_narrow_breakpoint,
|
|
46404
|
-
toolbar_priority: config.toolbar_priority
|
|
46782
|
+
toolbar_priority: config.toolbar_priority,
|
|
46783
|
+
paste_from_office: config.paste_from_office ?? true
|
|
46405
46784
|
};
|
|
46406
46785
|
}
|
|
46407
46786
|
createEditor() {
|
|
@@ -46604,6 +46983,9 @@ class HTMLEditor {
|
|
|
46604
46983
|
}),
|
|
46605
46984
|
TextDirection
|
|
46606
46985
|
];
|
|
46986
|
+
if (this.config.paste_from_office !== false) {
|
|
46987
|
+
extensions.push(PasteFromOffice);
|
|
46988
|
+
}
|
|
46607
46989
|
if (!this.config.basicEditor) {
|
|
46608
46990
|
extensions.push(
|
|
46609
46991
|
Image.configure({
|
|
@@ -46829,6 +47211,7 @@ export {
|
|
|
46829
47211
|
LineHeight,
|
|
46830
47212
|
LinkEditor,
|
|
46831
47213
|
Mention,
|
|
47214
|
+
PasteFromOffice,
|
|
46832
47215
|
SearchReplace,
|
|
46833
47216
|
SignatureBlock,
|
|
46834
47217
|
SourceEditor,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mdaemon/html-editor",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "A TinyMCE-compatible HTML editor built on TipTap",
|
|
5
5
|
"homepage": "https://github.com/mdaemon-technologies/MDHTMLEditor",
|
|
6
6
|
"repository": {
|
|
@@ -60,24 +60,24 @@
|
|
|
60
60
|
},
|
|
61
61
|
"license": "LGPL-3.0-or-later",
|
|
62
62
|
"dependencies": {
|
|
63
|
-
"@tiptap/core": "^3.23.
|
|
64
|
-
"@tiptap/extension-character-count": "^3.23.
|
|
65
|
-
"@tiptap/extension-code-block-lowlight": "^3.23.
|
|
66
|
-
"@tiptap/extension-color": "^3.23.
|
|
67
|
-
"@tiptap/extension-font-family": "^3.23.
|
|
68
|
-
"@tiptap/extension-highlight": "^3.23.
|
|
69
|
-
"@tiptap/extension-image": "^3.23.
|
|
70
|
-
"@tiptap/extension-link": "^3.23.
|
|
71
|
-
"@tiptap/extension-placeholder": "^3.23.
|
|
72
|
-
"@tiptap/extension-table": "^3.23.
|
|
73
|
-
"@tiptap/extension-table-cell": "^3.23.
|
|
74
|
-
"@tiptap/extension-table-header": "^3.23.
|
|
75
|
-
"@tiptap/extension-table-row": "^3.23.
|
|
76
|
-
"@tiptap/extension-text-align": "^3.23.
|
|
77
|
-
"@tiptap/extension-text-style": "^3.23.
|
|
78
|
-
"@tiptap/extension-underline": "^3.23.
|
|
79
|
-
"@tiptap/pm": "^3.23.
|
|
80
|
-
"@tiptap/starter-kit": "^3.23.
|
|
63
|
+
"@tiptap/core": "^3.23.4",
|
|
64
|
+
"@tiptap/extension-character-count": "^3.23.4",
|
|
65
|
+
"@tiptap/extension-code-block-lowlight": "^3.23.4",
|
|
66
|
+
"@tiptap/extension-color": "^3.23.4",
|
|
67
|
+
"@tiptap/extension-font-family": "^3.23.4",
|
|
68
|
+
"@tiptap/extension-highlight": "^3.23.4",
|
|
69
|
+
"@tiptap/extension-image": "^3.23.4",
|
|
70
|
+
"@tiptap/extension-link": "^3.23.4",
|
|
71
|
+
"@tiptap/extension-placeholder": "^3.23.4",
|
|
72
|
+
"@tiptap/extension-table": "^3.23.4",
|
|
73
|
+
"@tiptap/extension-table-cell": "^3.23.4",
|
|
74
|
+
"@tiptap/extension-table-header": "^3.23.4",
|
|
75
|
+
"@tiptap/extension-table-row": "^3.23.4",
|
|
76
|
+
"@tiptap/extension-text-align": "^3.23.4",
|
|
77
|
+
"@tiptap/extension-text-style": "^3.23.4",
|
|
78
|
+
"@tiptap/extension-underline": "^3.23.4",
|
|
79
|
+
"@tiptap/pm": "^3.23.4",
|
|
80
|
+
"@tiptap/starter-kit": "^3.23.4",
|
|
81
81
|
"lowlight": "^3.3.0"
|
|
82
82
|
},
|
|
83
83
|
"devDependencies": {
|