{"version":3,"sources":["jsdelivr-header.js","/npm/@wiris/mathtype-ckeditor5@8.14.0/src/plugin.js"],"names":[],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA,OCLS,WAAc,+BACd,eAAkB,6BAClB,cAAe,kBAAmB,iBAAkB,qBAAwB,iCAC5E,OAAQ,SAAU,2CAA8C,iCAGlE,qBAAsB,yEACtB,SAAU,iEACV,WAAY,+DACZ,SAAU,6DACV,UAAW,8DACX,kBAAmB,sEACnB,cAAe,kEACf,WAAY,+DACZ,UAAW,8DACX,kBAAmB,qEACnB,4DAGE,gBAAiB,oBAAuB,uBAC1C,yBAA0B,0BAE1B,aAAc,8CACd,aAAc,2CAEd,gBAAiB,yBAEjB,IAAI,gBAAkB,oBAEd,MAAM,iBAAiB,OACpC,mBAAW,GACT,MAAO,CAAC,OACV,CAEA,qBAAW,GACT,MAAO,UACT,CAEA,IAAA,GAEE,MAAM,EAAc,KAAK,kBACzB,gBAAkB,EAGlB,KAAK,eAGL,KAAK,UAAU,GAGf,KAAK,aAGL,KAAK,eAAe,GAGpB,KAAK,cACP,CAKA,OAAA,GAEE,iBAAiB,SACnB,CAMA,eAAA,GACE,MAAM,OAAE,GAAW,KAMb,EAAwB,CAAC,EAgB/B,IAAI,EAuBJ,OAtCA,EAAsB,YAAc,CAAC,EACrC,EAAsB,YAAY,OAAS,YAC3C,EAAsB,YAAY,cAAgB,MAClD,EAAsB,QAAU,YAAY,QAC5C,EAAsB,aAAe,EACrC,EAAsB,0BAA4B,CAAC,EACnD,EAAsB,0BAA0B,IAAM,yCACtD,EAAsB,0BAA0B,OAAS,OACzD,EAAsB,OAAS,EAAO,cACtC,EAAsB,WAAa,YACnC,EAAsB,iBAAkB,EAMpC,EAAsB,SAExB,EAAc,IAAI,qBAAqB,GACvC,EAAY,OACZ,EAAY,UAAU,KAAK,gBAAiB,CAAC,GAE7C,EAAY,eAEZ,KAAK,SACH,EAAO,QAAQ,KAAK,SACpB,SACA,CAAC,EAAK,KAEyB,IAAzB,EAAK,SAAS,SAChB,EAAY,mBAAmB,EAAK,UAAW,EAAK,UACpD,EAAI,OACN,GAEF,CAAE,SAAU,aAIT,CACT,CAKA,YAAA,GACE,MAAM,OAAE,GAAW,KAGnB,EAAO,SAAS,IAAI,WAAY,IAAI,gBAAgB,IAGpD,EAAO,SAAS,IAAI,WAAY,IAAI,gBAAgB,GACtD,CAMA,SAAA,CAAU,GACR,MAAM,OAAE,GAAW,KAGf,cAAc,IAAI,kBAEpB,EAAO,GAAG,iBAAiB,IAAI,YAAa,IAC1C,MAAM,EAAO,IAAI,WAAW,GAiB5B,OAdA,EAAK,KAAK,aAAa,GAAG,EAAO,SAAS,IAAI,YAAa,aAC3D,EAAK,IAAI,CACP,MAAO,cAAc,IAAI,cAAe,EAAY,eACpD,KAAM,SACN,SAAS,IAIX,EAAK,GAAG,WAAW,KACjB,EAAO,QAAQ,WAAY,CACzB,eACA,IAGG,CAAI,IAKX,cAAc,IAAI,gBAEpB,EAAO,GAAG,iBAAiB,IAAI,YAAa,IAC1C,MAAM,EAAO,IAAI,WAAW,GAkB5B,OAfA,EAAK,KAAK,aAAa,GAAG,EAAO,SAAS,IAAI,YAAa,aAE3D,EAAK,IAAI,CACP,MAAO,cAAc,IAAI,cAAe,EAAY,eACpD,KAAM,SACN,SAAS,IAIX,EAAK,GAAG,WAAW,KACjB,EAAO,QAAQ,WAAY,CACzB,eACA,IAGG,CAAI,IAKf,EAAO,QAAQ,KAAK,YAAY,cAClC,CAKA,UAAA,GACE,MAAM,OAAE,GAAW,KAAK,OAAO,MAE/B,EAAO,SAAS,SAAU,CACxB,eAAgB,gBAChB,gBAAiB,CAAC,UAAW,gBAEjC,CAKA,cAAA,CAAe,GACb,MAAM,OAAE,GAAW,KA+PnB,SAAS,EAAM,EAAY,GACzB,GAAI,EAAW,GAAG,QAChB,OAAO,EAAW,WAAW,EAAW,MAE1C,GAAI,EAAW,GAAG,WAAY,CAC5B,GAAI,EAAW,GAAG,gBAChB,OAAO,EAAW,mBAAmB,EAAW,KAAM,EAAW,iBAEnE,MAAM,EAAU,EAAW,uBAAuB,EAAW,KAAM,EAAW,iBAC9E,IAAK,MAAM,KAAS,EAAW,cAC7B,EAAW,OAAO,EAAW,iBAAiB,EAAS,OAAQ,EAAM,EAAY,IAEnF,OAAO,CACT,CAEA,MAAM,IAAI,UAAU,mCACtB,CA5QA,EAAO,WAAW,IAAI,UAAU,iBAAiB,CAC/C,KAAM,CACJ,KAAM,OACN,QAAS,kBAEX,MAAO,CAAC,GAAe,OAAQ,MAC7B,MAAM,EAAU,OAAO,cAAc,EAAY,SAAS,GAAG,aAAa,gBAC1E,OAAO,EAAY,cAAc,SAAU,CACzC,WACA,IAKN,EAAO,KAAK,iBAAiB,GAAG,gBAAgB,CAAC,EAAK,EAAM,KAC1D,MAAM,WAAE,EAAU,OAAE,GAAW,GACzB,SAAE,GAAa,EAGrB,IAAK,EAAW,KAAK,EAAU,CAAE,MAAM,IACrC,OAKF,MAAM,EAoJR,SAAqB,GACnB,MAAM,EAAY,EAAK,SAAS,GAChC,IAAK,GAAgC,cAAnB,EAAU,KAAsB,OAAO,EACzD,IAAK,MAAM,KAAS,EAAU,cAC5B,GAAmB,eAAf,EAAM,MAA4D,UAAnC,EAAM,aAAa,YACpD,OAAO,EAGX,OAAO,CACT,CA7JkB,CAAY,GAGtB,EAAY,IAAI,iBAAiB,EAAO,QAAQ,KAAK,UAKrD,EADe,IAAI,iBAAiB,EAAO,QAAQ,KAAK,UACpB,uBAAuB,EAAS,eAGpE,EAAiB,IAAI,EAAS,iBAAiB,KAAI,EAAE,EAAK,KAAW,IAAI,MAAQ,OAAU,KAAK,IAGtG,IAAI,EAAU,EAAU,OAAO,IAAyB,GAGxD,EAAU,KAAK,aAAa,QAAQ,KAAkB,YAGtD,EAAU,EAAQ,WAAW,MAAO,UAAU,WAAW,MAAO,UAAU,WAAW,MAAO,UAK5F,MAAM,EAAY,EACd,EAAO,WAAW,OAAO,UAAU,EAAS,EAAY,gBACxD,EAAO,cAAc,SAAU,CAAE,YAK/B,EAAc,EAAc,qBAAqB,EAAW,EAAK,aAGvE,IAAK,EACH,OAIF,EAAc,OAAO,OAAO,EAAW,EAAY,UAGnD,EAAW,QAAQ,EAAU,CAAE,MAAM,IAErC,MAAM,EAAQ,EAAc,cAAc,GAG1C,EAAK,WAAa,EAAO,YACvB,EAAc,OAAO,qBAAqB,GAC1C,EAAc,OAAO,oBAAoB,EAAM,EAAM,OAAS,KAI5D,EAAY,aAMd,EAAK,YAAc,EAAc,OAAO,iBAAiB,EAAY,aAAc,GAGnF,EAAK,YAAc,EAAK,WAAW,GACrC,IAIF,EAAO,KAAK,iBAAiB,GAC3B,eACA,CAAC,EAAK,EAAM,KACV,MAAM,WAAE,EAAU,OAAE,GAAW,GACzB,SAAE,GAAa,EAGrB,GAA8C,iBAA1C,EAAS,gBAAgB,OAAO,MAClC,OAOF,IAAK,EAAW,KAAK,EAAU,CAAE,MAAM,IACrC,OAIF,EAAW,QAAQ,EAAU,CAAE,MAAM,IACrC,IAAK,MAAM,KAAY,EAAS,gBAC9B,EAAW,QAAQ,EAAU,CAAE,WAAY,CAAC,KAG9C,IAAK,MAAM,KAAa,EAAS,gBAC/B,EAAW,QAAQ,EAAU,CAAE,QAAS,CAAC,KAG3C,MAAM,EAAiB,IAAI,EAAS,iBAAiB,KAAI,EAAE,EAAK,KAAW,IAAI,MAAQ,OAAU,KAAK,IAChG,EAAc,KAAK,aAAa,OAAO,MAEvC,EAAY,EAAO,cAAc,SAAU,CAAE,gBAK7C,EAAc,EAAc,qBAAqB,EAAW,EAAK,aAGvE,IAAK,EACH,OAIF,EAAc,OAAO,OAAO,EAAW,EAAY,UAGnD,EAAW,QAAQ,EAAU,CAAE,MAAM,IAErC,MAAM,EAAQ,EAAc,cAAc,GAG1C,EAAK,WAAa,EAAO,YACvB,EAAc,OAAO,qBAAqB,GAC1C,EAAc,OAAO,oBAAoB,EAAM,EAAM,OAAS,KAI5D,EAAY,aAMd,EAAK,YAAc,EAAc,OAAO,iBAAiB,EAAY,aAAc,GAGnF,EAAK,YAAc,EAAK,WAAW,GACrC,GAGF,CAAE,SAAU,SAuEd,EAAO,WAAW,IAAI,mBAAmB,iBAAiB,CACxD,MAAO,SACP,KAtDF,SAA0B,GAAa,OAAQ,IAC7C,MAAM,EAAgB,EAAW,uBAAuB,OAAQ,CAC9D,MAAO,mBAGH,EASR,SAAyB,GAAa,OAAQ,IAC5C,MAAM,EAAoB,IAAI,kBAAkB,EAAW,UAErD,EAAU,EAAU,aAAa,WACjC,EAAc,EAAU,aAAa,eAE3C,IAAK,IAAY,EACf,OAAO,KAGT,IAAI,EAAa,KAEjB,GAAI,EACF,EAAa,EAAkB,OAAO,GAAa,SAAS,QACvD,GAAI,EAAS,CAClB,MAAM,EAAa,EAAQ,WAAW,UAAW,cAE3C,EAAU,OAAO,UAAU,EAAY,EAAY,eACzD,EAAa,EAAkB,OAAO,GAAS,SAAS,GAGxD,EAAW,aAAa,cAAe,EAAS,EAClD,CAMA,GAAI,EACF,OAAO,EAAW,mBAAmB,MAAO,EAAW,gBAAiB,CACtE,uBAAwB,CAAC,SAI7B,OAAO,IACT,CA5CwB,CAAgB,EAAW,CAAE,OAAQ,IAM3D,OAJI,GACF,EAAW,OAAO,EAAW,iBAAiB,EAAe,GAAI,GAG5D,SAAS,EAAe,EACjC,IA8CA,EAAO,WAAW,IAAI,gBAAgB,iBAAiB,CACrD,MAAO,SACP,KA0BF,SAA0B,GAAa,OAAQ,IAC7C,MAAM,EAAoB,IAAI,kBAAkB,EAAW,UAGrD,EACJ,EAAU,aAAa,gBAAkB,OAAO,iBAAiB,EAAU,aAAa,YAEpF,EAAoB,EAAkB,OAAO,GAAY,SAAS,GAExE,OAAO,EAAM,EAAY,EAC3B,IAGA,EAAO,QAAQ,OAAO,GACpB,sBACA,uCAAuC,EAAO,OAAQ,GAAgB,EAAY,SAAS,qBAI7F,MAAM,IAAE,EAAG,IAAE,GAAQ,EAAO,KAK5B,EAAO,KAAK,GACV,OACC,IACC,MAAM,EAAS,EAAE,OACX,EAAe,OAAO,SAAS,GAIrC,EAAE,OAAS,OAAO,uBAAuB,EAAa,GAExD,CAAE,SAAU,QAMd,EAAO,KAAK,GACV,OACA,CAAC,EAAG,KAEF,IAAI,EAAe,EAAK,GAExB,MAAM,EAAS,wCACT,EAAW,GACjB,IAAI,EAGJ,KAAiD,QAAzC,EAAU,EAAO,KAAK,KAC5B,EAAS,KAAK,EAAQ,IAIxB,EAAS,SAAS,IAChB,GAAI,EAAQ,SAAS,oBAAqB,CAExC,MAAM,EAAQ,MAAM,MAAM,mBAAmB,QAC7C,EAAe,EAAa,QAAQ,EAAS,EAC/C,MAAO,GAAI,EAAQ,SAAS,QAAS,CAEnC,MAAM,EAAS,8BACT,EAAU,EAAQ,MAAM,GAC9B,GAAgB,OAAZ,EAAkB,CACpB,MAAM,EAAY,OAAO,cAAc,EAAQ,IAC/C,EAAe,EAAa,QAAQ,EAAS,EAC/C,CACF,KAGF,EAAK,GAAK,CAAY,GAExB,CAAE,SAAU,QAEhB,CAMA,YAAA,GACE,OAAO,YAAc,CACnB,UACA,cACA,YACA,cACA,UACA,4BACA,oBACA,kCACA,gCACA,YAEJ","file":"/npm/@wiris/mathtype-ckeditor5@8.14.0/src/plugin.js","sourceRoot":"","sourcesContent":["/**\n * Minified by jsDelivr using Terser v5.39.0.\n * Original file: /npm/@wiris/mathtype-ckeditor5@8.14.0/src/plugin.js\n *\n * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files\n */\n","// CKEditor imports\nimport { Plugin } from \"ckeditor5/src/core.js\";\nimport { ButtonView } from \"ckeditor5/src/ui.js\";\nimport { ClickObserver, HtmlDataProcessor, XmlDataProcessor, ViewUpcastWriter } from \"ckeditor5/src/engine.js\";\nimport { Widget, toWidget, viewToModelPositionOutsideModelElement } from \"ckeditor5/src/widget.js\";\n\n// MathType API imports\nimport IntegrationModel from \"@wiris/mathtype-html-integration-devkit/src/integrationmodel.js\";\nimport Core from \"@wiris/mathtype-html-integration-devkit/src/core.src.js\";\nimport Parser from \"@wiris/mathtype-html-integration-devkit/src/parser.js\";\nimport Util from \"@wiris/mathtype-html-integration-devkit/src/util.js\";\nimport Image from \"@wiris/mathtype-html-integration-devkit/src/image.js\";\nimport Configuration from \"@wiris/mathtype-html-integration-devkit/src/configuration.js\";\nimport Listeners from \"@wiris/mathtype-html-integration-devkit/src/listeners.js\";\nimport MathML from \"@wiris/mathtype-html-integration-devkit/src/mathml.js\";\nimport Latex from \"@wiris/mathtype-html-integration-devkit/src/latex.js\";\nimport StringManager from \"@wiris/mathtype-html-integration-devkit/src/stringmanager.js\";\nimport \"@wiris/mathtype-html-integration-devkit/src/md5.js\";\n\n// Local imports\nimport { MathTypeCommand, ChemTypeCommand } from \"./commands.js\";\nimport CKEditor5Integration from \"./integration.js\";\n\nimport mathIcon from \"../theme/icons/ckeditor5-formula.svg\";\nimport chemIcon from \"../theme/icons/ckeditor5-chem.svg\";\n\nimport packageInfo from \"../package.json\";\n\nexport let currentInstance = null; // eslint-disable-line import/no-mutable-exports\n\nexport default class MathType extends Plugin {\n  static get requires() {\n    return [Widget];\n  }\n\n  static get pluginName() {\n    return \"MathType\";\n  }\n\n  init() {\n    // Create the MathType API Integration object\n    const integration = this._addIntegration();\n    currentInstance = integration;\n\n    // Add the MathType and ChemType commands to the editor\n    this._addCommands();\n\n    // Add the buttons for MathType and ChemType\n    this._addViews(integration);\n\n    // Registers the <mathml> element in the schema\n    this._addSchema();\n\n    // Add the downcast and upcast converters\n    this._addConverters(integration);\n\n    // Expose the WirisPlugin variable to the window\n    this._exposeWiris();\n  }\n\n  /**\n   * Inherited from Plugin class: Executed when CKEditor5 is destroyed\n   */\n  destroy() {\n    // eslint-disable-line class-methods-use-this\n    currentInstance?.destroy();\n  }\n\n  /**\n   * Create the MathType API Integration object\n   * @returns {CKEditor5Integration} the integration object\n   */\n  _addIntegration() {\n    const { editor } = this;\n\n    /**\n     * Integration model constructor attributes.\n     * @type {integrationModelProperties}\n     */\n    const integrationProperties = {};\n    integrationProperties.environment = {};\n    integrationProperties.environment.editor = \"CKEditor5\";\n    integrationProperties.environment.editorVersion = \"5.x\";\n    integrationProperties.version = packageInfo.version;\n    integrationProperties.editorObject = editor;\n    integrationProperties.serviceProviderProperties = {};\n    integrationProperties.serviceProviderProperties.URI = \"https://www.wiris.net/demo/plugins/app\";\n    integrationProperties.serviceProviderProperties.server = \"java\";\n    integrationProperties.target = editor.sourceElement;\n    integrationProperties.scriptName = \"bundle.js\";\n    integrationProperties.managesLanguage = true;\n    // etc\n\n    // There are platforms like Drupal that initialize CKEditor but they hide or remove the container element.\n    // To avoid a wrong behavior, this integration only starts if the workspace container exists.\n    let integration;\n    if (integrationProperties.target) {\n      // Instance of the integration associated to this editor instance\n      integration = new CKEditor5Integration(integrationProperties);\n      integration.init();\n      integration.listeners.fire(\"onTargetReady\", {});\n\n      integration.checkElement();\n\n      this.listenTo(\n        editor.editing.view.document,\n        \"click\",\n        (evt, data) => {\n          // Is Double-click\n          if (data.domEvent.detail === 2) {\n            integration.doubleClickHandler(data.domTarget, data.domEvent);\n            evt.stop();\n          }\n        },\n        { priority: \"highest\" },\n      );\n    }\n\n    return integration;\n  }\n\n  /**\n   * Add the MathType and ChemType commands to the editor\n   */\n  _addCommands() {\n    const { editor } = this;\n\n    // Add command to open the formula editor\n    editor.commands.add(\"MathType\", new MathTypeCommand(editor));\n\n    // Add command to open the chemistry formula editor\n    editor.commands.add(\"ChemType\", new ChemTypeCommand(editor));\n  }\n\n  /**\n   * Add the buttons for MathType and ChemType\n   * @param {CKEditor5Integration} integration the integration object\n   */\n  _addViews(integration) {\n    const { editor } = this;\n\n    // Check if MathType editor is enabled\n    if (Configuration.get(\"editorEnabled\")) {\n      // Add button for the formula editor\n      editor.ui.componentFactory.add(\"MathType\", (locale) => {\n        const view = new ButtonView(locale);\n\n        // View is enabled iff command is enabled\n        view.bind(\"isEnabled\").to(editor.commands.get(\"MathType\"), \"isEnabled\");\n        view.set({\n          label: StringManager.get(\"insert_math\", integration.getLanguage()),\n          icon: mathIcon,\n          tooltip: true,\n        });\n\n        // Callback executed once the image is clicked.\n        view.on(\"execute\", () => {\n          editor.execute(\"MathType\", {\n            integration, // Pass integration as parameter\n          });\n        });\n\n        return view;\n      });\n    }\n\n    // Check if ChemType editor is enabled\n    if (Configuration.get(\"chemEnabled\")) {\n      // Add button for the chemistry formula editor\n      editor.ui.componentFactory.add(\"ChemType\", (locale) => {\n        const view = new ButtonView(locale);\n\n        // View is enabled iff command is enabled\n        view.bind(\"isEnabled\").to(editor.commands.get(\"ChemType\"), \"isEnabled\");\n\n        view.set({\n          label: StringManager.get(\"insert_chem\", integration.getLanguage()),\n          icon: chemIcon,\n          tooltip: true,\n        });\n\n        // Callback executed once the image is clicked.\n        view.on(\"execute\", () => {\n          editor.execute(\"ChemType\", {\n            integration, // Pass integration as parameter\n          });\n        });\n\n        return view;\n      });\n    }\n\n    // Observer for the Double-click event\n    editor.editing.view.addObserver(ClickObserver);\n  }\n\n  /**\n   * Registers the <mathml> element in the schema\n   */\n  _addSchema() {\n    const { schema } = this.editor.model;\n\n    schema.register(\"mathml\", {\n      inheritAllFrom: \"$inlineObject\",\n      allowAttributes: [\"formula\", \"htmlContent\"],\n    });\n  }\n\n  /**\n   * Add the downcast and upcast converters\n   */\n  _addConverters(integration) {\n    const { editor } = this;\n\n    // Editing view -> Model\n    editor.conversion.for(\"upcast\").elementToElement({\n      view: {\n        name: \"span\",\n        classes: \"ck-math-widget\",\n      },\n      model: (viewElement, { writer: modelWriter }) => {\n        const formula = MathML.safeXmlDecode(viewElement.getChild(0).getAttribute(\"data-mathml\"));\n        return modelWriter.createElement(\"mathml\", {\n          formula,\n        });\n      },\n    });\n\n    // Data view -> Model\n    editor.data.upcastDispatcher.on(\"element:math\", (evt, data, conversionApi) => {\n      const { consumable, writer } = conversionApi;\n      const { viewItem } = data;\n\n      // When element was already consumed then skip it.\n      if (!consumable.test(viewItem, { name: true })) {\n        return;\n      }\n\n      // If we encounter any <math> with a LaTeX annotation inside,\n      // convert it into a \"$$...$$\" string.\n      const isLatex = mathIsLatex(viewItem); // eslint-disable-line no-use-before-define\n\n      // Get the formula of the <math> (which is all its children).\n      const processor = new XmlDataProcessor(editor.editing.view.document);\n\n      // Only god knows why the following line makes viewItem lose all of its children,\n      // so we obtain isLatex before doing this because we need viewItem's children for that.\n      const upcastWriter = new ViewUpcastWriter(editor.editing.view.document);\n      const viewDocumentFragment = upcastWriter.createDocumentFragment(viewItem.getChildren());\n\n      // and obtain the attributes of <math> too!\n      const mathAttributes = [...viewItem.getAttributes()].map(([key, value]) => ` ${key}=\"${value}\"`).join(\"\");\n\n      // We process the document fragment\n      let formula = processor.toData(viewDocumentFragment) || \"\";\n\n      // And obtain the complete formula\n      formula = Util.htmlSanitize(`<math${mathAttributes}>${formula}</math>`);\n\n      // Replaces the < & > characters to its HTMLEntity to avoid render issues.\n      formula = formula.replaceAll('\"<\"', '\"&lt;\"').replaceAll('\">\"', '\"&gt;\"').replaceAll(\"><<\", \">&lt;<\");\n\n      /* Model node that contains what's going to actually be inserted. This can be either:\n            - A <mathml> element with a formula attribute set to the given formula, or\n            - If the original <math> had a LaTeX annotation, then the annotation surrounded by \"$$...$$\" */\n      const modelNode = isLatex\n        ? writer.createText(Parser.initParse(formula, integration.getLanguage()))\n        : writer.createElement(\"mathml\", { formula });\n\n      // Find allowed parent for element that we are going to insert.\n      // If current parent does not allow to insert element but one of the ancestors does\n      // then split nodes to allowed parent.\n      const splitResult = conversionApi.splitToAllowedParent(modelNode, data.modelCursor);\n\n      // When there is no split result it means that we can't insert element to model tree, so let's skip it.\n      if (!splitResult) {\n        return;\n      }\n\n      // Insert element on allowed position.\n      conversionApi.writer.insert(modelNode, splitResult.position);\n\n      // Consume appropriate value from consumable values list.\n      consumable.consume(viewItem, { name: true });\n\n      const parts = conversionApi.getSplitParts(modelNode);\n\n      // Set conversion result range.\n      data.modelRange = writer.createRange(\n        conversionApi.writer.createPositionBefore(modelNode),\n        conversionApi.writer.createPositionAfter(parts[parts.length - 1]),\n      );\n\n      // Now we need to check where the `modelCursor` should be.\n      if (splitResult.cursorParent) {\n        // If we split parent to insert our element then we want to continue conversion in the new part of the split parent.\n        //\n        // before: <allowed><notAllowed>foo[]</notAllowed></allowed>\n        // after:  <allowed><notAllowed>foo</notAllowed><converted></converted><notAllowed>[]</notAllowed></allowed>\n\n        data.modelCursor = conversionApi.writer.createPositionAt(splitResult.cursorParent, 0);\n      } else {\n        // Otherwise just continue after inserted element.\n        data.modelCursor = data.modelRange.end;\n      }\n    });\n\n    // Data view -> Model\n    editor.data.upcastDispatcher.on(\n      \"element:img\",\n      (evt, data, conversionApi) => {\n        const { consumable, writer } = conversionApi;\n        const { viewItem } = data;\n\n        // Only upcast when is wiris formula\n        if (viewItem.getClassNames().next().value !== \"Wirisformula\") {\n          return;\n        }\n\n        //  The following code ensures that the element's name, attributes, and classes are consumed.\n        // This means that they are marked as handled so that other parts of the system or plugins don't process them again.\n\n        // Check if we can consume the element name.\n        if (!consumable.test(viewItem, { name: true })) {\n          return;\n        }\n\n        // Consume the name, attributes, and classes so nothing else processes it.\n        consumable.consume(viewItem, { name: true });\n        for (const attrName of viewItem.getAttributes()) {\n          consumable.consume(viewItem, { attributes: [attrName] });\n        }\n\n        for (const className of viewItem.getClassNames()) {\n          consumable.consume(viewItem, { classes: [className] });\n        }\n\n        const mathAttributes = [...viewItem.getAttributes()].map(([key, value]) => ` ${key}=\"${value}\"`).join(\"\");\n        const htmlContent = Util.htmlSanitize(`<img${mathAttributes}>`);\n\n        const modelNode = writer.createElement(\"mathml\", { htmlContent });\n\n        // Find allowed parent for element that we are going to insert.\n        // If current parent does not allow to insert element but one of the ancestors does\n        // then split nodes to allowed parent.\n        const splitResult = conversionApi.splitToAllowedParent(modelNode, data.modelCursor);\n\n        // When there is no split result it means that we can't insert element to model tree, so let's skip it.\n        if (!splitResult) {\n          return;\n        }\n\n        // Insert element on allowed position.\n        conversionApi.writer.insert(modelNode, splitResult.position);\n\n        // Consume appropriate value from consumable values list.\n        consumable.consume(viewItem, { name: true });\n\n        const parts = conversionApi.getSplitParts(modelNode);\n\n        // Set conversion result range.\n        data.modelRange = writer.createRange(\n          conversionApi.writer.createPositionBefore(modelNode),\n          conversionApi.writer.createPositionAfter(parts[parts.length - 1]),\n        );\n\n        // Now we need to check where the `modelCursor` should be.\n        if (splitResult.cursorParent) {\n          // If we split parent to insert our element then we want to continue conversion in the new part of the split parent.\n          //\n          // before: <allowed><notAllowed>foo[]</notAllowed></allowed>\n          // after:  <allowed><notAllowed>foo</notAllowed><converted></converted><notAllowed>[]</notAllowed></allowed>\n\n          data.modelCursor = conversionApi.writer.createPositionAt(splitResult.cursorParent, 0);\n        } else {\n          // Otherwise just continue after inserted element.\n          data.modelCursor = data.modelRange.end;\n        }\n      },\n      // Ensures MathType processes the Wiris formulas before other plugins, preventing conflicts.\n      { priority: \"high\" },\n    );\n\n    /**\n     * Whether the given view <math> element has a LaTeX annotation element.\n     * @param {*} math\n     * @returns {bool}\n     */\n    function mathIsLatex(math) {\n      const semantics = math.getChild(0);\n      if (!semantics || semantics.name !== \"semantics\") return false;\n      for (const child of semantics.getChildren()) {\n        if (child.name === \"annotation\" && child.getAttribute(\"encoding\") === \"LaTeX\") {\n          return true;\n        }\n      }\n      return false;\n    }\n\n    function createViewWidget(modelItem, { writer: viewWriter }) {\n      const widgetElement = viewWriter.createContainerElement(\"span\", {\n        class: \"ck-math-widget\",\n      });\n\n      const mathUIElement = createViewImage(modelItem, { writer: viewWriter }); // eslint-disable-line no-use-before-define\n\n      if (mathUIElement) {\n        viewWriter.insert(viewWriter.createPositionAt(widgetElement, 0), mathUIElement);\n      }\n\n      return toWidget(widgetElement, viewWriter);\n    }\n\n    function createViewImage(modelItem, { writer: viewWriter }) {\n      const htmlDataProcessor = new HtmlDataProcessor(viewWriter.document);\n\n      const formula = modelItem.getAttribute(\"formula\");\n      const htmlContent = modelItem.getAttribute(\"htmlContent\");\n\n      if (!formula && !htmlContent) {\n        return null;\n      }\n\n      let imgElement = null;\n\n      if (htmlContent) {\n        imgElement = htmlDataProcessor.toView(htmlContent).getChild(0);\n      } else if (formula) {\n        const mathString = formula.replaceAll('ref=\"<\"', 'ref=\"&lt;\"');\n\n        const imgHtml = Parser.initParse(mathString, integration.getLanguage());\n        imgElement = htmlDataProcessor.toView(imgHtml).getChild(0);\n\n        // Add HTML element (<img>) to model\n        viewWriter.setAttribute(\"htmlContent\", imgHtml, modelItem);\n      }\n\n      /* Although we use the HtmlDataProcessor to obtain the attributes,\n       *  we must create a new EmptyElement which is independent of the\n       *  DataProcessor being used by this editor instance\n       */\n      if (imgElement) {\n        return viewWriter.createEmptyElement(\"img\", imgElement.getAttributes(), {\n          renderUnsafeAttributes: [\"src\"],\n        });\n      }\n\n      return null;\n    }\n\n    // Model -> Editing view\n    editor.conversion.for(\"editingDowncast\").elementToElement({\n      model: \"mathml\",\n      view: createViewWidget,\n    });\n\n    // Model -> Data view\n    editor.conversion.for(\"dataDowncast\").elementToElement({\n      model: \"mathml\",\n      view: createDataString, // eslint-disable-line no-use-before-define\n    });\n\n    /**\n     * Makes a copy of the given view node.\n     * @param {module:engine/view/node~Node} sourceNode Node to copy.\n     * @returns {module:engine/view/node~Node} Copy of the node.\n     */\n    function clone(viewWriter, sourceNode) {\n      if (sourceNode.is(\"text\")) {\n        return viewWriter.createText(sourceNode.data);\n      }\n      if (sourceNode.is(\"element\")) {\n        if (sourceNode.is(\"emptyElement\")) {\n          return viewWriter.createEmptyElement(sourceNode.name, sourceNode.getAttributes());\n        }\n        const element = viewWriter.createContainerElement(sourceNode.name, sourceNode.getAttributes());\n        for (const child of sourceNode.getChildren()) {\n          viewWriter.insert(viewWriter.createPositionAt(element, \"end\"), clone(viewWriter, child));\n        }\n        return element;\n      }\n\n      throw new Exception(\"Given node has unsupported type.\"); // eslint-disable-line no-undef\n    }\n\n    function createDataString(modelItem, { writer: viewWriter }) {\n      const htmlDataProcessor = new HtmlDataProcessor(viewWriter.document);\n\n      // Load img element\n      const mathString =\n        modelItem.getAttribute(\"htmlContent\") || Parser.endParseSaveMode(modelItem.getAttribute(\"formula\"));\n\n      const sourceMathElement = htmlDataProcessor.toView(mathString).getChild(0);\n\n      return clone(viewWriter, sourceMathElement);\n    }\n\n    // This stops the view selection getting into the <span>s and messing up caret movement\n    editor.editing.mapper.on(\n      \"viewToModelPosition\",\n      viewToModelPositionOutsideModelElement(editor.model, (viewElement) => viewElement.hasClass(\"ck-math-widget\")),\n    );\n\n    // Keep a reference to the original get and set function.\n    const { get, set } = editor.data;\n\n    /**\n     * Hack to transform $$latex$$ into <math> in editor.getData()'s output.\n     */\n    editor.data.on(\n      \"get\",\n      (e) => {\n        const output = e.return;\n        const parsedResult = Parser.endParse(output);\n\n        // Cleans all the semantics tag for safexml\n        // including the handwritten data points\n        e.return = MathML.removeSafeXMLSemantics(parsedResult);\n      },\n      { priority: \"low\" },\n    );\n\n    /**\n     * Hack to transform <math> with LaTeX into $$LaTeX$$ and formula images in editor.setData().\n     */\n    editor.data.on(\n      \"set\",\n      (e, args) => {\n        // Retrieve the data to be set on the CKEditor.\n        let modifiedData = args[0];\n        // Regex to find all mathml formulas.\n        const regexp = /(<img\\b[^>]*>)|(<math(.*?)<\\/math>)/gm;\n        const formulas = [];\n        let formula;\n\n        // Both data.set from the source plugin and console command are taken into account as the data received is MathML or an image containing the MathML.\n        while ((formula = regexp.exec(modifiedData)) !== null) {\n          formulas.push(formula[0]);\n        }\n\n        // Loop to find LaTeX and formula images and replace the MathML for the both.\n        formulas.forEach((formula) => {\n          if (formula.includes('encoding=\"LaTeX\"')) {\n            // LaTeX found.\n            const latex = `$$$${Latex.getLatexFromMathML(formula)}$$$`; // We add $$$ instead of $$ because the replace function ignores one $.\n            modifiedData = modifiedData.replace(formula, latex);\n          } else if (formula.includes(\"<img\")) {\n            // If we found a formula image, we should find MathML data, and then substitute the entire image.\n            const regexp = /«math\\b[^»]*»(.*?)«\\/math»/g;\n            const safexml = formula.match(regexp);\n            if (safexml !== null) {\n              const decodeXML = MathML.safeXmlDecode(safexml[0]);\n              modifiedData = modifiedData.replace(formula, decodeXML);\n            }\n          }\n        });\n\n        args[0] = modifiedData;\n      },\n      { priority: \"high\" },\n    );\n  }\n\n  /**\n   * Expose the WirisPlugin variable to the window\n   */\n  // eslint-disable-next-line class-methods-use-this\n  _exposeWiris() {\n    window.WirisPlugin = {\n      Core,\n      Parser,\n      Image,\n      MathML,\n      Util,\n      Configuration,\n      Listeners,\n      IntegrationModel,\n      currentInstance,\n      Latex,\n    };\n  }\n}\n"]}