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