From 89e77477c4612f9abe2ff64815cab9bec55555fe Mon Sep 17 00:00:00 2001 From: Stefan Hanauska Date: Mon, 3 Feb 2025 10:48:47 +0100 Subject: [PATCH] MBS-9904: Bulk edit displaynames --- amd/build/management.min.js | 2 +- amd/build/management.min.js.map | 2 +- amd/src/management.js | 27 ++++ classes/form/management_displaynames_form.php | 139 ++++++++++++++++++ lang/en/tiny_elements.php | 2 + templates/management.mustache | 6 + 6 files changed, 176 insertions(+), 2 deletions(-) create mode 100644 classes/form/management_displaynames_form.php diff --git a/amd/build/management.min.js b/amd/build/management.min.js index d415b72..a01adf3 100644 --- a/amd/build/management.min.js +++ b/amd/build/management.min.js @@ -1,3 +1,3 @@ -define("tiny_elements/management",["exports","core/modal","core_form/modalform","core/notification","core/str","core/ajax","core/templates"],(function(_exports,_modal,_modalform,_notification,_str,_ajax,_templates){function _getRequireWildcardCache(nodeInterop){if("function"!=typeof WeakMap)return null;var cacheBabelInterop=new WeakMap,cacheNodeInterop=new WeakMap;return(_getRequireWildcardCache=function(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop})(nodeInterop)}function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}function _defineProperty(obj,key,value){return key in obj?Object.defineProperty(obj,key,{value:value,enumerable:!0,configurable:!0,writable:!0}):obj[key]=value,obj}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=_exports.duplicateItem=_exports.deleteItem=void 0,_modal=_interopRequireDefault(_modal),_modalform=_interopRequireDefault(_modalform),_notification=function(obj,nodeInterop){if(!nodeInterop&&obj&&obj.__esModule)return obj;if(null===obj||"object"!=typeof obj&&"function"!=typeof obj)return{default:obj};var cache=_getRequireWildcardCache(nodeInterop);if(cache&&cache.has(obj))return cache.get(obj);var newObj={},hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj)if("default"!==key&&Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;desc&&(desc.get||desc.set)?Object.defineProperty(newObj,key,desc):newObj[key]=obj[key]}newObj.default=obj,cache&&cache.set(obj,newObj);return newObj}(_notification);class PreviewModal extends _modal.default{configure(modalConfig){modalConfig.removeOnClose=!0,modalConfig.large=!0,super.configure(modalConfig)}}_defineProperty(PreviewModal,"TYPE","tiny_elements/management_preview"),_defineProperty(PreviewModal,"TEMPLATE","tiny_elements/management_preview");function showModal(e,id,table){let title;e.preventDefault(),title=0==id?(0,_str.get_string)("additem","tiny_elements"):(0,_str.get_string)("edititem","tiny_elements");const modalForm=new _modalform.default({formClass:"tiny_elements\\form\\management_"+table+"_form",args:{id:id},modalConfig:{title:title}});modalForm.addEventListener(modalForm.events.FORM_SUBMITTED,(()=>{modalForm.getFormNode().elements.id.value||reload()})),modalForm.show()}async function importModalSubmitted(e){e.detail.update?location.reload():(e.stopPropagation(),(0,_templates.render)("tiny_elements/management_import_form_result",e.detail).then((async html=>(await _notification.default.alert((0,_str.get_string)("import_simulation","tiny_elements"),html,(0,_str.get_string)("close","tiny_elements")),!0))).catch((error=>{(0,_notification.exception)(error)})))}_exports.init=async params=>{if(document.getElementById("elements_import").addEventListener("click",(async e=>{!function(e){e.preventDefault();let title=(0,_str.get_string)("import","tiny_elements");const modalForm=new _modalform.default({formClass:"tiny_elements\\form\\management_import_form",args:{},modalConfig:{title:title}});modalForm.addEventListener(modalForm.events.FORM_SUBMITTED,importModalSubmitted),modalForm.show()}(e)})),document.getElementsByClassName("add").forEach((element=>{element.addEventListener("click",(async e=>{showModal(e,element.dataset.id,element.dataset.table)}))})),document.getElementsByClassName("edit").forEach((element=>{element.addEventListener("click",(async e=>{showModal(e,element.dataset.id,element.dataset.table)}))})),document.getElementsByClassName("delete").forEach((element=>{element.addEventListener("click",(async e=>{!function(e,id,title,table){e.preventDefault(),(0,_notification.deleteCancelPromise)((0,_str.get_string)("delete","tiny_elements",title),(0,_str.get_string)("deletewarning","tiny_elements")).then((async()=>{if(0!==id)try{if(await deleteItem(id,table)){const link=document.querySelector('[data-table="'+table+'"][data-id="'+id+'"]');if(link){link.closest(".item").remove()}}}catch(error){(0,_notification.exception)(error)}})).catch((()=>{}))}(e,element.dataset.id,element.dataset.title,element.dataset.table)}))})),document.getElementsByClassName("preview").forEach((element=>{element.addEventListener("click",(async e=>{!async function(e){e.preventDefault();let preview=e.target.closest(".preview");(await PreviewModal.create({templateContext:{component:preview.dataset.component,flavors:preview.dataset.flavors.trim().split(" "),config:M.cfg}})).show()}(e)}))})),document.getElementsByClassName("compcat").forEach((element=>{element.addEventListener("click",(async e=>{showItems(e,element.dataset.compcat)}))})),document.getElementById("elements_compflavor_button").addEventListener("click",(async e=>{!function(e){e.preventDefault();let title=(0,_str.get_string)("manage","tiny_elements");new _modalform.default({formClass:"tiny_elements\\form\\management_comp_flavor_form",args:{},modalConfig:{title:title}}).show()}(e)})),document.getElementsByClassName("duplicate").forEach((element=>{element.addEventListener("click",(async()=>{duplicateItem(element.dataset.id,element.dataset.table),reload()}))})),document.querySelectorAll(".flavor .card-body > .clickingextended, .component .card-body > .clickingextended, .variant .card-body > .clickingextended").forEach((element=>{element.addEventListener("click",(async e=>{e.target.closest(".item").querySelector("a.edit").click()}))})),params.compcatactive){let compcat=document.querySelector('.compcat[data-compcat="'+params.compcatactive+'"]');compcat&&(showItems(!1,params.compcatactive),compcat.classList.add("active"))}};const deleteItem=(id,table)=>(0,_ajax.call)([{methodname:"tiny_elements_delete_item",args:{id:id,table:table}}])[0];function showItems(e,compcat){document.querySelectorAll(".flavor, .component, .variant").forEach((element=>{element.classList.add("hidden")}));let itemsShow=document.getElementsByClassName(compcat),usedFlavors=[];itemsShow.forEach((element=>{if(element.classList.remove("hidden"),void 0!==element.dataset.flavors){let flavors=element.dataset.flavors.split(" ");for(let value of flavors)usedFlavors.includes(value)||0==value.length||usedFlavors.push(value)}}));let flavorstring=usedFlavors.map((item=>".".concat(item))).join(", ");if(flavorstring.length){document.querySelectorAll(flavorstring).forEach((element=>{element.classList.remove("hidden")}))}if(document.getElementsByClassName("addcontainer").forEach((element=>{element.classList.remove("hidden")})),e){document.getElementsByClassName("compcat").forEach((element=>{element.classList.remove("active")})),e.target.closest(".compcat").classList.add("active")}if("found-items"==compcat){let found=document.querySelector('.compcat[data-compcat="found-items"]');if(found.dataset.loneflavors.length){document.querySelectorAll(found.dataset.loneflavors).forEach((element=>{element.classList.remove("hidden")}))}if(found.dataset.lonevariants.length){document.querySelectorAll(found.dataset.lonevariants).forEach((element=>{element.classList.remove("hidden")}))}if(found.dataset.lonecomponents.length){document.querySelectorAll(found.dataset.lonecomponents).forEach((element=>{element.classList.remove("hidden")}))}}}function reload(){const compcat=document.querySelector(".compcat.active"),currentUrl=new URL(window.location.href);currentUrl.searchParams.set("compcat",compcat.dataset.compcat),window.location.href=currentUrl.toString()}_exports.deleteItem=deleteItem;const duplicateItem=(id,table)=>(0,_ajax.call)([{methodname:"tiny_elements_duplicate_item",args:{id:id,table:table}}])[0];_exports.duplicateItem=duplicateItem})); +define("tiny_elements/management",["exports","core/modal","core_form/modalform","core/notification","core/str","core/ajax","core/templates"],(function(_exports,_modal,_modalform,_notification,_str,_ajax,_templates){function _getRequireWildcardCache(nodeInterop){if("function"!=typeof WeakMap)return null;var cacheBabelInterop=new WeakMap,cacheNodeInterop=new WeakMap;return(_getRequireWildcardCache=function(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop})(nodeInterop)}function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}function _defineProperty(obj,key,value){return key in obj?Object.defineProperty(obj,key,{value:value,enumerable:!0,configurable:!0,writable:!0}):obj[key]=value,obj}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=_exports.duplicateItem=_exports.deleteItem=void 0,_modal=_interopRequireDefault(_modal),_modalform=_interopRequireDefault(_modalform),_notification=function(obj,nodeInterop){if(!nodeInterop&&obj&&obj.__esModule)return obj;if(null===obj||"object"!=typeof obj&&"function"!=typeof obj)return{default:obj};var cache=_getRequireWildcardCache(nodeInterop);if(cache&&cache.has(obj))return cache.get(obj);var newObj={},hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj)if("default"!==key&&Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;desc&&(desc.get||desc.set)?Object.defineProperty(newObj,key,desc):newObj[key]=obj[key]}newObj.default=obj,cache&&cache.set(obj,newObj);return newObj}(_notification);class PreviewModal extends _modal.default{configure(modalConfig){modalConfig.removeOnClose=!0,modalConfig.large=!0,super.configure(modalConfig)}}_defineProperty(PreviewModal,"TYPE","tiny_elements/management_preview"),_defineProperty(PreviewModal,"TEMPLATE","tiny_elements/management_preview");function showModal(e,id,table){let title;e.preventDefault(),title=0==id?(0,_str.get_string)("additem","tiny_elements"):(0,_str.get_string)("edititem","tiny_elements");const modalForm=new _modalform.default({formClass:"tiny_elements\\form\\management_"+table+"_form",args:{id:id},modalConfig:{title:title}});modalForm.addEventListener(modalForm.events.FORM_SUBMITTED,(()=>{modalForm.getFormNode().elements.id.value||reload()})),modalForm.show()}async function importModalSubmitted(e){e.detail.update?location.reload():(e.stopPropagation(),(0,_templates.render)("tiny_elements/management_import_form_result",e.detail).then((async html=>(await _notification.default.alert((0,_str.get_string)("import_simulation","tiny_elements"),html,(0,_str.get_string)("close","tiny_elements")),!0))).catch((error=>{(0,_notification.exception)(error)})))}_exports.init=async params=>{if(document.getElementById("elements_import").addEventListener("click",(async e=>{!function(e){e.preventDefault();let title=(0,_str.get_string)("import","tiny_elements");const modalForm=new _modalform.default({formClass:"tiny_elements\\form\\management_import_form",args:{},modalConfig:{title:title}});modalForm.addEventListener(modalForm.events.FORM_SUBMITTED,importModalSubmitted),modalForm.show()}(e)})),document.getElementsByClassName("add").forEach((element=>{element.addEventListener("click",(async e=>{showModal(e,element.dataset.id,element.dataset.table)}))})),document.getElementsByClassName("edit").forEach((element=>{element.addEventListener("click",(async e=>{showModal(e,element.dataset.id,element.dataset.table)}))})),document.getElementsByClassName("delete").forEach((element=>{element.addEventListener("click",(async e=>{!function(e,id,title,table){e.preventDefault(),(0,_notification.deleteCancelPromise)((0,_str.get_string)("delete","tiny_elements",title),(0,_str.get_string)("deletewarning","tiny_elements")).then((async()=>{if(0!==id)try{if(await deleteItem(id,table)){const link=document.querySelector('[data-table="'+table+'"][data-id="'+id+'"]');if(link){link.closest(".item").remove()}}}catch(error){(0,_notification.exception)(error)}})).catch((()=>{}))}(e,element.dataset.id,element.dataset.title,element.dataset.table)}))})),document.getElementsByClassName("preview").forEach((element=>{element.addEventListener("click",(async e=>{!async function(e){e.preventDefault();let preview=e.target.closest(".preview");(await PreviewModal.create({templateContext:{component:preview.dataset.component,flavors:preview.dataset.flavors.trim().split(" "),config:M.cfg}})).show()}(e)}))})),document.getElementsByClassName("compcat").forEach((element=>{element.addEventListener("click",(async e=>{showItems(e,element.dataset.compcat)}))})),document.getElementById("elements_compflavor_button").addEventListener("click",(async e=>{!function(e){e.preventDefault();let title=(0,_str.get_string)("manage","tiny_elements");new _modalform.default({formClass:"tiny_elements\\form\\management_comp_flavor_form",args:{},modalConfig:{title:title}}).show()}(e)})),document.getElementById("elements_displaynames_button").addEventListener("click",(async e=>{!function(e){e.preventDefault();let title=(0,_str.get_string)("manage","tiny_elements");const modalForm=new _modalform.default({formClass:"tiny_elements\\form\\management_displaynames_form",args:{},modalConfig:{title:title}});modalForm.addEventListener(modalForm.events.FORM_SUBMITTED,(()=>location.reload())),modalForm.show()}(e)})),document.getElementsByClassName("duplicate").forEach((element=>{element.addEventListener("click",(async()=>{duplicateItem(element.dataset.id,element.dataset.table),reload()}))})),document.querySelectorAll(".flavor .card-body > .clickingextended, .component .card-body > .clickingextended, .variant .card-body > .clickingextended").forEach((element=>{element.addEventListener("click",(async e=>{e.target.closest(".item").querySelector("a.edit").click()}))})),params.compcatactive){let compcat=document.querySelector('.compcat[data-compcat="'+params.compcatactive+'"]');compcat&&(showItems(!1,params.compcatactive),compcat.classList.add("active"))}};const deleteItem=(id,table)=>(0,_ajax.call)([{methodname:"tiny_elements_delete_item",args:{id:id,table:table}}])[0];function showItems(e,compcat){document.querySelectorAll(".flavor, .component, .variant").forEach((element=>{element.classList.add("hidden")}));let itemsShow=document.getElementsByClassName(compcat),usedFlavors=[];itemsShow.forEach((element=>{if(element.classList.remove("hidden"),void 0!==element.dataset.flavors){let flavors=element.dataset.flavors.split(" ");for(let value of flavors)usedFlavors.includes(value)||0==value.length||usedFlavors.push(value)}}));let flavorstring=usedFlavors.map((item=>".".concat(item))).join(", ");if(flavorstring.length){document.querySelectorAll(flavorstring).forEach((element=>{element.classList.remove("hidden")}))}if(document.getElementsByClassName("addcontainer").forEach((element=>{element.classList.remove("hidden")})),e){document.getElementsByClassName("compcat").forEach((element=>{element.classList.remove("active")})),e.target.closest(".compcat").classList.add("active")}if("found-items"==compcat){let found=document.querySelector('.compcat[data-compcat="found-items"]');if(found.dataset.loneflavors.length){document.querySelectorAll(found.dataset.loneflavors).forEach((element=>{element.classList.remove("hidden")}))}if(found.dataset.lonevariants.length){document.querySelectorAll(found.dataset.lonevariants).forEach((element=>{element.classList.remove("hidden")}))}if(found.dataset.lonecomponents.length){document.querySelectorAll(found.dataset.lonecomponents).forEach((element=>{element.classList.remove("hidden")}))}}}function reload(){const compcat=document.querySelector(".compcat.active"),currentUrl=new URL(window.location.href);currentUrl.searchParams.set("compcat",compcat.dataset.compcat),window.location.href=currentUrl.toString()}_exports.deleteItem=deleteItem;const duplicateItem=(id,table)=>(0,_ajax.call)([{methodname:"tiny_elements_duplicate_item",args:{id:id,table:table}}])[0];_exports.duplicateItem=duplicateItem})); //# sourceMappingURL=management.min.js.map \ No newline at end of file diff --git a/amd/build/management.min.js.map b/amd/build/management.min.js.map index b422d6a..64ded5f 100644 --- a/amd/build/management.min.js.map +++ b/amd/build/management.min.js.map @@ -1 +1 @@ -{"version":3,"file":"management.min.js","sources":["../src/management.js"],"sourcesContent":["import Modal from 'core/modal';\nimport ModalForm from 'core_form/modalform';\nimport Notification from 'core/notification';\nimport {get_string as getString} from 'core/str';\nimport {exception as displayException, deleteCancelPromise} from 'core/notification';\nimport {call as fetchMany} from 'core/ajax';\nimport {render as renderTemplate} from 'core/templates';\nclass PreviewModal extends Modal {\n static TYPE = \"tiny_elements/management_preview\";\n static TEMPLATE = \"tiny_elements/management_preview\";\n configure(modalConfig) {\n modalConfig.removeOnClose = true;\n modalConfig.large = true;\n super.configure(modalConfig);\n }\n}\n\nexport const init = async(params) => {\n\n // Add listener to import xml files.\n let importxml = document.getElementById('elements_import');\n importxml.addEventListener('click', async(e) => {\n importModal(e);\n });\n\n // Add listener for adding a new item.\n let additem = document.getElementsByClassName('add');\n additem.forEach(element => {\n element.addEventListener('click', async(e) => {\n showModal(e, element.dataset.id, element.dataset.table);\n });\n });\n\n // Add listener to edit items.\n let edititems = document.getElementsByClassName('edit');\n edititems.forEach(element => {\n element.addEventListener('click', async(e) => {\n showModal(e, element.dataset.id, element.dataset.table);\n });\n });\n\n // Add listener to delete items.\n let deleteitems = document.getElementsByClassName('delete');\n deleteitems.forEach(element => {\n element.addEventListener('click', async(e) => {\n deleteModal(e, element.dataset.id, element.dataset.title, element.dataset.table);\n });\n });\n\n // Add listener to preview items.\n let previewitems = document.getElementsByClassName('preview');\n previewitems.forEach(element => {\n element.addEventListener('click', async(e) => {\n previewModal(e);\n });\n });\n\n // Add listener to select compcat to show corresponding items.\n let compcats = document.getElementsByClassName('compcat');\n compcats.forEach(element => {\n element.addEventListener('click', async(e) => {\n showItems(e, element.dataset.compcat);\n });\n });\n\n // Add listener to manage component flavor relation.\n let compflavor = document.getElementById('elements_compflavor_button');\n compflavor.addEventListener('click', async(e) => {\n compflavorModal(e);\n });\n\n // Add listener to duplicate items.\n let duplicateitems = document.getElementsByClassName('duplicate');\n duplicateitems.forEach(element => {\n element.addEventListener('click', async() => {\n duplicateItem(element.dataset.id, element.dataset.table);\n reload();\n });\n });\n\n // Add image and text to item setting click area.\n let enlargeItems = document.querySelectorAll(\n '.flavor .card-body > .clickingextended, .component .card-body > .clickingextended, .variant .card-body > .clickingextended'\n );\n enlargeItems.forEach(element => {\n element.addEventListener('click', async(e) => {\n let item = e.target.closest('.item');\n item.querySelector('a.edit').click();\n });\n });\n\n // After submitting a new item, reset active compcat.\n if (params.compcatactive) {\n let compcat = document.querySelector('.compcat[data-compcat=\"' + params.compcatactive + '\"]');\n if (compcat) {\n showItems(false, params.compcatactive);\n compcat.classList.add('active');\n }\n }\n};\n\n/**\n * Show dynamic form to add/edit a source.\n * @param {*} e\n * @param {*} id\n * @param {*} table\n */\nfunction showModal(e, id, table) {\n e.preventDefault();\n let title;\n if (id == 0) {\n title = getString('additem', 'tiny_elements');\n } else {\n title = getString('edititem', 'tiny_elements');\n }\n\n const modalForm = new ModalForm({\n // Set formclass, depending on component.\n formClass: \"tiny_elements\\\\form\\\\management_\" + table + \"_form\",\n args: {\n id: id,\n },\n modalConfig: {title: title},\n });\n // Conditional reload page after submit.\n modalForm.addEventListener(modalForm.events.FORM_SUBMITTED, () => reloadIfNew(modalForm.getFormNode()));\n\n modalForm.show();\n}\n\n/**\n * Show modal to preview css version.\n * @param {*} e\n */\nasync function previewModal(e) {\n e.preventDefault();\n let preview = e.target.closest(\".preview\");\n const modal = await PreviewModal.create({\n templateContext: {\n component: preview.dataset.component,\n flavors: preview.dataset.flavors.trim().split(\" \"),\n config: M.cfg,\n },\n });\n modal.show();\n}\n\n/**\n * Show dynamic form to import xml backups.\n * @param {*} e\n */\nfunction importModal(e) {\n e.preventDefault();\n let title = getString('import', 'tiny_elements');\n\n const modalForm = new ModalForm({\n // Load import form.\n formClass: \"tiny_elements\\\\form\\\\management_import_form\",\n args: {},\n modalConfig: {title: title},\n });\n modalForm.addEventListener(modalForm.events.FORM_SUBMITTED, importModalSubmitted);\n\n modalForm.show();\n}\n\n/**\n * Process import form submit.\n * @param {*} e\n */\nasync function importModalSubmitted(e) {\n // Reload page after submit.\n if (e.detail.update) {\n location.reload();\n } else {\n e.stopPropagation();\n renderTemplate('tiny_elements/management_import_form_result', e.detail).then(async(html) => {\n await Notification.alert(\n getString('import_simulation', 'tiny_elements'),\n html,\n getString('close', 'tiny_elements')\n );\n return true;\n }).catch((error) => {\n displayException(error);\n });\n }\n}\n\n/**\n * Load modal to edit icon urls.\n * @param {*} e\n */\nfunction compflavorModal(e) {\n e.preventDefault();\n let title = getString('manage', 'tiny_elements');\n\n const modalForm = new ModalForm({\n // Load import form.\n formClass: \"tiny_elements\\\\form\\\\management_comp_flavor_form\",\n args: {},\n modalConfig: {title: title},\n });\n\n modalForm.show();\n}\n\n/**\n * Show dynamic form to delete a source.\n * @param {*} e\n * @param {*} id\n * @param {*} title\n * @param {*} table\n */\nfunction deleteModal(e, id, title, table) {\n e.preventDefault();\n\n deleteCancelPromise(\n getString('delete', 'tiny_elements', title),\n getString('deletewarning', 'tiny_elements'),\n ).then(async() => {\n if (id !== 0) {\n try {\n const deleted = await deleteItem(id, table);\n if (deleted) {\n const link = document.querySelector('[data-table=\"' + table + '\"][data-id=\"' + id + '\"]');\n if (link) {\n const card = link.closest(\".item\");\n card.remove();\n }\n }\n } catch (error) {\n displayException(error);\n }\n }\n return;\n }).catch(() => {\n return;\n });\n}\n\n/**\n * Delete elements items.\n * @param {*} id\n * @param {*} table\n * @returns {mixed}\n */\nexport const deleteItem = (\n id,\n table,\n) => fetchMany(\n [{\n methodname: 'tiny_elements_delete_item',\n args: {\n id,\n table,\n }\n }])[0];\n\n/**\n * Show items after clicking a compcat.\n * @param {*} e\n * @param {*} compcat\n */\nfunction showItems(e, compcat) {\n // But first hide all items.\n let itemsHide = document.querySelectorAll('.flavor, .component, .variant');\n itemsHide.forEach(element => {\n element.classList.add('hidden');\n });\n\n // Show component and variants with compcat name and read the flavors.\n let itemsShow = document.getElementsByClassName(compcat);\n let usedFlavors = [];\n itemsShow.forEach(element => {\n element.classList.remove('hidden');\n // Get all flavors to show if on compcat element.\n if (typeof element.dataset.flavors !== 'undefined') {\n let flavors = element.dataset.flavors.split(' ');\n for (let value of flavors) {\n if (!usedFlavors.includes(value) && value.length != 0) {\n usedFlavors.push(value);\n }\n }\n }\n });\n\n // Show the flavors.\n let flavorstring = usedFlavors.map(item => `.${item}`).join(', ');\n if (flavorstring.length) {\n let flavorsShow = document.querySelectorAll(flavorstring);\n flavorsShow.forEach(element => {\n element.classList.remove('hidden');\n });\n }\n\n // Show add buttons.\n let addsShow = document.getElementsByClassName('addcontainer');\n addsShow.forEach(element => {\n element.classList.remove('hidden');\n });\n\n // Unmark all and mark clicked compcat.\n if (e) {\n let items = document.getElementsByClassName('compcat');\n items.forEach(element => {\n element.classList.remove('active');\n });\n let item = e.target.closest('.compcat');\n item.classList.add('active');\n }\n\n // Special case, unassigned items, show all items without connection to compcat.\n if (compcat == 'found-items') {\n let found = document.querySelector('.compcat[data-compcat=\"found-items\"]');\n if (found.dataset.loneflavors.length) {\n let flavorsShow = document.querySelectorAll(found.dataset.loneflavors);\n flavorsShow.forEach(element => {\n element.classList.remove('hidden');\n });\n }\n if (found.dataset.lonevariants.length) {\n let variantsShow = document.querySelectorAll(found.dataset.lonevariants);\n variantsShow.forEach(element => {\n element.classList.remove('hidden');\n });\n }\n if (found.dataset.lonecomponents.length) {\n let componentsShow = document.querySelectorAll(found.dataset.lonecomponents);\n componentsShow.forEach(element => {\n element.classList.remove('hidden');\n });\n }\n }\n}\n\n/**\n * Reload for new items.\n * @param {*} form\n */\nfunction reloadIfNew(form) {\n // Newly created element without id?\n if (!form.elements.id.value) {\n reload();\n }\n}\n\n/**\n * Reload page with active compcat.\n */\nfunction reload() {\n // Reload page with active compcat.\n const compcat = document.querySelector('.compcat.active');\n const currentUrl = new URL(window.location.href);\n currentUrl.searchParams.set('compcat', compcat.dataset.compcat);\n window.location.href = currentUrl.toString();\n}\n\n/**\n * Duplicate elements items.\n * @param {*} id\n * @param {*} table\n * @returns {mixed}\n */\nexport const duplicateItem = (\n id,\n table,\n) => fetchMany(\n [{\n methodname: 'tiny_elements_duplicate_item',\n args: {\n id,\n table,\n }\n }])[0];\n\n"],"names":["PreviewModal","Modal","configure","modalConfig","removeOnClose","large","showModal","e","id","table","title","preventDefault","modalForm","ModalForm","formClass","args","addEventListener","events","FORM_SUBMITTED","getFormNode","elements","value","reload","show","importModalSubmitted","detail","update","location","stopPropagation","then","async","Notification","alert","html","catch","error","document","getElementById","importModal","getElementsByClassName","forEach","element","dataset","deleteItem","link","querySelector","closest","remove","deleteModal","preview","target","create","templateContext","component","flavors","trim","split","config","M","cfg","previewModal","showItems","compcat","compflavorModal","duplicateItem","querySelectorAll","click","params","compcatactive","classList","add","methodname","itemsShow","usedFlavors","includes","length","push","flavorstring","map","item","join","found","loneflavors","lonevariants","lonecomponents","currentUrl","URL","window","href","searchParams","set","toString"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"management.min.js","sources":["../src/management.js"],"sourcesContent":["import Modal from 'core/modal';\nimport ModalForm from 'core_form/modalform';\nimport Notification from 'core/notification';\nimport {get_string as getString} from 'core/str';\nimport {exception as displayException, deleteCancelPromise} from 'core/notification';\nimport {call as fetchMany} from 'core/ajax';\nimport {render as renderTemplate} from 'core/templates';\nclass PreviewModal extends Modal {\n static TYPE = \"tiny_elements/management_preview\";\n static TEMPLATE = \"tiny_elements/management_preview\";\n configure(modalConfig) {\n modalConfig.removeOnClose = true;\n modalConfig.large = true;\n super.configure(modalConfig);\n }\n}\n\nexport const init = async(params) => {\n\n // Add listener to import xml files.\n let importxml = document.getElementById('elements_import');\n importxml.addEventListener('click', async(e) => {\n importModal(e);\n });\n\n // Add listener for adding a new item.\n let additem = document.getElementsByClassName('add');\n additem.forEach(element => {\n element.addEventListener('click', async(e) => {\n showModal(e, element.dataset.id, element.dataset.table);\n });\n });\n\n // Add listener to edit items.\n let edititems = document.getElementsByClassName('edit');\n edititems.forEach(element => {\n element.addEventListener('click', async(e) => {\n showModal(e, element.dataset.id, element.dataset.table);\n });\n });\n\n // Add listener to delete items.\n let deleteitems = document.getElementsByClassName('delete');\n deleteitems.forEach(element => {\n element.addEventListener('click', async(e) => {\n deleteModal(e, element.dataset.id, element.dataset.title, element.dataset.table);\n });\n });\n\n // Add listener to preview items.\n let previewitems = document.getElementsByClassName('preview');\n previewitems.forEach(element => {\n element.addEventListener('click', async(e) => {\n previewModal(e);\n });\n });\n\n // Add listener to select compcat to show corresponding items.\n let compcats = document.getElementsByClassName('compcat');\n compcats.forEach(element => {\n element.addEventListener('click', async(e) => {\n showItems(e, element.dataset.compcat);\n });\n });\n\n // Add listener to manage component flavor relation.\n let compflavor = document.getElementById('elements_compflavor_button');\n compflavor.addEventListener('click', async(e) => {\n compflavorModal(e);\n });\n\n let displaynamesbutton = document.getElementById('elements_displaynames_button');\n displaynamesbutton.addEventListener('click', async(e) => {\n displaynamesModal(e);\n });\n\n // Add listener to duplicate items.\n let duplicateitems = document.getElementsByClassName('duplicate');\n duplicateitems.forEach(element => {\n element.addEventListener('click', async() => {\n duplicateItem(element.dataset.id, element.dataset.table);\n reload();\n });\n });\n\n // Add image and text to item setting click area.\n let enlargeItems = document.querySelectorAll(\n '.flavor .card-body > .clickingextended, .component .card-body > .clickingextended, .variant .card-body > .clickingextended'\n );\n enlargeItems.forEach(element => {\n element.addEventListener('click', async(e) => {\n let item = e.target.closest('.item');\n item.querySelector('a.edit').click();\n });\n });\n\n // After submitting a new item, reset active compcat.\n if (params.compcatactive) {\n let compcat = document.querySelector('.compcat[data-compcat=\"' + params.compcatactive + '\"]');\n if (compcat) {\n showItems(false, params.compcatactive);\n compcat.classList.add('active');\n }\n }\n};\n\n/**\n * Show dynamic form to add/edit a source.\n * @param {*} e\n * @param {*} id\n * @param {*} table\n */\nfunction showModal(e, id, table) {\n e.preventDefault();\n let title;\n if (id == 0) {\n title = getString('additem', 'tiny_elements');\n } else {\n title = getString('edititem', 'tiny_elements');\n }\n\n const modalForm = new ModalForm({\n // Set formclass, depending on component.\n formClass: \"tiny_elements\\\\form\\\\management_\" + table + \"_form\",\n args: {\n id: id,\n },\n modalConfig: {title: title},\n });\n // Conditional reload page after submit.\n modalForm.addEventListener(modalForm.events.FORM_SUBMITTED, () => reloadIfNew(modalForm.getFormNode()));\n\n modalForm.show();\n}\n\n/**\n * Show modal to preview css version.\n * @param {*} e\n */\nasync function previewModal(e) {\n e.preventDefault();\n let preview = e.target.closest(\".preview\");\n const modal = await PreviewModal.create({\n templateContext: {\n component: preview.dataset.component,\n flavors: preview.dataset.flavors.trim().split(\" \"),\n config: M.cfg,\n },\n });\n modal.show();\n}\n\n/**\n * Show dynamic form to import xml backups.\n * @param {*} e\n */\nfunction importModal(e) {\n e.preventDefault();\n let title = getString('import', 'tiny_elements');\n\n const modalForm = new ModalForm({\n // Load import form.\n formClass: \"tiny_elements\\\\form\\\\management_import_form\",\n args: {},\n modalConfig: {title: title},\n });\n modalForm.addEventListener(modalForm.events.FORM_SUBMITTED, importModalSubmitted);\n\n modalForm.show();\n}\n\n/**\n * Process import form submit.\n * @param {*} e\n */\nasync function importModalSubmitted(e) {\n // Reload page after submit.\n if (e.detail.update) {\n location.reload();\n } else {\n e.stopPropagation();\n renderTemplate('tiny_elements/management_import_form_result', e.detail).then(async(html) => {\n await Notification.alert(\n getString('import_simulation', 'tiny_elements'),\n html,\n getString('close', 'tiny_elements')\n );\n return true;\n }).catch((error) => {\n displayException(error);\n });\n }\n}\n\n/**\n * Load modal to edit icon urls.\n * @param {*} e\n */\nfunction compflavorModal(e) {\n e.preventDefault();\n let title = getString('manage', 'tiny_elements');\n\n const modalForm = new ModalForm({\n // Load import form.\n formClass: \"tiny_elements\\\\form\\\\management_comp_flavor_form\",\n args: {},\n modalConfig: {title: title},\n });\n\n modalForm.show();\n}\n\n/**\n * Load modal to edit displaynames.\n * @param {*} e\n * @returns {void}\n */\nfunction displaynamesModal(e) {\n e.preventDefault();\n let title = getString('manage', 'tiny_elements');\n\n const modalForm = new ModalForm({\n // Load displaynames bulk edit form.\n formClass: \"tiny_elements\\\\form\\\\management_displaynames_form\",\n args: {},\n modalConfig: {title: title},\n });\n\n // Reload page after submit.\n modalForm.addEventListener(modalForm.events.FORM_SUBMITTED, () => location.reload());\n\n modalForm.show();\n}\n\n/**\n * Show dynamic form to delete a source.\n * @param {*} e\n * @param {*} id\n * @param {*} title\n * @param {*} table\n */\nfunction deleteModal(e, id, title, table) {\n e.preventDefault();\n\n deleteCancelPromise(\n getString('delete', 'tiny_elements', title),\n getString('deletewarning', 'tiny_elements'),\n ).then(async() => {\n if (id !== 0) {\n try {\n const deleted = await deleteItem(id, table);\n if (deleted) {\n const link = document.querySelector('[data-table=\"' + table + '\"][data-id=\"' + id + '\"]');\n if (link) {\n const card = link.closest(\".item\");\n card.remove();\n }\n }\n } catch (error) {\n displayException(error);\n }\n }\n return;\n }).catch(() => {\n return;\n });\n}\n\n/**\n * Delete elements items.\n * @param {*} id\n * @param {*} table\n * @returns {mixed}\n */\nexport const deleteItem = (\n id,\n table,\n) => fetchMany(\n [{\n methodname: 'tiny_elements_delete_item',\n args: {\n id,\n table,\n }\n }])[0];\n\n/**\n * Show items after clicking a compcat.\n * @param {*} e\n * @param {*} compcat\n */\nfunction showItems(e, compcat) {\n // But first hide all items.\n let itemsHide = document.querySelectorAll('.flavor, .component, .variant');\n itemsHide.forEach(element => {\n element.classList.add('hidden');\n });\n\n // Show component and variants with compcat name and read the flavors.\n let itemsShow = document.getElementsByClassName(compcat);\n let usedFlavors = [];\n itemsShow.forEach(element => {\n element.classList.remove('hidden');\n // Get all flavors to show if on compcat element.\n if (typeof element.dataset.flavors !== 'undefined') {\n let flavors = element.dataset.flavors.split(' ');\n for (let value of flavors) {\n if (!usedFlavors.includes(value) && value.length != 0) {\n usedFlavors.push(value);\n }\n }\n }\n });\n\n // Show the flavors.\n let flavorstring = usedFlavors.map(item => `.${item}`).join(', ');\n if (flavorstring.length) {\n let flavorsShow = document.querySelectorAll(flavorstring);\n flavorsShow.forEach(element => {\n element.classList.remove('hidden');\n });\n }\n\n // Show add buttons.\n let addsShow = document.getElementsByClassName('addcontainer');\n addsShow.forEach(element => {\n element.classList.remove('hidden');\n });\n\n // Unmark all and mark clicked compcat.\n if (e) {\n let items = document.getElementsByClassName('compcat');\n items.forEach(element => {\n element.classList.remove('active');\n });\n let item = e.target.closest('.compcat');\n item.classList.add('active');\n }\n\n // Special case, unassigned items, show all items without connection to compcat.\n if (compcat == 'found-items') {\n let found = document.querySelector('.compcat[data-compcat=\"found-items\"]');\n if (found.dataset.loneflavors.length) {\n let flavorsShow = document.querySelectorAll(found.dataset.loneflavors);\n flavorsShow.forEach(element => {\n element.classList.remove('hidden');\n });\n }\n if (found.dataset.lonevariants.length) {\n let variantsShow = document.querySelectorAll(found.dataset.lonevariants);\n variantsShow.forEach(element => {\n element.classList.remove('hidden');\n });\n }\n if (found.dataset.lonecomponents.length) {\n let componentsShow = document.querySelectorAll(found.dataset.lonecomponents);\n componentsShow.forEach(element => {\n element.classList.remove('hidden');\n });\n }\n }\n}\n\n/**\n * Reload for new items.\n * @param {*} form\n */\nfunction reloadIfNew(form) {\n // Newly created element without id?\n if (!form.elements.id.value) {\n reload();\n }\n}\n\n/**\n * Reload page with active compcat.\n */\nfunction reload() {\n // Reload page with active compcat.\n const compcat = document.querySelector('.compcat.active');\n const currentUrl = new URL(window.location.href);\n currentUrl.searchParams.set('compcat', compcat.dataset.compcat);\n window.location.href = currentUrl.toString();\n}\n\n/**\n * Duplicate elements items.\n * @param {*} id\n * @param {*} table\n * @returns {mixed}\n */\nexport const duplicateItem = (\n id,\n table,\n) => fetchMany(\n [{\n methodname: 'tiny_elements_duplicate_item',\n args: {\n id,\n table,\n }\n }])[0];\n\n"],"names":["PreviewModal","Modal","configure","modalConfig","removeOnClose","large","showModal","e","id","table","title","preventDefault","modalForm","ModalForm","formClass","args","addEventListener","events","FORM_SUBMITTED","getFormNode","elements","value","reload","show","importModalSubmitted","detail","update","location","stopPropagation","then","async","Notification","alert","html","catch","error","document","getElementById","importModal","getElementsByClassName","forEach","element","dataset","deleteItem","link","querySelector","closest","remove","deleteModal","preview","target","create","templateContext","component","flavors","trim","split","config","M","cfg","previewModal","showItems","compcat","compflavorModal","displaynamesModal","duplicateItem","querySelectorAll","click","params","compcatactive","classList","add","methodname","itemsShow","usedFlavors","includes","length","push","flavorstring","map","item","join","found","loneflavors","lonevariants","lonecomponents","currentUrl","URL","window","href","searchParams","set","toString"],"mappings":"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"} \ No newline at end of file diff --git a/amd/src/management.js b/amd/src/management.js index e58f814..b4753c6 100644 --- a/amd/src/management.js +++ b/amd/src/management.js @@ -69,6 +69,11 @@ export const init = async(params) => { compflavorModal(e); }); + let displaynamesbutton = document.getElementById('elements_displaynames_button'); + displaynamesbutton.addEventListener('click', async(e) => { + displaynamesModal(e); + }); + // Add listener to duplicate items. let duplicateitems = document.getElementsByClassName('duplicate'); duplicateitems.forEach(element => { @@ -205,6 +210,28 @@ function compflavorModal(e) { modalForm.show(); } +/** + * Load modal to edit displaynames. + * @param {*} e + * @returns {void} + */ +function displaynamesModal(e) { + e.preventDefault(); + let title = getString('manage', 'tiny_elements'); + + const modalForm = new ModalForm({ + // Load displaynames bulk edit form. + formClass: "tiny_elements\\form\\management_displaynames_form", + args: {}, + modalConfig: {title: title}, + }); + + // Reload page after submit. + modalForm.addEventListener(modalForm.events.FORM_SUBMITTED, () => location.reload()); + + modalForm.show(); +} + /** * Show dynamic form to delete a source. * @param {*} e diff --git a/classes/form/management_displaynames_form.php b/classes/form/management_displaynames_form.php new file mode 100644 index 0000000..80c2cd8 --- /dev/null +++ b/classes/form/management_displaynames_form.php @@ -0,0 +1,139 @@ +. + +namespace tiny_elements\form; + +use core_form\dynamic_form; +use tiny_elements\local\utils; +use context; + +/** + * Form for bulk editing displaynames + * + * @package tiny_elements + * @copyright 2025 ISB Bayern + * @author Stefan Hanauska + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class management_displaynames_form extends dynamic_form { + /** + * Form definition + */ + public function definition() { + global $DB; + $count = $DB->count_records('tiny_elements_component'); + $mform =& $this->_form; + + $group = []; + $group[] = $mform->createElement('hidden', 'id'); + $group[] = $mform->createElement('static', 'longname', get_string('component', 'tiny_elements')); + $group[] = $mform->createElement('text', 'name', get_string('component', 'tiny_elements')); + $group[] = $mform->createElement('text', 'displayname', get_string('displayname', 'tiny_elements')); + + $options = [ + 'id' => [ + 'type' => PARAM_INT, + ], + 'name' => [ + 'type' => PARAM_TEXT, + ], + 'longname' => [ + 'type' => PARAM_TEXT, + ], + 'displayname' => [ + 'type' => PARAM_TEXT, + ], + ]; + + $this->repeat_elements($group, $count, $options, 'itemcount', 'adddummy', 0); + + $mform->removeElement('adddummy'); + + $mform->setAttributes(['data-formtype' => 'tiny_elements_displaynames']); + } + + /** + * Returns context where this form is used + * + * @return context + */ + protected function get_context_for_dynamic_submission(): context { + return \context_system::instance(); + } + + /** + * + * Checks if current user has sufficient permissions, otherwise throws exception + */ + protected function check_access_for_dynamic_submission(): void { + require_capability('tiny/elements:manage', $this->get_context_for_dynamic_submission()); + } + + /** + * Form processing. + * + * @return array + */ + public function process_dynamic_submission(): array { + global $DB; + + $formdata = $this->get_data(); + + $result = true; + + foreach ($formdata->id as $key => $id) { + $record = new \stdClass(); + $record->id = $id; + $record->displayname = $formdata->displayname[$key]; + $result &= $DB->update_record('tiny_elements_component', $record); + } + + return [ + 'update' => $result, + ]; + } + + /** + * Load in existing data as form defaults + */ + public function set_data_for_dynamic_submission(): void { + global $DB; + + $components = $DB->get_records('tiny_elements_component'); + $categories = $DB->get_records('tiny_elements_compcat'); + + $data = []; + foreach ($components as $component) { + $data['id'][] = $component->id; + $data['longname'][] = $categories[$component->compcat]->name . '/' . $component->name; + $data['name'][] = $component->name; + $data['displayname'][] = $component->displayname; + } + + $data['itemcount'] = count($components); + + $this->set_data($data); + } + + /** + * Returns url to set in $PAGE->set_url() when form is being rendered or submitted via AJAX + * + * @return moodle_url + */ + protected function get_page_url_for_dynamic_submission(): \moodle_url { + return new \moodle_url('/lib/editor/tiny/plugins/elements/management.php'); + } +} diff --git a/lang/en/tiny_elements.php b/lang/en/tiny_elements.php index e53ef2a..8079c23 100644 --- a/lang/en/tiny_elements.php +++ b/lang/en/tiny_elements.php @@ -26,6 +26,7 @@ defined('MOODLE_INTERNAL') || die(); $string['additem'] = 'Add item'; +$string['bulk_edit_displaynames'] = 'Bulk edit displaynames'; $string['button_elements'] = 'Elements'; $string['c4lcompatibility'] = 'If checked, the variant class name will be c4l-...-variant instead of elements-...-variant for compatibility with the original c4l components.'; $string['c4lcompatibility_help'] = 'c4l (components for learning) is the plugin elements is based on.'; @@ -35,6 +36,7 @@ $string['code_help'] = 'HTML code to insert. You can use {{VARIANTS}}, {{FLAVOR}} and {{PLACEHOLDER}} as placeholders for variants, flavors and text to be inserted.'; $string['compcat'] = 'Categories'; $string['compflavor_icons'] = 'Change button icons for components depending on flavors'; +$string['component'] = 'Component'; $string['component_flavor'] = 'Component/flavor'; $string['componentname'] = 'Component name'; $string['componentname_help'] = 'Name of the component use for internal use (also as a class name in CSS)'; diff --git a/templates/management.mustache b/templates/management.mustache index be38a6e..da6671d 100644 --- a/templates/management.mustache +++ b/templates/management.mustache @@ -187,6 +187,12 @@ {{/component}} +
+
+ +
+
+

{{#str}} variants, tiny_elements {{/str}}

{{#variant}}