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