added an ability to set custom css classes for Node's field and value (#604)
* update for gulp 4.0.0 * added an ability to set custom css classes for Node's field and value * v5.9.8-beta * wip * wip * wip * wip * wip * wip * cleanup * reverted ./dist/ files * cleanup * reverted package-lock.json * updated onClassName signature * recursive node class name update on change * add/remove css classes on node * example fix * merged remote * removed yarn.lock * changes get reflected on both sides of the diff view in example 20 * refactored and cleaned up example 20
This commit is contained in:
parent
160c82f378
commit
1c5d7d71ac
|
@ -0,0 +1,175 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
|
||||
|
||||
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">
|
||||
<script src="../dist/jsoneditor.js"></script>
|
||||
|
||||
<style type="text/css">
|
||||
body {
|
||||
font: 10.5pt arial;
|
||||
color: #4d4d4d;
|
||||
line-height: 150%;
|
||||
width: 500px;
|
||||
padding-left: 40px;
|
||||
}
|
||||
|
||||
code {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
#containerLeft {
|
||||
width: 500px;
|
||||
height: 500px;
|
||||
float: left;
|
||||
}
|
||||
#containerRight {
|
||||
width: 500px;
|
||||
height: 500px;
|
||||
float: right;
|
||||
}
|
||||
#wrapper {
|
||||
width: 1000px;
|
||||
}
|
||||
#containerRight .different_element {
|
||||
background-color: greenyellow !important;
|
||||
}
|
||||
#containerLeft .different_element {
|
||||
background-color: violet !important;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<p>
|
||||
JSON Diff
|
||||
</p>
|
||||
<div id="wrapper">
|
||||
<div id="containerLeft"></div>
|
||||
<div id="containerRight"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
var containerLeft, containerRight, options, json;
|
||||
|
||||
containerLeft = document.getElementById('containerLeft');
|
||||
containerRight = document.getElementById('containerRight');
|
||||
|
||||
function findNodeInJson(json, path){
|
||||
if(!json || path.length ===0) {
|
||||
return {field: undefined, value: undefined}
|
||||
}
|
||||
var first = path[0];
|
||||
var remainingPath = path.slice(1);
|
||||
|
||||
if(remainingPath.length === 0) {
|
||||
return {field: (typeof json[first] !== undefined ? first : undefined), value: json[first]};
|
||||
} else {
|
||||
return findNodeInJson(json[first], remainingPath)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
optionsLeft = {
|
||||
mode: 'tree',
|
||||
modes: ['code', 'form', 'text', 'tree', 'view'], // allowed modes
|
||||
onError: function (err) {
|
||||
alert(err.toString());
|
||||
},
|
||||
onClassName: function({ path, field, value }) {
|
||||
var thisNode = findNodeInJson(jsonLeft, path);
|
||||
var oppositeNode = findNodeInJson(jsonRight, path);
|
||||
|
||||
// this is not a proper way of comparing objects/values but's it's good enough for this example
|
||||
var isValueEqual = thisNode.value == oppositeNode.value;
|
||||
|
||||
if(Array.isArray(thisNode.value) && Array.isArray(oppositeNode.value)) {
|
||||
isValueEqual = thisNode.value.every(function (e) {
|
||||
return oppositeNode.value.includes(e);
|
||||
})
|
||||
}
|
||||
|
||||
if (thisNode.field === oppositeNode.field && isValueEqual) {
|
||||
return 'the_same_element';
|
||||
} else {
|
||||
return 'different_element'
|
||||
}
|
||||
},
|
||||
onChangeJSON: function (j) {
|
||||
jsonLeft = j;
|
||||
window.editorRight.refresh()
|
||||
}
|
||||
};
|
||||
|
||||
optionsRight = {
|
||||
mode: 'tree',
|
||||
modes: ['code', 'form', 'text', 'tree', 'view'], // allowed modes
|
||||
// name: "jsonContent",
|
||||
onError: function (err) {
|
||||
alert(err.toString());
|
||||
},
|
||||
onClassName: function({ path, field, value }) {
|
||||
|
||||
var thisNode = findNodeInJson(jsonRight, path);
|
||||
var oppositeNode = findNodeInJson(jsonLeft, path);
|
||||
|
||||
// this is not a proper way of comparing objects/values but's it's good enough for this example
|
||||
var isValueEqual = thisNode.value == oppositeNode.value;
|
||||
|
||||
if(Array.isArray(thisNode.value) && Array.isArray(oppositeNode.value)) {
|
||||
isValueEqual = thisNode.value.every(function (e) {
|
||||
return oppositeNode.value.includes(e);
|
||||
})
|
||||
}
|
||||
|
||||
if (thisNode.field === oppositeNode.field && isValueEqual) {
|
||||
return 'the_same_element';
|
||||
} else {
|
||||
return 'different_element'
|
||||
}
|
||||
},
|
||||
onChangeJSON: function (j) {
|
||||
jsonRight = j;
|
||||
window.editorLeft.refresh();
|
||||
}
|
||||
};
|
||||
|
||||
jsonLeft = {
|
||||
"arrayOfArrays": [1, 2, 999, [3,4,5]],
|
||||
"someField": true,
|
||||
"boolean": true,
|
||||
"htmlcode": '"',
|
||||
"escaped_unicode": '\\u20b9',
|
||||
"unicode": '\u20b9,\uD83D\uDCA9',
|
||||
"return": '\n',
|
||||
"null": null,
|
||||
"thisObjectDoesntExistOnTheRight" : {key: "value"},
|
||||
"number": 123,
|
||||
"object": {"a": "b","new":4, "c": "d", "e": [1, 2, 3]},
|
||||
"string": "Hello World",
|
||||
"url": "http://jsoneditoronline.org",
|
||||
"[0]": "zero"
|
||||
};
|
||||
|
||||
jsonRight = {
|
||||
"arrayOfArrays": [1, 2, [3,4,5]],
|
||||
"boolean": true,
|
||||
"htmlcode": '"',
|
||||
"escaped_unicode": '\\u20b9',
|
||||
"thisFieldDoesntExistOnTheLeft": 'foobar',
|
||||
"unicode": '\u20b9,\uD83D\uDCA9',
|
||||
"return": '\n',
|
||||
"null": null,
|
||||
"number": 123,
|
||||
"object": {"a": "b", "c": "d", "e": [1, 2, 3]},
|
||||
"string": "Hello World",
|
||||
"url": "http://jsoneditoronline.org",
|
||||
"[0]": "zero"
|
||||
};
|
||||
|
||||
window.editorLeft = new JSONEditor(containerLeft, optionsLeft, jsonLeft);
|
||||
window.editorRight = new JSONEditor(containerRight, optionsRight, jsonRight);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -82,6 +82,12 @@ if (typeof Promise === 'undefined') {
|
|||
* Only applicable for
|
||||
* modes 'form', 'tree' and
|
||||
* 'view'
|
||||
* {function} onClassName Callback method, triggered
|
||||
* when a Node DOM is rendered. Function returns
|
||||
* a css class name to be set on a node.
|
||||
* Only applicable for
|
||||
* modes 'form', 'tree' and
|
||||
* 'view'
|
||||
* {Number} maxVisibleChilds Number of children allowed for a node
|
||||
* in 'tree', 'view', or 'form' mode before
|
||||
* the "show more/show all" buttons appear.
|
||||
|
@ -168,7 +174,7 @@ JSONEditor.VALID_OPTIONS = [
|
|||
'ace', 'theme', 'autocomplete',
|
||||
'onChange', 'onChangeJSON', 'onChangeText',
|
||||
'onEditable', 'onError', 'onEvent', 'onModeChange', 'onNodeName', 'onValidate',
|
||||
'onSelectionChange', 'onTextSelectionChange',
|
||||
'onSelectionChange', 'onTextSelectionChange', 'onClassName',
|
||||
'colorPicker', 'onColorPicker',
|
||||
'timestampTag',
|
||||
'escapeUnicode', 'history', 'search', 'mode', 'modes', 'name', 'indentation',
|
||||
|
|
|
@ -31,7 +31,7 @@ function Node (editor, params) {
|
|||
this.editor = editor;
|
||||
this.dom = {};
|
||||
this.expanded = false;
|
||||
|
||||
|
||||
if(params && (params instanceof Object)) {
|
||||
this.setField(params.field, params.fieldEditable);
|
||||
if ('value' in params) {
|
||||
|
@ -913,7 +913,31 @@ Node.prototype.hideChilds = function(options) {
|
|||
delete this.visibleChilds;
|
||||
}
|
||||
};
|
||||
/**
|
||||
* set custom css classes on a node
|
||||
*/
|
||||
Node.prototype._updateCssClassName = function () {
|
||||
|
||||
if(this.dom.field
|
||||
&& this.editor
|
||||
&& this.editor.options
|
||||
&& typeof this.editor.options.onClassName ==='function'
|
||||
&& this.dom.tree){
|
||||
util.removeAllClassNames(this.dom.tree);
|
||||
const addClasses = this.editor.options.onClassName({ path: this.getPath(), field: this.field, value: this.value }) || "";
|
||||
util.addClassName(this.dom.tree, "jsoneditor-values " + addClasses);
|
||||
}
|
||||
}
|
||||
|
||||
Node.prototype.recursivelyUpdateCssClassesOnNodes = function () {
|
||||
this._updateCssClassName();
|
||||
if (this.childs !== 'undefined') {
|
||||
var i;
|
||||
for (i in this.childs) {
|
||||
this.childs[i].recursivelyUpdateCssClassesOnNodes();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Goes through the path from the node to the root and ensures that it is expanded
|
||||
|
@ -1649,7 +1673,7 @@ Node.prototype._updateDomValue = function () {
|
|||
}
|
||||
if (this.searchValue) {
|
||||
classNames.push('jsoneditor-highlight');
|
||||
}
|
||||
}
|
||||
|
||||
domValue.className = classNames.join(' ');
|
||||
|
||||
|
@ -1820,7 +1844,7 @@ Node.prototype._deleteDomColor = function () {
|
|||
*/
|
||||
Node.prototype._updateDomField = function () {
|
||||
var domField = this.dom.field;
|
||||
if (domField) {
|
||||
if (domField) {
|
||||
// make backgound color lightgray when empty
|
||||
var isEmpty = (String(this.field) == '' && this.parent.type != 'array');
|
||||
if (isEmpty) {
|
||||
|
@ -2484,6 +2508,8 @@ Node.prototype.updateDom = function (options) {
|
|||
// update field and value
|
||||
this._updateDomField();
|
||||
this._updateDomValue();
|
||||
|
||||
this._updateCssClassName();
|
||||
|
||||
// update childs indexes
|
||||
if (options && options.updateIndexes === true) {
|
||||
|
|
|
@ -550,13 +550,18 @@ treemode._onChange = function () {
|
|||
}
|
||||
}
|
||||
|
||||
// trigger the onClassName callback
|
||||
if(this.options.onClassName) {
|
||||
this.node.recursivelyUpdateCssClassesOnNodes();
|
||||
}
|
||||
|
||||
// trigger the onNodeName callback
|
||||
if (this.options.onNodeName && this.node.childs) {
|
||||
try {
|
||||
this.node.recursivelyUpdateNodeName();
|
||||
} catch (err) {
|
||||
console.error("Error in onNodeName callback: ", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -361,6 +361,14 @@ exports.addClassName = function addClassName(elem, className) {
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* remove all classes from the given elements style
|
||||
* @param {Element} elem
|
||||
*/
|
||||
exports.removeAllClassNames = function removeAllClassNames(elem) {
|
||||
elem.className = "";
|
||||
};
|
||||
|
||||
/**
|
||||
* add a className to the given elements style
|
||||
* @param {Element} elem
|
||||
|
|
Loading…
Reference in New Issue