Keyboard Shortcuts in Spine
Gmail has them. Github has them. Now your Spine app can have them (if it doesn’t already).
For repetitive tasks, keyboard shortcuts are a perfect medium for introducing efficiencies into an application. It’s a small feature with a lot of impact.
Keymaster
For this exercise, we’ll be using Thomas Fuchs’ Keymaster library. You’ll want to download it and drop it into vendor/assets/javascripts/
and include it in your manifest.
# application.js
//= require jquery
//= require jquery-ui
//= require keymaster
//= require app
//= require_tree .
Defining shortcuts is effortless and as simple as passing a shortcut key and function to the key
method exposed by keymaster. From the README:
// define short of 'a'
key('a', function(){ alert('you pressed a!') });
Keymaster + Spine
Here’s where the magic happens. You’ll be adding some code to your controllers and adding a new class to extend from those controllers.
Spine controllers have a shortcut for adding event listeners to DOM elements using the events
property.
events:
"click .close": "closeModal"
"click .item": "expandItem"
Keyboard shortcuts are nothing more than keyup
or keydown
events. Mimic this pattern and add a shortcuts
property using the syntax {"shortcutKey": "functionName"}
to your controller.
shortcuts:
"esc": "closeModal"
"enter": "expandItem"
"⌘+s": "save"
Great! You’ve added a property to declare which function should get called when a certain key or key combination is pressed. The next step is to pass our shortcuts
to keymaster to set up the key bindings.
To do that, create a file in app/assets/javascripts/app/lib/shortcuts.js.coffee
that looks like the following:
class Spine.Shortcuts
@extended: (klass) ->
instanceMethods =
delegateShortcuts: ->
for shortcut, callback of @shortcuts
match = shortcut.match(@eventSplitter)
shortcutKey = match[1]
scope = if match[2] == "" then "all" else match[2]
key(shortcutKey, scope, @proxy(@[callback]))
setScope: (scope) ->
key.setScope(scope)
@include instanceMethods
old_init = @::init
@::init = ->
old_init?()
@delegateShortcuts()
This class iterates through the shortcuts
object and passes the keyboard key and the function to keymaster, albeit in a roundabout way by hooking into the initialization process and calling the delegateShortcuts()
function to ensure the correct context.
From here, extend Spine.Shortcuts
in the controllers where you’ve added shortcuts
. It should look something like this:
class App.Items.ItemController extends Spine.Controller
@extend Spine.Events
@extend Spine.Shortcuts
Fire up your app and behold the power of keyboard shortcuts. Though, the hard part might be presenting these shortcuts to your users.
Comments
Simliar project i just created for Backbone.js: https://github.com/bry4n/backbone-shortcuts
Thanks so much! Exactly what I was looking for.