MDL-79041 core: Fix typo for MoodleNet resource URL
[moodle.git] / lib / amd / build / copy_to_clipboard.min.js.map
blob3472dc4c5e2e35ba3b949cdb8d0efe5b96c3f480
1 {"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-control\" 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 {get_string as 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 readily 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, remove 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(successMessage, {}));\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 * @param {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","getTextFromContainer","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,mBAAU,0BAA2B,QAU5DH,eAAiBP,YACfA,WAAWa,QAAQC,wBACZC,QAAQC,QAAQhB,WAAWa,QAAQC,0BAGvC,mBAAU,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,YACzBrB,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"}