').addClass(valClass).text(valValue).appendTo(container);
if (readOnly) {
valueLabel.addClass("readonly")
}
valueLabel.on("click", function(evt) {
if (readOnly) { return; }
evt.preventDefault();
evt.stopPropagation();
if (valType === 'str') {
valValue = valValue.substring(1,valValue.length-1);
} else if (valType === 'array') {
valValue = "";
} else if (valType === 'object') {
valValue = "";
}
var w = Math.max(150,valueLabel.width());
var val = $('').css({width:w+"px"}).val(""+valValue).insertAfter(valueLabel).typedInput({
types:[
'str','num','bool',
{value:"null",label:RED._("common.type.null"),hasValue:false},
{value:"array",label:RED._("common.type.array"),hasValue:false,icon:"red/images/typedInput/json.svg"},
{value:"object",label:RED._("common.type.object"),hasValue:false,icon:"red/images/typedInput/json.svg"}
],
default: valType
});
$(document).on("mousedown.nr-ui-json-editor", function(evt) {
var typedInputElement = val.next(".red-ui-typedInput-container")[0];
var target = evt.target;
while (target.nodeName !== 'BODY' && target !== typedInputElement && !$(target).hasClass("red-ui-typedInput-options")) {
target = target.parentElement;
}
if (target.nodeName === 'BODY') {
valType = val.typedInput("type");
valValue = val.typedInput("value");
if (valType === 'num') {
valValue = valValue.trim();
if (isNaN(valValue)) {
valType = 'str';
} else if (valValue === "") {
valValue = 0;
}
}
item.value = valValue;
var valClass;
switch(valType) {
case 'str': if (item.children) { orphanedChildren = item.children } item.treeList.makeLeaf(true); item.type = "string"; valClass = "red-ui-debug-msg-type-string"; valValue = '"'+valValue+'"'; break;
case 'num': if (item.children) { orphanedChildren = item.children } item.treeList.makeLeaf(true); item.type = "number"; valClass = "red-ui-debug-msg-type-number"; break;
case 'bool': if (item.children) { orphanedChildren = item.children } item.treeList.makeLeaf(true); item.type = "boolean"; valClass = "red-ui-debug-msg-type-other"; item.value = (valValue === "true"); break;
case 'null': if (item.children) { orphanedChildren = item.children } item.treeList.makeLeaf(true); item.type = "null"; valClass = "red-ui-debug-msg-type-null"; item.value = valValue = "null"; break;
case 'object':
item.treeList.makeParent(orphanedChildren);
item.type = "object";
valClass = "red-ui-debug-msg-type-meta";
item.value = valValue = "object";
item.children.forEach(function(child,i) {
if (child.hasOwnProperty('_key')) {
child.key = child._key;
delete child._key;
var keyText;
var keyLabel = child.element.find(".red-ui-editor-type-json-editor-label-key");
keyLabel.removeClass("red-ui-editor-type-json-editor-label-array-key");
if (typeof child.key === 'string') {
keyText = '"'+child.key+'"';
keyLabel.addClass('red-ui-debug-msg-type-string');
keyLabel.removeClass('red-ui-debug-msg-type-number');
} else {
keyText = child.key;
keyLabel.removeClass('red-ui-debug-msg-type-string');
keyLabel.addClass('red-ui-debug-msg-type-number');
}
keyLabel.text(keyText);
}
})
break;
case 'array':
item.treeList.makeParent(orphanedChildren);
item.type = "array";
valClass = "red-ui-debug-msg-type-meta";
item.value = valValue = "array["+(item.children.length)+"]";
item.children.forEach(function(child,i) {
child._key = child.key;
child.key = i;
child.element.find(".red-ui-editor-type-json-editor-label-key")
.addClass("red-ui-editor-type-json-editor-label-array-key")
.text(""+child.key)
.removeClass('red-ui-debug-msg-type-string')
.addClass('red-ui-debug-msg-type-number');
})
break;
}
valueLabel.text(valValue).removeClass().addClass("red-ui-editor-type-json-editor-label-value "+valClass);
val.remove();
valueLabel.show();
$(document).off("mousedown.nr-ui-json-editor");
$(document).off("keydown.nr-ui-json-editor");
}
})
$(document).on("keydown.nr-ui-json-editor",function(evt) {
if (evt.keyCode === 27) {
// Escape
val.remove();
valueLabel.show();
if (valType === 'str') {
valValue = '"'+valValue+'"';
}
$(document).off("mousedown.nr-ui-json-editor");
$(document).off("keydown.nr-ui-json-editor");
}
});
valueLabel.hide();
})
item.gutter = $('');
if(!readOnly) {
if (parent) {
$('').appendTo(item.gutter);
} else {
$('').appendTo(item.gutter);
}
$('').appendTo(item.gutter).on("click", function(evt) {
evt.preventDefault();
evt.stopPropagation();
showObjectMenu($(this), item, readOnly);
});
}
item.element = container;
return item;
}
function convertToObject(item) {
var element;
switch (item.type) {
case 'string': element = item.value; break;
case 'number': element = Number(item.value); break;
case 'boolean': element = item.value; break;
case 'null': element = null; break;
case 'object':
element = {};
item.children.forEach(function(child) {
element[child.key] = convertToObject(child);
})
break;
case 'array':
element = item.children.map(function(child) {
return convertToObject(child);
})
break;
}
return element;
}
var definition = {
show: function(options) {
var value = options.value;
var onCancel = options.cancel;
var onComplete = options.complete;
var type = "_json"
if ($("script[data-template-name='"+type+"']").length === 0) {
$(template).appendTo("#red-ui-editor-node-configs");
}
RED.view.state(RED.state.EDITING);
var expressionEditor;
var changeTimer;
var checkValid = function() {
var v = expressionEditor.getValue();
try {
JSON.parse(v);
$("#node-dialog-ok").removeClass('disabled');
return true;
} catch(err) {
$("#node-dialog-ok").addClass('disabled');
return false;
}
}
var rootNode;
var trayOptions = {
title: options.title,
focusElement: options.focusElement,
width: options.width||700,
buttons: [
{
id: "node-dialog-cancel",
text: RED._("common.label.cancel"),
click: function() {
if (onCancel) { onCancel(); }
RED.tray.close();
}
},
{
id: "node-dialog-ok",
text: RED._("common.label.done"),
class: "primary",
click: function() {
if (options.requireValid && !checkValid()) {
return;
}
var result;
if (activeTab === "json-ui") {
if (rootNode) {
result = JSON.stringify(convertToObject(rootNode),null,4);
} else {
result = expressionEditor.getValue();
}
} else if (activeTab === "json-raw") {
result = expressionEditor.getValue();
}
expressionEditor.saveView();
if (onComplete) { onComplete(result,null,expressionEditor) }
RED.tray.close();
}
}
],
resize: function(dimensions) {
var height = $(".red-ui-editor-type-json-tab-content").height();
$(".node-text-editor").css("height",(height-45)+"px");
expressionEditor.resize();
},
open: function(tray) {
var trayBody = tray.find('.red-ui-tray-body');
var dialogForm = RED.editor.buildEditForm(tray.find('.red-ui-tray-body'),'dialog-form',type,'editor');
var toolbarButtons = options.toolbarButtons || [];
if (toolbarButtons.length) {
toolbarButtons.forEach(function (button) {
var element = $('')
.insertBefore("#node-input-json-reformat")
.on("click", function (evt) {
evt.preventDefault();
if (button.click !== undefined) {
button.click.call(element, evt);
}
});
if (button.id) { element.attr("id", button.id); }
if (button.title) { element.attr("title", button.title); }
if (button.icon) { element.append($("").attr("class", button.icon)); }
if (button.label || button.text) {
element.append($("").text(" " + (button.label || button.text)));
}
});
}
var container = $("#red-ui-editor-type-json-tab-ui-container").css({"height":"100%"});
var filterDepth = Infinity;
var list = $('').appendTo(container).treeList({
selectable: false,
rootSortable: false,
sortable: ".red-ui-editor-type-json-editor-item-handle",
}).on("treelistchangeparent", function(event, evt) {
if (evt.old.type === 'array') {
evt.old.element.find(".red-ui-editor-type-json-editor-label-type").text("array["+evt.old.children.length+"]");
}
if (evt.item.parent.type === 'array') {
evt.item.parent.element.find(".red-ui-editor-type-json-editor-label-type").text("array["+evt.item.parent.children.length+"]");
}
}).on("treelistsort", function(event, item) {
item.children.forEach(function(child,i) {
if (item.type === 'array') {
child.key = i;
child.element.find(".red-ui-editor-type-json-editor-label-key")
.text(child.key)
.removeClass('red-ui-debug-msg-type-string')
.addClass('red-ui-debug-msg-type-number');
} else {
child.element.find(".red-ui-editor-type-json-editor-label-key")
.text('"'+child.key+'"')
.removeClass('red-ui-debug-msg-type-number')
.addClass('red-ui-debug-msg-type-string');
}
})
});
expressionEditor = RED.editor.createEditor({
id: 'node-input-json',
value: value||"",
mode:"ace/mode/json",
readOnly: !!options.readOnly,
stateId: options.stateId,
focus: true
});
if (options.requireValid) {
expressionEditor.getSession().on('change', function() {
clearTimeout(changeTimer);
changeTimer = setTimeout(checkValid,200);
});
checkValid();
}
$("#node-input-json-reformat").on("click", function(evt) {
evt.preventDefault();
var v = expressionEditor.getValue()||"";
try {
v = JSON.stringify(JSON.parse(v),null,4);
} catch(err) {
// TODO: do an optimistic auto-format
}
expressionEditor.getSession().setValue(v||"",-1);
});
dialogForm.i18n();
var finishedBuild = false;
var tabs = RED.tabs.create({
element: $("#red-ui-editor-type-json-tabs"),
onchange:function(tab) {
activeTab = tab.id;
$(".red-ui-editor-type-json-tab-content").hide();
if (finishedBuild) {
if (tab.id === "json-raw") {
if (rootNode) {
var result = JSON.stringify(convertToObject(rootNode),null,4);
expressionEditor.getSession().setValue(result||"",-1);
}
} else if (tab.id === "json-ui") {
var raw = expressionEditor.getValue().trim() ||"{}";
try {
var parsed = JSON.parse(raw);
rootNode = handleItem(null,parsed,0,null,options.readOnly);
rootNode.class = "red-ui-editor-type-json-root-node"
list.treeList('data',[rootNode]);
} catch(err) {
rootNode = null;
list.treeList('data',[{
label: RED._("jsonEditor.error.invalidJSON")+err.toString()
}]);
}
}
}
tab.content.show();
trayOptions.resize();
}
})
tabs.addTab({
id: 'json-raw',
label: options.readOnly ? RED._('jsonEditor.rawMode-readonly') : RED._('jsonEditor.rawMode'),
content: $("#red-ui-editor-type-json-tab-raw")
});
tabs.addTab({
id: 'json-ui',
label: options.readOnly ? RED._('jsonEditor.uiMode-readonly') : RED._('jsonEditor.uiMode'),
content: $("#red-ui-editor-type-json-tab-ui")
});
finishedBuild = true;
},
close: function() {
if (options.onclose) {
options.onclose();
}
expressionEditor.destroy();
},
show: function() {}
}
RED.tray.show(trayOptions);
}
}
RED.editor.registerTypeEditor("_json", definition);
})();