{"version":3,"file":"name_list_element.min.js","sources":["https:\/\/moodle.sonsbeekmedia.nl\/caie_39\/mod\/teachingtools\/amd\/src\/names\/name_list_element.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 .\n\n\/**\n * Manage the default input for the games.\n *\n * @module mod_teachingtools\/names\/name_list_element\n * @class NameListElement\n * @copyright 2023 Sonsbeekmedia\n * @author Bas Brands \n * @license http:\/\/www.gnu.org\/copyleft\/gpl.html GNU GPL v3 or later\n *\/\n\nexport default class NameListElement {\n el;\n names;\n rootElement;\n\n constructor(names, rootElement) {\n this.names = names;\n this.rootElement = rootElement;\n this.el = '[data-action=\"names-editor\"]';\n this.addEventListeners();\n }\n\n reselectElement() {\n return this.rootElement.querySelector(this.el);\n }\n\n update(names) {\n if (!this.reselectElement()) {\n return;\n }\n\n const nameEditor = this.reselectElement();\n\n if (nameEditor && document.activeElement !== nameEditor) {\n this.reselectElement().innerHTML = '';\n \/\/ Add all names as plain text to the contenteditable.\n names.forEach((name) => {\n \/\/ Create a new div element\n nameEditor.innerHTML += name + '
';\n });\n }\n }\n\n removeTags(str) {\n if ((str === null) || (str === '')) {\n return false;\n } else {\n str = str.toString();\n return str.replace(\/(<([^>]+)>)\/ig, '');\n }\n }\n\n addEventListeners() {\n const nameForm = this.rootElement.querySelector('[data-region=\"name-form\"]');\n const advancedInput = this.rootElement.querySelector('[data-action=\"editadvanced\"]');\n if (advancedInput) {\n advancedInput.addEventListener('change', () => {\n if (advancedInput.checked) {\n this.addRemoveListeners();\n this.rootElement.querySelector('[data-region=\"advancededit\"]').classList.remove('d-none');\n this.rootElement.querySelector('[data-region=\"simpleedit\"]').classList.add('d-none');\n } else {\n this.rootElement.querySelector('[data-region=\"advancededit\"]').classList.add('d-none');\n this.rootElement.querySelector('[data-region=\"simpleedit\"]').classList.remove('d-none');\n }\n });\n }\n if (nameForm) {\n nameForm.addEventListener('submit', (e) => {\n e.preventDefault();\n const nameField = nameForm.querySelector('[data-region=\"name-input\"]');\n const value = nameField.value;\n if (value !== '') {\n nameField.value = '';\n nameField.focus();\n this.names.add(value);\n }\n });\n }\n const removeNames = this.rootElement.querySelector('[data-action=\"remove-names\"]');\n if (removeNames) {\n removeNames.addEventListener('click', () => {\n this.names.names = [];\n this.names.updateListeners();\n });\n }\n\n \/\/ Add paste event listener to the contenteditable.\n const nameEditor = this.rootElement.querySelector('[data-action=\"names-editor\"]');\n\n if (nameEditor) {\n nameEditor.innerHTML = '';\n this.names.names.forEach((name) => {\n \/\/ Create a new div element\n const div = document.createElement(\"div\");\n div.innerHTML = name;\n nameEditor.appendChild(div);\n });\n\n nameEditor.addEventListener('paste', (e) => {\n let paste = (e.clipboardData || window.clipboardData).getData('text');\n paste = this.removeTags(paste);\n if (!paste) {\n return;\n }\n let lines = paste.split(\/\\r?\\n\/);\n \/\/ Remove empty lines.\n lines = lines.filter(line => line.trim().length !== 0);\n\n \/\/ Fill the contenteditable with the pasted lines.\n let pastLines = lines.map(line => {\n return `
${line}<\/div>`;\n });\n pastLines = pastLines.join('');\n\n const selection = window.getSelection();\n if (!selection.rangeCount) {\n return;\n }\n selection.deleteFromDocument();\n const newDiv = document.createElement('div');\n newDiv.innerHTML = pastLines;\n selection.getRangeAt(0).insertNode(newDiv);\n\n this.names.names = this.getLinesfromContentEditable(nameEditor);\n this.names.updateListeners();\n e.preventDefault();\n });\n\n \/\/ Add input event listener to the contenteditable.\n nameEditor.addEventListener('blur', (e) => {\n this.names.names = this.getLinesfromContentEditable(e.target);\n this.names.updateListeners();\n });\n }\n }\n\n getLinesfromContentEditable(contentEditableElement) {\n\n let newValue = '';\n let isOnFreshLine = true;\n\n \/**\n * Recursive function to navigate childNodes and build linebreaks with text\n * @param {object} childNodes The childNodes of the contentEditable element\n *\/\n function parseChildNodesForValueAndLines(childNodes) {\n for (let i = 0; i < childNodes.length; i++) {\n const childNode = childNodes[i];\n\n if (childNode.nodeName === 'BR') {\n \/\/ BRs are always line breaks which means the next loop is on a fresh line\n newValue += '\\n';\n isOnFreshLine = true;\n continue;\n }\n\n \/\/ We may or may not need to create a new line\n if (childNode.nodeName === 'DIV' && isOnFreshLine === false) {\n \/\/ Divs create new lines for themselves if they aren't already on one\n newValue += '\\n';\n }\n\n \/\/ Whether we created a new line or not, we'll use it for this content so the next loop will not be on a fresh line:\n isOnFreshLine = false;\n\n \/\/ Add the text content if this is a text node:\n if (childNode.nodeType === 3 && childNode.textContent) {\n newValue += childNode.textContent;\n }\n\n \/\/ If this node has children, get into them as well:\n parseChildNodesForValueAndLines(childNode.childNodes);\n }\n }\n\n \/\/ Parse the child nodes for HTML and newlines:\n parseChildNodesForValueAndLines(contentEditableElement.childNodes);\n \/\/ Clean out the empty lines.\n return newValue.split('\\n').map(name => name.trim()).filter(name => name !== '');\n }\n\n\n addRemoveListeners() {\n \/\/ Add the eventlisteners to the document.\n if (this.rootElement.dataset.removeListeners) {\n return;\n }\n this.rootElement.addEventListener('click', event => {\n\n \/\/ Show set from a card.\n const removeButton = event.target.closest('[data-action=\"remove-button\"]');\n if (removeButton) {\n event.preventDefault();\n this.names.remove(removeButton.dataset.index);\n }\n });\n this.rootElement.dataset.removeListeners = true;\n }\n}"],"names":["constructor","names","rootElement","el","addEventListeners","reselectElement","this","querySelector","update","nameEditor","document","activeElement","innerHTML","forEach","name","removeTags","str","toString","replace","nameForm","advancedInput","addEventListener","checked","addRemoveListeners","classList","remove","add","e","preventDefault","nameField","value","focus","removeNames","updateListeners","div","createElement","appendChild","paste","clipboardData","window","getData","lines","split","filter","line","trim","length","pastLines","map","join","selection","getSelection","rangeCount","deleteFromDocument","newDiv","getRangeAt","insertNode","getLinesfromContentEditable","target","contentEditableElement","newValue","isOnFreshLine","parseChildNodesForValueAndLines","childNodes","i","childNode","nodeName","nodeType","textContent","dataset","removeListeners","event","removeButton","closest","index"],"mappings":"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"}