mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
Add keyboard nav to treeList
This commit is contained in:
parent
3e9d2a8062
commit
337dfba2b8
@ -370,6 +370,8 @@ RED.clipboard = (function() {
|
|||||||
}
|
}
|
||||||
if (tab.id === "clipboard-dialog-import-tab-clipboard") {
|
if (tab.id === "clipboard-dialog-import-tab-clipboard") {
|
||||||
$("#clipboard-import").focus();
|
$("#clipboard-import").focus();
|
||||||
|
} else {
|
||||||
|
libraryBrowser.focus();
|
||||||
}
|
}
|
||||||
validateImport();
|
validateImport();
|
||||||
}
|
}
|
||||||
@ -471,6 +473,7 @@ RED.clipboard = (function() {
|
|||||||
} else {
|
} else {
|
||||||
$("#clipboard-dialog-export").button("option","label", RED._("clipboard.export.export"))
|
$("#clipboard-dialog-export").button("option","label", RED._("clipboard.export.export"))
|
||||||
$("#clipboard-dialog-download").hide();
|
$("#clipboard-dialog-download").hide();
|
||||||
|
libraryBrowser.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -492,7 +495,7 @@ RED.clipboard = (function() {
|
|||||||
|
|
||||||
libraryBrowser = RED.library.createBrowser({
|
libraryBrowser = RED.library.createBrowser({
|
||||||
container: $("#clipboard-dialog-export-tab-library-browser"),
|
container: $("#clipboard-dialog-export-tab-library-browser"),
|
||||||
addFolderButton: true,
|
folderTools: true,
|
||||||
onselect: function(file) {
|
onselect: function(file) {
|
||||||
if (file && file.label && !file.children) {
|
if (file && file.label && !file.children) {
|
||||||
$("#clipboard-dialog-tab-library-name").val(file.label);
|
$("#clipboard-dialog-tab-library-name").val(file.label);
|
||||||
|
@ -51,8 +51,55 @@
|
|||||||
var that = this;
|
var that = this;
|
||||||
|
|
||||||
this.element.addClass('red-ui-treeList');
|
this.element.addClass('red-ui-treeList');
|
||||||
|
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) {
|
||||||
|
var selected = that._topList.find(".selected").parent().data('data');
|
||||||
|
if (!selected && (evt.keyCode === 40 || evt.keyCode === 38)) {
|
||||||
|
that.select(that._data[0]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var target;
|
||||||
|
switch(evt.keyCode) {
|
||||||
|
case 37: // LEFT
|
||||||
|
if (selected.children&& selected.treeList.container.hasClass("expanded")) {
|
||||||
|
selected.treeList.collapse()
|
||||||
|
} else if (selected.parent) {
|
||||||
|
target = selected.parent;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 38: // UP
|
||||||
|
target = that._getPreviousSibling(selected);
|
||||||
|
if (target) {
|
||||||
|
target = that._getLastDescendant(target);
|
||||||
|
}
|
||||||
|
if (!target && selected.parent) {
|
||||||
|
target = selected.parent;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 39: // RIGHT
|
||||||
|
if (selected.children) {
|
||||||
|
if (!selected.treeList.container.hasClass("expanded")) {
|
||||||
|
selected.treeList.expand()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 40: //DOWN
|
||||||
|
if (selected.children && Array.isArray(selected.children) && selected.children.length > 0 && selected.treeList.container.hasClass("expanded")) {
|
||||||
|
target = selected.children[0];
|
||||||
|
} else {
|
||||||
|
target = that._getNextSibling(selected);
|
||||||
|
while (!target && selected.parent) {
|
||||||
|
selected = selected.parent;
|
||||||
|
target = that._getNextSibling(selected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if (target) {
|
||||||
|
that.select(target);
|
||||||
|
}
|
||||||
|
});
|
||||||
this._data = [];
|
this._data = [];
|
||||||
|
|
||||||
this._topList = $('<ol>').css({
|
this._topList = $('<ol>').css({
|
||||||
@ -68,11 +115,46 @@
|
|||||||
addItem: function(container,i,item) {
|
addItem: function(container,i,item) {
|
||||||
that._addSubtree(that._topList,container,item,0);
|
that._addSubtree(that._topList,container,item,0);
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
if (this.options.data) {
|
if (this.options.data) {
|
||||||
this.data(this.options.data);
|
this.data(this.options.data);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
_getLastDescendant: function(item) {
|
||||||
|
// Gets the last visible descendant of the item
|
||||||
|
if (!item.children || !item.treeList.container.hasClass("expanded") || item.children.length === 0) {
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
return this._getLastDescendant(item.children[item.children.length-1]);
|
||||||
|
},
|
||||||
|
_getPreviousSibling: function(item) {
|
||||||
|
var candidates;
|
||||||
|
if (!item.parent) {
|
||||||
|
candidates = this._data;
|
||||||
|
} else {
|
||||||
|
candidates = item.parent.children;
|
||||||
|
}
|
||||||
|
var index = candidates.indexOf(item);
|
||||||
|
if (index === 0) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return candidates[index-1];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_getNextSibling: function(item) {
|
||||||
|
var candidates;
|
||||||
|
if (!item.parent) {
|
||||||
|
candidates = this._data;
|
||||||
|
} else {
|
||||||
|
candidates = item.parent.children;
|
||||||
|
}
|
||||||
|
var index = candidates.indexOf(item);
|
||||||
|
if (index === candidates.length - 1) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return candidates[index+1];
|
||||||
|
}
|
||||||
|
},
|
||||||
_addChildren: function(container,parent,children,depth) {
|
_addChildren: function(container,parent,children,depth) {
|
||||||
var that = this;
|
var that = this;
|
||||||
var subtree = $('<ol>').appendTo(container).editableList({
|
var subtree = $('<ol>').appendTo(container).editableList({
|
||||||
@ -92,15 +174,21 @@
|
|||||||
_addSubtree: function(parentList, container, item, depth) {
|
_addSubtree: function(parentList, container, item, depth) {
|
||||||
var that = this;
|
var that = this;
|
||||||
item.treeList = {};
|
item.treeList = {};
|
||||||
|
item.treeList.container = container;
|
||||||
|
|
||||||
item.treeList.parentList = parentList;
|
item.treeList.parentList = parentList;
|
||||||
item.treeList.remove = function() {
|
item.treeList.remove = function() {
|
||||||
parentList.editableList('removeItem',item);
|
parentList.editableList('removeItem',item);
|
||||||
|
if (item.parent) {
|
||||||
|
var index = item.parent.children.indexOf(item);
|
||||||
|
item.parent.children.splice(index,1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
var labelNodeType = "<label>";
|
var labelNodeType = "<div>";
|
||||||
if (item.children && item.hasOwnProperty('selected')) {
|
// if (item.children && item.hasOwnProperty('selected')) {
|
||||||
labelNodeType = "<div>";
|
// labelNodeType = "<div>";
|
||||||
}
|
// }
|
||||||
var label = $(labelNodeType,{tabindex:"0",class:"red-ui-treeList-label"}).appendTo(container);
|
var label = $(labelNodeType,{class:"red-ui-treeList-label"}).appendTo(container);
|
||||||
item.treeList.label = label;
|
item.treeList.label = label;
|
||||||
if (item.class) {
|
if (item.class) {
|
||||||
label.addClass(item.class);
|
label.addClass(item.class);
|
||||||
@ -110,13 +198,25 @@
|
|||||||
})
|
})
|
||||||
label.on('mouseover',function(e) { that._trigger('itemmouseover',e,item); })
|
label.on('mouseover',function(e) { that._trigger('itemmouseover',e,item); })
|
||||||
label.on('mouseout',function(e) { that._trigger('itemmouseout',e,item); })
|
label.on('mouseout',function(e) { that._trigger('itemmouseout',e,item); })
|
||||||
|
label.on('mouseenter',function(e) { that._trigger('itemmouseenter',e,item); })
|
||||||
|
label.on('mouseleave',function(e) { that._trigger('itemmouseleave',e,item); })
|
||||||
|
|
||||||
if (item.children) {
|
if (item.children) {
|
||||||
item.treeList.addChild = function(newItem) {
|
item.treeList.addChild = function(newItem,select) {
|
||||||
item.treeList.childList.editableList('addItem',newItem)
|
item.treeList.childList.editableList('addItem',newItem)
|
||||||
|
newItem.parent = item;
|
||||||
item.children.push(newItem);
|
item.children.push(newItem);
|
||||||
|
if (select) {
|
||||||
|
setTimeout(function() {
|
||||||
|
that.select(newItem)
|
||||||
|
},100);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
item.treeList.expand = function() {
|
item.treeList.expand = function(done) {
|
||||||
|
if (container.hasClass("expanded")) {
|
||||||
|
done && done();
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!container.hasClass("built") && typeof item.children === 'function') {
|
if (!container.hasClass("built") && typeof item.children === 'function') {
|
||||||
container.addClass('built');
|
container.addClass('built');
|
||||||
var childrenAdded = false;
|
var childrenAdded = false;
|
||||||
@ -139,6 +239,7 @@
|
|||||||
spinner.remove();
|
spinner.remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
done && done();
|
||||||
that._trigger("childrenloaded",null,item)
|
that._trigger("childrenloaded",null,item)
|
||||||
});
|
});
|
||||||
if (!childrenAdded) {
|
if (!childrenAdded) {
|
||||||
@ -150,9 +251,9 @@
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
item.treeList.childList.slideDown('fast');
|
item.treeList.childList.slideDown('fast');
|
||||||
|
done && done();
|
||||||
}
|
}
|
||||||
container.addClass("expanded");
|
container.addClass("expanded");
|
||||||
|
|
||||||
}
|
}
|
||||||
item.treeList.collapse = function() {
|
item.treeList.collapse = function() {
|
||||||
item.treeList.childList.slideUp('fast');
|
item.treeList.childList.slideUp('fast');
|
||||||
@ -163,7 +264,9 @@
|
|||||||
// $('<span class="red-ui-treeList-icon"><i class="fa fa-folder-o" /></span>').appendTo(label);
|
// $('<span class="red-ui-treeList-icon"><i class="fa fa-folder-o" /></span>').appendTo(label);
|
||||||
label.click(function(e) {
|
label.click(function(e) {
|
||||||
if (container.hasClass("expanded")) {
|
if (container.hasClass("expanded")) {
|
||||||
item.treeList.collapse();
|
if (item.hasOwnProperty('selected') || label.hasClass("selected")) {
|
||||||
|
item.treeList.collapse();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
item.treeList.expand();
|
item.treeList.expand();
|
||||||
}
|
}
|
||||||
|
@ -61,6 +61,7 @@ RED.library = (function() {
|
|||||||
if (!selectedPath.children) {
|
if (!selectedPath.children) {
|
||||||
selectedPath = selectedPath.parent;
|
selectedPath = selectedPath.parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
var queryArgs = [];
|
var queryArgs = [];
|
||||||
var data = {};
|
var data = {};
|
||||||
for (var i=0; i<activeLibrary.fields.length; i++) {
|
for (var i=0; i<activeLibrary.fields.length; i++) {
|
||||||
@ -287,91 +288,117 @@ RED.library = (function() {
|
|||||||
console.warn("Deprecated call to RED.library.export");
|
console.warn("Deprecated call to RED.library.export");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var menuOptionMenu;
|
||||||
function createBrowser(options) {
|
function createBrowser(options) {
|
||||||
var panes = $('<div class="red-ui-library-browser"></div>').appendTo(options.container);
|
var panes = $('<div class="red-ui-library-browser"></div>').appendTo(options.container);
|
||||||
var dirList = $("<div>").css({width: "100%", height: "100%"}).appendTo(panes)
|
var dirList = $("<div>").css({width: "100%", height: "100%"}).appendTo(panes)
|
||||||
.treeList({}).on('treelistselect', function(event, item) {
|
.treeList({}).on('treelistselect', function(event, item) {
|
||||||
if (addButton) {
|
|
||||||
if (item.writable === false) {
|
|
||||||
addButton.prop('disabled', true);
|
|
||||||
} else {
|
|
||||||
addButton.prop('disabled', false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (options.onselect) {
|
if (options.onselect) {
|
||||||
options.onselect(item);
|
options.onselect(item);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
var addButton;
|
var itemTools = $("<div>").css({position: "absolute",bottom:"6px",right:"8px"});
|
||||||
if (options.addFolderButton) {
|
var menuButton = $('<button class="editor-button editor-button-small" type="button"><i class="fa fa-ellipsis-h"></i></button>')
|
||||||
var tools = $("<div>").css({position: "absolute",bottom:"3px",right:"25px"}).appendTo(panes)
|
.click(function(evt) {
|
||||||
addButton= $('<button type="button" class="editor-button editor-button-small"><i class="fa fa-plus"> <i class="fa fa-folder-o"></button>').appendTo(tools).click(function(e) {
|
evt.preventDefault();
|
||||||
var defaultFolderName = "new-folder";
|
evt.stopPropagation();
|
||||||
var defaultFolderNameMatches = {};
|
var elementPos = menuButton.offset();
|
||||||
|
|
||||||
var selected = dirList.treeList('selected');
|
var menuOptionMenu = RED.menu.init({id:"red-ui-library-browser-menu",
|
||||||
if (!selected.children) {
|
options: [
|
||||||
selected = selected.parent;
|
{id:"red-ui-library-browser-menu-addFolder",label:"New folder", onselect: function() {
|
||||||
}
|
var defaultFolderName = "new-folder";
|
||||||
selected.children.forEach(function(c) {
|
var defaultFolderNameMatches = {};
|
||||||
if (/^new-folder/.test(c.label)) {
|
|
||||||
defaultFolderNameMatches[c.label] = true
|
|
||||||
}
|
|
||||||
});
|
|
||||||
var folderIndex = 2;
|
|
||||||
while(defaultFolderNameMatches[defaultFolderName]) {
|
|
||||||
defaultFolderName = "new-folder-"+(folderIndex++)
|
|
||||||
}
|
|
||||||
|
|
||||||
selected.treeList.expand();
|
var selected = dirList.treeList('selected');
|
||||||
var input = $('<input type="text" class="red-ui-treeList-input">').val(defaultFolderName);
|
if (!selected.children) {
|
||||||
var newItem = {
|
selected = selected.parent;
|
||||||
icon: "fa fa-folder-o",
|
|
||||||
children:[],
|
|
||||||
path: selected.path,
|
|
||||||
element: input
|
|
||||||
}
|
|
||||||
var confirmAdd = function() {
|
|
||||||
var val = input.val().trim();
|
|
||||||
if (val === "") {
|
|
||||||
cancelAdd();
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
for (var i=0;i<selected.children.length;i++) {
|
|
||||||
if (selected.children[i].label === val) {
|
|
||||||
cancelAdd();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
var complete = function() {
|
||||||
}
|
selected.children.forEach(function(c) {
|
||||||
newItem.treeList.remove();
|
if (/^new-folder/.test(c.label)) {
|
||||||
selected.treeList.addChild({
|
defaultFolderNameMatches[c.label] = true
|
||||||
icon: "fa fa-folder",
|
}
|
||||||
children:[],
|
});
|
||||||
label: val,
|
var folderIndex = 2;
|
||||||
path: newItem.path+val+"/"
|
while(defaultFolderNameMatches[defaultFolderName]) {
|
||||||
});
|
defaultFolderName = "new-folder-"+(folderIndex++)
|
||||||
|
}
|
||||||
|
|
||||||
|
selected.treeList.expand();
|
||||||
|
var input = $('<input type="text" class="red-ui-treeList-input">').val(defaultFolderName);
|
||||||
|
var newItem = {
|
||||||
|
icon: "fa fa-folder-o",
|
||||||
|
children:[],
|
||||||
|
path: selected.path,
|
||||||
|
element: input
|
||||||
|
}
|
||||||
|
var confirmAdd = function() {
|
||||||
|
var val = input.val().trim();
|
||||||
|
if (val === "") {
|
||||||
|
cancelAdd();
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
for (var i=0;i<selected.children.length;i++) {
|
||||||
|
if (selected.children[i].label === val) {
|
||||||
|
cancelAdd();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
newItem.treeList.remove();
|
||||||
|
var finalItem = {
|
||||||
|
library: selected.library,
|
||||||
|
type: selected.type,
|
||||||
|
icon: "fa fa-folder",
|
||||||
|
children:[],
|
||||||
|
label: val,
|
||||||
|
path: newItem.path+val+"/"
|
||||||
|
}
|
||||||
|
selected.treeList.addChild(finalItem,true);
|
||||||
|
}
|
||||||
|
var cancelAdd = function() {
|
||||||
|
newItem.treeList.remove();
|
||||||
|
}
|
||||||
|
input.on('keydown', function(evt) {
|
||||||
|
evt.stopPropagation();
|
||||||
|
if (evt.keyCode === 13) {
|
||||||
|
confirmAdd();
|
||||||
|
} else if (evt.keyCode === 27) {
|
||||||
|
cancelAdd();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
input.blur(function() {
|
||||||
|
confirmAdd();
|
||||||
|
})
|
||||||
|
selected.treeList.addChild(newItem);
|
||||||
|
setTimeout(function() {
|
||||||
|
input.focus();
|
||||||
|
input.select();
|
||||||
|
},400);
|
||||||
|
}
|
||||||
|
selected.treeList.expand(complete);
|
||||||
|
|
||||||
|
} },
|
||||||
|
// null,
|
||||||
|
// {id:"red-ui-library-browser-menu-rename",label:"Rename", onselect: function() {} },
|
||||||
|
// {id:"red-ui-library-browser-menu-delete",label:"Delete", onselect: function() {} }
|
||||||
|
]
|
||||||
|
}).on('mouseleave', function(){ $(this).remove(); dirList.focus() })
|
||||||
|
.on('mouseup', function() { var self = $(this);self.hide(); dirList.focus(); setTimeout(function() { self.remove() },100)})
|
||||||
|
.appendTo("body");
|
||||||
|
menuOptionMenu.css({
|
||||||
|
position: "absolute",
|
||||||
|
top: elementPos.top+"px",
|
||||||
|
left: (elementPos.left - menuOptionMenu.width() + 20)+"px"
|
||||||
|
}).show();
|
||||||
|
|
||||||
|
}).appendTo(itemTools);
|
||||||
|
if (options.folderTools) {
|
||||||
|
dirList.on('treelistselect', function(event, item) {
|
||||||
|
if (item.writable !== false && item.treeList) {
|
||||||
|
itemTools.appendTo(item.treeList.label);
|
||||||
}
|
}
|
||||||
var cancelAdd = function() {
|
|
||||||
newItem.treeList.remove();
|
|
||||||
}
|
|
||||||
input.on('keydown', function(evt) {
|
|
||||||
if (evt.keyCode === 13) {
|
|
||||||
evt.stopPropagation();
|
|
||||||
confirmAdd();
|
|
||||||
} else if (evt.keyCode === 27) {
|
|
||||||
evt.stopPropagation();
|
|
||||||
cancelAdd();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
input.blur(function() {
|
|
||||||
confirmAdd();
|
|
||||||
})
|
|
||||||
selected.treeList.addChild(newItem);
|
|
||||||
setTimeout(function() {
|
|
||||||
input.focus();
|
|
||||||
input.select();
|
|
||||||
},200);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -379,11 +406,14 @@ RED.library = (function() {
|
|||||||
getSelected: function() {
|
getSelected: function() {
|
||||||
return dirList.treeList('selected');
|
return dirList.treeList('selected');
|
||||||
},
|
},
|
||||||
|
focus: function() {
|
||||||
|
dirList.focus();
|
||||||
|
},
|
||||||
data: function(content) {
|
data: function(content) {
|
||||||
dirList.treeList('data',content);
|
dirList.treeList('data',content);
|
||||||
setTimeout(function() {
|
// setTimeout(function() {
|
||||||
dirList.treeList('select',content[0]);
|
// dirList.treeList('select',content[0]);
|
||||||
},100);
|
// },100);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -112,7 +112,6 @@
|
|||||||
.red-ui-library-browser {
|
.red-ui-library-browser {
|
||||||
position: relative;
|
position: relative;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
.red-ui-treeList-container {
|
.red-ui-treeList-container {
|
||||||
background: white;
|
background: white;
|
||||||
border: none;
|
border: none;
|
||||||
|
@ -15,7 +15,9 @@
|
|||||||
**/
|
**/
|
||||||
|
|
||||||
.red-ui-treeList {
|
.red-ui-treeList {
|
||||||
|
&:focus {
|
||||||
|
outline: none !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.red-ui-treeList-container {
|
.red-ui-treeList-container {
|
||||||
@ -64,10 +66,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
label.red-ui-treeList-label {
|
|
||||||
display: block;
|
|
||||||
width: auto;
|
|
||||||
}
|
|
||||||
.red-ui-treeList-label {
|
.red-ui-treeList-label {
|
||||||
@include disable-selection;
|
@include disable-selection;
|
||||||
padding: 6px 0;
|
padding: 6px 0;
|
||||||
@ -77,6 +75,7 @@ label.red-ui-treeList-label {
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
// &:hover {
|
// &:hover {
|
||||||
// background: $list-item-background-hover;
|
// background: $list-item-background-hover;
|
||||||
|
Loading…
Reference in New Issue
Block a user