diff --git a/README.md b/README.md index d9b22591b..e7c2dab74 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,7 @@ Check out the wiki [here](https://github.com/tomasvana10/crossword_puzzle/wiki) - [NYTimes Mini Crossword](https://www.nytimes.com/crosswords/game/mini) - Heavily inspired the design of the web application - [CSS Pattern](https://css-pattern.com) - Background CSS patterns - [Pure CSS Toggle Switch](https://codepen.io/morgoe/pen/VvzWQg) - Toggle switch CSS patterns +- [W3Schools](https://www.w3schools.com/js/js_cookies.asp) - Cookie getting/setting code - Crossword completion sound effect (CC attribution): - Jazzy Chords by NenadSimic -- https://freesound.org/s/150879/ -- License: Creative Commons 0 diff --git a/crossword_puzzle/cword_webapp/static/interaction.js b/crossword_puzzle/cword_webapp/static/interaction.js index 7416779a8..4712e8c29 100644 --- a/crossword_puzzle/cword_webapp/static/interaction.js +++ b/crossword_puzzle/cword_webapp/static/interaction.js @@ -9,6 +9,17 @@ const modes = { // Cell manipulation directives ENTER: "enter", DEL: "del", }; +const gridOp = { // Grid operation directives + REVEAL: "reveal", + CHECK: "check", + CLEAR: "clear", +}; +const opMagnitude = { // The scale to which a grid operation is performed + CELL: "cell", + WORD: "word", + GRID: "grid", +} +const toggleIds = ["ts", "tw", "tc", "tz"]; class Interaction { /* Class to handle all forms of interaction with the web app, as well as to @@ -37,13 +48,15 @@ class Interaction { this.preventInitialLIZoom = true; this.setCoordsToEndOfWord = false; this.bypassPostCellShiftActions = false; + this.doNotSaveToggleState = true; // When the DOM is ready, trigger the ``onLoad`` method document.addEventListener("DOMContentLoaded", this.onLoad.bind(this)); } onLoad() { - /* Get crossword-related data from HTML body, provided by Flask. */ + /* Perform tasks that require the DOM content to be loaded. */ + this.body = document.querySelector("body"); this.grid = eval(this.body.getAttribute("data-grid")); this.directions = eval(this.body.getAttribute("data-directions")); @@ -57,6 +70,7 @@ class Interaction { ); this.errMsgs = eval(this.body.getAttribute("data-js_err_msgs")); this.wordCount = this.body.getAttribute("data-word_count"); + this.uuid = this.body.getAttribute("data-uuid"); this.skipToggle = document.getElementById("ts"); this.zoomToggle = document.getElementById("tz"); @@ -78,17 +92,31 @@ class Interaction { this.clicks.forEach(click => (click.volume = 0.175)); this.playClicks = false; - this.setListeners(); + this.setListeners(); Interaction.configureScrollHeights(); + + this.doNotSaveGridState = true; // Must use this flag to prevent the ``gridState`` + // cookie being overridden. + // Wipe the grid to prevent issues with the cell's node values, such as the + // newline character. + this.doSpecialButtonAction(opMagnitude.GRID, gridOp.CLEAR, false); + this.doNotSaveGridState = false; + + this.applyCookieData(); // Update grid and toggles this.displayOnloadPopup(); - // Clear the grid to prevent possible issues with HTML - this.doSpecialButtonAction("grid", "clear", false); - // Cycle placeholder text of a compound input element + + // This flag was initially toggled to true, as by default, the toggles are + // automatically turned off, thus overriding the toggle's cookies. It should + // be safe to make it false now. + this.doNotSaveToggleState = false; + + // Cycle placeholder text of a compound input element (if possible) setInterval(this.cycleCompoundInputPlaceholderText.bind(this), 750); } setListeners() { /* Add listeners and onclick functions. */ + document.querySelectorAll(".non_empty_cell").forEach(element => { element.onclick = event => this.onCellClick(event, element); element.classList.add("zoomTarget"); // Prevents the user from having @@ -119,11 +147,18 @@ class Interaction { } }); + // Detect checkboxes being modified + document + .querySelectorAll(".toggle_checkbox") + .forEach(element => + element.addEventListener("click", () => this.saveToggleState(element)) + ); + // Compound input button document.getElementById("compound_button").onclick = event => { event.stopPropagation(); // If we allow this event to propagate, it will be - // registered after the compound input is set, - // therefore closing it automatically due to the + // registered after the compound input is set, + // therefore closing it automatically due to the // click listener this.handleSetCompoundInput(false); }; @@ -142,8 +177,76 @@ class Interaction { ); } + saveGridState() { + /* Save the current grid values, classes (locked in/revealed and wrong), + cell focus position, and direction whenever modifying the grid. I could + have sprinkled this method around within the I/O related methods, but + instead, it is called whenever ``setValue`` is called or a check/reveal + special button action is completed. + + Additionally, the session's UUID is saved. Each crossword comes with its + own unique identifier, so if the user generates a new crossword, the web + app will notice that the UUID is different, therefore it will not attempt + to load the existing ``gridState`` cookie (if it even exists). + */ + + let [gridState, gridClassState] = this.getGrid(true); + Cookies.setCookie( + "gridState", + JSON.stringify([ + this.uuid, + gridState, + gridClassState, + this.cellCoords, + this.direction, + ]), + 1 // Expiry in days + ); + } + + saveToggleState(toggle) { + /* Update the toggle cookie to "1" if it is being turned on, or "0" if it is + being turned off. + */ + + if (this.doNotSaveToggleState) { + return; + } + Cookies.setCookie(toggle.id, toggle.checked ? "1" : "0", 100); + } + + applyCookieData() { + /* Apply all available cookie data to the web app, restoring the UI from a + prior state. + */ + + let state = Cookies.getCookie("gridState"); + let parsedState; + + try { + parsedState = JSON.parse(state); + this.direction = parsedState[4]; + } catch (err) { // The cookie doesn't exist, just select the first word + Interaction.getDefByNumber(1, true); + } + + if (state && parsedState[0] === this.uuid) { // Same crossword is being viewed + this.setGrid(parsedState[1], parsedState[2]); // Apply grid value and classes + Interaction.getCellElement(parsedState[3]).click(); // Select the stored cell + } + + toggleIds.forEach(id => { // Turn on the toggles if possible + let toggle = document.getElementById(id); + let toggleState = Cookies.getCookie(id); + if (toggleState) { + toggle.checked = Boolean(Number(toggleState)); + } + }); + } + playClick() { /* Keyboard sound effects (easter egg). */ + if (this.playClicks) { try { return this.clicks[ @@ -159,6 +262,7 @@ class Interaction { /* Zoom out from the most recently zoomed element if the user is disabling the zoom button or they pressed escape. */ + if (document.querySelector(".non_empty_cell.selectedZoomTarget")) { this.returnGridZoomElement.click(); } else if (document.querySelector(".def.selectedZoomTarget")) { @@ -171,6 +275,7 @@ class Interaction { a keybind. If this is the case, this function will process it and prevent ``this.handleStandardInput`` from running. */ + // Prevent input when a popup is toggled if (this.onloadPopupToggled || this.completionPopupToggled) { return; @@ -214,7 +319,7 @@ class Interaction { // User wants to clear the current word with [Shift + Backspace] if (backspaceKeys.includes(inputValue) && event.shiftKey) { - return this.doSpecialButtonAction("word", "clear", false); + return this.doSpecialButtonAction(opMagnitude.WORD, gridOp.CLEAR, false); } // User wants to select a definitions list item or a dropdown button @@ -277,7 +382,7 @@ class Interaction { if (Interaction.isEmpty(currentCell)) { this.wasEmpty = true; // Ensures skipCellCoords functions properly } - Interaction.setValue(currentCell, inputValue); + this.setValue(currentCell, inputValue); if (this.checkToggle.checked) { currentCell.classList.remove("wrong"); this.doGridOperation(currentCell, "check"); @@ -288,7 +393,7 @@ class Interaction { if (!this.checkToggle.checked) { currentCell.classList.remove("wrong"); } - + } else if (mode === modes.DEL) { // The focused cell has content, just delete it and do nothing if ( @@ -296,7 +401,7 @@ class Interaction { !currentCell.classList.contains("lock_in") ) { currentCell.classList.remove("wrong"); - return Interaction.setValue(currentCell, ""); + return this.setValue(currentCell, ""); } // Perform standard deletion, whereby the content of the cell to the @@ -306,7 +411,7 @@ class Interaction { this.shiftCellCoords(this.cellCoords, this.direction, mode) ); if (!priorCell.classList.contains("lock_in")) { - Interaction.setValue(priorCell, ""); + this.setValue(priorCell, ""); priorCell.classList.remove("wrong"); } } @@ -369,6 +474,7 @@ class Interaction { [ A ] [ ] [ ] - After the A has been deleted, the user must press enter once more in order to shift backwards to the previous word. */ + if (this.wordToggle.checked) { let arrow = mode === modes.DEL ? arrowKeys[2] : arrowKeys[3]; if ( @@ -393,23 +499,23 @@ class Interaction { beginning, as this form of word shifting is more explicit. This is achieved through the ``setToEnd`` parameter. */ + event?.preventDefault(); // This method is not always called by a listener, - // so optional chaining is used + // so optional chaining is used let offset = arrow === arrowKeys[2] ? -1 : 1; // You could argue it should - // be the other way + // be the other way let def = this.getDefinitionsListItemFromWord(); let newWordNum = Number(def.getAttribute("data-num")) + offset; - let newDef = document.querySelector(`[data-num="${newWordNum}"`); + let newDef = Interaction.getDefByNumber(newWordNum); if (!newDef) { // User is at the first or last word, so go to either the last // word (if deleting) or the first word (if inserting) let num = offset === 1 ? "1" : this.wordCount; - newDef = document.querySelector(`[data-num="${num}"]`); + newDef = Interaction.getDefByNumber(num); } let oldCellCoords = this.cellCoords; if (offset === -1 && setToEnd) { - this.setCoordsToEndOfWord = true; // Picked up by - // ``onDefinitionsListItemClick`` + this.setCoordsToEndOfWord = true; // Picked up by ``onDefinitionsListItemClick`` } newDef.focus(); newDef.click(); @@ -528,6 +634,7 @@ class Interaction { as well as alternating input directions if clicking at an intersecting point between two words. */ + if (this.doNotHandleStandardCellClick) { return (this.doNotHandleStandardCellClick = false); } @@ -635,8 +742,8 @@ class Interaction { Interaction.unfocusActiveElement(); this.hideDropdowns(); - let mode = event.shiftKey ? "reveal" : "check"; - this.doSpecialButtonAction("word", mode, false); + let mode = event.shiftKey ? gridOp.REVEAL : "check"; + this.doSpecialButtonAction(opMagnitude.WORD, mode, false); } handleSpacebarPress(event) { @@ -665,8 +772,7 @@ class Interaction { crosswordCompletionHandler() { if (this.isCrosswordComplete()) { Interaction.sleep(1).then(() => { - // Allow the input the user just made - // to be shown by the DOM + // Allow the input the user just made to be shown by the DOM this.handleEscapePress(null); this.displayCompletionPopup(); this.jazz.play(); @@ -692,46 +798,60 @@ class Interaction { // The user must have a word selected to be able to check/reveal the // current cell/word - if (this.cellCoords === null && magnitude !== "grid") { + if (this.cellCoords === null && magnitude !== opMagnitude.GRID) { return alert(this.errMsgs[0]); } switch (magnitude) { - case "cell": // Just do a single grid operation on the current cell + case opMagnitude.CELL: // Just do a single grid operation on the current cell let currentCell = Interaction.getCellElement(this.cellCoords); this.doGridOperation(currentCell, mode); - if (mode === "reveal") { + if (mode === gridOp.REVEAL) { // Automatically go to the next cell this.handleCellShift(modes.ENTER, currentCell); } break; - case "word": // Do a grid operation on each element of the word + case opMagnitude.WORD: // Do a grid operation on each element of the word + let wasWordEmpty = this.isWordEmpty(); // Remember if word was empty before + // clearing so we can shift the + // word selection if possible for (const cell of this.getWordElements()) { this.doGridOperation(cell, mode); } - if (mode === "reveal" && this.wordToggle.checked) { - // Automatically go to the next word - this.shiftWordSelection(null, arrowKeys[3]); + if (this.wordToggle.checked) { + if (mode === gridOp.REVEAL) { + this.shiftWordSelection(null, arrowKeys[3]); + } else if (mode === gridOp.CLEAR) { + if (wasWordEmpty) { + this.shiftWordSelection(null, arrowKeys[2]); + } + } } break; - case "grid": // Do a grid operation on each non empty cell of the grid + case opMagnitude.GRID: // Do a grid operation on each non empty cell of the grid document .querySelectorAll(".non_empty_cell") .forEach(cell => this.doGridOperation(cell, mode, onlyUnchecked)); } - this.crosswordCompletionHandler(); + if (mode !== gridOp.CLEAR) { + if (mode === gridOp.REVEAL) { + this.crosswordCompletionHandler(); + } + this.saveGridState(); // For any new ``lock_in`` or ``wrong`` classes that + // were just added + } } doGridOperation(cell, mode, onlyUnchecked = false) { /* Perform either a reveal, check or clear action on a single cell. */ - if (mode === "reveal") { + if (mode === gridOp.REVEAL) { cell.classList.remove("wrong"); - Interaction.setValue(cell, cell.getAttribute("data-value")); + this.setValue(cell, cell.getAttribute("data-value")); cell.classList.add("lock_in"); // This cell must now be correct, so lock // it in - } else if (mode === "check") { + } else if (mode === gridOp.CHECK) { if (!Interaction.isEmpty(cell)) { if (cell.hasCorrectValue()) { // This cell is correct, lock it in @@ -740,7 +860,7 @@ class Interaction { cell.classList.add("wrong"); } } - } else if (mode === "clear") { + } else if (mode === gridOp.CLEAR) { if ( // Clearing unrevealed (onlyUnchecked && !cell.classList.contains("lock_in")) || @@ -748,7 +868,7 @@ class Interaction { ) { cell.classList.remove("lock_in"); cell.classList.remove("wrong"); - Interaction.setValue(cell, ""); + this.setValue(cell, "", this.doNotSaveGridState); } } } @@ -791,6 +911,7 @@ class Interaction { } changeCellFocus(focus) { + this.saveGridState(); return (Interaction.getCellElement(this.cellCoords).style.backgroundColor = focus ? this.colourPalette.CELL_FOCUS : this.colourPalette.SUB); } @@ -832,7 +953,7 @@ class Interaction { let [row, col] = this.cellCoords; this.isDown = this.direction === this.directions[1]; this.staticIndex = this.isDown ? col : row; // The index that never changes (the row - // if direction is across, etc) + // if direction is across, etc) let [startCoords, endCoords] = this.isDown ? [row, row] : [col, col]; // Find starting coords of the word @@ -856,6 +977,10 @@ class Interaction { return [startCoords, endCoords]; } + isWordEmpty() { + return [...this.getWordElements()].every(cell => Interaction.isEmpty(cell)); + } + alternateDirection() { return (this.direction = this.direction === this.directions[0] @@ -877,7 +1002,23 @@ class Interaction { return this.getGrid().isEqualTo(this.grid); } - getGrid() { + setGrid(state, classes) { + for (let row = 0; row <= this.dimensions - 1; row++) { + for (let column = 0; column <= this.dimensions - 1; column++) { + let coords = [row, column]; + let cell = Interaction.getCellElement(coords); + if (cell.classList.contains("non_empty_cell")) { + this.setValue(cell, state[row][column]); + let class_ = classes[row][column]; + if (class_) { + cell.classList.add(class_); + } + } + } + } + } + + getGrid(withClasses = false) { /* Create an empty replica of the crossword grid, then update it according to the web app grid */ @@ -885,28 +1026,39 @@ class Interaction { let webAppGrid = Array.from({ length: this.dimensions }, () => Array(this.dimensions).fill(this.empty) ); + let classGrid = structuredClone(webAppGrid); document.querySelectorAll(".non_empty_cell").forEach(cell => { let row = parseInt(cell.getAttribute("data-row")); let column = parseInt(cell.getAttribute("data-column")); let value = cell.childNodes[0].nodeValue.toUpperCase(); webAppGrid[row][column] = value; + if (withClasses) { + let class_ = ""; + if (cell.classList.contains("wrong")) { + class_ = "wrong"; + } else if (cell.classList.contains("lock_in")) { + class_ = "lock_in"; + } + classGrid[row][column] = class_; + } }); - return webAppGrid; + return withClasses ? [webAppGrid, classGrid] : webAppGrid; } setCompoundInput(priorValue) { /* Remove the value of the current cell and add an input element to its children. */ + this.compoundInputActive = true; if (!priorValue) { this.wasEmpty = true; } let currentCell = Interaction.getCellElement(this.cellCoords); currentCell.onclick = event => Interaction.dummyCellClick(event); - Interaction.setValue(currentCell, ""); + this.setValue(currentCell, ""); let compoundInput = document.createElement("input"); compoundInput.value = priorValue; @@ -917,6 +1069,8 @@ class Interaction { } handleSetCompoundInput(andShiftForwarder = true) { + /* Perform steps prior to setting a compound input. */ + if (this.cellCoords === null) { // User must select a cell return alert(this.errMsgs[0]); @@ -937,20 +1091,17 @@ class Interaction { if (!this.compoundInputActive) { return; } // Maybe the user triggered this method with a click but no compound input - // element exists + // element exists let compoundInput = document.getElementsByClassName("compound_input")[0]; let cellOfCompoundInput = compoundInput.parentElement; let enteredText = compoundInput.value; - try { - if (!enteredText[0].match(onlyLangRegex)) { - enteredText = ""; - } - } catch (err) { - enteredText = ""; + if (enteredText.length === 0 || !enteredText[0].match(onlyLangRegex)) { + enteredText = ""; // Not a language character or is an empty string } + compoundInput.remove(); + this.setValue(cellOfCompoundInput, enteredText[0]); let nodes = cellOfCompoundInput.childNodes; - nodes[0].nodeValue = enteredText[0]; if (nodes.length > 1) { nodes[1].style.display = "inline"; // Reset number label display } @@ -962,16 +1113,17 @@ class Interaction { this.currentPlaceholder = 0; if (this.checkToggle.checked) { - this.doGridOperation(cellOfCompoundInput, "check"); + this.doGridOperation(cellOfCompoundInput, gridOp.CHECK); } if (andShift) { this.handleCellShift(modes.ENTER, cellOfCompoundInput); // Shift focus for - // ease of use + // ease of use } } cycleCompoundInputPlaceholderText() { /* Cycle placeholder text whenever a compound input element is active. */ + let compoundInput = document.getElementsByClassName("compound_input")[0]; if (compoundInput === undefined) { return; @@ -989,6 +1141,7 @@ class Interaction { /* Remove the compound input if it is already active and the ``cell`` element is not equal to the current cell. */ + if ( this.compoundInputActive && cell !== Interaction.getCellElement(this.cellCoords) @@ -998,7 +1151,8 @@ class Interaction { } followCellZoom(priorCell) { - /* If the priorCell was zoomed too, then now zoom to the current cell. */ + /* If ``priorCell`` was zoomed too, then zoom to the current cell. */ + if ( document.querySelectorAll(".non_empty_cell.selectedZoomTarget").length === 1 @@ -1015,6 +1169,7 @@ class Interaction { /* Close dropdowns and remove compound input (if possible) when clicking outside of the dropdown area. */ + if (!event.target.closest(".special_button, .dropdown, .dropdown_button")) { this.hideDropdowns(); this.removeCompoundInput(false); @@ -1032,6 +1187,7 @@ class Interaction { 3. You are focusing out of a "special_button" into something that is either another special button or something that isn't a "dropdown_button" */ + if ( !event.relatedTarget?.classList.contains("dropdown_button") || (event.target?.classList.contains("dropdown_button") && @@ -1063,6 +1219,7 @@ class Interaction { /* Opens the dropdown a user clicks on or closes it if they already have it open. */ + this.removeCompoundInput(false); let dropdown = document.getElementById(id); @@ -1110,19 +1267,17 @@ class Interaction { } } - closeOnloadPopup(firstTime = false) { + closeOnloadPopup() { this.onloadPopupToggled = false; document.getElementById("blur").classList.toggle("active"); document.getElementById("onload_popup").classList.toggle("active"); - if (firstTime) { - document.querySelector(`[data-num="1"`).click(); - } } preventZoomIfRequired(event) { /* Prevent the user from zooming if they do not have the "click to zoom" - button toggled on. This must be handled as the zoom functions from zoomooz.js - must always be in the HTML structure. */ + button toggled on. This must be handled as the zoom functions from zoomooz.js + must always be in the HTML structure. + */ if (!document.getElementById("tz").checked || this.preventInitialLIZoom) { this.preventInitialLIZoom = false; @@ -1130,6 +1285,21 @@ class Interaction { } } + setValue(cell, value, wait = false) { + cell.childNodes[0].nodeValue = value; + if (!wait) { + this.saveGridState(); + } + } + + static getDefByNumber(num, andClick = false) { + let cell = document.querySelector(`[data-num="${num}"`); + if (andClick) { + cell.click(); + } + return cell; + } + static dummyCellClick(event) { return event.stopImmediatePropagation(); } @@ -1138,12 +1308,6 @@ class Interaction { document.activeElement.blur(); } - static emulateEscapePress() { - return document.dispatchEvent( - new KeyboardEvent("keyboard", { key: "Escape" }) - ); - } - static sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } @@ -1152,10 +1316,6 @@ class Interaction { return !cell?.childNodes[0]?.nodeValue; } - static setValue(cell, value) { - return (cell.childNodes[0].nodeValue = value); - } - static getCellElement(coords) { return document.querySelector( `[data-row="${coords[0]}"][data-column="${coords[1]}"]` @@ -1187,6 +1347,34 @@ class Interaction { } } +class Cookies { + /* Cookie-related methods to save the grid and checkbox states. + Code is from W3Schools (https://www.w3schools.com/js/js_cookies.asp). + */ + + static setCookie(cname, cvalue, exdays) { + const d = new Date(); + d.setTime(d.getTime() + exdays * 24 * 60 * 60 * 1000); + let expires = "expires=" + d.toUTCString(); + document.cookie = `${cname}=${cvalue};${expires};path=/;SameSite=Lax`; + } + + static getCookie(cname) { + let name = cname + "="; + let ca = document.cookie.split(";"); + for (let i = 0; i < ca.length; i++) { + let c = ca[i]; + while (c.charAt(0) == " ") { + c = c.substring(1); + } + if (c.indexOf(name) == 0) { + return c.substring(name.length, c.length); + } + } + return ""; + } +} + Array.prototype.isEqualTo = function (arr) { return JSON.stringify(this) === JSON.stringify(arr); }; @@ -1197,8 +1385,6 @@ Element.prototype.hasCorrectValue = function () { ); }; -let interaction = new Interaction(); - // Enable easter egg through console function egg() { interaction.playClicks = !interaction.playClicks; @@ -1208,3 +1394,5 @@ function egg() { return "EASTER EGG OFF"; } } + +let interaction = new Interaction(); diff --git a/crossword_puzzle/cword_webapp/static/interaction.min.js b/crossword_puzzle/cword_webapp/static/interaction.min.js index 862ff113a..9bddb9860 100644 --- a/crossword_puzzle/cword_webapp/static/interaction.min.js +++ b/crossword_puzzle/cword_webapp/static/interaction.min.js @@ -1 +1 @@ -"use strict";function _typeof(t){return _typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},_typeof(t)}function _regeneratorRuntime(){/*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */_regeneratorRuntime=function(){return e};var t,e={},u=Object.prototype,o=u.hasOwnProperty,n=Object.defineProperty||function(t,e,u){t[e]=u.value},r="function"==typeof Symbol?Symbol:{},i=r.iterator||"@@iterator",l=r.asyncIterator||"@@asyncIterator",s=r.toStringTag||"@@toStringTag";function a(t,e,u){return Object.defineProperty(t,e,{value:u,enumerable:!0,configurable:!0,writable:!0}),t[e]}try{a({},"")}catch(t){a=function(t,e,u){return t[e]=u}}function c(t,e,u,o){var r=e&&e.prototype instanceof F?e:F,i=Object.create(r.prototype),l=new L(o||[]);return n(i,"_invoke",{value:w(t,u,l)}),i}function D(t,e,u){try{return{type:"normal",arg:t.call(e,u)}}catch(t){return{type:"throw",arg:t}}}e.wrap=c;var d="suspendedStart",h="suspendedYield",C="executing",E="completed",f={};function F(){}function p(){}function A(){}var m={};a(m,i,(function(){return this}));var y=Object.getPrototypeOf,v=y&&y(y(S([])));v&&v!==u&&o.call(v,i)&&(m=v);var g=A.prototype=F.prototype=Object.create(m);function B(t){["next","throw","return"].forEach((function(e){a(t,e,(function(t){return this._invoke(e,t)}))}))}function b(t,e){function u(n,r,i,l){var s=D(t[n],t,r);if("throw"!==s.type){var a=s.arg,c=a.value;return c&&"object"==_typeof(c)&&o.call(c,"__await")?e.resolve(c.__await).then((function(t){u("next",t,i,l)}),(function(t){u("throw",t,i,l)})):e.resolve(c).then((function(t){a.value=t,i(a)}),(function(t){return u("throw",t,i,l)}))}l(s.arg)}var r;n(this,"_invoke",{value:function(t,o){function n(){return new e((function(e,n){u(t,o,e,n)}))}return r=r?r.then(n,n):n()}})}function w(e,u,o){var n=d;return function(r,i){if(n===C)throw Error("Generator is already running");if(n===E){if("throw"===r)throw i;return{value:t,done:!0}}for(o.method=r,o.arg=i;;){var l=o.delegate;if(l){var s=k(l,o);if(s){if(s===f)continue;return s}}if("next"===o.method)o.sent=o._sent=o.arg;else if("throw"===o.method){if(n===d)throw n=E,o.arg;o.dispatchException(o.arg)}else"return"===o.method&&o.abrupt("return",o.arg);n=C;var a=D(e,u,o);if("normal"===a.type){if(n=o.done?E:h,a.arg===f)continue;return{value:a.arg,done:o.done}}"throw"===a.type&&(n=E,o.method="throw",o.arg=a.arg)}}}function k(e,u){var o=u.method,n=e.iterator[o];if(n===t)return u.delegate=null,"throw"===o&&e.iterator.return&&(u.method="return",u.arg=t,k(e,u),"throw"===u.method)||"return"!==o&&(u.method="throw",u.arg=new TypeError("The iterator does not provide a '"+o+"' method")),f;var r=D(n,e.iterator,u.arg);if("throw"===r.type)return u.method="throw",u.arg=r.arg,u.delegate=null,f;var i=r.arg;return i?i.done?(u[e.resultName]=i.value,u.next=e.nextLoc,"return"!==u.method&&(u.method="next",u.arg=t),u.delegate=null,f):i:(u.method="throw",u.arg=new TypeError("iterator result is not an object"),u.delegate=null,f)}function I(t){var e={tryLoc:t[0]};1 in t&&(e.catchLoc=t[1]),2 in t&&(e.finallyLoc=t[2],e.afterLoc=t[3]),this.tryEntries.push(e)}function _(t){var e=t.completion||{};e.type="normal",delete e.arg,t.completion=e}function L(t){this.tryEntries=[{tryLoc:"root"}],t.forEach(I,this),this.reset(!0)}function S(e){if(e||""===e){var u=e[i];if(u)return u.call(e);if("function"==typeof e.next)return e;if(!isNaN(e.length)){var n=-1,r=function u(){for(;++n=0;--r){var i=this.tryEntries[r],l=i.completion;if("root"===i.tryLoc)return n("end");if(i.tryLoc<=this.prev){var s=o.call(i,"catchLoc"),a=o.call(i,"finallyLoc");if(s&&a){if(this.prev=0;--u){var n=this.tryEntries[u];if(n.tryLoc<=this.prev&&o.call(n,"finallyLoc")&&this.prev=0;--e){var u=this.tryEntries[e];if(u.finallyLoc===t)return this.complete(u.completion,u.afterLoc),_(u),f}},catch:function(t){for(var e=this.tryEntries.length-1;e>=0;--e){var u=this.tryEntries[e];if(u.tryLoc===t){var o=u.completion;if("throw"===o.type){var n=o.arg;_(u)}return n}}throw Error("illegal catch attempt")},delegateYield:function(e,u,o){return this.delegate={iterator:S(e),resultName:u,nextLoc:o},"next"===this.method&&(this.arg=t),f}},e}function _slicedToArray(t,e){return _arrayWithHoles(t)||_iterableToArrayLimit(t,e)||_unsupportedIterableToArray(t,e)||_nonIterableRest()}function _nonIterableRest(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function _iterableToArrayLimit(t,e){var u=null==t?null:"undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(null!=u){var o,n,r,i,l=[],s=!0,a=!1;try{if(r=(u=u.call(t)).next,0===e){if(Object(u)!==u)return;s=!1}else for(;!(s=(o=r.call(u)).done)&&(l.push(o.value),l.length!==e);s=!0);}catch(t){a=!0,n=t}finally{try{if(!s&&null!=u.return&&(i=u.return(),Object(i)!==i))return}finally{if(a)throw n}}return l}}function _arrayWithHoles(t){if(Array.isArray(t))return t}function _createForOfIteratorHelper(t,e){var u="undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(!u){if(Array.isArray(t)||(u=_unsupportedIterableToArray(t))||e&&t&&"number"==typeof t.length){u&&(t=u);var o=0,n=function(){};return{s:n,n:function(){return o>=t.length?{done:!0}:{done:!1,value:t[o++]}},e:function(t){throw t},f:n}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var r,i=!0,l=!1;return{s:function(){u=u.call(t)},n:function(){var t=u.next();return i=t.done,t},e:function(t){l=!0,r=t},f:function(){try{i||null==u.return||u.return()}finally{if(l)throw r}}}}function _toConsumableArray(t){return _arrayWithoutHoles(t)||_iterableToArray(t)||_unsupportedIterableToArray(t)||_nonIterableSpread()}function _nonIterableSpread(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function _unsupportedIterableToArray(t,e){if(t){if("string"==typeof t)return _arrayLikeToArray(t,e);var u=Object.prototype.toString.call(t).slice(8,-1);return"Object"===u&&t.constructor&&(u=t.constructor.name),"Map"===u||"Set"===u?Array.from(t):"Arguments"===u||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(u)?_arrayLikeToArray(t,e):void 0}}function _iterableToArray(t){if("undefined"!=typeof Symbol&&null!=t[Symbol.iterator]||null!=t["@@iterator"])return Array.from(t)}function _arrayWithoutHoles(t){if(Array.isArray(t))return _arrayLikeToArray(t)}function _arrayLikeToArray(t,e){(null==e||e>t.length)&&(e=t.length);for(var u=0,o=new Array(e);u0&&void 0!==arguments[0]?arguments[0]:null,e=arguments.length>1?arguments[1]:void 0,u=arguments.length>2&&void 0!==arguments[2]&&arguments[2];null==t||t.preventDefault();var o=e===arrowKeys[2]?-1:1,n=this.getDefinitionsListItemFromWord(),r=Number(n.getAttribute("data-num"))+o,i=document.querySelector('[data-num="'.concat(r,'"'));if(!i){var l=1===o?"1":this.wordCount;i=document.querySelector('[data-num="'.concat(l,'"]'))}var s=this.cellCoords;-1===o&&u&&(this.setCoordsToEndOfWord=!0),i.focus(),i.click(),i.blur(),this.followCellZoom(s)}},{key:"skipCellCoords",value:function(t,e){var u=this.shiftCellCoords(t,e,modes.ENTER);if(u.isEqualTo(t))return u;if(!this.wasEmpty)return u;for(this.wasEmpty=!1;!Interaction.isEmpty(Interaction.getCellElement(u));){var o=u;if(u=this.shiftCellCoords(u,e,modes.ENTER),o.isEqualTo(u))break}return Interaction.isEmpty(Interaction.getCellElement(u))?u:this.wordToggle.checked?(this.shiftWordSelection(null,"ArrowDown"),this.bypassPostCellShiftActions=!0,this.cellCoords):this.shiftCellCoords(t,e,modes.ENTER)}},{key:"shiftCellCoords",value:function(t,e,u){var o=arguments.length>3&&void 0!==arguments[3]&&arguments[3],n=u==modes.ENTER?1:-1,r=e===this.directions[1]?[t[0]+n,t[1]]:[t[0],t[1]+n],i=Interaction.getCellElement(r);return null!==i&&i.classList.contains("non_empty_cell")||o?r:t}},{key:"onDefinitionsListItemClick",value:function(t,e,u){var o=document.querySelector('[data-num_label="'.concat(e,'"]')).parentElement;this.preventZoomIfRequired(t),this.removeCompoundInputIfRequired(o),this.setFocusMode(!1),document.activeElement.blur(),this.compoundInputActive&&document.getElementsByClassName("compound_input")[0].focus(),this.direction=u,this.cellCoords=Interaction.updateCellCoords(o),this.setCoordsToEndOfWord&&(this.cellCoords=Interaction.updateCellCoords(_toConsumableArray(this.getWordElements()).slice(-1)[0]),this.setCoordsToEndOfWord=!1),this.currentWord=this.updateCurrentWord(),this.setFocusMode(!0)}},{key:"onCellClick",value:function(t,e){if(this.doNotHandleStandardCellClick)return this.doNotHandleStandardCellClick=!1;this.preventZoomIfRequired(t),this.removeCompoundInputIfRequired(e),this.setFocusMode(!1);var u=Interaction.updateCellCoords(e);(this.intersections.includes(JSON.stringify(u))&&u.isEqualTo(this.cellCoords)||this.shouldDirectionBeAlternated(u))&&this.alternateDirection(),this.cellCoords=u,this.currentWord=this.updateCurrentWord(),this.setFocusMode(!0),this.updateDefinitionsListPos()}},{key:"handleArrowPress",value:function(t,e){e.preventDefault();var u=t===arrowKeys[3]||t===arrowKeys[1]?modes.ENTER:modes.DEL,o=t===arrowKeys[3]||t===arrowKeys[2]?this.directions[1]:this.directions[0],n=Interaction.getCellElement(this.cellCoords),r=this.shiftCellCoords(this.cellCoords,o,u,!0),i=!1;try{for(;Interaction.getCellElement(r).classList.contains("empty_cell");)r=this.shiftCellCoords(r,o,u,!0),i=!0}catch(t){r=this.cellCoords}this.setFocusMode(!1),this.shouldDirectionBeAlternated(r)?(this.alternateDirection(),i&&(this.cellCoords=r),i=!1):this.cellCoords=r,this.followCellZoom(n),this.currentWord=this.updateCurrentWord(),this.setFocusMode(!0),this.updateDefinitionsListPos()}},{key:"handleEnterPress",value:function(t){t.target.classList.contains("def")?(t.target.click(),t.target.blur(),this.zoomToggle.checked&&(this.doNotHandleStandardCellClick=!0,Interaction.getCellElement(this.cellCoords).click())):t.target.classList.contains("toggle")&&(t.target.click(),t.target.blur())}},{key:"handleEnterKeybindPress",value:function(t){Interaction.unfocusActiveElement(),this.hideDropdowns();var e=t.shiftKey?"reveal":"check";this.doSpecialButtonAction("word",e,!1)}},{key:"handleSpacebarPress",value:function(t){t.preventDefault(),this.setFocusMode(!1),this.alternateDirection(),this.currentWord=this.updateCurrentWord(),this.setFocusMode(!0),this.updateDefinitionsListPos()}},{key:"handleEscapePress",value:function(t){null==t||t.preventDefault(),Interaction.unfocusActiveElement(),this.hideDropdowns(),this.setFocusMode(!1),this.zoomOut(),this.cellCoords=null,this.currentWord=null}},{key:"crosswordCompletionHandler",value:function(){var t=this;this.isCrosswordComplete()&&Interaction.sleep(1).then((function(){t.handleEscapePress(null),t.displayCompletionPopup(),t.jazz.play()}))}},{key:"doSpecialButtonAction",value:function(t,e){var u=this,o=arguments.length>3&&void 0!==arguments[3]&&arguments[3];if((!(arguments.length>2&&void 0!==arguments[2])||arguments[2])&&this.onDropdownClick(e+"_dropdown"),null===this.cellCoords&&"grid"!==t)return alert(this.errMsgs[0]);switch(t){case"cell":var n=Interaction.getCellElement(this.cellCoords);this.doGridOperation(n,e),"reveal"===e&&this.handleCellShift(modes.ENTER,n);break;case"word":var r,i=_createForOfIteratorHelper(this.getWordElements());try{for(i.s();!(r=i.n()).done;){var l=r.value;this.doGridOperation(l,e)}}catch(t){i.e(t)}finally{i.f()}"reveal"===e&&this.wordToggle.checked&&this.shiftWordSelection(null,arrowKeys[3]);break;case"grid":document.querySelectorAll(".non_empty_cell").forEach((function(t){return u.doGridOperation(t,e,o)}))}this.crosswordCompletionHandler()}},{key:"doGridOperation",value:function(t,e){var u=arguments.length>2&&void 0!==arguments[2]&&arguments[2];"reveal"===e?(t.classList.remove("wrong"),Interaction.setValue(t,t.getAttribute("data-value")),t.classList.add("lock_in")):"check"===e?Interaction.isEmpty(t)||(t.hasCorrectValue()?t.classList.add("lock_in"):t.classList.add("wrong")):"clear"===e&&(u&&!t.classList.contains("lock_in")||!u)&&(t.classList.remove("lock_in"),t.classList.remove("wrong"),Interaction.setValue(t,""))}},{key:"shouldDirectionBeAlternated",value:function(t){return this.shiftCellCoords(t,this.direction,modes.ENTER).isEqualTo(t)&&this.shiftCellCoords(t,this.direction,modes.DEL).isEqualTo(t)}},{key:"setFocusMode",value:function(t){null!==this.cellCoords&&(this.changeWordFocus(t),this.changeCellFocus(t),this.changeDefinitionsListItemFocus(t))}},{key:"changeWordFocus",value:function(t){var e,u=_createForOfIteratorHelper(this.getWordElements());try{for(u.s();!(e=u.n()).done;){e.value.style.backgroundColor=t?this.colourPalette.WORD_FOCUS:this.colourPalette.SUB}}catch(t){u.e(t)}finally{u.f()}}},{key:"changeCellFocus",value:function(t){return Interaction.getCellElement(this.cellCoords).style.backgroundColor=t?this.colourPalette.CELL_FOCUS:this.colourPalette.SUB}},{key:"changeDefinitionsListItemFocus",value:function(t){return this.getDefinitionsListItemFromWord().style.backgroundColor=t?this.colourPalette.WORD_FOCUS:""}},{key:"updateCurrentWord",value:function(){var t,e="",u=_createForOfIteratorHelper(this.getWordElements());try{for(u.s();!(t=u.n()).done;){e+=t.value.getAttribute("data-value")}}catch(t){u.e(t)}finally{u.f()}return e.toUpperCase()}},{key:"getWordElements",value:_regeneratorRuntime().mark((function t(){var e,u,o,n,r,i;return _regeneratorRuntime().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:e=this.getWordIndices(),u=_slicedToArray(e,2),o=u[0],n=u[1],r=o;case 2:if(!(r<=n)){t.next=9;break}return i=this.isDown?[r,this.staticIndex]:[this.staticIndex,r],t.next=6,Interaction.getCellElement(i);case 6:r++,t.next=2;break;case 9:case"end":return t.stop()}}),t,this)}))},{key:"getWordIndices",value:function(){var t=_slicedToArray(this.cellCoords,2),e=t[0],u=t[1];this.isDown=this.direction===this.directions[1],this.staticIndex=this.isDown?u:e;for(var o=_slicedToArray(this.isDown?[e,e]:[u,u],2),n=o[0],r=o[1];n>0&&this.grid[this.isDown?n-1:e][this.isDown?u:n-1]!=this.empty;)n--;for(;r0&&void 0!==arguments[0])||arguments[0];if(null===this.cellCoords)return alert(this.errMsgs[0]);if(document.getElementsByClassName("compound_input")[0])return this.removeCompoundInput(t);var e=Interaction.getCellElement(this.cellCoords).childNodes,u=e[0].nodeValue;e.length>1&&(e[1].style.display="none"),this.setCompoundInput(u)}},{key:"removeCompoundInput",value:function(){var t=this,e=!(arguments.length>0&&void 0!==arguments[0])||arguments[0];if(this.compoundInputActive){var u=document.getElementsByClassName("compound_input")[0],o=u.parentElement,n=u.value;try{n[0].match(onlyLangRegex)||(n="")}catch(t){n=""}u.remove();var r=o.childNodes;r[0].nodeValue=n[0],r.length>1&&(r[1].style.display="inline"),o.onclick=function(e){return t.onCellClick(e,o)},o.classList.remove("lock_in","wrong"),this.compoundInputActive=!1,this.currentPlaceholder=0,this.checkToggle.checked&&this.doGridOperation(o,"check"),e&&this.handleCellShift(modes.ENTER,o)}}},{key:"cycleCompoundInputPlaceholderText",value:function(){var t=document.getElementsByClassName("compound_input")[0];void 0!==t&&(t.placeholder=compoundInputPlaceholders[this.currentPlaceholder],this.currentPlaceholder===compoundInputPlaceholders.length-1?this.currentPlaceholder=0:this.currentPlaceholder+=1)}},{key:"removeCompoundInputIfRequired",value:function(t){this.compoundInputActive&&t!==Interaction.getCellElement(this.cellCoords)&&this.removeCompoundInput()}},{key:"followCellZoom",value:function(t){if(1===document.querySelectorAll(".non_empty_cell.selectedZoomTarget").length){var e=Interaction.getCellElement(this.cellCoords);if(e!==t)return this.doNotHandleStandardCellClick=!0,e.click()}}},{key:"handleClick",value:function(t){t.target.closest(".special_button, .dropdown, .dropdown_button")||(this.hideDropdowns(),this.removeCompoundInput(!1))}},{key:"handleDropdownFocusOut",value:function(t){var e,u,o,n,r,i,l,s,a;(null===(e=t.relatedTarget)||void 0===e||!e.classList.contains("dropdown_button")||null!==(u=t.target)&&void 0!==u&&u.classList.contains("dropdown_button")&&null!==(o=t.relatedTarget)&&void 0!==o&&o.classList.contains("special_button")&&(null===(n=t.relatedTarget)||void 0===n||!n.id.startsWith(null===(r=this.currentDropdown)||void 0===r?void 0:r.substring(0,null===(i=this.currentDropdown)||void 0===i?void 0:i.indexOf("_"))))||null!==(l=t.target.id)&&void 0!==l&&l.endsWith("button")&&(null!==(s=t.relatedTarget)&&void 0!==s&&null!==(s=s.id)&&void 0!==s&&s.endsWith("button")||null===(a=t.relatedTarget)||void 0===a||null===(a=a.classList)||void 0===a||!a.contains("dropdown_button")))&&this.hideDropdowns()}},{key:"hideDropdowns",value:function(){document.querySelectorAll(".dropdown").forEach((function(t){return t.classList.remove("show_dropdown")})),document.querySelectorAll(".special_button").forEach((function(t){return t.innerHTML=t.innerHTML.replace("▲","▼")})),this.currentDropdown=null}},{key:"onDropdownClick",value:function(t){this.removeCompoundInput(!1);var e=document.getElementById(t);if(t===this.currentDropdown)return this.hideDropdowns(),void(this.currentDropdown=null);this.hideDropdowns();var u=document.getElementById(t.replace("_dropdown","_button"));u.innerHTML=u.innerHTML.replace("▼","▲"),e.classList.add("show_dropdown"),this.currentDropdown=t}},{key:"displayOnloadPopup",value:function(){this.onloadPopupToggled=!0,Interaction.sleep(200).then((function(){document.getElementById("blur").classList.toggle("active"),document.getElementById("onload_popup").classList.toggle("active"),Interaction.sleep(301).then((function(){document.getElementsByClassName("continue_button")[0].focus({focusVisible:!0})}))}))}},{key:"displayCompletionPopup",value:function(){this.completionPopupToggled=!this.completionPopupToggled,document.getElementById("blur").classList.toggle("active"),document.getElementById("completion_popup").classList.toggle("active"),this.completionPopupToggled&&Interaction.sleep(501).then((function(){return document.getElementsByClassName("close_button")[0].focus({focusVisible:!0})}))}},{key:"closeOnloadPopup",value:function(){var t=arguments.length>0&&void 0!==arguments[0]&&arguments[0];this.onloadPopupToggled=!1,document.getElementById("blur").classList.toggle("active"),document.getElementById("onload_popup").classList.toggle("active"),t&&document.querySelector('[data-num="1"').click()}},{key:"preventZoomIfRequired",value:function(t){document.getElementById("tz").checked&&!this.preventInitialLIZoom||(this.preventInitialLIZoom=!1,t.stopImmediatePropagation())}}],[{key:"dummyCellClick",value:function(t){return t.stopImmediatePropagation()}},{key:"unfocusActiveElement",value:function(){document.activeElement.blur()}},{key:"emulateEscapePress",value:function(){return document.dispatchEvent(new KeyboardEvent("keyboard",{key:"Escape"}))}},{key:"sleep",value:function(t){return new Promise((function(e){return setTimeout(e,t)}))}},{key:"isEmpty",value:function(t){var e;return!(null!=t&&null!==(e=t.childNodes[0])&&void 0!==e&&e.nodeValue)}},{key:"setValue",value:function(t,e){return t.childNodes[0].nodeValue=e}},{key:"getCellElement",value:function(t){return document.querySelector('[data-row="'.concat(t[0],'"][data-column="').concat(t[1],'"]'))}},{key:"updateCellCoords",value:function(t){return[parseInt(t.getAttribute("data-row")),parseInt(t.getAttribute("data-column"))]}},{key:"configureScrollHeights",value:function(){var t=document.querySelector(".definitions_a"),e=document.querySelector(".definitions_d");document.getElementById("return_def_zoom").style.height=Math.max(t.scrollHeight,e.scrollHeight)+"px";var u=document.getElementById("no_scroll");u.scrollHeight-1>u.clientHeight&&(u.style.overflowY="auto")}}])}();Array.prototype.isEqualTo=function(t){return JSON.stringify(this)===JSON.stringify(t)},Element.prototype.hasCorrectValue=function(){return this.childNodes[0].nodeValue.toUpperCase()===this.getAttribute("data-value")};var interaction=new Interaction;function egg(){return interaction.playClicks=!interaction.playClicks,interaction.playClicks?"EASTER EGG ON":"EASTER EGG OFF"} \ No newline at end of file +"use strict";function _typeof(t){return _typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},_typeof(t)}function _regeneratorRuntime(){/*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */_regeneratorRuntime=function(){return e};var t,e={},u=Object.prototype,o=u.hasOwnProperty,n=Object.defineProperty||function(t,e,u){t[e]=u.value},r="function"==typeof Symbol?Symbol:{},i=r.iterator||"@@iterator",s=r.asyncIterator||"@@asyncIterator",l=r.toStringTag||"@@toStringTag";function a(t,e,u){return Object.defineProperty(t,e,{value:u,enumerable:!0,configurable:!0,writable:!0}),t[e]}try{a({},"")}catch(t){a=function(t,e,u){return t[e]=u}}function c(t,e,u,o){var r=e&&e.prototype instanceof p?e:p,i=Object.create(r.prototype),s=new L(o||[]);return n(i,"_invoke",{value:b(t,u,s)}),i}function D(t,e,u){try{return{type:"normal",arg:t.call(e,u)}}catch(t){return{type:"throw",arg:t}}}e.wrap=c;var d="suspendedStart",h="suspendedYield",C="executing",E="completed",f={};function p(){}function F(){}function A(){}var m={};a(m,i,(function(){return this}));var y=Object.getPrototypeOf,g=y&&y(y(S([])));g&&g!==u&&o.call(g,i)&&(m=g);var v=A.prototype=p.prototype=Object.create(m);function B(t){["next","throw","return"].forEach((function(e){a(t,e,(function(t){return this._invoke(e,t)}))}))}function k(t,e){function u(n,r,i,s){var l=D(t[n],t,r);if("throw"!==l.type){var a=l.arg,c=a.value;return c&&"object"==_typeof(c)&&o.call(c,"__await")?e.resolve(c.__await).then((function(t){u("next",t,i,s)}),(function(t){u("throw",t,i,s)})):e.resolve(c).then((function(t){a.value=t,i(a)}),(function(t){return u("throw",t,i,s)}))}s(l.arg)}var r;n(this,"_invoke",{value:function(t,o){function n(){return new e((function(e,n){u(t,o,e,n)}))}return r=r?r.then(n,n):n()}})}function b(e,u,o){var n=d;return function(r,i){if(n===C)throw Error("Generator is already running");if(n===E){if("throw"===r)throw i;return{value:t,done:!0}}for(o.method=r,o.arg=i;;){var s=o.delegate;if(s){var l=w(s,o);if(l){if(l===f)continue;return l}}if("next"===o.method)o.sent=o._sent=o.arg;else if("throw"===o.method){if(n===d)throw n=E,o.arg;o.dispatchException(o.arg)}else"return"===o.method&&o.abrupt("return",o.arg);n=C;var a=D(e,u,o);if("normal"===a.type){if(n=o.done?E:h,a.arg===f)continue;return{value:a.arg,done:o.done}}"throw"===a.type&&(n=E,o.method="throw",o.arg=a.arg)}}}function w(e,u){var o=u.method,n=e.iterator[o];if(n===t)return u.delegate=null,"throw"===o&&e.iterator.return&&(u.method="return",u.arg=t,w(e,u),"throw"===u.method)||"return"!==o&&(u.method="throw",u.arg=new TypeError("The iterator does not provide a '"+o+"' method")),f;var r=D(n,e.iterator,u.arg);if("throw"===r.type)return u.method="throw",u.arg=r.arg,u.delegate=null,f;var i=r.arg;return i?i.done?(u[e.resultName]=i.value,u.next=e.nextLoc,"return"!==u.method&&(u.method="next",u.arg=t),u.delegate=null,f):i:(u.method="throw",u.arg=new TypeError("iterator result is not an object"),u.delegate=null,f)}function I(t){var e={tryLoc:t[0]};1 in t&&(e.catchLoc=t[1]),2 in t&&(e.finallyLoc=t[2],e.afterLoc=t[3]),this.tryEntries.push(e)}function _(t){var e=t.completion||{};e.type="normal",delete e.arg,t.completion=e}function L(t){this.tryEntries=[{tryLoc:"root"}],t.forEach(I,this),this.reset(!0)}function S(e){if(e||""===e){var u=e[i];if(u)return u.call(e);if("function"==typeof e.next)return e;if(!isNaN(e.length)){var n=-1,r=function u(){for(;++n=0;--r){var i=this.tryEntries[r],s=i.completion;if("root"===i.tryLoc)return n("end");if(i.tryLoc<=this.prev){var l=o.call(i,"catchLoc"),a=o.call(i,"finallyLoc");if(l&&a){if(this.prev=0;--u){var n=this.tryEntries[u];if(n.tryLoc<=this.prev&&o.call(n,"finallyLoc")&&this.prev=0;--e){var u=this.tryEntries[e];if(u.finallyLoc===t)return this.complete(u.completion,u.afterLoc),_(u),f}},catch:function(t){for(var e=this.tryEntries.length-1;e>=0;--e){var u=this.tryEntries[e];if(u.tryLoc===t){var o=u.completion;if("throw"===o.type){var n=o.arg;_(u)}return n}}throw Error("illegal catch attempt")},delegateYield:function(e,u,o){return this.delegate={iterator:S(e),resultName:u,nextLoc:o},"next"===this.method&&(this.arg=t),f}},e}function _createForOfIteratorHelper(t,e){var u="undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(!u){if(Array.isArray(t)||(u=_unsupportedIterableToArray(t))||e&&t&&"number"==typeof t.length){u&&(t=u);var o=0,n=function(){};return{s:n,n:function(){return o>=t.length?{done:!0}:{done:!1,value:t[o++]}},e:function(t){throw t},f:n}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var r,i=!0,s=!1;return{s:function(){u=u.call(t)},n:function(){var t=u.next();return i=t.done,t},e:function(t){s=!0,r=t},f:function(){try{i||null==u.return||u.return()}finally{if(s)throw r}}}}function _slicedToArray(t,e){return _arrayWithHoles(t)||_iterableToArrayLimit(t,e)||_unsupportedIterableToArray(t,e)||_nonIterableRest()}function _nonIterableRest(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function _iterableToArrayLimit(t,e){var u=null==t?null:"undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(null!=u){var o,n,r,i,s=[],l=!0,a=!1;try{if(r=(u=u.call(t)).next,0===e){if(Object(u)!==u)return;l=!1}else for(;!(l=(o=r.call(u)).done)&&(s.push(o.value),s.length!==e);l=!0);}catch(t){a=!0,n=t}finally{try{if(!l&&null!=u.return&&(i=u.return(),Object(i)!==i))return}finally{if(a)throw n}}return s}}function _arrayWithHoles(t){if(Array.isArray(t))return t}function _toConsumableArray(t){return _arrayWithoutHoles(t)||_iterableToArray(t)||_unsupportedIterableToArray(t)||_nonIterableSpread()}function _nonIterableSpread(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function _unsupportedIterableToArray(t,e){if(t){if("string"==typeof t)return _arrayLikeToArray(t,e);var u=Object.prototype.toString.call(t).slice(8,-1);return"Object"===u&&t.constructor&&(u=t.constructor.name),"Map"===u||"Set"===u?Array.from(t):"Arguments"===u||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(u)?_arrayLikeToArray(t,e):void 0}}function _iterableToArray(t){if("undefined"!=typeof Symbol&&null!=t[Symbol.iterator]||null!=t["@@iterator"])return Array.from(t)}function _arrayWithoutHoles(t){if(Array.isArray(t))return _arrayLikeToArray(t)}function _arrayLikeToArray(t,e){(null==e||e>t.length)&&(e=t.length);for(var u=0,o=new Array(e);u0&&void 0!==arguments[0]?arguments[0]:null,e=arguments.length>1?arguments[1]:void 0,u=arguments.length>2&&void 0!==arguments[2]&&arguments[2];null==t||t.preventDefault();var o=e===arrowKeys[2]?-1:1,n=this.getDefinitionsListItemFromWord(),r=Number(n.getAttribute("data-num"))+o,i=Interaction.getDefByNumber(r);if(!i){var s=1===o?"1":this.wordCount;i=Interaction.getDefByNumber(s)}var l=this.cellCoords;-1===o&&u&&(this.setCoordsToEndOfWord=!0),i.focus(),i.click(),i.blur(),this.followCellZoom(l)}},{key:"skipCellCoords",value:function(t,e){var u=this.shiftCellCoords(t,e,modes.ENTER);if(u.isEqualTo(t))return u;if(!this.wasEmpty)return u;for(this.wasEmpty=!1;!Interaction.isEmpty(Interaction.getCellElement(u));){var o=u;if(u=this.shiftCellCoords(u,e,modes.ENTER),o.isEqualTo(u))break}return Interaction.isEmpty(Interaction.getCellElement(u))?u:this.wordToggle.checked?(this.shiftWordSelection(null,"ArrowDown"),this.bypassPostCellShiftActions=!0,this.cellCoords):this.shiftCellCoords(t,e,modes.ENTER)}},{key:"shiftCellCoords",value:function(t,e,u){var o=arguments.length>3&&void 0!==arguments[3]&&arguments[3],n=u==modes.ENTER?1:-1,r=e===this.directions[1]?[t[0]+n,t[1]]:[t[0],t[1]+n],i=Interaction.getCellElement(r);return null!==i&&i.classList.contains("non_empty_cell")||o?r:t}},{key:"onDefinitionsListItemClick",value:function(t,e,u){var o=document.querySelector('[data-num_label="'.concat(e,'"]')).parentElement;this.preventZoomIfRequired(t),this.removeCompoundInputIfRequired(o),this.setFocusMode(!1),document.activeElement.blur(),this.compoundInputActive&&document.getElementsByClassName("compound_input")[0].focus(),this.direction=u,this.cellCoords=Interaction.updateCellCoords(o),this.setCoordsToEndOfWord&&(this.cellCoords=Interaction.updateCellCoords(_toConsumableArray(this.getWordElements()).slice(-1)[0]),this.setCoordsToEndOfWord=!1),this.currentWord=this.updateCurrentWord(),this.setFocusMode(!0)}},{key:"onCellClick",value:function(t,e){if(this.doNotHandleStandardCellClick)return this.doNotHandleStandardCellClick=!1;this.preventZoomIfRequired(t),this.removeCompoundInputIfRequired(e),this.setFocusMode(!1);var u=Interaction.updateCellCoords(e);(this.intersections.includes(JSON.stringify(u))&&u.isEqualTo(this.cellCoords)||this.shouldDirectionBeAlternated(u))&&this.alternateDirection(),this.cellCoords=u,this.currentWord=this.updateCurrentWord(),this.setFocusMode(!0),this.updateDefinitionsListPos()}},{key:"handleArrowPress",value:function(t,e){e.preventDefault();var u=t===arrowKeys[3]||t===arrowKeys[1]?modes.ENTER:modes.DEL,o=t===arrowKeys[3]||t===arrowKeys[2]?this.directions[1]:this.directions[0],n=Interaction.getCellElement(this.cellCoords),r=this.shiftCellCoords(this.cellCoords,o,u,!0),i=!1;try{for(;Interaction.getCellElement(r).classList.contains("empty_cell");)r=this.shiftCellCoords(r,o,u,!0),i=!0}catch(t){r=this.cellCoords}this.setFocusMode(!1),this.shouldDirectionBeAlternated(r)?(this.alternateDirection(),i&&(this.cellCoords=r),i=!1):this.cellCoords=r,this.followCellZoom(n),this.currentWord=this.updateCurrentWord(),this.setFocusMode(!0),this.updateDefinitionsListPos()}},{key:"handleEnterPress",value:function(t){t.target.classList.contains("def")?(t.target.click(),t.target.blur(),this.zoomToggle.checked&&(this.doNotHandleStandardCellClick=!0,Interaction.getCellElement(this.cellCoords).click())):t.target.classList.contains("toggle")&&(t.target.click(),t.target.blur())}},{key:"handleEnterKeybindPress",value:function(t){Interaction.unfocusActiveElement(),this.hideDropdowns();var e=t.shiftKey?gridOp.REVEAL:"check";this.doSpecialButtonAction(opMagnitude.WORD,e,!1)}},{key:"handleSpacebarPress",value:function(t){t.preventDefault(),this.setFocusMode(!1),this.alternateDirection(),this.currentWord=this.updateCurrentWord(),this.setFocusMode(!0),this.updateDefinitionsListPos()}},{key:"handleEscapePress",value:function(t){null==t||t.preventDefault(),Interaction.unfocusActiveElement(),this.hideDropdowns(),this.setFocusMode(!1),this.zoomOut(),this.cellCoords=null,this.currentWord=null}},{key:"crosswordCompletionHandler",value:function(){var t=this;this.isCrosswordComplete()&&Interaction.sleep(1).then((function(){t.handleEscapePress(null),t.displayCompletionPopup(),t.jazz.play()}))}},{key:"doSpecialButtonAction",value:function(t,e){var u=this,o=arguments.length>3&&void 0!==arguments[3]&&arguments[3];if((!(arguments.length>2&&void 0!==arguments[2])||arguments[2])&&this.onDropdownClick(e+"_dropdown"),null===this.cellCoords&&t!==opMagnitude.GRID)return alert(this.errMsgs[0]);switch(t){case opMagnitude.CELL:var n=Interaction.getCellElement(this.cellCoords);this.doGridOperation(n,e),e===gridOp.REVEAL&&this.handleCellShift(modes.ENTER,n);break;case opMagnitude.WORD:var r,i=this.isWordEmpty(),s=_createForOfIteratorHelper(this.getWordElements());try{for(s.s();!(r=s.n()).done;){var l=r.value;this.doGridOperation(l,e)}}catch(t){s.e(t)}finally{s.f()}this.wordToggle.checked&&(e===gridOp.REVEAL?this.shiftWordSelection(null,arrowKeys[3]):e===gridOp.CLEAR&&i&&this.shiftWordSelection(null,arrowKeys[2]));break;case opMagnitude.GRID:document.querySelectorAll(".non_empty_cell").forEach((function(t){return u.doGridOperation(t,e,o)}))}e!==gridOp.CLEAR&&(e===gridOp.REVEAL&&this.crosswordCompletionHandler(),this.saveGridState())}},{key:"doGridOperation",value:function(t,e){var u=arguments.length>2&&void 0!==arguments[2]&&arguments[2];e===gridOp.REVEAL?(t.classList.remove("wrong"),this.setValue(t,t.getAttribute("data-value")),t.classList.add("lock_in")):e===gridOp.CHECK?Interaction.isEmpty(t)||(t.hasCorrectValue()?t.classList.add("lock_in"):t.classList.add("wrong")):e===gridOp.CLEAR&&(u&&!t.classList.contains("lock_in")||!u)&&(t.classList.remove("lock_in"),t.classList.remove("wrong"),this.setValue(t,"",this.doNotSaveGridState))}},{key:"shouldDirectionBeAlternated",value:function(t){return this.shiftCellCoords(t,this.direction,modes.ENTER).isEqualTo(t)&&this.shiftCellCoords(t,this.direction,modes.DEL).isEqualTo(t)}},{key:"setFocusMode",value:function(t){null!==this.cellCoords&&(this.changeWordFocus(t),this.changeCellFocus(t),this.changeDefinitionsListItemFocus(t))}},{key:"changeWordFocus",value:function(t){var e,u=_createForOfIteratorHelper(this.getWordElements());try{for(u.s();!(e=u.n()).done;){e.value.style.backgroundColor=t?this.colourPalette.WORD_FOCUS:this.colourPalette.SUB}}catch(t){u.e(t)}finally{u.f()}}},{key:"changeCellFocus",value:function(t){return this.saveGridState(),Interaction.getCellElement(this.cellCoords).style.backgroundColor=t?this.colourPalette.CELL_FOCUS:this.colourPalette.SUB}},{key:"changeDefinitionsListItemFocus",value:function(t){return this.getDefinitionsListItemFromWord().style.backgroundColor=t?this.colourPalette.WORD_FOCUS:""}},{key:"updateCurrentWord",value:function(){var t,e="",u=_createForOfIteratorHelper(this.getWordElements());try{for(u.s();!(t=u.n()).done;){e+=t.value.getAttribute("data-value")}}catch(t){u.e(t)}finally{u.f()}return e.toUpperCase()}},{key:"getWordElements",value:_regeneratorRuntime().mark((function t(){var e,u,o,n,r,i;return _regeneratorRuntime().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:e=this.getWordIndices(),u=_slicedToArray(e,2),o=u[0],n=u[1],r=o;case 2:if(!(r<=n)){t.next=9;break}return i=this.isDown?[r,this.staticIndex]:[this.staticIndex,r],t.next=6,Interaction.getCellElement(i);case 6:r++,t.next=2;break;case 9:case"end":return t.stop()}}),t,this)}))},{key:"getWordIndices",value:function(){var t=_slicedToArray(this.cellCoords,2),e=t[0],u=t[1];this.isDown=this.direction===this.directions[1],this.staticIndex=this.isDown?u:e;for(var o=_slicedToArray(this.isDown?[e,e]:[u,u],2),n=o[0],r=o[1];n>0&&this.grid[this.isDown?n-1:e][this.isDown?u:n-1]!=this.empty;)n--;for(;r0&&void 0!==arguments[0]&&arguments[0],u=Array.from({length:this.dimensions},(function(){return Array(t.dimensions).fill(t.empty)})),o=structuredClone(u);return document.querySelectorAll(".non_empty_cell").forEach((function(t){var n=parseInt(t.getAttribute("data-row")),r=parseInt(t.getAttribute("data-column")),i=t.childNodes[0].nodeValue.toUpperCase();if(u[n][r]=i,e){var s="";t.classList.contains("wrong")?s="wrong":t.classList.contains("lock_in")&&(s="lock_in"),o[n][r]=s}})),e?[u,o]:u}},{key:"setCompoundInput",value:function(t){this.compoundInputActive=!0,t||(this.wasEmpty=!0);var e=Interaction.getCellElement(this.cellCoords);e.onclick=function(t){return Interaction.dummyCellClick(t)},this.setValue(e,"");var u=document.createElement("input");u.value=t,u.type="text",u.classList.add("compound_input"),e.appendChild(u),u.focus()}},{key:"handleSetCompoundInput",value:function(){var t=!(arguments.length>0&&void 0!==arguments[0])||arguments[0];if(null===this.cellCoords)return alert(this.errMsgs[0]);if(document.getElementsByClassName("compound_input")[0])return this.removeCompoundInput(t);var e=Interaction.getCellElement(this.cellCoords).childNodes,u=e[0].nodeValue;e.length>1&&(e[1].style.display="none"),this.setCompoundInput(u)}},{key:"removeCompoundInput",value:function(){var t=this,e=!(arguments.length>0&&void 0!==arguments[0])||arguments[0];if(this.compoundInputActive){var u=document.getElementsByClassName("compound_input")[0],o=u.parentElement,n=u.value;0!==n.length&&n[0].match(onlyLangRegex)||(n=""),u.remove(),this.setValue(o,n[0]);var r=o.childNodes;r.length>1&&(r[1].style.display="inline"),o.onclick=function(e){return t.onCellClick(e,o)},o.classList.remove("lock_in","wrong"),this.compoundInputActive=!1,this.currentPlaceholder=0,this.checkToggle.checked&&this.doGridOperation(o,gridOp.CHECK),e&&this.handleCellShift(modes.ENTER,o)}}},{key:"cycleCompoundInputPlaceholderText",value:function(){var t=document.getElementsByClassName("compound_input")[0];void 0!==t&&(t.placeholder=compoundInputPlaceholders[this.currentPlaceholder],this.currentPlaceholder===compoundInputPlaceholders.length-1?this.currentPlaceholder=0:this.currentPlaceholder+=1)}},{key:"removeCompoundInputIfRequired",value:function(t){this.compoundInputActive&&t!==Interaction.getCellElement(this.cellCoords)&&this.removeCompoundInput()}},{key:"followCellZoom",value:function(t){if(1===document.querySelectorAll(".non_empty_cell.selectedZoomTarget").length){var e=Interaction.getCellElement(this.cellCoords);if(e!==t)return this.doNotHandleStandardCellClick=!0,e.click()}}},{key:"handleClick",value:function(t){t.target.closest(".special_button, .dropdown, .dropdown_button")||(this.hideDropdowns(),this.removeCompoundInput(!1))}},{key:"handleDropdownFocusOut",value:function(t){var e,u,o,n,r,i,s,l,a;(null===(e=t.relatedTarget)||void 0===e||!e.classList.contains("dropdown_button")||null!==(u=t.target)&&void 0!==u&&u.classList.contains("dropdown_button")&&null!==(o=t.relatedTarget)&&void 0!==o&&o.classList.contains("special_button")&&(null===(n=t.relatedTarget)||void 0===n||!n.id.startsWith(null===(r=this.currentDropdown)||void 0===r?void 0:r.substring(0,null===(i=this.currentDropdown)||void 0===i?void 0:i.indexOf("_"))))||null!==(s=t.target.id)&&void 0!==s&&s.endsWith("button")&&(null!==(l=t.relatedTarget)&&void 0!==l&&null!==(l=l.id)&&void 0!==l&&l.endsWith("button")||null===(a=t.relatedTarget)||void 0===a||null===(a=a.classList)||void 0===a||!a.contains("dropdown_button")))&&this.hideDropdowns()}},{key:"hideDropdowns",value:function(){document.querySelectorAll(".dropdown").forEach((function(t){return t.classList.remove("show_dropdown")})),document.querySelectorAll(".special_button").forEach((function(t){return t.innerHTML=t.innerHTML.replace("▲","▼")})),this.currentDropdown=null}},{key:"onDropdownClick",value:function(t){this.removeCompoundInput(!1);var e=document.getElementById(t);if(t===this.currentDropdown)return this.hideDropdowns(),void(this.currentDropdown=null);this.hideDropdowns();var u=document.getElementById(t.replace("_dropdown","_button"));u.innerHTML=u.innerHTML.replace("▼","▲"),e.classList.add("show_dropdown"),this.currentDropdown=t}},{key:"displayOnloadPopup",value:function(){this.onloadPopupToggled=!0,Interaction.sleep(200).then((function(){document.getElementById("blur").classList.toggle("active"),document.getElementById("onload_popup").classList.toggle("active"),Interaction.sleep(301).then((function(){document.getElementsByClassName("continue_button")[0].focus({focusVisible:!0})}))}))}},{key:"displayCompletionPopup",value:function(){this.completionPopupToggled=!this.completionPopupToggled,document.getElementById("blur").classList.toggle("active"),document.getElementById("completion_popup").classList.toggle("active"),this.completionPopupToggled&&Interaction.sleep(501).then((function(){return document.getElementsByClassName("close_button")[0].focus({focusVisible:!0})}))}},{key:"closeOnloadPopup",value:function(){this.onloadPopupToggled=!1,document.getElementById("blur").classList.toggle("active"),document.getElementById("onload_popup").classList.toggle("active")}},{key:"preventZoomIfRequired",value:function(t){document.getElementById("tz").checked&&!this.preventInitialLIZoom||(this.preventInitialLIZoom=!1,t.stopImmediatePropagation())}},{key:"setValue",value:function(t,e){var u=arguments.length>2&&void 0!==arguments[2]&&arguments[2];t.childNodes[0].nodeValue=e,u||this.saveGridState()}}],[{key:"getDefByNumber",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]&&arguments[1],u=document.querySelector('[data-num="'.concat(t,'"'));return e&&u.click(),u}},{key:"dummyCellClick",value:function(t){return t.stopImmediatePropagation()}},{key:"unfocusActiveElement",value:function(){document.activeElement.blur()}},{key:"sleep",value:function(t){return new Promise((function(e){return setTimeout(e,t)}))}},{key:"isEmpty",value:function(t){var e;return!(null!=t&&null!==(e=t.childNodes[0])&&void 0!==e&&e.nodeValue)}},{key:"getCellElement",value:function(t){return document.querySelector('[data-row="'.concat(t[0],'"][data-column="').concat(t[1],'"]'))}},{key:"updateCellCoords",value:function(t){return[parseInt(t.getAttribute("data-row")),parseInt(t.getAttribute("data-column"))]}},{key:"configureScrollHeights",value:function(){var t=document.querySelector(".definitions_a"),e=document.querySelector(".definitions_d");document.getElementById("return_def_zoom").style.height=Math.max(t.scrollHeight,e.scrollHeight)+"px";var u=document.getElementById("no_scroll");u.scrollHeight-1>u.clientHeight&&(u.style.overflowY="auto")}}])}(),Cookies=function(){return _createClass((function t(){_classCallCheck(this,t)}),null,[{key:"setCookie",value:function(t,e,u){var o=new Date;o.setTime(o.getTime()+24*u*60*60*1e3);var n="expires="+o.toUTCString();document.cookie="".concat(t,"=").concat(e,";").concat(n,";path=/;SameSite=Lax")}},{key:"getCookie",value:function(t){for(var e=t+"=",u=document.cookie.split(";"),o=0;o