lib/editor/tiny/plugins/link/amd/src/ui.js

  1. // This file is part of Moodle - http://moodle.org/
  2. //
  3. // Moodle is free software: you can redistribute it and/or modify
  4. // it under the terms of the GNU General Public License as published by
  5. // the Free Software Foundation, either version 3 of the License, or
  6. // (at your option) any later version.
  7. //
  8. // Moodle is distributed in the hope that it will be useful,
  9. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. // GNU General Public License for more details.
  12. //
  13. // You should have received a copy of the GNU General Public License
  14. // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
  15. /**
  16. * Tiny Link UI.
  17. *
  18. * @module tiny_link/ui
  19. * @copyright 2023 Huong Nguyen <huongnv13@gmail.com>
  20. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  21. */
  22. import {getFilePicker} from 'editor_tiny/options';
  23. import {displayFilepicker} from 'editor_tiny/utils';
  24. import LinkModal from 'tiny_link/modal';
  25. import {getPermissions} from "tiny_link/options";
  26. import {setLink, getCurrentLinkData, unSetLink} from "tiny_link/link";
  27. import Selectors from 'tiny_link/selectors';
  28. /**
  29. * Handle action.
  30. *
  31. * @param {TinyMCE} editor
  32. * @param {boolean} unlink
  33. */
  34. export const handleAction = (editor, unlink = false) => {
  35. if (!unlink) {
  36. displayDialogue(editor);
  37. } else {
  38. unSetLink(editor);
  39. }
  40. };
  41. /**
  42. * Display the link dialogue.
  43. *
  44. * @param {TinyMCE} editor
  45. * @returns {Promise<void>}
  46. */
  47. const displayDialogue = async(editor) => {
  48. const modal = await LinkModal.create({
  49. templateContext: getTemplateContext(editor),
  50. });
  51. const $root = await modal.getRoot();
  52. const root = $root[0];
  53. const currentForm = root.querySelector('form');
  54. root.addEventListener('click', (e) => {
  55. const submitAction = e.target.closest(Selectors.actions.submit);
  56. const linkBrowserAction = e.target.closest(Selectors.actions.linkBrowser);
  57. if (submitAction) {
  58. e.preventDefault();
  59. setLink(currentForm, editor);
  60. modal.destroy();
  61. }
  62. if (linkBrowserAction) {
  63. e.preventDefault();
  64. displayFilepicker(editor, 'link').then((params) => {
  65. filePickerCallback(params, currentForm, editor);
  66. return modal.destroy();
  67. }).catch();
  68. }
  69. });
  70. const linkTitle = root.querySelector(Selectors.elements.urlText);
  71. const linkUrl = root.querySelector(Selectors.elements.urlEntry);
  72. linkTitle.addEventListener('change', () => {
  73. if (linkTitle.value.length > 0) {
  74. linkTitle.dataset.useLinkAsText = 'false';
  75. } else {
  76. linkTitle.dataset.useLinkAsText = 'true';
  77. linkTitle.value = linkUrl.value;
  78. }
  79. });
  80. linkUrl.addEventListener('keyup', () => {
  81. updateTextToDisplay(currentForm);
  82. });
  83. };
  84. /**
  85. * Get template context.
  86. *
  87. * @param {TinyMCE} editor
  88. * @returns {Object}
  89. */
  90. const getTemplateContext = (editor) => {
  91. const data = getCurrentLinkData(editor);
  92. return Object.assign({}, {
  93. elementid: editor.id,
  94. showfilepicker: getPermissions(editor).filepicker &&
  95. (typeof getFilePicker(editor, 'link') !== 'undefined'),
  96. isupdating: Object.keys(data).length > 0,
  97. }, data);
  98. };
  99. /**
  100. * Update the dialogue after a link was selected in the File Picker.
  101. *
  102. * @param {Object} params
  103. * @param {Element} currentForm
  104. * @param {TinyMCE} editor
  105. */
  106. const filePickerCallback = (params, currentForm, editor) => {
  107. if (params.url) {
  108. const inputUrl = currentForm.querySelector(Selectors.elements.urlEntry);
  109. inputUrl.value = params.url;
  110. setLink(currentForm, editor);
  111. }
  112. };
  113. /**
  114. * Update the text to display if the user does not provide the custom text.
  115. *
  116. * @param {Element} currentForm
  117. */
  118. const updateTextToDisplay = (currentForm) => {
  119. const urlEntry = currentForm.querySelector(Selectors.elements.urlEntry);
  120. const urlText = currentForm.querySelector(Selectors.elements.urlText);
  121. if (urlText.dataset.useLinkAsText === 'true') {
  122. urlText.value = urlEntry.value;
  123. }
  124. };