From ecd9bf021f3334e9aa773f519f46eb05c1a8fc6f Mon Sep 17 00:00:00 2001 From: Cristina Date: Mon, 2 Jul 2018 13:13:02 +0200 Subject: [PATCH 1/5] Add API functionality to extend event behaviour. --- .gitignore | 1 + HISTORY.md | 5 ++ docs/api.md | 19 +++++++ examples/16_extend_event_api.html | 86 +++++++++++++++++++++++++++++++ package.json | 2 +- src/js/JSONEditor.js | 12 ++++- src/js/Node.js | 6 ++- src/js/treemode.js | 12 +++-- 8 files changed, 136 insertions(+), 7 deletions(-) create mode 100644 examples/16_extend_event_api.html diff --git a/.gitignore b/.gitignore index 363c86a..4157ddb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .idea +*.iml .vscode build downloads diff --git a/HISTORY.md b/HISTORY.md index 7319dfb..10e7ddc 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -2,6 +2,11 @@ https://github.com/josdejong/jsoneditor +## 2018-07-02, version 5.19.0 + +- Implemented API: `extendEvent` to let extend behaviour when an event is +fired in a node using internal structures and code. + ## 2018-06-27, version 5.18.0 diff --git a/docs/api.md b/docs/api.md index f4fe59d..48680c5 100644 --- a/docs/api.md +++ b/docs/api.md @@ -226,6 +226,25 @@ Constructs a new JSONEditor. } ``` Only applicable when `mode` is 'tree'. + +- `{function} extendEvent` + + Set a function that will be triggered after node event. This is added at the + end of a node event execution, not replaced. It means that actions for that + event will be executed and after that, if this function is provided, this code + will be executed. + + signature should be: + ```js + /** + * @param {Node} the Node where event has been triggered + * @param {event} the event triggered + */ + function extendEvent(node, event) { + ... + } + ``` + Only applicable when `mode` is 'form', 'tree' or 'view'. - `{string} language` diff --git a/examples/16_extend_event_api.html b/examples/16_extend_event_api.html new file mode 100644 index 0000000..be56a8e --- /dev/null +++ b/examples/16_extend_event_api.html @@ -0,0 +1,86 @@ + + + + + + + + + + + + +

+ When clicking on a field or leaf, a log message will be shown in console. +

+ +
+
+
+ + + + diff --git a/package.json b/package.json index 67210dc..307ebd4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "jsoneditor", - "version": "5.18.0", + "version": "5.19.0", "main": "./index", "description": "A web-based tool to view, edit, format, and validate JSON", "tags": [ diff --git a/src/js/JSONEditor.js b/src/js/JSONEditor.js index f6d15b6..c01df3d 100644 --- a/src/js/JSONEditor.js +++ b/src/js/JSONEditor.js @@ -55,6 +55,13 @@ var util = require('./util'); * overlay and display the modals in a * centered location. * Defaults to document.body + * 'text' and 'code' + * {function} extendEvent Triggered after onEvent + * to extend event + * behaviour. + * Only applicable for + * modes 'form', 'tree' and + * 'view' * @param {Object | undefined} json JSON object */ function JSONEditor (container, options, json) { @@ -93,8 +100,9 @@ function JSONEditor (container, options, json) { 'ajv', 'schema', 'schemaRefs','templates', 'ace', 'theme','autocomplete', 'onChange', 'onEditable', 'onError', 'onModeChange', 'onSelectionChange', 'onTextSelectionChange', - 'escapeUnicode', 'history', 'search', 'mode', 'modes', 'name', 'indentation', - 'sortObjectKeys', 'navigationBar', 'statusBar', 'languages', 'language' + 'escapeUnicode', 'history', 'search', 'mode', 'modes', 'name', 'indentation', + 'sortObjectKeys', 'navigationBar', 'statusBar', 'languages', 'language', + 'extendEvent' ]; Object.keys(options).forEach(function (option) { diff --git a/src/js/Node.js b/src/js/Node.js index fc60904..968db58 100644 --- a/src/js/Node.js +++ b/src/js/Node.js @@ -2370,8 +2370,9 @@ Node.prototype._createDomTree = function () { /** * Handle an event. The event is caught centrally by the editor * @param {Event} event + * @param {extendEvent} function with code for extend event behaviour. */ -Node.prototype.onEvent = function (event) { +Node.prototype.onEvent = function (event, extendEvent) { var type = event.type, target = event.target || event.srcElement, dom = this.dom, @@ -2550,6 +2551,9 @@ Node.prototype.onEvent = function (event) { if (type == 'keydown') { this.onKeyDown(event); } + + // Execute event extension + if (extendEvent) extendEvent(this, event); }; /** diff --git a/src/js/treemode.js b/src/js/treemode.js index 50488bf..043d92f 100644 --- a/src/js/treemode.js +++ b/src/js/treemode.js @@ -35,6 +35,8 @@ var treemode = {}; * characters are escaped. * false by default. * {Object} schema A JSON Schema for validation + * {function} extendEvent Function triggered + * after Node event. * @private */ treemode.create = function (container, options) { @@ -63,6 +65,9 @@ treemode.create = function (container, options) { this.history = new History(this); } + if (options.extendEvent) + this.extendEvent = this.options.extendEvent; + this._createFrame(); this._createTable(); }; @@ -119,7 +124,8 @@ treemode._setOptions = function (options) { schemaRefs: null, autocomplete: null, navigationBar : true, - onSelectionChange: null + onSelectionChange: null, + extendEvent: null }; // copy all options @@ -889,13 +895,13 @@ treemode._onEvent = function (event) { } if (node) { - node.onEvent(event); + node.onEvent(event, this.options.extendEvent); } }; /** * Update TreePath components - * @param {Array} pathNodes list of nodes in path from root to selection + * @param {Array} pathNodes list of nodes in path from root to selection * @private */ treemode._updateTreePath = function (pathNodes) { From 9de11c04cde55d3bd3b21dd1906651e6a6456f12 Mon Sep 17 00:00:00 2001 From: Cristina Date: Mon, 16 Jul 2018 16:52:41 +0200 Subject: [PATCH 2/5] Changes due to PR. --- HISTORY.md | 4 +- docs/api.md | 20 +++++---- examples/16_on_event_api.html | 84 +++++++++++++++++++++++++++++++++++ src/js/JSONEditor.js | 14 +++--- src/js/Node.js | 34 ++++++++++++-- src/js/treemode.js | 12 +++-- 6 files changed, 140 insertions(+), 28 deletions(-) create mode 100644 examples/16_on_event_api.html diff --git a/HISTORY.md b/HISTORY.md index 10e7ddc..0a3ff42 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -4,8 +4,8 @@ https://github.com/josdejong/jsoneditor ## 2018-07-02, version 5.19.0 -- Implemented API: `extendEvent` to let extend behaviour when an event is -fired in a node using internal structures and code. +- Implemented API: `onEvent` triggered when an event occurs in a JSON field or +value. ## 2018-06-27, version 5.18.0 diff --git a/docs/api.md b/docs/api.md index 48680c5..4d4aefc 100644 --- a/docs/api.md +++ b/docs/api.md @@ -227,20 +227,24 @@ Constructs a new JSONEditor. ``` Only applicable when `mode` is 'tree'. -- `{function} extendEvent` +- `{function} onEvent` - Set a function that will be triggered after node event. This is added at the - end of a node event execution, not replaced. It means that actions for that - event will be executed and after that, if this function is provided, this code - will be executed. + Set a callback function that will be triggered when an event will occur in + a JSON field or value. + + In case of field event, node information will be + `{field: string, path: string[]}`. + In case of value event, node information will be + `{field: string, path: string[], value: string}` signature should be: ```js /** - * @param {Node} the Node where event has been triggered - * @param {event} the event triggered + * @param {Node} the Node where event has been triggered + identified by {field: string, path: string[] [, value: string]}` + * @param {event} the event fired */ - function extendEvent(node, event) { + function onEvent(node, event) { ... } ``` diff --git a/examples/16_on_event_api.html b/examples/16_on_event_api.html new file mode 100644 index 0000000..f526200 --- /dev/null +++ b/examples/16_on_event_api.html @@ -0,0 +1,84 @@ + + + + + + + + + + + + +

+ When clicking on a JSON field or value, a log message will be shown in + console. +

+ +
+
+
+ + + + diff --git a/src/js/JSONEditor.js b/src/js/JSONEditor.js index c01df3d..9b41f4d 100644 --- a/src/js/JSONEditor.js +++ b/src/js/JSONEditor.js @@ -56,12 +56,12 @@ var util = require('./util'); * centered location. * Defaults to document.body * 'text' and 'code' - * {function} extendEvent Triggered after onEvent - * to extend event - * behaviour. - * Only applicable for - * modes 'form', 'tree' and - * 'view' + * {function} onEvent Callback method, triggered + * when an event occurs in + * a JSON field or value. + * Only applicable for + * modes 'form', 'tree' and + * 'view' * @param {Object | undefined} json JSON object */ function JSONEditor (container, options, json) { @@ -102,7 +102,7 @@ function JSONEditor (container, options, json) { 'onChange', 'onEditable', 'onError', 'onModeChange', 'onSelectionChange', 'onTextSelectionChange', 'escapeUnicode', 'history', 'search', 'mode', 'modes', 'name', 'indentation', 'sortObjectKeys', 'navigationBar', 'statusBar', 'languages', 'language', - 'extendEvent' + 'onEvent' ]; Object.keys(options).forEach(function (option) { diff --git a/src/js/Node.js b/src/js/Node.js index 968db58..c2dee6f 100644 --- a/src/js/Node.js +++ b/src/js/Node.js @@ -2370,9 +2370,8 @@ Node.prototype._createDomTree = function () { /** * Handle an event. The event is caught centrally by the editor * @param {Event} event - * @param {extendEvent} function with code for extend event behaviour. */ -Node.prototype.onEvent = function (event, extendEvent) { +Node.prototype.onEvent = function (event) { var type = event.type, target = event.target || event.srcElement, dom = this.dom, @@ -2552,8 +2551,35 @@ Node.prototype.onEvent = function (event, extendEvent) { this.onKeyDown(event); } - // Execute event extension - if (extendEvent) extendEvent(this, event); + if (typeof this.editor.options.onEvent === 'function') { + this._onEvent(event); + } +}; + +/** + * Trigger external onEvent provided in options if node is a JSON field or + * value. + * Information provided depends on the element: + * - If event occurs in a field, {field: string, path: string[]} + * - If event occurs in a value, {field: string, path: string[], value: + * string} + * @param {Event} event + * @private + */ +Node.prototype._onEvent = function (event) { + var element = event.target; + if (this.parent && + (element === this.dom.field || element === this.dom.value)) { + var info = { + field: this.getField(), + path: this.getPath() + }; + // For leaf values, include value + if (!this._hasChilds() &&element === this.dom.value) { + info.value = this.getValue(); + } + this.editor.options.onEvent(info, event); + } }; /** diff --git a/src/js/treemode.js b/src/js/treemode.js index 043d92f..378961c 100644 --- a/src/js/treemode.js +++ b/src/js/treemode.js @@ -35,8 +35,9 @@ var treemode = {}; * characters are escaped. * false by default. * {Object} schema A JSON Schema for validation - * {function} extendEvent Function triggered - * after Node event. + * {function} onEvent Function triggered + * when an event occurs + * in a field or value. * @private */ treemode.create = function (container, options) { @@ -65,9 +66,6 @@ treemode.create = function (container, options) { this.history = new History(this); } - if (options.extendEvent) - this.extendEvent = this.options.extendEvent; - this._createFrame(); this._createTable(); }; @@ -125,7 +123,7 @@ treemode._setOptions = function (options) { autocomplete: null, navigationBar : true, onSelectionChange: null, - extendEvent: null + onEvent: null }; // copy all options @@ -895,7 +893,7 @@ treemode._onEvent = function (event) { } if (node) { - node.onEvent(event, this.options.extendEvent); + node.onEvent(event); } }; From ef74ede75e9fb9e5f943084e2fc94ee67a9c1b23 Mon Sep 17 00:00:00 2001 From: Cristina Date: Thu, 26 Jul 2018 01:48:03 +0200 Subject: [PATCH 3/5] Use extended path with type for onEvent --- docs/api.md | 7 +-- examples/16_extend_event_api.html | 86 ------------------------------- examples/16_on_event_api.html | 66 ++++++++++++++++++------ src/js/Node.js | 33 +++++++++--- 4 files changed, 79 insertions(+), 113 deletions(-) delete mode 100644 examples/16_extend_event_api.html diff --git a/docs/api.md b/docs/api.md index 4d4aefc..f908455 100644 --- a/docs/api.md +++ b/docs/api.md @@ -233,15 +233,16 @@ Constructs a new JSONEditor. a JSON field or value. In case of field event, node information will be - `{field: string, path: string[]}`. + `{field: String, path: [{name: String, type: String}]}`. In case of value event, node information will be - `{field: string, path: string[], value: string}` + `{field: String, path: [{name: String, type: String}], value: String}` signature should be: ```js /** * @param {Node} the Node where event has been triggered - identified by {field: string, path: string[] [, value: string]}` + identified by {field: String, path: [{name: String, type: String}] [, + value: String]}` * @param {event} the event fired */ function onEvent(node, event) { diff --git a/examples/16_extend_event_api.html b/examples/16_extend_event_api.html deleted file mode 100644 index be56a8e..0000000 --- a/examples/16_extend_event_api.html +++ /dev/null @@ -1,86 +0,0 @@ - - - - - - - - - - - - -

- When clicking on a field or leaf, a log message will be shown in console. -

- -
-
-
- - - - diff --git a/examples/16_on_event_api.html b/examples/16_on_event_api.html index f526200..ab99240 100644 --- a/examples/16_on_event_api.html +++ b/examples/16_on_event_api.html @@ -44,37 +44,69 @@ options = { mode: 'tree', modes: ['code', 'form', 'text', 'tree', 'view'], // allowed modes + name: "jsonContent", onError: function (err) { alert(err.toString()); }, onEvent: function(node, event) { if (event.type === 'click') { var message = 'click on <' + node.field + - '> under path <' + node.path + '>'; + '> under path <' + printPath(node.path) + + '> with pretty path: <' + prettyPrintPath(node.path) + '>'; if (node.value) message += ' with value <' + node.value + '>'; console.log(message); } + function prettyPrintPath(path) { + var str = ''; + for (var i=0; i0 && (path[i-1].type === 'array')) { + str += '[' + element.name + ']' + } else { + str += (str.length > 0) ? ','+element.name : element.name; + } + } + return str; + } + function printPath(path) { + var str = ''; + for (var i=0; i Date: Mon, 30 Jul 2018 13:09:27 +0200 Subject: [PATCH 4/5] Use getPath in onEvent --- examples/16_on_event_api.html | 34 +++++++++++++++------------------- src/js/Node.js | 23 +---------------------- 2 files changed, 16 insertions(+), 41 deletions(-) diff --git a/examples/16_on_event_api.html b/examples/16_on_event_api.html index ab99240..25c4f77 100644 --- a/examples/16_on_event_api.html +++ b/examples/16_on_event_api.html @@ -51,7 +51,7 @@ onEvent: function(node, event) { if (event.type === 'click') { var message = 'click on <' + node.field + - '> under path <' + printPath(node.path) + + '> under path <' + node.path + '> with pretty path: <' + prettyPrintPath(node.path) + '>'; if (node.value) message += ' with value <' + node.value + '>'; console.log(message); @@ -60,37 +60,33 @@ var str = ''; for (var i=0; i0 && (path[i-1].type === 'array')) { - str += '[' + element.name + ']' + if (typeof element === 'number') { + str += '[' + element + ']' } else { - str += (str.length > 0) ? ','+element.name : element.name; + if (str.length > 0) str += ','; + str += element; } } return str; } - function printPath(path) { - var str = ''; - for (var i=0; i Date: Fri, 10 Aug 2018 12:29:25 +0200 Subject: [PATCH 5/5] Update documentation --- docs/api.md | 7 +++---- src/js/Node.js | 14 ++++++++------ 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/docs/api.md b/docs/api.md index f908455..b0877a5 100644 --- a/docs/api.md +++ b/docs/api.md @@ -233,16 +233,15 @@ Constructs a new JSONEditor. a JSON field or value. In case of field event, node information will be - `{field: String, path: [{name: String, type: String}]}`. + `{field: string, path: {string|number}[]}`. In case of value event, node information will be - `{field: String, path: [{name: String, type: String}], value: String}` + `{field: string, path: {string|number}[], value: string}` signature should be: ```js /** * @param {Node} the Node where event has been triggered - identified by {field: String, path: [{name: String, type: String}] [, - value: String]}` + identified by {field: string, path: {string|number}[] [, value: string]}` * @param {event} the event fired */ function onEvent(node, event) { diff --git a/src/js/Node.js b/src/js/Node.js index cd8a5da..f4b7019 100644 --- a/src/js/Node.js +++ b/src/js/Node.js @@ -90,7 +90,8 @@ Node.prototype._updateEditability = function () { /** * Get the path of this node - * @return {String[]} Array containing the path to this node + * @return {{string|number}[]} Array containing the path to this node. + * Element is a number if is the index of an array, a string otherwise. */ Node.prototype.getPath = function () { var node = this; @@ -2378,6 +2379,11 @@ Node.prototype.onEvent = function (event) { node = this, expandable = this._hasChilds(); + + if (typeof this.editor.options.onEvent === 'function') { + this._onEvent(event); + } + // check if mouse is on menu or on dragarea. // If so, highlight current row and its childs if (target == dom.drag || target == dom.menu) { @@ -2550,10 +2556,6 @@ Node.prototype.onEvent = function (event) { if (type == 'keydown') { this.onKeyDown(event); } - - if (typeof this.editor.options.onEvent === 'function') { - this._onEvent(event); - } }; /** @@ -2561,7 +2563,7 @@ Node.prototype.onEvent = function (event) { * value. * Information provided depends on the element, value is only included if * event occurs in a JSON value: - * {field: String, path: [{name: String, type: String}] [, value: String]} + * {field: string, path: {string|number}[] [, value: string]} * @param {Event} event * @private */