Search code examples
dojoaccessibilitydijit.tree

Dojo dijit tree with checkbox is not keyboard accessible


I have created a dijit.Tree object where every node is a checkbox. When you select/deselect the parent node, the child nodes get selected/deselected; when one of the children is deselected, the parent gets deselected; when all the children are selected, the parent gets selected. It works perfectly fine.
However I need it to be keyboard accessible. When I navigate to the tree nodes and press spacebar or Enter, nothing happens.

I tried adding tabindex and aria-role to the checkbox (programmatically), but it did not work.

Here is the fiddle - http://jsfiddle.net/pdabade/pyz9Lcpv/65/

require([ 
"dojo/_base/window", "dojo/store/Memory",
"dijit/tree/ObjectStoreModel",
"dijit/Tree", "dijit/form/CheckBox", "dojo/dom",
"dojo/domReady!"
], function(win, Memory, ObjectStoreModel, Tree, checkBox, dom) {

// Create test store, adding the getChildren() method required by      ObjectStoreModel
var myStore = new Memory({
data: [{
  id: 'allDocuments',
  name: 'All Documents'
}, {
  id: 'inboxDocuments',
  name: 'Inbox Documents',
  parent: 'allDocuments'
}, {
  id: 'outboxDocuments',
  name: 'Outbox Documents',
  parent: 'allDocuments'
}, {
  id: 'draftDocuments',
  name: 'Draft Documents',
  parent: 'allDocuments'
}, {
  id: 'finalDocuments',
  name: 'Final Documents',
  parent: 'allDocuments'
}],
getChildren: function(object) {
  return this.query({
    parent: object.id
  });
}
});
// Create the model
var myModel = new ObjectStoreModel({
store: myStore,
query: {
  id: 'allDocuments'
}
});

// Create the Tree.
var tree = new Tree({
model: myModel,

autoExpand: true,
getIconClass: function(item, opened) {
  // console.log('tree getIconClass', item, opened);
  // console.log('tree item type', item.id);
},

onClick: function(item, node, event) {
  //node._iconClass= "dijitFolderClosed";
  //node.iconNode.className = "dijitFolderClosed";
  var _this = this;
  console.log(item.id);
  var id = node.domNode.id,
    isNodeSelected = node.checkBox.get('checked');

  dojo.query('#' + id + ' .dijitCheckBox').forEach(function(node) {
    dijit.getEnclosingWidget(node).set('checked', isNodeSelected);
  });

  if (item.id != 'allComments') {
    if (!isNodeSelected) {
      var parent = node.tree.rootNode; // parent node id
      //console.log(node);
      parent.checkBox.set('checked', false);
    } else {
      var parent = node.tree.rootNode;
      var selected = true;
      var i = 0;
      dojo.query('#' + parent.id +  '.dijitCheckBox').forEach(function(node) {
        if (i > 0) {
          var isSet = dijit.getEnclosingWidget(node).get('checked');
          console.log(isSet);
          if (isSet == false) {
            selected = false;
          }
        }
        i++;
      });
      if (selected) {
        parent.checkBox.set('checked', true);
      }
    }

  }
  //console.log(node.id);
},
_createTreeNode: function(args) {
  var tnode = new dijit._TreeNode(args);
  tnode.labelNode.innerHTML = args.label;
  console.log(args);
  var cb = new dijit.form.CheckBox({
    "aria-checked": "false",
    "aria-describedby": args.label
  });
  cb.placeAt(tnode.labelNode, "first");
  tnode.checkBox = cb;


  return tnode;
}

});
tree.placeAt(contentHere);
tree.startup();
tree.checkedItems();
//tree.expandAll();


});

}

Any ideas as to how to make it keyboard accessible?

Thanks!


Solution

  • Looking into the dijit/Tree source I see that it sets the function _onNodePress() as an event handler for keyboard events. You can override it (or add an aspect after it) and handle the key presses you want manually. It takes as argument the tree node and an event object that you can use to check specifically for the space and the enter key.

    I forked your jsfiddle with an example: https://jsfiddle.net/pgianna/jjore5sm/1/

    _onNodePress: function(/*TreeNode*/ nodeWidget, /*Event*/ e){
        // This is the original implementation of _onNodePress:
        this.focusNode(nodeWidget);
    
        // This requires "dojo/keys"
        if (e.keyCode == keys.ENTER || e.keyCode == keys.SPACE)
        {
            var cb = nodeWidget.checkBox;
            cb.set('checked', !cb.get('checked'));
        }
    }