/////////////////////////////////////////////////////////////////////////// // Copyright © 2014 - 2018 Esri. All Rights Reserved. // // Licensed under the Apache License Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. /////////////////////////////////////////////////////////////////////////// define(['dojo/_base/declare', 'dijit/_WidgetBase', 'dijit/_TemplatedMixin', 'dojo/text!./templates/_TreeNode.html', 'dojo/_base/lang', 'dojo/_base/html', 'dojo/_base/array', 'dojo/_base/event', 'dojo/query', 'dojo/aspect', 'dojo/on', 'dojo/Evented', 'dijit/registry', 'dijit/Tree', 'jimu/utils' ], function(declare, _WidgetBase, _TemplatedMixin, tnTemplate, lang, html, array, dojoEvent, query, aspect, on, Evented, registry, DojoTree, jimuUtils) { /*jshint unused: false*/ var JimuTreeNode = declare([DojoTree._TreeNode, Evented], { templateString: tnTemplate, declaredClass: 'jimu._TreeNode', //options: isLeaf: false, groupId: "", //radio group postCreate: function(){ this.inherited(arguments); html.addClass(this.domNode, 'jimu-tree-node'); this.isLeaf = !!this.isLeaf; if(this.groupId){ this.checkNode = html.toDom(''); this.checkNode.name = this.groupId; } else{ this.checkNode = html.toDom(''); } html.addClass(this.checkNode, "jimu-tree-check-node"); html.place(this.checkNode, this.contentNode, 'first'); this.own(on(this.checkNode, 'click', lang.hitch(this, this._onClick))); if(this.isLeaf){ if(this.groupId){ html.setStyle(this.checkNode, 'display', 'none'); }else{ html.setStyle(this.checkNode, 'display', 'inline'); } } else{ html.setStyle(this.checkNode, 'display', 'none'); } if(this.isLeaf){ html.addClass(this.domNode, 'jimu-tree-leaf-node'); }else{ html.addClass(this.domNode, 'jimu-tree-not-leaf-node'); } }, // hasSelectedClass: function(){ // if(this.rowNode){ // if(html.hasClass(this.rowNode, 'dijitTreeRowSelected')){ // return true; // } // } // return false; // }, select: function(){ if(this.isLeaf){ this.checkNode.checked = true; html.addClass(this.domNode, 'jimu-tree-selected-leaf-node'); } }, unselect: function(){ if(this.isLeaf){ this.checkNode.checked = false; html.removeClass(this.domNode, 'jimu-tree-selected-leaf-node'); } }, toggleSelect: function(){ if(this.isLeaf){ if(this.checkNode.checked){ this.unselect(); }else{ this.select(); } } }, _onClick: function(evt){ var target = evt.target || evt.srcElement; if(target === this.checkNode){ this.tree._onCheckNodeClick(this, this.checkNode.checked, evt); } else{ this.tree._onClick(this, evt); } }, _onChange: function(){ if(this.isLeaf){ setTimeout(lang.hitch(this, function(){ if(this.checkNode.checked){ this.emit('tn-select', this); } else{ this.emit('tn-unselect', this); } }), 100); } }, destroy: function(){ delete this.tree; this.inherited(arguments); } }); var JimuTree = declare([DojoTree, Evented], { declaredClass:'jimu._Tree', openOnClick: true, //options: multiple: true, uniqueId: '', showRoot: false, //public methods: //getSelectedItems //getTreeNodeByItemId //selectItem //unselectItem //removeItem //getAllLeafTreeNodeWidgets //getAllTreeNodeWidgets //method need to be override //isLeafItem postMixInProperties: function(){ this.inherited(arguments); this.uniqueId = "tree_" + jimuUtils.getRandomString(); }, postCreate: function(){ this.inherited(arguments); html.addClass(this.domNode, 'jimu-tree'); this.own(aspect.before(this, 'onClick', lang.hitch(this, this._jimuBeforeClick))); //this.own(aspect.before(this, 'onOpen', lang.hitch(this, this._jimuBeforeOpen))); if(this.rootLoadingIndicator){ html.setStyle(this.rootLoadingIndicator, 'display', 'none'); } //disable selection by shift key or ctrl key + mouse click //http://stackoverflow.com/questions/12261723/ //how-to-disable-multiple-selection-of-nodes-in-dijit-tree this.dndController.singular = true; }, removeItem: function(id){ this.model.store.remove(id); }, getAllItems: function(){ var allTNs = this.getAllTreeNodeWidgets(); var items = array.map(allTNs, lang.hitch(this, function(tn){ var a = tn.item;//lang.clone(tn.item); a.selected = tn.checkNode.checked; return a; })); return items; }, getSelectedItems: function(){ var allTNs = this.getAllTreeNodeWidgets(); var selectedTNs = array.filter(allTNs, lang.hitch(this, function(tn){ return tn.checkNode.checked; })); // selectedTNs = array.filter(selectedTNs, lang.hitch(this, function(tn){ // return tn.hasSelectedClass(); // })); var items = array.map(selectedTNs, lang.hitch(this, function(tn){ return tn.item; })); return items;//lang.clone(items) may throw an error }, getFilteredItems: function(func){ var allTNs = this.getAllTreeNodeWidgets(); var allItems = array.map(allTNs, lang.hitch(this, function(tn){ var a = tn.item;//lang.clone(tn.item); a.selected = tn.checkNode.checked; return a; })); var filteredItems = array.filter(allItems, lang.hitch(this, function(item){ return func(item); })); return filteredItems; }, getTreeNodeByItemId: function(itemId){ var doms = this._getAllTreeNodeDoms(); for(var i = 0; i < doms.length; i++){ var d = doms[i]; var tn = registry.byNode(d); if(tn.item.id.toString() === itemId.toString()){ return tn; } } return null; }, selectItem: function(itemId){ var tn = this.getTreeNodeByItemId(itemId); if(tn && tn.isLeaf){ //tn.select(); this.selectNodeWidget(tn); } }, unselectItem: function(itemId){ var tn = this.getTreeNodeByItemId(itemId); if(tn && tn.isLeaf){ tn.unselect(); } }, getAllLeafTreeNodeWidgets: function(){ var tns = this.getAllTreeNodeWidgets(); return array.filter(tns, lang.hitch(this, function(tn){ return tn.isLeaf; })); }, getAllTreeNodeWidgets: function(){ var doms = this._getAllTreeNodeDoms(); return array.map(doms, lang.hitch(this, function(node){ return registry.byNode(node); })); }, //to be override isLeafItem: function(item){ return item && item.isLeaf; }, _getAllTreeNodeDoms: function(){ return query('.dijitTreeNode', this.domNode); }, _createTreeNode: function(args){ args.isLeaf = this.isLeafItem(args.item); if(!this.multiple){ args.groupId = this.uniqueId; } var tn = new JimuTreeNode(args); // this.own(on(tn, 'tn-select', lang.hitch(this, this._onTreeNodeSelect))); // this.own(on(tn, 'tn-unselect', lang.hitch(this, this._onTreeNodeUnselect))); return tn; }, _onTreeNodeSelect: function(/*TreeNode*/ nodeWidget){ var item = nodeWidget.item; var args = { item: item, treeNode: nodeWidget }; this.emit('item-select', args); }, _onTreeNodeUnselect: function(/*TreeNode*/ nodeWidget){ var item = nodeWidget.item; var args = { item: item, treeNode: nodeWidget }; this.emit('item-unselect', args); }, selectNodeWidget: function(nodeWidget){ if(!this.multiple){ this.unselectAllLeafNodeWidgets(); } nodeWidget.select(); }, _jimuBeforeClick: function(item, node, evt){ /*jshint unused: false*/ //only handle leaf node if(node.isLeaf){ var target = evt.target || evt.srcElement; //if click in node, we don't handle it //only handle it when click the row if(!html.hasClass(target, 'jimu-tree-check-node')){ if(this.multiple){ node.toggleSelect(); }else{ //node.select(); this.selectNodeWidget(node); } } } return arguments; }, _onCheckNodeClick: function(/*TreeNode*/ nodeWidget,/*Boolean*/ newState, /*Event*/ evt){ if(!this.multiple && newState){ this.unselectAllLeafNodeWidgets(); } dojoEvent.stop(evt); this.focusNode(nodeWidget); setTimeout(lang.hitch(this, function(){ if(newState){ //nodeWidget.select(); this.selectNodeWidget(nodeWidget); }else{ nodeWidget.unselect(); } //nodeWidget.checkNode.checked = newState; this.onClick(nodeWidget.item, nodeWidget, evt); }), 0); }, unselectAllLeafNodeWidgets: function(){ // var allCbxes = query('.jimu-tree-check-node', this.domNode); // array.forEach(allCbxes, lang.hitch(this, function(checkNode){ // checkNode.checked = false; // })); var nodes = this.getAllLeafTreeNodeWidgets(); array.forEach(nodes, lang.hitch(this, function(nodeWidget){ nodeWidget.unselect(); })); } }); return JimuTree; });