Merge branch 'dev' into function-modules

This commit is contained in:
Nick O'Leary
2021-02-13 00:21:27 +00:00
122 changed files with 3732 additions and 545 deletions

View File

@@ -72,9 +72,7 @@ RED.clipboard = (function() {
text: RED._("clipboard.export.copy"),
click: function() {
if (activeTab === "red-ui-clipboard-dialog-export-tab-clipboard") {
$("#red-ui-clipboard-dialog-export-text").select();
document.execCommand("copy");
document.getSelection().removeAllRanges();
copyText($("#red-ui-clipboard-dialog-export-text").val());
RED.notify(RED._("clipboard.nodesExported"),{id:"clipboard"});
$( this ).dialog( "close" );
} else {
@@ -222,14 +220,22 @@ RED.clipboard = (function() {
'</div>'+
'<div id="red-ui-clipboard-dialog-export-tabs-content" class="red-ui-clipboard-dialog-tabs-content">'+
'<div id="red-ui-clipboard-dialog-export-tab-clipboard" class="red-ui-clipboard-dialog-tab-clipboard">'+
'<div class="form-row" style="height:calc(100% - 30px)">'+
'<textarea readonly id="red-ui-clipboard-dialog-export-text"></textarea>'+
'<div id="red-ui-clipboard-dialog-export-tab-clipboard-tab-bar">'+
'<ul id="red-ui-clipboard-dialog-export-tab-clipboard-tabs"></ul>'+
'</div>'+
'<div class="form-row" style="text-align: right;">'+
'<span id="red-ui-clipboard-dialog-export-fmt-group" class="button-group">'+
'<a id="red-ui-clipboard-dialog-export-fmt-mini" class="red-ui-button red-ui-button-small toggle" href="#" data-i18n="clipboard.export.compact"></a>'+
'<a id="red-ui-clipboard-dialog-export-fmt-full" class="red-ui-button red-ui-button-small toggle" href="#" data-i18n="clipboard.export.formatted"></a>'+
'</span>'+
'<div class="red-ui-clipboard-dialog-export-tab-clipboard-tab" id="red-ui-clipboard-dialog-export-tab-clipboard-preview">'+
'<div id="red-ui-clipboard-dialog-export-tab-clipboard-preview-list"></div>'+
'</div>'+
'<div class="red-ui-clipboard-dialog-export-tab-clipboard-tab" id="red-ui-clipboard-dialog-export-tab-clipboard-json">'+
'<div class="form-row" style="height:calc(100% - 40px)">'+
'<textarea readonly id="red-ui-clipboard-dialog-export-text"></textarea>'+
'</div>'+
'<div class="form-row" style="text-align: right;">'+
'<span id="red-ui-clipboard-dialog-export-fmt-group" class="button-group">'+
'<a id="red-ui-clipboard-dialog-export-fmt-mini" class="red-ui-button red-ui-button-small toggle" href="#" data-i18n="clipboard.export.compact"></a>'+
'<a id="red-ui-clipboard-dialog-export-fmt-full" class="red-ui-button red-ui-button-small toggle" href="#" data-i18n="clipboard.export.formatted"></a>'+
'</span>'+
'</div>'+
'</div>'+
'</div>'+
'<div id="red-ui-clipboard-dialog-export-tab-library" class="red-ui-clipboard-dialog-tab-library">'+
@@ -592,6 +598,30 @@ RED.clipboard = (function() {
})
loadFlowLibrary(libraryBrowser,"local",RED._("library.types.local"));
var clipboardTabs = RED.tabs.create({
id: "red-ui-clipboard-dialog-export-tab-clipboard-tabs",
onchange: function(tab) {
$(".red-ui-clipboard-dialog-export-tab-clipboard-tab").hide();
$("#" + tab.id).show();
}
});
clipboardTabs.addTab({
id: "red-ui-clipboard-dialog-export-tab-clipboard-preview",
label: RED._("clipboard.exportNodes")
});
clipboardTabs.addTab({
id: "red-ui-clipboard-dialog-export-tab-clipboard-json",
label: RED._("editor.types.json")
});
var previewList = $("#red-ui-clipboard-dialog-export-tab-clipboard-preview-list").css({position:"absolute",top:0,right:0,bottom:0,left:0}).treeList({
data: []
})
refreshExportPreview();
$("#red-ui-clipboard-dialog-tab-library-name").val("flows.json").select();
dialogContainer.i18n();
@@ -630,10 +660,10 @@ RED.clipboard = (function() {
}
$(this).parent().children().removeClass('selected');
$(this).addClass('selected');
var type = $(this).attr('id');
var type = $(this).attr('id').substring("red-ui-clipboard-dialog-export-rng-".length);
var flow = "";
var nodes = null;
if (type === 'red-ui-clipboard-dialog-export-rng-selected') {
if (type === 'selected') {
var selection = RED.workspaces.selection();
if (selection.length > 0) {
nodes = [];
@@ -647,14 +677,14 @@ RED.clipboard = (function() {
}
// Don't include the subflow meta-port nodes in the exported selection
nodes = RED.nodes.createExportableNodeSet(nodes.filter(function(n) { return n.type !== 'subflow'}));
} else if (type === 'red-ui-clipboard-dialog-export-rng-flow') {
} else if (type === 'flow') {
var activeWorkspace = RED.workspaces.active();
nodes = RED.nodes.groups(activeWorkspace);
nodes = nodes.concat(RED.nodes.filterNodes({z:activeWorkspace}));
var parentNode = RED.nodes.workspace(activeWorkspace)||RED.nodes.subflow(activeWorkspace);
nodes.unshift(parentNode);
nodes = RED.nodes.createExportableNodeSet(nodes);
} else if (type === 'red-ui-clipboard-dialog-export-rng-full') {
} else if (type === 'full') {
nodes = RED.nodes.createCompleteNodeSet(false);
}
if (nodes !== null) {
@@ -670,8 +700,10 @@ RED.clipboard = (function() {
$("#red-ui-clipboard-dialog-export").addClass('disabled');
}
$("#red-ui-clipboard-dialog-export-text").val(flow);
setTimeout(function() { $("#red-ui-clipboard-dialog-export-text").scrollTop(0); },50);
$("#red-ui-clipboard-dialog-export-text").trigger("focus");
setTimeout(function() {
$("#red-ui-clipboard-dialog-export-text").scrollTop(0);
refreshExportPreview(type);
},50);
})
$("#red-ui-clipboard-dialog-ok").hide();
@@ -717,6 +749,93 @@ RED.clipboard = (function() {
}
function refreshExportPreview(type) {
var flowData = $("#red-ui-clipboard-dialog-export-text").val() || "[]";
var flow = JSON.parse(flowData);
var flows = {};
var subflows = {};
var nodes = [];
var nodesByZ = {};
var treeFlows = [];
var treeSubflows = [];
flow.forEach(function(node) {
if (node.type === "tab") {
flows[node.id] = {
element: getFlowLabel(node,false),
deferBuild: type !== "flow",
expanded: type === "flow",
children: []
};
treeFlows.push(flows[node.id])
} else if (node.type === "subflow") {
subflows[node.id] = {
element: getNodeLabel(node,false),
deferBuild: true,
children: []
};
treeSubflows.push(subflows[node.id])
} else {
nodes.push(node);
}
});
var globalNodes = [];
var parentlessNodes = [];
nodes.forEach(function(node) {
var treeNode = {
element: getNodeLabel(node, false, false)
};
if (node.z) {
if (!flows[node.z] && !subflows[node.z]) {
parentlessNodes.push(treeNode)
} else if (flows[node.z]) {
flows[node.z].children.push(treeNode)
} else if (subflows[node.z]) {
subflows[node.z].children.push(treeNode)
}
} else {
globalNodes.push(treeNode);
}
});
var treeData = [];
if (parentlessNodes.length > 0) {
treeData = treeData.concat(parentlessNodes);
}
if (type === "flow") {
treeData = treeData.concat(treeFlows);
} else if (treeFlows.length > 0) {
treeData.push({
label: RED._("menu.label.flows"),
deferBuild: treeFlows.length > 20,
expanded: treeFlows.length <= 20,
children: treeFlows
})
}
if (treeSubflows.length > 0) {
treeData.push({
label: RED._("menu.label.subflows"),
deferBuild: treeSubflows.length > 10,
expanded: treeSubflows.length <= 10,
children: treeSubflows
})
}
if (globalNodes.length > 0) {
treeData.push({
label: RED._("sidebar.info.globalConfig"),
deferBuild: globalNodes.length > 10,
expanded: globalNodes.length <= 10,
children: globalNodes
})
}
$("#red-ui-clipboard-dialog-export-tab-clipboard-preview-list").treeList('data',treeData);
}
function loadFlowLibrary(browser,library,label) {
// if (includeExamples) {
// listing.push({
@@ -756,6 +875,7 @@ RED.clipboard = (function() {
}
function copyText(value,element,msg) {
var truncated = false;
var currentFocus = document.activeElement;
if (typeof value !== "string" ) {
value = JSON.stringify(value, function(key,value) {
if (value !== null && typeof value === 'object') {
@@ -787,7 +907,7 @@ RED.clipboard = (function() {
if (truncated) {
msg += "_truncated";
}
$("#red-ui-clipboard-hidden").val(value).select();
$("#red-ui-clipboard-hidden").val(value).focus().select();
var result = document.execCommand("copy");
if (result && element) {
var popover = RED.popover.create({
@@ -801,6 +921,10 @@ RED.clipboard = (function() {
},1000);
popover.open();
}
$("#red-ui-clipboard-hidden").val("");
if (currentFocus) {
$(currentFocus).focus();
}
return result;
}

View File

@@ -444,16 +444,18 @@ RED.editor = (function() {
for (var d in definition.defaults) {
if (definition.defaults.hasOwnProperty(d)) {
if (definition.defaults[d].type) {
var configTypeDef = RED.nodes.getType(definition.defaults[d].type);
if (configTypeDef) {
if (configTypeDef.exclusive) {
prepareConfigNodeButton(node,d,definition.defaults[d].type,prefix);
if (!definition.defaults[d]._type.array) {
var configTypeDef = RED.nodes.getType(definition.defaults[d].type);
if (configTypeDef && configTypeDef.category === 'config') {
if (configTypeDef.exclusive) {
prepareConfigNodeButton(node,d,definition.defaults[d].type,prefix);
} else {
prepareConfigNodeSelect(node,d,definition.defaults[d].type,prefix);
}
} else {
prepareConfigNodeSelect(node,d,definition.defaults[d].type,prefix);
console.log("Unknown type:", definition.defaults[d].type);
preparePropertyEditor(node,d,prefix,definition.defaults);
}
} else {
console.log("Unknown type:", definition.defaults[d].type);
preparePropertyEditor(node,d,prefix,definition.defaults);
}
} else {
preparePropertyEditor(node,d,prefix,definition.defaults);
@@ -494,11 +496,13 @@ RED.editor = (function() {
populateCredentialsInputs(node, definition.credentials, node.credentials, prefix);
completePrepare();
} else {
$.getJSON(getCredentialsURL(node.type, node.id), function (data) {
node.credentials = data;
node.credentials._ = $.extend(true,{},data);
if (!/^subflow:/.test(definition.type)) {
populateCredentialsInputs(node, definition.credentials, node.credentials, prefix);
getNodeCredentials(node.type, node.id, function(data) {
if (data) {
node.credentials = data;
node.credentials._ = $.extend(true,{},data);
if (!/^subflow:/.test(definition.type)) {
populateCredentialsInputs(node, definition.credentials, node.credentials, prefix);
}
}
completePrepare();
});
@@ -1086,8 +1090,11 @@ RED.editor = (function() {
node.infoEditor = nodeInfoEditor;
return nodeInfoEditor;
}
var buildingEditDialog = false;
function showEditDialog(node, defaultTab) {
if (buildingEditDialog) { return }
buildingEditDialog = true;
var editing_node = node;
var isDefaultIcon;
var defaultIcon;
@@ -1612,6 +1619,7 @@ RED.editor = (function() {
if (defaultTab) {
editorTabs.activateTab(defaultTab);
}
buildingEditDialog = false;
done();
});
},
@@ -1663,6 +1671,8 @@ RED.editor = (function() {
* prefix - the input prefix of the parent property
*/
function showEditConfigNodeDialog(name,type,id,prefix) {
if (buildingEditDialog) { return }
buildingEditDialog = true;
var adding = (id == "_ADD_");
var node_def = RED.nodes.getType(type);
var editing_config_node = RED.nodes.node(id);
@@ -1826,6 +1836,7 @@ RED.editor = (function() {
trayBody.i18n();
trayFooter.i18n();
finishedBuilding = true;
buildingEditDialog = false;
done();
});
},
@@ -2149,6 +2160,8 @@ RED.editor = (function() {
}
function showEditSubflowDialog(subflow) {
if (buildingEditDialog) { return }
buildingEditDialog = true;
var editing_node = subflow;
editStack.push(subflow);
RED.view.state(RED.state.EDITING);
@@ -2405,15 +2418,17 @@ RED.editor = (function() {
buildEditForm(nodePropertiesTab.content,"dialog-form","subflow-template", undefined, editing_node);
trayBody.i18n();
$.getJSON(getCredentialsURL("subflow", subflow.id), function (data) {
subflow.credentials = data;
subflow.credentials._ = $.extend(true,{},data);
getNodeCredentials("subflow", subflow.id, function(data) {
if (data) {
subflow.credentials = data;
subflow.credentials._ = $.extend(true,{},data);
}
$("#subflow-input-name").val(subflow.name);
RED.text.bidi.prepareInput($("#subflow-input-name"));
finishedBuilding = true;
buildingEditDialog = false;
done();
});
},
@@ -2434,7 +2449,39 @@ RED.editor = (function() {
RED.tray.show(trayOptions);
}
function getNodeCredentials(type, id, done) {
var timeoutNotification;
var intialTimeout = setTimeout(function() {
timeoutNotification = RED.notify($('<p data-i18n="[prepend]editor.loadCredentials"> <img src="red/images/spin.svg"/></p>').i18n(),{fixed: true})
},800);
$.ajax({
url: getCredentialsURL(type,id),
dataType: 'json',
success: function(data) {
if (timeoutNotification) {
timeoutNotification.close();
timeoutNotification = null;
}
clearTimeout(intialTimeout);
done(data);
},
error: function(jqXHR,status,error) {
if (timeoutNotification) {
timeoutNotification.close();
timeoutNotification = null;
}
clearTimeout(intialTimeout);
RED.notify(RED._("editor.errors.credentialLoadFailed"),"error")
done(null);
},
timeout: 30000,
});
}
function showEditGroupDialog(group) {
if (buildingEditDialog) { return }
buildingEditDialog = true;
var editing_node = group;
editStack.push(group);
RED.view.state(RED.state.EDITING);
@@ -2658,6 +2705,7 @@ RED.editor = (function() {
prepareEditDialog(group,group._def,"node-input", function() {
trayBody.i18n();
finishedBuilding = true;
buildingEditDialog = false;
done();
});
},

View File

@@ -97,13 +97,18 @@ RED.palette = (function() {
label = RED.utils.sanitize(label);
var words = label.split(/[ -]/);
var words = label.split(/([ -]|\\n )/);
var displayLines = [];
var currentLine = "";
for (var i=0;i<words.length;i++) {
var word = words[i];
if (word === "\\n ") {
displayLines.push(currentLine);
currentLine = "";
continue;
}
var sep = (i == 0) ? "" : " ";
var newWidth = RED.view.calculateTextWidth(currentLine+sep+word, "red-ui-palette-label");
if (newWidth < nodeWidth) {
@@ -165,7 +170,16 @@ RED.palette = (function() {
metaData = typeInfo.set.module+" : ";
}
metaData += type;
$('<button type="button" onclick="RED.sidebar.help.show(\''+type+'\'); return false;" class="red-ui-button red-ui-button-small" style="float: right"><i class="fa fa-book"></i></button>').appendTo(popOverContent)
if (/^subflow:/.test(type)) {
$('<button type="button" onclick="RED.workspaces.show(\''+type.substring(8).replace(/'/g,"\\'")+'\'); return false;" class="red-ui-button red-ui-button-small" style="float: right; margin-left: 5px;"><i class="fa fa-pencil"></i></button>').appendTo(popOverContent)
}
var safeType = type.replace(/'/g,"\\'");
$('<button type="button" onclick="RED.search.show(\'type:'+safeType+'\'); return false;" class="red-ui-button red-ui-button-small" style="float: right; margin-left: 5px;"><i class="fa fa-search"></i></button>').appendTo(popOverContent)
$('<button type="button" onclick="RED.sidebar.help.show(\''+safeType+'\'); return false;" class="red-ui-button red-ui-button-small" style="float: right; margin-left: 5px;"><i class="fa fa-book"></i></button>').appendTo(popOverContent)
$('<p>',{style:"font-size: 0.8em"}).text(metaData).appendTo(popOverContent);
}
} catch(err) {
@@ -396,7 +410,8 @@ RED.palette = (function() {
RED.workspaces.show(nt.substring(8));
e.preventDefault();
});
nodeInfo = RED.utils.renderMarkdown(def.info||"");
var subflow = RED.nodes.subflow(nt.substring(8));
nodeInfo = RED.utils.renderMarkdown(subflow.info||"");
}
setLabel(nt,d,label,nodeInfo);

View File

@@ -464,12 +464,43 @@ RED.subflow = (function() {
$("#red-ui-subflow-delete").on("click", function(event) {
event.preventDefault();
var startDirty = RED.nodes.dirty();
var historyEvent = removeSubflow(RED.workspaces.active());
historyEvent.t = 'delete';
historyEvent.dirty = startDirty;
var subflow = RED.nodes.subflow(RED.workspaces.active());
if (subflow.instances.length > 0) {
var msg = $('<div>')
$('<p>').text(RED._("subflow.subflowInstances",{count: subflow.instances.length})).appendTo(msg);
$('<p>').text(RED._("subflow.confirmDelete")).appendTo(msg);
var confirmDeleteNotification = RED.notify(msg, {
modal: true,
fixed: true,
buttons: [
{
text: RED._('common.label.cancel'),
click: function() {
confirmDeleteNotification.close();
}
},
{
text: RED._('workspace.confirmDelete'),
class: "primary",
click: function() {
confirmDeleteNotification.close();
completeDelete();
}
}
]
});
RED.history.push(historyEvent);
return;
} else {
completeDelete();
}
function completeDelete() {
var startDirty = RED.nodes.dirty();
var historyEvent = removeSubflow(RED.workspaces.active());
historyEvent.t = 'delete';
historyEvent.dirty = startDirty;
RED.history.push(historyEvent);
}
});

View File

@@ -119,34 +119,17 @@ RED.sidebar.info.outliner = (function() {
return div;
}
function getSubflowLabel(n) {
var div = $('<div>',{class:"red-ui-info-outline-item"});
RED.utils.createNodeIcon(n).appendTo(div);
var contentDiv = $('<div>',{class:"red-ui-search-result-description"}).appendTo(div);
var labelText = getNodeLabelText(n);
var label = $('<div>',{class:"red-ui-search-result-node-label red-ui-info-outline-item-label"}).appendTo(contentDiv);
if (labelText) {
label.text(labelText)
} else {
label.html("&nbsp;")
}
addControls(n, div);
return div;
// var div = $('<div>',{class:"red-ui-info-outline-item red-ui-info-outline-item-flow"});
// var contentDiv = $('<div>',{class:"red-ui-search-result-description red-ui-info-outline-item-label"}).appendTo(div);
// contentDiv.text(n.name || n.id);
// addControls(n, div);
// return div;
}
function addControls(n,div) {
var controls = $('<div>',{class:"red-ui-info-outline-item-controls red-ui-info-outline-item-hover-controls"}).appendTo(div);
if (n.type === "subflow") {
var subflowInstanceBadge = $('<button type="button" class="red-ui-info-outline-item-control-users red-ui-button red-ui-button-small"><i class="fa fa-toggle-right"></i></button>').text(n.instances.length).appendTo(controls).on("click",function(evt) {
evt.preventDefault();
evt.stopPropagation();
RED.search.show("type:subflow:"+n.id);
})
// RED.popover.tooltip(userCountBadge,function() { return RED._('editor.nodesUse',{count:n.users.length})});
}
if (n._def.category === "config" && n.type !== "group") {
var userCountBadge = $('<button type="button" class="red-ui-info-outline-item-control-users red-ui-button red-ui-button-small"><i class="fa fa-toggle-right"></i></button>').text(n.users.length).appendTo(controls).on("click",function(evt) {
evt.preventDefault();
@@ -169,7 +152,7 @@ RED.sidebar.info.outliner = (function() {
// evt.stopPropagation();
// RED.view.reveal(n.id);
// })
if (n.type !== 'group' && n.type !== 'subflow') {
if (n.type !== 'subflow') {
var toggleButton = $('<button type="button" class="red-ui-info-outline-item-control-disable red-ui-button red-ui-button-small"><i class="fa fa-circle-thin"></i><i class="fa fa-ban"></i></button>').appendTo(controls).on("click",function(evt) {
evt.preventDefault();
evt.stopPropagation();
@@ -179,6 +162,46 @@ RED.sidebar.info.outliner = (function() {
} else {
RED.workspaces.disable(n.id)
}
} else if (n.type === 'group') {
var groupNodes = RED.group.getNodes(n,true);
var groupHistoryEvent = {
t:'multi',
events:[],
dirty: RED.nodes.dirty()
}
var targetState;
groupNodes.forEach(function(n) {
if (n.type !== 'group') {
if (targetState === undefined) {
targetState = !n.d;
}
var state = !!n.d;
if (state !== targetState) {
var historyEvent = {
t: "edit",
node: n,
changed: n.changed,
changes: {
d: n.d
}
}
if (n.d) {
delete n.d;
} else {
n.d = true;
}
n.dirty = true;
n.changed = true;
RED.events.emit("nodes:change",n);
groupHistoryEvent.events.push(historyEvent);
}
}
if (groupHistoryEvent.events.length > 0) {
RED.history.push(groupHistoryEvent);
RED.nodes.dirty(true)
RED.view.redraw();
}
})
} else {
// TODO: this ought to be a utility function in RED.nodes
var historyEvent = {
@@ -198,11 +221,15 @@ RED.sidebar.info.outliner = (function() {
n.dirty = true;
n.changed = true;
RED.events.emit("nodes:change",n);
RED.history.push(historyEvent);
RED.nodes.dirty(true)
RED.view.redraw();
}
});
RED.popover.tooltip(toggleButton,function() {
if (n.type === "group") {
return RED._("common.label.enable")+" / "+RED._("common.label.disable")
}
return RED._("common.label."+(((n.type==='tab' && n.disabled) || (n.type!=='tab' && n.d))?"enable":"disable"));
});
} else {
@@ -486,6 +513,13 @@ RED.sidebar.info.outliner = (function() {
existingObject.treeList.remove();
delete objects[n.id]
if (/^subflow:/.test(n.type)) {
var sfType = n.type.substring(8);
if (objects[sfType]) {
objects[sfType].element.find(".red-ui-info-outline-item-control-users").text(RED.nodes.subflow(sfType).instances.length);
}
}
// If this is a group being removed, it may have an empty item
if (empties[n.id]) {
delete empties[n.id];
@@ -587,6 +621,12 @@ RED.sidebar.info.outliner = (function() {
configNodeTypes[parent].types[n.type].treeList.addChild(objects[n.id]);
}
objects[n.id].element.toggleClass("red-ui-info-outline-item-disabled", !!n.d)
if (/^subflow:/.test(n.type)) {
var sfType = n.type.substring(8);
if (objects[sfType]) {
objects[sfType].element.find(".red-ui-info-outline-item-control-users").text(RED.nodes.subflow(sfType).instances.length);
}
}
updateSearch();
}

View File

@@ -338,7 +338,7 @@ RED.sidebar.info = (function() {
count++;
propRow = $('<tr class="red-ui-help-info-property-row'+(expandedSections.property?"":" hide")+'"><td></td><td></td></tr>').appendTo(tableBody);
$(propRow.children()[0]).text(n);
if (defaults[n].type) {
if (defaults[n].type && !defaults[n]._type.array) {
var configNode = RED.nodes.node(val);
if (!configNode) {
RED.utils.createObjectElement(undefined).appendTo(propRow.children()[1]);

View File

@@ -109,13 +109,19 @@ RED.userSettings = (function() {
function compText(a, b) {
return a.text.localeCompare(b.text);
}
var viewSettings = [
{
options: [
{setting:"editor-language",local: true, label:"menu.label.view.language",options:function(done){ done([{val:'',text:RED._('menu.label.view.browserDefault')}].concat(RED.settings.theme("languages").map(localeToName).sort(compText))) }},
]
},{
},
// {
// options: [
// {setting:"theme", label:"Theme",options:function(done){ done([{val:'',text:'default'}].concat(RED.settings.theme("themes"))) }},
// ]
// },
{
title: "menu.label.view.grid",
options: [
{setting:"view-show-grid",oldSetting:"menu-menu-item-view-show-grid",label:"menu.label.view.showGrid", default: true, toggle:true,onchange:"core:toggle-show-grid"},

View File

@@ -615,18 +615,25 @@ RED.utils = (function() {
return element;
}
function normalisePropertyExpression(str) {
function createError(code, message) {
var e = new Error(message);
e.code = code;
return e;
}
function normalisePropertyExpression(str,msg) {
// This must be kept in sync with validatePropertyExpression
// in editor/js/ui/utils.js
var length = str.length;
if (length === 0) {
throw new Error("Invalid property expression: zero-length");
throw createError("INVALID_EXPR","Invalid property expression: zero-length");
}
var parts = [];
var start = 0;
var inString = false;
var inBox = false;
var boxExpression = false;
var quoteChar;
var v;
for (var i=0;i<length;i++) {
@@ -634,14 +641,14 @@ RED.utils = (function() {
if (!inString) {
if (c === "'" || c === '"') {
if (i != start) {
throw new Error("Invalid property expression: unexpected "+c+" at position "+i);
throw createError("INVALID_EXPR","Invalid property expression: unexpected "+c+" at position "+i);
}
inString = true;
quoteChar = c;
start = i+1;
} else if (c === '.') {
if (i===0) {
throw new Error("Invalid property expression: unexpected . at position 0");
throw createError("INVALID_EXPR","Invalid property expression: unexpected . at position 0");
}
if (start != i) {
v = str.substring(start,i);
@@ -652,57 +659,99 @@ RED.utils = (function() {
}
}
if (i===length-1) {
throw new Error("Invalid property expression: unterminated expression");
throw createError("INVALID_EXPR","Invalid property expression: unterminated expression");
}
// Next char is first char of an identifier: a-z 0-9 $ _
if (!/[a-z0-9\$\_]/i.test(str[i+1])) {
throw new Error("Invalid property expression: unexpected "+str[i+1]+" at position "+(i+1));
throw createError("INVALID_EXPR","Invalid property expression: unexpected "+str[i+1]+" at position "+(i+1));
}
start = i+1;
} else if (c === '[') {
if (i === 0) {
throw new Error("Invalid property expression: unexpected "+c+" at position "+i);
throw createError("INVALID_EXPR","Invalid property expression: unexpected "+c+" at position "+i);
}
if (start != i) {
parts.push(str.substring(start,i));
}
if (i===length-1) {
throw new Error("Invalid property expression: unterminated expression");
throw createError("INVALID_EXPR","Invalid property expression: unterminated expression");
}
// Next char is either a quote or a number
if (!/["'\d]/.test(str[i+1])) {
throw new Error("Invalid property expression: unexpected "+str[i+1]+" at position "+(i+1));
// Start of a new expression. If it starts with msg it is a nested expression
// Need to scan ahead to find the closing bracket
if (/^msg[.\[]/.test(str.substring(i+1))) {
var depth = 1;
var inLocalString = false;
var localStringQuote;
for (var j=i+1;j<length;j++) {
if (/["']/.test(str[j])) {
if (inLocalString) {
if (str[j] === localStringQuote) {
inLocalString = false
}
} else {
inLocalString = true;
localStringQuote = str[j]
}
}
if (str[j] === '[') {
depth++;
} else if (str[j] === ']') {
depth--;
}
if (depth === 0) {
try {
if (msg) {
parts.push(getMessageProperty(msg, str.substring(i+1,j)))
} else {
parts.push(normalisePropertyExpression(str.substring(i+1,j), msg));
}
inBox = false;
i = j;
start = j+1;
break;
} catch(err) {
throw createError("INVALID_EXPR","Invalid expression started at position "+(i+1))
}
}
}
if (depth > 0) {
throw createError("INVALID_EXPR","Invalid property expression: unmatched '[' at position "+i);
}
continue;
} else if (!/["'\d]/.test(str[i+1])) {
// Next char is either a quote or a number
throw createError("INVALID_EXPR","Invalid property expression: unexpected "+str[i+1]+" at position "+(i+1));
}
start = i+1;
inBox = true;
} else if (c === ']') {
if (!inBox) {
throw new Error("Invalid property expression: unexpected "+c+" at position "+i);
throw createError("INVALID_EXPR","Invalid property expression: unexpected "+c+" at position "+i);
}
if (start != i) {
v = str.substring(start,i);
if (/^\d+$/.test(v)) {
parts.push(parseInt(v));
} else {
throw new Error("Invalid property expression: unexpected array expression at position "+start);
throw createError("INVALID_EXPR","Invalid property expression: unexpected array expression at position "+start);
}
}
start = i+1;
inBox = false;
} else if (c === ' ') {
throw new Error("Invalid property expression: unexpected ' ' at position "+i);
throw createError("INVALID_EXPR","Invalid property expression: unexpected ' ' at position "+i);
}
} else {
if (c === quoteChar) {
if (i-start === 0) {
throw new Error("Invalid property expression: zero-length string at position "+start);
throw createError("INVALID_EXPR","Invalid property expression: zero-length string at position "+start);
}
parts.push(str.substring(start,i));
// If inBox, next char must be a ]. Otherwise it may be [ or .
if (inBox && !/\]/.test(str[i+1])) {
throw new Error("Invalid property expression: unexpected array expression at position "+start);
throw createError("INVALID_EXPR","Invalid property expression: unexpected array expression at position "+start);
} else if (!inBox && i+1!==length && !/[\[\.]/.test(str[i+1])) {
throw new Error("Invalid property expression: unexpected "+str[i+1]+" expression at position "+(i+1));
throw createError("INVALID_EXPR","Invalid property expression: unexpected "+str[i+1]+" expression at position "+(i+1));
}
start = i+1;
inString = false;
@@ -711,7 +760,7 @@ RED.utils = (function() {
}
if (inBox || inString) {
throw new Error("Invalid property expression: unterminated expression");
throw new createError("INVALID_EXPR","Invalid property expression: unterminated expression");
}
if (start < length) {
parts.push(str.substring(start));

View File

@@ -2276,7 +2276,7 @@ RED.view = (function() {
}
function calculateTextWidth(str, className) {
var result=convertLineBreakCharacter(str);
var result = convertLineBreakCharacter(str);
var width = 0;
for (var i=0;i<result.length;i++) {
var calculateTextW=calculateTextDimensions(result[i],className)[0];