SpecKeyboard - mar10/fancytree GitHub Wiki
Fancytree should be controllable using the keyboard. When embedded into a web form, it should behave like a control (e.g. a listbox).
There is an experimental extension (see demo).
Yet there are still open questions, so this feature is open for discussion and the API is subject to change.
Please discuss here: https://github.com/mar10/fancytree/issues/71
The option keyboard: true
should be used to control if standard keyboard
navigation is enabled.
-
Key mapping:
-
+
: Expand node. -
-
: Collapse node. -
SPACE
: in select mode: toggle selection. Otherwise set active. -
ENTER
: Set active. -
BACKSPACE
: Set focus to parent. -
LEFT
: If expanded: collapse. Otherwise set focus to parent. -
RIGHT
: If collapsed: expand. Otherwise set focus to first child. -
UP
: Set focus to previous sibling (or parent if already on first sibling). -
DOWN
: Set focus to next visible node. -
Ctrl-Cursor
: Same asCursor
, but only sets the focus, even ifautoActivate
is on. -
F2
edit title (requires edit extension)
-
-
Note that we distinguish 'focused', 'active', and 'selected'. 'Set focus' only sets a dotted border around the node. When
autoActivate
is enabled (which is on by default), the node also gets activated. -
Special case table extension: If the table is only used readonly to get a column-alignment, we can use the above mapping.
??? If the grid contains checkboxes or input fields however, it would be desirable to navigate between the grid cells withTAB
,Shift-TAB
,UP
,DOWN
?
The tabbable: true
option was added to control the behavior when the tree is
part of a web form.
If we TAB through a form that contains a tree and other controls, the tree
should behave like a listbox, i.e.
- be entered / exited using TAB, i.e. be part of the tab index chain
- set focus to the active node when entered using TAB
- it is possible that the tree control is active, but no node is yet active (see the listbox in the 'Embed in Forms' demo, at least in Safari).
- optionally activate first node when entered using TAB and no node was active
- gray out active node marker when tree control looses focus
If the default implementation for keyboard: true
also satisfies these
requirements (and makes all users happy), maybe we can remove the tabbable option.
- Support multiple trees on one page
- Play nicely with other controls (listbox, input, ...) on the same page or form.
- A disabled tree should ignore keystrokes
- Don't break key handling for other controls on the same page (see https://github.com/mar10/fancytree/issues/71 )
- Setting
keyboard: false
will disable keyboard navigation for the tree. (??? but keep it in the TAB-chain?) - Allow implementation of WAI-ARIA support (see SpecAria)
- Should work if the node titles contain tabbable elemts (like
<a>
or<input>
).
- Use valid HTML
- Setting
tabbable: false
will remove the tree from the tab chain. - Should be portable to the table extension
(TODO)
Dynatree is the predecessor of Fancytree.
- Nodes use
<a>
tags for titles, which get the system focus on click. - bind "keydown.dynatree" to widget.element --> node._onKeydown(event)
- bind focus + blur to tree.divTree --> node._onFocus(event)
- _onKeydown: implement navgation and preventDefault()
- _onKeypress: does nothing
- _onFocus: set
tree.tnFocused
and add classfocused
to the node
Known Problems
Using <a>
tags may cause problems on IE (i.e. auto-scrolling to the left sometimes,
when user click on a node).
- nodes are simple
span
tags - container:
<ul tabindex="0">
(when tabbable option is true) - keydown is bound to document, because $container might not receive key events, because the nodes cannot have the system focus.
- $(document).on("keydown" + ns)
--> maintain global
focusTree
variable --> tree.nodeKeydown(event) - tree.$container.on("focusin" + ns + " focusout" + ns) --> tree.treeOnFocusInOut(event);
-
nodeKeydown(event)
: implement default navigation key mapping (see above) -
treeOnFocusInOut(event)
: callsnodeSetFocus()
-
nodeSetFocus(event)
: maintainnode.tree.focusNode
and calls nodeRenderStatus()
<div id="tree">
<ul class="fancytree-container" tabindex="0" >
</ul>
</div>
Known Problems
Backspace and arrow key don't work in input elements (including elements outside of tree contianer if tabbable
options is false, see issue #71).
- nodes are simple
span
tags - when
tabbable
option is true,tabindex="0"
is added to container -
keydown
is bound to $container. (NOTE: Iftabbable
option is false $container can't receive key events) - $container.on("keydown" + ns)
--> maintain global
focusTree
variable --> tree.nodeKeydown(event) - tree.$container.on("focusin" + ns + " focusout" + ns) --> tree.treeOnFocusInOut(event);
-
nodeKeydown(event)
: implement default navigation key mapping (see above) -
treeOnFocusInOut(event)
: callsnodeSetFocus()
-
nodeSetFocus(event)
: maintainnode.tree.focusNode
and calls nodeRenderStatus()
Known Problems
If tabbable
option is false $container can't receive key events, so keyboard navigation should be disabled. But you can't move focus to the tree by keyboard in that mode, therefore keyboard navigation is useless (when tabbable
option is false).
It's possible to insert invisible dummy element with tabIndex=0
inside $container, so $container will be able to handle key events even if tabbable
option is false. But in this case the tree will be tabbable in fact, but system focus will be invisible. It seems that it's useless complication.
Possible improvements
Remove global focusTree
variable. It seems that the boolean field focused
is enough. That field will be set and cleared in treeSetFocus
.
Variant 4: Bind key handler to container and set tabIndex for nodes (implemented in 'tabbable' branch)
tabbable
option can be set to "nodes" value (tabbable: "nodes"
). In this mode individual nodes can receive system focus:
- nodes:
<span tabIndex="0"></span>
- $container doesn't have
tabIndex
attribute -
keydown
is bound to $container. - $container.on("keydown" + ns)
--> maintain global
focusTree
variable --> tree.nodeKeydown(event) - tree.$container.on("focusin" + ns + " focusout" + ns) --> tree.treeOnFocusInOut(event);
-
nodeKeydown(event)
: implement default navigation key mapping (see above) -
treeOnFocusInOut(event)
: callsnodeSetFocus()
-
nodeSetFocus(event)
--> triggerfocus
event fornode.span
element --> maintainnode.tree.focusNode
and calls nodeRenderStatus()
When tabbable
options has other values, this variant is equivalent to variant #3.
(not tested, but maybe worth a try?)
- The currently focused node has tabindex=0; all other nodes don't have a tabindex (or have it set to -1?)
- Container has tabindex=0 when no node is focused, (-1 or none otherwise?)
- A global focusTree variable is no longer required, but we need to detect a blur event for the tree
- If a node span contains
<input>
fields, the node itself doesn't need to be focusable(?)
Instead when the node is activated it sets the focus to the first embedded control.
Vice versa, when an embedded input control gets the focus, it marks the parent node as active/focused. - 'node span' means 'node tr' when ext-table is used
- Optionally UP, DOWN, TAB could be intercepted in embedded controls to allow keyboard navigation?
Currently 'Variant 2' is implemented.
Variants 3 and 4 are implemented in 'tabbable' experimental branch.
Variant 5 is implemented in 'gridnav' experimental branch.