From fbb5b807812fc58a6dad2aeb5bdaf3fcdfd76622 Mon Sep 17 00:00:00 2001 From: Andrew Nicols Date: Thu, 6 Feb 2025 13:50:02 +0800 Subject: [PATCH] MDL-83794 editor_tiny: Explicitly list MathML content --- lib/editor/tiny/amd/build/content.min.js | 10 +- lib/editor/tiny/amd/build/content.min.js.map | 2 +- lib/editor/tiny/amd/src/content.js | 101 ++++++++++++++----- 3 files changed, 83 insertions(+), 30 deletions(-) diff --git a/lib/editor/tiny/amd/build/content.min.js b/lib/editor/tiny/amd/build/content.min.js index f820606f3c7..b7fffc55230 100644 --- a/lib/editor/tiny/amd/build/content.min.js +++ b/lib/editor/tiny/amd/build/content.min.js @@ -1,3 +1,11 @@ -define("editor_tiny/content",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.addSVGSupport=_exports.addMathMLSupport=void 0;_exports.addMathMLSupport=editor=>{editor.on("PreInit",(()=>{editor.schema.addCustomElements({math:{extends:"div"},"tiny-math-span":{extends:"span"},"tiny-math-block":{extends:"div"}}),editor.parser.addNodeFilter("math",(nodes=>nodes.forEach((node=>{if(node.parent&&("tiny-math-block"===node.parent.name||"tiny-math-span"===node.parent.name))return;const displayMode=(node=>{const style=node.attr("style");return null!=style&&style.includes("display")&&style.match(/display:[^;]*inline/)?"tiny-math-span":"tiny-math-block"})(node);node.wrap(editor.editorManager.html.Node.create(displayMode,{contenteditable:"false"}))})))),editor.serializer.addNodeFilter("tiny-math-span, tiny-math-block",((nodes,name)=>nodes.forEach((node=>{const displayMode=name.replace("tiny-math-","");node.children().forEach((child=>{const currentStyle=child.attr("style");currentStyle?child.attr("style","".concat(currentStyle,";display: ").concat(displayMode)):child.attr("style","display: ".concat(displayMode))})),node.unwrap()}))))}))};_exports.addSVGSupport=editor=>{editor.on("PreInit",(()=>{editor.schema.addCustomElements({svg:{extends:"div"},"tiny-svg-block":{extends:"div"}}),editor.parser.addNodeFilter("svg",(nodes=>nodes.forEach((node=>{node.wrap(editor.editorManager.html.Node.create("tiny-svg-block",{contenteditable:"false"}))})))),editor.serializer.addNodeFilter("tiny-svg-block",(nodes=>nodes.forEach((node=>{node.unwrap()}))))}))}})); +define("editor_tiny/content",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.addSVGSupport=_exports.addMathMLSupport=void 0; +/** + * Module to assist with creation and management of content. + * + * @module editor_tiny/content + * @copyright Andrew Lyons + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +const mathmlContent=["math","maction","annotation","annotation-xml","menclose","merror","mfenced","mfrac","mi","mmultiscripts","mn","mo","mover","mpadded","mphantom","mprescripts","mroot","mrow","ms","semantics","mspace","msqrt","mstyle","msub","msup","msubsup","mtable","mtd","mtext","mtr","munder","munderover","math","mi","mn","mo","ms","mspace","mtext","menclose","merror","mfenced","mfrac","mpadded","mphantom","mroot","mrow","msqrt","mstyle","mmultiscripts","mover","mprescripts","msub","msubsup","msup","munder","munderover","mtable","mtd","mtr","maction","annotation","annotation-xml","semantics"];_exports.addMathMLSupport=editor=>{editor.on("PreInit",(()=>{editor.schema.addCustomElements(mathmlContent.join(",")),editor.schema.addCustomElements("~tiny-math-span,tiny-math-block"),editor.parser.addNodeFilter("math",(nodes=>nodes.forEach((node=>{if(node.parent&&("tiny-math-block"===node.parent.name||"tiny-math-span"===node.parent.name))return;const displayMode=(node=>{const style=node.attr("style");return null!=style&&style.includes("display")&&style.match(/display:[^;]*inline/)?"tiny-math-span":"tiny-math-block"})(node);node.wrap(editor.editorManager.html.Node.create(displayMode,{contenteditable:"false"}))})))),editor.serializer.addNodeFilter("tiny-math-span, tiny-math-block",((nodes,name)=>nodes.forEach((node=>{const displayMode=name.replace("tiny-math-","");node.children().forEach((child=>{const currentStyle=child.attr("style");currentStyle?child.attr("style","".concat(currentStyle,";display: ").concat(displayMode)):child.attr("style","display: ".concat(displayMode))})),node.unwrap()}))))}))};_exports.addSVGSupport=editor=>{editor.on("PreInit",(()=>{editor.schema.addCustomElements("svg,tiny-svg-block"),editor.parser.addNodeFilter("svg",(nodes=>nodes.forEach((node=>{node.wrap(editor.editorManager.html.Node.create("tiny-svg-block",{contenteditable:"false"}))})))),editor.serializer.addNodeFilter("tiny-svg-block",(nodes=>nodes.forEach((node=>{node.unwrap()}))))}))}})); //# sourceMappingURL=content.min.js.map \ No newline at end of file diff --git a/lib/editor/tiny/amd/build/content.min.js.map b/lib/editor/tiny/amd/build/content.min.js.map index d68a9fd5596..959c2f01ec8 100644 --- a/lib/editor/tiny/amd/build/content.min.js.map +++ b/lib/editor/tiny/amd/build/content.min.js.map @@ -1 +1 @@ -{"version":3,"file":"content.min.js","sources":["../src/content.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * TODO describe module content\n *\n * @module editor_tiny/content\n * @copyright 2025 Andrew Lyons \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\n/**\n * Add MathML support to the editor.\n *\n * @param { } editor\n */\nexport const addMathMLSupport = (editor) => {\n const getNodeType = (node) => {\n const style = node.attr('style');\n if (style?.includes('display')) {\n if (style.match(/display:[^;]*inline/)) {\n return 'tiny-math-span';\n }\n }\n return 'tiny-math-block';\n };\n\n\n editor.on('PreInit', () => {\n editor.schema.addCustomElements({\n // Add support for MathML by defining some tiny-math blocks which extends SPAN/DIV.\n // Note: This is blind support and does not check the child content.\n // Any invalid markup will be accepted.\n // Note: We use the same names as the Tiny Premium Math plugin to avoid conflicts if both are enabled.\n math: {\n 'extends': 'div',\n },\n 'tiny-math-span': {\n 'extends': \"span\",\n },\n 'tiny-math-block': {\n 'extends': \"div\",\n },\n });\n\n // Add a Parser filter to wrap math nodes in a tiny-math-[block|span] element.\n editor.parser.addNodeFilter('math', (nodes) => nodes.forEach((node) => {\n if (node.parent) {\n if (node.parent.name === 'tiny-math-block' || node.parent.name === 'tiny-math-span') {\n // Already wrapped.\n return;\n }\n }\n\n const displayMode = getNodeType(node);\n node.wrap(editor.editorManager.html.Node.create(displayMode, {\n contenteditable: 'false',\n }));\n }));\n\n // Add a Serializer filter to remove the tiny-math-[block|span] wrapper.\n editor.serializer.addNodeFilter('tiny-math-span, tiny-math-block', (nodes, name) => nodes.forEach((node) => {\n const displayMode = name.replace('tiny-math-', '');\n node.children().forEach((child) => {\n const currentStyle = child.attr('style');\n if (currentStyle) {\n child.attr('style', `${currentStyle};display: ${displayMode}`);\n } else {\n child.attr('style', `display: ${displayMode}`);\n }\n });\n node.unwrap();\n }));\n });\n};\n\n/**\n * Add SVG support to the editor.\n *\n * @param {TinyMCE} editor\n */\nexport const addSVGSupport = (editor) => {\n editor.on('PreInit', () => {\n editor.schema.addCustomElements({\n // Add support for SVG by defining an SVG tag which extends DIV.\n // Note: This is blind support and does not check the child content.\n // Any invalid markup will be accepted.\n svg: {\n 'extends': \"div\",\n },\n 'tiny-svg-block': {\n 'extends': \"div\",\n },\n });\n\n editor.parser.addNodeFilter('svg', (nodes) => nodes.forEach((node) => {\n node.wrap(editor.editorManager.html.Node.create('tiny-svg-block', {\n contenteditable: 'false',\n }));\n }));\n editor.serializer.addNodeFilter('tiny-svg-block', (nodes) => nodes.forEach((node) => {\n node.unwrap();\n }));\n });\n};\n"],"names":["editor","on","schema","addCustomElements","math","parser","addNodeFilter","nodes","forEach","node","parent","name","displayMode","style","attr","includes","match","getNodeType","wrap","editorManager","html","Node","create","contenteditable","serializer","replace","children","child","currentStyle","unwrap","svg"],"mappings":"uMA4BiCA,SAY7BA,OAAOC,GAAG,WAAW,KACjBD,OAAOE,OAAOC,kBAAkB,CAK5BC,KAAM,SACS,wBAEG,SACH,0BAEI,SACJ,SAKnBJ,OAAOK,OAAOC,cAAc,QAASC,OAAUA,MAAMC,SAASC,UACtDA,KAAKC,SACoB,oBAArBD,KAAKC,OAAOC,MAAmD,mBAArBF,KAAKC,OAAOC,mBAMxDC,YArCOH,CAAAA,aACXI,MAAQJ,KAAKK,KAAK,gBACpBD,MAAAA,OAAAA,MAAOE,SAAS,YACZF,MAAMG,MAAM,uBACL,iBAGR,mBA8BiBC,CAAYR,MAChCA,KAAKS,KAAKlB,OAAOmB,cAAcC,KAAKC,KAAKC,OAAOV,YAAa,CACzDW,gBAAiB,gBAKzBvB,OAAOwB,WAAWlB,cAAc,mCAAmC,CAACC,MAAOI,OAASJ,MAAMC,SAASC,aACzFG,YAAcD,KAAKc,QAAQ,aAAc,IAC/ChB,KAAKiB,WAAWlB,SAASmB,cACfC,aAAeD,MAAMb,KAAK,SAC5Bc,aACAD,MAAMb,KAAK,kBAAYc,kCAAyBhB,cAEhDe,MAAMb,KAAK,2BAAqBF,iBAGxCH,KAAKoB,yCAUa7B,SAC1BA,OAAOC,GAAG,WAAW,KACjBD,OAAOE,OAAOC,kBAAkB,CAI5B2B,IAAK,SACU,wBAEG,SACH,SAInB9B,OAAOK,OAAOC,cAAc,OAAQC,OAAUA,MAAMC,SAASC,OACzDA,KAAKS,KAAKlB,OAAOmB,cAAcC,KAAKC,KAAKC,OAAO,iBAAkB,CAC9DC,gBAAiB,gBAGzBvB,OAAOwB,WAAWlB,cAAc,kBAAmBC,OAAUA,MAAMC,SAASC,OACxEA,KAAKoB"} \ No newline at end of file +{"version":3,"file":"content.min.js","sources":["../src/content.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Module to assist with creation and management of content.\n *\n * @module editor_tiny/content\n * @copyright Andrew Lyons \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\n// MathML valid elements retrieved from https://developer.mozilla.org/en-US/docs/Web/MathML/Element.\nconst mathmlContent = [\n 'math',\n 'maction',\n 'annotation',\n 'annotation-xml',\n 'menclose',\n 'merror',\n 'mfenced',\n 'mfrac',\n 'mi',\n 'mmultiscripts',\n 'mn',\n 'mo',\n 'mover',\n 'mpadded',\n 'mphantom',\n 'mprescripts',\n 'mroot',\n 'mrow',\n 'ms',\n 'semantics',\n 'mspace',\n 'msqrt',\n 'mstyle',\n 'msub',\n 'msup',\n 'msubsup',\n 'mtable',\n 'mtd',\n 'mtext',\n 'mtr',\n 'munder',\n 'munderover',\n 'math',\n 'mi',\n 'mn',\n 'mo',\n 'ms',\n 'mspace',\n 'mtext',\n 'menclose',\n 'merror',\n 'mfenced',\n 'mfrac',\n 'mpadded',\n 'mphantom',\n 'mroot',\n 'mrow',\n 'msqrt',\n 'mstyle',\n 'mmultiscripts',\n 'mover',\n 'mprescripts',\n 'msub',\n 'msubsup',\n 'msup',\n 'munder',\n 'munderover',\n 'mtable',\n 'mtd',\n 'mtr',\n 'maction',\n 'annotation',\n 'annotation-xml',\n 'semantics',\n];\n\n/**\n * Add MathML support to the editor.\n *\n * @param { } editor\n */\nexport const addMathMLSupport = (editor) => {\n const getNodeType = (node) => {\n const style = node.attr('style');\n if (style?.includes('display')) {\n if (style.match(/display:[^;]*inline/)) {\n return 'tiny-math-span';\n }\n }\n return 'tiny-math-block';\n };\n\n\n editor.on('PreInit', () => {\n editor.schema.addCustomElements(mathmlContent.join(','));\n editor.schema.addCustomElements('~tiny-math-span,tiny-math-block');\n\n // Add a Parser filter to wrap math nodes in a tiny-math-[block|span] element.\n editor.parser.addNodeFilter('math', (nodes) => nodes.forEach((node) => {\n if (node.parent) {\n if (node.parent.name === 'tiny-math-block' || node.parent.name === 'tiny-math-span') {\n // Already wrapped.\n return;\n }\n }\n\n const displayMode = getNodeType(node);\n node.wrap(editor.editorManager.html.Node.create(displayMode, {\n contenteditable: 'false',\n }));\n }));\n\n // Add a Serializer filter to remove the tiny-math-[block|span] wrapper.\n editor.serializer.addNodeFilter('tiny-math-span, tiny-math-block', (nodes, name) => nodes.forEach((node) => {\n const displayMode = name.replace('tiny-math-', '');\n node.children().forEach((child) => {\n const currentStyle = child.attr('style');\n if (currentStyle) {\n child.attr('style', `${currentStyle};display: ${displayMode}`);\n } else {\n child.attr('style', `display: ${displayMode}`);\n }\n });\n node.unwrap();\n }));\n });\n};\n\n/**\n * Add SVG support to the editor.\n *\n * @param {TinyMCE} editor\n */\nexport const addSVGSupport = (editor) => {\n editor.on('PreInit', () => {\n editor.schema.addCustomElements('svg,tiny-svg-block');\n\n editor.parser.addNodeFilter('svg', (nodes) => nodes.forEach((node) => {\n node.wrap(editor.editorManager.html.Node.create('tiny-svg-block', {\n contenteditable: 'false',\n }));\n }));\n editor.serializer.addNodeFilter('tiny-svg-block', (nodes) => nodes.forEach((node) => {\n node.unwrap();\n }));\n });\n};\n"],"names":["mathmlContent","editor","on","schema","addCustomElements","join","parser","addNodeFilter","nodes","forEach","node","parent","name","displayMode","style","attr","includes","match","getNodeType","wrap","editorManager","html","Node","create","contenteditable","serializer","replace","children","child","currentStyle","unwrap"],"mappings":";;;;;;;;MAwBMA,cAAgB,CAClB,OACA,UACA,aACA,iBACA,WACA,SACA,UACA,QACA,KACA,gBACA,KACA,KACA,QACA,UACA,WACA,cACA,QACA,OACA,KACA,YACA,SACA,QACA,SACA,OACA,OACA,UACA,SACA,MACA,QACA,MACA,SACA,aACA,OACA,KACA,KACA,KACA,KACA,SACA,QACA,WACA,SACA,UACA,QACA,UACA,WACA,QACA,OACA,QACA,SACA,gBACA,QACA,cACA,OACA,UACA,OACA,SACA,aACA,SACA,MACA,MACA,UACA,aACA,iBACA,uCAQ6BC,SAY7BA,OAAOC,GAAG,WAAW,KACjBD,OAAOE,OAAOC,kBAAkBJ,cAAcK,KAAK,MACnDJ,OAAOE,OAAOC,kBAAkB,mCAGhCH,OAAOK,OAAOC,cAAc,QAASC,OAAUA,MAAMC,SAASC,UACtDA,KAAKC,SACoB,oBAArBD,KAAKC,OAAOC,MAAmD,mBAArBF,KAAKC,OAAOC,mBAMxDC,YAxBOH,CAAAA,aACXI,MAAQJ,KAAKK,KAAK,gBACpBD,MAAAA,OAAAA,MAAOE,SAAS,YACZF,MAAMG,MAAM,uBACL,iBAGR,mBAiBiBC,CAAYR,MAChCA,KAAKS,KAAKlB,OAAOmB,cAAcC,KAAKC,KAAKC,OAAOV,YAAa,CACzDW,gBAAiB,gBAKzBvB,OAAOwB,WAAWlB,cAAc,mCAAmC,CAACC,MAAOI,OAASJ,MAAMC,SAASC,aACzFG,YAAcD,KAAKc,QAAQ,aAAc,IAC/ChB,KAAKiB,WAAWlB,SAASmB,cACfC,aAAeD,MAAMb,KAAK,SAC5Bc,aACAD,MAAMb,KAAK,kBAAYc,kCAAyBhB,cAEhDe,MAAMb,KAAK,2BAAqBF,iBAGxCH,KAAKoB,yCAUa7B,SAC1BA,OAAOC,GAAG,WAAW,KACjBD,OAAOE,OAAOC,kBAAkB,sBAEhCH,OAAOK,OAAOC,cAAc,OAAQC,OAAUA,MAAMC,SAASC,OACzDA,KAAKS,KAAKlB,OAAOmB,cAAcC,KAAKC,KAAKC,OAAO,iBAAkB,CAC9DC,gBAAiB,gBAGzBvB,OAAOwB,WAAWlB,cAAc,kBAAmBC,OAAUA,MAAMC,SAASC,OACxEA,KAAKoB"} \ No newline at end of file diff --git a/lib/editor/tiny/amd/src/content.js b/lib/editor/tiny/amd/src/content.js index 81ce5e97d95..840372a04a4 100644 --- a/lib/editor/tiny/amd/src/content.js +++ b/lib/editor/tiny/amd/src/content.js @@ -14,13 +14,81 @@ // along with Moodle. If not, see . /** - * TODO describe module content + * Module to assist with creation and management of content. * * @module editor_tiny/content - * @copyright 2025 Andrew Lyons + * @copyright Andrew Lyons * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ +// MathML valid elements retrieved from https://developer.mozilla.org/en-US/docs/Web/MathML/Element. +const mathmlContent = [ + 'math', + 'maction', + 'annotation', + 'annotation-xml', + 'menclose', + 'merror', + 'mfenced', + 'mfrac', + 'mi', + 'mmultiscripts', + 'mn', + 'mo', + 'mover', + 'mpadded', + 'mphantom', + 'mprescripts', + 'mroot', + 'mrow', + 'ms', + 'semantics', + 'mspace', + 'msqrt', + 'mstyle', + 'msub', + 'msup', + 'msubsup', + 'mtable', + 'mtd', + 'mtext', + 'mtr', + 'munder', + 'munderover', + 'math', + 'mi', + 'mn', + 'mo', + 'ms', + 'mspace', + 'mtext', + 'menclose', + 'merror', + 'mfenced', + 'mfrac', + 'mpadded', + 'mphantom', + 'mroot', + 'mrow', + 'msqrt', + 'mstyle', + 'mmultiscripts', + 'mover', + 'mprescripts', + 'msub', + 'msubsup', + 'msup', + 'munder', + 'munderover', + 'mtable', + 'mtd', + 'mtr', + 'maction', + 'annotation', + 'annotation-xml', + 'semantics', +]; + /** * Add MathML support to the editor. * @@ -39,21 +107,8 @@ export const addMathMLSupport = (editor) => { editor.on('PreInit', () => { - editor.schema.addCustomElements({ - // Add support for MathML by defining some tiny-math blocks which extends SPAN/DIV. - // Note: This is blind support and does not check the child content. - // Any invalid markup will be accepted. - // Note: We use the same names as the Tiny Premium Math plugin to avoid conflicts if both are enabled. - math: { - 'extends': 'div', - }, - 'tiny-math-span': { - 'extends': "span", - }, - 'tiny-math-block': { - 'extends': "div", - }, - }); + editor.schema.addCustomElements(mathmlContent.join(',')); + editor.schema.addCustomElements('~tiny-math-span,tiny-math-block'); // Add a Parser filter to wrap math nodes in a tiny-math-[block|span] element. editor.parser.addNodeFilter('math', (nodes) => nodes.forEach((node) => { @@ -93,17 +148,7 @@ export const addMathMLSupport = (editor) => { */ export const addSVGSupport = (editor) => { editor.on('PreInit', () => { - editor.schema.addCustomElements({ - // Add support for SVG by defining an SVG tag which extends DIV. - // Note: This is blind support and does not check the child content. - // Any invalid markup will be accepted. - svg: { - 'extends': "div", - }, - 'tiny-svg-block': { - 'extends': "div", - }, - }); + editor.schema.addCustomElements('svg,tiny-svg-block'); editor.parser.addNodeFilter('svg', (nodes) => nodes.forEach((node) => { node.wrap(editor.editorManager.html.Node.create('tiny-svg-block', {