algone
algone

Reputation: 93

Richfaces Tree navigation via arrow key (left, right, up, down), tab and enter

I have a tree component that works fine. However, we would like to make the app more user friendly for people with a disability. The app should enable users to:

Here is my current tree component which works fine:

 <rich:tree id="fileTree" var="item" selection="#{FILES.selection}" binding="#{FILES.binding}"

                       rightClickSelection="true" toggleType="ajax" selectionType="ajax" render="fileTree" 
                       oncomplete="set_resource_updated(#{FILES.selected});" 
                       onmousedown="var_allow_select = mouse_right_click(event);" onbeforeselectionchange="return var_allow_select;" >

                <rich:treeModelRecursiveAdaptor roots="#{FILES.list}" nodes="#{item.directories}" leaf="#{not item.directory}">
                    <rich:treeNode expanded="#{item.expanded}"  render="fileTree" > 
                        <a href="#" class="treelnk" >
                        <a4j:outputPanel id="itemP1" >
                            <h:outputText value="#{item.name}" style="font-weight: #{item eq FILES.selectedNode ? 'bold':'normal'};"/>
                            <rich:dragSource dragValue="#{item}" type="typeT1" dragIndicator="fileI1"/>
                            <rich:dropTarget dropValue="#{item}" acceptedTypes="typeT1,typeT2" execute="itemP1,itemP2"
                                             dropListener="#{FILES.dropListener}" immediate="true" render="popupDragDrop" oncomplete="#{rich:component('popupDragDrop')}.show()"/>
                        </a4j:outputPanel>
                        <rich:dragIndicator id="fileI1" acceptClass="accept" rejectClass="reject" draggingClass="default">
                            <h:outputText value="#{item.name}" style="padding-left: 10px"/>
                        </rich:dragIndicator>
                        </a>
                    </rich:treeNode>
                    <rich:treeModelAdaptor nodes="#{item.files}">
                        <rich:treeNode expanded="#{item.expanded}" render="fileTree" >
                            <a href="#" class="treelnk" >
                            <a4j:outputPanel id="itemP2" styleClass="panel">
                                <h:outputText value="#{item.name}" style="font-weight: #{item eq FILES.selectedNode ? 'bold':'normal'};"/>
                                <rich:dragSource dragValue="#{item}" type="typeT2" dragIndicator="fileI2"/>
                                <rich:dropTarget dropValue="#{item}" acceptedTypes="typeT1,typeT2" execute="itemP1,itemP2"
                                                 dropListener="#{FILES.dropListener}" immediate="true" render="popupDragDrop" oncomplete="#{rich:component('popupDragDrop')}.show()"/>
                            </a4j:outputPanel>
                            <rich:dragIndicator id="fileI2" acceptClass="accept" rejectClass="reject" draggingClass="default">
                                <h:outputText value="#{item.name}" style="padding-left: 10px; "/>
                            </rich:dragIndicator>
                            </a>
                        </rich:treeNode>
                    </rich:treeModelAdaptor>
                </rich:treeModelRecursiveAdaptor>
            </rich:tree>

I have checked for solutions here, but most of them suggests serversides handling and event handling. Is there a way this could be done totally on the client side?

Upvotes: 0

Views: 595

Answers (2)

The user friendly web application for people with dissability may consist of external navigation component which makes possible to navigate the <rich:tree> simpler. You may consider using wizard-styled buttons: prev / next expanding relevant branches and selecting them in an order.

To implement such component you'd need some communication with server, though.

I'd keep all possible selections for navigating with prev / next in the list (flatTraversalOrder):

@ManagedBean
@ViewScoped
public class TreeNavigator {

    private List<SequenceRowKey> flatTraversalOrder;

    @ManagedProperty("#{treeBean}")
    private YourTreeBean treeBean;

    @PostConstruct
    public void initialize() {
        flatTraversalOrder = createTraversalOrder(treeBean.getRootNode());
    }

    // Put desired nodes in desired order here, e.g. all children of root:
    private List<SequenceRowKey> createTraversalOrder(YourTreeNode rootNode) {
        List<SequenceRowKey> result = new ArrayList<>();
        for (Iterator<Object> i = rootNode.getChildrenKeysIterator(); i.hasNext();) {
            result.add(new SequenceRowKey(i.next()));
        }
        return result;
    }

    public void selectNext() {
        List<Object> selectionList = new ArrayList<>(treeBean.getSelection());
        SequenceRowKey selectionKey = (SequenceRowKey) selectionList.get(0);
        int indexInTraversalList = flatTraversalOrder.indexOf(selectionKey);
        if ((indexInTraversalList == -1) || (indexInTraversalList == flatTraversalOrder.size() - 1)) {
            return;
        }
        SequenceRowKey toBeSelectedKey = flatTraversalOrder.get(indexInTraversalList + 1);
        treeBean.getSelection().clear();
        treeBean.getSelection().add(toBeSelectedKey);
    }
}

selectNext() may be called from large next button or triggered by keyboard event.

The tree bean:

@ManagedBean
@ViewScoped
public class YourTreeBean {

    private YourTreeNode rootNode;

    private Collection<Object> selection;

    //getters and setters

}

I've implemented app in which I additionaly expand nodes if selection goes inside them. You can find the working example, description and GitHub repo over here:

Interactions with RichTree

Upvotes: 0

Makhiel
Makhiel

Reputation: 3884

Toggling the node is easy, each node has a toggle() method and you can toggle the current one like this:

tree.getSelection().getNodes()[0].toggle()

Traversing the tree on the other hand is rather difficult. The tree keeps references to sets of nodes but not to the whole structure - i.e. there is no easy way to tell which node should be the next one selected. jQuery might help you.

$('.rf-trn-cnt')

this returns a list of all nodes, you can then call mousedown() on a node to select it.

Upvotes: 1

Related Questions