diff --git a/style.css b/style.css index 91fd283..3ea1255 100644 --- a/style.css +++ b/style.css @@ -110,14 +110,13 @@ input[type="number"]::-webkit-calendar-picker-indicator { font-size: 0.9rem !important; } .grid input:disabled { - color: white; - background: #6666ff; + color: white !important; + background: #6666ff !important; cursor: not-allowed !important; } -.grid input:disabled, .grid input.forbidden:enabled { - background: #ffffaa; - cursor: not-allowed !important; + background: #ffffaa !important; + cursor: not-allowed; } .grid input.same-value:enabled { background: #ffff33; @@ -129,7 +128,7 @@ input[type="number"]::-webkit-calendar-picker-indicator { } .grid input.same-value:disabled, .tools button.same-value:enabled, -.tools input:enabled:checked+label { +.tools input:enabled:checked + label { color: #ffffaa !important; background: #00b359 !important; } @@ -138,7 +137,7 @@ input[type="number"]::-webkit-calendar-picker-indicator { } .tools button, -.tools input+label { +.tools input + label { color: white; text-shadow: -1px -1px #5b6c9e; background: #8ca6f2; @@ -156,22 +155,28 @@ input[type="number"]::-webkit-calendar-picker-indicator { height: 24px; } .tools input { - display:none; + position: fixed; + opacity: 0; + width: 0; + pointer-events: none; } .tools button:enabled:hover, -.tools input:enabled:hover+label { +.tools button:enabled:focus, +.tools input:enabled:hover + label, +.tools input:enabled:focus + label { border-width: 1px; border-style: outset; padding: 5px 5px 5px 6px; margin: 1px 1px 1px 2px; } -.tools input:enabled:checked:hover+label { +.tools input:enabled:checked:hover + label, +.tools input:enabled:checked:focus + label { border-width: 3px; border-style: inset; padding: 4px 2px 2px 5px; margin: 1px 1px 1px 2px; } -.tools input:enabled:checked+label { +.tools input:enabled:checked + label { text-shadow: -1px -1px #005f2f; border: 2px inset #00b359; background: #00b359; @@ -179,14 +184,14 @@ input[type="number"]::-webkit-calendar-picker-indicator { margin: 1px 1px 0px 2px; } .tools button:enabled:active, -.tools input:enabled:active+label { +.tools input:enabled:active + label { border-width: 4px !important; border-style: inset !important; padding: 4px 0px 0px 5px !important; margin: 0px 1px 0px 2px !important; } .tools button:disabled, -.tools input:disabled+label { +.tools input:disabled + label { text-shadow: -1px -1px #555; color: #ccc; background: darkgrey; diff --git a/sudoku.js b/sudoku.js index 6d096ca..21633b8 100644 --- a/sudoku.js +++ b/sudoku.js @@ -52,6 +52,35 @@ window.onload = function () { rowId++ } + loadSavedGame() + + boxes.forEach(box => { + box.neighbourhood = new Set(rows[box.rowId].concat(columns[box.columnId]).concat(regions[box.regionId])) + box.neighbourhood.delete(box) + box.neighbourhood = Array.from(box.neighbourhood) + searchCandidatesOf(box) + }) + + for (label of document.getElementsByTagName("label")) { + label.control.label = label + } + + if (/Win/.test(navigator.platform) || /Linux/.test(navigator.platform)) accessKeyModifiers = "Alt+Maj+" + else if (/Mac/.test(navigator.platform)) accessKeyModifiers = "⌃⌥" + for (node of document.querySelectorAll("*[accesskey]")) { + shortcut = ` [${node.accessKeyLabel||(accessKeyModifiers+node.accessKey)}]` + if (node.title) node.title += shortcut + else if (node.label) node.label.title += shortcut + } + + refreshUI() + + if ("serviceWorker" in navigator) { + navigator.serviceWorker.register(`service-worker.php?location=${location.pathname}`) + } +} + +function loadSavedGame() { const savedGame = localStorage[location.pathname] if (savedGame) { boxes.forEach((box, i) => { @@ -62,25 +91,6 @@ window.onload = function () { }) fixGridLink.href = savedGame } - - boxes.forEach(box => { - box.neighbourhood = new Set(rows[box.rowId].concat(columns[box.columnId]).concat(regions[box.regionId])) - box.neighbourhood.delete(box) - box.neighbourhood = Array.from(box.neighbourhood) - searchCandidatesOf(box) - }) - - if (/Win/.test(navigator.platform) || /Linux/.test(navigator.platform)) accessKeyModifiers = "Alt+Maj+" - else if (/Mac/.test(navigator.platform)) accessKeyModifiers = "⌃⌥" - for (node of document.querySelectorAll("*[accesskey]")) { - node.title += " [" + (node.accessKeyLabel || accessKeyModifiers + node.accessKey) + "]" - } - - refreshUI() - - if ("serviceWorker" in navigator) { - navigator.serviceWorker.register(`service-worker.php?location=${location.pathname}`) - } } function searchCandidatesOf(box) { @@ -111,10 +121,6 @@ function onfocus() { } function onclick() { - if (this.value == "" && this.candidates.size == 1) { - valueToInsert = this.candidates.values().next().value - document.getElementById("insertRadio" + valueToInsert).checked = true - } if (inkPenRadio.checked) { if (valueToInsert) { this.value = valueToInsert @@ -145,20 +151,95 @@ function oninput() { this.previousPlaceholder = this.placeholder refreshBox(this) } + + if (suggestionTimer) clearTimeout(suggestionTimer) + suggestionTimer = setTimeout(showSuggestion, SUGESTION_DELAY) } function refreshBox(box) { + saveGame() + checkBox(box) + refreshUI() +} + +function saveGame() { let saveGame = boxes.map(box => box.value || UNKNOWN).join("") localStorage[location.pathname] = saveGame fixGridLink.href = saveGame +} +function refreshUI() { + enableRadio() + highlight() + showEasyBoxes() +} + +function enableRadio() { + for (radio of insertRadioGroup.getElementsByTagName("input")) { + if (boxes.filter(box => box.value == "").some(box => box.candidates.has(radio.value))) { + radio.disabled = false + radio.label.title = `Insérer un ${radio.value} [${radio.accessKeyLabel||(accessKeyModifiers+radio.accessKey)}]` + } else { + radio.disabled = true + radio.label.title = `Tous les ${radio.value} sont posés.` + if (valueToInsert == radio.value) { + let nextRadio = document.querySelector(".insertRadioGroup :checked ~ input:enabled") || document.querySelector(".insertRadioGroup :enabled") + if (nextRadio) { + nextRadio.click() + nextRadio.onfocus() + } else { + valueToInsert = "" + } + } + } + } +} + +function highlight() { + boxes.forEach(box => { + if (valueToInsert && box.value == valueToInsert) { + box.classList.add("same-value") + box.tabIndex = -1 + } else { + box.classList.remove("same-value") + if (box.disabled) { + box.classList.add("forbidden") + } else { + if (valueToInsert && highlighterCheckbox.checked && !box.candidates.has(valueToInsert)) { + box.classList.add("forbidden") + box.tabIndex = -1 + } else { + box.classList.remove("forbidden") + box.tabIndex = 0 + } + } + } + }) + highlighterCheckbox.label.title = "Surligner les lignes, colonnes et régions contenant déjà " + (valueToInsert? "un " + valueToInsert: "le chiffre sélectionné") +} + +function showEasyBoxes() { + boxes.filter(box => !box.disabled).forEach(box => { + if (!box.value && box.candidates.size == 1) { + box.classList.add("one-candidate") + box.onclick = function() { + valueToInsert = this.candidates.values().next().value + document.getElementById("insertRadio" + valueToInsert).checked = true + onclick.apply(box) + } + } else { + box.classList.remove("one-candidate") + box.onclick = onclick + } + }) +} + +function checkBox(box) { box.neighbourhood.concat([box]).forEach(neighbour => { searchCandidatesOf(neighbour) neighbour.setCustomValidity("") }) - refreshUI() - for (neighbour1 of box.neighbourhood) { if (neighbour1.value) { for (area of [ @@ -187,56 +268,6 @@ function refreshBox(box) { } } -function refreshUI() { - for (radio of insertRadioGroup.getElementsByTagName("input")) { - const label = radio.nextElementSibling - if (boxes.filter(box => box.value == "").some(box => box.candidates.has(radio.value))) { - radio.disabled = false - if (radio.previousTitle) { - label.title = radio.previousTitle - label.previousTitle = null - } - } else { - radio.disabled = true - label.previousTitle = label.title - label.title = `Tous les ${radio.value} sont posés` - if (valueToInsert == radio.value) valueToInsert = "" - } - } - - highlight() - - boxes.filter(box => !box.disabled).forEach(box => { - if (!box.value && box.candidates.size == 1) box.classList.add("one-candidate") - else box.classList.remove("one-candidate") - }) - if (suggestionTimer) clearTimeout(suggestionTimer) - suggestionTimer = setTimeout(showSuggestion, SUGESTION_DELAY) -} - -function highlight() { - boxes.forEach(box => { - if (valueToInsert && box.value == valueToInsert) { - box.classList.add("same-value") - box.tabIndex = -1 - } else { - box.classList.remove("same-value") - if (box.disabled) { - box.classList.add("forbidden") - } else { - if (valueToInsert && highlighterCheckbox.checked && !box.candidates.has(valueToInsert)) { - box.classList.add("forbidden") - box.tabIndex = -1 - } else { - box.classList.remove("forbidden") - box.tabIndex = 0 - } - } - } - }) - highlighterCheckbox.nextElementSibling.title = "Surligner les lignes, colonnes et régions contenant déjà " + (valueToInsert? "un " + valueToInsert: "le chiffre sélectionné") -} - function onblur() { if (this.classList.contains("pencil")) { this.placeholder = this.value @@ -289,7 +320,9 @@ function restart() { function showSuggestion() { const easyBoxes = boxes.filter(box => box.value == "" && box.candidates.size == 1) if (easyBoxes.length) { - shuffle(easyBoxes)[0].placeholder = "💡" + let randomEasyBox = shuffle(easyBoxes)[0] + randomEasyBox.placeholder = "💡" + randomEasyBox.focus() } else { clearTimeout(suggestionTimer) suggestionTimer = null @@ -321,17 +354,19 @@ function oncontextmenu(event) { } contextMenu.style.left = `${event.pageX}px` contextMenu.style.top = `${event.pageY}px` + console.log(event.target) contextMenu.style.display = "block" return false } document.onclick = function (event) { - contextMenu.style.display = "none" + if (contextMenu.style.display == "block") + contextMenu.style.display = "none" } document.onkeydown = function(event) { - if (event.key == "Escape") { + if (event.key == "Escape" && contextMenu.style.display == "block") { event.preventDefault() contextMenu.style.display = "none" } -} \ No newline at end of file +} diff --git a/sudoku.php b/sudoku.php index 8d94f0f..52eb670 100644 --- a/sudoku.php +++ b/sudoku.php @@ -90,26 +90,17 @@
\n"; - echo " \n"; + echo " \n"; } ?>
- - - - - - - - - - + + + + + +