📄 tree.js
字号:
this._itemNodeMap[this.model.getIdentity(item)] = rn; rn._updateLayout(); // sets "dijitTreeIsRoot" CSS classname // load top level children this._expandNode(rn); }), function(err){ console.error(this, ": error loading root: ", err); } ); }, ////////////// Data store related functions ////////////////////// // These just get passed to the model; they are here for back-compat mayHaveChildren: function(/*dojo.data.Item*/ item){ // summary // User overridable function to tell if an item has or may have children. // Controls whether or not +/- expando icon is shown. // (For efficiency reasons we may not want to check if an element actually // has children until user clicks the expando node) }, getItemChildren: function(/*dojo.data.Item*/ parentItem, /*function(items)*/ onComplete){ // summary // User overridable function that return array of child items of given parent item, // or if parentItem==null then return top items in tree }, /////////////////////////////////////////////////////// // Functions for converting an item to a TreeNode getLabel: function(/*dojo.data.Item*/ item){ // summary: user overridable function to get the label for a tree node (given the item) return this.model.getLabel(item); // String }, getIconClass: function(/*dojo.data.Item*/ item, /*Boolean*/ opened){ // summary: user overridable function to return CSS class name to display icon return (!item || this.model.mayHaveChildren(item)) ? (opened ? "dijitFolderOpened" : "dijitFolderClosed") : "dijitLeaf" }, getLabelClass: function(/*dojo.data.Item*/ item, /*Boolean*/ opened){ // summary: user overridable function to return CSS class name to display label }, /////////// Keyboard and Mouse handlers //////////////////// _onKeyPress: function(/*Event*/ e){ // summary: translates keypress events into commands for the controller if(e.altKey){ return; } var treeNode = dijit.getEnclosingWidget(e.target); if(!treeNode){ return; } // Note: On IE e.keyCode is not 0 for printables so check e.charCode. // In dojo charCode is universally 0 for non-printables. if(e.charCode){ // handle printables (letter navigation) // Check for key navigation. var navKey = e.charCode; if(!e.altKey && !e.ctrlKey && !e.shiftKey && !e.metaKey){ navKey = (String.fromCharCode(navKey)).toLowerCase(); this._onLetterKeyNav( { node: treeNode, key: navKey } ); dojo.stopEvent(e); } }else{ // handle non-printables (arrow keys) var map = this._keyHandlerMap; if(!map){ // setup table mapping keys to events map = {}; map[dojo.keys.ENTER]="_onEnterKey"; map[this.isLeftToRight() ? dojo.keys.LEFT_ARROW : dojo.keys.RIGHT_ARROW]="_onLeftArrow"; map[this.isLeftToRight() ? dojo.keys.RIGHT_ARROW : dojo.keys.LEFT_ARROW]="_onRightArrow"; map[dojo.keys.UP_ARROW]="_onUpArrow"; map[dojo.keys.DOWN_ARROW]="_onDownArrow"; map[dojo.keys.HOME]="_onHomeKey"; map[dojo.keys.END]="_onEndKey"; this._keyHandlerMap = map; } if(this._keyHandlerMap[e.keyCode]){ this[this._keyHandlerMap[e.keyCode]]( { node: treeNode, item: treeNode.item } ); dojo.stopEvent(e); } } }, _onEnterKey: function(/*Object*/ message){ this._publish("execute", { item: message.item, node: message.node} ); this.onClick(message.item, message.node); }, _onDownArrow: function(/*Object*/ message){ // summary: down arrow pressed; get next visible node, set focus there var node = this._getNextNode(message.node); if(node && node.isTreeNode){ this.focusNode(node); } }, _onUpArrow: function(/*Object*/ message){ // summary: up arrow pressed; move to previous visible node var node = message.node; // if younger siblings var previousSibling = node.getPreviousSibling(); if(previousSibling){ node = previousSibling; // if the previous node is expanded, dive in deep while(node.isExpandable && node.isExpanded && node.hasChildren()){ // move to the last child var children = node.getChildren(); node = children[children.length-1]; } }else{ // if this is the first child, return the parent // unless the parent is the root of a tree with a hidden root var parent = node.getParent(); if(!(!this.showRoot && parent === this.rootNode)){ node = parent; } } if(node && node.isTreeNode){ this.focusNode(node); } }, _onRightArrow: function(/*Object*/ message){ // summary: right arrow pressed; go to child node var node = message.node; // if not expanded, expand, else move to 1st child if(node.isExpandable && !node.isExpanded){ this._expandNode(node); }else if(node.hasChildren()){ node = node.getChildren()[0]; if(node && node.isTreeNode){ this.focusNode(node); } } }, _onLeftArrow: function(/*Object*/ message){ // summary: // Left arrow pressed. // If not collapsed, collapse, else move to parent. var node = message.node; if(node.isExpandable && node.isExpanded){ this._collapseNode(node); }else{ node = node.getParent(); if(node && node.isTreeNode){ this.focusNode(node); } } }, _onHomeKey: function(){ // summary: home pressed; get first visible node, set focus there var node = this._getRootOrFirstNode(); if(node){ this.focusNode(node); } }, _onEndKey: function(/*Object*/ message){ // summary: end pressed; go to last visible node var node = this; while(node.isExpanded){ var c = node.getChildren(); node = c[c.length - 1]; } if(node && node.isTreeNode){ this.focusNode(node); } }, _onLetterKeyNav: function(message){ // summary: letter key pressed; search for node starting with first char = key var node = startNode = message.node, key = message.key; do{ node = this._getNextNode(node); //check for last node, jump to first node if necessary if(!node){ node = this._getRootOrFirstNode(); } }while(node !== startNode && (node.label.charAt(0).toLowerCase() != key)); if(node && node.isTreeNode){ // no need to set focus if back where we started if(node !== startNode){ this.focusNode(node); } } }, _onClick: function(/*Event*/ e){ // summary: translates click events into commands for the controller to process var domElement = e.target; // find node var nodeWidget = dijit.getEnclosingWidget(domElement); if(!nodeWidget || !nodeWidget.isTreeNode){ return; } if( (this.openOnClick && nodeWidget.isExpandable) || (domElement == nodeWidget.expandoNode || domElement == nodeWidget.expandoNodeText) ){ // expando node was clicked, or label of a folder node was clicked; open it if(nodeWidget.isExpandable){ this._onExpandoClick({node:nodeWidget}); } }else{ this._publish("execute", { item: nodeWidget.item, node: nodeWidget} ); this.onClick(nodeWidget.item, nodeWidget); this.focusNode(nodeWidget); } dojo.stopEvent(e); }, _onExpandoClick: function(/*Object*/ message){ // summary: user clicked the +/- icon; expand or collapse my children. var node = message.node; // If we are collapsing, we might be hiding the currently focused node. // Also, clicking the expando node might have erased focus from the current node. // For simplicity's sake just focus on the node with the expando. this.focusNode(node); if(node.isExpanded){ this._collapseNode(node); }else{ this._expandNode(node); } }, onClick: function(/* dojo.data */ item, /*TreeNode*/ node){ // summary: user overridable function for executing a tree item }, _getNextNode: function(node){ // summary: get next visible node if(node.isExpandable && node.isExpanded && node.hasChildren()){ // if this is an expanded node, get the first child return node.getChildren()[0]; // _TreeNode }else{ // find a parent node with a sibling while(node && node.isTreeNode){ var returnNode = node.getNextSibling(); if(returnNode){ return returnNode; // _TreeNode } node = node.getParent(); } return null; } }, _getRootOrFirstNode: function(){ // summary: get first visible node return this.showRoot ? this.rootNode : this.rootNode.getChildren()[0]; }, _collapseNode: function(/*_TreeNode*/ node){ // summary: called when the user has requested to collapse the node if(node.isExpandable){ if(node.state == "LOADING"){ // ignore clicks while we are in the process of loading data return; } node.collapse(); if(this.persist && node.item){ delete this._openedItemIds[this.model.getIdentity(node.item)]; this._saveState(); } } }, _expandNode: function(/*_TreeNode*/ node){ // summary: called when the user has requested to expand the node if(!node.isExpandable){ return; } var model = this.model, item = node.item; switch(node.state){ case "LOADING": // ignore clicks while we are in the process of loading data return; case "UNCHECKED": // need to load all the children, and then expand node.markProcessing(); var _this = this; model.getChildren(item, function(items){ node.unmarkProcessing(); node.setChildItems(items); _this._expandNode(node); }, function(err){ console.error(_this, ": error loading root children: ", err); }); break; default: // data is already loaded; just proceed node.expand(); if(this.persist && item){ this._openedItemIds[model.getIdentity(item)] = true; this._saveState(); } } }, ////////////////// Miscellaneous functions //////////////// blurNode: function(){ // summary // Removes focus from the currently focused node (which must be visible). // Usually not called directly (just call focusNode() on another node instead) var node = this.lastFocused; if(!node){ return; } var labelNode = node.labelNode; dojo.removeClass(labelNode, "dijitTreeLabelFocused"); labelNode.setAttribute("tabIndex", "-1"); dijit.setWaiState(labelNode, "selected", false); this.lastFocused = null; }, focusNode: function(/* _tree.Node */ node){ // summary // Focus on the specified node (which must be visible) // set focus so that the label will be voiced using screen readers node.labelNode.focus(); }, _onBlur: function(){ // summary: // We've moved away from the whole tree. The currently "focused" node // (see focusNode above) should remain as the lastFocused node so we can // tab back into the tree. Just change CSS to get rid of the dotted border // until that time this.inherited(arguments); if(this.lastFocused){ var labelNode = this.lastFocused.labelNode; dojo.removeClass(labelNode, "dijitTreeLabelFocused"); } }, _onTreeFocus: function(/*Widget*/ node){ // summary: // called from onFocus handler of treeitem labelNode to set styles, wai state and tabindex // for currently focused treeitem. if (node){ if(node != this.lastFocused){ this.blurNode(); } var labelNode = node.labelNode; // set tabIndex so that the tab key can find this node labelNode.setAttribute("tabIndex", "0"); dijit.setWaiState(labelNode, "selected", true); dojo.addClass(labelNode, "dijitTreeLabelFocused"); this.lastFocused = node; } }, //////////////// Events from the model ////////////////////////// _onItemDelete: function(/*Object*/ item){ //summary: delete event from the store // TODO: currently this isn't called, and technically doesn't need to be, // but it would help with garbage collection var identity = this.model.getIdentity(item); var node = this._itemNodeMap[identity]; if(node){ var parent = node.getParent(); if(parent){ // if node has not already been orphaned from a _onSetItem(parent, "children", ..) call... parent.removeChild(node); } delete this._itemNodeMap[identity]; node.destroyRecursive(); } }, _onItemChange: function(/*Item*/ item){ //summary: set data event on an item in the store var model = this.model, identity = model.getIdentity(item), node = this._itemNodeMap[identity]; if(node){ node.setLabelNode(this.getLabel(item)); node._updateItemClasses(item); } }, _onItemChildrenChange: function(/*dojo.data.Item*/ parent, /*dojo.data.Item[]*/ newChildrenList){ //summary: set data event on an item in the store var model = this.model, identity = model.getIdentity(parent), parentNode = this._itemNodeMap[identity]; if(parentNode){ parentNode.setChildItems(newChildrenList); } }, /////////////// Miscellaneous funcs _saveState: function(){ //summary: create and save a cookie with the currently expanded nodes identifiers if(!this.persist){ return; } var ary = []; for(var id in this._openedItemIds){ ary.push(id); } dojo.cookie(this.cookieName, ary.join(",")); }, destroy: function(){ if(this.rootNode){ this.rootNode.destroyRecursive(); } this.rootNode = null; this.inherited(arguments); }, destroyRecursive: function(){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -