The former grey was almost indistinguishable from its background colours
even on a good screen. I've separated the cursor colour from the grid
colour and made it a lot darker. This gives a contrast ratio over 3.0
even against a darkened tile.
The cursor is still hard to see against trackwork, so maybe something
that isn't grey would be even better.
The keyboard code was prone to adding null items to the undo history,
and was also unreadable. Rather than fix it, I've replaced it with a
jump to the mouse drop handling, lightly enhanced to reject drops on
things that aren't tiles.
Now rather than mucking around with the cursor keys, you can just type a
four-digit number and press Enter. Of course, if you still want to muck
around with the cursor keys they work the same as before.
Since Backspace was already assigned to clear the peg under the cursor,
I haven't co-opted it for the obvious action of clearing the peg to the
left of the cursor and moving the cursor left. The left arrow key is a
reasonable alternative anyway.
For consistency, 'L' now labels the pegs with numbers rather than
letters, and is documented.
It's annoying having to move it to the left each time. I suppose I
could enter the second guess in reverse order, but then I'd need to move
the cursor all the way to the right to submit it, which is just as bad.
This has been broken since 2015. It was accidentally using
"IS_CURSOR_SELECT(button)" in place of "button == CURSOR_SELECT" and
these are not the same thing.
It's sometimes useful to be able to have an HTML element that visually
forms an extension of the puzzle's border. By putting the puzzle's
colour 0 (which we assume to be its background) into a CSS variable,
such elements can do something like "background-color:
var(--puzzle-background)" to get that effect even if the puzzle uses a
non-default background colour.
At least one puzzle does no actual decoding in decode_ui, but does
re-initialise some fields. This is unnecessary because the mid-end only
calls decode_ui() with a game_ui it just allocated using new_ui().
By constructing the <input type=file> off screen and activating it from
JavaScript, we can jump straight to the browser's upload dialogue box
without interposing our own one. This gives a smoother experience, and
also avoids the difficult-to-handle <input type=file> ever being
visible.
Instead of an align=center HTML attribute, we now centre its contents
using CSS. Also, this element contains all the important contents of
the page, so it seems appropriate to us the HTML5 <main> element for
this.
There's not much point in re-requesting the drawing context from the
offscreen canvas at the start of each drawing operation. The canvas
keeps the context around and returns it on every call to getContext(),
so we may as well just keep our reference to it too. This does mean
that the front-end won't detect puzzles drawing outside of a redraw
operation, but I think it's the mid-end's job to assert things like
that.
Rumours that I'm doing this because I had a mysterious bug whereby ctx
was unexpectedly null are entirely true.
This is more compact than carefully drawing it on a canvas in
JavaScript. More importantly, the SVG resize handle scales nicely as
the page is zoomed, or on high-DPI screens.
At the moment, the nice SVG resize handle is removed by JavaScript,
but we need to wait a little while for everyone to get the new HTML
cached before changing that.
With word-wrapping disabled, long status-bar texts fall off the
right-hand end rather than wrapping onto an invisible second line.
This is less confusing because it makes the overflow more obvious.
I've also turned on "text-overflow: ellipsis" for extra obviousness.
Finally, this also the need to explicitly set the height of the status
bar, not that that was doing any harm.
They were set to "1px", which isn't a valid value since they're meant to
be integers. Since they weren't valid, they were ignored. This doesn't
seem to have caused any trouble, so they may as well be removed. In any
case, the canvas is invisible until after its size has been set by
JavaScript.
Specifying the { alpha: false } option when creating a rendering context
tells the browser that we won't use transparency, and the standard
puzzle canvases, along with blitters, are all opaque. No obvious
effect, but the MDN suggests that this should reduce CPU usage.
The one exception here is the resize handle, which actually is
transparent.
By default, CSS uses "object-fit: fill", which means that an object is
independently scaled in both dimensions to fit its containing box.
This is simpler than what I'd assumed (which was "object-fill:
contain"). Obviously, the HTML could be changed to use a different
object-fit, in which case this code would have to detect it, but for
now following the CSS default is more correct than not.
The highlights for covered squares now have a minimum width of 1 pixel,
which means that Mines is comfortably playabale down to about 8 pixel
tilesize, below which the numbers become unreadable.
Each menu item has a -0.5px margin so that the borders of adjacent menu
items overlap, but we don't actually want the menu items to protrude
beyond the containing <ul>. Adding 0.5px of padding to the <ul>
achieves that.
This is so that (given time for caches to expire) I can switch to having
a persistent dialogue box in HTML rather than fabricating it from
scratch in JavaScript each time it's used.
Menu items that open dialogue boxes are now marked with ellipses, while
menu items that lead to submenus have pointing triangles.
The triangles are implemented as SVG files embedded in data: URLs in the
CSS, which is kind of silly but also works really well. There are
suitable characters in Unicode, but some of my test systems don't have
fonts containing them, so maybe the SVG is better.
I expect Escape to exit the menu, and SoftRight should do that as well
for KaiOS. Backspace goes up one level through the menus, again because
that's conventional on KaiOS and not too confusing elsewhere.
In the bubbling phase it managed to catch the "Enter" keypress that
opened a dialogue box from the menu and use it to close the dialogue
box again. I think it's probably reasonable to have it run earlier and
just permanently steal any keypresses it wants.
When we disable a button, it loses focus but doesn't generate a "blur"
event. This means our "focus-within" class goes wrong. Instead of
relying on "blur" events to remove the class, remove it from any
inappropriate elements in the "focus" handler. This requires attaching
the handler to the root element of the document, but I've got plans that
need that anyway.
Old browsers (like KaiOS 2.5) don't have :focus-within, but it's pretty
easy to replace the pseudo-class with a real .focus-within class
maintained by JavaScript event handlers. This is made only marginally
fiddlier by the odd fact that "focus" and "blur" events don't bubble.
Once the input focus is in the menu system (for instance by Shift+Tab
from the puzzle), you can move left and right through the menu bar and
up and down within each menu. Enter selects a menu item. The current
menu item is tracked by giving it the input focus.