mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
commit
87e537da90
31
Gruntfile.js
31
Gruntfile.js
@ -118,6 +118,24 @@ module.exports = function(grunt) {
|
||||
"editor/js/ui/touch/radialMenu.js"
|
||||
],
|
||||
dest: "public/red/red.js"
|
||||
},
|
||||
vendor: {
|
||||
files: {
|
||||
"public/vendor/vendor.js": [
|
||||
"editor/vendor/jquery/js/jquery-1.11.1.min.js",
|
||||
"editor/vendor/bootstrap/js/bootstrap.min.js",
|
||||
"editor/vendor/jquery/js/jquery-ui-1.10.3.custom.min.js",
|
||||
"editor/vendor/jquery/js/jquery.ui.touch-punch.min.js",
|
||||
"editor/vendor/marked/marked.min.js",
|
||||
"editor/vendor/orion/built-editor.min.js",
|
||||
"editor/vendor/d3/d3.v3.min.js"
|
||||
],
|
||||
"public/vendor/vendor.css": [
|
||||
"editor/vendor/orion/built-editor.css"
|
||||
// TODO: resolve relative resource paths in
|
||||
// bootstrap/FA/jquery
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
uglify: {
|
||||
@ -214,7 +232,13 @@ module.exports = function(grunt) {
|
||||
},
|
||||
{
|
||||
cwd: 'editor/vendor',
|
||||
src: '**',
|
||||
src: [
|
||||
'ace/**',
|
||||
'bootstrap/css/**',
|
||||
'bootstrap/img/**',
|
||||
'jquery/css/**',
|
||||
'font-awesome/**'
|
||||
],
|
||||
expand: true,
|
||||
dest: 'public/vendor/'
|
||||
},
|
||||
@ -244,7 +268,8 @@ module.exports = function(grunt) {
|
||||
'nodes/*.demo',
|
||||
'nodes/core/**',
|
||||
'red/**',
|
||||
'public/**'
|
||||
'public/**',
|
||||
'editor/templates/**'
|
||||
],
|
||||
dest: path.resolve('<%= paths.dist %>/node-red-<%= pkg.version %>')
|
||||
}]
|
||||
@ -333,7 +358,7 @@ module.exports = function(grunt) {
|
||||
|
||||
grunt.registerTask('build',
|
||||
'Builds editor content',
|
||||
['clean:build','concat:build','uglify:build','sass:build','copy:build','attachCopyright']);
|
||||
['clean:build','concat:build','concat:vendor','uglify:build','sass:build','copy:build','attachCopyright']);
|
||||
|
||||
grunt.registerTask('dev',
|
||||
'Developer mode: run node-red, watch for source changes and build/restart',
|
||||
|
@ -23,8 +23,8 @@
|
||||
<title>Node-RED</title>
|
||||
<link href="vendor/bootstrap/css/bootstrap.min.css" rel="stylesheet" media="screen">
|
||||
<link href="vendor/jquery/css/smoothness/jquery-ui-1.10.3.custom.min.css" rel="stylesheet" media="screen">
|
||||
<link rel="stylesheet" type="text/css" href="vendor/orion/built-editor.css"/>
|
||||
<link rel="stylesheet" type="text/css" href="vendor/font-awesome/css/font-awesome.min.css"/>
|
||||
<link rel="stylesheet" href="vendor/font-awesome/css/font-awesome.min.css">
|
||||
<link rel="stylesheet" href="vendor/vendor.css">
|
||||
<link rel="stylesheet" href="red/style.min.css">
|
||||
</head>
|
||||
<body spellcheck="false">
|
||||
@ -168,15 +168,9 @@
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script src="vendor/jquery/js/jquery-1.11.1.min.js"></script>
|
||||
<script src="vendor/bootstrap/js/bootstrap.min.js"></script>
|
||||
<script src="vendor/jquery/js/jquery-ui-1.10.3.custom.min.js"></script>
|
||||
<script src="vendor/jquery/js/jquery.ui.touch-punch.min.js"></script>
|
||||
<script src="vendor/marked/marked.min.js"></script>
|
||||
<script src="vendor/orion/built-editor.min.js"></script>
|
||||
<script src="vendor/vendor.js"></script>
|
||||
<script src="vendor/ace/ace.js"></script>
|
||||
<script src="vendor/ace/ext-language_tools.js"></script>
|
||||
<script src="vendor/d3/d3.v3.min.js"></script>
|
||||
<script src="red/red.min.js"></script>
|
||||
|
||||
</body>
|
||||
|
@ -138,34 +138,37 @@ var RED = (function() {
|
||||
function loadEditor() {
|
||||
RED.menu.init({id:"btn-sidemenu",
|
||||
options: [
|
||||
{id:"btn-sidebar",label:"Sidebar",toggle:true,onselect:RED.sidebar.toggleSidebar, selected: true},
|
||||
{id:"btn-node-status",label:"Display node status",toggle:true,onselect:toggleStatus, selected: true},
|
||||
{id:"menu-item-sidebar",label:"Sidebar",toggle:true,onselect:RED.sidebar.toggleSidebar, selected: true},
|
||||
{id:"menu-item-status",label:"Display node status",toggle:true,onselect:toggleStatus, selected: true},
|
||||
null,
|
||||
{id:"btn-import-menu",label:"Import",options:[
|
||||
{id:"btn-import-clipboard",label:"Clipboard",onselect:RED.clipboard.import},
|
||||
{id:"btn-import-library",label:"Library",options:[]}
|
||||
{id:"menu-item-import",label:"Import",options:[
|
||||
{id:"menu-item-import-clipboard",label:"Clipboard",onselect:RED.clipboard.import},
|
||||
{id:"menu-item-import-library",label:"Library",options:[]}
|
||||
]},
|
||||
{id:"btn-export-menu",label:"Export",disabled:true,options:[
|
||||
{id:"btn-export-clipboard",label:"Clipboard",disabled:true,onselect:RED.clipboard.export},
|
||||
{id:"btn-export-library",label:"Library",disabled:true,onselect:RED.library.export}
|
||||
{id:"menu-item-export",label:"Export",disabled:true,options:[
|
||||
{id:"menu-item-export-clipboard",label:"Clipboard",disabled:true,onselect:RED.clipboard.export},
|
||||
{id:"menu-item-export-library",label:"Library",disabled:true,onselect:RED.library.export}
|
||||
]},
|
||||
null,
|
||||
{id:"btn-config-nodes",label:"Configuration nodes",onselect:RED.sidebar.config.show},
|
||||
{id:"menu-item-config-nodes",label:"Configuration nodes",onselect:RED.sidebar.config.show},
|
||||
null,
|
||||
{id:"btn-subflow-menu",label:"Subflows", options: [
|
||||
{id:"btn-create-subflow",label:"Create subflow",onselect:RED.subflow.createSubflow},
|
||||
{id:"btn-convert-subflow",label:"Selection to subflow",disabled:true,onselect:RED.subflow.convertToSubflow},
|
||||
{id:"menu-item-subflow",label:"Subflows", options: [
|
||||
{id:"menu-item-subflow-create",label:"Create subflow",onselect:RED.subflow.createSubflow},
|
||||
{id:"menu-item-subflow-convert",label:"Selection to subflow",disabled:true,onselect:RED.subflow.convertToSubflow},
|
||||
]},
|
||||
null,
|
||||
{id:"btn-workspace-menu",label:"Workspaces",options:[
|
||||
{id:"btn-workspace-add",label:"Add",onselect:RED.workspaces.add},
|
||||
{id:"btn-workspace-edit",label:"Rename",onselect:RED.workspaces.edit},
|
||||
{id:"btn-workspace-delete",label:"Delete",onselect:RED.workspaces.remove},
|
||||
{id:"menu-item-workspace",label:"Workspaces",options:[
|
||||
{id:"menu-item-workspace-add",label:"Add",onselect:RED.workspaces.add},
|
||||
{id:"menu-item-workspace-edit",label:"Rename",onselect:RED.workspaces.edit},
|
||||
{id:"menu-item-workspace-delete",label:"Delete",onselect:RED.workspaces.remove},
|
||||
null
|
||||
]},
|
||||
null,
|
||||
{id:"btn-keyboard-shortcuts",label:"Keyboard Shortcuts",onselect:RED.keyboard.showHelp},
|
||||
{id:"btn-help",label:"Node-RED Website", href:"http://nodered.org/docs"}
|
||||
{id:"menu-item-keyboard-shortcuts",label:"Keyboard Shortcuts",onselect:RED.keyboard.showHelp},
|
||||
{id:"menu-item-help",
|
||||
label: RED.settings.theme("menu.menu-item-help.label","Node-RED Website"),
|
||||
href: RED.settings.theme("menu.menu-item-help.url","http://nodered.org/docs")
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
@ -178,7 +181,8 @@ var RED = (function() {
|
||||
RED.workspaces.init();
|
||||
RED.clipboard.init();
|
||||
RED.view.init();
|
||||
RED.deploy.init();
|
||||
|
||||
RED.deploy.init(RED.settings.theme("deployButton",null));
|
||||
|
||||
RED.keyboard.add(/* ? */ 191,{shift:true},function(){RED.keyboard.showHelp();d3.event.preventDefault();});
|
||||
RED.comms.connect();
|
||||
@ -192,7 +196,7 @@ var RED = (function() {
|
||||
$(function() {
|
||||
|
||||
if ((window.location.hostname !== "localhost") && (window.location.hostname !== "127.0.0.1")) {
|
||||
document.title = "Node-RED : "+window.location.hostname;
|
||||
document.title = document.title+" : "+window.location.hostname;
|
||||
}
|
||||
|
||||
ace.require("ace/ext/language_tools");
|
||||
|
@ -119,13 +119,30 @@ RED.settings = (function () {
|
||||
});
|
||||
};
|
||||
|
||||
function theme(property,defaultValue) {
|
||||
if (!RED.settings.editorTheme) {
|
||||
return defaultValue;
|
||||
}
|
||||
var parts = property.split(".");
|
||||
var v = RED.settings.editorTheme;
|
||||
try {
|
||||
for (var i=0;i<parts.length;i++) {
|
||||
v = v[parts[i]];
|
||||
}
|
||||
return v;
|
||||
} catch(err) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
init: init,
|
||||
load: load,
|
||||
set: set,
|
||||
get: get,
|
||||
remove: remove
|
||||
remove: remove,
|
||||
|
||||
theme: theme
|
||||
}
|
||||
})
|
||||
();
|
||||
|
@ -129,13 +129,13 @@ RED.clipboard = (function() {
|
||||
init: function() {
|
||||
RED.view.on("selection-changed",function(selection) {
|
||||
if (!selection.nodes) {
|
||||
RED.menu.setDisabled("btn-export-menu",true);
|
||||
RED.menu.setDisabled("btn-export-clipboard",true);
|
||||
RED.menu.setDisabled("btn-export-library",true);
|
||||
RED.menu.setDisabled("menu-item-export",true);
|
||||
RED.menu.setDisabled("menu-item-export-clipboard",true);
|
||||
RED.menu.setDisabled("menu-item-export-library",true);
|
||||
} else {
|
||||
RED.menu.setDisabled("btn-export-menu",false);
|
||||
RED.menu.setDisabled("btn-export-clipboard",false);
|
||||
RED.menu.setDisabled("btn-export-library",false);
|
||||
RED.menu.setDisabled("menu-item-export",false);
|
||||
RED.menu.setDisabled("menu-item-export-clipboard",false);
|
||||
RED.menu.setDisabled("menu-item-export-library",false);
|
||||
}
|
||||
});
|
||||
RED.keyboard.add(/* e */ 69,{ctrl:true},function(){exportNodes();d3.event.preventDefault();});
|
||||
|
@ -29,12 +29,43 @@ RED.deploy = (function() {
|
||||
$("#btn-deploy img").attr("src",deploymentTypes[type].img);
|
||||
}
|
||||
|
||||
function init() {
|
||||
|
||||
var deployButton = $('<li><span class="deploy-button-group button-group">'+
|
||||
'<a id="btn-deploy" class="action-deploy disabled" href="#"><img id="btn-icn-deploy" src="red/images/deploy-full-o.png"> <span>Deploy</span></a>'+
|
||||
'<a id="btn-deploy-options" data-toggle="dropdown" class="" href="#"><i class="fa fa-caret-down"></i></a>'+
|
||||
/**
|
||||
* options:
|
||||
* type: "default" - Button with drop-down options - no further customisation available
|
||||
* type: "simple" - Button without dropdown. Customisations:
|
||||
* label: the text to display - default: "Deploy"
|
||||
* icon : the icon to use. Null removes the icon. default: "red/images/deploy-full-o.png"
|
||||
*/
|
||||
function init(options) {
|
||||
options = options || {};
|
||||
var type = options.type || "default";
|
||||
|
||||
if (type == "default") {
|
||||
$('<li><span class="deploy-button-group button-group">'+
|
||||
'<a id="btn-deploy" class="deploy-button disabled" href="#"><img id="btn-deploy-icon" src="red/images/deploy-full-o.png"> <span>Deploy</span></a>'+
|
||||
'<a id="btn-deploy-options" data-toggle="dropdown" class="deploy-button" href="#"><i class="fa fa-caret-down"></i></a>'+
|
||||
'</span></li>').prependTo(".header-toolbar");
|
||||
RED.menu.init({id:"btn-deploy-options",
|
||||
options: [
|
||||
{id:"deploymenu-item-full",toggle:"deploy-type",icon:"red/images/deploy-full.png",label:"Full",sublabel:"Deploys everything in the workspace",onselect:function(s) { if(s){changeDeploymentType("full")}}},
|
||||
{id:"deploymenu-item-flow",toggle:"deploy-type",icon:"red/images/deploy-flows.png",label:"Modified Flows",sublabel:"Only deploys flows that contain changed nodes", onselect:function(s) {if(s){changeDeploymentType("flows")}}},
|
||||
{id:"deploymenu-item-node",toggle:"deploy-type",icon:"red/images/deploy-nodes.png",label:"Modified Nodes",sublabel:"Only deploys nodes that have changed",onselect:function(s) { if(s){changeDeploymentType("nodes")}}}
|
||||
]
|
||||
});
|
||||
} else if (type == "simple") {
|
||||
var label = options.label || "Deploy";
|
||||
var icon = 'red/images/deploy-full-o.png';
|
||||
if (options.hasOwnProperty('icon')) {
|
||||
icon = options.icon;
|
||||
}
|
||||
|
||||
$('<li><span class="deploy-button-group button-group">'+
|
||||
'<a id="btn-deploy" class="deploy-button disabled" href="#">'+
|
||||
(icon?'<img id="btn-deploy-icon" src="'+icon+'"> ':'')+
|
||||
'<span>'+label+'</span></a>'+
|
||||
'</span></li>').prependTo(".header-toolbar");
|
||||
}
|
||||
|
||||
$('#btn-deploy').click(function() { save(); });
|
||||
|
||||
@ -61,14 +92,6 @@ RED.deploy = (function() {
|
||||
]
|
||||
});
|
||||
|
||||
RED.menu.init({id:"btn-deploy-options",
|
||||
options: [
|
||||
{id:"btn-deploy-full",toggle:"deploy-type",icon:"red/images/deploy-full.png",label:"Full",sublabel:"Deploys everything in the workspace",onselect:function(s) { if(s){changeDeploymentType("full")}}},
|
||||
{id:"btn-deploy-flow",toggle:"deploy-type",icon:"red/images/deploy-flows.png",label:"Modified Flows",sublabel:"Only deploys flows that contain changed nodes", onselect:function(s) {if(s){changeDeploymentType("flows")}}},
|
||||
{id:"btn-deploy-node",toggle:"deploy-type",icon:"red/images/deploy-nodes.png",label:"Modified Nodes",sublabel:"Only deploys nodes that have changed",onselect:function(s) { if(s){changeDeploymentType("nodes")}}}
|
||||
]
|
||||
});
|
||||
|
||||
RED.nodes.on('change',function(state) {
|
||||
if (state.dirty) {
|
||||
window.onbeforeunload = function() {
|
||||
@ -114,8 +137,8 @@ RED.deploy = (function() {
|
||||
}
|
||||
var nns = RED.nodes.createCompleteNodeSet();
|
||||
|
||||
$("#btn-icn-deploy").removeClass('fa-download');
|
||||
$("#btn-icn-deploy").addClass('spinner');
|
||||
$("#btn-deploy-icon").removeClass('fa-download');
|
||||
$("#btn-deploy-icon").addClass('spinner');
|
||||
RED.nodes.dirty(false);
|
||||
|
||||
$.ajax({
|
||||
@ -153,8 +176,8 @@ RED.deploy = (function() {
|
||||
RED.notify("<strong>Error</strong>: no response from server","error");
|
||||
}
|
||||
}).always(function() {
|
||||
$("#btn-icn-deploy").removeClass('spinner');
|
||||
$("#btn-icn-deploy").addClass('fa-download');
|
||||
$("#btn-deploy-icon").removeClass('spinner');
|
||||
$("#btn-deploy-icon").addClass('fa-download');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -786,7 +786,7 @@ RED.editor = (function() {
|
||||
changes['name'] = editing_node.name;
|
||||
editing_node.name = newName;
|
||||
changed = true;
|
||||
$("#btn-workspace-menu-"+editing_node.id.replace(".","-")).text("Subflow: "+newName);
|
||||
$("#menu-item-workspace-menu-"+editing_node.id.replace(".","-")).text("Subflow: "+newName);
|
||||
}
|
||||
|
||||
RED.palette.refresh();
|
||||
|
@ -59,7 +59,14 @@ RED.keyboard = (function() {
|
||||
}
|
||||
|
||||
|
||||
var dialog = $('<div id="keyboard-help-dialog" class="hide">'+
|
||||
var dialog = null;
|
||||
|
||||
function showKeyboardHelp() {
|
||||
if (!RED.settings.theme("menu.menu-item-keyboard-shortcuts",true)) {
|
||||
return;
|
||||
}
|
||||
if (!dialog) {
|
||||
dialog = $('<div id="keyboard-help-dialog" class="hide">'+
|
||||
'<div style="vertical-align: top;display:inline-block; box-sizing: border-box; width:50%; padding: 10px;">'+
|
||||
'<table class="keyboard-shortcuts">'+
|
||||
'<tr><td><span class="help-key">Ctrl/⌘</span> + <span class="help-key">a</span></td><td>Select all nodes</td></tr>'+
|
||||
@ -97,8 +104,8 @@ RED.keyboard = (function() {
|
||||
RED.keyboard.enable();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function showKeyboardHelp() {
|
||||
dialog.dialog("open");
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,7 @@ RED.library = (function() {
|
||||
var li;
|
||||
var a;
|
||||
var ul = document.createElement("ul");
|
||||
ul.id = "btn-import-library-submenu";
|
||||
ul.id = "menu-item-import-library-submenu";
|
||||
ul.className = "dropdown-menu";
|
||||
if (data.d) {
|
||||
for (i in data.d) {
|
||||
@ -63,7 +63,7 @@ RED.library = (function() {
|
||||
};
|
||||
var menu = buildMenu(data,"");
|
||||
//TODO: need an api in RED.menu for this
|
||||
$("#btn-import-library-submenu").replaceWith(menu);
|
||||
$("#menu-item-import-library-submenu").replaceWith(menu);
|
||||
});
|
||||
}
|
||||
|
||||
@ -392,17 +392,19 @@ RED.library = (function() {
|
||||
init: function() {
|
||||
RED.view.on("selection-changed",function(selection) {
|
||||
if (!selection.nodes) {
|
||||
RED.menu.setDisabled("btn-export-menu",true);
|
||||
RED.menu.setDisabled("btn-export-clipboard",true);
|
||||
RED.menu.setDisabled("btn-export-library",true);
|
||||
RED.menu.setDisabled("menu-item-export",true);
|
||||
RED.menu.setDisabled("menu-item-export-clipboard",true);
|
||||
RED.menu.setDisabled("menu-item-export-library",true);
|
||||
} else {
|
||||
RED.menu.setDisabled("btn-export-menu",false);
|
||||
RED.menu.setDisabled("btn-export-clipboard",false);
|
||||
RED.menu.setDisabled("btn-export-library",false);
|
||||
RED.menu.setDisabled("menu-item-export",false);
|
||||
RED.menu.setDisabled("menu-item-export-clipboard",false);
|
||||
RED.menu.setDisabled("menu-item-export-library",false);
|
||||
}
|
||||
});
|
||||
|
||||
if (RED.settings.theme("menu.menu-item-import-library") !== false) {
|
||||
loadFlowLibrary();
|
||||
}
|
||||
},
|
||||
create: createUI,
|
||||
loadFlowLibrary: loadFlowLibrary,
|
||||
|
@ -23,6 +23,13 @@ RED.menu = (function() {
|
||||
function createMenuItem(opt) {
|
||||
var item;
|
||||
|
||||
if (opt !== null && opt.id) {
|
||||
var themeSetting = RED.settings.theme("menu."+opt.id);
|
||||
if (themeSetting === false) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function setState() {
|
||||
var savedStateActive = isSavedStateActive(opt.id);
|
||||
if (savedStateActive) {
|
||||
@ -113,7 +120,10 @@ RED.menu = (function() {
|
||||
var submenu = $('<ul id="'+opt.id+'-submenu" class="dropdown-menu"></ul>').appendTo(item);
|
||||
|
||||
for (var i=0;i<opt.options.length;i++) {
|
||||
createMenuItem(opt.options[i]).appendTo(submenu);
|
||||
var li = createMenuItem(opt.options[i]);
|
||||
if (li) {
|
||||
li.appendTo(submenu);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (opt.disabled) {
|
||||
@ -148,9 +158,16 @@ RED.menu = (function() {
|
||||
|
||||
var topMenu = $("<ul/>",{id:options.id+"-submenu", class:"dropdown-menu pull-right"}).insertAfter(button);
|
||||
|
||||
var lastAddedSeparator = false;
|
||||
for (var i=0;i<options.options.length;i++) {
|
||||
var opt = options.options[i];
|
||||
createMenuItem(opt).appendTo(topMenu);
|
||||
if (opt !== null || !lastAddedSeparator) {
|
||||
var li = createMenuItem(opt);
|
||||
if (li) {
|
||||
li.appendTo(topMenu);
|
||||
lastAddedSeparator = (opt === null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -176,7 +193,7 @@ RED.menu = (function() {
|
||||
} else {
|
||||
$("#"+id).removeClass("active");
|
||||
}
|
||||
if (opt.onselect) {
|
||||
if (opt && opt.onselect) {
|
||||
opt.onselect.call(opt,state);
|
||||
}
|
||||
setSavedState(id, state);
|
||||
@ -198,7 +215,9 @@ RED.menu = (function() {
|
||||
}
|
||||
|
||||
function setAction(id,action) {
|
||||
menuItems[id].onselect = action;
|
||||
var opt = menuItems[id];
|
||||
if (opt) {
|
||||
opt.onselect = action;
|
||||
$("#"+id).click(function() {
|
||||
if ($(this).parent().hasClass("disabled")) {
|
||||
return;
|
||||
@ -210,6 +229,7 @@ RED.menu = (function() {
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
init: createMenu,
|
||||
|
@ -51,14 +51,14 @@ RED.sidebar = (function() {
|
||||
sidebarSeparator.chartRight = winWidth-$("#workspace").width()-$("#workspace").offset().left-2;
|
||||
|
||||
|
||||
if (!RED.menu.isSelected("btn-sidebar")) {
|
||||
if (!RED.menu.isSelected("menu-item-sidebar")) {
|
||||
sidebarSeparator.opening = true;
|
||||
var newChartRight = 15;
|
||||
$("#sidebar").addClass("closing");
|
||||
$("#workspace").css("right",newChartRight);
|
||||
$("#chart-zoom-controls").css("right",newChartRight+20);
|
||||
$("#sidebar").width(0);
|
||||
RED.menu.setSelected("btn-sidebar",true);
|
||||
RED.menu.setSelected("menu-item-sidebar",true);
|
||||
eventHandler.emit("resize");
|
||||
}
|
||||
sidebarSeparator.width = $("#sidebar").width();
|
||||
@ -104,7 +104,7 @@ RED.sidebar = (function() {
|
||||
stop:function(event,ui) {
|
||||
if (sidebarSeparator.closing) {
|
||||
$("#sidebar").removeClass("closing");
|
||||
RED.menu.setSelected("btn-sidebar",false);
|
||||
RED.menu.setSelected("menu-item-sidebar",false);
|
||||
if ($("#sidebar").width() < 180) {
|
||||
$("#sidebar").width(180);
|
||||
$("#workspace").css("right",208);
|
||||
@ -138,7 +138,7 @@ RED.sidebar = (function() {
|
||||
}
|
||||
|
||||
function init () {
|
||||
RED.keyboard.add(/* SPACE */ 32,{ctrl:true},function(){RED.menu.setSelected("btn-sidebar",!RED.menu.isSelected("btn-sidebar"));d3.event.preventDefault();});
|
||||
RED.keyboard.add(/* SPACE */ 32,{ctrl:true},function(){RED.menu.setSelected("menu-item-sidebar",!RED.menu.isSelected("menu-item-sidebar"));d3.event.preventDefault();});
|
||||
showSidebar();
|
||||
RED.sidebar.info.show();
|
||||
}
|
||||
|
@ -177,9 +177,9 @@ RED.subflow = (function() {
|
||||
|
||||
RED.view.on("selection-changed",function(selection) {
|
||||
if (!selection.nodes) {
|
||||
RED.menu.setDisabled("btn-convert-subflow",true);
|
||||
RED.menu.setDisabled("menu-item-subflow-convert",true);
|
||||
} else {
|
||||
RED.menu.setDisabled("btn-convert-subflow",false);
|
||||
RED.menu.setDisabled("menu-item-subflow-convert",false);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -259,8 +259,8 @@ RED.view = (function() {
|
||||
$("#workspace-subflow-add-input").toggleClass("disabled",activeSubflow.in.length > 0);
|
||||
}
|
||||
|
||||
RED.menu.setDisabled("btn-workspace-edit", activeSubflow);
|
||||
RED.menu.setDisabled("btn-workspace-delete",RED.workspaces.count() == 1 || activeSubflow);
|
||||
RED.menu.setDisabled("menu-item-workspace-edit", activeSubflow);
|
||||
RED.menu.setDisabled("menu-item-workspace-delete",RED.workspaces.count() == 1 || activeSubflow);
|
||||
|
||||
if (workspaceScrollPositions[event.workspace]) {
|
||||
chart.scrollLeft(workspaceScrollPositions[event.workspace].left);
|
||||
|
@ -102,18 +102,18 @@ RED.workspaces = (function() {
|
||||
}
|
||||
},
|
||||
onadd: function(tab) {
|
||||
RED.menu.addItem("btn-workspace-menu",{
|
||||
id:"btn-workspace-menu-"+tab.id.replace(".","-"),
|
||||
RED.menu.addItem("menu-item-workspace",{
|
||||
id:"menu-item-workspace-menu-"+tab.id.replace(".","-"),
|
||||
label:tab.label,
|
||||
onselect:function() {
|
||||
workspace_tabs.activateTab(tab.id);
|
||||
}
|
||||
});
|
||||
RED.menu.setDisabled("btn-workspace-delete",workspace_tabs.count() == 1);
|
||||
RED.menu.setDisabled("menu-item-workspace-delete",workspace_tabs.count() == 1);
|
||||
},
|
||||
onremove: function(tab) {
|
||||
RED.menu.setDisabled("btn-workspace-delete",workspace_tabs.count() == 1);
|
||||
RED.menu.removeItem("btn-workspace-menu-"+tab.id.replace(".","-"));
|
||||
RED.menu.setDisabled("menu-item-workspace-delete",workspace_tabs.count() == 1);
|
||||
RED.menu.removeItem("menu-item-workspace-menu-"+tab.id.replace(".","-"));
|
||||
}
|
||||
});
|
||||
|
||||
@ -141,7 +141,7 @@ RED.workspaces = (function() {
|
||||
if (workspace.label != label) {
|
||||
workspace_tabs.renameTab(workspace.id,label);
|
||||
RED.nodes.dirty(true);
|
||||
$("#btn-workspace-menu-"+workspace.id.replace(".","-")).text(label);
|
||||
$("#menu-item-workspace-menu-"+workspace.id.replace(".","-")).text(label);
|
||||
// TODO: update entry in menu
|
||||
}
|
||||
$( this ).dialog( "close" );
|
||||
@ -195,7 +195,7 @@ RED.workspaces = (function() {
|
||||
$('#btn-workspace-add-tab').on("click",function(e) {addWorkspace(); e.preventDefault()});
|
||||
RED.sidebar.on("resize",workspace_tabs.resize);
|
||||
|
||||
RED.menu.setAction('btn-workspace-delete',function() {
|
||||
RED.menu.setAction('menu-item-workspace-delete',function() {
|
||||
deleteWorkspace(RED.nodes.workspace(activeWorkspace));
|
||||
});
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ RED.user = (function() {
|
||||
}
|
||||
|
||||
var dialog = $('<div id="node-dialog-login" class="hide">'+
|
||||
'<div style="display: inline-block;width: 250px; vertical-align: top; margin-right: 10px; margin-bottom: 20px;"><img src="red/images/node-red-256.png"/></div>'+
|
||||
'<div style="display: inline-block;width: 250px; vertical-align: top; margin-right: 10px; margin-bottom: 20px;"><img id="node-dialog-login-image" src=""/></div>'+
|
||||
'<div style="display: inline-block; width: 250px; vertical-align: bottom; margin-left: 10px; margin-bottom: 20px;">'+
|
||||
'<form id="node-dialog-login-fields" class="form-horizontal" style="margin-bottom: 0px;"></form>'+
|
||||
'</div>'+
|
||||
@ -45,6 +45,13 @@ RED.user = (function() {
|
||||
success: function(data) {
|
||||
if (data.type == "credentials") {
|
||||
var i=0;
|
||||
|
||||
if (data.image) {
|
||||
$("#node-dialog-login-image").attr("src",data.image);
|
||||
} else {
|
||||
$("#node-dialog-login-image").attr("src","red/images/node-red-256.png");
|
||||
}
|
||||
|
||||
for (;i<data.prompts.length;i++) {
|
||||
var field = data.prompts[i];
|
||||
var row = $("<div/>",{class:"form-row"});
|
||||
@ -110,10 +117,10 @@ RED.user = (function() {
|
||||
}
|
||||
|
||||
function updateUserMenu() {
|
||||
$("#btn-usermenu-submenu li").remove();
|
||||
$("#usermenu-submenu li").remove();
|
||||
if (RED.settings.user.anonymous) {
|
||||
RED.menu.addItem("btn-usermenu",{
|
||||
id:"btn-login",
|
||||
id:"usermenu-item-login",
|
||||
label:"Login",
|
||||
onselect: function() {
|
||||
RED.user.login({cancelable:true},function() {
|
||||
@ -126,11 +133,11 @@ RED.user = (function() {
|
||||
});
|
||||
} else {
|
||||
RED.menu.addItem("btn-usermenu",{
|
||||
id:"btn-username",
|
||||
id:"usermenu-item-username",
|
||||
label:"<b>"+RED.settings.user.username+"</b>"
|
||||
});
|
||||
RED.menu.addItem("btn-usermenu",{
|
||||
id:"btn-logout",
|
||||
id:"usermenu-item-logout",
|
||||
label:"Logout",
|
||||
onselect: function() {
|
||||
RED.user.logout();
|
||||
@ -144,6 +151,8 @@ RED.user = (function() {
|
||||
|
||||
function init() {
|
||||
if (RED.settings.user) {
|
||||
if (!RED.settings.editorTheme || !RED.settings.editorTheme.hasOwnProperty("userMenu")) {
|
||||
|
||||
$('<li><a id="btn-usermenu" class="button hide" data-toggle="dropdown" href="#"><i class="fa fa-user"></i></a></li>')
|
||||
.prependTo(".header-toolbar");
|
||||
|
||||
@ -152,6 +161,7 @@ RED.user = (function() {
|
||||
});
|
||||
updateUserMenu();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return {
|
||||
|
@ -14,6 +14,20 @@
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
$activeButton: #121212;
|
||||
|
||||
$deployButton: #8C101C;
|
||||
$deployButtonHover: #6E0A1E;
|
||||
$deployButtonActive: #4C0A17;
|
||||
|
||||
$deployDisabledButton: #444;
|
||||
$deployDisabledButtonHover: #555;
|
||||
$deployDisabledButtonActive: #444;
|
||||
|
||||
$headerMenuBackground: #121212;
|
||||
$headerMenuItemHover: #323232;
|
||||
$headerMenuItemDivider: #464646;
|
||||
|
||||
#header {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
@ -34,29 +48,29 @@ span.logo {
|
||||
font-size: 30px;
|
||||
line-height: 30px;
|
||||
text-decoration: none;
|
||||
}
|
||||
span.logo span {
|
||||
|
||||
span {
|
||||
vertical-align: middle;
|
||||
font-size: 16px !important;
|
||||
}
|
||||
span.logo img {
|
||||
img {
|
||||
height: 18px;
|
||||
}
|
||||
#header ul.header-toolbar {
|
||||
}
|
||||
|
||||
.header-toolbar {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
list-style: none;
|
||||
float: right;
|
||||
}
|
||||
|
||||
#header ul.header-toolbar > li {
|
||||
> li {
|
||||
display: inline-block;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#header ul.header-toolbar > li {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
.button {
|
||||
@ -68,7 +82,7 @@ span.logo img {
|
||||
text-align: center;
|
||||
line-height: 40px;
|
||||
display: inline-block;
|
||||
font-size: 14px;
|
||||
font-size: 20px;
|
||||
padding: 0px 12px;
|
||||
text-decoration: none;
|
||||
color: #C7C7C7;
|
||||
@ -76,110 +90,96 @@ span.logo img {
|
||||
vertical-align: middle;
|
||||
border-left: 2px solid #000;
|
||||
border-right: 2px solid #000;
|
||||
}
|
||||
#header .button:not(.disabled):hover {
|
||||
border-color: #323232;
|
||||
}
|
||||
|
||||
#btn-deploy {
|
||||
background: #8C101C; /*#d24741;*/
|
||||
color: #eee !important;
|
||||
&:hover {
|
||||
border-color: $headerMenuItemHover;
|
||||
}
|
||||
#btn-deploy + a {
|
||||
background: #8C101C; /*#BA403B;*/
|
||||
color: #eee;
|
||||
}
|
||||
#btn-deploy + a:hover {
|
||||
background: #6E0A1E; /*#AD3C38;*/
|
||||
color: #eee;
|
||||
}
|
||||
#btn-deploy + a:active {
|
||||
background: #4C0A17; /*#aa1f19;*/
|
||||
color: #ccc;
|
||||
}
|
||||
span.deploy-button-group.open > #btn-deploy + a {
|
||||
background: #121212 !important;
|
||||
}
|
||||
|
||||
#btn-deploy:not(.disabled):hover {
|
||||
background: #6E0A1E; /*#ca3f39;*/
|
||||
}
|
||||
|
||||
|
||||
#btn-deploy:not(.disabled):active {
|
||||
background: #4C0A17 /*#aa1f19*/ !important;
|
||||
}
|
||||
#btn-deploy:not(.disabled):active {
|
||||
color: #ccc !important;
|
||||
}
|
||||
|
||||
#btn-deploy.disabled {
|
||||
cursor: default;
|
||||
background: #444;
|
||||
color: #999 !important;
|
||||
}
|
||||
|
||||
#btn-deploy.disabled + a {
|
||||
background: #444;
|
||||
color: #ddd;
|
||||
}
|
||||
#btn-deploy.disabled + a:hover {
|
||||
background: #555;
|
||||
color: #ddd;
|
||||
}
|
||||
#btn-deploy.disabled + a:active {
|
||||
background: #444;
|
||||
color: #ddd;
|
||||
}
|
||||
span.deploy-button-group.open > #btn-deploy.disabled + a {
|
||||
background: #121212 !important;
|
||||
}
|
||||
|
||||
|
||||
#btn-deploy img {
|
||||
margin-right: 8px;
|
||||
}
|
||||
#btn-deploy.disabled img {
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
.button-group {
|
||||
display: inline-block;
|
||||
margin: auto 15px;
|
||||
vertical-align: middle;
|
||||
background: #555;
|
||||
clear: both;
|
||||
}
|
||||
.button-group > a {
|
||||
display: inline-block;
|
||||
float: left;
|
||||
line-height: 22px;
|
||||
font-size: 14px;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
padding: 4px 8px;
|
||||
color: #ccc;
|
||||
margin: 0;
|
||||
}
|
||||
.button-group > a:last-child {
|
||||
|
||||
.deploy-button {
|
||||
background: $deployButton;
|
||||
color: #eee !important;
|
||||
|
||||
&:hover {
|
||||
background: $deployButtonHover;
|
||||
}
|
||||
|
||||
&:active {
|
||||
background: $deployButtonActive;
|
||||
color: #ccc !important;
|
||||
}
|
||||
}
|
||||
|
||||
#btn-deploy {
|
||||
|
||||
padding: 4px 12px;
|
||||
|
||||
&.disabled {
|
||||
cursor: default;
|
||||
background: $deployDisabledButton;
|
||||
color: #999 !important;
|
||||
|
||||
img {
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
&+ #btn-deploy-options {
|
||||
background: $deployDisabledButton;
|
||||
color: #ddd;
|
||||
}
|
||||
&+ #btn-deploy-options:hover {
|
||||
background: $deployDisabledButtonHover;
|
||||
}
|
||||
&+ #btn-deploy-options:active {
|
||||
background: $deployDisabledButton;
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.deploy-button-group.open {
|
||||
#btn-deploy-options {
|
||||
background: $activeButton !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#header .button {
|
||||
font-size: 20px !important;
|
||||
&:active, &.active {
|
||||
background: $activeButton;
|
||||
}
|
||||
#header .button:active, #header .button.active {
|
||||
background: #121212;
|
||||
}
|
||||
#header .button:focus {
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
|
||||
#header li.open .button {
|
||||
background: #121212;
|
||||
border-color: #121212;
|
||||
background: $activeButton;
|
||||
border-color: $activeButton;
|
||||
}
|
||||
|
||||
|
||||
#header ul.dropdown-menu {
|
||||
background: #121212;
|
||||
background: $headerMenuBackground;
|
||||
width: 250px !important;
|
||||
margin-top: 0;
|
||||
}
|
||||
@ -219,12 +219,12 @@ span.deploy-button-group.open > #btn-deploy.disabled + a {
|
||||
|
||||
#header ul.dropdown-menu > li:hover > a,
|
||||
#header ul.dropdown-menu > li:focus > a {
|
||||
background: #323232 !important;
|
||||
background: $headerMenuItemHover !important;
|
||||
}
|
||||
|
||||
#header ul.dropdown-menu li.divider {
|
||||
background: #464646;
|
||||
border-bottom-color: #323232;
|
||||
background: $headerMenuItemDivider;
|
||||
border-bottom-color: $headerMenuItemHover;
|
||||
}
|
||||
#header ul.dropdown-menu li.disabled a {
|
||||
color: #666;
|
||||
|
@ -17,7 +17,9 @@
|
||||
|
||||
#palette {
|
||||
position: absolute;
|
||||
top: 5px; left:10px; bottom: 10px;
|
||||
top: 5px;
|
||||
bottom: 10px;
|
||||
left:10px;
|
||||
background: #f3f3f3;
|
||||
width: 170px;
|
||||
text-align: center;
|
||||
@ -29,13 +31,12 @@
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left:0;
|
||||
right: 0;
|
||||
bottom: 35px;
|
||||
left:0;
|
||||
padding: 5px;
|
||||
overflow-y: auto;
|
||||
box-sizing:border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
}
|
||||
.palette-spinner {
|
||||
padding-top: 40px;
|
||||
@ -53,7 +54,6 @@
|
||||
padding: 3px;
|
||||
border-top: 1px solid #999;
|
||||
box-sizing:border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
}
|
||||
#palette-search i.fa-search {
|
||||
position: absolute;
|
||||
@ -82,7 +82,6 @@
|
||||
margin: 0px;
|
||||
height: 30px;
|
||||
box-sizing:border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
}
|
||||
|
||||
#palette-search input:focus {
|
||||
|
@ -17,12 +17,13 @@
|
||||
|
||||
|
||||
#sidebar {
|
||||
width: 305px;
|
||||
position: absolute;
|
||||
right: 10px; top: 5px; bottom:10px;
|
||||
top: 5px;
|
||||
right: 10px;
|
||||
bottom: 10px;
|
||||
width: 305px;
|
||||
background: #fff;
|
||||
box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
@include component-border;
|
||||
}
|
||||
|
||||
@ -33,17 +34,22 @@
|
||||
}
|
||||
|
||||
#sidebar-content {
|
||||
position: absolute;
|
||||
top: 30px;
|
||||
right: 0;
|
||||
bottom: 1px;
|
||||
left: 0px;
|
||||
font-size: 1.2em;
|
||||
overflow-y: auto;
|
||||
position: absolute;
|
||||
top: 30px; left: 0px; right: 0; bottom: 1px;
|
||||
}
|
||||
|
||||
#sidebar-separator {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
right: 316px;
|
||||
bottom:10px;
|
||||
width: 15px;
|
||||
background: url(images/grip.png) no-repeat 50% 50%;
|
||||
position: absolute;
|
||||
right: 316px; top: 5px; bottom:10px;
|
||||
cursor: col-resize;
|
||||
}
|
||||
|
||||
|
@ -14,10 +14,6 @@
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
#workspace {
|
||||
margin-left: 160px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#chart {
|
||||
overflow: auto;
|
||||
@ -32,12 +28,16 @@
|
||||
outline: none;
|
||||
}
|
||||
|
||||
|
||||
#workspace {
|
||||
position: absolute;
|
||||
margin: 0;
|
||||
top:5px; left:190px; bottom: 10px; right: 330px;
|
||||
top:5px;
|
||||
left:190px;
|
||||
bottom: 10px;
|
||||
right: 330px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#chart-zoom-controls {
|
||||
position: absolute;
|
||||
bottom:30px; right: 350px;
|
||||
|
182
editor/templates/index.mst
Normal file
182
editor/templates/index.mst
Normal file
@ -0,0 +1,182 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0"/>
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="mobile-web-app-capable" content="yes">
|
||||
<!--
|
||||
Copyright 2013, 2015 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.
|
||||
-->
|
||||
<head>
|
||||
<title>{{ page.title }}</title>
|
||||
<link rel="icon" type="image/png" href="{{ page.favicon }}">
|
||||
<link href="vendor/bootstrap/css/bootstrap.min.css" rel="stylesheet" media="screen">
|
||||
<link href="vendor/jquery/css/smoothness/jquery-ui-1.10.3.custom.min.css" rel="stylesheet" media="screen">
|
||||
<link rel="stylesheet" href="vendor/font-awesome/css/font-awesome.min.css">
|
||||
<link rel="stylesheet" href="vendor/vendor.css">
|
||||
<link rel="stylesheet" href="red/style.min.css">
|
||||
{{#page.css}}
|
||||
<link rel="stylesheet" href="{{.}}">
|
||||
{{/page.css}}
|
||||
|
||||
</head>
|
||||
<body spellcheck="false">
|
||||
<div id="header">
|
||||
<span class="logo">{{#header.image}}<img src="{{.}}">{{/header.image}} <span>{{ header.title }}</span></span>
|
||||
<ul class="header-toolbar hide">
|
||||
<li><a id="btn-sidemenu" class="button" data-toggle="dropdown" href="#"><i class="fa fa-bars"></i></a></li>
|
||||
<ul>
|
||||
</div>
|
||||
<div id="main-container" class="sidebar-closed hide">
|
||||
<div id="palette">
|
||||
<img src="red/images/spin.svg" class="palette-spinner hide"/>
|
||||
<div id="palette-container" class="palette-scroll">
|
||||
</div>
|
||||
<div id="palette-search">
|
||||
<i class="fa fa-search"></i><input id="palette-search-input" type="text" placeholder="filter"><a href="#" id="palette-search-clear"><i class="fa fa-times"></i></a></input>
|
||||
</div>
|
||||
</div><!-- /palette -->
|
||||
|
||||
<div id="workspace">
|
||||
<ul id="workspace-tabs"></ul>
|
||||
<div id="workspace-add-tab"><a id="btn-workspace-add-tab" href="#"><i class="fa fa-plus"></i></a></div>
|
||||
<div id="chart"></div>
|
||||
<div id="workspace-toolbar">
|
||||
<a class="button" id="workspace-subflow-edit" href="#"><i class="fa fa-pencil"></i> edit name</a>
|
||||
<a class="button disabled" id="workspace-subflow-add-input" href="#"><i class="fa fa-plus"></i> input</a>
|
||||
<a class="button" id="workspace-subflow-add-output" href="#"><i class="fa fa-plus"></i> output</a>
|
||||
<a class="button" id="workspace-subflow-delete" href="#"><i class="fa fa-trash"></i> delete subflow</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="chart-zoom-controls">
|
||||
<div class="btn-group">
|
||||
<a class="btn btn-mini" id="btn-zoom-out" href="#"><i class="fa fa-search-minus"></i></a>
|
||||
<a class="btn btn-mini" id="btn-zoom-zero" href="#"><i class="fa fa-dot-circle-o"></i></a>
|
||||
<a class="btn btn-mini" id="btn-zoom-in" href="#"><i class="fa fa-search-plus"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="sidebar">
|
||||
<ul id="sidebar-tabs"></ul>
|
||||
<div id="sidebar-content"></div>
|
||||
</div>
|
||||
|
||||
<div id="sidebar-separator"></div>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="notifications"></div>
|
||||
<div id="dropTarget"><div>Drop the flow here<br/><i class="fa fa-download"></i></div></div>
|
||||
|
||||
<div id="dialog" class="hide"><form id="dialog-form" class="form-horizontal"></form></div>
|
||||
<div id="node-config-dialog" class="hide"><form id="dialog-config-form" class="form-horizontal"></form><div class="form-tips" id="node-config-dialog-user-count"></div></div>
|
||||
<div id="subflow-dialog" class="hide">
|
||||
<form class="form-horizontal">
|
||||
<div class="form-row">
|
||||
<label>Name</label><input type="text" id="subflow-input-name">
|
||||
</div>
|
||||
</form>
|
||||
<div class="form-tips" id="subflow-dialog-user-count"></div>
|
||||
</div>
|
||||
|
||||
<div id="node-dialog-confirm-deploy" class="hide">
|
||||
<form class="form-horizontal">
|
||||
<div id="node-dialog-confirm-deploy-config" style="text-align: center; padding-top: 30px;">
|
||||
Some of the nodes are not properly configured. Are you sure you want to deploy?
|
||||
</div>
|
||||
<div id="node-dialog-confirm-deploy-unknown" style="text-align: center; padding-top: 10px;">
|
||||
The workspace contains some unknown node types:
|
||||
<ul style="width: 300px; margin: auto; text-align: left;" id="node-dialog-confirm-deploy-unknown-list"></ul>
|
||||
Are you sure you want to deploy?
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div id="node-dialog-library-save-confirm" class="hide">
|
||||
<form class="form-horizontal">
|
||||
<div style="text-align: center; padding-top: 30px;">
|
||||
A <span id="node-dialog-library-save-type"></span> called <span id="node-dialog-library-save-name"></span> already exists. Overwrite?
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div id="node-dialog-library-save" class="hide">
|
||||
<form class="form-horizontal">
|
||||
<div class="form-row">
|
||||
<label for="node-dialog-library-save-folder"><i class="fa fa-folder-open"></i> Folder</label>
|
||||
<input type="text" id="node-dialog-library-save-folder" placeholder="Folder">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-dialog-library-save-filename"><i class="fa fa-file"></i> Filename</label>
|
||||
<input type="text" id="node-dialog-library-save-filename" placeholder="Filename">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div id="node-dialog-library-lookup" class="hide">
|
||||
<form class="form-horizontal">
|
||||
<div class="form-row">
|
||||
<ul id="node-dialog-library-breadcrumbs" class="breadcrumb">
|
||||
<li class="active"><a href="#">Library</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div style="vertical-align: top; display: inline-block; height: 100%; width: 30%; padding-right: 20px;">
|
||||
<div id="node-select-library" style="border: 1px solid #999; width: 100%; height: 100%; overflow:scroll;"><ul></ul></div>
|
||||
</div>
|
||||
<div style="vertical-align: top; display: inline-block;width: 65%; height: 100%;">
|
||||
<div style="height: 100%; width: 95%;" class="node-text-editor" id="node-select-library-text" ></div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div id="node-dialog-rename-workspace" class="hide">
|
||||
<form class="form-horizontal">
|
||||
<div class="form-row">
|
||||
<label for="node-input-workspace-name" ><i class="fa fa-tag"></i> Name:</label>
|
||||
<input type="text" id="node-input-workspace-name">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div id="node-dialog-delete-workspace" class="hide">
|
||||
<form class="form-horizontal">
|
||||
<div style="text-align: center; padding-top: 30px;">
|
||||
Are you sure you want to delete '<span id="node-dialog-delete-workspace-name"></span>'?
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<script type="text/x-red" data-template-name="export-library-dialog">
|
||||
<div class="form-row">
|
||||
<label for="node-input-filename" ><i class="fa fa-file"></i> Filename:</label>
|
||||
<input type="text" id="node-input-filename" placeholder="Filename">
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-template-name="subflow">
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
|
||||
<input type="text" id="node-input-name" placeholder="name">
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script src="vendor/vendor.js"></script>
|
||||
<script src="vendor/ace/ace.js"></script>
|
||||
<script src="vendor/ace/ext-language_tools.js"></script>
|
||||
<script src="red/red.min.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
@ -22,6 +22,8 @@ var Tokens = require("./tokens");
|
||||
var Users = require("./users");
|
||||
var permissions = require("./permissions");
|
||||
|
||||
var theme = require("../theme");
|
||||
|
||||
var settings = null;
|
||||
var log = require("../../log");
|
||||
|
||||
@ -80,6 +82,9 @@ function login(req,res) {
|
||||
"type":"credentials",
|
||||
"prompts":[{id:"username",type:"text",label:"Username"},{id:"password",type:"password",label:"Password"}]
|
||||
}
|
||||
if (theme.context().login && theme.context().login.image) {
|
||||
response.image = theme.context().login.image;
|
||||
}
|
||||
}
|
||||
res.json(response);
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ var nodes = require("./nodes");
|
||||
var flows = require("./flows");
|
||||
var library = require("./library");
|
||||
var info = require("./info");
|
||||
var theme = require("./theme");
|
||||
|
||||
var auth = require("./auth");
|
||||
var needsPermission = auth.needsPermission;
|
||||
@ -41,9 +42,13 @@ function init(adminApp,storage) {
|
||||
|
||||
// Editor
|
||||
if (!settings.disableEditor) {
|
||||
ui.init(settings);
|
||||
var editorApp = express();
|
||||
editorApp.get("/",ui.ensureSlash,ui.editor);
|
||||
editorApp.get("/icons/:icon",ui.icon);
|
||||
if (settings.editorTheme) {
|
||||
editorApp.use("/theme",theme.init(settings));
|
||||
}
|
||||
editorApp.use("/",ui.editorResources);
|
||||
adminApp.use(editorApp);
|
||||
}
|
||||
|
@ -14,6 +14,7 @@
|
||||
* limitations under the License.
|
||||
**/
|
||||
var settings = require('../settings');
|
||||
var theme = require("./theme");
|
||||
|
||||
var util = require('util');
|
||||
|
||||
@ -23,7 +24,12 @@ module.exports = {
|
||||
httpNodeRoot: settings.httpNodeRoot,
|
||||
version: settings.version,
|
||||
user: req.user
|
||||
};
|
||||
}
|
||||
|
||||
var themeSettings = theme.settings();
|
||||
if (themeSettings) {
|
||||
safeSettings.editorTheme = themeSettings;
|
||||
}
|
||||
|
||||
if (util.isArray(settings.paletteCategories)) {
|
||||
safeSettings.paletteCategories = settings.paletteCategories;
|
||||
|
151
red/api/theme.js
Normal file
151
red/api/theme.js
Normal file
@ -0,0 +1,151 @@
|
||||
/**
|
||||
* Copyright 2015 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.
|
||||
**/
|
||||
|
||||
var express = require("express");
|
||||
var util = require("util");
|
||||
var path = require("path");
|
||||
var fs = require("fs");
|
||||
var clone = require("clone");
|
||||
|
||||
var defaultContext = {
|
||||
page: {
|
||||
title: "Node-RED",
|
||||
favicon: "favicon.ico"
|
||||
},
|
||||
header: {
|
||||
title: "Node-RED",
|
||||
image: "red/images/node-red.png"
|
||||
}
|
||||
};
|
||||
|
||||
var themeContext = clone(defaultContext);
|
||||
var themeSettings = null;
|
||||
|
||||
function serveFile(app,baseUrl,file) {
|
||||
try {
|
||||
var stats = fs.statSync(file);
|
||||
var url = baseUrl+path.basename(file);
|
||||
//console.log(url,"->",file);
|
||||
app.get(url,function(req, res) {
|
||||
res.sendfile(file);
|
||||
});
|
||||
return "theme"+url;
|
||||
} catch(err) {
|
||||
//TODO: log filenotfound
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
init: function(settings) {
|
||||
var i;
|
||||
var url;
|
||||
themeContext = clone(defaultContext);
|
||||
themeSettings = null;
|
||||
|
||||
if (settings.editorTheme) {
|
||||
var theme = settings.editorTheme;
|
||||
themeSettings = {};
|
||||
|
||||
var themeApp = express();
|
||||
|
||||
if (theme.page) {
|
||||
if (theme.page.css) {
|
||||
var styles = theme.page.css;
|
||||
if (!util.isArray(styles)) {
|
||||
styles = [styles];
|
||||
}
|
||||
themeContext.page.css = [];
|
||||
|
||||
for (i=0;i<styles.length;i++) {
|
||||
url = serveFile(themeApp,"/css/",styles[i]);
|
||||
if (url) {
|
||||
themeContext.page.css.push(url);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (theme.page.favicon) {
|
||||
url = serveFile(themeApp,"/favicon/",theme.page.favicon)
|
||||
if (url) {
|
||||
themeContext.page.favicon = url;
|
||||
}
|
||||
}
|
||||
|
||||
themeContext.page.title = theme.page.title || themeContext.page.title;
|
||||
}
|
||||
|
||||
if (theme.header) {
|
||||
|
||||
themeContext.header.title = theme.header.title || themeContext.header.title;
|
||||
if (theme.header.hasOwnProperty("image")) {
|
||||
if (theme.header.image) {
|
||||
url = serveFile(themeApp,"/header/",theme.header.image);
|
||||
if (url) {
|
||||
themeContext.header.image = url;
|
||||
}
|
||||
} else {
|
||||
themeContext.header.image = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (theme.deployButton) {
|
||||
if (theme.deployButton.type == "simple") {
|
||||
themeSettings.deployButton = {
|
||||
type: "simple"
|
||||
}
|
||||
if (theme.deployButton.label) {
|
||||
themeSettings.deployButton.label = theme.deployButton.label;
|
||||
}
|
||||
if (theme.deployButton.icon) {
|
||||
url = serveFile(themeApp,"/deploy/",theme.deployButton.icon);
|
||||
if (url) {
|
||||
themeSettings.deployButton.icon = url;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (theme.hasOwnProperty("userMenu")) {
|
||||
themeSettings.userMenu = theme.userMenu;
|
||||
}
|
||||
|
||||
if (theme.login) {
|
||||
if (theme.login.image) {
|
||||
url = serveFile(themeApp,"/login/",theme.login.image);
|
||||
if (url) {
|
||||
themeContext.login = {
|
||||
image: url
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (theme.hasOwnProperty("menu")) {
|
||||
themeSettings.menu = theme.menu;
|
||||
}
|
||||
|
||||
return themeApp;
|
||||
}
|
||||
},
|
||||
context: function() {
|
||||
return themeContext;
|
||||
},
|
||||
settings: function() {
|
||||
return themeSettings;
|
||||
}
|
||||
}
|
@ -17,8 +17,12 @@ var express = require('express');
|
||||
var fs = require("fs");
|
||||
var path = require("path");
|
||||
|
||||
var theme = require("./theme");
|
||||
|
||||
var Mustache = require("mustache");
|
||||
|
||||
var events = require("../events");
|
||||
var settings = require("../settings");
|
||||
var settings;
|
||||
|
||||
var icon_paths = [path.resolve(__dirname + '/../../public/icons')];
|
||||
var iconCache = {};
|
||||
@ -29,7 +33,16 @@ events.on("node-icon-dir",function(dir) {
|
||||
icon_paths.push(path.resolve(dir));
|
||||
});
|
||||
|
||||
var templateDir = path.resolve(__dirname+"/../../editor/templates");
|
||||
var editorTemplate;
|
||||
|
||||
module.exports = {
|
||||
init: function(_settings) {
|
||||
settings = _settings;
|
||||
editorTemplate = fs.readFileSync(path.join(templateDir,"index.mst"),"utf8");
|
||||
Mustache.parse(editorTemplate);
|
||||
},
|
||||
|
||||
ensureSlash: function(req,res,next) {
|
||||
var parts = req.originalUrl.split("?");
|
||||
if (parts[0].slice(-1) != "/") {
|
||||
@ -56,7 +69,7 @@ module.exports = {
|
||||
}
|
||||
},
|
||||
editor: function(req,res) {
|
||||
res.sendfile(path.resolve(__dirname + '/../../public/index.html'));
|
||||
res.send(Mustache.render(editorTemplate,theme.context()));
|
||||
},
|
||||
editorResources: express.static(__dirname + '/../../public')
|
||||
};
|
||||
|
@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright 2014 IBM Corp.
|
||||
* Copyright 2014, 2015 IBM Corp.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -24,6 +24,8 @@ var app = express();
|
||||
var settings = require("../../../red/settings");
|
||||
var info = require("../../../red/api/info");
|
||||
|
||||
var theme = require("../../../red/api/theme");
|
||||
|
||||
describe("info api", function() {
|
||||
describe("settings handler", function() {
|
||||
before(function() {
|
||||
@ -34,12 +36,16 @@ describe("info api", function() {
|
||||
paletteCategories :["red","blue","green"]
|
||||
}
|
||||
settings.init(userSettings);
|
||||
|
||||
sinon.stub(theme,"settings",function() { return { test: 456 };});
|
||||
|
||||
app = express();
|
||||
app.get("/settings",info.settings);
|
||||
});
|
||||
|
||||
after(function() {
|
||||
settings.reset();
|
||||
theme.settings.restore();
|
||||
});
|
||||
|
||||
it('returns the filtered settings', function(done) {
|
||||
@ -53,6 +59,7 @@ describe("info api", function() {
|
||||
res.body.should.have.property("httpNodeRoot","testHttpNodeRoot");
|
||||
res.body.should.have.property("version","testVersion");
|
||||
res.body.should.have.property("paletteCategories",["red","blue","green"]);
|
||||
res.body.should.have.property("editorTheme",{test:456});
|
||||
res.body.should.not.have.property("foo",123);
|
||||
done();
|
||||
});
|
||||
|
103
test/red/api/theme_spec.js
Normal file
103
test/red/api/theme_spec.js
Normal file
@ -0,0 +1,103 @@
|
||||
/**
|
||||
* Copyright 2015 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.
|
||||
**/
|
||||
|
||||
var should = require("should");
|
||||
var request = require('supertest');
|
||||
var express = require('express');
|
||||
var sinon = require('sinon');
|
||||
var when = require('when');
|
||||
var fs = require("fs");
|
||||
|
||||
var app = express();
|
||||
var settings = require("../../../red/settings");
|
||||
|
||||
var theme = require("../../../red/api/theme");
|
||||
|
||||
describe("theme handler", function() {
|
||||
beforeEach(function() {
|
||||
sinon.stub(fs,"statSync",function() { return true; });
|
||||
});
|
||||
afterEach(function() {
|
||||
theme.init({});
|
||||
fs.statSync.restore();
|
||||
});
|
||||
it("applies the default theme", function() {
|
||||
var result = theme.init({});
|
||||
should.not.exist(result);
|
||||
|
||||
var context = theme.context();
|
||||
context.should.have.a.property("page");
|
||||
context.page.should.have.a.property("title","Node-RED");
|
||||
context.page.should.have.a.property("favicon","favicon.ico");
|
||||
context.should.have.a.property("header");
|
||||
context.header.should.have.a.property("title","Node-RED");
|
||||
context.header.should.have.a.property("image","red/images/node-red.png");
|
||||
|
||||
should.not.exist(theme.settings());
|
||||
});
|
||||
|
||||
it("picks up custom theme", function() {
|
||||
var result = theme.init({
|
||||
editorTheme: {
|
||||
page: {
|
||||
title: "Test Page Title",
|
||||
favicon: "/absolute/path/to/theme/icon",
|
||||
css: "/absolute/path/to/custom/css/file"
|
||||
},
|
||||
header: {
|
||||
title: "Test Header Title",
|
||||
image: "/absolute/path/to/header/image" // or null to remove image
|
||||
},
|
||||
|
||||
deployButton: {
|
||||
type:"simple",
|
||||
label:"Save",
|
||||
icon: "/absolute/path/to/deploy/button/image" // or null to remove image
|
||||
},
|
||||
|
||||
menu: { // Hide unwanted menu items by id. see editor/js/main.js:loadEditor for complete list
|
||||
"menu-item-import-library": false,
|
||||
"menu-item-export-library": false,
|
||||
"menu-item-keyboard-shortcuts": false,
|
||||
"menu-item-help": {
|
||||
label: "Alternative Help Link Text",
|
||||
url: "http://example.com"
|
||||
}
|
||||
},
|
||||
|
||||
userMenu: false, // Hide the user-menu even if adminAuth is enabled
|
||||
|
||||
login: {
|
||||
image: "/absolute/path/to/login/page/big/image" // a 256x256 image
|
||||
}
|
||||
}
|
||||
});
|
||||
should.exist(result);
|
||||
|
||||
var context = theme.context();
|
||||
context.should.have.a.property("page");
|
||||
context.page.should.have.a.property("title","Test Page Title");
|
||||
context.should.have.a.property("header");
|
||||
context.header.should.have.a.property("title","Test Header Title");
|
||||
|
||||
var settings = theme.settings();
|
||||
settings.should.have.a.property("deployButton");
|
||||
settings.should.have.a.property("userMenu");
|
||||
settings.should.have.a.property("menu");
|
||||
|
||||
});
|
||||
|
||||
});
|
Loading…
Reference in New Issue
Block a user