@mdaemon/html-editor 1.1.0 → 1.2.1
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 +441 -41
- package/dist/index.mjs +441 -41
- 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
|
@@ -17437,6 +17437,26 @@ function canInsertNode(state, nodeType) {
|
|
|
17437
17437
|
}
|
|
17438
17438
|
return false;
|
|
17439
17439
|
}
|
|
17440
|
+
function getStyleProperty(element, propertyName) {
|
|
17441
|
+
const styleAttr = element.getAttribute("style");
|
|
17442
|
+
if (!styleAttr) {
|
|
17443
|
+
return null;
|
|
17444
|
+
}
|
|
17445
|
+
const decls = styleAttr.split(";").map((decl) => decl.trim()).filter(Boolean);
|
|
17446
|
+
const target = propertyName.toLowerCase();
|
|
17447
|
+
for (let i = decls.length - 1; i >= 0; i -= 1) {
|
|
17448
|
+
const decl = decls[i];
|
|
17449
|
+
const colonIndex = decl.indexOf(":");
|
|
17450
|
+
if (colonIndex === -1) {
|
|
17451
|
+
continue;
|
|
17452
|
+
}
|
|
17453
|
+
const prop = decl.slice(0, colonIndex).trim().toLowerCase();
|
|
17454
|
+
if (prop === target) {
|
|
17455
|
+
return decl.slice(colonIndex + 1).trim();
|
|
17456
|
+
}
|
|
17457
|
+
}
|
|
17458
|
+
return null;
|
|
17459
|
+
}
|
|
17440
17460
|
var markdown_exports = {};
|
|
17441
17461
|
__export$1(markdown_exports, {
|
|
17442
17462
|
createAtomBlockMarkdownSpec: () => createAtomBlockMarkdownSpec,
|
|
@@ -18874,7 +18894,7 @@ var Italic = Mark2.create({
|
|
|
18874
18894
|
];
|
|
18875
18895
|
}
|
|
18876
18896
|
});
|
|
18877
|
-
const encodedTlds = "
|
|
18897
|
+
const encodedTlds = "aaa1rp3bb0ott3vie4c1le2ogado5udhabi7c0ademy5centure6ountant0s9o1tor4d0s1ult4e0g1ro2tna4f0l1rica5g0akhan5ency5i0g1rbus3force5tel5kdn3l0ibaba4pay4lfinanz6state5y2sace3tom5m0azon4ericanexpress7family11x2fam3ica3sterdam8nalytics7droid5quan4z2o0l2partments8p0le4q0uarelle8r0ab1mco4chi3my2pa2t0e3s0da2ia2sociates9t0hleta5torney7u0ction5di0ble3o3spost5thor3o0s4w0s2x0a2z0ure5ba0by2idu3namex4d1k2r0celona5laycard4s5efoot5gains6seball5ketball8uhaus5yern5b0c1t1va3cg1n2d1e0ats2uty4er2rlin4st0buy5t2f1g1h0arti5i0ble3d1ke2ng0o3o1z2j1lack0friday9ockbuster8g1omberg7ue3m0s1w2n0pparibas9o0ats3ehringer8fa2m1nd2o0k0ing5sch2tik2on4t1utique6x2r0adesco6idgestone9oadway5ker3ther5ussels7s1t1uild0ers6siness6y1zz3v1w1y1z0h3ca0b1fe2l0l1vinklein9m0era3p2non3petown5ital0one8r0avan4ds2e0er0s4s2sa1e1h1ino4t0ering5holic7ba1n1re3c1d1enter4o1rn3f0a1d2g1h0anel2nel4rity4se2t2eap3intai5ristmas6ome4urch5i0priani6rcle4sco3tadel4i0c2y3k1l0aims4eaning6ick2nic1que6othing5ud3ub0med6m1n1o0ach3des3ffee4llege4ogne5m0mbank4unity6pany2re3uter5sec4ndos3struction8ulting7tact3ractors9oking4l1p2rsica5untry4pon0s4rses6pa2r0edit0card4union9icket5own3s1uise0s6u0isinella9v1w1x1y0mru3ou3z2dad1nce3ta1e1ing3sun4y2clk3ds2e0al0er2s3gree4livery5l1oitte5ta3mocrat6ntal2ist5si0gn4v2hl2iamonds6et2gital5rect0ory7scount3ver5h2y2j1k1m1np2o0cs1tor4g1mains5t1wnload7rive4tv2ubai3pont4rban5vag2r2z2earth3t2c0o2deka3u0cation8e1g1mail3erck5nergy4gineer0ing9terprises10pson4quipment8r0icsson6ni3s0q1tate5t1u0rovision8s2vents5xchange6pert3osed4ress5traspace10fage2il1rwinds6th3mily4n0s2rm0ers5shion4t3edex3edback6rrari3ero6i0delity5o2lm2nal1nce1ial7re0stone6mdale6sh0ing5t0ness6j1k1lickr3ghts4r2orist4wers5y2m1o0o0d1tball6rd1ex2sale4um3undation8x2r0ee1senius7l1ogans4ntier7tr2ujitsu5n0d2rniture7tbol5yi3ga0l0lery3o1up4me0s3p1rden4y2b0iz3d0n2e0a1nt0ing5orge5f1g0ee3h1i0ft0s3ves2ing5l0ass3e1obal2o4m0ail3bh2o1x2n1odaddy5ld0point6f2odyear5g0le4p1t1v2p1q1r0ainger5phics5tis4een3ipe3ocery4up4s1t1u0cci3ge2ide2tars5ru3w1y2hair2mburg5ngout5us3bo2dfc0bank7ealth0care8lp1sinki6re1mes5iphop4samitsu7tachi5v2k0t2m1n1ockey4ldings5iday5medepot5goods5s0ense7nda3rse3spital5t0ing5t0els3mail5use3w2r1sbc3t1u0ghes5yatt3undai7ibm2cbc2e1u2d1e0ee3fm2kano4l1m0amat4db2mo0bilien9n0c1dustries8finiti5o2g1k1stitute6urance4e4t0ernational10uit4vestments10o1piranga7q1r0ish4s0maili5t0anbul7t0au2v3jaguar4va3cb2e0ep2tzt3welry6io2ll2m0p2nj2o0bs1urg4t1y2p0morgan6rs3uegos4niper7kaufen5ddi3e0rryhotels6properties14fh2g1h1i0a1ds2m1ndle4tchen5wi3m1n1oeln3matsu5sher5p0mg2n2r0d1ed3uokgroup8w1y0oto4z2la0caixa5mborghini8er3nd0rover6xess5salle5t0ino3robe5w0yer5b1c1ds2ease3clerc5frak4gal2o2xus4gbt3i0dl2fe0insurance9style7ghting6ke2lly3mited4o2ncoln4k2ve1ing5k1lc1p2oan0s3cker3us3l1ndon4tte1o3ve3pl0financial11r1s1t0d0a3u0ndbeck6xe1ury5v1y2ma0drid4if1son4keup4n0agement7go3p1rket0ing3s4riott5shalls7ttel5ba2c0kinsey7d1e0d0ia3et2lbourne7me1orial6n0u2rck0msd7g1h1iami3crosoft7l1ni1t2t0subishi9k1l0b1s2m0a2n1o0bi0le4da2e1i1m1nash3ey2ster5rmon3tgage6scow4to0rcycles9v0ie4p1q1r1s0d2t0n1r2u0seum3ic4v1w1x1y1z2na0b1goya4me2vy3ba2c1e0c1t0bank4flix4work5ustar5w0s2xt0direct7us4f0l2g0o2hk2i0co2ke1on3nja3ssan1y5l1o0kia3rton4w0ruz3tv4p1r0a1w2tt2u1yc2z2obi1server7ffice5kinawa6layan0group9lo3m0ega4ne1g1l0ine5oo2pen3racle3nge4g0anic5igins6saka4tsuka4t2vh3pa0ge2nasonic7ris2s1tners4s1y3y2ccw3e0t2f0izer5g1h0armacy6d1ilips5one2to0graphy6s4ysio5ics1tet2ures6d1n0g1k2oneer5zza4k1l0ace2y0station9umbing5s3m1n0c2ohl2ker3litie5rn2st3r0axi3ess3ime3o0d0uctions8f1gressive8mo2perties3y5tection8u0dential9s1t1ub2w0c2y2qa1pon3uebec3st5racing4dio4e0ad1lestate6tor2y4cipes5d0umbrella9hab3ise0n3t2liance6n0t0als5pair3ort3ublican8st0aurant8view0s5xroth6ich0ardli6oh3l1o1p2o0cks3deo3gers4om3s0vp3u0gby3hr2n2w0e2yukyu6sa0arland6fe0ty4kura4le1on3msclub4ung5ndvik0coromant12ofi4p1rl2s1ve2xo3b0i1s2c0b1haeffler7midt4olarships8ol3ule3warz5ience5ot3d1e0arch3t2cure1ity6ek2lect4ner3rvices6ven3w1x0y3fr2g1h0angrila6rp3ell3ia1ksha5oes2p0ping5uji3w3i0lk2na1gles5te3j1k0i0n2y0pe4l0ing4m0art3ile4n0cf3o0ccer3ial4ftbank4ware6hu2lar2utions7ng1y2y2pa0ce3ort2t3r0l2s1t0ada2ples4r1tebank4farm7c0group6ockholm6rage3e3ream4udio2y3yle4u0cks3pplies3y2ort5rf1gery5zuki5v1watch4iss4x1y0dney4stems6z2tab1ipei4lk2obao4rget4tamotors6r2too4x0i3c0i2d0k2eam2ch0nology8l1masek5nnis4va3f1g1h0d1eater2re6iaa2ckets5enda4ps2res2ol4j0maxx4x2k0maxx5l1m0all4n1o0day3kyo3ols3p1ray3shiba5tal3urs3wn2yota3s3r0ade1ing4ining5vel0ers0insurance16ust3v2t1ube2i1nes3shu4v0s2w1z2ua1bank3s2g1k1nicom3versity8o2ol2ps2s1y1z2va0cations7na1guard7c1e0gas3ntures6risign5mögensberater2ung14sicherung10t2g1i0ajes4deo3g1king4llas4n1p1rgin4sa1ion4va1o3laanderen9n1odka3lvo3te1ing3o2yage5u2wales2mart4ter4ng0gou5tch0es6eather0channel12bcam3er2site5d0ding5ibo2r3f1hoswho6ien2ki2lliamhill9n0dows4e1ners6me2oodside6rk0s2ld3w2s1tc1f3xbox3erox4ihuan4n2xx2yz3yachts4hoo3maxun5ndex5e1odobashi7ga2kohama6u0tube6t1un3za0ppos4ra3ero3ip2m1one3uerich6w2";
|
|
18878
18898
|
const encodedUtlds = "ελ1υ2бг1ел3дети4ею2католик6ом3мкд2он1сква6онлайн5рг3рус2ф2сайт3рб3укр3қаз3հայ3ישראל5קום3ابوظبي5رامكو5لاردن4بحرين5جزائر5سعودية6عليان5مغرب5مارات5یران5بارت2زار4يتك3ھارت5تونس4سودان3رية5شبكة4عراق2ب2مان4فلسطين6قطر3كاثوليك6وم3مصر2ليسيا5وريتانيا7قع4همراه5پاکستان7ڀارت4कॉम3नेट3भारत0म्3ोत5संगठन5বাংলা5ভারত2ৰত4ਭਾਰਤ4ભારત4ଭାରତ4இந்தியா6லங்கை6சிங்கப்பூர்11భారత్5ಭಾರತ4ഭാരതം5ලංකා4คอม3ไทย3ລາວ3გე2みんな3アマゾン4クラウド4グーグル4コム2ストア3セール3ファッション6ポイント4世界2中信1国1國1文网3亚马逊3企业2佛山2信息2健康2八卦2公司1益2台湾1灣2商城1店1标2嘉里0大酒店5在线2大拿2天主教3娱乐2家電2广东2微博2慈善2我爱你3手机2招聘2政务1府2新加坡2闻2时尚2書籍2机构2淡马锡3游戏2澳門2点看2移动2组织机构4网址1店1站1络2联通2谷歌2购物2通販2集团2電訊盈科4飞利浦3食品2餐厅2香格里拉3港2닷넷1컴2삼성2한국2";
|
|
18879
18899
|
const numeric = "numeric";
|
|
18880
18900
|
const ascii = "ascii";
|
|
@@ -19804,8 +19824,6 @@ function init$1({
|
|
|
19804
19824
|
ta(Email$1, groups.domain, EmailDomain);
|
|
19805
19825
|
tt(Email$1, DOT, EmailDomainDot);
|
|
19806
19826
|
tt(Email$1, HYPHEN, EmailDomainHyphen);
|
|
19807
|
-
const EmailColon = tt(Email$1, COLON);
|
|
19808
|
-
ta(EmailColon, groups.numeric, Email);
|
|
19809
19827
|
const DomainHyphen = tt(Domain, HYPHEN);
|
|
19810
19828
|
const DomainDot = tt(Domain, DOT);
|
|
19811
19829
|
tt(DomainHyphen, HYPHEN, DomainHyphen);
|
|
@@ -19869,11 +19887,11 @@ function init$1({
|
|
|
19869
19887
|
const [OPEN, CLOSE] = bracketPairs[i];
|
|
19870
19888
|
const UrlOpen = tt(Url$1, OPEN);
|
|
19871
19889
|
tt(UrlNonaccept, OPEN, UrlOpen);
|
|
19872
|
-
tt(UrlOpen, CLOSE, Url$1);
|
|
19873
19890
|
const UrlOpenQ = makeState(Url);
|
|
19874
19891
|
ta(UrlOpen, qsAccepting, UrlOpenQ);
|
|
19875
19892
|
const UrlOpenSyms = makeState();
|
|
19876
|
-
ta(UrlOpen, qsNonAccepting);
|
|
19893
|
+
ta(UrlOpen, qsNonAccepting, UrlOpenSyms);
|
|
19894
|
+
tt(UrlOpen, CLOSE, Url$1);
|
|
19877
19895
|
ta(UrlOpenQ, qsAccepting, UrlOpenQ);
|
|
19878
19896
|
ta(UrlOpenQ, qsNonAccepting, UrlOpenSyms);
|
|
19879
19897
|
ta(UrlOpenSyms, qsAccepting, UrlOpenQ);
|
|
@@ -22608,6 +22626,7 @@ var CharacterCount = Extension.create({
|
|
|
22608
22626
|
addOptions() {
|
|
22609
22627
|
return {
|
|
22610
22628
|
limit: null,
|
|
22629
|
+
autoTrim: true,
|
|
22611
22630
|
mode: "textSize",
|
|
22612
22631
|
textCounter: (text) => text.length,
|
|
22613
22632
|
wordCounter: (text) => text.split(" ").filter((word) => word !== "").length
|
|
@@ -22645,7 +22664,8 @@ var CharacterCount = Extension.create({
|
|
|
22645
22664
|
return;
|
|
22646
22665
|
}
|
|
22647
22666
|
const limit = this.options.limit;
|
|
22648
|
-
|
|
22667
|
+
const autoTrim = this.options.autoTrim;
|
|
22668
|
+
if (limit === null || limit === void 0 || limit === 0 || autoTrim === false) {
|
|
22649
22669
|
initialEvaluationDone = true;
|
|
22650
22670
|
return;
|
|
22651
22671
|
}
|
|
@@ -23195,21 +23215,8 @@ var BackgroundColor = Extension.create({
|
|
|
23195
23215
|
default: null,
|
|
23196
23216
|
parseHTML: (element) => {
|
|
23197
23217
|
var _a;
|
|
23198
|
-
const
|
|
23199
|
-
|
|
23200
|
-
const decls = styleAttr.split(";").map((s) => s.trim()).filter(Boolean);
|
|
23201
|
-
for (let i = decls.length - 1; i >= 0; i -= 1) {
|
|
23202
|
-
const parts = decls[i].split(":");
|
|
23203
|
-
if (parts.length >= 2) {
|
|
23204
|
-
const prop = parts[0].trim().toLowerCase();
|
|
23205
|
-
const val = parts.slice(1).join(":").trim();
|
|
23206
|
-
if (prop === "background-color") {
|
|
23207
|
-
return val.replace(/['"]+/g, "");
|
|
23208
|
-
}
|
|
23209
|
-
}
|
|
23210
|
-
}
|
|
23211
|
-
}
|
|
23212
|
-
return (_a = element.style.backgroundColor) == null ? void 0 : _a.replace(/['"]+/g, "");
|
|
23218
|
+
const value = (_a = getStyleProperty(element, "background-color")) != null ? _a : element.style.backgroundColor;
|
|
23219
|
+
return value == null ? void 0 : value.replace(/['"]+/g, "");
|
|
23213
23220
|
},
|
|
23214
23221
|
renderHTML: (attributes) => {
|
|
23215
23222
|
if (!attributes.backgroundColor) {
|
|
@@ -23251,21 +23258,8 @@ var Color = Extension.create({
|
|
|
23251
23258
|
default: null,
|
|
23252
23259
|
parseHTML: (element) => {
|
|
23253
23260
|
var _a;
|
|
23254
|
-
const
|
|
23255
|
-
|
|
23256
|
-
const decls = styleAttr.split(";").map((s) => s.trim()).filter(Boolean);
|
|
23257
|
-
for (let i = decls.length - 1; i >= 0; i -= 1) {
|
|
23258
|
-
const parts = decls[i].split(":");
|
|
23259
|
-
if (parts.length >= 2) {
|
|
23260
|
-
const prop = parts[0].trim().toLowerCase();
|
|
23261
|
-
const val = parts.slice(1).join(":").trim();
|
|
23262
|
-
if (prop === "color") {
|
|
23263
|
-
return val.replace(/['"]+/g, "");
|
|
23264
|
-
}
|
|
23265
|
-
}
|
|
23266
|
-
}
|
|
23267
|
-
}
|
|
23268
|
-
return (_a = element.style.color) == null ? void 0 : _a.replace(/['"]+/g, "");
|
|
23261
|
+
const value = (_a = getStyleProperty(element, "color")) != null ? _a : element.style.color;
|
|
23262
|
+
return value == null ? void 0 : value.replace(/['"]+/g, "");
|
|
23269
23263
|
},
|
|
23270
23264
|
renderHTML: (attributes) => {
|
|
23271
23265
|
if (!attributes.color) {
|
|
@@ -23305,7 +23299,14 @@ var FontFamily = Extension.create({
|
|
|
23305
23299
|
attributes: {
|
|
23306
23300
|
fontFamily: {
|
|
23307
23301
|
default: null,
|
|
23308
|
-
|
|
23302
|
+
// Prefer the raw inline `style` attribute so unquoted or
|
|
23303
|
+
// single-quoted multi-word names are preserved instead of being
|
|
23304
|
+
// canonicalized by `element.style.fontFamily`, which forces double
|
|
23305
|
+
// quotes that then get HTML-encoded to `"` on serialization.
|
|
23306
|
+
parseHTML: (element) => {
|
|
23307
|
+
var _a;
|
|
23308
|
+
return (_a = getStyleProperty(element, "font-family")) != null ? _a : element.style.fontFamily;
|
|
23309
|
+
},
|
|
23309
23310
|
renderHTML: (attributes) => {
|
|
23310
23311
|
if (!attributes.fontFamily) {
|
|
23311
23312
|
return {};
|
|
@@ -23344,7 +23345,13 @@ var FontSize$1 = Extension.create({
|
|
|
23344
23345
|
attributes: {
|
|
23345
23346
|
fontSize: {
|
|
23346
23347
|
default: null,
|
|
23347
|
-
|
|
23348
|
+
// Prefer the raw inline `style` attribute so the original format
|
|
23349
|
+
// is preserved instead of the canonicalized value returned by
|
|
23350
|
+
// `element.style.fontSize`.
|
|
23351
|
+
parseHTML: (element) => {
|
|
23352
|
+
var _a;
|
|
23353
|
+
return (_a = getStyleProperty(element, "font-size")) != null ? _a : element.style.fontSize;
|
|
23354
|
+
},
|
|
23348
23355
|
renderHTML: (attributes) => {
|
|
23349
23356
|
if (!attributes.fontSize) {
|
|
23350
23357
|
return {};
|
|
@@ -23383,7 +23390,13 @@ var LineHeight$1 = Extension.create({
|
|
|
23383
23390
|
attributes: {
|
|
23384
23391
|
lineHeight: {
|
|
23385
23392
|
default: null,
|
|
23386
|
-
|
|
23393
|
+
// Prefer the raw inline `style` attribute so the original format
|
|
23394
|
+
// is preserved instead of the canonicalized value returned by
|
|
23395
|
+
// `element.style.lineHeight`.
|
|
23396
|
+
parseHTML: (element) => {
|
|
23397
|
+
var _a;
|
|
23398
|
+
return (_a = getStyleProperty(element, "line-height")) != null ? _a : element.style.lineHeight;
|
|
23399
|
+
},
|
|
23387
23400
|
renderHTML: (attributes) => {
|
|
23388
23401
|
if (!attributes.lineHeight) {
|
|
23389
23402
|
return {};
|
|
@@ -23450,7 +23463,11 @@ var Highlight = Mark2.create({
|
|
|
23450
23463
|
return {
|
|
23451
23464
|
color: {
|
|
23452
23465
|
default: null,
|
|
23453
|
-
|
|
23466
|
+
// Prefer `data-color` (set by our own `renderHTML`) for lossless
|
|
23467
|
+
// round-trips. Otherwise parse the raw inline `style` attribute so
|
|
23468
|
+
// the original color format (e.g. `#rrggbb`) is preserved instead of
|
|
23469
|
+
// the canonicalized `rgb(...)` value from `element.style.backgroundColor`.
|
|
23470
|
+
parseHTML: (element) => element.getAttribute("data-color") || getStyleProperty(element, "background-color") || element.style.backgroundColor,
|
|
23454
23471
|
renderHTML: (attributes) => {
|
|
23455
23472
|
if (!attributes.color) {
|
|
23456
23473
|
return {};
|
|
@@ -44033,6 +44050,384 @@ const Mention = Node3.create({
|
|
|
44033
44050
|
];
|
|
44034
44051
|
}
|
|
44035
44052
|
});
|
|
44053
|
+
const WORD_MARKERS = [
|
|
44054
|
+
'xmlns:o="urn:schemas-microsoft-com:office:office"',
|
|
44055
|
+
'xmlns:w="urn:schemas-microsoft-com:office:word"',
|
|
44056
|
+
'class="Mso',
|
|
44057
|
+
"class=Mso",
|
|
44058
|
+
'style="mso-',
|
|
44059
|
+
"style='mso-"
|
|
44060
|
+
];
|
|
44061
|
+
const EXCEL_MARKERS = [
|
|
44062
|
+
'xmlns:x="urn:schemas-microsoft-com:office:excel"',
|
|
44063
|
+
"ProgId content=Excel.Sheet",
|
|
44064
|
+
'ProgId content="Excel.Sheet"'
|
|
44065
|
+
];
|
|
44066
|
+
function isWordContent(html) {
|
|
44067
|
+
return WORD_MARKERS.some((marker) => html.includes(marker));
|
|
44068
|
+
}
|
|
44069
|
+
function isExcelContent(html) {
|
|
44070
|
+
return EXCEL_MARKERS.some((marker) => html.includes(marker));
|
|
44071
|
+
}
|
|
44072
|
+
function isOfficeContent(html) {
|
|
44073
|
+
return isWordContent(html) || isExcelContent(html);
|
|
44074
|
+
}
|
|
44075
|
+
function removeConditionalComments(html) {
|
|
44076
|
+
return html.replace(/<!--\[if[^\]]*\]>[\s\S]*?<!\[endif\]-->/gi, "");
|
|
44077
|
+
}
|
|
44078
|
+
const OFFICE_NS_TAG_PATTERN = /(?:<\/?)(?:o|w|v|m|x|st\d):/i;
|
|
44079
|
+
function removeOfficeElements(doc2) {
|
|
44080
|
+
const allElements = Array.from(doc2.body.querySelectorAll("*"));
|
|
44081
|
+
for (const el2 of allElements) {
|
|
44082
|
+
const tagName = el2.tagName.toLowerCase();
|
|
44083
|
+
if (OFFICE_NS_TAG_PATTERN.test(`<${tagName}`)) {
|
|
44084
|
+
const parent = el2.parentNode;
|
|
44085
|
+
if (parent) {
|
|
44086
|
+
while (el2.firstChild) {
|
|
44087
|
+
parent.insertBefore(el2.firstChild, el2);
|
|
44088
|
+
}
|
|
44089
|
+
parent.removeChild(el2);
|
|
44090
|
+
}
|
|
44091
|
+
}
|
|
44092
|
+
}
|
|
44093
|
+
const remaining = Array.from(doc2.body.querySelectorAll("*"));
|
|
44094
|
+
for (const el2 of remaining) {
|
|
44095
|
+
const attrs = Array.from(el2.attributes);
|
|
44096
|
+
for (const attr of attrs) {
|
|
44097
|
+
if (attr.name.startsWith("xmlns:") || attr.name === "xmlns") {
|
|
44098
|
+
el2.removeAttribute(attr.name);
|
|
44099
|
+
}
|
|
44100
|
+
}
|
|
44101
|
+
}
|
|
44102
|
+
}
|
|
44103
|
+
function parseListStyles(doc2) {
|
|
44104
|
+
const styleMap = /* @__PURE__ */ new Map();
|
|
44105
|
+
const styleEls = doc2.querySelectorAll("style");
|
|
44106
|
+
for (const styleEl of Array.from(styleEls)) {
|
|
44107
|
+
const css2 = styleEl.textContent ?? "";
|
|
44108
|
+
const listRulePattern = /@list\s+(l\d+):level(\d+)\s*\{([^}]*)\}/gi;
|
|
44109
|
+
let match;
|
|
44110
|
+
while ((match = listRulePattern.exec(css2)) !== null) {
|
|
44111
|
+
const listId = match[1];
|
|
44112
|
+
const level = match[2];
|
|
44113
|
+
const body = match[3];
|
|
44114
|
+
const key = `${listId}:level${level}`;
|
|
44115
|
+
const formatMatch = /mso-level-number-format:\s*([^;]+)/i.exec(body);
|
|
44116
|
+
if (formatMatch) {
|
|
44117
|
+
const format = formatMatch[1].trim().toLowerCase();
|
|
44118
|
+
styleMap.set(key, format !== "bullet");
|
|
44119
|
+
} else {
|
|
44120
|
+
styleMap.set(key, true);
|
|
44121
|
+
}
|
|
44122
|
+
}
|
|
44123
|
+
}
|
|
44124
|
+
return styleMap;
|
|
44125
|
+
}
|
|
44126
|
+
function parseListStyle(style2) {
|
|
44127
|
+
const match = /mso-list:\s*(l\d+)\s+level(\d+)\s+/i.exec(style2);
|
|
44128
|
+
if (!match) return null;
|
|
44129
|
+
return {
|
|
44130
|
+
listId: match[1],
|
|
44131
|
+
level: parseInt(match[2], 10),
|
|
44132
|
+
isOrdered: false
|
|
44133
|
+
// Will be resolved from style rules
|
|
44134
|
+
};
|
|
44135
|
+
}
|
|
44136
|
+
function convertWordLists(doc2) {
|
|
44137
|
+
const listStyles = parseListStyles(doc2);
|
|
44138
|
+
const listParagraphs = Array.from(doc2.body.querySelectorAll('[class*="MsoList"]'));
|
|
44139
|
+
if (listParagraphs.length === 0) return;
|
|
44140
|
+
const groups = [];
|
|
44141
|
+
let currentGroup = [];
|
|
44142
|
+
for (const p of listParagraphs) {
|
|
44143
|
+
const el2 = p;
|
|
44144
|
+
const style2 = el2.getAttribute("style") ?? "";
|
|
44145
|
+
if (!parseListStyle(style2)) continue;
|
|
44146
|
+
if (currentGroup.length > 0) {
|
|
44147
|
+
const lastEl = currentGroup[currentGroup.length - 1];
|
|
44148
|
+
let nextSibling = lastEl.nextElementSibling;
|
|
44149
|
+
while (nextSibling && nextSibling !== el2 && nextSibling.textContent?.trim() === "") {
|
|
44150
|
+
nextSibling = nextSibling.nextElementSibling;
|
|
44151
|
+
}
|
|
44152
|
+
if (nextSibling !== el2) {
|
|
44153
|
+
groups.push(currentGroup);
|
|
44154
|
+
currentGroup = [];
|
|
44155
|
+
}
|
|
44156
|
+
}
|
|
44157
|
+
currentGroup.push(el2);
|
|
44158
|
+
}
|
|
44159
|
+
if (currentGroup.length > 0) {
|
|
44160
|
+
groups.push(currentGroup);
|
|
44161
|
+
}
|
|
44162
|
+
for (const group of groups) {
|
|
44163
|
+
convertListGroup(doc2, group, listStyles);
|
|
44164
|
+
}
|
|
44165
|
+
}
|
|
44166
|
+
function convertListGroup(doc2, paragraphs, listStyles) {
|
|
44167
|
+
if (paragraphs.length === 0) return;
|
|
44168
|
+
const rootInfo = parseListStyle(paragraphs[0].getAttribute("style") ?? "");
|
|
44169
|
+
if (!rootInfo) return;
|
|
44170
|
+
const parent = paragraphs[0].parentNode;
|
|
44171
|
+
if (!parent) return;
|
|
44172
|
+
const rootKey = `${rootInfo.listId}:level${rootInfo.level}`;
|
|
44173
|
+
const isRootOrdered = listStyles.get(rootKey) ?? false;
|
|
44174
|
+
const rootList = doc2.createElement(isRootOrdered ? "ol" : "ul");
|
|
44175
|
+
const stack = [{ element: rootList, level: rootInfo.level }];
|
|
44176
|
+
for (const p of paragraphs) {
|
|
44177
|
+
const style2 = p.getAttribute("style") ?? "";
|
|
44178
|
+
const info = parseListStyle(style2);
|
|
44179
|
+
if (!info) continue;
|
|
44180
|
+
const key = `${info.listId}:level${info.level}`;
|
|
44181
|
+
const isOrdered = listStyles.get(key) ?? false;
|
|
44182
|
+
while (stack.length > 1 && stack[stack.length - 1].level >= info.level) {
|
|
44183
|
+
stack.pop();
|
|
44184
|
+
}
|
|
44185
|
+
if (info.level > stack[stack.length - 1].level) {
|
|
44186
|
+
const currentList = stack[stack.length - 1].element;
|
|
44187
|
+
let lastLi = currentList.lastElementChild;
|
|
44188
|
+
if (!lastLi || lastLi.tagName.toLowerCase() !== "li") {
|
|
44189
|
+
lastLi = doc2.createElement("li");
|
|
44190
|
+
currentList.appendChild(lastLi);
|
|
44191
|
+
}
|
|
44192
|
+
const subList = doc2.createElement(isOrdered ? "ol" : "ul");
|
|
44193
|
+
lastLi.appendChild(subList);
|
|
44194
|
+
stack.push({ element: subList, level: info.level });
|
|
44195
|
+
}
|
|
44196
|
+
const li = doc2.createElement("li");
|
|
44197
|
+
removeListMarkers(p);
|
|
44198
|
+
while (p.firstChild) {
|
|
44199
|
+
li.appendChild(p.firstChild);
|
|
44200
|
+
}
|
|
44201
|
+
const cleanedStyle = cleanMsoStyles(style2);
|
|
44202
|
+
if (cleanedStyle) {
|
|
44203
|
+
li.setAttribute("style", cleanedStyle);
|
|
44204
|
+
}
|
|
44205
|
+
stack[stack.length - 1].element.appendChild(li);
|
|
44206
|
+
}
|
|
44207
|
+
parent.insertBefore(rootList, paragraphs[0]);
|
|
44208
|
+
for (const p of paragraphs) {
|
|
44209
|
+
p.remove();
|
|
44210
|
+
}
|
|
44211
|
+
}
|
|
44212
|
+
function removeListMarkers(el2) {
|
|
44213
|
+
const spans = Array.from(el2.querySelectorAll("span"));
|
|
44214
|
+
for (const span of spans) {
|
|
44215
|
+
const style2 = span.getAttribute("style") ?? "";
|
|
44216
|
+
if (/mso-list:\s*Ignore/i.test(style2)) {
|
|
44217
|
+
span.remove();
|
|
44218
|
+
}
|
|
44219
|
+
}
|
|
44220
|
+
}
|
|
44221
|
+
const MSO_PROPERTY_PATTERN = /\bmso-[^:]+:[^;]+;?\s*/gi;
|
|
44222
|
+
const MSO_CLASS_PATTERN = /\bMso\w*|\bxl\d+/g;
|
|
44223
|
+
function cleanMsoStyles(style2) {
|
|
44224
|
+
let cleaned = style2.replace(MSO_PROPERTY_PATTERN, "");
|
|
44225
|
+
cleaned = cleaned.replace(/;\s*;/g, ";").replace(/^\s*;\s*/, "").replace(/\s*;\s*$/, "").trim();
|
|
44226
|
+
return cleaned || "";
|
|
44227
|
+
}
|
|
44228
|
+
function cleanFontFamily(value) {
|
|
44229
|
+
const first2 = value.split(",")[0].trim();
|
|
44230
|
+
return first2.replace(/^["']|["']$/g, "");
|
|
44231
|
+
}
|
|
44232
|
+
function cleanElementStyles(doc2) {
|
|
44233
|
+
const allElements = Array.from(doc2.body.querySelectorAll("*"));
|
|
44234
|
+
for (const el2 of allElements) {
|
|
44235
|
+
const className = el2.getAttribute("class");
|
|
44236
|
+
if (className) {
|
|
44237
|
+
const cleaned = className.replace(MSO_CLASS_PATTERN, "").trim();
|
|
44238
|
+
if (cleaned) {
|
|
44239
|
+
el2.setAttribute("class", cleaned);
|
|
44240
|
+
} else {
|
|
44241
|
+
el2.removeAttribute("class");
|
|
44242
|
+
}
|
|
44243
|
+
}
|
|
44244
|
+
const style2 = el2.getAttribute("style");
|
|
44245
|
+
if (style2) {
|
|
44246
|
+
let cleaned = cleanMsoStyles(style2);
|
|
44247
|
+
const fontFamilyMatch = /font-family:\s*([^;]+)/i.exec(cleaned);
|
|
44248
|
+
if (fontFamilyMatch) {
|
|
44249
|
+
const cleanedFont = cleanFontFamily(fontFamilyMatch[1]);
|
|
44250
|
+
cleaned = cleaned.replace(fontFamilyMatch[0], `font-family: ${cleanedFont}`);
|
|
44251
|
+
}
|
|
44252
|
+
if (cleaned) {
|
|
44253
|
+
el2.setAttribute("style", cleaned);
|
|
44254
|
+
} else {
|
|
44255
|
+
el2.removeAttribute("style");
|
|
44256
|
+
}
|
|
44257
|
+
}
|
|
44258
|
+
const attrsToRemove = Array.from(el2.attributes).filter(
|
|
44259
|
+
(attr) => attr.name.startsWith("v:") || attr.name.startsWith("o:") || attr.name === "lang"
|
|
44260
|
+
);
|
|
44261
|
+
for (const attr of attrsToRemove) {
|
|
44262
|
+
el2.removeAttribute(attr.name);
|
|
44263
|
+
}
|
|
44264
|
+
}
|
|
44265
|
+
}
|
|
44266
|
+
function removeEmptyWrappers(doc2) {
|
|
44267
|
+
let changed = true;
|
|
44268
|
+
while (changed) {
|
|
44269
|
+
changed = false;
|
|
44270
|
+
const spans = Array.from(doc2.body.querySelectorAll("span"));
|
|
44271
|
+
for (const span of spans) {
|
|
44272
|
+
if (span.attributes.length === 0) {
|
|
44273
|
+
const parent = span.parentNode;
|
|
44274
|
+
if (parent) {
|
|
44275
|
+
while (span.firstChild) {
|
|
44276
|
+
parent.insertBefore(span.firstChild, span);
|
|
44277
|
+
}
|
|
44278
|
+
parent.removeChild(span);
|
|
44279
|
+
changed = true;
|
|
44280
|
+
}
|
|
44281
|
+
}
|
|
44282
|
+
}
|
|
44283
|
+
}
|
|
44284
|
+
const emptyParas = Array.from(doc2.body.querySelectorAll("p"));
|
|
44285
|
+
for (const p of emptyParas) {
|
|
44286
|
+
if (p.innerHTML.trim() === "" && doc2.body.children.length > 1) {
|
|
44287
|
+
p.remove();
|
|
44288
|
+
}
|
|
44289
|
+
}
|
|
44290
|
+
}
|
|
44291
|
+
function normalizeExcelTables(doc2) {
|
|
44292
|
+
const tables = Array.from(doc2.body.querySelectorAll("table"));
|
|
44293
|
+
for (const table of tables) {
|
|
44294
|
+
removeExcelAttributes(table);
|
|
44295
|
+
const cells = Array.from(table.querySelectorAll("td, th"));
|
|
44296
|
+
for (const cell of cells) {
|
|
44297
|
+
removeExcelAttributes(cell);
|
|
44298
|
+
const style2 = cell.getAttribute("style");
|
|
44299
|
+
if (style2) {
|
|
44300
|
+
const cleaned = cleanMsoStyles(style2);
|
|
44301
|
+
if (cleaned) {
|
|
44302
|
+
cell.setAttribute("style", cleaned);
|
|
44303
|
+
} else {
|
|
44304
|
+
cell.removeAttribute("style");
|
|
44305
|
+
}
|
|
44306
|
+
}
|
|
44307
|
+
}
|
|
44308
|
+
const rows = Array.from(table.querySelectorAll("tr"));
|
|
44309
|
+
for (const row of rows) {
|
|
44310
|
+
removeExcelAttributes(row);
|
|
44311
|
+
}
|
|
44312
|
+
}
|
|
44313
|
+
}
|
|
44314
|
+
const EXCEL_ATTRS = [
|
|
44315
|
+
"x:num",
|
|
44316
|
+
"x:str",
|
|
44317
|
+
"x:fmla",
|
|
44318
|
+
"x:autofilter",
|
|
44319
|
+
"mso-number-format"
|
|
44320
|
+
];
|
|
44321
|
+
function removeExcelAttributes(el2) {
|
|
44322
|
+
for (const attr of EXCEL_ATTRS) {
|
|
44323
|
+
el2.removeAttribute(attr);
|
|
44324
|
+
}
|
|
44325
|
+
const className = el2.getAttribute("class");
|
|
44326
|
+
if (className) {
|
|
44327
|
+
const cleaned = className.replace(MSO_CLASS_PATTERN, "").trim();
|
|
44328
|
+
if (cleaned) {
|
|
44329
|
+
el2.setAttribute("class", cleaned);
|
|
44330
|
+
} else {
|
|
44331
|
+
el2.removeAttribute("class");
|
|
44332
|
+
}
|
|
44333
|
+
}
|
|
44334
|
+
}
|
|
44335
|
+
const DANGEROUS_TAGS = [
|
|
44336
|
+
"script",
|
|
44337
|
+
"iframe",
|
|
44338
|
+
"object",
|
|
44339
|
+
"embed",
|
|
44340
|
+
"applet",
|
|
44341
|
+
"form",
|
|
44342
|
+
"input",
|
|
44343
|
+
"textarea",
|
|
44344
|
+
"select",
|
|
44345
|
+
"button"
|
|
44346
|
+
];
|
|
44347
|
+
const EVENT_ATTR_PATTERN = /^on/i;
|
|
44348
|
+
const DANGEROUS_URL_PATTERN = /^\s*(javascript|vbscript|data\s*:(?!image))/i;
|
|
44349
|
+
function sanitize(doc2) {
|
|
44350
|
+
for (const tag of DANGEROUS_TAGS) {
|
|
44351
|
+
const elements = Array.from(doc2.body.querySelectorAll(tag));
|
|
44352
|
+
for (const el2 of elements) {
|
|
44353
|
+
el2.remove();
|
|
44354
|
+
}
|
|
44355
|
+
}
|
|
44356
|
+
const allElements = Array.from(doc2.body.querySelectorAll("*"));
|
|
44357
|
+
for (const el2 of allElements) {
|
|
44358
|
+
const attrs = Array.from(el2.attributes);
|
|
44359
|
+
for (const attr of attrs) {
|
|
44360
|
+
if (EVENT_ATTR_PATTERN.test(attr.name)) {
|
|
44361
|
+
el2.removeAttribute(attr.name);
|
|
44362
|
+
continue;
|
|
44363
|
+
}
|
|
44364
|
+
if ((attr.name === "href" || attr.name === "src" || attr.name === "action") && DANGEROUS_URL_PATTERN.test(attr.value)) {
|
|
44365
|
+
el2.removeAttribute(attr.name);
|
|
44366
|
+
}
|
|
44367
|
+
}
|
|
44368
|
+
const src = el2.getAttribute("src");
|
|
44369
|
+
if (src && src.startsWith("file://")) {
|
|
44370
|
+
el2.removeAttribute("src");
|
|
44371
|
+
}
|
|
44372
|
+
const href = el2.getAttribute("href");
|
|
44373
|
+
if (href && href.startsWith("file://")) {
|
|
44374
|
+
el2.removeAttribute("href");
|
|
44375
|
+
}
|
|
44376
|
+
}
|
|
44377
|
+
}
|
|
44378
|
+
function removeStyleBlocks(doc2) {
|
|
44379
|
+
const styles = Array.from(doc2.querySelectorAll("style"));
|
|
44380
|
+
for (const s of styles) {
|
|
44381
|
+
s.remove();
|
|
44382
|
+
}
|
|
44383
|
+
}
|
|
44384
|
+
function removeHeadElements(doc2) {
|
|
44385
|
+
const selectors = ["meta", "link", "title", "xml"];
|
|
44386
|
+
for (const selector of selectors) {
|
|
44387
|
+
const elements = Array.from(doc2.body.querySelectorAll(selector));
|
|
44388
|
+
for (const el2 of elements) {
|
|
44389
|
+
el2.remove();
|
|
44390
|
+
}
|
|
44391
|
+
}
|
|
44392
|
+
}
|
|
44393
|
+
function transformOfficeHTML(html) {
|
|
44394
|
+
if (!isOfficeContent(html)) {
|
|
44395
|
+
return html;
|
|
44396
|
+
}
|
|
44397
|
+
let cleaned = removeConditionalComments(html);
|
|
44398
|
+
const parser = new DOMParser();
|
|
44399
|
+
const doc2 = parser.parseFromString(cleaned, "text/html");
|
|
44400
|
+
removeHeadElements(doc2);
|
|
44401
|
+
if (isWordContent(html)) {
|
|
44402
|
+
convertWordLists(doc2);
|
|
44403
|
+
}
|
|
44404
|
+
removeOfficeElements(doc2);
|
|
44405
|
+
if (isExcelContent(html)) {
|
|
44406
|
+
normalizeExcelTables(doc2);
|
|
44407
|
+
}
|
|
44408
|
+
cleanElementStyles(doc2);
|
|
44409
|
+
removeStyleBlocks(doc2);
|
|
44410
|
+
removeEmptyWrappers(doc2);
|
|
44411
|
+
sanitize(doc2);
|
|
44412
|
+
return doc2.body.innerHTML;
|
|
44413
|
+
}
|
|
44414
|
+
const PasteFromOffice = Extension.create({
|
|
44415
|
+
name: "pasteFromOffice",
|
|
44416
|
+
addOptions() {
|
|
44417
|
+
return {
|
|
44418
|
+
enabled: true
|
|
44419
|
+
};
|
|
44420
|
+
},
|
|
44421
|
+
addStorage() {
|
|
44422
|
+
return {};
|
|
44423
|
+
},
|
|
44424
|
+
transformPastedHTML(html) {
|
|
44425
|
+
if (!this.options.enabled) {
|
|
44426
|
+
return html;
|
|
44427
|
+
}
|
|
44428
|
+
return transformOfficeHTML(html);
|
|
44429
|
+
}
|
|
44430
|
+
});
|
|
44036
44431
|
const en = {
|
|
44037
44432
|
"Bold": "Bold",
|
|
44038
44433
|
"Italic": "Italic",
|
|
@@ -46403,7 +46798,8 @@ class HTMLEditor {
|
|
|
46403
46798
|
convert_unsafe_embeds: config.convert_unsafe_embeds ?? true,
|
|
46404
46799
|
format_empty_lines: config.format_empty_lines ?? true,
|
|
46405
46800
|
toolbar_narrow_breakpoint: config.toolbar_narrow_breakpoint,
|
|
46406
|
-
toolbar_priority: config.toolbar_priority
|
|
46801
|
+
toolbar_priority: config.toolbar_priority,
|
|
46802
|
+
paste_from_office: config.paste_from_office ?? true
|
|
46407
46803
|
};
|
|
46408
46804
|
}
|
|
46409
46805
|
createEditor() {
|
|
@@ -46606,6 +47002,9 @@ class HTMLEditor {
|
|
|
46606
47002
|
}),
|
|
46607
47003
|
TextDirection
|
|
46608
47004
|
];
|
|
47005
|
+
if (this.config.paste_from_office !== false) {
|
|
47006
|
+
extensions.push(PasteFromOffice);
|
|
47007
|
+
}
|
|
46609
47008
|
if (!this.config.basicEditor) {
|
|
46610
47009
|
extensions.push(
|
|
46611
47010
|
Image.configure({
|
|
@@ -46830,6 +47229,7 @@ exports.HTMLEditor = HTMLEditor;
|
|
|
46830
47229
|
exports.LineHeight = LineHeight;
|
|
46831
47230
|
exports.LinkEditor = LinkEditor;
|
|
46832
47231
|
exports.Mention = Mention;
|
|
47232
|
+
exports.PasteFromOffice = PasteFromOffice;
|
|
46833
47233
|
exports.SearchReplace = SearchReplace;
|
|
46834
47234
|
exports.SignatureBlock = SignatureBlock;
|
|
46835
47235
|
exports.SourceEditor = SourceEditor;
|
package/dist/index.mjs
CHANGED
|
@@ -17435,6 +17435,26 @@ function canInsertNode(state, nodeType) {
|
|
|
17435
17435
|
}
|
|
17436
17436
|
return false;
|
|
17437
17437
|
}
|
|
17438
|
+
function getStyleProperty(element, propertyName) {
|
|
17439
|
+
const styleAttr = element.getAttribute("style");
|
|
17440
|
+
if (!styleAttr) {
|
|
17441
|
+
return null;
|
|
17442
|
+
}
|
|
17443
|
+
const decls = styleAttr.split(";").map((decl) => decl.trim()).filter(Boolean);
|
|
17444
|
+
const target = propertyName.toLowerCase();
|
|
17445
|
+
for (let i = decls.length - 1; i >= 0; i -= 1) {
|
|
17446
|
+
const decl = decls[i];
|
|
17447
|
+
const colonIndex = decl.indexOf(":");
|
|
17448
|
+
if (colonIndex === -1) {
|
|
17449
|
+
continue;
|
|
17450
|
+
}
|
|
17451
|
+
const prop = decl.slice(0, colonIndex).trim().toLowerCase();
|
|
17452
|
+
if (prop === target) {
|
|
17453
|
+
return decl.slice(colonIndex + 1).trim();
|
|
17454
|
+
}
|
|
17455
|
+
}
|
|
17456
|
+
return null;
|
|
17457
|
+
}
|
|
17438
17458
|
var markdown_exports = {};
|
|
17439
17459
|
__export$1(markdown_exports, {
|
|
17440
17460
|
createAtomBlockMarkdownSpec: () => createAtomBlockMarkdownSpec,
|
|
@@ -18872,7 +18892,7 @@ var Italic = Mark2.create({
|
|
|
18872
18892
|
];
|
|
18873
18893
|
}
|
|
18874
18894
|
});
|
|
18875
|
-
const encodedTlds = "
|
|
18895
|
+
const encodedTlds = "aaa1rp3bb0ott3vie4c1le2ogado5udhabi7c0ademy5centure6ountant0s9o1tor4d0s1ult4e0g1ro2tna4f0l1rica5g0akhan5ency5i0g1rbus3force5tel5kdn3l0ibaba4pay4lfinanz6state5y2sace3tom5m0azon4ericanexpress7family11x2fam3ica3sterdam8nalytics7droid5quan4z2o0l2partments8p0le4q0uarelle8r0ab1mco4chi3my2pa2t0e3s0da2ia2sociates9t0hleta5torney7u0ction5di0ble3o3spost5thor3o0s4w0s2x0a2z0ure5ba0by2idu3namex4d1k2r0celona5laycard4s5efoot5gains6seball5ketball8uhaus5yern5b0c1t1va3cg1n2d1e0ats2uty4er2rlin4st0buy5t2f1g1h0arti5i0ble3d1ke2ng0o3o1z2j1lack0friday9ockbuster8g1omberg7ue3m0s1w2n0pparibas9o0ats3ehringer8fa2m1nd2o0k0ing5sch2tik2on4t1utique6x2r0adesco6idgestone9oadway5ker3ther5ussels7s1t1uild0ers6siness6y1zz3v1w1y1z0h3ca0b1fe2l0l1vinklein9m0era3p2non3petown5ital0one8r0avan4ds2e0er0s4s2sa1e1h1ino4t0ering5holic7ba1n1re3c1d1enter4o1rn3f0a1d2g1h0anel2nel4rity4se2t2eap3intai5ristmas6ome4urch5i0priani6rcle4sco3tadel4i0c2y3k1l0aims4eaning6ick2nic1que6othing5ud3ub0med6m1n1o0ach3des3ffee4llege4ogne5m0mbank4unity6pany2re3uter5sec4ndos3struction8ulting7tact3ractors9oking4l1p2rsica5untry4pon0s4rses6pa2r0edit0card4union9icket5own3s1uise0s6u0isinella9v1w1x1y0mru3ou3z2dad1nce3ta1e1ing3sun4y2clk3ds2e0al0er2s3gree4livery5l1oitte5ta3mocrat6ntal2ist5si0gn4v2hl2iamonds6et2gital5rect0ory7scount3ver5h2y2j1k1m1np2o0cs1tor4g1mains5t1wnload7rive4tv2ubai3pont4rban5vag2r2z2earth3t2c0o2deka3u0cation8e1g1mail3erck5nergy4gineer0ing9terprises10pson4quipment8r0icsson6ni3s0q1tate5t1u0rovision8s2vents5xchange6pert3osed4ress5traspace10fage2il1rwinds6th3mily4n0s2rm0ers5shion4t3edex3edback6rrari3ero6i0delity5o2lm2nal1nce1ial7re0stone6mdale6sh0ing5t0ness6j1k1lickr3ghts4r2orist4wers5y2m1o0o0d1tball6rd1ex2sale4um3undation8x2r0ee1senius7l1ogans4ntier7tr2ujitsu5n0d2rniture7tbol5yi3ga0l0lery3o1up4me0s3p1rden4y2b0iz3d0n2e0a1nt0ing5orge5f1g0ee3h1i0ft0s3ves2ing5l0ass3e1obal2o4m0ail3bh2o1x2n1odaddy5ld0point6f2odyear5g0le4p1t1v2p1q1r0ainger5phics5tis4een3ipe3ocery4up4s1t1u0cci3ge2ide2tars5ru3w1y2hair2mburg5ngout5us3bo2dfc0bank7ealth0care8lp1sinki6re1mes5iphop4samitsu7tachi5v2k0t2m1n1ockey4ldings5iday5medepot5goods5s0ense7nda3rse3spital5t0ing5t0els3mail5use3w2r1sbc3t1u0ghes5yatt3undai7ibm2cbc2e1u2d1e0ee3fm2kano4l1m0amat4db2mo0bilien9n0c1dustries8finiti5o2g1k1stitute6urance4e4t0ernational10uit4vestments10o1piranga7q1r0ish4s0maili5t0anbul7t0au2v3jaguar4va3cb2e0ep2tzt3welry6io2ll2m0p2nj2o0bs1urg4t1y2p0morgan6rs3uegos4niper7kaufen5ddi3e0rryhotels6properties14fh2g1h1i0a1ds2m1ndle4tchen5wi3m1n1oeln3matsu5sher5p0mg2n2r0d1ed3uokgroup8w1y0oto4z2la0caixa5mborghini8er3nd0rover6xess5salle5t0ino3robe5w0yer5b1c1ds2ease3clerc5frak4gal2o2xus4gbt3i0dl2fe0insurance9style7ghting6ke2lly3mited4o2ncoln4k2ve1ing5k1lc1p2oan0s3cker3us3l1ndon4tte1o3ve3pl0financial11r1s1t0d0a3u0ndbeck6xe1ury5v1y2ma0drid4if1son4keup4n0agement7go3p1rket0ing3s4riott5shalls7ttel5ba2c0kinsey7d1e0d0ia3et2lbourne7me1orial6n0u2rck0msd7g1h1iami3crosoft7l1ni1t2t0subishi9k1l0b1s2m0a2n1o0bi0le4da2e1i1m1nash3ey2ster5rmon3tgage6scow4to0rcycles9v0ie4p1q1r1s0d2t0n1r2u0seum3ic4v1w1x1y1z2na0b1goya4me2vy3ba2c1e0c1t0bank4flix4work5ustar5w0s2xt0direct7us4f0l2g0o2hk2i0co2ke1on3nja3ssan1y5l1o0kia3rton4w0ruz3tv4p1r0a1w2tt2u1yc2z2obi1server7ffice5kinawa6layan0group9lo3m0ega4ne1g1l0ine5oo2pen3racle3nge4g0anic5igins6saka4tsuka4t2vh3pa0ge2nasonic7ris2s1tners4s1y3y2ccw3e0t2f0izer5g1h0armacy6d1ilips5one2to0graphy6s4ysio5ics1tet2ures6d1n0g1k2oneer5zza4k1l0ace2y0station9umbing5s3m1n0c2ohl2ker3litie5rn2st3r0axi3ess3ime3o0d0uctions8f1gressive8mo2perties3y5tection8u0dential9s1t1ub2w0c2y2qa1pon3uebec3st5racing4dio4e0ad1lestate6tor2y4cipes5d0umbrella9hab3ise0n3t2liance6n0t0als5pair3ort3ublican8st0aurant8view0s5xroth6ich0ardli6oh3l1o1p2o0cks3deo3gers4om3s0vp3u0gby3hr2n2w0e2yukyu6sa0arland6fe0ty4kura4le1on3msclub4ung5ndvik0coromant12ofi4p1rl2s1ve2xo3b0i1s2c0b1haeffler7midt4olarships8ol3ule3warz5ience5ot3d1e0arch3t2cure1ity6ek2lect4ner3rvices6ven3w1x0y3fr2g1h0angrila6rp3ell3ia1ksha5oes2p0ping5uji3w3i0lk2na1gles5te3j1k0i0n2y0pe4l0ing4m0art3ile4n0cf3o0ccer3ial4ftbank4ware6hu2lar2utions7ng1y2y2pa0ce3ort2t3r0l2s1t0ada2ples4r1tebank4farm7c0group6ockholm6rage3e3ream4udio2y3yle4u0cks3pplies3y2ort5rf1gery5zuki5v1watch4iss4x1y0dney4stems6z2tab1ipei4lk2obao4rget4tamotors6r2too4x0i3c0i2d0k2eam2ch0nology8l1masek5nnis4va3f1g1h0d1eater2re6iaa2ckets5enda4ps2res2ol4j0maxx4x2k0maxx5l1m0all4n1o0day3kyo3ols3p1ray3shiba5tal3urs3wn2yota3s3r0ade1ing4ining5vel0ers0insurance16ust3v2t1ube2i1nes3shu4v0s2w1z2ua1bank3s2g1k1nicom3versity8o2ol2ps2s1y1z2va0cations7na1guard7c1e0gas3ntures6risign5mögensberater2ung14sicherung10t2g1i0ajes4deo3g1king4llas4n1p1rgin4sa1ion4va1o3laanderen9n1odka3lvo3te1ing3o2yage5u2wales2mart4ter4ng0gou5tch0es6eather0channel12bcam3er2site5d0ding5ibo2r3f1hoswho6ien2ki2lliamhill9n0dows4e1ners6me2oodside6rk0s2ld3w2s1tc1f3xbox3erox4ihuan4n2xx2yz3yachts4hoo3maxun5ndex5e1odobashi7ga2kohama6u0tube6t1un3za0ppos4ra3ero3ip2m1one3uerich6w2";
|
|
18876
18896
|
const encodedUtlds = "ελ1υ2бг1ел3дети4ею2католик6ом3мкд2он1сква6онлайн5рг3рус2ф2сайт3рб3укр3қаз3հայ3ישראל5קום3ابوظبي5رامكو5لاردن4بحرين5جزائر5سعودية6عليان5مغرب5مارات5یران5بارت2زار4يتك3ھارت5تونس4سودان3رية5شبكة4عراق2ب2مان4فلسطين6قطر3كاثوليك6وم3مصر2ليسيا5وريتانيا7قع4همراه5پاکستان7ڀارت4कॉम3नेट3भारत0म्3ोत5संगठन5বাংলা5ভারত2ৰত4ਭਾਰਤ4ભારત4ଭାରତ4இந்தியா6லங்கை6சிங்கப்பூர்11భారత్5ಭಾರತ4ഭാരതം5ලංකා4คอม3ไทย3ລາວ3გე2みんな3アマゾン4クラウド4グーグル4コム2ストア3セール3ファッション6ポイント4世界2中信1国1國1文网3亚马逊3企业2佛山2信息2健康2八卦2公司1益2台湾1灣2商城1店1标2嘉里0大酒店5在线2大拿2天主教3娱乐2家電2广东2微博2慈善2我爱你3手机2招聘2政务1府2新加坡2闻2时尚2書籍2机构2淡马锡3游戏2澳門2点看2移动2组织机构4网址1店1站1络2联通2谷歌2购物2通販2集团2電訊盈科4飞利浦3食品2餐厅2香格里拉3港2닷넷1컴2삼성2한국2";
|
|
18877
18897
|
const numeric = "numeric";
|
|
18878
18898
|
const ascii = "ascii";
|
|
@@ -19802,8 +19822,6 @@ function init$1({
|
|
|
19802
19822
|
ta(Email$1, groups.domain, EmailDomain);
|
|
19803
19823
|
tt(Email$1, DOT, EmailDomainDot);
|
|
19804
19824
|
tt(Email$1, HYPHEN, EmailDomainHyphen);
|
|
19805
|
-
const EmailColon = tt(Email$1, COLON);
|
|
19806
|
-
ta(EmailColon, groups.numeric, Email);
|
|
19807
19825
|
const DomainHyphen = tt(Domain, HYPHEN);
|
|
19808
19826
|
const DomainDot = tt(Domain, DOT);
|
|
19809
19827
|
tt(DomainHyphen, HYPHEN, DomainHyphen);
|
|
@@ -19867,11 +19885,11 @@ function init$1({
|
|
|
19867
19885
|
const [OPEN, CLOSE] = bracketPairs[i];
|
|
19868
19886
|
const UrlOpen = tt(Url$1, OPEN);
|
|
19869
19887
|
tt(UrlNonaccept, OPEN, UrlOpen);
|
|
19870
|
-
tt(UrlOpen, CLOSE, Url$1);
|
|
19871
19888
|
const UrlOpenQ = makeState(Url);
|
|
19872
19889
|
ta(UrlOpen, qsAccepting, UrlOpenQ);
|
|
19873
19890
|
const UrlOpenSyms = makeState();
|
|
19874
|
-
ta(UrlOpen, qsNonAccepting);
|
|
19891
|
+
ta(UrlOpen, qsNonAccepting, UrlOpenSyms);
|
|
19892
|
+
tt(UrlOpen, CLOSE, Url$1);
|
|
19875
19893
|
ta(UrlOpenQ, qsAccepting, UrlOpenQ);
|
|
19876
19894
|
ta(UrlOpenQ, qsNonAccepting, UrlOpenSyms);
|
|
19877
19895
|
ta(UrlOpenSyms, qsAccepting, UrlOpenQ);
|
|
@@ -22606,6 +22624,7 @@ var CharacterCount = Extension.create({
|
|
|
22606
22624
|
addOptions() {
|
|
22607
22625
|
return {
|
|
22608
22626
|
limit: null,
|
|
22627
|
+
autoTrim: true,
|
|
22609
22628
|
mode: "textSize",
|
|
22610
22629
|
textCounter: (text) => text.length,
|
|
22611
22630
|
wordCounter: (text) => text.split(" ").filter((word) => word !== "").length
|
|
@@ -22643,7 +22662,8 @@ var CharacterCount = Extension.create({
|
|
|
22643
22662
|
return;
|
|
22644
22663
|
}
|
|
22645
22664
|
const limit = this.options.limit;
|
|
22646
|
-
|
|
22665
|
+
const autoTrim = this.options.autoTrim;
|
|
22666
|
+
if (limit === null || limit === void 0 || limit === 0 || autoTrim === false) {
|
|
22647
22667
|
initialEvaluationDone = true;
|
|
22648
22668
|
return;
|
|
22649
22669
|
}
|
|
@@ -23193,21 +23213,8 @@ var BackgroundColor = Extension.create({
|
|
|
23193
23213
|
default: null,
|
|
23194
23214
|
parseHTML: (element) => {
|
|
23195
23215
|
var _a;
|
|
23196
|
-
const
|
|
23197
|
-
|
|
23198
|
-
const decls = styleAttr.split(";").map((s) => s.trim()).filter(Boolean);
|
|
23199
|
-
for (let i = decls.length - 1; i >= 0; i -= 1) {
|
|
23200
|
-
const parts = decls[i].split(":");
|
|
23201
|
-
if (parts.length >= 2) {
|
|
23202
|
-
const prop = parts[0].trim().toLowerCase();
|
|
23203
|
-
const val = parts.slice(1).join(":").trim();
|
|
23204
|
-
if (prop === "background-color") {
|
|
23205
|
-
return val.replace(/['"]+/g, "");
|
|
23206
|
-
}
|
|
23207
|
-
}
|
|
23208
|
-
}
|
|
23209
|
-
}
|
|
23210
|
-
return (_a = element.style.backgroundColor) == null ? void 0 : _a.replace(/['"]+/g, "");
|
|
23216
|
+
const value = (_a = getStyleProperty(element, "background-color")) != null ? _a : element.style.backgroundColor;
|
|
23217
|
+
return value == null ? void 0 : value.replace(/['"]+/g, "");
|
|
23211
23218
|
},
|
|
23212
23219
|
renderHTML: (attributes) => {
|
|
23213
23220
|
if (!attributes.backgroundColor) {
|
|
@@ -23249,21 +23256,8 @@ var Color = Extension.create({
|
|
|
23249
23256
|
default: null,
|
|
23250
23257
|
parseHTML: (element) => {
|
|
23251
23258
|
var _a;
|
|
23252
|
-
const
|
|
23253
|
-
|
|
23254
|
-
const decls = styleAttr.split(";").map((s) => s.trim()).filter(Boolean);
|
|
23255
|
-
for (let i = decls.length - 1; i >= 0; i -= 1) {
|
|
23256
|
-
const parts = decls[i].split(":");
|
|
23257
|
-
if (parts.length >= 2) {
|
|
23258
|
-
const prop = parts[0].trim().toLowerCase();
|
|
23259
|
-
const val = parts.slice(1).join(":").trim();
|
|
23260
|
-
if (prop === "color") {
|
|
23261
|
-
return val.replace(/['"]+/g, "");
|
|
23262
|
-
}
|
|
23263
|
-
}
|
|
23264
|
-
}
|
|
23265
|
-
}
|
|
23266
|
-
return (_a = element.style.color) == null ? void 0 : _a.replace(/['"]+/g, "");
|
|
23259
|
+
const value = (_a = getStyleProperty(element, "color")) != null ? _a : element.style.color;
|
|
23260
|
+
return value == null ? void 0 : value.replace(/['"]+/g, "");
|
|
23267
23261
|
},
|
|
23268
23262
|
renderHTML: (attributes) => {
|
|
23269
23263
|
if (!attributes.color) {
|
|
@@ -23303,7 +23297,14 @@ var FontFamily = Extension.create({
|
|
|
23303
23297
|
attributes: {
|
|
23304
23298
|
fontFamily: {
|
|
23305
23299
|
default: null,
|
|
23306
|
-
|
|
23300
|
+
// Prefer the raw inline `style` attribute so unquoted or
|
|
23301
|
+
// single-quoted multi-word names are preserved instead of being
|
|
23302
|
+
// canonicalized by `element.style.fontFamily`, which forces double
|
|
23303
|
+
// quotes that then get HTML-encoded to `"` on serialization.
|
|
23304
|
+
parseHTML: (element) => {
|
|
23305
|
+
var _a;
|
|
23306
|
+
return (_a = getStyleProperty(element, "font-family")) != null ? _a : element.style.fontFamily;
|
|
23307
|
+
},
|
|
23307
23308
|
renderHTML: (attributes) => {
|
|
23308
23309
|
if (!attributes.fontFamily) {
|
|
23309
23310
|
return {};
|
|
@@ -23342,7 +23343,13 @@ var FontSize$1 = Extension.create({
|
|
|
23342
23343
|
attributes: {
|
|
23343
23344
|
fontSize: {
|
|
23344
23345
|
default: null,
|
|
23345
|
-
|
|
23346
|
+
// Prefer the raw inline `style` attribute so the original format
|
|
23347
|
+
// is preserved instead of the canonicalized value returned by
|
|
23348
|
+
// `element.style.fontSize`.
|
|
23349
|
+
parseHTML: (element) => {
|
|
23350
|
+
var _a;
|
|
23351
|
+
return (_a = getStyleProperty(element, "font-size")) != null ? _a : element.style.fontSize;
|
|
23352
|
+
},
|
|
23346
23353
|
renderHTML: (attributes) => {
|
|
23347
23354
|
if (!attributes.fontSize) {
|
|
23348
23355
|
return {};
|
|
@@ -23381,7 +23388,13 @@ var LineHeight$1 = Extension.create({
|
|
|
23381
23388
|
attributes: {
|
|
23382
23389
|
lineHeight: {
|
|
23383
23390
|
default: null,
|
|
23384
|
-
|
|
23391
|
+
// Prefer the raw inline `style` attribute so the original format
|
|
23392
|
+
// is preserved instead of the canonicalized value returned by
|
|
23393
|
+
// `element.style.lineHeight`.
|
|
23394
|
+
parseHTML: (element) => {
|
|
23395
|
+
var _a;
|
|
23396
|
+
return (_a = getStyleProperty(element, "line-height")) != null ? _a : element.style.lineHeight;
|
|
23397
|
+
},
|
|
23385
23398
|
renderHTML: (attributes) => {
|
|
23386
23399
|
if (!attributes.lineHeight) {
|
|
23387
23400
|
return {};
|
|
@@ -23448,7 +23461,11 @@ var Highlight = Mark2.create({
|
|
|
23448
23461
|
return {
|
|
23449
23462
|
color: {
|
|
23450
23463
|
default: null,
|
|
23451
|
-
|
|
23464
|
+
// Prefer `data-color` (set by our own `renderHTML`) for lossless
|
|
23465
|
+
// round-trips. Otherwise parse the raw inline `style` attribute so
|
|
23466
|
+
// the original color format (e.g. `#rrggbb`) is preserved instead of
|
|
23467
|
+
// the canonicalized `rgb(...)` value from `element.style.backgroundColor`.
|
|
23468
|
+
parseHTML: (element) => element.getAttribute("data-color") || getStyleProperty(element, "background-color") || element.style.backgroundColor,
|
|
23452
23469
|
renderHTML: (attributes) => {
|
|
23453
23470
|
if (!attributes.color) {
|
|
23454
23471
|
return {};
|
|
@@ -44031,6 +44048,384 @@ const Mention = Node3.create({
|
|
|
44031
44048
|
];
|
|
44032
44049
|
}
|
|
44033
44050
|
});
|
|
44051
|
+
const WORD_MARKERS = [
|
|
44052
|
+
'xmlns:o="urn:schemas-microsoft-com:office:office"',
|
|
44053
|
+
'xmlns:w="urn:schemas-microsoft-com:office:word"',
|
|
44054
|
+
'class="Mso',
|
|
44055
|
+
"class=Mso",
|
|
44056
|
+
'style="mso-',
|
|
44057
|
+
"style='mso-"
|
|
44058
|
+
];
|
|
44059
|
+
const EXCEL_MARKERS = [
|
|
44060
|
+
'xmlns:x="urn:schemas-microsoft-com:office:excel"',
|
|
44061
|
+
"ProgId content=Excel.Sheet",
|
|
44062
|
+
'ProgId content="Excel.Sheet"'
|
|
44063
|
+
];
|
|
44064
|
+
function isWordContent(html) {
|
|
44065
|
+
return WORD_MARKERS.some((marker) => html.includes(marker));
|
|
44066
|
+
}
|
|
44067
|
+
function isExcelContent(html) {
|
|
44068
|
+
return EXCEL_MARKERS.some((marker) => html.includes(marker));
|
|
44069
|
+
}
|
|
44070
|
+
function isOfficeContent(html) {
|
|
44071
|
+
return isWordContent(html) || isExcelContent(html);
|
|
44072
|
+
}
|
|
44073
|
+
function removeConditionalComments(html) {
|
|
44074
|
+
return html.replace(/<!--\[if[^\]]*\]>[\s\S]*?<!\[endif\]-->/gi, "");
|
|
44075
|
+
}
|
|
44076
|
+
const OFFICE_NS_TAG_PATTERN = /(?:<\/?)(?:o|w|v|m|x|st\d):/i;
|
|
44077
|
+
function removeOfficeElements(doc2) {
|
|
44078
|
+
const allElements = Array.from(doc2.body.querySelectorAll("*"));
|
|
44079
|
+
for (const el2 of allElements) {
|
|
44080
|
+
const tagName = el2.tagName.toLowerCase();
|
|
44081
|
+
if (OFFICE_NS_TAG_PATTERN.test(`<${tagName}`)) {
|
|
44082
|
+
const parent = el2.parentNode;
|
|
44083
|
+
if (parent) {
|
|
44084
|
+
while (el2.firstChild) {
|
|
44085
|
+
parent.insertBefore(el2.firstChild, el2);
|
|
44086
|
+
}
|
|
44087
|
+
parent.removeChild(el2);
|
|
44088
|
+
}
|
|
44089
|
+
}
|
|
44090
|
+
}
|
|
44091
|
+
const remaining = Array.from(doc2.body.querySelectorAll("*"));
|
|
44092
|
+
for (const el2 of remaining) {
|
|
44093
|
+
const attrs = Array.from(el2.attributes);
|
|
44094
|
+
for (const attr of attrs) {
|
|
44095
|
+
if (attr.name.startsWith("xmlns:") || attr.name === "xmlns") {
|
|
44096
|
+
el2.removeAttribute(attr.name);
|
|
44097
|
+
}
|
|
44098
|
+
}
|
|
44099
|
+
}
|
|
44100
|
+
}
|
|
44101
|
+
function parseListStyles(doc2) {
|
|
44102
|
+
const styleMap = /* @__PURE__ */ new Map();
|
|
44103
|
+
const styleEls = doc2.querySelectorAll("style");
|
|
44104
|
+
for (const styleEl of Array.from(styleEls)) {
|
|
44105
|
+
const css2 = styleEl.textContent ?? "";
|
|
44106
|
+
const listRulePattern = /@list\s+(l\d+):level(\d+)\s*\{([^}]*)\}/gi;
|
|
44107
|
+
let match;
|
|
44108
|
+
while ((match = listRulePattern.exec(css2)) !== null) {
|
|
44109
|
+
const listId = match[1];
|
|
44110
|
+
const level = match[2];
|
|
44111
|
+
const body = match[3];
|
|
44112
|
+
const key = `${listId}:level${level}`;
|
|
44113
|
+
const formatMatch = /mso-level-number-format:\s*([^;]+)/i.exec(body);
|
|
44114
|
+
if (formatMatch) {
|
|
44115
|
+
const format = formatMatch[1].trim().toLowerCase();
|
|
44116
|
+
styleMap.set(key, format !== "bullet");
|
|
44117
|
+
} else {
|
|
44118
|
+
styleMap.set(key, true);
|
|
44119
|
+
}
|
|
44120
|
+
}
|
|
44121
|
+
}
|
|
44122
|
+
return styleMap;
|
|
44123
|
+
}
|
|
44124
|
+
function parseListStyle(style2) {
|
|
44125
|
+
const match = /mso-list:\s*(l\d+)\s+level(\d+)\s+/i.exec(style2);
|
|
44126
|
+
if (!match) return null;
|
|
44127
|
+
return {
|
|
44128
|
+
listId: match[1],
|
|
44129
|
+
level: parseInt(match[2], 10),
|
|
44130
|
+
isOrdered: false
|
|
44131
|
+
// Will be resolved from style rules
|
|
44132
|
+
};
|
|
44133
|
+
}
|
|
44134
|
+
function convertWordLists(doc2) {
|
|
44135
|
+
const listStyles = parseListStyles(doc2);
|
|
44136
|
+
const listParagraphs = Array.from(doc2.body.querySelectorAll('[class*="MsoList"]'));
|
|
44137
|
+
if (listParagraphs.length === 0) return;
|
|
44138
|
+
const groups = [];
|
|
44139
|
+
let currentGroup = [];
|
|
44140
|
+
for (const p of listParagraphs) {
|
|
44141
|
+
const el2 = p;
|
|
44142
|
+
const style2 = el2.getAttribute("style") ?? "";
|
|
44143
|
+
if (!parseListStyle(style2)) continue;
|
|
44144
|
+
if (currentGroup.length > 0) {
|
|
44145
|
+
const lastEl = currentGroup[currentGroup.length - 1];
|
|
44146
|
+
let nextSibling = lastEl.nextElementSibling;
|
|
44147
|
+
while (nextSibling && nextSibling !== el2 && nextSibling.textContent?.trim() === "") {
|
|
44148
|
+
nextSibling = nextSibling.nextElementSibling;
|
|
44149
|
+
}
|
|
44150
|
+
if (nextSibling !== el2) {
|
|
44151
|
+
groups.push(currentGroup);
|
|
44152
|
+
currentGroup = [];
|
|
44153
|
+
}
|
|
44154
|
+
}
|
|
44155
|
+
currentGroup.push(el2);
|
|
44156
|
+
}
|
|
44157
|
+
if (currentGroup.length > 0) {
|
|
44158
|
+
groups.push(currentGroup);
|
|
44159
|
+
}
|
|
44160
|
+
for (const group of groups) {
|
|
44161
|
+
convertListGroup(doc2, group, listStyles);
|
|
44162
|
+
}
|
|
44163
|
+
}
|
|
44164
|
+
function convertListGroup(doc2, paragraphs, listStyles) {
|
|
44165
|
+
if (paragraphs.length === 0) return;
|
|
44166
|
+
const rootInfo = parseListStyle(paragraphs[0].getAttribute("style") ?? "");
|
|
44167
|
+
if (!rootInfo) return;
|
|
44168
|
+
const parent = paragraphs[0].parentNode;
|
|
44169
|
+
if (!parent) return;
|
|
44170
|
+
const rootKey = `${rootInfo.listId}:level${rootInfo.level}`;
|
|
44171
|
+
const isRootOrdered = listStyles.get(rootKey) ?? false;
|
|
44172
|
+
const rootList = doc2.createElement(isRootOrdered ? "ol" : "ul");
|
|
44173
|
+
const stack = [{ element: rootList, level: rootInfo.level }];
|
|
44174
|
+
for (const p of paragraphs) {
|
|
44175
|
+
const style2 = p.getAttribute("style") ?? "";
|
|
44176
|
+
const info = parseListStyle(style2);
|
|
44177
|
+
if (!info) continue;
|
|
44178
|
+
const key = `${info.listId}:level${info.level}`;
|
|
44179
|
+
const isOrdered = listStyles.get(key) ?? false;
|
|
44180
|
+
while (stack.length > 1 && stack[stack.length - 1].level >= info.level) {
|
|
44181
|
+
stack.pop();
|
|
44182
|
+
}
|
|
44183
|
+
if (info.level > stack[stack.length - 1].level) {
|
|
44184
|
+
const currentList = stack[stack.length - 1].element;
|
|
44185
|
+
let lastLi = currentList.lastElementChild;
|
|
44186
|
+
if (!lastLi || lastLi.tagName.toLowerCase() !== "li") {
|
|
44187
|
+
lastLi = doc2.createElement("li");
|
|
44188
|
+
currentList.appendChild(lastLi);
|
|
44189
|
+
}
|
|
44190
|
+
const subList = doc2.createElement(isOrdered ? "ol" : "ul");
|
|
44191
|
+
lastLi.appendChild(subList);
|
|
44192
|
+
stack.push({ element: subList, level: info.level });
|
|
44193
|
+
}
|
|
44194
|
+
const li = doc2.createElement("li");
|
|
44195
|
+
removeListMarkers(p);
|
|
44196
|
+
while (p.firstChild) {
|
|
44197
|
+
li.appendChild(p.firstChild);
|
|
44198
|
+
}
|
|
44199
|
+
const cleanedStyle = cleanMsoStyles(style2);
|
|
44200
|
+
if (cleanedStyle) {
|
|
44201
|
+
li.setAttribute("style", cleanedStyle);
|
|
44202
|
+
}
|
|
44203
|
+
stack[stack.length - 1].element.appendChild(li);
|
|
44204
|
+
}
|
|
44205
|
+
parent.insertBefore(rootList, paragraphs[0]);
|
|
44206
|
+
for (const p of paragraphs) {
|
|
44207
|
+
p.remove();
|
|
44208
|
+
}
|
|
44209
|
+
}
|
|
44210
|
+
function removeListMarkers(el2) {
|
|
44211
|
+
const spans = Array.from(el2.querySelectorAll("span"));
|
|
44212
|
+
for (const span of spans) {
|
|
44213
|
+
const style2 = span.getAttribute("style") ?? "";
|
|
44214
|
+
if (/mso-list:\s*Ignore/i.test(style2)) {
|
|
44215
|
+
span.remove();
|
|
44216
|
+
}
|
|
44217
|
+
}
|
|
44218
|
+
}
|
|
44219
|
+
const MSO_PROPERTY_PATTERN = /\bmso-[^:]+:[^;]+;?\s*/gi;
|
|
44220
|
+
const MSO_CLASS_PATTERN = /\bMso\w*|\bxl\d+/g;
|
|
44221
|
+
function cleanMsoStyles(style2) {
|
|
44222
|
+
let cleaned = style2.replace(MSO_PROPERTY_PATTERN, "");
|
|
44223
|
+
cleaned = cleaned.replace(/;\s*;/g, ";").replace(/^\s*;\s*/, "").replace(/\s*;\s*$/, "").trim();
|
|
44224
|
+
return cleaned || "";
|
|
44225
|
+
}
|
|
44226
|
+
function cleanFontFamily(value) {
|
|
44227
|
+
const first2 = value.split(",")[0].trim();
|
|
44228
|
+
return first2.replace(/^["']|["']$/g, "");
|
|
44229
|
+
}
|
|
44230
|
+
function cleanElementStyles(doc2) {
|
|
44231
|
+
const allElements = Array.from(doc2.body.querySelectorAll("*"));
|
|
44232
|
+
for (const el2 of allElements) {
|
|
44233
|
+
const className = el2.getAttribute("class");
|
|
44234
|
+
if (className) {
|
|
44235
|
+
const cleaned = className.replace(MSO_CLASS_PATTERN, "").trim();
|
|
44236
|
+
if (cleaned) {
|
|
44237
|
+
el2.setAttribute("class", cleaned);
|
|
44238
|
+
} else {
|
|
44239
|
+
el2.removeAttribute("class");
|
|
44240
|
+
}
|
|
44241
|
+
}
|
|
44242
|
+
const style2 = el2.getAttribute("style");
|
|
44243
|
+
if (style2) {
|
|
44244
|
+
let cleaned = cleanMsoStyles(style2);
|
|
44245
|
+
const fontFamilyMatch = /font-family:\s*([^;]+)/i.exec(cleaned);
|
|
44246
|
+
if (fontFamilyMatch) {
|
|
44247
|
+
const cleanedFont = cleanFontFamily(fontFamilyMatch[1]);
|
|
44248
|
+
cleaned = cleaned.replace(fontFamilyMatch[0], `font-family: ${cleanedFont}`);
|
|
44249
|
+
}
|
|
44250
|
+
if (cleaned) {
|
|
44251
|
+
el2.setAttribute("style", cleaned);
|
|
44252
|
+
} else {
|
|
44253
|
+
el2.removeAttribute("style");
|
|
44254
|
+
}
|
|
44255
|
+
}
|
|
44256
|
+
const attrsToRemove = Array.from(el2.attributes).filter(
|
|
44257
|
+
(attr) => attr.name.startsWith("v:") || attr.name.startsWith("o:") || attr.name === "lang"
|
|
44258
|
+
);
|
|
44259
|
+
for (const attr of attrsToRemove) {
|
|
44260
|
+
el2.removeAttribute(attr.name);
|
|
44261
|
+
}
|
|
44262
|
+
}
|
|
44263
|
+
}
|
|
44264
|
+
function removeEmptyWrappers(doc2) {
|
|
44265
|
+
let changed = true;
|
|
44266
|
+
while (changed) {
|
|
44267
|
+
changed = false;
|
|
44268
|
+
const spans = Array.from(doc2.body.querySelectorAll("span"));
|
|
44269
|
+
for (const span of spans) {
|
|
44270
|
+
if (span.attributes.length === 0) {
|
|
44271
|
+
const parent = span.parentNode;
|
|
44272
|
+
if (parent) {
|
|
44273
|
+
while (span.firstChild) {
|
|
44274
|
+
parent.insertBefore(span.firstChild, span);
|
|
44275
|
+
}
|
|
44276
|
+
parent.removeChild(span);
|
|
44277
|
+
changed = true;
|
|
44278
|
+
}
|
|
44279
|
+
}
|
|
44280
|
+
}
|
|
44281
|
+
}
|
|
44282
|
+
const emptyParas = Array.from(doc2.body.querySelectorAll("p"));
|
|
44283
|
+
for (const p of emptyParas) {
|
|
44284
|
+
if (p.innerHTML.trim() === "" && doc2.body.children.length > 1) {
|
|
44285
|
+
p.remove();
|
|
44286
|
+
}
|
|
44287
|
+
}
|
|
44288
|
+
}
|
|
44289
|
+
function normalizeExcelTables(doc2) {
|
|
44290
|
+
const tables = Array.from(doc2.body.querySelectorAll("table"));
|
|
44291
|
+
for (const table of tables) {
|
|
44292
|
+
removeExcelAttributes(table);
|
|
44293
|
+
const cells = Array.from(table.querySelectorAll("td, th"));
|
|
44294
|
+
for (const cell of cells) {
|
|
44295
|
+
removeExcelAttributes(cell);
|
|
44296
|
+
const style2 = cell.getAttribute("style");
|
|
44297
|
+
if (style2) {
|
|
44298
|
+
const cleaned = cleanMsoStyles(style2);
|
|
44299
|
+
if (cleaned) {
|
|
44300
|
+
cell.setAttribute("style", cleaned);
|
|
44301
|
+
} else {
|
|
44302
|
+
cell.removeAttribute("style");
|
|
44303
|
+
}
|
|
44304
|
+
}
|
|
44305
|
+
}
|
|
44306
|
+
const rows = Array.from(table.querySelectorAll("tr"));
|
|
44307
|
+
for (const row of rows) {
|
|
44308
|
+
removeExcelAttributes(row);
|
|
44309
|
+
}
|
|
44310
|
+
}
|
|
44311
|
+
}
|
|
44312
|
+
const EXCEL_ATTRS = [
|
|
44313
|
+
"x:num",
|
|
44314
|
+
"x:str",
|
|
44315
|
+
"x:fmla",
|
|
44316
|
+
"x:autofilter",
|
|
44317
|
+
"mso-number-format"
|
|
44318
|
+
];
|
|
44319
|
+
function removeExcelAttributes(el2) {
|
|
44320
|
+
for (const attr of EXCEL_ATTRS) {
|
|
44321
|
+
el2.removeAttribute(attr);
|
|
44322
|
+
}
|
|
44323
|
+
const className = el2.getAttribute("class");
|
|
44324
|
+
if (className) {
|
|
44325
|
+
const cleaned = className.replace(MSO_CLASS_PATTERN, "").trim();
|
|
44326
|
+
if (cleaned) {
|
|
44327
|
+
el2.setAttribute("class", cleaned);
|
|
44328
|
+
} else {
|
|
44329
|
+
el2.removeAttribute("class");
|
|
44330
|
+
}
|
|
44331
|
+
}
|
|
44332
|
+
}
|
|
44333
|
+
const DANGEROUS_TAGS = [
|
|
44334
|
+
"script",
|
|
44335
|
+
"iframe",
|
|
44336
|
+
"object",
|
|
44337
|
+
"embed",
|
|
44338
|
+
"applet",
|
|
44339
|
+
"form",
|
|
44340
|
+
"input",
|
|
44341
|
+
"textarea",
|
|
44342
|
+
"select",
|
|
44343
|
+
"button"
|
|
44344
|
+
];
|
|
44345
|
+
const EVENT_ATTR_PATTERN = /^on/i;
|
|
44346
|
+
const DANGEROUS_URL_PATTERN = /^\s*(javascript|vbscript|data\s*:(?!image))/i;
|
|
44347
|
+
function sanitize(doc2) {
|
|
44348
|
+
for (const tag of DANGEROUS_TAGS) {
|
|
44349
|
+
const elements = Array.from(doc2.body.querySelectorAll(tag));
|
|
44350
|
+
for (const el2 of elements) {
|
|
44351
|
+
el2.remove();
|
|
44352
|
+
}
|
|
44353
|
+
}
|
|
44354
|
+
const allElements = Array.from(doc2.body.querySelectorAll("*"));
|
|
44355
|
+
for (const el2 of allElements) {
|
|
44356
|
+
const attrs = Array.from(el2.attributes);
|
|
44357
|
+
for (const attr of attrs) {
|
|
44358
|
+
if (EVENT_ATTR_PATTERN.test(attr.name)) {
|
|
44359
|
+
el2.removeAttribute(attr.name);
|
|
44360
|
+
continue;
|
|
44361
|
+
}
|
|
44362
|
+
if ((attr.name === "href" || attr.name === "src" || attr.name === "action") && DANGEROUS_URL_PATTERN.test(attr.value)) {
|
|
44363
|
+
el2.removeAttribute(attr.name);
|
|
44364
|
+
}
|
|
44365
|
+
}
|
|
44366
|
+
const src = el2.getAttribute("src");
|
|
44367
|
+
if (src && src.startsWith("file://")) {
|
|
44368
|
+
el2.removeAttribute("src");
|
|
44369
|
+
}
|
|
44370
|
+
const href = el2.getAttribute("href");
|
|
44371
|
+
if (href && href.startsWith("file://")) {
|
|
44372
|
+
el2.removeAttribute("href");
|
|
44373
|
+
}
|
|
44374
|
+
}
|
|
44375
|
+
}
|
|
44376
|
+
function removeStyleBlocks(doc2) {
|
|
44377
|
+
const styles = Array.from(doc2.querySelectorAll("style"));
|
|
44378
|
+
for (const s of styles) {
|
|
44379
|
+
s.remove();
|
|
44380
|
+
}
|
|
44381
|
+
}
|
|
44382
|
+
function removeHeadElements(doc2) {
|
|
44383
|
+
const selectors = ["meta", "link", "title", "xml"];
|
|
44384
|
+
for (const selector of selectors) {
|
|
44385
|
+
const elements = Array.from(doc2.body.querySelectorAll(selector));
|
|
44386
|
+
for (const el2 of elements) {
|
|
44387
|
+
el2.remove();
|
|
44388
|
+
}
|
|
44389
|
+
}
|
|
44390
|
+
}
|
|
44391
|
+
function transformOfficeHTML(html) {
|
|
44392
|
+
if (!isOfficeContent(html)) {
|
|
44393
|
+
return html;
|
|
44394
|
+
}
|
|
44395
|
+
let cleaned = removeConditionalComments(html);
|
|
44396
|
+
const parser = new DOMParser();
|
|
44397
|
+
const doc2 = parser.parseFromString(cleaned, "text/html");
|
|
44398
|
+
removeHeadElements(doc2);
|
|
44399
|
+
if (isWordContent(html)) {
|
|
44400
|
+
convertWordLists(doc2);
|
|
44401
|
+
}
|
|
44402
|
+
removeOfficeElements(doc2);
|
|
44403
|
+
if (isExcelContent(html)) {
|
|
44404
|
+
normalizeExcelTables(doc2);
|
|
44405
|
+
}
|
|
44406
|
+
cleanElementStyles(doc2);
|
|
44407
|
+
removeStyleBlocks(doc2);
|
|
44408
|
+
removeEmptyWrappers(doc2);
|
|
44409
|
+
sanitize(doc2);
|
|
44410
|
+
return doc2.body.innerHTML;
|
|
44411
|
+
}
|
|
44412
|
+
const PasteFromOffice = Extension.create({
|
|
44413
|
+
name: "pasteFromOffice",
|
|
44414
|
+
addOptions() {
|
|
44415
|
+
return {
|
|
44416
|
+
enabled: true
|
|
44417
|
+
};
|
|
44418
|
+
},
|
|
44419
|
+
addStorage() {
|
|
44420
|
+
return {};
|
|
44421
|
+
},
|
|
44422
|
+
transformPastedHTML(html) {
|
|
44423
|
+
if (!this.options.enabled) {
|
|
44424
|
+
return html;
|
|
44425
|
+
}
|
|
44426
|
+
return transformOfficeHTML(html);
|
|
44427
|
+
}
|
|
44428
|
+
});
|
|
44034
44429
|
const en = {
|
|
44035
44430
|
"Bold": "Bold",
|
|
44036
44431
|
"Italic": "Italic",
|
|
@@ -46401,7 +46796,8 @@ class HTMLEditor {
|
|
|
46401
46796
|
convert_unsafe_embeds: config.convert_unsafe_embeds ?? true,
|
|
46402
46797
|
format_empty_lines: config.format_empty_lines ?? true,
|
|
46403
46798
|
toolbar_narrow_breakpoint: config.toolbar_narrow_breakpoint,
|
|
46404
|
-
toolbar_priority: config.toolbar_priority
|
|
46799
|
+
toolbar_priority: config.toolbar_priority,
|
|
46800
|
+
paste_from_office: config.paste_from_office ?? true
|
|
46405
46801
|
};
|
|
46406
46802
|
}
|
|
46407
46803
|
createEditor() {
|
|
@@ -46604,6 +47000,9 @@ class HTMLEditor {
|
|
|
46604
47000
|
}),
|
|
46605
47001
|
TextDirection
|
|
46606
47002
|
];
|
|
47003
|
+
if (this.config.paste_from_office !== false) {
|
|
47004
|
+
extensions.push(PasteFromOffice);
|
|
47005
|
+
}
|
|
46607
47006
|
if (!this.config.basicEditor) {
|
|
46608
47007
|
extensions.push(
|
|
46609
47008
|
Image.configure({
|
|
@@ -46829,6 +47228,7 @@ export {
|
|
|
46829
47228
|
LineHeight,
|
|
46830
47229
|
LinkEditor,
|
|
46831
47230
|
Mention,
|
|
47231
|
+
PasteFromOffice,
|
|
46832
47232
|
SearchReplace,
|
|
46833
47233
|
SignatureBlock,
|
|
46834
47234
|
SourceEditor,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mdaemon/html-editor",
|
|
3
|
-
"version": "1.1
|
|
3
|
+
"version": "1.2.1",
|
|
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": {
|