From 5938143002b31e4877ae909476c36e6ae9016a4a Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Fri, 28 Apr 2017 20:49:01 +0100 Subject: [PATCH] Move view and keyboard into user settings dialog --- editor/js/main.js | 12 +- editor/js/ui/actions.js | 2 +- editor/js/ui/common/editableList.js | 2 +- editor/js/ui/common/menu.js | 22 +- editor/js/ui/common/tabs.js | 6 + editor/js/ui/keyboard.js | 318 +++++++++++++++++++++------- editor/js/ui/tab-info.js | 4 +- editor/js/ui/userSettings.js | 129 ++++++++++- editor/js/ui/view.js | 49 ++++- editor/sass/editor.scss | 1 + editor/sass/keyboard.scss | 83 +++++++- editor/sass/mixins.scss | 18 +- editor/sass/style.scss | 2 + editor/sass/tabs.scss | 44 ++++ editor/sass/userSettings.scss | 59 ++++++ red/api/locales/en-US/editor.json | 4 +- red/api/locales/en-US/infotips.json | 12 +- 17 files changed, 643 insertions(+), 124 deletions(-) create mode 100644 editor/sass/userSettings.scss diff --git a/editor/js/main.js b/editor/js/main.js index 8af2c7a35..59ec5e814 100644 --- a/editor/js/main.js +++ b/editor/js/main.js @@ -171,10 +171,10 @@ function loadEditor() { var menuOptions = []; menuOptions.push({id:"menu-item-view-menu",label:RED._("menu.label.view.view"),options:[ - {id:"menu-item-view-show-grid",label:RED._("menu.label.view.showGrid"),toggle:true,onselect:"core:toggle-show-grid"}, - {id:"menu-item-view-snap-grid",label:RED._("menu.label.view.snapGrid"),toggle:true,onselect:"core:toggle-snap-grid"}, - {id:"menu-item-status",label:RED._("menu.label.displayStatus"),toggle:true,onselect:"core:toggle-status", selected: true}, - null, + // {id:"menu-item-view-show-grid",setting:"view-show-grid",label:RED._("menu.label.view.showGrid"),toggle:true,onselect:"core:toggle-show-grid"}, + // {id:"menu-item-view-snap-grid",setting:"view-snap-grid",label:RED._("menu.label.view.snapGrid"),toggle:true,onselect:"core:toggle-snap-grid"}, + // {id:"menu-item-status",setting:"node-show-status",label:RED._("menu.label.displayStatus"),toggle:true,onselect:"core:toggle-status", selected: true}, + //null, // {id:"menu-item-bidi",label:RED._("menu.label.view.textDir"),options:[ // {id:"menu-item-bidi-default",toggle:"text-direction",label:RED._("menu.label.view.defaultDir"),selected: true, onselect:function(s) { if(s){RED.text.bidi.setTextDirection("")}}}, // {id:"menu-item-bidi-ltr",toggle:"text-direction",label:RED._("menu.label.view.ltr"), onselect:function(s) { if(s){RED.text.bidi.setTextDirection("ltr")}}}, @@ -182,7 +182,8 @@ // {id:"menu-item-bidi-auto",toggle:"text-direction",label:RED._("menu.label.view.auto"), onselect:function(s) { if(s){RED.text.bidi.setTextDirection("auto")}}} // ]}, // null, - {id:"menu-item-sidebar",label:RED._("menu.label.sidebar.show"),toggle:true,onselect:"core:toggle-sidebar", selected: true} + {id:"menu-item-sidebar",label:RED._("menu.label.sidebar.show"),toggle:true,onselect:"core:toggle-sidebar", selected: true}, + null ]}); menuOptions.push(null); menuOptions.push({id:"menu-item-import",label:RED._("menu.label.import"),options:[ @@ -217,7 +218,6 @@ menuOptions.push(null); menuOptions.push({id:"menu-item-keyboard-shortcuts",label:RED._("menu.label.keyboardShortcuts"),onselect:"core:show-help"}); - menuOptions.push({id:"menu-item-show-tips",label:RED._("menu.label.showTips"),toggle:true,selected:true,onselect:"core:toggle-show-tips"}); menuOptions.push({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") diff --git a/editor/js/ui/actions.js b/editor/js/ui/actions.js index 78b9a4c99..a56069579 100644 --- a/editor/js/ui/actions.js +++ b/editor/js/ui/actions.js @@ -21,7 +21,7 @@ RED.actions = (function() { var result = []; Object.keys(actions).forEach(function(action) { var shortcut = RED.keyboard.getShortcut(action); - result.push({id:action,scope:shortcut?shortcut.scope:undefined,key:shortcut?shortcut.key:undefined}) + result.push({id:action,scope:shortcut?shortcut.scope:undefined,key:shortcut?shortcut.key:undefined,user:shortcut?shortcut.user:undefined}) }) return result; } diff --git a/editor/js/ui/common/editableList.js b/editor/js/ui/common/editableList.js index 33c5c9843..437da24e5 100644 --- a/editor/js/ui/common/editableList.js +++ b/editor/js/ui/common/editableList.js @@ -170,7 +170,7 @@ var that = this; var count = 0; if (!this.activeFilter) { - this.element.children().show(); + return this.element.children().show(); } var items = this.items(); items.each(function (i,el) { diff --git a/editor/js/ui/common/menu.js b/editor/js/ui/common/menu.js index 89a783883..6f803a659 100644 --- a/editor/js/ui/common/menu.js +++ b/editor/js/ui/common/menu.js @@ -28,7 +28,17 @@ RED.menu = (function() { } function setInitialState() { - var savedStateActive = isSavedStateActive(opt.id); + var savedStateActive = RED.settings.get("menu-" + opt.id); + if (opt.setting) { + // May need to migrate pre-0.17 setting + + if (savedStateActive !== null) { + RED.settings.set(opt.setting,savedStateActive); + RED.settings.remove("menu-" + opt.id); + } else { + savedStateActive = RED.settings.get(opt.setting); + } + } if (savedStateActive) { link.addClass("active"); triggerAction(opt.id,true); @@ -176,18 +186,10 @@ RED.menu = (function() { } } - function isSavedStateActive(id) { - return RED.settings.get("menu-" + id); - } - function isSelected(id) { return $("#" + id).hasClass("active"); } - function setSavedState(id, state) { - RED.settings.set("menu-" + id, state); - } - function setSelected(id,state) { if (isSelected(id) == state) { return; @@ -201,7 +203,7 @@ RED.menu = (function() { if (opt && opt.onselect) { triggerAction(opt.id,state); } - setSavedState(id, state); + RED.settings.set(opt.setting||("menu-"+opt.id), state); } function toggleSelected(id) { diff --git a/editor/js/ui/common/tabs.js b/editor/js/ui/common/tabs.js index ab5460e0a..d5e0c95b8 100644 --- a/editor/js/ui/common/tabs.js +++ b/editor/js/ui/common/tabs.js @@ -26,6 +26,9 @@ RED.tabs = (function() { var wrapper = ul.wrap( "
" ).parent(); var scrollContainer = ul.wrap( "
" ).parent(); wrapper.addClass("red-ui-tabs"); + if (options.vertical) { + wrapper.addClass("red-ui-tabs-vertical"); + } if (options.addButton && typeof options.addButton === 'function') { wrapper.addClass("red-ui-tabs-add"); var addButton = $('
').appendTo(wrapper); @@ -146,6 +149,9 @@ RED.tabs = (function() { } function updateTabWidths() { + if (options.vertical) { + return; + } var tabs = ul.find("li.red-ui-tab"); var width = wrapper.width(); var tabCount = tabs.size(); diff --git a/editor/js/ui/keyboard.js b/editor/js/ui/keyboard.js index 9d4a56466..f645b3b55 100644 --- a/editor/js/ui/keyboard.js +++ b/editor/js/ui/keyboard.js @@ -48,6 +48,7 @@ RED.keyboard = (function() { 93: true } var actionToKeyMap = {} + var defaultKeyMap = {}; // FF generates some different keycodes because reasons. var firefoxKeyCodeMap = { @@ -57,20 +58,45 @@ RED.keyboard = (function() { } function init() { + var userKeymap = RED.settings.get('keymap') || {}; $.getJSON("red/keymap.json",function(data) { for (var scope in data) { if (data.hasOwnProperty(scope)) { var keys = data[scope]; for (var key in keys) { if (keys.hasOwnProperty(key)) { - addHandler(scope,key,keys[key]); + if (!userKeymap.hasOwnProperty(keys[key])) { + addHandler(scope,key,keys[key],false); + defaultKeyMap[keys[key]] = { + scope:scope, + key:key, + user:false + }; + } } } } } + for (var action in userKeymap) { + if (userKeymap.hasOwnProperty(action)) { + var obj = userKeymap[action]; + if (obj.hasOwnProperty('key')) { + addHandler(obj.scope, obj.key, action, true); + } + } + } }) - RED.actions.add("core:show-help", showKeyboardHelp); + } + function revertToDefault(action) { + var currentAction = actionToKeyMap[action]; + if (currentAction) { + removeHandler(currentAction.key); + } + if (defaultKeyMap.hasOwnProperty(action)) { + var obj = defaultKeyMap[action]; + addHandler(obj.scope, obj.key, action, false); + } } function parseKeySpecifier(key) { var parts = key.toLowerCase().split("-"); @@ -126,10 +152,12 @@ RED.keyboard = (function() { if (partialState) { partialState = null; return resolveKeyEvent(evt); - } else { + } else if (Object.keys(handler).length > 0) { partialState = handler; evt.preventDefault(); return null; + } else { + return null; } } else if (handler.scope && handler.scope !== "*") { var target = evt.target; @@ -174,6 +202,9 @@ RED.keyboard = (function() { if (typeof key === 'string') { if (typeof cbdown === 'string') { actionToKeyMap[cbdown] = {scope:scope,key:key}; + if (typeof ondown === 'boolean') { + actionToKeyMap[cbdown].user = ondown; + } } var parts = key.split(" "); for (i=0;i'; - function showKeyboardHelp() { - if (!RED.settings.theme("menu.menu-item-keyboard-shortcuts",true)) { - return; - } - if (!shortcutDialog) { - shortcutDialog = $('
'+ - '
'+ - '
shortcut
'+ - '
action
'+ - '
scope
'+ - '
'+ - '
    '+ - '
    ') - .appendTo("body"); - - var shortcutList = $('#keyboard-shortcut-list').editableList({ - addButton: false, - scrollOnAdd: false, - addItem: function(container,i,object) { - var item = $('
    ').appendTo(container); - - var key = $('
    ').appendTo(item); - if (object.key) { - key.append(formatKey(object.key)); - } else { - item.addClass("keyboard-shortcut-entry-unassigned"); - key.html(RED._('keyboard.unassigned')); - } - - var text = object.id.replace(/(^.+:([a-z]))|(-([a-z]))/g,function() { - if (arguments[5] === 0) { - return arguments[2].toUpperCase(); - } else { - return " "+arguments[4].toUpperCase(); - } - }); - var label = $('
    ').html(text).appendTo(item); - if (object.scope) { - $('
    ').html(object.scope).appendTo(item); - } - - - }, - }); - var shortcuts = RED.actions.list(); - shortcuts.sort(function(A,B) { - return A.id.localeCompare(B.id); - }); - shortcuts.forEach(function(s) { - shortcutList.editableList('addItem',s); - }) - - shortcutDialog.dialog({ - modal: true, - autoOpen: false, - width: "800", - height: "400", - title:RED._("keyboard.title"), - resizable: false - }); - } - - shortcutDialog.dialog("open"); - } function formatKey(key) { var formattedKey = isMac?key.replace(/ctrl-?/,"⌘"):key; formattedKey = isMac?formattedKey.replace(/alt-?/,"⌥"):key; @@ -332,6 +303,206 @@ RED.keyboard = (function() { return ''+formattedKey.split(" ").join(' ')+''; } + function validateKey(key) { + key = key.trim(); + var parts = key.split(" "); + for (i=0;i').attr('placeholder',RED._('keyboard.unassigned')).val(object.key||"").appendTo(key); + keyInput.on("keyup",function(e) { + if (e.keyCode === 13) { + return endEditShortcut(); + } + var currentVal = $(this).val(); + currentVal = currentVal.trim(); + var valid = (currentVal === "" || RED.keyboard.validateKey(currentVal)); + $(this).toggleClass("input-error",!valid); + }) + + var scopeSelect = $('').appendTo(scope); + scopeSelect.val(object.scope||'*'); + + var div = $('
    ').appendTo(scope); + var okButton = $('').appendTo(div); + var revertButton = $('').appendTo(div); + + okButton.click(function(e) { + e.stopPropagation(); + endEditShortcut(); + }); + revertButton.click(function(e) { + e.stopPropagation(); + RED.keyboard.revertToDefault(object.id); + container.empty(); + container.removeClass('keyboard-shortcut-entry-expanded'); + var shortcut = RED.keyboard.getShortcut(object.id); + var userKeymap = RED.settings.get('keymap') || {}; + delete userKeymap[object.id]; + RED.settings.set('keymap',userKeymap); + + var obj = { + id:object.id, + scope:shortcut?shortcut.scope:undefined, + key:shortcut?shortcut.key:undefined, + user:shortcut?shortcut.user:undefined + } + buildShortcutRow(container,obj); + }) + + keyInput.focus(); + } + } + + function endEditShortcut(cancel) { + var container = $('.keyboard-shortcut-entry-expanded'); + if (container.length === 1) { + var object = container.data('data'); + var keyInput = container.find(".keyboard-shortcut-entry-key input"); + var scopeSelect = container.find(".keyboard-shortcut-entry-scope select"); + if (!cancel) { + var key = keyInput.val().trim(); + var scope = scopeSelect.val(); + var valid = (key === "" || RED.keyboard.validateKey(key)); + if (valid) { + var current = RED.keyboard.getShortcut(object.id); + if ((!current && key) || (current && (current.scope !== scope || current.key !== key))) { + var keyDiv = container.find(".keyboard-shortcut-entry-key"); + var scopeDiv = container.find(".keyboard-shortcut-entry-scope"); + keyDiv.empty(); + scopeDiv.empty(); + if (object.key) { + RED.keyboard.remove(object.key,true); + } + container.find(".keyboard-shortcut-entry-text i").css("opacity",1); + if (key === "") { + keyDiv.parent().addClass("keyboard-shortcut-entry-unassigned"); + keyDiv.append($('').text(RED._('keyboard.unassigned')) ); + delete object.key; + delete object.scope; + } else { + keyDiv.parent().removeClass("keyboard-shortcut-entry-unassigned"); + keyDiv.append(RED.keyboard.formatKey(key)) + $("").text(scope).appendTo(scopeDiv); + object.key = key; + object.scope = scope; + RED.keyboard.add(object.scope,object.key,object.id,true); + } + var userKeymap = RED.settings.get('keymap') || {}; + userKeymap[object.id] = RED.keyboard.getShortcut(object.id); + RED.settings.set('keymap',userKeymap); + } + } + } + keyInput.remove(); + scopeSelect.remove(); + $('.keyboard-shortcut-edit').remove(); + container.removeClass('keyboard-shortcut-entry-expanded'); + } + } + + function buildShortcutRow(container,object) { + var item = $('
    ').appendTo(container); + container.data('data',object); + + var text = object.id.replace(/(^.+:([a-z]))|(-([a-z]))/g,function() { + if (arguments[5] === 0) { + return arguments[2].toUpperCase(); + } else { + return " "+arguments[4].toUpperCase(); + } + }); + var label = $('
    ').addClass("keyboard-shortcut-entry-text").text(text).appendTo(item); + + var user = $('').prependTo(label); + + if (!object.user) { + user.css("opacity",0); + } + + var key = $('
    ').appendTo(item); + if (object.key) { + key.append(RED.keyboard.formatKey(object.key)); + } else { + item.addClass("keyboard-shortcut-entry-unassigned"); + key.append($('').text(RED._('keyboard.unassigned')) ); + } + + var scope = $('
    ').appendTo(item); + + $("").text(object.scope === '*'?'global':object.scope||"").appendTo(scope); + container.click(editShortcut); + } + + function getSettingsPane() { + var pane = $('
    '); + + $('
    '+ + '
    '+ + '
    shortcut
    '+ + '
    scope
    '+ + '
    ').appendTo(pane); + + pane.find("input").searchBox({ + delay: 100, + change: function() { + var filterValue = $(this).val().trim(); + if (filterValue === "") { + shortcutList.editableList('filter', null); + } else { + filterValue = filterValue.replace(/\s/g,""); + shortcutList.editableList('filter', function(data) { + return data.id.toLowerCase().replace(/^.*:/,"").replace("-","").indexOf(filterValue) > -1; + }) + } + } + }); + + var shortcutList = $('
      ').css({ + position: "absolute", + top: "32px", + bottom: "0", + left: "0", + right: "0" + }).appendTo(pane).editableList({ + addButton: false, + scrollOnAdd: false, + addItem: function(container,i,object) { + buildShortcutRow(container,object); + }, + + }); + var shortcuts = RED.actions.list(); + shortcuts.sort(function(A,B) { + var Aid = A.id.replace(/^.*:/,"").replace(/[ -]/g,"").toLowerCase(); + var Bid = B.id.replace(/^.*:/,"").replace(/[ -]/g,"").toLowerCase(); + return Aid.localeCompare(Bid); + }); + shortcuts.forEach(function(s) { + shortcutList.editableList('addItem',s); + }); + return pane; + } + return { init: init, add: addHandler, @@ -339,7 +510,10 @@ RED.keyboard = (function() { getShortcut: function(actionName) { return actionToKeyMap[actionName]; }, - formatKey: formatKey + revertToDefault: revertToDefault, + formatKey: formatKey, + validateKey: validateKey, + getSettingsPane: getSettingsPane } })(); diff --git a/editor/js/ui/tab-info.js b/editor/js/ui/tab-info.js index be97a7da9..1210b8449 100644 --- a/editor/js/ui/tab-info.js +++ b/editor/js/ui/tab-info.js @@ -74,7 +74,7 @@ RED.sidebar.info = (function() { tipClose.click(function(e) { e.preventDefault(); RED.actions.invoke("core:toggle-show-tips"); - RED.notify("You can re-open the tips from the side menu"); + RED.notify(RED._("sidebar.info.showTips")); }); RED.sidebar.addTab({ @@ -267,7 +267,7 @@ RED.sidebar.info = (function() { RED.actions.add("core:toggle-show-tips",function(state) { if (state === undefined) { - RED.menu.toggleSelected("menu-item-show-tips"); + RED.userSettings.toggle("view-show-tips"); } else { enabled = state; if (enabled) { diff --git a/editor/js/ui/userSettings.js b/editor/js/ui/userSettings.js index 393422c93..1a43de726 100644 --- a/editor/js/ui/userSettings.js +++ b/editor/js/ui/userSettings.js @@ -16,14 +16,15 @@ RED.userSettings = (function() { - var trayWidth = null; + var trayWidth = 700; var settingsVisible = false; - function show() { + function show(initialTab) { if (settingsVisible) { return; } settingsVisible = true; + var tabContainer; var trayOptions = { title: "User Settings", @@ -42,17 +43,20 @@ RED.userSettings = (function() { }, open: function(tray) { var trayBody = tray.find('.editor-tray-body'); + var tabContainer = $('
      ',{id:"user-settings-tabs-container"}).appendTo(trayBody); - $('
        ',{id:"user-settings-tabs"}).appendTo(trayBody); + $('
          ',{id:"user-settings-tabs"}).appendTo(tabContainer); var tabContents = $('
          ',{id:"user-settings-tabs-content"}).appendTo(trayBody); - $('
          View Tab
          ').appendTo(tabContents); - $('
          Keyboard Tab
          ').appendTo(tabContents); - $('
          Something Tab
          ').appendTo(tabContents); + createViewPane().hide().appendTo(tabContents); + RED.keyboard.getSettingsPane().hide().appendTo(tabContents); + + $('
          ').appendTo(tabContents); var tabs = RED.tabs.create({ id: "user-settings-tabs", + vertical: true, onchange: function(tab) { $("#user-settings-tabs-content").children().hide(); $("#" + tab.id).show(); @@ -64,15 +68,31 @@ RED.userSettings = (function() { }); tabs.addTab({ id: "user-settings-tab-keyboard", - label: "Keyboard Shortcuts" + label: "Keyboard" }); tabs.addTab({ - id: "user-settings-tab-something", - label: "Something Else" + id: "user-settings-tab-palette", + label: "Palette" }); + if (initialTab) { + tabs.activateTab("user-settings-tab-"+initialTab) + } }, close: function() { settingsVisible = false; + + viewSettings.forEach(function(section) { + section.options.forEach(function(opt) { + var input = $("#user-settings-"+opt.setting); + if (opt.toggle) { + setSelected(opt.setting,input.prop('checked')); + } else { + setSelected(opt.setting,input.val()); + } + }); + }) + + }, show: function() {} } @@ -82,10 +102,99 @@ RED.userSettings = (function() { RED.tray.show(trayOptions); } + var viewSettings = [ + { + title: "Grid", + options: [ + {setting:"view-show-grid",label:"menu.label.view.showGrid",toggle:true,onchange:"core:toggle-show-grid"}, + {setting:"view-snap-grid",label:"menu.label.view.snapGrid",toggle:true,onchange:"core:toggle-snap-grid"}, + {setting:"view-grid-size",label:"menu.label.view.gridSize",type:"number",default: 20, onchange:RED.view.gridSize} + ] + }, + { + title: "Nodes", + options: [ + {setting:"view-node-status",label:"menu.label.displayStatus",toggle:true,onchange:"core:toggle-status", selected: true} + ] + }, + { + title: "Other", + options: [ + {setting:"view-show-tips",label:"menu.label.showTips",toggle:true,default:true,onchange:"core:toggle-show-tips"} + ] + } + ]; + + var allSettings = {}; + + function createViewPane() { + + var pane = $('
          '); + + viewSettings.forEach(function(section) { + $('

          ').text(section.title).appendTo(pane); + section.options.forEach(function(opt) { + var initialState = RED.settings.get(opt.setting); + var row = $('').appendTo(pane); + var input; + if (opt.toggle) { + input = $('').appendTo(row).find("input"); + input.prop('checked',initialState); + } else { + $('').appendTo(row); + $('').appendTo(row).val(initialState); + } + }); + }) + return pane; + } + + function setSelected(id, value) { + var opt = allSettings[id]; + RED.settings.set(opt.setting,value); + var callback = opt.onchange; + if (typeof callback === 'string') { + callback = RED.actions.get(callback); + } + if (callback) { + callback.call(opt,value); + } + } + function toggle(id) { + var opt = allSettings[id]; + var state = RED.settings.get(opt.setting); + setSelected(id,!state); + } + + function init() { RED.actions.add("core:show-user-settings",show); + RED.actions.add("core:show-help", function() { show('keyboard')}); + + viewSettings.forEach(function(section) { + section.options.forEach(function(opt) { + allSettings[opt.setting] = opt; + if (opt.onchange) { + var value = RED.settings.get(opt.setting); + if (value === null && opt.hasOwnProperty('default')) { + value = opt.default; + RED.settings.set(opt.setting,value); + } + + var callback = opt.onchange; + if (typeof callback === 'string') { + callback = RED.actions.get(callback); + } + if (callback) { + callback.call(opt,value); + } + } + }); + }); + } return { - init: init + init: init, + toggle: toggle }; })(); diff --git a/editor/js/ui/view.js b/editor/js/ui/view.js index b67a91d0a..926503639 100644 --- a/editor/js/ui/view.js +++ b/editor/js/ui/view.js @@ -239,6 +239,41 @@ RED.view = (function() { }); grid.style("visibility","hidden"); + updateGrid(); + + function updateGrid() { + grid.selectAll("line.horizontal").remove(); + grid.selectAll("line.horizontal").data(gridScale.ticks(space_width/gridSize)).enter() + .append("line") + .attr( + { + "class":"horizontal", + "x1" : 0, + "x2" : space_width, + "y1" : function(d){ return gridScale(d);}, + "y2" : function(d){ return gridScale(d);}, + "fill" : "none", + "shape-rendering" : "crispEdges", + "stroke" : "#eee", + "stroke-width" : "1px" + }); + grid.selectAll("line.vertical").remove(); + grid.selectAll("line.vertical").data(gridScale.ticks(space_width/gridSize)).enter() + .append("line") + .attr( + { + "class":"vertical", + "y1" : 0, + "y2" : space_width, + "x1" : function(d){ return gridScale(d);}, + "x2" : function(d){ return gridScale(d);}, + "fill" : "none", + "shape-rendering" : "crispEdges", + "stroke" : "#eee", + "stroke-width" : "1px" + }); + } + var dragGroup = vis.append("g"); var drag_lines = []; @@ -408,21 +443,21 @@ RED.view = (function() { RED.actions.add("core:toggle-show-grid",function(state) { if (state === undefined) { - RED.menu.toggleSelected("menu-item-view-show-grid"); + RED.userSettings.toggle("view-show-grid"); } else { toggleShowGrid(state); } }); RED.actions.add("core:toggle-snap-grid",function(state) { if (state === undefined) { - RED.menu.toggleSelected("menu-item-view-snap-grid"); + RED.userSettings.toggle("view-snap-grid"); } else { toggleSnapGrid(state); } }); RED.actions.add("core:toggle-status",function(state) { if (state === undefined) { - RED.menu.toggleSelected("menu-item-status"); + RED.userSettings.toggle("view-node-status"); } else { toggleStatus(state); } @@ -2743,6 +2778,14 @@ RED.view = (function() { RED.sidebar.config.show(id); } } + }, + gridSize: function(v) { + if (v === undefined) { + return gridSize; + } else { + gridSize = v; + updateGrid(); + } } }; diff --git a/editor/sass/editor.scss b/editor/sass/editor.scss index 499b33a8e..01ca54bca 100644 --- a/editor/sass/editor.scss +++ b/editor/sass/editor.scss @@ -46,6 +46,7 @@ overflow: auto; } .editor-tray-body { + position: relative; form { margin: 20px; } diff --git a/editor/sass/keyboard.scss b/editor/sass/keyboard.scss index e272b238a..27eca649f 100644 --- a/editor/sass/keyboard.scss +++ b/editor/sass/keyboard.scss @@ -19,31 +19,88 @@ padding-top: 10px; } + +#user-settings-tab-keyboard .red-ui-editableList-container { + border-radius: 0; + border: none; + padding: 0; +} + + .keyboard-shortcut-entry.keyboard-shortcut-list-header { - padding:0 30px 0 5px; + padding:0 5px 0 5px; div { color: #666 !important; } + .red-ui-searchBox-container { + width: calc(100% - 20px); + } + .keyboard-shortcut-entry-scope { + text-align: center; + } } -#keyboard-shortcut-list { + +.keyboard-shortcut-list-header { + border-bottom: 1px solid $primary-border-color; + +} +.keyboard-shortcut-list { position: absolute; top:30px; left:10px; right:10px; bottom:10px; + li { + padding: 0; + .red-ui-editableList-item-content { + padding: 8px; + cursor: pointer; + } + } + li:hover { + background: #f6f6f6; + } } .keyboard-shortcut-entry { - padding: 0px 20px 0 10px; div { display: inline-block; } + // white-space: nowrap; + + select { + margin: 0; + width: calc(100% - 30px); + font-size: 0.9em; + margin-right: 5px; + } } .keyboard-shortcut-entry-key { - width:150px; + width:160px; + vertical-align: middle; + input { + margin:0; + width: calc(100% - 5px); + } +} +.keyboard-shortcut-entry-text { + vertical-align: middle; + width: calc(100% - 160px - 100px - 10px); + overflow: hidden; + i { + color: #ccc; + margin-right: 5px; + } } .keyboard-shortcut-entry-scope { - float: right; + width:100px; color: #999; + vertical-align: middle; + text-align: right; +} +.keyboard-shortcut-entry:not(.keyboard-shortcut-list-header) { + .keyboard-shortcut-entry-scope { + font-size: 0.8em; + } } .keyboard-shortcut-entry-unassigned { color: #999; @@ -51,7 +108,21 @@ font-style: italic; } } - +.keyboard-shortcut-entry-expanded { + .keyboard-shortcut-entry-key { + width: 150px; + } + .keyboard-shortcut-entry-text { + } + .keyboard-shortcut-entry-scope { + width: 110px; + } + span { + display: none; + } +} +.keyboard-shortcut-edit { +} .help-key { border: 1px solid #ddd; padding: 4px; diff --git a/editor/sass/mixins.scss b/editor/sass/mixins.scss index 9896cb102..e817ec40b 100644 --- a/editor/sass/mixins.scss +++ b/editor/sass/mixins.scss @@ -80,12 +80,28 @@ border-top-right-radius: 0; border-bottom-right-radius: 0; } + .button-group-vertical & { + display: block; + min-width: 22px; + } + .button-group-vertical &:not(:first-child) { + border-top: none; + border-top-left-radius: 0; + border-top-right-radius: 0; + } + .button-group-vertical &:not(:last-child) { + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; + } &:focus { outline: 1px solid $workspace-button-color-focus-outline; } } - +.button-group-vertical { + display: inline-block; + vertical-align: middle; +} .button-group:not(:last-child) { margin-right: 10px; } diff --git a/editor/sass/style.scss b/editor/sass/style.scss index f6b267e7b..c8022a6f8 100644 --- a/editor/sass/style.scss +++ b/editor/sass/style.scss @@ -45,6 +45,8 @@ @import "palette-editor"; @import "diff"; +@import "userSettings"; + @import "ui/common/editableList"; @import "ui/common/searchBox"; diff --git a/editor/sass/tabs.scss b/editor/sass/tabs.scss index 636dabd51..4b2dc7f5d 100644 --- a/editor/sass/tabs.scss +++ b/editor/sass/tabs.scss @@ -113,6 +113,50 @@ &.red-ui-tabs-add.red-ui-tabs-scrollable { padding-right: 59px; } + + &.red-ui-tabs-vertical { + box-sizing: border-box; + height: 100%; + border-right: 1px solid $primary-border-color; + margin: 0; + background: #f3f3f3; + overflow: visible; + + .red-ui-tabs-scroll-container { + height: auto; + overflow-x:visible; + overflow-y: scroll; + } + + & ul { + padding: 0; + height: auto; + border: none; + width: calc(100% + 1px); + li { + width: 100%; + display: block; + margin: 0; + border: none; + border-right: 1px solid $primary-border-color; + height: auto; + &:not(:first-child) { + border-top: 1px solid $secondary-border-color; + } + &:last-child { + border-bottom: 1px solid $secondary-border-color; + } + + a.red-ui-tab-label { + padding: 9px; + } + + &.active { + border-right: 1px solid #fff; + } + } + } + } } .red-ui-tab-button { position: absolute; diff --git a/editor/sass/userSettings.scss b/editor/sass/userSettings.scss new file mode 100644 index 000000000..0fe07409e --- /dev/null +++ b/editor/sass/userSettings.scss @@ -0,0 +1,59 @@ +/** + * Copyright JS Foundation and other contributors, http://js.foundation + * + * 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. + **/ + +#user-settings-tabs-container { + position: absolute; + top: 0; + left: 0; + bottom: 0; + width: 120px; + background: #f3f3f3; +} +#user-settings-tabs-content { + position: absolute; + top: 0; + left: 120px; + right: 0; + bottom: 0; + padding: 0; + h3:not(:first-child) { + border-top: 1px solid $secondary-border-color; + margin-top: 15px; + margin-bottom: 10px; + padding-top: 20px; + } + label { + display: inline-block; + min-width: 100px; + input { + vertical-align: top; + padding-bottom: 0; + } + } + input { + margin-bottom: 0; + } + input[type='number'] { + width: 60px; + } +} + +#user-settings-tab-view { + padding: 8px 20px 20px; +} +.user-settings-row { + padding: 5px 10px 2px; +} diff --git a/red/api/locales/en-US/editor.json b/red/api/locales/en-US/editor.json index 4084b1cea..c572ed4b0 100644 --- a/red/api/locales/en-US/editor.json +++ b/red/api/locales/en-US/editor.json @@ -31,6 +31,7 @@ "view": "View", "showGrid": "Show grid", "snapGrid": "Snap to grid", + "gridSize": "Grid size", "textDir": "Text Direction", "defaultDir": "Default", "ltr": "Left-to-right", @@ -354,7 +355,8 @@ "info": "Information", "blank": "blank", "null": "null", - "arrayItems": "__count__ items" + "arrayItems": "__count__ items", + "showTips":"You can open the tips from the settings panel" }, "config": { "name": "Configuration nodes", diff --git a/red/api/locales/en-US/infotips.json b/red/api/locales/en-US/infotips.json index 46ce4502c..1f3a4f9a0 100644 --- a/red/api/locales/en-US/infotips.json +++ b/red/api/locales/en-US/infotips.json @@ -5,7 +5,7 @@ "tip2" : "{{core:toggle-sidebar}} will toggle the view of this sidebar", "tip3" : "You can manage your palette of nodes with {{core:manage-palette}}", "tip4" : "Your flow configuration nodes are listed in the sidebar panel. It can been accessed from the menu or with {{core:show-config-tab}}", - "tip5" : "Enable or disable these tips from the option in the menu", + "tip5" : "Enable or disable these tips from the option in the settings", "tip6" : "Move the selected nodes using the [left] [up] [down] and [right] keys. Hold [shift] to nudge them further", "tip7" : "Dragging a node onto a wire will splice it into the link", "tip8" : "Export the selected nodes, or the current tab with {{core:show-export-dialog}}", @@ -19,15 +19,5 @@ "tip16" : "Switch flow tabs with {{core:show-previous-tab}} and {{core:show-next-tab}}", "tip17" : "You can confirm your changes in the node edit tray with {{core:confirm-edit-tray}} or cancel them with {{core:cancel-edit-tray}}", "tip18" : "Pressing {{core:edit-selected-node}} will edit the first node in the current selection" - }, - "info-tbd": { - "tip1" : "Press the Deploy button above to start the flow running. You can choose to deploy the whole flow or just the changes.", - "tip2" : "Options like Show grid and Snap to grid are under the menu icon
          View", - "tip4" : " Manage palette can be used to find, add and remove extra nodes.", - "tip5" : "Nodes may install examples under
          Import Examples", - "tip6" : "Lots of example flows can be found on flows.nodered.org
          They can then be imported by drag and drop to the workspace.", - "tip7" : "Shift-click and drag on a connector to move all the attached wires in one go.", - "tip8" : "The Node-RED Dashboard package can be used to create simple User Interfaces.", - "tip10": "Got a question?
          Join us on Slack
          or the
          Node-RED Google group" } }