mirror of
https://github.com/moodle/moodle.git
synced 2025-03-23 00:50:15 +01:00
MDL-77740 editor_tiny: Set the Editor window from the iFrame element
This is a workaround for an upstream bug which I have not been able to reproduce outside of Moodle whereby the editor.contentWindow does not math the editor.iframeElement.contentWindow when it should. This issue only seems to affect Firefox, and it may even be a bug in Firefox. It can only be reproduced when using a fresh browser which has never had a TinyMCE window open.
This commit is contained in:
parent
0b973b52e9
commit
50d1671a54
2
lib/editor/tiny/amd/build/editor.min.js
vendored
2
lib/editor/tiny/amd/build/editor.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2
lib/editor/tiny/amd/build/utils.min.js
vendored
2
lib/editor/tiny/amd/build/utils.min.js
vendored
@ -1,3 +1,3 @@
|
||||
define("editor_tiny/utils",["exports","core/templates","./options","core/str"],(function(_exports,_templates,_options,_str){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.removeToolbarButtons=_exports.removeToolbarButton=_exports.removeSubmenuItem=_exports.removeMenubarItems=_exports.removeMenubarItem=_exports.getPluginMetadata=_exports.getImagePath=_exports.getDocumentationLink=_exports.getButtonImage=_exports.ensureEditorIsValid=_exports.displayFilepicker=_exports.addToolbarSection=_exports.addToolbarButtons=_exports.addToolbarButton=_exports.addQuickbarsToolbarItem=_exports.addMenubarItem=_exports.addContextmenuItem=void 0;const getImagePath=function(identifier){let component=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"editor_tiny";return Promise.resolve(M.util.image_url(identifier,component))};_exports.getImagePath=getImagePath;_exports.getButtonImage=async function(identifier){let component=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"editor_tiny";return(0,_templates.renderForPromise)("editor_tiny/toolbar_button",{image:await getImagePath(identifier,component)})};_exports.displayFilepicker=(editor,filetype)=>new Promise(((resolve,reject)=>{const configuration=(0,_options.getFilePicker)(editor,filetype);if(configuration){const options={...configuration,formcallback:resolve};M.core_filepicker.show(Y,options)}else reject("Unknown filetype ".concat(filetype))}));_exports.addToolbarButton=(toolbar,section,button)=>{if(!toolbar)return[{name:section,items:[button]}];return JSON.parse(JSON.stringify(toolbar)).map((item=>(item.name===section&&item.items.push(button),item)))};_exports.addToolbarButtons=(toolbar,section,buttons)=>{if(!toolbar)return[{name:section,items:buttons}];return JSON.parse(JSON.stringify(toolbar)).map((item=>(item.name===section&&buttons.forEach((button=>item.items.push(button))),item)))};_exports.addToolbarSection=function(toolbar,name,relativeTo){let append=!(arguments.length>3&&void 0!==arguments[3])||arguments[3];const newSection={name:name,items:[]},sectionInserted=toolbar.some(((section,index)=>section.name===relativeTo&&(append?toolbar.splice(index+1,0,newSection):toolbar.splice(index,0,newSection),!0)));return sectionInserted||(append?toolbar.push(newSection):toolbar.unshift(newSection)),toolbar};_exports.addMenubarItem=(menubar,section,menuitem)=>{if(!menubar){({})[section]={title:section,items:menuitem}}const mutatedMenubar=JSON.parse(JSON.stringify(menubar));return Array.from(Object.entries(mutatedMenubar)).forEach((_ref=>{let[name,menu]=_ref;name===section&&(menu.items="".concat(menu.items," ").concat(menuitem))})),mutatedMenubar};_exports.addContextmenuItem=function(contextmenu){const contextmenuItems=(null!=contextmenu?contextmenu:"").split(" ");for(var _len=arguments.length,menuitems=new Array(_len>1?_len-1:0),_key=1;_key<_len;_key++)menuitems[_key-1]=arguments[_key];return contextmenuItems.concat(menuitems).filter((item=>""!==item)).join(" ")};_exports.addQuickbarsToolbarItem=function(toolbar){return toolbar};const getDocumentationLink=pluginName=>"https://docs.moodle.org/en/editor_tiny/".concat(pluginName);_exports.getDocumentationLink=getDocumentationLink;_exports.getPluginMetadata=async function(component,pluginName){let url=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;const name=await(0,_str.get_string)("helplinktext",component);return{getMetadata:()=>({name:name,url:null!=url?url:getDocumentationLink(pluginName)})}};_exports.ensureEditorIsValid=editor=>{var _editor$targetElm;return null!=editor&&null!==(_editor$targetElm=editor.targetElm)&&void 0!==_editor$targetElm&&_editor$targetElm.closest("body")?editor:(editor.destroy(),null)};_exports.removeToolbarButton=(toolbar,section,button)=>{if(!toolbar)return[{name:section,items:[button]}];return JSON.parse(JSON.stringify(toolbar)).map((item=>(item.name===section&&item.items.splice(item.items.indexOf(button),1),item)))};_exports.removeToolbarButtons=(toolbar,section,buttons)=>{if(!toolbar)return[{name:section,items:buttons}];return JSON.parse(JSON.stringify(toolbar)).map((item=>(item.name===section&&buttons.forEach((button=>item.items.splice(item.items.indexOf(button),1))),item)))};_exports.removeSubmenuItem=async(editor,section,submenuitem)=>{const menuItems=editor.ui.registry.getAll().menuItems[section],submenuitemtitle=await(0,_str.get_string)(submenuitem,"editor_tiny");menuItems&&editor.ui.registry.addNestedMenuItem(section,{text:menuItems.text,getSubmenuItems:()=>{let newSubmenu=[];return menuItems.getSubmenuItems().forEach((item=>{item.text.trim()!=submenuitemtitle&&newSubmenu.push(item)})),newSubmenu}})};_exports.removeMenubarItem=(menubar,section,menuitem)=>(menubar[section].items=menubar[section].items.replace(menuitem,""),menubar);_exports.removeMenubarItems=(menubar,section,menuitems)=>{const regexPattern=new RegExp(menuitems.join("|"),"ig");return menubar[section].items=menubar[section].items.replace(regexPattern,""),menubar}}));
|
||||
define("editor_tiny/utils",["exports","core/templates","./options","core/str"],(function(_exports,_templates,_options,_str){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.removeToolbarButtons=_exports.removeToolbarButton=_exports.removeSubmenuItem=_exports.removeMenubarItems=_exports.removeMenubarItem=_exports.getPluginMetadata=_exports.getImagePath=_exports.getDocumentationLink=_exports.getButtonImage=_exports.ensureEditorIsValid=_exports.displayFilepicker=_exports.addToolbarSection=_exports.addToolbarButtons=_exports.addToolbarButton=_exports.addQuickbarsToolbarItem=_exports.addMenubarItem=_exports.addContextmenuItem=void 0;const getImagePath=function(identifier){let component=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"editor_tiny";return Promise.resolve(M.util.image_url(identifier,component))};_exports.getImagePath=getImagePath;_exports.getButtonImage=async function(identifier){let component=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"editor_tiny";return(0,_templates.renderForPromise)("editor_tiny/toolbar_button",{image:await getImagePath(identifier,component)})};_exports.displayFilepicker=(editor,filetype)=>new Promise(((resolve,reject)=>{const configuration=(0,_options.getFilePicker)(editor,filetype);if(configuration){const options={...configuration,formcallback:resolve};M.core_filepicker.show(Y,options)}else reject("Unknown filetype ".concat(filetype))}));_exports.addToolbarButton=(toolbar,section,button)=>{if(!toolbar)return[{name:section,items:[button]}];return JSON.parse(JSON.stringify(toolbar)).map((item=>(item.name===section&&item.items.push(button),item)))};_exports.addToolbarButtons=(toolbar,section,buttons)=>{if(!toolbar)return[{name:section,items:buttons}];return JSON.parse(JSON.stringify(toolbar)).map((item=>(item.name===section&&buttons.forEach((button=>item.items.push(button))),item)))};_exports.addToolbarSection=function(toolbar,name,relativeTo){let append=!(arguments.length>3&&void 0!==arguments[3])||arguments[3];const newSection={name:name,items:[]},sectionInserted=toolbar.some(((section,index)=>section.name===relativeTo&&(append?toolbar.splice(index+1,0,newSection):toolbar.splice(index,0,newSection),!0)));return sectionInserted||(append?toolbar.push(newSection):toolbar.unshift(newSection)),toolbar};_exports.addMenubarItem=(menubar,section,menuitem)=>{if(!menubar){({})[section]={title:section,items:menuitem}}const mutatedMenubar=JSON.parse(JSON.stringify(menubar));return Array.from(Object.entries(mutatedMenubar)).forEach((_ref=>{let[name,menu]=_ref;name===section&&(menu.items="".concat(menu.items," ").concat(menuitem))})),mutatedMenubar};_exports.addContextmenuItem=function(contextmenu){const contextmenuItems=(null!=contextmenu?contextmenu:"").split(" ");for(var _len=arguments.length,menuitems=new Array(_len>1?_len-1:0),_key=1;_key<_len;_key++)menuitems[_key-1]=arguments[_key];return contextmenuItems.concat(menuitems).filter((item=>""!==item)).join(" ")};_exports.addQuickbarsToolbarItem=function(toolbar){return toolbar};const getDocumentationLink=pluginName=>"https://docs.moodle.org/en/editor_tiny/".concat(pluginName);_exports.getDocumentationLink=getDocumentationLink;_exports.getPluginMetadata=async function(component,pluginName){let url=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;const name=await(0,_str.get_string)("helplinktext",component);return{getMetadata:()=>({name:name,url:null!=url?url:getDocumentationLink(pluginName)})}};_exports.ensureEditorIsValid=editor=>editor.getElement().isConnected?editor:null;_exports.removeToolbarButton=(toolbar,section,button)=>{if(!toolbar)return[{name:section,items:[button]}];return JSON.parse(JSON.stringify(toolbar)).map((item=>(item.name===section&&item.items.splice(item.items.indexOf(button),1),item)))};_exports.removeToolbarButtons=(toolbar,section,buttons)=>{if(!toolbar)return[{name:section,items:buttons}];return JSON.parse(JSON.stringify(toolbar)).map((item=>(item.name===section&&buttons.forEach((button=>item.items.splice(item.items.indexOf(button),1))),item)))};_exports.removeSubmenuItem=async(editor,section,submenuitem)=>{const menuItems=editor.ui.registry.getAll().menuItems[section],submenuitemtitle=await(0,_str.get_string)(submenuitem,"editor_tiny");menuItems&&editor.ui.registry.addNestedMenuItem(section,{text:menuItems.text,getSubmenuItems:()=>{let newSubmenu=[];return menuItems.getSubmenuItems().forEach((item=>{item.text.trim()!=submenuitemtitle&&newSubmenu.push(item)})),newSubmenu}})};_exports.removeMenubarItem=(menubar,section,menuitem)=>(menubar[section].items=menubar[section].items.replace(menuitem,""),menubar);_exports.removeMenubarItems=(menubar,section,menuitems)=>{const regexPattern=new RegExp(menuitems.join("|"),"ig");return menubar[section].items=menubar[section].items.replace(regexPattern,""),menubar}}));
|
||||
|
||||
//# sourceMappingURL=utils.min.js.map
|
File diff suppressed because one or more lines are too long
@ -267,6 +267,14 @@ const getStandardConfig = (target, tinyMCE, options, plugins) => {
|
||||
setup: (editor) => {
|
||||
Options.register(editor, options);
|
||||
|
||||
editor.on('PreInit', function() {
|
||||
// Work around a bug in TinyMCE with Firefox.
|
||||
// When an editor is removed, and replaced with an identically attributed editor (same ID),
|
||||
// and the Firefox window is freshly opened (e.g. Behat, Private browsing), the wrong contentWindow
|
||||
// is assigned to the editor instance leading to an NS_ERROR_UNEXPECTED error in Firefox.
|
||||
// This is a workaround for that issue.
|
||||
this.contentWindow = this.iframeElement.contentWindow;
|
||||
});
|
||||
editor.on('init', function() {
|
||||
// Hide justify alignment sub-menu.
|
||||
removeSubmenuItem(editor, 'align', 'tiny:justify');
|
||||
@ -390,18 +398,21 @@ export const setupForTarget = async(target, options = {}) => {
|
||||
// we need to manually destroy the editor.
|
||||
// We could theoretically do this with a Mutation Observer, but in some cases the Node may be moved,
|
||||
// or added back elsewhere in the DOM.
|
||||
|
||||
// First remove any detached editors.
|
||||
tinyMCE.get().filter((editor) => !editor.getElement().isConnected).forEach((editor) => {
|
||||
editor.remove();
|
||||
});
|
||||
|
||||
// Now check for any existing editor which shares the same ID.
|
||||
const existingEditor = tinyMCE.EditorManager.get(target.id);
|
||||
if (existingEditor) {
|
||||
if (existingEditor.targetElm.closest('body')) {
|
||||
if (existingEditor.targetElm === target) {
|
||||
pendingPromise.resolve();
|
||||
return Promise.resolve(existingEditor);
|
||||
} else {
|
||||
pendingPromise.resolve();
|
||||
throw new Error('TinyMCE instance already exists for different target with same ID');
|
||||
}
|
||||
if (existingEditor.getElement() === target) {
|
||||
pendingPromise.resolve();
|
||||
return Promise.resolve(existingEditor);
|
||||
} else {
|
||||
existingEditor.destroy();
|
||||
pendingPromise.resolve();
|
||||
throw new Error('TinyMCE instance already exists for different target with same ID');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -238,8 +238,7 @@ export const ensureEditorIsValid = (editor) => {
|
||||
// we need to manually destroy the editor.
|
||||
// We could theoretically do this with a Mutation Observer, but in some cases the Node may be moved,
|
||||
// or added back elsewhere in the DOM.
|
||||
if (!editor?.targetElm?.closest('body')) {
|
||||
editor.destroy();
|
||||
if (!editor.getElement().isConnected) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user