mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
Add config-node sidebar tab
Accessed from the drop-down menu
This commit is contained in:
parent
1bdbd6a5b0
commit
cfd8d137cf
@ -49,6 +49,8 @@
|
||||
</ul>
|
||||
</li>
|
||||
<li class="divider"></li>
|
||||
<li><a id="btn-config-nodes" tabindex="-1" href="#"><i class="icon-th-list"></i> Configuration nodes...</a></li>
|
||||
<li class="divider"></li>
|
||||
<li class="dropdown-submenu pull-left"><a tabindex="-1" href="#"><i class="icon-th-large"></i> Workspaces</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a id="btn-workspace-add" tabindex="-1" href="#"><i class="icon-plus"></i> Add</a></li>
|
||||
@ -307,6 +309,7 @@
|
||||
<script src="red/ui/view.js"></script>
|
||||
<script src="red/ui/sidebar.js"></script>
|
||||
<script src="red/ui/palette.js"></script>
|
||||
<script src="red/ui/tab-config.js"></script>
|
||||
<script src="red/ui/editor.js"></script>
|
||||
<script src="red/ui/library.js"></script>
|
||||
<script src="red/ui/notifications.js"></script>
|
||||
|
@ -39,9 +39,27 @@ RED.nodes = function() {
|
||||
function addNode(n) {
|
||||
if (n._def.category == "config") {
|
||||
configNodes[n.id] = n;
|
||||
RED.configTab.refresh();
|
||||
} else {
|
||||
n.dirty = true;
|
||||
nodes.push(n);
|
||||
var updatedConfigNode = false;
|
||||
for (var d in n._def.defaults) {
|
||||
var property = n._def.defaults[d];
|
||||
if (property.type) {
|
||||
var type = getType(property.type)
|
||||
if (type && type.category == "config") {
|
||||
var configNode = configNodes[n[d]];
|
||||
if (configNode) {
|
||||
updatedConfigNode = true;
|
||||
configNode.users.push(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (updatedConfigNode) {
|
||||
RED.configTab.refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
function addLink(l) {
|
||||
@ -68,6 +86,7 @@ RED.nodes = function() {
|
||||
var removedLinks = [];
|
||||
if (id in configNodes) {
|
||||
delete configNodes[id];
|
||||
RED.configTab.refresh();
|
||||
} else {
|
||||
var node = getNode(id);
|
||||
if (node) {
|
||||
@ -75,6 +94,24 @@ RED.nodes = function() {
|
||||
removedLinks = links.filter(function(l) { return (l.source === node) || (l.target === node); });
|
||||
removedLinks.map(function(l) {links.splice(links.indexOf(l), 1); });
|
||||
}
|
||||
var updatedConfigNode = false;
|
||||
for (var d in node._def.defaults) {
|
||||
var property = node._def.defaults[d];
|
||||
if (property.type) {
|
||||
var type = getType(property.type)
|
||||
if (type && type.category == "config") {
|
||||
var configNode = configNodes[node[d]];
|
||||
if (configNode) {
|
||||
updatedConfigNode = true;
|
||||
var users = configNode.users;
|
||||
users.splice(users.indexOf(node),1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (updatedConfigNode) {
|
||||
RED.configTab.refresh();
|
||||
}
|
||||
}
|
||||
return removedLinks;
|
||||
}
|
||||
|
@ -267,11 +267,12 @@ RED.editor = function() {
|
||||
RED.keyboard.enable();
|
||||
|
||||
if (RED.view.state() != RED.state.IMPORT_DRAGGING) {
|
||||
RED.view.state(0);
|
||||
RED.view.state(RED.state.DEFAULT);
|
||||
}
|
||||
$( this ).dialog('option','height','auto');
|
||||
$( this ).dialog('option','width','500');
|
||||
editing_node = null;
|
||||
RED.configTab.refresh();
|
||||
}
|
||||
});
|
||||
|
||||
@ -462,14 +463,22 @@ RED.editor = function() {
|
||||
resize: function(e,ui) {
|
||||
},
|
||||
open: function(e) {
|
||||
if (RED.view.state() != RED.state.EDITING) {
|
||||
RED.keyboard.disable();
|
||||
}
|
||||
},
|
||||
close: function(e) {
|
||||
if (RED.view.state() != RED.state.EDITING) {
|
||||
RED.keyboard.enable();
|
||||
}
|
||||
RED.configTab.refresh();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
return {
|
||||
edit: showEditDialog,
|
||||
editConfig: showEditConfigNodeDialog,
|
||||
validateNode: validateNode,
|
||||
updateNodeProperties: updateNodeProperties // TODO: only exposed for edit-undo
|
||||
}
|
||||
|
@ -21,12 +21,15 @@ RED.sidebar = function() {
|
||||
onchange:function(id) {
|
||||
$("#sidebar-content").children().hide();
|
||||
$("#"+id).show();
|
||||
},
|
||||
onremove: function(id) {
|
||||
$("#"+id).remove();
|
||||
}
|
||||
});
|
||||
function addTab(title,content) {
|
||||
function addTab(title,content,closeable) {
|
||||
$("#sidebar-content").append(content);
|
||||
$(content).hide();
|
||||
sidebar_tabs.addTab({id:"tab-"+title,label:title});
|
||||
sidebar_tabs.addTab({id:"tab-"+title,label:title,closeable:closeable});
|
||||
//content.style.position = "absolute";
|
||||
//$('#sidebar').tabs("refresh");
|
||||
}
|
||||
@ -101,9 +104,21 @@ RED.sidebar = function() {
|
||||
}
|
||||
toggleSidebar();
|
||||
|
||||
function showSidebar(id) {
|
||||
if (!$("#btn-sidebar").hasClass("active")) {
|
||||
toggleSidebar();
|
||||
}
|
||||
sidebar_tabs.activateTab("tab-"+id);
|
||||
}
|
||||
|
||||
function containsTab(id) {
|
||||
return sidebar_tabs.contains("tab-"+id);
|
||||
}
|
||||
|
||||
return {
|
||||
addTab: addTab
|
||||
addTab: addTab,
|
||||
show: showSidebar,
|
||||
containsTab: containsTab
|
||||
}
|
||||
|
||||
}();
|
||||
|
@ -14,6 +14,7 @@
|
||||
* limitations under the License.
|
||||
**/
|
||||
RED.state = {
|
||||
DEFAULT: 0,
|
||||
MOVING: 1,
|
||||
JOINING: 2,
|
||||
MOVING_ACTIVE: 3,
|
||||
|
84
public/red/ui/tab-config.js
Normal file
84
public/red/ui/tab-config.js
Normal file
@ -0,0 +1,84 @@
|
||||
/**
|
||||
* Copyright 2013 IBM Corp.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
RED.configTab = function() {
|
||||
|
||||
var content = document.createElement("div");
|
||||
content.id = "tab-config";
|
||||
content.style.paddingTop = "4px";
|
||||
content.style.paddingLeft = "4px";
|
||||
content.style.paddingRight = "4px";
|
||||
|
||||
var list = $("<ul>",{class:"tab-config-list"}).appendTo(content);
|
||||
|
||||
$("#btn-config-nodes").click(function(){
|
||||
if (!RED.sidebar.containsTab("config")) {
|
||||
RED.sidebar.addTab("config",content,true);
|
||||
}
|
||||
refresh();
|
||||
RED.sidebar.show("config");
|
||||
});
|
||||
|
||||
function refresh() {
|
||||
list.empty();
|
||||
var count = 0;
|
||||
RED.nodes.eachConfig(function(node) {
|
||||
count += 1;
|
||||
var li = list.find("#tab-config-list-type-"+node.type);
|
||||
if (li.length == 0) {
|
||||
li = $("<li>",{id:"tab-config-list-type-"+node.type}).appendTo(list);
|
||||
$('<div class="tab-config-list-type">'+node.type+'</div>').appendTo(li);
|
||||
}
|
||||
var label = "";
|
||||
if (typeof node._def.label == "function") {
|
||||
label = node._def.label.call(node);
|
||||
} else {
|
||||
label = node._def.label;
|
||||
}
|
||||
|
||||
var entry = $('<div class="tab-config-list-entry"></div>').appendTo(li);
|
||||
entry.on('dblclick',function(e) {
|
||||
RED.editor.editConfig("", node.type, node.id);
|
||||
});
|
||||
|
||||
var userArray = node.users.map(function(n) { return n.id });
|
||||
entry.on('mouseover',function(e) {
|
||||
RED.nodes.eachNode(function(node) {
|
||||
if( userArray.indexOf(node.id) != -1) {
|
||||
node.highlighted = true;
|
||||
node.dirty = true;
|
||||
}
|
||||
});
|
||||
RED.view.redraw();
|
||||
});
|
||||
|
||||
entry.on('mouseout',function(e) {
|
||||
RED.nodes.eachNode(function(node) {
|
||||
if(node.highlighted) {
|
||||
node.highlighted = false;
|
||||
node.dirty = true;
|
||||
}
|
||||
});
|
||||
RED.view.redraw();
|
||||
});
|
||||
|
||||
$('<div class="tab-config-list-label">'+label+'</div>').appendTo(entry);
|
||||
$('<div class="tab-config-list-users">'+node.users.length+'</div>').appendTo(entry);
|
||||
});
|
||||
}
|
||||
return {
|
||||
refresh:refresh
|
||||
}
|
||||
}();
|
@ -34,6 +34,7 @@ RED.tabs = function() {
|
||||
if (options.ondblclick) {
|
||||
options.ondblclick($(this).attr('href').slice(1));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function activateTab(link) {
|
||||
@ -61,13 +62,38 @@ RED.tabs = function() {
|
||||
ul.find("li.red-ui-tab a").on("click",onTabClick).on("dblclick",onTabDblClick);
|
||||
updateTabWidths();
|
||||
|
||||
|
||||
function removeTab(id) {
|
||||
var li = ul.find("a[href='#"+id+"']").parent();
|
||||
if (li.hasClass("active")) {
|
||||
var tab = li.prev();
|
||||
if (tab.size() == 0) {
|
||||
tab = li.next();
|
||||
}
|
||||
activateTab(tab.find("a"));
|
||||
}
|
||||
li.remove();
|
||||
if (options.onremove) {
|
||||
options.onremove(id);
|
||||
}
|
||||
updateTabWidths();
|
||||
}
|
||||
return {
|
||||
addTab: function(tab) {
|
||||
var li = $("<li/>",{class:"red-ui-tab"}).appendTo(ul);
|
||||
var link = $("<a/>",{href:"#"+tab.id}).appendTo(li);
|
||||
var link = $("<a/>",{href:"#"+tab.id, class:"red-ui-tab-label"}).appendTo(li);
|
||||
link.html(tab.label);
|
||||
|
||||
link.on("click",onTabClick);
|
||||
link.on("dblclick",onTabDblClick);
|
||||
if (tab.closeable) {
|
||||
var closeLink = $("<a/>",{href:"#",class:"red-ui-tab-close"}).appendTo(li);
|
||||
closeLink.html('<i class="icon-remove" />');
|
||||
|
||||
closeLink.on("click",function(event) {
|
||||
removeTab(tab.id);
|
||||
});
|
||||
}
|
||||
updateTabWidths();
|
||||
if (options.onadd) {
|
||||
options.onadd(tab);
|
||||
@ -77,26 +103,16 @@ RED.tabs = function() {
|
||||
activateTab(link);
|
||||
}
|
||||
},
|
||||
removeTab: function(id) {
|
||||
var li = ul.find("a[href='#"+id+"']").parent();
|
||||
if (li.hasClass("active")) {
|
||||
var tab = li.prev();
|
||||
if (tab.size() == 0) {
|
||||
tab = li.next();
|
||||
}
|
||||
activateTab(tab.find("a"));
|
||||
}
|
||||
li.remove();
|
||||
if (options.onremove) {
|
||||
options.onremove(id);
|
||||
}
|
||||
|
||||
},
|
||||
removeTab: removeTab,
|
||||
activateTab: activateTab,
|
||||
resize: updateTabWidths,
|
||||
count: function() {
|
||||
return ul.find("li.red-ui-tab").size();
|
||||
},
|
||||
contains: function(id) {
|
||||
return ul.find("a[href='#"+id+"']").length > 0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -704,11 +704,31 @@ ul.red-ui-tabs li {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
ul.red-ui-tabs li a {
|
||||
ul.red-ui-tabs li a.red-ui-tab-label {
|
||||
display: block;
|
||||
padding: 3px 16px;
|
||||
color: #666;
|
||||
}
|
||||
ul.red-ui-tabs li {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
ul.red-ui-tabs li a.red-ui-tab-close {
|
||||
background: rgba(227,227,227,0.8);
|
||||
position: absolute;
|
||||
right: 2px;
|
||||
top: 2px;
|
||||
display: block;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
text-align: center;
|
||||
padding: 0px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
ul.red-ui-tabs li a.red-ui-tab-close:hover {
|
||||
background: #bbb !important;
|
||||
}
|
||||
ul.red-ui-tabs li a:hover {
|
||||
text-decoration: none;
|
||||
background: #f0f0f0;
|
||||
@ -721,7 +741,10 @@ ul.red-ui-tabs li.active {
|
||||
ul.red-ui-tabs li.active a {
|
||||
color: #333;
|
||||
}
|
||||
ul.red-ui-tabs li.active a:hover {
|
||||
ul.red-ui-tabs li.active a.red-ui-tab-close {
|
||||
background: rgba(255,255,255,0.8);
|
||||
}
|
||||
ul.red-ui-tabs li.active a.red-ui-tab-label:hover {
|
||||
background: #fff;
|
||||
}
|
||||
ul.red-ui-tabs li.red-ui-add-tab {
|
||||
@ -732,3 +755,56 @@ ul.red-ui-tabs li.red-ui-add-tab {
|
||||
ul.red-ui-tabs li.red-ui-add-tab a {
|
||||
padding: 2px 4px;
|
||||
}
|
||||
|
||||
ul.tab-config-list {
|
||||
list-style-type: none;
|
||||
padding: 3px;
|
||||
margin: 0;
|
||||
-webkit-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
ul.tab-config-list li {
|
||||
max-width: 400px;
|
||||
font-size: 13px;
|
||||
background: #f3f3f3;
|
||||
margin: 10px auto;
|
||||
border-radius: 3px;
|
||||
border: 1px solid #ccc;
|
||||
padding: 3px 8px;
|
||||
}
|
||||
div.tab-config-list-type {
|
||||
}
|
||||
|
||||
div.tab-config-list-entry {
|
||||
position: relative;
|
||||
margin: 4px 0;
|
||||
padding: 8px 4px 8px 10px;
|
||||
background: #fff;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
div.tab-config-list-entry:hover {
|
||||
background: #f6f6f6;
|
||||
}
|
||||
|
||||
div.tab-config-list-label {
|
||||
}
|
||||
div.tab-config-list-users {
|
||||
position: absolute;
|
||||
right: 3px;
|
||||
top: 3px;
|
||||
bottom: 3px;
|
||||
line-height: 27px;
|
||||
font-size: 11px;
|
||||
background: #f6f6f6;
|
||||
float: right;
|
||||
border: 1px solid #eee;
|
||||
border-radius: 3px;
|
||||
padding: 1px 5px;
|
||||
}
|
||||
|
||||
|
35
red/nodes.js
35
red/nodes.js
@ -239,6 +239,39 @@ module.exports.getNodeConfigs = node_type_registry.getNodeConfigs;
|
||||
module.exports.addLogHandler = registry.addLogHandler;
|
||||
|
||||
module.exports.load = function(settings) {
|
||||
function scanForNodes(dir) {
|
||||
var pm = path.join(dir,"node_modules");
|
||||
if (fs.existsSync(pm)) {
|
||||
fs.readdirSync(pm).filter(function(fn) {
|
||||
var pkgfn = path.join(pm,fn,"package.json");
|
||||
if (fs.existsSync(pkgfn)) {
|
||||
var pkg = require(pkgfn);
|
||||
if (pkg['node-red']) {
|
||||
console.log(pkg.name,pkg.version);
|
||||
var nr = pkg['node-red'];
|
||||
if (nr.nodes) {
|
||||
var nrn = nr.nodes;
|
||||
for (var i in nrn) {
|
||||
console.log(" ",i,":",nrn[i]);
|
||||
try {
|
||||
require(path.join(pm,fn,nrn[i]));
|
||||
} catch(err) {
|
||||
util.log("["+i+"] "+err);
|
||||
//console.log(err.stack);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var up = path.join(dir,"..");
|
||||
if (up !== dir) {
|
||||
scanForNodes(up);
|
||||
}
|
||||
}
|
||||
|
||||
function loadNodes(dir) {
|
||||
fs.readdirSync(dir).sort().filter(function(fn){
|
||||
var stats = fs.statSync(path.join(dir,fn));
|
||||
@ -262,8 +295,10 @@ module.exports.load = function(settings) {
|
||||
});
|
||||
}
|
||||
loadNodes(__dirname+"/../nodes");
|
||||
scanForNodes(__dirname+"/../nodes");
|
||||
if (settings.nodesDir) {
|
||||
loadNodes(settings.nodesDir);
|
||||
scanForNodes(settings.nodesDir);
|
||||
}
|
||||
//events.emit("nodes-loaded");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user