axes
(gitlab / addons.mozilla.org) is a WebExtension inspired by Konqueror's "access keys" feature, Uzbl Browser's "link following" feature and similar functionality available in Vimperator, Vimium, Pentadactyl and Tridactyl addons.
The general idea of all above is to show text labels near each document link, and when the user types the characters matching one of these labels, the appropriate link receives a click. This can save a lot of time, because the user does not have to switch between mouse and keyboard.
axes
extends and generalizes that idea.
The purpose of axes
is to provide keyboard access to mostly all of the meaningful ways of interaction with mostly all of the element types, e.g. it is possible to select from drop-down-on-hover menus, etc.
On the picture below there is an example of how the addon can be used to open multiple links at once (note the input field at the bottom).
A power user may get an imposing benefit after learning a special DSL created to describe element targets and ways of interaction with them. The main concepts of this language are events, targets, modifiers, actions and arguments.
Each event consists of exactly one target and a list of modifiers, which can be empty. User input is a list of space-separated events.
Targets are something the user can interact with, they specify lists of DOM elements. Each target can be defined using label query or selector.
Labels are small pieces of text dynamically bound to UI elements of the document that appear directly on the screen when the script is in interactive mode. The value of label bound to a specific element is not constant and depends on scroll position and current mode.
Label queries may consist of single label or label list. Label lists must be enclosed in brackets. They may consist of a single label as well, but also may include label intervals (in form of from-to
, where from
and to
are labels), other label lists (comma-separated) and exclusion expressions. Exclusion expressions allow to filter lists of labels. They are denoted with \
(similar to relative complement notation, a set-theoritical term meaning set subtraction). On the right side of backslash character there should be a label list or an exclusion pattern. Exclusion patterns specify rules to exclude labels based on their index number. They are literally strings consisting of +
and -
characters, as well as numbers, that are syntactic sugar to strip away long sequences of similar plus or minus characters (the number specifies how many times the preceding character should be repeated). It should be noted that \
is left-associative, so a\b\c
is (a\b)\c
and not a\(b\c)
. Parentheses can be used when left associativity isn't wanted.
Example:
Let's analyze the label list on the picture above, namely [l-b4\+-6\bc-bq]
.
First, the overall l-b4
interval gets expanded to a list of labels. Then, the exclusion pattern filters it, leaving each seventh label starting from l
(note that plus character is first, and -6
expands to ------
). Then the second exclusion pattern removes the elements that fall into bc-bq
interval, namely bc
, bj
and bq
.
Selector targets utilize the syntax of CSS selectors, slightly expanding it to allow filtering and element selection by index.
Selectors should be specified in figure brackets. Selector target (despite the brackets) is either a raw CSS selector with optional index list or an exclusion expression denoted with \
.
Index list is a comma-separated list of numbers or number intervals (e.g. 0-10
). Index list may be specified on the right side of a CSS selector, separated from it with |
character.
Selector exclusion expressions are left-associative. It is possible to group expressions using parentheses when right associativity is needed.
Example: {a|0,1-3\.someclass|1-4\a|1}
selects links (the a
selector) with indexes 0, 2, 3, excluding the ones that have someclass
in their class list, and also have indexes from 1 to 4 in a list of elements returned by .someclass
selector (so the first .someclass
element with index number 0 will not be excluded).
Each action is a function that accepts a list of DOM elements. It also has a special color associated with it.
Some actions accept arguments. Actions do not have textual representation; there are no ways to call them other than using modifiers.
See list of all available actions below.
Modifiers were introduced to name actions efficiently and to separate the notion of action by itself from its name.
Modifiers are associated with lists of actions. Each modifier is just a single character (one of !
, @
, #
, $
, %
, ^
, &
, *
, _
, +
, -
, =
, ~
, "
, ;
, :
, \
, |
, /
, ?
, .
, >
, <
and ,
) or a `
-enclosed user-defined [a-z0-9]
-string (user can add new modifiers at the "Modifiers" section of the addon settings page).
Argument is a single-quoted string that can be passed to a modifier by placing it right after. Quotes can be escaped with \
character.
Modifiers accept positional arguments (e.g. %'arg1''arg2'
).
Note: both input-mode and instant-mode are being referred to as interactive-mode when the difference between them is not important.
When the addon is in input-mode
, the user can see a textarea field waiting for input at the bottom, as well as labels near some of the DOM elements. If labels overlap (due to elements being too close to each other), they start blinking so that each label in each overlapping group gets to the top for some time and then fades back, repeatedly. The stroke color of each label gives the user some information about what type of element the label is bound to. Blue color means links, green means images, red means audio or video and gray means all the other types - (see settings.labels.stroke_styles
at JSON settings). It is very common, for example, that images on websites appear wrapped in <a>
tags, so that it would be very hard to determine which of the labels is bound to specific type of element without the stroke coloring feature.
While the user types, if the input gets incorrect, the textarea field gets highlighted with red color, and a message describing the error pops up at the top-right corner of the window. This message disappears when the input gets corrected.
Instant mode is just the same as input mode, except for that the execution begins just at the time the first valid input is entered. Thus, it saves one key press when dealing with trivial user inputs.
A stub representing "no mode" state.
Addon settings' page sections are listed below.
This section comprises the addon's behavior options and appearance settings.
At the first column the user can see modifier names (or (none)
for "no modifier"). Some rows of the table (the ones that represent user-defined modifiers) can be removed, while others cannot. At the second column there is a list of actions associated with modifiers on the left. Actions bound to modifiers may have any number of default arguments. Each action has its own preference regarding what to do with user-defined arguments passed to its modifier.
There are six options described in the table below:
Option | Description |
---|---|
Ignore |
Silently ignore arguments. |
Accept |
Ignore default arguments, use user-specified if any. |
Append |
Append user arguments to the end of the argument list (so that named user-specified arguments will take higher precedence). |
Prepend |
Put user arguments to the beginning of the argument list. |
Warn |
Show warning while reading the input as the user types. |
Reject |
Emit error so that it will not be possible to process the input. |
Default modifiers settings are listed here.
Autodetection
is a special action that resolves to some other action based on a mapping from CSS selectors matching elements to actions, as defined at the settings page. By default it is used if no other modifiers were given.
If none of the selectors match the element, nothing happens.
At the hotkeys table, on the left there is a row of buttons containing key bindings' values. Each of these values may be changed by clicking the button and then entering a new key sequence.
"Global" checkbox, if set, makes the hotkey available even if the focus currently belongs to an editable element (input, textarea, etc.)
"Prevent default" checkbox allows to suppress default effect of the hotkey (e.g. for 'ctrl+s' do not show dialog, for input fields do not change the value). However, it only affects the last key in a sequence.
The last optional field only takes effect when used with Enter mode
options. It can be used to set the initial value of the user input field, thus shortening the way to enter a specific event sequence by a few key presses.
Default hotkeys are listed here.
Element selectors are used to determine which elements should have labels. The syntax of CSS selectors is used. URL-specific rules are being applied sequentially one by one. During that process, two lists of selectors are being formed, namely "include" and "exclude" lists. Finally, the result is a list of all DOM elements that match at least one selector of the former and do not match any selectors of the latter list.
then
-options are listed below:
Option | Description |
---|---|
include selector |
Add selector to "include" list and go to the next rule. |
exclude selector |
Add selector to "exclude" list and go to the next rule. |
add selector and return |
Add selector to "include" list and discard remaining rules |
set selector to |
Ignore all preceding rules, overwrite "include" list selectors and set "exclude list" to be empty. |
Note: adding too many exclude selector
rules may increase startup times.
Startup preferences define how the script will behave on different URLs. It is possible to match the URL literally, by substring, by prefix substring, by domain or by regular expression. The syntax of regular expressions is identical to the JavaScript standard. It is possible to disable (or enable) the script, disable specific hotkeys or set the addon to enter interactive mode right after the page load. Some options (namely, Disable hotkey
, Start input mode
and Start instant mode
accept optional values as strings):
-
to disable a hotkey the literal string containing the binding should be used, which can be found at hotkeys settings.
-
the meaning of value field when one of the two interactive mode options is selected is the same as at the hotkeys settings - it sets the initial input.
Keymaps are useful if the user has more than one input locale and doesn't want to check if the input method is set to latin every time.
There is no way to determine using JS which layout is currently active, so the only option is to blindly map the non-latin characters to the latin ones, according to the key locations on the keyboard.
Currently only russian-computer
keymap is available.
Some configuration options lack corresponding UI controls at the settings page, but can be modified through a JSON editor. It is safe, because the parsed input always passes validation before use. In case of a syntax error, the cursor will be set to the position where this error appears in the editor. In case of a value error (i.e. caused by inacceptable properties' values or values of a wrong type being entered), a list of errors will appear under the textarea field, describing the exact path to the wrong value and a reason why it was rejected:
See action autodetection.
Pops up a help message with a list of hotkeys and modifiers.
Clicks the element using .click()
method.
Opens link in a new tab if possible (and immediately switches to it). Fails on javascript:
URLs.
If the element does not have the href
attribute, uses src
.
Opens link in the current tab, even if the target=_blank
attribute is set.
If the element does not have the href
attribute, uses src
.
Remove the element from DOM using .remove()
method.
Focuses the element. If more than one elements given, pops up a warning and focuses the last.
Triggers an event using EventTarget.dispatchEvent method. Accepts list of events as arguments (on
prefix should be omitted).
If the element's tag is input
and type is checkbox
or radio
, sets its checked
property to either true
(when called with non-empty first argument) or false
(otherwise).
If the element is either input
with type="text"
or textarea
, sets value
property to the first argument.
Downloads links, images. audio and video. Pass saveAs
as argument to open a file saving dialog. Pass any other string to use it as a file name. When both passed, ignores the former.
Accepts property names as arguments. First property that is defined for the element will be used.
Available properties are:
value
src
href
textContent
imageData
(file contents as image file, can be pasted into a graphics editor)dataURL
(resized image)originalDataURL
(original file)
This action is for <video>
and <audio>
only.
Toggles .muted
property. This action is for <video>
and <audio>
only.
When the user pastes text into the input field, the text becomes automatically escaped, so the quotes never break.
Hotkey | Meaning | Global | Prevents default | Value |
---|---|---|---|---|
f |
Start input mode | false | true | |
shift+f |
Start instant mode | false | true | |
f2 c |
Clear messages | true | true | |
f2 e |
Leave focused element | true | true | |
f2 2 |
Start input mode | true | true | |
f2 f2 |
Start instant mode | true | true | |
f2 3 |
Start instant mode | true | true | = |
f2 o |
Turn off until page reload | true | true | |
f2 p |
Turn off on this page | true | true | |
f2 d |
Turn off on this domain | true | true | |
f2 h |
Show help | true | true |
These are the defaults. If you are reading this guide inside the browser extension, refer to the actual settings.
Modifier | Meaning |
---|---|
(none) | Autodetection |
- |
Open in new tab |
_ |
Open in new tab (inactive) |
~ |
Open in this tab |
` | ` |
^ |
Focus element |
, |
Click |
= |
Copy contents (value, textContent) |
\ |
Copy contents (outerHTML) |
+ |
Copy contents (href, src) |
* |
Copy contents (imageData) |
. |
Copy contents (originalDataURL) |
/ |
Copy contents (dataURL) |
% |
Remove element |
! |
Mute media |
@ |
Toggle pause |
# |
Trigger events (mouseover, mouseenter) |
$ |
Trigger events (mouseleave, mouseout) |
& |
Trigger events (click) |
; |
Download url |
: |
Download url (saveAs) |
> |
Set value, Focus element |
? |
Show help |
" |
|
< |
|
`nt` |
Open in new tab |
`it` |
Open in new tab (inactive) |
`sv` |
Set value |
`fs` |
Focus element |
`cc` |
Copy contents (value, textContent) |
`cs` |
Copy contents (href, src) |
`ci` |
Copy contents (imageData) |
`cu` |
Copy contents (originalDataURL) |
`rm` |
Remove element |
`mt` |
Mute media |
`ps` |
Toggle pause |
`dl` |
Download url |
`sa` |
Download url (saveAs) |
Dependencies:
- grunt (tip: use local
./node_modules/grunt/bin/grunt
binary) - pandoc - to embed README.md into
settings.html
.
Run npm install && npm test && grunt pack
to get the .xpi file.
A Lisp-like language interpreter will be plugged into the extension to allow creating custom actions and interact with DOM elements directly. The idea is to make possible to enter something like
(map download $ take 2 $ sortBy sizeOnScreen $ query 'img')
right into the input field or easily bind this code to a hotkey.
It will unlikely increase the extension size or decrease performance drastically, because:
- Parser, the largest part of the language bundle, is separated from the core (evaluator) and is able to run as a background script - that means, for arbitrary number of content scripts (tabs), single parser can be used.
- The evaluator is tiny. It's about 1/5 of the current extension's size (both minified).
- It can be loaded only when necessary.