diff --git a/public/lib/editor/tiny/plugins/media/amd/build/usedfiles.min.js b/public/lib/editor/tiny/plugins/media/amd/build/usedfiles.min.js index 5615690a785..c20a7f5e956 100644 --- a/public/lib/editor/tiny/plugins/media/amd/build/usedfiles.min.js +++ b/public/lib/editor/tiny/plugins/media/amd/build/usedfiles.min.js @@ -5,6 +5,6 @@ define("tiny_media/usedfiles",["exports","core/templates","core/config"],(functi * @module tiny_media/usedfiles * @copyright 2022, Stevani Andolo * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */(Templates),_config=(obj=_config)&&obj.__esModule?obj:{default:obj};class UsedFileManager{constructor(files,userContext,itemId,elementId){this.files=files,this.userContext=userContext,this.itemId=itemId,this.elementId=elementId}getElementId(){return this.elementId}getUsedFiles(){const editor=window.parent.tinymce.EditorManager.get(this.getElementId());if(!editor)return window.console.error("Editor not found for ".concat(this.getElementId())),[];const content=editor.getContent(),baseUrl="".concat(_config.default.wwwroot,"/draftfile.php/").concat(this.userContext,"/user/draft/").concat(this.itemId,"/"),pattern=new RegExp("[\"']"+baseUrl.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&")+"(?.+?)[\\?\"']","gm");return[...content.matchAll(pattern)].map((match=>decodeURIComponent(match.groups.filename)))}findUnusedFiles(usedFiles){return Object.entries(this.files).filter((_ref=>{let[filename]=_ref;return!usedFiles.includes(filename)})).map((_ref2=>{let[filename]=_ref2;return filename}))}findMissingFiles(usedFiles){return usedFiles.filter((filename=>!this.files.hasOwnProperty(filename)))}updateFiles(){const form=document.querySelector("form"),usedFiles=this.getUsedFiles(),unusedFiles=this.findUnusedFiles(usedFiles),missingFiles=this.findMissingFiles(usedFiles);return form.querySelectorAll('input[type=checkbox][name^="deletefile"]').forEach((checkbox=>{unusedFiles.includes(checkbox.dataset.filename)||checkbox.closest(".fitem").remove()})),form.classList.toggle("has-missing-files",!!missingFiles.length),form.classList.toggle("has-unused-files",!!unusedFiles.length),Templates.renderForPromise("tiny_media/missingfiles",{missingFiles:missingFiles}).then((_ref3=>{let{html:html,js:js}=_ref3;Templates.replaceNodeContents(form.querySelector(".missing-files"),html,js)}))}}_exports.init=(files,usercontext,itemid,elementid)=>{const manager=new UsedFileManager(files,usercontext,itemid,elementid);return manager.updateFiles(),manager}})); + */(Templates),_config=(obj=_config)&&obj.__esModule?obj:{default:obj};class UsedFileManager{constructor(userContext,itemId,elementId){this.files=this.getFiles(),this.userContext=userContext,this.itemId=itemId,this.elementId=elementId}getElementId(){return this.elementId}getUsedFiles(){const editor=window.parent.tinymce.EditorManager.get(this.getElementId());if(!editor)return window.console.error("Editor not found for ".concat(this.getElementId())),[];const content=editor.getContent(),baseUrl="".concat(_config.default.wwwroot,"/draftfile.php/").concat(this.userContext,"/user/draft/").concat(this.itemId,"/"),pattern=new RegExp("[\"']"+baseUrl.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&")+"(?.+?)[\\?\"']","gm");return[...content.matchAll(pattern)].map((match=>decodeURIComponent(match.groups.filename)))}findUnusedFiles(usedFiles){return Object.entries(this.files).filter((_ref=>{let[filename]=_ref;return!usedFiles.includes(filename)})).map((_ref2=>{let[filename]=_ref2;return filename}))}findMissingFiles(usedFiles){return usedFiles.filter((filename=>!this.files.hasOwnProperty(filename)))}updateFiles(){const form=document.querySelector("form"),usedFiles=this.getUsedFiles(),unusedFiles=this.findUnusedFiles(usedFiles),missingFiles=this.findMissingFiles(usedFiles);return form.querySelectorAll('input[type=checkbox][name^="deletefile"]').forEach((checkbox=>{unusedFiles.includes(checkbox.dataset.filename)||checkbox.closest(".fitem").remove()})),form.classList.toggle("has-missing-files",!!missingFiles.length),form.classList.toggle("has-unused-files",!!unusedFiles.length),Templates.renderForPromise("tiny_media/missingfiles",{missingFiles:missingFiles}).then((_ref3=>{let{html:html,js:js}=_ref3;Templates.replaceNodeContents(form.querySelector(".missing-files"),html,js)}))}getFiles(){const files={};return document.querySelectorAll('input[type=checkbox][name^="deletefile"]').forEach((input=>{files[input.dataset.filename]=input.dataset.filehash})),files}}_exports.init=(files,usercontext,itemid,elementid)=>{const manager=new UsedFileManager(files,usercontext,itemid,elementid);return manager.updateFiles(),manager}})); //# sourceMappingURL=usedfiles.min.js.map \ No newline at end of file diff --git a/public/lib/editor/tiny/plugins/media/amd/build/usedfiles.min.js.map b/public/lib/editor/tiny/plugins/media/amd/build/usedfiles.min.js.map index cc037dc3b24..cd3c083c514 100644 --- a/public/lib/editor/tiny/plugins/media/amd/build/usedfiles.min.js.map +++ b/public/lib/editor/tiny/plugins/media/amd/build/usedfiles.min.js.map @@ -1 +1 @@ -{"version":3,"file":"usedfiles.min.js","sources":["../src/usedfiles.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 Media Manager usedfiles.\n *\n * @module tiny_media/usedfiles\n * @copyright 2022, Stevani Andolo \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport * as Templates from 'core/templates';\nimport Config from 'core/config';\n\nclass UsedFileManager {\n constructor(files, userContext, itemId, elementId) {\n this.files = files;\n this.userContext = userContext;\n this.itemId = itemId;\n this.elementId = elementId;\n }\n\n getElementId() {\n return this.elementId;\n }\n\n getUsedFiles() {\n const editor = window.parent.tinymce.EditorManager.get(this.getElementId());\n if (!editor) {\n window.console.error(`Editor not found for ${this.getElementId()}`);\n return [];\n }\n const content = editor.getContent();\n const baseUrl = `${Config.wwwroot}/draftfile.php/${this.userContext}/user/draft/${this.itemId}/`;\n const pattern = new RegExp(\"[\\\"']\" + baseUrl.replace(/[-/\\\\^$*+?.()|[\\]{}]/g, '\\\\$&') + \"(?.+?)[\\\\?\\\"']\", 'gm');\n\n const usedFiles = [...content.matchAll(pattern)].map((match) => decodeURIComponent(match.groups.filename));\n\n return usedFiles;\n }\n\n // Return an array of unused files.\n findUnusedFiles(usedFiles) {\n return Object.entries(this.files)\n .filter(([filename]) => !usedFiles.includes(filename))\n .map(([filename]) => filename);\n }\n\n // Return an array of missing files.\n findMissingFiles(usedFiles) {\n return usedFiles.filter((filename) => !this.files.hasOwnProperty(filename));\n }\n\n updateFiles() {\n const form = document.querySelector('form');\n const usedFiles = this.getUsedFiles();\n const unusedFiles = this.findUnusedFiles(usedFiles);\n const missingFiles = this.findMissingFiles(usedFiles);\n\n form.querySelectorAll('input[type=checkbox][name^=\"deletefile\"]').forEach((checkbox) => {\n if (!unusedFiles.includes(checkbox.dataset.filename)) {\n checkbox.closest('.fitem').remove();\n }\n });\n\n form.classList.toggle('has-missing-files', !!missingFiles.length);\n form.classList.toggle('has-unused-files', !!unusedFiles.length);\n\n return Templates.renderForPromise('tiny_media/missingfiles', {\n missingFiles,\n }).then(({html, js}) => {\n Templates.replaceNodeContents(form.querySelector('.missing-files'), html, js);\n return;\n });\n }\n}\n\nexport const init = (files, usercontext, itemid, elementid) => {\n const manager = new UsedFileManager(files, usercontext, itemid, elementid);\n manager.updateFiles();\n\n return manager;\n};\n"],"names":["UsedFileManager","constructor","files","userContext","itemId","elementId","getElementId","this","getUsedFiles","editor","window","parent","tinymce","EditorManager","get","console","error","content","getContent","baseUrl","Config","wwwroot","pattern","RegExp","replace","matchAll","map","match","decodeURIComponent","groups","filename","findUnusedFiles","usedFiles","Object","entries","filter","_ref","includes","_ref2","findMissingFiles","hasOwnProperty","updateFiles","form","document","querySelector","unusedFiles","missingFiles","querySelectorAll","forEach","checkbox","dataset","closest","remove","classList","toggle","length","Templates","renderForPromise","then","_ref3","html","js","replaceNodeContents","usercontext","itemid","elementid","manager"],"mappings":";;;;;;;+EA0BMA,gBACFC,YAAYC,MAAOC,YAAaC,OAAQC,gBAC/BH,MAAQA,WACRC,YAAcA,iBACdC,OAASA,YACTC,UAAYA,UAGrBC,sBACWC,KAAKF,UAGhBG,qBACUC,OAASC,OAAOC,OAAOC,QAAQC,cAAcC,IAAIP,KAAKD,oBACvDG,cACDC,OAAOK,QAAQC,qCAA8BT,KAAKD,iBAC3C,SAELW,QAAUR,OAAOS,aACjBC,kBAAaC,gBAAOC,kCAAyBd,KAAKJ,mCAA0BI,KAAKH,YACjFkB,QAAU,IAAIC,OAAO,QAAUJ,QAAQK,QAAQ,wBAAyB,QAAU,2BAA4B,YAElG,IAAIP,QAAQQ,SAASH,UAAUI,KAAKC,OAAUC,mBAAmBD,MAAME,OAAOC,YAMpGC,gBAAgBC,kBACLC,OAAOC,QAAQ3B,KAAKL,OACtBiC,QAAOC,WAAEN,sBAAeE,UAAUK,SAASP,aAC3CJ,KAAIY,YAAER,uBAAcA,YAI7BS,iBAAiBP,kBACNA,UAAUG,QAAQL,WAAcvB,KAAKL,MAAMsC,eAAeV,YAGrEW,oBACUC,KAAOC,SAASC,cAAc,QAC9BZ,UAAYzB,KAAKC,eACjBqC,YAActC,KAAKwB,gBAAgBC,WACnCc,aAAevC,KAAKgC,iBAAiBP,kBAE3CU,KAAKK,iBAAiB,4CAA4CC,SAASC,WAClEJ,YAAYR,SAASY,SAASC,QAAQpB,WACvCmB,SAASE,QAAQ,UAAUC,YAInCV,KAAKW,UAAUC,OAAO,sBAAuBR,aAAaS,QAC1Db,KAAKW,UAAUC,OAAO,qBAAsBT,YAAYU,QAEjDC,UAAUC,iBAAiB,0BAA2B,CACzDX,aAAAA,eACDY,MAAKC,YAACC,KAACA,KAADC,GAAOA,UACZL,UAAUM,oBAAoBpB,KAAKE,cAAc,kBAAmBgB,KAAMC,sBAMlE,CAAC3D,MAAO6D,YAAaC,OAAQC,mBACvCC,QAAU,IAAIlE,gBAAgBE,MAAO6D,YAAaC,OAAQC,kBAChEC,QAAQzB,cAEDyB"} \ No newline at end of file +{"version":3,"file":"usedfiles.min.js","sources":["../src/usedfiles.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 Media Manager usedfiles.\n *\n * @module tiny_media/usedfiles\n * @copyright 2022, Stevani Andolo \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport * as Templates from 'core/templates';\nimport Config from 'core/config';\n\nclass UsedFileManager {\n constructor(userContext, itemId, elementId) {\n this.files = this.getFiles();\n this.userContext = userContext;\n this.itemId = itemId;\n this.elementId = elementId;\n }\n\n getElementId() {\n return this.elementId;\n }\n\n getUsedFiles() {\n const editor = window.parent.tinymce.EditorManager.get(this.getElementId());\n if (!editor) {\n window.console.error(`Editor not found for ${this.getElementId()}`);\n return [];\n }\n const content = editor.getContent();\n const baseUrl = `${Config.wwwroot}/draftfile.php/${this.userContext}/user/draft/${this.itemId}/`;\n const pattern = new RegExp(\"[\\\"']\" + baseUrl.replace(/[-/\\\\^$*+?.()|[\\]{}]/g, '\\\\$&') + \"(?.+?)[\\\\?\\\"']\", 'gm');\n\n const usedFiles = [...content.matchAll(pattern)].map((match) => decodeURIComponent(match.groups.filename));\n\n return usedFiles;\n }\n\n // Return an array of unused files.\n findUnusedFiles(usedFiles) {\n return Object.entries(this.files)\n .filter(([filename]) => !usedFiles.includes(filename))\n .map(([filename]) => filename);\n }\n\n // Return an array of missing files.\n findMissingFiles(usedFiles) {\n return usedFiles.filter((filename) => !this.files.hasOwnProperty(filename));\n }\n\n updateFiles() {\n const form = document.querySelector('form');\n const usedFiles = this.getUsedFiles();\n const unusedFiles = this.findUnusedFiles(usedFiles);\n const missingFiles = this.findMissingFiles(usedFiles);\n\n form.querySelectorAll('input[type=checkbox][name^=\"deletefile\"]').forEach((checkbox) => {\n if (!unusedFiles.includes(checkbox.dataset.filename)) {\n checkbox.closest('.fitem').remove();\n }\n });\n\n form.classList.toggle('has-missing-files', !!missingFiles.length);\n form.classList.toggle('has-unused-files', !!unusedFiles.length);\n\n return Templates.renderForPromise('tiny_media/missingfiles', {\n missingFiles,\n }).then(({html, js}) => {\n Templates.replaceNodeContents(form.querySelector('.missing-files'), html, js);\n return;\n });\n }\n\n /**\n * Retrieves a list of existing files selected for deletion.\n *\n * @returns {Object} An object where the keys are filenames and the values are file hashes.\n *\n */\n getFiles() {\n const files = {};\n document.querySelectorAll('input[type=checkbox][name^=\"deletefile\"]').forEach(input => {\n files[input.dataset.filename] = input.dataset.filehash;\n });\n return files;\n }\n}\n\nexport const init = (files, usercontext, itemid, elementid) => {\n const manager = new UsedFileManager(files, usercontext, itemid, elementid);\n manager.updateFiles();\n\n return manager;\n};\n"],"names":["UsedFileManager","constructor","userContext","itemId","elementId","files","this","getFiles","getElementId","getUsedFiles","editor","window","parent","tinymce","EditorManager","get","console","error","content","getContent","baseUrl","Config","wwwroot","pattern","RegExp","replace","matchAll","map","match","decodeURIComponent","groups","filename","findUnusedFiles","usedFiles","Object","entries","filter","_ref","includes","_ref2","findMissingFiles","hasOwnProperty","updateFiles","form","document","querySelector","unusedFiles","missingFiles","querySelectorAll","forEach","checkbox","dataset","closest","remove","classList","toggle","length","Templates","renderForPromise","then","_ref3","html","js","replaceNodeContents","input","filehash","usercontext","itemid","elementid","manager"],"mappings":";;;;;;;+EA0BMA,gBACFC,YAAYC,YAAaC,OAAQC,gBACxBC,MAAQC,KAAKC,gBACbL,YAAcA,iBACdC,OAASA,YACTC,UAAYA,UAGrBI,sBACWF,KAAKF,UAGhBK,qBACUC,OAASC,OAAOC,OAAOC,QAAQC,cAAcC,IAAIT,KAAKE,oBACvDE,cACDC,OAAOK,QAAQC,qCAA8BX,KAAKE,iBAC3C,SAELU,QAAUR,OAAOS,aACjBC,kBAAaC,gBAAOC,kCAAyBhB,KAAKJ,mCAA0BI,KAAKH,YACjFoB,QAAU,IAAIC,OAAO,QAAUJ,QAAQK,QAAQ,wBAAyB,QAAU,2BAA4B,YAElG,IAAIP,QAAQQ,SAASH,UAAUI,KAAKC,OAAUC,mBAAmBD,MAAME,OAAOC,YAMpGC,gBAAgBC,kBACLC,OAAOC,QAAQ7B,KAAKD,OACtB+B,QAAOC,WAAEN,sBAAeE,UAAUK,SAASP,aAC3CJ,KAAIY,YAAER,uBAAcA,YAI7BS,iBAAiBP,kBACNA,UAAUG,QAAQL,WAAczB,KAAKD,MAAMoC,eAAeV,YAGrEW,oBACUC,KAAOC,SAASC,cAAc,QAC9BZ,UAAY3B,KAAKG,eACjBqC,YAAcxC,KAAK0B,gBAAgBC,WACnCc,aAAezC,KAAKkC,iBAAiBP,kBAE3CU,KAAKK,iBAAiB,4CAA4CC,SAASC,WAClEJ,YAAYR,SAASY,SAASC,QAAQpB,WACvCmB,SAASE,QAAQ,UAAUC,YAInCV,KAAKW,UAAUC,OAAO,sBAAuBR,aAAaS,QAC1Db,KAAKW,UAAUC,OAAO,qBAAsBT,YAAYU,QAEjDC,UAAUC,iBAAiB,0BAA2B,CACzDX,aAAAA,eACDY,MAAKC,YAACC,KAACA,KAADC,GAAOA,UACZL,UAAUM,oBAAoBpB,KAAKE,cAAc,kBAAmBgB,KAAMC,OAWjFvD,iBACSF,MAAQ,UACduC,SAASI,iBAAiB,4CAA4CC,SAAQe,QAC1E3D,MAAM2D,MAAMb,QAAQpB,UAAYiC,MAAMb,QAAQc,YAE3C5D,qBAIK,CAACA,MAAO6D,YAAaC,OAAQC,mBACvCC,QAAU,IAAIrE,gBAAgBK,MAAO6D,YAAaC,OAAQC,kBAChEC,QAAQ3B,cAED2B"} \ No newline at end of file diff --git a/public/lib/editor/tiny/plugins/media/amd/src/usedfiles.js b/public/lib/editor/tiny/plugins/media/amd/src/usedfiles.js index 9404b7460bc..0d23f6a72cc 100644 --- a/public/lib/editor/tiny/plugins/media/amd/src/usedfiles.js +++ b/public/lib/editor/tiny/plugins/media/amd/src/usedfiles.js @@ -25,8 +25,8 @@ import * as Templates from 'core/templates'; import Config from 'core/config'; class UsedFileManager { - constructor(files, userContext, itemId, elementId) { - this.files = files; + constructor(userContext, itemId, elementId) { + this.files = this.getFiles(); this.userContext = userContext; this.itemId = itemId; this.elementId = elementId; @@ -85,6 +85,20 @@ class UsedFileManager { return; }); } + + /** + * Retrieves a list of existing files selected for deletion. + * + * @returns {Object} An object where the keys are filenames and the values are file hashes. + * + */ + getFiles() { + const files = {}; + document.querySelectorAll('input[type=checkbox][name^="deletefile"]').forEach(input => { + files[input.dataset.filename] = input.dataset.filehash; + }); + return files; + } } export const init = (files, usercontext, itemid, elementid) => { diff --git a/public/lib/editor/tiny/plugins/media/classes/form/manage_files_form.php b/public/lib/editor/tiny/plugins/media/classes/form/manage_files_form.php index 1d09b05ccee..72733c137b6 100644 --- a/public/lib/editor/tiny/plugins/media/classes/form/manage_files_form.php +++ b/public/lib/editor/tiny/plugins/media/classes/form/manage_files_form.php @@ -102,14 +102,13 @@ class manage_files_form extends \moodleform { $mform->addElement('static', '', '', html_writer::tag('div', get_string('unusedfilesdesc', 'tiny_media'))); foreach ($files as $hash => $file) { - $mform->addElement('checkbox', "deletefile[{$hash}]", '', $file, ['data-filename' => $file]); + $mform->addElement('checkbox', "deletefile[{$hash}]", '', $file, ['data-filename' => $file, 'data-filehash' => $hash]); $mform->setType("deletefile[{$hash}]", PARAM_INT); } $mform->addElement('submit', 'delete', get_string('deleteselected', 'tiny_media')); $PAGE->requires->js_call_amd('tiny_media/usedfiles', 'init', [ - 'files' => array_flip($files), 'usercontext' => $usercontext->id, 'itemid' => $itemid, 'elementid' => $elementid,