diff --git a/amd/build/ui.min.js b/amd/build/ui.min.js index 8bb2788..2710e92 100644 --- a/amd/build/ui.min.js +++ b/amd/build/ui.min.js @@ -6,6 +6,6 @@ define("tiny_elements/ui",["exports","tiny_elements/modal","tiny_elements/option * @copyright 2025 ISB Bayern * @copyright based on the work of Marc Català * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.handleAction=void 0,_modal_events=_interopRequireDefault(_modal_events),_data=_interopRequireDefault(_data);let currentFlavor="",currentFlavorId=0,currentCategoryId=1,currentCategoryName="",lastFlavor=[],selection="",data={};_exports.handleAction=async editor=>{selection=editor.selection.getContent(),data=new _data.default((0,_options2.getContextId)(editor),(0,_options.isStudent)(editor),(0,_options.showPreview)(editor),(0,_options.canManage)(editor)),await data.loadData(),(0,_variantslib.setData)(data),currentCategoryId=await(0,_preferencelib.loadPreferences)(_preferencelib.Preferences.category),lastFlavor=await(0,_preferencelib.loadPreferences)(_preferencelib.Preferences.category_flavors),null==lastFlavor&&(lastFlavor=[]);let componentVariants=await(0,_preferencelib.loadPreferences)(_preferencelib.Preferences.component_variants);null==componentVariants&&(componentVariants={}),(0,_variantslib.loadVariantPreferences)(componentVariants),await displayDialogue(editor)};const displayDialogue=async editor=>{const templateContext=data.getTemplateContext(editor),modal=await _modal.ElementsModal.create({type:_modal.ElementsModal.TYPE,templateContext:templateContext,large:!0}),modalClass=data.getPreviewElements()?"elements-modal":"elements-modal-no-preview";editor.targetElm.closest("body").classList.add(modalClass),modal.show(),modal.getRoot().on(_modal_events.default.hidden,(()=>{handleModalHidden(editor)}));const soleCategories=modal.getRoot()[0].querySelectorAll(".elements-category.no-flavors");soleCategories.forEach((node=>{node.addEventListener("click",(event=>{handleCategoryClick(event,modal)}))}));const selectCategories=modal.getRoot()[0].querySelectorAll(".elements-category-flavor");selectCategories.forEach((node=>{node.addEventListener("click",(event=>{handleCategoryFlavorClick(event,modal)}))}));modal.getRoot()[0].querySelectorAll(".nav-link.dropdown-toggle").forEach((node=>{node.addEventListener("click",(event=>{handleCategoryRemember(event,modal)}))}));modal.getRoot()[0].querySelectorAll(".elementst-dialog-button").forEach((node=>{node.addEventListener("click",(event=>{handleButtonClick(event,editor,modal)})),data.getPreviewElements()&&(node.addEventListener("mouseenter",(event=>{handleButtonMouseEvent(event,modal,!0)})),node.addEventListener("mouseleave",(event=>{handleButtonMouseEvent(event,modal,!1)})))}));if(modal.getRoot()[0].querySelectorAll(".elements-button-variant").forEach((node=>{node.addEventListener("click",(event=>{handleVariantClick(event,modal)}))})),soleCategories.length>0||selectCategories.length>0){const savedCategory=currentCategoryId,savedFlavor=lastFlavor[currentCategoryId];if(0==soleCategories.length||soleCategories[0].displayorder>selectCategories[0].displayorder?selectCategories[0].click():soleCategories[0].click(),0!=savedCategory&&(soleCategories.forEach((node=>{node.dataset.categoryid==savedCategory&&node.click()})),selectCategories.forEach((node=>{node.dataset.categoryid==savedCategory&&node.click()})),savedFlavor)){const flavorlink=modal.getRoot()[0].querySelector('.elements-category-flavor[data-id="'+savedFlavor+'"]');flavorlink&&flavorlink.click()}}},handleCategoryClick=(event,modal)=>{const link=event.target;currentCategoryId=link.dataset.categoryid,currentCategoryName=link.dataset.categoryname;modal.getRoot()[0].querySelectorAll(".nav-link, .dropdown-item").forEach((node=>node.classList.remove("active"))),link.classList.add("active"),showCategoryButtons(modal,currentCategoryName)},handleCategoryFlavorClick=(event,modal)=>{const link=event.target;currentFlavor=link.dataset.flavor,currentFlavorId=link.dataset.id,currentCategoryId=link.dataset.categoryid,currentCategoryName=link.dataset.categoryname,lastFlavor[currentCategoryId]=currentFlavorId;modal.getRoot()[0].querySelectorAll(".nav-link, .dropdown-item").forEach((node=>node.classList.remove("active"))),link.classList.add("active");modal.getRoot()[0].querySelector('.nav-link[data-categoryid="'+currentCategoryId+'"]').classList.add("active");modal.getRoot()[0].querySelectorAll(".elements-buttons-preview button").forEach((componentButton=>{if(componentButton.dataset.flavor=currentFlavor,""!=componentButton.dataset.flavorlist&&!componentButton.dataset.flavorlist.split(",").includes(currentFlavor)||componentButton.dataset.category!=currentCategoryName)componentButton.classList.add("elements-hidden");else if(componentButton.classList.remove("elements-hidden"),""!=componentButton.dataset.flavorlist){let variants=(0,_variantslib.getVariantsClass)(data.getComponentById(componentButton.dataset.id).name,currentFlavor);componentButton.querySelectorAll(".elements-button-variant").forEach((variant=>{updateVariantButtonState(variant,-1!=variants.indexOf(variant.dataset.variantclass))}))}}))},handleCategoryRemember=(event,modal)=>{const link=event.target;if(currentCategoryId=link.dataset.categoryid,currentCategoryName=link.dataset.categoryname,currentFlavorId=lastFlavor[currentCategoryId],null!=currentFlavorId){let e={target:modal.getRoot()[0].querySelector('.elements-category-flavor[data-id="'+currentFlavorId+'"]')};handleCategoryFlavorClick(e,modal)}},handleModalHidden=editor=>{editor.targetElm.closest("body").classList.remove("elements-modal-no-preview"),0!=currentCategoryId&&0!=currentFlavorId&&(0,_preferencelib.savePreferences)([{type:_preferencelib.Preferences.category,value:currentCategoryId},{type:_preferencelib.Preferences.category_flavors,value:JSON.stringify(lastFlavor)},{type:_preferencelib.Preferences.component_variants,value:JSON.stringify((0,_variantslib.getVariantPreferences)())}])},updateComponentCode=function(componentCode,selectedButton,placeholder){let flavor=arguments.length>3&&void 0!==arguments[3]?arguments[3]:"";componentCode=componentCode.replace("{{PLACEHOLDER}}",placeholder);const comp=data.getComponentById(selectedButton),variants=(0,_variantslib.getVariantsClass)(comp.name,flavor);return componentCode=variants.length>0?(componentCode=componentCode.replace("{{VARIANTS}}",variants.join(" "))).replace("{{VARIANTSHTML}}",(0,_variantslib.getVariantsHtml)(comp.name,flavor)):(componentCode=componentCode.replace("{{VARIANTS}}","")).replace("{{VARIANTSHTML}}",""),componentCode=(componentCode=(componentCode=currentFlavor?componentCode.replace("{{FLAVOR}}","elements-"+currentFlavor+"-flavor"):componentCode.replace("{{FLAVOR}}","")).replace("{{COMPONENT}}","elements-"+comp.name)).replace("{{CATEGORY}}","elements-"+data.getCategoryById(currentCategoryId).name),componentCode=applyRandomID(componentCode),componentCode=applyLangStrings(componentCode)},handleButtonClick=async(event,editor,modal)=>{const selectedButton=event.target.closest("button").dataset.id,comp=data.getComponentById(selectedButton);if(comp){let componentCode=comp.code;const placeholder=selection.length>0?selection:comp.text;let flavor=comp.flavors.length>0?currentFlavor:"";const randomId=generateRandomID(),newNode=document.createElement("span");newNode.dataset.id=randomId,newNode.innerHTML=placeholder,componentCode=updateComponentCode(componentCode,selectedButton,newNode.outerHTML,flavor),editor.selection.setContent(componentCode);const nodeSel=editor.dom.select('span[data-id="'+randomId+'"]');null!=nodeSel&&nodeSel[0]&&editor.selection.select(nodeSel[0]),modal.destroy(),editor.focus()}},handleButtonMouseEvent=(event,modal,show)=>{const selectedButton=event.target.closest("button").dataset.id,node=modal.getRoot()[0].querySelector('div[data-id="code-preview-'+selectedButton+'"]'),previewDefault=modal.getRoot()[0].querySelector('div[data-id="code-preview-default"]'),comp=data.getComponentById(selectedButton);let flavor=comp.flavors.length>0?currentFlavor:"";const placeholder=selection.length>0?selection:comp.text;node.innerHTML=updateComponentCode(comp.code,selectedButton,placeholder,flavor),node&&(show?(previewDefault.classList.toggle("elements-hidden"),node.classList.toggle("elements-hidden")):(node.classList.toggle("elements-hidden"),previewDefault.classList.toggle("elements-hidden")))},handleVariantClick=(event,modal)=>{event.stopPropagation();const variant=event.target.closest("span"),button=event.target.closest("button"),comp=data.getComponentById(button.dataset.id),flavor=comp.flavors.length>0?currentFlavor:"";updateVariantComponentState(variant,button,modal,!1,!0);modal.getRoot()[0].querySelector('div[data-id="code-preview-'+button.dataset.id+'"]').innerHTML=updateComponentCode(comp.code,button.dataset.id,comp.text,flavor)},updateVariantComponentState=(variant,button,modal,show,updateHtml)=>{const selectedVariant=variant.dataset.variantclass,selectedButton=button.dataset.id,componentClass=button.dataset.classcomponent,previewComponent=modal.getRoot()[0].querySelector('div[data-id="code-preview-'+button.dataset.id+'"] .'+componentClass),variantPreview=modal.getRoot()[0].querySelector('span[data-id="variantHTML-'+button.dataset.id+'"]'),comp=data.getComponentById(selectedButton);let variantsHtml="",hasflavors=comp.flavors.length>0;previewComponent?updateHtml?("on"==variant.dataset.state?((0,_variantslib.removeVariant)(comp.name,variant.dataset.variant,hasflavors?currentFlavor:""),updateVariantButtonState(variant,!1),previewComponent.classList.remove(selectedVariant)):((0,_variantslib.addVariant)(comp.name,variant.dataset.variant,hasflavors?currentFlavor:""),updateVariantButtonState(variant,!0),previewComponent.classList.add(selectedVariant)),variantPreview&&(variantPreview.innerHTML=(0,_variantslib.getVariantsHtml)(comp.name,currentFlavor))):(variantsHtml=(0,_variantslib.getVariantsHtml)(comp.name,currentFlavor),show?(previewComponent.classList.add(selectedVariant),variantsHtml+=(0,_variantslib.getVariantHtml)(variant.dataset.variant)):previewComponent.classList.remove(selectedVariant),variantPreview&&(variantPreview.innerHTML=variantsHtml)):"on"==variant.dataset.state?((0,_variantslib.removeVariant)(comp.name,variant.dataset.variant,hasflavors?currentFlavor:""),updateVariantButtonState(variant,!1)):((0,_variantslib.addVariant)(comp.name,variant.dataset.variant,hasflavors?currentFlavor:""),updateVariantButtonState(variant,!0))},updateVariantButtonState=(variant,activate)=>{activate?(variant.dataset.state="on",variant.classList.remove(variant.dataset.variant+"-variant-off"),variant.classList.add(variant.dataset.variant+"-variant-on"),variant.classList.add("on")):(variant.dataset.state="off",variant.classList.remove(variant.dataset.variant+"-variant-on"),variant.classList.add(variant.dataset.variant+"-variant-off"),variant.classList.remove("on"))},showCategoryButtons=(modal,context)=>{const showNodes=modal.getRoot()[0].querySelectorAll('button[data-type="'+context+'"]'),hideNodes=modal.getRoot()[0].querySelectorAll('button[data-type]:not([data-type="'+context+'"])');showNodes.forEach((node=>node.classList.remove("elements-hidden"))),hideNodes.forEach((node=>node.classList.add("elements-hidden")))},applyLangStrings=text=>([...text.matchAll(/{{#([^}]*)}}/g)].forEach((strLang=>{text=text.replace("{{#"+strLang[1]+"}}",data.getLangString(strLang[1]))})),text),generateRandomID=()=>{const timestamp=(new Date).getTime();return"R"+Math.round(1e5*Math.random())+"-"+timestamp},applyRandomID=text=>{const compRegex=/{{@ID}}/g;return text.match(compRegex)&&(text=text.replace(compRegex,generateRandomID())),text}})); + */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.handleAction=void 0,_modal_events=_interopRequireDefault(_modal_events),_data=_interopRequireDefault(_data);let currentFlavor="",currentFlavorId=0,currentCategoryId=1,currentCategoryName="",lastFlavor=[],selection="",data={};_exports.handleAction=async editor=>{selection=editor.selection.getContent(),data=new _data.default((0,_options2.getContextId)(editor),(0,_options.isStudent)(editor),(0,_options.showPreview)(editor),(0,_options.canManage)(editor)),await data.loadData(),(0,_variantslib.setData)(data),currentCategoryId=await(0,_preferencelib.loadPreferences)(_preferencelib.Preferences.category),lastFlavor=await(0,_preferencelib.loadPreferences)(_preferencelib.Preferences.category_flavors),null==lastFlavor&&(lastFlavor=[]);let componentVariants=await(0,_preferencelib.loadPreferences)(_preferencelib.Preferences.component_variants);null==componentVariants&&(componentVariants={}),(0,_variantslib.loadVariantPreferences)(componentVariants),await displayDialogue(editor)};const displayDialogue=async editor=>{const templateContext=data.getTemplateContext(editor),modal=await _modal.ElementsModal.create({type:_modal.ElementsModal.TYPE,templateContext:templateContext,large:!0}),modalClass=data.getPreviewElements()?"elements-modal":"elements-modal-no-preview";editor.targetElm.closest("body").classList.add(modalClass),modal.show(),modal.getRoot().on(_modal_events.default.hidden,(()=>{handleModalHidden(editor)}));const soleCategories=modal.getRoot()[0].querySelectorAll(".elements-category.no-flavors");soleCategories.forEach((node=>{node.addEventListener("click",(event=>{handleCategoryClick(event,modal)}))}));const selectCategories=modal.getRoot()[0].querySelectorAll(".elements-category-flavor");selectCategories.forEach((node=>{node.addEventListener("click",(event=>{handleCategoryFlavorClick(event,modal)}))}));modal.getRoot()[0].querySelectorAll(".nav-link.dropdown-toggle").forEach((node=>{node.addEventListener("click",(event=>{handleCategoryRemember(event,modal)}))}));modal.getRoot()[0].querySelectorAll(".elementst-dialog-button").forEach((node=>{node.addEventListener("click",(event=>{handleButtonClick(event,editor,modal)})),data.getPreviewElements()&&(node.addEventListener("mouseenter",(event=>{handleButtonMouseEvent(event,modal,!0)})),node.addEventListener("mouseleave",(event=>{handleButtonMouseEvent(event,modal,!1)})))}));if(modal.getRoot()[0].querySelectorAll(".elements-button-variant").forEach((node=>{node.addEventListener("click",(event=>{handleVariantClick(event,modal)}))})),soleCategories.length>0||selectCategories.length>0){const savedCategory=currentCategoryId,savedFlavor=lastFlavor[currentCategoryId];if(0==soleCategories.length||soleCategories[0].displayorder>selectCategories[0].displayorder?selectCategories[0].click():soleCategories[0].click(),0!=savedCategory&&(soleCategories.forEach((node=>{node.dataset.categoryid==savedCategory&&node.click()})),selectCategories.forEach((node=>{node.dataset.categoryid==savedCategory&&node.click()})),savedFlavor)){const flavorlink=modal.getRoot()[0].querySelector('.elements-category-flavor[data-id="'+savedFlavor+'"]');flavorlink&&flavorlink.click()}}},handleCategoryClick=(event,modal)=>{const link=event.target;currentCategoryId=link.dataset.categoryid,currentCategoryName=link.dataset.categoryname;modal.getRoot()[0].querySelectorAll(".nav-link, .dropdown-item").forEach((node=>node.classList.remove("active"))),link.classList.add("active"),showCategoryButtons(modal,currentCategoryName)},handleCategoryFlavorClick=(event,modal)=>{const link=event.target;currentFlavor=link.dataset.flavor,currentFlavorId=link.dataset.id,currentCategoryId=link.dataset.categoryid,currentCategoryName=link.dataset.categoryname,lastFlavor[currentCategoryId]=currentFlavorId;modal.getRoot()[0].querySelectorAll(".nav-link, .dropdown-item").forEach((node=>node.classList.remove("active"))),link.classList.add("active");modal.getRoot()[0].querySelector('.nav-link[data-categoryid="'+currentCategoryId+'"]').classList.add("active");modal.getRoot()[0].querySelectorAll(".elements-buttons-preview button").forEach((componentButton=>{if(componentButton.dataset.flavor=currentFlavor,""!=componentButton.dataset.flavorlist&&!componentButton.dataset.flavorlist.split(",").includes(currentFlavor)||componentButton.dataset.category!=currentCategoryName)componentButton.classList.add("elements-hidden");else if(componentButton.classList.remove("elements-hidden"),""!=componentButton.dataset.flavorlist){let variants=(0,_variantslib.getVariantsClass)(data.getComponentById(componentButton.dataset.id).name,currentFlavor);componentButton.querySelectorAll(".elements-button-variant").forEach((variant=>{updateVariantButtonState(variant,-1!=variants.indexOf(variant.dataset.variantclass))}))}}))},handleCategoryRemember=(event,modal)=>{const link=event.target;if(currentCategoryId=link.dataset.categoryid,currentCategoryName=link.dataset.categoryname,currentFlavorId=lastFlavor[currentCategoryId],null!=currentFlavorId){let e={target:modal.getRoot()[0].querySelector('.elements-category-flavor[data-id="'+currentFlavorId+'"]')};handleCategoryFlavorClick(e,modal)}},handleModalHidden=editor=>{editor.targetElm.closest("body").classList.remove("elements-modal-no-preview"),0!=currentCategoryId&&0!=currentFlavorId&&(0,_preferencelib.savePreferences)([{type:_preferencelib.Preferences.category,value:currentCategoryId},{type:_preferencelib.Preferences.category_flavors,value:JSON.stringify(lastFlavor)},{type:_preferencelib.Preferences.component_variants,value:JSON.stringify((0,_variantslib.getVariantPreferences)())}])},updateComponentCode=function(componentCode,selectedButton,placeholder){let flavor=arguments.length>3&&void 0!==arguments[3]?arguments[3]:"";componentCode=componentCode.replace("{{PLACEHOLDER}}",placeholder);const comp=data.getComponentById(selectedButton),variants=(0,_variantslib.getVariantsClass)(comp.name,flavor);return componentCode=variants.length>0?(componentCode=componentCode.replace("{{VARIANTS}}",variants.join(" "))).replace("{{VARIANTSHTML}}",(0,_variantslib.getVariantsHtml)(comp.name,flavor)):(componentCode=componentCode.replace("{{VARIANTS}}","")).replace("{{VARIANTSHTML}}",""),componentCode=(componentCode=(componentCode=currentFlavor?componentCode.replace("{{FLAVOR}}","elements-"+currentFlavor+"-flavor"):componentCode.replace("{{FLAVOR}}","")).replace("{{COMPONENT}}","elements-"+comp.name)).replace("{{CATEGORY}}","elements-"+data.getCategoryById(currentCategoryId).name),componentCode=applyRandomID(componentCode),componentCode=applyLangStrings(componentCode)},handleButtonClick=async(event,editor,modal)=>{const selectedButton=event.target.closest("button").dataset.id,comp=data.getComponentById(selectedButton);if(comp){let componentCode=comp.code;const placeholder=selection.length>0?selection:comp.text;let flavor=comp.flavors.length>0?currentFlavor:"";const randomId=generateRandomID(),newNode=document.createElement("span");newNode.dataset.id=randomId,newNode.innerHTML=placeholder,componentCode=updateComponentCode(componentCode,selectedButton,newNode.outerHTML,flavor),editor.selection.setContent(componentCode);const nodeSel=editor.dom.select('span[data-id="'+randomId+'"]');null!=nodeSel&&nodeSel[0]&&editor.selection.select(nodeSel[0]),modal.destroy(),editor.focus(),editor.undoManager.add()}},handleButtonMouseEvent=(event,modal,show)=>{const selectedButton=event.target.closest("button").dataset.id,node=modal.getRoot()[0].querySelector('div[data-id="code-preview-'+selectedButton+'"]'),previewDefault=modal.getRoot()[0].querySelector('div[data-id="code-preview-default"]'),comp=data.getComponentById(selectedButton);let flavor=comp.flavors.length>0?currentFlavor:"";const placeholder=selection.length>0?selection:comp.text;node.innerHTML=updateComponentCode(comp.code,selectedButton,placeholder,flavor),node&&(show?(previewDefault.classList.toggle("elements-hidden"),node.classList.toggle("elements-hidden")):(node.classList.toggle("elements-hidden"),previewDefault.classList.toggle("elements-hidden")))},handleVariantClick=(event,modal)=>{event.stopPropagation();const variant=event.target.closest("span"),button=event.target.closest("button"),comp=data.getComponentById(button.dataset.id),flavor=comp.flavors.length>0?currentFlavor:"";updateVariantComponentState(variant,button,modal,!1,!0);modal.getRoot()[0].querySelector('div[data-id="code-preview-'+button.dataset.id+'"]').innerHTML=updateComponentCode(comp.code,button.dataset.id,comp.text,flavor)},updateVariantComponentState=(variant,button,modal,show,updateHtml)=>{const selectedVariant=variant.dataset.variantclass,selectedButton=button.dataset.id,componentClass=button.dataset.classcomponent,previewComponent=modal.getRoot()[0].querySelector('div[data-id="code-preview-'+button.dataset.id+'"] .'+componentClass),variantPreview=modal.getRoot()[0].querySelector('span[data-id="variantHTML-'+button.dataset.id+'"]'),comp=data.getComponentById(selectedButton);let variantsHtml="",hasflavors=comp.flavors.length>0;previewComponent?updateHtml?("on"==variant.dataset.state?((0,_variantslib.removeVariant)(comp.name,variant.dataset.variant,hasflavors?currentFlavor:""),updateVariantButtonState(variant,!1),previewComponent.classList.remove(selectedVariant)):((0,_variantslib.addVariant)(comp.name,variant.dataset.variant,hasflavors?currentFlavor:""),updateVariantButtonState(variant,!0),previewComponent.classList.add(selectedVariant)),variantPreview&&(variantPreview.innerHTML=(0,_variantslib.getVariantsHtml)(comp.name,currentFlavor))):(variantsHtml=(0,_variantslib.getVariantsHtml)(comp.name,currentFlavor),show?(previewComponent.classList.add(selectedVariant),variantsHtml+=(0,_variantslib.getVariantHtml)(variant.dataset.variant)):previewComponent.classList.remove(selectedVariant),variantPreview&&(variantPreview.innerHTML=variantsHtml)):"on"==variant.dataset.state?((0,_variantslib.removeVariant)(comp.name,variant.dataset.variant,hasflavors?currentFlavor:""),updateVariantButtonState(variant,!1)):((0,_variantslib.addVariant)(comp.name,variant.dataset.variant,hasflavors?currentFlavor:""),updateVariantButtonState(variant,!0))},updateVariantButtonState=(variant,activate)=>{activate?(variant.dataset.state="on",variant.classList.remove(variant.dataset.variant+"-variant-off"),variant.classList.add(variant.dataset.variant+"-variant-on"),variant.classList.add("on")):(variant.dataset.state="off",variant.classList.remove(variant.dataset.variant+"-variant-on"),variant.classList.add(variant.dataset.variant+"-variant-off"),variant.classList.remove("on"))},showCategoryButtons=(modal,context)=>{const showNodes=modal.getRoot()[0].querySelectorAll('button[data-type="'+context+'"]'),hideNodes=modal.getRoot()[0].querySelectorAll('button[data-type]:not([data-type="'+context+'"])');showNodes.forEach((node=>node.classList.remove("elements-hidden"))),hideNodes.forEach((node=>node.classList.add("elements-hidden")))},applyLangStrings=text=>([...text.matchAll(/{{#([^}]*)}}/g)].forEach((strLang=>{text=text.replace("{{#"+strLang[1]+"}}",data.getLangString(strLang[1]))})),text),generateRandomID=()=>{const timestamp=(new Date).getTime();return"R"+Math.round(1e5*Math.random())+"-"+timestamp},applyRandomID=text=>{const compRegex=/{{@ID}}/g;return text.match(compRegex)&&(text=text.replace(compRegex,generateRandomID())),text}})); //# sourceMappingURL=ui.min.js.map \ No newline at end of file diff --git a/amd/build/ui.min.js.map b/amd/build/ui.min.js.map index b9defba..bb9411b 100644 --- a/amd/build/ui.min.js.map +++ b/amd/build/ui.min.js.map @@ -1 +1 @@ -{"version":3,"file":"ui.min.js","sources":["../src/ui.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 * Tiny Elements UI.\n *\n * @module tiny_elements/ui\n * @copyright 2025 ISB Bayern\n * @copyright based on the work of Marc Català \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport {ElementsModal} from 'tiny_elements/modal';\nimport {\n isStudent,\n showPreview,\n canManage\n} from 'tiny_elements/options';\nimport ModalEvents from 'core/modal_events';\nimport {\n addVariant,\n getVariantsClass,\n getVariantHtml,\n getVariantPreferences,\n getVariantsHtml,\n loadVariantPreferences,\n removeVariant,\n setData as setVariantsData\n} from 'tiny_elements/variantslib';\nimport {\n savePreferences,\n loadPreferences,\n Preferences\n} from 'tiny_elements/preferencelib';\nimport {getContextId} from 'editor_tiny/options';\nimport Data from 'tiny_elements/data';\n\nlet currentFlavor = '';\nlet currentFlavorId = 0;\nlet currentCategoryId = 1;\nlet currentCategoryName = '';\nlet lastFlavor = [];\nlet selection = '';\nlet data = {};\n\n/**\n * Handle action\n *\n * @param {TinyMCE} editor\n */\nexport const handleAction = async(editor) => {\n selection = editor.selection.getContent();\n data = new Data(\n getContextId(editor),\n isStudent(editor),\n showPreview(editor),\n canManage(editor)\n );\n await data.loadData();\n setVariantsData(data);\n\n currentCategoryId = await loadPreferences(Preferences.category);\n\n lastFlavor = await loadPreferences(Preferences.category_flavors);\n if (lastFlavor === null || lastFlavor === undefined) {\n lastFlavor = [];\n }\n\n let componentVariants = await loadPreferences(Preferences.component_variants);\n if (componentVariants === null || componentVariants === undefined) {\n componentVariants = {};\n }\n loadVariantPreferences(componentVariants);\n await displayDialogue(editor);\n};\n\n/**\n * Display modal\n *\n * @param {TinyMCE} editor\n */\nconst displayDialogue = async(editor) => {\n const templateContext = data.getTemplateContext(editor);\n // Show modal with buttons.\n const modal = await ElementsModal.create({\n type: ElementsModal.TYPE,\n templateContext: templateContext,\n large: true,\n });\n\n // Choose class to modal.\n const modalClass = data.getPreviewElements() ? 'elements-modal' : 'elements-modal-no-preview';\n\n // Set class to modal.\n editor.targetElm.closest('body').classList.add(modalClass);\n\n modal.show();\n\n // Event modal listener.\n modal.getRoot().on(ModalEvents.hidden, () => {\n handleModalHidden(editor);\n });\n\n // Event listener for categories without flavors.\n const soleCategories = modal.getRoot()[0].querySelectorAll('.elements-category.no-flavors');\n soleCategories.forEach(node => {\n node.addEventListener('click', (event) => {\n handleCategoryClick(event, modal);\n });\n });\n\n // Event listener for categories with flavors.\n const selectCategories = modal.getRoot()[0].querySelectorAll('.elements-category-flavor');\n selectCategories.forEach(node => {\n node.addEventListener('click', (event) => {\n handleCategoryFlavorClick(event, modal);\n });\n });\n\n // Event listener for category dropdown, triggering to switch to last used flavor.\n const selectCategoriesRemember = modal.getRoot()[0].querySelectorAll('.nav-link.dropdown-toggle');\n selectCategoriesRemember.forEach(node => {\n node.addEventListener('click', (event) => {\n handleCategoryRemember(event, modal);\n });\n });\n\n // Event buttons listeners.\n const buttons = modal.getRoot()[0].querySelectorAll('.elementst-dialog-button');\n buttons.forEach(node => {\n node.addEventListener('click', (event) => {\n handleButtonClick(event, editor, modal);\n });\n if (data.getPreviewElements()) {\n node.addEventListener('mouseenter', (event) => {\n handleButtonMouseEvent(event, modal, true);\n });\n node.addEventListener('mouseleave', (event) => {\n handleButtonMouseEvent(event, modal, false);\n });\n }\n });\n\n // Event variants listeners.\n const variants = modal.getRoot()[0].querySelectorAll('.elements-button-variant');\n variants.forEach(node => {\n node.addEventListener('click', (event) => {\n handleVariantClick(event, modal);\n });\n });\n\n // Select first or saved category.\n if (soleCategories.length > 0 || selectCategories.length > 0) {\n const savedCategory = currentCategoryId;\n const savedFlavor = lastFlavor[currentCategoryId];\n if (soleCategories.length == 0 || soleCategories[0].displayorder > selectCategories[0].displayorder) {\n selectCategories[0].click();\n } else {\n soleCategories[0].click();\n }\n if (savedCategory != 0) {\n soleCategories.forEach((node) => {\n if (node.dataset.categoryid == savedCategory) {\n node.click();\n }\n });\n selectCategories.forEach((node) => {\n if (node.dataset.categoryid == savedCategory) {\n node.click();\n }\n });\n if (savedFlavor) {\n const flavorlink = modal.getRoot()[0].querySelector(\n '.elements-category-flavor[data-id=\"' + savedFlavor + '\"]'\n );\n if (flavorlink) {\n flavorlink.click();\n }\n }\n }\n }\n};\n\n/**\n * Handle a click within filter button.\n *\n * @param {MouseEvent} event The change event\n * @param {obj} modal\n */\nconst handleCategoryClick = (event, modal) => {\n const link = event.target;\n currentCategoryId = link.dataset.categoryid;\n currentCategoryName = link.dataset.categoryname;\n\n // Remove active from all and set to selected.\n const links = modal.getRoot()[0].querySelectorAll('.nav-link, .dropdown-item');\n links.forEach(node => node.classList.remove('active'));\n link.classList.add('active');\n\n // Show/hide component buttons.\n showCategoryButtons(modal, currentCategoryName);\n};\n\n/**\n * Handle a click on a flavor in the category dropdown.\n *\n * @param {MouseEvent} event The change event\n * @param {obj} modal\n */\nconst handleCategoryFlavorClick = (event, modal) => {\n const link = event.target;\n currentFlavor = link.dataset.flavor;\n currentFlavorId = link.dataset.id;\n currentCategoryId = link.dataset.categoryid;\n currentCategoryName = link.dataset.categoryname;\n lastFlavor[currentCategoryId] = currentFlavorId;\n\n // Remove active from all and set to selected.\n const links = modal.getRoot()[0].querySelectorAll('.nav-link, .dropdown-item');\n links.forEach(node => node.classList.remove('active'));\n link.classList.add('active');\n const category = modal.getRoot()[0].querySelector('.nav-link[data-categoryid=\"' + currentCategoryId + '\"]');\n category.classList.add('active');\n\n const componentButtons = modal.getRoot()[0].querySelectorAll('.elements-buttons-preview button');\n componentButtons.forEach(componentButton => {\n componentButton.dataset.flavor = currentFlavor;\n if (\n (componentButton.dataset.flavorlist == '' || componentButton.dataset.flavorlist.split(',').includes(currentFlavor)) &&\n componentButton.dataset.category == currentCategoryName\n ) {\n componentButton.classList.remove('elements-hidden');\n if (componentButton.dataset.flavorlist != '') {\n let variants = getVariantsClass(data.getComponentById(componentButton.dataset.id).name, currentFlavor);\n let availableVariants = componentButton.querySelectorAll('.elements-button-variant');\n availableVariants.forEach((variant) => {\n updateVariantButtonState(variant, variants.indexOf(variant.dataset.variantclass) != -1);\n });\n }\n } else {\n componentButton.classList.add('elements-hidden');\n }\n });\n\n};\n\n/**\n * When opening the category dropdown, try to load remembered flavor.\n *\n * @param {MouseEvent} event The change event\n * @param {obj} modal\n */\nconst handleCategoryRemember = (event, modal) => {\n const link = event.target;\n currentCategoryId = link.dataset.categoryid;\n currentCategoryName = link.dataset.categoryname;\n currentFlavorId = lastFlavor[currentCategoryId];\n\n if (currentFlavorId != undefined) {\n // Call handleCategoryFlavorClick with tampered data.\n let e = {target: modal.getRoot()[0].querySelector('.elements-category-flavor[data-id=\"' + currentFlavorId + '\"]')};\n handleCategoryFlavorClick(e, modal);\n }\n};\n\n/**\n * Handle when closing the Modal.\n *\n * @param {obj} editor\n */\nconst handleModalHidden = (editor) => {\n editor.targetElm.closest('body').classList.remove('elements-modal-no-preview');\n if (currentCategoryId != 0 && currentFlavorId != 0) {\n savePreferences([\n {type: Preferences.category, value: currentCategoryId},\n {type: Preferences.category_flavors, value: JSON.stringify(lastFlavor)},\n {type: Preferences.component_variants, value: JSON.stringify(getVariantPreferences())}\n ]);\n }\n};\n\nconst updateComponentCode = (componentCode, selectedButton, placeholder, flavor = '') => {\n componentCode = componentCode.replace('{{PLACEHOLDER}}', placeholder);\n const comp = data.getComponentById(selectedButton);\n // Return active variants for current component.\n const variants = getVariantsClass(comp.name, flavor);\n\n // Apply variants to html component.\n if (variants.length > 0) {\n componentCode = componentCode.replace('{{VARIANTS}}', variants.join(' '));\n componentCode = componentCode.replace('{{VARIANTSHTML}}', getVariantsHtml(comp.name, flavor));\n } else {\n componentCode = componentCode.replace('{{VARIANTS}}', '');\n componentCode = componentCode.replace('{{VARIANTSHTML}}', '');\n }\n\n if (currentFlavor) {\n componentCode = componentCode.replace('{{FLAVOR}}', 'elements-' + currentFlavor + '-flavor');\n } else {\n componentCode = componentCode.replace('{{FLAVOR}}', '');\n }\n\n componentCode = componentCode.replace('{{COMPONENT}}', 'elements-' + comp.name);\n componentCode = componentCode.replace('{{CATEGORY}}', 'elements-' + data.getCategoryById(currentCategoryId).name);\n\n // Apply random IDs.\n componentCode = applyRandomID(componentCode);\n\n // Apply lang strings.\n componentCode = applyLangStrings(componentCode);\n\n return componentCode;\n};\n\n/**\n * Handle a click in a component button.\n *\n * @param {MouseEvent} event The click event\n * @param {obj} editor\n * @param {obj} modal\n */\nconst handleButtonClick = async(event, editor, modal) => {\n const selectedButton = event.target.closest('button').dataset.id;\n\n const comp = data.getComponentById(selectedButton);\n\n // Component button.\n if (comp) {\n let componentCode = comp.code;\n const placeholder = (selection.length > 0 ? selection : comp.text);\n\n let flavor = comp.flavors.length > 0 ? currentFlavor : '';\n\n // Create a new node to replace the placeholder.\n const randomId = generateRandomID();\n const newNode = document.createElement('span');\n newNode.dataset.id = randomId;\n newNode.innerHTML = placeholder;\n componentCode = updateComponentCode(componentCode, selectedButton, newNode.outerHTML, flavor);\n // Sets new content.\n editor.selection.setContent(componentCode);\n\n // Select text.\n const nodeSel = editor.dom.select('span[data-id=\"' + randomId + '\"]');\n if (nodeSel?.[0]) {\n editor.selection.select(nodeSel[0]);\n }\n\n modal.destroy();\n editor.focus();\n }\n};\n\n/**\n * Handle a mouse events mouseenter/mouseleave in a component button.\n *\n * @param {MouseEvent} event The click event\n * @param {obj} modal\n * @param {bool} show\n */\nconst handleButtonMouseEvent = (event, modal, show) => {\n const selectedButton = event.target.closest('button').dataset.id;\n const node = modal.getRoot()[0].querySelector('div[data-id=\"code-preview-' + selectedButton + '\"]');\n const previewDefault = modal.getRoot()[0].querySelector('div[data-id=\"code-preview-default\"]');\n const comp = data.getComponentById(selectedButton);\n\n let flavor = comp.flavors.length > 0 ? currentFlavor : '';\n\n const placeholder = (selection.length > 0 ? selection : comp.text);\n\n node.innerHTML = updateComponentCode(comp.code, selectedButton, placeholder, flavor);\n\n if (node) {\n if (show) {\n previewDefault.classList.toggle('elements-hidden');\n node.classList.toggle('elements-hidden');\n } else {\n node.classList.toggle('elements-hidden');\n previewDefault.classList.toggle('elements-hidden');\n }\n }\n};\n\n/**\n * Handle a mouse event within the variant buttons.\n *\n * @param {MouseEvent} event The mouseenter/mouseleave event\n * @param {obj} modal\n */\nconst handleVariantClick = (event, modal) => {\n event.stopPropagation();\n const variant = event.target.closest('span');\n const button = event.target.closest('button');\n const comp = data.getComponentById(button.dataset.id);\n const flavor = comp.flavors.length > 0 ? currentFlavor : '';\n\n updateVariantComponentState(variant, button, modal, false, true);\n\n const node = modal.getRoot()[0].querySelector('div[data-id=\"code-preview-' + button.dataset.id + '\"]');\n node.innerHTML = updateComponentCode(\n comp.code,\n button.dataset.id,\n comp.text,\n flavor\n );\n};\n\n/**\n * Update a variant component UI.\n *\n * @param {obj} variant\n * @param {obj} button\n * @param {obj} modal\n * @param {bool} show\n * @param {bool} updateHtml\n */\nconst updateVariantComponentState = (variant, button, modal, show, updateHtml) => {\n const selectedVariant = variant.dataset.variantclass;\n const selectedButton = button.dataset.id;\n const componentClass = button.dataset.classcomponent;\n const previewComponent = modal.getRoot()[0]\n .querySelector('div[data-id=\"code-preview-' + button.dataset.id + '\"] .' + componentClass);\n const variantPreview = modal.getRoot()[0]\n .querySelector('span[data-id=\"variantHTML-' + button.dataset.id + '\"]');\n const comp = data.getComponentById(selectedButton);\n let variantsHtml = '';\n let hasflavors = comp.flavors.length > 0;\n\n if (previewComponent) {\n if (updateHtml) {\n if (variant.dataset.state == 'on') {\n removeVariant(comp.name, variant.dataset.variant, hasflavors ? currentFlavor : '');\n updateVariantButtonState(variant, false);\n previewComponent.classList.remove(selectedVariant);\n } else {\n addVariant(comp.name, variant.dataset.variant, hasflavors ? currentFlavor : '');\n updateVariantButtonState(variant, true);\n previewComponent.classList.add(selectedVariant);\n }\n\n // Update variant preview HTML.\n if (variantPreview) {\n variantPreview.innerHTML = getVariantsHtml(comp.name, currentFlavor);\n }\n } else {\n variantsHtml = getVariantsHtml(comp.name, currentFlavor);\n if (show) {\n previewComponent.classList.add(selectedVariant);\n variantsHtml += getVariantHtml(variant.dataset.variant);\n } else {\n previewComponent.classList.remove(selectedVariant);\n }\n\n // Update variant preview HTML.\n if (variantPreview) {\n variantPreview.innerHTML = variantsHtml;\n }\n }\n } else {\n // Update variants preferences.\n if (variant.dataset.state == 'on') {\n removeVariant(comp.name, variant.dataset.variant, hasflavors ? currentFlavor : '');\n updateVariantButtonState(variant, false);\n } else {\n addVariant(comp.name, variant.dataset.variant, hasflavors ? currentFlavor : '');\n updateVariantButtonState(variant, true);\n }\n }\n};\n\n/**\n * Update a variant button UI.\n *\n * @param {obj} variant\n * @param {bool} activate\n */\nconst updateVariantButtonState = (variant, activate) => {\n if (activate) {\n variant.dataset.state = 'on';\n variant.classList.remove(variant.dataset.variant + '-variant-off');\n variant.classList.add(variant.dataset.variant + '-variant-on');\n variant.classList.add('on');\n } else {\n variant.dataset.state = 'off';\n variant.classList.remove(variant.dataset.variant + '-variant-on');\n variant.classList.add(variant.dataset.variant + '-variant-off');\n variant.classList.remove('on');\n }\n};\n\n/**\n * Show/hide buttons depend on selected context.\n *\n * @param {object} modal\n * @param {String} context\n */\nconst showCategoryButtons = (modal, context) => {\n const showNodes = modal.getRoot()[0].querySelectorAll('button[data-type=\"' + context + '\"]');\n const hideNodes = modal.getRoot()[0].querySelectorAll('button[data-type]:not([data-type=\"' + context + '\"])');\n\n showNodes.forEach(node => node.classList.remove('elements-hidden'));\n hideNodes.forEach(node => node.classList.add('elements-hidden'));\n};\n\n/**\n * Replace all localized strings.\n *\n * @param {String} text\n * @return {String} String with lang tags replaced with a localized string.\n */\nconst applyLangStrings = (text) => {\n const compRegex = /{{#([^}]*)}}/g;\n\n [...text.matchAll(compRegex)].forEach(strLang => {\n text = text.replace('{{#' + strLang[1] + '}}', data.getLangString(strLang[1]));\n });\n\n return text;\n};\n\n/**\n * Generates a random string.\n * @return {string} A random string\n */\nconst generateRandomID = () => {\n const timestamp = new Date().getTime();\n return 'R' + Math.round(Math.random() * 100000) + '-' + timestamp;\n};\n\n/**\n * Replace all ID tags with a random string.\n * @param {String} text\n * @return {String} String with all ID tags replaced with a random string.\n */\nconst applyRandomID = (text) => {\n const compRegex = /{{@ID}}/g;\n\n if (text.match(compRegex)) {\n text = text.replace(compRegex, generateRandomID());\n }\n\n return text;\n};\n"],"names":["currentFlavor","currentFlavorId","currentCategoryId","currentCategoryName","lastFlavor","selection","data","async","editor","getContent","Data","loadData","Preferences","category","category_flavors","componentVariants","component_variants","displayDialogue","templateContext","getTemplateContext","modal","ElementsModal","create","type","TYPE","large","modalClass","getPreviewElements","targetElm","closest","classList","add","show","getRoot","on","ModalEvents","hidden","handleModalHidden","soleCategories","querySelectorAll","forEach","node","addEventListener","event","handleCategoryClick","selectCategories","handleCategoryFlavorClick","handleCategoryRemember","handleButtonClick","handleButtonMouseEvent","handleVariantClick","length","savedCategory","savedFlavor","displayorder","click","dataset","categoryid","flavorlink","querySelector","link","target","categoryname","remove","showCategoryButtons","flavor","id","componentButton","flavorlist","split","includes","variants","getComponentById","name","variant","updateVariantButtonState","indexOf","variantclass","undefined","e","value","JSON","stringify","updateComponentCode","componentCode","selectedButton","placeholder","replace","comp","join","getCategoryById","applyRandomID","applyLangStrings","code","text","flavors","randomId","generateRandomID","newNode","document","createElement","innerHTML","outerHTML","setContent","nodeSel","dom","select","destroy","focus","previewDefault","toggle","stopPropagation","button","updateVariantComponentState","updateHtml","selectedVariant","componentClass","classcomponent","previewComponent","variantPreview","variantsHtml","hasflavors","state","activate","context","showNodes","hideNodes","matchAll","strLang","getLangString","timestamp","Date","getTime","Math","round","random","compRegex","match"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"ui.min.js","sources":["../src/ui.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 * Tiny Elements UI.\n *\n * @module tiny_elements/ui\n * @copyright 2025 ISB Bayern\n * @copyright based on the work of Marc Català \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport {ElementsModal} from 'tiny_elements/modal';\nimport {\n isStudent,\n showPreview,\n canManage\n} from 'tiny_elements/options';\nimport ModalEvents from 'core/modal_events';\nimport {\n addVariant,\n getVariantsClass,\n getVariantHtml,\n getVariantPreferences,\n getVariantsHtml,\n loadVariantPreferences,\n removeVariant,\n setData as setVariantsData\n} from 'tiny_elements/variantslib';\nimport {\n savePreferences,\n loadPreferences,\n Preferences\n} from 'tiny_elements/preferencelib';\nimport {getContextId} from 'editor_tiny/options';\nimport Data from 'tiny_elements/data';\n\nlet currentFlavor = '';\nlet currentFlavorId = 0;\nlet currentCategoryId = 1;\nlet currentCategoryName = '';\nlet lastFlavor = [];\nlet selection = '';\nlet data = {};\n\n/**\n * Handle action\n *\n * @param {TinyMCE} editor\n */\nexport const handleAction = async(editor) => {\n selection = editor.selection.getContent();\n data = new Data(\n getContextId(editor),\n isStudent(editor),\n showPreview(editor),\n canManage(editor)\n );\n await data.loadData();\n setVariantsData(data);\n\n currentCategoryId = await loadPreferences(Preferences.category);\n\n lastFlavor = await loadPreferences(Preferences.category_flavors);\n if (lastFlavor === null || lastFlavor === undefined) {\n lastFlavor = [];\n }\n\n let componentVariants = await loadPreferences(Preferences.component_variants);\n if (componentVariants === null || componentVariants === undefined) {\n componentVariants = {};\n }\n loadVariantPreferences(componentVariants);\n await displayDialogue(editor);\n};\n\n/**\n * Display modal\n *\n * @param {TinyMCE} editor\n */\nconst displayDialogue = async(editor) => {\n const templateContext = data.getTemplateContext(editor);\n // Show modal with buttons.\n const modal = await ElementsModal.create({\n type: ElementsModal.TYPE,\n templateContext: templateContext,\n large: true,\n });\n\n // Choose class to modal.\n const modalClass = data.getPreviewElements() ? 'elements-modal' : 'elements-modal-no-preview';\n\n // Set class to modal.\n editor.targetElm.closest('body').classList.add(modalClass);\n\n modal.show();\n\n // Event modal listener.\n modal.getRoot().on(ModalEvents.hidden, () => {\n handleModalHidden(editor);\n });\n\n // Event listener for categories without flavors.\n const soleCategories = modal.getRoot()[0].querySelectorAll('.elements-category.no-flavors');\n soleCategories.forEach(node => {\n node.addEventListener('click', (event) => {\n handleCategoryClick(event, modal);\n });\n });\n\n // Event listener for categories with flavors.\n const selectCategories = modal.getRoot()[0].querySelectorAll('.elements-category-flavor');\n selectCategories.forEach(node => {\n node.addEventListener('click', (event) => {\n handleCategoryFlavorClick(event, modal);\n });\n });\n\n // Event listener for category dropdown, triggering to switch to last used flavor.\n const selectCategoriesRemember = modal.getRoot()[0].querySelectorAll('.nav-link.dropdown-toggle');\n selectCategoriesRemember.forEach(node => {\n node.addEventListener('click', (event) => {\n handleCategoryRemember(event, modal);\n });\n });\n\n // Event buttons listeners.\n const buttons = modal.getRoot()[0].querySelectorAll('.elementst-dialog-button');\n buttons.forEach(node => {\n node.addEventListener('click', (event) => {\n handleButtonClick(event, editor, modal);\n });\n if (data.getPreviewElements()) {\n node.addEventListener('mouseenter', (event) => {\n handleButtonMouseEvent(event, modal, true);\n });\n node.addEventListener('mouseleave', (event) => {\n handleButtonMouseEvent(event, modal, false);\n });\n }\n });\n\n // Event variants listeners.\n const variants = modal.getRoot()[0].querySelectorAll('.elements-button-variant');\n variants.forEach(node => {\n node.addEventListener('click', (event) => {\n handleVariantClick(event, modal);\n });\n });\n\n // Select first or saved category.\n if (soleCategories.length > 0 || selectCategories.length > 0) {\n const savedCategory = currentCategoryId;\n const savedFlavor = lastFlavor[currentCategoryId];\n if (soleCategories.length == 0 || soleCategories[0].displayorder > selectCategories[0].displayorder) {\n selectCategories[0].click();\n } else {\n soleCategories[0].click();\n }\n if (savedCategory != 0) {\n soleCategories.forEach((node) => {\n if (node.dataset.categoryid == savedCategory) {\n node.click();\n }\n });\n selectCategories.forEach((node) => {\n if (node.dataset.categoryid == savedCategory) {\n node.click();\n }\n });\n if (savedFlavor) {\n const flavorlink = modal.getRoot()[0].querySelector(\n '.elements-category-flavor[data-id=\"' + savedFlavor + '\"]'\n );\n if (flavorlink) {\n flavorlink.click();\n }\n }\n }\n }\n};\n\n/**\n * Handle a click within filter button.\n *\n * @param {MouseEvent} event The change event\n * @param {obj} modal\n */\nconst handleCategoryClick = (event, modal) => {\n const link = event.target;\n currentCategoryId = link.dataset.categoryid;\n currentCategoryName = link.dataset.categoryname;\n\n // Remove active from all and set to selected.\n const links = modal.getRoot()[0].querySelectorAll('.nav-link, .dropdown-item');\n links.forEach(node => node.classList.remove('active'));\n link.classList.add('active');\n\n // Show/hide component buttons.\n showCategoryButtons(modal, currentCategoryName);\n};\n\n/**\n * Handle a click on a flavor in the category dropdown.\n *\n * @param {MouseEvent} event The change event\n * @param {obj} modal\n */\nconst handleCategoryFlavorClick = (event, modal) => {\n const link = event.target;\n currentFlavor = link.dataset.flavor;\n currentFlavorId = link.dataset.id;\n currentCategoryId = link.dataset.categoryid;\n currentCategoryName = link.dataset.categoryname;\n lastFlavor[currentCategoryId] = currentFlavorId;\n\n // Remove active from all and set to selected.\n const links = modal.getRoot()[0].querySelectorAll('.nav-link, .dropdown-item');\n links.forEach(node => node.classList.remove('active'));\n link.classList.add('active');\n const category = modal.getRoot()[0].querySelector('.nav-link[data-categoryid=\"' + currentCategoryId + '\"]');\n category.classList.add('active');\n\n const componentButtons = modal.getRoot()[0].querySelectorAll('.elements-buttons-preview button');\n componentButtons.forEach(componentButton => {\n componentButton.dataset.flavor = currentFlavor;\n if (\n (componentButton.dataset.flavorlist == '' || componentButton.dataset.flavorlist.split(',').includes(currentFlavor)) &&\n componentButton.dataset.category == currentCategoryName\n ) {\n componentButton.classList.remove('elements-hidden');\n if (componentButton.dataset.flavorlist != '') {\n let variants = getVariantsClass(data.getComponentById(componentButton.dataset.id).name, currentFlavor);\n let availableVariants = componentButton.querySelectorAll('.elements-button-variant');\n availableVariants.forEach((variant) => {\n updateVariantButtonState(variant, variants.indexOf(variant.dataset.variantclass) != -1);\n });\n }\n } else {\n componentButton.classList.add('elements-hidden');\n }\n });\n\n};\n\n/**\n * When opening the category dropdown, try to load remembered flavor.\n *\n * @param {MouseEvent} event The change event\n * @param {obj} modal\n */\nconst handleCategoryRemember = (event, modal) => {\n const link = event.target;\n currentCategoryId = link.dataset.categoryid;\n currentCategoryName = link.dataset.categoryname;\n currentFlavorId = lastFlavor[currentCategoryId];\n\n if (currentFlavorId != undefined) {\n // Call handleCategoryFlavorClick with tampered data.\n let e = {target: modal.getRoot()[0].querySelector('.elements-category-flavor[data-id=\"' + currentFlavorId + '\"]')};\n handleCategoryFlavorClick(e, modal);\n }\n};\n\n/**\n * Handle when closing the Modal.\n *\n * @param {obj} editor\n */\nconst handleModalHidden = (editor) => {\n editor.targetElm.closest('body').classList.remove('elements-modal-no-preview');\n if (currentCategoryId != 0 && currentFlavorId != 0) {\n savePreferences([\n {type: Preferences.category, value: currentCategoryId},\n {type: Preferences.category_flavors, value: JSON.stringify(lastFlavor)},\n {type: Preferences.component_variants, value: JSON.stringify(getVariantPreferences())}\n ]);\n }\n};\n\nconst updateComponentCode = (componentCode, selectedButton, placeholder, flavor = '') => {\n componentCode = componentCode.replace('{{PLACEHOLDER}}', placeholder);\n const comp = data.getComponentById(selectedButton);\n // Return active variants for current component.\n const variants = getVariantsClass(comp.name, flavor);\n\n // Apply variants to html component.\n if (variants.length > 0) {\n componentCode = componentCode.replace('{{VARIANTS}}', variants.join(' '));\n componentCode = componentCode.replace('{{VARIANTSHTML}}', getVariantsHtml(comp.name, flavor));\n } else {\n componentCode = componentCode.replace('{{VARIANTS}}', '');\n componentCode = componentCode.replace('{{VARIANTSHTML}}', '');\n }\n\n if (currentFlavor) {\n componentCode = componentCode.replace('{{FLAVOR}}', 'elements-' + currentFlavor + '-flavor');\n } else {\n componentCode = componentCode.replace('{{FLAVOR}}', '');\n }\n\n componentCode = componentCode.replace('{{COMPONENT}}', 'elements-' + comp.name);\n componentCode = componentCode.replace('{{CATEGORY}}', 'elements-' + data.getCategoryById(currentCategoryId).name);\n\n // Apply random IDs.\n componentCode = applyRandomID(componentCode);\n\n // Apply lang strings.\n componentCode = applyLangStrings(componentCode);\n\n return componentCode;\n};\n\n/**\n * Handle a click in a component button.\n *\n * @param {MouseEvent} event The click event\n * @param {obj} editor\n * @param {obj} modal\n */\nconst handleButtonClick = async(event, editor, modal) => {\n const selectedButton = event.target.closest('button').dataset.id;\n\n const comp = data.getComponentById(selectedButton);\n\n // Component button.\n if (comp) {\n let componentCode = comp.code;\n const placeholder = (selection.length > 0 ? selection : comp.text);\n\n let flavor = comp.flavors.length > 0 ? currentFlavor : '';\n\n // Create a new node to replace the placeholder.\n const randomId = generateRandomID();\n const newNode = document.createElement('span');\n newNode.dataset.id = randomId;\n newNode.innerHTML = placeholder;\n componentCode = updateComponentCode(componentCode, selectedButton, newNode.outerHTML, flavor);\n // Sets new content.\n editor.selection.setContent(componentCode);\n\n // Select text.\n const nodeSel = editor.dom.select('span[data-id=\"' + randomId + '\"]');\n if (nodeSel?.[0]) {\n editor.selection.select(nodeSel[0]);\n }\n\n modal.destroy();\n editor.focus();\n editor.undoManager.add();\n }\n};\n\n/**\n * Handle a mouse events mouseenter/mouseleave in a component button.\n *\n * @param {MouseEvent} event The click event\n * @param {obj} modal\n * @param {bool} show\n */\nconst handleButtonMouseEvent = (event, modal, show) => {\n const selectedButton = event.target.closest('button').dataset.id;\n const node = modal.getRoot()[0].querySelector('div[data-id=\"code-preview-' + selectedButton + '\"]');\n const previewDefault = modal.getRoot()[0].querySelector('div[data-id=\"code-preview-default\"]');\n const comp = data.getComponentById(selectedButton);\n\n let flavor = comp.flavors.length > 0 ? currentFlavor : '';\n\n const placeholder = (selection.length > 0 ? selection : comp.text);\n\n node.innerHTML = updateComponentCode(comp.code, selectedButton, placeholder, flavor);\n\n if (node) {\n if (show) {\n previewDefault.classList.toggle('elements-hidden');\n node.classList.toggle('elements-hidden');\n } else {\n node.classList.toggle('elements-hidden');\n previewDefault.classList.toggle('elements-hidden');\n }\n }\n};\n\n/**\n * Handle a mouse event within the variant buttons.\n *\n * @param {MouseEvent} event The mouseenter/mouseleave event\n * @param {obj} modal\n */\nconst handleVariantClick = (event, modal) => {\n event.stopPropagation();\n const variant = event.target.closest('span');\n const button = event.target.closest('button');\n const comp = data.getComponentById(button.dataset.id);\n const flavor = comp.flavors.length > 0 ? currentFlavor : '';\n\n updateVariantComponentState(variant, button, modal, false, true);\n\n const node = modal.getRoot()[0].querySelector('div[data-id=\"code-preview-' + button.dataset.id + '\"]');\n node.innerHTML = updateComponentCode(\n comp.code,\n button.dataset.id,\n comp.text,\n flavor\n );\n};\n\n/**\n * Update a variant component UI.\n *\n * @param {obj} variant\n * @param {obj} button\n * @param {obj} modal\n * @param {bool} show\n * @param {bool} updateHtml\n */\nconst updateVariantComponentState = (variant, button, modal, show, updateHtml) => {\n const selectedVariant = variant.dataset.variantclass;\n const selectedButton = button.dataset.id;\n const componentClass = button.dataset.classcomponent;\n const previewComponent = modal.getRoot()[0]\n .querySelector('div[data-id=\"code-preview-' + button.dataset.id + '\"] .' + componentClass);\n const variantPreview = modal.getRoot()[0]\n .querySelector('span[data-id=\"variantHTML-' + button.dataset.id + '\"]');\n const comp = data.getComponentById(selectedButton);\n let variantsHtml = '';\n let hasflavors = comp.flavors.length > 0;\n\n if (previewComponent) {\n if (updateHtml) {\n if (variant.dataset.state == 'on') {\n removeVariant(comp.name, variant.dataset.variant, hasflavors ? currentFlavor : '');\n updateVariantButtonState(variant, false);\n previewComponent.classList.remove(selectedVariant);\n } else {\n addVariant(comp.name, variant.dataset.variant, hasflavors ? currentFlavor : '');\n updateVariantButtonState(variant, true);\n previewComponent.classList.add(selectedVariant);\n }\n\n // Update variant preview HTML.\n if (variantPreview) {\n variantPreview.innerHTML = getVariantsHtml(comp.name, currentFlavor);\n }\n } else {\n variantsHtml = getVariantsHtml(comp.name, currentFlavor);\n if (show) {\n previewComponent.classList.add(selectedVariant);\n variantsHtml += getVariantHtml(variant.dataset.variant);\n } else {\n previewComponent.classList.remove(selectedVariant);\n }\n\n // Update variant preview HTML.\n if (variantPreview) {\n variantPreview.innerHTML = variantsHtml;\n }\n }\n } else {\n // Update variants preferences.\n if (variant.dataset.state == 'on') {\n removeVariant(comp.name, variant.dataset.variant, hasflavors ? currentFlavor : '');\n updateVariantButtonState(variant, false);\n } else {\n addVariant(comp.name, variant.dataset.variant, hasflavors ? currentFlavor : '');\n updateVariantButtonState(variant, true);\n }\n }\n};\n\n/**\n * Update a variant button UI.\n *\n * @param {obj} variant\n * @param {bool} activate\n */\nconst updateVariantButtonState = (variant, activate) => {\n if (activate) {\n variant.dataset.state = 'on';\n variant.classList.remove(variant.dataset.variant + '-variant-off');\n variant.classList.add(variant.dataset.variant + '-variant-on');\n variant.classList.add('on');\n } else {\n variant.dataset.state = 'off';\n variant.classList.remove(variant.dataset.variant + '-variant-on');\n variant.classList.add(variant.dataset.variant + '-variant-off');\n variant.classList.remove('on');\n }\n};\n\n/**\n * Show/hide buttons depend on selected context.\n *\n * @param {object} modal\n * @param {String} context\n */\nconst showCategoryButtons = (modal, context) => {\n const showNodes = modal.getRoot()[0].querySelectorAll('button[data-type=\"' + context + '\"]');\n const hideNodes = modal.getRoot()[0].querySelectorAll('button[data-type]:not([data-type=\"' + context + '\"])');\n\n showNodes.forEach(node => node.classList.remove('elements-hidden'));\n hideNodes.forEach(node => node.classList.add('elements-hidden'));\n};\n\n/**\n * Replace all localized strings.\n *\n * @param {String} text\n * @return {String} String with lang tags replaced with a localized string.\n */\nconst applyLangStrings = (text) => {\n const compRegex = /{{#([^}]*)}}/g;\n\n [...text.matchAll(compRegex)].forEach(strLang => {\n text = text.replace('{{#' + strLang[1] + '}}', data.getLangString(strLang[1]));\n });\n\n return text;\n};\n\n/**\n * Generates a random string.\n * @return {string} A random string\n */\nconst generateRandomID = () => {\n const timestamp = new Date().getTime();\n return 'R' + Math.round(Math.random() * 100000) + '-' + timestamp;\n};\n\n/**\n * Replace all ID tags with a random string.\n * @param {String} text\n * @return {String} String with all ID tags replaced with a random string.\n */\nconst applyRandomID = (text) => {\n const compRegex = /{{@ID}}/g;\n\n if (text.match(compRegex)) {\n text = text.replace(compRegex, generateRandomID());\n }\n\n return text;\n};\n"],"names":["currentFlavor","currentFlavorId","currentCategoryId","currentCategoryName","lastFlavor","selection","data","async","editor","getContent","Data","loadData","Preferences","category","category_flavors","componentVariants","component_variants","displayDialogue","templateContext","getTemplateContext","modal","ElementsModal","create","type","TYPE","large","modalClass","getPreviewElements","targetElm","closest","classList","add","show","getRoot","on","ModalEvents","hidden","handleModalHidden","soleCategories","querySelectorAll","forEach","node","addEventListener","event","handleCategoryClick","selectCategories","handleCategoryFlavorClick","handleCategoryRemember","handleButtonClick","handleButtonMouseEvent","handleVariantClick","length","savedCategory","savedFlavor","displayorder","click","dataset","categoryid","flavorlink","querySelector","link","target","categoryname","remove","showCategoryButtons","flavor","id","componentButton","flavorlist","split","includes","variants","getComponentById","name","variant","updateVariantButtonState","indexOf","variantclass","undefined","e","value","JSON","stringify","updateComponentCode","componentCode","selectedButton","placeholder","replace","comp","join","getCategoryById","applyRandomID","applyLangStrings","code","text","flavors","randomId","generateRandomID","newNode","document","createElement","innerHTML","outerHTML","setContent","nodeSel","dom","select","destroy","focus","undoManager","previewDefault","toggle","stopPropagation","button","updateVariantComponentState","updateHtml","selectedVariant","componentClass","classcomponent","previewComponent","variantPreview","variantsHtml","hasflavors","state","activate","context","showNodes","hideNodes","matchAll","strLang","getLangString","timestamp","Date","getTime","Math","round","random","compRegex","match"],"mappings":"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"} \ No newline at end of file diff --git a/amd/src/ui.js b/amd/src/ui.js index e843d4b..161b70d 100644 --- a/amd/src/ui.js +++ b/amd/src/ui.js @@ -360,6 +360,7 @@ const handleButtonClick = async(event, editor, modal) => { modal.destroy(); editor.focus(); + editor.undoManager.add(); } };