diff --git a/editor/js/ui/keyboard.js b/editor/js/ui/keyboard.js index a7f815b0f..3316426ae 100644 --- a/editor/js/ui/keyboard.js +++ b/editor/js/ui/keyboard.js @@ -15,6 +15,8 @@ **/ RED.keyboard = (function() { + var isMac = /Mac/i.test(window.navigator.platform); + var handlers = {}; var partialState; @@ -253,7 +255,6 @@ RED.keyboard = (function() { var dialog = null; - var isMac = /Mac/i.test(window.navigator.platform); var cmdCtrlKey = ''+(isMac?'⌘':'Ctrl')+''; function showKeyboardHelp() { @@ -281,7 +282,7 @@ RED.keyboard = (function() { ''+cmdCtrlKey+' + f'+RED._("keyboard.searchBox")+''+ ''+cmdCtrlKey+' + Shift + p'+RED._("keyboard.managePalette")+''+ ' '+ - ' '+RED._("keyboard.nudgeNode")+''+ + ' '+RED._("keyboard.nudgeNode")+''+ 'Shift + '+RED._("keyboard.moveNode")+''+ ' '+ ''+cmdCtrlKey+' + c'+RED._("keyboard.copyNode")+''+ @@ -303,6 +304,15 @@ RED.keyboard = (function() { dialog.dialog("open"); } + function formatKey(key) { + var formattedKey = isMac?key.replace(/ctrl-?/,"⌘"):key; + formattedKey = formattedKey.replace(/shift-?/,"⇧") + formattedKey = formattedKey.replace(/left/,"←") + formattedKey = formattedKey.replace(/up/,"↑") + formattedKey = formattedKey.replace(/right/,"→") + formattedKey = formattedKey.replace(/down/,"↓") + return ''+formattedKey.split(" ").join(' ')+''; + } return { init: init, @@ -310,7 +320,8 @@ RED.keyboard = (function() { remove: removeHandler, getShortcut: function(actionName) { return actionToKeyMap[actionName]; - } + }, + formatKey: formatKey } })(); diff --git a/editor/js/ui/tab-info.js b/editor/js/ui/tab-info.js index 33216dd22..cf22367b6 100644 --- a/editor/js/ui/tab-info.js +++ b/editor/js/ui/tab-info.js @@ -67,6 +67,7 @@ RED.sidebar.info = (function() { } function refresh(node) { + tips.stop(); $(content).empty(); var table = $('
'); var tableBody = $('').appendTo(table); @@ -145,20 +146,76 @@ RED.sidebar.info = (function() { }); } - var infotimeout; - function clear() { - //$(content).html(""); - if (!infotimeout) { - var r = parseInt(Math.random() * RED._("infotips:infoLength")); - $(content).html('
'+RED._("infotips:info.tip"+r)+'
'); - infotimeout = setTimeout(function() { infotimeout=null; }, 20000); + + var tips = (function() { + var startDelay = 2000; + var cycleDelay = 10000; + var startTimeout; + var refreshTimeout; + var tipCount = -1; + + + function setTip() { + + var r = Math.floor(Math.random() * tipCount); + var tip = RED._("infotips:info.tip"+r); + + var m; + while ((m=/({{(.*?)}})/.exec(tip))) { + var shortcut = RED.keyboard.getShortcut(m[2]); + if (shortcut) { + tip = tip.replace(m[1],RED.keyboard.formatKey(shortcut.key)); + } else { + return; + } + } + while ((m=/(\[(.*?)\])/.exec(tip))) { + tip = tip.replace(m[1],RED.keyboard.formatKey(m[2])); + } + $('
'+tip+'
').appendTo(content).fadeIn(200); + if (startTimeout) { + startTimeout = null; + refreshTimeout = setInterval(cycleTips,cycleDelay); + } } + function cycleTips() { + $(".node-info-tip").fadeOut(300,function() { + $(this).remove(); + setTip(); + }) + } + return { + start: function() { + if (!startTimeout && !refreshTimeout) { + $(content).html(""); + if (tipCount === -1) { + do { + tipCount++; + } while(RED._("infotips:info.tip"+tipCount)!=="infotips:info.tip"+tipCount); + } + startTimeout = setTimeout(setTip,startDelay); + } + }, + stop: function() { + clearInterval(refreshTimeout); + clearTimeout(startTimeout); + refreshTimeout = null; + startTimeout = null; + } + } + })(); + + function clear() { + tips.start(); } function set(html) { + tips.stop(); $(content).html(html); } + + RED.events.on("view:selection-changed",function(selection) { if (selection.nodes) { if (selection.nodes.length == 1) { diff --git a/editor/sass/keyboard.scss b/editor/sass/keyboard.scss index 6c05e5046..e355223f6 100644 --- a/editor/sass/keyboard.scss +++ b/editor/sass/keyboard.scss @@ -37,4 +37,6 @@ font-family: Courier, monospace; box-shadow: #999 1px 1px 1px; } - +.help-key-block { + white-space: nowrap; +} diff --git a/editor/sass/tab-info.scss b/editor/sass/tab-info.scss index c7cf8e27e..eda9098c3 100644 --- a/editor/sass/tab-info.scss +++ b/editor/sass/tab-info.scss @@ -82,20 +82,17 @@ div.node-info { } } .node-info-tip { - margin: 10px; - margin-top: 30px; - border-radius: 6px; - padding: 12px; - font-size: 18px; + position: absolute; + top: 40%; + left:0; + right:0; + padding: 20px; + font-size: 16px; text-align: center; - color : #aaa; + line-height: 1.9em; + color : #bbb; background-color: #fff; - code { - font-size: 16px; - font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; - font-weight: 700; - padding: 3px 8px 3px 8px; - border-radius: 4px; - color: #aaa; - } + @include disable-selection; + cursor: default; + } diff --git a/red/api/locales/en-US/infotips.json b/red/api/locales/en-US/infotips.json index cc7f68826..ca4fdf630 100644 --- a/red/api/locales/en-US/infotips.json +++ b/red/api/locales/en-US/infotips.json @@ -1,16 +1,32 @@ { "info": { - "tip0" : "Use the delete key to remove a node.", + "tip0" : "You can remove the selected nodes or links with {{core:delete}}", + "tip1" : "Search for nodes using {{core:search}}", + "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", + "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:export}}", + "tip9" : "Import a flow by dragging its JSON into the editor, or with {{core:import}}", + "tip10" : "[shift] [click] and drag on a node port to move all of the attached wires or just the selected one", + "tip11" : "Show the Info tab with {{core:show-info-tab}} or the Debug tab with {{core:show-debug-tab}}", + "tip12" : "[ctrl] [click] in the workspace to open the quick-add dialog", + "tip13" : "Hold down [ctrl] when you [click] on a node port to enable quick-wiring", + "tip14" : "Hold down [shift] when you [click] on a node to also select all of its connected nodes", + "tip15" : "Hold down [ctrl] when you [click] on a node to add or remove it from the current selection", + "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}}" + }, + "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", - "tip3" : "ctrl . or ⌘ . can be used to search for nodes and tabs.", "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.", - "tip9" : "ctrlspace will toggle the view of this sidebar.", "tip10": "Got a question?
Join us on Slack
or the
Node-RED Google group" - }, - "infoLength": "11" + } } diff --git a/red/runtime/i18n.js b/red/runtime/i18n.js index 0d45b71e4..f555cb5fa 100644 --- a/red/runtime/i18n.js +++ b/red/runtime/i18n.js @@ -24,6 +24,13 @@ var defaultLang = "en-US"; var resourceMap = {}; var resourceCache = {}; +function registerMessageCatalogs(catalogs) { + var promises = catalogs.map(function(catalog) { + return registerMessageCatalog(catalog.namespace,catalog.dir,catalog.file); + }); + return when.settle(promises); +} + function registerMessageCatalog(namespace,dir,file) { return when.promise(function(resolve,reject) { resourceMap[namespace] = { basedir:dir, file:file}; @@ -109,6 +116,7 @@ function getCatalog(namespace,lang) { var obj = module.exports = { init: init, registerMessageCatalog: registerMessageCatalog, + registerMessageCatalogs: registerMessageCatalogs, catalog: getCatalog, i: i18n, defaultLang: defaultLang