From 41b10fd5e4783b521d30dbaa7d32d7210fa09471 Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Sun, 31 Jan 2016 22:27:14 +0000 Subject: [PATCH 01/22] Add new style tray editor --- Gruntfile.js | 1 + editor/js/ui/editor.js | 523 +++++++++++++++++++------------------ editor/js/ui/sidebar.js | 6 +- editor/js/ui/tray.js | 127 +++++++++ editor/sass/colors.scss | 4 + editor/sass/editor.scss | 2 +- editor/sass/mixins.scss | 5 +- editor/sass/sidebar.scss | 5 +- editor/sass/style.scss | 2 +- editor/sass/workspace.scss | 58 ++++ editor/templates/index.mst | 15 +- 11 files changed, 480 insertions(+), 268 deletions(-) create mode 100644 editor/js/ui/tray.js diff --git a/Gruntfile.js b/Gruntfile.js index 491aa86ec..954866ec7 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -120,6 +120,7 @@ module.exports = function(grunt) { "editor/js/ui/tab-info.js", "editor/js/ui/tab-config.js", "editor/js/ui/editor.js", + "editor/js/ui/tray.js", "editor/js/ui/clipboard.js", "editor/js/ui/library.js", "editor/js/ui/notifications.js", diff --git a/editor/js/ui/editor.js b/editor/js/ui/editor.js index 99690e07f..cbd08a5ea 100644 --- a/editor/js/ui/editor.js +++ b/editor/js/ui/editor.js @@ -14,6 +14,11 @@ * limitations under the License. **/ RED.editor = (function() { + + + var editStack = []; + + var editing_node = null; var editing_config_node = null; var subflowEditor; @@ -173,239 +178,8 @@ RED.editor = (function() { } function createDialog(){ - $( "#dialog" ).dialog({ - modal: true, - autoOpen: false, - dialogClass: "ui-dialog-no-close", - closeOnEscape: false, - minWidth: 500, - width: 'auto', - buttons: [ - { - id: "node-dialog-ok", - text: RED._("common.label.ok"), - click: function() { - if (editing_node) { - var changes = {}; - var changed = false; - var wasDirty = RED.nodes.dirty(); - var d; - - if (editing_node._def.oneditsave) { - var oldValues = {}; - for (d in editing_node._def.defaults) { - if (editing_node._def.defaults.hasOwnProperty(d)) { - if (typeof editing_node[d] === "string" || typeof editing_node[d] === "number") { - oldValues[d] = editing_node[d]; - } else { - oldValues[d] = $.extend(true,{},{v:editing_node[d]}).v; - } - } - } - var rc = editing_node._def.oneditsave.call(editing_node); - if (rc === true) { - changed = true; - } - - for (d in editing_node._def.defaults) { - if (editing_node._def.defaults.hasOwnProperty(d)) { - if (oldValues[d] === null || typeof oldValues[d] === "string" || typeof oldValues[d] === "number") { - if (oldValues[d] !== editing_node[d]) { - changes[d] = oldValues[d]; - changed = true; - } - } else { - if (JSON.stringify(oldValues[d]) !== JSON.stringify(editing_node[d])) { - changes[d] = oldValues[d]; - changed = true; - } - } - } - } - } - - if (editing_node._def.defaults) { - for (d in editing_node._def.defaults) { - if (editing_node._def.defaults.hasOwnProperty(d)) { - var input = $("#node-input-"+d); - var newValue; - if (input.attr('type') === "checkbox") { - newValue = input.prop('checked'); - } else { - newValue = input.val(); - } - if (newValue != null) { - if (d === "outputs" && (newValue.trim() === "" || isNaN(newValue))) { - continue; - } - if (editing_node[d] != newValue) { - if (editing_node._def.defaults[d].type) { - if (newValue == "_ADD_") { - newValue = ""; - } - // Change to a related config node - var configNode = RED.nodes.node(editing_node[d]); - if (configNode) { - var users = configNode.users; - users.splice(users.indexOf(editing_node),1); - } - configNode = RED.nodes.node(newValue); - if (configNode) { - configNode.users.push(editing_node); - } - } - changes[d] = editing_node[d]; - editing_node[d] = newValue; - changed = true; - } - } - } - } - } - if (editing_node._def.credentials) { - var prefix = 'node-input'; - var credDefinition = editing_node._def.credentials; - var credsChanged = updateNodeCredentials(editing_node,credDefinition,prefix); - changed = changed || credsChanged; - } - - var removedLinks = updateNodeProperties(editing_node); - if (changed) { - var wasChanged = editing_node.changed; - editing_node.changed = true; - RED.nodes.dirty(true); - - var activeSubflow = RED.nodes.subflow(RED.workspaces.active()); - var subflowInstances = null; - if (activeSubflow) { - subflowInstances = []; - RED.nodes.eachNode(function(n) { - if (n.type == "subflow:"+RED.workspaces.active()) { - subflowInstances.push({ - id:n.id, - changed:n.changed - }); - n.changed = true; - n.dirty = true; - updateNodeProperties(n); - } - }); - } - var historyEvent = { - t:'edit', - node:editing_node, - changes:changes, - links:removedLinks, - dirty:wasDirty, - changed:wasChanged - }; - if (subflowInstances) { - historyEvent.subflow = { - instances:subflowInstances - } - } - RED.history.push(historyEvent); - } - editing_node.dirty = true; - validateNode(editing_node); - RED.view.redraw(true); - } - $( this ).dialog( "close" ); - } - }, - { - id: "node-dialog-cancel", - text: RED._("common.label.cancel"), - click: function() { - if (editing_node && editing_node._def) { - if (editing_node._def.oneditcancel) { - editing_node._def.oneditcancel.call(editing_node); - } - - for (var d in editing_node._def.defaults) { - if (editing_node._def.defaults.hasOwnProperty(d)) { - var def = editing_node._def.defaults[d]; - if (def.type) { - var configTypeDef = RED.nodes.getType(def.type); - if (configTypeDef && configTypeDef.exclusive) { - var input = $("#node-input-"+d).val()||""; - if (input !== "" && !editing_node[d]) { - // This node has an exclusive config node that - // has just been added. As the user is cancelling - // the edit, need to delete the just-added config - // node so that it doesn't get orphaned. - RED.nodes.remove(input); - } - } - } - } - - } - - - } - $( this ).dialog( "close" ); - } - } - ], - resize: function(e,ui) { - if (editing_node) { - $(this).dialog('option',"sizeCache-"+editing_node.type,ui.size); - if (editing_node._def.oneditresize) { - var form = $("#dialog-form"); - editing_node._def.oneditresize.call(editing_node,{width:form.width(),height:form.height()}); - } - } - }, - open: function(e) { - var minWidth = $(this).dialog('option','minWidth'); - if ($(this).outerWidth() < minWidth) { - $(this).dialog('option','width',minWidth); - } else { - $(this).dialog('option','width',$(this).outerWidth()); - } - RED.keyboard.disable(); - if (editing_node) { - var size = $(this).dialog('option','sizeCache-'+editing_node.type); - if (size) { - $(this).dialog('option','width',size.width); - $(this).dialog('option','height',size.height); - } - if (editing_node._def.oneditresize) { - setTimeout(function() { - var form = $("#dialog-form"); - editing_node._def.oneditresize.call(editing_node,{width:form.width(),height:form.height()}); - },0); - } - } - }, - close: function(e) { - RED.keyboard.enable(); - - if (RED.view.state() != RED.state.IMPORT_DRAGGING) { - RED.view.state(RED.state.DEFAULT); - } - $( this ).dialog('option','height','auto'); - $( this ).dialog('option','width','auto'); - if (editing_node) { - RED.sidebar.info.refresh(editing_node); - } - RED.workspaces.refresh(); - - var buttons = $( this ).dialog("option","buttons"); - if (buttons.length == 3) { - $( this ).dialog("option","buttons",buttons.splice(1)); - } - editing_node = null; - } - }).parent().on('keydown', function(evt) { - if (evt.keyCode === $.ui.keyCode.ESCAPE && (evt.metaKey || evt.ctrlKey)) { - $("#node-dialog-cancel").click(); - } else if (evt.keyCode === $.ui.keyCode.ENTER && (evt.metaKey || evt.ctrlKey)) { - $("#node-dialog-ok").click(); - } - }); - } + return; + }; /** * Create a config-node select box for this property @@ -622,7 +396,8 @@ RED.editor = (function() { } function showEditDialog(node) { - editing_node = node; + editStack.push({node:node}); + var editing_node = node; RED.view.state(RED.state.EDITING); var type = node.type; if (node.type.substring(0,8) == "subflow:") { @@ -639,34 +414,260 @@ RED.editor = (function() { }); $( "#dialog" ).dialog("option","buttons",buttons); } - $("#dialog-form").html($("script[data-template-name='"+type+"']").html()); - var ns; - if (node._def.set.module === "node-red") { - ns = "node-red"; - } else { - ns = node._def.set.id; - } - $("#dialog-form").find('[data-i18n]').each(function() { - var current = $(this).attr("data-i18n"); - var keys = current.split(";"); - for (var i=0;i').appendTo(trayBody); + dialogForm.html($("script[data-template-name='"+type+"']").html()); + var ns; + if (node._def.set.module === "node-red") { + ns = "node-red"; + } else { + ns = node._def.set.id; + } + dialogForm.find('[data-i18n]').each(function() { + var current = $(this).attr("data-i18n"); + var keys = current.split(";"); + for (var i=0;i').prependTo(dialogForm); + prepareEditDialog(node,node._def,"node-input"); + dialogForm.i18n(); + + // var minWidth = $(this).dialog('option','minWidth'); + // if ($(this).outerWidth() < minWidth) { + // $(this).dialog('option','width',minWidth); + // } else { + // $(this).dialog('option','width',$(this).outerWidth()); + // } + // if (editing_node) { + // var size = $(this).dialog('option','sizeCache-'+editing_node.type); + // if (size) { + // $(this).dialog('option','width',size.width); + // $(this).dialog('option','height',size.height); + // } + // if (editing_node._def.oneditresize) { + // setTimeout(function() { + // var form = $("#dialog-form"); + // editing_node._def.oneditresize.call(editing_node,{width:form.width(),height:form.height()}); + // },0); + // } + // } + }, + close: function() { + RED.keyboard.enable(); + if (RED.view.state() != RED.state.IMPORT_DRAGGING) { + RED.view.state(RED.state.DEFAULT); + } + if (editing_node) { + RED.sidebar.info.refresh(editing_node); + } + RED.workspaces.refresh(); + RED.tray.close(); + } + } + /*).parent().on('keydown', function(evt) { + if (evt.keyCode === $.ui.keyCode.ESCAPE && (evt.metaKey || evt.ctrlKey)) { + $("#node-dialog-cancel").click(); + } else if (evt.keyCode === $.ui.keyCode.ENTER && (evt.metaKey || evt.ctrlKey)) { + $("#node-dialog-ok").click(); } - $(this).attr("data-i18n",keys.join(";")); }); - $('').appendTo("#dialog-form"); - prepareEditDialog(node,node._def,"node-input"); - $("#dialog").i18n(); - $( "#dialog" ).dialog("option","title","Edit "+type+" node").dialog( "open" ); + */ + RED.tray.show(trayOptions); } function showEditConfigNodeDialog(name,type,id) { @@ -1163,7 +1164,6 @@ RED.editor = (function() { }); } - function showEditSubflowDialog(subflow) { editing_node = subflow; RED.view.state(RED.state.EDITING); @@ -1186,8 +1186,9 @@ RED.editor = (function() { return { - init: function(){ - createDialog(); + init: function() { + RED.tray.init(); + //createDialog(); createNodeConfigDialog(); createSubflowDialog(); }, diff --git a/editor/js/ui/sidebar.js b/editor/js/ui/sidebar.js index 2357eb9b3..3b3b2777b 100644 --- a/editor/js/ui/sidebar.js +++ b/editor/js/ui/sidebar.js @@ -102,13 +102,13 @@ RED.sidebar = (function() { sidebarSeparator.start = ui.position.left; sidebarSeparator.chartWidth = $("#workspace").width(); sidebarSeparator.chartRight = winWidth-$("#workspace").width()-$("#workspace").offset().left-2; - - + if (!RED.menu.isSelected("menu-item-sidebar")) { sidebarSeparator.opening = true; var newChartRight = 7; $("#sidebar").addClass("closing"); $("#workspace").css("right",newChartRight); + $("#editor-stack").css("right",newChartRight+1); $("#sidebar").width(0); RED.menu.setSelected("menu-item-sidebar",true); RED.events.emit("sidebar:resize"); @@ -147,6 +147,7 @@ RED.sidebar = (function() { var newChartRight = sidebarSeparator.chartRight-d; $("#workspace").css("right",newChartRight); + $("#editor-stack").css("right",newChartRight+1); $("#sidebar").width(newSidebarWidth); sidebar_tabs.resize(); @@ -159,6 +160,7 @@ RED.sidebar = (function() { if ($("#sidebar").width() < 180) { $("#sidebar").width(180); $("#workspace").css("right",187); + $("#editor-stack").css("right",188); } } $("#sidebar-separator").css("left","auto"); diff --git a/editor/js/ui/tray.js b/editor/js/ui/tray.js new file mode 100644 index 000000000..9b83986f9 --- /dev/null +++ b/editor/js/ui/tray.js @@ -0,0 +1,127 @@ +/** + * Copyright 2016 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.tray = (function() { + + var stack = []; + + function resize() { + + } + return { + init: function() { + $( window ).resize(function() { + if (stack.length > 0) { + var tray = stack[stack.length-1]; + var trayHeight = tray.tray.height()-tray.header.outerHeight()-tray.footer.outerHeight(); + tray.body.height(trayHeight-40); + + if (tray.options.resize) { + tray.options.resize(); + } + } + }); + + }, + show: function show(options) { + if (stack.length > 0) { + var oldTray = stack[stack.length-1]; + oldTray.tray.css({ + right: -(oldTray.tray.width()+10)+"px" + }); + setTimeout(function() { + oldTray.tray.detach(); + },400) + } + var el = $('
'); + var header = $('
'+(options.title||"")+'
').appendTo(el); + var body = $('
').appendTo(el); + var footer = $('').appendTo(el); + //'
'+ + // ''+ + // ''+ + if (options.buttons) { + for (var i=0;i').appendTo(footer); + if (button.id) { + b.attr('id',button.id); + } + if (button.text) { + b.text(button.text); + } + if (button.click) { + b.click(button.click); + } + } + } + el.appendTo("#editor-stack"); + var tray = { + tray: el, + header: header, + body: body, + footer: footer, + options: options + }; + if (options.open) { + options.open(body); + } + + $("#editor-shade").show(); + el.css({ + right: -(el.width()+10)+"px", + transition: "right 0.3s ease" + }); + $("#workspace").scrollLeft(0); + + stack.push(tray); + + setTimeout(function() { + var trayHeight = el.height()-header.outerHeight()-footer.outerHeight(); + body.height(trayHeight-40); + + if (options.resize) { + options.resize(); + } + el.css({right:0}); + },0); + }, + close: function close() { + if (stack.length > 0) { + var tray = stack.pop(); + tray.tray.css({ + right: -(tray.tray.width()+10)+"px" + }); + setTimeout(function() { + if (tray.options.close) { + tray.options.close(); + } + tray.tray.remove(); + if (stack.length > 0) { + var oldTray = stack[stack.length-1]; + oldTray.tray.appendTo("#editor-stack"); + setTimeout(function() { + oldTray.tray.css({right:0}); + },0); + } + },400) + if (stack.length === 0) { + $("#editor-shade").hide(); + } + } + } + } +})(); diff --git a/editor/sass/colors.scss b/editor/sass/colors.scss index e40a5b752..4d5c390d7 100644 --- a/editor/sass/colors.scss +++ b/editor/sass/colors.scss @@ -14,6 +14,8 @@ * limitations under the License. **/ +$background-color: #f3f3f3; + $form-placeholder-color: #bbbbbb; $form-text-color: #444; $form-input-focus-color: rgba(85,150,230,0.8); @@ -45,6 +47,8 @@ $workspace-button-color-hover: #666; $workspace-button-color-active: #666; $workspace-button-color-selected: #AAA; +$workspace-button-color-focus-outline: rgba(85,150,230,0.2); + $typedInput-button-background: #efefef; $typedInput-button-background-hover: #ddd; $typedInput-button-background-active: #e3e3e3; diff --git a/editor/sass/editor.scss b/editor/sass/editor.scss index fe1722bc1..59e2430f0 100644 --- a/editor/sass/editor.scss +++ b/editor/sass/editor.scss @@ -14,7 +14,7 @@ * limitations under the License. **/ -.dialog-form, #dialog-form, #dialog-config-form { +.dialog-form,#dialog-form, #dialog-config-form { margin: 0; height: 100%; } diff --git a/editor/sass/mixins.scss b/editor/sass/mixins.scss index 4c2eb5711..84c3ede58 100644 --- a/editor/sass/mixins.scss +++ b/editor/sass/mixins.scss @@ -62,10 +62,13 @@ background: $workspace-button-background-active; cursor: default; } - .button-group &:not(:first-child) { border-left: none; } + + &:focus { + outline: 1px solid $workspace-button-color-focus-outline; + } } @mixin workspace-button-toggle { @include workspace-button; diff --git a/editor/sass/sidebar.scss b/editor/sass/sidebar.scss index d188e3b71..f64dca97c 100644 --- a/editor/sass/sidebar.scss +++ b/editor/sass/sidebar.scss @@ -22,6 +22,7 @@ width: 315px; background: #fff; box-sizing: border-box; + z-index: 100; @include component-border; } @@ -46,13 +47,15 @@ right: 315px; bottom:10px; width: 7px; - background: url(images/grip.png) no-repeat 50% 50%; + z-index: 101; + background: $background-color url(images/grip.png) no-repeat 50% 50%; cursor: col-resize; } .sidebar-closed > #sidebar { display: none; } .sidebar-closed > #sidebar-separator { right: 0px !important; } .sidebar-closed > #workspace { right: 7px !important; } +.sidebar-closed > #editor-stack { right: 8px !important; } #sidebar .button { @include workspace-button; diff --git a/editor/sass/style.scss b/editor/sass/style.scss index 08b90bd4b..19c89f188 100644 --- a/editor/sass/style.scss +++ b/editor/sass/style.scss @@ -52,7 +52,7 @@ body { font-size: 14px; font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif; padding-top: 100px; - background: #f3f3f3; + background: $background-color; } #main-container { diff --git a/editor/sass/workspace.scss b/editor/sass/workspace.scss index bb7126874..4d7b0d74b 100644 --- a/editor/sass/workspace.scss +++ b/editor/sass/workspace.scss @@ -50,6 +50,64 @@ margin-right: 35px; } +#editor-stack { + position: absolute; + margin: 0; + top: 0; + bottom: 0px; + right: 323px; + width: 0; +} +.editor-tray { + position:absolute; + margin: 0; + top: 0; + min-width: 500px; + width: auto; + right: -1000px; + bottom: 0; + background: #fff; + border-left: 1px solid $primary-border-color; + border-bottom: 1px solid $primary-border-color; + box-sizing: content-box; + box-shadow: -1px 0 10px rgba(0,0,0,0.1); +} +.editor-tray.open { + right: 0; +} +.editor-tray-body { + width: auto; + padding: 20px; + min-width: 500px; + box-sizing: border-box; + overflow-y: scroll; +} +.editor-tray-header { + padding: 10px; + box-sizing: border-box; + font-weight: bold; + height: 40px; + border-bottom: 1px solid $primary-border-color; + background: $palette-header-background; +} +.editor-tray-footer { + @include component-footer; + height: auto; + padding: 8px; + button { + @include workspace-button; + padding: 0.4em 1em; + } + +} +#editor-shade { + position: absolute; + top:0; + bottom:0; + left:0; + right:0; + background: rgba(220,220,220,0.5); +} #workspace-add-tab { position: absolute; box-sizing: border-box; diff --git a/editor/templates/index.mst b/editor/templates/index.mst index 7344befcc..e50f10979 100644 --- a/editor/templates/index.mst +++ b/editor/templates/index.mst @@ -65,6 +65,19 @@ +
+
+ +