@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 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 = "aaa1rp3bb0ott3vie4c1le2ogado5udhabi7c0ademy5centure6ountant0s9o1tor4d0s1ult4e0g1ro2tna4f0l1rica5g0akhan5ency5i0g1rbus3force5tel5kdn3l0ibaba4pay4lfinanz6state5y2sace3tom5m0azon4ericanexpress7family11x2fam3ica3sterdam8nalytics7droid5quan4z2o0l2partments8p0le4q0uarelle8r0ab1mco4chi3my2pa2t0e3s0da2ia2sociates9t0hleta5torney7u0ction5di0ble3o3spost5thor3o0s4w0s2x0a2z0ure5ba0by2idu3namex4d1k2r0celona5laycard4s5efoot5gains6seball5ketball8uhaus5yern5b0c1t1va3cg1n2d1e0ats2uty4er2rlin4st0buy5t2f1g1h0arti5i0ble3d1ke2ng0o3o1z2j1lack0friday9ockbuster8g1omberg7ue3m0s1w2n0pparibas9o0ats3ehringer8fa2m1nd2o0k0ing5sch2tik2on4t1utique6x2r0adesco6idgestone9oadway5ker3ther5ussels7s1t1uild0ers6siness6y1zz3v1w1y1z0h3ca0b1fe2l0l1vinklein9m0era3p2non3petown5ital0one8r0avan4ds2e0er0s4s2sa1e1h1ino4t0ering5holic7ba1n1re3c1d1enter4o1rn3f0a1d2g1h0anel2nel4rity4se2t2eap3intai5ristmas6ome4urch5i0priani6rcle4sco3tadel4i0c2y3k1l0aims4eaning6ick2nic1que6othing5ud3ub0med6m1n1o0ach3des3ffee4llege4ogne5m0mbank4unity6pany2re3uter5sec4ndos3struction8ulting7tact3ractors9oking4l1p2rsica5untry4pon0s4rses6pa2r0edit0card4union9icket5own3s1uise0s6u0isinella9v1w1x1y0mru3ou3z2dad1nce3ta1e1ing3sun4y2clk3ds2e0al0er2s3gree4livery5l1oitte5ta3mocrat6ntal2ist5si0gn4v2hl2iamonds6et2gital5rect0ory7scount3ver5h2y2j1k1m1np2o0cs1tor4g1mains5t1wnload7rive4tv2ubai3nlop4pont4rban5vag2r2z2earth3t2c0o2deka3u0cation8e1g1mail3erck5nergy4gineer0ing9terprises10pson4quipment8r0icsson6ni3s0q1tate5t1u0rovision8s2vents5xchange6pert3osed4ress5traspace10fage2il1rwinds6th3mily4n0s2rm0ers5shion4t3edex3edback6rrari3ero6i0delity5o2lm2nal1nce1ial7re0stone6mdale6sh0ing5t0ness6j1k1lickr3ghts4r2orist4wers5y2m1o0o0d1tball6rd1ex2sale4um3undation8x2r0ee1senius7l1ogans4ntier7tr2ujitsu5n0d2rniture7tbol5yi3ga0l0lery3o1up4me0s3p1rden4y2b0iz3d0n2e0a1nt0ing5orge5f1g0ee3h1i0ft0s3ves2ing5l0ass3e1obal2o4m0ail3bh2o1x2n1odaddy5ld0point6f2o0dyear5g0le4p1t1v2p1q1r0ainger5phics5tis4een3ipe3ocery4up4s1t1u0cci3ge2ide2tars5ru3w1y2hair2mburg5ngout5us3bo2dfc0bank7ealth0care8lp1sinki6re1mes5iphop4samitsu7tachi5v2k0t2m1n1ockey4ldings5iday5medepot5goods5s0ense7nda3rse3spital5t0ing5t0els3mail5use3w2r1sbc3t1u0ghes5yatt3undai7ibm2cbc2e1u2d1e0ee3fm2kano4l1m0amat4db2mo0bilien9n0c1dustries8finiti5o2g1k1stitute6urance4e4t0ernational10uit4vestments10o1piranga7q1r0ish4s0maili5t0anbul7t0au2v3jaguar4va3cb2e0ep2tzt3welry6io2ll2m0p2nj2o0bs1urg4t1y2p0morgan6rs3uegos4niper7kaufen5ddi3e0rryhotels6properties14fh2g1h1i0a1ds2m1ndle4tchen5wi3m1n1oeln3matsu5sher5p0mg2n2r0d1ed3uokgroup8w1y0oto4z2la0caixa5mborghini8er3nd0rover6xess5salle5t0ino3robe5w0yer5b1c1ds2ease3clerc5frak4gal2o2xus4gbt3i0dl2fe0insurance9style7ghting6ke2lly3mited4o2ncoln4k2ve1ing5k1lc1p2oan0s3cker3us3l1ndon4tte1o3ve3pl0financial11r1s1t0d0a3u0ndbeck6xe1ury5v1y2ma0drid4if1son4keup4n0agement7go3p1rket0ing3s4riott5shalls7ttel5ba2c0kinsey7d1e0d0ia3et2lbourne7me1orial6n0u2rckmsd7g1h1iami3crosoft7l1ni1t2t0subishi9k1l0b1s2m0a2n1o0bi0le4da2e1i1m1nash3ey2ster5rmon3tgage6scow4to0rcycles9v0ie4p1q1r1s0d2t0n1r2u0seum3ic4v1w1x1y1z2na0b1goya4me2vy3ba2c1e0c1t0bank4flix4work5ustar5w0s2xt0direct7us4f0l2g0o2hk2i0co2ke1on3nja3ssan1y5l1o0kia3rton4w0ruz3tv4p1r0a1w2tt2u1yc2z2obi1server7ffice5kinawa6layan0group9lo3m0ega4ne1g1l0ine5oo2pen3racle3nge4g0anic5igins6saka4tsuka4t2vh3pa0ge2nasonic7ris2s1tners4s1y3y2ccw3e0t2f0izer5g1h0armacy6d1ilips5one2to0graphy6s4ysio5ics1tet2ures6d1n0g1k2oneer5zza4k1l0ace2y0station9umbing5s3m1n0c2ohl2ker3litie5rn2st3r0axi3ess3ime3o0d0uctions8f1gressive8mo2perties3y5tection8u0dential9s1t1ub2w0c2y2qa1pon3uebec3st5racing4dio4e0ad1lestate6tor2y4cipes5d0stone5umbrella9hab3ise0n3t2liance6n0t0als5pair3ort3ublican8st0aurant8view0s5xroth6ich0ardli6oh3l1o1p2o0cks3deo3gers4om3s0vp3u0gby3hr2n2w0e2yukyu6sa0arland6fe0ty4kura4le1on3msclub4ung5ndvik0coromant12ofi4p1rl2s1ve2xo3b0i1s2c0b1haeffler7midt4olarships8ol3ule3warz5ience5ot3d1e0arch3t2cure1ity6ek2lect4ner3rvices6ven3w1x0y3fr2g1h0angrila6rp3ell3ia1ksha5oes2p0ping5uji3w3i0lk2na1gles5te3j1k0i0n2y0pe4l0ing4m0art3ile4n0cf3o0ccer3ial4ftbank4ware6hu2lar2utions7ng1y2y2pa0ce3ort2t3r0l2s1t0ada2ples4r1tebank4farm7c0group6ockholm6rage3e3ream4udio2y3yle4u0cks3pplies3y2ort5rf1gery5zuki5v1watch4iss4x1y0dney4stems6z2tab1ipei4lk2obao4rget4tamotors6r2too4x0i3c0i2d0k2eam2ch0nology8l1masek5nnis4va3f1g1h0d1eater2re6iaa2ckets5enda4ps2res2ol4j0maxx4x2k0maxx5l1m0all4n1o0day3kyo3ols3p1ray3shiba5tal3urs3wn2yota3s3r0ade1ing4ining5vel0ers0insurance16ust3v2t1ube2i1nes3shu4v0s2w1z2ua1bank3s2g1k1nicom3versity8o2ol2ps2s1y1z2va0cations7na1guard7c1e0gas3ntures6risign5mögensberater2ung14sicherung10t2g1i0ajes4deo3g1king4llas4n1p1rgin4sa1ion4va1o3laanderen9n1odka3lvo3te1ing3o2yage5u2wales2mart4ter4ng0gou5tch0es6eather0channel12bcam3er2site5d0ding5ibo2r3f1hoswho6ien2ki2lliamhill9n0dows4e1ners6me2olterskluwer11odside6rk0s2ld3w2s1tc1f3xbox3erox4ihuan4n2xx2yz3yachts4hoo3maxun5ndex5e1odobashi7ga2kohama6u0tube6t1un3za0ppos4ra3ero3ip2m1one3uerich6w2";
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
- if (limit === null || limit === void 0 || limit === 0) {
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 styleAttr = element.getAttribute("style");
23199
- if (styleAttr) {
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 styleAttr = element.getAttribute("style");
23255
- if (styleAttr) {
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
- parseHTML: (element) => element.style.fontFamily,
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 `&quot;` 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
- parseHTML: (element) => element.style.fontSize,
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
- parseHTML: (element) => element.style.lineHeight,
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
- parseHTML: (element) => element.getAttribute("data-color") || element.style.backgroundColor,
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 = "aaa1rp3bb0ott3vie4c1le2ogado5udhabi7c0ademy5centure6ountant0s9o1tor4d0s1ult4e0g1ro2tna4f0l1rica5g0akhan5ency5i0g1rbus3force5tel5kdn3l0ibaba4pay4lfinanz6state5y2sace3tom5m0azon4ericanexpress7family11x2fam3ica3sterdam8nalytics7droid5quan4z2o0l2partments8p0le4q0uarelle8r0ab1mco4chi3my2pa2t0e3s0da2ia2sociates9t0hleta5torney7u0ction5di0ble3o3spost5thor3o0s4w0s2x0a2z0ure5ba0by2idu3namex4d1k2r0celona5laycard4s5efoot5gains6seball5ketball8uhaus5yern5b0c1t1va3cg1n2d1e0ats2uty4er2rlin4st0buy5t2f1g1h0arti5i0ble3d1ke2ng0o3o1z2j1lack0friday9ockbuster8g1omberg7ue3m0s1w2n0pparibas9o0ats3ehringer8fa2m1nd2o0k0ing5sch2tik2on4t1utique6x2r0adesco6idgestone9oadway5ker3ther5ussels7s1t1uild0ers6siness6y1zz3v1w1y1z0h3ca0b1fe2l0l1vinklein9m0era3p2non3petown5ital0one8r0avan4ds2e0er0s4s2sa1e1h1ino4t0ering5holic7ba1n1re3c1d1enter4o1rn3f0a1d2g1h0anel2nel4rity4se2t2eap3intai5ristmas6ome4urch5i0priani6rcle4sco3tadel4i0c2y3k1l0aims4eaning6ick2nic1que6othing5ud3ub0med6m1n1o0ach3des3ffee4llege4ogne5m0mbank4unity6pany2re3uter5sec4ndos3struction8ulting7tact3ractors9oking4l1p2rsica5untry4pon0s4rses6pa2r0edit0card4union9icket5own3s1uise0s6u0isinella9v1w1x1y0mru3ou3z2dad1nce3ta1e1ing3sun4y2clk3ds2e0al0er2s3gree4livery5l1oitte5ta3mocrat6ntal2ist5si0gn4v2hl2iamonds6et2gital5rect0ory7scount3ver5h2y2j1k1m1np2o0cs1tor4g1mains5t1wnload7rive4tv2ubai3nlop4pont4rban5vag2r2z2earth3t2c0o2deka3u0cation8e1g1mail3erck5nergy4gineer0ing9terprises10pson4quipment8r0icsson6ni3s0q1tate5t1u0rovision8s2vents5xchange6pert3osed4ress5traspace10fage2il1rwinds6th3mily4n0s2rm0ers5shion4t3edex3edback6rrari3ero6i0delity5o2lm2nal1nce1ial7re0stone6mdale6sh0ing5t0ness6j1k1lickr3ghts4r2orist4wers5y2m1o0o0d1tball6rd1ex2sale4um3undation8x2r0ee1senius7l1ogans4ntier7tr2ujitsu5n0d2rniture7tbol5yi3ga0l0lery3o1up4me0s3p1rden4y2b0iz3d0n2e0a1nt0ing5orge5f1g0ee3h1i0ft0s3ves2ing5l0ass3e1obal2o4m0ail3bh2o1x2n1odaddy5ld0point6f2o0dyear5g0le4p1t1v2p1q1r0ainger5phics5tis4een3ipe3ocery4up4s1t1u0cci3ge2ide2tars5ru3w1y2hair2mburg5ngout5us3bo2dfc0bank7ealth0care8lp1sinki6re1mes5iphop4samitsu7tachi5v2k0t2m1n1ockey4ldings5iday5medepot5goods5s0ense7nda3rse3spital5t0ing5t0els3mail5use3w2r1sbc3t1u0ghes5yatt3undai7ibm2cbc2e1u2d1e0ee3fm2kano4l1m0amat4db2mo0bilien9n0c1dustries8finiti5o2g1k1stitute6urance4e4t0ernational10uit4vestments10o1piranga7q1r0ish4s0maili5t0anbul7t0au2v3jaguar4va3cb2e0ep2tzt3welry6io2ll2m0p2nj2o0bs1urg4t1y2p0morgan6rs3uegos4niper7kaufen5ddi3e0rryhotels6properties14fh2g1h1i0a1ds2m1ndle4tchen5wi3m1n1oeln3matsu5sher5p0mg2n2r0d1ed3uokgroup8w1y0oto4z2la0caixa5mborghini8er3nd0rover6xess5salle5t0ino3robe5w0yer5b1c1ds2ease3clerc5frak4gal2o2xus4gbt3i0dl2fe0insurance9style7ghting6ke2lly3mited4o2ncoln4k2ve1ing5k1lc1p2oan0s3cker3us3l1ndon4tte1o3ve3pl0financial11r1s1t0d0a3u0ndbeck6xe1ury5v1y2ma0drid4if1son4keup4n0agement7go3p1rket0ing3s4riott5shalls7ttel5ba2c0kinsey7d1e0d0ia3et2lbourne7me1orial6n0u2rckmsd7g1h1iami3crosoft7l1ni1t2t0subishi9k1l0b1s2m0a2n1o0bi0le4da2e1i1m1nash3ey2ster5rmon3tgage6scow4to0rcycles9v0ie4p1q1r1s0d2t0n1r2u0seum3ic4v1w1x1y1z2na0b1goya4me2vy3ba2c1e0c1t0bank4flix4work5ustar5w0s2xt0direct7us4f0l2g0o2hk2i0co2ke1on3nja3ssan1y5l1o0kia3rton4w0ruz3tv4p1r0a1w2tt2u1yc2z2obi1server7ffice5kinawa6layan0group9lo3m0ega4ne1g1l0ine5oo2pen3racle3nge4g0anic5igins6saka4tsuka4t2vh3pa0ge2nasonic7ris2s1tners4s1y3y2ccw3e0t2f0izer5g1h0armacy6d1ilips5one2to0graphy6s4ysio5ics1tet2ures6d1n0g1k2oneer5zza4k1l0ace2y0station9umbing5s3m1n0c2ohl2ker3litie5rn2st3r0axi3ess3ime3o0d0uctions8f1gressive8mo2perties3y5tection8u0dential9s1t1ub2w0c2y2qa1pon3uebec3st5racing4dio4e0ad1lestate6tor2y4cipes5d0stone5umbrella9hab3ise0n3t2liance6n0t0als5pair3ort3ublican8st0aurant8view0s5xroth6ich0ardli6oh3l1o1p2o0cks3deo3gers4om3s0vp3u0gby3hr2n2w0e2yukyu6sa0arland6fe0ty4kura4le1on3msclub4ung5ndvik0coromant12ofi4p1rl2s1ve2xo3b0i1s2c0b1haeffler7midt4olarships8ol3ule3warz5ience5ot3d1e0arch3t2cure1ity6ek2lect4ner3rvices6ven3w1x0y3fr2g1h0angrila6rp3ell3ia1ksha5oes2p0ping5uji3w3i0lk2na1gles5te3j1k0i0n2y0pe4l0ing4m0art3ile4n0cf3o0ccer3ial4ftbank4ware6hu2lar2utions7ng1y2y2pa0ce3ort2t3r0l2s1t0ada2ples4r1tebank4farm7c0group6ockholm6rage3e3ream4udio2y3yle4u0cks3pplies3y2ort5rf1gery5zuki5v1watch4iss4x1y0dney4stems6z2tab1ipei4lk2obao4rget4tamotors6r2too4x0i3c0i2d0k2eam2ch0nology8l1masek5nnis4va3f1g1h0d1eater2re6iaa2ckets5enda4ps2res2ol4j0maxx4x2k0maxx5l1m0all4n1o0day3kyo3ols3p1ray3shiba5tal3urs3wn2yota3s3r0ade1ing4ining5vel0ers0insurance16ust3v2t1ube2i1nes3shu4v0s2w1z2ua1bank3s2g1k1nicom3versity8o2ol2ps2s1y1z2va0cations7na1guard7c1e0gas3ntures6risign5mögensberater2ung14sicherung10t2g1i0ajes4deo3g1king4llas4n1p1rgin4sa1ion4va1o3laanderen9n1odka3lvo3te1ing3o2yage5u2wales2mart4ter4ng0gou5tch0es6eather0channel12bcam3er2site5d0ding5ibo2r3f1hoswho6ien2ki2lliamhill9n0dows4e1ners6me2olterskluwer11odside6rk0s2ld3w2s1tc1f3xbox3erox4ihuan4n2xx2yz3yachts4hoo3maxun5ndex5e1odobashi7ga2kohama6u0tube6t1un3za0ppos4ra3ero3ip2m1one3uerich6w2";
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
- if (limit === null || limit === void 0 || limit === 0) {
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 styleAttr = element.getAttribute("style");
23197
- if (styleAttr) {
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 styleAttr = element.getAttribute("style");
23253
- if (styleAttr) {
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
- parseHTML: (element) => element.style.fontFamily,
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 `&quot;` 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
- parseHTML: (element) => element.style.fontSize,
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
- parseHTML: (element) => element.style.lineHeight,
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
- parseHTML: (element) => element.getAttribute("data-color") || element.style.backgroundColor,
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.0",
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.1",
64
- "@tiptap/extension-character-count": "^3.23.1",
65
- "@tiptap/extension-code-block-lowlight": "^3.23.1",
66
- "@tiptap/extension-color": "^3.23.1",
67
- "@tiptap/extension-font-family": "^3.23.1",
68
- "@tiptap/extension-highlight": "^3.23.1",
69
- "@tiptap/extension-image": "^3.23.1",
70
- "@tiptap/extension-link": "^3.23.1",
71
- "@tiptap/extension-placeholder": "^3.23.1",
72
- "@tiptap/extension-table": "^3.23.1",
73
- "@tiptap/extension-table-cell": "^3.23.1",
74
- "@tiptap/extension-table-header": "^3.23.1",
75
- "@tiptap/extension-table-row": "^3.23.1",
76
- "@tiptap/extension-text-align": "^3.23.1",
77
- "@tiptap/extension-text-style": "^3.23.1",
78
- "@tiptap/extension-underline": "^3.23.1",
79
- "@tiptap/pm": "^3.23.1",
80
- "@tiptap/starter-kit": "^3.23.1",
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": {