Separate 'focus' from 'selected' state in treeList

This commit is contained in:
Nick O'Leary 2021-10-12 16:49:38 +01:00
parent be7e28af5d
commit 7cd92faf0d
No known key found for this signature in database
GPG Key ID: 4F2157149161A6C9
4 changed files with 85 additions and 34 deletions

View File

@ -24,6 +24,9 @@
* - rootSortable: boolean - if 'sortable' is set, then setting this to * - rootSortable: boolean - if 'sortable' is set, then setting this to
* false, prevents items being sorted to the * false, prevents items being sorted to the
* top level of the tree * top level of the tree
* - autoSelect: boolean - default true - triggers item selection when navigating
* list by keyboard. If the list has checkboxed items
* you probably want to set this to false
* *
* methods: * methods:
* - data(items) - clears existing items and replaces with new data * - data(items) - clears existing items and replaces with new data
@ -50,6 +53,7 @@
* deferBuild: true/false, // don't build any ui elements for the item's children * deferBuild: true/false, // don't build any ui elements for the item's children
* until it is expanded by the user. * until it is expanded by the user.
* element: // custom dom element to use for the item - ignored if `label` is set * element: // custom dom element to use for the item - ignored if `label` is set
* collapsible: true/false, // prevent a parent item from being collapsed. default true.
* } * }
* ] * ]
* *
@ -90,77 +94,96 @@
$.widget( "nodered.treeList", { $.widget( "nodered.treeList", {
_create: function() { _create: function() {
var that = this; var that = this;
var autoSelect = true;
if (that.options.autoSelect === false) {
autoSelect = false;
}
this.element.addClass('red-ui-treeList'); this.element.addClass('red-ui-treeList');
this.element.attr("tabIndex",0); this.element.attr("tabIndex",0);
var wrapper = $('<div>',{class:'red-ui-treeList-container'}).appendTo(this.element); var wrapper = $('<div>',{class:'red-ui-treeList-container'}).appendTo(this.element);
this.element.on('keydown', function(evt) { this.element.on('keydown', function(evt) {
var selected = that._topList.find(".selected").parent().data('data'); var focussed = that._topList.find(".focus").parent().data('data');
if (!selected && (evt.keyCode === 40 || evt.keyCode === 38)) { if (!focussed && (evt.keyCode === 40 || evt.keyCode === 38)) {
that.select(that._data[0]); if (that._data[0]) {
if (autoSelect) {
that.select(that._data[0]);
} else {
that._topList.find(".focus").removeClass("focus")
}
that._data[0].treeList.label.addClass('focus')
}
return; return;
} }
var target; var target;
switch(evt.keyCode) { switch(evt.keyCode) {
case 32: // SPACE
case 13: // ENTER case 13: // ENTER
evt.preventDefault(); evt.preventDefault();
evt.stopPropagation(); evt.stopPropagation();
if (selected.children) { if (focussed.checkbox) {
if (selected.treeList.container.hasClass("expanded")) { focussed.treeList.checkbox.trigger("click");
selected.treeList.collapse() } else if (focussed.radio) {
focussed.treeList.radio.trigger("click");
} else if (focussed.children) {
if (focussed.treeList.container.hasClass("expanded")) {
focussed.treeList.collapse()
} else { } else {
selected.treeList.expand() focussed.treeList.expand()
} }
} else { } else {
that._trigger("confirm",null,selected) that._trigger("confirm",null,focussed)
} }
break; break;
case 37: // LEFT case 37: // LEFT
evt.preventDefault(); evt.preventDefault();
evt.stopPropagation(); evt.stopPropagation();
if (selected.children&& selected.treeList.container.hasClass("expanded")) { if (focussed.children&& focussed.treeList.container.hasClass("expanded")) {
selected.treeList.collapse() focussed.treeList.collapse()
} else if (selected.parent) { } else if (focussed.parent) {
target = selected.parent; target = focussed.parent;
} }
break; break;
case 38: // UP case 38: // UP
evt.preventDefault(); evt.preventDefault();
evt.stopPropagation(); evt.stopPropagation();
target = that._getPreviousSibling(selected); target = that._getPreviousSibling(focussed);
if (target) { if (target) {
target = that._getLastDescendant(target); target = that._getLastDescendant(target);
} }
if (!target && selected.parent) { if (!target && focussed.parent) {
target = selected.parent; target = focussed.parent;
} }
break; break;
case 39: // RIGHT case 39: // RIGHT
evt.preventDefault(); evt.preventDefault();
evt.stopPropagation(); evt.stopPropagation();
if (selected.children) { if (focussed.children) {
if (!selected.treeList.container.hasClass("expanded")) { if (!focussed.treeList.container.hasClass("expanded")) {
selected.treeList.expand() focussed.treeList.expand()
} }
} }
break break
case 40: //DOWN case 40: //DOWN
evt.preventDefault(); evt.preventDefault();
evt.stopPropagation(); evt.stopPropagation();
if (selected.children && Array.isArray(selected.children) && selected.children.length > 0 && selected.treeList.container.hasClass("expanded")) { if (focussed.children && Array.isArray(focussed.children) && focussed.children.length > 0 && focussed.treeList.container.hasClass("expanded")) {
target = selected.children[0]; target = focussed.children[0];
} else { } else {
target = that._getNextSibling(selected); target = that._getNextSibling(focussed);
while (!target && selected.parent) { while (!target && focussed.parent) {
selected = selected.parent; focussed = focussed.parent;
target = that._getNextSibling(selected); target = that._getNextSibling(focussed);
} }
} }
break break
} }
if (target) { if (target) {
that.select(target); if (autoSelect) {
that.select(target);
} else {
that._topList.find(".focus").removeClass("focus")
}
target.treeList.label.addClass('focus')
} }
}); });
this._data = []; this._data = [];
@ -463,6 +486,9 @@
container.addClass("expanded"); container.addClass("expanded");
} }
item.treeList.collapse = function() { item.treeList.collapse = function() {
if (item.collapsible === false) {
return
}
if (!item.children) { if (!item.children) {
return; return;
} }
@ -583,7 +609,7 @@
// Already a parent because we've got the angle-right icon // Already a parent because we've got the angle-right icon
return; return;
} }
$('<i class="fa fa-angle-right" />').appendTo(treeListIcon); $('<i class="fa fa-angle-right" />').toggleClass("hide",item.collapsible === false).appendTo(treeListIcon);
treeListIcon.on("click.red-ui-treeList-expand", function(e) { treeListIcon.on("click.red-ui-treeList-expand", function(e) {
e.stopPropagation(); e.stopPropagation();
e.preventDefault(); e.preventDefault();
@ -634,6 +660,8 @@
label.on("click", function(e) { label.on("click", function(e) {
e.stopPropagation(); e.stopPropagation();
cb.trigger("click"); cb.trigger("click");
that._topList.find(".focus").removeClass("focus")
label.addClass('focus')
}) })
} }
item.treeList.select = function(v) { item.treeList.select = function(v) {
@ -641,6 +669,7 @@
cb.trigger("click"); cb.trigger("click");
} }
} }
item.treeList.checkbox = cb;
selectWrapper.appendTo(label) selectWrapper.appendTo(label)
} else if (item.radio) { } else if (item.radio) {
var selectWrapper = $('<span class="red-ui-treeList-icon"></span>'); var selectWrapper = $('<span class="red-ui-treeList-icon"></span>');
@ -669,6 +698,8 @@
label.on("click", function(e) { label.on("click", function(e) {
e.stopPropagation(); e.stopPropagation();
cb.trigger("click"); cb.trigger("click");
that._topList.find(".focus").removeClass("focus")
label.addClass('focus')
}) })
} }
item.treeList.select = function(v) { item.treeList.select = function(v) {
@ -677,6 +708,7 @@
} }
} }
selectWrapper.appendTo(label) selectWrapper.appendTo(label)
item.treeList.radio = cb;
} else { } else {
label.on("click", function(e) { label.on("click", function(e) {
if (!that.options.multi) { if (!that.options.multi) {
@ -684,10 +716,14 @@
} }
label.addClass("selected"); label.addClass("selected");
that._selected.add(item); that._selected.add(item);
that._topList.find(".focus").removeClass("focus")
label.addClass('focus')
that._trigger("select",e,item) that._trigger("select",e,item)
}) })
label.on("dblclick", function(e) { label.on("dblclick", function(e) {
that._topList.find(".focus").removeClass("focus")
label.addClass('focus')
if (!item.children) { if (!item.children) {
that._trigger("confirm",e,item); that._trigger("confirm",e,item);
} }
@ -835,6 +871,9 @@
if (item.treeList.label) { if (item.treeList.label) {
item.treeList.label.addClass("selected"); item.treeList.label.addClass("selected");
} }
that._topList.find(".focus").removeClass("focus");
if (triggerEvent !== false) { if (triggerEvent !== false) {
this._trigger("select",null,item) this._trigger("select",null,item)
} }
@ -842,6 +881,9 @@
clearSelection: function() { clearSelection: function() {
this._selected.forEach(function(item) { this._selected.forEach(function(item) {
item.selected = false; item.selected = false;
if (item.treeList.checkbox) {
item.treeList.checkbox.prop('checked',false)
}
if (item.treeList.label) { if (item.treeList.label) {
item.treeList.label.removeClass("selected") item.treeList.label.removeClass("selected")
} }

View File

@ -287,11 +287,11 @@ RED.sidebar.info.outliner = (function() {
var node = RED.nodes.node(item.id) || RED.nodes.group(item.id); var node = RED.nodes.node(item.id) || RED.nodes.group(item.id);
if (node) { if (node) {
if (node.type === 'group' || node._def.category !== "config") { if (node.type === 'group' || node._def.category !== "config") {
RED.view.select({nodes:[node]}) // RED.view.select({nodes:[node]})
} else if (node._def.category === "config") { } else if (node._def.category === "config") {
RED.sidebar.info.refresh(node); RED.sidebar.info.refresh(node);
} else { } else {
RED.view.select({nodes:[]}) // RED.view.select({nodes:[]})
} }
} }
}) })

View File

@ -434,16 +434,19 @@ div.red-ui-info-table {
} }
.red-ui-info-outline-item-controls { .red-ui-info-outline-item-controls {
position: absolute; position: absolute;
top:0; top:1px;
bottom: 0; bottom: 1px;
right: 0px; right: 1px;
padding: 2px 3px 0 1px; padding: 1px 2px 0 1px;
text-align: right; text-align: right;
background: $list-item-background; background: $list-item-background;
.red-ui-treeList-label:hover & { .red-ui-treeList-label:hover & {
background: $list-item-background-hover; background: $list-item-background-hover;
} }
.red-ui-treeList-label.focus & {
background: $list-item-background-hover;
}
.red-ui-treeList-label.selected & { .red-ui-treeList-label.selected & {
background: $list-item-background-selected; background: $list-item-background-selected;
} }

View File

@ -89,6 +89,12 @@
color: $list-item-color; color: $list-item-color;
text-decoration: none; text-decoration: none;
} }
&.focus, &.focus .red-ui-treeList-sublabel-text {
background: $list-item-background-hover;
outline: 1px solid $form-input-focus-color !important;
outline-offset: -1px;
color: $list-item-color;
}
&.selected, &.selected .red-ui-treeList-sublabel-text { &.selected, &.selected .red-ui-treeList-sublabel-text {
background: $list-item-background-selected; background: $list-item-background-selected;
outline: none; outline: none;