+function ($) { 'use strict'; var Node = function (row) { var template = /treetable-([A-Za-z0-9_-]+)/; var parentTemplate = /treetable-parent-([A-Za-z0-9_-]+)/; this.row = row; this.id = null; if (template.test(this.row.attr('data-node'))) { this.id = template.exec(this.row.attr('data-node'))[1]; } this.parentId = null; if (parentTemplate.test(this.row.attr('data-pnode'))) { this.parentId = parentTemplate.exec(this.row.attr('data-pnode'))[1]; } this.children = []; this.status = true; } Node.prototype.addChildren = function(treeContainer) { var self = this; var templateData = "treetable-parent-" + self.id; var $children = treeContainer.find('[data-pnode="' + templateData + '"]'); if ($children.length != 0) { $.each($children, function(index, child) { var childNode = new Node($(child)); self.children.push(childNode) childNode.addChildren(treeContainer); }); } } Node.prototype.initIndent = function(treeFy) { this.row.find('.treetable-indent').remove(); var expander = this.row.find('.treetable-expander'); var depth = this.getDepth(treeFy.$table); for (var i = 0; i < depth; i++) { var indentTemplate = treeFy.options.indentTemplate; $(indentTemplate).insertBefore(expander); } } Node.prototype.initExpander = function(treeFy) { var self = this; var element = self.row.find('td').get(treeFy.options.treeColumn); var $expander = self.row.find('.treetable-expander'); if ($expander) { $expander.remove(); } var expanderTemplate = treeFy.options.expanderTemplate; $(expanderTemplate).prependTo(element).click(function(event) { //self.toggle($(this).closest('tr')); self.toggle(); }); } Node.prototype.renderExpand = function(treeFy) { var $expander = this.row.find('.treetable-expander'); if ($expander) { if (!this.row.hasClass('treetable-collapsed')) { $expander.removeClass(treeFy.options.expanderCollapsedClass); $expander.addClass(treeFy.options.expanderExpandedClass); } else { $expander.removeClass(treeFy.options.expanderExpandedClass); $expander.addClass(treeFy.options.expanderCollapsedClass); } } else { this.initExpander(treeFy); this.renderExpand(treeFy); } } Node.prototype.toggle = function() { if (this.row.hasClass('treetable-expanded')) { if (!this.isLeaf() && !this.row.hasClass('treetable-collapsed')) { this.row.removeClass('treetable-expanded'); this.row.addClass('treetable-collapsed'); } } else { if (!this.isLeaf() && !this.row.hasClass('treetable-expanded')) { this.row.removeClass('treetable-collapsed'); this.row.addClass('treetable-expanded'); } } } /* 是否为叶子节点 */ Node.prototype.isLeaf = function() { return this.children.length === 0; } Node.prototype.isCollapsed = function(treeContainer) { var isRoot = (this.getDepth(treeContainer) === 0); if (isRoot) { return false; } else { if (this.getParentNode(treeContainer).row.hasClass('treetable-collapsed')) { return true; } else { return this.getParentNode(treeContainer).isCollapsed(treeContainer); } } } Node.prototype.getDepth = function(treeContainer) { if (this.getParentNode(treeContainer) === null) { return 0; } return this.getParentNode(treeContainer).getDepth(treeContainer) + 1; } Node.prototype.getParentNode = function(treeContainer) { if (this.parentId === null) { return null; } else { return this.getNodeById(this.parentId, treeContainer); } } Node.prototype.getNodeById = function(id, treeContainer) { var templateData = "treetable-" + id; var $row = treeContainer.find('[data-node="' + templateData + '"]'); var node = new Node($row); node.addChildren(treeContainer); return node; } var TreeFy = function (element, options) { this.options = options; this.$table = $(element); var allNodes = this.getAllNodes(); this.initTree(allNodes); return TreeFy; } TreeFy.VERSION = '0.0.1' TreeFy.prototype.getAllNodes = function() { var self = this; var result = $.grep(self.$table.find('tr'), function(trElement) { var nodeData = $(trElement).attr('data-node'); var template = /treetable-([A-Za-z0-9_-]+)/; return template.test(nodeData); }); var $allNodes = $(result); var allNodes = []; $.each($allNodes, function() { var node = new Node($(this)); node.addChildren(self.$table); allNodes.push(node); }); return allNodes; } TreeFy.prototype.initTree = function(allNodes) { var self = this; var rootNodes = []; $.each(allNodes, function() { var noChildren = this.children.length === 0; if (!noChildren) { this.row.addClass(self.options.initStatusClass); } if (!this.parentId) { rootNodes.push(this); } }); self.initNode(rootNodes); self.render(rootNodes); } TreeFy.prototype.initNode = function(nodes) { var self = this; $.each(nodes, function() { self.initNode(this.children); this.initExpander(self); this.initIndent(self); var $row = this.row; var click_nodes = []; click_nodes.push(this); $row.find('.treetable-expander').on("click", function(event) { event.stopPropagation(); self.render(click_nodes); }); }); } TreeFy.prototype.render = function(nodes) { var self = this; $.each(nodes, function(node) { //若父节点折叠, 隐藏子节点 if (this.isCollapsed(self.$table)) { this.row.hide(); } else { this.row.show(); } if (!this.isLeaf()) { this.renderExpand(self); self.render(this.children); } }) } // PLUGIN DEFINITION // ======================= function Plugin(option) { var args = arguments; var ret; return this.each(function () { var $this = $(this) var data = $this.data('treeFy') if (!data) { var options = $.extend(true, {}, $.fn.treeFy.defaults, typeof option == 'object' && option); $this.data('treeFy', (data = new TreeFy(this, options))); } if (typeof option == 'string') data[option].call($this) }) if (typeof option == 'string') { if (args.length == 1) { var _ret = data[option].call(data); if (typeof _ret != 'undefined') { ret = _ret; } } else { var _ret = data[option].apply(data, Array.prototype.slice.call(args, 1)); if (typeof _ret != 'undefined') { ret = _ret; } } } if (typeof ret != 'undefined') { return ret; } return this; } var old = $.fn.treeFy $.fn.treeFy = Plugin $.fn.treeFy.Constructor = TreeFy $.fn.treeFy.defaults = { expanderTemplate: '', indentTemplate: '', expanderExpandedClass: 'fa fa-angle-down', expanderCollapsedClass: 'fa fa-angle-right', treeColumn: 0, initStatusClass: 'treetable-expanded' } // ALERT NO CONFLICT // ================= $.fn.treeFy.noConflict = function () { $.fn.treeFy = old return this } }(jQuery);