diff --git a/CHANGELOG.md b/CHANGELOG.md index 6770f3158..29b8dabb0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,18 @@ +#### 0.19.4: Maintenance Release + + - Fix race condition in non-cache lfs context Fixes #1888 + - LocalFileSystem Context: Remove extra flush code + - Prevent race condition in caching mode of lfs context (#1889) + - Allow context store name to be provided in the key + - Switch node: only use promises when absolutely necessary + - Fix dbl-click handling on webkit-based browsers + - Ensure context.flow/global cannot be deleted or enumerated + - Handle context.get with multiple levels of unknown key Fixes #1883 + - Fix global.get("foo.bar") for functionGlobalContext set values + - Fix node color bug (#1877) + - Merge pull request #1857 from cclauss/patch-1 + - Define raw_input() in Python 3 & fix time.sleep() + #### 0.19.3: Maintenance Release - Split node - fix complete to send msg for k/v object diff --git a/packages/node_modules/@node-red/editor-api/lib/editor/locales/en-US/editor.json b/packages/node_modules/@node-red/editor-api/lib/editor/locales/en-US/editor.json index 07aacaff7..1385c56a8 100644 --- a/packages/node_modules/@node-red/editor-api/lib/editor/locales/en-US/editor.json +++ b/packages/node_modules/@node-red/editor-api/lib/editor/locales/en-US/editor.json @@ -270,6 +270,7 @@ "defaultLabel": "use default label", "searchIcons": "Search icons", "useDefault": "use default", + "description": "Description", "errors": { "scopeChange": "Changing the scope will make it unavailable to nodes in other flows that use it" } diff --git a/packages/node_modules/@node-red/editor-api/lib/editor/locales/ja/editor.json b/packages/node_modules/@node-red/editor-api/lib/editor/locales/ja/editor.json index 779c0d089..878cacd90 100644 --- a/packages/node_modules/@node-red/editor-api/lib/editor/locales/ja/editor.json +++ b/packages/node_modules/@node-red/editor-api/lib/editor/locales/ja/editor.json @@ -266,6 +266,7 @@ "defaultLabel": "既定の名前を使用", "searchIcons": "アイコンを検索", "useDefault": "デフォルトを使用", + "description": "詳細", "errors": { "scopeChange": "スコープの変更は、他のフローで使われているノードを無効にします" } diff --git a/packages/node_modules/@node-red/editor-client/src/js/nodes.js b/packages/node_modules/@node-red/editor-client/src/js/nodes.js index 12ff3e682..d1ff205ab 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/nodes.js +++ b/packages/node_modules/@node-red/editor-client/src/js/nodes.js @@ -510,6 +510,9 @@ RED.nodes = (function() { } } } + if (n.info) { + node.info = n.info; + } return node; } @@ -904,7 +907,14 @@ RED.nodes = (function() { } if (!existingConfigNode || existingConfigNode._def.exclusive) { //} || !compareNodes(existingConfigNode,n,true) || existingConfigNode.z !== n.z) { - configNode = {id:n.id, z:n.z, type:n.type, users:[], _config:{}}; + configNode = { + id:n.id, + z:n.z, + type:n.type, + info: n.info, + users:[], + _config:{} + }; for (d in def.defaults) { if (def.defaults.hasOwnProperty(d)) { configNode[d] = n[d]; @@ -947,6 +957,7 @@ RED.nodes = (function() { inputLabels: n.inputLabels, outputLabels: n.outputLabels, icon: n.icon, + info: n.info, changed:false, _config:{} }; diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/editor.js b/packages/node_modules/@node-red/editor-client/src/js/ui/editor.js index 46904131b..73ef5e6b7 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/editor.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/editor.js @@ -772,7 +772,7 @@ RED.editor = (function() { searchInput.focus(); } - function buildLabelForm(container,node) { + function buildAppearanceForm(container,node) { var dialogForm = $('
').appendTo(container); var inputCount = node.inputs || node._def.inputs || 0; @@ -882,10 +882,27 @@ RED.editor = (function() { return changed; } + function buildDescriptionForm(container,node) { + var dialogForm = $('
').appendTo(container); + $('
').appendTo(dialogForm); + var nodeInfoEditor = RED.editor.createEditor({ + id: "node-info-input-info-editor", + mode: 'ace/mode/markdown', + value: "" + }); + if (node.info) { + nodeInfoEditor.getSession().setValue(node.info, -1); + } + return nodeInfoEditor; + } + function showEditDialog(node) { var editing_node = node; var isDefaultIcon; var defaultIcon; + var nodeInfoEditor; + var finishedBuilding = false; + editStack.push(node); RED.view.state(RED.state.EDITING); var type = node.type; @@ -1126,6 +1143,33 @@ RED.editor = (function() { } } + var oldInfo = node.info; + if (nodeInfoEditor) { + var newInfo = nodeInfoEditor.getValue(); + if (!!oldInfo) { + // Has existing info property + if (newInfo.trim() === "") { + // New value is blank - remove the property + changed = true; + changes.info = oldInfo; + delete node.info; + } else if (newInfo !== oldInfo) { + // New value is different + changed = true; + changes.info = oldInfo; + node.info = newInfo; + } + } else { + // No existing info + if (newInfo.trim() !== "") { + // New value is not blank + changed = true; + changes.info = undefined; + node.info = newInfo; + } + } + } + if (changed) { var wasChanged = editing_node.changed; editing_node.changed = true; @@ -1174,8 +1218,8 @@ RED.editor = (function() { ], resize: function(dimensions) { editTrayWidthCache[type] = dimensions.width; - $(".editor-tray-content").height(dimensions.height - 78); - var form = $(".editor-tray-content form").height(dimensions.height - 78 - 40); + $(".editor-tray-content").height(dimensions.height - 50); + var form = $(".editor-tray-content form").height(dimensions.height - 50 - 40); if (editing_node && editing_node._def.oneditresize) { try { editing_node._def.oneditresize.call(editing_node,{width:form.width(),height:form.height()}); @@ -1189,25 +1233,23 @@ RED.editor = (function() { var trayBody = tray.find('.editor-tray-body'); trayBody.parent().css('overflow','hidden'); - var stack = RED.stack.create({ - container: trayBody, - singleExpanded: true - }); - var nodeProperties = stack.add({ - title: RED._("editor.nodeProperties"), - expanded: true - }); - nodeProperties.content.addClass("editor-tray-content"); + var editorTabEl = $('').appendTo(trayBody); + var editorContent = $('
').appendTo(trayBody); - var portLabels = stack.add({ - title: RED._("editor.portLabels"), - onexpand: function() { - refreshLabelForm(this.content,node); - } + var editorTabs = RED.tabs.create({ + element:editorTabEl, + onchange:function(tab) { + editorContent.children().hide(); + if (tab.onchange) { + tab.onchange.call(tab); + } + tab.content.show(); + if (finishedBuilding) { + RED.tray.resize(); + } + }, + collapsible: true }); - portLabels.content.addClass("editor-tray-content"); - - if (editing_node) { RED.sidebar.info.refresh(editing_node); } @@ -1224,11 +1266,48 @@ RED.editor = (function() { } else { isDefaultIcon = true; } - buildEditForm(nodeProperties.content,"dialog-form",type,ns); - buildLabelForm(portLabels.content,node); + + var nodePropertiesTab = { + id: "editor-tab-properties", + label: "Properties", + name: "Properties", + content: $('
', {class:"editor-tray-content"}).appendTo(editorContent).hide(), + iconClass: "fa fa-cog" + }; + buildEditForm(nodePropertiesTab.content,"dialog-form",type,ns); + editorTabs.addTab(nodePropertiesTab); + + if (!node._def.defaults || !node._def.defaults.hasOwnProperty('info')) { + var descriptionTab = { + id: "editor-tab-description", + label: "Description", + name: "Description", + content: $('
', {class:"editor-tray-content"}).appendTo(editorContent).hide(), + iconClass: "fa fa-file-text-o", + onchange: function() { + nodeInfoEditor.focus(); + } + }; + editorTabs.addTab(descriptionTab); + nodeInfoEditor = buildDescriptionForm(descriptionTab.content,node); + } + + var appearanceTab = { + id: "editor-tab-appearance", + label: "Appearance", + name: "Appearance", + content: $('
', {class:"editor-tray-content"}).appendTo(editorContent).hide(), + iconClass: "fa fa-object-group", + onchange: function() { + refreshLabelForm(this.content,node); + } + }; + buildAppearanceForm(appearanceTab.content,node); + editorTabs.addTab(appearanceTab); prepareEditDialog(node,node._def,"node-input", function() { trayBody.i18n(); + finishedBuilding = true; done(); }); }, @@ -1240,6 +1319,10 @@ RED.editor = (function() { RED.sidebar.info.refresh(editing_node); } RED.workspaces.refresh(); + if (nodeInfoEditor) { + nodeInfoEditor.destroy(); + nodeInfoEditor = null; + } RED.view.redraw(true); editStack.pop(); }, @@ -1277,6 +1360,8 @@ RED.editor = (function() { var adding = (id == "_ADD_"); var node_def = RED.nodes.getType(type); var editing_config_node = RED.nodes.node(id); + var nodeInfoEditor; + var finishedBuilding = false; var ns; if (node_def.set.module === "node-red") { @@ -1309,7 +1394,8 @@ RED.editor = (function() { RED.view.state(RED.state.EDITING); var trayOptions = { title: getEditStackTitle(), //(adding?RED._("editor.addNewConfig", {type:type}):RED._("editor.editConfig", {type:type})), - resize: function() { + resize: function(dimensions) { + $(".editor-tray-content").height(dimensions.height - 50); if (editing_config_node && editing_config_node._def.oneditresize) { var form = $("#node-config-dialog-edit-form"); try { @@ -1321,6 +1407,7 @@ RED.editor = (function() { }, open: function(tray, done) { var trayHeader = tray.find(".editor-tray-header"); + var trayBody = tray.find('.editor-tray-body'); var trayFooter = tray.find(".editor-tray-footer"); if (node_def.hasUsers !== false) { @@ -1328,7 +1415,49 @@ RED.editor = (function() { } trayFooter.append(''); - var dialogForm = buildEditForm(tray.find('.editor-tray-body'),"node-config-dialog-edit-form",type,ns); + var editorTabEl = $('
    ').appendTo(trayBody); + var editorContent = $('
    ').appendTo(trayBody); + + var editorTabs = RED.tabs.create({ + element:editorTabEl, + onchange:function(tab) { + editorContent.children().hide(); + if (tab.onchange) { + tab.onchange.call(tab); + } + tab.content.show(); + if (finishedBuilding) { + RED.tray.resize(); + } + }, + collapsible: true + }); + + var nodePropertiesTab = { + id: "editor-tab-cproperties", + label: "Properties", + name: "Properties", + content: $('
    ', {class:"editor-tray-content"}).appendTo(editorContent).hide(), + iconClass: "fa fa-cog" + }; + editorTabs.addTab(nodePropertiesTab); + buildEditForm(nodePropertiesTab.content,"node-config-dialog-edit-form",type,ns); + + if (!node_def.defaults || !node_def.defaults.hasOwnProperty('info')) { + var descriptionTab = { + id: "editor-tab-description", + label: "Description", + name: "Description", + content: $('
    ', {class:"editor-tray-content"}).appendTo(editorContent).hide(), + iconClass: "fa fa-file-text-o", + onchange: function() { + nodeInfoEditor.focus(); + } + }; + editorTabs.addTab(descriptionTab); + nodeInfoEditor = buildDescriptionForm(descriptionTab.content,editing_config_node); + } + prepareEditDialog(editing_config_node,node_def,"node-config-input", function() { if (editing_config_node._def.exclusive) { @@ -1376,17 +1505,20 @@ RED.editor = (function() { } }); } - tabSelect.i18n(); - - dialogForm.i18n(); if (node_def.hasUsers !== false) { $("#node-config-dialog-user-count").find("span").text(RED._("editor.nodesUse", {count:editing_config_node.users.length})).parent().show(); } + trayBody.i18n(); + finishedBuilding = true; done(); }); }, close: function() { RED.workspaces.refresh(); + if (nodeInfoEditor) { + nodeInfoEditor.destroy(); + nodeInfoEditor = null; + } editStack.pop(); }, show: function() { @@ -1480,6 +1612,31 @@ RED.editor = (function() { } } } + + if (nodeInfoEditor) { + editing_config_node.info = nodeInfoEditor.getValue(); + + var oldInfo = editing_config_node.info; + if (nodeInfoEditor) { + var newInfo = nodeInfoEditor.getValue(); + if (!!oldInfo) { + // Has existing info property + if (newInfo.trim() === "") { + // New value is blank - remove the property + delete editing_config_node.info; + } else if (newInfo !== oldInfo) { + // New value is different + editing_config_node.info = newInfo; + } + } else { + // No existing info + if (newInfo.trim() !== "") { + // New value is not blank + editing_config_node.info = newInfo; + } + } + } + } editing_config_node.label = configTypeDef.label; editing_config_node.z = scope; @@ -1667,7 +1824,7 @@ RED.editor = (function() { editStack.push(subflow); RED.view.state(RED.state.EDITING); var subflowEditor; - + var finishedBuilding = false; var trayOptions = { title: getEditStackTitle(), buttons: [ @@ -1768,48 +1925,76 @@ RED.editor = (function() { } ], resize: function(dimensions) { - $(".editor-tray-content").height(dimensions.height - 78); - var form = $(".editor-tray-content form").height(dimensions.height - 78 - 40); - - var rows = $("#dialog-form>div:not(.node-text-editor-row)"); - var editorRow = $("#dialog-form>div.node-text-editor-row"); - var height = $("#dialog-form").height(); - for (var i=0;i').appendTo(trayBody); + var editorContent = $('
    ').appendTo(trayBody); + + var editorTabs = RED.tabs.create({ + element:editorTabEl, + onchange:function(tab) { + editorContent.children().hide(); + if (tab.onchange) { + tab.onchange.call(tab); + } + tab.content.show(); + if (finishedBuilding) { + RED.tray.resize(); + } + }, + collapsible: true }); + var nodePropertiesTab = { + id: "editor-tab-properties", + label: "Properties", + name: "Properties", + content: $('
    ', {class:"editor-tray-content"}).appendTo(editorContent).hide(), + iconClass: "fa fa-cog" + }; + buildEditForm(nodePropertiesTab.content,"dialog-form","subflow-template"); + editorTabs.addTab(nodePropertiesTab); + + var descriptionTab = { + id: "editor-tab-description", + label: "Description", + name: "Description", + content: $('
    ', {class:"editor-tray-content"}).appendTo(editorContent).hide(), + iconClass: "fa fa-file-text-o", + onchange: function() { + subflowEditor.focus(); + } + }; + editorTabs.addTab(descriptionTab); + subflowEditor = buildDescriptionForm(descriptionTab.content,editing_node); + + var appearanceTab = { + id: "editor-tab-appearance", + label: "Appearance", + name: "Appearance", + content: $('
    ', {class:"editor-tray-content"}).appendTo(editorContent).hide(), + iconClass: "fa fa-object-group", + onchange: function() { + refreshLabelForm(this.content,editing_node); + } + }; + buildAppearanceForm(appearanceTab.content,editing_node); + editorTabs.addTab(appearanceTab); + + + + $("#subflow-input-name").val(subflow.name); RED.text.bidi.prepareInput($("#subflow-input-name")); @@ -1836,10 +2021,7 @@ RED.editor = (function() { } }) - $("#subflow-input-category").val(subflow.category||"subflows"); - - subflowEditor.getSession().setValue(subflow.info||"",-1); var userCount = 0; var subflowType = "subflow:"+editing_node.id; @@ -1850,8 +2032,8 @@ RED.editor = (function() { }); $("#subflow-dialog-user-count").text(RED._("subflow.subflowInstances", {count:userCount})).show(); - buildLabelForm(portLabels.content,subflow); trayBody.i18n(); + finishedBuilding = true; }, close: function() { if (RED.view.state() != RED.state.IMPORT_DRAGGING) { @@ -1860,6 +2042,7 @@ RED.editor = (function() { RED.sidebar.info.refresh(editing_node); RED.workspaces.refresh(); subflowEditor.destroy(); + subflowEditor = null; editStack.pop(); editing_node = null; }, diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/search.js b/packages/node_modules/@node-red/editor-client/src/js/ui/search.js index f13281807..837f6831e 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/search.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/search.js @@ -118,6 +118,7 @@ RED.search = (function() { } } } + function ensureSelectedIsVisible() { var selectedEntry = searchResults.find("li.selected"); if (selectedEntry.length === 1) { @@ -143,6 +144,7 @@ RED.search = (function() { search($(this).val()); } }); + searchInput.on('keydown',function(evt) { var children; if (results.length > 0) { @@ -229,12 +231,13 @@ RED.search = (function() { }); } + function reveal(node) { hide(); RED.view.reveal(node.id); } - function show() { + function show(v) { if (disabled) { return; } @@ -250,11 +253,13 @@ RED.search = (function() { createDialog(); } dialog.slideDown(300); + searchInput.searchBox('value',v) RED.events.emit("search:open"); visible = true; } searchInput.focus(); } + function hide() { if (visible) { RED.keyboard.remove("escape"); diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/subflow.js b/packages/node_modules/@node-red/editor-client/src/js/ui/subflow.js index a7bfd47b1..7eaa9627d 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/subflow.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/subflow.js @@ -21,8 +21,6 @@ RED.subflow = (function() { var _subflowTemplateEditTemplate = ''; diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/tab-config.js b/packages/node_modules/@node-red/editor-client/src/js/ui/tab-config.js index 00caea6cd..438fbe359 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/tab-config.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/tab-config.js @@ -140,7 +140,8 @@ RED.sidebar.config = (function() { var entry = $('
  • ').appendTo(list); $('
    ').text(label).appendTo(entry); if (node._def.hasUsers !== false) { - var iconContainer = $('
    ',{class:"palette_icon_container palette_icon_container_right"}).text(node.users.length).appendTo(entry); + var iconContainer = $('
    ',{class:"palette_icon_container palette_icon_container_right"}).appendTo(entry); + var butt = $('').click(function(e) { e.preventDefault(); RED.search.show(node.id); }).text(node.users.length).appendTo(iconContainer); if (node.users.length === 0) { entry.addClass("config_node_unused"); } @@ -161,7 +162,6 @@ RED.sidebar.config = (function() { }); RED.view.redraw(); }); - entry.on('mouseout',function(e) { RED.nodes.eachNode(function(node) { if(node.highlighted) { diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/tab-info.js b/packages/node_modules/@node-red/editor-client/src/js/ui/tab-info.js index 7802f6e1a..287df1130 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/tab-info.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/tab-info.js @@ -277,6 +277,10 @@ RED.sidebar.info = (function() { // TODO: help infoText = infoText + marked(textInfo); } + if (node.info) { + infoSection.title.text(RED._("sidebar.info.nodeHelp")); + infoText = marked(node.info || "") || ('' + RED._("sidebar.info.none") + ''); + } if (infoText) { setInfoText(infoText); } diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/tray.js b/packages/node_modules/@node-red/editor-client/src/js/ui/tray.js index 3c6a78a6b..2fdbb2ac8 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/tray.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/tray.js @@ -232,6 +232,7 @@ RED.tray = (function() { } }, + resize: handleWindowResize, close: function close(done) { if (stack.length > 0) { var tray = stack.pop(); diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/utils.js b/packages/node_modules/@node-red/editor-client/src/js/ui/utils.js index b5e4c1f4a..bdfd2088b 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/utils.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/utils.js @@ -826,7 +826,11 @@ RED.utils = (function() { } result = nodeColorCache[type]; } - return result; + if (result) { + return result; + } else { + return "#ddd"; + } } function addSpinnerOverlay(container,contain) { diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/view.js b/packages/node_modules/@node-red/editor-client/src/js/ui/view.js index a80f7446f..6e6560418 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/view.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/view.js @@ -1766,7 +1766,7 @@ RED.view = (function() { clickTime = now; dblClickPrimed = (lastClickNode == mousedown_node && - d3.event.buttons === 1 && + d3.event.button === 0 && !d3.event.shiftKey && !d3.event.metaKey && !d3.event.altKey && !d3.event.ctrlKey); lastClickNode = mousedown_node; diff --git a/packages/node_modules/@node-red/nodes/99-sample.html.demo b/packages/node_modules/@node-red/nodes/99-sample.html.demo index 94e049e31..c7548b032 100644 --- a/packages/node_modules/@node-red/nodes/99-sample.html.demo +++ b/packages/node_modules/@node-red/nodes/99-sample.html.demo @@ -67,6 +67,7 @@ }, inputs:1, // set the number of inputs - only 0 or 1 outputs:1, // set the number of outputs - 0 to n + color: "#ddd", // set icon color // set the icon (held in icons dir below where you save the node) icon: "myicon.png", // saved in icons/myicon.png label: function() { // sets the default label contents diff --git a/packages/node_modules/@node-red/nodes/core/hardware/nrgpio.py b/packages/node_modules/@node-red/nodes/core/hardware/nrgpio.py index 0cde0e4df..7908ca117 100755 --- a/packages/node_modules/@node-red/nodes/core/hardware/nrgpio.py +++ b/packages/node_modules/@node-red/nodes/core/hardware/nrgpio.py @@ -21,7 +21,12 @@ import os import subprocess from time import sleep -bounce = 25; +try: + raw_input # Python 2 +except NameError: + raw_input = input # Python 3 + +bounce = 25 if len(sys.argv) > 2: cmd = sys.argv[1].lower() @@ -198,7 +203,7 @@ if len(sys.argv) > 2: elif cmd == "kbd": # catch keyboard button events try: while not os.path.isdir("/dev/input/by-path"): - time.sleep(10) + sleep(10) infile = subprocess.check_output("ls /dev/input/by-path/ | grep -m 1 'kbd'", shell=True).strip() infile_path = "/dev/input/by-path/" + infile EVENT_SIZE = struct.calcsize('llHHI') diff --git a/packages/node_modules/@node-red/nodes/core/io/21-httprequest.js b/packages/node_modules/@node-red/nodes/core/io/21-httprequest.js index 4ddb1d3b9..28d67d077 100644 --- a/packages/node_modules/@node-red/nodes/core/io/21-httprequest.js +++ b/packages/node_modules/@node-red/nodes/core/io/21-httprequest.js @@ -83,6 +83,7 @@ module.exports = function(RED) { opts.headers = {}; opts.encoding = null; // Force NodeJs to return a Buffer (instead of a string) opts.maxRedirects = 21; + opts.jar = request.jar(); var ctSet = "Content-Type"; // set default camel case var clSet = "Content-Length"; if (msg.headers) { @@ -112,28 +113,42 @@ module.exports = function(RED) { } if (msg.hasOwnProperty('followRedirects')) { opts.followRedirect = msg.followRedirects; + } + if (!opts.hasOwnProperty('followRedirect') || opts.followRedirect) { + opts.followRedirect = function(res) { + if (this.headers.cookie) { + delete this.headers.cookie; + } + return true; + }; + } + if (opts.headers.hasOwnProperty('cookie')) { + var cookies = cookie.parse(opts.headers.cookie); + for (var name in cookies) { + if (cookies.hasOwnProperty(name)) { + if (cookies[name] === null) { + // This case clears a cookie for HTTP In/Response nodes. + // Ignore for this node. + } else { + opts.jar.setCookie(name + '=' + cookies[name], url); + } + } } + delete opts.headers.cookie; + } if (msg.cookies) { - var cookies = []; - if (opts.headers.hasOwnProperty('cookie')) { - cookies.push(opts.headers.cookie); - } - for (var name in msg.cookies) { if (msg.cookies.hasOwnProperty(name)) { if (msg.cookies[name] === null || msg.cookies[name].value === null) { // This case clears a cookie for HTTP In/Response nodes. // Ignore for this node. } else if (typeof msg.cookies[name] === 'object') { - cookies.push(cookie.serialize(name,msg.cookies[name].value)); + opts.jar.setCookie(name + '=' + msg.cookies[name].value, url); } else { - cookies.push(cookie.serialize(name,msg.cookies[name])); + opts.jar.setCookie(name + '=' + msg.cookies[name], url); } } } - if (cookies.length > 0) { - opts.headers.cookie = cookies.join("; "); - } } if (this.credentials && this.credentials.user) { opts.auth = { diff --git a/packages/node_modules/@node-red/nodes/core/logic/10-switch.js b/packages/node_modules/@node-red/nodes/core/logic/10-switch.js index 89593047e..1d9c52971 100644 --- a/packages/node_modules/@node-red/nodes/core/logic/10-switch.js +++ b/packages/node_modules/@node-red/nodes/core/logic/10-switch.js @@ -92,31 +92,80 @@ module.exports = function(RED) { } function getProperty(node,msg) { - return new Promise((resolve,reject) => { + if (node.useAsyncRules) { + return new Promise((resolve,reject) => { + if (node.propertyType === 'jsonata') { + RED.util.evaluateJSONataExpression(node.property,msg,(err,value) => { + if (err) { + reject(RED._("switch.errors.invalid-expr",{error:err.message})); + } else { + resolve(value); + } + }); + } else { + RED.util.evaluateNodeProperty(node.property,node.propertyType,node,msg,(err,value) => { + if (err) { + resolve(undefined); + } else { + resolve(value); + } + }); + } + }); + } else { if (node.propertyType === 'jsonata') { - RED.util.evaluateJSONataExpression(node.property,msg,(err,value) => { - if (err) { - reject(RED._("switch.errors.invalid-expr",{error:err.message})); - } else { - resolve(value); - } - }); + try { + return RED.util.evaluateJSONataExpression(node.property,msg); + } catch(err) { + throw new Error(RED._("switch.errors.invalid-expr",{error:err.message})) + } } else { - RED.util.evaluateNodeProperty(node.property,node.propertyType,node,msg,(err,value) => { - if (err) { - resolve(undefined); - } else { - resolve(value); - } - }); + try { + return RED.util.evaluateNodeProperty(node.property,node.propertyType,node,msg); + } catch(err) { + return undefined; + } } - }); + } } function getV1(node,msg,rule,hasParts) { - return new Promise( (resolve,reject) => { + if (node.useAsyncRules) { + return new Promise( (resolve,reject) => { + if (rule.vt === 'prev') { + resolve(node.previousValue); + } else if (rule.vt === 'jsonata') { + var exp = rule.v; + if (rule.t === 'jsonata_exp') { + if (hasParts) { + exp.assign("I", msg.parts.index); + exp.assign("N", msg.parts.count); + } + } + RED.util.evaluateJSONataExpression(exp,msg,(err,value) => { + if (err) { + reject(RED._("switch.errors.invalid-expr",{error:err.message})); + } else { + resolve(value); + } + }); + } else if (rule.vt === 'json') { + resolve("json"); // TODO: ?! invalid case + } else if (rule.vt === 'null') { + resolve("null"); + } else { + RED.util.evaluateNodeProperty(rule.v,rule.vt,node,msg, function(err,value) { + if (err) { + resolve(undefined); + } else { + resolve(value); + } + }); + } + }); + } else { if (rule.vt === 'prev') { - resolve(node.previousValue); + return node.previousValue; } else if (rule.vt === 'jsonata') { var exp = rule.v; if (rule.t === 'jsonata_exp') { @@ -125,83 +174,120 @@ module.exports = function(RED) { exp.assign("N", msg.parts.count); } } - RED.util.evaluateJSONataExpression(exp,msg,(err,value) => { - if (err) { - reject(RED._("switch.errors.invalid-expr",{error:err.message})); - } else { - resolve(value); - } - }); + try { + return RED.util.evaluateJSONataExpression(exp,msg); + } catch(err) { + throw new Error(RED._("switch.errors.invalid-expr",{error:err.message})) + } } else if (rule.vt === 'json') { - resolve("json"); + return "json"; // TODO: ?! invalid case } else if (rule.vt === 'null') { - resolve("null"); + return "null"; } else { - RED.util.evaluateNodeProperty(rule.v,rule.vt,node,msg, function(err,value) { - if (err) { - resolve(undefined); - } else { - resolve(value); - } - }); + try { + return RED.util.evaluateNodeProperty(rule.v,rule.vt,node,msg); + } catch(err) { + return undefined; + } } - }); + } } function getV2(node,msg,rule) { - return new Promise((resolve,reject) => { + if (node.useAsyncRules) { + return new Promise((resolve,reject) => { + var v2 = rule.v2; + if (rule.v2t === 'prev') { + resolve(node.previousValue); + } else if (rule.v2t === 'jsonata') { + RED.util.evaluateJSONataExpression(rule.v2,msg,(err,value) => { + if (err) { + reject(RED._("switch.errors.invalid-expr",{error:err.message})); + } else { + resolve(value); + } + }); + } else if (typeof v2 !== 'undefined') { + RED.util.evaluateNodeProperty(rule.v2,rule.v2t,node,msg, function(err,value) { + if (err) { + resolve(undefined); + } else { + resolve(value); + } + }); + } else { + resolve(v2); + } + }) + } else { var v2 = rule.v2; if (rule.v2t === 'prev') { - resolve(node.previousValue); + return node.previousValue; } else if (rule.v2t === 'jsonata') { - RED.util.evaluateJSONataExpression(rule.v2,msg,(err,value) => { - if (err) { - reject(RED._("switch.errors.invalid-expr",{error:err.message})); - } else { - resolve(value); - } - }); + try { + return RED.util.evaluateJSONataExpression(rule.v2,msg); + } catch(err) { + throw new Error(RED._("switch.errors.invalid-expr",{error:err.message})) + } } else if (typeof v2 !== 'undefined') { - RED.util.evaluateNodeProperty(rule.v2,rule.v2t,node,msg, function(err,value) { - if (err) { - resolve(undefined); - } else { - resolve(value); - } - }); + try { + return RED.util.evaluateNodeProperty(rule.v2,rule.v2t,node,msg); + } catch(err) { + return undefined; + } } else { - resolve(v2); + return v2; } - }) + } } function applyRule(node, msg, property, state) { - return new Promise((resolve,reject) => { + if (node.useAsyncRules) { + return new Promise((resolve,reject) => { - var rule = node.rules[state.currentRule]; - var v1,v2; + var rule = node.rules[state.currentRule]; + var v1,v2; - getV1(node,msg,rule,state.hasParts).then(value => { - v1 = value; - }).then(()=>getV2(node,msg,rule)).then(value => { - v2 = value; - }).then(() => { - if (rule.t == "else") { - property = state.elseflag; - state.elseflag = true; - } - if (operators[rule.t](property,v1,v2,rule.case,msg.parts)) { - state.onward.push(msg); - state.elseflag = false; - if (node.checkall == "false") { - return resolve(false); + getV1(node,msg,rule,state.hasParts).then(value => { + v1 = value; + }).then(()=>getV2(node,msg,rule)).then(value => { + v2 = value; + }).then(() => { + if (rule.t == "else") { + property = state.elseflag; + state.elseflag = true; } - } else { - state.onward.push(null); + if (operators[rule.t](property,v1,v2,rule.case,msg.parts)) { + state.onward.push(msg); + state.elseflag = false; + if (node.checkall == "false") { + return resolve(false); + } + } else { + state.onward.push(null); + } + resolve(state.currentRule < node.rules.length - 1); + }); + }) + } else { + var rule = node.rules[state.currentRule]; + var v1 = getV1(node,msg,rule,state.hasParts); + var v2 = getV2(node,msg,rule); + if (rule.t == "else") { + property = state.elseflag; + state.elseflag = true; + } + if (operators[rule.t](property,v1,v2,rule.case,msg.parts)) { + state.onward.push(msg); + state.elseflag = false; + if (node.checkall == "false") { + return false; } - resolve(state.currentRule < node.rules.length - 1); - }); - }) + } else { + state.onward.push(null); + } + return state.currentRule < node.rules.length - 1 + } } function applyRules(node, msg, property,state) { @@ -215,7 +301,18 @@ module.exports = function(RED) { msg.parts.hasOwnProperty("index") } } - return applyRule(node,msg,property,state).then(hasMore => { + if (node.useAsyncRules) { + return applyRule(node,msg,property,state).then(hasMore => { + if (hasMore) { + state.currentRule++; + return applyRules(node,msg,property,state); + } else { + node.previousValue = property; + return state.onward; + } + }); + } else { + var hasMore = applyRule(node,msg,property,state); if (hasMore) { state.currentRule++; return applyRules(node,msg,property,state); @@ -223,7 +320,7 @@ module.exports = function(RED) { node.previousValue = property; return state.onward; } - }); + } } @@ -248,6 +345,14 @@ module.exports = function(RED) { var valid = true; var repair = n.repair; var needsCount = repair; + this.useAsyncRules = ( + this.propertyType === 'flow' || + this.propertyType === 'global' || ( + this.propertyType === 'jsonata' && + /\$(flow|global)Context/.test(this.property) + ) + ); + for (var i=0; i applyRules(node,msg,property)) - .then(onward => { - if (!repair || !hasParts) { - node.send(onward); - } - else { - sendGroupMessages(onward, msg); - } - }).catch(err => { - node.warn(err); - }); + if (node.useAsyncRules) { + return getProperty(node,msg) + .then(property => applyRules(node,msg,property)) + .then(onward => { + if (!repair || !hasParts) { + node.send(onward); + } + else { + sendGroupMessages(onward, msg); + } + }).catch(err => { + node.warn(err); + }); + } else { + try { + var property = getProperty(node,msg); + var onward = applyRules(node,msg,property); + if (!repair || !hasParts) { + node.send(onward); + } else { + sendGroupMessages(onward, msg); + } + } catch(err) { + node.warn(err); + } + } } function clearPending() { @@ -473,7 +608,11 @@ module.exports = function(RED) { } this.on('input', function(msg) { - processMessageQueue(msg); + if (node.useAsyncRules) { + processMessageQueue(msg); + } else { + processMessage(msg,true); + } }); this.on('close', function() { diff --git a/packages/node_modules/@node-red/runtime/lib/nodes/context/index.js b/packages/node_modules/@node-red/runtime/lib/nodes/context/index.js index 2f700cf30..6f63344e3 100644 --- a/packages/node_modules/@node-red/runtime/lib/nodes/context/index.js +++ b/packages/node_modules/@node-red/runtime/lib/nodes/context/index.js @@ -15,7 +15,8 @@ **/ var clone = require("clone"); -var log = require("@node-red/util").log; // TODO: separate module +var log = require("@node-red/util").log; +var util = require("@node-red/util").util; var memory = require("./memory"); var settings; @@ -209,104 +210,131 @@ function createContext(id,seed) { insertSeedValues = function(keys,values) { if (!Array.isArray(keys)) { if (values[0] === undefined) { - values[0] = seed[keys]; + values[0] = util.getObjectProperty(seed,keys); } } else { for (var i=0;i