mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
TreeList updates for the outliner sidebar
All data items now get their `item.treeList` api added even if deferBuild is set. This means the apis can be used regardless of whether the tree has built their ui pieces. Also adds a number of new api calls Top-level methods: - clearSelection - clears selection from the list - filter(filterFunc) - filters the tree using the provided function Data item functions: - item.treeList.sortChildren(sortFunction) - item.treeList.replaceElement(element)
This commit is contained in:
parent
5c0b500f48
commit
d2d872f51c
@ -27,7 +27,8 @@
|
|||||||
*
|
*
|
||||||
* methods:
|
* methods:
|
||||||
* - data(items) - clears existing items and replaces with new data
|
* - data(items) - clears existing items and replaces with new data
|
||||||
*
|
* - clearSelection - clears the selected items
|
||||||
|
* - filter(filterFunc) - filters the tree using the provided function
|
||||||
* events:
|
* events:
|
||||||
* - treelistselect : function(event, item) {}
|
* - treelistselect : function(event, item) {}
|
||||||
* - treelistconfirm : function(event,item) {}
|
* - treelistconfirm : function(event,item) {}
|
||||||
@ -59,9 +60,9 @@
|
|||||||
* properties and functions:
|
* properties and functions:
|
||||||
*
|
*
|
||||||
* item.parent - set to the parent item
|
* item.parent - set to the parent item
|
||||||
|
* item.depth - the depth in the tree (0 == root)
|
||||||
* item.treeList.container
|
* item.treeList.container
|
||||||
* item.treeList.label - the label element for the item
|
* item.treeList.label - the label element for the item
|
||||||
* item.treeList.depth - the depth in the tree (0 == root)
|
|
||||||
* item.treeList.parentList - the editableList instance this item is in
|
* item.treeList.parentList - the editableList instance this item is in
|
||||||
* item.treeList.remove() - removes the item from the tree
|
* item.treeList.remove() - removes the item from the tree
|
||||||
* item.treeList.makeLeaf(detachChildElements) - turns an element with children into a leaf node,
|
* item.treeList.makeLeaf(detachChildElements) - turns an element with children into a leaf node,
|
||||||
@ -78,8 +79,8 @@
|
|||||||
* Optionally selects the item after adding.
|
* Optionally selects the item after adding.
|
||||||
* item.treeList.expand(done) - expands the parent item to show children. Optional 'done' callback.
|
* item.treeList.expand(done) - expands the parent item to show children. Optional 'done' callback.
|
||||||
* item.treeList.collapse() - collapse the parent item to hide children.
|
* item.treeList.collapse() - collapse the parent item to hide children.
|
||||||
*
|
* item.treeList.sortChildren(sortFunction) - does a one-time sort of the children using sortFunction
|
||||||
*
|
* item.treeList.replaceElement(element) - replace the custom element for the item
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@ -151,7 +152,7 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
this._data = [];
|
this._data = [];
|
||||||
|
this._items = {};
|
||||||
this._topList = $('<ol class="red-ui-treeList-list">').css({
|
this._topList = $('<ol class="red-ui-treeList-list">').css({
|
||||||
position:'absolute',
|
position:'absolute',
|
||||||
top: 0,
|
top: 0,
|
||||||
@ -244,7 +245,8 @@
|
|||||||
that._trigger("changeparent",null,evt);
|
that._trigger("changeparent",null,evt);
|
||||||
});
|
});
|
||||||
that._trigger("sort",null,parent);
|
that._trigger("sort",null,parent);
|
||||||
}
|
},
|
||||||
|
filter: parent.treeList.childFilter
|
||||||
});
|
});
|
||||||
if (!!that.options.sortable) {
|
if (!!that.options.sortable) {
|
||||||
subtree.addClass('red-ui-treeList-sortable');
|
subtree.addClass('red-ui-treeList-sortable');
|
||||||
@ -289,21 +291,175 @@
|
|||||||
}
|
}
|
||||||
return reparentedEvent;
|
return reparentedEvent;
|
||||||
},
|
},
|
||||||
_addSubtree: function(parentList, container, item, depth) {
|
_initItem: function(item,depth) {
|
||||||
|
if (item.treeList) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
var that = this;
|
var that = this;
|
||||||
|
this._items[item.id] = item;
|
||||||
item.treeList = {};
|
item.treeList = {};
|
||||||
item.treeList.depth = depth;
|
item.depth = depth;
|
||||||
item.treeList.container = container;
|
|
||||||
|
|
||||||
item.treeList.parentList = parentList;
|
|
||||||
item.treeList.remove = function() {
|
item.treeList.remove = function() {
|
||||||
parentList.editableList('removeItem',item);
|
if (item.treeList.parentList) {
|
||||||
|
item.treeList.parentList.editableList('removeItem',item);
|
||||||
|
}
|
||||||
if (item.parent) {
|
if (item.parent) {
|
||||||
var index = item.parent.children.indexOf(item);
|
var index = item.parent.children.indexOf(item);
|
||||||
item.parent.children.splice(index,1)
|
item.parent.children.splice(index,1)
|
||||||
that._trigger("sort",null,item.parent);
|
that._trigger("sort",null,item.parent);
|
||||||
}
|
}
|
||||||
|
delete(that._items[item.id]);
|
||||||
}
|
}
|
||||||
|
item.treeList.insertChildAt = function(newItem,position,select) {
|
||||||
|
newItem.parent = item;
|
||||||
|
item.children.splice(position,0,newItem);
|
||||||
|
var processChildren = function(parent,i) {
|
||||||
|
that._initItem(i,parent.depth+1)
|
||||||
|
i.parent = parent;
|
||||||
|
if (i.children && typeof i.children !== 'function') {
|
||||||
|
i.children.forEach(function(item) {
|
||||||
|
processChildren(i, item, parent.depth+2)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
processChildren(item,newItem);
|
||||||
|
|
||||||
|
if (!item.deferBuild) {
|
||||||
|
item.treeList.childList.editableList('insertItemAt',newItem,position)
|
||||||
|
if (select) {
|
||||||
|
setTimeout(function() {
|
||||||
|
that.select(newItem)
|
||||||
|
},100);
|
||||||
|
}
|
||||||
|
that._trigger("sort",null,item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
item.treeList.addChild = function(newItem,select) {
|
||||||
|
item.treeList.insertChildAt(newItem,item.children.length,select);
|
||||||
|
}
|
||||||
|
item.treeList.expand = function(done) {
|
||||||
|
if (!item.children) {
|
||||||
|
if (done) { done() }
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!item.treeList.container) {
|
||||||
|
item.expanded = true;
|
||||||
|
if (done) { done() }
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var container = item.treeList.container;
|
||||||
|
if (container.hasClass("expanded")) {
|
||||||
|
if (done) { done() }
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!container.hasClass("built") && (item.deferBuild || typeof item.children === 'function')) {
|
||||||
|
container.addClass('built');
|
||||||
|
var childrenAdded = false;
|
||||||
|
var spinner;
|
||||||
|
var startTime = 0;
|
||||||
|
var completeBuild = function(children) {
|
||||||
|
childrenAdded = true;
|
||||||
|
item.treeList.childList = that._addChildren(container,item,children,depth).hide();
|
||||||
|
var delta = Date.now() - startTime;
|
||||||
|
if (delta < 400) {
|
||||||
|
setTimeout(function() {
|
||||||
|
item.treeList.childList.slideDown('fast');
|
||||||
|
if (spinner) {
|
||||||
|
spinner.remove();
|
||||||
|
}
|
||||||
|
},400-delta);
|
||||||
|
} else {
|
||||||
|
item.treeList.childList.slideDown('fast');
|
||||||
|
if (spinner) {
|
||||||
|
spinner.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
item.expanded = true;
|
||||||
|
if (done) { done() }
|
||||||
|
that._trigger("childrenloaded",null,item)
|
||||||
|
}
|
||||||
|
if (typeof item.children === 'function') {
|
||||||
|
item.children(completeBuild,item);
|
||||||
|
} else {
|
||||||
|
delete item.deferBuild;
|
||||||
|
completeBuild(item.children);
|
||||||
|
}
|
||||||
|
if (!childrenAdded) {
|
||||||
|
startTime = Date.now();
|
||||||
|
spinner = $('<div class="red-ui-treeList-spinner">').css({
|
||||||
|
"background-position": (35+depth*20)+'px 50%'
|
||||||
|
}).appendTo(container);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (that._loadingData) {
|
||||||
|
item.treeList.childList.show();
|
||||||
|
} else {
|
||||||
|
item.treeList.childList.slideDown('fast');
|
||||||
|
}
|
||||||
|
item.expanded = true;
|
||||||
|
if (done) { done() }
|
||||||
|
}
|
||||||
|
container.addClass("expanded");
|
||||||
|
}
|
||||||
|
item.treeList.collapse = function() {
|
||||||
|
if (!item.children) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
item.expanded = false;
|
||||||
|
if (item.treeList.container) {
|
||||||
|
item.treeList.childList.slideUp('fast');
|
||||||
|
item.treeList.container.removeClass("expanded");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
item.treeList.sortChildren = function(sortFunc) {
|
||||||
|
if (!item.children) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
item.children.sort(sortFunc);
|
||||||
|
if (item.treeList.childList) {
|
||||||
|
// Do a one-off sort of the list, which means calling sort twice:
|
||||||
|
// 1. first with the desired sort function
|
||||||
|
item.treeList.childList.editableList('sort',sortFunc);
|
||||||
|
// 2. and then with null to remove it
|
||||||
|
item.treeList.childList.editableList('sort',null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
item.treeList.replaceElement = function (element) {
|
||||||
|
if (item.element && item.treeList.container) {
|
||||||
|
$(item.element).remove();
|
||||||
|
item.element = element;
|
||||||
|
$(item.element).appendTo(label);
|
||||||
|
$(item.element).css({
|
||||||
|
width: "calc(100% - "+(labelPaddingWidth+20+(item.icon?20:0))+"px)"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.children && typeof item.children !== "function") {
|
||||||
|
item.children.forEach(function(i) {
|
||||||
|
that._initItem(i,depth+1);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_addSubtree: function(parentList, container, item, depth) {
|
||||||
|
var that = this;
|
||||||
|
this._initItem(item,depth);
|
||||||
|
// item.treeList = {};
|
||||||
|
// item.treeList.depth = depth;
|
||||||
|
item.treeList.container = container;
|
||||||
|
|
||||||
|
item.treeList.parentList = parentList;
|
||||||
|
// item.treeList.remove = function() {
|
||||||
|
// parentList.editableList('removeItem',item);
|
||||||
|
// if (item.parent) {
|
||||||
|
// var index = item.parent.children.indexOf(item);
|
||||||
|
// item.parent.children.splice(index,1)
|
||||||
|
// that._trigger("sort",null,item.parent);
|
||||||
|
// }
|
||||||
|
// delete(that._items[item.id]);
|
||||||
|
// }
|
||||||
|
|
||||||
var label = $("<div>",{class:"red-ui-treeList-label"}).appendTo(container);
|
var label = $("<div>",{class:"red-ui-treeList-label"}).appendTo(container);
|
||||||
item.treeList.label = label;
|
item.treeList.label = label;
|
||||||
@ -357,6 +513,7 @@
|
|||||||
treeListIcon.off("click.red-ui-treeList-expand");
|
treeListIcon.off("click.red-ui-treeList-expand");
|
||||||
delete item.children;
|
delete item.children;
|
||||||
container.removeClass("expanded");
|
container.removeClass("expanded");
|
||||||
|
delete item.expanded;
|
||||||
}
|
}
|
||||||
item.treeList.makeParent = function(children) {
|
item.treeList.makeParent = function(children) {
|
||||||
if (treeListIcon.children().length) {
|
if (treeListIcon.children().length) {
|
||||||
@ -388,86 +545,6 @@
|
|||||||
item.treeList.childList = that._addChildren(container,item,item.children,depth).hide();
|
item.treeList.childList = that._addChildren(container,item,item.children,depth).hide();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
item.treeList.insertChildAt = function(newItem,position,select) {
|
|
||||||
newItem.parent = item;
|
|
||||||
item.children.splice(position,0,newItem);
|
|
||||||
|
|
||||||
if (!item.deferBuild) {
|
|
||||||
item.treeList.childList.editableList('insertItemAt',newItem,position)
|
|
||||||
if (select) {
|
|
||||||
setTimeout(function() {
|
|
||||||
that.select(newItem)
|
|
||||||
},100);
|
|
||||||
}
|
|
||||||
that._trigger("sort",null,item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
item.treeList.addChild = function(newItem,select) {
|
|
||||||
item.treeList.insertChildAt(newItem,item.children.length,select);
|
|
||||||
}
|
|
||||||
item.treeList.expand = function(done) {
|
|
||||||
if (!item.children) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (container.hasClass("expanded")) {
|
|
||||||
if (done) { done() }
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!container.hasClass("built") && (item.deferBuild || typeof item.children === 'function')) {
|
|
||||||
container.addClass('built');
|
|
||||||
var childrenAdded = false;
|
|
||||||
var spinner;
|
|
||||||
var startTime = 0;
|
|
||||||
var completeBuild = function(children) {
|
|
||||||
childrenAdded = true;
|
|
||||||
item.treeList.childList = that._addChildren(container,item,children,depth).hide();
|
|
||||||
var delta = Date.now() - startTime;
|
|
||||||
if (delta < 400) {
|
|
||||||
setTimeout(function() {
|
|
||||||
item.treeList.childList.slideDown('fast');
|
|
||||||
if (spinner) {
|
|
||||||
spinner.remove();
|
|
||||||
}
|
|
||||||
},400-delta);
|
|
||||||
} else {
|
|
||||||
item.treeList.childList.slideDown('fast');
|
|
||||||
if (spinner) {
|
|
||||||
spinner.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (done) { done() }
|
|
||||||
that._trigger("childrenloaded",null,item)
|
|
||||||
}
|
|
||||||
if (typeof item.children === 'function') {
|
|
||||||
item.children(completeBuild,item);
|
|
||||||
} else {
|
|
||||||
delete item.deferBuild;
|
|
||||||
completeBuild(item.children);
|
|
||||||
}
|
|
||||||
if (!childrenAdded) {
|
|
||||||
startTime = Date.now();
|
|
||||||
spinner = $('<div class="red-ui-treeList-spinner">').css({
|
|
||||||
"background-position": (35+depth*20)+'px 50%'
|
|
||||||
}).appendTo(container);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
if (that._loadingData) {
|
|
||||||
item.treeList.childList.show();
|
|
||||||
} else {
|
|
||||||
item.treeList.childList.slideDown('fast');
|
|
||||||
}
|
|
||||||
if (done) { done() }
|
|
||||||
}
|
|
||||||
container.addClass("expanded");
|
|
||||||
}
|
|
||||||
item.treeList.collapse = function() {
|
|
||||||
if (!item.children) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
item.treeList.childList.slideUp('fast');
|
|
||||||
container.removeClass("expanded");
|
|
||||||
}
|
|
||||||
|
|
||||||
var treeListIcon = $('<span class="red-ui-treeList-icon"></span>').appendTo(label);
|
var treeListIcon = $('<span class="red-ui-treeList-icon"></span>').appendTo(label);
|
||||||
if (item.children) {
|
if (item.children) {
|
||||||
@ -499,7 +576,9 @@
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
label.on("click", function(e) {
|
label.on("click", function(e) {
|
||||||
|
if (!that.options.multi) {
|
||||||
that._topList.find(".selected").removeClass("selected");
|
that._topList.find(".selected").removeClass("selected");
|
||||||
|
}
|
||||||
label.addClass("selected");
|
label.addClass("selected");
|
||||||
that._trigger("select",e,item)
|
that._trigger("select",e,item)
|
||||||
})
|
})
|
||||||
@ -508,9 +587,22 @@
|
|||||||
that._trigger("confirm",e,item);
|
that._trigger("confirm",e,item);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
item.treeList.select = function(v) {
|
||||||
|
if (!that.options.multi) {
|
||||||
|
that._topList.find(".selected").removeClass("selected");
|
||||||
|
}
|
||||||
|
label.toggleClass("selected",v);
|
||||||
|
if (v) {
|
||||||
|
that._trigger("select",null,item)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (item.icon) {
|
if (item.icon) {
|
||||||
|
if (typeof item.icon === "string") {
|
||||||
$('<span class="red-ui-treeList-icon"><i class="'+item.icon+'" /></span>').appendTo(label);
|
$('<span class="red-ui-treeList-icon"><i class="'+item.icon+'" /></span>').appendTo(label);
|
||||||
|
} else {
|
||||||
|
$('<span class="red-ui-treeList-icon">').appendTo(label).append(item.icon);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (item.hasOwnProperty('label') || item.hasOwnProperty('sublabel')) {
|
if (item.hasOwnProperty('label') || item.hasOwnProperty('sublabel')) {
|
||||||
if (item.hasOwnProperty('label')) {
|
if (item.hasOwnProperty('label')) {
|
||||||
@ -542,6 +634,7 @@
|
|||||||
var that = this;
|
var that = this;
|
||||||
if (items !== undefined) {
|
if (items !== undefined) {
|
||||||
this._data = items;
|
this._data = items;
|
||||||
|
this._items = {};
|
||||||
this._topList.editableList('empty');
|
this._topList.editableList('empty');
|
||||||
this._loadingData = true;
|
this._loadingData = true;
|
||||||
for (var i=0; i<items.length;i++) {
|
for (var i=0; i<items.length;i++) {
|
||||||
@ -557,18 +650,41 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
show: function(id) {
|
show: function(id) {
|
||||||
for (var i=0;i<this._data.length;i++) {
|
var that = this;
|
||||||
if (this._data[i].id === id) {
|
var item = this._items[id];
|
||||||
this._topList.editableList('show',this._data[i]);
|
var stack = [];
|
||||||
|
var i = item;
|
||||||
|
while(i) {
|
||||||
|
stack.unshift(i);
|
||||||
|
i = i.parent;
|
||||||
|
}
|
||||||
|
var handleStack = function() {
|
||||||
|
var item = stack.shift();
|
||||||
|
if (stack.length === 0) {
|
||||||
|
item.treeList.parentList.editableList('show',item);
|
||||||
|
} else {
|
||||||
|
item.treeList.expand(handleStack)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
handleStack();
|
||||||
|
|
||||||
|
// for (var i=0;i<this._data.length;i++) {
|
||||||
|
// if (this._data[i].id === id) {
|
||||||
|
// this._topList.editableList('show',this._data[i]);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
},
|
},
|
||||||
select: function(item) {
|
select: function(item) {
|
||||||
|
if (!this.options.multi) {
|
||||||
this._topList.find(".selected").removeClass("selected");
|
this._topList.find(".selected").removeClass("selected");
|
||||||
|
}
|
||||||
item.treeList.label.addClass("selected");
|
item.treeList.label.addClass("selected");
|
||||||
this._trigger("select",null,item)
|
this._trigger("select",null,item)
|
||||||
|
|
||||||
},
|
},
|
||||||
|
clearSelection: function() {
|
||||||
|
this._topList.find(".selected").removeClass("selected");
|
||||||
|
},
|
||||||
selected: function() {
|
selected: function() {
|
||||||
var s = this._topList.find(".selected");
|
var s = this._topList.find(".selected");
|
||||||
if (this.options.multi) {
|
if (this.options.multi) {
|
||||||
@ -583,6 +699,34 @@
|
|||||||
} else {
|
} else {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
filter: function(filterFunc) {
|
||||||
|
var filter = function(item) {
|
||||||
|
// console.log(item);
|
||||||
|
var childCount = 0;
|
||||||
|
if (filterFunc && filterFunc(item)) {
|
||||||
|
childCount++;
|
||||||
|
}
|
||||||
|
if (item.children && typeof item.children !== "function") {
|
||||||
|
if (item.treeList.childList) {
|
||||||
|
childCount += item.treeList.childList.editableList('filter', filter);
|
||||||
|
} else {
|
||||||
|
item.treeList.childFilter = filter;
|
||||||
|
if (filterFunc) {
|
||||||
|
item.children.forEach(function(i) {
|
||||||
|
if (filter(i)) {
|
||||||
|
childCount++;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!filterFunc) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return childCount > 0
|
||||||
|
}
|
||||||
|
return this._topList.editableList('filter', filter);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user