mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
Move envVar list component to own file
This commit is contained in:
parent
741fe3dd90
commit
4463a7d4ba
@ -593,10 +593,11 @@ RED.nodes = (function() {
|
||||
outputLabels: function(i) { return sf.outputLabels?sf.outputLabels[i]:null },
|
||||
oneditprepare: function() {
|
||||
if (this.type !== 'subflow') {
|
||||
// Whilst this definition is used for both template and instance
|
||||
// nodes, the work to build the edit form for the template nodes
|
||||
// is handled elsewhere.
|
||||
// A subflow instance node
|
||||
RED.subflow.buildEditForm("subflow",this);
|
||||
} else {
|
||||
// A subflow template node
|
||||
RED.subflow.buildEditForm("subflow-template", this);
|
||||
}
|
||||
},
|
||||
oneditresize: function(size) {
|
||||
@ -681,7 +682,13 @@ RED.nodes = (function() {
|
||||
}
|
||||
|
||||
|
||||
function convertWorkspace(n) {
|
||||
function convertWorkspace(n,opts) {
|
||||
var exportCreds = true;
|
||||
if (opts) {
|
||||
if (opts.hasOwnProperty("credentials")) {
|
||||
exportCreds = opts.credentials;
|
||||
}
|
||||
}
|
||||
var node = {};
|
||||
node.id = n.id;
|
||||
node.type = n.type;
|
||||
@ -690,19 +697,21 @@ RED.nodes = (function() {
|
||||
node[d] = n[d];
|
||||
}
|
||||
}
|
||||
var credentialSet = {};
|
||||
if (n.credentials) {
|
||||
for (var tabCred in n.credentials) {
|
||||
if (n.credentials.hasOwnProperty(tabCred)) {
|
||||
if (!n.credentials._ ||
|
||||
n.credentials["has_"+tabCred] != n.credentials._["has_"+tabCred] ||
|
||||
(n.credentials["has_"+tabCred] && n.credentials[tabCred])) {
|
||||
credentialSet[tabCred] = n.credentials[tabCred];
|
||||
if (exportCreds) {
|
||||
var credentialSet = {};
|
||||
if (n.credentials) {
|
||||
for (var tabCred in n.credentials) {
|
||||
if (n.credentials.hasOwnProperty(tabCred)) {
|
||||
if (!n.credentials._ ||
|
||||
n.credentials["has_"+tabCred] != n.credentials._["has_"+tabCred] ||
|
||||
(n.credentials["has_"+tabCred] && n.credentials[tabCred])) {
|
||||
credentialSet[tabCred] = n.credentials[tabCred];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Object.keys(credentialSet).length > 0) {
|
||||
node.credentials = credentialSet;
|
||||
if (Object.keys(credentialSet).length > 0) {
|
||||
node.credentials = credentialSet;
|
||||
}
|
||||
}
|
||||
}
|
||||
return node;
|
||||
@ -725,7 +734,7 @@ RED.nodes = (function() {
|
||||
}
|
||||
|
||||
if (n.type === 'tab') {
|
||||
return convertWorkspace(n);
|
||||
return convertWorkspace(n, { credentials: exportCreds });
|
||||
}
|
||||
var node = {};
|
||||
node.id = n.id;
|
||||
@ -1047,7 +1056,7 @@ RED.nodes = (function() {
|
||||
var i;
|
||||
for (i=0;i<workspacesOrder.length;i++) {
|
||||
if (workspaces[workspacesOrder[i]].type == "tab") {
|
||||
nns.push(convertWorkspace(workspaces[workspacesOrder[i]]));
|
||||
nns.push(convertWorkspace(workspaces[workspacesOrder[i]], opts));
|
||||
}
|
||||
}
|
||||
for (i in subflows) {
|
||||
|
616
packages/node_modules/@node-red/editor-client/src/js/ui/editors/envVarList.js
vendored
Normal file
616
packages/node_modules/@node-red/editor-client/src/js/ui/editors/envVarList.js
vendored
Normal file
@ -0,0 +1,616 @@
|
||||
RED.editor.envVarList = (function() {
|
||||
|
||||
var currentLocale = 'en-US';
|
||||
var DEFAULT_ENV_TYPE_LIST = ['str','num','bool','json','bin','env'];
|
||||
var DEFAULT_ENV_TYPE_LIST_INC_CRED = ['str','num','bool','json','bin','env','cred'];
|
||||
|
||||
/**
|
||||
* Create env var edit interface
|
||||
* @param container - container
|
||||
* @param node - subflow node
|
||||
*/
|
||||
function buildPropertiesList(envContainer, node) {
|
||||
|
||||
var isTemplateNode = (node.type === "subflow");
|
||||
|
||||
envContainer
|
||||
.css({
|
||||
'min-height':'150px',
|
||||
'min-width':'450px'
|
||||
})
|
||||
.editableList({
|
||||
header: isTemplateNode?$('<div><div><div></div><div data-i18n="common.label.name"></div><div data-i18n="editor-tab.defaultValue"></div><div></div></div></div>'):undefined,
|
||||
addItem: function(container, i, opt) {
|
||||
// If this is an instance node, these are properties unique to
|
||||
// this instance - ie opt.parent will not be defined.
|
||||
|
||||
if (isTemplateNode) {
|
||||
container.addClass("red-ui-editor-subflow-env-editable")
|
||||
}
|
||||
|
||||
var envRow = $('<div/>').appendTo(container);
|
||||
var nameField = null;
|
||||
var valueField = null;
|
||||
|
||||
nameField = $('<input/>', {
|
||||
class: "node-input-env-name",
|
||||
type: "text",
|
||||
placeholder: RED._("common.label.name")
|
||||
}).attr("autocomplete","disable").appendTo(envRow).val(opt.name);
|
||||
valueField = $('<input/>',{
|
||||
style: "width:100%",
|
||||
class: "node-input-env-value",
|
||||
type: "text",
|
||||
}).attr("autocomplete","disable").appendTo(envRow)
|
||||
valueField.typedInput({default:'str',types:isTemplateNode?DEFAULT_ENV_TYPE_LIST:DEFAULT_ENV_TYPE_LIST_INC_CRED});
|
||||
valueField.typedInput('type', opt.type);
|
||||
if (opt.type === "cred") {
|
||||
if (opt.value) {
|
||||
valueField.typedInput('value', opt.value);
|
||||
} else if (node.credentials && node.credentials[opt.name]) {
|
||||
valueField.typedInput('value', node.credentials[opt.name]);
|
||||
} else if (node.credentials && node.credentials['has_'+opt.name]) {
|
||||
valueField.typedInput('value', "__PWRD__");
|
||||
} else {
|
||||
valueField.typedInput('value', "");
|
||||
}
|
||||
} else {
|
||||
valueField.typedInput('value', opt.value);
|
||||
}
|
||||
|
||||
|
||||
opt.nameField = nameField;
|
||||
opt.valueField = valueField;
|
||||
|
||||
var actionButton = $('<a/>',{href:"#",class:"red-ui-editableList-item-remove red-ui-button red-ui-button-small"}).appendTo(envRow);
|
||||
$('<i/>',{class:"fa "+(opt.parent?"fa-reply":"fa-remove")}).appendTo(actionButton);
|
||||
var removeTip = RED.popover.tooltip(actionButton,RED._("subflow.env.remove"));
|
||||
actionButton.on("click", function(evt) {
|
||||
evt.preventDefault();
|
||||
removeTip.close();
|
||||
container.parent().addClass("red-ui-editableList-item-deleting")
|
||||
container.fadeOut(300, function() {
|
||||
envContainer.editableList('removeItem',opt);
|
||||
});
|
||||
});
|
||||
|
||||
if (isTemplateNode) {
|
||||
// Add the UI customisation row
|
||||
// if `opt.ui` does not exist, then apply defaults. If these
|
||||
// defaults do not change then they will get stripped off
|
||||
// before saving.
|
||||
if (opt.type === 'cred') {
|
||||
opt.ui = opt.ui || {
|
||||
icon: "",
|
||||
type: "cred"
|
||||
}
|
||||
opt.ui.type = "cred";
|
||||
} else {
|
||||
opt.ui = opt.ui || {
|
||||
icon: "",
|
||||
type: "input",
|
||||
opts: {types:DEFAULT_ENV_TYPE_LIST}
|
||||
}
|
||||
}
|
||||
opt.ui.label = opt.ui.label || {};
|
||||
opt.ui.type = opt.ui.type || "input";
|
||||
|
||||
var uiRow = $('<div/>').appendTo(container).hide();
|
||||
// save current info for reverting on cancel
|
||||
// var copy = $.extend(true, {}, ui);
|
||||
|
||||
$('<a href="#"><i class="fa fa-angle-right"></a>').prependTo(envRow).on("click", function (evt) {
|
||||
evt.preventDefault();
|
||||
if ($(this).hasClass('expanded')) {
|
||||
uiRow.slideUp();
|
||||
$(this).removeClass('expanded');
|
||||
} else {
|
||||
uiRow.slideDown();
|
||||
$(this).addClass('expanded');
|
||||
}
|
||||
});
|
||||
|
||||
buildEnvEditRow(uiRow, opt.ui, nameField, valueField);
|
||||
nameField.trigger('change');
|
||||
}
|
||||
},
|
||||
sortable: ".red-ui-editableList-item-handle",
|
||||
removable: false
|
||||
});
|
||||
var parentEnv = {};
|
||||
var envList = [];
|
||||
if (/^subflow:/.test(node.type)) {
|
||||
var subflowDef = RED.nodes.subflow(node.type.substring(8));
|
||||
if (subflowDef.env) {
|
||||
subflowDef.env.forEach(function(env) {
|
||||
var item = {
|
||||
name:env.name,
|
||||
parent: {
|
||||
type: env.type,
|
||||
value: env.value,
|
||||
ui: env.ui
|
||||
}
|
||||
}
|
||||
envList.push(item);
|
||||
parentEnv[env.name] = item;
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (node.env) {
|
||||
for (var i = 0; i < node.env.length; i++) {
|
||||
var env = node.env[i];
|
||||
if (parentEnv.hasOwnProperty(env.name)) {
|
||||
parentEnv[env.name].type = env.type;
|
||||
parentEnv[env.name].value = env.value;
|
||||
} else {
|
||||
envList.push({
|
||||
name: env.name,
|
||||
type: env.type,
|
||||
value: env.value,
|
||||
ui: env.ui
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
envList.forEach(function(env) {
|
||||
if (env.parent && env.parent.ui && env.parent.ui.type === 'hide') {
|
||||
return;
|
||||
}
|
||||
if (!isTemplateNode && env.parent) {
|
||||
return;
|
||||
}
|
||||
envContainer.editableList('addItem', JSON.parse(JSON.stringify(env)));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create UI edit interface for environment variable
|
||||
* @param container - container
|
||||
* @param env - env var definition
|
||||
* @param nameField - name field of env var
|
||||
* @param valueField - value field of env var
|
||||
*/
|
||||
function buildEnvEditRow(container, ui, nameField, valueField) {
|
||||
container.addClass("red-ui-editor-subflow-env-ui-row")
|
||||
var topRow = $('<div></div>').appendTo(container);
|
||||
$('<div></div>').appendTo(topRow);
|
||||
$('<div>').text(RED._("editor.icon")).appendTo(topRow);
|
||||
$('<div>').text(RED._("editor.label")).appendTo(topRow);
|
||||
$('<div>').text(RED._("editor.inputType")).appendTo(topRow);
|
||||
|
||||
var row = $('<div></div>').appendTo(container);
|
||||
$('<div><i class="red-ui-editableList-item-handle fa fa-bars"></i></div>').appendTo(row);
|
||||
var typeOptions = {
|
||||
'input': {types:DEFAULT_ENV_TYPE_LIST},
|
||||
'select': {opts:[]},
|
||||
'spinner': {},
|
||||
'cred': {}
|
||||
};
|
||||
if (ui.opts) {
|
||||
typeOptions[ui.type] = ui.opts;
|
||||
} else {
|
||||
// Pick up the default values if not otherwise provided
|
||||
ui.opts = typeOptions[ui.type];
|
||||
}
|
||||
var iconCell = $('<div></div>').appendTo(row);
|
||||
|
||||
var iconButton = $('<a href="#"></a>').appendTo(iconCell);
|
||||
iconButton.on("click", function(evt) {
|
||||
evt.preventDefault();
|
||||
var icon = ui.icon || "";
|
||||
var iconPath = (icon ? RED.utils.separateIconPath(icon) : {});
|
||||
RED.editor.iconPicker.show(iconButton, null, iconPath, true, function (newIcon) {
|
||||
iconButton.empty();
|
||||
var path = newIcon || "";
|
||||
var newPath = RED.utils.separateIconPath(path);
|
||||
if (newPath) {
|
||||
$('<i class="fa"></i>').addClass(newPath.file).appendTo(iconButton);
|
||||
}
|
||||
ui.icon = path;
|
||||
});
|
||||
})
|
||||
|
||||
if (ui.icon) {
|
||||
var newPath = RED.utils.separateIconPath(ui.icon);
|
||||
$('<i class="fa '+newPath.file+'"></i>').appendTo(iconButton);
|
||||
}
|
||||
|
||||
var labelCell = $('<div></div>').appendTo(row);
|
||||
|
||||
var label = ui.label && ui.label[currentLocale] || "";
|
||||
var labelInput = $('<input type="text">').val(label).appendTo(labelCell);
|
||||
ui.labelField = labelInput;
|
||||
labelInput.on('change', function(evt) {
|
||||
ui.label = ui.label || {};
|
||||
var val = $(this).val().trim();
|
||||
if (val === "") {
|
||||
delete ui.label[currentLocale];
|
||||
} else {
|
||||
ui.label[currentLocale] = val;
|
||||
}
|
||||
})
|
||||
var labelIcon = $('<span class="red-ui-editor-subflow-env-lang-icon"><i class="fa fa-language"></i></span>').appendTo(labelCell);
|
||||
RED.popover.tooltip(labelIcon,function() {
|
||||
var langs = Object.keys(ui.label);
|
||||
var content = $("<div>");
|
||||
if (langs.indexOf(currentLocale) === -1) {
|
||||
langs.push(currentLocale);
|
||||
langs.sort();
|
||||
}
|
||||
langs.forEach(function(l) {
|
||||
var row = $('<div>').appendTo(content);
|
||||
$('<span>').css({display:"inline-block",width:"120px"}).text(RED._("languages."+l)+(l===currentLocale?"*":"")).appendTo(row);
|
||||
$('<span>').text(ui.label[l]||"").appendTo(row);
|
||||
});
|
||||
return content;
|
||||
})
|
||||
|
||||
nameField.on('change',function(evt) {
|
||||
labelInput.attr("placeholder",$(this).val())
|
||||
});
|
||||
|
||||
var inputCell = $('<div></div>').appendTo(row);
|
||||
var inputCellInput = $('<input type="text">').css("width","100%").appendTo(inputCell);
|
||||
if (ui.type === "input") {
|
||||
inputCellInput.val(ui.opts.types.join(","));
|
||||
}
|
||||
var checkbox;
|
||||
var selectBox;
|
||||
|
||||
inputCellInput.typedInput({
|
||||
types: [
|
||||
{
|
||||
value:"input",
|
||||
label:RED._("editor.inputs.input"), icon:"fa fa-i-cursor",showLabel:false,multiple:true,options:[
|
||||
{value:"str",label:RED._("editor.types.str"),icon:"red/images/typedInput/az.svg"},
|
||||
{value:"num",label:RED._("editor.types.num"),icon:"red/images/typedInput/09.svg"},
|
||||
{value:"bool",label:RED._("editor.types.bool"),icon:"red/images/typedInput/bool.svg"},
|
||||
{value:"json",label:RED._("editor.types.json"),icon:"red/images/typedInput/json.svg"},
|
||||
{value: "bin",label: RED._("editor.types.bin"),icon: "red/images/typedInput/bin.svg"},
|
||||
{value: "env",label: RED._("editor.types.env"),icon: "red/images/typedInput/env.svg"},
|
||||
{value: "cred",label: RED._("editor.types.cred"),icon: "fa fa-lock"}
|
||||
],
|
||||
default: DEFAULT_ENV_TYPE_LIST,
|
||||
valueLabel: function(container,value) {
|
||||
container.css("padding",0);
|
||||
var innerContainer = $('<div class="red-ui-editor-subflow-env-input-type"></div>').appendTo(container);
|
||||
|
||||
var input = $('<div class="placeholder-input">').appendTo(innerContainer);
|
||||
$('<span><i class="fa fa-i-cursor"></i></span>').appendTo(input);
|
||||
if (value.length) {
|
||||
value.forEach(function(v) {
|
||||
if (!/^fa /.test(v.icon)) {
|
||||
$('<img>',{src:v.icon,style:"max-width:14px; padding: 0 3px; margin-top:-4px; margin-left: 1px"}).appendTo(input);
|
||||
} else {
|
||||
var s = $('<span>',{style:"max-width:14px; padding: 0 3px; margin-top:-4px; margin-left: 1px"}).appendTo(input);
|
||||
$("<i>",{class: v.icon}).appendTo(s);
|
||||
}
|
||||
})
|
||||
} else {
|
||||
$('<span class="red-ui-editor-subflow-env-input-type-placeholder"></span>').text(RED._("editor.selectType")).appendTo(input);
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
value: "cred",
|
||||
label: RED._("typedInput.type.cred"), icon:"fa fa-lock", showLabel: false,
|
||||
valueLabel: function(container,value) {
|
||||
container.css("padding",0);
|
||||
var innerContainer = $('<div class="red-ui-editor-subflow-env-input-type">').css({
|
||||
"border-top-right-radius": "4px",
|
||||
"border-bottom-right-radius": "4px"
|
||||
}).appendTo(container);
|
||||
$('<div class="placeholder-input">').html("••••••••").appendTo(innerContainer);
|
||||
}
|
||||
},
|
||||
{
|
||||
value:"select",
|
||||
label:RED._("editor.inputs.select"), icon:"fa fa-tasks",showLabel:false,
|
||||
valueLabel: function(container,value) {
|
||||
container.css("padding","0");
|
||||
|
||||
selectBox = $('<select></select>').appendTo(container);
|
||||
if (ui.opts && Array.isArray(ui.opts.opts)) {
|
||||
ui.opts.opts.forEach(function(o) {
|
||||
var label = lookupLabel(o.l, o.l["en-US"]||o.v, currentLocale);
|
||||
// $('<option>').val((o.t||'str')+":"+o.v).text(label).appendTo(selectBox);
|
||||
$('<option>').val(o.v).text(label).appendTo(selectBox);
|
||||
})
|
||||
}
|
||||
selectBox.on('change', function(evt) {
|
||||
var v = selectBox.val();
|
||||
// var parts = v.split(":");
|
||||
// var t = parts.shift();
|
||||
// v = parts.join(":");
|
||||
//
|
||||
// valueField.typedInput("type",'str')
|
||||
valueField.typedInput("value",v)
|
||||
});
|
||||
selectBox.val(valueField.typedInput("value"));
|
||||
// selectBox.val(valueField.typedInput('type')+":"+valueField.typedInput("value"));
|
||||
},
|
||||
expand: {
|
||||
icon: "fa-caret-down",
|
||||
minWidth: 400,
|
||||
content: function(container) {
|
||||
var content = $('<div class="red-ui-editor-subflow-ui-edit-panel">').appendTo(container);
|
||||
var optList = $('<ol>').appendTo(content).editableList({
|
||||
header:$("<div><div>"+RED._("editor.select.label")+"</div><div>"+RED._("editor.select.value")+"</div></div>"),
|
||||
addItem: function(row,index,itemData) {
|
||||
var labelDiv = $('<div>').appendTo(row);
|
||||
var label = lookupLabel(itemData.l, "", currentLocale);
|
||||
itemData.label = $('<input type="text">').val(label).appendTo(labelDiv);
|
||||
itemData.label.on('keydown', function(evt) {
|
||||
if (evt.keyCode === 13) {
|
||||
itemData.input.focus();
|
||||
evt.preventDefault();
|
||||
}
|
||||
});
|
||||
var labelIcon = $('<span class="red-ui-editor-subflow-env-lang-icon"><i class="fa fa-language"></i></span>').appendTo(labelDiv);
|
||||
RED.popover.tooltip(labelIcon,function() {
|
||||
return currentLocale;
|
||||
})
|
||||
itemData.input = $('<input type="text">').val(itemData.v).appendTo(row);
|
||||
|
||||
// Problem using a TI here:
|
||||
// - this is in a popout panel
|
||||
// - clicking the expand button in the TI will close the parent edit tray
|
||||
// and open the type editor.
|
||||
// - but it leaves the popout panel over the top.
|
||||
// - there is no way to get back to the popout panel after closing the type editor
|
||||
//.typedInput({default:itemData.t||'str', types:DEFAULT_ENV_TYPE_LIST});
|
||||
itemData.input.on('keydown', function(evt) {
|
||||
if (evt.keyCode === 13) {
|
||||
// Enter or Tab
|
||||
var index = optList.editableList('indexOf',itemData);
|
||||
var length = optList.editableList('length');
|
||||
if (index + 1 === length) {
|
||||
var newItem = {};
|
||||
optList.editableList('addItem',newItem);
|
||||
setTimeout(function() {
|
||||
if (newItem.label) {
|
||||
newItem.label.focus();
|
||||
}
|
||||
},100)
|
||||
} else {
|
||||
var nextItem = optList.editableList('getItemAt',index+1);
|
||||
if (nextItem.label) {
|
||||
nextItem.label.focus()
|
||||
}
|
||||
}
|
||||
evt.preventDefault();
|
||||
}
|
||||
});
|
||||
},
|
||||
sortable: true,
|
||||
removable: true,
|
||||
height: 160
|
||||
})
|
||||
if (ui.opts.opts.length > 0) {
|
||||
ui.opts.opts.forEach(function(o) {
|
||||
optList.editableList('addItem',$.extend(true,{},o))
|
||||
})
|
||||
} else {
|
||||
optList.editableList('addItem',{})
|
||||
}
|
||||
return {
|
||||
onclose: function() {
|
||||
var items = optList.editableList('items');
|
||||
var vals = [];
|
||||
items.each(function (i,el) {
|
||||
var data = el.data('data');
|
||||
var l = data.label.val().trim();
|
||||
var v = data.input.val();
|
||||
// var t = data.input.typedInput('type');
|
||||
// var v = data.input.typedInput('value');
|
||||
if (l.length > 0) {
|
||||
data.l = data.l || {};
|
||||
data.l[currentLocale] = l;
|
||||
}
|
||||
data.v = v;
|
||||
|
||||
if (l.length > 0 || v.length > 0) {
|
||||
var val = {l:data.l,v:data.v};
|
||||
// if (t !== 'str') {
|
||||
// val.t = t;
|
||||
// }
|
||||
vals.push(val);
|
||||
}
|
||||
});
|
||||
ui.opts.opts = vals;
|
||||
inputCellInput.typedInput('value',Date.now())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
value:"checkbox",
|
||||
label:RED._("editor.inputs.checkbox"), icon:"fa fa-check-square-o",showLabel:false,
|
||||
valueLabel: function(container,value) {
|
||||
container.css("padding",0);
|
||||
checkbox = $('<input type="checkbox">').appendTo(container);
|
||||
checkbox.on('change', function(evt) {
|
||||
valueField.typedInput('value',$(this).prop('checked')?"true":"false");
|
||||
})
|
||||
checkbox.prop('checked',valueField.typedInput('value')==="true");
|
||||
}
|
||||
},
|
||||
{
|
||||
value:"spinner",
|
||||
label:RED._("editor.inputs.spinner"), icon:"fa fa-sort-numeric-asc", showLabel:false,
|
||||
valueLabel: function(container,value) {
|
||||
container.css("padding",0);
|
||||
var innerContainer = $('<div class="red-ui-editor-subflow-env-input-type"></div>').appendTo(container);
|
||||
|
||||
var input = $('<div class="placeholder-input">').appendTo(innerContainer);
|
||||
$('<span><i class="fa fa-sort-numeric-asc"></i></span>').appendTo(input);
|
||||
|
||||
var min = ui.opts && ui.opts.min;
|
||||
var max = ui.opts && ui.opts.max;
|
||||
var label = "";
|
||||
if (min !== undefined && max !== undefined) {
|
||||
label = Math.min(min,max)+" - "+Math.max(min,max);
|
||||
} else if (min !== undefined) {
|
||||
label = "> "+min;
|
||||
} else if (max !== undefined) {
|
||||
label = "< "+max;
|
||||
}
|
||||
$('<span>').css("margin-left","15px").text(label).appendTo(input);
|
||||
},
|
||||
expand: {
|
||||
icon: "fa-caret-down",
|
||||
content: function(container) {
|
||||
var content = $('<div class="red-ui-editor-subflow-ui-edit-panel">').appendTo(container);
|
||||
content.css("padding","8px 5px")
|
||||
var min = ui.opts.min;
|
||||
var max = ui.opts.max;
|
||||
var minInput = $('<input type="number" style="margin-bottom:0; width:60px">');
|
||||
minInput.val(min);
|
||||
var maxInput = $('<input type="number" style="margin-bottom:0; width:60px">');
|
||||
maxInput.val(max);
|
||||
$('<div class="form-row" style="margin-bottom:3px"><label>'+RED._("editor.spinner.min")+'</label></div>').append(minInput).appendTo(content);
|
||||
$('<div class="form-row" style="margin-bottom:0"><label>'+RED._("editor.spinner.max")+'</label></div>').append(maxInput).appendTo(content);
|
||||
return {
|
||||
onclose: function() {
|
||||
var min = minInput.val().trim();
|
||||
var max = maxInput.val().trim();
|
||||
if (min !== "") {
|
||||
ui.opts.min = parseInt(min);
|
||||
} else {
|
||||
delete ui.opts.min;
|
||||
}
|
||||
if (max !== "") {
|
||||
ui.opts.max = parseInt(max);
|
||||
} else {
|
||||
delete ui.opts.max;
|
||||
}
|
||||
inputCellInput.typedInput('value',Date.now())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
value:"none",
|
||||
label:RED._("editor.inputs.none"), icon:"fa fa-times",hasValue:false
|
||||
},
|
||||
{
|
||||
value:"hide",
|
||||
label:RED._("editor.inputs.hidden"), icon:"fa fa-ban",hasValue:false
|
||||
}
|
||||
],
|
||||
default: 'none'
|
||||
}).on("typedinputtypechange", function(evt,type) {
|
||||
ui.type = $(this).typedInput("type");
|
||||
ui.opts = typeOptions[ui.type];
|
||||
if (ui.type === 'input') {
|
||||
// In the case of 'input' type, the typedInput uses the multiple-option
|
||||
// mode. Its value needs to be set to a comma-separately list of the
|
||||
// selected options.
|
||||
inputCellInput.typedInput('value',ui.opts.types.join(","))
|
||||
} else {
|
||||
// No other type cares about `value`, but doing this will
|
||||
// force a refresh of the label now that `ui.opts` has
|
||||
// been updated.
|
||||
inputCellInput.typedInput('value',Date.now())
|
||||
}
|
||||
|
||||
switch (ui.type) {
|
||||
case 'input':
|
||||
valueField.typedInput('types',ui.opts.types);
|
||||
break;
|
||||
case 'select':
|
||||
valueField.typedInput('types',['str']);
|
||||
break;
|
||||
case 'checkbox':
|
||||
valueField.typedInput('types',['bool']);
|
||||
break;
|
||||
case 'spinner':
|
||||
valueField.typedInput('types',['num']);
|
||||
break;
|
||||
case 'cred':
|
||||
valueField.typedInput('types',['cred']);
|
||||
break;
|
||||
default:
|
||||
valueField.typedInput('types',DEFAULT_ENV_TYPE_LIST)
|
||||
}
|
||||
if (ui.type === 'checkbox') {
|
||||
valueField.typedInput('type','bool');
|
||||
} else if (ui.type === 'spinner') {
|
||||
valueField.typedInput('type','num');
|
||||
}
|
||||
if (ui.type !== 'checkbox') {
|
||||
checkbox = null;
|
||||
}
|
||||
|
||||
}).on("change", function(evt,type) {
|
||||
if (ui.type === 'input') {
|
||||
var types = inputCellInput.typedInput('value');
|
||||
ui.opts.types = (types === "") ? ["str"] : types.split(",");
|
||||
valueField.typedInput('types',ui.opts.types);
|
||||
}
|
||||
});
|
||||
valueField.on("change", function(evt) {
|
||||
if (checkbox) {
|
||||
checkbox.prop('checked',$(this).typedInput('value')==="true")
|
||||
}
|
||||
})
|
||||
// Set the input to the right type. This will trigger the 'typedinputtypechange'
|
||||
// event handler (just above ^^) to update the value if needed
|
||||
inputCellInput.typedInput('type',ui.type)
|
||||
}
|
||||
|
||||
function setLocale(l, list) {
|
||||
currentLocale = l;
|
||||
if (list) {
|
||||
var items = list.editableList("items");
|
||||
items.each(function (i, item) {
|
||||
var entry = $(this).data('data');
|
||||
var labelField = entry.ui.labelField;
|
||||
labelField.val(lookupLabel(entry.ui.label, "", currentLocale));
|
||||
if (labelField.timeout) {
|
||||
clearTimeout(labelField.timeout);
|
||||
delete labelField.timeout;
|
||||
}
|
||||
labelField.addClass("input-updated");
|
||||
labelField.timeout = setTimeout(function() {
|
||||
delete labelField.timeout
|
||||
labelField.removeClass("input-updated");
|
||||
},3000);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup text for specific locale
|
||||
* @param labels - dict of labels
|
||||
* @param defaultLabel - fallback label if not found
|
||||
* @param locale - target locale
|
||||
* @returns {string} text for specified locale
|
||||
*/
|
||||
function lookupLabel(labels, defaultLabel, locale) {
|
||||
if (labels) {
|
||||
if (labels[locale]) {
|
||||
return labels[locale];
|
||||
}
|
||||
if (locale) {
|
||||
var lang = locale.substring(0, 2);
|
||||
if (labels[lang]) {
|
||||
return labels[lang];
|
||||
}
|
||||
}
|
||||
}
|
||||
return defaultLabel;
|
||||
}
|
||||
|
||||
return {
|
||||
create: buildPropertiesList,
|
||||
setLocale: setLocale,
|
||||
lookupLabel: lookupLabel,
|
||||
DEFAULT_ENV_TYPE_LIST: DEFAULT_ENV_TYPE_LIST,
|
||||
DEFAULT_ENV_TYPE_LIST_INC_CRED: DEFAULT_ENV_TYPE_LIST_INC_CRED
|
||||
}
|
||||
})();
|
@ -10,7 +10,7 @@
|
||||
var form = $('<form class="dialog-form form-horizontal"></form>').appendTo(content);
|
||||
var listContainer = $('<div class="form-row node-input-env-container-row"></div>').appendTo(form);
|
||||
this.list = $('<ol></ol>').appendTo(listContainer);
|
||||
RED.subflow.buildPropertiesList(this.list, node);
|
||||
RED.editor.envVarList.create(this.list, node);
|
||||
return content;
|
||||
},
|
||||
resize: function(node, size) {
|
||||
|
@ -30,13 +30,6 @@
|
||||
}
|
||||
RED.editor.buildEditForm(content,formStyle,nodeType,i18nNamespace,node);
|
||||
|
||||
if (nodeType === "subflow-template") {
|
||||
// This is the 'edit properties' dialog for a subflow template
|
||||
// TODO: this needs to happen later in the dialog open sequence
|
||||
// so that credentials can be loaded prior to building the form
|
||||
RED.subflow.buildEditForm("subflow-template", node);
|
||||
}
|
||||
|
||||
return content;
|
||||
},
|
||||
resize: function(node, size) {
|
||||
|
63
packages/node_modules/@node-red/editor-client/src/js/ui/editors/panes/subflowProperties.js
vendored
Normal file
63
packages/node_modules/@node-red/editor-client/src/js/ui/editors/panes/subflowProperties.js
vendored
Normal file
@ -0,0 +1,63 @@
|
||||
;(function() {
|
||||
|
||||
RED.editor.registerEditorPane("editor-tab-subflow-properties", function() {
|
||||
return {
|
||||
label: RED._("editor-tab.properties"),
|
||||
name: RED._("editor-tab.properties"),
|
||||
iconClass: "fa fa-cog",
|
||||
create: function(container, node) {
|
||||
var content = $('<div>', {class:"red-ui-tray-content"}).appendTo(container);
|
||||
|
||||
var dialogForm = $('<form id="dialog-form" class="form-horizontal"></form>').appendTo(content);
|
||||
$('<div class="form-row">'+
|
||||
'<label for="node-input-name" data-i18n="[append]editor:common.label.name"><i class="fa fa-tag"></i> </label>'+
|
||||
'<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">'+
|
||||
'</div>').appendTo(dialogForm);
|
||||
|
||||
var row = $('<div class="form-row node-text-editor-row">'+
|
||||
'<label for="node-input-info" data-i18n="editor:workspace.info" style="width:300px;"></label>'+
|
||||
'<div style="min-height:150px;" class="node-text-editor" id="node-input-info"></div>'+
|
||||
'</div>').appendTo(dialogForm);
|
||||
this.tabflowEditor = RED.editor.createEditor({
|
||||
id: 'node-input-info',
|
||||
mode: 'ace/mode/markdown',
|
||||
value: ""
|
||||
});
|
||||
|
||||
$('<input type="text" style="display: none;" />').prependTo(dialogForm);
|
||||
dialogForm.on("submit", function(e) { e.preventDefault();});
|
||||
|
||||
$("#node-input-name").val(node.label);
|
||||
RED.text.bidi.prepareInput($("#node-input-name"));
|
||||
this.tabflowEditor.getSession().setValue(node.info || "", -1);
|
||||
return content;
|
||||
},
|
||||
resize: function(node, size) {
|
||||
$("#node-input-info").css("height", (size.height-70)+"px");
|
||||
this.tabflowEditor.resize();
|
||||
},
|
||||
close: function(node) {
|
||||
this.tabflowEditor.destroy();
|
||||
},
|
||||
apply: function(workspace, editState) {
|
||||
var label = $( "#node-input-name" ).val();
|
||||
|
||||
if (workspace.label != label) {
|
||||
editState.changes.label = workspace.label;
|
||||
editState.changed = true;
|
||||
workspace.label = label;
|
||||
}
|
||||
|
||||
var info = this.tabflowEditor.getValue();
|
||||
if (workspace.info !== info) {
|
||||
editState.changes.info = workspace.info;
|
||||
editState.changed = true;
|
||||
workspace.info = info;
|
||||
}
|
||||
$("#red-ui-tab-"+(workspace.id.replace(".","-"))).toggleClass('red-ui-workspace-disabled',!!workspace.disabled);
|
||||
$("#red-ui-workspace").toggleClass("red-ui-workspace-disabled",!!workspace.disabled);
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
})();
|
@ -16,8 +16,6 @@
|
||||
|
||||
RED.subflow = (function() {
|
||||
|
||||
var currentLocale = "en-US";
|
||||
|
||||
var _subflowEditTemplate = '<script type="text/x-red" data-template-name="subflow">'+
|
||||
'<div class="form-row">'+
|
||||
'<label for="node-input-name" data-i18n="[append]editor:common.label.name"><i class="fa fa-tag"></i> </label>'+
|
||||
@ -918,588 +916,11 @@ RED.subflow = (function() {
|
||||
locales.val(locale);
|
||||
|
||||
locales.on("change", function() {
|
||||
currentLocale = $(this).val();
|
||||
var items = $("#node-input-env-container").editableList("items");
|
||||
items.each(function (i, item) {
|
||||
var entry = $(this).data('data');
|
||||
var labelField = entry.ui.labelField;
|
||||
labelField.val(lookupLabel(entry.ui.label, "", currentLocale));
|
||||
if (labelField.timeout) {
|
||||
clearTimeout(labelField.timeout);
|
||||
delete labelField.timeout;
|
||||
}
|
||||
labelField.addClass("input-updated");
|
||||
labelField.timeout = setTimeout(function() {
|
||||
delete labelField.timeout
|
||||
labelField.removeClass("input-updated");
|
||||
},3000);
|
||||
});
|
||||
RED.editor.envVarList.setLocale($(this).val(), $("#node-input-env-container"));
|
||||
});
|
||||
RED.editor.envVarList.setLocale(locale);
|
||||
}
|
||||
|
||||
var DEFAULT_ENV_TYPE_LIST = ['str','num','bool','json','bin','env'];
|
||||
var DEFAULT_ENV_TYPE_LIST_INC_CRED = ['str','num','bool','json','bin','env','cred'];
|
||||
|
||||
/**
|
||||
* Create env var edit interface
|
||||
* @param container - container
|
||||
* @param node - subflow node
|
||||
*/
|
||||
function buildPropertiesList(envContainer, node) {
|
||||
|
||||
var isTemplateNode = (node.type === "subflow");
|
||||
|
||||
if (isTemplateNode) {
|
||||
buildEnvControl(envContainer, node);
|
||||
}
|
||||
envContainer
|
||||
.css({
|
||||
'min-height':'150px',
|
||||
'min-width':'450px'
|
||||
})
|
||||
.editableList({
|
||||
header: isTemplateNode?$('<div><div><div></div><div data-i18n="common.label.name"></div><div data-i18n="editor-tab.defaultValue"></div><div></div></div></div>'):undefined,
|
||||
addItem: function(container, i, opt) {
|
||||
// If this is an instance node, these are properties unique to
|
||||
// this instance - ie opt.parent will not be defined.
|
||||
|
||||
if (isTemplateNode) {
|
||||
container.addClass("red-ui-editor-subflow-env-editable")
|
||||
}
|
||||
|
||||
var envRow = $('<div/>').appendTo(container);
|
||||
var nameField = null;
|
||||
var valueField = null;
|
||||
|
||||
nameField = $('<input/>', {
|
||||
class: "node-input-env-name",
|
||||
type: "text",
|
||||
placeholder: RED._("common.label.name")
|
||||
}).attr("autocomplete","disable").appendTo(envRow).val(opt.name);
|
||||
valueField = $('<input/>',{
|
||||
style: "width:100%",
|
||||
class: "node-input-env-value",
|
||||
type: "text",
|
||||
}).attr("autocomplete","disable").appendTo(envRow)
|
||||
valueField.typedInput({default:'str',types:isTemplateNode?DEFAULT_ENV_TYPE_LIST:DEFAULT_ENV_TYPE_LIST_INC_CRED});
|
||||
valueField.typedInput('type', opt.type);
|
||||
if (opt.type === "cred") {
|
||||
if (opt.value) {
|
||||
valueField.typedInput('value', opt.value);
|
||||
} else if (node.credentials && node.credentials[opt.name]) {
|
||||
valueField.typedInput('value', node.credentials[opt.name]);
|
||||
} else if (node.credentials && node.credentials['has_'+opt.name]) {
|
||||
valueField.typedInput('value', "__PWRD__");
|
||||
} else {
|
||||
valueField.typedInput('value', "");
|
||||
}
|
||||
} else {
|
||||
valueField.typedInput('value', opt.value);
|
||||
}
|
||||
|
||||
|
||||
opt.nameField = nameField;
|
||||
opt.valueField = valueField;
|
||||
|
||||
var actionButton = $('<a/>',{href:"#",class:"red-ui-editableList-item-remove red-ui-button red-ui-button-small"}).appendTo(envRow);
|
||||
$('<i/>',{class:"fa "+(opt.parent?"fa-reply":"fa-remove")}).appendTo(actionButton);
|
||||
var removeTip = RED.popover.tooltip(actionButton,RED._("subflow.env.remove"));
|
||||
actionButton.on("click", function(evt) {
|
||||
evt.preventDefault();
|
||||
removeTip.close();
|
||||
container.parent().addClass("red-ui-editableList-item-deleting")
|
||||
container.fadeOut(300, function() {
|
||||
envContainer.editableList('removeItem',opt);
|
||||
});
|
||||
});
|
||||
|
||||
if (isTemplateNode) {
|
||||
// Add the UI customisation row
|
||||
// if `opt.ui` does not exist, then apply defaults. If these
|
||||
// defaults do not change then they will get stripped off
|
||||
// before saving.
|
||||
if (opt.type === 'cred') {
|
||||
opt.ui = opt.ui || {
|
||||
icon: "",
|
||||
type: "cred"
|
||||
}
|
||||
opt.ui.type = "cred";
|
||||
} else {
|
||||
opt.ui = opt.ui || {
|
||||
icon: "",
|
||||
type: "input",
|
||||
opts: {types:DEFAULT_ENV_TYPE_LIST}
|
||||
}
|
||||
}
|
||||
opt.ui.label = opt.ui.label || {};
|
||||
opt.ui.type = opt.ui.type || "input";
|
||||
|
||||
var uiRow = $('<div/>').appendTo(container).hide();
|
||||
// save current info for reverting on cancel
|
||||
// var copy = $.extend(true, {}, ui);
|
||||
|
||||
$('<a href="#"><i class="fa fa-angle-right"></a>').prependTo(envRow).on("click", function (evt) {
|
||||
evt.preventDefault();
|
||||
if ($(this).hasClass('expanded')) {
|
||||
uiRow.slideUp();
|
||||
$(this).removeClass('expanded');
|
||||
} else {
|
||||
uiRow.slideDown();
|
||||
$(this).addClass('expanded');
|
||||
}
|
||||
});
|
||||
|
||||
buildEnvEditRow(uiRow, opt.ui, nameField, valueField);
|
||||
nameField.trigger('change');
|
||||
}
|
||||
},
|
||||
sortable: ".red-ui-editableList-item-handle",
|
||||
removable: false
|
||||
});
|
||||
var parentEnv = {};
|
||||
var envList = [];
|
||||
if (/^subflow:/.test(node.type)) {
|
||||
var subflowDef = RED.nodes.subflow(node.type.substring(8));
|
||||
if (subflowDef.env) {
|
||||
subflowDef.env.forEach(function(env) {
|
||||
var item = {
|
||||
name:env.name,
|
||||
parent: {
|
||||
type: env.type,
|
||||
value: env.value,
|
||||
ui: env.ui
|
||||
}
|
||||
}
|
||||
envList.push(item);
|
||||
parentEnv[env.name] = item;
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (node.env) {
|
||||
for (var i = 0; i < node.env.length; i++) {
|
||||
var env = node.env[i];
|
||||
if (parentEnv.hasOwnProperty(env.name)) {
|
||||
parentEnv[env.name].type = env.type;
|
||||
parentEnv[env.name].value = env.value;
|
||||
} else {
|
||||
envList.push({
|
||||
name: env.name,
|
||||
type: env.type,
|
||||
value: env.value,
|
||||
ui: env.ui
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
envList.forEach(function(env) {
|
||||
if (env.parent && env.parent.ui && env.parent.ui.type === 'hide') {
|
||||
return;
|
||||
}
|
||||
if (!isTemplateNode && env.parent) {
|
||||
return;
|
||||
}
|
||||
envContainer.editableList('addItem', JSON.parse(JSON.stringify(env)));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create UI edit interface for environment variable
|
||||
* @param container - container
|
||||
* @param env - env var definition
|
||||
* @param nameField - name field of env var
|
||||
* @param valueField - value field of env var
|
||||
*/
|
||||
function buildEnvEditRow(container, ui, nameField, valueField) {
|
||||
container.addClass("red-ui-editor-subflow-env-ui-row")
|
||||
var topRow = $('<div></div>').appendTo(container);
|
||||
$('<div></div>').appendTo(topRow);
|
||||
$('<div>').text(RED._("editor.icon")).appendTo(topRow);
|
||||
$('<div>').text(RED._("editor.label")).appendTo(topRow);
|
||||
$('<div>').text(RED._("editor.inputType")).appendTo(topRow);
|
||||
|
||||
var row = $('<div></div>').appendTo(container);
|
||||
$('<div><i class="red-ui-editableList-item-handle fa fa-bars"></i></div>').appendTo(row);
|
||||
var typeOptions = {
|
||||
'input': {types:DEFAULT_ENV_TYPE_LIST},
|
||||
'select': {opts:[]},
|
||||
'spinner': {},
|
||||
'cred': {}
|
||||
};
|
||||
if (ui.opts) {
|
||||
typeOptions[ui.type] = ui.opts;
|
||||
} else {
|
||||
// Pick up the default values if not otherwise provided
|
||||
ui.opts = typeOptions[ui.type];
|
||||
}
|
||||
var iconCell = $('<div></div>').appendTo(row);
|
||||
|
||||
var iconButton = $('<a href="#"></a>').appendTo(iconCell);
|
||||
iconButton.on("click", function(evt) {
|
||||
evt.preventDefault();
|
||||
var icon = ui.icon || "";
|
||||
var iconPath = (icon ? RED.utils.separateIconPath(icon) : {});
|
||||
RED.editor.iconPicker.show(iconButton, null, iconPath, true, function (newIcon) {
|
||||
iconButton.empty();
|
||||
var path = newIcon || "";
|
||||
var newPath = RED.utils.separateIconPath(path);
|
||||
if (newPath) {
|
||||
$('<i class="fa"></i>').addClass(newPath.file).appendTo(iconButton);
|
||||
}
|
||||
ui.icon = path;
|
||||
});
|
||||
})
|
||||
|
||||
if (ui.icon) {
|
||||
var newPath = RED.utils.separateIconPath(ui.icon);
|
||||
$('<i class="fa '+newPath.file+'"></i>').appendTo(iconButton);
|
||||
}
|
||||
|
||||
var labelCell = $('<div></div>').appendTo(row);
|
||||
|
||||
var label = ui.label && ui.label[currentLocale] || "";
|
||||
var labelInput = $('<input type="text">').val(label).appendTo(labelCell);
|
||||
ui.labelField = labelInput;
|
||||
labelInput.on('change', function(evt) {
|
||||
ui.label = ui.label || {};
|
||||
var val = $(this).val().trim();
|
||||
if (val === "") {
|
||||
delete ui.label[currentLocale];
|
||||
} else {
|
||||
ui.label[currentLocale] = val;
|
||||
}
|
||||
})
|
||||
var labelIcon = $('<span class="red-ui-editor-subflow-env-lang-icon"><i class="fa fa-language"></i></span>').appendTo(labelCell);
|
||||
RED.popover.tooltip(labelIcon,function() {
|
||||
var langs = Object.keys(ui.label);
|
||||
var content = $("<div>");
|
||||
if (langs.indexOf(currentLocale) === -1) {
|
||||
langs.push(currentLocale);
|
||||
langs.sort();
|
||||
}
|
||||
langs.forEach(function(l) {
|
||||
var row = $('<div>').appendTo(content);
|
||||
$('<span>').css({display:"inline-block",width:"120px"}).text(RED._("languages."+l)+(l===currentLocale?"*":"")).appendTo(row);
|
||||
$('<span>').text(ui.label[l]||"").appendTo(row);
|
||||
});
|
||||
return content;
|
||||
})
|
||||
|
||||
nameField.on('change',function(evt) {
|
||||
labelInput.attr("placeholder",$(this).val())
|
||||
});
|
||||
|
||||
var inputCell = $('<div></div>').appendTo(row);
|
||||
var inputCellInput = $('<input type="text">').css("width","100%").appendTo(inputCell);
|
||||
if (ui.type === "input") {
|
||||
inputCellInput.val(ui.opts.types.join(","));
|
||||
}
|
||||
var checkbox;
|
||||
var selectBox;
|
||||
|
||||
inputCellInput.typedInput({
|
||||
types: [
|
||||
{
|
||||
value:"input",
|
||||
label:RED._("editor.inputs.input"), icon:"fa fa-i-cursor",showLabel:false,multiple:true,options:[
|
||||
{value:"str",label:RED._("editor.types.str"),icon:"red/images/typedInput/az.svg"},
|
||||
{value:"num",label:RED._("editor.types.num"),icon:"red/images/typedInput/09.svg"},
|
||||
{value:"bool",label:RED._("editor.types.bool"),icon:"red/images/typedInput/bool.svg"},
|
||||
{value:"json",label:RED._("editor.types.json"),icon:"red/images/typedInput/json.svg"},
|
||||
{value: "bin",label: RED._("editor.types.bin"),icon: "red/images/typedInput/bin.svg"},
|
||||
{value: "env",label: RED._("editor.types.env"),icon: "red/images/typedInput/env.svg"},
|
||||
{value: "cred",label: RED._("editor.types.cred"),icon: "fa fa-lock"}
|
||||
],
|
||||
default: DEFAULT_ENV_TYPE_LIST,
|
||||
valueLabel: function(container,value) {
|
||||
container.css("padding",0);
|
||||
var innerContainer = $('<div class="red-ui-editor-subflow-env-input-type"></div>').appendTo(container);
|
||||
|
||||
var input = $('<div class="placeholder-input">').appendTo(innerContainer);
|
||||
$('<span><i class="fa fa-i-cursor"></i></span>').appendTo(input);
|
||||
if (value.length) {
|
||||
value.forEach(function(v) {
|
||||
if (!/^fa /.test(v.icon)) {
|
||||
$('<img>',{src:v.icon,style:"max-width:14px; padding: 0 3px; margin-top:-4px; margin-left: 1px"}).appendTo(input);
|
||||
} else {
|
||||
var s = $('<span>',{style:"max-width:14px; padding: 0 3px; margin-top:-4px; margin-left: 1px"}).appendTo(input);
|
||||
$("<i>",{class: v.icon}).appendTo(s);
|
||||
}
|
||||
})
|
||||
} else {
|
||||
$('<span class="red-ui-editor-subflow-env-input-type-placeholder"></span>').text(RED._("editor.selectType")).appendTo(input);
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
value: "cred",
|
||||
label: RED._("typedInput.type.cred"), icon:"fa fa-lock", showLabel: false,
|
||||
valueLabel: function(container,value) {
|
||||
container.css("padding",0);
|
||||
var innerContainer = $('<div class="red-ui-editor-subflow-env-input-type">').css({
|
||||
"border-top-right-radius": "4px",
|
||||
"border-bottom-right-radius": "4px"
|
||||
}).appendTo(container);
|
||||
$('<div class="placeholder-input">').html("••••••••").appendTo(innerContainer);
|
||||
}
|
||||
},
|
||||
{
|
||||
value:"select",
|
||||
label:RED._("editor.inputs.select"), icon:"fa fa-tasks",showLabel:false,
|
||||
valueLabel: function(container,value) {
|
||||
container.css("padding","0");
|
||||
|
||||
selectBox = $('<select></select>').appendTo(container);
|
||||
if (ui.opts && Array.isArray(ui.opts.opts)) {
|
||||
ui.opts.opts.forEach(function(o) {
|
||||
var label = lookupLabel(o.l, o.l["en-US"]||o.v, currentLocale);
|
||||
// $('<option>').val((o.t||'str')+":"+o.v).text(label).appendTo(selectBox);
|
||||
$('<option>').val(o.v).text(label).appendTo(selectBox);
|
||||
})
|
||||
}
|
||||
selectBox.on('change', function(evt) {
|
||||
var v = selectBox.val();
|
||||
// var parts = v.split(":");
|
||||
// var t = parts.shift();
|
||||
// v = parts.join(":");
|
||||
//
|
||||
// valueField.typedInput("type",'str')
|
||||
valueField.typedInput("value",v)
|
||||
});
|
||||
selectBox.val(valueField.typedInput("value"));
|
||||
// selectBox.val(valueField.typedInput('type')+":"+valueField.typedInput("value"));
|
||||
},
|
||||
expand: {
|
||||
icon: "fa-caret-down",
|
||||
minWidth: 400,
|
||||
content: function(container) {
|
||||
var content = $('<div class="red-ui-editor-subflow-ui-edit-panel">').appendTo(container);
|
||||
var optList = $('<ol>').appendTo(content).editableList({
|
||||
header:$("<div><div>"+RED._("editor.select.label")+"</div><div>"+RED._("editor.select.value")+"</div></div>"),
|
||||
addItem: function(row,index,itemData) {
|
||||
var labelDiv = $('<div>').appendTo(row);
|
||||
var label = lookupLabel(itemData.l, "", currentLocale);
|
||||
itemData.label = $('<input type="text">').val(label).appendTo(labelDiv);
|
||||
itemData.label.on('keydown', function(evt) {
|
||||
if (evt.keyCode === 13) {
|
||||
itemData.input.focus();
|
||||
evt.preventDefault();
|
||||
}
|
||||
});
|
||||
var labelIcon = $('<span class="red-ui-editor-subflow-env-lang-icon"><i class="fa fa-language"></i></span>').appendTo(labelDiv);
|
||||
RED.popover.tooltip(labelIcon,function() {
|
||||
return currentLocale;
|
||||
})
|
||||
itemData.input = $('<input type="text">').val(itemData.v).appendTo(row);
|
||||
|
||||
// Problem using a TI here:
|
||||
// - this is in a popout panel
|
||||
// - clicking the expand button in the TI will close the parent edit tray
|
||||
// and open the type editor.
|
||||
// - but it leaves the popout panel over the top.
|
||||
// - there is no way to get back to the popout panel after closing the type editor
|
||||
//.typedInput({default:itemData.t||'str', types:DEFAULT_ENV_TYPE_LIST});
|
||||
itemData.input.on('keydown', function(evt) {
|
||||
if (evt.keyCode === 13) {
|
||||
// Enter or Tab
|
||||
var index = optList.editableList('indexOf',itemData);
|
||||
var length = optList.editableList('length');
|
||||
if (index + 1 === length) {
|
||||
var newItem = {};
|
||||
optList.editableList('addItem',newItem);
|
||||
setTimeout(function() {
|
||||
if (newItem.label) {
|
||||
newItem.label.focus();
|
||||
}
|
||||
},100)
|
||||
} else {
|
||||
var nextItem = optList.editableList('getItemAt',index+1);
|
||||
if (nextItem.label) {
|
||||
nextItem.label.focus()
|
||||
}
|
||||
}
|
||||
evt.preventDefault();
|
||||
}
|
||||
});
|
||||
},
|
||||
sortable: true,
|
||||
removable: true,
|
||||
height: 160
|
||||
})
|
||||
if (ui.opts.opts.length > 0) {
|
||||
ui.opts.opts.forEach(function(o) {
|
||||
optList.editableList('addItem',$.extend(true,{},o))
|
||||
})
|
||||
} else {
|
||||
optList.editableList('addItem',{})
|
||||
}
|
||||
return {
|
||||
onclose: function() {
|
||||
var items = optList.editableList('items');
|
||||
var vals = [];
|
||||
items.each(function (i,el) {
|
||||
var data = el.data('data');
|
||||
var l = data.label.val().trim();
|
||||
var v = data.input.val();
|
||||
// var t = data.input.typedInput('type');
|
||||
// var v = data.input.typedInput('value');
|
||||
if (l.length > 0) {
|
||||
data.l = data.l || {};
|
||||
data.l[currentLocale] = l;
|
||||
}
|
||||
data.v = v;
|
||||
|
||||
if (l.length > 0 || v.length > 0) {
|
||||
var val = {l:data.l,v:data.v};
|
||||
// if (t !== 'str') {
|
||||
// val.t = t;
|
||||
// }
|
||||
vals.push(val);
|
||||
}
|
||||
});
|
||||
ui.opts.opts = vals;
|
||||
inputCellInput.typedInput('value',Date.now())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
value:"checkbox",
|
||||
label:RED._("editor.inputs.checkbox"), icon:"fa fa-check-square-o",showLabel:false,
|
||||
valueLabel: function(container,value) {
|
||||
container.css("padding",0);
|
||||
checkbox = $('<input type="checkbox">').appendTo(container);
|
||||
checkbox.on('change', function(evt) {
|
||||
valueField.typedInput('value',$(this).prop('checked')?"true":"false");
|
||||
})
|
||||
checkbox.prop('checked',valueField.typedInput('value')==="true");
|
||||
}
|
||||
},
|
||||
{
|
||||
value:"spinner",
|
||||
label:RED._("editor.inputs.spinner"), icon:"fa fa-sort-numeric-asc", showLabel:false,
|
||||
valueLabel: function(container,value) {
|
||||
container.css("padding",0);
|
||||
var innerContainer = $('<div class="red-ui-editor-subflow-env-input-type"></div>').appendTo(container);
|
||||
|
||||
var input = $('<div class="placeholder-input">').appendTo(innerContainer);
|
||||
$('<span><i class="fa fa-sort-numeric-asc"></i></span>').appendTo(input);
|
||||
|
||||
var min = ui.opts && ui.opts.min;
|
||||
var max = ui.opts && ui.opts.max;
|
||||
var label = "";
|
||||
if (min !== undefined && max !== undefined) {
|
||||
label = Math.min(min,max)+" - "+Math.max(min,max);
|
||||
} else if (min !== undefined) {
|
||||
label = "> "+min;
|
||||
} else if (max !== undefined) {
|
||||
label = "< "+max;
|
||||
}
|
||||
$('<span>').css("margin-left","15px").text(label).appendTo(input);
|
||||
},
|
||||
expand: {
|
||||
icon: "fa-caret-down",
|
||||
content: function(container) {
|
||||
var content = $('<div class="red-ui-editor-subflow-ui-edit-panel">').appendTo(container);
|
||||
content.css("padding","8px 5px")
|
||||
var min = ui.opts.min;
|
||||
var max = ui.opts.max;
|
||||
var minInput = $('<input type="number" style="margin-bottom:0; width:60px">');
|
||||
minInput.val(min);
|
||||
var maxInput = $('<input type="number" style="margin-bottom:0; width:60px">');
|
||||
maxInput.val(max);
|
||||
$('<div class="form-row" style="margin-bottom:3px"><label>'+RED._("editor.spinner.min")+'</label></div>').append(minInput).appendTo(content);
|
||||
$('<div class="form-row" style="margin-bottom:0"><label>'+RED._("editor.spinner.max")+'</label></div>').append(maxInput).appendTo(content);
|
||||
return {
|
||||
onclose: function() {
|
||||
var min = minInput.val().trim();
|
||||
var max = maxInput.val().trim();
|
||||
if (min !== "") {
|
||||
ui.opts.min = parseInt(min);
|
||||
} else {
|
||||
delete ui.opts.min;
|
||||
}
|
||||
if (max !== "") {
|
||||
ui.opts.max = parseInt(max);
|
||||
} else {
|
||||
delete ui.opts.max;
|
||||
}
|
||||
inputCellInput.typedInput('value',Date.now())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
value:"none",
|
||||
label:RED._("editor.inputs.none"), icon:"fa fa-times",hasValue:false
|
||||
},
|
||||
{
|
||||
value:"hide",
|
||||
label:RED._("editor.inputs.hidden"), icon:"fa fa-ban",hasValue:false
|
||||
}
|
||||
],
|
||||
default: 'none'
|
||||
}).on("typedinputtypechange", function(evt,type) {
|
||||
ui.type = $(this).typedInput("type");
|
||||
ui.opts = typeOptions[ui.type];
|
||||
if (ui.type === 'input') {
|
||||
// In the case of 'input' type, the typedInput uses the multiple-option
|
||||
// mode. Its value needs to be set to a comma-separately list of the
|
||||
// selected options.
|
||||
inputCellInput.typedInput('value',ui.opts.types.join(","))
|
||||
} else {
|
||||
// No other type cares about `value`, but doing this will
|
||||
// force a refresh of the label now that `ui.opts` has
|
||||
// been updated.
|
||||
inputCellInput.typedInput('value',Date.now())
|
||||
}
|
||||
|
||||
switch (ui.type) {
|
||||
case 'input':
|
||||
valueField.typedInput('types',ui.opts.types);
|
||||
break;
|
||||
case 'select':
|
||||
valueField.typedInput('types',['str']);
|
||||
break;
|
||||
case 'checkbox':
|
||||
valueField.typedInput('types',['bool']);
|
||||
break;
|
||||
case 'spinner':
|
||||
valueField.typedInput('types',['num']);
|
||||
break;
|
||||
case 'cred':
|
||||
valueField.typedInput('types',['cred']);
|
||||
break;
|
||||
default:
|
||||
valueField.typedInput('types',DEFAULT_ENV_TYPE_LIST)
|
||||
}
|
||||
if (ui.type === 'checkbox') {
|
||||
valueField.typedInput('type','bool');
|
||||
} else if (ui.type === 'spinner') {
|
||||
valueField.typedInput('type','num');
|
||||
}
|
||||
if (ui.type !== 'checkbox') {
|
||||
checkbox = null;
|
||||
}
|
||||
|
||||
}).on("change", function(evt,type) {
|
||||
if (ui.type === 'input') {
|
||||
var types = inputCellInput.typedInput('value');
|
||||
ui.opts.types = (types === "") ? ["str"] : types.split(",");
|
||||
valueField.typedInput('types',ui.opts.types);
|
||||
}
|
||||
});
|
||||
valueField.on("change", function(evt) {
|
||||
if (checkbox) {
|
||||
checkbox.prop('checked',$(this).typedInput('value')==="true")
|
||||
}
|
||||
})
|
||||
// Set the input to the right type. This will trigger the 'typedinputtypechange'
|
||||
// event handler (just above ^^) to update the value if needed
|
||||
inputCellInput.typedInput('type',ui.type)
|
||||
}
|
||||
|
||||
function buildEnvUIRow(row, tenv, ui, node) {
|
||||
ui.label = ui.label||{};
|
||||
@ -1508,7 +929,7 @@ RED.subflow = (function() {
|
||||
ui.opts = {};
|
||||
} else if (!ui.type) {
|
||||
ui.type = "input";
|
||||
ui.opts = {types:DEFAULT_ENV_TYPE_LIST}
|
||||
ui.opts = { types: RED.editor.envVarList.DEFAULT_ENV_TYPE_LIST }
|
||||
} else {
|
||||
if (!ui.opts) {
|
||||
ui.opts = (ui.type === "select") ? {opts:[]} : {};
|
||||
@ -1517,7 +938,7 @@ RED.subflow = (function() {
|
||||
|
||||
var labels = ui.label || {};
|
||||
var locale = RED.i18n.lang();
|
||||
var labelText = lookupLabel(labels, labels["en-US"]||tenv.name, locale);
|
||||
var labelText = RED.editor.envVarList.lookupLabel(labels, labels["en-US"]||tenv.name, locale);
|
||||
var label = $('<label>').appendTo(row);
|
||||
$('<span> </span>').appendTo(row);
|
||||
var labelContainer = $('<span></span>').appendTo(label);
|
||||
@ -1570,7 +991,7 @@ RED.subflow = (function() {
|
||||
input = $('<select>').css('width','70%').appendTo(row);
|
||||
if (ui.opts.opts) {
|
||||
ui.opts.opts.forEach(function(o) {
|
||||
$('<option>').val(o.v).text(lookupLabel(o.l, o.l['en-US']||o.v, locale)).appendTo(input);
|
||||
$('<option>').val(o.v).text(RED.editor.envVarList.lookupLabel(o.l, o.l['en-US']||o.v, locale)).appendTo(input);
|
||||
})
|
||||
}
|
||||
input.val(val.value);
|
||||
@ -1636,9 +1057,8 @@ RED.subflow = (function() {
|
||||
* @param uiContainer - container for UI
|
||||
* @param envList - env var definitions of template
|
||||
*/
|
||||
function buildEnvUI(uiContainer, envList,node) {
|
||||
function buildEnvUI(uiContainer, envList, node) {
|
||||
uiContainer.empty();
|
||||
var elementID = 0;
|
||||
for (var i = 0; i < envList.length; i++) {
|
||||
var tenv = envList[i];
|
||||
if (tenv.ui && tenv.ui.type === 'hide') {
|
||||
@ -1646,8 +1066,6 @@ RED.subflow = (function() {
|
||||
}
|
||||
var row = $("<div/>", { class: "form-row" }).appendTo(uiContainer);
|
||||
buildEnvUIRow(row,tenv, tenv.ui || {}, node);
|
||||
|
||||
// console.log(ui);
|
||||
}
|
||||
}
|
||||
// buildEnvUI
|
||||
@ -1683,7 +1101,7 @@ RED.subflow = (function() {
|
||||
// icon: "",
|
||||
// label: {},
|
||||
// type: "input",
|
||||
// opts: {types:DEFAULT_ENV_TYPE_LIST}
|
||||
// opts: {types:RED.editor.envVarList.DEFAULT_ENV_TYPE_LIST}
|
||||
// }
|
||||
if (!ui.icon) {
|
||||
delete ui.icon;
|
||||
@ -1693,7 +1111,7 @@ RED.subflow = (function() {
|
||||
}
|
||||
switch (ui.type) {
|
||||
case "input":
|
||||
if (JSON.stringify(ui.opts) === JSON.stringify({types:DEFAULT_ENV_TYPE_LIST})) {
|
||||
if (JSON.stringify(ui.opts) === JSON.stringify({types:RED.editor.envVarList.DEFAULT_ENV_TYPE_LIST})) {
|
||||
// This is the default input config. Delete it as it will
|
||||
// be applied automatically
|
||||
delete ui.type;
|
||||
@ -1820,7 +1238,7 @@ RED.subflow = (function() {
|
||||
ui.type = "cred";
|
||||
} else {
|
||||
ui.type = "input";
|
||||
ui.opts = {types:DEFAULT_ENV_TYPE_LIST}
|
||||
ui.opts = {types:RED.editor.envVarList.DEFAULT_ENV_TYPE_LIST}
|
||||
}
|
||||
} else {
|
||||
ui.opts = ui.opts || {};
|
||||
@ -1867,36 +1285,15 @@ RED.subflow = (function() {
|
||||
return 'node-input-subflow-env-'+name.replace(/[^a-z0-9-_]/ig,"_");
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup text for specific locale
|
||||
* @param labels - dict of labels
|
||||
* @param defaultLabel - fallback label if not found
|
||||
* @param locale - target locale
|
||||
* @returns {string} text for specified locale
|
||||
*/
|
||||
function lookupLabel(labels, defaultLabel, locale) {
|
||||
if (labels) {
|
||||
if (labels[locale]) {
|
||||
return labels[locale];
|
||||
}
|
||||
if (locale) {
|
||||
var lang = locale.substring(0, 2);
|
||||
if (labels[lang]) {
|
||||
return labels[lang];
|
||||
}
|
||||
}
|
||||
}
|
||||
return defaultLabel;
|
||||
}
|
||||
|
||||
// Called by subflow.oneditprepare for both instances and templates
|
||||
function buildEditForm(type,node) {
|
||||
if (type === "subflow-template") {
|
||||
// This is called by the `properties` edit pane when
|
||||
// editing a subflow template.
|
||||
buildPropertiesList($('#node-input-env-container'), node);
|
||||
// This is the tabbed UI that offers the env list - with UI options
|
||||
// plus the preview tab
|
||||
buildEnvControl($('#node-input-env-container'), node);
|
||||
RED.editor.envVarList.create($('#node-input-env-container'), node);
|
||||
} else if (type === "subflow") {
|
||||
// This gets called by the subflow type `oneditprepare` function
|
||||
// registered in nodes.js#addSubflow()
|
||||
// This is the rendered version of the subflow env var list
|
||||
buildEnvUI($("#subflow-input-ui"), getSubflowInstanceParentEnv(node), node);
|
||||
}
|
||||
}
|
||||
@ -1912,7 +1309,6 @@ RED.subflow = (function() {
|
||||
removeStatus: removeSubflowStatus,
|
||||
|
||||
buildEditForm: buildEditForm,
|
||||
buildPropertiesList: buildPropertiesList,
|
||||
|
||||
exportSubflowTemplateEnv: exportEnvList,
|
||||
exportSubflowInstanceEnv: exportSubflowInstanceEnv
|
||||
|
Loading…
Reference in New Issue
Block a user