AutorÃa | Ultima modificación | Ver Log |
{"version":3,"file":"copy_to_clipboard.min.js","sources":["../src/copy_to_clipboard.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 <http://www.gnu.org/licenses/>.\n\n/**\n * A JavaScript module that enhances a button and text container to support copy-to-clipboard functionality.\n *\n * This module needs to be loaded by pages/templates/modules that require this functionality.\n *
\n * To enable copy-to-clipboard functionality, we need a trigger element (usually a button) and a copy target element\n * (e.g. a div, span, text input, or text area).\n *\n * In the trigger element, we need to declare the <code>data-action=\"copytoclipboard\"</code> attribute and set the\n * <code>data-clipboard-target</code> attribute which is the CSS selector that points to the target element that contains the text\n * to be copied.\n *\n * When the text is successfully copied to the clipboard, a toast message that indicates that the copy operation was a success\n * will be shown. This success message can be customised by setting the <code>data-clipboard-success-message</code> attribute in the\n * trigger element.\n *\n * @module core/copy_to_clipboard\n * @copyright 2021 Jun Pataleta\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n *\n * @example <caption>Markup for the trigger and target elements</caption>\n * <input type=\"text\" id=\"textinputtocopy\" class=\"form-contr
ol\" value=\"Copy me!\" readonly />\n * <button id=\"copybutton\" data-action=\"copytoclipboard\" data-clipboard-target=\"#textinputtocopy\"\n * data-clipboard-success-message=\"Success!\" class=\"btn btn-secondary\">\n * Copy to clipboard\n * </button>\n */\nimport {getString} from 'core/str';\nimport {add as addToast} from 'core/toast';\nimport {prefetchStrings} from 'core/prefetch';\n\n/**\n * Add event listeners to trigger elements through event delegation.\n *\n * @private\n */\nconst addEventListeners = () => {\n document.addEventListener('click', e => {\n const copyButton = e.target.closest('[data-action=\"copytoclipboard\"]');\n if (!copyButton) {\n return;\n }\n\n if (!copyButton.dataset.clipboardTarget) {\n return;\n }\n\n const copyTarget = document.querySelector(copyButton.dataset.clipboardTarget);\n if (!copyTarget) {\n return;\n }\n\n // This is a copy target and there is content.\n
// Prevent the default action.\n e.preventDefault();\n\n // We have a copy target - great. Let's copy its content.\n const textToCopy = getTextFromContainer(copyTarget);\n if (!textToCopy) {\n displayFailureToast();\n return;\n }\n\n if (navigator.clipboard) {\n navigator.clipboard.writeText(textToCopy)\n .then(() => displaySuccessToast(copyButton)).catch();\n\n return;\n }\n\n // The clipboard API is not available.\n // This may happen when the page is not served over SSL.\n // Try to fall back to document.execCommand() approach of copying the text.\n // WARNING: This is deprecated functionality that may get dropped at anytime by browsers.\n\n if (copyTarget instanceof HTMLInputElement || copyTarget instanceof HTMLTextAreaElement) {\n // Focus and select the text in the target element.\n // If the execCommand fails, at least the user can re
adily copy the text.\n copyTarget.focus();\n\n if (copyNodeContentToClipboard(copyButton, copyTarget)) {\n // If the copy was successful then focus back on the copy button.\n copyButton.focus();\n }\n } else {\n // This copyTarget is not an input, or text area so cannot be used with the execCommand('copy') command.\n // To work around this we create a new textarea and copy that.\n // This textarea must be part of the DOM and must be visible.\n // We (ab)use the sr-only tag to ensure that it is considered visible to the browser, whilst being\n // hidden from view by the user.\n const copyRegion = document.createElement('textarea');\n copyRegion.value = textToCopy;\n copyRegion.classList.add('sr-only');\n document.body.appendChild(copyRegion);\n\n copyNodeContentToClipboard(copyButton, copyRegion);\n\n // After copying, re
move the temporary element and move focus back to the triggering button.\n copyRegion.remove();\n copyButton.focus();\n }\n });\n};\n\n/**\n * Copy the content of the selected element to the clipboard, and display a notifiction if successful.\n *\n * @param {HTMLElement} copyButton\n * @param {HTMLElement} copyTarget\n * @returns {boolean}\n * @private\n */\nconst copyNodeContentToClipboard = (copyButton, copyTarget) => {\n copyTarget.select();\n\n // Try to copy the text from the target element.\n if (document.execCommand('copy')) {\n displaySuccessToast(copyButton);\n return true;\n }\n\n displayFailureToast();\n return false;\n};\n\n/**\n * Displays a toast containing the success message.\n *\n * @param {HTMLElement} copyButton The element that copies the text from the container.\n * @returns {Promise<void>}\n * @private\n */\nconst displaySuccessToast = copyButton => getSuccessText(copyButton)\n .then(successMessage => addToast(successMes
sage, {}));\n\n/**\n * Displays a toast containing the failure message.\n *\n * @returns {Promise<void>}\n * @private\n */\nconst displayFailureToast = () => getFailureText()\n .then(message => addToast(message, {type: 'warning'}));\n\n/**\n * Fetches the failure message to show to the user.\n *\n * @returns {Promise}\n * @private\n */\nconst getFailureText = () => getString('unabletocopytoclipboard', 'core');\n\n/**\n * Fetches the success message to show to the user.\n *\n * @param {HTMLElement} copyButton The element that copies the text from the container. This may contain the custom success message\n * via its data-clipboard-success-message attribute.\n * @returns {Promise|*}\n * @private\n */\nconst getSuccessText = copyButton => {\n if (copyButton.dataset.clipboardSuccessMessage) {\n return Promise.resolve(copyButton.dataset.clipboardSuccessMessage);\n }\n\n return getString('textcopiedtoclipboard', 'core');\n};\n\n/**\n * Fetches the text to be copied from the container.\n *\n * @p
aram {HTMLElement} container The element containing the text to be copied.\n * @returns {null|string}\n * @private\n */\nconst getTextFromContainer = container => {\n if (container.value) {\n // For containers which are form elements (e.g. text area, text input), get the element's value.\n return container.value;\n } else if (container.innerText) {\n // For other elements, try to use the innerText attribute.\n return container.innerText;\n }\n\n return null;\n};\n\nlet loaded = false;\nif (!loaded) {\n prefetchStrings('core', [\n 'textcopiedtoclipboard',\n 'unabletocopytoclipboard',\n ]);\n\n // Add event listeners.\n addEventListeners();\n loaded = true;\n}\n"],"names":["copyNodeContentToClipboard","copyButton","copyTarget","select","document","execCommand","displaySuccessToast","displayFailureToast","getSuccessText","then","successMessage","getFailureText","message","type","dataset","clipboardSuccessMessage","Promise","resolve","getTextFr
omContainer","container","value","innerText","loaded","addEventListener","e","target","closest","clipboardTarget","querySelector","preventDefault","textToCopy","navigator","clipboard","writeText","catch","HTMLInputElement","HTMLTextAreaElement","focus","copyRegion","createElement","classList","add","body","appendChild","remove"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;MA+HMA,2BAA6B,CAACC,WAAYC,cAC5CA,WAAWC,SAGPC,SAASC,YAAY,SACrBC,oBAAoBL,aACb,IAGXM,uBACO,IAULD,oBAAsBL,YAAcO,eAAeP,YACpDQ,MAAKC,iBAAkB,cAASA,eAAgB,MAQ/CH,oBAAsB,IAAMI,iBAC7BF,MAAKG,UAAW,cAASA,QAAS,CAACC,KAAM,cAQxCF,eAAiB,KAAM,kBAAU,0BAA2B,QAU5DH,eAAiBP,YACfA,WAAWa,QAAQC,wBACZC,QAAQC,QAAQhB,WAAWa,QAAQC,0BAGvC,kBAAU,wBAAyB,QAUxCG,qBAAuBC,WACrBA,UAAUC,MAEHD,UAAUC,MACVD,UAAUE,UAEVF,UAAUE,UAGd,SAGPC,QAAS,EACRA,uCACe,OAAQ,CACpB,wBACA,4BA1JJlB,SAASmB,iBAAiB,SAASC,UACzBvB,WAAauB,EAAEC,OAAOC,QAAQ,uCAC/BzB,sBAIAA,WAAWa,QAAQa,6BAIlBzB,WAAaE,SAASwB,cAAc3B,WAAWa,QAAQa,qBACxDzB,kBAMLsB,EAAEK,uBAGIC,WAAaZ,qBAAqBhB,eACnC4B,cAKDC,UAAUC,UACVD,UAAUC,UAAUC,UAAUH,YA
CzBrB,MAAK,IAAMH,oBAAoBL,cAAaiC,gBAUjDhC,sBAAsBiC,kBAAoBjC,sBAAsBkC,oBAGhElC,WAAWmC,QAEPrC,2BAA2BC,WAAYC,aAEvCD,WAAWoC,YAEZ,OAMGC,WAAalC,SAASmC,cAAc,YAC1CD,WAAWlB,MAAQU,WACnBQ,WAAWE,UAAUC,IAAI,WACzBrC,SAASsC,KAAKC,YAAYL,YAE1BtC,2BAA2BC,WAAYqC,YAGvCA,WAAWM,SACX3C,WAAWoC,aAxCX9B,yBAyIRe,QAAS"}