mirror of
				https://github.com/node-red/node-red.git
				synced 2025-03-01 10:36:34 +00:00 
			
		
		
		
	Add editorTheme setting
This commit is contained in:
		
							
								
								
									
										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> | ||||
| @@ -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; | ||||
|   | ||||
							
								
								
									
										113
									
								
								red/api/theme.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								red/api/theme.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,113 @@ | ||||
| /** | ||||
|  * 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 themeContext = { | ||||
|     page: { | ||||
|         title: "Node-RED", | ||||
|         favicon: "favicon.ico" | ||||
|         //css: [""] | ||||
|     }, | ||||
|     header: { | ||||
|         title: "Node-RED", | ||||
|         image: "red/images/node-red.png" | ||||
|     } | ||||
| }; | ||||
|  | ||||
| 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 url; | ||||
|     } catch(err) { | ||||
|         //TODO: log filenotfound | ||||
|         return null; | ||||
|     } | ||||
| } | ||||
|  | ||||
| module.exports = { | ||||
|     init: function(settings) { | ||||
|         var i; | ||||
|         var url; | ||||
|         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("/theme"+url); | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|                  | ||||
|                 if (theme.page.favicon) { | ||||
|                     url = serveFile(themeApp,"/favicon/",theme.page.favicon) | ||||
|                     if (url) { | ||||
|                         themeContext.page.favicon = "/theme"+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 = "/theme"+url; | ||||
|                         } | ||||
|                     } else { | ||||
|                         themeContext.header.image = null; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|              | ||||
|             //themeSettings.deployButton = theme.deployButton || themeSettings.deployButton; | ||||
|              | ||||
|             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') | ||||
| }; | ||||
|   | ||||
							
								
								
									
										0
									
								
								test/red/api/theme_spec.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								test/red/api/theme_spec.js
									
									
									
									
									
										Normal file
									
								
							
		Reference in New Issue
	
	Block a user