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