]> git.gir.st - VimFx.git/blob - documentation/api.md
Consistently refer to options as "options"
[VimFx.git] / documentation / api.md
1 <!--
2 This is part of the VimFx documentation.
3 Copyright Simon Lydell 2015, 2016.
4 See the file README.md for copying conditions.
5 -->
6
7 # API
8
9 This file documents VimFx’s [config file] API.
10
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.
14
15
16 ## `config.js` API
17
18 In `config.js`, the following API is available as the variable `vimfx`.
19
20 ### `vimfx.get(...)`, `vimfx.getDefault(...)` and `vimfx.set(...)`
21
22 Gets or sets the (default) value of a VimFx option.
23
24 You can see all options 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.
28
29 #### `vimfx.get(option)`
30
31 Gets the value of the VimFx option `option`.
32
33 ```js
34 // Get the value of the Hint characters option:
35 vimfx.get('hints.chars')
36 // Get all keyboard shortcuts (as a string) for the `f` command:
37 vimfx.get('mode.normal.follow')
38 ```
39
40 #### `vimfx.getDefault(option)`
41
42 Gets the default value of the VimFx option `option`.
43
44 Useful when you wish to extend a default, rather than replacing it. See below.
45
46 #### `vimfx.set(option, value)`
47
48 Sets the value of the VimFx option `option` to `value`.
49
50 ```js
51 // Set the value of the Hint characters option:
52 vimfx.set('hints.chars', 'abcdefghijklmnopqrstuvwxyz')
53 // Add yet a keyboard shortcut for the `f` command:
54 vimfx.set('mode.normal.follow', vimfx.getDefault('mode.normal.follow') + ' ee')
55 ```
56
57 When extending an option (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 option
60 would be `f e e e e`. Also, if you find that example very verbose: Remember
61 that you’re using a programming language! Write a small helper function that
62 suits your needs.
63
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 options 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.
69
70 ```js
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 // options page in the Add-ons Manager.
74 vimfx.set('mode.normal.focus_location_bar', 'ö')
75 vimfx.set('mode.normal.focus_search_bar', 'ö')
76
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]
81 ```
82
83 ### `vimfx.addCommand(options, fn)`
84
85 Creates a new command.
86
87 `options`:
88
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 option name (preference key) 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 options 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
103 existing ones.
104
105 `fn` is called when the command is activated. See the [onInput] documentation
106 below for more information.
107
108 <strong id="custom-command-shortcuts">Note</strong> that you have to give the
109 new command a shortcut in VimFx’s options page in the Add-ons Manager or set
110 one using `vimfx.set(...)` to able to use the new command.
111
112 ```js
113 vimfx.addCommand({
114 name: 'hello',
115 description: 'Log Hello World',
116 }, () => {
117 console.log('Hello World!')
118 })
119 // Optional:
120 vimfx.set('custom.mode.normal.hello', 'gö')
121 ```
122
123 ### `vimfx.addOptionOverrides(...)` and `vimfx.addKeyOverrides(...)`
124
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.
127
128 A rule is an `Array` of length 2:
129
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.
134
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.
137
138 #### `vimfx.addOptionOverrides(...rules)`
139
140 The rules are matched any time the value of a VimFx option is needed.
141
142 The matching function receives a [location object].
143
144 The override is an object whose keys are VimFx option names and whose values
145 override the option in question. The values should be formatted as in an
146 [options object].
147
148 ```js
149 vimfx.addOptionOverrides(
150 [ ({hostname, pathname, hash}) =>
151 `${hostname}${pathname}${hash}` === 'google.com/',
152 {prevent_autofocus: false}
153 ]
154 )
155
156 vimfx.addOptionOverrides(
157 [ ({hostname}) => hostname === 'imgur.com',
158 {
159 pattern_attrs: ['class'],
160 pattern_selector: 'div.next-prev .btn',
161 prev_patterns: [/\bnavPrev\b/],
162 next_patterns: [/\bnavNext\b/],
163 }
164 ]
165 )
166 ```
167
168 #### `vimfx.addKeyOverrides(...rules)`
169
170 The rules are matched any time you press a key that is not part of the tail of a
171 multi-key shortcut.
172
173 The matching function receives a [location object] as well as the current
174 mode name (one of the keys of [`vimfx.modes`]).
175
176 The override is an array of keys which should not activate VimFx commands but be
177 sent to the page.
178
179 This allows to disable commands on specific sites. To _add_ commands on specific
180 sites, add them globally and then disable them on all _other_ sites.
181
182 ```js
183 vimfx.addKeyOverrides(
184 [ location => location.hostname === 'facebook.com',
185 ['j', 'k']
186 ]
187 )
188 ```
189
190 ### `vimfx.send(vim, message, data = null, callback = null)`
191
192 Send `message` (a string) to the instance of `frame.js` in the tab managed by
193 [`vim`][vim object], and pass it `data`. If provided, `callback` must be a
194 function that takes a single argument, which is the data that `frame.js`
195 responds with. `frame.js` uses its [`vimfx.listen(...)`] method to listen for
196 (and optionally respond to) `message`.
197
198 Here is an example:
199
200 ```js
201 // config.js
202 // You get a `vim` instance by using `vimfx.addCommand(...)` or `vimfx.on(...)`.
203 vimfx.send(vim, 'getSelection', {example: 5}, selection => {
204 console.log('Currently selected text:', selection)
205 })
206 ```
207
208 ```js
209 // frame.js
210 vimfx.listen('getSelection', ({example}, callback) => {
211 console.log('`example` should be 5:', example)
212 let selection = content.getSelection().toString()
213 callback(selection)
214 })
215 ```
216
217 What if you want to do it the other way around: Send a message _from_ `frame.js`
218 and listen for it in `config.js`? That’s not the common use case, so VimFx does
219 not provide convenience functions for it. Yes, `vimfx.send(...)`, and
220 `vimfx.listen(...)` in `frame.js`, are just light wrappers around the standard
221 Firefox [Message Manager] to make it easier to create custom commands that ask
222 `frame.js` for information about the current web page (as in the above example).
223 If you want to send messages any other way, you’ll need to use the Message
224 Manager directly. See [the `shutdown` event] for an example.
225
226 (While it would have made sense to provide `vim.send(message, data, callback)`
227 instead of `vimfx.send(vim, message, data, callback)`, the latter was chosen for
228 symmetry between `config.js` and `frame.js`. Use `vimfx.send()` to send
229 messages, and `vimfx.listen()` to listen for them.)
230
231 ### `vimfx.on(eventName, listener)` and `vimfx.off(eventName, listener)`
232
233 After calling `vimfx.on(eventName, listener)`, `listener(data)` will be called
234 when `eventName` is fired, where `data` is an object. Which properties `data`
235 has is specific to each event.
236
237 You may use `vimfx.off(eventName, listener)` if you’d like to remove your
238 added listener for some reason.
239
240 While [`vimfx.send(...)`] and [`vimfx.listen(...)`] are all about passing
241 messages between `config.js` and `frame.js`, `vimfx.on(...)` is all about doing
242 something whenever VimFx emits internal events.
243
244 #### The `locationChange` event
245
246 Occurs when opening a new tab, navigating to a new URL or refreshing the page,
247 causing a full page load.
248
249 `data`:
250
251 - vim: The current [vim object].
252 - location: A [location object].
253
254 This event can be used to enter a different mode by default on some pages (which
255 can be used to replace the blacklist option).
256
257 ```js
258 vimfx.on('locationChange', ({vim, location}) => {
259 if (location.hostname === 'example.com') {
260 vimfx.modes.normal.commands.enter_mode_ignore.run({vim, blacklist: true})
261 }
262 })
263 ```
264
265 #### The `notification` and `hideNotification` events
266
267 The `notification` event occurs when `vim.notify(message)` is called, and means
268 that `message` should be displayed to the user.
269
270 The `hideNotification` event occurs when the `vim.hideNotification()` is called,
271 and means that the current notification is requested to be hidden.
272
273 `data`:
274
275 - vim: The current [vim object].
276 - message: The message that should be notified. Only for the `notification`
277 event.
278
279 Both of these events are emitted even if the [`notifications_enabled`] option is
280 disabled, allowing you to display notifications in any way you want.
281
282 #### The `modeChange` event
283
284 Occurs whenever the current mode in any tab changes. The initial entering of the
285 default mode in new tabs also counts as a mode change.
286
287 `data`:
288
289 - vim: The current [vim object].
290
291 ```js
292 vimfx.on('modeChange', ({vim}) => {
293 let mode = vimfx.modes[vim.mode].name
294 vim.notify(`Entering mode: ${mode}`)
295 })
296 ```
297
298 #### The `TabSelect` event
299
300 Occurs whenever any tab in any window is selected. This is also fired when
301 Firefox starts for the currently selected tab.
302
303 `data`:
304
305 - event: The `event` object passed to the standard Firefox [TabSelect] event.
306
307 #### The `modeDisplayChange` event
308
309 This is basically a combination of the `modeChange` and the `TabSelect` events.
310 The event is useful for knowing when to update UI showing the current mode.
311
312 `data`:
313
314 - vim: The current [vim object].
315
316 (VimFx itself uses this event to update the toolbar [button], by setting
317 `#main-window[vimfx-mode]` to the current mode. You may use this with custom
318 [styling].)
319
320 #### The `focusTypeChange` event
321
322 Occurs when focusing or blurring any element. See also the [`blur_timeout`]
323 option.
324
325 `data`:
326
327 - vim: The current [vim object].
328
329 `data.vim.focusType` has been updated just before this event fires.
330
331 (VimFx itself uses this event to update the toolbar [button], by setting
332 `#main-window[vimfx-focus-type]` to the current focus type. You may use this
333 with custom [styling].)
334
335 #### The `shutdown` event
336
337 Occurs when:
338
339 - VimFx shuts down: When Firefox shuts down, when VimFx is disabled or when
340 VimFx is updated.
341 - When the config file is reloaded using the `gC` command.
342
343 `data`: No data at all is passed.
344
345 If you care about that things you do in `config.js` and `frame.js` are undone
346 when any of the above happens, read on.
347
348 If all you do is using the methods of the `vimfx` object, you shouldn’t need to
349 care about this event.
350
351 The following methods don’t need any undoing:
352
353 - `vimfx.get(...)`
354 - `vimfx.getDefault(...)`
355 - `vimfx.send(...)`
356 - `vimfx.off(...)`
357
358 The following methods are automatically undone when the `shutdown` event fires.
359 This means that if you, for example, add a custom command in `config.js` but
360 then remove it from `config.js` and hit `gC`, the custom command will be gone in
361 VimFx.
362
363 - `vimfx.set(...)`
364 - `vimfx.addCommand(...)`
365 - `vimfx.addOptionOverrides(...)`
366 - `vimfx.addKeyOverrides(...)`
367 - `vimfx.on(...)`
368
369 The following require manual undoing:
370
371 - `vimfx.mode`. Any changes you do here must be manually undone.
372
373 If you add event listeners in `frame.js`, here’s an example of how to remove
374 them on `shutdown`:
375
376 ```js
377 // config.js
378 vimfx.on('shutdown', () => {
379 Components.classes['@mozilla.org/globalmessagemanager;1']
380 .getService(Components.interfaces.nsIMessageListenerManager)
381 // Send this message to _all_ frame scripts.
382 .broadcastAsyncMessage('VimFx-config:shutdown')
383 })
384 ```
385
386 ```js
387 // frame.js
388 let listeners = []
389 function listen(eventName, listener) {
390 addEventListener(eventName, listener, true)
391 listeners.push([eventName, listener])
392 }
393
394 listen('focus', event => {
395 console.log('focused element', event.target)
396 })
397
398 addMessageListener('VimFx-config:shutdown', () => {
399 listeners.forEach(([eventName, listener]) => {
400 removeMessageListener(eventName, listener, true)
401 })
402 })
403 ```
404
405 ### `vimfx.modes`
406
407 An object whose keys are mode names and whose values are [mode object]s.
408
409 This is a very low-level part of the API. It allows to:
410
411 - Access all commands and run them. This is the most common thing that a config
412 file user needs it for.
413
414 ```js
415 let {commands} = vimfx.modes.normal
416 // Inside a custom command:
417 commands.tab_new.run(args)
418 ```
419
420 - Adding new commands. It is recommended to use the `vimfx.addCommand(...)`
421 helper instead. It’s easier.
422
423 ```js
424 vimfx.modes.normal.commands.new_command = {
425 pref: 'extensions.my_extension.mode.normal.new_command',
426 category: 'misc',
427 order: 10000,
428 description: translate('mode.normal.new_command'),
429 run: args => console.log('New command! args:', args)
430 }
431 ```
432
433 - Adding new modes. This is the most advanced customization you can do to VimFx.
434 Expect having to read VimFx’s source code to figure it all out.
435
436 ```js
437 vimfx.modes.new_mode = {
438 name: translate('mode.new_mode'),
439 order: 10000,
440 commands: {},
441 onEnter(args) {},
442 onLeave(args) {},
443 onInput(args, match) {
444 if (match.type === 'full') {
445 match.command.run(args)
446 }
447 return (match.type !== 'none')
448 },
449 }
450 ```
451
452 Have a look at [modes.coffee] and [commands.coffee] for more information.
453
454 ### `vimfx.get('categories')`
455
456 An object whose keys are category names and whose values are [category object]s.
457
458 ```js
459 let categories = vimfx.get('categories')
460
461 // Add a new category.
462 categories.custom = {
463 name: 'Custom commands',
464 order: 10000,
465 }
466
467 // Swap the order of the Location and Tabs categories.
468 ;[commands.focus_location_bar.order, categories.tabs.order] =
469 [categories.tabs.order, commands.focus_location_bar.order]
470 ```
471
472 ### Custom hint commands
473
474 Apart from the standard hint commands, you can create your own.
475
476 You may run any VimFx command by using the following pattern:
477
478 ```js
479 // config.js
480 vimfx.addCommand({
481 name: 'run_other_command_example',
482 description: 'Run other command example',
483 }, (args) => {
484 // Replace 'follow' with any command name here:
485 vimfx.modes.normal.commands.follow.run(args)
486 })
487 ```
488
489 All hint commands (except `eb`) also support `args.callbackOverride`:
490
491 ```js
492 // config.js
493 vimfx.addCommand({
494 name: 'custom_hint_command_example',
495 description: 'Custom hint command example',
496 }, (args) => {
497 vimfx.modes.normal.commands.follow.run(Object.assign({}, args, {
498 callbackOverride({type, href, id, timesLeft}) {
499 console.log('Marker data:', {type, href, id, timesLeft})
500 return (timesLeft > 1)
501 },
502 }))
503 })
504 ```
505
506 This lets you piggy-back on one of the existing hint commands by getting the
507 same hints on screen as that command, but then doing something different with
508 the matched hint marker.
509
510 `callbackOverride` is called with an object with the following properties:
511
512 - type: `String`. The type of the element of the matched hint marker. See
513 [`vimfx.setHintMatcher(...)`] for all possible values.
514
515 - href: `String` or `null`. If `type` is `'link'`, then this is the `href`
516 attribute of the element of the matched hint marker.
517
518 - id: An id that you can pass to [`vimfx.getMarkerElement(...)`] to get the
519 element of the matched hint marker.
520
521 - timesLeft: `Number`. Calling a hint command with a count means that you want
522 to run it _count_ times in a row. This number tells how many times there are
523 left to run. If you don’t provide a count, the number is `1`.
524
525 `callbackOverride` should return `true` if you want the hint markers to
526 re-appear on screen after you’ve matched one of them (as in the `af` command),
527 and `false` if you wish to exit Hints mode. If your command ignores counts,
528 simply always return `false`. Otherwise you most likely want to return
529 `timesLeft > 1`.
530
531 Here’s an example which adds a silly command for marking links with
532 color—`http://` links with red and all other links with green.
533
534 ```js
535 // config.js
536 let {commands} = vimfx.modes.normal
537
538 vimfx.addCommand({
539 name: 'mark_link',
540 category: 'browsing',
541 description: 'Mark link with red or green',
542 }, (args) => {
543 let {vim} = args
544 commands.follow_in_tab.run(Object.assign({}, args, {
545 callbackOverride({type, href, id, timesLeft}) {
546 if (href) {
547 let color = href.startsWith('http://') ? 'red' : 'green'
548 vimfx.send(vim, 'highlight_marker_element', {id, color})
549 }
550 return false
551 },
552 }))
553 })
554 ```
555
556 ```js
557 // frame.js
558 vimfx.listen('highlight_marker_element', ({id, color}) => {
559 let element = vimfx.getMarkerElement(id)
560 if (element) {
561 element.style.backgroundColor = color
562 }
563 })
564 ```
565
566 ### Mode object
567
568 A mode is an object with the following properties:
569
570 - name: `String`. A human readable name of the mode used in the Keyboard
571 Shortcuts help dialog and VimFx’s options page in the Add-ons Manager. Config
572 file users adding custom modes could simply use a hard-coded string; extension
573 authors are encouraged to look up the name from a locale file.
574 - order: `Number`. The first of the default modes has the order `100` and then
575 they increase by `100` per mode. This allows to put new modes between two
576 already existing ones.
577 - commands: `Object`. The keys are command names and the values are [command
578 object]s.
579 - onEnter(data, ...args): `Function`. Called when the mode is entered.
580 - onLeave(data): `Function`. Called when the mode is left.
581 - onInput(data, match): `Function`. Called when a key is pressed.
582
583 #### onEnter, onLeave and onInput
584
585 These methods are called with an object (called `data` above) with the following
586 properties:
587
588 - vim: The current [vim object].
589 - storage: An object unique to the current [vim object] and to the current mode.
590 Allows to share things between commands of the same mode by getting and
591 setting keys on it.
592
593 ##### onEnter
594
595 This method is called with an object as mentioned above, and after that there
596 may be any number of arguments that the mode is free to do whatever it wants
597 with.
598
599 ##### onInput
600
601 The object passed to this method (see above) also has the following properties:
602
603 - uiEvent: `Event` or `false`. The keydown event object if the event occurred in
604 the browser UI, `false` otherwise (if the event occurred in web page content).
605 - count: `Number`. The count for the command. `undefined` if no count. (This is
606 simply a copy of `match.count`. `match` is defined below.)
607
608 The above object should be passed to commands when running them. The mode is
609 free to do whatever it wants with the return value (if any) of the commands it
610 runs.
611
612 It also receives a [match object] as the second argument.
613
614 `onInput` should return `true` if the current keypress should not be passed on
615 to the browser and web pages, and `false` otherwise.
616
617 ### Category object
618
619 A category is an object with the following properties:
620
621 - name: `String`. A human readable name of the category used in the Keyboard
622 Shortcuts help dialog and VimFx’s options page in the Add-ons Manager. Config
623 file users adding custom categories could simply a use hard-coded string;
624 extension authors are encouraged to look up the name from a locale file.
625 - order: `Number`. The first of the default categories is the “uncategorized”
626 category. It has the order `100` and then they increase by `100` per category.
627 This allows to put new categories between two already existing ones.
628
629 ### Command object
630
631 A command is an object with the following properties:
632
633 - pref: `String`. The option name (preference key) used to store the shortcuts
634 for the command.
635 - run(args): `Function`. Called when the command is activated.
636 - description: `String`. A description of the command, shown in the Keyboard
637 Shortcuts help dialog and VimFx’s options page in the Add-ons Manager. Config
638 file users adding custom commands could simply use a hard-coded string;
639 extension authors are encouraged to look up the name from a locale file.
640 - category: `String`. The category to add the command to. The value has to be
641 one of the keys of [`vimfx.get('categories')`][categories].
642 - order: `Number`. The first of the default commands has the order `100` and
643 then they increase by `100` per command. This allows to put new commands
644 between two already existing ones.
645
646 ### Match object
647
648 A `match` object has the following properties:
649
650 - type: `String`. It has one of the following values:
651
652 - `'full'`: The current keypress, together with previous keypresses, fully
653 matches a command shortcut.
654 - `'partial'`: The current keypress, together with previous keypresses,
655 partially matches a command shortcut.
656 - `'count'`: The current keypress is not part of a command shortcut, but is a
657 digit and contributes to the count of a future matched command.
658 - `'none'`: The current keypress is not part of a command shortcut and does
659 not contribute to a count.
660
661 - likelyConflict: `Boolean`. This is `true` if the current keypress is likely to
662 cause conflicts with default Firefox behavior of that key, and `false`
663 otherwise. A mode might not want to run commands and suppress the event if
664 this value is `true`. VimFx uses the current keypress and `vim.focusType` of
665 the current [vim object] to decide if the current keypress is a likely
666 conflict:
667
668 1. If the key is part of the tail of a shortcut, it is never a conflict.
669 2. If `vim.focusType` is `'activatable'` or `'adjustable'` and the key is
670 present in [`activatable_element_keys`] or [`adjustable_element_keys`]
671 (respectively), then it is a likely conflict.
672 3. Finally, unless `vim.focusType` is `'none'`, then it is a likely conflict.
673 This most commonly means that a text input is focused.
674
675 Note that any VimFx shortcut starting with a keypress involving a modifier is
676 _very_ likely to conflict with either a Firefox default shortcut or a shortcut
677 from some other add-on. This is _not_ attempted to be detected in any way.
678 Instead, VimFx uses no modifiers in any default Normal mode shortcuts, leaving
679 it up to you to choose modifier-shortcuts that work out for you if you want
680 such shortcuts. In other words, for modifier-shortcuts the point of VimFx _is_
681 to conflict (overriding default shortcuts).
682
683 - command: `null` unless `type` is `'full'`. Then it is the matched command (a
684 [command object]).
685
686 The matched command should usually be run at this point. It is suitable to
687 pass on the object passed to [onInput] to the command. Some modes might choose
688 to add extra properties to the object first. (That is favored over passing
689 several arguments, since it makes it easier for the command to in turn pass
690 the same data it got on to another command, if needed.)
691
692 Usually the return value of the command isn’t used, but that’s up to the mode.
693
694 - count: `Number`. The count for the command. `undefined` if no count.
695
696 - specialKeys: `Object`. The keys may be any of the following:
697
698 - `<force>`
699 - `<late>`
700
701 If a key exists, its value is always `true`. The keys that exist indicate the
702 [special keys] for the sequence used for the matched command (if any).
703
704 - keyStr: `String`. The current keypress represented as a string.
705
706 - unmodifiedKey: `String`. `keyStr` without modifiers.
707
708 - rawKey: `String`. Unchanged [`event.key`].
709
710 - rawCode: `String`. Unchanged [`event.code`].
711
712 - toplevel: `Boolean`. Whether or not the match was a toplevel match in the
713 shortcut key tree. This is `true` unless the match is part of the tail of a
714 multi-key shortcut.
715
716 - discard(): `Function`. Discards keys pressed so far: If `type` is `'partial'`
717 or `'count'`. For example, if you have typed `12g`, run `match.discard()` and
718 then press `$`, the `$` command will be run instead of `12g$`.
719
720 ### Vim object
721
722 There is one `vim` object per tab.
723
724 A `vim` object has the following properties:
725
726 - window: [`Window`]. The current Firefox window object. Most commands
727 interacting with Firefox’s UI use this.
728
729 - browser: [`Browser`]. The `browser` that this vim object handles.
730
731 - options: `Object`. Provides access to all of VimFx’s options. It is an
732 [options object].
733
734 - mode: `String`. The current mode name.
735
736 - focusType: `String`. The type of currently focused element. VimFx decides the
737 type based on how it responds to keystorkes. It has one of the following
738 values:
739
740 - `'ignore'`: Some kind of Vim-style editor. VimFx automatically
741 enters Ignore mode when this focus type is encountered.
742 - `'editable'`: Some kind of text input, a `<select>` element or a
743 “contenteditable” element.
744 - `'activatable'`: An “activatable” element (link or button).
745 (See also the [`activatable_element_keys`] option.)
746 - `'adjustable'`: An “adjustable” element (form control or video
747 player). (See also the [`adjustable_element_keys`] option.)
748 - `'findbar'`: The findbar text input is focused.
749 - `'none'`: The currently focused element does not appear to respond to
750 keystrokes in any special way.
751
752 [The `focusTypeChange` event] is fired whenever `focusType` is updated.
753
754 `match.likelyConflict` of [match object]s depend on `focusType`.
755
756 - isUIEvent(event): `Function`. Returns `true` if `event` occurred in the
757 browser UI, and `false` otherwise (if it occurred in web page content).
758
759 - notify(message): `Function`. Display a notification with the text `message`.
760
761 - hideNotification(): `Function`. Hide the current notification (if any).
762
763 - markPageInteraction(value=true): `Function`. When `value` is `true` (as it is
764 by default when the argument is omitted), marks that the user has interacted
765 with the page. After that [autofocus prevention] is not done anymore. Commands
766 interacting with web page content might want to do this. If `value` is
767 `false`, the state is reset and autofocus prevention _will_ be done again.
768
769 **Warning:** There are also properties starting with an underscore on `vim`
770 objects. They are private, and not supposed to be used outside of VimFx’s own
771 source code. They may change at any time.
772
773 ### Options object
774
775 An `options` object provides access to all of VimFx’s options. It is an object
776 whose keys are VimFx option names.
777
778 Note that the values are not just simply `vimfx.get(option)` for the `option` in
779 question; they are _parsed_ (`parse(vimfx.get(option))`):
780
781 - Space-separated options are parsed into arrays of strings. For example,
782 `pattern_attrs: ['class']`.
783
784 - `blacklist`, `prev_patterns` and `next_patterns` are parsed into arrays of
785 regular expressions. For example, `prev_patterns: [/\bnavPrev\b/]`.
786
787 (See [parse-prefs.coffee] for all details.)
788
789 Any [option overrides] are automatically taken into account when getting an
790 option value.
791
792 The [special options] are also available on this object.
793
794
795 ### Location object
796
797 A location object is very similar to [`window.location`] in web pages.
798 Technically, it is a [`URL`] instance. You can experiment with the current
799 location object by opening the [web console] and entering `location`.
800
801
802 ## `frame.js` API
803
804 In `frame.js`, the following API is available as the variable `vimfx`.
805
806 ### `vimfx.listen(message, listener)`
807
808 Listen for `message` (a string) from `config.js`. `listener` will be called with
809 the data sent from `config.js` (if any), and optionally a callback function if
810 `config.js` wants you to respond. If so, call the callback function, optionally
811 with some data to send back to `config.js.` `config.js` uses its
812 [`vimfx.send(...)`] method to send `message` (and optionally some data along
813 with it).
814
815 See the [`vimfx.send(...)`] method in `config.js` for more information and
816 examples.
817
818 ### `vimfx.setHintMatcher(hintMatcher)`
819
820 `hintMatcher` is a function that lets you customize which elements do and don’t
821 get hints. It might help to read about [the hint commands] first.
822
823 If you call `vimfx.setHintMatcher(hintMatcher)` more than once, only the
824 `hintMatcher` provided the last time will be used.
825
826 ```js
827 vimfx.setHintMatcher((id, element, type) => {
828 // Inspect `element` and return a different `type` if needed.
829 return type
830 })
831 ```
832
833 The arguments passed to the `hintMatcher` function are:
834
835 - id: `String`. A string identifying which command is used:
836
837 - `'normal'`: `f` or `af`.
838 - `'tab'`: `F`, `et`, `ew` or `ep`.
839 - `'copy'`: `yf`.
840 - `'focus'`: `ef`.
841 - `'context'`: `ec`.
842 - `'select'`: `v`, `av` or `yv`.
843
844 - element: `Element`. One out of all elements currently inside the viewport.
845
846 - type: `String` or `null`. If a string, it means that `element` should get a
847 hint. If `null`, it won’t. See the available strings below. When a marker
848 is matched, `type` decides what happens to `element`.
849
850 This parameter tells how VimFx has matched `element`. You have the opportunity
851 to change that.
852
853 The available type strings depend on `id`:
854
855 - normal:
856
857 - link: A “proper” link (not used as a button with the help of JavaScript),
858 with an `href` attribute.
859 - text: An element that can you can type in, such as text inputs.
860 - clickable: Some clickable element not falling into another category.
861 - clickable-special: Like “clickable,” but uses a different technique to
862 simulate a click on the element. If “clickable” doesn’t work, try this one.
863 - scrollable: A scrollable element.
864
865 - tab:
866
867 - link: Like “link” when `id` is “normal” (see above).
868
869 - copy:
870
871 - link: Like “link” when `id` is “normal” (see above).
872 - text: Like “text” when `id` is “normal” (see above), except that in this
873 case “contenteditable” elements are not included.
874 - contenteditable: Elements with “contenteditable” turned on.
875
876 - focus:
877
878 - focusable: Any focusable element not falling into another category.
879 - scrollable: Like “scrollable” when `id` is “normal” (see above).
880
881 - context:
882
883 - context: An element that can have a context menu opened.
884
885 - select:
886
887 - selectable: An element with selectable text (but not text inputs).
888
889 The function must return `null` or a string like the `type` parameter.
890
891 ### `vimfx.getMarkerElement(id)`
892
893 Takes an id that has been given to you when creating [custom hint commands] and
894 returns the DOM element associated with that id. If no element can be found,
895 `null` is returned.
896
897
898 ## Stability
899
900 The API is currently **experimental** and therefore **unstable.** Things might
901 break with new VimFx versions. However, no breaking changes are planned, and
902 will be avoided if feasible.
903
904 As soon as VimFx 1.0.0 (which does not seem to be too far away) is released
905 backwards compatibility will be a priority and won’t be broken until VimFx
906 2.0.0.
907
908 [option overrides]: #vimfxaddoptionoverridesrules
909 [`vimfx.send(...)`]: #vimfxsendvim-message-data--null-callback--null
910 [`vimfx.listen(...)`]: #vimfxlistenmessage-listener
911 [categories]: #vimfxgetcategories
912 [custom hint commands]: #custom-hints-commands
913 [`vimfx.modes`]: #vimfxmodes
914 [onInput]: #oninput
915 [mode object]: #mode-object
916 [category object]: #category-object
917 [command object]: #command-object
918 [match object]: #match-object
919 [vim object]: #vim-object
920 [options object]: #options-object
921 [location object]: #location-object
922 [The `focusTypeChange` event]: #the-focustypechange-event
923 [the `shutdown` event]: #the-shutdown-event
924 [`vimfx.setHintMatcher(...)`]: #vimfxsethintmatcherhintmatcher
925 [`vimfx.getMarkerElement(...)`]: #vimfxgetmarkerelementid
926
927 [blacklisted]: options.md#blacklist
928 [special options]: options.md#special-options
929 [config file]: config-file.md
930 [bootstrap.js]: config-file.md#bootstrapjs
931 [autofocus prevention]: options.md#prevent-autofocus
932 [`activatable_element_keys`]: options.md#activatable_element_keys
933 [`adjustable_element_keys`]: options.md#adjustable_element_keys
934 [`blur_timeout`]: options.md#blur_timeout
935 [`notifications_enabled`]: options.md#notifications_enabled
936
937 [button]: button.md
938 [the hint commands]: commands.md#the-hint-commands--hints-mode
939 [special keys]: shortcuts.md#special-keys
940 [styling]: styling.md
941
942 [defaults.coffee]: ../extension/lib/defaults.coffee
943 [parse-prefs.coffee]: ../extension/lib/parse-prefs.coffee
944 [modes.coffee]: ../extension/lib/modes.coffee
945 [commands.coffee]: ../extension/lib/commands.coffee
946 [vim.coffee]: ../extension/lib/vim.coffee
947
948 [`event.key`]: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key
949 [`event.code`]: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code
950 [`Window`]: https://developer.mozilla.org/en-US/docs/Web/API/Window
951 [`Browser`]: https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/browser
952 [`window.location`]: https://developer.mozilla.org/en-US/docs/Web/API/Location
953 [`URL`]: https://developer.mozilla.org/en-US/docs/Web/API/URL
954 [Message Manager]: https://developer.mozilla.org/en-US/Firefox/Multiprocess_Firefox/Message_Manager
955 [TabSelect]: https://developer.mozilla.org/en-US/docs/Web/Events/TabSelect
956 [web console]: https://developer.mozilla.org/en-US/docs/Tools/Web_Console
957 [about:config]: http://kb.mozillazine.org/About:config
Imprint / Impressum