Table of contents
- Getting started
- Mapping
- Keyboard layout
- Contexts
- Custom contexts
- Site-specific mappings
- Overloading
- Passing mode
- Events
- Self documenting
A minimal configuration to get started:
const modal = new Modal
modal.enable('Text', 'Command')
modal.map('Command', ['KeyJ'], ({ repeat }) => scroll.down(repeat), 'Scroll down', 'Scroll')
modal.map('Command', ['KeyK'], ({ repeat }) => scroll.up(repeat), 'Scroll up', 'Scroll')
Note: The commands scroll with scroll.js.
Creating and removing mappings boils down to the following commands:
map(context, keys, command, description, label)
unmap(context, keys)
-
context
dictates in what context the mapping will be available. -
keys
is a list of keys representing a chord – a key sequence in which the keys are pressed at the same time.
They are composed of a single key code and optionally, one or multiple modifiers.
See the list of key values for special keys.
Note: Commands are bound to physical keys and displayed with the US layout by default. See the Keyboard layout section for configuration.
command
is the function to evaluate.
The function takes exactly one argument, the keydown
event that triggered the command.
For most commands, this argument can be ignored.
The command can also be an instance of Modal
to allow command chaining.
-
description
is the description of the command. -
label
is the label of the command.
Example – Scroll with scroll.js:
modal.map('Command', ['KeyJ'], ({ repeat }) => scroll.down(repeat), 'Scroll down', 'Scroll')
modal.map('Command', ['KeyK'], ({ repeat }) => scroll.up(repeat), 'Scroll up', 'Scroll')
Example – Display keys with the US layout:
modal.keyMap = {
Backquote: { key: '`', shiftKey: '~' }, Digit1: { key: '1', shiftKey: '!' }, Digit2: { key: '2', shiftKey: '@' }, Digit3: { key: '3', shiftKey: '#' }, Digit4: { key: '4', shiftKey: '$' }, Digit5: { key: '5', shiftKey: '%' }, Digit6: { key: '6', shiftKey: '^' }, Digit7: { key: '7', shiftKey: '&' }, Digit8: { key: '8', shiftKey: '*' }, Digit9: { key: '9', shiftKey: '(' }, Digit0: { key: '0', shiftKey: ')' }, Minus: { key: '-', shiftKey: '_' }, Equal: { key: '=', shiftKey: '+' },
KeyQ: { key: 'q', shiftKey: 'Q' }, KeyW: { key: 'w', shiftKey: 'W' }, KeyE: { key: 'e', shiftKey: 'E' }, KeyR: { key: 'r', shiftKey: 'R' }, KeyT: { key: 't', shiftKey: 'T' }, KeyY: { key: 'y', shiftKey: 'Y' }, KeyU: { key: 'u', shiftKey: 'U' }, KeyI: { key: 'i', shiftKey: 'I' }, KeyO: { key: 'o', shiftKey: 'O' }, KeyP: { key: 'p', shiftKey: 'P' }, BracketLeft: { key: '[', shiftKey: '{' }, BracketRight: { key: ']', shiftKey: '}' }, Backslash: { key: '\\', shiftKey: '|' },
KeyA: { key: 'a', shiftKey: 'A' }, KeyS: { key: 's', shiftKey: 'S' }, KeyD: { key: 'd', shiftKey: 'D' }, KeyF: { key: 'f', shiftKey: 'F' }, KeyG: { key: 'g', shiftKey: 'G' }, KeyH: { key: 'h', shiftKey: 'H' }, KeyJ: { key: 'j', shiftKey: 'J' }, KeyK: { key: 'k', shiftKey: 'K' }, KeyL: { key: 'l', shiftKey: 'L' }, Semicolon: { key: ';', shiftKey: ':' }, Quote: { key: "'", shiftKey: '"' },
KeyZ: { key: 'z', shiftKey: 'Z' }, KeyX: { key: 'x', shiftKey: 'X' }, KeyC: { key: 'c', shiftKey: 'C' }, KeyV: { key: 'v', shiftKey: 'V' }, KeyB: { key: 'b', shiftKey: 'B' }, KeyN: { key: 'n', shiftKey: 'N' }, KeyM: { key: 'm', shiftKey: 'M' }, Comma: { key: ',', shiftKey: '<' }, Period: { key: '.', shiftKey: '>' }, Slash: { key: '/', shiftKey: '?' }
}
modal.js lets you map a key to a command in different contexts:
Command
⇒ Context for entering keyboard commands.Text
⇒ Context for typing.Link
⇒ Context for links.Image
⇒ Context for links.Video
⇒ Context for videos.Document
⇒ Context when selecting the whole document.Page
⇒ Context without filtering.
By default, only Page
is enabled.
enable(...filters)
You can create a vi-like interface with the following configuration:
modal.enable('Text', 'Command')
Custom contexts can be created using filters.
filter(name, filter, parent)
-
name
is the filter name. -
filter
is a function that dictates in what context the mapping will be available.
A third parameter can be passed to inherit a context and its commands.
parent
is the parent context.
Example – Create a context for tables:
modal.filter('Table', () => modal.findParent((element) => element.nodeName === 'TABLE'), 'Command')
Example – Create GitHub-specific mappings:
modal.filter('GitHub', () => location.hostname === 'github.com', 'Command')
modal.filter('GitHub · Notifications', () => location.pathname === '/notifications', 'GitHub')
modal.enable('GitHub · Notifications', 'GitHub', ...)
// GitHub · Notifications – https://github.com/notifications
modal.map('GitHub · Notifications', ['KeyR'], () => document.querySelector('form[action="/notifications/mark"]').submit(), 'Mark all as read', 'GitHub · Notifications')
You can bind different commands to a same key, depending on the context.
Example – Add mappings to yank pages and links with clipboard.js:
modal.map('Document', ['KeyY'], () => Clipboard.copy(location.href), 'Copy page address', 'Clipboard')
modal.map('Link', ['KeyY'], ({ target }) => Clipboard.copy(target.href), 'Copy link address', 'Clipboard')
Pass all keys but Alt + Escape:
const pass = new Modal('Pass')
modal.map('Page', ['Alt', 'Escape'], pass, 'Pass all keys to the page', 'Pass keys')
pass.map('Page', ['Alt', 'Escape'], modal, 'Stop passing keys to the page', 'Pass keys')
Commands can be registered to be executed when certain events arise.
context-change(context)
command(command)
default(event)
start()
stop()
Example – Display the current context:
modal.on('context-change', (context) => {
modal.notify({
id: 'context',
message: context.name
})
})
Finally, you can display all available commands in the current context with the help command.
modal.map('Page', ['F1'], () => modal.help(), 'Show help', 'Help')