From d2d872f51c65352baa5f2c5a910a089d9b659118 Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Mon, 27 Apr 2020 11:14:47 +0100 Subject: [PATCH] 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) --- .../src/js/ui/common/treeList.js | 340 +++++++++++++----- 1 file changed, 242 insertions(+), 98 deletions(-) diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/common/treeList.js b/packages/node_modules/@node-red/editor-client/src/js/ui/common/treeList.js index ed04733c9..8e3281b3b 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/common/treeList.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/common/treeList.js @@ -27,7 +27,8 @@ * * methods: * - 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: * - treelistselect : function(event, item) {} * - treelistconfirm : function(event,item) {} @@ -59,9 +60,9 @@ * properties and functions: * * item.parent - set to the parent item + * item.depth - the depth in the tree (0 == root) * item.treeList.container * 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.remove() - removes the item from the tree * item.treeList.makeLeaf(detachChildElements) - turns an element with children into a leaf node, @@ -78,8 +79,8 @@ * Optionally selects the item after adding. * 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.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._items = {}; this._topList = $('
    ').css({ position:'absolute', top: 0, @@ -244,7 +245,8 @@ that._trigger("changeparent",null,evt); }); that._trigger("sort",null,parent); - } + }, + filter: parent.treeList.childFilter }); if (!!that.options.sortable) { subtree.addClass('red-ui-treeList-sortable'); @@ -289,21 +291,175 @@ } return reparentedEvent; }, - _addSubtree: function(parentList, container, item, depth) { + _initItem: function(item,depth) { + if (item.treeList) { + return; + } var that = this; + this._items[item.id] = item; item.treeList = {}; - item.treeList.depth = depth; - item.treeList.container = container; - - item.treeList.parentList = parentList; + item.depth = depth; item.treeList.remove = function() { - parentList.editableList('removeItem',item); + if (item.treeList.parentList) { + item.treeList.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]); } + 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 = $('
    ').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 = $("
    ",{class:"red-ui-treeList-label"}).appendTo(container); item.treeList.label = label; @@ -357,6 +513,7 @@ treeListIcon.off("click.red-ui-treeList-expand"); delete item.children; container.removeClass("expanded"); + delete item.expanded; } item.treeList.makeParent = function(children) { if (treeListIcon.children().length) { @@ -388,86 +545,6 @@ 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 = $('
    ').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 = $('').appendTo(label); if (item.children) { @@ -499,7 +576,9 @@ } } else { label.on("click", function(e) { - that._topList.find(".selected").removeClass("selected"); + if (!that.options.multi) { + that._topList.find(".selected").removeClass("selected"); + } label.addClass("selected"); that._trigger("select",e,item) }) @@ -508,9 +587,22 @@ 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) { - $('').appendTo(label); + if (typeof item.icon === "string") { + $('').appendTo(label); + } else { + $('').appendTo(label).append(item.icon); + } } if (item.hasOwnProperty('label') || item.hasOwnProperty('sublabel')) { if (item.hasOwnProperty('label')) { @@ -542,6 +634,7 @@ var that = this; if (items !== undefined) { this._data = items; + this._items = {}; this._topList.editableList('empty'); this._loadingData = true; for (var i=0; i 0 + } + return this._topList.editableList('filter', filter); } });