npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

keymage

v1.1.3

Published

Javascript keyboard bindings (shortcuts) handler with support for key chords

Downloads

1,507

Readme

keymage.js

Keymage is a small (1.5kb min.gz) library for handling key bindings in JavaScript. It supports nested application scopes, has a simple DSL for defining keys and can handle key chords.

Build Status - or check tests in browser

Features

  • Simple language for defining bindings
  • Key sequences (a-la Emacs chords)
  • Nested scopes
  • Default modifier (defmod key which is command on OS X and control elsewhere)
  • Ability to prevent defaults for whole sequence

Usage

Include keymage.min.js in your page:

<script src="keymage.min.js"></script>

There are no dependencies. It is possible to use library as a simple JS module, as an AMD module or as CommonJS module.

It worth to note that Keymage is on cdnjs which enables you to use it without downloading.

Plus, of course, it's on NPM.

Defining shortcuts

Keymage exposes a single function, keymage:

// bind on 'a'
keymage('a', function() { alert("You pressed 'a'"); });

// returning false prevents default browser reaction (you can always use
// e.preventDefault(), of course)
keymage('ctrl-e', function() { return false; });

// binding on 'defmod' binds on Command key on OS X and on Control key in other
// systems
keymage('defmod-j', function() { alert("I am fired"); });

Handler function receives two arguments: the original event and the context so you can understand what and why was fired.

The context contains those properties:

  • shortcut is a string you've originally provided for binding
  • scope is a scope which is currently active
  • definitionScope is a scope where this shortcut was defined
keymage('alt-c', function(e, ctx) {
    console.log(ctx.shortcut, ctx.scope, ctx.definitionScope);
});

// -> "alt-c", "", ""

Sequences

Keymage supports key sequences:

keymage('ctrl-j k', function() { alert("Nice!"); });

For this to fire you have to first press both ctrl and j, and then k. Here's the catch though: ctrl-j in most browsers means "open downloads". Which will break your sequence obviously.

And while I encourage you to not override browser hotkeys, let's imagine you have to do that. For this, you can pass an option object as last parameter, having 'preventDefault' property set to true:

keymage('ctrl-t ctrl-j k',
        function() { alert("wow"); },
        {preventDefault: true});

This option will prevent default on every key press which looks like a valid part of a bound sequence (including the one triggering your handler). And in this case it's perfectly legitimate - you're overriding ctrl-j in the middle of sequence, so common browser hotkey will still work.

Scopes

Keymage support nested scopes. This means that your application can have few areas where you can gradually have more and more specific shortcuts. It works like this:

// You can skip scope argument if you want global work-always shortcut
keymage('ctrl-j q', function() { alert("Default scope"); });

// This will fire after "keymage.setScope('chat')"
keymage('chat', 'ctrl-j w', function() { alert("Chat scope"); });

// This will fire after "keymage.setScope('chat.input')"
keymage('chat.input', 'ctrl-j e', function() { alert("Chat.input scope"); });

You can control scopes with helpful pushScope and popScope methods. This way your nested view (or whatever is enabling nested scope) doesn't need to know about parent scope:

keymage.pushScope('chat') // scope is 'chat'

keymage.pushScope('input') // scope is 'chat.input'

keymage.popScope() // scope is 'chat'

keymage.pushScope('deep')
keymage.pushScope('deeper') // scope is 'chat.deep.deeper'

// way to jump out of deep scoping
keymage.popScope('chat') // scope is ''

pushScope returns resulting scope and popScope returns topmost scope it removed (so with parameters it's the one you've asked to remove).

Note that calling popScope with name of a scope which is repeated few times will pop topmost one, i.e.:

keymage.setScope('this.scope.is.deep.scope')
keymage.popScope('scope') // scope is 'this'

Options

Last and optional argument to keymage function is an option object. Here is a list of possible options:

  • preventDefault: when true, calls event.preventDefault() on every key press which looks like a part of defined sequence.

  • context: binding handler will be called with provided object as a context.

Unbinding

And if you ever need to unbind a handler, use this:

keymage.unbind('ctrl-j k', your_handler_function);

Also, keymage(...) returns a function, which unbinds this shortcut when called:

var unbinder = keymage('ctrl-j k', your_handler_function);
unbinder();