UNPKG

zui

Version:

一个基于 Bootstrap 深度定制开源前端实践方案,帮助你快速构建现代跨屏应用。

412 lines (372 loc) 15.1 kB
/* ======================================================================== * ZUI: tree.js [1.4.0+] * http://zui.sexy * ======================================================================== * Copyright (c) 2016 cnezsoft.com; Licensed MIT * ======================================================================== */ (function($) { 'use strict'; var name = 'zui.tree'; // modal name var globalId = 0; // The tree modal class var Tree = function(element, options) { this.name = name; this.$ = $(element); this.getOptions(options); this._init(); }; var DETAULT_ACTIONS = { sort: { template: '<a class="sort-handler" href="javascript:;"><i class="icon icon-move"></i></a>' }, add: { template: '<a href="javascript:;"><i class="icon icon-plus"></i></a>' }, edit: { template: '<a href="javascript:;"><i class="icon icon-pencil"></i></a>' }, "delete": { template: '<a href="javascript:;"><i class="icon icon-trash"></i></a>' } }; function formatActions(actions, parentActions) { if(actions === false) return actions; if(!actions) return parentActions; if(actions === true) { actions = {add: true, "delete": true, edit: true, sort: true}; } else if(typeof actions === 'string') { actions = actions.split(','); } var _actions; if($.isArray(actions)) { _actions = {}; $.each(actions, function(idx, action) { if($.isPlainObject(action)) { _actions[action.action] = action; } else { _actions[action] = true; } }); actions = _actions; } if($.isPlainObject(actions)) { _actions = {}; $.each(actions, function(name, action) { if(action) { _actions[name] = $.extend({type: name}, DETAULT_ACTIONS[name], $.isPlainObject(action) ? action : null); } else { _actions[name] = false; } }); actions = _actions; } return parentActions ? $.extend(true, {}, parentActions, actions) : actions; } function createActionEle(action, name, template) { name = name || action.type; return $(template || action.template).addClass('tree-action').attr($.extend({'data-type': name, title: action.title || ''}, action.attr)).data('action', action); } // default options Tree.DEFAULTS = { animate: null, initialState: 'normal', // 'normal' | 'preserve' | 'expand' | 'collapse', toggleTemplate: '<i class="list-toggle icon"></i>', // sortable: false, // }; Tree.prototype.add = function(rootEle, items, expand, disabledAnimate, notStore) { var $e = $(rootEle), $ul, options = this.options; if($e.is('li')) { $ul = $e.children('ul'); if(!$ul.length) { $ul = $('<ul/>'); $e.append($ul); this._initList($ul, $e); } } else { $ul = $e; } if($ul) { var that = this; if(!$.isArray(items)) { items = [items]; } $.each(items, function(idx, item) { var $li = $('<li/>').data(item).appendTo($ul); if(item.id !== undefined) $li.attr('data-id', item.id); var $wrapper = options.itemWrapper ? $(options.itemWrapper === true ? '<div class="tree-item-wrapper"/>' : options.itemWrapper).appendTo($li) : $li; if(item.html) { $wrapper.html(item.html) } else if($.isFunction(that.options.itemCreator)) { var itemContent = that.options.itemCreator($li, item); if(itemContent !== true && itemContent !== false) $wrapper.html(itemContent); } else if(item.url) { $wrapper.append($('<a/>', {href: item.url}).text(item.title || item.name)); } else { $wrapper.append($('<span/>').text(item.title || item.name)); } that._initItem($li, item.idx || idx, $ul, item); if(item.children && item.children.length) { that.add($li, item.children); } }); this._initList($ul); if(expand && !$ul.hasClass('tree')) { that.expand($ul.parent('li'), disabledAnimate, notStore); } } }; Tree.prototype.reload = function(data) { var that = this; if(data) { that.$.empty(); that.add(that.$, data); } if(that.isPreserve) { if(that.store.time) { that.$.find('li:not(.tree-action-item)').each(function() { var $li= $(this); that[that.store[$li.data('id')] ? 'expand' : 'collapse']($li, true, true); }); } } }; Tree.prototype._initList = function($list, $parentItem, idx, data) { var that = this; if(!$list.hasClass('tree')) { $parentItem = ($parentItem || $list.closest('li')).addClass('has-list'); if(!$parentItem.find('.list-toggle').length) { $parentItem.prepend(this.options.toggleTemplate); } idx = idx || $parentItem.data('idx'); } else { idx = 0; $parentItem = null; } $list.removeClass('has-active-item'); var $children = $list.attr('data-idx', idx || 0).children('li:not(.tree-action-item)').each(function(index) { that._initItem($(this), index + 1, $list); }); if($children.length === 1 && !$children.find('ul').length) { $children.addClass('tree-single-item'); } data = data || ($parentItem ? $parentItem.data() : null); var actions = formatActions(data ? data.actions : null, this.actions); if(actions) { if(actions.add && actions.add.templateInList !== false) { var $actionItem = $list.children('li.tree-action-item'); if(!$actionItem.length) { $('<li class="tree-action-item"/>').append(createActionEle(actions.add, 'add', actions.add.templateInList)).appendTo($list); } else { $actionItem.detach().appendTo($list); } } if(actions.sort) { $list.sortable($.extend({ dragCssClass: 'tree-drag-holder', trigger: '.sort-handler', selector: 'li:not(.tree-action-item)', finish: function(e) { that.callEvent('action', {action: actions.sort, $list: $list, target: e.target, item: data}); } }, actions.sort.options, $.isPlainObject(this.options.sortable) ? this.options.sortable : null)); } } if($parentItem && ($parentItem.hasClass('open') || (data && data.open))) { $parentItem.addClass('open in'); } }; Tree.prototype._initItem = function($item, idx, $parentList, data) { if(idx === undefined) { var $pre = $item.prev('li'); idx = $pre.length ? ($pre.data('idx') + 1) : 1; } $parentList = $parentList || $item.closest('ul'); $item.attr('data-idx', idx).removeClass('tree-single-item'); if(!$item.data('id')) { var id = idx; if(!$parentList.hasClass('tree')) { id = $parentList.parent('li').data('id') + '-' + id; } $item.attr('data-id', id); } if ($item.hasClass('active')) { $parentList.parent('li').addClass('has-active-item'); } data = data || $item.data(); var actions = formatActions(data.actions, this.actions); if(actions) { var $actions = $item.find('.tree-actions'); if(!$actions.length) { $actions = $('<div class="tree-actions"/>').appendTo(this.options.itemWrapper ? $item.find('.tree-item-wrapper') : $item); $.each(actions, function(actionName, action) { if(action) $actions.append(createActionEle(action, actionName)); }); } } var $children = $item.children('ul'); if($children.length) { this._initList($children, $item, idx, data); } }; Tree.prototype._init = function() { var options = this.options, that = this; this.actions = formatActions(options.actions); this.$.addClass('tree'); if(options.animate) this.$.addClass('tree-animate'); this._initList(this.$); var initialState = options.initialState; var isPreserveEnable = $.zui && $.zui.store && $.zui.store.enable; if(isPreserveEnable) { this.selector = name + '::' + (options.name || '') + '#' + (this.$.attr('id') || globalId++); this.store = $.zui.store[options.name ? 'get' : 'pageGet'](this.selector, {}); } if(initialState === 'preserve') { if(isPreserveEnable) this.isPreserve = true; else this.options.initialState = initialState = 'normal'; } // init data this.reload(options.data); if(isPreserveEnable) this.isPreserve = true; if(initialState === 'expand') { this.expand(); } else if(initialState === 'collapse') { this.collapse(); } // Bind event this.$.on('click', '.list-toggle,a[href="#"],.tree-toggle', function(e) { var $this = $(this); var $li = $this.parent('li'); that.callEvent('hit', {target: $li, item: $li.data()}); that.toggle($li); if($this.is('a')) e.preventDefault(); }).on('click', '.tree-action', function() { var $action = $(this); var action = $action.data(); if(action.action) action = action.action; if(action.type === 'sort') return; var $li = $action.closest('li:not(.tree-action-item)'); that.callEvent('action', {action: action, target: this, $item: $li, item: $li.data()}); }); }; Tree.prototype.preserve = function($li, id, expand) { if(!this.isPreserve) return; if($li) { id = id || $li.data('id'); expand = expand === undefined ? $li.hasClass('open') : false; if(expand) this.store[id] = expand; else delete this.store[id]; this.store.time = new Date().getTime(); $.zui.store[this.options.name ? 'set' : 'pageSet'](this.selector, this.store); } else { var that = this; this.store = {}; this.$.find('li').each(function() { that.preserve($(this)); }); } }; Tree.prototype.expand = function($li, disabledAnimate, notStore) { if($li) { $li.addClass('open'); if(!disabledAnimate && this.options.animate) { setTimeout(function() { $li.addClass('in'); }, 10); } else { $li.addClass('in'); } } else { $li = this.$.find('li.has-list').addClass('open in'); } if(!notStore) this.preserve($li); this.callEvent('expand', $li, this); }; Tree.prototype.show = function($lis, disabledAnimate, notStore) { var that = this; $lis.each(function() { var $li = $(this); that.expand($li, disabledAnimate, notStore); if($li) { var $ul = $li.parent('ul'); while($ul && $ul.length && !$ul.hasClass('tree')) { var $parentLi = $ul.parent('li'); if($parentLi.length) { that.expand($parentLi, disabledAnimate, notStore); $ul = $parentLi.parent('ul'); } else { $ul = false; } } } }); }; Tree.prototype.collapse = function($li, disabledAnimate, notStore) { if($li) { if(!disabledAnimate && this.options.animate) { $li.removeClass('in'); setTimeout(function() { $li.removeClass('open'); }, 300); } else { $li.removeClass('open in'); } } else { $li = this.$.find('li.has-list').removeClass('open in'); } if(!notStore) this.preserve($li); this.callEvent('collapse', $li, this); }; Tree.prototype.toggle = function($li) { var collapse = ($li && $li.hasClass('open')) || $li === false || ($li === undefined && this.$.find('li.has-list.open').length); this[collapse ? 'collapse' : 'expand']($li); }; // Get and init options Tree.prototype.getOptions = function(options) { this.options = $.extend({}, Tree.DEFAULTS, this.$.data(), options); if(this.options.animate === null && this.$.hasClass('tree-animate')) { this.options.animate = true; } }; Tree.prototype.toData = function($ul, filter) { if($.isFunction($ul)) { filter = $ul; $ul = null; } $ul = $ul || this.$; var that = this; return $ul.children('li:not(.tree-action-item)').map(function() { var $li = $(this); var data = $li.data(); delete data['zui.droppable']; var $children = $li.children('ul'); if($children.length) data.children = that.toData($children); return $.isFunction(filter) ? filter(data, $li) : data; }).get(); }; // Call event helper Tree.prototype.callEvent = function(name, params) { var result; if($.isFunction(this.options[name])) { result = this.options[name](params, this); } this.$.trigger($.Event(name + '.' + this.name, params)); return result; }; // Extense jquery element $.fn.tree = function(option, params) { return this.each(function() { var $this = $(this); var data = $this.data(name); var options = typeof option == 'object' && option; if(!data) $this.data(name, (data = new Tree(this, options))); if(typeof option == 'string') data[option](params); }); }; $.fn.tree.Constructor = Tree; // Auto call tree after document load complete $(function() { $('[data-ride="tree"]').tree(); }); }(jQuery));