You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

175 lines
5.7 KiB

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