@wiris/mathtype-ckeditor5 8.14.0 → 8.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,7 +5,7 @@
5
5
  })(this, (function (exports, ckeditor5) { 'use strict';
6
6
 
7
7
  var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
8
- /*! @license DOMPurify 3.3.0 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.3.0/LICENSE */
8
+ /*! @license DOMPurify 3.3.1 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.3.1/LICENSE */
9
9
 
10
10
  const {
11
11
  entries,
@@ -303,7 +303,7 @@
303
303
  function createDOMPurify() {
304
304
  let window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal();
305
305
  const DOMPurify = root => createDOMPurify(root);
306
- DOMPurify.version = '3.3.0';
306
+ DOMPurify.version = '3.3.1';
307
307
  DOMPurify.removed = [];
308
308
  if (!window || !window.document || window.document.nodeType !== NODE_TYPE.document || !window.Element) {
309
309
  // Not running in a browser, provide a factory function
@@ -649,6 +649,12 @@
649
649
  }
650
650
  addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS, transformCaseFunc);
651
651
  }
652
+ if (cfg.ADD_FORBID_CONTENTS) {
653
+ if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) {
654
+ FORBID_CONTENTS = clone(FORBID_CONTENTS);
655
+ }
656
+ addToSet(FORBID_CONTENTS, cfg.ADD_FORBID_CONTENTS, transformCaseFunc);
657
+ }
652
658
  /* Add #text in case KEEP_CONTENT is set to true */
653
659
  if (KEEP_CONTENT) {
654
660
  ALLOWED_TAGS['#text'] = true;
@@ -4026,6 +4032,27 @@
4026
4032
  if (mathML == null) {
4027
4033
  mathML = imgObject.getAttribute("alt");
4028
4034
  }
4035
+ // WARNING: This code is needed for CKEditor 5 Track Changes compatibility.
4036
+ // Preserve Track Changes attributes when converting image back to MathML.
4037
+ // This ensures change tracking information is maintained during the roundtrip conversion
4038
+ // (MathML → Image → MathML) in collaborative editing scenarios.
4039
+ const TRACK_CHANGES_ATTRIBUTE_PREFIXES = [
4040
+ "data-suggestion-",
4041
+ "data-comment-"
4042
+ ];
4043
+ const preservedAttributes = {};
4044
+ // Extract Track Changes attributes from the image element
4045
+ for (const { name: attributeName, value: attributeValue } of imgObject.attributes){
4046
+ const isTrackChangesAttribute = TRACK_CHANGES_ATTRIBUTE_PREFIXES.some((prefix)=>attributeName.startsWith(prefix));
4047
+ if (isTrackChangesAttribute) {
4048
+ preservedAttributes[attributeName] = attributeValue;
4049
+ }
4050
+ }
4051
+ // If Track Changes attributes were found, inject them into the MathML opening tag
4052
+ if (Object.keys(preservedAttributes).length > 0) {
4053
+ const attributesString = Object.keys(preservedAttributes).map((name)=>` ${name}="${Util.htmlEntities(preservedAttributes[name])}"`).join("");
4054
+ mathML = mathML.replace(/(<math)/i, `$1${attributesString}`);
4055
+ }
4029
4056
  if (convertToSafeXml) {
4030
4057
  const safeMathML = MathML.safeXmlEncode(mathML);
4031
4058
  return safeMathML;
@@ -4772,6 +4799,29 @@
4772
4799
  mathmlSubstring = mathmlSubstring.substring(4, mathmlSubstring.length);
4773
4800
  imgObject.setAttribute(Configuration.get("imageCustomEditorName"), mathmlSubstring);
4774
4801
  }
4802
+ // WARNING: This code is needed for CKEditor 5 Track Changes compatibility.
4803
+ // Preserve Track Changes attributes (suggestions and comments) when converting MathML to image.
4804
+ // These attributes are needed to maintain change tracking information in collaborative editing scenarios.
4805
+ // They are extracted from the input MathML and transferred to the output image element.
4806
+ const TRACK_CHANGES_ATTRIBUTE_PREFIXES = [
4807
+ "data-suggestion-",
4808
+ "data-comment-"
4809
+ ];
4810
+ const attributePattern = /([\w-]+)="([^"]*)"/g;
4811
+ let attributeMatch;
4812
+ // Parse only the opening <math> tag to extract attributes
4813
+ const mathOpeningTagEnd = mathml.indexOf(">");
4814
+ if (mathOpeningTagEnd !== -1) {
4815
+ const mathOpeningTag = mathml.substring(0, mathOpeningTagEnd);
4816
+ while((attributeMatch = attributePattern.exec(mathOpeningTag)) !== null){
4817
+ const [, attributeName, attributeValue] = attributeMatch;
4818
+ // Transfer Track Changes attributes from MathML to image
4819
+ const isTrackChangesAttribute = TRACK_CHANGES_ATTRIBUTE_PREFIXES.some((prefix)=>attributeName.startsWith(prefix));
4820
+ if (isTrackChangesAttribute) {
4821
+ imgObject.setAttribute(attributeName, Util.htmlEntitiesDecode(attributeValue));
4822
+ }
4823
+ }
4824
+ }
4775
4825
  // Performance enabled.
4776
4826
  if (Configuration.get("wirisPluginPerformance") && (Configuration.get("saveMode") === "xml" || Configuration.get("saveMode") === "safeXml")) {
4777
4827
  let result = JSON.parse(Parser.createShowImageSrc(data, language));
@@ -9742,6 +9792,8 @@
9742
9792
  * Opens formula editor to editing an existing formula. Can be overwritten in order to make some
9743
9793
  * actions from integration part before the formula is edited.
9744
9794
  */ openExistingFormulaEditor() {
9795
+ // Recover owner integration instance.
9796
+ WirisPlugin.currentInstance = this;
9745
9797
  if (window.navigator.onLine) {
9746
9798
  this.core.editionProperties.isNewElement = false;
9747
9799
  this.core.openModalDialog(this.target, this.isIframe);
@@ -11263,7 +11315,9 @@
11263
11315
  // Remove selection
11264
11316
  if (!viewSelection.isCollapsed) {
11265
11317
  for (const range of viewSelection.getRanges()){
11266
- writer.remove(this.editorObject.editing.mapper.toModelRange(range));
11318
+ const modelRange = this.editorObject.editing.mapper.toModelRange(range);
11319
+ const modelSelection = this.editorObject.model.createSelection(modelRange);
11320
+ this.editorObject.model.deleteContent(modelSelection);
11267
11321
  }
11268
11322
  }
11269
11323
  // Set carret after the formula
@@ -11279,7 +11333,7 @@
11279
11333
  if (mathml) {
11280
11334
  this.editorObject.model.insertObject(modelElementNew, position);
11281
11335
  }
11282
- writer.remove(modelElementOld);
11336
+ this.editorObject.model.deleteContent(this.editorObject.model.createSelection(modelElementOld, 'on'));
11283
11337
  }
11284
11338
  // eslint-disable-next-line consistent-return
11285
11339
  return modelElementNew;
@@ -11323,6 +11377,14 @@
11323
11377
  returnObject.node = windowTarget.document.createTextNode(`$$${returnObject.latex}$$`);
11324
11378
  this.editorObject.model.change((writer)=>{
11325
11379
  const { latexRange } = this.core.editionProperties;
11380
+ // Add null check for latexRange.
11381
+ // When the editor is initialized in a textarea element, latexRange may not be set on initial load.
11382
+ // This check ensures formulas can still be inserted by falling back to MathML insertion if latexRange is not available.
11383
+ if (!latexRange) {
11384
+ // Fallback to regular MathML insertion if latexRange is not available
11385
+ this.insertMathml(mathml);
11386
+ return;
11387
+ }
11326
11388
  const startNode = this.findText(latexRange.startContainer);
11327
11389
  const endNode = this.findText(latexRange.endContainer);
11328
11390
  let startPosition = writer.createPositionAt(startNode.parent, startNode.startOffset + latexRange.startOffset);
@@ -11350,7 +11412,8 @@
11350
11412
  range = writer.createRange(startPosition, endPosition);
11351
11413
  }
11352
11414
  }
11353
- writer.remove(range);
11415
+ const modelSelection = this.editorObject.model.createSelection(range);
11416
+ this.editorObject.model.deleteContent(modelSelection);
11354
11417
  writer.insertText(`$$${returnObject.latex}$$`, startNode.getAttributes(), startPosition);
11355
11418
  });
11356
11419
  } else {
@@ -11471,7 +11534,7 @@
11471
11534
 
11472
11535
  var chemIcon = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Generator: Adobe Illustrator 22.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->\n<svg version=\"1.1\" id=\"Layer_1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0px\" y=\"0px\"\n\t viewBox=\"0 0 40.3 49.5\" style=\"enable-background:new 0 0 40.3 49.5;\" xml:space=\"preserve\">\n<style type=\"text/css\">\n\t.st0{fill:#A4CF61;}\n</style>\n<path class=\"st0\" d=\"M39.2,12.1c0-1.9-1.1-3.6-2.7-4.4L24.5,0.9l0,0c-0.7-0.4-1.5-0.6-2.4-0.6c-0.9,0-1.7,0.2-2.4,0.6l0,0L2.3,10.8\n\tl0,0C0.9,11.7,0,13.2,0,14.9h0v19.6h0c0,1.7,0.9,3.3,2.3,4.1l0,0l17.4,9.9l0,0c0.7,0.4,1.5,0.6,2.4,0.6c0.9,0,1.7-0.2,2.4-0.6l0,0\n\tl12.2-6.9h0c1.5-0.8,2.6-2.5,2.6-4.3c0-2.7-2.2-4.9-4.9-4.9c-0.9,0-1.8,0.3-2.5,0.7l0,0l-9.7,5.6l-12.3-7V17.8l12.3-7l9.9,5.7l0,0\n\tc0.7,0.4,1.5,0.6,2.4,0.6C37,17,39.2,14.8,39.2,12.1\"/>\n</svg>\n";
11473
11536
 
11474
- var version = "8.14.0";
11537
+ var version = "8.15.1";
11475
11538
  var packageInfo = {
11476
11539
  version: version};
11477
11540
 
@@ -11491,7 +11554,9 @@
11491
11554
  const integration = this._addIntegration();
11492
11555
  currentInstance = integration;
11493
11556
  // Add the MathType and ChemType commands to the editor
11494
- this._addCommands();
11557
+ this._addCommands(integration);
11558
+ // Add the track changes feature integration
11559
+ this._addTrackChangesIntegration(integration);
11495
11560
  // Add the buttons for MathType and ChemType
11496
11561
  this._addViews(integration);
11497
11562
  // Registers the <mathml> element in the schema
@@ -11811,7 +11876,8 @@
11811
11876
  imgElement = htmlDataProcessor.toView(htmlContent).getChild(0);
11812
11877
  } else if (formula) {
11813
11878
  const mathString = formula.replaceAll('ref="<"', 'ref="&lt;"');
11814
- const imgHtml = Parser.initParse(mathString, integration.getLanguage());
11879
+ const lang = integration?.getLanguage() || "en"; // Safe fallback to 'en' in case integration is undefined.
11880
+ const imgHtml = Parser.initParse(mathString, lang);
11815
11881
  imgElement = htmlDataProcessor.toView(imgHtml).getChild(0);
11816
11882
  // Add HTML element (<img>) to model
11817
11883
  viewWriter.setAttribute("htmlContent", imgHtml, modelItem);
@@ -11869,13 +11935,63 @@
11869
11935
  editor.editing.mapper.on("viewToModelPosition", ckeditor5.viewToModelPositionOutsideModelElement(editor.model, (viewElement)=>viewElement.hasClass("ck-math-widget")));
11870
11936
  // Keep a reference to the original get and set function.
11871
11937
  const { get, set } = editor.data;
11938
+ // Listen to the preview command execution to set a flag in localStorage.
11939
+ // This flag will be used in the getData() to prevent converting formulas while generating the preview.
11940
+ // This is necessary because the preview command uses editor.getData() multiple times internally.
11941
+ const previewCommand = editor.commands.get("previewFinalContent");
11942
+ if (previewCommand) {
11943
+ this.listenTo(previewCommand, "execute", ()=>{
11944
+ localStorage.setItem("isGeneratingPreview", true);
11945
+ setTimeout(()=>{
11946
+ localStorage.setItem("isGeneratingPreview", false);
11947
+ }, 1000);
11948
+ }, {
11949
+ priority: "high"
11950
+ });
11951
+ }
11872
11952
  /**
11873
- * Hack to transform $$latex$$ into <math> in editor.getData()'s output.
11953
+ * Listener for getData() that handles Track Changes and semantics cleanup.
11954
+ *
11955
+ * This listener intercepts the getData() call and processes the output differently
11956
+ * depending on whether we're generating a preview or performing a save operation:
11957
+ *
11958
+ * - Preview Mode: Removes deleted formulas (marked with Track Changes deletion attributes)
11959
+ * while preserving formula images for visual representation.
11960
+ * - Save Mode: Converts formulas to clean MathML by removing semantic annotations
11961
+ * and handwritten data, ensuring clean storage format.
11874
11962
  */ editor.data.on("get", (e)=>{
11875
11963
  const output = e.return;
11964
+ // Check if we're in preview mode (flag set by previewFinalContent command)
11965
+ const isGeneratingPreview = localStorage.getItem("isGeneratingPreview");
11966
+ if (isGeneratingPreview === "true") {
11967
+ // Wrap a <span> around all img elements to preserve Track Changes visibility for formulas.
11968
+ // Span must contain all the img attributes to avoid render issues.
11969
+ const attributesToPreserve = [
11970
+ "data-suggestion-",
11971
+ "data-comment-"
11972
+ ];
11973
+ const previewOutput = output.replace(/<img([^>]*class="Wirisformula"[^>]*)>/g, (match, attributes)=>{
11974
+ // Extract Track Changes attributes
11975
+ const trackChangesAttrs = [];
11976
+ attributesToPreserve.forEach((prefix)=>{
11977
+ const regex = new RegExp(`(${prefix}[^=]*="[^"]*")`, "g");
11978
+ let attrMatch;
11979
+ while((attrMatch = regex.exec(attributes)) !== null){
11980
+ trackChangesAttrs.push(attrMatch[1]);
11981
+ }
11982
+ });
11983
+ const spanAttrs = trackChangesAttrs.length > 0 ? ` ${trackChangesAttrs.join(" ")}` : "";
11984
+ return `<span${spanAttrs}>${match}</span>`;
11985
+ });
11986
+ // Cleans all the semantics tag for safexml
11987
+ // including the handwritten data points
11988
+ e.return = MathML.removeSafeXMLSemantics(previewOutput);
11989
+ return;
11990
+ }
11991
+ // In save mode, convert formula images back to clean MathML
11876
11992
  const parsedResult = Parser.endParse(output);
11877
- // Cleans all the semantics tag for safexml
11878
- // including the handwritten data points
11993
+ // Remove all semantic annotations (including handwritten data points)
11994
+ // to ensure clean, standard MathML format for storage
11879
11995
  e.return = MathML.removeSafeXMLSemantics(parsedResult);
11880
11996
  }, {
11881
11997
  priority: "low"
@@ -11931,6 +12047,18 @@
11931
12047
  Latex
11932
12048
  };
11933
12049
  }
12050
+ _addTrackChangesIntegration(integration) {
12051
+ const { editor } = this;
12052
+ if (editor.plugins.has("TrackChangesEditing")) {
12053
+ const trackChangesEditing = editor.plugins.get("TrackChangesEditing");
12054
+ // Makes MathType and ChemType buttons available when editor is in the track changes mode
12055
+ trackChangesEditing.enableCommand("MathType");
12056
+ trackChangesEditing.enableCommand("ChemType");
12057
+ // Adds custom label replacing the default 'mathml'.
12058
+ // Handles both singular and plural forms.
12059
+ trackChangesEditing.descriptionFactory.registerElementLabel("mathml", (quantity)=>(quantity > 1 ? `${quantity} ` : "") + StringManager.get(quantity > 1 ? "formulas" : "formula", integration?.getLanguage() || "en"));
12060
+ }
12061
+ }
11934
12062
  }
11935
12063
 
11936
12064
  exports.CKEditor5Integration = CKEditor5Integration;