]> git.gir.st - VimFx.git/blob - documentation/api.md
Improve and add more 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 VimFx has an API. It is intended to be used by users who would like to write a
10 so-called [config file].
11
12 ## Getting the API
13
14 ```js
15 let {classes: Cc, interfaces: Ci, utils: Cu} = Components
16 Cu.import('resource://gre/modules/Services.jsm')
17 let apiPref = 'extensions.VimFx.api_url'
18 let apiUrl = Services.prefs.getComplexValue(apiPref, Ci.nsISupportsString).data
19 Cu.import(apiUrl, {}).getAPI(vimfx => {
20
21 // Do things with the `vimfx` object here.
22
23 })
24 ```
25
26 You might also want to take a look at the [config file bootstrap.js
27 example][bootstrap.js].
28
29 Note that the callback passed to `getAPI` is called once every time VimFx starts
30 up, not once per Firefox session! This means that if you update VimFx (or
31 disable and then enable it), the callback is re-run with the new version.
32
33
34 ## API
35
36 The following sub-sections assume that you store VimFx’s API in a variable
37 called `vimfx`.
38
39 ### `vimfx.get(pref)`, `vimfx.getDefault(pref)` and `vimfx.set(pref, value)`
40
41 Gets or sets the (default) value of the VimFx pref `pref`.
42
43 You can see all prefs in [defaults.coffee], or by opening [about:config] and
44 filtering by `extensions.vimfx`. Note that you can also access the [special
45 options], which may not be accessed in [about:config], using `vimfx.get()` and
46 `vimfx.set()`—in fact, this is the _only_ way of accessing those options.
47
48 #### `vimfx.get(pref)`
49
50 Gets the value of the VimFx pref `pref`.
51
52 ```js
53 // Get the value of the Hint chars option:
54 vimfx.get('hint_chars')
55 // Get all keyboard shortcuts (as a string) for the `f` command:
56 vimfx.get('mode.normal.follow')
57 ```
58
59 #### `vimfx.getDefault(pref)`
60
61 Gets the default value of the VimFx pref `pref`.
62
63 Useful when you wish to extend a default, rather than replacing it. See below.
64
65 #### `vimfx.set(pref, value)`
66
67 Sets the value of the VimFx pref `pref` to `value`.
68
69 ```js
70 // Set the value of the Hint chars option:
71 vimfx.set('hint_chars', 'abcdefghijklmnopqrstuvwxyz')
72 // Add yet a keyboard shortcut for the `f` command:
73 vimfx.set('mode.normal.follow', vimfx.getDefault('mode.normal.follow') + ' e')
74 ```
75
76 When extending a pref (as in the second example above), be sure to use
77 `vimfx.getDefault` rather than `vimfx.get`. Otherwise you get a multiplying
78 effect. In the above example, after starting Firefox a few times the pref would
79 be `f e e e e`. Also, if you find that example very verbose: Remember that
80 you’re using a programming language! Write a small helper function that suits
81 your needs.
82
83 Note: If you produce conflicting keyboard shortcuts, the order of your code does
84 not matter. The command that comes first in VimFx’s settings page in the Add-ons
85 Manager (and in the Keyboard Shortcuts help dialog) gets the shortcut; the other
86 one(s) do(es) not. See the notes about order in [mode object], [category object]
87 and [command object] for more information about order.
88
89 ```js
90 // Even though we set the shortcut for focusing the search bar last, the command
91 // for focusing the location bar “wins”, because it comes first in VimFx’s
92 // settings page in the Add-ons Manager.
93 vimfx.set('mode.normal.focus_location_bar', 'ö')
94 vimfx.set('mode.normal.focus_search_bar', 'ö')
95
96 // Swapping their orders also swaps the “winner”.
97 let {commands} = vimfx.modes.normal
98 ;[commands.focus_location_bar.order, commands.focus_search_bar.order] =
99 [commands.focus_search_bar.order, commands.focus_location_bar.order]
100 ```
101
102 ### `vimfx.addCommand(options, fn)`
103
104 Creates a new command.
105
106 `options`:
107
108 - name: `String`. The name used when accessing the command via
109 `vimfx.modes[options.mode].commands[options.name]`. It is also used for the
110 pref used to store the shortcuts for the command:
111 `` `custom.mode.${options.mode}.${options.name}` ``.
112 - description: `String`. Shown in the Keyboard Shortcuts help dialog and VimFx’s
113 settings page in the Add-ons Manager.
114 - mode: `String`. Defaults to `'normal'`. The mode to add the command to. The
115 value has to be one of the keys of [`vimfx.modes`].
116 - category: `String`. Defaults to `'misc'` for Normal mode and `''`
117 (uncategorized) otherwise. The category to add the command to. The
118 value has to be one of the keys of [`vimfx.get('categories')`][categories].
119 - order: `Number`. Defaults to putting the command at the end of the category.
120 The first of the default commands has the order `100` and then they increase
121 by `100` per command. This allows to put new commands between two already
122 existing ones.
123
124 `fn` is called when the command is activated. See the [onInput] documentation
125 below for more information.
126
127 <strong id="custom-command-shortcuts">Note</strong> that you have to give the
128 new command a shortcut in VimFx’s settings page in the Add-ons Manager or set
129 one using `vimfx.set()` to able to use the new command.
130
131 ```js
132 vimfx.addCommand({
133 name: 'hello',
134 description: 'Log Hello World',
135 }, => {
136 console.log('Hello World!')
137 })
138 // Optional:
139 vimfx.set('custom.mode.normal.hello', 'gö')
140 ```
141
142 ### `vimfx.addOptionOverrides(...rules)` and `vimfx.addKeyOverrides(...rules)`
143
144 These methods take any number of arguments. Each argument is a rule. The rules
145 are added in order. The methods may be run multiple times.
146
147 A rule is an `Array` of length 2:
148
149 1. The first item is a function that returns `true` if the rule should be
150 applied and `false` if not. This is called the matching function.
151 2. The second item is the value that should be used if the rule is applied. This
152 is called the override.
153
154 The rules are tried in the same order they were added. When a matching rule is
155 found it is applied. No more rules will be applied.
156
157 #### `vimfx.addOptionOverrides(...rules)`
158
159 The rules are matched any time the value of a VimFx pref is needed.
160
161 The matching function receives a [location object].
162
163 The override is an object whose keys are VimFx pref names and whose values
164 override the pref in question. The values should be formatted as in an [options
165 object].
166
167 ```js
168 vimfx.addOptionOverrides(
169 [ ({hostname, pathname, hash}) =>
170 `${hostname}${pathname}${hash}` === 'google.com/',
171 {prevent_autofocus: false}
172 ]
173 )
174 ```
175
176 #### `vimfx.addKeyOverrides(...rules)`
177
178 The rules are matched any time you press a key that is not part of the tail of a
179 multi-key shortcut.
180
181 The matching function receives a [location object] as well as the current
182 mode name (one of the keys of [`vimfx.modes`]).
183
184 The override is an array of keys which should not activate VimFx commands but be
185 sent to the page.
186
187 This allows to disable commands on specific sites. To _add_ commands on specific
188 sites, add them globally and then disable them on all _other_ sites.
189
190 ```js
191 vimfx.addKeyOverrides(
192 [ location => location.hostname === 'facebook.com',
193 ['j', 'k']
194 ]
195 )
196 ```
197
198 ### `vimfx.on(eventName, listener)`
199
200 Runs `listener(data)` when `eventName` is fired.
201
202 #### The `locationChange` event
203
204 Occurs when opening a new tab, navigating to a new URL or refreshing the page,
205 causing a full page load. The data passed to listeners is an object with the
206 following properties:
207
208 - vim: The current [vim object].
209 - location: A [location object].
210
211 This can be used to enter a different mode by default on some pages (which can
212 be used to replace the blacklist option).
213
214 ```js
215 vimfx.on('locationChange', ({vim, location}) => {
216 if (location.hostname === 'example.com') {
217 vim.enterMode('ignore')
218 }
219 })
220 ```
221
222 #### The `notification` and `hideNotification` events
223
224 The `notification` event occurs when `vim.notify(message)` is called, and means
225 that `message` should be displayed to the user.
226
227 The `hideNotification` event occurs when the `vim.hideNotification()` is called,
228 and means that the current notification is requested to be hidden.
229
230 The data passed to listeners is an object with the following properties:
231
232 - vim: The current [vim object].
233 - message: The message that should be notified. Only for the `notification`
234 event.
235
236 Both of these events are emitted even if the [`notifications_enabled`] option is
237 disabled, allowing you to display notifications in any way you want.
238
239 #### The `modeChange` event
240
241 Occurs whenever the current mode in any tab changes. The initial entering of the
242 default mode in new tabs also counts as a mode change. The data passed to
243 listeners is the current [vim object].
244
245 ```js
246 vimfx.on('modeChange', vim => {
247 let mode = vimfx.modes[vim.mode].name
248 vim.notify(`Entering mode: ${mode}`)
249 })
250 ```
251
252 #### The `TabSelect` event
253
254 Occurs whenever any tab in any window is selected. This is also fired when
255 Firefox starts for the currently selected tab. The data passed to listeners is
256 the `event` object passed to the standard Firefox [TabSelect] event.
257
258 ### The `modeDisplayChange` event
259
260 This is basically a combination of the `modeChange` and the `TabSelect` events.
261 The event is useful for knowing when to update UI showing the current mode. The
262 data passed to listeners is the current [vim object].
263
264 (VimFx itself uses this event to update the toolbar [button], by setting
265 `#main-window[vimfx-mode]` to the current mode. You may use this with custom
266 [styling].)
267
268 #### The `focusTypeChange` event
269
270 Occurs when focusing or blurring any element. The data passed to listeners is an
271 object with the following properties:
272
273 - vim: The current [vim object].
274 - focusType: A string similar to `match.focus` of a [match object], with the
275 following differences:
276
277 - The current pressed key is _not_ taken into account, because focus and blur
278 events have no current key.
279 - The value is never `null` or `'other'`, but `'none'` instead.
280
281 (VimFx itself uses this event to update the toolbar [button], by setting
282 `#main-window[vimfx-focus-type]` to the current focus type. You may use this
283 with custom [styling].)
284
285
286
287 ### `vimfx.modes`
288
289 An object whose keys are mode names and whose values are [mode object]s.
290
291 This is a very low-level part of the API. It allows to:
292
293 - Access all commands and run them. This is the most common thing that a config
294 file user needs it for.
295
296 ```js
297 let {commands} = vimfx.modes.normal
298 // Inside a custom command:
299 commands.tab_new.run(args)
300 ```
301
302 - Adding new commands. It is recommended to use the `vimfx.addCommand()` helper
303 instead. It’s easier.
304
305 ```js
306 vimfx.modes.normal.commands.new_command = {
307 pref: 'extensions.my_extension.mode.normal.new_command',
308 category: 'misc',
309 order: 10000,
310 description: translate('mode.normal.new_command'),
311 run: args => console.log('New command! args:', args)
312 }
313 ```
314
315 - Adding new modes. This is the most advanced customization you can do to VimFx.
316 Expect having to read VimFx’s source code to figure it all out.
317
318 ```js
319 vimfx.modes.new_mode = {
320 name: () => translate('mode.new_mode'),
321 order: 10000,
322 commands: {},
323 onEnter(args) {},
324 onLeave(args) {},
325 onInput(args, match) {
326 if (match.type === 'full') {
327 match.command.run(args)
328 }
329 return (match.type !== 'none')
330 },
331 }
332 ```
333
334 Have a look at [modes.coffee] and [commands.coffee] for more information.
335
336 ### `vimfx.get('categories')`
337
338 An object whose keys are category names and whose values are [category object]s.
339
340 ```js
341 let categories = vimfx.get('categories')
342
343 // Add a new category.
344 categories.custom = {
345 name: () => 'Custom commands',
346 order: 10000,
347 }
348
349 // Swap the order of the Location and Tabs categories.
350 ;[commands.focus_location_bar.order, categories.tabs.order] =
351 [categories.tabs.order, commands.focus_location_bar.order]
352 ```
353
354 ### Mode object
355
356 A mode is an object with the following properties:
357
358 - name: `String`. A human readable name of the mode used in the Keyboard
359 Shortcuts help dialog and VimFx’s settings page in the Add-ons Manager. Config
360 file users adding custom modes could simply use a hard-coded string; extension
361 authors are encouraged to look up the name from a locale file.
362 - order: `Number`. The first of the default modes has the order `100` and then
363 they increase by `100` per mode. This allows to put new modes between two
364 already existing ones.
365 - commands: `Object`. The keys are command names and the values are [command
366 object]s.
367 - onEnter(data, ...args): `Function`. Called when the mode is entered.
368 - onLeave(data): `Function`. Called when the mode is left.
369 - onInput(data, match): `Function`. Called when a key is pressed.
370
371 #### onEnter, onLeave and onInput
372
373 These methods are called with an object (called `data` above) with the following
374 properties:
375
376 - vim: The current [vim object].
377 - storage: An object unique to the current [vim object] and to the current mode.
378 Allows to share things between commands of the same mode by getting and
379 setting keys on it.
380
381 ##### onEnter
382
383 This method is called with an object as mentioned above, and after that there
384 may be any number of arguments (`args` in `vim.enterMode(modeName, ...args)`)
385 that the mode is free to do whatever it wants with.
386
387 Whatever is returned from `onEnter` will be returned from
388 `vim.enterMode(modeName, ...args)`.
389
390 ##### onInput
391
392 The object passed to this method (see above) also has the following properties:
393
394 - uiEvent: `Event` or `false`. The keydown event object if the event occurred in
395 the browser UI, `false` otherwise (if the event occurred in web page content).
396 - count: `Number`. The count for the command. `undefined` if no count. (This is
397 simply a copy of `match.count`. `match` is defined below.)
398
399 The above object should be passed to commands when running them. The mode is
400 free to do whatever it wants with the return value (if any) of the commands it
401 runs.
402
403 It also receives a [match object] as the second argument.
404
405 `onInput` should return `true` if the current keypress should not be passed on
406 to the browser and web pages, and `false` otherwise.
407
408 ### Category object
409
410 A category is an object with the following properties:
411
412 - name: `String`. A human readable name of the category used in the Keyboard
413 Shortcuts help dialog and VimFx’s settings page in the Add-ons Manager. Config
414 file users adding custom categories could simply a use hard-coded string;
415 extension authors are encouraged to look up the name from a locale file.
416 - order: `Number`. The first of the default categories is the “uncategorized”
417 category. It has the order `100` and then they increase by `100` per category.
418 This allows to put new categories between two already existing ones.
419
420 ### Command object
421
422 A command is an object with the following properties:
423
424 - pref: `String`. The pref used to store the shortcuts for the command.
425 - run(args): `Function`. Called when the command is activated.
426 - description: `String`. A description of the command, shown in the Keyboard
427 Shortcuts help dialog and VimFx’s settings page in the Add-ons Manager. Config
428 file users adding custom commands could simply use a hard-coded string;
429 extension authors are encouraged to look up the name from a locale file.
430 - category: `String`. The category to add the command to. The value has to be
431 one of the keys of [`vimfx.get('categories')`][categories].
432 - order: `Number`. The first of the default commands has the order `100` and
433 then they increase by `100` per command. This allows to put new commands
434 between two already existing ones.
435
436 ### Match object
437
438 A `match` object has the following properties:
439
440 - type: `String`. It has one of the following values:
441
442 - `'full'`: The current keypress, together with previous keypresses, fully
443 matches a command shortcut.
444 - `'partial'`: The current keypress, together with previous keypresses,
445 partially matches a command shortcut.
446 - `'count'`: The current keypress is not part of a command shortcut, but is a
447 digit and contributes to the count of a future matched command.
448 - `'none'`: The current keypress is not part of a command shortcut and does
449 not contribute to a count.
450
451 - focus: `String` or `null`. The type of currently focused _element_ plus
452 current pressed _key_ combo. You might not want to run commands and suppress
453 the event if this value is anything other than null. It has one of the
454 following values, depending on what kind of _element_ is focused and which
455 _key_ was pressed:
456
457 - `'editable'`: element: some kind of text input, a `<select>` element or a
458 “contenteditable” element. key: any pressed key.
459 - `'activatable'`: element: an “activatable” element (link or button).
460 key: see the [`activatable_element_keys`] option.
461 - `'adjustable'`: element: an “adjustable” element (form control or video
462 player). key: see the [`adjustable_element_keys`] option.
463 - `'other'`: element: some other kind of element that can receive keystrokes,
464 for example an element in fullscreen mode. key: any pressed key.
465
466 If none of the above criteria is met, the value is `null`, which means that
467 the currently focused element does not appear to respond to keystrokes in any
468 special way.
469
470 - command: `null` unless `type` is `'full'`. Then it is the matched command (a
471 [command object]).
472
473 The matched command should usually be run at this point. It is suitable to
474 pass on the object passed to [onInput] to the command. Some modes might choose
475 to add extra properties to the object first. (That is favored over passing
476 several arguments, since it makes it easier for the command to in turn pass
477 the same data it got on to another command, if needed.)
478
479 Usually the return value of the command isn’t used, but that’s up to the mode.
480
481 - count: `Number`. The count for the command. `undefined` if no count.
482
483 - specialKeys: `Object`. The keys may be any of the following:
484
485 - `<force>`
486 - `<late>`
487
488 If a key exists, its value is always `true`. The keys that exist indicate the
489 [special keys] for the sequence used for the matched command (if any).
490
491 - keyStr: `String`. The current keypress represented as a string.
492
493 - unmodifiedKey: `String`. `keyStr` without modifiers.
494
495 - toplevel: `Boolean`. Whether or not the match was a toplevel match in the
496 shortcut key tree. This is `true` unless the match is part of the tail of a
497 multi-key shortcut.
498
499 - discard(): `Function`. Discards keys pressed so far: If `type` is `'partial'`
500 or `'count'`. For example, if you have typed `12g`, run `match.discard()` and
501 then press `$`, the `$` command will be run instead of `12g$`.
502
503 ### Vim object
504
505 There is one `vim` object per tab.
506
507 A `vim` object has the following properties:
508
509 - window: [`Window`]. The current Firefox window object. Most commands
510 interacting with Firefox’s UI use this.
511
512 - browser: [`Browser`]. The `browser` that this vim object handles.
513
514 - options: `Object`. Provides access to all of VimFx’s options. It is an
515 [options object].
516
517 - mode: `String`. The current mode name.
518
519 - enterMode(modeName, ...args): `Function`. Enter mode `modeName`, passing
520 `...args` to the mode. It is up to every mode to do whatever it wants to with
521 `...args`. If `modeName` was already the current mode, nothing is done and
522 `undefined` is returned. Otherwise it us up to the mode to return whatever it
523 wants to.
524
525 - isUIEvent(event): `Function`. Returns `true` if `event` occurred in the
526 browser UI, and `false` otherwise (if it occurred in web page content).
527
528 - notify(message): `Function`. Display a notification with the text `message`.
529
530 - hideNotification(): `Function`. Hide the current notification (if any).
531
532 - markPageInteraction(value=true): `Function`. When `value` is `true` (as it is
533 by default when the argument is omitted), marks that the user has interacted
534 with the page. After that [autofocus prevention] is not done anymore. Commands
535 interacting with web page content might want to do this. If `value` is
536 `false`, the state is reset and autofocus prevention _will_ be done again.
537
538 **Warning:** There are also properties starting with an underscore on `vim`
539 objects. They are private, and not supposed to be used outside of VimFx’s own
540 source code. They may change at any time.
541
542 ### Options object
543
544 An `options` object provides access to all of VimFx’s options. It is an object
545 whose keys are VimFx pref names.
546
547 Note that the values are not just simply `vimfx.get(pref)` for the `pref` in
548 question; they are _parsed_ (`parse(vimfx.get(pref))`):
549
550 - Space-separated prefs are parsed into arrays of strings.
551
552 - `black_list` and `{prev,next}_patterns` are parsed into arrays of regular
553 expressions.
554
555 (See [parse-prefs.coffee] for all details.)
556
557 Any [option overrides] are automatically taken into account when getting an
558 option value.
559
560 The [special options] are also available on this object.
561
562
563 ### Location object
564
565 A location object is very similar to [`window.location`] in web pages.
566 Technically, it is a [`URL`] instance. You can experiment with the current
567 location object by opening the [web console] and entering `location`.
568
569
570 ## Frame script API
571
572 In frame scripts, the API consists of assigning global variables prefixed with
573 `VimFx`. VimFx then uses these when needed.
574
575 ```js
576 this.VimFxSomething = ...
577 ```
578
579 ### `VimFxHintMatcher(...)`
580
581 If available, it is used to let you customize which elements do and don’t get
582 hints. It might help to read about [the `f` commands] first.
583
584 ```js
585 this.VimFxHintMatcher = (id, element, {type, semantic}) => {
586 // Inspect `element` and change `type` and `semantic` if needed.
587 return {type, semantic}
588 }
589 ```
590
591 The arguments passed to this function are:
592
593 - id: `String`. A string identifying which command is used:
594
595 - `'normal'`: `f` or `af`.
596 - `'tab'`: `F`, `gf` or `gF`.
597 - `'copy'`: `yf`.
598 - `'focus'`: `zf`.
599
600 - element: `Element`. One out of all elements currently inside the viewport.
601
602 - info: `Object`. It has the following properties:
603
604 - type: `String` or `null`. If a string, it means that `element` should get a
605 hint. If `null`, it won’t. See the available strings below. When a marker
606 is matched, `type` decides what happens to `element`.
607 - semantic: `Boolean`. Indicates whether or not the element is “semantic.”
608 Semantic elements get better hints.
609
610 This object contains information on how VimFx has matched `element`. You have
611 the opportunity to change this.
612
613 The available type strings depend on `id`:
614
615 - normal:
616
617 - link: A “proper” link (not used as a button with the help of JavaScript),
618 with an `href` attribute.
619 - text: An element that can you can type in, such as text inputs.
620 - clickable: Some clickable element not falling into another category.
621 - clickable-special: Like “clickable,” but uses a different technique to
622 simulate a click on the element. If “clickable” doesn’t work, try this one.
623 - scrollable: A scrollable element.
624
625 - tab:
626
627 - link: Like “link” when `id` is “normal” (see above).
628
629 - copy:
630
631 - link: Like “link” when `id` is “normal” (see above).
632 - text: Like “text” when `id` is “normal” (see above), except that in this
633 case “contenteditable” elements are not included.
634 - contenteditable: Elements with “contenteditable” turned on.
635
636 - focus:
637
638 - focusable: Any focusable element not falling into another category.
639 - scrollable: Like “scrollable” when `id` is “normal” (see above).
640
641 The function must return an object like the `info` parameter (with the `type`
642 and `semantic` properties).
643
644
645 ## Stability
646
647 The API is currently **experimental** and therefore **unstable.** Things might
648 break with new VimFx versions. However, no breaking changes are planned, and
649 will be avoided if feasible.
650
651 As soon as VimFx 1.0.0 (which does not seem to be too far away) is released
652 backwards compatibility will be a priority and won’t be broken until VimFx
653 2.0.0.
654
655 [option overrides]: #vimfxaddoptionoverridesrules
656 [categories]: #vimfxgetcategories
657 [`vimfx.modes`]: #vimfxmodes
658 [onInput]: #oninput
659 [mode object]: #mode-object
660 [category object]: #category-object
661 [command object]: #command-object
662 [match object]: #match-object
663 [vim object]: #vim-object
664 [options object]: #options-object
665 [location object]: #location-object
666
667 [blacklisted]: options.md#blacklist
668 [special options]: options.md#special-options
669 [config file]: config-file.md
670 [bootstrap.js]: config-file.md#bootstrapjs
671 [autofocus prevention]: options.md#prevent-autofocus
672 [`activatable_element_keys`]: options.md#activatable_element_keys
673 [`adjustable_element_keys`]: options.md#adjustable_element_keys
674 [`notifications_enabled`]: options.md#notifications_enabled
675
676 [button]: button.md
677 [the `f` commands]: commands.md#the-f-commands--hints-mode
678 [special keys]: shortcuts.md#special-keys
679 [styling]: styling.md
680
681 [defaults.coffee]: ../extension/lib/defaults.coffee
682 [parse-prefs.coffee]: ../extension/lib/parse-prefs.coffee
683 [modes.coffee]: ../extension/lib/modes.coffee
684 [commands.coffee]: ../extension/lib/commands.coffee
685 [vim.coffee]: ../extension/lib/vim.coffee
686
687 [`Window`]: https://developer.mozilla.org/en-US/docs/Web/API/Window
688 [`Browser`]: https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/browser
689 [`window.location`]: https://developer.mozilla.org/en-US/docs/Web/API/Location
690 [`URL`]: https://developer.mozilla.org/en-US/docs/Web/API/URL
691 [TabSelect]: https://developer.mozilla.org/en-US/docs/Web/Events/TabSelect
692 [web console]: https://developer.mozilla.org/en-US/docs/Tools/Web_Console
693 [about:config]: http://kb.mozillazine.org/About:config
Imprint / Impressum