Released v5.2.0

This commit is contained in:
jos 2016-03-20 18:19:13 +01:00
parent bfad6f5e7b
commit aeca44405e
13 changed files with 1091 additions and 952 deletions

View File

@ -3,7 +3,7 @@
https://github.com/josdejong/jsoneditor https://github.com/josdejong/jsoneditor
## not yet released, version 5.2.0 ## 2016-03-20, version 5.2.0
- Implemented method `editor.destroy()` to properly cleanup the editor (#278). - Implemented method `editor.destroy()` to properly cleanup the editor (#278).
- Fixed #268: JSONEditor now trims text in fields and values. - Fixed #268: JSONEditor now trims text in fields and values.

View File

@ -24,8 +24,8 @@
* Copyright (c) 2011-2016 Jos de Jong, http://jsoneditoronline.org * Copyright (c) 2011-2016 Jos de Jong, http://jsoneditoronline.org
* *
* @author Jos de Jong, <wjosdejong@gmail.com> * @author Jos de Jong, <wjosdejong@gmail.com>
* @version 5.1.5 * @version 5.2.0
* @date 2016-02-15 * @date 2016-03-20
*/ */
(function webpackUniversalModuleDefinition(root, factory) { (function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object') if(typeof exports === 'object' && typeof module === 'object')
@ -215,10 +215,9 @@ return /******/ (function(modules) { // webpackBootstrap
}; };
/** /**
* Detach the editor from the DOM * Destroy the editor. Clean up DOM, event listeners, and web workers.
* @private
*/ */
JSONEditor.prototype._delete = function () {}; JSONEditor.prototype.destroy = function () {};
/** /**
* Set JSON object in editor * Set JSON object in editor
@ -292,7 +291,7 @@ return /******/ (function(modules) { // webpackBootstrap
name = this.getName(); name = this.getName();
data = this[asText ? 'getText' : 'get'](); // get text or json data = this[asText ? 'getText' : 'get'](); // get text or json
this._delete(); this.destroy();
util.clear(this); util.clear(this);
util.extend(this, config.mixin); util.extend(this, config.mixin);
this.create(container, options); this.create(container, options);
@ -465,7 +464,7 @@ return /******/ (function(modules) { // webpackBootstrap
var SearchBox = __webpack_require__(6); var SearchBox = __webpack_require__(6);
var ContextMenu = __webpack_require__(7); var ContextMenu = __webpack_require__(7);
var Node = __webpack_require__(8); var Node = __webpack_require__(8);
var modeswitcher = __webpack_require__(9); var ModeSwitcher = __webpack_require__(9);
var util = __webpack_require__(3); var util = __webpack_require__(3);
// create a mixin with the functions for tree mode // create a mixin with the functions for tree mode
@ -505,6 +504,8 @@ return /******/ (function(modules) { // webpackBootstrap
this.validateSchema = null; // will be set in .setSchema(schema) this.validateSchema = null; // will be set in .setSchema(schema)
this.errorNodes = []; this.errorNodes = [];
this.node = null;
this.focusTarget = null;
this._setOptions(options); this._setOptions(options);
@ -517,12 +518,39 @@ return /******/ (function(modules) { // webpackBootstrap
}; };
/** /**
* Detach the editor from the DOM * Destroy the editor. Clean up DOM, event listeners, and web workers.
* @private
*/ */
treemode._delete = function () { treemode.destroy = function () {
if (this.frame && this.container && this.frame.parentNode == this.container) { if (this.frame && this.container && this.frame.parentNode == this.container) {
this.container.removeChild(this.frame); this.container.removeChild(this.frame);
this.frame = null;
}
this.container = null;
this.dom = null;
this.clear();
this.node = null;
this.focusTarget = null;
this.selection = null;
this.multiselection = null;
this.errorNodes = null;
this.validateSchema = null;
this._debouncedValidate = null;
if (this.history) {
this.history.destroy();
this.history = null;
}
if (this.searchBox) {
this.searchBox.destroy();
this.searchBox = null;
}
if (this.modeSwitcher) {
this.modeSwitcher.destroy();
this.modeSwitcher = null;
} }
}; };
@ -556,12 +584,6 @@ return /******/ (function(modules) { // webpackBootstrap
this._debouncedValidate = util.debounce(this.validate.bind(this), this.DEBOUNCE_INTERVAL); this._debouncedValidate = util.debounce(this.validate.bind(this), this.DEBOUNCE_INTERVAL);
}; };
// node currently being edited
var focusNode = undefined;
// dom having focus
var domFocus = null;
/** /**
* Set JSON object in editor * Set JSON object in editor
* @param {Object | undefined} json JSON data * @param {Object | undefined} json JSON data
@ -618,8 +640,8 @@ return /******/ (function(modules) { // webpackBootstrap
*/ */
treemode.get = function () { treemode.get = function () {
// remove focus from currently edited node // remove focus from currently edited node
if (focusNode) { if (this.focusTarget) {
focusNode.blur(); this.focusTarget.blur();
} }
if (this.node) { if (this.node) {
@ -982,7 +1004,7 @@ return /******/ (function(modules) { // webpackBootstrap
} }
return { return {
dom: domFocus, dom: this.focusTarget,
range: range, range: range,
nodes: this.multiselection.nodes.slice(0), nodes: this.multiselection.nodes.slice(0),
scrollTop: this.content ? this.content.scrollTop : 0 scrollTop: this.content ? this.content.scrollTop : 0
@ -1148,9 +1170,14 @@ return /******/ (function(modules) { // webpackBootstrap
// create mode box // create mode box
if (this.options && this.options.modes && this.options.modes.length) { if (this.options && this.options.modes && this.options.modes.length) {
var modeBox = modeswitcher.create(this, this.options.modes, this.options.mode); var me = this;
this.menu.appendChild(modeBox); this.modeSwitcher = new ModeSwitcher(this.menu, this.options.modes, this.options.mode, function onSwitch(mode) {
this.dom.modeBox = modeBox; me.modeSwitcher.destroy();
// switch mode and restore focus
me.setMode(mode);
me.modeSwitcher.focus();
});
} }
// create search box // create search box
@ -1198,7 +1225,7 @@ return /******/ (function(modules) { // webpackBootstrap
} }
if (event.type == 'focus') { if (event.type == 'focus') {
domFocus = event.target; this.focusTarget = event.target;
} }
if (event.type == 'mousedown') { if (event.type == 'mousedown') {
@ -1471,9 +1498,10 @@ return /******/ (function(modules) { // webpackBootstrap
var handled = false; var handled = false;
if (keynum == 9) { // Tab or Shift+Tab if (keynum == 9) { // Tab or Shift+Tab
var me = this;
setTimeout(function () { setTimeout(function () {
// select all text when moving focus to an editable div // select all text when moving focus to an editable div
util.selectContentEditable(domFocus); util.selectContentEditable(me.focusTarget);
}, 0); }, 0);
} }
@ -1624,7 +1652,7 @@ return /******/ (function(modules) { // webpackBootstrap
// failed to load ace, no problem, we will fall back to plain text // failed to load ace, no problem, we will fall back to plain text
} }
var modeswitcher = __webpack_require__(9); var ModeSwitcher = __webpack_require__(9);
var util = __webpack_require__(3); var util = __webpack_require__(3);
// create a mixin with the functions for text mode // create a mixin with the functions for text mode
@ -1741,9 +1769,13 @@ return /******/ (function(modules) { // webpackBootstrap
// create mode box // create mode box
if (this.options && this.options.modes && this.options.modes.length) { if (this.options && this.options.modes && this.options.modes.length) {
var modeBox = modeswitcher.create(this, this.options.modes, this.options.mode); this.modeSwitcher = new ModeSwitcher(this.menu, this.options.modes, this.options.mode, function onSwitch(mode) {
this.menu.appendChild(modeBox); me.modeSwitcher.destroy();
this.dom.modeBox = modeBox;
// switch mode and restore focus
me.setMode(mode);
me.modeSwitcher.focus();
});
} }
this.content = document.createElement('div'); this.content = document.createElement('div');
@ -1871,18 +1903,27 @@ return /******/ (function(modules) { // webpackBootstrap
}; };
/** /**
* Detach the editor from the DOM * Destroy the editor. Clean up DOM, event listeners, and web workers.
* @private
*/ */
textmode._delete = function () { textmode.destroy = function () {
// remove old ace editor // remove old ace editor
if (this.aceEditor) { if (this.aceEditor) {
this.aceEditor.destroy(); this.aceEditor.destroy();
this.aceEditor = null;
} }
if (this.frame && this.container && this.frame.parentNode == this.container) { if (this.frame && this.container && this.frame.parentNode == this.container) {
this.container.removeChild(this.frame); this.container.removeChild(this.frame);
} }
if (this.modeSwitcher) {
this.modeSwitcher.destroy();
this.modeSwitcher = null;
}
this.textarea = null;
this._debouncedValidate = null;
}; };
/** /**
@ -2966,6 +3007,9 @@ return /******/ (function(modules) { // webpackBootstrap
*/ */
function History (editor) { function History (editor) {
this.editor = editor; this.editor = editor;
this.history = [];
this.index = -1;
this.clear(); this.clear();
// map with all supported actions // map with all supported actions
@ -3208,6 +3252,16 @@ return /******/ (function(modules) { // webpackBootstrap
} }
}; };
/**
* Destroy history
*/
History.prototype.destroy = function () {
this.editor = null;
this.history = [];
this.index = -1;
};
module.exports = History; module.exports = History;
@ -3509,6 +3563,21 @@ return /******/ (function(modules) { // webpackBootstrap
this._onSearch(); this._onSearch();
}; };
/**
* Destroy the search box
*/
SearchBox.prototype.destroy = function () {
this.editor = null;
this.dom.container.removeChild(this.dom.table);
this.dom = null;
this.results = null;
this.activeResult = null;
this._clearDelay();
};
module.exports = SearchBox; module.exports = SearchBox;
@ -6052,7 +6121,6 @@ return /******/ (function(modules) { // webpackBootstrap
target = event.target || event.srcElement, target = event.target || event.srcElement,
dom = this.dom, dom = this.dom,
node = this, node = this,
focusNode,
expandable = this._hasChilds(); expandable = this._hasChilds();
// check if mouse is on menu or on dragarea. // check if mouse is on menu or on dragarea.
@ -6101,10 +6169,6 @@ return /******/ (function(modules) { // webpackBootstrap
if (target == domValue) { if (target == domValue) {
//noinspection FallthroughInSwitchStatementJS //noinspection FallthroughInSwitchStatementJS
switch (type) { switch (type) {
case 'focus':
focusNode = this;
break;
case 'blur': case 'blur':
case 'change': case 'change':
this._getDomValue(true); this._getDomValue(true);
@ -6154,10 +6218,6 @@ return /******/ (function(modules) { // webpackBootstrap
var domField = dom.field; var domField = dom.field;
if (target == domField) { if (target == domField) {
switch (type) { switch (type) {
case 'focus':
focusNode = this;
break;
case 'blur': case 'blur':
case 'change': case 'change':
this._getDomField(true); this._getDomField(true);
@ -7323,7 +7383,7 @@ return /******/ (function(modules) { // webpackBootstrap
* @private * @private
*/ */
Node.prototype._unescapeHTML = function (escapedText) { Node.prototype._unescapeHTML = function (escapedText) {
var json = '"' + this._escapeJSON(escapedText) + '"'; var json = '"' + this._escapeJSON(escapedText.trim()) + '"';
var htmlEscaped = util.parse(json); var htmlEscaped = util.parse(json);
return htmlEscaped return htmlEscaped
@ -7387,64 +7447,48 @@ return /******/ (function(modules) { // webpackBootstrap
/** /**
* Create a select box to be used in the editor menu's, which allows to switch mode * Create a select box to be used in the editor menu's, which allows to switch mode
* @param {Object} editor * @param {HTMLElement} container
* @param {String[]} modes Available modes: 'code', 'form', 'text', 'tree', 'view' * @param {String[]} modes Available modes: 'code', 'form', 'text', 'tree', 'view'
* @param {String} current Available modes: 'code', 'form', 'text', 'tree', 'view' * @param {String} current Available modes: 'code', 'form', 'text', 'tree', 'view'
* @returns {HTMLElement} box * @param {function(mode: string)} onSwitch Callback invoked on switch
* @constructor
*/ */
function createModeSwitcher(editor, modes, current) { function ModeSwitcher(container, modes, current, onSwitch) {
// TODO: decouple mode switcher from editor
/**
* Switch the mode of the editor
* @param {String} mode
*/
function switchMode(mode) {
// switch mode
editor.setMode(mode);
// restore focus on mode box
var modeBox = editor.dom && editor.dom.modeBox;
if (modeBox) {
modeBox.focus();
}
}
// available modes // available modes
var availableModes = { var availableModes = {
code: { code: {
'text': 'Code', 'text': 'Code',
'title': 'Switch to code highlighter', 'title': 'Switch to code highlighter',
'click': function () { 'click': function () {
switchMode('code') onSwitch('code')
} }
}, },
form: { form: {
'text': 'Form', 'text': 'Form',
'title': 'Switch to form editor', 'title': 'Switch to form editor',
'click': function () { 'click': function () {
switchMode('form'); onSwitch('form');
} }
}, },
text: { text: {
'text': 'Text', 'text': 'Text',
'title': 'Switch to plain text editor', 'title': 'Switch to plain text editor',
'click': function () { 'click': function () {
switchMode('text'); onSwitch('text');
} }
}, },
tree: { tree: {
'text': 'Tree', 'text': 'Tree',
'title': 'Switch to tree editor', 'title': 'Switch to tree editor',
'click': function () { 'click': function () {
switchMode('tree'); onSwitch('tree');
} }
}, },
view: { view: {
'text': 'View', 'text': 'View',
'title': 'Switch to tree view', 'title': 'Switch to tree view',
'click': function () { 'click': function () {
switchMode('view'); onSwitch('view');
} }
} }
}; };
@ -7479,15 +7523,38 @@ return /******/ (function(modules) { // webpackBootstrap
menu.show(box); menu.show(box);
}; };
var div = document.createElement('div'); var frame = document.createElement('div');
div.className = 'jsoneditor-modes'; frame.className = 'jsoneditor-modes';
div.style.position = 'relative'; frame.style.position = 'relative';
div.appendChild(box); frame.appendChild(box);
return div; container.appendChild(frame);
this.dom = {
container: container,
box: box,
frame: frame
};
} }
exports.create = createModeSwitcher; /**
* Set focus to switcher
*/
ModeSwitcher.prototype.focus = function () {
this.dom.box.focus();
};
/**
* Destroy the ModeSwitcher, remove from DOM
*/
ModeSwitcher.prototype.destroy = function () {
if (this.dom && this.dom.frame && this.dom.frame.parentNode) {
this.dom.frame.parentNode.removeChild(this.dom.frame);
}
this.dom = null;
};
module.exports = ModeSwitcher;
/***/ }, /***/ },

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

30
dist/jsoneditor.css vendored
View File

@ -47,11 +47,18 @@ div.jsoneditor-value.jsoneditor-empty::after {
content: "value"; content: "value";
} }
div.jsoneditor-value.jsoneditor-url { div.jsoneditor-value.jsoneditor-url,
a.jsoneditor-value.jsoneditor-url {
color: green; color: green;
text-decoration: underline; text-decoration: underline;
} }
a.jsoneditor-value.jsoneditor-url {
display: inline-block;
padding: 2px;
margin: 2px;
}
a.jsoneditor-value.jsoneditor-url:hover, a.jsoneditor-value.jsoneditor-url:hover,
a.jsoneditor-value.jsoneditor-url:focus { a.jsoneditor-value.jsoneditor-url:focus {
color: #ee422e; color: #ee422e;
@ -483,6 +490,9 @@ div.jsoneditor-contextmenu ul li button {
cursor: pointer; cursor: pointer;
color: #4d4d4d; color: #4d4d4d;
background: transparent; background: transparent;
font-size: 10pt;
font-family: arial, sans-serif;
box-sizing: border-box;
line-height: 26px; line-height: 26px;
text-align: left; text-align: left;
} }
@ -809,10 +819,18 @@ table.jsoneditor-search div.jsoneditor-results {
/* For Firefox */ /* For Firefox */
} }
table.jsoneditor-search div.jsoneditor-results {
color: white;
padding-right: 5px;
line-height: 24px;
}
table.jsoneditor-search { table.jsoneditor-search {
position: absolute; position: absolute;
right: 2px; right: 4px;
top: 2px; top: 4px;
border-collapse: collapse;
border-spacing: 0;
} }
table.jsoneditor-search div.jsoneditor-frame { table.jsoneditor-search div.jsoneditor-frame {
@ -834,12 +852,6 @@ table.jsoneditor-search input {
line-height: 20px; line-height: 20px;
} }
table.jsoneditor-search .jsoneditor-results {
color: #4d4d4d;
padding-right: 5px;
line-height: 24px;
}
table.jsoneditor-search button { table.jsoneditor-search button {
width: 16px; width: 16px;
height: 24px; height: 24px;

1715
dist/jsoneditor.js vendored

File diff suppressed because it is too large Load Diff

2
dist/jsoneditor.map vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -6,7 +6,7 @@
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css"> <link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">
<script src="../dist/jsoneditor.js"></script> <script src="../dist/jsoneditor.js"></script>
<script src="http://bgrins.github.io/filereader.js"></script> <script src="https://bgrins.github.io/filereader.js/filereader.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2014-11-29/FileSaver.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2014-11-29/FileSaver.min.js"></script>
<style> <style>

View File

@ -1,6 +1,6 @@
{ {
"name": "jsoneditor", "name": "jsoneditor",
"version": "5.1.5", "version": "5.2.0",
"main": "./index", "main": "./index",
"description": "A web-based tool to view, edit, format, and validate JSON", "description": "A web-based tool to view, edit, format, and validate JSON",
"tags": [ "tags": [

View File

@ -2121,10 +2121,6 @@ Node.prototype.onEvent = function (event) {
if (target == domValue) { if (target == domValue) {
//noinspection FallthroughInSwitchStatementJS //noinspection FallthroughInSwitchStatementJS
switch (type) { switch (type) {
case 'focus':
this.editor.focusNode = this;
break;
case 'blur': case 'blur':
case 'change': case 'change':
this._getDomValue(true); this._getDomValue(true);
@ -2174,10 +2170,6 @@ Node.prototype.onEvent = function (event) {
var domField = dom.field; var domField = dom.field;
if (target == domField) { if (target == domField) {
switch (type) { switch (type) {
case 'focus':
this.editor.focusNode = this;
break;
case 'blur': case 'blur':
case 'change': case 'change':
this._getDomField(true); this._getDomField(true);

View File

@ -44,7 +44,7 @@ treemode.create = function (container, options) {
this.errorNodes = []; this.errorNodes = [];
this.node = null; this.node = null;
this.focusNode = null; this.focusTarget = null;
this._setOptions(options); this._setOptions(options);
@ -70,7 +70,7 @@ treemode.destroy = function () {
this.clear(); this.clear();
this.node = null; this.node = null;
this.focusNode = null; this.focusTarget = null;
this.selection = null; this.selection = null;
this.multiselection = null; this.multiselection = null;
this.errorNodes = null; this.errorNodes = null;
@ -179,8 +179,8 @@ treemode.set = function (json, name) {
*/ */
treemode.get = function () { treemode.get = function () {
// remove focus from currently edited node // remove focus from currently edited node
if (this.focusNode) { if (this.focusTarget) {
this.focusNode.blur(); this.focusTarget.blur();
} }
if (this.node) { if (this.node) {
@ -543,7 +543,7 @@ treemode.getSelection = function () {
} }
return { return {
dom: this.dom.focus, dom: this.focusTarget,
range: range, range: range,
nodes: this.multiselection.nodes.slice(0), nodes: this.multiselection.nodes.slice(0),
scrollTop: this.content ? this.content.scrollTop : 0 scrollTop: this.content ? this.content.scrollTop : 0
@ -764,7 +764,7 @@ treemode._onEvent = function (event) {
} }
if (event.type == 'focus') { if (event.type == 'focus') {
this.dom.focus = event.target; this.focusTarget = event.target;
} }
if (event.type == 'mousedown') { if (event.type == 'mousedown') {
@ -1037,9 +1037,10 @@ treemode._onKeyDown = function (event) {
var handled = false; var handled = false;
if (keynum == 9) { // Tab or Shift+Tab if (keynum == 9) { // Tab or Shift+Tab
var me = this;
setTimeout(function () { setTimeout(function () {
// select all text when moving focus to an editable div // select all text when moving focus to an editable div
util.selectContentEditable(this.dom.focus); util.selectContentEditable(me.focusTarget);
}, 0); }, 0);
} }