loading...
Cover image for A few sneak peeks into Hey.com technology (II - Keyboard shortcuts)

A few sneak peeks into Hey.com technology (II - Keyboard shortcuts)

borama profile image Matouš Borák Updated on ・5 min read

A few sneak peeks into Hey.com technology (7 Part Series)

1) A few sneak peeks into Hey.com technology (I - Intro) 2) A few sneak peeks into Hey.com technology (II - Keyboard shortcuts) 3 ... 5 3) A few sneak peeks into Hey.com technology (III - Turbolinks frames) 4) A few sneak peeks into Hey.com technology (IV - Turbolinks frames continued) 5) A few sneak peeks into Hey.com technology (V - Stimulus enhancements) 6) A few sneak peeks into Hey.com technology (VI - Template page updates) 7) A few sneak peeks into Hey.com technology (VII - Template page updates continued)

Let’s start with a nice little feature of Hey, the keyboard shortcuts. Every Hey page has a few shortcuts defined that allow you to do the common tasks without ever touching your mouse. You can learn the keystrokes from a listing that will pop up by pressing "?" or clicking the little keyboard icon in the bottom-right corner of each page.

Hey keyboard shortcuts popup menu

Basically, there are two types of shortcuts in Hey: one will just take your browser to another page (as if you clicked a regular <a href="..."> link), the other one will trigger some custom JavaScript action, making the current page interactive.

OK, how do they work? Let’s dive into the source code!

Page transition shortcuts

When we open the Page inspector on the Imbox page (which, as we know, is not a typo), we’ll find several <a> tags that seem to be relevant for keyboard shortcuts, right near the top of the HTML body.

Page transition shortcuts

Let’s dissect one of them. As you can see, it’s just a normal HTML link, nothing special:

<a data-controller="hotkey" data-hotkey="2" href="/feedbox" hidden="hidden">
  The Feed
</a>
  • It has its URL (href) that leads to the Feedbox page.
  • It also has a content, “The feed”, but it’s not shown on the page because of the hidden attribute. This is a global attribute serving just this particular purpose - including things in the DOM but not showing them. Thus, the tag sits silently in the page, unseen.
  • Now, the data-controller attribute is important and is probably familiar to anyone dealing with recent versions of Rails: it’s a pointer to the corresponding Stimulus controller and the value suggests that this controller has something to do with hotkeys.
  • Finally, the data-hotkey attribute must be the particular key stroke definition of this keyboard shortcut, meaning that pressing the "2" key will load the Feedbox page.

BTW, I find it notable that even if we don’t have a clue how these link internals are wired together, these little tags, these single lines of HTML code still state their purpose very well. They define the shortcuts and it’s immediately obvious what key leads to what page! This is the cleanness and focus on readability that I like about Rails. In a Rails template, you would write such link somehow like this (or, even better, you would create a hotkey_link helper method):

link_to "The feed", "/feebox", data: { controller: "hotkey", hotkey: "2" }, 
                               hidden: true

To further understand how the hotkey link works, we have to say something about Stimulus. It is a small and highly opinionated JavaScript framework that allows you to get rid of JS “sprinkles” in the templates, move all JS code out to separate “controller” files and link them to the page in a very clean and readable way - via HTML attributes. If you haven’t met Stimulus yet, give it a few minutes and read through the Stimulus Handbook and you’ll grasp everything needed to go on here.

The data-controller link attribute directs us to the "hotkey" Stimulus controller. Let’s have a look at it then! We’ll switch to the Debugger tab in the Developer tools and expand the Webpack ⟶ app/javascriptcontrollers path to find and open the hotkey_controller.js:

The hotkey_controller code

We won’t pretend to understand everything but one thing jumps out right away: the code imports two functions, install and uninstall, from the @github/hotkey library and …there is even a link to it in the comment… so let’s peek in:

Github hotkey library

And voilá! The Github library obviously does all the low-level hardcore stuff that is needed to set up a hotkey on a page. All it needs is an element on the page with a data-hotkey attribute and when someone presses the given key, it virtually clicks the element. Given that our element is an <a> tag, clicking it will simply visit the target page from the href attribute.

For all this to work, you need to call the install method from the library, giving the to-be-clicked element as an argument. That is precisely what is being done in the connect method of the Stimulus controller. The connect method is called whenever the corresponding HTML element (the <a> tag in our case) is added to the DOM, i.e. just after loading the web page.

I think the life cycle of a page keyboard shortcut is complete now:

  • Installing the shortcut:

    • As the page loads, the Stimulus framework finds the data-controller attribute in the “hotkey links”.
    • Stimulus creates a new instance of the hotkey_controller and calls its initialize and connect methods.
    • The connect method calls the install method from the Github hotkey library which will actually add the proper low level JS event handler for the key press.
  • When the key is pressed:

    • The low-level (keydown) event is triggered by the browser.
    • This is caught by the Github library event handler.
    • This handler virtually “clicks” the original element, i.e. the "hotkey" link.
    • The browser visits the URL in the link.

 Generic action shortcuts

What if we wanted to call a custom JS function instead of visiting a page upon our hotkey press? Firstly, we probably should not use an <a> element for our hotkey definition, so that the browser won’t try to visit another page upon “clicking” it.

Next, we can use the Stimulus convention to tell the browser what action to call upon the click event in our element.

We can find an example in the Hey source code:

Hotkey definition with custom JS action

This time it’s a button element and it has only one particular difference from the "hotkey link": it defines the data-action attribute:

<button ... data-action="bulk-actions#select">...</button>

This is a short form of an expression which has the following equivalent meaning:

<button ... data-action="click->bulk-actions#select">...</button>

In the Stimulus convention, the data-action attribute tells the Stimulus framework to watch for the JS event given before the -> and when the event triggers, call the Stimulus controller action given after the ->. If the event name is not specified, it defaults to the click event for the button element.

Thus, in our case the select action from the bulk_actions_controller.js will be called upon "clicking" this hidden button, i.e. upon pressing the "x" key on your keyboard. Neat, isn’t it?

Summary

With the convenient usage of the Github hotkeys library, the web page code can be kept very clean and concise. And it is the Stimulus framework that makes the code very flexible, without cluttering the HTML page code itself. The HTML page stays short and clean and the JS code is bundled elsewhere and nicely cached. The Stimulus convention makes the whole process readable and predictable which is always a good thing!

Thanks for reading, stay tuned for more Hey tech goodness! Next time I’ll dig into a great new feature − automatic updating of custom page areas from the server!

A few sneak peeks into Hey.com technology (7 Part Series)

1) A few sneak peeks into Hey.com technology (I - Intro) 2) A few sneak peeks into Hey.com technology (II - Keyboard shortcuts) 3 ... 5 3) A few sneak peeks into Hey.com technology (III - Turbolinks frames) 4) A few sneak peeks into Hey.com technology (IV - Turbolinks frames continued) 5) A few sneak peeks into Hey.com technology (V - Stimulus enhancements) 6) A few sneak peeks into Hey.com technology (VI - Template page updates) 7) A few sneak peeks into Hey.com technology (VII - Template page updates continued)

Posted on Jun 19 by:

borama profile

Matouš Borák

@borama

CTO at NejRemeslnici, Ruby on Rails developer. Dad of two.

Discussion

markdown guide