• bootstraptreeview 拖拽


    /* =========================================================
     * bootstrap-treeview.js v1.2.0
     * =========================================================
     * Copyright 2013 Jonathan Miles
     * Project URL : http://www.jondmiles.com/bootstrap-treeview
     *
     * 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.
     * ========================================================= */
    
    ; (function ($, window, document, undefined) {
    
        /*global jQuery, console*/
    
        'use strict';
    
        var pluginName = 'treeview';
    
        var _default = {};
    
        _default.settings = {
    
            injectStyle: true,
    
            levels: 2,
    
            expandIcon: 'glyphicon glyphicon-plus',
            collapseIcon: 'glyphicon glyphicon-minus',
            emptyIcon: 'glyphicon',
            nodeIcon: '',
            selectedIcon: '',
            checkedIcon: 'glyphicon glyphicon-check',
            uncheckedIcon: 'glyphicon glyphicon-unchecked',
    
            color: undefined, // '#000000',
            backColor: undefined, // '#FFFFFF',
            borderColor: undefined, // '#dddddd',
            onhoverColor: '#F5F5F5',
            selectedColor: '#FFFFFF',
            selectedBackColor: '#428bca',
            searchResultColor: '#D9534F',
            searchResultBackColor: undefined, //'#FFFFFF',
    
            enableLinks: false,
            highlightSelected: true,
            highlightSearchResults: true,
            showBorder: true,
            showIcon: true,
            showCheckbox: false,
            showTags: false,
            multiSelect: false,
    
            // Event handlers
            onNodeChecked: undefined,
            onNodeCollapsed: undefined,
            onNodeDisabled: undefined,
            onNodeEnabled: undefined,
            onNodeExpanded: undefined,
            onNodeSelected: undefined,
            onNodeUnchecked: undefined,
            onNodeUnselected: undefined,
            onSearchComplete: undefined,
            onSearchCleared: undefined,
            onDragStart: undefined
        };
    
        _default.options = {
            silent: false,
            ignoreChildren: false
        };
    
        _default.searchOptions = {
            ignoreCase: true,
            exactMatch: false,
            revealResults: true
        };
    
        var Tree = function (element, options) {
    
            this.$element = $(element);
            this.elementId = element.id;
            this.styleId = this.elementId + '-style';
    
            this.init(options);
    
            return {
    
                // Options (public access)
                options: this.options,
    
                // Initialize / destroy methods
                init: $.proxy(this.init, this),
                remove: $.proxy(this.remove, this),
    
                // Get methods
                getNode: $.proxy(this.getNode, this),
                getParent: $.proxy(this.getParent, this),
                getSiblings: $.proxy(this.getSiblings, this),
                getSelected: $.proxy(this.getSelected, this),
                getUnselected: $.proxy(this.getUnselected, this),
                getExpanded: $.proxy(this.getExpanded, this),
                getCollapsed: $.proxy(this.getCollapsed, this),
                getChecked: $.proxy(this.getChecked, this),
                getUnchecked: $.proxy(this.getUnchecked, this),
                getDisabled: $.proxy(this.getDisabled, this),
                getEnabled: $.proxy(this.getEnabled, this),
    
                // Select methods
                selectNode: $.proxy(this.selectNode, this),
                unselectNode: $.proxy(this.unselectNode, this),
                toggleNodeSelected: $.proxy(this.toggleNodeSelected, this),
    
                // Expand / collapse methods
                collapseAll: $.proxy(this.collapseAll, this),
                collapseNode: $.proxy(this.collapseNode, this),
                expandAll: $.proxy(this.expandAll, this),
                expandNode: $.proxy(this.expandNode, this),
                toggleNodeExpanded: $.proxy(this.toggleNodeExpanded, this),
                revealNode: $.proxy(this.revealNode, this),
    
                // Expand / collapse methods
                checkAll: $.proxy(this.checkAll, this),
                checkNode: $.proxy(this.checkNode, this),
                uncheckAll: $.proxy(this.uncheckAll, this),
                uncheckNode: $.proxy(this.uncheckNode, this),
                toggleNodeChecked: $.proxy(this.toggleNodeChecked, this),
    
                // Disable / enable methods
                disableAll: $.proxy(this.disableAll, this),
                disableNode: $.proxy(this.disableNode, this),
                enableAll: $.proxy(this.enableAll, this),
                enableNode: $.proxy(this.enableNode, this),
                toggleNodeDisabled: $.proxy(this.toggleNodeDisabled, this),
    
                // Search methods
                search: $.proxy(this.search, this),
                clearSearch: $.proxy(this.clearSearch, this)
            };
        };
    
        Tree.prototype.init = function (options) {
    
            this.tree = [];
            this.nodes = [];
    
            if (options.data) {
                if (typeof options.data === 'string') {
                    options.data = $.parseJSON(options.data);
                }
                this.tree = $.extend(true, [], options.data);
                delete options.data;
            }
            this.options = $.extend({}, _default.settings, options);
    
            this.destroy();
            this.subscribeEvents();
            this.setInitialStates({ nodes: this.tree }, 0);
            this.render();
        };
    
        Tree.prototype.remove = function () {
            this.destroy();
            $.removeData(this, pluginName);
            $('#' + this.styleId).remove();
        };
    
        Tree.prototype.destroy = function () {
    
            if (!this.initialized) return;
    
            this.$wrapper.remove();
            this.$wrapper = null;
    
            // Switch off events
            this.unsubscribeEvents();
    
            // Reset this.initialized flag
            this.initialized = false;
        };
    
        Tree.prototype.unsubscribeEvents = function () {
    
            this.$element.off('click');
            this.$element.off('nodeChecked');
            this.$element.off('nodeCollapsed');
            this.$element.off('nodeDisabled');
            this.$element.off('nodeEnabled');
            this.$element.off('nodeExpanded');
            this.$element.off('nodeSelected');
            this.$element.off('nodeUnchecked');
            this.$element.off('nodeUnselected');
            this.$element.off('searchComplete');
            this.$element.off('searchCleared');
        };
    
        Tree.prototype.subscribeEvents = function () {
    
            this.unsubscribeEvents();
    
            this.$element.on('click', $.proxy(this.clickHandler, this));
    
            if (typeof (this.options.onNodeChecked) === 'function') {
                this.$element.on('nodeChecked', this.options.onNodeChecked);
            }
    
            if (typeof (this.options.onNodeCollapsed) === 'function') {
                this.$element.on('nodeCollapsed', this.options.onNodeCollapsed);
            }
    
            if (typeof (this.options.onNodeDisabled) === 'function') {
                this.$element.on('nodeDisabled', this.options.onNodeDisabled);
            }
    
            if (typeof (this.options.onNodeEnabled) === 'function') {
                this.$element.on('nodeEnabled', this.options.onNodeEnabled);
            }
    
            if (typeof (this.options.onNodeExpanded) === 'function') {
                this.$element.on('nodeExpanded', this.options.onNodeExpanded);
            }
    
            if (typeof (this.options.onNodeSelected) === 'function') {
                this.$element.on('nodeSelected', this.options.onNodeSelected);
            }
    
            if (typeof (this.options.onNodeUnchecked) === 'function') {
                this.$element.on('nodeUnchecked', this.options.onNodeUnchecked);
            }
    
            if (typeof (this.options.onNodeUnselected) === 'function') {
                this.$element.on('nodeUnselected', this.options.onNodeUnselected);
            }
    
            if (typeof (this.options.onSearchComplete) === 'function') {
                this.$element.on('searchComplete', this.options.onSearchComplete);
            }
    
            if (typeof (this.options.onSearchCleared) === 'function') {
                this.$element.on('searchCleared', this.options.onSearchCleared);
            }
        };
    
        /*
            Recurse the tree structure and ensure all nodes have
            valid initial states.  User defined states will be preserved.
            For performance we also take this opportunity to
            index nodes in a flattened structure
        */
        Tree.prototype.setInitialStates = function (node, level) {
    
            if (!node.nodes) return;
            level += 1;
    
            var parent = node;
            var _this = this;
            $.each(node.nodes, function checkStates(index, node) {
    
                // nodeId : unique, incremental identifier
                node.nodeId = _this.nodes.length;
    
                // parentId : transversing up the tree
                node.parentId = parent.nodeId;
    
                // if not provided set selectable default value
                if (!node.hasOwnProperty('selectable')) {
                    node.selectable = true;
                }
    
                // where provided we should preserve states
                node.state = node.state || {};
    
                // set checked state; unless set always false
                if (!node.state.hasOwnProperty('checked')) {
                    node.state.checked = false;
                }
    
                // set enabled state; unless set always false
                if (!node.state.hasOwnProperty('disabled')) {
                    node.state.disabled = false;
                }
    
                // set expanded state; if not provided based on levels
                if (!node.state.hasOwnProperty('expanded')) {
                    if (!node.state.disabled &&
                        (level < _this.options.levels) &&
                        (node.nodes && node.nodes.length > 0)) {
                        node.state.expanded = true;
                    }
                    else {
                        node.state.expanded = false;
                    }
                }
    
                // set selected state; unless set always false
                if (!node.state.hasOwnProperty('selected')) {
                    node.state.selected = false;
                }
    
                // index nodes in a flattened structure for use later
                _this.nodes.push(node);
    
                // recurse child nodes and transverse the tree
                if (node.nodes) {
                    _this.setInitialStates(node, level);
                }
            });
        };
    
        Tree.prototype.clickHandler = function (event) {
    
            if (!this.options.enableLinks) event.preventDefault();
    
            var target = $(event.target);
            var node = this.findNode(target);
            if (!node || node.state.disabled) return;
    
            var classList = target.attr('class') ? target.attr('class').split(' ') : [];
            if ((classList.indexOf('expand-icon') !== -1)) {
    
                this.toggleExpandedState(node, _default.options);
                this.render();
            }
            else if ((classList.indexOf('check-icon') !== -1)) {
    
                this.toggleCheckedState(node, _default.options);
                this.render();
            }
            else {
    
                if (node.selectable) {
                    this.toggleSelectedState(node, _default.options);
                } else {
                    this.toggleExpandedState(node, _default.options);
                }
    
                this.render();
            }
        };
    
        // Looks up the DOM for the closest parent list item to retrieve the
        // data attribute nodeid, which is used to lookup the node in the flattened structure.
        Tree.prototype.findNode = function (target) {
    
            var nodeId = target.closest('li.list-group-item').attr('data-nodeid');
            var node = this.nodes[nodeId];
    
            if (!node) {
                console.log('Error: node does not exist');
            }
            return node;
        };
    
        Tree.prototype.toggleExpandedState = function (node, options) {
            if (!node) return;
            this.setExpandedState(node, !node.state.expanded, options);
        };
    
        Tree.prototype.setExpandedState = function (node, state, options) {
    
            if (state === node.state.expanded) return;
    
            if (state && node.nodes) {
    
                // Expand a node
                node.state.expanded = true;
                if (!options.silent) {
                    this.$element.trigger('nodeExpanded', $.extend(true, {}, node));
                }
            }
            else if (!state) {
    
                // Collapse a node
                node.state.expanded = false;
                if (!options.silent) {
                    this.$element.trigger('nodeCollapsed', $.extend(true, {}, node));
                }
    
                // Collapse child nodes
                if (node.nodes && !options.ignoreChildren) {
                    $.each(node.nodes, $.proxy(function (index, node) {
                        this.setExpandedState(node, false, options);
                    }, this));
                }
            }
        };
    
        Tree.prototype.toggleSelectedState = function (node, options) {
            if (!node) return;
            this.setSelectedState(node, !node.state.selected, options);
        };
    
        Tree.prototype.setSelectedState = function (node, state, options) {
    
            if (state === node.state.selected) return;
    
            if (state) {
    
                // If multiSelect false, unselect previously selected
                if (!this.options.multiSelect) {
                    $.each(this.findNodes('true', 'g', 'state.selected'), $.proxy(function (index, node) {
                        this.setSelectedState(node, false, options);
                    }, this));
                }
    
                // Continue selecting node
                node.state.selected = true;
                if (!options.silent) {
                    this.$element.trigger('nodeSelected', $.extend(true, {}, node));
                }
            }
            else {
    
                // Unselect node
                node.state.selected = false;
                if (!options.silent) {
                    this.$element.trigger('nodeUnselected', $.extend(true, {}, node));
                }
            }
        };
    
        Tree.prototype.toggleCheckedState = function (node, options) {
            if (!node) return;
            this.setCheckedState(node, !node.state.checked, options);
        };
    
        Tree.prototype.setCheckedState = function (node, state, options) {
    
            if (state === node.state.checked) return;
    
            if (state) {
    
                // Check node
                node.state.checked = true;
    
                if (!options.silent) {
                    this.$element.trigger('nodeChecked', $.extend(true, {}, node));
                }
            }
            else {
    
                // Uncheck node
                node.state.checked = false;
                if (!options.silent) {
                    this.$element.trigger('nodeUnchecked', $.extend(true, {}, node));
                }
            }
        };
    
        Tree.prototype.setDisabledState = function (node, state, options) {
    
            if (state === node.state.disabled) return;
    
            if (state) {
    
                // Disable node
                node.state.disabled = true;
    
                // Disable all other states
                this.setExpandedState(node, false, options);
                this.setSelectedState(node, false, options);
                this.setCheckedState(node, false, options);
    
                if (!options.silent) {
                    this.$element.trigger('nodeDisabled', $.extend(true, {}, node));
                }
            }
            else {
    
                // Enabled node
                node.state.disabled = false;
                if (!options.silent) {
                    this.$element.trigger('nodeEnabled', $.extend(true, {}, node));
                }
            }
        };
    
        Tree.prototype.render = function () {
    
            if (!this.initialized) {
    
                // Setup first time only components
                this.$element.addClass(pluginName);
                this.$wrapper = $(this.template.list);
    
                this.injectStyle();
    
                this.initialized = true;
            }
    
            this.$element.empty().append(this.$wrapper.empty());
    
            // Build tree
            this.buildTree(this.tree, 0);
        };
    
        // Starting from the root node, and recursing down the
        // structure we build the tree one node at a time
        Tree.prototype.buildTree = function (nodes, level) {
    
            if (!nodes) return;
            level += 1;
    
            var _this = this;
            $.each(nodes, function addNodes(id, node) {
    
                var treeItem = $(_this.template.item)
                    .addClass('node-' + _this.elementId)
                    .addClass(node.state.checked ? 'node-checked' : '')
                    .addClass(node.state.disabled ? 'node-disabled' : '')
                    .addClass(node.state.selected ? 'node-selected' : '')
                    .addClass(node.searchResult ? 'search-result' : '')
                    .attr('data-nodeid', node.nodeId)
                    // .attr('data-parent-code', node.parentCode) //  这个是当前节点的父级节点的code,主要是为了实现父级拖拽的时候可以把子级同时移动 gz。
                    .attr('data-level', node.dataLevel) // 这个是当前节点的层级数据,之前有就可以不写 gz。
                    .attr('draggable', true) // 激发拖拽 gz
                    .attr("ondrop", "drop(event)") // 结束拖拽 gz
                    .attr("ondragover", "allowDrop(event)") // 拖拽中 gz
                    .attr("ondragstart", "drag(event)") // 目标开始拖拽事件 gz
                    .attr("ondragenter", "dragEnter(event)") //当拖拽对象进入投放区时触发
                    .attr("ondragleave", "dragLeave(event)") //元素被拖出了投放区时触发
                    .attr('style', _this.buildStyleOverride(node));
    
                // Add indent/spacer to mimic tree structure
                for (var i = 0; i < (level - 1); i++) {
                    treeItem.append(_this.template.indent);
                }
    
                // Add expand, collapse or empty spacer icons
                var classList = [];
                if (node.nodes) {
                    classList.push('expand-icon');
                    if (node.state.expanded) {
                        classList.push(_this.options.collapseIcon);
                    }
                    else {
                        classList.push(_this.options.expandIcon);
                    }
                }
                else {
                    classList.push(_this.options.emptyIcon);
                }
    
                treeItem
                    .append($(_this.template.icon)
                        .addClass(classList.join(' '))
                    );
    
    
                // Add node icon
                if (_this.options.showIcon) {
    
                    var classList = ['node-icon'];
    
                    classList.push(node.icon || _this.options.nodeIcon);
                    if (node.state.selected) {
                        classList.pop();
                        classList.push(node.selectedIcon || _this.options.selectedIcon ||
                            node.icon || _this.options.nodeIcon);
                    }
    
                    treeItem
                        .append($(_this.template.icon)
                            .addClass(classList.join(' '))
                        );
                }
    
                // Add check / unchecked icon
                if (_this.options.showCheckbox) {
    
                    var classList = ['check-icon'];
                    if (node.state.checked) {
                        classList.push(_this.options.checkedIcon);
                    }
                    else {
                        classList.push(_this.options.uncheckedIcon);
                    }
    
                    treeItem
                        .append($(_this.template.icon)
                            .addClass(classList.join(' '))
                        );
                }
    
                // Add text
                if (_this.options.enableLinks) {
                    // Add hyperlink
                    treeItem
                        .append($(_this.template.link)
                            .attr('href', node.href)
                            .append(node.text)
                        );
                }
                else {
                    // otherwise just text
                    treeItem
                        .append(node.text);
                }
    
                // Add tags as badges
                if (_this.options.showTags && node.tags) {
                    $.each(node.tags, function addTag(id, tag) {
                        treeItem
                            .append($(_this.template.badge)
                                .append(tag)
                            );
                    });
                }
    
                // Add item to the tree
                _this.$wrapper.append(treeItem);
    
                // Recursively add child ndoes
                if (node.nodes && node.state.expanded && !node.state.disabled) {
                    return _this.buildTree(node.nodes, level);
                }
            });
        };
    
        // Define any node level style override for
        // 1. selectedNode
        // 2. node|data assigned color overrides
        Tree.prototype.buildStyleOverride = function (node) {
    
            if (node.state.disabled) return '';
    
            var color = node.color;
            var backColor = node.backColor;
    
            if (this.options.highlightSelected && node.state.selected) {
                if (this.options.selectedColor) {
                    color = this.options.selectedColor;
                }
                if (this.options.selectedBackColor) {
                    backColor = this.options.selectedBackColor;
                }
            }
    
            if (this.options.highlightSearchResults && node.searchResult && !node.state.disabled) {
                if (this.options.searchResultColor) {
                    color = this.options.searchResultColor;
                }
                if (this.options.searchResultBackColor) {
                    backColor = this.options.searchResultBackColor;
                }
            }
    
            return 'color:' + color +
                ';background-color:' + backColor + ';';
        };
    
        // Add inline style into head
        Tree.prototype.injectStyle = function () {
    
            if (this.options.injectStyle && !document.getElementById(this.styleId)) {
                $('<style type="text/css" id="' + this.styleId + '"> ' + this.buildStyle() + ' </style>').appendTo('head');
            }
        };
    
        // Construct trees style based on user options
        Tree.prototype.buildStyle = function () {
    
            var style = '.node-' + this.elementId + '{';
    
            if (this.options.color) {
                style += 'color:' + this.options.color + ';';
            }
    
            if (this.options.backColor) {
                style += 'background-color:' + this.options.backColor + ';';
            }
    
            if (!this.options.showBorder) {
                style += 'border:none;';
            }
            else if (this.options.borderColor) {
                style += 'border:1px solid ' + this.options.borderColor + ';';
            }
            style += '}';
    
            if (this.options.onhoverColor) {
                style += '.node-' + this.elementId + ':not(.node-disabled):hover{' +
                    'background-color:' + this.options.onhoverColor + ';' +
                    '}';
            }
    
            return this.css + style;
        };
    
        Tree.prototype.template = {
            list: '<ul class="list-group"></ul>',
            item: '<li class="list-group-item"></li>',
            indent: '<span class="indent"></span>',
            icon: '<span class="icon"></span>',
            link: '<a href="#" style="color:inherit;"></a>',
            badge: '<span class="badge"></span>'
        };
    
        Tree.prototype.css = '.treeview .list-group-item{cursor:pointer}.treeview span.indent{margin-left:10px;margin-right:10px}.treeview span.icon{12px;margin-right:5px}.treeview .node-disabled{color:silver;cursor:not-allowed}'
    
    
        /**
            Returns a single node object that matches the given node id.
            @param {Number} nodeId - A node's unique identifier
            @return {Object} node - Matching node
        */
        Tree.prototype.getNode = function (nodeId) {
            return this.nodes[nodeId];
        };
    
        /**
            Returns the parent node of a given node, if valid otherwise returns undefined.
            @param {Object|Number} identifier - A valid node or node id
            @returns {Object} node - The parent node
        */
        Tree.prototype.getParent = function (identifier) {
            var node = this.identifyNode(identifier);
            return this.nodes[node.parentId];
        };
    
        /**
            Returns an array of sibling nodes for a given node, if valid otherwise returns undefined.
            @param {Object|Number} identifier - A valid node or node id
            @returns {Array} nodes - Sibling nodes
        */
        Tree.prototype.getSiblings = function (identifier) {
            var node = this.identifyNode(identifier);
            var parent = this.getParent(node);
            var nodes = parent ? parent.nodes : this.tree;
            return nodes.filter(function (obj) {
                return obj.nodeId !== node.nodeId;
            });
        };
    
        /**
            Returns an array of selected nodes.
            @returns {Array} nodes - Selected nodes
        */
        Tree.prototype.getSelected = function () {
            return this.findNodes('true', 'g', 'state.selected');
        };
    
        /**
            Returns an array of unselected nodes.
            @returns {Array} nodes - Unselected nodes
        */
        Tree.prototype.getUnselected = function () {
            return this.findNodes('false', 'g', 'state.selected');
        };
    
        /**
            Returns an array of expanded nodes.
            @returns {Array} nodes - Expanded nodes
        */
        Tree.prototype.getExpanded = function () {
            return this.findNodes('true', 'g', 'state.expanded');
        };
    
        /**
            Returns an array of collapsed nodes.
            @returns {Array} nodes - Collapsed nodes
        */
        Tree.prototype.getCollapsed = function () {
            return this.findNodes('false', 'g', 'state.expanded');
        };
    
        /**
            Returns an array of checked nodes.
            @returns {Array} nodes - Checked nodes
        */
        Tree.prototype.getChecked = function () {
            return this.findNodes('true', 'g', 'state.checked');
        };
    
        /**
            Returns an array of unchecked nodes.
            @returns {Array} nodes - Unchecked nodes
        */
        Tree.prototype.getUnchecked = function () {
            return this.findNodes('false', 'g', 'state.checked');
        };
    
        /**
            Returns an array of disabled nodes.
            @returns {Array} nodes - Disabled nodes
        */
        Tree.prototype.getDisabled = function () {
            return this.findNodes('true', 'g', 'state.disabled');
        };
    
        /**
            Returns an array of enabled nodes.
            @returns {Array} nodes - Enabled nodes
        */
        Tree.prototype.getEnabled = function () {
            return this.findNodes('false', 'g', 'state.disabled');
        };
    
    
        /**
            Set a node state to selected
            @param {Object|Number} identifiers - A valid node, node id or array of node identifiers
            @param {optional Object} options
        */
        Tree.prototype.selectNode = function (identifiers, options) {
            this.forEachIdentifier(identifiers, options, $.proxy(function (node, options) {
                this.setSelectedState(node, true, options);
            }, this));
    
            this.render();
        };
    
        /**
            Set a node state to unselected
            @param {Object|Number} identifiers - A valid node, node id or array of node identifiers
            @param {optional Object} options
        */
        Tree.prototype.unselectNode = function (identifiers, options) {
            this.forEachIdentifier(identifiers, options, $.proxy(function (node, options) {
                this.setSelectedState(node, false, options);
            }, this));
    
            this.render();
        };
    
        /**
            Toggles a node selected state; selecting if unselected, unselecting if selected.
            @param {Object|Number} identifiers - A valid node, node id or array of node identifiers
            @param {optional Object} options
        */
        Tree.prototype.toggleNodeSelected = function (identifiers, options) {
            this.forEachIdentifier(identifiers, options, $.proxy(function (node, options) {
                this.toggleSelectedState(node, options);
            }, this));
    
            this.render();
        };
    
    
        /**
            Collapse all tree nodes
            @param {optional Object} options
        */
        Tree.prototype.collapseAll = function (options) {
            var identifiers = this.findNodes('true', 'g', 'state.expanded');
            this.forEachIdentifier(identifiers, options, $.proxy(function (node, options) {
                this.setExpandedState(node, false, options);
            }, this));
    
            this.render();
        };
    
        /**
            Collapse a given tree node
            @param {Object|Number} identifiers - A valid node, node id or array of node identifiers
            @param {optional Object} options
        */
        Tree.prototype.collapseNode = function (identifiers, options) {
            this.forEachIdentifier(identifiers, options, $.proxy(function (node, options) {
                this.setExpandedState(node, false, options);
            }, this));
    
            this.render();
        };
    
        /**
            Expand all tree nodes
            @param {optional Object} options
        */
        Tree.prototype.expandAll = function (options) {
            options = $.extend({}, _default.options, options);
    
            if (options && options.levels) {
                this.expandLevels(this.tree, options.levels, options);
            }
            else {
                var identifiers = this.findNodes('false', 'g', 'state.expanded');
                this.forEachIdentifier(identifiers, options, $.proxy(function (node, options) {
                    this.setExpandedState(node, true, options);
                }, this));
            }
    
            this.render();
        };
    
        /**
            Expand a given tree node
            @param {Object|Number} identifiers - A valid node, node id or array of node identifiers
            @param {optional Object} options
        */
        Tree.prototype.expandNode = function (identifiers, options) {
            this.forEachIdentifier(identifiers, options, $.proxy(function (node, options) {
                this.setExpandedState(node, true, options);
                if (node.nodes && (options && options.levels)) {
                    this.expandLevels(node.nodes, options.levels - 1, options);
                }
            }, this));
    
            this.render();
        };
    
        Tree.prototype.expandLevels = function (nodes, level, options) {
            options = $.extend({}, _default.options, options);
    
            $.each(nodes, $.proxy(function (index, node) {
                this.setExpandedState(node, (level > 0) ? true : false, options);
                if (node.nodes) {
                    this.expandLevels(node.nodes, level - 1, options);
                }
            }, this));
        };
    
        /**
            Reveals a given tree node, expanding the tree from node to root.
            @param {Object|Number|Array} identifiers - A valid node, node id or array of node identifiers
            @param {optional Object} options
        */
        Tree.prototype.revealNode = function (identifiers, options) {
            this.forEachIdentifier(identifiers, options, $.proxy(function (node, options) {
                var parentNode = this.getParent(node);
                while (parentNode) {
                    this.setExpandedState(parentNode, true, options);
                    parentNode = this.getParent(parentNode);
                };
            }, this));
    
            this.render();
        };
    
        /**
            Toggles a nodes expanded state; collapsing if expanded, expanding if collapsed.
            @param {Object|Number} identifiers - A valid node, node id or array of node identifiers
            @param {optional Object} options
        */
        Tree.prototype.toggleNodeExpanded = function (identifiers, options) {
            this.forEachIdentifier(identifiers, options, $.proxy(function (node, options) {
                this.toggleExpandedState(node, options);
            }, this));
    
            this.render();
        };
    
    
        /**
            Check all tree nodes
            @param {optional Object} options
        */
        Tree.prototype.checkAll = function (options) {
            var identifiers = this.findNodes('false', 'g', 'state.checked');
            this.forEachIdentifier(identifiers, options, $.proxy(function (node, options) {
                this.setCheckedState(node, true, options);
            }, this));
    
            this.render();
        };
    
        /**
            Check a given tree node
            @param {Object|Number} identifiers - A valid node, node id or array of node identifiers
            @param {optional Object} options
        */
        Tree.prototype.checkNode = function (identifiers, options) {
            this.forEachIdentifier(identifiers, options, $.proxy(function (node, options) {
                this.setCheckedState(node, true, options);
            }, this));
    
            this.render();
        };
    
        /**
            Uncheck all tree nodes
            @param {optional Object} options
        */
        Tree.prototype.uncheckAll = function (options) {
            var identifiers = this.findNodes('true', 'g', 'state.checked');
            this.forEachIdentifier(identifiers, options, $.proxy(function (node, options) {
                this.setCheckedState(node, false, options);
            }, this));
    
            this.render();
        };
    
        /**
            Uncheck a given tree node
            @param {Object|Number} identifiers - A valid node, node id or array of node identifiers
            @param {optional Object} options
        */
        Tree.prototype.uncheckNode = function (identifiers, options) {
            this.forEachIdentifier(identifiers, options, $.proxy(function (node, options) {
                this.setCheckedState(node, false, options);
            }, this));
    
            this.render();
        };
    
        /**
            Toggles a nodes checked state; checking if unchecked, unchecking if checked.
            @param {Object|Number} identifiers - A valid node, node id or array of node identifiers
            @param {optional Object} options
        */
        Tree.prototype.toggleNodeChecked = function (identifiers, options) {
            this.forEachIdentifier(identifiers, options, $.proxy(function (node, options) {
                this.toggleCheckedState(node, options);
            }, this));
    
            this.render();
        };
    
    
        /**
            Disable all tree nodes
            @param {optional Object} options
        */
        Tree.prototype.disableAll = function (options) {
            var identifiers = this.findNodes('false', 'g', 'state.disabled');
            this.forEachIdentifier(identifiers, options, $.proxy(function (node, options) {
                this.setDisabledState(node, true, options);
            }, this));
    
            this.render();
        };
    
        /**
            Disable a given tree node
            @param {Object|Number} identifiers - A valid node, node id or array of node identifiers
            @param {optional Object} options
        */
        Tree.prototype.disableNode = function (identifiers, options) {
            this.forEachIdentifier(identifiers, options, $.proxy(function (node, options) {
                this.setDisabledState(node, true, options);
            }, this));
    
            this.render();
        };
    
        /**
            Enable all tree nodes
            @param {optional Object} options
        */
        Tree.prototype.enableAll = function (options) {
            var identifiers = this.findNodes('true', 'g', 'state.disabled');
            this.forEachIdentifier(identifiers, options, $.proxy(function (node, options) {
                this.setDisabledState(node, false, options);
            }, this));
    
            this.render();
        };
    
        /**
            Enable a given tree node
            @param {Object|Number} identifiers - A valid node, node id or array of node identifiers
            @param {optional Object} options
        */
        Tree.prototype.enableNode = function (identifiers, options) {
            this.forEachIdentifier(identifiers, options, $.proxy(function (node, options) {
                this.setDisabledState(node, false, options);
            }, this));
    
            this.render();
        };
    
        /**
            Toggles a nodes disabled state; disabling is enabled, enabling if disabled.
            @param {Object|Number} identifiers - A valid node, node id or array of node identifiers
            @param {optional Object} options
        */
        Tree.prototype.toggleNodeDisabled = function (identifiers, options) {
            this.forEachIdentifier(identifiers, options, $.proxy(function (node, options) {
                this.setDisabledState(node, !node.state.disabled, options);
            }, this));
    
            this.render();
        };
    
    
        /**
            Common code for processing multiple identifiers
        */
        Tree.prototype.forEachIdentifier = function (identifiers, options, callback) {
    
            options = $.extend({}, _default.options, options);
    
            if (!(identifiers instanceof Array)) {
                identifiers = [identifiers];
            }
    
            $.each(identifiers, $.proxy(function (index, identifier) {
                callback(this.identifyNode(identifier), options);
            }, this));
        };
    
        /*
            Identifies a node from either a node id or object
        */
        Tree.prototype.identifyNode = function (identifier) {
            return ((typeof identifier) === 'number') ?
                this.nodes[identifier] :
                identifier;
        };
    
        /**
            Searches the tree for nodes (text) that match given criteria
            @param {String} pattern - A given string to match against
            @param {optional Object} options - Search criteria options
            @return {Array} nodes - Matching nodes
        */
        Tree.prototype.search = function (pattern, options) {
            options = $.extend({}, _default.searchOptions, options);
    
            this.clearSearch({ render: false });
    
            var results = [];
            if (pattern && pattern.length > 0) {
    
                if (options.exactMatch) {
                    pattern = '^' + pattern + '$';
                }
    
                var modifier = 'g';
                if (options.ignoreCase) {
                    modifier += 'i';
                }
    
                results = this.findNodes(pattern, modifier);
    
                // Add searchResult property to all matching nodes
                // This will be used to apply custom styles
                // and when identifying result to be cleared
                $.each(results, function (index, node) {
                    node.searchResult = true;
                })
            }
    
            // If revealResults, then render is triggered from revealNode
            // otherwise we just call render.
            if (options.revealResults) {
                this.revealNode(results);
            }
            else {
                this.render();
            }
    
            this.$element.trigger('searchComplete', $.extend(true, {}, results));
    
            return results;
        };
    
        /**
            Clears previous search results
        */
        Tree.prototype.clearSearch = function (options) {
    
            options = $.extend({}, { render: true }, options);
    
            var results = $.each(this.findNodes('true', 'g', 'searchResult'), function (index, node) {
                node.searchResult = false;
            });
    
            if (options.render) {
                this.render();
            }
    
            this.$element.trigger('searchCleared', $.extend(true, {}, results));
        };
    
        /**
            Find nodes that match a given criteria
            @param {String} pattern - A given string to match against
            @param {optional String} modifier - Valid RegEx modifiers
            @param {optional String} attribute - Attribute to compare pattern against
            @return {Array} nodes - Nodes that match your criteria
        */
        Tree.prototype.findNodes = function (pattern, modifier, attribute) {
    
            modifier = modifier || 'g';
            attribute = attribute || 'text';
    
            var _this = this;
            return $.grep(this.nodes, function (node) {
                var val = _this.getNodeValue(node, attribute);
                if (typeof val === 'string') {
                    return val.match(new RegExp(pattern, modifier));
                }
            });
        };
    
        /**
            Recursive find for retrieving nested attributes values
            All values are return as strings, unless invalid
            @param {Object} obj - Typically a node, could be any object
            @param {String} attr - Identifies an object property using dot notation
            @return {String} value - Matching attributes string representation
        */
        Tree.prototype.getNodeValue = function (obj, attr) {
            var index = attr.indexOf('.');
            if (index > 0) {
                var _obj = obj[attr.substring(0, index)];
                var _attr = attr.substring(index + 1, attr.length);
                return this.getNodeValue(_obj, _attr);
            }
            else {
                if (obj.hasOwnProperty(attr)) {
                    return obj[attr].toString();
                }
                else {
                    return undefined;
                }
            }
        };
    
        var logError = function (message) {
            if (window.console) {
                window.console.error(message);
            }
        };
    
        // Prevent against multiple instantiations,
        // handle updates and method calls
        $.fn[pluginName] = function (options, args) {
    
            var result;
    
            this.each(function () {
                var _this = $.data(this, pluginName);
                if (typeof options === 'string') {
                    if (!_this) {
                        logError('Not initialized, can not call method : ' + options);
                    }
                    else if (!$.isFunction(_this[options]) || options.charAt(0) === '_') {
                        logError('No such method : ' + options);
                    }
                    else {
                        if (!(args instanceof Array)) {
                            args = [args];
                        }
                        result = _this[options].apply(_this, args);
                    }
                }
                else if (typeof options === 'boolean') {
                    result = _this;
                }
                else {
                    $.data(this, pluginName, new Tree(this, $.extend(true, {}, options)));
                }
            });
    
            return result || this;
        };
    
    })(jQuery, window, document);

    html需要添加拖拽事件

    <!DOCTYPE html>
    <html>
    
    <head>
        <title>Bootstrap Tree View</title>
        <link href="./packages/treeview/bootstrap.css" rel="stylesheet">
        <!-- <link href="./css/bootstrap-treeview.css" rel="stylesheet"> -->
    
    </head>
    
    <body>
        <div class="container">
            <h1>Bootstrap Tree View</h1>
            <br>
            <div id="treeview1" class=""></div>
    
        </div>
        <script src="./packages/treeview/jquery.js"></script>
        <script src="./packages/treeview/bootstrap-treeview.js"></script>
        <script type="text/javascript">
            var defaultData = [{
                    text: 'Parent 1',
                    href: '#parent1',
                    code: 'code1',
                    id: 1,
                    parentCode: 'code1',
                    dataLevel: 1,
                    nodes: [{
                            text: 'Child 1',
                            href: '#child1',
                            tag: "child1",
                            dataLevel: 2,
                            nodes: [{
                                    text: 'Grandchild 1',
                                    href: '#grandchild1',
                                    dataLevel: 3,
                                },
                                {
                                    text: 'Grandchild 2',
                                    href: '#grandchild2',
                                    dataLevel: 3,
                                },
                                {
                                    text: 'Grandchild 3',
                                    href: '#grandchild3',
                                    dataLevel: 3,
                                }
                            ]
                        },
                        {
                            text: 'Child 2',
                            href: '#child2',
                            dataLevel: 2,
                        }
                    ]
                },
    
            ];
    
    
            $('#treeview1').treeview({
                data: defaultData,
    
            });
    
            function allowDrop(ev) {
                ev.preventDefault();
            }
    
            function drag(ev) {
                console.log('开始');
                console.log(defaultData);
                console.log(ev)
                console.log(ev.target);
                let _nodeid = ev.target.attributes['data-nodeid'].nodeValue; // 获取要移动元素的层级
                let _level = ev.target.attributes['data-level'].nodeValue; // 获取要移动元素的节点id
                ev.dataTransfer.setData("nodeid", _nodeid); // 存储要移动元素的层级
                ev.dataTransfer.setData("level", _level); // 存储要移动元素的节点id
            }
    
            function drop(ev) {
                console.log('结束');
                ev.preventDefault();
                console.log(ev.target);
                let _nodeid = ev.target.attributes['data-nodeid'].nodeValue;
                let _level = ev.target.attributes['data-level'].nodeValue;
                let data_level = ev.dataTransfer.getData("level"); // 要移动元素的层级
                var data_nodeid = ev.dataTransfer.getData("nodeid"); // 要移动元素的节点id
                console.log(_level, data_level);
                if (data_level === _level) {
                    $("li[data-nodeid='" + _nodeid + "']").insertAfter($("li[data-nodeid='" + data_nodeid +
                        "']"));
                } else {
                    alert('不是同一级目录,无法进行移动操作')
                }
            }
            // 当拖拽对象进入投放区时触发
            function dragEnter(ev) {
                console.log(ev.target);
                $(ev.target).attr("style", "border:solid 1px red")
            }
            // 元素被拖出了投放区时触发
            function dragLeave(ev) {
                console.log(ev.target);
                $(ev.target).attr("style", "border:solid 1px #dddddd")
            }
        </script>
    </body>
    
    </html>
  • 相关阅读:
    静态化之优化
    SEO小技巧
    apache 工具和简单优化
    apache rewrite机制
    nginx php win平台配置
    mvc 简单模型
    php无限分类三种方式
    【转】sqlserver查询数据库中有多少个表
    【转】sqlserver数据库之间的表的复制
    SET ANSI_NULLS (TransactSQL)
  • 原文地址:https://www.cnblogs.com/guozhe/p/16178213.html
Copyright © 2020-2023  润新知