目录
fuelux tree配置项(动态数据+字体图标)
fuelux tree 的HTML:
配置 非无穷树(实际开发中):
配置 循环树(官网API):
Fuel UX Tree 树的js (动过手脚使其能自定义图标)
配置 树的 样式
在web项目开发中,我们不免会遇到各种树的信息展示,我也遇到同样的 问题,不过目前的前端树展示千奇百怪,其中 `ztree(功能最强,样式騒丑)` 还有`bootstrap 的 Treeview也不错`,今天,讲的是 ` fuelux tree` 中的 树 插件,这个插件的好处 就是树的节点图标可自定义(需要改代码,后面会展示),什么`bootstrap 的glyphicon字体`、`font-awesome的 fa 字体`,话不多说,直接上代码
$(function() {
var treeDataSource = new StaticTreeDataSource(folders);
$('#MyTree').tree({
dataSource: treeDataSource.getData,
multiSelect: false, //能否多选节点
folderSelect: false, //根节点能否选中
//注:配置 节点 首先 必须HTML 中的图标和 自定义的图标统一
//否则 不统一可能 节点 能展开 但图标没有切换 或者 不能展开
iconFolderOpen: "glyphicon-minus-sign", //节点展开图标
iconFolderClose: "glyphicon-plus-sign" //节点关闭图标
});
})
//初始化树的信息
function StaticTreeDataSource(treeData) {
var nodes = treeData;
this.getData = function(options, callback) {
console.log(JSON.stringify(options))
//数据第一次初始化时 此时的 options 没有信息
if($.isEmptyObject(options)) {
nodes = nodes;
} else {
//获取当前点击节点的 options
if(options.children == null || options.children == undefined) {
nodes = {};
} else {
nodes = options.children;
}
}
//方法回调 添加当前选中节点的子节点
callback({
data: nodes
});
}
}
var folders = [{
"name": "Aquire",
"type": "item"
},
{
"name": "Onboard",
"type": "item"
},
{
"name": "Engage",
"type": "folder",
"attr": {
"id": "Engage",
"data-icon": "glyphicon glyphicon-folder-open",
"style": "color: rebeccapurple;"
},
"children": [{
"name": "Abandoned Cart",
"type": "folder",
"children": [{
"name": "Archive",
"type": "item"
}]
},
{
"name": "Birthday",
"type": "item"
},
{
"name": "Browse Retargeting",
"type": "item"
},
{
"name": "Loyalty",
"type": "item"
},
{
"name": "Newsletter",
"type": "item"
},
{
"name": "Post-Purchase",
"type": "item"
},
{
"name": "Promotional",
"type": "item"
},
{
"name": "Transactional",
"type": "folder",
"children": [{
"name": "Archive",
"type": "item"
}]
},
{
"name": "Wish List",
"type": "item"
}
]
},
{
"name": "Retain",
"type": "item",
"attr": {
"id": "sky-and-water-i",
"style": "color: rebeccapurple;" //自定义节点颜色
}
}
];
function staticDataSource(parentData, callback) {
childNodesArray = [{
"name": "Ascending and Descending",
"type": "folder",
"attr": {
"id": "ascending-and-descending"
}
},
{
"name": "Sky and Water I",
"type": "item",
"attr": {
"id": "sky-and-water-i",
"data-icon": "glyphicon glyphicon-file",
"style": "color: rebeccapurple;"
}
},
{
"name": "Drawing Hands",
"type": "folder",
"attr": {
"id": "drawing-hands"
}
},
{
"name": "Waterfall",
"type": "item",
"attr": {
"id": "waterfall",
"data-icon": "glyphicon glyphicon-cloud",
"style": "color: rebeccapurple;"
}
},
{
"name": "Belvedere",
"type": "folder",
"attr": {
"id": "belvedere"
}
},
{
"name": "Relativity",
"type": "item",
"attr": {
"id": "relativity",
"data-icon": "glyphicon glyphicon-picture",
"style": "color: rebeccapurple;"
}
},
{
"name": "House of Stairs",
"type": "folder",
"attr": {
"id": "house-of-stairs"
}
},
{
"name": "Convex and Concave",
"type": "item",
"attr": {
"id": "convex-and-concave",
"data-icon": "glyphicon glyphicon-tags",
"style": "color: rebeccapurple;"
}
}
];
callback({
data: childNodesArray
});
}
//初始化 树信息
$('#MyTree').tree({
dataSource: staticDataSource,
multiSelect: false,
folderSelect: false,
iconFolderOpen: "glyphicon-minus-sign",
iconFolderClose: "glyphicon-plus-sign"
});
Fuel UX Tree 树的js (动过手脚使其能自定义图标)
这里用的的是
FuelUX 3.0
/*
* Fuel UX Tree 3.0
* https://github.com/ExactTarget/fuelux
*
* Copyright (c) 2014 ExactTarget
* Licensed under the BSD New license.
*/
// -- BEGIN UMD WRAPPER PREFACE --
// For more information on UMD visit:
// https://github.com/umdjs/umd/blob/master/jqueryPlugin.js
(function (factory) {
if (typeof define === 'function' && define.amd) {
// if AMD loader is available, register as an anonymous module.
define(['jquery'], factory);
} else if (typeof exports === 'object') {
// Node/CommonJS
module.exports = factory(require('jquery'));
} else {
// OR use browser globals if AMD is not present
factory(jQuery);
}
}(function ($) {
// -- END UMD WRAPPER PREFACE --
// -- BEGIN MODULE CODE HERE --
var old = $.fn.tree;
// TREE CONSTRUCTOR AND PROTOTYPE
var Tree = function Tree(element, options) {
this.$element = $(element);
this.options = $.extend({}, $.fn.tree.defaults, options);
if (this.options.itemSelect) {
this.$element.on('click.fu.tree', '.tree-item', $.proxy(function (ev) {
this.selectItem(ev.currentTarget);
}, this));
}
this.$element.on('click.fu.tree', '.tree-branch-name', $.proxy(function (ev) {
this.toggleFolder(ev.currentTarget);
}, this));
// folderSelect default is true
if (this.options.folderSelect) {
this.$element.addClass('tree-folder-select');
this.$element.off('click.fu.tree', '.tree-branch-name');
this.$element.on('click.fu.tree', '.icon-caret', $.proxy(function (ev) {
this.toggleFolder($(ev.currentTarget).parent());
}, this));
this.$element.on('click.fu.tree', '.tree-branch-name', $.proxy(function (ev) {
this.selectFolder($(ev.currentTarget));
}, this));
}
this.render();
};
Tree.prototype = {
constructor: Tree,
deselectAll: function deselectAll(nodes) {
// clear all child tree nodes and style as deselected
nodes = nodes || this.$element;
var $selectedElements = $(nodes).find('.tree-selected');
$selectedElements.each(function (index, element) {
styleNodeDeselected( $(element), $(element).find( '.glyphicon' ) );
});
return $selectedElements;
},
destroy: function destroy() {
// any external bindings [none]
// empty elements to return to original markup
this.$element.find("li:not([data-template])").remove();
this.$element.remove();
// returns string of markup
return this.$element[0].outerHTML;
},
render: function render() {
this.populate(this.$element);
},
populate: function populate($el, isBackgroundProcess) {
var self = this;
var $parent = ($el.hasClass('tree')) ? $el : $el.parent();
var loader = $parent.find('.tree-loader:eq(0)');
var treeData = $parent.data();
isBackgroundProcess = isBackgroundProcess || false; // no user affordance needed (ex.- "loading")
if (isBackgroundProcess === false) {
loader.removeClass('hide hidden'); // hide is deprecated
}
this.options.dataSource(treeData ? treeData : {}, function (items) {
loader.addClass('hidden');
$.each(items.data, function (index, value) {
var $entity;
if (value.type === 'folder') {
$entity = self.$element.find('[data-template=treebranch]:eq(0)').clone().removeClass('hide hidden').removeData('template'); // hide is deprecated
$entity.data(value);
$entity.find('.tree-branch-name > .tree-label').html(value.text || value.name);
} else if (value.type === 'item') {
$entity = self.$element.find('[data-template=treeitem]:eq(0)').clone().removeClass('hide hidden').removeData('template'); // hide is deprecated
$entity.find('.tree-item-name > .tree-label').html(value.text || value.name);
$entity.data(value);
}
// Decorate $entity with data or other attributes making the
// element easily accessable with libraries like jQuery.
//
// Values are contained within the object returned
// for folders and items as attr:
//
// {
// text: "An Item",
// type: 'item',
// attr = {
// 'classes': 'required-item red-text',
// 'data-parent': parentId,
// 'guid': guid,
// 'id': guid
// }
// };
//
// the "name" attribute is also supported but is deprecated for "text".
// add attributes to tree-branch or tree-item
var attr = value.attr || value.dataAttributes || [];
$.each(attr, function (key, value) {
switch (key) {
case 'cssClass':
case 'class':
case 'className':
$entity.addClass(value);
break;
// allow custom icons
case 'data-icon':
$entity.find('.icon-item').removeClass().addClass('icon-item ' + value);
$entity.attr(key, value);
break;
// ARIA support
case 'id':
$entity.attr(key, value);
$entity.attr('aria-labelledby', value + '-label');
$entity.find('.tree-branch-name > .tree-label').attr('id', value + '-label');
break;
// style, data-*
default:
$entity.attr(key, value);
break;
}
});
// add child nodes
if ($el.hasClass('tree-branch-header')) {
$parent.find('.tree-branch-children:eq(0)').append($entity);
} else {
$el.append($entity);
}
});
// return newly populated folder
self.$element.trigger('loaded.fu.tree', $parent);
});
},
selectTreeNode: function selectItem(clickedElement, nodeType) {
var clicked = {}; // object for clicked element
clicked.$element = $(clickedElement);
var selected = {}; // object for selected elements
selected.$elements = this.$element.find('.tree-selected');
selected.dataForEvent = [];
// determine clicked element and it's icon
if (nodeType === 'folder') {
// make the clicked.$element the container branch
clicked.$element = clicked.$element.closest('.tree-branch');
clicked.$icon = clicked.$element.find('.icon-folder');
}
else {
clicked.$icon = clicked.$element.find('.icon-item');
}
clicked.elementData = clicked.$element.data();
// the below functions pass objects by copy/reference and use modified object in this function
if ( this.options.multiSelect ) {
multiSelectSyncNodes(this, clicked, selected);
}
else {
singleSelectSyncNodes(this, clicked, selected);
}
// all done with the DOM, now fire events
this.$element.trigger(selected.eventType + '.fu.tree', {
target: clicked.elementData,
selected: selected.dataForEvent
});
clicked.$element.trigger('updated.fu.tree', {
selected: selected.dataForEvent,
item: clicked.$element,
eventType: selected.eventType
});
},
discloseFolder: function discloseFolder(el) {
var $el = $(el);
var $branch = $el.closest('.tree-branch');
var $treeFolderContent = $branch.find('.tree-branch-children');
var $treeFolderContentFirstChild = $treeFolderContent.eq(0);
//take care of the styles
$branch.addClass('tree-open');
$branch.attr('aria-expanded', 'true');
$treeFolderContentFirstChild.removeClass('hide hidden'); // hide is deprecated
//DIY 配置 节点展开图标 首先 必须HTML 中的图标和 自定义的图标统一
$branch.find('> .tree-branch-header .icon-folder').eq(0)
.removeClass(this.options.iconFolderClose)
.addClass(this.options.iconFolderOpen);
/*//原本的 节点 关闭 切换
$branch.find('> .tree-branch-header .icon-folder').eq(0)
.removeClass('glyphicon-folder-close')
.addClass('glyphicon-folder-open'); */
//add the children to the folder
if (!$treeFolderContent.children().length) {
this.populate($treeFolderContent);
}
this.$element.trigger('disclosedFolder.fu.tree', $branch.data());
},
closeFolder: function closeFolder(el) {
var $el = $(el);
var $branch = $el.closest('.tree-branch');
var $treeFolderContent = $branch.find('.tree-branch-children');
var $treeFolderContentFirstChild = $treeFolderContent.eq(0);
//take care of the styles
$branch.removeClass('tree-open');
$branch.attr('aria-expanded', 'false');
$treeFolderContentFirstChild.addClass('hidden');
// DIY 配置 节点 关闭 切换图标
$branch.find('> .tree-branch-header .icon-folder').eq(0)
.removeClass(this.options.iconFolderOpen)
.addClass(this.options.iconFolderClose);
/* //原本的 节点关闭切换
* $branch.find('> .tree-branch-header .icon-folder').eq(0)
.removeClass('glyphicon-folder-open')
.addClass('glyphicon-folder-close');*/
// remove chidren if no cache
if (!this.options.cacheItems) {
$treeFolderContentFirstChild.empty();
}
this.$element.trigger('closed.fu.tree', $branch.data());
},
toggleFolder: function toggleFolder(el) {
var $el = $(el);
/**
* DIY 修改 判断节点 是否展开
*/
if ($el.parent(".tree-branch-header").parent(".tree-branch").hasClass("tree-open")) {
this.closeFolder(el);
} else{
this.discloseFolder(el);
}
/** //原本的 节点展开判断
if ($el.find('.glyphicon-folder-close').length) {
this.discloseFolder(el);
} else if ($el.find('.glyphicon-folder-open').length) {
this.closeFolder(el);
} */
},
selectFolder: function selectFolder(el) {
if (this.options.folderSelect) {
this.selectTreeNode(el, 'folder');
}
},
selectItem: function selectItem(el) {
if (this.options.itemSelect) {
this.selectTreeNode(el, 'item');
}
},
selectedItems: function selectedItems() {
var $sel = this.$element.find('.tree-selected');
var data = [];
$.each($sel, function (index, value) {
data.push($(value).data());
});
return data;
},
// collapses open folders
collapse: function collapse() {
var self = this;
var reportedClosed = [];
var closedReported = function closedReported(event, closed) {
reportedClosed.push(closed);
// hide is deprecated
if (self.$element.find(".tree-branch.tree-open:not('.hidden, .hide')").length === 0) {
self.$element.trigger('closedAll.fu.tree', {
tree: self.$element,
reportedClosed: reportedClosed
});
self.$element.off('loaded.fu.tree', self.$element, closedReported);
}
};
//trigger callback when all folders have reported closed
self.$element.on('closed.fu.tree', closedReported);
self.$element.find(".tree-branch.tree-open:not('.hidden, .hide')").each(function () {
self.closeFolder(this);
});
},
//disclose visible will only disclose visible tree folders
discloseVisible: function discloseVisible() {
var self = this;
var $openableFolders = self.$element.find(".tree-branch:not('.tree-open, .hidden, .hide')");
var reportedOpened = [];
var openReported = function openReported(event, opened) {
reportedOpened.push(opened);
if (reportedOpened.length === $openableFolders.length) {
self.$element.trigger('disclosedVisible.fu.tree', {
tree: self.$element,
reportedOpened: reportedOpened
});
/*
* Unbind the `openReported` event. `discloseAll` may be running and we want to reset this
* method for the next iteration.
*/
self.$element.off('loaded.fu.tree', self.$element, openReported);
}
};
//trigger callback when all folders have reported opened
self.$element.on('loaded.fu.tree', openReported);
// open all visible folders
self.$element.find(".tree-branch:not('.tree-open, .hidden, .hide')").each(function triggerOpen() {
self.discloseFolder($(this).find('.tree-branch-header'));
});
},
/**
* Disclose all will keep listening for `loaded.fu.tree` and if `$(tree-el).data('ignore-disclosures-limit')`
* is `true` (defaults to `true`) it will attempt to disclose any new closed folders than were
* loaded in during the last disclosure.
*/
discloseAll: function discloseAll() {
var self = this;
//first time
if (typeof self.$element.data('disclosures') === 'undefined') {
self.$element.data('disclosures', 0);
}
var isExceededLimit = (self.options.disclosuresUpperLimit >= 1 && self.$element.data('disclosures') >= self.options.disclosuresUpperLimit);
var isAllDisclosed = self.$element.find(".tree-branch:not('.tree-open, .hidden, .hide')").length === 0;
if (!isAllDisclosed) {
if (isExceededLimit) {
self.$element.trigger('exceededDisclosuresLimit.fu.tree', {
tree: self.$element,
disclosures: self.$element.data('disclosures')
});
/*
* If you've exceeded the limit, the loop will be killed unless you
* explicitly ignore the limit and start the loop again:
*
* $tree.one('exceededDisclosuresLimit.fu.tree', function () {
* $tree.data('ignore-disclosures-limit', true);
* $tree.tree('discloseAll');
* });
*/
if (!self.$element.data('ignore-disclosures-limit')) {
return;
}
}
self.$element.data('disclosures', self.$element.data('disclosures') + 1);
/*
* A new branch that is closed might be loaded in, make sure those get handled too.
* This attachment needs to occur before calling `discloseVisible` to make sure that
* if the execution of `discloseVisible` happens _super fast_ (as it does in our QUnit tests
* this will still be called. However, make sure this only gets called _once_, because
* otherwise, every single time we go through this loop, _another_ event will be bound
* and then when the trigger happens, this will fire N times, where N equals the number
* of recursive `discloseAll` executions (instead of just one)
*/
self.$element.one('disclosedVisible.fu.tree', function () {
self.discloseAll();
});
/*
* If the page is very fast, calling this first will cause `disclosedVisible.fu.tree` to not
* be bound in time to be called, so, we need to call this last so that the things bound
* and triggered above can have time to take place before the next execution of the
* `discloseAll` method.
*/
self.discloseVisible();
} else {
self.$element.trigger('disclosedAll.fu.tree', {
tree: self.$element,
disclosures: self.$element.data('disclosures')
});
//if `cacheItems` is false, and they call closeAll, the data is trashed and therefore
//disclosures needs to accurately reflect that
if (!self.options.cacheItems) {
self.$element.one('closeAll.fu.tree', function () {
self.$element.data('disclosures', 0);
});
}
}
},
// This refreshes the children of a folder. Please destroy and re-initilize for "root level" refresh.
// The data of the refreshed folder is not updated. This control's architecture only allows updating of children.
// Folder renames should probably be handled directly on the node.
refreshFolder: function refreshFolder($el) {
var $treeFolder = $el.closest('.tree-branch');
var $treeFolderChildren = $treeFolder.find('.tree-branch-children');
$treeFolderChildren.eq(0).empty();
if ($treeFolder.hasClass('tree-open')) {
this.populate($treeFolderChildren, false);
}
else {
this.populate($treeFolderChildren, true);
}
this.$element.trigger('refreshedFolder.fu.tree', $treeFolder.data());
}
};
// ALIASES
//alias for collapse for consistency. "Collapse" is an ambiguous term (collapse what? All? One specific branch?)
Tree.prototype.closeAll = Tree.prototype.collapse;
//alias for backwards compatibility because there's no reason not to.
Tree.prototype.openFolder = Tree.prototype.discloseFolder;
//For library consistency
Tree.prototype.getValue = Tree.prototype.selectedItems;
// PRIVATE FUNCTIONS
function styleNodeSelected ($element, $icon) {
$element.addClass('tree-selected');
if ( $element.data('type') === 'item' && $icon.hasClass('fueluxicon-bullet') ) {
$icon.removeClass('fueluxicon-bullet').addClass('glyphicon-ok'); // make checkmark
}
}
function styleNodeDeselected ($element, $icon) {
$element.removeClass('tree-selected');
if ( $element.data('type') === 'item' && $icon.hasClass('glyphicon-ok') ) {
$icon.removeClass('glyphicon-ok').addClass('fueluxicon-bullet'); // make bullet
}
}
function multiSelectSyncNodes (self, clicked, selected) {
// search for currently selected and add to selected data list if needed
$.each(selected.$elements, function (index, element) {
var $element = $(element);
if ($element[0] !== clicked.$element[0]) {
selected.dataForEvent.push( $($element).data() );
}
});
if (clicked.$element.hasClass('tree-selected')) {
styleNodeDeselected (clicked.$element, clicked.$icon);
// set event data
selected.eventType = 'deselected';
}
else {
styleNodeSelected(clicked.$element, clicked.$icon);
// set event data
selected.eventType = 'selected';
selected.dataForEvent.push(clicked.elementData);
}
}
function singleSelectSyncNodes(self, clicked, selected) {
// element is not currently selected
if (selected.$elements[0] !== clicked.$element[0]) {
var clearedElements = self.deselectAll(self.$element);
styleNodeSelected(clicked.$element, clicked.$icon);
// set event data
selected.eventType = 'selected';
selected.dataForEvent = [clicked.elementData];
}
else {
styleNodeDeselected(clicked.$element, clicked.$icon);
// set event data
selected.eventType = 'deselected';
selected.dataForEvent = [];
}
}
// TREE PLUGIN DEFINITION
$.fn.tree = function tree(option) {
var args = Array.prototype.slice.call(arguments, 1);
var methodReturn;
var $set = this.each(function () {
var $this = $(this);
var data = $this.data('fu.tree');
var options = typeof option === 'object' && option;
if (!data) {
$this.data('fu.tree', (data = new Tree(this, options)));
}
if (typeof option === 'string') {
methodReturn = data[option].apply(data, args);
}
});
return (methodReturn === undefined) ? $set : methodReturn;
};
$.fn.tree.defaults = {
dataSource: function dataSource(options, callback) {},
multiSelect: false,
cacheItems: true,
folderSelect: true,
itemSelect: true,
// DIY 配置 节点 默认 展开 关闭 图标
//打开图标
iconFolderOpen:"glyphicon-minus-sign",
//关闭图标
iconFolderClose:"glyphicon-plus-sign",
/*
* How many times `discloseAll` should be called before a stopping and firing
* an `exceededDisclosuresLimit` event. You can force it to continue by
* listening for this event, setting `ignore-disclosures-limit` to `true` and
* starting `discloseAll` back up again. This lets you make more decisions
* about if/when/how/why/how many times `discloseAll` will be started back
* up after it exceeds the limit.
*
* $tree.one('exceededDisclosuresLimit.fu.tree', function () {
* $tree.data('ignore-disclosures-limit', true);
* $tree.tree('discloseAll');
* });
*
* `disclusuresUpperLimit` defaults to `0`, so by default this trigger
* will never fire. The true hard the upper limit is the browser's
* ability to load new items (i.e. it will keep loading until the browser
* falls over and dies). On the Fuel UX `index.html` page, the point at
* which the page became super slow (enough to seem almost unresponsive)
* was `4`, meaning 256 folders had been opened, and 1024 were attempting to open.
*/
disclosuresUpperLimit: 0
};
$.fn.tree.Constructor = Tree;
$.fn.tree.noConflict = function () {
$.fn.tree = old;
return this;
};
// NO DATA-API DUE TO NEED OF DATA-SOURCE
// -- BEGIN UMD WRAPPER AFTERWORD --
}));
// -- END UMD WRAPPER AFTERWORD --
.content {
margin: 0px auto;
width: 400px;
height: 400px;
overflow: auto;
padding: 10px;
border: 1px solid #CCCCCC;
}
.tree {
padding-left: 14px;
overflow: auto;
position: relative
}
.tree:before {
width: 1px;
z-index: 1;
display: block;
content: "";
position: absolute;
top: -21px;
bottom: 16px;
left: 0;
border-left: 1px dotted #666
}
.tree.tree-solid-line {
padding-left: 12px
}
.tree.tree-solid-line:before {
border-left: 1px solid #999
}
.tree.tree-solid-line .tree-folder .tree-folder-content:before {
border-left: 1px solid #999
}
.tree.tree-no-line {
padding-left: 0
}
.tree.tree-no-line:before {
display: none
}
.tree.tree-no-line .tree-folder .tree-folder-content:before {
display: none
}
.tree .tree-folder {
width: auto;
min-height: 20px;
cursor: pointer
}
.tree .tree-folder .tree-folder-header {
position: relative;
min-height: 20px;
line-height: 20px;
min-width: 100px
}
.tree .tree-folder .tree-folder-header:hover {
background-color: #eee
}
.tree .tree-folder .tree-folder-header .tree-folder-name {
margin-left: 2px
}
.tree .tree-folder img {
margin-left: 4px
}
.tree .tree-folder .tree-folder-content {
margin-left: 23px;
position: relative
}
.tree .tree-folder .tree-folder-content:before {
display: inline-block;
content: "";
position: absolute;
width: 1px;
z-index: 1;
top: -9px;
bottom: 16px;
left: -12px;
border-left: 1px dotted #666
}
.tree .tree-item {
position: relative;
min-height: 20px;
line-height: 20px;
min-width: 100px;
cursor: pointer
}
.tree .tree-item:hover {
background-color: #eee
}
.tree .tree-item .tree-item-name {
margin-left: 2px
}
.tree .tree-folder,
.tree .tree-item {
position: relative
}
.tree .tree-folder:before,
.tree .tree-item:before {
display: inline-block;
content: "";
position: absolute;
top: 14px;
left: -13px;
width: 18px;
height: 0;
border-top: 1px dotted #666;
z-index: 1
}
.tree .tree-selected {
background-color: #eee;
color: #262626
}
.tree .tree-selected:hover {
background-color: #e5e5e5
}
.tree .tree-folder .tree-folder-header .tree-folder-name,
.tree .tree-item .tree-item-name {
display: inline;
z-index: 2
}
.tree.tree-solid-line .tree-folder:before,
.tree.tree-solid-line .tree-item:before {
border-top: 1px solid #999
}
.tree.tree-no-line .tree-folder:before,
.tree.tree-no-line .tree-item:before {
display: none
}
.tree .tree-item,
.tree .tree-folder {
border: 1px solid transparent
}
.tree .tree-item,
.tree .tree-folder .tree-folder-header {
margin: 0;
padding: 4px 5px 6px 5px;
color: #333;
-webkit-box-sizing: content-box;
-moz-box-sizing: content-box;
box-sizing: content-box
}
.tree .tree-item .tree-item-name>i,
.tree .tree-folder .tree-folder-header>i {
color: #666;
display: inline-block;
font-family: FontAwesome;
font-style: normal;
font-weight: normal;
line-height: 1;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale
}
.tree .tree-item.tree-selected i,
.tree .tree-item .tree-item-name i {
margin-left: 2px;
width: 14px;
display: inline-block;
text-align: center;
margin-right: 1px;
color: #262626
}
.tree.tree-plus-minus .tree-folder-header .fa-folder-open:before {
height: 16px;
width: 16px;
line-height: 16px;
vertical-align: middle;
display: inline-block;
background-position: 0 -21px;
content: ""
}
.tree.tree-plus-minus .tree-folder-header .fa-folder:before {
height: 16px;
width: 16px;
line-height: 16px;
vertical-align: middle;
display: inline-block;
background-position: 0 2px;
content: ""
}
.tree.tree-plus-minus .tree-folder-name {
margin-left: 0 !important
}
.tree .tree-actions {
display: none;
position: absolute;
margin-top: 1px;
right: 4px
}
.tree .tree-item:hover .tree-actions,
.tree .tree-folder-header:hover .tree-actions {
display: inline-block
}
.tree .tree-actions>i {
font-weight: 300;
padding: 1px 3px;
text-align: center;
font-size: 14px;
color: #333;
margin-right: 6px;
margin-top: 0;
display: inline-block
}
.tree .tree-actions>i:hover {
font-weight: bold
}
.tree-loading {
color: #2dc3e8;
margin-left: 30px
}