{"version":3,"file":"flipcards.min.js","sources":["https:\/\/moodle.sonsbeekmedia.nl\/caie_39\/mod\/teachingtools\/teachingapp\/flipcards\/amd\/src\/flipcards.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 * The flipping of cards.\n *\n * @module teachingapp_flipcards\/flipcards\n * @class flipcards\n * @copyright 2023 Sonsbeekmedia\n * @author Bas Brands \n * @license http:\/\/www.gnu.org\/copyleft\/gpl.html GNU GPL v3 or later\n *\/\n\nimport GameEngineLoader from 'mod_teachingtools\/game_engine';\nimport Templates from 'core\/templates';\nimport Notification from 'core\/notification';\nimport Tns from 'mod_teachingtools\/tinyslider';\nimport textFit from 'mod_teachingtools\/textFit';\n\nclass GameElement {\n\n \/**\n * GameElement class constructor.\n * Initializes a new instance of the GameElement class.\n * @param {Array} names An array of names to be used within the game element.\n * @param {HTMLElement} rootElement The root DOM element where the game element will be attached.\n *\/\n constructor(names, rootElement) {\n this.names = names;\n this.rootElement = rootElement;\n this.drawZone = this.rootElement.querySelector('[data-region=\"flipcards-draw-zone\"]');\n this.editButton = this.rootElement.querySelector('[data-action=\"editcard\"]');\n this.configuratorButton = this.rootElement.querySelector('[data-dismiss=\"configurator\"]');\n\n this.textFitSettings = {\n alignVert: true, \/\/ If true, textFit will align vertically using css tables\n alignHoriz: true, \/\/ If true, textFit will set text-align: center.\n multiLine: true, \/\/ If true, textFit will not set white-space: no-wrap\n detectMultiLine: true, \/\/ Disable to turn off automatic multi-line sensing.\n minFontSize: 6,\n maxFontSize: 40,\n reProcess: true, \/\/ If true, textFit will re-process already-fit nodes. Set to 'false' for better performance\n widthOnly: false, \/\/ If true, textFit will fit text to element width, regardless of text height\n alignVertWithFlexbox: false, \/\/ If true, textFit will use flexbox for vertical alignment\n };\n this.editButtonEvents();\n this.addEventListeners();\n this.createAriaLive();\n this.render();\n this.sliderStart = 0;\n this.slider = null;\n this.currentIndex = 0;\n }\n\n \/**\n * Updates the names array with a new set of names.\n * @param {Array} names An array of new names to replace the existing names.\n *\/\n update(names) {\n this.names.names = names;\n }\n\n \/**\n * Renders the game element by creating card elements for each name and setting up the game area.\n *\/\n render() {\n const names = this.names.names;\n const wrapper = this.rootElement.querySelector('[data-region=\"flipcards-wrapper\"]');\n\n wrapper.dataset.numcards = names.length;\n wrapper.innerHTML = '';\n\n \/\/ Creat a new tinder slider.\n const newCards = document.createElement('div');\n\n \/\/ Results will be displayed here.\n const endOfDeck = document.createElement('div');\n endOfDeck.classList.add('endofdeck', 'd-none');\n endOfDeck.textContent = 'End of deck';\n endOfDeck.dataset.region = 'endofdeck';\n\n \/\/ Cards will be added here.\n const newList = document.createElement('div');\n newList.classList.add('flipslides');\n newCards.appendChild(endOfDeck);\n newCards.appendChild(newList);\n newCards.dataset.region = 'flipcards';\n wrapper.appendChild(newCards);\n\n const namesmap = names.map((name, i) => {\n const last = i === names.length - 1;\n \/\/ Split the name in two parts by semi-colon.\n const parts = name.split('|');\n const newName = {\n text: parts[0],\n back: parts[1],\n index: i,\n last: last,\n first: i === 0,\n modurl: M.cfg.wwwroot + '\/mod\/teachingtools\/teachingapp\/flipcards\/pix\/'\n };\n return newName;\n });\n\n const template = {\n cards: namesmap\n };\n Templates.render('teachingapp_flipcards\/slide', template).then((html) => {\n newList.innerHTML = html;\n this.cardEvents();\n this.createSlider();\n this.updateAriaLive();\n return '';\n }).catch(Notification.exception);\n }\n\n \/**\n * Initializes the slider functionality for navigating through cards.\n *\/\n createSlider() {\n const previousString = 'Previous';\n const nextString = 'Next';\n const btnLeftString = `${previousString}<\/span>` +\n `<\/i><\/span>`;\n const btnRightString = `${nextString}<\/span>` +\n `<\/i><\/span>`;\n this.slider = Tns.tns({\n container: '.flipslides',\n items: 1,\n slideBy: 'page',\n controlsText: [btnLeftString, btnRightString],\n loop: false,\n startIndex: this.currentIndex\n });\n\n if (this.slider) {\n this.slider.events.on('indexChanged', () => {\n const index = this.slider.getInfo().index;\n const currentSlide = this.slider.getInfo().slideItems[index];\n const currentCard = currentSlide.querySelector('.card');\n currentCard.setAttribute('tabindex', 0);\n currentCard.classList.add('focus');\n\n \/\/ Remove flip class from all cards.\n const cards = this.rootElement.querySelectorAll('[data-region=\"flipcards\"] .card');\n cards.forEach((card) => {\n card.classList.remove('flip');\n card.classList.remove('editing');\n if (card !== currentCard) {\n card.classList.remove('focus');\n card.setAttribute('tabindex', -1);\n }\n });\n this.updateAriaLive();\n });\n if (this.currentIndex > 0) {\n this.slider.goTo(this.currentIndex);\n }\n }\n this.slider.goTo(this.sliderStart);\n if (this.sliderStart === 'last') {\n this.toggleEditMode();\n }\n this.sliderStart = 0;\n const currentCard = this.rootElement.querySelector('[data-region=\"flipcards\"] .tns-slide-active .card');\n currentCard.setAttribute('tabindex', 0);\n\n const fronts = this.rootElement.querySelectorAll('[data-region=\"flipcards\"] .front .text');\n fronts.forEach((front) => {\n textFit(front, this.textFitSettings);\n });\n const backs = this.rootElement.querySelectorAll('[data-region=\"flipcards\"] .back .text');\n backs.forEach((back) => {\n textFit(back, this.textFitSettings);\n });\n }\n\n \/**\n * Sets up event listeners for each card to handle flip, save, cancel, and delete actions.\n *\/\n cardEvents() {\n const cards = this.rootElement.querySelectorAll('[data-region=\"flipcards\"] .card');\n cards.forEach((card) => {\n card.addEventListener('click', (e) => {\n if (!card.classList.contains('editing')) {\n card.classList.toggle('flip');\n this.updateAriaLive();\n }\n e.preventDefault();\n });\n const saveButton = card.querySelector('[data-action=\"save\"]');\n saveButton.addEventListener('click', (e) => {\n this.saveCardChanges(card);\n e.preventDefault();\n });\n saveButton.addEventListener('keydown', (e) => {\n if (e.key === 'Enter') {\n this.saveCardChanges(card);\n e.preventDefault();\n }\n });\n\n const cancelButton = card.querySelector('[data-action=\"cancel\"]');\n cancelButton.addEventListener('click', (e) => {\n setTimeout(() => {\n card.classList.remove('editing');\n this.editButton.focus();\n }, 100);\n e.preventDefault();\n });\n cancelButton.addEventListener('keydown', (e) => {\n if (e.key === 'Enter') {\n setTimeout(() => {\n card.classList.remove('editing');\n this.editButton.focus();\n }, 100);\n e.preventDefault();\n }\n });\n\n const deleteButton = card.querySelector('[data-action=\"delete\"]');\n deleteButton.addEventListener('click', (e) => {\n const cardIndex = card.dataset.cardId;\n card.classList.add('deleted');\n setTimeout(() => {\n this.names.remove(cardIndex);\n this.editButton.focus();\n }, 500);\n e.preventDefault();\n });\n deleteButton.addEventListener('keydown', (e) => {\n if (e.key === 'Enter') {\n const cardIndex = card.dataset.cardId;\n card.classList.add('deleted');\n setTimeout(() => {\n this.names.remove(cardIndex);\n this.render();\n this.editButton.focus();\n }, 500);\n e.preventDefault();\n }\n });\n });\n }\n\n \/**\n * Saves changes made to a card, updating the name array and re-rendering the card text.\n * @param {HTMLElement} card The card element whose changes are to be saved.\n *\/\n saveCardChanges(card) {\n const cardIndex = card.dataset.cardId;\n const frontText = card.querySelector('[data-region=\"fronttext\"]');\n const backText = card.querySelector('[data-region=\"backtext\"]');\n const newName = frontText.value + '|' + backText.value;\n this.names.update(cardIndex, newName);\n\n \/\/ Set the new front and back texts.\n const frontDiv = card.querySelector('.front .text');\n const backDiv = card.querySelector('.back .text');\n frontDiv.textContent = frontText.value;\n backDiv.textContent = backText.value;\n setTimeout(() => {\n card.classList.remove('editing');\n textFit(frontDiv, this.textFitSettings);\n textFit(backDiv, this.textFitSettings);\n this.editButton.focus();\n }, 100);\n }\n\n \/**\n * Sets up event listeners for the edit button to allow toggling edit mode on the active card.\n *\/\n editButtonEvents() {\n if (!this.editButton) {\n return;\n }\n this.editButton.addEventListener('click', (e) => {\n this.toggleEditMode();\n e.preventDefault();\n });\n this.configuratorButton.addEventListener('click', () => {\n this.render();\n });\n }\n\n \/**\n * Toggle the edit mode on the active card.\n *\/\n toggleEditMode() {\n const card = this.rootElement.querySelector('[data-region=\"flipcards\"] .tns-slide-active .card');\n card.classList.toggle('editing');\n if (card.classList.contains('editing')) {\n const frontText = card.querySelector('[data-region=\"fronttext\"]');\n frontText.focus();\n } else {\n this.editButton.focus();\n }\n }\n\n \/**\n * Focuses the active card in the slider.\n *\/\n focusActiveCard() {\n const card = this.rootElement.querySelector('[data-region=\"flipcards\"] .tns-slide-active .card');\n card.focus();\n }\n\n \/**\n * Updates an ARIA live region with information about the groups.\n *\/\n updateAriaLive() {\n if (!this.ariaLive) {\n this.createAriaLive();\n }\n const index = this.slider.getInfo().index;\n const currentSlide = this.slider.getInfo().slideItems[index];\n const currentCard = currentSlide.querySelector('.card');\n let cardText = '';\n if (currentCard.classList.contains('flip')) {\n cardText = 'Back text: ' + currentCard.querySelector('.back .text').textContent;\n } else {\n cardText = 'Front text: ' + currentCard.querySelector('.front .text').textContent;\n }\n const message = 'Card ' + (index + 1) + ' of ' + this.names.names.length + '. ' + cardText;\n this.ariaLive.textContent = message;\n }\n\n \/**\n * Creates an ARIA live region for announcing dynamic updates to screen readers.\n *\/\n createAriaLive() {\n const ariaLive = document.createElement('div');\n ariaLive.setAttribute('aria-live', 'polite');\n ariaLive.setAttribute('aria-atomic', 'true');\n ariaLive.setAttribute('aria-relevant', 'additions');\n ariaLive.classList.add('sr-only');\n this.rootElement.appendChild(ariaLive);\n this.ariaLive = ariaLive;\n }\n\n \/**\n * Adds global event listeners to the root element for handling reset, add card actions, and keyboard navigation.\n *\/\n addEventListeners() {\n this.rootElement.addEventListener('click', (e) => {\n if (e.target.closest('[data-action=\"reset\"]')) {\n this.render();\n e.preventDefault();\n }\n if (e.target.closest('[data-action=\"addcard\"]')) {\n this.names.add('');\n this.sliderStart = 'last';\n this.currentIndex = this.names.names.length - 1;\n this.render();\n e.preventDefault();\n }\n });\n this.rootElement.addEventListener('keydown', (e) => {\n if (e.key === 'Tab') {\n this.drawZone.classList.add('tab');\n if (e.target.classList.contains('card')) {\n this.updateAriaLive();\n } else {\n const cards = this.rootElement.querySelectorAll('[data-region=\"flipcards\"] .card');\n cards.forEach((card) => {\n card.classList.remove('focus');\n });\n }\n }\n if (e.target.closest('.tns-outer')) {\n if (e.key === 'ArrowRight') {\n this.slider.goTo('next');\n setTimeout(() => {\n this.focusActiveCard();\n }, 500);\n e.preventDefault();\n }\n if (e.key === 'ArrowLeft') {\n this.slider.goTo('prev');\n setTimeout(() => {\n this.focusActiveCard();\n }, 500);\n e.preventDefault();\n }\n if (e.key === 'Enter') {\n const card = this.rootElement.querySelector('[data-region=\"flipcards\"] .tns-slide-active .card');\n if (!card.classList.contains('editing')) {\n card.classList.toggle('flip');\n this.updateAriaLive();\n e.preventDefault();\n }\n }\n }\n });\n this.rootElement.addEventListener('mousedown', () => {\n this.drawZone.classList.remove('tab');\n });\n }\n}\n\nconst init = async(cmid) => {\n const GE = new GameEngineLoader('flipcards', cmid);\n await GE.load();\n const game = new GameElement(GE.names, GE.rootElement);\n GE.run(game);\n};\n\nexport default {\n init: init,\n GameElement\n};\n"],"names":["GameElement","constructor","names","rootElement","drawZone","this","querySelector","editButton","configuratorButton","textFitSettings","alignVert","alignHoriz","multiLine","detectMultiLine","minFontSize","maxFontSize","reProcess","widthOnly","alignVertWithFlexbox","editButtonEvents","addEventListeners","createAriaLive","render","sliderStart","slider","currentIndex","update","wrapper","dataset","numcards","length","innerHTML","newCards","document","createElement","endOfDeck","classList","add","textContent","region","newList","appendChild","template","cards","map","name","i","last","parts","split","text","back","index","first","modurl","M","cfg","wwwroot","then","html","cardEvents","createSlider","updateAriaLive","catch","Notification","exception","btnLeftString","btnRightString","Tns","tns","container","items","slideBy","controlsText","loop","startIndex","events","on","getInfo","currentCard","slideItems","setAttribute","querySelectorAll","forEach","card","remove","goTo","toggleEditMode","front","addEventListener","e","contains","toggle","preventDefault","saveButton","saveCardChanges","key","cancelButton","setTimeout","focus","deleteButton","cardIndex","cardId","frontText","backText","newName","value","frontDiv","backDiv","focusActiveCard","ariaLive","cardText","message","target","closest","init","async","GE","GameEngineLoader","cmid","load","game","run"],"mappings":"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"}