@editora/core 1.0.0 → 1.0.2
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 +9 -0
- package/dist/A11yCheckerPlugin.native-CZKpi3uF.mjs +475 -0
- package/dist/A11yCheckerPlugin.native-CZKpi3uF.mjs.map +1 -0
- package/dist/AnchorPlugin.native-7es9PVZ9.mjs +340 -0
- package/dist/AnchorPlugin.native-7es9PVZ9.mjs.map +1 -0
- package/dist/BackgroundColorPlugin.native-Dip5uqTg.mjs +449 -0
- package/dist/BackgroundColorPlugin.native-Dip5uqTg.mjs.map +1 -0
- package/dist/BlockquotePlugin.native-JFmOLsxN.mjs +48 -0
- package/dist/BlockquotePlugin.native-JFmOLsxN.mjs.map +1 -0
- package/dist/BoldPlugin.native-BAzzoqU5.mjs +45 -0
- package/dist/BoldPlugin.native-BAzzoqU5.mjs.map +1 -0
- package/dist/CapitalizationPlugin.native-DOMsh5R7.mjs +79 -0
- package/dist/CapitalizationPlugin.native-DOMsh5R7.mjs.map +1 -0
- package/dist/ChecklistPlugin.native-Dccs3nLe.mjs +153 -0
- package/dist/ChecklistPlugin.native-Dccs3nLe.mjs.map +1 -0
- package/dist/ClearFormattingPlugin.native-BZPDHswo.mjs +27 -0
- package/dist/ClearFormattingPlugin.native-BZPDHswo.mjs.map +1 -0
- package/dist/CodePlugin.native-DD9xFIid.mjs +1679 -0
- package/dist/CodePlugin.native-DD9xFIid.mjs.map +1 -0
- package/dist/CodeSamplePlugin.native-DMbEdO9j.mjs +326 -0
- package/dist/CodeSamplePlugin.native-DMbEdO9j.mjs.map +1 -0
- package/dist/CommentsPlugin.native-2zQV8Ia4.mjs +473 -0
- package/dist/CommentsPlugin.native-2zQV8Ia4.mjs.map +1 -0
- package/dist/DirectionPlugin.native-Be7wCzkI.mjs +59 -0
- package/dist/DirectionPlugin.native-Be7wCzkI.mjs.map +1 -0
- package/dist/DocumentManagerPlugin.native-BvZL5CSG.mjs +116 -0
- package/dist/DocumentManagerPlugin.native-BvZL5CSG.mjs.map +1 -0
- package/dist/EmbedIframePlugin.native-ifr9KLdN.mjs +461 -0
- package/dist/EmbedIframePlugin.native-ifr9KLdN.mjs.map +1 -0
- package/dist/EmojisPlugin.native-D6mJSnSR.mjs +1033 -0
- package/dist/EmojisPlugin.native-D6mJSnSR.mjs.map +1 -0
- package/dist/FontFamilyPlugin.native-BzS_9qbM.mjs +106 -0
- package/dist/FontFamilyPlugin.native-BzS_9qbM.mjs.map +1 -0
- package/dist/FontSizePlugin.native-DkLMLPue.mjs +186 -0
- package/dist/FontSizePlugin.native-DkLMLPue.mjs.map +1 -0
- package/dist/FootnotePlugin.native-BciVc9W6.mjs +128 -0
- package/dist/FootnotePlugin.native-BciVc9W6.mjs.map +1 -0
- package/dist/FullscreenPlugin.native-ChXyxeNw.mjs +77 -0
- package/dist/FullscreenPlugin.native-ChXyxeNw.mjs.map +1 -0
- package/dist/HeadingPlugin.native-DrLYwQnQ.mjs +64 -0
- package/dist/HeadingPlugin.native-DrLYwQnQ.mjs.map +1 -0
- package/dist/HistoryPlugin.native-DoDRifCf.mjs +89 -0
- package/dist/HistoryPlugin.native-DoDRifCf.mjs.map +1 -0
- package/dist/IndentPlugin.native-CbFugPoi.mjs +133 -0
- package/dist/IndentPlugin.native-CbFugPoi.mjs.map +1 -0
- package/dist/ItalicPlugin.native-CQjjDyUL.mjs +43 -0
- package/dist/ItalicPlugin.native-CQjjDyUL.mjs.map +1 -0
- package/dist/LineHeightPlugin.native-CWQT2FIa.mjs +73 -0
- package/dist/LineHeightPlugin.native-CWQT2FIa.mjs.map +1 -0
- package/dist/LinkPlugin.native-BdAOV-iu.mjs +206 -0
- package/dist/LinkPlugin.native-BdAOV-iu.mjs.map +1 -0
- package/dist/ListPlugin.native-CLFU5AUQ.mjs +59 -0
- package/dist/ListPlugin.native-CLFU5AUQ.mjs.map +1 -0
- package/dist/MathPlugin.native-DE_ii-LA.mjs +182 -0
- package/dist/MathPlugin.native-DE_ii-LA.mjs.map +1 -0
- package/dist/MediaManagerPlugin.native-DaYFDzNM.mjs +533 -0
- package/dist/MediaManagerPlugin.native-DaYFDzNM.mjs.map +1 -0
- package/dist/MergeTagPlugin.native-CrxyThyn.mjs +178 -0
- package/dist/MergeTagPlugin.native-CrxyThyn.mjs.map +1 -0
- package/dist/PageBreakPlugin.native-DDjcDyRW.mjs +172 -0
- package/dist/PageBreakPlugin.native-DDjcDyRW.mjs.map +1 -0
- package/dist/PreviewPlugin.native-DBvfpmIv.mjs +322 -0
- package/dist/PreviewPlugin.native-DBvfpmIv.mjs.map +1 -0
- package/dist/PrintPlugin.native-BUpm52VJ.mjs +311 -0
- package/dist/PrintPlugin.native-BUpm52VJ.mjs.map +1 -0
- package/dist/SpecialCharactersPlugin.native-x7a2SWXc.mjs +731 -0
- package/dist/SpecialCharactersPlugin.native-x7a2SWXc.mjs.map +1 -0
- package/dist/SpellCheckPlugin.native-B7yTh0iE.mjs +465 -0
- package/dist/SpellCheckPlugin.native-B7yTh0iE.mjs.map +1 -0
- package/dist/StrikethroughPlugin.native-ChaZLaXw.mjs +43 -0
- package/dist/StrikethroughPlugin.native-ChaZLaXw.mjs.map +1 -0
- package/dist/TablePlugin.native-EEWXn1-s.mjs +491 -0
- package/dist/TablePlugin.native-EEWXn1-s.mjs.map +1 -0
- package/dist/TemplatePlugin.native-BlSn1c9h.mjs +564 -0
- package/dist/TemplatePlugin.native-BlSn1c9h.mjs.map +1 -0
- package/dist/TextAlignmentPlugin.native-CQIs1m7R.mjs +97 -0
- package/dist/TextAlignmentPlugin.native-CQIs1m7R.mjs.map +1 -0
- package/dist/TextColorPlugin.native-D6SmTglm.mjs +432 -0
- package/dist/TextColorPlugin.native-D6SmTglm.mjs.map +1 -0
- package/dist/UnderlinePlugin.native-QpIcK4L2.mjs +35 -0
- package/dist/UnderlinePlugin.native-QpIcK4L2.mjs.map +1 -0
- package/dist/core.css +1 -0
- package/dist/documentManager-irzj9n3V.mjs +37627 -0
- package/dist/documentManager-irzj9n3V.mjs.map +1 -0
- package/dist/editorContainerHelpers-C7kdWnS0.mjs +27 -0
- package/dist/editorContainerHelpers-C7kdWnS0.mjs.map +1 -0
- package/dist/editora.min.js +519 -4
- package/dist/editora.min.js.map +1 -0
- package/dist/editora.umd.js +519 -4
- package/dist/editora.umd.js.map +1 -0
- package/dist/index-BF5RBhL9.js +4 -0
- package/dist/index-BF5RBhL9.js.map +1 -0
- package/dist/index-BPsf460l.mjs +1243 -0
- package/dist/index-BPsf460l.mjs.map +1 -0
- package/dist/index.cjs.js +517 -4
- package/dist/index.cjs.js.map +1 -0
- package/dist/index.es-CuicffkQ.mjs +6665 -0
- package/dist/index.es-CuicffkQ.mjs.map +1 -0
- package/dist/index.esm.js +1403 -122
- package/dist/index.esm.js.map +1 -0
- package/dist/plugin-loader.js +55 -0
- package/dist/plugin-loader.js.map +1 -0
- package/dist/purify.es-CKpwg8Tk.mjs +471 -0
- package/dist/purify.es-CKpwg8Tk.mjs.map +1 -0
- package/dist/webcomponent-core.js +1243 -0
- package/dist/webcomponent-core.js.map +1 -0
- package/dist/webcomponent-core.min.css +1 -0
- package/dist/webcomponent-core.min.js +597 -0
- package/dist/webcomponent-core.min.js.map +1 -0
- package/dist/webcomponent.cjs.js +2 -0
- package/dist/webcomponent.cjs.js.map +1 -0
- package/dist/webcomponent.esm.js +6 -0
- package/dist/webcomponent.esm.js.map +1 -0
- package/dist/webcomponent.js +1286 -0
- package/dist/webcomponent.js.map +1 -0
- package/dist/webcomponent.min.css +1 -0
- package/dist/webcomponent.min.js +4076 -0
- package/dist/webcomponent.min.js.map +1 -0
- package/package.json +64 -6
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SpecialCharactersPlugin.native-x7a2SWXc.mjs","sources":["../../plugins/special-characters/src/SpecialCharactersPlugin.native.ts"],"sourcesContent":["import type { Plugin } from '@editora/core';\n\n/**\n * SpecialCharactersPlugin - Native implementation\n * \n * Features:\n * - Dialog with 8 categorized tabs (All, Currency, Text, Quotation, Mathematical, Extended Latin, Symbols, Arrows)\n * - Search/filter characters by name or symbol\n * - Grid display with hover effects\n * - Click to insert at cursor\n * - Responsive design\n * - Complete character sets with descriptions\n */\n\ntype CharacterCategory =\n | \"all\"\n | \"currency\"\n | \"text\"\n | \"quotation\"\n | \"mathematical\"\n | \"extended-latin\"\n | \"symbols\"\n | \"arrows\";\n\nconst characterSets: Record<\n CharacterCategory,\n { name: string; characters: string[] }\n> = {\n all: {\n name: \"All\",\n characters: [\n \"€\", \"£\", \"¥\", \"¢\", \"₹\", \"₽\", \"₩\", \"₿\", \"₺\", \"₴\", \"₦\", \"₨\", \"₪\", \"₫\", \"₭\", \"₮\", \"₯\", \"₰\", \"₱\", \"₲\", \"₳\", \"₴\", \"₵\", \"₶\", \"₷\", \"₹\", \"₺\", \"₼\", \"₽\", \"₾\", \"₿\",\n '\"', \"'\", \"«\", \"»\", \"„\", \"‟\", \"‹\", \"›\", \"‚\", \"‛\", \"〝\", \"〞\", \"〟\", \"‟\", \"„\",\n \"©\", \"®\", \"™\", \"°\", \"§\", \"¶\", \"†\", \"‡\", \"•\", \"‣\", \"⁃\", \"‰\", \"‱\", \"′\", \"″\", \"‴\", \"‵\", \"‶\", \"‷\", \"※\", \"‼\", \"‽\", \"‾\", \"‿\", \"⁀\", \"⁁\", \"⁂\", \"⁃\", \"⁇\", \"⁈\", \"⁉\",\n \"+\", \"-\", \"×\", \"÷\", \"=\", \"≠\", \"≈\", \"≡\", \"≤\", \"≥\", \"<\", \">\", \"±\", \"∓\", \"∴\", \"∵\", \"∶\", \"∷\", \"∸\", \"∹\", \"∺\", \"∻\", \"∼\", \"∽\", \"∾\", \"∿\", \"≀\", \"≁\", \"≂\", \"≃\", \"≄\", \"≅\", \"≆\", \"≇\", \"≈\", \"≉\", \"≊\", \"≋\", \"≌\", \"≍\", \"≎\", \"≏\", \"≐\", \"≑\", \"≒\", \"≓\", \"≔\", \"≕\", \"≖\", \"≗\", \"≘\", \"≙\", \"≚\", \"≛\", \"≜\", \"≝\", \"≞\", \"≟\", \"≠\", \"≡\", \"≢\", \"≣\", \"≤\", \"≥\", \"≦\", \"≧\", \"≨\", \"≩\", \"≪\", \"≫\", \"≬\", \"≭\", \"≮\", \"≯\", \"≰\", \"≱\", \"≲\", \"≳\", \"≴\", \"≵\", \"≶\", \"≷\", \"≸\", \"≹\", \"≺\", \"≻\", \"≼\", \"≽\", \"≾\", \"≿\",\n \"À\", \"Á\", \"Â\", \"Ã\", \"Ä\", \"Å\", \"Æ\", \"Ç\", \"È\", \"É\", \"Ê\", \"Ë\", \"Ì\", \"Í\", \"Î\", \"Ï\", \"Ð\", \"Ñ\", \"Ò\", \"Ó\", \"Ô\", \"Õ\", \"Ö\", \"×\", \"Ø\", \"Ù\", \"Ú\", \"Û\", \"Ü\", \"Ý\", \"Þ\", \"ß\", \"à\", \"á\", \"â\", \"ã\", \"ä\", \"å\", \"æ\", \"ç\", \"è\", \"é\", \"ê\", \"ë\", \"ì\", \"í\", \"î\", \"ï\", \"ð\", \"ñ\", \"ò\", \"ó\", \"ô\", \"õ\", \"ö\", \"÷\", \"ø\", \"ù\", \"ú\", \"û\", \"ü\", \"ý\", \"þ\", \"ÿ\",\n \"¡\", \"¿\", \"‽\", \"‼\", \"⁇\", \"⁈\", \"⁉\", \"※\", \"‾\", \"‿\", \"⁀\", \"⁁\", \"⁂\", \"⁃\",\n \"←\", \"↑\", \"→\", \"↓\", \"↔\", \"↕\", \"↖\", \"↗\", \"↘\", \"↙\", \"↚\", \"↛\", \"↜\", \"↝\", \"↞\", \"↟\", \"↠\", \"↡\", \"↢\", \"↣\", \"↤\", \"↥\", \"↦\", \"↧\", \"↨\", \"↩\", \"↪\", \"↫\", \"↬\", \"↭\", \"↮\", \"↯\", \"↰\", \"↱\", \"↲\", \"↳\", \"↴\", \"↵\", \"↶\", \"↷\", \"↸\", \"↹\", \"↺\", \"↻\", \"↼\", \"↽\", \"↾\", \"↿\", \"⇀\", \"⇁\", \"⇂\", \"⇃\", \"⇄\", \"⇅\", \"⇆\", \"⇇\", \"⇈\", \"⇉\", \"⇊\", \"⇋\", \"⇌\", \"⇍\", \"⇎\", \"⇏\", \"⇐\", \"⇑\", \"⇒\", \"⇓\", \"⇔\", \"⇕\", \"⇖\", \"⇗\", \"⇘\", \"⇙\", \"⇚\", \"⇛\", \"⇜\", \"⇝\", \"⇞\", \"⇟\", \"⇠\", \"⇡\", \"⇢\", \"⇣\", \"⇤\", \"⇥\", \"⇦\", \"⇧\", \"⇨\", \"⇩\", \"⇪\", \"⇫\", \"⇬\", \"⇭\", \"⇮\", \"⇯\", \"⇰\", \"⇱\", \"⇲\", \"⇳\", \"⇴\", \"⇵\", \"⇶\", \"⇷\", \"⇸\", \"⇹\", \"⇺\", \"⇻\", \"⇼\", \"⇽\", \"⇾\", \"⇿\",\n ],\n },\n currency: {\n name: \"Currency\",\n characters: [\"€\", \"£\", \"¥\", \"¢\", \"₹\", \"₽\", \"₩\", \"₿\", \"₺\", \"₴\", \"₦\", \"₨\", \"₪\", \"₫\", \"₭\", \"₮\", \"₯\", \"₰\", \"₱\", \"₲\", \"₳\", \"₵\", \"₶\", \"₷\", \"₼\", \"₾\", \"₿\"],\n },\n text: {\n name: \"Text\",\n characters: [\"©\", \"®\", \"™\", \"°\", \"§\", \"¶\", \"†\", \"‡\", \"•\", \"‣\", \"⁃\", \"‰\", \"‱\", \"′\", \"″\", \"‴\", \"‵\", \"‶\", \"‷\", \"※\", \"‼\", \"‽\", \"‾\", \"‿\", \"⁀\", \"⁁\", \"⁂\"],\n },\n quotation: {\n name: \"Quotation\",\n characters: ['\"', \"'\", \"«\", \"»\", \"„\", \"‟\", \"‹\", \"›\", \"‚\", \"‛\", \"〝\", \"〞\", \"〟\"],\n },\n mathematical: {\n name: \"Mathematical\",\n characters: [\"+\", \"-\", \"×\", \"÷\", \"=\", \"≠\", \"≈\", \"≡\", \"≤\", \"≥\", \"<\", \">\", \"±\", \"∓\", \"∴\", \"∵\", \"∶\", \"∷\", \"∸\", \"∹\", \"∺\", \"∻\", \"∼\", \"∽\", \"∾\", \"∿\", \"≀\", \"≁\", \"≂\", \"≃\", \"≄\", \"≅\", \"≆\", \"≇\", \"≉\", \"≊\", \"≋\", \"≌\", \"≍\", \"≎\", \"≏\", \"≐\", \"≑\", \"≒\", \"≓\", \"≔\", \"≕\", \"≖\", \"≗\", \"≘\", \"≙\", \"≚\", \"≛\", \"≜\", \"≝\", \"≞\", \"≟\", \"≢\", \"≣\", \"≦\", \"≧\", \"≨\", \"≩\", \"≪\", \"≫\", \"≬\", \"≭\", \"≮\", \"≯\", \"≰\", \"≱\", \"≲\", \"≳\", \"≴\", \"≵\", \"≶\", \"≷\", \"≸\", \"≹\", \"≺\", \"≻\", \"≼\", \"≽\", \"≾\", \"≿\"],\n },\n \"extended-latin\": {\n name: \"Extended Latin\",\n characters: [\"À\", \"Á\", \"Â\", \"Ã\", \"Ä\", \"Å\", \"Æ\", \"Ç\", \"È\", \"É\", \"Ê\", \"Ë\", \"Ì\", \"Í\", \"Î\", \"Ï\", \"Ð\", \"Ñ\", \"Ò\", \"Ó\", \"Ô\", \"Õ\", \"Ö\", \"×\", \"Ø\", \"Ù\", \"Ú\", \"Û\", \"Ü\", \"Ý\", \"Þ\", \"ß\", \"à\", \"á\", \"â\", \"ã\", \"ä\", \"å\", \"æ\", \"ç\", \"è\", \"é\", \"ê\", \"ë\", \"ì\", \"í\", \"î\", \"ï\", \"ð\", \"ñ\", \"ò\", \"ó\", \"ô\", \"õ\", \"ö\", \"÷\", \"ø\", \"ù\", \"ú\", \"û\", \"ü\", \"ý\", \"þ\", \"ÿ\"],\n },\n symbols: {\n name: \"Symbols\",\n characters: [\"¡\", \"¿\", \"‽\", \"‼\", \"⁇\", \"⁈\", \"⁉\", \"※\", \"‾\", \"‿\", \"⁀\", \"⁁\", \"⁂\", \"⁃\"],\n },\n arrows: {\n name: \"Arrows\",\n characters: [\"←\", \"↑\", \"→\", \"↓\", \"↔\", \"↕\", \"↖\", \"↗\", \"↘\", \"↙\", \"↚\", \"↛\", \"↜\", \"↝\", \"↞\", \"↟\", \"↠\", \"↡\", \"↢\", \"↣\", \"↤\", \"↥\", \"↦\", \"↧\", \"↨\", \"↩\", \"↪\", \"↫\", \"↬\", \"↭\", \"↮\", \"↯\", \"↰\", \"↱\", \"↲\", \"↳\", \"↴\", \"↵\", \"↶\", \"↷\", \"↸\", \"↹\", \"↺\", \"↻\", \"↼\", \"↽\", \"↾\", \"↿\", \"⇀\", \"⇁\", \"⇂\", \"⇃\", \"⇄\", \"⇅\", \"⇆\", \"⇇\", \"⇈\", \"⇉\", \"⇊\", \"⇋\", \"⇌\", \"⇍\", \"⇎\", \"⇏\", \"⇐\", \"⇑\", \"⇒\", \"⇓\", \"⇔\", \"⇕\", \"⇖\", \"⇗\", \"⇘\", \"⇙\", \"⇚\", \"⇛\", \"⇜\", \"⇝\", \"⇞\", \"⇟\", \"⇠\", \"⇡\", \"⇢\", \"⇣\", \"⇤\", \"⇥\", \"⇦\", \"⇧\", \"⇨\", \"⇩\", \"⇪\", \"⇫\", \"⇬\", \"⇭\", \"⇮\", \"⇯\", \"⇰\", \"⇱\", \"⇲\", \"⇳\", \"⇴\", \"⇵\", \"⇶\", \"⇷\", \"⇸\", \"⇹\", \"⇺\", \"⇻\", \"⇼\", \"⇽\", \"⇾\", \"⇿\"],\n },\n};\n\nconst descriptions: Record<string, string> = {\n \"€\": \"euro\", \"£\": \"pound\", \"¥\": \"yen\", \"¢\": \"cent\", \"₹\": \"rupee\", \"₽\": \"ruble\", \"₩\": \"won\", \"₿\": \"bitcoin\",\n '\"': \"quote\", \"'\": \"apostrophe\", \"«\": \"left angle quote\", \"»\": \"right angle quote\", \"„\": \"low quote\",\n \"©\": \"copyright\", \"®\": \"registered\", \"™\": \"trademark\", \"°\": \"degree\", \"§\": \"section\", \"¶\": \"paragraph\",\n \"†\": \"dagger\", \"‡\": \"double dagger\", \"•\": \"bullet\", \"‰\": \"per mille\", \"′\": \"prime\", \"″\": \"double prime\",\n \"+\": \"plus\", \"-\": \"minus\", \"×\": \"multiplication\", \"÷\": \"division\", \"=\": \"equals\", \"≠\": \"not equal\",\n \"≈\": \"approximately\", \"≡\": \"identical\", \"≤\": \"less or equal\", \"≥\": \"greater or equal\", \"±\": \"plus minus\",\n \"À\": \"a grave\", \"Á\": \"a acute\", \"Â\": \"a circumflex\", \"Ã\": \"a tilde\", \"Ä\": \"a diaeresis\", \"Ç\": \"c cedilla\",\n \"←\": \"left arrow\", \"↑\": \"up arrow\", \"→\": \"right arrow\", \"↓\": \"down arrow\", \"↔\": \"left right arrow\",\n};\n\n// Module-level flag\nlet isDialogOpen = false;\n\n/**\n * Inject dialog styles into document head\n */\nconst injectStyles = (): void => {\n if (typeof document === 'undefined') return;\n const styleId = 'special-characters-plugin-styles';\n if (document.getElementById(styleId)) return;\n \n const style = document.createElement('style');\n style.id = styleId;\n style.textContent = `\n .special-characters-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background-color: rgba(0, 0, 0, 0.5);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10000;\n }\n\n .special-characters-dialog {\n background: white;\n border-radius: 8px;\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);\n max-width: 800px;\n width: 90%;\n max-height: 80vh;\n display: flex;\n flex-direction: column;\n }\n\n .special-characters-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 16px 20px;\n border-bottom: 1px solid #e1e5e9;\n }\n\n .special-characters-header h2 {\n margin: 0;\n font-size: 18px;\n font-weight: 600;\n color: #1a202c;\n }\n\n .special-characters-close {\n background: none;\n border: none;\n font-size: 24px;\n cursor: pointer;\n color: #718096;\n padding: 0;\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 4px;\n }\n\n .special-characters-close:hover {\n background-color: #f7fafc;\n color: #2d3748;\n }\n\n .special-characters-content {\n display: flex;\n flex: 1;\n overflow: hidden;\n }\n\n .special-characters-main-content {\n flex: 1;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n\n .special-characters-search {\n padding: 16px 16px 0 16px;\n }\n\n .special-characters-search-input {\n width: 100%;\n padding: 10px 12px;\n border: 1px solid #e1e5e9;\n border-radius: 6px;\n font-size: 14px;\n color: #2d3748;\n background-color: #ffffff;\n transition: border-color 0.2s ease, box-shadow 0.2s ease;\n box-sizing: border-box;\n }\n\n .special-characters-search-input:focus {\n outline: none;\n border-color: #4299e1;\n box-shadow: 0 0 0 3px rgba(66, 153, 225, 0.1);\n }\n\n .special-characters-tabs {\n display: flex;\n flex-direction: column;\n width: 180px;\n border-right: 1px solid #e1e5e9;\n background-color: #f8fafc;\n }\n\n .special-characters-tab {\n padding: 12px 16px;\n border: none;\n background: none;\n text-align: left;\n cursor: pointer;\n font-size: 14px;\n color: #4a5568;\n border-bottom: 1px solid #e1e5e9;\n transition: all 0.2s ease;\n }\n\n .special-characters-tab:hover {\n background-color: #edf2f7;\n color: #2d3748;\n }\n\n .special-characters-tab.active {\n background-color: #4299e1;\n color: white;\n font-weight: 500;\n }\n\n .special-characters-grid {\n padding: 16px;\n overflow-y: auto;\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(40px, 1fr));\n gap: 8px;\n }\n\n .special-characters-item {\n width: 40px;\n height: 40px;\n display: flex;\n align-items: center;\n justify-content: center;\n border: 1px solid #e1e5e9;\n background: white;\n border-radius: 4px;\n cursor: pointer;\n font-size: 18px;\n transition: all 0.2s ease;\n color: #2d3748;\n }\n\n .special-characters-item:hover {\n background-color: #4299e1;\n border-color: #4299e1;\n color: white;\n transform: scale(1.05);\n }\n\n .special-characters-item:active {\n transform: scale(0.95);\n }\n\n .special-characters-no-results {\n grid-column: 1 / -1;\n text-align: center;\n color: #718096;\n font-size: 14px;\n padding: 40px 20px;\n background-color: #f8fafc;\n border-radius: 6px;\n border: 1px solid #e1e5e9;\n }\n\n @media (max-width: 768px) {\n .special-characters-dialog {\n width: 95%;\n max-height: 90vh;\n }\n\n .special-characters-content {\n flex-direction: column;\n }\n\n .special-characters-tabs {\n width: 100%;\n border-right: none;\n border-bottom: 1px solid #e1e5e9;\n flex-direction: row;\n overflow-x: auto;\n }\n\n .special-characters-tab {\n border-bottom: none;\n border-right: 1px solid #e1e5e9;\n white-space: nowrap;\n }\n }\n `;\n \n document.head.appendChild(style);\n};\n\n/**\n * Insert character at cursor position\n */\nconst insertCharacter = (character: string): void => {\n const selection = window.getSelection();\n if (selection && selection.rangeCount > 0) {\n const range = selection.getRangeAt(0);\n range.deleteContents();\n const textNode = document.createTextNode(character);\n range.insertNode(textNode);\n range.setStartAfter(textNode);\n range.setEndAfter(textNode);\n selection.removeAllRanges();\n selection.addRange(range);\n }\n};\n\n/**\n * Show special characters dialog\n */\nconst showSpecialCharactersDialog = (): void => {\n if (typeof window === 'undefined' || isDialogOpen) return;\n \n isDialogOpen = true;\n injectStyles();\n\n let activeTab: CharacterCategory = 'all';\n let searchQuery = '';\n\n // Create overlay\n const overlay = document.createElement('div');\n overlay.className = 'special-characters-overlay';\n\n // Create dialog\n const dialog = document.createElement('div');\n dialog.className = 'special-characters-dialog';\n\n // Render function\n const render = () => {\n // Filter characters\n const currentCharacters = characterSets[activeTab].characters.filter(char => {\n if (!searchQuery.trim()) return true;\n const query = searchQuery.toLowerCase();\n return char.toLowerCase().includes(query) || \n (descriptions[char] || '').toLowerCase().includes(query);\n });\n\n dialog.innerHTML = `\n <div class=\"special-characters-header\">\n <h2>Insert Special Characters</h2>\n <button class=\"special-characters-close\">×</button>\n </div>\n <div class=\"special-characters-content\">\n <div class=\"special-characters-tabs\">\n ${(Object.keys(characterSets) as CharacterCategory[]).map(category => `\n <button class=\"special-characters-tab ${activeTab === category ? 'active' : ''}\" data-category=\"${category}\">\n ${characterSets[category].name}\n </button>\n `).join('')}\n </div>\n <div class=\"special-characters-main-content\">\n <div class=\"special-characters-search\">\n <input type=\"text\" placeholder=\"Search characters...\" value=\"${searchQuery}\" class=\"special-characters-search-input\">\n </div>\n <div class=\"special-characters-grid\">\n ${currentCharacters.length > 0 \n ? currentCharacters.map(char => `\n <button class=\"special-characters-item\" data-char=\"${char}\" title=\"${descriptions[char] || char}\">\n ${char}\n </button>\n `).join('')\n : `<div class=\"special-characters-no-results\">No characters found for \"${searchQuery}\"</div>`\n }\n </div>\n </div>\n </div>\n `;\n\n // Event listeners\n const closeBtn = dialog.querySelector('.special-characters-close');\n closeBtn?.addEventListener('click', closeDialog);\n\n // Tab switching\n dialog.querySelectorAll('.special-characters-tab').forEach(tab => {\n tab.addEventListener('click', (e) => {\n const category = (e.target as HTMLElement).getAttribute('data-category') as CharacterCategory;\n if (category) {\n activeTab = category;\n render();\n }\n });\n });\n\n // Search\n const searchInput = dialog.querySelector('.special-characters-search-input') as HTMLInputElement;\n searchInput?.addEventListener('input', (e) => {\n searchQuery = (e.target as HTMLInputElement).value;\n render();\n });\n\n // Character insertion\n dialog.querySelectorAll('.special-characters-item').forEach(item => {\n item.addEventListener('click', (e) => {\n const char = (e.target as HTMLElement).getAttribute('data-char');\n if (char) {\n insertCharacter(char);\n closeDialog();\n }\n });\n });\n };\n\n const closeDialog = () => {\n if (overlay.parentNode) {\n overlay.parentNode.removeChild(overlay);\n }\n isDialogOpen = false;\n document.removeEventListener('keydown', handleEscape);\n };\n\n const handleEscape = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n e.preventDefault();\n e.stopPropagation();\n closeDialog();\n }\n };\n\n // Overlay click\n overlay.addEventListener('click', (e) => {\n if (e.target === overlay) {\n closeDialog();\n }\n });\n\n document.addEventListener('keydown', handleEscape);\n\n // Initial render\n render();\n overlay.appendChild(dialog);\n document.body.appendChild(overlay);\n};\n\nexport const SpecialCharactersPlugin = (): Plugin => ({\n name: 'specialCharacters',\n \n toolbar: [{\n label: 'Special Characters',\n command: 'insertSpecialCharacter',\n icon: '<svg width=\"24\" height=\"24\" focusable=\"false\"><path d=\"M15 18h4l1-2v4h-6v-3.3l1.4-1a6 6 0 0 0 1.8-2.9 6.3 6.3 0 0 0-.1-4.1 5.8 5.8 0 0 0-3-3.2c-.6-.3-1.3-.5-2.1-.5a5.1 5.1 0 0 0-3.9 1.8 6.3 6.3 0 0 0-1.3 6 6.2 6.2 0 0 0 1.8 3l1.4.9V20H4v-4l1 2h4v-.5l-2-1L5.4 15A6.5 6.5 0 0 1 4 11c0-1 .2-1.9.6-2.7A7 7 0 0 1 6.3 6C7.1 5.4 8 5 9 4.5c1-.3 2-.5 3.1-.5a8.8 8.8 0 0 1 5.7 2 7 7 0 0 1 1.7 2.3 6 6 0 0 1 .2 4.8c-.2.7-.6 1.3-1 1.9a7.6 7.6 0 0 1-3.6 2.5v.5Z\" fill-rule=\"evenodd\"></path></svg>'\n }],\n \n commands: {\n insertSpecialCharacter: () => {\n showSpecialCharactersDialog();\n return true;\n }\n },\n \n keymap: {}\n});\n"],"names":["characterSets","descriptions","isDialogOpen","injectStyles","styleId","style","insertCharacter","character","selection","range","textNode","showSpecialCharactersDialog","activeTab","searchQuery","overlay","dialog","render","currentCharacters","char","query","category","closeBtn","closeDialog","tab","e","searchInput","item","handleEscape","SpecialCharactersPlugin"],"mappings":"AAwBA,MAAMA,IAGF;AAAA,EACF,KAAK;AAAA,IACH,MAAM;AAAA,IACN,YAAY;AAAA,MACV;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MACtJ;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MACtE;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MACtJ;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAC7b;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAC3T;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MACjE;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AAAA,MAAK;AA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"}
|
|
@@ -0,0 +1,465 @@
|
|
|
1
|
+
const A = /* @__PURE__ */ new Set([
|
|
2
|
+
"the",
|
|
3
|
+
"a",
|
|
4
|
+
"an",
|
|
5
|
+
"and",
|
|
6
|
+
"or",
|
|
7
|
+
"but",
|
|
8
|
+
"in",
|
|
9
|
+
"on",
|
|
10
|
+
"at",
|
|
11
|
+
"to",
|
|
12
|
+
"for",
|
|
13
|
+
"of",
|
|
14
|
+
"with",
|
|
15
|
+
"by",
|
|
16
|
+
"from",
|
|
17
|
+
"is",
|
|
18
|
+
"are",
|
|
19
|
+
"be",
|
|
20
|
+
"was",
|
|
21
|
+
"were",
|
|
22
|
+
"have",
|
|
23
|
+
"has",
|
|
24
|
+
"had",
|
|
25
|
+
"do",
|
|
26
|
+
"does",
|
|
27
|
+
"did",
|
|
28
|
+
"will",
|
|
29
|
+
"would",
|
|
30
|
+
"could",
|
|
31
|
+
"should",
|
|
32
|
+
"may",
|
|
33
|
+
"might",
|
|
34
|
+
"must",
|
|
35
|
+
"can",
|
|
36
|
+
"this",
|
|
37
|
+
"that",
|
|
38
|
+
"these",
|
|
39
|
+
"those",
|
|
40
|
+
"what",
|
|
41
|
+
"which",
|
|
42
|
+
"who",
|
|
43
|
+
"whom",
|
|
44
|
+
"where",
|
|
45
|
+
"when",
|
|
46
|
+
"why",
|
|
47
|
+
"how",
|
|
48
|
+
"all",
|
|
49
|
+
"each",
|
|
50
|
+
"every",
|
|
51
|
+
"both",
|
|
52
|
+
"few",
|
|
53
|
+
"more",
|
|
54
|
+
"most",
|
|
55
|
+
"other",
|
|
56
|
+
"same",
|
|
57
|
+
"such",
|
|
58
|
+
"no",
|
|
59
|
+
"nor",
|
|
60
|
+
"not",
|
|
61
|
+
"only",
|
|
62
|
+
"own",
|
|
63
|
+
"so",
|
|
64
|
+
"than",
|
|
65
|
+
"too",
|
|
66
|
+
"very",
|
|
67
|
+
"just",
|
|
68
|
+
"as",
|
|
69
|
+
"if",
|
|
70
|
+
"because",
|
|
71
|
+
"while",
|
|
72
|
+
"although",
|
|
73
|
+
"though",
|
|
74
|
+
"it",
|
|
75
|
+
"its",
|
|
76
|
+
"their",
|
|
77
|
+
"them",
|
|
78
|
+
"they",
|
|
79
|
+
"you",
|
|
80
|
+
"he",
|
|
81
|
+
"she",
|
|
82
|
+
"we",
|
|
83
|
+
"me",
|
|
84
|
+
"him",
|
|
85
|
+
"her",
|
|
86
|
+
"us",
|
|
87
|
+
"our",
|
|
88
|
+
"i",
|
|
89
|
+
"my",
|
|
90
|
+
"your",
|
|
91
|
+
"his",
|
|
92
|
+
"hers",
|
|
93
|
+
"ours",
|
|
94
|
+
"yours",
|
|
95
|
+
"theirs",
|
|
96
|
+
"editor",
|
|
97
|
+
"document",
|
|
98
|
+
"text",
|
|
99
|
+
"word",
|
|
100
|
+
"paragraph",
|
|
101
|
+
"line",
|
|
102
|
+
"page",
|
|
103
|
+
"content",
|
|
104
|
+
"hello",
|
|
105
|
+
"world",
|
|
106
|
+
"test",
|
|
107
|
+
"example",
|
|
108
|
+
"sample",
|
|
109
|
+
"demo",
|
|
110
|
+
"lorem",
|
|
111
|
+
"ipsum"
|
|
112
|
+
]), x = /* @__PURE__ */ new Set(), y = /* @__PURE__ */ new Set();
|
|
113
|
+
let f = !1, p = null, g = null, l = null;
|
|
114
|
+
const D = () => {
|
|
115
|
+
try {
|
|
116
|
+
const t = localStorage.getItem("rte-custom-dictionary");
|
|
117
|
+
t && JSON.parse(t).forEach((e) => x.add(e.toLowerCase()));
|
|
118
|
+
} catch (t) {
|
|
119
|
+
console.warn("Failed to load custom dictionary:", t);
|
|
120
|
+
}
|
|
121
|
+
}, F = () => {
|
|
122
|
+
try {
|
|
123
|
+
const t = Array.from(x);
|
|
124
|
+
localStorage.setItem("rte-custom-dictionary", JSON.stringify(t));
|
|
125
|
+
} catch (t) {
|
|
126
|
+
console.warn("Failed to save custom dictionary:", t);
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
function $(t, r) {
|
|
130
|
+
const e = [];
|
|
131
|
+
for (let o = 0; o <= r.length; o++) e[o] = [o];
|
|
132
|
+
for (let o = 0; o <= t.length; o++) e[0][o] = o;
|
|
133
|
+
for (let o = 1; o <= r.length; o++)
|
|
134
|
+
for (let s = 1; s <= t.length; s++)
|
|
135
|
+
r.charAt(o - 1) === t.charAt(s - 1) ? e[o][s] = e[o - 1][s - 1] : e[o][s] = Math.min(
|
|
136
|
+
e[o - 1][s - 1] + 1,
|
|
137
|
+
// substitution
|
|
138
|
+
e[o][s - 1] + 1,
|
|
139
|
+
// insertion
|
|
140
|
+
e[o - 1][s] + 1
|
|
141
|
+
// deletion
|
|
142
|
+
);
|
|
143
|
+
return e[r.length][t.length];
|
|
144
|
+
}
|
|
145
|
+
function I(t) {
|
|
146
|
+
const r = t.toLowerCase();
|
|
147
|
+
return A.has(r) || x.has(r) || y.has(r);
|
|
148
|
+
}
|
|
149
|
+
function R(t, r = 5) {
|
|
150
|
+
const e = t.toLowerCase(), s = Array.from(A).map((n) => ({ word: n, distance: $(e, n) }));
|
|
151
|
+
return s.sort((n, i) => n.distance - i.distance), s.filter((n) => n.distance <= 3).slice(0, r).map((n) => n.word);
|
|
152
|
+
}
|
|
153
|
+
function j(t) {
|
|
154
|
+
if (t.nodeType !== Node.ELEMENT_NODE) return !1;
|
|
155
|
+
const r = t;
|
|
156
|
+
return !!(r.closest('code, pre, [contenteditable="false"], .rte-widget, .rte-template, .rte-comment, .rte-merge-tag') || r.hasAttribute("data-comment-id") || r.hasAttribute("data-template") || r.hasAttribute("data-merge-tag"));
|
|
157
|
+
}
|
|
158
|
+
function q(t) {
|
|
159
|
+
const r = [], e = /([\p{L}\p{M}\p{N}\p{Emoji_Presentation}\u200d'-]+|[\uD800-\uDBFF][\uDC00-\uDFFF])/gu;
|
|
160
|
+
let o;
|
|
161
|
+
for (; (o = e.exec(t.data)) !== null; ) {
|
|
162
|
+
const s = o[0], n = o.index, i = n + s.length;
|
|
163
|
+
/https?:\/\//.test(s) || /@/.test(s) || /\{\{.*\}\}/.test(s) || /^\d+$/.test(s) || I(s) || /[a-z][A-Z]/.test(s) || /-/.test(s) || s[0] === s[0].toUpperCase() && s.length > 1 || r.push({
|
|
164
|
+
id: `${s}-${n}`,
|
|
165
|
+
node: t,
|
|
166
|
+
startOffset: n,
|
|
167
|
+
endOffset: i,
|
|
168
|
+
word: s,
|
|
169
|
+
suggestions: R(s),
|
|
170
|
+
ignored: !1
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
return r;
|
|
174
|
+
}
|
|
175
|
+
const b = () => {
|
|
176
|
+
const t = window.getSelection();
|
|
177
|
+
if (t && t.rangeCount > 0) {
|
|
178
|
+
let e = t.getRangeAt(0).startContainer;
|
|
179
|
+
for (; e && e !== document.body; ) {
|
|
180
|
+
if (e.nodeType === Node.ELEMENT_NODE) {
|
|
181
|
+
const o = e;
|
|
182
|
+
if (o.getAttribute("contenteditable") === "true")
|
|
183
|
+
return o;
|
|
184
|
+
}
|
|
185
|
+
e = e.parentNode;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
const r = document.activeElement;
|
|
189
|
+
if (r) {
|
|
190
|
+
if (r.getAttribute("contenteditable") === "true")
|
|
191
|
+
return r;
|
|
192
|
+
const e = r.closest('[contenteditable="true"]');
|
|
193
|
+
if (e) return e;
|
|
194
|
+
}
|
|
195
|
+
return document.querySelector('[contenteditable="true"]');
|
|
196
|
+
};
|
|
197
|
+
function v() {
|
|
198
|
+
const t = b();
|
|
199
|
+
if (!t) return [];
|
|
200
|
+
const r = [], e = document.createTreeWalker(
|
|
201
|
+
t,
|
|
202
|
+
NodeFilter.SHOW_TEXT,
|
|
203
|
+
{
|
|
204
|
+
acceptNode: (s) => {
|
|
205
|
+
var n;
|
|
206
|
+
return !((n = s.textContent) != null && n.trim()) || s.parentNode && j(s.parentNode) ? NodeFilter.FILTER_REJECT : NodeFilter.FILTER_ACCEPT;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
);
|
|
210
|
+
let o = e.nextNode();
|
|
211
|
+
for (; o; )
|
|
212
|
+
r.push(...q(o)), o = e.nextNode();
|
|
213
|
+
return r;
|
|
214
|
+
}
|
|
215
|
+
function w(t) {
|
|
216
|
+
const r = b();
|
|
217
|
+
r && (t || (t = v()), r.querySelectorAll(".rte-misspelled").forEach((e) => {
|
|
218
|
+
const o = e.parentNode;
|
|
219
|
+
if (o) {
|
|
220
|
+
for (; e.firstChild; )
|
|
221
|
+
o.insertBefore(e.firstChild, e);
|
|
222
|
+
o.removeChild(e);
|
|
223
|
+
}
|
|
224
|
+
}), t.forEach((e) => {
|
|
225
|
+
if (y.has(e.word.toLowerCase())) return;
|
|
226
|
+
const o = e.node.data.length;
|
|
227
|
+
if (!(e.startOffset < 0 || e.endOffset > o || e.startOffset >= e.endOffset))
|
|
228
|
+
try {
|
|
229
|
+
const s = document.createRange();
|
|
230
|
+
s.setStart(e.node, e.startOffset), s.setEnd(e.node, e.endOffset);
|
|
231
|
+
const n = document.createElement("span");
|
|
232
|
+
n.className = "rte-misspelled", n.setAttribute("data-word", e.word), n.setAttribute("data-suggestions", e.suggestions.join(",")), n.setAttribute("title", `Suggestions: ${e.suggestions.join(", ")}`), n.style.borderBottom = "2px wavy red", n.style.cursor = "pointer", s.surroundContents(n);
|
|
233
|
+
} catch (s) {
|
|
234
|
+
}
|
|
235
|
+
}), m());
|
|
236
|
+
}
|
|
237
|
+
function C() {
|
|
238
|
+
const t = document.querySelector('[contenteditable="true"]');
|
|
239
|
+
t && t.querySelectorAll(".rte-misspelled").forEach((r) => {
|
|
240
|
+
const e = r.parentNode;
|
|
241
|
+
if (e) {
|
|
242
|
+
for (; r.firstChild; )
|
|
243
|
+
e.insertBefore(r.firstChild, r);
|
|
244
|
+
e.removeChild(r);
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
function L(t, r) {
|
|
249
|
+
const e = document.createRange();
|
|
250
|
+
e.setStart(t.node, t.startOffset), e.setEnd(t.node, t.endOffset);
|
|
251
|
+
const o = document.createTextNode(r);
|
|
252
|
+
e.deleteContents(), e.insertNode(o);
|
|
253
|
+
}
|
|
254
|
+
function T(t) {
|
|
255
|
+
y.add(t.toLowerCase()), C(), w(), m();
|
|
256
|
+
}
|
|
257
|
+
function O(t) {
|
|
258
|
+
x.add(t.toLowerCase()), F(), C(), w(), m();
|
|
259
|
+
}
|
|
260
|
+
function _(t) {
|
|
261
|
+
const r = b();
|
|
262
|
+
if (!r) return { total: 0, misspelled: 0, accuracy: 100 };
|
|
263
|
+
t || (t = v());
|
|
264
|
+
const e = t.filter((i) => !y.has(i.word.toLowerCase())).length, n = ((r.textContent || "").match(/[\p{L}\p{M}\p{N}]+/gu) || []).length;
|
|
265
|
+
return {
|
|
266
|
+
total: n,
|
|
267
|
+
misspelled: e,
|
|
268
|
+
accuracy: n > 0 ? (n - e) / n * 100 : 100
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
function H(t, r, e, o, s) {
|
|
272
|
+
document.querySelectorAll(".rte-spellcheck-menu").forEach((a) => a.remove());
|
|
273
|
+
const n = document.createElement("div");
|
|
274
|
+
if (n.className = "rte-spellcheck-menu", n.style.cssText = `
|
|
275
|
+
position: fixed;
|
|
276
|
+
left: ${t}px;
|
|
277
|
+
top: ${r}px;
|
|
278
|
+
background: #fff;
|
|
279
|
+
border: 1px solid #ccc;
|
|
280
|
+
border-radius: 4px;
|
|
281
|
+
box-shadow: 0 2px 8px rgba(0,0,0,0.15);
|
|
282
|
+
z-index: 99999;
|
|
283
|
+
padding: 4px 0;
|
|
284
|
+
min-width: 160px;
|
|
285
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
|
286
|
+
font-size: 13px;
|
|
287
|
+
`, o.slice(0, 5).forEach((a) => {
|
|
288
|
+
const u = document.createElement("div");
|
|
289
|
+
u.className = "rte-spellcheck-menu-item", u.textContent = a, u.style.cssText = "padding: 6px 16px; cursor: pointer; transition: background 0.2s;", u.onmouseenter = () => u.style.backgroundColor = "#f0f0f0", u.onmouseleave = () => u.style.backgroundColor = "transparent", u.onclick = () => {
|
|
290
|
+
var S;
|
|
291
|
+
const E = s.parentNode;
|
|
292
|
+
if (E) {
|
|
293
|
+
for (const h of E.childNodes)
|
|
294
|
+
if (h.nodeType === Node.TEXT_NODE && ((S = h.textContent) != null && S.includes(e))) {
|
|
295
|
+
const N = h.textContent.indexOf(e), z = {
|
|
296
|
+
node: h,
|
|
297
|
+
startOffset: N,
|
|
298
|
+
endOffset: N + e.length
|
|
299
|
+
};
|
|
300
|
+
L(z, a);
|
|
301
|
+
break;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
n.remove();
|
|
305
|
+
}, n.appendChild(u);
|
|
306
|
+
}), o.length > 0) {
|
|
307
|
+
const a = document.createElement("div");
|
|
308
|
+
a.style.cssText = "height: 1px; background: #ddd; margin: 4px 0;", n.appendChild(a);
|
|
309
|
+
}
|
|
310
|
+
const i = document.createElement("div");
|
|
311
|
+
i.className = "rte-spellcheck-menu-item", i.textContent = "Ignore Once", i.style.cssText = "padding: 6px 16px; cursor: pointer; color: #666;", i.onmouseenter = () => i.style.backgroundColor = "#f0f0f0", i.onmouseleave = () => i.style.backgroundColor = "transparent", i.onclick = () => {
|
|
312
|
+
s.remove(), n.remove();
|
|
313
|
+
}, n.appendChild(i);
|
|
314
|
+
const d = document.createElement("div");
|
|
315
|
+
d.className = "rte-spellcheck-menu-item", d.textContent = "Ignore All", d.style.cssText = "padding: 6px 16px; cursor: pointer; color: #666;", d.onmouseenter = () => d.style.backgroundColor = "#f0f0f0", d.onmouseleave = () => d.style.backgroundColor = "transparent", d.onclick = () => {
|
|
316
|
+
T(e), n.remove();
|
|
317
|
+
}, n.appendChild(d);
|
|
318
|
+
const c = document.createElement("div");
|
|
319
|
+
c.className = "rte-spellcheck-menu-item", c.textContent = "Add to Dictionary", c.style.cssText = "padding: 6px 16px; cursor: pointer; color: #1976d2;", c.onmouseenter = () => c.style.backgroundColor = "#f0f0f0", c.onmouseleave = () => c.style.backgroundColor = "transparent", c.onclick = () => {
|
|
320
|
+
O(e), n.remove();
|
|
321
|
+
}, n.appendChild(c), document.body.appendChild(n);
|
|
322
|
+
const k = (a) => {
|
|
323
|
+
n.contains(a.target) || (n.remove(), document.removeEventListener("mousedown", k));
|
|
324
|
+
};
|
|
325
|
+
setTimeout(() => document.addEventListener("mousedown", k), 0);
|
|
326
|
+
}
|
|
327
|
+
function W() {
|
|
328
|
+
document.addEventListener("contextmenu", (t) => {
|
|
329
|
+
const r = t.target;
|
|
330
|
+
if (r && r.classList.contains("rte-misspelled")) {
|
|
331
|
+
t.preventDefault();
|
|
332
|
+
const e = r.getAttribute("data-word"), o = (r.getAttribute("data-suggestions") || "").split(",").filter((s) => s);
|
|
333
|
+
H(t.clientX, t.clientY, e, o, r);
|
|
334
|
+
}
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
function B() {
|
|
338
|
+
const t = document.createElement("div");
|
|
339
|
+
return t.className = "rte-spell-check-panel", t.style.cssText = `
|
|
340
|
+
position: fixed;
|
|
341
|
+
right: 0;
|
|
342
|
+
top: 0;
|
|
343
|
+
width: 350px;
|
|
344
|
+
height: 100vh;
|
|
345
|
+
background: white;
|
|
346
|
+
border-left: 1px solid #ddd;
|
|
347
|
+
box-shadow: -2px 0 4px rgba(0,0,0,0.1);
|
|
348
|
+
overflow-y: auto;
|
|
349
|
+
z-index: 10000;
|
|
350
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
|
351
|
+
padding: 16px;
|
|
352
|
+
`, document.body.appendChild(t), t;
|
|
353
|
+
}
|
|
354
|
+
function m() {
|
|
355
|
+
if (!l) return;
|
|
356
|
+
const t = v(), r = _(t);
|
|
357
|
+
l.innerHTML = `
|
|
358
|
+
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px;">
|
|
359
|
+
<h3 style="margin: 0; font-size: 16px; font-weight: 600;">Spell Check</h3>
|
|
360
|
+
<button class="rte-spellcheck-close" style="background: none; border: none; font-size: 22px; cursor: pointer; color: #888;">✕</button>
|
|
361
|
+
</div>
|
|
362
|
+
|
|
363
|
+
<div style="display: flex; gap: 24px; margin-bottom: 16px; padding-bottom: 16px; border-bottom: 1px solid #eee;">
|
|
364
|
+
<div>
|
|
365
|
+
<div style="font-size: 12px; color: #999;">Total Words</div>
|
|
366
|
+
<div style="font-size: 16px; font-weight: 600; color: #333;">${r.total}</div>
|
|
367
|
+
</div>
|
|
368
|
+
<div>
|
|
369
|
+
<div style="font-size: 12px; color: #999;">Misspelled</div>
|
|
370
|
+
<div style="font-size: 16px; font-weight: 600; color: #d32f2f;">${r.misspelled}</div>
|
|
371
|
+
</div>
|
|
372
|
+
<div>
|
|
373
|
+
<div style="font-size: 12px; color: #999;">Accuracy</div>
|
|
374
|
+
<div style="font-size: 16px; font-weight: 600; color: #388e3c;">${r.accuracy.toFixed(1)}%</div>
|
|
375
|
+
</div>
|
|
376
|
+
</div>
|
|
377
|
+
|
|
378
|
+
<div class="misspellings-list">
|
|
379
|
+
${t.length === 0 ? '<div style="padding: 12px; text-align: center; color: #999; font-size: 13px;">No spelling errors found</div>' : t.map((o, s) => `
|
|
380
|
+
<div class="misspelling-item" data-word="${o.word}" data-index="${s}" style="padding: 8px; margin-bottom: 8px; background-color: #f5f5f5; border-radius: 4px;">
|
|
381
|
+
<div class="word-header" style="display: flex; justify-content: space-between; align-items: center; cursor: pointer;">
|
|
382
|
+
<span style="font-weight: 600; color: #d32f2f;">${o.word}</span>
|
|
383
|
+
<button class="expand-btn" style="background: none; border: none; cursor: pointer; font-size: 12px; color: #666;">▶</button>
|
|
384
|
+
</div>
|
|
385
|
+
<div class="suggestions" style="display: none; margin-top: 8px; padding-top: 8px; border-top: 1px solid #ddd;">
|
|
386
|
+
${o.suggestions.length > 0 ? `<div style="font-size: 12px; font-weight: 600; color: #333; margin-bottom: 6px;">Suggestions:</div>
|
|
387
|
+
${o.suggestions.map((n) => `<button class="suggestion-btn" data-suggestion="${n}" style="display: inline-block; margin-right: 6px; margin-bottom: 6px; padding: 4px 8px; background-color: #1976d2; color: white; border: none; border-radius: 3px; font-size: 12px; cursor: pointer;">${n}</button>`).join("")}` : '<div style="font-size: 12px; color: #999; margin-bottom: 8px;">No suggestions</div>'}
|
|
388
|
+
<div style="margin-top: 8px; display: flex; gap: 6px;">
|
|
389
|
+
<button class="ignore-btn" style="font-size: 12px; padding: 4px 8px; background-color: white; border: 1px solid #ddd; border-radius: 3px; cursor: pointer;">Ignore</button>
|
|
390
|
+
<button class="add-btn" style="font-size: 12px; padding: 4px 8px; background-color: white; border: 1px solid #ddd; border-radius: 3px; cursor: pointer;">Add to Dictionary</button>
|
|
391
|
+
</div>
|
|
392
|
+
</div>
|
|
393
|
+
</div>
|
|
394
|
+
`).join("")}
|
|
395
|
+
</div>
|
|
396
|
+
`;
|
|
397
|
+
const e = l.querySelector(".rte-spellcheck-close");
|
|
398
|
+
e == null || e.addEventListener("click", () => {
|
|
399
|
+
M();
|
|
400
|
+
}), l.querySelectorAll(".word-header").forEach((o, s) => {
|
|
401
|
+
o.addEventListener("click", () => {
|
|
402
|
+
const n = o.closest(".misspelling-item"), i = n == null ? void 0 : n.querySelector(".suggestions"), d = o.querySelector(".expand-btn");
|
|
403
|
+
i && d && (i.style.display === "none" ? (i.style.display = "block", d.textContent = "▼") : (i.style.display = "none", d.textContent = "▶"));
|
|
404
|
+
});
|
|
405
|
+
}), l.querySelectorAll(".suggestion-btn").forEach((o) => {
|
|
406
|
+
o.addEventListener("click", () => {
|
|
407
|
+
const s = o.getAttribute("data-suggestion"), n = o.closest(".misspelling-item");
|
|
408
|
+
n == null || n.getAttribute("data-word");
|
|
409
|
+
const i = parseInt((n == null ? void 0 : n.getAttribute("data-index")) || "0");
|
|
410
|
+
t[i] && L(t[i], s);
|
|
411
|
+
});
|
|
412
|
+
}), l.querySelectorAll(".ignore-btn").forEach((o) => {
|
|
413
|
+
o.addEventListener("click", () => {
|
|
414
|
+
const s = o.closest(".misspelling-item"), n = s == null ? void 0 : s.getAttribute("data-word");
|
|
415
|
+
T(n);
|
|
416
|
+
});
|
|
417
|
+
}), l.querySelectorAll(".add-btn").forEach((o) => {
|
|
418
|
+
o.addEventListener("click", () => {
|
|
419
|
+
const s = o.closest(".misspelling-item"), n = s == null ? void 0 : s.getAttribute("data-word");
|
|
420
|
+
O(n);
|
|
421
|
+
});
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
function P() {
|
|
425
|
+
const t = b();
|
|
426
|
+
t && (p && p.disconnect(), p = new MutationObserver((r) => {
|
|
427
|
+
r.some((e) => e.type === "characterData" || e.type === "childList") && (g && clearTimeout(g), g = window.setTimeout(() => {
|
|
428
|
+
f && (w(), m());
|
|
429
|
+
}, 350));
|
|
430
|
+
}), p.observe(t, {
|
|
431
|
+
characterData: !0,
|
|
432
|
+
childList: !0,
|
|
433
|
+
subtree: !0
|
|
434
|
+
}));
|
|
435
|
+
}
|
|
436
|
+
function V() {
|
|
437
|
+
p && (p.disconnect(), p = null), g && (clearTimeout(g), g = null);
|
|
438
|
+
}
|
|
439
|
+
function M() {
|
|
440
|
+
return f = !f, f ? (w(), W(), P(), l || (l = B(), m())) : (C(), V(), l && (l.remove(), l = null)), f;
|
|
441
|
+
}
|
|
442
|
+
const G = () => ({
|
|
443
|
+
name: "spellCheck",
|
|
444
|
+
init: () => {
|
|
445
|
+
D();
|
|
446
|
+
},
|
|
447
|
+
toolbar: [
|
|
448
|
+
{
|
|
449
|
+
label: "Spell Check",
|
|
450
|
+
command: "toggleSpellCheck",
|
|
451
|
+
icon: '<svg width="24px" height="24px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <path d="M3 12.5L3.84375 9.5M3.84375 9.5L5 5.38889C5 5.38889 5.25 4.5 6 4.5C6.75 4.5 7 5.38889 7 5.38889L8.15625 9.5M3.84375 9.5H8.15625M9 12.5L8.15625 9.5M13 16.8333L15.4615 19.5L21 13.5M12 8.5H15C16.1046 8.5 17 7.60457 17 6.5C17 5.39543 16.1046 4.5 15 4.5H12V8.5ZM12 8.5H16C17.1046 8.5 18 9.39543 18 10.5C18 11.6046 17.1046 12.5 16 12.5H12V8.5Z" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path> </g></svg>',
|
|
452
|
+
shortcut: "F7"
|
|
453
|
+
}
|
|
454
|
+
],
|
|
455
|
+
commands: {
|
|
456
|
+
toggleSpellCheck: () => (M(), !0)
|
|
457
|
+
},
|
|
458
|
+
keymap: {
|
|
459
|
+
F7: "toggleSpellCheck"
|
|
460
|
+
}
|
|
461
|
+
});
|
|
462
|
+
export {
|
|
463
|
+
G as SpellCheckPlugin
|
|
464
|
+
};
|
|
465
|
+
//# sourceMappingURL=SpellCheckPlugin.native-B7yTh0iE.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SpellCheckPlugin.native-B7yTh0iE.mjs","sources":["../../plugins/spell-check/src/SpellCheckPlugin.native.ts"],"sourcesContent":["import { Plugin } from '@editora/core';\n\n/**\n * Spell Check Plugin - Native Implementation\n * \n * Features:\n * - Real-time spell checking with visual highlights (red wavy underline)\n * - Dictionary-based word validation (English words + custom dictionary)\n * - Edit distance algorithm for intelligent suggestions\n * - Right-click context menu on misspelled words with suggestions\n * - Side panel with spell check stats and misspellings list\n * - Ignore/Add to dictionary functionality\n * - Protected contexts (code, comments, merge tags, URLs, emails)\n * - Incremental spell checking with debouncing\n * - MutationObserver for automatic re-checking\n */\n\n// ===== Core Data Structures =====\n\ninterface SpellCheckIssue {\n id: string;\n node: Text;\n startOffset: number;\n endOffset: number;\n word: string;\n suggestions: string[];\n ignored?: boolean;\n}\n\n// English dictionary with common words\nconst ENGLISH_DICTIONARY = new Set([\n 'the', 'a', 'an', 'and', 'or', 'but', 'in', 'on', 'at', 'to', 'for',\n 'of', 'with', 'by', 'from', 'is', 'are', 'be', 'was', 'were', 'have',\n 'has', 'had', 'do', 'does', 'did', 'will', 'would', 'could', 'should',\n 'may', 'might', 'must', 'can', 'this', 'that', 'these', 'those', 'what',\n 'which', 'who', 'whom', 'where', 'when', 'why', 'how', 'all', 'each',\n 'every', 'both', 'few', 'more', 'most', 'other', 'same', 'such', 'no',\n 'nor', 'not', 'only', 'own', 'so', 'than', 'too', 'very', 'just', 'as',\n 'if', 'because', 'while', 'although', 'though', 'it', 'its', 'their',\n 'them', 'they', 'you', 'he', 'she', 'we', 'me', 'him', 'her', 'us', 'our',\n 'i', 'my', 'your', 'his', 'hers', 'ours', 'yours', 'theirs', 'editor',\n 'document', 'text', 'word', 'paragraph', 'line', 'page', 'content',\n 'hello', 'world', 'test', 'example', 'sample', 'demo', 'lorem', 'ipsum'\n]);\n\nconst customDictionary = new Set<string>();\nconst ignoredWords = new Set<string>();\n\n// Module-level state\nlet isSpellCheckEnabled = false;\nlet mutationObserver: MutationObserver | null = null;\nlet debounceTimeout: number | null = null;\nlet sidePanelElement: HTMLElement | null = null;\n\n// Load custom dictionary from localStorage\nconst loadCustomDictionary = () => {\n try {\n const saved = localStorage.getItem('rte-custom-dictionary');\n if (saved) {\n const words = JSON.parse(saved) as string[];\n words.forEach(word => customDictionary.add(word.toLowerCase()));\n }\n } catch (e) {\n console.warn('Failed to load custom dictionary:', e);\n }\n};\n\n// Save custom dictionary to localStorage\nconst saveCustomDictionary = () => {\n try {\n const words = Array.from(customDictionary);\n localStorage.setItem('rte-custom-dictionary', JSON.stringify(words));\n } catch (e) {\n console.warn('Failed to save custom dictionary:', e);\n }\n};\n\n// ===== Spell Check Engine =====\n\n/**\n * Edit distance algorithm (Levenshtein distance) for suggestions\n */\nfunction editDistance(a: string, b: string): number {\n const matrix: number[][] = [];\n for (let i = 0; i <= b.length; i++) matrix[i] = [i];\n for (let j = 0; j <= a.length; j++) matrix[0][j] = j;\n for (let i = 1; i <= b.length; i++) {\n for (let j = 1; j <= a.length; j++) {\n if (b.charAt(i - 1) === a.charAt(j - 1)) {\n matrix[i][j] = matrix[i - 1][j - 1];\n } else {\n matrix[i][j] = Math.min(\n matrix[i - 1][j - 1] + 1, // substitution\n matrix[i][j - 1] + 1, // insertion\n matrix[i - 1][j] + 1 // deletion\n );\n }\n }\n }\n return matrix[b.length][a.length];\n}\n\n/**\n * Check if word is in dictionary\n */\nfunction checkWord(word: string): boolean {\n const w = word.toLowerCase();\n return ENGLISH_DICTIONARY.has(w) || customDictionary.has(w) || ignoredWords.has(w);\n}\n\n/**\n * Get spelling suggestions using edit distance\n */\nfunction getSuggestions(word: string, maxSuggestions = 5): string[] {\n const wordLower = word.toLowerCase();\n const words = Array.from(ENGLISH_DICTIONARY);\n const distances = words.map(w => ({ word: w, distance: editDistance(wordLower, w) }));\n distances.sort((a, b) => a.distance - b.distance);\n return distances.filter(d => d.distance <= 3).slice(0, maxSuggestions).map(d => d.word);\n}\n\n/**\n * Check if a node is in a protected context (code, comments, etc.)\n */\nfunction isProtected(node: Node): boolean {\n if (node.nodeType !== Node.ELEMENT_NODE) return false;\n const el = node as HTMLElement;\n if (\n el.closest('code, pre, [contenteditable=\"false\"], .rte-widget, .rte-template, .rte-comment, .rte-merge-tag') ||\n el.hasAttribute('data-comment-id') ||\n el.hasAttribute('data-template') ||\n el.hasAttribute('data-merge-tag')\n ) return true;\n return false;\n}\n\n/**\n * Tokenize a text node and find misspellings\n */\nfunction tokenizeTextNode(node: Text): SpellCheckIssue[] {\n const issues: SpellCheckIssue[] = [];\n const wordRegex = /([\\p{L}\\p{M}\\p{N}\\p{Emoji_Presentation}\\u200d'-]+|[\\uD800-\\uDBFF][\\uDC00-\\uDFFF])/gu;\n let match;\n \n while ((match = wordRegex.exec(node.data)) !== null) {\n const word = match[0];\n const start = match.index;\n const end = start + word.length;\n \n // Skip URLs, emails, merge tags, and numbers\n if (/https?:\\/\\//.test(word) || /@/.test(word) || /\\{\\{.*\\}\\}/.test(word) || /^\\d+$/.test(word)) continue;\n \n // Skip already correct words\n if (checkWord(word)) continue;\n \n // Skip camelCase, hyphenated words, and proper nouns (capitalized)\n if (/[a-z][A-Z]/.test(word) || /-/.test(word) || (word[0] === word[0].toUpperCase() && word.length > 1)) continue;\n \n issues.push({\n id: `${word}-${start}`,\n node,\n startOffset: start,\n endOffset: end,\n word,\n suggestions: getSuggestions(word),\n ignored: false\n });\n }\n \n return issues;\n}\n\n/**\n * Find the active editor element\n */\nconst findActiveEditor = (): HTMLElement | null => {\n // Try to find editor from current selection\n const selection = window.getSelection();\n if (selection && selection.rangeCount > 0) {\n let node: Node | null = selection.getRangeAt(0).startContainer;\n while (node && node !== document.body) {\n if (node.nodeType === Node.ELEMENT_NODE) {\n const element = node as HTMLElement;\n if (element.getAttribute('contenteditable') === 'true') {\n return element;\n }\n }\n node = node.parentNode;\n }\n }\n \n // Try active element\n const activeElement = document.activeElement;\n if (activeElement) {\n if (activeElement.getAttribute('contenteditable') === 'true') {\n return activeElement as HTMLElement;\n }\n const editor = activeElement.closest('[contenteditable=\"true\"]');\n if (editor) return editor as HTMLElement;\n }\n \n // Fallback to first editor\n return document.querySelector('[contenteditable=\"true\"]');\n};\n\n/**\n * Scan entire document for misspellings\n */\nfunction scanDocumentForMisspellings(): SpellCheckIssue[] {\n const editor = findActiveEditor();\n if (!editor) return [];\n \n const issues: SpellCheckIssue[] = [];\n const walker = document.createTreeWalker(\n editor,\n NodeFilter.SHOW_TEXT,\n {\n acceptNode: (node) => {\n if (!node.textContent?.trim()) return NodeFilter.FILTER_REJECT;\n if (node.parentNode && isProtected(node.parentNode)) return NodeFilter.FILTER_REJECT;\n return NodeFilter.FILTER_ACCEPT;\n }\n }\n );\n \n let textNode = walker.nextNode() as Text;\n while (textNode) {\n issues.push(...tokenizeTextNode(textNode));\n textNode = walker.nextNode() as Text;\n }\n \n return issues;\n}\n\n/**\n * Highlight misspelled words with red wavy underline\n */\nfunction highlightMisspelledWords(issues?: SpellCheckIssue[]): void {\n const editor = findActiveEditor();\n if (!editor) return;\n \n if (!issues) issues = scanDocumentForMisspellings();\n \n // Clear existing highlights\n editor.querySelectorAll('.rte-misspelled').forEach(el => {\n const parent = el.parentNode;\n if (parent) {\n while (el.firstChild) {\n parent.insertBefore(el.firstChild, el);\n }\n parent.removeChild(el);\n }\n });\n \n // Add new highlights\n issues.forEach(issue => {\n if (ignoredWords.has(issue.word.toLowerCase())) return;\n \n // Defensive check: ensure offsets are within bounds\n const nodeLength = issue.node.data.length;\n if (\n issue.startOffset < 0 ||\n issue.endOffset > nodeLength ||\n issue.startOffset >= issue.endOffset\n ) {\n return;\n }\n \n try {\n const range = document.createRange();\n range.setStart(issue.node, issue.startOffset);\n range.setEnd(issue.node, issue.endOffset);\n \n const span = document.createElement('span');\n span.className = 'rte-misspelled';\n span.setAttribute('data-word', issue.word);\n span.setAttribute('data-suggestions', issue.suggestions.join(','));\n span.setAttribute('title', `Suggestions: ${issue.suggestions.join(', ')}`);\n span.style.borderBottom = '2px wavy red';\n span.style.cursor = 'pointer';\n \n range.surroundContents(span);\n } catch (e) {\n // Skip if range surroundContents fails\n }\n });\n \n // Update side panel\n updateSidePanel();\n}\n\n/**\n * Clear all spell check highlights\n */\nfunction clearSpellCheckHighlights(): void {\n const editor = document.querySelector('[contenteditable=\"true\"]');\n if (!editor) return;\n \n editor.querySelectorAll('.rte-misspelled').forEach(el => {\n const parent = el.parentNode;\n if (parent) {\n while (el.firstChild) {\n parent.insertBefore(el.firstChild, el);\n }\n parent.removeChild(el);\n }\n });\n}\n\n/**\n * Replace a misspelled word with a suggestion\n */\nfunction replaceWord(issue: SpellCheckIssue, replacement: string): void {\n const range = document.createRange();\n range.setStart(issue.node, issue.startOffset);\n range.setEnd(issue.node, issue.endOffset);\n \n const textNode = document.createTextNode(replacement);\n range.deleteContents();\n range.insertNode(textNode);\n \n // MutationObserver will trigger highlight and panel update\n}\n\n/**\n * Ignore a word (session only)\n */\nfunction ignoreWord(word: string): void {\n ignoredWords.add(word.toLowerCase());\n clearSpellCheckHighlights();\n highlightMisspelledWords();\n updateSidePanel(); // Immediate update needed since no DOM change\n}\n\n/**\n * Add word to custom dictionary (persistent)\n */\nfunction addToDictionary(word: string): void {\n customDictionary.add(word.toLowerCase());\n saveCustomDictionary(); // Save to localStorage\n clearSpellCheckHighlights();\n highlightMisspelledWords();\n updateSidePanel(); // Immediate update needed since no DOM change\n}\n\n/**\n * Get spell check statistics\n */\nfunction getSpellCheckStats(issues?: SpellingIssue[]): { total: number; misspelled: number; accuracy: number } {\n const editor = findActiveEditor();\n if (!editor) return { total: 0, misspelled: 0, accuracy: 100 };\n \n // Use provided issues or scan if not provided\n if (!issues) {\n issues = scanDocumentForMisspellings();\n }\n const misspelled = issues.filter(i => !ignoredWords.has(i.word.toLowerCase())).length;\n \n // Count total words\n const text = editor.textContent || '';\n const words = text.match(/[\\p{L}\\p{M}\\p{N}]+/gu) || [];\n const total = words.length;\n \n return {\n total,\n misspelled,\n accuracy: total > 0 ? ((total - misspelled) / total) * 100 : 100\n };\n}\n\n// ===== Context Menu =====\n\n/**\n * Show context menu for misspelled word\n */\nfunction showSpellCheckContextMenu(x: number, y: number, word: string, suggestions: string[], target: HTMLElement): void {\n // Remove existing menus\n document.querySelectorAll('.rte-spellcheck-menu').forEach(el => el.remove());\n \n const menu = document.createElement('div');\n menu.className = 'rte-spellcheck-menu';\n menu.style.cssText = `\n position: fixed;\n left: ${x}px;\n top: ${y}px;\n background: #fff;\n border: 1px solid #ccc;\n border-radius: 4px;\n box-shadow: 0 2px 8px rgba(0,0,0,0.15);\n z-index: 99999;\n padding: 4px 0;\n min-width: 160px;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n font-size: 13px;\n `;\n \n // Add suggestions\n suggestions.slice(0, 5).forEach(suggestion => {\n const item = document.createElement('div');\n item.className = 'rte-spellcheck-menu-item';\n item.textContent = suggestion;\n item.style.cssText = 'padding: 6px 16px; cursor: pointer; transition: background 0.2s;';\n item.onmouseenter = () => item.style.backgroundColor = '#f0f0f0';\n item.onmouseleave = () => item.style.backgroundColor = 'transparent';\n item.onclick = () => {\n // Find the text node and create issue\n const parent = target.parentNode;\n if (parent) {\n for (const node of parent.childNodes) {\n if (node.nodeType === Node.TEXT_NODE && node.textContent?.includes(word)) {\n const idx = node.textContent.indexOf(word);\n const issue: SpellCheckIssue = {\n id: `${word}-${idx}`,\n node: node as Text,\n startOffset: idx,\n endOffset: idx + word.length,\n word,\n suggestions,\n ignored: false\n };\n replaceWord(issue, suggestion);\n break;\n }\n }\n }\n menu.remove();\n };\n menu.appendChild(item);\n });\n \n // Separator\n if (suggestions.length > 0) {\n const separator = document.createElement('div');\n separator.style.cssText = 'height: 1px; background: #ddd; margin: 4px 0;';\n menu.appendChild(separator);\n }\n \n // Ignore Once\n const ignoreOnce = document.createElement('div');\n ignoreOnce.className = 'rte-spellcheck-menu-item';\n ignoreOnce.textContent = 'Ignore Once';\n ignoreOnce.style.cssText = 'padding: 6px 16px; cursor: pointer; color: #666;';\n ignoreOnce.onmouseenter = () => ignoreOnce.style.backgroundColor = '#f0f0f0';\n ignoreOnce.onmouseleave = () => ignoreOnce.style.backgroundColor = 'transparent';\n ignoreOnce.onclick = () => {\n target.remove();\n menu.remove();\n };\n menu.appendChild(ignoreOnce);\n \n // Ignore All\n const ignoreAll = document.createElement('div');\n ignoreAll.className = 'rte-spellcheck-menu-item';\n ignoreAll.textContent = 'Ignore All';\n ignoreAll.style.cssText = 'padding: 6px 16px; cursor: pointer; color: #666;';\n ignoreAll.onmouseenter = () => ignoreAll.style.backgroundColor = '#f0f0f0';\n ignoreAll.onmouseleave = () => ignoreAll.style.backgroundColor = 'transparent';\n ignoreAll.onclick = () => {\n ignoreWord(word);\n menu.remove();\n };\n menu.appendChild(ignoreAll);\n \n // Add to Dictionary\n const addToDict = document.createElement('div');\n addToDict.className = 'rte-spellcheck-menu-item';\n addToDict.textContent = 'Add to Dictionary';\n addToDict.style.cssText = 'padding: 6px 16px; cursor: pointer; color: #1976d2;';\n addToDict.onmouseenter = () => addToDict.style.backgroundColor = '#f0f0f0';\n addToDict.onmouseleave = () => addToDict.style.backgroundColor = 'transparent';\n addToDict.onclick = () => {\n addToDictionary(word);\n menu.remove();\n };\n menu.appendChild(addToDict);\n \n document.body.appendChild(menu);\n \n // Close on click outside\n const dismiss = (ev: MouseEvent) => {\n if (!menu.contains(ev.target as Node)) {\n menu.remove();\n document.removeEventListener('mousedown', dismiss);\n }\n };\n setTimeout(() => document.addEventListener('mousedown', dismiss), 0);\n}\n\n/**\n * Attach context menu to document\n */\nfunction attachSpellCheckContextMenu(): void {\n document.addEventListener('contextmenu', (e) => {\n const target = e.target as HTMLElement;\n if (target && target.classList.contains('rte-misspelled')) {\n e.preventDefault();\n const word = target.getAttribute('data-word')!;\n const suggestions = (target.getAttribute('data-suggestions') || '').split(',').filter(s => s);\n showSpellCheckContextMenu(e.clientX, e.clientY, word, suggestions, target);\n }\n });\n}\n\n// ===== Side Panel =====\n\n/**\n * Create and show side panel\n */\nfunction createSidePanel(): HTMLElement {\n const panel = document.createElement('div');\n panel.className = 'rte-spell-check-panel';\n panel.style.cssText = `\n position: fixed;\n right: 0;\n top: 0;\n width: 350px;\n height: 100vh;\n background: white;\n border-left: 1px solid #ddd;\n box-shadow: -2px 0 4px rgba(0,0,0,0.1);\n overflow-y: auto;\n z-index: 10000;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n padding: 16px;\n `;\n \n document.body.appendChild(panel);\n return panel;\n}\n\n/**\n * Update side panel content\n */\nfunction updateSidePanel(): void {\n if (!sidePanelElement) return;\n \n const issues = scanDocumentForMisspellings();\n const stats = getSpellCheckStats(issues); // Pass issues to avoid duplicate scan\n \n sidePanelElement.innerHTML = `\n <div style=\"display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px;\">\n <h3 style=\"margin: 0; font-size: 16px; font-weight: 600;\">Spell Check</h3>\n <button class=\"rte-spellcheck-close\" style=\"background: none; border: none; font-size: 22px; cursor: pointer; color: #888;\">✕</button>\n </div>\n \n <div style=\"display: flex; gap: 24px; margin-bottom: 16px; padding-bottom: 16px; border-bottom: 1px solid #eee;\">\n <div>\n <div style=\"font-size: 12px; color: #999;\">Total Words</div>\n <div style=\"font-size: 16px; font-weight: 600; color: #333;\">${stats.total}</div>\n </div>\n <div>\n <div style=\"font-size: 12px; color: #999;\">Misspelled</div>\n <div style=\"font-size: 16px; font-weight: 600; color: #d32f2f;\">${stats.misspelled}</div>\n </div>\n <div>\n <div style=\"font-size: 12px; color: #999;\">Accuracy</div>\n <div style=\"font-size: 16px; font-weight: 600; color: #388e3c;\">${stats.accuracy.toFixed(1)}%</div>\n </div>\n </div>\n \n <div class=\"misspellings-list\">\n ${issues.length === 0 \n ? '<div style=\"padding: 12px; text-align: center; color: #999; font-size: 13px;\">No spelling errors found</div>'\n : issues.map((issue, idx) => `\n <div class=\"misspelling-item\" data-word=\"${issue.word}\" data-index=\"${idx}\" style=\"padding: 8px; margin-bottom: 8px; background-color: #f5f5f5; border-radius: 4px;\">\n <div class=\"word-header\" style=\"display: flex; justify-content: space-between; align-items: center; cursor: pointer;\">\n <span style=\"font-weight: 600; color: #d32f2f;\">${issue.word}</span>\n <button class=\"expand-btn\" style=\"background: none; border: none; cursor: pointer; font-size: 12px; color: #666;\">▶</button>\n </div>\n <div class=\"suggestions\" style=\"display: none; margin-top: 8px; padding-top: 8px; border-top: 1px solid #ddd;\">\n ${issue.suggestions.length > 0 \n ? `<div style=\"font-size: 12px; font-weight: 600; color: #333; margin-bottom: 6px;\">Suggestions:</div>\n ${issue.suggestions.map(s => `<button class=\"suggestion-btn\" data-suggestion=\"${s}\" style=\"display: inline-block; margin-right: 6px; margin-bottom: 6px; padding: 4px 8px; background-color: #1976d2; color: white; border: none; border-radius: 3px; font-size: 12px; cursor: pointer;\">${s}</button>`).join('')}`\n : '<div style=\"font-size: 12px; color: #999; margin-bottom: 8px;\">No suggestions</div>'\n }\n <div style=\"margin-top: 8px; display: flex; gap: 6px;\">\n <button class=\"ignore-btn\" style=\"font-size: 12px; padding: 4px 8px; background-color: white; border: 1px solid #ddd; border-radius: 3px; cursor: pointer;\">Ignore</button>\n <button class=\"add-btn\" style=\"font-size: 12px; padding: 4px 8px; background-color: white; border: 1px solid #ddd; border-radius: 3px; cursor: pointer;\">Add to Dictionary</button>\n </div>\n </div>\n </div>\n `).join('')\n }\n </div>\n `;\n \n // Event listeners\n const closeBtn = sidePanelElement.querySelector('.rte-spellcheck-close');\n closeBtn?.addEventListener('click', () => {\n toggleSpellCheck();\n });\n \n // Toggle expand/collapse\n sidePanelElement.querySelectorAll('.word-header').forEach((header, idx) => {\n header.addEventListener('click', () => {\n const item = header.closest('.misspelling-item');\n const suggestions = item?.querySelector('.suggestions') as HTMLElement;\n const expandBtn = header.querySelector('.expand-btn');\n if (suggestions && expandBtn) {\n if (suggestions.style.display === 'none') {\n suggestions.style.display = 'block';\n expandBtn.textContent = '▼';\n } else {\n suggestions.style.display = 'none';\n expandBtn.textContent = '▶';\n }\n }\n });\n });\n \n // Suggestion buttons\n sidePanelElement.querySelectorAll('.suggestion-btn').forEach(btn => {\n btn.addEventListener('click', () => {\n const suggestion = btn.getAttribute('data-suggestion')!;\n const item = btn.closest('.misspelling-item');\n const word = item?.getAttribute('data-word')!;\n const issueIndex = parseInt(item?.getAttribute('data-index') || '0');\n \n if (issues[issueIndex]) {\n replaceWord(issues[issueIndex], suggestion);\n }\n });\n });\n \n // Ignore buttons\n sidePanelElement.querySelectorAll('.ignore-btn').forEach(btn => {\n btn.addEventListener('click', () => {\n const item = btn.closest('.misspelling-item');\n const word = item?.getAttribute('data-word')!;\n ignoreWord(word);\n });\n });\n \n // Add to dictionary buttons\n sidePanelElement.querySelectorAll('.add-btn').forEach(btn => {\n btn.addEventListener('click', () => {\n const item = btn.closest('.misspelling-item');\n const word = item?.getAttribute('data-word')!;\n addToDictionary(word);\n });\n });\n}\n\n// ===== MutationObserver for incremental spell check =====\n\nfunction startMutationObserver(): void {\n const editor = findActiveEditor();\n if (!editor) return;\n \n if (mutationObserver) mutationObserver.disconnect();\n \n mutationObserver = new MutationObserver((mutations) => {\n // Only trigger on text/content changes\n if (mutations.some(m => m.type === 'characterData' || m.type === 'childList')) {\n // Debounce the highlight function\n if (debounceTimeout) clearTimeout(debounceTimeout);\n debounceTimeout = window.setTimeout(() => {\n if (isSpellCheckEnabled) {\n highlightMisspelledWords();\n updateSidePanel(); // Update side panel when content changes\n }\n }, 350);\n }\n });\n \n mutationObserver.observe(editor, {\n characterData: true,\n childList: true,\n subtree: true\n });\n}\n\nfunction stopMutationObserver(): void {\n if (mutationObserver) {\n mutationObserver.disconnect();\n mutationObserver = null;\n }\n if (debounceTimeout) {\n clearTimeout(debounceTimeout);\n debounceTimeout = null;\n }\n}\n\n// ===== Main Toggle Function =====\n\nfunction toggleSpellCheck(): void {\n isSpellCheckEnabled = !isSpellCheckEnabled;\n \n if (isSpellCheckEnabled) {\n // Enable spell check\n highlightMisspelledWords();\n attachSpellCheckContextMenu();\n startMutationObserver();\n \n // Create and show side panel\n if (!sidePanelElement) {\n sidePanelElement = createSidePanel();\n updateSidePanel();\n }\n } else {\n // Disable spell check\n clearSpellCheckHighlights();\n stopMutationObserver();\n \n // Remove side panel\n if (sidePanelElement) {\n sidePanelElement.remove();\n sidePanelElement = null;\n }\n }\n \n return isSpellCheckEnabled;\n}\n\n// ===== Plugin Export =====\n\nexport const SpellCheckPlugin = (): Plugin => ({\n name: 'spellCheck',\n \n init: () => {\n // Load custom dictionary from localStorage on plugin initialization\n loadCustomDictionary();\n },\n \n toolbar: [\n {\n label: 'Spell Check',\n command: 'toggleSpellCheck',\n icon: '<svg width=\"24px\" height=\"24px\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><g id=\"SVGRepo_bgCarrier\" stroke-width=\"0\"></g><g id=\"SVGRepo_tracerCarrier\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></g><g id=\"SVGRepo_iconCarrier\"> <path d=\"M3 12.5L3.84375 9.5M3.84375 9.5L5 5.38889C5 5.38889 5.25 4.5 6 4.5C6.75 4.5 7 5.38889 7 5.38889L8.15625 9.5M3.84375 9.5H8.15625M9 12.5L8.15625 9.5M13 16.8333L15.4615 19.5L21 13.5M12 8.5H15C16.1046 8.5 17 7.60457 17 6.5C17 5.39543 16.1046 4.5 15 4.5H12V8.5ZM12 8.5H16C17.1046 8.5 18 9.39543 18 10.5C18 11.6046 17.1046 12.5 16 12.5H12V8.5Z\" stroke=\"#000000\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></path> </g></svg>',\n shortcut: 'F7'\n }\n ],\n \n commands: {\n toggleSpellCheck: () => {\n toggleSpellCheck();\n return true;\n }\n },\n \n keymap: {\n 'F7': 'toggleSpellCheck'\n }\n});\n"],"names":["ENGLISH_DICTIONARY","customDictionary","ignoredWords","isSpellCheckEnabled","mutationObserver","debounceTimeout","sidePanelElement","loadCustomDictionary","saved","word","e","saveCustomDictionary","words","editDistance","a","b","matrix","i","j","checkWord","w","getSuggestions","maxSuggestions","wordLower","distances","d","isProtected","node","el","tokenizeTextNode","issues","wordRegex","match","start","end","findActiveEditor","selection","element","activeElement","editor","scanDocumentForMisspellings","walker","_a","textNode","highlightMisspelledWords","parent","issue","nodeLength","range","span","updateSidePanel","clearSpellCheckHighlights","replaceWord","replacement","ignoreWord","addToDictionary","getSpellCheckStats","misspelled","total","showSpellCheckContextMenu","x","y","suggestions","target","menu","suggestion","item","idx","separator","ignoreOnce","ignoreAll","addToDict","dismiss","ev","attachSpellCheckContextMenu","createSidePanel","panel","stats","s","closeBtn","toggleSpellCheck","header","expandBtn","btn","issueIndex","startMutationObserver","mutations","m","stopMutationObserver","SpellCheckPlugin"],"mappings":"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"}
|