mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
Add visual json editor
This commit is contained in:
parent
c97786e12c
commit
e3e0378857
@ -739,7 +739,16 @@
|
||||
},
|
||||
"jsonEditor": {
|
||||
"title": "JSON editor",
|
||||
"format": "format JSON"
|
||||
"format": "format JSON",
|
||||
"rawMode": "Edit JSON",
|
||||
"uiMode": "Visual editor",
|
||||
"insertAbove": "Insert above",
|
||||
"insertBelow": "Insert below",
|
||||
"addItem": "Add item",
|
||||
"copyPath": "Copy path to item",
|
||||
"expandItems": "Expand items",
|
||||
"collapseItems": "Collapse items",
|
||||
"duplicate": "Duplicate"
|
||||
},
|
||||
"markdownEditor": {
|
||||
"title": "Markdown editor",
|
||||
|
@ -185,6 +185,7 @@
|
||||
}
|
||||
},
|
||||
_destroy: function() {
|
||||
this.topContainer.remove();
|
||||
},
|
||||
_refreshFilter: function() {
|
||||
var that = this;
|
||||
@ -230,7 +231,7 @@
|
||||
this.uiHeight = desiredHeight;
|
||||
this._resize();
|
||||
},
|
||||
addItem: function(data) {
|
||||
insertItemAt: function(data,index) {
|
||||
var that = this;
|
||||
data = data || {};
|
||||
var li = $('<li>');
|
||||
@ -248,7 +249,13 @@
|
||||
});
|
||||
}
|
||||
if (!added) {
|
||||
li.appendTo(this.element);
|
||||
if (index <= 0) {
|
||||
li.prependTo(this.element);
|
||||
} else if (index > that.element.children().length-1) {
|
||||
li.appendTo(this.element);
|
||||
} else {
|
||||
li.insertBefore(this.element.children().eq(index));
|
||||
}
|
||||
}
|
||||
var row = $('<div/>').addClass("red-ui-editableList-item-content").appendTo(li);
|
||||
row.data('data',data);
|
||||
@ -293,6 +300,9 @@
|
||||
},0);
|
||||
}
|
||||
},
|
||||
addItem: function(data) {
|
||||
this.insertItemAt(data,this.element.children().length)
|
||||
},
|
||||
addItems: function(items) {
|
||||
for (var i=0; i<items.length;i++) {
|
||||
this.addItem(items[i]);
|
||||
|
@ -20,6 +20,10 @@
|
||||
* - data : array - initial items to display in tree
|
||||
* - multi : boolean - if true, .selected will return an array of results
|
||||
* otherwise, returns the first selected item
|
||||
* - sortable: boolean/string - TODO: see editableList
|
||||
* - rootSortable: boolean - if 'sortable' is set, then setting this to
|
||||
* false, prevents items being sorted to the
|
||||
* top level of the tree
|
||||
*
|
||||
* methods:
|
||||
* - data(items) - clears existing items and replaces with new data
|
||||
@ -27,25 +31,57 @@
|
||||
* events:
|
||||
* - treelistselect : function(event, item) {}
|
||||
* - treelistconfirm : function(event,item) {}
|
||||
* - treelistchangeparent: function(event,item, oldParent, newParent) {}
|
||||
*
|
||||
* data:
|
||||
* [
|
||||
* {
|
||||
* label: 'Local', // label for the item
|
||||
* sublabel: 'Local', // a sub-label for the item
|
||||
* icon: 'fa fa-rocket', // (optional) icon for the item
|
||||
* selected: true/false, // (optional) if present, display checkbox accordingly
|
||||
* children: [] | function(done,item) // (optional) an array of child items, or a function
|
||||
* // that will call the `done` callback with an array
|
||||
* // of child items
|
||||
* expanded: true/false, // show the child items by default
|
||||
* deferBuild: true/false, // don't build any ui elements for the item's children
|
||||
* until it is expanded by the user.
|
||||
* element: // custom dom element to use for the item - ignored if `label` is set
|
||||
* }
|
||||
* ]
|
||||
*
|
||||
*
|
||||
*
|
||||
* var treeList = $("<div>").css({width: "100%", height: "100%"}).treeList({data:[...]})
|
||||
* treeList.on('treelistselect', function(e,item) { console.log(item)})
|
||||
* treeList.treeList('data',[ ... ] )
|
||||
*
|
||||
*
|
||||
* After `data` has been added to the tree, each item is augmented the following
|
||||
* properties and functions:
|
||||
*
|
||||
* item.parent - set to the parent item
|
||||
* item.treeList.container
|
||||
* item.treeList.label - the label element for the item
|
||||
* item.treeList.depth - the depth in the tree (0 == root)
|
||||
* item.treeList.parentList - the editableList instance this item is in
|
||||
* item.treeList.remove() - removes the item from the tree
|
||||
* item.treeList.makeLeaf(detachChildElements) - turns an element with children into a leaf node,
|
||||
* removing the UI decoration etc.
|
||||
* detachChildElements - any children with custom
|
||||
* elements will be detached rather than removed
|
||||
* so jQuery event handlers are preserved in case
|
||||
* the child elements need to be reattached later
|
||||
* item.treeList.makeParent(children) - turns an element into a parent node, adding the necessary
|
||||
* UI decoration.
|
||||
* item.treeList.insertChildAt(newItem,position,select) - adds a child item an the specified position.
|
||||
* Optionally selects the item after adding.
|
||||
* item.treeList.addChild(newItem,select) - appends a child item.
|
||||
* Optionally selects the item after adding.
|
||||
* item.treeList.expand(done) - expands the parent item to show children. Optional 'done' callback.
|
||||
* item.treeList.collapse() - collapse the parent item to hide children.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
$.widget( "nodered.treeList", {
|
||||
@ -116,20 +152,30 @@
|
||||
});
|
||||
this._data = [];
|
||||
|
||||
this._topList = $('<ol>').css({
|
||||
this._topList = $('<ol class="red-ui-treeList-list">').css({
|
||||
position:'absolute',
|
||||
top: 0,
|
||||
left:0,
|
||||
right:0,
|
||||
bottom:0
|
||||
}).appendTo(wrapper).editableList({
|
||||
}).appendTo(wrapper);
|
||||
|
||||
var topListOptions = {
|
||||
addButton: false,
|
||||
scrollOnAdd: false,
|
||||
height: '100%',
|
||||
addItem: function(container,i,item) {
|
||||
that._addSubtree(that._topList,container,item,0);
|
||||
}
|
||||
})
|
||||
};
|
||||
if (this.options.rootSortable !== false && !!this.options.sortable) {
|
||||
topListOptions.sortable = this.options.sortable;
|
||||
topListOptions.connectWith = '.red-ui-treeList-sortable';
|
||||
this._topList.addClass('red-ui-treeList-sortable');
|
||||
}
|
||||
this._topList.editableList(topListOptions)
|
||||
|
||||
|
||||
if (this.options.data) {
|
||||
this.data(this.options.data);
|
||||
}
|
||||
@ -171,23 +217,82 @@
|
||||
},
|
||||
_addChildren: function(container,parent,children,depth) {
|
||||
var that = this;
|
||||
var subtree = $('<ol>').appendTo(container).editableList({
|
||||
var subtree = $('<ol class="red-ui-treeList-list">').appendTo(container).editableList({
|
||||
connectWith: ".red-ui-treeList-sortable",
|
||||
sortable: that.options.sortable,
|
||||
addButton: false,
|
||||
scrollOnAdd: false,
|
||||
height: 'auto',
|
||||
addItem: function(container,i,item) {
|
||||
that._addSubtree(subtree,container,item,depth+1);
|
||||
},
|
||||
sortItems: function(data) {
|
||||
var children = [];
|
||||
var reparented = [];
|
||||
data.each(function() {
|
||||
var child = $(this).data('data');
|
||||
children.push(child);
|
||||
var evt = that._fixDepths(parent,child);
|
||||
if (evt) {
|
||||
reparented.push(evt);
|
||||
}
|
||||
})
|
||||
if (Array.isArray(parent.children)) {
|
||||
parent.children = children;
|
||||
}
|
||||
reparented.forEach(function(evt) {
|
||||
that._trigger("changeparent",null,evt);
|
||||
});
|
||||
that._trigger("sort",null,parent);
|
||||
}
|
||||
});
|
||||
if (!!that.options.sortable) {
|
||||
subtree.addClass('red-ui-treeList-sortable');
|
||||
}
|
||||
for (var i=0;i<children.length;i++) {
|
||||
children[i].parent = parent;
|
||||
subtree.editableList('addItem',children[i])
|
||||
}
|
||||
return subtree;
|
||||
},
|
||||
_fixDepths: function(parent,child) {
|
||||
// If child has just been moved into parent in the UI
|
||||
// this will fix up the internal data structures to match.
|
||||
// The calling function must take care of getting child
|
||||
// into the parent.children array. The rest is up to us.
|
||||
var that = this;
|
||||
var reparentedEvent = null;
|
||||
if (child.parent !== parent) {
|
||||
reparented = true;
|
||||
var oldParent = child.parent;
|
||||
child.parent = parent;
|
||||
reparentedEvent = {
|
||||
item: child,
|
||||
old: oldParent,
|
||||
}
|
||||
}
|
||||
if (child.depth !== parent.depth+1) {
|
||||
child.depth = parent.depth+1;
|
||||
var labelPaddingWidth = ((child.gutter?child.gutter.width()+2:0)+(child.depth*20));
|
||||
child.treeList.labelPadding.width(labelPaddingWidth+'px');
|
||||
if (child.element) {
|
||||
$(child.element).css({
|
||||
width: "calc(100% - "+(labelPaddingWidth+20+(child.icon?20:0))+"px)"
|
||||
})
|
||||
}
|
||||
// This corrects all child item depths
|
||||
if (child.children && Array.isArray(child.children)) {
|
||||
child.children.forEach(function(item) {
|
||||
that._fixDepths(child,item);
|
||||
})
|
||||
}
|
||||
}
|
||||
return reparentedEvent;
|
||||
},
|
||||
_addSubtree: function(parentList, container, item, depth) {
|
||||
var that = this;
|
||||
item.treeList = {};
|
||||
item.treeList.depth = depth;
|
||||
item.treeList.container = container;
|
||||
|
||||
item.treeList.parentList = parentList;
|
||||
@ -196,87 +301,80 @@
|
||||
if (item.parent) {
|
||||
var index = item.parent.children.indexOf(item);
|
||||
item.parent.children.splice(index,1)
|
||||
that._trigger("sort",null,item.parent);
|
||||
}
|
||||
}
|
||||
var labelNodeType = "<div>";
|
||||
// if (item.children && item.hasOwnProperty('selected')) {
|
||||
// labelNodeType = "<div>";
|
||||
// }
|
||||
var label = $(labelNodeType,{class:"red-ui-treeList-label"}).appendTo(container);
|
||||
|
||||
var label = $("<div>",{class:"red-ui-treeList-label"}).appendTo(container);
|
||||
item.treeList.label = label;
|
||||
if (item.class) {
|
||||
label.addClass(item.class);
|
||||
}
|
||||
label.css({
|
||||
paddingLeft: (depth*15)+'px'
|
||||
})
|
||||
if (item.gutter) {
|
||||
item.gutter.css({
|
||||
position: 'absolute'
|
||||
}).appendTo(label)
|
||||
|
||||
}
|
||||
var labelPaddingWidth = (item.gutter?item.gutter.width()+2:0)+(depth*20);
|
||||
item.treeList.labelPadding = $('<span>').css({
|
||||
display: "inline-block",
|
||||
width: labelPaddingWidth+'px'
|
||||
}).appendTo(label);
|
||||
|
||||
label.on('mouseover',function(e) { that._trigger('itemmouseover',e,item); })
|
||||
label.on('mouseout',function(e) { that._trigger('itemmouseout',e,item); })
|
||||
label.on('mouseenter',function(e) { that._trigger('itemmouseenter',e,item); })
|
||||
label.on('mouseleave',function(e) { that._trigger('itemmouseleave',e,item); })
|
||||
|
||||
if (item.children) {
|
||||
item.treeList.addChild = function(newItem,select) {
|
||||
item.treeList.childList.editableList('addItem',newItem)
|
||||
newItem.parent = item;
|
||||
item.children.push(newItem);
|
||||
if (select) {
|
||||
setTimeout(function() {
|
||||
that.select(newItem)
|
||||
},100);
|
||||
}
|
||||
item.treeList.makeLeaf = function(detachChildElements) {
|
||||
if (!treeListIcon.children().length) {
|
||||
// Already a leaf
|
||||
return
|
||||
}
|
||||
item.treeList.expand = function(done) {
|
||||
if (container.hasClass("expanded")) {
|
||||
done && done();
|
||||
return;
|
||||
}
|
||||
if (!container.hasClass("built") && typeof item.children === 'function') {
|
||||
container.addClass('built');
|
||||
var childrenAdded = false;
|
||||
var spinner;
|
||||
var startTime = 0;
|
||||
item.children(function(children) {
|
||||
childrenAdded = true;
|
||||
item.treeList.childList = that._addChildren(container,item,children,depth).hide();
|
||||
var delta = Date.now() - startTime;
|
||||
if (delta < 400) {
|
||||
setTimeout(function() {
|
||||
item.treeList.childList.slideDown('fast');
|
||||
if (spinner) {
|
||||
spinner.remove();
|
||||
}
|
||||
},400-delta);
|
||||
} else {
|
||||
item.treeList.childList.slideDown('fast');
|
||||
if (spinner) {
|
||||
spinner.remove();
|
||||
if (detachChildElements && item.children) {
|
||||
var detachChildren = function(item) {
|
||||
if (item.children) {
|
||||
item.children.forEach(function(child) {
|
||||
if (child.element) {
|
||||
child.element.detach();
|
||||
}
|
||||
}
|
||||
done && done();
|
||||
that._trigger("childrenloaded",null,item)
|
||||
},item);
|
||||
if (!childrenAdded) {
|
||||
startTime = Date.now();
|
||||
spinner = $('<div class="red-ui-treeList-spinner">').css({
|
||||
"background-position": (35+depth*15)+'px 50%'
|
||||
}).appendTo(container);
|
||||
if (child.gutter) {
|
||||
child.gutter.detach();
|
||||
}
|
||||
detachChildren(child);
|
||||
});
|
||||
}
|
||||
|
||||
} else {
|
||||
item.treeList.childList.slideDown('fast');
|
||||
done && done();
|
||||
}
|
||||
container.addClass("expanded");
|
||||
detachChildren(item);
|
||||
}
|
||||
item.treeList.collapse = function() {
|
||||
item.treeList.childList.slideUp('fast');
|
||||
container.removeClass("expanded");
|
||||
treeListIcon.empty();
|
||||
if (!item.deferBuild) {
|
||||
item.treeList.childList.remove();
|
||||
delete item.treeList.childList;
|
||||
}
|
||||
|
||||
$('<span class="red-ui-treeList-icon"><i class="fa fa-angle-right" /></span>').appendTo(label);
|
||||
label.off("click.red-ui-treeList-expand");
|
||||
treeListIcon.off("click.red-ui-treeList-expand");
|
||||
delete item.children;
|
||||
container.removeClass("expanded");
|
||||
}
|
||||
item.treeList.makeParent = function(children) {
|
||||
if (treeListIcon.children().length) {
|
||||
// Already a parent because we've got the angle-right icon
|
||||
return;
|
||||
}
|
||||
$('<i class="fa fa-angle-right" />').appendTo(treeListIcon);
|
||||
treeListIcon.on("click.red-ui-treeList-expand", function(e) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
if (container.hasClass("expanded")) {
|
||||
item.treeList.collapse();
|
||||
} else {
|
||||
item.treeList.expand();
|
||||
}
|
||||
});
|
||||
// $('<span class="red-ui-treeList-icon"><i class="fa fa-folder-o" /></span>').appendTo(label);
|
||||
label.on("click", function(e) {
|
||||
label.on("click.red-ui-treeList-expand", function(e) {
|
||||
if (container.hasClass("expanded")) {
|
||||
if (item.hasOwnProperty('selected') || label.hasClass("selected")) {
|
||||
item.treeList.collapse();
|
||||
@ -285,9 +383,97 @@
|
||||
item.treeList.expand();
|
||||
}
|
||||
})
|
||||
} else {
|
||||
$('<span class="red-ui-treeList-icon"></span>').appendTo(label);
|
||||
if (!item.children) {
|
||||
item.children = children||[];
|
||||
item.treeList.childList = that._addChildren(container,item,item.children,depth).hide();
|
||||
}
|
||||
}
|
||||
item.treeList.insertChildAt = function(newItem,position,select) {
|
||||
newItem.parent = item;
|
||||
item.children.splice(position,0,newItem);
|
||||
|
||||
if (!item.deferBuild) {
|
||||
item.treeList.childList.editableList('insertItemAt',newItem,position)
|
||||
if (select) {
|
||||
setTimeout(function() {
|
||||
that.select(newItem)
|
||||
},100);
|
||||
}
|
||||
that._trigger("sort",null,item);
|
||||
}
|
||||
}
|
||||
item.treeList.addChild = function(newItem,select) {
|
||||
item.treeList.insertChildAt(newItem,item.children.length,select);
|
||||
}
|
||||
item.treeList.expand = function(done) {
|
||||
if (!item.children) {
|
||||
return;
|
||||
}
|
||||
if (container.hasClass("expanded")) {
|
||||
done && done();
|
||||
return;
|
||||
}
|
||||
if (!container.hasClass("built") && (item.deferBuild || typeof item.children === 'function')) {
|
||||
container.addClass('built');
|
||||
var childrenAdded = false;
|
||||
var spinner;
|
||||
var startTime = 0;
|
||||
var completeBuild = function(children) {
|
||||
childrenAdded = true;
|
||||
item.treeList.childList = that._addChildren(container,item,children,depth).hide();
|
||||
var delta = Date.now() - startTime;
|
||||
if (delta < 400) {
|
||||
setTimeout(function() {
|
||||
item.treeList.childList.slideDown('fast');
|
||||
if (spinner) {
|
||||
spinner.remove();
|
||||
}
|
||||
},400-delta);
|
||||
} else {
|
||||
item.treeList.childList.slideDown('fast');
|
||||
if (spinner) {
|
||||
spinner.remove();
|
||||
}
|
||||
}
|
||||
done && done();
|
||||
that._trigger("childrenloaded",null,item)
|
||||
}
|
||||
if (typeof item.children === 'function') {
|
||||
item.children(completeBuild,item);
|
||||
} else {
|
||||
delete item.deferBuild;
|
||||
completeBuild(item.children);
|
||||
}
|
||||
if (!childrenAdded) {
|
||||
startTime = Date.now();
|
||||
spinner = $('<div class="red-ui-treeList-spinner">').css({
|
||||
"background-position": (35+depth*20)+'px 50%'
|
||||
}).appendTo(container);
|
||||
}
|
||||
|
||||
} else {
|
||||
if (that._loadingData) {
|
||||
item.treeList.childList.show();
|
||||
} else {
|
||||
item.treeList.childList.slideDown('fast');
|
||||
}
|
||||
done && done();
|
||||
}
|
||||
container.addClass("expanded");
|
||||
}
|
||||
item.treeList.collapse = function() {
|
||||
if (!item.children) {
|
||||
return;
|
||||
}
|
||||
item.treeList.childList.slideUp('fast');
|
||||
container.removeClass("expanded");
|
||||
}
|
||||
|
||||
var treeListIcon = $('<span class="red-ui-treeList-icon"></span>').appendTo(label);
|
||||
if (item.children) {
|
||||
item.treeList.makeParent();
|
||||
}
|
||||
|
||||
if (item.hasOwnProperty('selected')) {
|
||||
var selectWrapper = $('<span class="red-ui-treeList-icon"></span>').appendTo(label);
|
||||
var cb = $('<input class="red-ui-treeList-checkbox" type="checkbox">').prop('checked',item.selected).appendTo(selectWrapper);
|
||||
@ -326,19 +512,22 @@
|
||||
if (item.icon) {
|
||||
$('<span class="red-ui-treeList-icon"><i class="'+item.icon+'" /></span>').appendTo(label);
|
||||
}
|
||||
if (item.label || item.sublabel) {
|
||||
if (item.label) {
|
||||
if (item.hasOwnProperty('label') || item.hasOwnProperty('sublabel')) {
|
||||
if (item.hasOwnProperty('label')) {
|
||||
$('<span class="red-ui-treeList-label-text"></span>').text(item.label).appendTo(label);
|
||||
}
|
||||
if (item.sublabel) {
|
||||
if (item.hasOwnProperty('sublabel')) {
|
||||
$('<span class="red-ui-treeList-sublabel-text"></span>').text(item.sublabel).appendTo(label);
|
||||
}
|
||||
|
||||
} else if (item.element) {
|
||||
$(item.element).appendTo(label);
|
||||
$(item.element).css({
|
||||
width: "calc(100% - "+(labelPaddingWidth+20+(item.icon?20:0))+"px)"
|
||||
})
|
||||
}
|
||||
if (item.children) {
|
||||
if (Array.isArray(item.children)) {
|
||||
if (Array.isArray(item.children) && !item.deferBuild) {
|
||||
item.treeList.childList = that._addChildren(container,item,item.children,depth).hide();
|
||||
}
|
||||
if (item.expanded) {
|
||||
@ -350,12 +539,17 @@
|
||||
this._topList.editableList('empty');
|
||||
},
|
||||
data: function(items) {
|
||||
var that = this;
|
||||
if (items !== undefined) {
|
||||
this._data = items;
|
||||
this._topList.editableList('empty');
|
||||
this._loadingData = true;
|
||||
for (var i=0; i<items.length;i++) {
|
||||
this._topList.editableList('addItem',items[i]);
|
||||
}
|
||||
setTimeout(function() {
|
||||
delete that._loadingData;
|
||||
},200);
|
||||
this._trigger("select")
|
||||
|
||||
} else {
|
||||
|
@ -249,9 +249,15 @@
|
||||
that.validate();
|
||||
that.element.val(that.value());
|
||||
that.element.trigger('change',that.propertyType,that.value());
|
||||
});
|
||||
this.input.on('keydown', function(evt) {
|
||||
if (evt.keyCode >= 37 && evt.keyCode <= 40) {
|
||||
evt.stopPropagation();
|
||||
}
|
||||
})
|
||||
this.selectTrigger.on("click", function(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
that._showTypeMenu();
|
||||
});
|
||||
this.selectTrigger.on('keydown',function(evt) {
|
||||
@ -259,6 +265,7 @@
|
||||
// Down
|
||||
that._showTypeMenu();
|
||||
}
|
||||
evt.stopPropagation();
|
||||
}).on('focus', function() {
|
||||
that.uiSelect.addClass('red-ui-typedInput-focus');
|
||||
})
|
||||
@ -271,12 +278,14 @@
|
||||
});
|
||||
this.optionSelectTrigger.on("click", function(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
that._showOptionSelectMenu();
|
||||
}).on('keydown', function(evt) {
|
||||
if (evt.keyCode === 40) {
|
||||
// Down
|
||||
that._showOptionSelectMenu();
|
||||
}
|
||||
evt.stopPropagation();
|
||||
}).on('blur', function() {
|
||||
that.uiSelect.removeClass('red-ui-typedInput-focus');
|
||||
}).on('focus', function() {
|
||||
@ -357,6 +366,7 @@
|
||||
|
||||
op.on("click", function(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
callback(opt.value);
|
||||
that._hideMenu(menu);
|
||||
});
|
||||
@ -376,9 +386,11 @@
|
||||
// UP
|
||||
$(this).children(":focus").prev().trigger("focus");
|
||||
} else if (evt.keyCode === 27) {
|
||||
// ESCAPE
|
||||
evt.preventDefault();
|
||||
that._hideMenu(menu);
|
||||
}
|
||||
evt.stopPropagation();
|
||||
})
|
||||
|
||||
|
||||
@ -516,6 +528,7 @@
|
||||
this.optionMenu.remove();
|
||||
}
|
||||
this.menu.remove();
|
||||
this.uiSelect.remove();
|
||||
},
|
||||
types: function(types) {
|
||||
var that = this;
|
||||
|
@ -16,7 +16,419 @@
|
||||
(function() {
|
||||
|
||||
|
||||
var template = '<script type="text/x-red" data-template-name="_json"><div class="form-row" style="margin-bottom: 3px; text-align: right;"><button id="node-input-json-reformat" class="red-ui-button red-ui-button-small"><span data-i18n="jsonEditor.format"></span></button></div><div class="form-row node-text-editor-row"><div style="height: 200px;min-height: 150px;" class="node-text-editor" id="node-input-json"></div></div></script>';
|
||||
// var template = '<script type="text/x-red" data-template-name="_json"></script>';
|
||||
var template = '<script type="text/x-red" data-template-name="_json">'+
|
||||
'<ul id="red-ui-editor-type-json-tabs"></ul>'+
|
||||
'<div id="red-ui-editor-type-json-tab-raw" class="red-ui-editor-type-json-tab-content hide">'+
|
||||
'<div class="form-row" style="margin-bottom: 3px; text-align: right;">'+
|
||||
'<button id="node-input-json-reformat" class="red-ui-button red-ui-button-small"><span data-i18n="jsonEditor.format"></span></button>'+
|
||||
'</div>'+
|
||||
'<div class="form-row node-text-editor-row">'+
|
||||
'<div style="height: 200px;min-height: 150px;" class="node-text-editor" id="node-input-json"></div>'+
|
||||
'</div>'+
|
||||
'</div>'+
|
||||
'<div id="red-ui-editor-type-json-tab-ui" class="red-ui-editor-type-json-tab-content hide">'+
|
||||
'<div id="red-ui-editor-type-json-tab-ui-container"></div>'+
|
||||
'</div>'+
|
||||
'</script>';
|
||||
|
||||
var activeTab;
|
||||
|
||||
function insertNewItem(parent,index,copyIndex) {
|
||||
var newValue = "";
|
||||
|
||||
if (parent.children.length > 0) {
|
||||
switch (parent.children[Math.max(0,Math.min(parent.children.length-1,copyIndex))].type) {
|
||||
case 'string': newValue = ""; break;
|
||||
case 'number': newValue = 0; break;
|
||||
case 'boolean': newValue = true; break;
|
||||
case 'null': newValue = null; break;
|
||||
case 'object': newValue = {}; break;
|
||||
case 'array': newValue = []; break;
|
||||
}
|
||||
}
|
||||
var newKey;
|
||||
if (parent.type === 'array') {
|
||||
newKey = parent.children.length;
|
||||
} else {
|
||||
var usedKeys = {};
|
||||
parent.children.forEach(function(child) { usedKeys[child.key] = true })
|
||||
var keyRoot = "item";
|
||||
var keySuffix = 2;
|
||||
newKey = keyRoot;
|
||||
while(usedKeys[newKey]) {
|
||||
newKey = keyRoot+"-"+(keySuffix++);
|
||||
}
|
||||
}
|
||||
var newItem = handleItem(newKey,newValue,parent.depth+1,parent);
|
||||
parent.treeList.insertChildAt(newItem, index, true);
|
||||
parent.treeList.expand();
|
||||
}
|
||||
function showObjectMenu(button,item) {
|
||||
var elementPos = button.offset();
|
||||
var options = [];
|
||||
if (item.parent) {
|
||||
options.push({id:"red-ui-editor-type-json-menu-insert-above", icon:"fa fa-toggle-up", label:RED._('jsonEditor.insertAbove'),onselect:function(){
|
||||
var index = item.parent.children.indexOf(item);
|
||||
insertNewItem(item.parent,index,index);
|
||||
}});
|
||||
options.push({id:"red-ui-editor-type-json-menu-insert-below", icon:"fa fa-toggle-down", label:RED._('jsonEditor.insertBelow'),onselect:function(){
|
||||
var index = item.parent.children.indexOf(item)+1;
|
||||
insertNewItem(item.parent,index,index-1);
|
||||
}});
|
||||
}
|
||||
if (item.type === 'array' || item.type === 'object') {
|
||||
options.push({id:"red-ui-editor-type-json-menu-add-child", icon:"fa fa-plus", label:RED._('jsonEditor.addItem'),onselect:function(){
|
||||
insertNewItem(item,item.children.length,item.children.length-1);
|
||||
}});
|
||||
}
|
||||
if (item.parent) {
|
||||
options.push({id:"red-ui-editor-type-json-menu-copy-path", icon:"fa fa-terminal", label:RED._('jsonEditor.copyPath'),onselect:function(){
|
||||
var i = item;
|
||||
var path = "";
|
||||
var newPath;
|
||||
while(i.parent) {
|
||||
if (i.parent.type === "array") {
|
||||
newPath = "["+i.key+"]";
|
||||
} else {
|
||||
if (/^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(i.key)) {
|
||||
newPath = i.key;
|
||||
} else {
|
||||
newPath = "[\""+i.key.replace(/"/,"\\\"")+"\"]"
|
||||
}
|
||||
}
|
||||
path = newPath+(path.length>0 && path[0] !== "["?".":"")+path;
|
||||
i = i.parent;
|
||||
}
|
||||
RED.clipboard.copyText(path,item.element,"clipboard.copyMessagePath");
|
||||
}});
|
||||
|
||||
options.push({id:"red-ui-editor-type-json-menu-duplicate", icon:"fa fa-copy", label:RED._("jsonEditor.duplicate"),onselect:function(){
|
||||
var newKey = item.key;
|
||||
if (item.parent.type === 'array') {
|
||||
newKey = parent.children.length;
|
||||
} else {
|
||||
var m = /^(.*?)(-(\d+))?$/.exec(newKey);
|
||||
var usedKeys = {};
|
||||
item.parent.children.forEach(function(child) { usedKeys[child.key] = true })
|
||||
var keyRoot = m[1];
|
||||
var keySuffix = 2;
|
||||
if (m[3] !== undefined) {
|
||||
keySuffix = parseInt(m[3]);
|
||||
}
|
||||
newKey = keyRoot;
|
||||
while(usedKeys[newKey]) {
|
||||
newKey = keyRoot+"-"+(keySuffix++);
|
||||
}
|
||||
}
|
||||
var newItem = handleItem(newKey,convertToObject(item),item.parent.depth+1,item.parent);
|
||||
var index = item.parent.children.indexOf(item)+1;
|
||||
|
||||
item.parent.treeList.insertChildAt(newItem, index, true);
|
||||
item.parent.treeList.expand();
|
||||
}});
|
||||
|
||||
options.push({id:"red-ui-editor-type-json-menu-delete", icon:"fa fa-times", label:RED._('common.label.delete'),onselect:function(){
|
||||
item.treeList.remove();
|
||||
}});
|
||||
}
|
||||
if (item.type === 'array' || item.type === 'object') {
|
||||
options.push(null)
|
||||
options.push({id:"red-ui-editor-type-json-menu-expand-children",icon:"fa fa-angle-double-down", label:RED._('jsonEditor.expandItems'),onselect:function(){
|
||||
item.treeList.expand();
|
||||
item.children.forEach(function(child) {
|
||||
child.treeList.expand();
|
||||
})
|
||||
}});
|
||||
options.push({id:"red-ui-editor-type-json-menu-collapse-children",icon:"fa fa-angle-double-up", label:RED._('jsonEditor.collapseItems'),onselect:function(){
|
||||
item.children.forEach(function(child) {
|
||||
child.treeList.collapse();
|
||||
})
|
||||
}});
|
||||
}
|
||||
|
||||
var menuOptionMenu = RED.menu.init({
|
||||
id:"red-ui-editor-type-json-menu",
|
||||
options: options
|
||||
});
|
||||
menuOptionMenu.css({
|
||||
position: "absolute"
|
||||
})
|
||||
menuOptionMenu.on('mouseleave', function(){ $(this).hide() });
|
||||
menuOptionMenu.on('mouseup', function() { $(this).hide() });
|
||||
menuOptionMenu.appendTo("body");
|
||||
var top = elementPos.top;
|
||||
var height = menuOptionMenu.height();
|
||||
var winHeight = $(window).height();
|
||||
if (top+height > winHeight) {
|
||||
top -= (top+height)-winHeight + 20;
|
||||
}
|
||||
menuOptionMenu.css({
|
||||
top: top+"px",
|
||||
left: elementPos.left+"px"
|
||||
})
|
||||
menuOptionMenu.show();
|
||||
}
|
||||
|
||||
function parseObject(obj,depth,parent) {
|
||||
var result = [];
|
||||
for (var prop in obj) {
|
||||
if (obj.hasOwnProperty(prop)) {
|
||||
result.push(handleItem(prop,obj[prop],depth,parent));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
function parseArray(obj,depth,parent) {
|
||||
var result = [];
|
||||
var l = obj.length;
|
||||
for (var i=0;i<l;i++) {
|
||||
result.push(handleItem(i,obj[i],depth,parent));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
function handleItem(key,val,depth,parent) {
|
||||
var item = {depth:depth, type: typeof val};
|
||||
var container = $('<span class="red-ui-editor-type-json-editor-label">');
|
||||
if (key != null) {
|
||||
item.key = key;
|
||||
var keyText;
|
||||
if (typeof key === 'string') {
|
||||
keyText = '"'+key+'"';
|
||||
} else {
|
||||
keyText = key;
|
||||
}
|
||||
var keyLabel = $('<span class="red-ui-debug-msg-object-key red-ui-editor-type-json-editor-label-key">').text(keyText).appendTo(container);
|
||||
keyLabel.addClass('red-ui-debug-msg-type-'+(typeof key));
|
||||
if (parent && parent.type === "array") {
|
||||
keyLabel.addClass("red-ui-editor-type-json-editor-label-array-key")
|
||||
}
|
||||
|
||||
keyLabel.on("click", function(evt) {
|
||||
if (item.parent.type === 'array') {
|
||||
return;
|
||||
}
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
var w = Math.max(150,keyLabel.width());
|
||||
var keyInput = $('<input type="text" class="red-ui-editor-type-json-editor-key">').css({width:w+"px"}).val(""+item.key).insertAfter(keyLabel).typedInput({types:['str']});
|
||||
$(document).on("mousedown.nr-ui-json-editor", function(evt) {
|
||||
var typedInputElement = keyInput.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') {
|
||||
var newKey = keyInput.typedInput("value");
|
||||
item.key = newKey;
|
||||
var keyText;
|
||||
if (typeof newKey === 'string') {
|
||||
keyText = '"'+newKey+'"';
|
||||
} else {
|
||||
keyText = newKey;
|
||||
}
|
||||
keyLabel.text(keyText);
|
||||
keyInput.remove();
|
||||
keyLabel.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
|
||||
keyInput.remove();
|
||||
keyLabel.show();
|
||||
$(document).off("mousedown.nr-ui-json-editor");
|
||||
$(document).off("keydown.nr-ui-json-editor");
|
||||
}
|
||||
});
|
||||
keyLabel.hide();
|
||||
});
|
||||
$('<span>').text(" : ").appendTo(container);
|
||||
}
|
||||
|
||||
if (Array.isArray(val)) {
|
||||
item.expanded = depth < 2;
|
||||
item.type = "array";
|
||||
item.deferBuild = depth >= 2;
|
||||
item.children = parseArray(val,depth+1,item);
|
||||
} else if (val !== null && item.type === "object") {
|
||||
item.expanded = depth < 2;
|
||||
item.children = parseObject(val,depth+1,item);
|
||||
item.deferBuild = depth >= 2;
|
||||
} else {
|
||||
item.value = val;
|
||||
if (val === null) {
|
||||
item.type = 'null'
|
||||
}
|
||||
}
|
||||
|
||||
var valType;
|
||||
var valValue = "";
|
||||
var valClass;
|
||||
switch(item.type) {
|
||||
case 'string': valType = 'str'; valValue = '"'+item.value+'"'; valClass = "red-ui-debug-msg-type-string"; break;
|
||||
case 'number': valType = 'num'; valValue = item.value; valClass = "red-ui-debug-msg-type-number";break;
|
||||
case 'boolean': valType = 'bool'; valValue = item.value; valClass = "red-ui-debug-msg-type-other";break;
|
||||
case 'null': valType = item.type; valValue = item.type; valClass = "red-ui-debug-msg-type-null";break;
|
||||
case 'object':
|
||||
valType = item.type;
|
||||
valValue = item.type;//+"{"+item.children.length+"}";
|
||||
valClass = "red-ui-debug-msg-type-meta";
|
||||
break;
|
||||
case 'array':
|
||||
valType = item.type;
|
||||
valValue = item.type+"["+item.children.length+"]";
|
||||
valClass = "red-ui-debug-msg-type-meta";
|
||||
break;
|
||||
}
|
||||
//
|
||||
var orphanedChildren;
|
||||
var valueLabel = $('<span class="red-ui-editor-type-json-editor-label-value">').addClass(valClass).text(valValue).appendTo(container);
|
||||
valueLabel.on("click", function(evt) {
|
||||
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 = $('<input type="text" class="red-ui-editor-type-json-editor-value">').css({width:w+"px"}).val(""+valValue).insertAfter(valueLabel).typedInput({
|
||||
types:[
|
||||
'str','num','bool',
|
||||
{value:"null",label:"null",hasValue:false},
|
||||
{value:"array",label:"array",hasValue:false},
|
||||
{value:"object",label:"object",hasValue:false}
|
||||
],
|
||||
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': item.children && (orphanedChildren = item.children); item.treeList.makeLeaf(true); item.type = "string"; valClass = "red-ui-debug-msg-type-string"; valValue = '"'+valValue+'"'; break;
|
||||
case 'num': item.children && (orphanedChildren = item.children); item.treeList.makeLeaf(true); item.type = "number"; valClass = "red-ui-debug-msg-type-number"; break;
|
||||
case 'bool': 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': 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 = $('<span class="red-ui-editor-type-json-editor-item-gutter"></span>');
|
||||
|
||||
if (parent) {//red-ui-editor-type-json-editor-item-handle
|
||||
$('<span class="red-ui-editor-type-json-editor-item-handle"><i class="fa fa-bars"></span>').appendTo(item.gutter);
|
||||
} else {
|
||||
$('<span></span>').appendTo(item.gutter);
|
||||
}
|
||||
$('<button type="button" class="editor-button editor-button-small"><i class="fa fa-caret-down"></button>').appendTo(item.gutter).on("click", function(evt) {
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
showObjectMenu($(this), item);
|
||||
});
|
||||
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) {
|
||||
@ -41,9 +453,11 @@
|
||||
return false;
|
||||
}
|
||||
}
|
||||
var rootNode;
|
||||
|
||||
var trayOptions = {
|
||||
title: options.title,
|
||||
width: "inherit",
|
||||
width: options.width||700,
|
||||
buttons: [
|
||||
{
|
||||
id: "node-dialog-cancel",
|
||||
@ -60,25 +474,60 @@
|
||||
if (options.requireValid && !checkValid()) {
|
||||
return;
|
||||
}
|
||||
onComplete(expressionEditor.getValue());
|
||||
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();
|
||||
}
|
||||
onComplete && onComplete(result);
|
||||
RED.tray.close();
|
||||
}
|
||||
}
|
||||
],
|
||||
resize: function(dimensions) {
|
||||
var rows = $("#dialog-form>div:not(.node-text-editor-row)");
|
||||
var editorRow = $("#dialog-form>div.node-text-editor-row");
|
||||
var height = $("#dialog-form").height();
|
||||
for (var i=0;i<rows.size();i++) {
|
||||
height -= $(rows[i]).outerHeight(true);
|
||||
}
|
||||
height -= (parseInt($("#dialog-form").css("marginTop"))+parseInt($("#dialog-form").css("marginBottom")));
|
||||
$(".node-text-editor").css("height",height+"px");
|
||||
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 container = $("#red-ui-editor-type-json-tab-ui-container").css({"height":"100%"});
|
||||
var filterDepth = Infinity;
|
||||
var list = $('<div class="red-ui-debug-msg-payload red-ui-editor-type-json-editor">').appendTo(container).treeList({
|
||||
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: "",
|
||||
@ -103,9 +552,56 @@
|
||||
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);
|
||||
rootNode.class = "red-ui-editor-type-json-root-node"
|
||||
list.treeList('data',[rootNode]);
|
||||
} catch(err) {
|
||||
rootNode = null;
|
||||
list.treeList('data',[{
|
||||
label: "Invalid JSON: "+err.toString()
|
||||
}]);
|
||||
}
|
||||
}
|
||||
}
|
||||
tab.content.show();
|
||||
trayOptions.resize();
|
||||
}
|
||||
})
|
||||
|
||||
tabs.addTab({
|
||||
id: 'json-raw',
|
||||
label: RED._('jsonEditor.rawMode'),
|
||||
content: $("#red-ui-editor-type-json-tab-raw")
|
||||
});
|
||||
tabs.addTab({
|
||||
id: 'json-ui',
|
||||
label: RED._('jsonEditor.uiMode'),
|
||||
content: $("#red-ui-editor-type-json-tab-ui")
|
||||
});
|
||||
finishedBuild = true;
|
||||
|
||||
|
||||
},
|
||||
close: function() {
|
||||
expressionEditor.destroy();
|
||||
// expressionEditor.destroy();
|
||||
if (options.onclose) {
|
||||
options.onclose();
|
||||
}
|
||||
|
@ -461,3 +461,114 @@ button.red-ui-button-small
|
||||
margin: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.red-ui-editor input.red-ui-editor-type-json-editor-key {
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
.red-ui-editor-type-json-editor {
|
||||
height: calc(100% - 10px);
|
||||
.red-ui-treeList-container {
|
||||
background: $secondary-background;
|
||||
}
|
||||
.red-ui-treeList-label {
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
white-space: nowrap;
|
||||
min-height: 35px;
|
||||
.red-ui-treeList-icon:before {
|
||||
content:'';
|
||||
display: inline-block;
|
||||
height: 35px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
> span, > span > span {
|
||||
vertical-align: middle;
|
||||
}
|
||||
&:hover, &:hover .red-ui-treeList-sublabel-text {
|
||||
background: $secondary-background-disabled;
|
||||
.red-ui-editor-type-json-editor-item-gutter {
|
||||
> span, > button {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
}
|
||||
&.selected {
|
||||
.red-ui-editor-type-json-editor-item-gutter {
|
||||
background: $secondary-background-hover;
|
||||
}
|
||||
&:hover {
|
||||
.red-ui-editor-type-json-editor-item-gutter {
|
||||
background: $secondary-background-selected;
|
||||
}
|
||||
}
|
||||
}
|
||||
&.red-ui-editor-type-json-root-node {
|
||||
.red-ui-editor-type-json-editor-item-gutter {
|
||||
> span, > button {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.red-ui-editor-type-json-editor-controls {
|
||||
height: 34px;
|
||||
line-height: 34px;
|
||||
display: none;
|
||||
}
|
||||
.red-ui-editor-type-json-editor-key {
|
||||
width: 100px;
|
||||
}
|
||||
.red-ui-editor-type-json-editor-label {
|
||||
display: inline-block;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
.red-ui-editor-type-json-editor-label-value {
|
||||
min-width: 200px;
|
||||
}
|
||||
.red-ui-editor-type-json-editor-label-value,
|
||||
.red-ui-editor-type-json-editor-label-key {
|
||||
display: inline-block;
|
||||
box-sizing: border-box;
|
||||
min-height: 34px;
|
||||
line-height: 30px;
|
||||
padding: 0 2px;
|
||||
border: 2px solid rgba(0,0,0,0);
|
||||
border-radius: 3px;
|
||||
&:not(.red-ui-editor-type-json-editor-label-array-key):hover {
|
||||
border-color: $list-item-background-hover;
|
||||
border-style: dashed;
|
||||
}
|
||||
}
|
||||
.red-ui-editor-type-json-editor-item-gutter {
|
||||
width: 48px;
|
||||
padding-left: 4px;
|
||||
|
||||
height: 100%;
|
||||
line-height: 35px;
|
||||
color: $tertiary-text-color;
|
||||
background: $secondary-background-disabled;
|
||||
> span {
|
||||
display: inline-block;
|
||||
height: 35px;
|
||||
line-height: 35px;
|
||||
width: 20px;
|
||||
text-align:center;
|
||||
}
|
||||
> span, > button {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
.red-ui-editor-type-json-editor-item-handle {
|
||||
cursor: move;
|
||||
}
|
||||
.red-ui-editor-type-json-tab-content {
|
||||
position: relative;
|
||||
height: calc(100% - 40px);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user