2 This is part of the VimFx documentation.
3 Copyright Simon Lydell 2015, 2016.
4 See the file README.md for copying conditions.
9 This file documents VimFx’s [config file] API.
11 Both `config.js` and `frame.js` have access to a variable called `vimfx`. Note
12 that while the variables have the same name, they are different and provide
13 different API methods.
18 In `config.js`, the following API is available as the variable `vimfx`.
20 ### `vimfx.get(...)`, `vimfx.getDefault(...)` and `vimfx.set(...)`
22 Gets or sets the (default) value of a VimFx pref.
24 You can see all prefs in [defaults.coffee], or by opening [about:config] and
25 filtering by `extensions.vimfx`. Note that you can also access the [special
26 options], which may not be accessed in [about:config], using `vimfx.get(...)`
27 and `vimfx.set(...)`—in fact, this is the _only_ way of accessing those options.
29 #### `vimfx.get(pref)`
31 Gets the value of the VimFx pref `pref`.
34 // Get the value of the Hint chars option:
35 vimfx.get('hint_chars')
36 // Get all keyboard shortcuts (as a string) for the `f` command:
37 vimfx.get('mode.normal.follow')
40 #### `vimfx.getDefault(pref)`
42 Gets the default value of the VimFx pref `pref`.
44 Useful when you wish to extend a default, rather than replacing it. See below.
46 #### `vimfx.set(pref, value)`
48 Sets the value of the VimFx pref `pref` to `value`.
51 // Set the value of the Hint chars option:
52 vimfx.set('hint_chars', 'abcdefghijklmnopqrstuvwxyz')
53 // Add yet a keyboard shortcut for the `f` command:
54 vimfx.set('mode.normal.follow', vimfx.getDefault('mode.normal.follow') + ' e')
57 When extending a pref (as in the second example above), be sure to use
58 `vimfx.getDefault` rather than `vimfx.get`. Otherwise you get a multiplying
59 effect. In the above example, after starting Firefox a few times the pref would
60 be `f e e e e`. Also, if you find that example very verbose: Remember that
61 you’re using a programming language! Write a small helper function that suits
64 Note: If you produce conflicting keyboard shortcuts, the order of your code does
65 not matter. The command that comes first in VimFx’s settings page in the Add-ons
66 Manager (and in the Keyboard Shortcuts help dialog) gets the shortcut; the other
67 one(s) do(es) not. See the notes about order in [mode object], [category object]
68 and [command object] for more information about order.
71 // Even though we set the shortcut for focusing the search bar last, the command
72 // for focusing the location bar “wins”, because it comes first in VimFx’s
73 // settings page in the Add-ons Manager.
74 vimfx.set('mode.normal.focus_location_bar', 'ö')
75 vimfx.set('mode.normal.focus_search_bar', 'ö')
77 // Swapping their orders also swaps the “winner”.
78 let {commands} = vimfx.modes.normal
79 ;[commands.focus_location_bar.order, commands.focus_search_bar.order] =
80 [commands.focus_search_bar.order, commands.focus_location_bar.order]
83 ### `vimfx.addCommand(options, fn)`
85 Creates a new command.
89 - name: `String`. The name used when accessing the command via
90 `vimfx.modes[options.mode].commands[options.name]`. It is also used for the
91 pref used to store the shortcuts for the command:
92 `` `custom.mode.${options.mode}.${options.name}` ``.
93 - description: `String`. Shown in the Keyboard Shortcuts help dialog and VimFx’s
94 settings page in the Add-ons Manager.
95 - mode: `String`. Defaults to `'normal'`. The mode to add the command to. The
96 value has to be one of the keys of [`vimfx.modes`].
97 - category: `String`. Defaults to `'misc'` for Normal mode and `''`
98 (uncategorized) otherwise. The category to add the command to. The
99 value has to be one of the keys of [`vimfx.get('categories')`][categories].
100 - order: `Number`. Defaults to putting the command at the end of the category.
101 The first of the default commands has the order `100` and then they increase
102 by `100` per command. This allows to put new commands between two already
105 `fn` is called when the command is activated. See the [onInput] documentation
106 below for more information.
108 <strong id="custom-command-shortcuts">Note</strong> that you have to give the
109 new command a shortcut in VimFx’s settings page in the Add-ons Manager or set
110 one using `vimfx.set(...)` to able to use the new command.
115 description: 'Log Hello World',
117 console.log('Hello World!')
120 vimfx.set('custom.mode.normal.hello', 'gö')
123 ### `vimfx.addOptionOverrides(...)` and `vimfx.addKeyOverrides(...)`
125 These methods take any number of arguments. Each argument is a rule. The rules
126 are added in order. The methods may be run multiple times.
128 A rule is an `Array` of length 2:
130 1. The first item is a function that returns `true` if the rule should be
131 applied and `false` if not. This is called the matching function.
132 2. The second item is the value that should be used if the rule is applied. This
133 is called the override.
135 The rules are tried in the same order they were added. When a matching rule is
136 found it is applied. No more rules will be applied.
138 #### `vimfx.addOptionOverrides(...rules)`
140 The rules are matched any time the value of a VimFx pref is needed.
142 The matching function receives a [location object].
144 The override is an object whose keys are VimFx pref names and whose values
145 override the pref in question. The values should be formatted as in an [options
149 vimfx.addOptionOverrides(
150 [ ({hostname, pathname, hash}) =>
151 `${hostname}${pathname}${hash}` === 'google.com/',
152 {prevent_autofocus: false}
157 #### `vimfx.addKeyOverrides(...rules)`
159 The rules are matched any time you press a key that is not part of the tail of a
162 The matching function receives a [location object] as well as the current
163 mode name (one of the keys of [`vimfx.modes`]).
165 The override is an array of keys which should not activate VimFx commands but be
168 This allows to disable commands on specific sites. To _add_ commands on specific
169 sites, add them globally and then disable them on all _other_ sites.
172 vimfx.addKeyOverrides(
173 [ location => location.hostname === 'facebook.com',
179 ### `vimfx.send(vim, message, data = null, callback = null)`
181 Send `message` (a string) to the instance of `frame.js` in the tab managed by
182 [`vim`][vim object], and pass it `data`. If provided, `callback` must be a
183 function that takes a single argument, which is the data that `frame.js`
184 responds with. `frame.js` uses its [`vimfx.listen(...)`] method to listen for
185 (and optionally respond to) `message`.
191 // You get a `vim` instance by using `vimfx.addCommand(...)` or `vimfx.on(...)`.
192 vimfx.send(vim, 'getSelection', {example: 5}, selection => {
193 console.log('Currently selected text:', selection)
199 vimfx.listen('getSelection', ({example}, callback) => {
200 console.log('`example` should be 5:', example)
201 let selection = content.getSelection().toString()
206 What if you want to do it the other way around: Send a message _from_ `frame.js`
207 and listen for it in `config.js`? That’s not the common use case, so VimFx does
208 not provide convenience functions for it. Yes, `vimfx.send(...)`, and
209 `vimfx.listen(...)` in `frame.js`, are just light wrappers around the standard
210 Firefox [Message Manager] to make it easier to create custom commands that ask
211 `frame.js` for information about the current web page (as in the above example).
212 If you want to send messages any other way, you’ll need to use the Message
213 Manager directly. See [the `shutdown` event] for an example.
215 (While it would have made sense to provide `vim.send(message, data, callback)`
216 instead of `vimfx.send(vim, message, data, callback)`, the latter was chosen for
217 symmetry between `config.js` and `frame.js`. Use `vimfx.send()` to send
218 messages, and `vimfx.listen()` to listen for them.)
220 ### `vimfx.on(eventName, listener)` and `vimfx.off(eventName, listener)`
222 After calling `vimfx.on(eventName, listener)`, `listener(data)` will be called
223 when `eventName` is fired.
225 You may use `vimfx.off(eventName, listener)` if you’d like to remove your
226 added listener for some reason.
228 While [`vimfx.send(...)`] and [`vimfx.listen(...)`] are all about passing
229 messages between `config.js` and `frame.js`, `vimfx.on(...)` is all about doing
230 something whenever VimFx emits internal events.
232 #### The `locationChange` event
234 Occurs when opening a new tab, navigating to a new URL or refreshing the page,
235 causing a full page load. The data passed to listeners is an object with the
236 following properties:
238 - vim: The current [vim object].
239 - location: A [location object].
241 This can be used to enter a different mode by default on some pages (which can
242 be used to replace the blacklist option).
245 vimfx.on('locationChange', ({vim, location}) => {
246 if (location.hostname === 'example.com') {
247 vim.enterMode('ignore')
252 #### The `notification` and `hideNotification` events
254 The `notification` event occurs when `vim.notify(message)` is called, and means
255 that `message` should be displayed to the user.
257 The `hideNotification` event occurs when the `vim.hideNotification()` is called,
258 and means that the current notification is requested to be hidden.
260 The data passed to listeners is an object with the following properties:
262 - vim: The current [vim object].
263 - message: The message that should be notified. Only for the `notification`
266 Both of these events are emitted even if the [`notifications_enabled`] option is
267 disabled, allowing you to display notifications in any way you want.
269 #### The `modeChange` event
271 Occurs whenever the current mode in any tab changes. The initial entering of the
272 default mode in new tabs also counts as a mode change. The data passed to
273 listeners is the current [vim object].
276 vimfx.on('modeChange', vim => {
277 let mode = vimfx.modes[vim.mode].name
278 vim.notify(`Entering mode: ${mode}`)
282 #### The `TabSelect` event
284 Occurs whenever any tab in any window is selected. This is also fired when
285 Firefox starts for the currently selected tab. The data passed to listeners is
286 the `event` object passed to the standard Firefox [TabSelect] event.
288 #### The `modeDisplayChange` event
290 This is basically a combination of the `modeChange` and the `TabSelect` events.
291 The event is useful for knowing when to update UI showing the current mode. The
292 data passed to listeners is the current [vim object].
294 (VimFx itself uses this event to update the toolbar [button], by setting
295 `#main-window[vimfx-mode]` to the current mode. You may use this with custom
298 #### The `focusTypeChange` event
300 Occurs when focusing or blurring any element. The data passed to listeners is an
301 object with the following properties:
303 - vim: The current [vim object].
304 - focusType: A string similar to `match.focus` of a [match object], with the
305 following differences:
307 - The current pressed key is _not_ taken into account, because focus and blur
308 events have no current key.
309 - The value is never `null` or `'other'`, but `'none'` instead.
311 (VimFx itself uses this event to update the toolbar [button], by setting
312 `#main-window[vimfx-focus-type]` to the current focus type. You may use this
313 with custom [styling].)
315 #### The `shutdown` event
319 - VimFx shuts down: When Firefox shuts down, when VimFx is disabled or when
321 - When the config file is reloaded using the `zr` command.
323 If you care about that things you do in `config.js` and `frame.js` are undone
324 when any of the above happens, read on.
326 If all you do is using the methods of the `vimfx` object, you shouldn’t need to
327 care about this event.
329 The following methods don’t need any undoing:
332 - `vimfx.getDefault(...)`
336 The following methods are automatically undone when the `shutdown` event fires.
337 This means that if you, for example, add a custom command in `config.js` but
338 then remove it from `config.js` and hit `zr`, the custom command will be gone in
342 - `vimfx.addCommand(...)`
343 - `vimfx.addOptionOverrides(...)`
344 - `vimfx.addKeyOverrides(...)`
347 The following require manual undoing:
349 - `vimfx.mode`. Any changes you do here must be manually undone.
351 If you add event listeners in `frame.js`, here’s an example of how to remove
356 vimfx.on('shutdown', () => {
357 Components.classes['@mozilla.org/globalmessagemanager;1']
358 .getService(Components.interfaces.nsIMessageListenerManager)
359 // Send this message to _all_ frame scripts.
360 .broadcastAsyncMessage('VimFx-config:shutdown')
367 function listen(eventName, listener) {
368 addEventListener(eventName, listener, true)
369 listeners.push([eventName, listener])
372 listen('focus', event => {
373 console.log('focused element', event.target)
376 addMessageListener('VimFx-config:shutdown', () => {
377 listeners.forEach(([eventName, listener]) => {
378 removeMessageListener(eventName, listener, true)
385 An object whose keys are mode names and whose values are [mode object]s.
387 This is a very low-level part of the API. It allows to:
389 - Access all commands and run them. This is the most common thing that a config
390 file user needs it for.
393 let {commands} = vimfx.modes.normal
394 // Inside a custom command:
395 commands.tab_new.run(args)
398 - Adding new commands. It is recommended to use the `vimfx.addCommand(...)`
399 helper instead. It’s easier.
402 vimfx.modes.normal.commands.new_command = {
403 pref: 'extensions.my_extension.mode.normal.new_command',
406 description: translate('mode.normal.new_command'),
407 run: args => console.log('New command! args:', args)
411 - Adding new modes. This is the most advanced customization you can do to VimFx.
412 Expect having to read VimFx’s source code to figure it all out.
415 vimfx.modes.new_mode = {
416 name: translate('mode.new_mode'),
421 onInput(args, match) {
422 if (match.type === 'full') {
423 match.command.run(args)
425 return (match.type !== 'none')
430 Have a look at [modes.coffee] and [commands.coffee] for more information.
432 ### `vimfx.get('categories')`
434 An object whose keys are category names and whose values are [category object]s.
437 let categories = vimfx.get('categories')
439 // Add a new category.
440 categories.custom = {
441 name: 'Custom commands',
445 // Swap the order of the Location and Tabs categories.
446 ;[commands.focus_location_bar.order, categories.tabs.order] =
447 [categories.tabs.order, commands.focus_location_bar.order]
452 A mode is an object with the following properties:
454 - name: `String`. A human readable name of the mode used in the Keyboard
455 Shortcuts help dialog and VimFx’s settings page in the Add-ons Manager. Config
456 file users adding custom modes could simply use a hard-coded string; extension
457 authors are encouraged to look up the name from a locale file.
458 - order: `Number`. The first of the default modes has the order `100` and then
459 they increase by `100` per mode. This allows to put new modes between two
460 already existing ones.
461 - commands: `Object`. The keys are command names and the values are [command
463 - onEnter(data, ...args): `Function`. Called when the mode is entered.
464 - onLeave(data): `Function`. Called when the mode is left.
465 - onInput(data, match): `Function`. Called when a key is pressed.
467 #### onEnter, onLeave and onInput
469 These methods are called with an object (called `data` above) with the following
472 - vim: The current [vim object].
473 - storage: An object unique to the current [vim object] and to the current mode.
474 Allows to share things between commands of the same mode by getting and
479 This method is called with an object as mentioned above, and after that there
480 may be any number of arguments (`args` in `vim.enterMode(modeName, ...args)`)
481 that the mode is free to do whatever it wants with.
483 Whatever is returned from `onEnter` will be returned from
484 `vim.enterMode(modeName, ...args)`.
488 The object passed to this method (see above) also has the following properties:
490 - uiEvent: `Event` or `false`. The keydown event object if the event occurred in
491 the browser UI, `false` otherwise (if the event occurred in web page content).
492 - count: `Number`. The count for the command. `undefined` if no count. (This is
493 simply a copy of `match.count`. `match` is defined below.)
495 The above object should be passed to commands when running them. The mode is
496 free to do whatever it wants with the return value (if any) of the commands it
499 It also receives a [match object] as the second argument.
501 `onInput` should return `true` if the current keypress should not be passed on
502 to the browser and web pages, and `false` otherwise.
506 A category is an object with the following properties:
508 - name: `String`. A human readable name of the category used in the Keyboard
509 Shortcuts help dialog and VimFx’s settings page in the Add-ons Manager. Config
510 file users adding custom categories could simply a use hard-coded string;
511 extension authors are encouraged to look up the name from a locale file.
512 - order: `Number`. The first of the default categories is the “uncategorized”
513 category. It has the order `100` and then they increase by `100` per category.
514 This allows to put new categories between two already existing ones.
518 A command is an object with the following properties:
520 - pref: `String`. The pref used to store the shortcuts for the command.
521 - run(args): `Function`. Called when the command is activated.
522 - description: `String`. A description of the command, shown in the Keyboard
523 Shortcuts help dialog and VimFx’s settings page in the Add-ons Manager. Config
524 file users adding custom commands could simply use a hard-coded string;
525 extension authors are encouraged to look up the name from a locale file.
526 - category: `String`. The category to add the command to. The value has to be
527 one of the keys of [`vimfx.get('categories')`][categories].
528 - order: `Number`. The first of the default commands has the order `100` and
529 then they increase by `100` per command. This allows to put new commands
530 between two already existing ones.
534 A `match` object has the following properties:
536 - type: `String`. It has one of the following values:
538 - `'full'`: The current keypress, together with previous keypresses, fully
539 matches a command shortcut.
540 - `'partial'`: The current keypress, together with previous keypresses,
541 partially matches a command shortcut.
542 - `'count'`: The current keypress is not part of a command shortcut, but is a
543 digit and contributes to the count of a future matched command.
544 - `'none'`: The current keypress is not part of a command shortcut and does
545 not contribute to a count.
547 - focus: `String` or `null`. The type of currently focused _element_ plus
548 current pressed _key_ combo. You might not want to run commands and suppress
549 the event if this value is anything other than null. It has one of the
550 following values, depending on what kind of _element_ is focused and which
553 - `'editable'`: element: some kind of text input, a `<select>` element or a
554 “contenteditable” element. key: any pressed key.
555 - `'activatable'`: element: an “activatable” element (link or button).
556 key: see the [`activatable_element_keys`] option.
557 - `'adjustable'`: element: an “adjustable” element (form control or video
558 player). key: see the [`adjustable_element_keys`] option.
559 - `'other'`: element: some other kind of element that can receive keystrokes.
560 key: any pressed key.
562 If none of the above criteria is met, the value is `null`, which means that
563 the currently focused element does not appear to respond to keystrokes in any
566 - command: `null` unless `type` is `'full'`. Then it is the matched command (a
569 The matched command should usually be run at this point. It is suitable to
570 pass on the object passed to [onInput] to the command. Some modes might choose
571 to add extra properties to the object first. (That is favored over passing
572 several arguments, since it makes it easier for the command to in turn pass
573 the same data it got on to another command, if needed.)
575 Usually the return value of the command isn’t used, but that’s up to the mode.
577 - count: `Number`. The count for the command. `undefined` if no count.
579 - specialKeys: `Object`. The keys may be any of the following:
584 If a key exists, its value is always `true`. The keys that exist indicate the
585 [special keys] for the sequence used for the matched command (if any).
587 - keyStr: `String`. The current keypress represented as a string.
589 - unmodifiedKey: `String`. `keyStr` without modifiers.
591 - toplevel: `Boolean`. Whether or not the match was a toplevel match in the
592 shortcut key tree. This is `true` unless the match is part of the tail of a
595 - discard(): `Function`. Discards keys pressed so far: If `type` is `'partial'`
596 or `'count'`. For example, if you have typed `12g`, run `match.discard()` and
597 then press `$`, the `$` command will be run instead of `12g$`.
601 There is one `vim` object per tab.
603 A `vim` object has the following properties:
605 - window: [`Window`]. The current Firefox window object. Most commands
606 interacting with Firefox’s UI use this.
608 - browser: [`Browser`]. The `browser` that this vim object handles.
610 - options: `Object`. Provides access to all of VimFx’s options. It is an
613 - mode: `String`. The current mode name.
615 - enterMode(modeName, ...args): `Function`. Enter mode `modeName`, passing
616 `...args` to the mode. It is up to every mode to do whatever it wants to with
617 `...args`. If `modeName` was already the current mode, nothing is done and
618 `undefined` is returned. Otherwise it us up to the mode to return whatever it
621 - isUIEvent(event): `Function`. Returns `true` if `event` occurred in the
622 browser UI, and `false` otherwise (if it occurred in web page content).
624 - notify(message): `Function`. Display a notification with the text `message`.
626 - hideNotification(): `Function`. Hide the current notification (if any).
628 - markPageInteraction(value=true): `Function`. When `value` is `true` (as it is
629 by default when the argument is omitted), marks that the user has interacted
630 with the page. After that [autofocus prevention] is not done anymore. Commands
631 interacting with web page content might want to do this. If `value` is
632 `false`, the state is reset and autofocus prevention _will_ be done again.
634 **Warning:** There are also properties starting with an underscore on `vim`
635 objects. They are private, and not supposed to be used outside of VimFx’s own
636 source code. They may change at any time.
640 An `options` object provides access to all of VimFx’s options. It is an object
641 whose keys are VimFx pref names.
643 Note that the values are not just simply `vimfx.get(pref)` for the `pref` in
644 question; they are _parsed_ (`parse(vimfx.get(pref))`):
646 - Space-separated prefs are parsed into arrays of strings.
648 - `black_list` and `{prev,next}_patterns` are parsed into arrays of regular
651 (See [parse-prefs.coffee] for all details.)
653 Any [option overrides] are automatically taken into account when getting an
656 The [special options] are also available on this object.
661 A location object is very similar to [`window.location`] in web pages.
662 Technically, it is a [`URL`] instance. You can experiment with the current
663 location object by opening the [web console] and entering `location`.
668 In `frame.js`, the following API is available as the variable `vimfx`.
670 ### `vimfx.listen(message, listener)`
672 Listen for `message` (a string) from `config.js`. `listener` will be called with
673 the data sent from `config.js` (if any), and optionally a callback function if
674 `config.js` wants you to respond. If so, call the callback function, optionally
675 with some data to send back to `config.js.` `config.js` uses its
676 [`vimfx.send(...)`] method to send `message` (and optionally some data along
679 See the [`vimfx.send(...)`] method in `config.js` for more information and
682 ### `vimfx.setHintMatcher(hintMatcher)`
684 `hintMatcher` is a function that lets you customize which elements do and don’t
685 get hints. It might help to read about [the `f` commands] first.
687 If you call `vimfx.setHintMatcher(hintMatcher)` more than once, only the
688 `hintMatcher` provided the last time will be used.
691 vimfx.setHintMatcher((id, element, {type, semantic}) => {
692 // Inspect `element` and change `type` and `semantic` if needed.
693 return {type, semantic}
697 The arguments passed to the `hintMatcher` function are:
699 - id: `String`. A string identifying which command is used:
701 - `'normal'`: `f` or `af`.
702 - `'tab'`: `F`, `gf` or `gF`.
706 - element: `Element`. One out of all elements currently inside the viewport.
708 - info: `Object`. It has the following properties:
710 - type: `String` or `null`. If a string, it means that `element` should get a
711 hint. If `null`, it won’t. See the available strings below. When a marker
712 is matched, `type` decides what happens to `element`.
713 - semantic: `Boolean`. Indicates whether or not the element is “semantic.”
714 Semantic elements get better hints.
716 This object contains information on how VimFx has matched `element`. You have
717 the opportunity to change this.
719 The available type strings depend on `id`:
723 - link: A “proper” link (not used as a button with the help of JavaScript),
724 with an `href` attribute.
725 - text: An element that can you can type in, such as text inputs.
726 - clickable: Some clickable element not falling into another category.
727 - clickable-special: Like “clickable,” but uses a different technique to
728 simulate a click on the element. If “clickable” doesn’t work, try this one.
729 - scrollable: A scrollable element.
733 - link: Like “link” when `id` is “normal” (see above).
737 - link: Like “link” when `id` is “normal” (see above).
738 - text: Like “text” when `id` is “normal” (see above), except that in this
739 case “contenteditable” elements are not included.
740 - contenteditable: Elements with “contenteditable” turned on.
744 - focusable: Any focusable element not falling into another category.
745 - scrollable: Like “scrollable” when `id` is “normal” (see above).
747 The function must return an object like the `info` parameter (with the `type`
748 and `semantic` properties).
753 The API is currently **experimental** and therefore **unstable.** Things might
754 break with new VimFx versions. However, no breaking changes are planned, and
755 will be avoided if feasible.
757 As soon as VimFx 1.0.0 (which does not seem to be too far away) is released
758 backwards compatibility will be a priority and won’t be broken until VimFx
761 [option overrides]: #vimfxaddoptionoverridesrules
762 [`vimfx.send(...)`]: #vimfxsendvim-message-data--null-callback--null
763 [`vimfx.listen(...)`]: #vimfxlistenmessage-listener
764 [categories]: #vimfxgetcategories
765 [`vimfx.modes`]: #vimfxmodes
767 [mode object]: #mode-object
768 [category object]: #category-object
769 [command object]: #command-object
770 [match object]: #match-object
771 [vim object]: #vim-object
772 [options object]: #options-object
773 [location object]: #location-object
774 [the `shutdown` event]: #the-shutdown-event
776 [blacklisted]: options.md#blacklist
777 [special options]: options.md#special-options
778 [config file]: config-file.md
779 [bootstrap.js]: config-file.md#bootstrapjs
780 [autofocus prevention]: options.md#prevent-autofocus
781 [`activatable_element_keys`]: options.md#activatable_element_keys
782 [`adjustable_element_keys`]: options.md#adjustable_element_keys
783 [`notifications_enabled`]: options.md#notifications_enabled
786 [the `f` commands]: commands.md#the-f-commands--hints-mode
787 [special keys]: shortcuts.md#special-keys
788 [styling]: styling.md
790 [defaults.coffee]: ../extension/lib/defaults.coffee
791 [parse-prefs.coffee]: ../extension/lib/parse-prefs.coffee
792 [modes.coffee]: ../extension/lib/modes.coffee
793 [commands.coffee]: ../extension/lib/commands.coffee
794 [vim.coffee]: ../extension/lib/vim.coffee
796 [`Window`]: https://developer.mozilla.org/en-US/docs/Web/API/Window
797 [`Browser`]: https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/browser
798 [`window.location`]: https://developer.mozilla.org/en-US/docs/Web/API/Location
799 [`URL`]: https://developer.mozilla.org/en-US/docs/Web/API/URL
800 [Message Manager]: https://developer.mozilla.org/en-US/Firefox/Multiprocess_Firefox/Message_Manager
801 [TabSelect]: https://developer.mozilla.org/en-US/docs/Web/Events/TabSelect
802 [web console]: https://developer.mozilla.org/en-US/docs/Tools/Web_Console
803 [about:config]: http://kb.mozillazine.org/About:config