diff --git a/devel/moth.py b/devel/moth.py index ee13f46..6a62116 100644 --- a/devel/moth.py +++ b/devel/moth.py @@ -75,6 +75,7 @@ class Puzzle: self.authors = [] self.answers = [] self.scripts = [] + self.pattern = None self.hint = None self.files = {} self.body = io.StringIO() @@ -104,6 +105,8 @@ class Puzzle: self.summary = val elif key == 'answer': self.answers.append(val) + elif key == 'pattern': + self.pattern = val elif key == 'hint': self.hint = val elif key == 'name': @@ -271,6 +274,7 @@ class Puzzle: 'hashes': self.hashes(), 'files': files, 'scripts': self.scripts, + 'pattern': self.pattern, 'body': self.html_body(), } diff --git a/example-puzzles/example/5/puzzle.moth b/example-puzzles/example/5/puzzle.moth index d59937e..9c3be6b 100644 --- a/example-puzzles/example/5/puzzle.moth +++ b/example-puzzles/example/5/puzzle.moth @@ -11,7 +11,7 @@ This page has an associated `helpers.js` script you can include to assist with input formatting, so people aren't confused about how to enter an answer. -You could also write your own JavaScript to validate things +You could also write your own JavaScript to validate things. This is just a demonstration page. You will probably only want one of these in a page, diff --git a/theme/basic.css b/theme/basic.css index 2c5170d..9614028 100644 --- a/theme/basic.css +++ b/theme/basic.css @@ -50,6 +50,9 @@ iframe#body { img { max-width: 100%; } +input:invalid { + border-color: red; +} #messages { min-height: 3em; border: solid black 2px; diff --git a/theme/puzzle.js b/theme/puzzle.js index 6ab5f07..0781287 100644 --- a/theme/puzzle.js +++ b/theme/puzzle.js @@ -44,11 +44,15 @@ function devel_addin(obj, e) { } } + + // The routine used to hash answers in compiled puzzle packages function djb2hash(buf) { let h = 5381 - for (let c of (new TextEncoder).encode(buf)) { // JavaScript is weird. - h = ((h * 33) + c) & 0xffffffff + for (let c of (new TextEncoder).encode(buf)) { // Encode as UTF-8 and read in each byte + // JavaScript converts everything to a signed 32-bit integer when you do bitwise operations. + // So we have to do "unsigned right shift" by zero to get it back to unsigned. + h = (((h * 33) + c) & 0xffffffff) >>> 0 } return h } @@ -132,6 +136,11 @@ function loadPuzzle(categoryName, points, puzzleId) { for (let se of doc.querySelectorAll("[src],[href]")) { se.outerHTML = se.outerHTML.replace(/(src|href)="([^/]+)"/i, "$1=\"" + base + "$2\"") } + + // If a validation pattern was provided, set that + if (obj.pattern) { + document.querySelector("#answer").pattern = obj.pattern + } // Replace puzzle children with what's in `doc` Array.from(puzzle.childNodes).map(e => e.remove())