The Advent Crossword

Last year, at the end of November, I got the idea of making a crossword advent calendar. It works fairly well, because you can make a grid with 24 entries, one for each day of advent, and I have enough friends and family to send a few out and make it worthwhile.

I (well, Liz and I) drew a grid, devised printed out some clues and did some improvised cutting and pasting to make an improvised advent calendar, then sent it out with some Christmas cards. It amused enough people that we thought it would be worth doing again, but it sure was a faff.

So this time I chose a completely different faff: let's try to do it online. And here it is!

How to do it

As you can tell from this site, I'm a bit of a noob, so I was approaching this from first principles. My understanding of the options was as follows: you can draw things on pages by:

  1. moving round bits of HTML
  2. drawing with SVGs, a type of image defined using XML
  3. getting an HTML canvas and drawing bits on it using Javascript

There are also probably hundreds of dialects of the above options using the many many Javascript libraries, the two pre-eminent as of 2017 being Facebook's React and Google's Angular. But on the basis that I thought I could figure out how to do it, I opted for option 3, with a bit of option 1 round the edges. I didn't use any additional libraries available, with the exception of (Scott Hamper's Cookies.js)[https://github.com/ScottHamper/Cookies] for setting and getting cookies.

The nitty gritty

I ran up against the deadline again, but by the week before advent I had something working. The important thing with HTML canvas is to keep the state of the crossword (white squares, black squares, clue numbers, entered letters) readily available, so when anything changes you just draw it all over again. This works well once you've figured out how to represent everything.

The most difficult part is capturing keyboard events in order to pop them in the grid. Regular computer keyboards aren't so bad - you just listen to what's happening using element.addEventListener('keypress', ...) or some such thing, but making this work on a phone is tricky:

  • you need to get the little keyboard up, or no-one's going to be entering anything
  • for some reason, those little keyboards are quite loth to tell you what someone just pressed
  • when you do open one of those little keyboards, the browser tries to jump to the right place. But in this kind of thing, it's gonna try quite hard to be the wrong place

Enter the hacks, just like web development is supposed to have but doesn't have so much any more. What worked for me (more or less) is to have an input field, like on any form, that gets the focus when someone selects a clue. That pops up the keyboard. We don't actually want to see this input, so hide it behind the crossword grid. If we're careful, we can make the browser jump to the right place too. Then, when someone enters a letter, instead of asking what letter was entered, check our hidden input to see what it was. Then get rid of it again.

This works, to a point. If you know what you're looking for, you can sometimes see this little interloper hanging around, and the browser doesn't do an amazing job of jumping to the right place. But it's not so bad, and we've got ourselves a crossword. Give it a go!

p.s. It's a cryptic crossword, so if you don't know what that means it's going to look pretty strange.