From c32c6d4a196d6133833fe67c16214274f83a14c2 Mon Sep 17 00:00:00 2001 From: Viresh Ratnakar <39968616+viresh-ratnakar@users.noreply.github.com> Date: Tue, 8 Sep 2020 17:05:58 -0700 Subject: [PATCH] v0.90 ### Version: Exolve v0.90 Septeber 8 2020 - Add functionality to limit checking/revealing to just the current cell rather than the whole current light. This is done when there is a long click (500+ms) on "Check this" or "Reveal this." Caveat; this does not work on phones and tablets (I only tested on Android) as they deal with long-presses in some special way that I'll try to work with, at some point. - Change the default background color of the current clue strip (shown above the grid) to 'white' instead of 'mistyrose' (the active clues in the clues lists still get the 'mistyrose'). This results in a more relaxed appearance (I should have realized this and made this change earlier!). Of course this can be customized too (`exolve-option: color-currclue:mistyrose` will restore the current colour scheme). When the current clue is an orphan, its background continues to be shown as 'linen' (which can be changed with `exolve-option: color-orphan:white`, for example). - When there are multiple Exolve puzzles, use a running variable to set the index of a new one, rather than using the # of existing puzzles, as we might also need to destroy puzzles from a web page (for example, to show a preview). - Allow under-construction grids to specify '?' as the letter in a cell. This is treated just like '0', except that a '0' signifies that the grid has cells where the solution has not been provided, but a '?' does not. - Bug-fix: when the enum specified hyphenation in a child clue, and that child clue did not exist in the clues lists, we were hitting an uninitialized property. - Separately track the solution to display for a clue from the anno to display. Wrao displayed anno in its own span. Wrap the text of the clue in its own span. - Remove weird extra space between prev/next buttons in te current clue strip. - When typing in the grid, let space-bar advance to the next cell. - When typing in the grid, if an invalid character (such as punctuation) is typed, we were deleting the current entry. Don't do that (delete only with space or backspace or a new valid entry). --- CHANGELOG.md | 36 ++++++ README.md | 23 +++- exolve-m-simple.html | 6 +- exolve-m.css | 4 +- exolve-m.html | 6 +- exolve-m.js | 225 ++++++++++++++++++++++----------- exolve-widget.html | 4 +- exolve.html | 225 ++++++++++++++++++++++----------- test-15x15-unsolved.html | 4 +- test-3d-solved.html | 4 +- test-basic-solved.html | 4 +- test-basic-unsolved.html | 4 +- test-big-grid.html | 4 +- test-color-scheme.html | 4 +- test-customize-puzzle.html | 4 +- test-deleted-clues-solved.html | 4 +- test-diagramless-solved.html | 4 +- test-diagramless-unsolved.html | 4 +- test-exolve-div.html | 4 +- test-hindi.html | 4 +- test-jigsaw-solved.html | 4 +- test-jigsaw-unsolved.html | 4 +- test-linked-solved.html | 4 +- test-linked-unsolved.html | 7 +- test-mixed-solved.html | 4 +- test-ninas-colours.html | 4 +- test-no-clues.html | 4 +- test-nonnum.html | 4 +- test-numeric.html | 4 +- test-partial-solved.html | 39 ++++++ test-questions.html | 4 +- test-russian.html | 4 +- test-scroll.html | 4 +- test-skipped-numbers.html | 4 +- test-two-puzzles.html | 4 +- test-widget.html | 4 +- 36 files changed, 462 insertions(+), 217 deletions(-) create mode 100644 test-partial-solved.html diff --git a/CHANGELOG.md b/CHANGELOG.md index 37f7eef2..4da5eba8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,41 @@ # Changelog +### Version: Exolve v0.90 Septeber 8 2020 + +- Add functionality to limit checking/revealing to just the current cell + rather than the whole current light. This is done when there is a long + click (500+ms) on "Check this" or "Reveal this." Caveat; this does + not work on phones and tablets (I only tested on Android) as they deal + with long-presses in some special way that I'll try to work with, at some + point. +- Change the default background color of the current clue strip (shown above + the grid) to 'white' instead of 'mistyrose' (the active clues in the clues + lists still get the 'mistyrose'). This results in a more relaxed appearance + (I should have realized this and made this change earlier!). Of course + this can be customized too (`exolve-option: color-currclue:mistyrose` will + restore the current colour scheme). When the current clue is an orphan, its + background continues to be shown as 'linen' (which can be changed with + `exolve-option: color-orphan:white`, for example). +- When there are multiple Exolve puzzles, use a running variable to set + the index of a new one, rather than using the # of existing puzzles, + as we might also need to destroy puzzles from a web page (for example, + to show a preview). +- Allow under-construction grids to specify '?' as the letter in a cell. + This is treated just like '0', except that a '0' signifies that the + grid has cells where the solution has not been provided, but a '?' + does not. +- Bug-fix: when the enum specified hyphenation in a child clue, and that + child clue did not exist in the clues lists, we were hitting an + uninitialized property. +- Separately track the solution to display for a clue from the anno to + display. Wrao displayed anno in its own span. Wrap the text of the + clue in its own span. +- Remove weird extra space between prev/next buttons in te current clue strip. +- When typing in the grid, let space-bar advance to the next cell. +- When typing in the grid, if an invalid character (such as punctuation) is + typed, we were deleting the current entry. Don't do that (delete only + with space or backspace or a new valid entry). + ### Version: Exolve v0.89 August 31 2020 - Add "conf" parameter defaulting to true, to revealAll(), checkAll(), diff --git a/README.md b/README.md index ec6e966d..65c796e2 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ## An Easily Configurable Interactive Crossword Solver -### Version: Exolve v0.89 August 31 2020 +### Version: Exolve v0.90 September 8 2020 Exolve can help you create online interactively solvable crosswords (simple ones with blocks and/or bars as well as those that are jumbles or are @@ -87,6 +87,12 @@ fully filled lights, if there are any. If there are none (i.e., if all remaining letters in the current light also cross other fully filled lights), only then will these remaining letters get cleared. +A long click on either of "Check this" or "Reveal this" will toggle the text +"this" to "cell," and the checking/revealing will then only happen on the +current cell (as opposed to the whole light), for that particular activation +of the button. Caveat: this does not seem to work on phones and tablets (only +tested on Android devices though). + Exolve supports diagramless puzzles, where the blocked squares are not identified and the solver has to figure out their locations. In fact, exolve supports *partially* diagramless puzzless, where only some squares or some @@ -281,6 +287,10 @@ indicate blocked squares). In this grid, 1 Across = ACE, 1 Down = ARE, 3 Down = ERR, and 3 Across = EAR. When solution letters are included like this, the control buttons for checking/revealing answers get shown. +In a grid with solutions provided, setters may use the letter '?' as a +placeholder in any light square for which they have not yet decided what +letter to place. + Grid without solutions provided: ``` exolve-grid: @@ -958,9 +968,10 @@ be overriding), and descriptions. |----------------------------|---------------|-----------------------------------| | `colour-background` | black | The background: blocked squares and bars.| | `colour-cell` | white | Light squares. | -| `colour-active` | mistyrose | Squares for the light(s) currently active. The current clue(s) also get(s) this as background colour.| +| `colour-active` | mistyrose | Squares for the light(s) currently active. The current clue(s) in the clues list also get(s) this as background colour.| +| `colour-currclue` | white | Background for the current clue above the grid.| +| `colour-orphan` | linen | The background colour of the current clue(s) without known location(s) in the grid.| | `colour-input` | #ffb6b4 | The light square where the solver is typing.| -| `colour-orphan` | linen | The colour of the current clue(s) without known location(s) in the grid.| | `colour-light-label` | black | The number (or nun-numeric label) of a clue, in its first square. | | `colour-light-label-input` | black | Same as above, in the square where the solver is typing.| | `colour-light-text` | black | The typed solution letters in lights.| @@ -1059,11 +1070,13 @@ Here are all the names of pieces of text that you can relabel: | `clear-all` | Clear all! | | `clear-all.hover` | Clear everything! A second click clears all placeholder entries in clues without known squares| | `check` | Check this | -| `check.hover` | Erase mistakes in highlighted squares| +| `checkcell` | Check cell | +| `check.hover` | Erase mistakes in highlighted squares. Long-click to check the just current cell| | `check-all` | Check all! | | `check-all.hover` | Erase all mistakes. Reveal any available annos if no mistakes| | `reveal` | Reveal this | -| `reveal.hover` | Reveal highlighted clue/squares | +| `revealcell` | Reveal cell | +| `reveal.hover` | Reveal highlighted clue/squares. Long-click to reveal the just current cell| | `show-ninas` | Show ninas | | `show-ninas.hover` | Show ninas hidden in the grid/clues | | `hide-ninas` | Hide ninas | diff --git a/exolve-m-simple.html b/exolve-m-simple.html index 70a940fb..d14145b1 100644 --- a/exolve-m-simple.html +++ b/exolve-m-simple.html @@ -14,11 +14,11 @@ See the full Exolve license notice in exolve-m.js. -Version: Exolve v0.89 August 31 2020 +Version: Exolve v0.90 September 8 2020 --> - - + + Exolve diff --git a/exolve-m.css b/exolve-m.css index 11957845..fc60c0f0 100644 --- a/exolve-m.css +++ b/exolve-m.css @@ -5,7 +5,7 @@ Copyright (c) 2019 Viresh Ratnakar See the full license notice in exolve-m.js. -Version: Exolve v0.89 August 31 2020 +Version: Exolve v0.90 September 8 2020 */ @media (max-width: 500px) { @@ -139,7 +139,7 @@ Version: Exolve v0.89 August 31 2020 word-wrap: break-word; font-weight: bold; margin: 0; - padding: 2px 0; + padding: 2px; } .xlv-curr-orphan, .xlv-curr-clue-label { diff --git a/exolve-m.html b/exolve-m.html index 069eb55b..f5a44a39 100644 --- a/exolve-m.html +++ b/exolve-m.html @@ -10,10 +10,10 @@ See the full Exolve license notice in exolve-m.js. -Version: Exolve v0.89 August 31 2020 +Version: Exolve v0.90 September 8 2020 --> - - + + Exolve (replace with puzzle title) diff --git a/exolve-m.js b/exolve-m.js index f983d8c4..335a898e 100644 --- a/exolve-m.js +++ b/exolve-m.js @@ -21,7 +21,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -The latest code and documentation for exolve can be found at: +The latest code and documentation for Exolve can be found at: https://github.com/viresh-ratnakar/exolve */ @@ -73,7 +73,7 @@ function Exolve(puzzleText, customizer=null, addStateToUrl=true, visTop=0) { - this.VERSION = 'Exolve v0.89 August 31 2020' + this.VERSION = 'Exolve v0.90 September 8 2020' this.puzzleText = puzzleText this.containerId = containerId @@ -136,6 +136,9 @@ function Exolve(puzzleText, this.activeCells = []; this.activeClues = []; this.showingNinas = false + // Couple of vars to get long click on check/reveal to use just a cell. + this.cellLightToggleTimer = null; + this.cellNotLight = false; this.numCellsToFill = 0 this.numCellsFilled = 0 @@ -157,8 +160,9 @@ function Exolve(puzzleText, 'background': 'black', 'cell': 'white', 'active': 'mistyrose', - 'input': '#ffb6b4', + 'currclue': 'white', 'orphan': 'linen', + 'input': '#ffb6b4', 'light-label': 'black', 'light-text': 'black', 'light-label-input': 'black', @@ -191,11 +195,13 @@ function Exolve(puzzleText, 'clear-all': 'Clear all!', 'clear-all.hover': 'Clear everything! A second click clears all placeholder entries in clues without known squares', 'check': 'Check this', - 'check.hover': 'Erase mistakes in highlighted squares', + 'checkcell': 'Check cell', + 'check.hover': 'Erase mistakes in highlighted squares. Long-click to check just the current cell', 'check-all': 'Check all', 'check-all.hover': 'Erase all mistakes. Reveal any available annos if no mistakes', 'reveal': 'Reveal this', - 'reveal.hover': 'Reveal highlighted clue/squares', + 'revealcell': 'Reveal cell', + 'reveal.hover': 'Reveal highlighted clue/squares. Long-click to reveal just the current cell', 'show-ninas': 'Show ninas', 'show-ninas.hover': 'Show ninas hidden in the grid/clues', 'hide-ninas': 'Hide ninas', @@ -277,13 +283,13 @@ Exolve.prototype.init = function() { 'and should only have alphanumeric characters or -: ' + this.id) } if (!exolvePuzzles) { - exolvePuzzles = {} + exolvePuzzles = {'42xlvIndex42': 1} } if (exolvePuzzles[this.id]) { this.throwErr('Puzzle id ' + this.id + ' is already in use') } exolvePuzzles[this.id] = this - this.index = Object.keys(exolvePuzzles).length + this.index = exolvePuzzles['42xlvIndex42']++ this.prefix = 'xlv' + this.index const basicHTML = ` @@ -447,6 +453,8 @@ Exolve.prototype.init = function() { this.gridPanel = document.getElementById(this.prefix + '-grid-panel'); this.svg = document.getElementById(this.prefix + '-grid'); this.gridInputWrapper = document.getElementById(this.prefix + '-grid-input-wrapper'); + this.gridInputWrapper.style.width = '' + this.squareDim + 'px' + this.gridInputWrapper.style.height = '' + (this.squareDim - 2) + 'px' this.gridInputWrapper.insertAdjacentHTML('beforeend', `
`) this.gridInputWrapper.insertAdjacentHTML('beforeend', @@ -478,8 +486,8 @@ Exolve.prototype.init = function() { this.statusNumTotal = document.getElementById(this.prefix + '-status-num-total') if (this.addStateToUrl) { document.getElementById(this.prefix + '-saving').insertAdjacentHTML('beforeend', - ` You can bookmark/save this - link as additional back-up: + ` + ${this.textLabels['saving-bookmark']} URL`); this.savingURL = document.getElementById(this.prefix + '-saving-url') } @@ -491,7 +499,9 @@ Exolve.prototype.init = function() { this.clearAllButton.addEventListener('click', this.clearAll.bind(this)); this.checkButton = document.getElementById(this.prefix + '-check') - this.checkButton.addEventListener('click', this.checkCurr.bind(this)); + this.checkButton.addEventListener('mousedown', this.cellLightToggler.bind( + this, this.checkButton, this.textLabels['checkcell'])); + this.checkButton.addEventListener('mouseup', this.checkCurr.bind(this)); this.checkAllButton = document.getElementById(this.prefix + '-check-all') this.checkAllButton.addEventListener('click', this.checkAll.bind(this)); @@ -500,7 +510,9 @@ Exolve.prototype.init = function() { this.ninasButton.addEventListener('click', this.toggleNinas.bind(this)); this.revealButton = document.getElementById(this.prefix + '-reveal') - this.revealButton.addEventListener('click', this.revealCurr.bind(this)); + this.revealButton.addEventListener('mousedown', this.cellLightToggler.bind( + this, this.revealButton, this.textLabels['revealcell'])); + this.revealButton.addEventListener('mouseup', this.revealCurr.bind(this)); this.revealAllButton = document.getElementById(this.prefix + '-reveal-all') this.revealAllButton.addEventListener('click', this.revealAll.bind(this)); @@ -635,7 +647,7 @@ Exolve.prototype.parseSection = function() { const MARKER = 'exolve-' while (this.nextLine < this.numLines && this.specLines[this.nextLine].trim().indexOf(MARKER) != 0) { - this.nextLine++; + this.nextLine++; } if (this.nextLine >= this.numLines) { return null @@ -1022,14 +1034,14 @@ Exolve.prototype.caseCheck = function(c) { return false } -// display chars: A-Z, ⬛, 0-9 -// state chars: A-Z, '-' (DIGIT0), '~' (DIGIT1), 2-9, '0' (blank), '1' (block -// in diagramless cell), '.' +// In this description, "alphabets" means A-Z or language-specific letters. +// display chars: alphabets, ⬛, 0-9 +// state chars: alphabets, '-' (DIGIT0), '~' (DIGIT1), 2-9, '0' (blank), +// '1' (block in diagramless cell), '.' // grid[i][j].solution and grid[i][j].currLetter are in "state char" space. -// grid specified originally, consumed by parseGrid() is in state char space, -// except: -// 0 can mean the digit 0 if allow-digits is true and there are entries -// other than 0. +// grid specified originally, consumed by parseGrid() either uses just '0' +// and '.' or uses '.' and alphabets and '?' (and 0-9 if allow-digits). + Exolve.prototype.isValidDisplayChar = function(c) { if (this.caseCheck(c)) { return true @@ -1042,12 +1054,12 @@ Exolve.prototype.isValidDisplayChar = function(c) { } return false } - Exolve.prototype.isValidStateChar = function(c) { if (this.caseCheck(c)) { return true } - if (this.allowDigits && ((c >= '2' && c <= '9') || c == this.DIGIT0 || c == this.DIGIT1)) { + if (this.allowDigits && + ((c >= '2' && c <= '9') || c == this.DIGIT0 || c == this.DIGIT1)) { return true } if (c == '0') { @@ -1058,9 +1070,12 @@ Exolve.prototype.isValidStateChar = function(c) { } return false } +Exolve.prototype.isValidGridChar = function(c) { + return this.isValidStateChar(c) || c == '?' +} Exolve.prototype.stateToDisplayChar = function(c) { - if (c == '0') { + if (c == '0' || c == '?') { return '' } if (c == '1') { @@ -1095,10 +1110,12 @@ Exolve.prototype.newGridCell = function(row, col, letter) { let cell = {} cell.row = row cell.col = col + cell.currLetter = '?' cell.solution = letter.toUpperCase() cell.isLight = false if (cell.solution != '.') { - if (cell.solution != '0' && !this.isValidDisplayChar(cell.solution)) { + if (cell.solution != '0' && cell.solution != '?' && + !this.isValidDisplayChar(cell.solution)) { this.throwErr('Bad grid entry at ' + row + ',' + col + ':' + letter); } cell.isLight = true @@ -1209,7 +1226,7 @@ Exolve.prototype.parseGrid = function() { } else if (gridCell.solution == '1') { gridCell.solution = this.DIGIT1; } - if (!this.isValidStateChar(gridCell.solution)) { + if (!this.isValidGridChar(gridCell.solution)) { this.throwErr('Invalid grid entry[' + i + '][' + j + ']: ' + saved) } } @@ -1279,6 +1296,11 @@ Exolve.prototype.newClue = function(index) { clue.dir = index.substr(0, 1) clue.label = index.substr(1) clue.cells = [] + clue.clue = '' + clue.enumLen = 0 + clue.hyphenAfter = [] + clue.wordEndAfter = [] + clue.anno = '' return clue }; @@ -1790,7 +1812,8 @@ Exolve.prototype.setClueSolution = function(ci) { } let solution = ''; for (let cell of cells) { - let c = this.stateToDisplayChar(this.grid[cell[0]][cell[1]].solution) + let sol = this.grid[cell[0]][cell[1]].solution + let c = (sol == '?' ? '?' : this.stateToDisplayChar(sol)) if (!c) { return } @@ -2268,14 +2291,15 @@ Exolve.prototype.finalClueTweaks = function() { for (let clueIndex of this.allClueIndices) { let theClue = this.clues[clueIndex] this.setClueSolution(clueIndex) + theClue.dispSol = '' if (this.addSolutionToAnno && theClue.solution && !this.isOrphan(clueIndex) && !this.roughlyStartsWith(theClue.anno, theClue.solution)) { // For orphans, we reveal in their placeholder blanks. - theClue.anno = '' + theClue.solution + - '. ' + theClue.anno; + theClue.dispSol = '' + theClue.solution + + '. '; } - if (theClue.anno) { + if (theClue.anno || theClue.dispSol) { this.hasReveals = true } if (!theClue.fullDisplayLabel) { @@ -2342,7 +2366,7 @@ Exolve.prototype.setWordEndsAndHyphens = function() { } } } - if (!this.clues[clueIndex] || !this.clues[clueIndex].clue) { + if (!this.clues[clueIndex]) { clueLabel = '' clueIndex = '' positionInClue = -1 @@ -2396,7 +2420,7 @@ Exolve.prototype.setWordEndsAndHyphens = function() { } } } - if (!this.clues[clueIndex] || !this.clues[clueIndex].clue) { + if (!this.clues[clueIndex]) { clueLabel = '' clueIndex = '' positionInClue = -1 @@ -2657,7 +2681,8 @@ Exolve.prototype.displayClues = function() { } if (this.clues[clueIndex].startNewTable) { let newPanel = document.createElement('div') - newPanel.setAttributeNS(null, 'class', 'xlv-clues-box'); + newPanel.setAttributeNS(null, 'class', + 'xlv-clues-box xlv-clues-extra-panel'); newPanel.appendChild(document.createElement('hr')) let newTable = document.createElement('table') newPanel.appendChild(newTable) @@ -2697,7 +2722,7 @@ Exolve.prototype.displayClues = function() { this.clueStateToggler.bind(this, clueIndex)); } let col2 = document.createElement('td') - col2.innerHTML = this.clues[clueIndex].clue + col2.innerHTML = '' + this.clues[clueIndex].clue + '' if (col1NumChars > 2) { // More than two unicode chars in col1. Need to indent col2. col1Chars = col1Chars.substr(2) @@ -2741,16 +2766,17 @@ Exolve.prototype.displayClues = function() { this.clues[clueIndex].clue = this.stripLineBreaks(this.clues[clueIndex].clue) } - if (this.clues[clueIndex].anno) { - let anno = document.createElement('span') - anno.setAttributeNS(null, 'class', 'xlv-anno-text'); - anno.innerHTML = ' ' + this.clues[clueIndex].anno - anno.style.color = this.colorScheme['anno'] - anno.style.display = 'none' - this.revelationList.push(anno) - col2.appendChild(anno) - this.clues[clueIndex].annoSpan = anno - } + let annoSpan = document.createElement('span') + annoSpan.setAttributeNS(null, 'class', 'xlv-anno-text'); + annoSpan.style.color = this.colorScheme['anno'] + annoSpan.style.display = 'none' + if (this.clues[clueIndex].anno || this.clues[clueIndex].dispSol) { + annoSpan.innerHTML = ' ' + this.clues[clueIndex].dispSol + + '' + this.clues[clueIndex].anno + '' + this.revelationList.push(annoSpan) + } + col2.appendChild(annoSpan) + this.clues[clueIndex].annoSpan = annoSpan tr.appendChild(col1) tr.appendChild(col2) tr.addEventListener('click', this.clueActivator.bind(this, clueIndex)); @@ -2831,12 +2857,16 @@ Exolve.prototype.getGridStateAndNumFilled = function() { for (let j = 0; j < this.gridWidth; j++) { let gridCell = this.grid[i][j] if (gridCell.isLight || gridCell.isDgmless) { + let stateLetter = gridCell.currLetter + if (stateLetter == '?') { + stateLetter = '0' + } if (this.langMaxCharCodes == 1) { - state = state + gridCell.currLetter + state = state + stateLetter } else { - state = state + gridCell.currLetter + '$' + state = state + stateLetter + '$' } - if (gridCell.currLetter != '0') { + if (stateLetter != '0') { numFilled++ } } else { @@ -3182,8 +3212,6 @@ Exolve.prototype.gnavToInner = function(cell, dir) { return null } - this.gridInputWrapper.style.width = '' + this.squareDim + 'px' - this.gridInputWrapper.style.height = '' + (this.squareDim - 2) + 'px' this.gridInputWrapper.style.left = '' + gridCell.cellLeft + 'px' this.gridInputWrapper.style.top = '' + gridCell.cellTop + 'px' this.gridInput.value = gridCell.prefill ? '' : @@ -3364,7 +3392,7 @@ Exolve.prototype.getLinkedClues = function(clueIndex) { Exolve.prototype.getCurrClueButtons = function() { return `   + title="${this.textLabels['curr-clue-prev.hover']}">${this.textLabels['curr-clue-prev']} `; } @@ -3430,7 +3458,7 @@ Exolve.prototype.cnavToInner = function(activeClueIndex, grabFocus = false) { let colour = orphan ? this.colorScheme['orphan'] : this.colorScheme['active']; for (let clueIndex of clueIndices) { let theClue = this.clues[clueIndex] - if (theClue.anno || (orphan && theClue.cellsOfOrphan)) { + if (theClue.anno || theClue.solution || (orphan && theClue.cellsOfOrphan)) { this.revealButton.disabled = false } if (!theClue.clueTR) { @@ -3444,7 +3472,9 @@ Exolve.prototype.cnavToInner = function(activeClueIndex, grabFocus = false) { } this.currClueIndex = activeClueIndex this.currClue.innerHTML = this.getCurrClueButtons() + - curr.fullDisplayLabel + curr.clue + curr.fullDisplayLabel + + `${curr.clue}` + document.getElementById(this.prefix + '-curr-clue-prev').addEventListener( 'click', this.cnavPrev.bind(this)) document.getElementById(this.prefix + '-curr-clue-next').addEventListener( @@ -3470,7 +3500,8 @@ Exolve.prototype.cnavToInner = function(activeClueIndex, grabFocus = false) { } } } - this.currClue.style.background = colour + this.currClue.style.background = orphan ? + this.colorScheme['orphan'] : this.colorScheme['currclue']; this.updateClueState(parentIndex, false, null) this.makeCurrClueVisible(); return gnav @@ -3797,7 +3828,8 @@ Exolve.prototype.handleKeyUpInner = function(key, shift=false) { this.usingGnav = true if (key == 8) { let gridCell = this.currCell() - if (gridCell.currLetter != '0' && !gridCell.prefill) { + if (gridCell.currLetter != '0' && gridCell.currLetter != '?' && + !gridCell.prefill) { return true } // backspace in an empty or prefilled cell @@ -4011,13 +4043,13 @@ Exolve.prototype.updateClueState = solved = true } } - } else if (clue.annoSpan && clue.annoSpan.style.display == '') { + } else if ((clue.anno || clue.dispSol) && clue.annoSpan.style.display == '') { solved = true } else if (this.allCellsKnown(clueIndex)) { solved = numFilled == clue.enumLen } if (solved && numFilled == numPrefilled && annoPrefilled && - (clue.annoSpan || clue.solution)) { + (clue.anno || clue.dispSol)) { this.revealClueAnno(clueIndex); } let cls = solved ? 'xlv-solved' : '' @@ -4073,15 +4105,9 @@ Exolve.prototype.handleGridInput = function() { if (!gridCell.isLight && !gridCell.isDgmless) { return; } - if (gridCell.prefill) { - // Changes disallowed - this.gridInput.value = '' - this.advanceCursor() - return - } let newInput = this.gridInput.value let currDisplayChar = this.stateToDisplayChar(gridCell.currLetter) - if (gridCell.currLetter != '0' && + if (gridCell.currLetter != '0' && gridCell.currLetter != '?' && newInput != currDisplayChar && this.langMaxCharCodes == 1) { // The "new" input may be before or after the old input. let index = newInput.indexOf(currDisplayChar) @@ -4090,15 +4116,29 @@ Exolve.prototype.handleGridInput = function() { } } let displayChar = newInput.substr(0, this.langMaxCharCodes) - if (displayChar == ' ' && gridCell.isDgmless) { - // spacebar creates a blocked cell in a diagramless puzzle cell - displayChar = this.BLOCK_CHAR + let wasSpace = displayChar == ' ' + if (wasSpace) { + if (gridCell.isDgmless) { + // spacebar creates a blocked cell in a diagramless puzzle cell + displayChar = this.BLOCK_CHAR + } else { + displayChar = '' + } } else { displayChar = displayChar.toUpperCase() - if (!this.isValidDisplayChar(displayChar)) { - displayChar = '' + if (displayChar && !this.isValidDisplayChar(displayChar)) { + // restore + this.gridInput.value = gridCell.prefill ? '' : + this.stateToDisplayChar(gridCell.currLetter) + return } } + if (gridCell.prefill) { + // Changes disallowed + this.gridInput.value = '' + this.advanceCursor() + return + } let stateChar = this.displayToStateChar(displayChar) let oldLetter = gridCell.currLetter gridCell.currLetter = stateChar @@ -4133,7 +4173,8 @@ Exolve.prototype.handleGridInput = function() { this.updateAndSaveState() - if (this.isValidDisplayChar(displayChar) && this.langMaxCharCodes == 1) { + if (wasSpace || + (this.isValidDisplayChar(displayChar) && this.langMaxCharCodes == 1)) { this.advanceCursor() } } @@ -4149,7 +4190,8 @@ Exolve.prototype.createListeners = function() { // Listen for tab/shift tab everywhere in the puzzle area. this.frame.addEventListener('keydown', this.handleTabKeyDown.bind(this)); this.gridInput.addEventListener('input', this.handleGridInput.bind(this)); - this.gridInputWrapper.addEventListener('click', this.toggleCurrDirAndActivate.bind(this)); + this.gridInputWrapper.addEventListener('click', + this.toggleCurrDirAndActivate.bind(this)); let boundDeactivator = this.deactivator.bind(this) this.background.addEventListener('click', boundDeactivator); // Clicking on the title will also unselect current clue (useful @@ -4508,7 +4550,7 @@ Exolve.prototype.isFull = function(clueIndex) { numPrefills++; continue } - if (gridCell.currLetter == '0') { + if (gridCell.currLetter == '0' || gridCell.currLetter == '?') { return [0, 0]; } } @@ -4548,7 +4590,7 @@ Exolve.prototype.clearCurr = function() { if (gridCell.prefill) { continue } - if (gridCell.currLetter == '0') { + if (gridCell.currLetter == '0' || gridCell.currLetter == '?') { continue } if (gridCell.acrossClueLabel && gridCell.downClueLabel) { @@ -4644,7 +4686,31 @@ Exolve.prototype.clearAll = function(conf=true) { this.refocus() } +Exolve.prototype.cellLightTogglerDone = function(button, text) { + if (this.activeCells.length == 0 || !this.currCell() || + !this.currCell().isLight || + this.gridInputWrapper.style.display == 'none') { + return + } + button.innerHTML = text + this.cellNotLight = true +} + +Exolve.prototype.cellLightToggler = function(button, text) { + if (this.cellLightToggleTimer) { + clearTimeout(this.cellLightToggleTimer) + this.cellLightToggleTimer = null + } + this.cellLightToggleTimer = setTimeout( + this.cellLightTogglerDone.bind(this, button, text), 500); +} + Exolve.prototype.checkCurr = function() { + if (this.cellLightToggleTimer) { + clearTimeout(this.cellLightToggleTimer) + this.cellLightToggleTimer = null + } + this.checkButton.innerHTML = this.textLabels['check'] let resetActiveCells = false if (this.activeCells.length == 0 && this.currClueIndex && !this.allCellsKnown(this.currClueIndex)) { @@ -4667,6 +4733,9 @@ Exolve.prototype.checkCurr = function() { continue } allCorrectNum = 0 + if (this.cellNotLight && !this.atCurr(row, col)) { + continue; + } gridCell.currLetter = '0' gridCell.textNode.nodeValue = '' if (this.atCurr(row, col)) { @@ -4708,6 +4777,7 @@ Exolve.prototype.checkCurr = function() { this.updateAndSaveState() } this.refocus() + this.cellNotLight = false; } Exolve.prototype.checkAll = function(conf=true) { @@ -4763,11 +4833,16 @@ Exolve.prototype.revealClueAnno = function(ci) { } Exolve.prototype.revealCurr = function() { + if (this.cellLightToggleTimer) { + clearTimeout(this.cellLightToggleTimer) + this.cellLightToggleTimer = null + } + this.revealButton.innerHTML = this.textLabels['reveal'] // If active cells are present and usingGnav, we reveal only those (the // current clue might be pointing to a random orphan). let clueIndexForAnnoReveal = null let addCellsFromOrphanClue = null - if (this.usingGnav && this.activeCells.length > 0) { + if (this.usingGnav && this.activeCells.length > 0 && !this.cellNotLight) { if (this.currClueIndex && !this.isOrphan(this.currClueIndex)) { clueIndexForAnnoReveal = this.currClueIndex } @@ -4784,7 +4859,7 @@ Exolve.prototype.revealCurr = function() { addCellsFromOrphanClue = this.clues[orphanClueForCells] } } - } else if (this.currClueIndex) { + } else if (this.currClueIndex && !this.cellNotLight) { clueIndexForAnnoReveal = this.currClueIndex let parentClueIndex = this.clues[this.currClueIndex].parentClueIndex || this.currClueIndex @@ -4812,6 +4887,9 @@ Exolve.prototype.revealCurr = function() { for (let x of this.activeCells) { let row = x[0] let col = x[1] + if (this.cellNotLight && !this.atCurr(row, col)) { + continue + } let gridCell = this.grid[row][col] if (gridCell.prefill) { continue @@ -4837,11 +4915,12 @@ Exolve.prototype.revealCurr = function() { } } this.updateActiveCluesState() - if (this.currClueIndex) { + if (this.currClueIndex && !this.cellNotLight) { this.updateClueState(this.currClueIndex, false, 'solved') } this.updateAndSaveState() this.refocus() + this.cellNotLight = false; } Exolve.prototype.revealAll = function(conf=true) { diff --git a/exolve-widget.html b/exolve-widget.html index d40cdcc4..e7de2d94 100644 --- a/exolve-widget.html +++ b/exolve-widget.html @@ -17,8 +17,8 @@ - - + + + + Test-15x15 diff --git a/test-3d-solved.html b/test-3d-solved.html index b7971f7a..459218e5 100644 --- a/test-3d-solved.html +++ b/test-3d-solved.html @@ -3,8 +3,8 @@ - - + + Test-3D diff --git a/test-basic-solved.html b/test-basic-solved.html index 0463cb00..a4d42bc5 100644 --- a/test-basic-solved.html +++ b/test-basic-solved.html @@ -3,8 +3,8 @@ - - + + Test-Basic diff --git a/test-basic-unsolved.html b/test-basic-unsolved.html index 002ee52f..48f0abd1 100644 --- a/test-basic-unsolved.html +++ b/test-basic-unsolved.html @@ -3,8 +3,8 @@ - - + + Test-Basic diff --git a/test-big-grid.html b/test-big-grid.html index c6f5fba2..29f49542 100644 --- a/test-big-grid.html +++ b/test-big-grid.html @@ -3,8 +3,8 @@ - - + + Test-Big diff --git a/test-color-scheme.html b/test-color-scheme.html index 37daf15d..0063b702 100644 --- a/test-color-scheme.html +++ b/test-color-scheme.html @@ -3,8 +3,8 @@ - - + + Test-Color-Scheme diff --git a/test-customize-puzzle.html b/test-customize-puzzle.html index a56de84d..86f98177 100644 --- a/test-customize-puzzle.html +++ b/test-customize-puzzle.html @@ -3,8 +3,8 @@ - - + + + + Test-3D diff --git a/test-diagramless-solved.html b/test-diagramless-solved.html index 4cf1ddac..5e21fee3 100644 --- a/test-diagramless-solved.html +++ b/test-diagramless-solved.html @@ -3,8 +3,8 @@ - - + + Test-Diagramless diff --git a/test-diagramless-unsolved.html b/test-diagramless-unsolved.html index 1949ca81..7c31960c 100644 --- a/test-diagramless-unsolved.html +++ b/test-diagramless-unsolved.html @@ -3,8 +3,8 @@ - - + + Test-Diagramless diff --git a/test-exolve-div.html b/test-exolve-div.html index 5d7f34b6..f61a8b41 100644 --- a/test-exolve-div.html +++ b/test-exolve-div.html @@ -3,8 +3,8 @@ - - + + Test-Exolve-Div diff --git a/test-hindi.html b/test-hindi.html index d651d4f6..dfbd011f 100644 --- a/test-hindi.html +++ b/test-hindi.html @@ -3,8 +3,8 @@ - - + + Test-Hindi diff --git a/test-jigsaw-solved.html b/test-jigsaw-solved.html index 53e8a479..39f9cd2b 100644 --- a/test-jigsaw-solved.html +++ b/test-jigsaw-solved.html @@ -3,8 +3,8 @@ - - + + Test-Jigsaw diff --git a/test-jigsaw-unsolved.html b/test-jigsaw-unsolved.html index c56d5964..e3f7f61e 100644 --- a/test-jigsaw-unsolved.html +++ b/test-jigsaw-unsolved.html @@ -3,8 +3,8 @@ - - + + Test-Jigsaw diff --git a/test-linked-solved.html b/test-linked-solved.html index 0b5fccf1..58ddcc97 100644 --- a/test-linked-solved.html +++ b/test-linked-solved.html @@ -3,8 +3,8 @@ - - + + Test-Linked diff --git a/test-linked-unsolved.html b/test-linked-unsolved.html index 074c2cc7..019838b3 100644 --- a/test-linked-unsolved.html +++ b/test-linked-unsolved.html @@ -3,8 +3,8 @@ - - + + Test-Linked @@ -33,13 +33,12 @@ 0 0 0 0 exolve-across: 1, 3 crew eli (4,1.1.1) - 5 see 1d 6, 13 blah blah (4,3) 10 see 6d 11, 8 blah blah (4,3) 15 see 11d exolve-down - 1,2,4,5 car rna wed raid (3,3,3,4) + 1,2,4,5 car rna wed raid (3,3,3,2-2) 2 see 1 3 see 1a 4 see 1 diff --git a/test-mixed-solved.html b/test-mixed-solved.html index 60f18bbd..1f9760a3 100644 --- a/test-mixed-solved.html +++ b/test-mixed-solved.html @@ -3,8 +3,8 @@ - - + + Test-Mixed diff --git a/test-ninas-colours.html b/test-ninas-colours.html index 9c7a9903..948f214f 100644 --- a/test-ninas-colours.html +++ b/test-ninas-colours.html @@ -3,8 +3,8 @@ - - + + Test-Ninas-Colours diff --git a/test-no-clues.html b/test-no-clues.html index 4c9c232d..4f98bede 100644 --- a/test-no-clues.html +++ b/test-no-clues.html @@ -3,8 +3,8 @@ - - + + Test-No-Clues diff --git a/test-nonnum.html b/test-nonnum.html index 6511af2b..e50a9684 100644 --- a/test-nonnum.html +++ b/test-nonnum.html @@ -3,8 +3,8 @@ - - + + Test-NonNum diff --git a/test-numeric.html b/test-numeric.html index 7330b47d..f9c656be 100644 --- a/test-numeric.html +++ b/test-numeric.html @@ -3,8 +3,8 @@ - - + + Test-Numeric diff --git a/test-partial-solved.html b/test-partial-solved.html new file mode 100644 index 00000000..37431461 --- /dev/null +++ b/test-partial-solved.html @@ -0,0 +1,39 @@ + + + + + + + + +Test-Partial + + + + + + diff --git a/test-questions.html b/test-questions.html index 02451db6..275eff0e 100644 --- a/test-questions.html +++ b/test-questions.html @@ -3,8 +3,8 @@ - - + + Test-Questions diff --git a/test-russian.html b/test-russian.html index ab2d73ca..b1d427b7 100644 --- a/test-russian.html +++ b/test-russian.html @@ -3,8 +3,8 @@ - - + + Test-Russian diff --git a/test-scroll.html b/test-scroll.html index 94d90937..88bd5896 100644 --- a/test-scroll.html +++ b/test-scroll.html @@ -3,8 +3,8 @@ - - + + Test-Scroll diff --git a/test-skipped-numbers.html b/test-skipped-numbers.html index 4e855545..d60e93a0 100644 --- a/test-skipped-numbers.html +++ b/test-skipped-numbers.html @@ -3,8 +3,8 @@ - - + + Test-Skipped-Numbers diff --git a/test-two-puzzles.html b/test-two-puzzles.html index 1b077330..2dc6123c 100644 --- a/test-two-puzzles.html +++ b/test-two-puzzles.html @@ -3,8 +3,8 @@ - - + + Test-Two-Puzzles diff --git a/test-widget.html b/test-widget.html index 465dd0bb..13a7bb19 100644 --- a/test-widget.html +++ b/test-widget.html @@ -8,7 +8,7 @@ Test Widget 1. - +
+