1/** 2 * Integrates move capability into the media manager 3 * Based on the implementation in diagrams plugin 4 */ 5class MoveMediaManager { 6 7 constructor() { 8 // user is not allowed to move anything 9 if (!JSINFO.move_allowrename) return; 10 11 const filePanel = document.querySelector('#mediamanager__page .panel.file'); 12 if (filePanel) { 13 const observer = new MutationObserver(this.#addMoveButton.bind(this)); 14 observer.observe(filePanel, {childList: true, subtree: true}); 15 } 16 } 17 18 /** 19 * Observer callback to add the move button in the detail panel of the media manager 20 * 21 * @param mutationsList 22 * @param observer 23 */ 24 async #addMoveButton(mutationsList, observer) { 25 for (let mutation of mutationsList) { 26 // div.file has been filled with new content? 27 if (mutation.type !== 'childList') continue; 28 29 // check that the file panel contains a link to a file 30 if (mutation.target.classList.contains('file') === false) continue; 31 const link = mutation.target.querySelector('a.select.mediafile'); 32 if (!link) continue; 33 34 const actionList = mutation.target.querySelector('ul.actions'); 35 if (actionList.querySelector('button.move-btn')) continue; // already added 36 37 const deleteButton = actionList.querySelector('form#mediamanager__btn_delete'); 38 if (deleteButton === null) continue; // no delete permissions 39 40 const src = link.textContent; 41 42 const moveButton = document.createElement('button'); 43 moveButton.classList.add('move-btn'); 44 moveButton.innerText = LANG.plugins.move.moveButton; 45 46 moveButton.addEventListener('click', this.#showDialog.bind(this, src)); 47 actionList.appendChild(moveButton); 48 } 49 } 50 51 /** 52 * Show the move dialog 53 * 54 * Uses JQuery UI 55 * 56 * @param {string} src 57 * @param {Event} event 58 * @returns {Promise<void>} 59 */ 60 async #showDialog(src, event) { 61 event.preventDefault(); 62 event.stopPropagation(); 63 64 const $form = jQuery(this.#buildForm(src)); 65 $form.dialog({ 66 title: LANG.plugins.move.moveButton, 67 width: 600, 68 appendTo: '.dokuwiki', 69 modal: true, 70 close: function () { 71 // do not reuse the dialog 72 // https://stackoverflow.com/a/2864783 73 jQuery(this).dialog('destroy').remove(); 74 } 75 }); 76 } 77 78 /** 79 * Create the form for the old and new file names 80 * 81 * @param {string} src 82 * @returns {HTMLDivElement} 83 */ 84 #buildForm(src) { 85 const wrapper = document.createElement('div'); 86 const form = document.createElement('form'); 87 wrapper.appendChild(form); 88 89 const intro = document.createElement('p'); 90 intro.innerText = LANG.plugins.move.dialogIntro; 91 form.appendChild(intro); 92 93 const errorContainer = document.createElement('div'); 94 errorContainer.className = 'move-error'; 95 form.appendChild(errorContainer); 96 97 const original = document.createElement('input'); 98 original.type = 'hidden'; 99 original.name = 'move-old-filename'; 100 original.value = src; 101 form.appendChild(original); 102 103 const sectok = document.querySelector('form#mediamanager__btn_delete input[name=sectok]').cloneNode(); 104 form.appendChild(sectok); 105 106 // strip file extension and put it in a readonly field so it may not be modified 107 const fileExt = document.createElement('input'); 108 fileExt.type = 'text'; 109 fileExt.readOnly = true; 110 fileExt.size = 5; 111 fileExt.name = 'move-file-ext'; 112 fileExt.value = src.split('.').pop(); 113 114 const destination = document.createElement('input'); 115 destination.type = 'text'; 116 destination.className = 'edit'; 117 destination.name = 'move-new-filename'; 118 destination.value = src.substring(0, src.length - (fileExt.value.length + 1)); 119 destination.size = 50; 120 form.appendChild(destination); 121 form.appendChild(fileExt); 122 123 const button = document.createElement('button'); 124 button.innerText = LANG.plugins.move.moveButton; 125 form.appendChild(button); 126 127 form.addEventListener('submit', this.#requestMove.bind(this, form)); 128 129 return wrapper; 130 } 131 132 /** 133 * Send move request to backend 134 * 135 * @param {HTMLFormElement} form 136 * @param {Event} event 137 * @returns {Promise<void>} 138 */ 139 async #requestMove(form, event) { 140 141 event.preventDefault(); 142 event.stopPropagation(); 143 144 const src = form.querySelector('input[name="move-old-filename"]').value; 145 const dst = form.querySelector('input[name="move-new-filename"]').value; 146 const ext = form.querySelector('input[name="move-file-ext"]').value; 147 const sectok = form.querySelector('input[name="sectok"]').value; 148 const err = form.querySelector('div.move-error'); 149 150 jQuery.post( 151 DOKU_BASE + 'lib/exe/ajax.php', 152 { 153 call: 'plugin_move_rename_mediamanager', 154 src: src, 155 dst: dst + '.' + ext, 156 sectok: sectok 157 }, 158 // redirect or display error 159 function (result) { 160 if (result.success) { 161 window.location.href = result.redirect_url; 162 } else { 163 err.classList.add('error'); 164 err.innerText = result.error; 165 } 166 } 167 ); 168 } 169} 170 171// initialize 172document.addEventListener('DOMContentLoaded', () => { 173 new MoveMediaManager(); 174}); 175