Unified JSONEditor and JSONFormatter. Added method setMode. Renamed a lot of stuff.
This commit is contained in:
parent
6679c88075
commit
501099056b
|
@ -147,7 +147,7 @@ span.header-light {
|
|||
overflow: hidden;
|
||||
}
|
||||
|
||||
#jsonformatter, #jsoneditor {
|
||||
#codeEditor, #treeEditor {
|
||||
height: 100%;
|
||||
width: 400px;
|
||||
|
||||
|
@ -156,12 +156,12 @@ span.header-light {
|
|||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
#jsonformatter {
|
||||
#codeEditor {
|
||||
float: left;
|
||||
padding: 15px 0 15px 15px;
|
||||
}
|
||||
|
||||
#jsoneditor {
|
||||
#treeEditor {
|
||||
float: left;
|
||||
padding: 15px 15px 15px 0;
|
||||
}
|
||||
|
|
121
app/web/app.js
121
app/web/app.js
|
@ -26,21 +26,21 @@
|
|||
* Copyright (C) 2011-2013 Jos de Jong, http://jsoneditoronline.org
|
||||
*
|
||||
* @author Jos de Jong, <wjosdejong@gmail.com>
|
||||
* @date 2013-03-08
|
||||
* @date 2013-04-30
|
||||
*/
|
||||
|
||||
|
||||
var editor = null;
|
||||
var formatter = null;
|
||||
var treeEditor = null;
|
||||
var codeEditor = null;
|
||||
|
||||
var app = {};
|
||||
|
||||
/**
|
||||
* Get the JSON from the code editor and load it in the tree editor
|
||||
*/
|
||||
app.CodeToEditor = function() {
|
||||
app.CodeToTree = function() {
|
||||
try {
|
||||
editor.set(formatter.get());
|
||||
treeEditor.set(codeEditor.get());
|
||||
}
|
||||
catch (err) {
|
||||
app.notify.showError(err);
|
||||
|
@ -50,9 +50,9 @@ app.CodeToEditor = function() {
|
|||
/**
|
||||
* Get the JSON from the tree editor and load it into the code editor
|
||||
*/
|
||||
app.editorToCode = function () {
|
||||
app.treeToCode = function () {
|
||||
try {
|
||||
formatter.set(editor.get());
|
||||
codeEditor.set(treeEditor.get());
|
||||
}
|
||||
catch (err) {
|
||||
app.notify.showError(err);
|
||||
|
@ -60,7 +60,7 @@ app.editorToCode = function () {
|
|||
};
|
||||
|
||||
/**
|
||||
* Load the interface (editor, formatter, splitter)
|
||||
* Load the interface (tree editor, code editor, splitter)
|
||||
*/
|
||||
// TODO: split the method load in multiple methods, it is too large
|
||||
app.load = function() {
|
||||
|
@ -94,31 +94,32 @@ app.load = function() {
|
|||
}
|
||||
}
|
||||
|
||||
// Store whether editor or formatter is last changed
|
||||
// Store whether tree editor or code editor is last changed
|
||||
app.lastChanged = undefined;
|
||||
|
||||
// formatter
|
||||
var container = document.getElementById("jsonformatter");
|
||||
formatter = new jsoneditor.JSONFormatter(container, {
|
||||
// code editor
|
||||
var container = document.getElementById("codeEditor");
|
||||
codeEditor = new jsoneditor.JSONEditor(container, {
|
||||
mode: 'code',
|
||||
change: function () {
|
||||
app.lastChanged = formatter;
|
||||
app.lastChanged = codeEditor;
|
||||
}
|
||||
});
|
||||
formatter.set(json);
|
||||
formatter.onError = function (err) {
|
||||
codeEditor.set(json);
|
||||
codeEditor.onError = function (err) {
|
||||
app.notify.showError(err);
|
||||
};
|
||||
|
||||
// editor
|
||||
container = document.getElementById("jsoneditor");
|
||||
editor = new jsoneditor.JSONEditor(container, {
|
||||
// tree editor
|
||||
container = document.getElementById("treeEditor");
|
||||
treeEditor = new jsoneditor.JSONEditor(container, {
|
||||
mode: 'tree',
|
||||
change: function () {
|
||||
app.lastChanged = editor;
|
||||
app.lastChanged = treeEditor;
|
||||
}
|
||||
});
|
||||
editor.set(json);
|
||||
// TODO: automatically synchronize data of formatter and editor? (editor should keep its state though)
|
||||
treeEditor.set(json);
|
||||
// TODO: automatically synchronize data of code and tree editor? (tree editor should keep its state though)
|
||||
|
||||
// splitter
|
||||
app.splitter = new Splitter({
|
||||
|
@ -128,18 +129,18 @@ app.load = function() {
|
|||
}
|
||||
});
|
||||
|
||||
// button Code-to-Editor
|
||||
var toEditor = document.getElementById('toEditor');
|
||||
toEditor.onclick = function () {
|
||||
// button Code-to-Tree
|
||||
var toTree = document.getElementById('toTree');
|
||||
toTree.onclick = function () {
|
||||
this.focus();
|
||||
app.CodeToEditor();
|
||||
app.CodeToTree();
|
||||
};
|
||||
|
||||
// button Editor-to-Dode
|
||||
// button Tree-to-Code
|
||||
var toCode = document.getElementById('toCode');
|
||||
toCode.onclick = function () {
|
||||
this.focus();
|
||||
app.editorToCode();
|
||||
app.treeToCode();
|
||||
};
|
||||
|
||||
// web page resize handler
|
||||
|
@ -186,8 +187,8 @@ app.load = function() {
|
|||
var domSave = document.getElementById('save');
|
||||
domSave.onclick = app.saveFile;
|
||||
|
||||
// set focus on the formatter
|
||||
formatter.focus();
|
||||
// set focus on the code editor
|
||||
codeEditor.focus();
|
||||
|
||||
// enforce FireFox to not do spell checking on any input field
|
||||
document.body.spellcheck = false;
|
||||
|
@ -203,14 +204,14 @@ app.load = function() {
|
|||
*/
|
||||
app.openCallback = function (err, data) {
|
||||
if (!err) {
|
||||
if (data != undefined) {
|
||||
formatter.setText(data);
|
||||
if (data != null) {
|
||||
codeEditor.setText(data);
|
||||
try {
|
||||
var json = jsoneditor.util.parse(data);
|
||||
editor.set(json);
|
||||
treeEditor.set(json);
|
||||
}
|
||||
catch (err) {
|
||||
editor.set({});
|
||||
treeEditor.set({});
|
||||
app.notify.showError(err);
|
||||
}
|
||||
}
|
||||
|
@ -245,20 +246,20 @@ app.openUrl = function (url) {
|
|||
* Open a file explorer to save the file.
|
||||
*/
|
||||
app.saveFile = function () {
|
||||
// first synchronize the editors and formatters contents
|
||||
if (app.lastChanged == editor) {
|
||||
app.editorToCode();
|
||||
// first synchronize both editors contents
|
||||
if (app.lastChanged == treeEditor) {
|
||||
app.treeToCode();
|
||||
}
|
||||
/* TODO: also sync from formatter to editor? will clear the history ...
|
||||
if (app.lastChanged == formatter) {
|
||||
/* TODO: also sync from code to tree editor? will clear the history ...
|
||||
if (app.lastChanged == codeEditor) {
|
||||
app.CodeToEditor();
|
||||
}
|
||||
*/
|
||||
app.lastChanged = undefined;
|
||||
|
||||
// save the text from the formatter
|
||||
// save the text from the code editor
|
||||
// TODO: show a 'saving...' notification
|
||||
var data = formatter.getText();
|
||||
var data = codeEditor.getText();
|
||||
app.retriever.saveFile(data, function (err) {
|
||||
if (err) {
|
||||
app.notify.showError(err);
|
||||
|
@ -271,14 +272,14 @@ app.saveFile = function () {
|
|||
*/
|
||||
app.clearFile = function () {
|
||||
var json = {};
|
||||
formatter.set(json);
|
||||
editor.set(json);
|
||||
codeEditor.set(json);
|
||||
treeEditor.set(json);
|
||||
};
|
||||
|
||||
app.resize = function() {
|
||||
var domMenu = document.getElementById('menu');
|
||||
var domEditor = document.getElementById('jsoneditor');
|
||||
var domFormatter = document.getElementById('jsonformatter');
|
||||
var domTreeEditor = document.getElementById('treeEditor');
|
||||
var domCodeEditor = document.getElementById('codeEditor');
|
||||
var domSplitter = document.getElementById('splitter');
|
||||
var domSplitterButtons = document.getElementById('buttons');
|
||||
var domSplitterDrag = document.getElementById('drag');
|
||||
|
@ -297,27 +298,27 @@ app.resize = function() {
|
|||
|
||||
// calculate horizontal splitter position
|
||||
var value = app.splitter.getValue();
|
||||
var showFormatter = (value > 0);
|
||||
var showEditor = (value < 1);
|
||||
var showButtons = showFormatter && showEditor;
|
||||
var showCodeEditor = (value > 0);
|
||||
var showTreeEditor = (value < 1);
|
||||
var showButtons = showCodeEditor && showTreeEditor;
|
||||
domSplitterButtons.style.display = showButtons ? '' : 'none';
|
||||
|
||||
var splitterWidth = domSplitter.clientWidth;
|
||||
var splitterLeft;
|
||||
if (!showFormatter) {
|
||||
// formatter not visible
|
||||
if (!showCodeEditor) {
|
||||
// code editor not visible
|
||||
splitterLeft = 0;
|
||||
domSplitterDrag.innerHTML = '›';
|
||||
domSplitterDrag.title = 'Drag right to show the code editor';
|
||||
}
|
||||
else if (!showEditor) {
|
||||
// editor not visible
|
||||
else if (!showTreeEditor) {
|
||||
// tree editor not visible
|
||||
splitterLeft = width * value - splitterWidth;
|
||||
domSplitterDrag.innerHTML = '‹';
|
||||
domSplitterDrag.title = 'Drag left to show the tree editor';
|
||||
}
|
||||
else {
|
||||
// both editor and formatter visible
|
||||
// both tree and code editor visible
|
||||
splitterLeft = width * value - splitterWidth / 2;
|
||||
|
||||
// TODO: find a character with vertical dots that works on IE8 too, or use an image
|
||||
|
@ -326,10 +327,10 @@ app.resize = function() {
|
|||
domSplitterDrag.title = 'Drag left or right to change the width of the panels';
|
||||
}
|
||||
|
||||
// resize formatter
|
||||
domFormatter.style.display = (value == 0) ? 'none' : '';
|
||||
domFormatter.style.width = Math.max(Math.round(splitterLeft), 0) + 'px';
|
||||
formatter.resize();
|
||||
// resize code editor
|
||||
domCodeEditor.style.display = (value == 0) ? 'none' : '';
|
||||
domCodeEditor.style.width = Math.max(Math.round(splitterLeft), 0) + 'px';
|
||||
codeEditor.resize();
|
||||
|
||||
// resize the splitter
|
||||
domSplitterDrag.style.height = (domSplitter.clientHeight -
|
||||
|
@ -337,12 +338,12 @@ app.resize = function() {
|
|||
(showButtons ? margin : 0)) + 'px';
|
||||
domSplitterDrag.style.lineHeight = domSplitterDrag.style.height;
|
||||
|
||||
// resize editor
|
||||
// resize tree editor
|
||||
// the width has a -1 to prevent the width from being just half a pixel
|
||||
// wider than the window, causing the content elements to wrap...
|
||||
domEditor.style.display = (value == 1) ? 'none' : '';
|
||||
domEditor.style.left = Math.round(splitterLeft + splitterWidth) + 'px';
|
||||
domEditor.style.width = Math.max(Math.round(width - splitterLeft - splitterWidth - 2), 0) + 'px';
|
||||
domTreeEditor.style.display = (value == 1) ? 'none' : '';
|
||||
domTreeEditor.style.left = Math.round(splitterLeft + splitterWidth) + 'px';
|
||||
domTreeEditor.style.width = Math.max(Math.round(width - splitterLeft - splitterWidth - 2), 0) + 'px';
|
||||
}
|
||||
|
||||
// align main menu with ads
|
||||
|
|
|
@ -123,17 +123,17 @@
|
|||
|
||||
<div id="auto">
|
||||
<div id="contents">
|
||||
<div id="jsonformatter"></div>
|
||||
<div id="codeEditor"></div>
|
||||
|
||||
<div id="splitter">
|
||||
<div id="buttons">
|
||||
<div>
|
||||
<button id="toEditor" class="convert" title="Code to editor">
|
||||
<button id="toTree" class="convert" title="Copy code to tree editor">
|
||||
<div class="convert-right"></div>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button id="toCode" class="convert" title="Editor to code">
|
||||
<button id="toCode" class="convert" title="Copy tree to code editor">
|
||||
<div class="convert-left"></div>
|
||||
</button>
|
||||
</div>
|
||||
|
@ -142,7 +142,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div id="jsoneditor"></div>
|
||||
<div id="treeEditor"></div>
|
||||
|
||||
<script type="text/javascript">
|
||||
app.load();
|
||||
|
|
|
@ -56,7 +56,8 @@
|
|||
-->
|
||||
|
||||
<script type="text/javascript" src="../../jsoneditor/js/jsoneditor.js"></script>
|
||||
<script type="text/javascript" src="../../jsoneditor/js/jsonformatter.js"></script>
|
||||
<script type="text/javascript" src="../../jsoneditor/js/treeeditor.js"></script>
|
||||
<script type="text/javascript" src="../../jsoneditor/js/texteditor.js"></script>
|
||||
<script type="text/javascript" src="../../jsoneditor/js/node.js"></script>
|
||||
<script type="text/javascript" src="../../jsoneditor/js/appendnode.js"></script>
|
||||
<script type="text/javascript" src="../../jsoneditor/js/contextmenu.js"></script>
|
||||
|
@ -64,6 +65,7 @@
|
|||
<script type="text/javascript" src="../../jsoneditor/js/searchbox.js"></script>
|
||||
<script type="text/javascript" src="../../jsoneditor/js/highlighter.js"></script>
|
||||
<script type="text/javascript" src="../../jsoneditor/js/util.js"></script>
|
||||
<script type="text/javascript" src="../../jsoneditor/js/module.js"></script>
|
||||
<script type="text/javascript" src="queryparams.js"></script>
|
||||
<script type="text/javascript" src="ajax.js"></script>
|
||||
<script type="text/javascript" src="fileretriever.js"></script>
|
||||
|
@ -153,17 +155,17 @@
|
|||
|
||||
<div id="auto">
|
||||
<div id="contents">
|
||||
<div id="jsonformatter"></div>
|
||||
<div id="codeEditor"></div>
|
||||
|
||||
<div id="splitter">
|
||||
<div id="buttons">
|
||||
<div>
|
||||
<button id="toEditor" class="convert" title="JSON to Editor">
|
||||
<button id="toTree" class="convert" title="Copy code to tree editor">
|
||||
<div class="convert-right"></div>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button id="toCode" class="convert" title="Editor to JSON">
|
||||
<button id="toCode" class="convert" title="Copy tree to code editor">
|
||||
<div class="convert-left"></div>
|
||||
</button>
|
||||
</div>
|
||||
|
@ -172,7 +174,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div id="jsoneditor"></div>
|
||||
<div id="treeEditor"></div>
|
||||
|
||||
<script type="text/javascript">
|
||||
app.load();
|
||||
|
|
|
@ -61,7 +61,8 @@
|
|||
<!-- concatenate the javascript files -->
|
||||
<concat destfile="${jsoneditor}/tmp.js">
|
||||
<fileset dir="${js_src}" includes="jsoneditor.js"/>
|
||||
<fileset dir="${js_src}" includes="jsonformatter.js"/>
|
||||
<fileset dir="${js_src}" includes="treeeditor.js"/>
|
||||
<fileset dir="${js_src}" includes="texteditor.js"/>
|
||||
<fileset dir="${js_src}" includes="node.js"/>
|
||||
<fileset dir="${js_src}" includes="appendnode.js"/>
|
||||
<fileset dir="${js_src}" includes="contextmenu.js"/>
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
|
||||
http://jsoneditoronline.org
|
||||
|
||||
## not yet released, version 2.2.0
|
||||
|
||||
- Unified JSONFormatter and JSONEditor in one editor with a switchable mode.
|
||||
|
||||
|
||||
## 2013-03-11, version 2.1.1
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
// create the editor
|
||||
var container = document.getElementById("jsoneditor");
|
||||
var options = {
|
||||
mode: "viewer"
|
||||
mode: "view"
|
||||
};
|
||||
var json = {
|
||||
"array": [1, 2, 3],
|
||||
|
|
|
@ -1,45 +1,23 @@
|
|||
/**
|
||||
* @license
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy
|
||||
* of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*
|
||||
* Copyright (c) 2011-2013 Jos de Jong, http://jsoneditoronline.org
|
||||
*
|
||||
* @author Jos de Jong, <wjosdejong@gmail.com>
|
||||
*/
|
||||
|
||||
// create namespace
|
||||
var jsoneditor = jsoneditor || {};
|
||||
|
||||
/**
|
||||
* @constructor jsoneditor.AppendNode
|
||||
* @extends jsoneditor.Node
|
||||
* @param {jsoneditor.JSONEditor} editor
|
||||
* @constructor AppendNode
|
||||
* @extends Node
|
||||
* @param {TreeEditor} editor
|
||||
* Create a new AppendNode. This is a special node which is created at the
|
||||
* end of the list with childs for an object or array
|
||||
*/
|
||||
jsoneditor.AppendNode = function (editor) {
|
||||
function AppendNode (editor) {
|
||||
/** @type {TreeEditor} */
|
||||
this.editor = editor;
|
||||
this.dom = {};
|
||||
};
|
||||
}
|
||||
|
||||
jsoneditor.AppendNode.prototype = new jsoneditor.Node();
|
||||
AppendNode.prototype = new Node();
|
||||
|
||||
/**
|
||||
* Return a table row with an append button.
|
||||
* @return {Element} dom TR element
|
||||
*/
|
||||
jsoneditor.AppendNode.prototype.getDom = function () {
|
||||
// TODO: do not create the DOM for the appendNode when in viewer mode
|
||||
AppendNode.prototype.getDom = function () {
|
||||
// TODO: implement a new solution for the append node
|
||||
var dom = this.dom;
|
||||
|
||||
|
@ -52,26 +30,21 @@ jsoneditor.AppendNode.prototype.getDom = function () {
|
|||
trAppend.node = this;
|
||||
dom.tr = trAppend;
|
||||
|
||||
// when in viewer mode, don't create the contents for the append node
|
||||
// but return here.
|
||||
if (!this.editor.mode.editor) {
|
||||
return trAppend;
|
||||
}
|
||||
|
||||
// TODO: consistent naming
|
||||
|
||||
// a cell for the dragarea column
|
||||
var tdDrag = document.createElement('td');
|
||||
dom.tdDrag = tdDrag;
|
||||
if (this.editor.mode.edit) {
|
||||
// a cell for the dragarea column
|
||||
dom.tdDrag = document.createElement('td');
|
||||
|
||||
// create context menu
|
||||
var tdMenu = document.createElement('td');
|
||||
var menu = document.createElement('button');
|
||||
menu.className = 'contextmenu';
|
||||
menu.title = 'Click to open the actions menu (Ctrl+M)';
|
||||
dom.menu = menu;
|
||||
dom.tdMenu = tdMenu;
|
||||
tdMenu.appendChild(dom.menu);
|
||||
// create context menu
|
||||
var tdMenu = document.createElement('td');
|
||||
dom.tdMenu = tdMenu;
|
||||
var menu = document.createElement('button');
|
||||
menu.className = 'contextmenu';
|
||||
menu.title = 'Click to open the actions menu (Ctrl+M)';
|
||||
dom.menu = menu;
|
||||
tdMenu.appendChild(dom.menu);
|
||||
}
|
||||
|
||||
// a cell for the contents (showing text 'empty')
|
||||
var tdAppend = document.createElement('td');
|
||||
|
@ -90,7 +63,7 @@ jsoneditor.AppendNode.prototype.getDom = function () {
|
|||
/**
|
||||
* Update the HTML dom of the Node
|
||||
*/
|
||||
jsoneditor.AppendNode.prototype.updateDom = function () {
|
||||
AppendNode.prototype.updateDom = function () {
|
||||
var dom = this.dom;
|
||||
var tdAppend = dom.td;
|
||||
if (tdAppend) {
|
||||
|
@ -108,15 +81,23 @@ jsoneditor.AppendNode.prototype.updateDom = function () {
|
|||
var trAppend = dom.tr;
|
||||
if (!this.isVisible()) {
|
||||
if (dom.tr.firstChild) {
|
||||
trAppend.removeChild(dom.tdDrag);
|
||||
trAppend.removeChild(dom.tdMenu);
|
||||
if (dom.tdDrag) {
|
||||
trAppend.removeChild(dom.tdDrag);
|
||||
}
|
||||
if (dom.tdMenu) {
|
||||
trAppend.removeChild(dom.tdMenu);
|
||||
}
|
||||
trAppend.removeChild(tdAppend);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!dom.tr.firstChild) {
|
||||
trAppend.appendChild(dom.tdDrag);
|
||||
trAppend.appendChild(dom.tdMenu);
|
||||
if (dom.tdDrag) {
|
||||
trAppend.appendChild(dom.tdDrag);
|
||||
}
|
||||
if (dom.tdMenu) {
|
||||
trAppend.appendChild(dom.tdMenu);
|
||||
}
|
||||
trAppend.appendChild(tdAppend);
|
||||
}
|
||||
}
|
||||
|
@ -127,7 +108,7 @@ jsoneditor.AppendNode.prototype.updateDom = function () {
|
|||
* the AppendNode is visible when its parent has no childs (i.e. is empty).
|
||||
* @return {boolean} isVisible
|
||||
*/
|
||||
jsoneditor.AppendNode.prototype.isVisible = function () {
|
||||
AppendNode.prototype.isVisible = function () {
|
||||
return (this.parent.childs.length == 0);
|
||||
};
|
||||
|
||||
|
@ -137,9 +118,9 @@ jsoneditor.AppendNode.prototype.isVisible = function () {
|
|||
* @param {function} [onClose] Callback method called when the context menu
|
||||
* is being closed.
|
||||
*/
|
||||
jsoneditor.AppendNode.prototype.showContextMenu = function (anchor, onClose) {
|
||||
AppendNode.prototype.showContextMenu = function (anchor, onClose) {
|
||||
var node = this;
|
||||
var titles = jsoneditor.Node.TYPE_TITLES;
|
||||
var titles = Node.TYPE_TITLES;
|
||||
var items = [
|
||||
// create append button
|
||||
{
|
||||
|
@ -187,7 +168,7 @@ jsoneditor.AppendNode.prototype.showContextMenu = function (anchor, onClose) {
|
|||
}
|
||||
];
|
||||
|
||||
var menu = new jsoneditor.ContextMenu(items, {close: onClose});
|
||||
var menu = new ContextMenu(items, {close: onClose});
|
||||
menu.show(anchor);
|
||||
};
|
||||
|
||||
|
@ -195,7 +176,7 @@ jsoneditor.AppendNode.prototype.showContextMenu = function (anchor, onClose) {
|
|||
* Handle an event. The event is catched centrally by the editor
|
||||
* @param {Event} event
|
||||
*/
|
||||
jsoneditor.AppendNode.prototype.onEvent = function (event) {
|
||||
AppendNode.prototype.onEvent = function (event) {
|
||||
var type = event.type;
|
||||
var target = event.target || event.srcElement;
|
||||
var dom = this.dom;
|
||||
|
@ -216,9 +197,9 @@ jsoneditor.AppendNode.prototype.onEvent = function (event) {
|
|||
var highlighter = this.editor.highlighter;
|
||||
highlighter.highlight(this.parent);
|
||||
highlighter.lock();
|
||||
jsoneditor.util.addClassName(dom.menu, 'selected');
|
||||
util.addClassName(dom.menu, 'selected');
|
||||
this.showContextMenu(dom.menu, function () {
|
||||
jsoneditor.util.removeClassName(dom.menu, 'selected');
|
||||
util.removeClassName(dom.menu, 'selected');
|
||||
highlighter.unlock();
|
||||
highlighter.unhighlight();
|
||||
});
|
||||
|
|
|
@ -1,25 +1,3 @@
|
|||
/**
|
||||
* @license
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy
|
||||
* of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*
|
||||
* Copyright (c) 2011-2013 Jos de Jong, http://jsoneditoronline.org
|
||||
*
|
||||
* @author Jos de Jong, <wjosdejong@gmail.com>
|
||||
*/
|
||||
|
||||
// create namespace
|
||||
var jsoneditor = jsoneditor || {};
|
||||
|
||||
/**
|
||||
* A context menu
|
||||
* @param {Object[]} items Array containing the menu structure
|
||||
|
@ -29,7 +7,7 @@ var jsoneditor = jsoneditor || {};
|
|||
* context menu is being closed.
|
||||
* @constructor
|
||||
*/
|
||||
jsoneditor.ContextMenu = function (items, options) {
|
||||
function ContextMenu (items, options) {
|
||||
this.dom = {};
|
||||
|
||||
var me = this;
|
||||
|
@ -162,14 +140,14 @@ jsoneditor.ContextMenu = function (items, options) {
|
|||
var height = (items.length + (item.submenu ? item.submenu.length : 0)) * 24;
|
||||
me.maxHeight = Math.max(me.maxHeight, height);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the currently visible buttons
|
||||
* @return {Array.<HTMLElement>} buttons
|
||||
* @private
|
||||
*/
|
||||
jsoneditor.ContextMenu.prototype._getVisibleButtons = function () {
|
||||
ContextMenu.prototype._getVisibleButtons = function () {
|
||||
var buttons = [];
|
||||
var me = this;
|
||||
this.dom.items.forEach(function (item) {
|
||||
|
@ -192,23 +170,23 @@ jsoneditor.ContextMenu.prototype._getVisibleButtons = function () {
|
|||
};
|
||||
|
||||
// currently displayed context menu, a singleton. We may only have one visible context menu
|
||||
jsoneditor.ContextMenu.visibleMenu = undefined;
|
||||
ContextMenu.visibleMenu = undefined;
|
||||
|
||||
/**
|
||||
* Attach the menu to an anchor
|
||||
* @param {HTMLElement} anchor
|
||||
*/
|
||||
jsoneditor.ContextMenu.prototype.show = function (anchor) {
|
||||
ContextMenu.prototype.show = function (anchor) {
|
||||
this.hide();
|
||||
|
||||
// calculate whether the menu fits below the anchor
|
||||
var windowHeight = jsoneditor.util.getWindowHeight();
|
||||
var windowHeight = util.getWindowHeight();
|
||||
var anchorHeight = anchor.offsetHeight;
|
||||
var menuHeight = this.maxHeight;
|
||||
|
||||
// position the menu
|
||||
var left = jsoneditor.util.getAbsoluteLeft(anchor);
|
||||
var top = jsoneditor.util.getAbsoluteTop(anchor);
|
||||
var left = util.getAbsoluteLeft(anchor);
|
||||
var top = util.getAbsoluteTop(anchor);
|
||||
if (top + anchorHeight + menuHeight < windowHeight) {
|
||||
// display the menu below the anchor
|
||||
this.dom.menu.style.left = left + 'px';
|
||||
|
@ -228,45 +206,45 @@ jsoneditor.ContextMenu.prototype.show = function (anchor) {
|
|||
// create and attach event listeners
|
||||
var me = this;
|
||||
var list = this.dom.list;
|
||||
this.eventListeners.mousedown = jsoneditor.util.addEventListener(
|
||||
this.eventListeners.mousedown = util.addEventListener(
|
||||
document, 'mousedown', function (event) {
|
||||
// hide menu on click outside of the menu
|
||||
event = event || window.event;
|
||||
var target = event.target || event.srcElement;
|
||||
if ((target != list) && !me._isChildOf(target, list)) {
|
||||
me.hide();
|
||||
jsoneditor.util.stopPropagation(event);
|
||||
jsoneditor.util.preventDefault(event);
|
||||
util.stopPropagation(event);
|
||||
util.preventDefault(event);
|
||||
}
|
||||
});
|
||||
this.eventListeners.mousewheel = jsoneditor.util.addEventListener(
|
||||
this.eventListeners.mousewheel = util.addEventListener(
|
||||
document, 'mousewheel', function () {
|
||||
// hide the menu on mouse scroll
|
||||
jsoneditor.util.stopPropagation(event);
|
||||
jsoneditor.util.preventDefault(event);
|
||||
util.stopPropagation(event);
|
||||
util.preventDefault(event);
|
||||
});
|
||||
this.eventListeners.keydown = jsoneditor.util.addEventListener(
|
||||
this.eventListeners.keydown = util.addEventListener(
|
||||
document, 'keydown', function (event) {
|
||||
me._onKeyDown(event);
|
||||
});
|
||||
|
||||
// move focus to the first button in the context menu
|
||||
this.selection = jsoneditor.util.getSelection();
|
||||
this.selection = util.getSelection();
|
||||
this.anchor = anchor;
|
||||
setTimeout(function () {
|
||||
me.dom.focusButton.focus();
|
||||
}, 0);
|
||||
|
||||
if (jsoneditor.ContextMenu.visibleMenu) {
|
||||
jsoneditor.ContextMenu.visibleMenu.hide();
|
||||
if (ContextMenu.visibleMenu) {
|
||||
ContextMenu.visibleMenu.hide();
|
||||
}
|
||||
jsoneditor.ContextMenu.visibleMenu = this;
|
||||
ContextMenu.visibleMenu = this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Hide the context menu if visible
|
||||
*/
|
||||
jsoneditor.ContextMenu.prototype.hide = function () {
|
||||
ContextMenu.prototype.hide = function () {
|
||||
// remove the menu from the DOM
|
||||
if (this.dom.menu.parentNode) {
|
||||
this.dom.menu.parentNode.removeChild(this.dom.menu);
|
||||
|
@ -281,14 +259,14 @@ jsoneditor.ContextMenu.prototype.hide = function () {
|
|||
if (this.eventListeners.hasOwnProperty(name)) {
|
||||
var fn = this.eventListeners[name];
|
||||
if (fn) {
|
||||
jsoneditor.util.removeEventListener(document, name, fn);
|
||||
util.removeEventListener(document, name, fn);
|
||||
}
|
||||
delete this.eventListeners[name];
|
||||
}
|
||||
}
|
||||
|
||||
if (jsoneditor.ContextMenu.visibleMenu == this) {
|
||||
jsoneditor.ContextMenu.visibleMenu = undefined;
|
||||
if (ContextMenu.visibleMenu == this) {
|
||||
ContextMenu.visibleMenu = undefined;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -298,7 +276,7 @@ jsoneditor.ContextMenu.prototype.hide = function () {
|
|||
* @param {Object} domItem
|
||||
* @private
|
||||
*/
|
||||
jsoneditor.ContextMenu.prototype._onExpandItem = function (domItem) {
|
||||
ContextMenu.prototype._onExpandItem = function (domItem) {
|
||||
var me = this;
|
||||
var alreadyVisible = (domItem == this.expandedItem);
|
||||
|
||||
|
@ -311,7 +289,7 @@ jsoneditor.ContextMenu.prototype._onExpandItem = function (domItem) {
|
|||
setTimeout(function () {
|
||||
if (me.expandedItem != expandedItem) {
|
||||
expandedItem.ul.style.display = '';
|
||||
jsoneditor.util.removeClassName(expandedItem.ul.parentNode, 'selected');
|
||||
util.removeClassName(expandedItem.ul.parentNode, 'selected');
|
||||
}
|
||||
}, 300); // timeout duration must match the css transition duration
|
||||
this.expandedItem = undefined;
|
||||
|
@ -327,7 +305,7 @@ jsoneditor.ContextMenu.prototype._onExpandItem = function (domItem) {
|
|||
ul.style.padding = '5px 10px';
|
||||
}
|
||||
}, 0);
|
||||
jsoneditor.util.addClassName(ul.parentNode, 'selected');
|
||||
util.addClassName(ul.parentNode, 'selected');
|
||||
this.expandedItem = domItem;
|
||||
}
|
||||
};
|
||||
|
@ -337,7 +315,7 @@ jsoneditor.ContextMenu.prototype._onExpandItem = function (domItem) {
|
|||
* @param {Event} event
|
||||
* @private
|
||||
*/
|
||||
jsoneditor.ContextMenu.prototype._onKeyDown = function (event) {
|
||||
ContextMenu.prototype._onKeyDown = function (event) {
|
||||
event = event || window.event;
|
||||
var target = event.target || event.srcElement;
|
||||
var keynum = event.which || event.keyCode;
|
||||
|
@ -349,7 +327,7 @@ jsoneditor.ContextMenu.prototype._onKeyDown = function (event) {
|
|||
|
||||
// restore previous selection and focus
|
||||
if (this.selection) {
|
||||
jsoneditor.util.setSelection(this.selection);
|
||||
util.setSelection(this.selection);
|
||||
}
|
||||
if (this.anchor) {
|
||||
this.anchor.focus();
|
||||
|
@ -437,8 +415,8 @@ jsoneditor.ContextMenu.prototype._onKeyDown = function (event) {
|
|||
// TODO: arrow left and right
|
||||
|
||||
if (handled) {
|
||||
jsoneditor.util.stopPropagation(event);
|
||||
jsoneditor.util.preventDefault(event);
|
||||
util.stopPropagation(event);
|
||||
util.preventDefault(event);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -448,7 +426,7 @@ jsoneditor.ContextMenu.prototype._onKeyDown = function (event) {
|
|||
* @param {Element} parent
|
||||
* @return {boolean} isChild
|
||||
*/
|
||||
jsoneditor.ContextMenu.prototype._isChildOf = function (child, parent) {
|
||||
ContextMenu.prototype._isChildOf = function (child, parent) {
|
||||
var e = child.parentNode;
|
||||
while (e) {
|
||||
if (e == parent) {
|
||||
|
|
|
@ -1,39 +1,17 @@
|
|||
/**
|
||||
* @license
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy
|
||||
* of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*
|
||||
* Copyright (c) 2011-2013 Jos de Jong, http://jsoneditoronline.org
|
||||
*
|
||||
* @author Jos de Jong, <wjosdejong@gmail.com>
|
||||
*/
|
||||
|
||||
// create namespace
|
||||
var jsoneditor = jsoneditor || {};
|
||||
|
||||
/**
|
||||
* The highlighter can highlight/unhighlight a node, and
|
||||
* animate the visibility of a context menu.
|
||||
* @constructor jsoneditor.Highlighter
|
||||
* @constructor Highlighter
|
||||
*/
|
||||
jsoneditor.Highlighter = function () {
|
||||
function Highlighter () {
|
||||
this.locked = false;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Hightlight given node and its childs
|
||||
* @param {jsoneditor.Node} node
|
||||
* @param {Node} node
|
||||
*/
|
||||
jsoneditor.Highlighter.prototype.highlight = function (node) {
|
||||
Highlighter.prototype.highlight = function (node) {
|
||||
if (this.locked) {
|
||||
return;
|
||||
}
|
||||
|
@ -57,7 +35,7 @@ jsoneditor.Highlighter.prototype.highlight = function (node) {
|
|||
* Unhighlight currently highlighted node.
|
||||
* Will be done after a delay
|
||||
*/
|
||||
jsoneditor.Highlighter.prototype.unhighlight = function () {
|
||||
Highlighter.prototype.unhighlight = function () {
|
||||
if (this.locked) {
|
||||
return;
|
||||
}
|
||||
|
@ -81,7 +59,7 @@ jsoneditor.Highlighter.prototype.unhighlight = function () {
|
|||
* Cancel an unhighlight action (if before the timeout of the unhighlight action)
|
||||
* @private
|
||||
*/
|
||||
jsoneditor.Highlighter.prototype._cancelUnhighlight = function () {
|
||||
Highlighter.prototype._cancelUnhighlight = function () {
|
||||
if (this.unhighlightTimer) {
|
||||
clearTimeout(this.unhighlightTimer);
|
||||
this.unhighlightTimer = undefined;
|
||||
|
@ -92,13 +70,13 @@ jsoneditor.Highlighter.prototype._cancelUnhighlight = function () {
|
|||
* Lock highlighting or unhighlighting nodes.
|
||||
* methods highlight and unhighlight do not work while locked.
|
||||
*/
|
||||
jsoneditor.Highlighter.prototype.lock = function () {
|
||||
Highlighter.prototype.lock = function () {
|
||||
this.locked = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Unlock highlighting or unhighlighting nodes
|
||||
*/
|
||||
jsoneditor.Highlighter.prototype.unlock = function () {
|
||||
Highlighter.prototype.unlock = function () {
|
||||
this.locked = false;
|
||||
};
|
||||
|
|
|
@ -1,31 +1,9 @@
|
|||
/**
|
||||
* @license
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy
|
||||
* of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*
|
||||
* Copyright (c) 2011-2013 Jos de Jong, http://jsoneditoronline.org
|
||||
*
|
||||
* @author Jos de Jong, <wjosdejong@gmail.com>
|
||||
*/
|
||||
|
||||
// create namespace
|
||||
var jsoneditor = jsoneditor || {};
|
||||
|
||||
/**
|
||||
* @constructor jsoneditor.History
|
||||
* @constructor History
|
||||
* Store action history, enables undo and redo
|
||||
* @param {jsoneditor.JSONEditor} editor
|
||||
* @param {JSONEditor} editor
|
||||
*/
|
||||
jsoneditor.History = function (editor) {
|
||||
function History (editor) {
|
||||
this.editor = editor;
|
||||
this.clear();
|
||||
|
||||
|
@ -125,13 +103,13 @@ jsoneditor.History = function (editor) {
|
|||
// TODO: restore the original caret position and selection with each undo
|
||||
// TODO: implement history for actions "expand", "collapse", "scroll", "setDocument"
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* The method onChange is executed when the History is changed, and can
|
||||
* be overloaded.
|
||||
*/
|
||||
jsoneditor.History.prototype.onChange = function () {};
|
||||
History.prototype.onChange = function () {};
|
||||
|
||||
/**
|
||||
* Add a new action to the history
|
||||
|
@ -144,7 +122,7 @@ jsoneditor.History.prototype.onChange = function () {};
|
|||
* value are provided). params contains all information
|
||||
* needed to undo or redo the action.
|
||||
*/
|
||||
jsoneditor.History.prototype.add = function (action, params) {
|
||||
History.prototype.add = function (action, params) {
|
||||
this.index++;
|
||||
this.history[this.index] = {
|
||||
'action': action,
|
||||
|
@ -164,7 +142,7 @@ jsoneditor.History.prototype.add = function (action, params) {
|
|||
/**
|
||||
* Clear history
|
||||
*/
|
||||
jsoneditor.History.prototype.clear = function () {
|
||||
History.prototype.clear = function () {
|
||||
this.history = [];
|
||||
this.index = -1;
|
||||
|
||||
|
@ -176,7 +154,7 @@ jsoneditor.History.prototype.clear = function () {
|
|||
* Check if there is an action available for undo
|
||||
* @return {Boolean} canUndo
|
||||
*/
|
||||
jsoneditor.History.prototype.canUndo = function () {
|
||||
History.prototype.canUndo = function () {
|
||||
return (this.index >= 0);
|
||||
};
|
||||
|
||||
|
@ -184,14 +162,14 @@ jsoneditor.History.prototype.canUndo = function () {
|
|||
* Check if there is an action available for redo
|
||||
* @return {Boolean} canRedo
|
||||
*/
|
||||
jsoneditor.History.prototype.canRedo = function () {
|
||||
History.prototype.canRedo = function () {
|
||||
return (this.index < this.history.length - 1);
|
||||
};
|
||||
|
||||
/**
|
||||
* Undo the last action
|
||||
*/
|
||||
jsoneditor.History.prototype.undo = function () {
|
||||
History.prototype.undo = function () {
|
||||
if (this.canUndo()) {
|
||||
var obj = this.history[this.index];
|
||||
if (obj) {
|
||||
|
@ -216,7 +194,7 @@ jsoneditor.History.prototype.undo = function () {
|
|||
/**
|
||||
* Redo the last action
|
||||
*/
|
||||
jsoneditor.History.prototype.redo = function () {
|
||||
History.prototype.redo = function () {
|
||||
if (this.canRedo()) {
|
||||
this.index++;
|
||||
|
||||
|
|
|
@ -1,32 +1,10 @@
|
|||
/**
|
||||
* @license
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy
|
||||
* of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*
|
||||
* Copyright (c) 2011-2013 Jos de Jong, http://jsoneditoronline.org
|
||||
*
|
||||
* @author Jos de Jong, <wjosdejong@gmail.com>
|
||||
*/
|
||||
|
||||
// create namespace
|
||||
var jsoneditor = jsoneditor || {};
|
||||
|
||||
/**
|
||||
* jsoneditor.JSONEditor
|
||||
* @constructor JSONEditor
|
||||
* @param {Element} container Container element
|
||||
* @param {Object} [options] Object with options. available options:
|
||||
* {String} mode Editor mode. Available values:
|
||||
* 'editor' (default), 'viewer',
|
||||
* and 'form'.
|
||||
* 'tree' (default), 'view',
|
||||
* 'form', 'text', and 'code'.
|
||||
* {Boolean} search Enable search box.
|
||||
* True by default
|
||||
* {Boolean} history Enable history (undo/redo).
|
||||
|
@ -34,689 +12,155 @@ var jsoneditor = jsoneditor || {};
|
|||
* {function} change Callback method, triggered
|
||||
* on change of contents
|
||||
* {String} name Field name for the root node.
|
||||
* {Number} indentation Number of indentation
|
||||
* spaces. 4 by default.
|
||||
* @param {Object | undefined} json JSON object
|
||||
*/
|
||||
jsoneditor.JSONEditor = function (container, options, json) {
|
||||
if (!(this instanceof jsoneditor.JSONEditor)) {
|
||||
function JSONEditor (container, options, json) {
|
||||
if (!(this instanceof JSONEditor)) {
|
||||
throw new Error('JSONEditor constructor called without "new".');
|
||||
}
|
||||
|
||||
// check availability of JSON parser (not available in IE7 and older)
|
||||
if (typeof(JSON) == 'undefined') {
|
||||
throw new Error ('Your browser does not support JSON. \n\n' +
|
||||
'Please install the newest version of your browser.\n' +
|
||||
'(all modern browsers support JSON).');
|
||||
if (arguments.length) {
|
||||
this._create(container, options, json);
|
||||
}
|
||||
}
|
||||
|
||||
if (!container) {
|
||||
throw new Error('No container element provided.');
|
||||
}
|
||||
/**
|
||||
* Configuration for all registered modes. Example:
|
||||
* {
|
||||
* tree: {
|
||||
* editor: TreeEditor,
|
||||
* data: 'json'
|
||||
* },
|
||||
* text: {
|
||||
* editor: TextEditor,
|
||||
* data: 'text'
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* @type { Object.<String, {editor: Object, data: String} > }
|
||||
*/
|
||||
JSONEditor.modes = {};
|
||||
|
||||
/**
|
||||
* Create the JSONEditor
|
||||
* @param {Element} container Container element
|
||||
* @param {Object} [options] See description in constructor
|
||||
* @param {Object | undefined} json JSON object
|
||||
* @private
|
||||
*/
|
||||
JSONEditor.prototype._create = function (container, options, json) {
|
||||
this.container = container;
|
||||
this.dom = {};
|
||||
this.highlighter = new jsoneditor.Highlighter();
|
||||
this.selection = undefined; // will hold the last input selection
|
||||
this.options = options || {};
|
||||
this.json = json || {};
|
||||
|
||||
this._setOptions(options);
|
||||
|
||||
if (this.options.history && !this.mode.viewer) {
|
||||
this.history = new jsoneditor.History(this);
|
||||
}
|
||||
|
||||
this._createFrame();
|
||||
this._createTable();
|
||||
|
||||
this.set(json || {});
|
||||
var mode = this.options.mode || 'tree';
|
||||
this.setMode(mode);
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize and set default options
|
||||
* @param {Object} [options] Object with options. available options:
|
||||
* {String} mode Editor mode. Available values:
|
||||
* 'editor' (default), 'viewer',
|
||||
* and 'form'.
|
||||
* {Boolean} search Enable search box.
|
||||
* True by default.
|
||||
* {Boolean} history Enable history (undo/redo).
|
||||
* True by default.
|
||||
* {function} change Callback method, triggered
|
||||
* on change of contents.
|
||||
* {String} name Field name for the root node.
|
||||
* Detach the editor from the DOM
|
||||
* @private
|
||||
*/
|
||||
jsoneditor.JSONEditor.prototype._setOptions = function (options) {
|
||||
this.options = {
|
||||
search: true,
|
||||
history: true,
|
||||
mode: 'editor',
|
||||
name: undefined // field name of root node
|
||||
};
|
||||
|
||||
// copy all options
|
||||
if (options) {
|
||||
for (var prop in options) {
|
||||
if (options.hasOwnProperty(prop)) {
|
||||
this.options[prop] = options[prop];
|
||||
}
|
||||
}
|
||||
|
||||
// check for deprecated options
|
||||
if (options['enableSearch']) {
|
||||
// deprecated since version 1.6.0, 2012-11-03
|
||||
this.options.search = options['enableSearch'];
|
||||
console.log('WARNING: Option "enableSearch" is deprecated. Use "search" instead.');
|
||||
}
|
||||
if (options['enableHistory']) {
|
||||
// deprecated since version 1.6.0, 2012-11-03
|
||||
this.options.history = options['enableHistory'];
|
||||
console.log('WARNING: Option "enableHistory" is deprecated. Use "history" instead.');
|
||||
}
|
||||
}
|
||||
|
||||
// interpret the mode options
|
||||
this.mode = {
|
||||
editor: (this.options.mode != 'viewer' && this.options.mode != 'form'),
|
||||
viewer: (this.options.mode == 'viewer'),
|
||||
form: (this.options.mode == 'form')
|
||||
};
|
||||
};
|
||||
|
||||
// node currently being edited
|
||||
jsoneditor.JSONEditor.focusNode = undefined;
|
||||
JSONEditor.prototype._delete = function () {};
|
||||
|
||||
/**
|
||||
* Set JSON object in editor
|
||||
* @param {Object | undefined} json JSON data
|
||||
* @param {String} [name] Optional field name for the root node.
|
||||
* Can also be set using setName(name).
|
||||
*/
|
||||
jsoneditor.JSONEditor.prototype.set = function (json, name) {
|
||||
// adjust field name for root node
|
||||
if (name) {
|
||||
this.options.name = name;
|
||||
}
|
||||
|
||||
// verify if json is valid JSON, ignore when a function
|
||||
if (json instanceof Function || (json === undefined)) {
|
||||
this.clear();
|
||||
}
|
||||
else {
|
||||
this.content.removeChild(this.table); // Take the table offline
|
||||
|
||||
// replace the root node
|
||||
var params = {
|
||||
'field': this.options.name,
|
||||
'value': json
|
||||
};
|
||||
var node = new jsoneditor.Node(this, params);
|
||||
this._setRoot(node);
|
||||
|
||||
// expand
|
||||
var recurse = false;
|
||||
this.node.expand(recurse);
|
||||
|
||||
this.content.appendChild(this.table); // Put the table online again
|
||||
}
|
||||
|
||||
// TODO: maintain history, store last state and previous document
|
||||
if (this.history) {
|
||||
this.history.clear();
|
||||
}
|
||||
JSONEditor.prototype.set = function (json) {
|
||||
this.json = json;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get JSON object from editor
|
||||
* @return {Object | undefined} json
|
||||
* Get JSON from the editor
|
||||
* @returns {Object} json
|
||||
*/
|
||||
jsoneditor.JSONEditor.prototype.get = function () {
|
||||
// remove focus from currently edited node
|
||||
if (jsoneditor.JSONEditor.focusNode) {
|
||||
jsoneditor.JSONEditor.focusNode.blur();
|
||||
}
|
||||
JSONEditor.prototype.get = function () {
|
||||
return this.json;
|
||||
};
|
||||
|
||||
if (this.node) {
|
||||
return this.node.getValue();
|
||||
}
|
||||
else {
|
||||
return undefined;
|
||||
}
|
||||
/**
|
||||
* Set string containing JSON for the editor
|
||||
* @param {String | undefined} jsonText
|
||||
*/
|
||||
JSONEditor.prototype.setText = function (jsonText) {
|
||||
this.json = util.parse(jsonText);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get stringified JSON contents from the editor
|
||||
* @returns {String} jsonText
|
||||
*/
|
||||
JSONEditor.prototype.getText = function () {
|
||||
return JSON.stringify(this.json);
|
||||
};
|
||||
|
||||
/**
|
||||
* Set a field name for the root node.
|
||||
* @param {String | undefined} name
|
||||
*/
|
||||
jsoneditor.JSONEditor.prototype.setName = function (name) {
|
||||
this.options.name = name;
|
||||
if (this.node) {
|
||||
this.node.updateField(this.options.name);
|
||||
JSONEditor.prototype.setName = function (name) {
|
||||
if (!this.options) {
|
||||
this.options = {};
|
||||
}
|
||||
this.options.name = name;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the field name for the root node.
|
||||
* @return {String | undefined} name
|
||||
*/
|
||||
jsoneditor.JSONEditor.prototype.getName = function () {
|
||||
return this.options.name;
|
||||
JSONEditor.prototype.getName = function () {
|
||||
return this.options && this.options.name;
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove the root node from the editor
|
||||
* Change the mode of the editor
|
||||
* @param {String} mode
|
||||
*/
|
||||
jsoneditor.JSONEditor.prototype.clear = function () {
|
||||
if (this.node) {
|
||||
this.node.collapse();
|
||||
this.tbody.removeChild(this.node.getDom());
|
||||
delete this.node;
|
||||
}
|
||||
};
|
||||
JSONEditor.prototype.setMode = function (mode) {
|
||||
var container = this.container,
|
||||
options = util.extend({}, this.options),
|
||||
data,
|
||||
name;
|
||||
|
||||
/**
|
||||
* Set the root node for the json editor
|
||||
* @param {jsoneditor.Node} node
|
||||
* @private
|
||||
*/
|
||||
jsoneditor.JSONEditor.prototype._setRoot = function (node) {
|
||||
this.clear();
|
||||
options.mode = mode;
|
||||
var config = JSONEditor.modes[mode];
|
||||
if (config) {
|
||||
if (config.data == 'text') {
|
||||
// text
|
||||
name = this.getName();
|
||||
data = this.getText();
|
||||
|
||||
this.node = node;
|
||||
this._delete();
|
||||
util.clear(this);
|
||||
util.extend(this, config.editor.prototype);
|
||||
this._create(container, options);
|
||||
|
||||
// append to the dom
|
||||
this.tbody.appendChild(node.getDom());
|
||||
};
|
||||
|
||||
/**
|
||||
* Search text in all nodes
|
||||
* The nodes will be expanded when the text is found one of its childs,
|
||||
* else it will be collapsed. Searches are case insensitive.
|
||||
* @param {String} text
|
||||
* @return {Object[]} results Array with nodes containing the search results
|
||||
* The result objects contains fields:
|
||||
* - {jsoneditor.Node} node,
|
||||
* - {String} elem the dom element name where
|
||||
* the result is found ('field' or
|
||||
* 'value')
|
||||
*/
|
||||
jsoneditor.JSONEditor.prototype.search = function (text) {
|
||||
var results;
|
||||
if (this.node) {
|
||||
this.content.removeChild(this.table); // Take the table offline
|
||||
results = this.node.search(text);
|
||||
this.content.appendChild(this.table); // Put the table online again
|
||||
}
|
||||
else {
|
||||
results = [];
|
||||
}
|
||||
|
||||
return results;
|
||||
};
|
||||
|
||||
/**
|
||||
* Expand all nodes
|
||||
*/
|
||||
jsoneditor.JSONEditor.prototype.expandAll = function () {
|
||||
if (this.node) {
|
||||
this.content.removeChild(this.table); // Take the table offline
|
||||
this.node.expand();
|
||||
this.content.appendChild(this.table); // Put the table online again
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Collapse all nodes
|
||||
*/
|
||||
jsoneditor.JSONEditor.prototype.collapseAll = function () {
|
||||
if (this.node) {
|
||||
this.content.removeChild(this.table); // Take the table offline
|
||||
this.node.collapse();
|
||||
this.content.appendChild(this.table); // Put the table online again
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The method onChange is called whenever a field or value is changed, created,
|
||||
* deleted, duplicated, etc.
|
||||
* @param {String} action Change action. Available values: "editField",
|
||||
* "editValue", "changeType", "appendNode",
|
||||
* "removeNode", "duplicateNode", "moveNode", "expand",
|
||||
* "collapse".
|
||||
* @param {Object} params Object containing parameters describing the change.
|
||||
* The parameters in params depend on the action (for
|
||||
* example for "editValue" the Node, old value, and new
|
||||
* value are provided). params contains all information
|
||||
* needed to undo or redo the action.
|
||||
* @private
|
||||
*/
|
||||
jsoneditor.JSONEditor.prototype._onAction = function (action, params) {
|
||||
// add an action to the history
|
||||
if (this.history) {
|
||||
this.history.add(action, params);
|
||||
}
|
||||
|
||||
// trigger the onChange callback
|
||||
if (this.options.change) {
|
||||
try {
|
||||
this.options.change();
|
||||
this.setName(name);
|
||||
this.setText(data);
|
||||
}
|
||||
catch (err) {
|
||||
console.log('Error in change callback: ', err);
|
||||
else {
|
||||
// json
|
||||
name = this.getName();
|
||||
data = this.get();
|
||||
|
||||
this._delete();
|
||||
util.clear(this);
|
||||
util.extend(this, config.editor.prototype);
|
||||
this._create(container, options);
|
||||
|
||||
this.setName(name);
|
||||
this.set(data);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Start autoscrolling when given mouse position is above the top of the
|
||||
* editor contents, or below the bottom.
|
||||
* @param {Number} mouseY Absolute mouse position in pixels
|
||||
*/
|
||||
jsoneditor.JSONEditor.prototype.startAutoScroll = function (mouseY) {
|
||||
var me = this;
|
||||
var content = this.content;
|
||||
var top = jsoneditor.util.getAbsoluteTop(content);
|
||||
var height = content.clientHeight;
|
||||
var bottom = top + height;
|
||||
var margin = 24;
|
||||
var interval = 50; // ms
|
||||
|
||||
if ((mouseY < top + margin) && content.scrollTop > 0) {
|
||||
this.autoScrollStep = ((top + margin) - mouseY) / 3;
|
||||
}
|
||||
else if (mouseY > bottom - margin &&
|
||||
height + content.scrollTop < content.scrollHeight) {
|
||||
this.autoScrollStep = ((bottom - margin) - mouseY) / 3;
|
||||
}
|
||||
else {
|
||||
this.autoScrollStep = undefined;
|
||||
}
|
||||
|
||||
if (this.autoScrollStep) {
|
||||
if (!this.autoScrollTimer) {
|
||||
this.autoScrollTimer = setInterval(function () {
|
||||
if (me.autoScrollStep) {
|
||||
content.scrollTop -= me.autoScrollStep;
|
||||
}
|
||||
else {
|
||||
me.stopAutoScroll();
|
||||
}
|
||||
}, interval);
|
||||
if (typeof config.load === 'function') {
|
||||
config.load.call(this);
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.stopAutoScroll();
|
||||
throw new Error('Unknown mode "' + options.mode + '"');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Stop auto scrolling. Only applicable when scrolling
|
||||
*/
|
||||
jsoneditor.JSONEditor.prototype.stopAutoScroll = function () {
|
||||
if (this.autoScrollTimer) {
|
||||
clearTimeout(this.autoScrollTimer);
|
||||
delete this.autoScrollTimer;
|
||||
}
|
||||
if (this.autoScrollStep) {
|
||||
delete this.autoScrollStep;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Set the focus to an element in the JSONEditor, set text selection, and
|
||||
* set scroll position.
|
||||
* @param {Object} selection An object containing fields:
|
||||
* {Element | undefined} dom The dom element
|
||||
* which has focus
|
||||
* {Range | TextRange} range A text selection
|
||||
* {Number} scrollTop Scroll position
|
||||
*/
|
||||
jsoneditor.JSONEditor.prototype.setSelection = function (selection) {
|
||||
if (!selection) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ('scrollTop' in selection && this.content) {
|
||||
// TODO: animated scroll
|
||||
this.content.scrollTop = selection.scrollTop;
|
||||
}
|
||||
if (selection.range) {
|
||||
jsoneditor.util.setSelectionOffset(selection.range);
|
||||
}
|
||||
if (selection.dom) {
|
||||
selection.dom.focus();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the current focus
|
||||
* @return {Object} selection An object containing fields:
|
||||
* {Element | undefined} dom The dom element
|
||||
* which has focus
|
||||
* {Range | TextRange} range A text selection
|
||||
* {Number} scrollTop Scroll position
|
||||
*/
|
||||
jsoneditor.JSONEditor.prototype.getSelection = function () {
|
||||
return {
|
||||
dom: jsoneditor.JSONEditor.domFocus,
|
||||
scrollTop: this.content ? this.content.scrollTop : 0,
|
||||
range: jsoneditor.util.getSelectionOffset()
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Adjust the scroll position such that given top position is shown at 1/4
|
||||
* of the window height.
|
||||
* @param {Number} top
|
||||
* @param {function(boolean)} [callback] Callback, executed when animation is
|
||||
* finished. The callback returns true
|
||||
* when animation is finished, or false
|
||||
* when not.
|
||||
*/
|
||||
jsoneditor.JSONEditor.prototype.scrollTo = function (top, callback) {
|
||||
var content = this.content;
|
||||
if (content) {
|
||||
var editor = this;
|
||||
// cancel any running animation
|
||||
if (editor.animateTimeout) {
|
||||
clearTimeout(editor.animateTimeout);
|
||||
delete editor.animateTimeout;
|
||||
}
|
||||
if (editor.animateCallback) {
|
||||
editor.animateCallback(false);
|
||||
delete editor.animateCallback;
|
||||
}
|
||||
|
||||
// calculate final scroll position
|
||||
var height = content.clientHeight;
|
||||
var bottom = content.scrollHeight - height;
|
||||
var finalScrollTop = Math.min(Math.max(top - height / 4, 0), bottom);
|
||||
|
||||
// animate towards the new scroll position
|
||||
var animate = function () {
|
||||
var scrollTop = content.scrollTop;
|
||||
var diff = (finalScrollTop - scrollTop);
|
||||
if (Math.abs(diff) > 3) {
|
||||
content.scrollTop += diff / 3;
|
||||
editor.animateCallback = callback;
|
||||
editor.animateTimeout = setTimeout(animate, 50);
|
||||
}
|
||||
else {
|
||||
// finished
|
||||
if (callback) {
|
||||
callback(true);
|
||||
}
|
||||
content.scrollTop = finalScrollTop;
|
||||
delete editor.animateTimeout;
|
||||
delete editor.animateCallback;
|
||||
}
|
||||
};
|
||||
animate();
|
||||
}
|
||||
else {
|
||||
if (callback) {
|
||||
callback(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Create main frame
|
||||
* @private
|
||||
*/
|
||||
jsoneditor.JSONEditor.prototype._createFrame = function () {
|
||||
// create the frame
|
||||
this.container.innerHTML = '';
|
||||
this.frame = document.createElement('div');
|
||||
this.frame.className = 'jsoneditor';
|
||||
this.container.appendChild(this.frame);
|
||||
|
||||
// create one global event listener to handle all events from all nodes
|
||||
var editor = this;
|
||||
var onEvent = function (event) {
|
||||
editor._onEvent(event);
|
||||
};
|
||||
this.frame.onclick = function (event) {
|
||||
onEvent(event);
|
||||
|
||||
// prevent default submit action when JSONEditor is located inside a form
|
||||
jsoneditor.util.preventDefault(event);
|
||||
};
|
||||
this.frame.oninput = onEvent;
|
||||
this.frame.onchange = onEvent;
|
||||
this.frame.onkeydown = onEvent;
|
||||
this.frame.onkeyup = onEvent;
|
||||
this.frame.oncut = onEvent;
|
||||
this.frame.onpaste = onEvent;
|
||||
this.frame.onmousedown = onEvent;
|
||||
this.frame.onmouseup = onEvent;
|
||||
this.frame.onmouseover = onEvent;
|
||||
this.frame.onmouseout = onEvent;
|
||||
// Note: focus and blur events do not propagate, therefore they defined
|
||||
// using an eventListener with useCapture=true
|
||||
// see http://www.quirksmode.org/blog/archives/2008/04/delegating_the.html
|
||||
jsoneditor.util.addEventListener(this.frame, 'focus', onEvent, true);
|
||||
jsoneditor.util.addEventListener(this.frame, 'blur', onEvent, true);
|
||||
this.frame.onfocusin = onEvent; // for IE
|
||||
this.frame.onfocusout = onEvent; // for IE
|
||||
|
||||
// create menu
|
||||
this.menu = document.createElement('div');
|
||||
this.menu.className = 'menu';
|
||||
this.frame.appendChild(this.menu);
|
||||
|
||||
// create expand all button
|
||||
var expandAll = document.createElement('button');
|
||||
expandAll.className = 'expand-all';
|
||||
expandAll.title = 'Expand all fields';
|
||||
expandAll.onclick = function () {
|
||||
editor.expandAll();
|
||||
};
|
||||
this.menu.appendChild(expandAll);
|
||||
|
||||
// create expand all button
|
||||
var collapseAll = document.createElement('button');
|
||||
collapseAll.title = 'Collapse all fields';
|
||||
collapseAll.className = 'collapse-all';
|
||||
collapseAll.onclick = function () {
|
||||
editor.collapseAll();
|
||||
};
|
||||
this.menu.appendChild(collapseAll);
|
||||
|
||||
// create undo/redo buttons
|
||||
if (this.history) {
|
||||
// create separator
|
||||
var separator = document.createElement('span');
|
||||
separator.innerHTML = ' ';
|
||||
this.menu.appendChild(separator);
|
||||
|
||||
// create undo button
|
||||
var undo = document.createElement('button');
|
||||
undo.className = 'undo';
|
||||
undo.title = 'Undo last action (Ctrl+Z)';
|
||||
undo.onclick = function () {
|
||||
editor._onUndo();
|
||||
};
|
||||
this.menu.appendChild(undo);
|
||||
this.dom.undo = undo;
|
||||
|
||||
// create redo button
|
||||
var redo = document.createElement('button');
|
||||
redo.className = 'redo';
|
||||
redo.title = 'Redo (Ctrl+Shift+Z)';
|
||||
redo.onclick = function () {
|
||||
editor._onRedo();
|
||||
};
|
||||
this.menu.appendChild(redo);
|
||||
this.dom.redo = redo;
|
||||
|
||||
// register handler for onchange of history
|
||||
this.history.onChange = function () {
|
||||
undo.disabled = !editor.history.canUndo();
|
||||
redo.disabled = !editor.history.canRedo();
|
||||
};
|
||||
this.history.onChange();
|
||||
}
|
||||
|
||||
// create search box
|
||||
if (this.options.search) {
|
||||
this.searchBox = new jsoneditor.SearchBox(this, this.menu);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Perform an undo action
|
||||
* @private
|
||||
*/
|
||||
jsoneditor.JSONEditor.prototype._onUndo = function () {
|
||||
if (this.history) {
|
||||
// undo last action
|
||||
this.history.undo();
|
||||
|
||||
// trigger change callback
|
||||
if (this.options.change) {
|
||||
this.options.change();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Perform a redo action
|
||||
* @private
|
||||
*/
|
||||
jsoneditor.JSONEditor.prototype._onRedo = function () {
|
||||
if (this.history) {
|
||||
// redo last action
|
||||
this.history.redo();
|
||||
|
||||
// trigger change callback
|
||||
if (this.options.change) {
|
||||
this.options.change();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Event handler
|
||||
* @param event
|
||||
* @private
|
||||
*/
|
||||
jsoneditor.JSONEditor.prototype._onEvent = function (event) {
|
||||
event = event || window.event;
|
||||
var target = event.target || event.srcElement;
|
||||
|
||||
if (event.type == 'keydown') {
|
||||
this._onKeyDown(event);
|
||||
}
|
||||
|
||||
if (event.type == 'focus') {
|
||||
jsoneditor.JSONEditor.domFocus = target;
|
||||
}
|
||||
|
||||
var node = jsoneditor.Node.getNodeFromTarget(target);
|
||||
if (node) {
|
||||
node.onEvent(event);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Event handler for keydown. Handles shortcut keys
|
||||
* @param {Event} event
|
||||
* @private
|
||||
*/
|
||||
jsoneditor.JSONEditor.prototype._onKeyDown = function (event) {
|
||||
var keynum = event.which || event.keyCode;
|
||||
var ctrlKey = event.ctrlKey;
|
||||
var shiftKey = event.shiftKey;
|
||||
var handled = false;
|
||||
|
||||
if (keynum == 9) { // Tab or Shift+Tab
|
||||
// FIXME: selecting all text on tab key does not work on IE8 (-> put selectContentEditable() in keyup too?)
|
||||
//jsoneditor.Node.select(jsoneditor.JSONEditor.domFocus);
|
||||
setTimeout(function () {
|
||||
// select all text when moving focus to an editable div
|
||||
jsoneditor.util.selectContentEditable(jsoneditor.JSONEditor.domFocus);
|
||||
}, 0);
|
||||
}
|
||||
|
||||
if (this.searchBox) {
|
||||
if (ctrlKey && keynum == 70) { // Ctrl+F
|
||||
this.searchBox.dom.search.focus();
|
||||
this.searchBox.dom.search.select();
|
||||
handled = true;
|
||||
}
|
||||
else if (keynum == 114 || (ctrlKey && keynum == 71)) { // F3 or Ctrl+G
|
||||
var focus = true;
|
||||
if (!shiftKey) {
|
||||
// select next search result (F3 or Ctrl+G)
|
||||
this.searchBox.next(focus);
|
||||
}
|
||||
else {
|
||||
// select previous search result (Shift+F3 or Ctrl+Shift+G)
|
||||
this.searchBox.previous(focus);
|
||||
}
|
||||
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.history) {
|
||||
if (ctrlKey && !shiftKey && keynum == 90) { // Ctrl+Z
|
||||
// undo
|
||||
this._onUndo();
|
||||
handled = true;
|
||||
}
|
||||
else if (ctrlKey && shiftKey && keynum == 90) { // Ctrl+Shift+Z
|
||||
// redo
|
||||
this._onRedo();
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (handled) {
|
||||
jsoneditor.util.preventDefault(event);
|
||||
jsoneditor.util.stopPropagation(event);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Create main table
|
||||
* @private
|
||||
*/
|
||||
jsoneditor.JSONEditor.prototype._createTable = function () {
|
||||
var contentOuter = document.createElement('div');
|
||||
contentOuter.className = 'outer';
|
||||
this.contentOuter = contentOuter;
|
||||
|
||||
this.content = document.createElement('div');
|
||||
this.content.className = 'content';
|
||||
contentOuter.appendChild(this.content);
|
||||
|
||||
this.table = document.createElement('table');
|
||||
this.table.className = 'content';
|
||||
this.content.appendChild(this.table);
|
||||
|
||||
// IE8 does not handle overflow='auto' correctly.
|
||||
// Therefore, set overflow to 'scroll'
|
||||
var ieVersion = jsoneditor.util.getInternetExplorerVersion();
|
||||
if (ieVersion == 8) {
|
||||
this.content.style.overflow = 'scroll';
|
||||
}
|
||||
|
||||
// create colgroup where the first two columns don't have a fixed
|
||||
// width, and the edit columns do have a fixed width
|
||||
var col;
|
||||
this.colgroupContent = document.createElement('colgroup');
|
||||
col = document.createElement('col');
|
||||
col.width = "24px";
|
||||
this.colgroupContent.appendChild(col);
|
||||
col = document.createElement('col');
|
||||
col.width = "24px";
|
||||
this.colgroupContent.appendChild(col);
|
||||
col = document.createElement('col');
|
||||
this.colgroupContent.appendChild(col);
|
||||
this.table.appendChild(this.colgroupContent);
|
||||
|
||||
this.tbody = document.createElement('tbody');
|
||||
this.table.appendChild(this.tbody);
|
||||
|
||||
this.frame.appendChild(contentOuter);
|
||||
};
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
* Copyright (c) 2011-2013 Jos de Jong, http://jsoneditoronline.org
|
||||
*
|
||||
* @author Jos de Jong, <wjosdejong@gmail.com>
|
||||
* @date 2013-02-21
|
||||
* @date 2013-04-29
|
||||
*/
|
||||
|
||||
(function () {
|
||||
|
@ -36,10 +36,13 @@
|
|||
/***code_placeholder***/
|
||||
|
||||
// module exports
|
||||
var jsoneditorExports = {
|
||||
'JSONEditor': jsoneditor.JSONEditor,
|
||||
'JSONFormatter': jsoneditor.JSONFormatter,
|
||||
'util': jsoneditor.util
|
||||
var jsoneditor = {
|
||||
'JSONEditor': JSONEditor,
|
||||
'JSONFormatter': function () {
|
||||
throw new Error('JSONFormatter is deprecated. ' +
|
||||
'Use JSONEditor with mode "text" or "code" instead');
|
||||
},
|
||||
'util': util
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -65,7 +68,7 @@ var loadCss = function () {
|
|||
*/
|
||||
if (typeof(module) != 'undefined' && typeof(exports) != 'undefined') {
|
||||
loadCss();
|
||||
module.exports = exports = jsoneditorExports;
|
||||
module.exports = exports = jsoneditor;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -74,12 +77,12 @@ if (typeof(module) != 'undefined' && typeof(exports) != 'undefined') {
|
|||
if (typeof(require) != 'undefined' && typeof(define) != 'undefined') {
|
||||
define(function () {
|
||||
loadCss();
|
||||
return jsoneditorExports;
|
||||
return jsoneditor;
|
||||
});
|
||||
}
|
||||
else {
|
||||
// create attach the module to window, load as a regular javascript file
|
||||
window['jsoneditor'] = jsoneditorExports;
|
||||
// attach the module to the window, load as a regular javascript file
|
||||
window['jsoneditor'] = jsoneditor;
|
||||
}
|
||||
|
||||
})();
|
||||
})();
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,33 +1,11 @@
|
|||
/**
|
||||
* @license
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy
|
||||
* of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*
|
||||
* Copyright (c) 2011-2013 Jos de Jong, http://jsoneditoronline.org
|
||||
*
|
||||
* @author Jos de Jong, <wjosdejong@gmail.com>
|
||||
*/
|
||||
|
||||
// create namespace
|
||||
var jsoneditor = jsoneditor || {};
|
||||
|
||||
/**
|
||||
* @constructor jsoneditor.SearchBox
|
||||
* @constructor SearchBox
|
||||
* Create a search box in given HTML container
|
||||
* @param {jsoneditor.JSONEditor} editor The JSON Editor to attach to
|
||||
* @param {JSONEditor} editor The JSON Editor to attach to
|
||||
* @param {Element} container HTML container element of where to
|
||||
* create the search box
|
||||
*/
|
||||
jsoneditor.SearchBox = function(editor, container) {
|
||||
function SearchBox (editor, container) {
|
||||
var searchBox = this;
|
||||
|
||||
this.editor = editor;
|
||||
|
@ -119,15 +97,14 @@ jsoneditor.SearchBox = function(editor, container) {
|
|||
td = document.createElement('td');
|
||||
td.appendChild(searchPrevious);
|
||||
tr.appendChild(td);
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Go to the next search result
|
||||
* @param {boolean} [focus] If true, focus will be set to the next result
|
||||
* focus is false by default.
|
||||
*/
|
||||
jsoneditor.SearchBox.prototype.next = function(focus) {
|
||||
SearchBox.prototype.next = function(focus) {
|
||||
if (this.results != undefined) {
|
||||
var index = (this.resultIndex != undefined) ? this.resultIndex + 1 : 0;
|
||||
if (index > this.results.length - 1) {
|
||||
|
@ -142,7 +119,7 @@ jsoneditor.SearchBox.prototype.next = function(focus) {
|
|||
* @param {boolean} [focus] If true, focus will be set to the next result
|
||||
* focus is false by default.
|
||||
*/
|
||||
jsoneditor.SearchBox.prototype.previous = function(focus) {
|
||||
SearchBox.prototype.previous = function(focus) {
|
||||
if (this.results != undefined) {
|
||||
var max = this.results.length - 1;
|
||||
var index = (this.resultIndex != undefined) ? this.resultIndex - 1 : max;
|
||||
|
@ -160,7 +137,7 @@ jsoneditor.SearchBox.prototype.previous = function(focus) {
|
|||
* focus is false by default.
|
||||
* @private
|
||||
*/
|
||||
jsoneditor.SearchBox.prototype._setActiveResult = function(index, focus) {
|
||||
SearchBox.prototype._setActiveResult = function(index, focus) {
|
||||
// de-activate current active result
|
||||
if (this.activeResult) {
|
||||
var prevNode = this.activeResult.node;
|
||||
|
@ -207,7 +184,7 @@ jsoneditor.SearchBox.prototype._setActiveResult = function(index, focus) {
|
|||
* Cancel any running onDelayedSearch.
|
||||
* @private
|
||||
*/
|
||||
jsoneditor.SearchBox.prototype._clearDelay = function() {
|
||||
SearchBox.prototype._clearDelay = function() {
|
||||
if (this.timeout != undefined) {
|
||||
clearTimeout(this.timeout);
|
||||
delete this.timeout;
|
||||
|
@ -220,7 +197,7 @@ jsoneditor.SearchBox.prototype._clearDelay = function() {
|
|||
* @param {Event} event
|
||||
* @private
|
||||
*/
|
||||
jsoneditor.SearchBox.prototype._onDelayedSearch = function (event) {
|
||||
SearchBox.prototype._onDelayedSearch = function (event) {
|
||||
// execute the search after a short delay (reduces the number of
|
||||
// search actions while typing in the search text box)
|
||||
this._clearDelay();
|
||||
|
@ -239,7 +216,7 @@ jsoneditor.SearchBox.prototype._onDelayedSearch = function (event) {
|
|||
* Default is false.
|
||||
* @private
|
||||
*/
|
||||
jsoneditor.SearchBox.prototype._onSearch = function (event, forceSearch) {
|
||||
SearchBox.prototype._onSearch = function (event, forceSearch) {
|
||||
this._clearDelay();
|
||||
|
||||
var value = this.dom.search.value;
|
||||
|
@ -270,14 +247,14 @@ jsoneditor.SearchBox.prototype._onSearch = function (event, forceSearch) {
|
|||
* @param {Event} event
|
||||
* @private
|
||||
*/
|
||||
jsoneditor.SearchBox.prototype._onKeyDown = function (event) {
|
||||
SearchBox.prototype._onKeyDown = function (event) {
|
||||
event = event || window.event;
|
||||
var keynum = event.which || event.keyCode;
|
||||
if (keynum == 27) { // ESC
|
||||
this.dom.search.value = ''; // clear search
|
||||
this._onSearch(event);
|
||||
jsoneditor.util.preventDefault(event);
|
||||
jsoneditor.util.stopPropagation(event);
|
||||
util.preventDefault(event);
|
||||
util.stopPropagation(event);
|
||||
}
|
||||
else if (keynum == 13) { // Enter
|
||||
if (event.ctrlKey) {
|
||||
|
@ -292,8 +269,8 @@ jsoneditor.SearchBox.prototype._onKeyDown = function (event) {
|
|||
// move to the next search result
|
||||
this.next();
|
||||
}
|
||||
jsoneditor.util.preventDefault(event);
|
||||
jsoneditor.util.stopPropagation(event);
|
||||
util.preventDefault(event);
|
||||
util.stopPropagation(event);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -302,7 +279,7 @@ jsoneditor.SearchBox.prototype._onKeyDown = function (event) {
|
|||
* @param {Event} event
|
||||
* @private
|
||||
*/
|
||||
jsoneditor.SearchBox.prototype._onKeyUp = function (event) {
|
||||
SearchBox.prototype._onKeyUp = function (event) {
|
||||
event = event || window.event;
|
||||
var keynum = event.which || event.keyCode;
|
||||
if (keynum != 27 && keynum != 13) { // !show and !Enter
|
||||
|
|
|
@ -1,28 +1,6 @@
|
|||
/**
|
||||
* @license
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy
|
||||
* of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*
|
||||
* Copyright (c) 2011-2013 Jos de Jong, http://jsoneditoronline.org
|
||||
*
|
||||
* @author Jos de Jong, <wjosdejong@gmail.com>
|
||||
*/
|
||||
|
||||
// create namespace
|
||||
var jsoneditor = jsoneditor || {};
|
||||
|
||||
/**
|
||||
* Create a JSONFormatter and attach it to given container
|
||||
* @constructor jsoneditor.JSONFormatter
|
||||
* Create a TextEditor and attach it to given container
|
||||
* @constructor TextEditor
|
||||
* @param {Element} container
|
||||
* @param {Object} [options] Object with options. available options:
|
||||
* {String} mode Available values:
|
||||
|
@ -34,11 +12,23 @@ var jsoneditor = jsoneditor || {};
|
|||
* triggered on change
|
||||
* @param {JSON | String} [json] initial contents of the formatter
|
||||
*/
|
||||
jsoneditor.JSONFormatter = function (container, options, json) {
|
||||
if (!(this instanceof jsoneditor.JSONFormatter)) {
|
||||
throw new Error('JSONFormatter constructor called without "new".');
|
||||
function TextEditor(container, options, json) {
|
||||
if (!(this instanceof TextEditor)) {
|
||||
throw new Error('TextEditor constructor called without "new".');
|
||||
}
|
||||
|
||||
this._create(container, options, json);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a TextEditor and attach it to given container
|
||||
* @constructor TextEditor
|
||||
* @param {Element} container
|
||||
* @param {Object} [options] See description in constructor
|
||||
* @param {JSON | String} [json] initial contents of the formatter
|
||||
* @private
|
||||
*/
|
||||
TextEditor.prototype._create = function (container, options, json) {
|
||||
// check availability of JSON parser (not available in IE7 and older)
|
||||
if (typeof(JSON) == 'undefined') {
|
||||
throw new Error('Your browser does not support JSON. \n\n' +
|
||||
|
@ -59,7 +49,7 @@ jsoneditor.JSONFormatter = function (container, options, json) {
|
|||
console.log('WARNING: Cannot load code editor, Ace library not loaded. ' +
|
||||
'Falling back to plain text editor');
|
||||
}
|
||||
if (jsoneditor.util.getInternetExplorerVersion() == 8) {
|
||||
if (util.getInternetExplorerVersion() == 8) {
|
||||
this.mode = 'text';
|
||||
console.log('WARNING: Cannot load code editor, Ace is not supported on IE8. ' +
|
||||
'Falling back to plain text editor');
|
||||
|
@ -78,8 +68,8 @@ jsoneditor.JSONFormatter = function (container, options, json) {
|
|||
this.frame = document.createElement('div');
|
||||
this.frame.className = 'jsoneditor';
|
||||
this.frame.onclick = function (event) {
|
||||
// prevent default submit action when JSONFormatter is located inside a form
|
||||
jsoneditor.util.preventDefault(event);
|
||||
// prevent default submit action when TextEditor is located inside a form
|
||||
util.preventDefault(event);
|
||||
};
|
||||
|
||||
// create menu
|
||||
|
@ -183,21 +173,31 @@ jsoneditor.JSONFormatter = function (container, options, json) {
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Detach the editor from the DOM
|
||||
* @private
|
||||
*/
|
||||
TextEditor.prototype._delete = function () {
|
||||
if (this.frame && this.container && this.frame.parentNode == this.container) {
|
||||
this.container.removeChild(this.frame);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* This method is executed on error.
|
||||
* It can be overwritten for each instance of the JSONFormatter
|
||||
* It can be overwritten for each instance of the TextEditor
|
||||
* @param {String} err
|
||||
*/
|
||||
jsoneditor.JSONFormatter.prototype.onError = function(err) {
|
||||
TextEditor.prototype.onError = function(err) {
|
||||
// action should be implemented for the instance
|
||||
};
|
||||
|
||||
/**
|
||||
* Compact the code in the formatter
|
||||
*/
|
||||
jsoneditor.JSONFormatter.prototype.compact = function () {
|
||||
TextEditor.prototype.compact = function () {
|
||||
try {
|
||||
var json = jsoneditor.util.parse(this.getText());
|
||||
var json = util.parse(this.getText());
|
||||
this.setText(JSON.stringify(json));
|
||||
}
|
||||
catch (err) {
|
||||
|
@ -208,9 +208,9 @@ jsoneditor.JSONFormatter.prototype.compact = function () {
|
|||
/**
|
||||
* Format the code in the formatter
|
||||
*/
|
||||
jsoneditor.JSONFormatter.prototype.format = function () {
|
||||
TextEditor.prototype.format = function () {
|
||||
try {
|
||||
var json = jsoneditor.util.parse(this.getText());
|
||||
var json = util.parse(this.getText());
|
||||
this.setText(JSON.stringify(json, null, this.indentation));
|
||||
}
|
||||
catch (err) {
|
||||
|
@ -221,7 +221,7 @@ jsoneditor.JSONFormatter.prototype.format = function () {
|
|||
/**
|
||||
* Set focus to the formatter
|
||||
*/
|
||||
jsoneditor.JSONFormatter.prototype.focus = function () {
|
||||
TextEditor.prototype.focus = function () {
|
||||
if (this.textarea) {
|
||||
this.textarea.focus();
|
||||
}
|
||||
|
@ -233,7 +233,7 @@ jsoneditor.JSONFormatter.prototype.focus = function () {
|
|||
/**
|
||||
* Resize the formatter
|
||||
*/
|
||||
jsoneditor.JSONFormatter.prototype.resize = function () {
|
||||
TextEditor.prototype.resize = function () {
|
||||
if (this.editor) {
|
||||
var force = false;
|
||||
this.editor.resize(force);
|
||||
|
@ -244,7 +244,7 @@ jsoneditor.JSONFormatter.prototype.resize = function () {
|
|||
* Set json data in the formatter
|
||||
* @param {Object} json
|
||||
*/
|
||||
jsoneditor.JSONFormatter.prototype.set = function(json) {
|
||||
TextEditor.prototype.set = function(json) {
|
||||
this.setText(JSON.stringify(json, null, this.indentation));
|
||||
};
|
||||
|
||||
|
@ -252,15 +252,15 @@ jsoneditor.JSONFormatter.prototype.set = function(json) {
|
|||
* Get json data from the formatter
|
||||
* @return {Object} json
|
||||
*/
|
||||
jsoneditor.JSONFormatter.prototype.get = function() {
|
||||
return jsoneditor.util.parse(this.getText());
|
||||
TextEditor.prototype.get = function() {
|
||||
return util.parse(this.getText());
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the text contents of the JSONFormatter
|
||||
* @return {String} text
|
||||
* Get the text contents of the TextEditor
|
||||
* @return {String} jsonText
|
||||
*/
|
||||
jsoneditor.JSONFormatter.prototype.getText = function() {
|
||||
TextEditor.prototype.getText = function() {
|
||||
if (this.textarea) {
|
||||
return this.textarea.value;
|
||||
}
|
||||
|
@ -271,14 +271,26 @@ jsoneditor.JSONFormatter.prototype.getText = function() {
|
|||
};
|
||||
|
||||
/**
|
||||
* Set the text contents of the JSONFormatter
|
||||
* @param {String} text
|
||||
* Set the text contents of the TextEditor
|
||||
* @param {String} jsonText
|
||||
*/
|
||||
jsoneditor.JSONFormatter.prototype.setText = function(text) {
|
||||
TextEditor.prototype.setText = function(jsonText) {
|
||||
if (this.textarea) {
|
||||
this.textarea.value = text;
|
||||
this.textarea.value = jsonText;
|
||||
}
|
||||
if (this.editor) {
|
||||
return this.editor.setValue(text, -1);
|
||||
this.editor.setValue(jsonText, -1);
|
||||
}
|
||||
};
|
||||
|
||||
// register modes at the JSONEditor
|
||||
JSONEditor.modes.text = {
|
||||
editor: TextEditor,
|
||||
data: 'text',
|
||||
load: TextEditor.prototype.format
|
||||
};
|
||||
JSONEditor.modes.code = {
|
||||
editor: TextEditor,
|
||||
data: 'text',
|
||||
load: TextEditor.prototype.format
|
||||
};
|
|
@ -0,0 +1,761 @@
|
|||
/**
|
||||
* @constructor TreeEditor
|
||||
* @param {Element} container Container element
|
||||
* @param {Object} [options] Object with options. available options:
|
||||
* {String} mode Editor mode. Available values:
|
||||
* 'tree' (default), 'view',
|
||||
* and 'form'.
|
||||
* {Boolean} search Enable search box.
|
||||
* True by default
|
||||
* {Boolean} history Enable history (undo/redo).
|
||||
* True by default
|
||||
* {function} change Callback method, triggered
|
||||
* on change of contents
|
||||
* {String} name Field name for the root node.
|
||||
* @param {Object | undefined} json JSON object
|
||||
*/
|
||||
function TreeEditor(container, options, json) {
|
||||
if (!(this instanceof TreeEditor)) {
|
||||
throw new Error('TreeEditor constructor called without "new".');
|
||||
}
|
||||
|
||||
this._create(container, options, json);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the TreeEditor
|
||||
* @param {Element} container Container element
|
||||
* @param {Object} [options] See description in constructor
|
||||
* @param {Object | undefined} json JSON object
|
||||
* @private
|
||||
*/
|
||||
TreeEditor.prototype._create = function (container, options, json) {
|
||||
// check availability of JSON parser (not available in IE7 and older)
|
||||
if (typeof(JSON) == 'undefined') {
|
||||
throw new Error ('Your browser does not support JSON. \n\n' +
|
||||
'Please install the newest version of your browser.\n' +
|
||||
'(all modern browsers support JSON).');
|
||||
}
|
||||
|
||||
if (!container) {
|
||||
throw new Error('No container element provided.');
|
||||
}
|
||||
this.container = container;
|
||||
this.dom = {};
|
||||
this.highlighter = new Highlighter();
|
||||
this.selection = undefined; // will hold the last input selection
|
||||
|
||||
this._setOptions(options);
|
||||
|
||||
if (this.options.history && !this.mode.view) {
|
||||
this.history = new History(this);
|
||||
}
|
||||
|
||||
this._createFrame();
|
||||
this._createTable();
|
||||
|
||||
this.set(json || {});
|
||||
};
|
||||
|
||||
/**
|
||||
* Detach the editor from the DOM
|
||||
* @private
|
||||
*/
|
||||
TreeEditor.prototype._delete = function () {
|
||||
if (this.frame && this.container && this.frame.parentNode == this.container) {
|
||||
this.container.removeChild(this.frame);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize and set default options
|
||||
* @param {Object} [options] See description in constructor
|
||||
* @private
|
||||
*/
|
||||
TreeEditor.prototype._setOptions = function (options) {
|
||||
this.options = {
|
||||
search: true,
|
||||
history: true,
|
||||
mode: 'tree',
|
||||
name: undefined // field name of root node
|
||||
};
|
||||
|
||||
// copy all options
|
||||
if (options) {
|
||||
for (var prop in options) {
|
||||
if (options.hasOwnProperty(prop)) {
|
||||
this.options[prop] = options[prop];
|
||||
}
|
||||
}
|
||||
|
||||
// check for deprecated options
|
||||
if (options['enableSearch']) {
|
||||
// deprecated since version 1.6.0, 2012-11-03
|
||||
this.options.search = options['enableSearch'];
|
||||
console.log('WARNING: Option "enableSearch" is deprecated. Use "search" instead.');
|
||||
}
|
||||
if (options['enableHistory']) {
|
||||
// deprecated since version 1.6.0, 2012-11-03
|
||||
this.options.history = options['enableHistory'];
|
||||
console.log('WARNING: Option "enableHistory" is deprecated. Use "history" instead.');
|
||||
}
|
||||
if (options['mode'] == 'editor') {
|
||||
// deprecated since version 2.2.0, 2013-04-30
|
||||
this.options.mode = 'tree';
|
||||
console.log('WARNING: Mode "editor" is deprecated. Use "tree" instead.');
|
||||
}
|
||||
if (options['mode'] == 'viewer') {
|
||||
// deprecated since version 2.2.0, 2013-04-30
|
||||
this.options.mode = 'view';
|
||||
console.log('WARNING: Mode "viewer" is deprecated. Use "view" instead.');
|
||||
}
|
||||
}
|
||||
|
||||
// interpret the mode options
|
||||
this.mode = {
|
||||
edit: (this.options.mode != 'view' && this.options.mode != 'form'),
|
||||
view: (this.options.mode == 'view'),
|
||||
form: (this.options.mode == 'form')
|
||||
};
|
||||
};
|
||||
|
||||
// node currently being edited
|
||||
TreeEditor.focusNode = undefined;
|
||||
|
||||
/**
|
||||
* Set JSON object in editor
|
||||
* @param {Object | undefined} json JSON data
|
||||
* @param {String} [name] Optional field name for the root node.
|
||||
* Can also be set using setName(name).
|
||||
*/
|
||||
TreeEditor.prototype.set = function (json, name) {
|
||||
// adjust field name for root node
|
||||
if (name) {
|
||||
this.options.name = name;
|
||||
}
|
||||
|
||||
// verify if json is valid JSON, ignore when a function
|
||||
if (json instanceof Function || (json === undefined)) {
|
||||
this.clear();
|
||||
}
|
||||
else {
|
||||
this.content.removeChild(this.table); // Take the table offline
|
||||
|
||||
// replace the root node
|
||||
var params = {
|
||||
'field': this.options.name,
|
||||
'value': json
|
||||
};
|
||||
var node = new Node(this, params);
|
||||
this._setRoot(node);
|
||||
|
||||
// expand
|
||||
var recurse = false;
|
||||
this.node.expand(recurse);
|
||||
|
||||
this.content.appendChild(this.table); // Put the table online again
|
||||
}
|
||||
|
||||
// TODO: maintain history, store last state and previous document
|
||||
if (this.history) {
|
||||
this.history.clear();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get JSON object from editor
|
||||
* @return {Object | undefined} json
|
||||
*/
|
||||
TreeEditor.prototype.get = function () {
|
||||
// remove focus from currently edited node
|
||||
if (TreeEditor.focusNode) {
|
||||
TreeEditor.focusNode.blur();
|
||||
}
|
||||
|
||||
if (this.node) {
|
||||
return this.node.getValue();
|
||||
}
|
||||
else {
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the text contents of the TreeEditor
|
||||
* @return {String} jsonText
|
||||
*/
|
||||
TreeEditor.prototype.getText = function() {
|
||||
return JSON.stringify(this.get());
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the text contents of the TreeEditor
|
||||
* @param {String} jsonText
|
||||
*/
|
||||
TreeEditor.prototype.setText = function(jsonText) {
|
||||
this.set(util.parse(jsonText));
|
||||
};
|
||||
|
||||
/**
|
||||
* Set a field name for the root node.
|
||||
* @param {String | undefined} name
|
||||
*/
|
||||
TreeEditor.prototype.setName = function (name) {
|
||||
this.options.name = name;
|
||||
if (this.node) {
|
||||
this.node.updateField(this.options.name);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the field name for the root node.
|
||||
* @return {String | undefined} name
|
||||
*/
|
||||
TreeEditor.prototype.getName = function () {
|
||||
return this.options.name;
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove the root node from the editor
|
||||
*/
|
||||
TreeEditor.prototype.clear = function () {
|
||||
if (this.node) {
|
||||
this.node.collapse();
|
||||
this.tbody.removeChild(this.node.getDom());
|
||||
delete this.node;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the root node for the json editor
|
||||
* @param {Node} node
|
||||
* @private
|
||||
*/
|
||||
TreeEditor.prototype._setRoot = function (node) {
|
||||
this.clear();
|
||||
|
||||
this.node = node;
|
||||
|
||||
// append to the dom
|
||||
this.tbody.appendChild(node.getDom());
|
||||
};
|
||||
|
||||
/**
|
||||
* Search text in all nodes
|
||||
* The nodes will be expanded when the text is found one of its childs,
|
||||
* else it will be collapsed. Searches are case insensitive.
|
||||
* @param {String} text
|
||||
* @return {Object[]} results Array with nodes containing the search results
|
||||
* The result objects contains fields:
|
||||
* - {Node} node,
|
||||
* - {String} elem the dom element name where
|
||||
* the result is found ('field' or
|
||||
* 'value')
|
||||
*/
|
||||
TreeEditor.prototype.search = function (text) {
|
||||
var results;
|
||||
if (this.node) {
|
||||
this.content.removeChild(this.table); // Take the table offline
|
||||
results = this.node.search(text);
|
||||
this.content.appendChild(this.table); // Put the table online again
|
||||
}
|
||||
else {
|
||||
results = [];
|
||||
}
|
||||
|
||||
return results;
|
||||
};
|
||||
|
||||
/**
|
||||
* Expand all nodes
|
||||
*/
|
||||
TreeEditor.prototype.expandAll = function () {
|
||||
if (this.node) {
|
||||
this.content.removeChild(this.table); // Take the table offline
|
||||
this.node.expand();
|
||||
this.content.appendChild(this.table); // Put the table online again
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Collapse all nodes
|
||||
*/
|
||||
TreeEditor.prototype.collapseAll = function () {
|
||||
if (this.node) {
|
||||
this.content.removeChild(this.table); // Take the table offline
|
||||
this.node.collapse();
|
||||
this.content.appendChild(this.table); // Put the table online again
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The method onChange is called whenever a field or value is changed, created,
|
||||
* deleted, duplicated, etc.
|
||||
* @param {String} action Change action. Available values: "editField",
|
||||
* "editValue", "changeType", "appendNode",
|
||||
* "removeNode", "duplicateNode", "moveNode", "expand",
|
||||
* "collapse".
|
||||
* @param {Object} params Object containing parameters describing the change.
|
||||
* The parameters in params depend on the action (for
|
||||
* example for "editValue" the Node, old value, and new
|
||||
* value are provided). params contains all information
|
||||
* needed to undo or redo the action.
|
||||
* @private
|
||||
*/
|
||||
TreeEditor.prototype._onAction = function (action, params) {
|
||||
// add an action to the history
|
||||
if (this.history) {
|
||||
this.history.add(action, params);
|
||||
}
|
||||
|
||||
// trigger the onChange callback
|
||||
if (this.options.change) {
|
||||
try {
|
||||
this.options.change();
|
||||
}
|
||||
catch (err) {
|
||||
console.log('Error in change callback: ', err);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Start autoscrolling when given mouse position is above the top of the
|
||||
* editor contents, or below the bottom.
|
||||
* @param {Number} mouseY Absolute mouse position in pixels
|
||||
*/
|
||||
TreeEditor.prototype.startAutoScroll = function (mouseY) {
|
||||
var me = this;
|
||||
var content = this.content;
|
||||
var top = util.getAbsoluteTop(content);
|
||||
var height = content.clientHeight;
|
||||
var bottom = top + height;
|
||||
var margin = 24;
|
||||
var interval = 50; // ms
|
||||
|
||||
if ((mouseY < top + margin) && content.scrollTop > 0) {
|
||||
this.autoScrollStep = ((top + margin) - mouseY) / 3;
|
||||
}
|
||||
else if (mouseY > bottom - margin &&
|
||||
height + content.scrollTop < content.scrollHeight) {
|
||||
this.autoScrollStep = ((bottom - margin) - mouseY) / 3;
|
||||
}
|
||||
else {
|
||||
this.autoScrollStep = undefined;
|
||||
}
|
||||
|
||||
if (this.autoScrollStep) {
|
||||
if (!this.autoScrollTimer) {
|
||||
this.autoScrollTimer = setInterval(function () {
|
||||
if (me.autoScrollStep) {
|
||||
content.scrollTop -= me.autoScrollStep;
|
||||
}
|
||||
else {
|
||||
me.stopAutoScroll();
|
||||
}
|
||||
}, interval);
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.stopAutoScroll();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Stop auto scrolling. Only applicable when scrolling
|
||||
*/
|
||||
TreeEditor.prototype.stopAutoScroll = function () {
|
||||
if (this.autoScrollTimer) {
|
||||
clearTimeout(this.autoScrollTimer);
|
||||
delete this.autoScrollTimer;
|
||||
}
|
||||
if (this.autoScrollStep) {
|
||||
delete this.autoScrollStep;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Set the focus to an element in the TreeEditor, set text selection, and
|
||||
* set scroll position.
|
||||
* @param {Object} selection An object containing fields:
|
||||
* {Element | undefined} dom The dom element
|
||||
* which has focus
|
||||
* {Range | TextRange} range A text selection
|
||||
* {Number} scrollTop Scroll position
|
||||
*/
|
||||
TreeEditor.prototype.setSelection = function (selection) {
|
||||
if (!selection) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ('scrollTop' in selection && this.content) {
|
||||
// TODO: animated scroll
|
||||
this.content.scrollTop = selection.scrollTop;
|
||||
}
|
||||
if (selection.range) {
|
||||
util.setSelectionOffset(selection.range);
|
||||
}
|
||||
if (selection.dom) {
|
||||
selection.dom.focus();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the current focus
|
||||
* @return {Object} selection An object containing fields:
|
||||
* {Element | undefined} dom The dom element
|
||||
* which has focus
|
||||
* {Range | TextRange} range A text selection
|
||||
* {Number} scrollTop Scroll position
|
||||
*/
|
||||
TreeEditor.prototype.getSelection = function () {
|
||||
return {
|
||||
dom: TreeEditor.domFocus,
|
||||
scrollTop: this.content ? this.content.scrollTop : 0,
|
||||
range: util.getSelectionOffset()
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Adjust the scroll position such that given top position is shown at 1/4
|
||||
* of the window height.
|
||||
* @param {Number} top
|
||||
* @param {function(boolean)} [callback] Callback, executed when animation is
|
||||
* finished. The callback returns true
|
||||
* when animation is finished, or false
|
||||
* when not.
|
||||
*/
|
||||
TreeEditor.prototype.scrollTo = function (top, callback) {
|
||||
var content = this.content;
|
||||
if (content) {
|
||||
var editor = this;
|
||||
// cancel any running animation
|
||||
if (editor.animateTimeout) {
|
||||
clearTimeout(editor.animateTimeout);
|
||||
delete editor.animateTimeout;
|
||||
}
|
||||
if (editor.animateCallback) {
|
||||
editor.animateCallback(false);
|
||||
delete editor.animateCallback;
|
||||
}
|
||||
|
||||
// calculate final scroll position
|
||||
var height = content.clientHeight;
|
||||
var bottom = content.scrollHeight - height;
|
||||
var finalScrollTop = Math.min(Math.max(top - height / 4, 0), bottom);
|
||||
|
||||
// animate towards the new scroll position
|
||||
var animate = function () {
|
||||
var scrollTop = content.scrollTop;
|
||||
var diff = (finalScrollTop - scrollTop);
|
||||
if (Math.abs(diff) > 3) {
|
||||
content.scrollTop += diff / 3;
|
||||
editor.animateCallback = callback;
|
||||
editor.animateTimeout = setTimeout(animate, 50);
|
||||
}
|
||||
else {
|
||||
// finished
|
||||
if (callback) {
|
||||
callback(true);
|
||||
}
|
||||
content.scrollTop = finalScrollTop;
|
||||
delete editor.animateTimeout;
|
||||
delete editor.animateCallback;
|
||||
}
|
||||
};
|
||||
animate();
|
||||
}
|
||||
else {
|
||||
if (callback) {
|
||||
callback(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Create main frame
|
||||
* @private
|
||||
*/
|
||||
TreeEditor.prototype._createFrame = function () {
|
||||
// create the frame
|
||||
this.frame = document.createElement('div');
|
||||
this.frame.className = 'jsoneditor';
|
||||
this.container.appendChild(this.frame);
|
||||
|
||||
// create one global event listener to handle all events from all nodes
|
||||
var editor = this;
|
||||
var onEvent = function (event) {
|
||||
editor._onEvent(event);
|
||||
};
|
||||
this.frame.onclick = function (event) {
|
||||
onEvent(event);
|
||||
|
||||
// prevent default submit action when TreeEditor is located inside a form
|
||||
util.preventDefault(event);
|
||||
};
|
||||
this.frame.oninput = onEvent;
|
||||
this.frame.onchange = onEvent;
|
||||
this.frame.onkeydown = onEvent;
|
||||
this.frame.onkeyup = onEvent;
|
||||
this.frame.oncut = onEvent;
|
||||
this.frame.onpaste = onEvent;
|
||||
this.frame.onmousedown = onEvent;
|
||||
this.frame.onmouseup = onEvent;
|
||||
this.frame.onmouseover = onEvent;
|
||||
this.frame.onmouseout = onEvent;
|
||||
// Note: focus and blur events do not propagate, therefore they defined
|
||||
// using an eventListener with useCapture=true
|
||||
// see http://www.quirksmode.org/blog/archives/2008/04/delegating_the.html
|
||||
util.addEventListener(this.frame, 'focus', onEvent, true);
|
||||
util.addEventListener(this.frame, 'blur', onEvent, true);
|
||||
this.frame.onfocusin = onEvent; // for IE
|
||||
this.frame.onfocusout = onEvent; // for IE
|
||||
|
||||
// create menu
|
||||
this.menu = document.createElement('div');
|
||||
this.menu.className = 'menu';
|
||||
this.frame.appendChild(this.menu);
|
||||
|
||||
// create expand all button
|
||||
var expandAll = document.createElement('button');
|
||||
expandAll.className = 'expand-all';
|
||||
expandAll.title = 'Expand all fields';
|
||||
expandAll.onclick = function () {
|
||||
editor.expandAll();
|
||||
};
|
||||
this.menu.appendChild(expandAll);
|
||||
|
||||
// create expand all button
|
||||
var collapseAll = document.createElement('button');
|
||||
collapseAll.title = 'Collapse all fields';
|
||||
collapseAll.className = 'collapse-all';
|
||||
collapseAll.onclick = function () {
|
||||
editor.collapseAll();
|
||||
};
|
||||
this.menu.appendChild(collapseAll);
|
||||
|
||||
// create undo/redo buttons
|
||||
if (this.history) {
|
||||
// create separator
|
||||
var separator = document.createElement('span');
|
||||
separator.innerHTML = ' ';
|
||||
this.menu.appendChild(separator);
|
||||
|
||||
// create undo button
|
||||
var undo = document.createElement('button');
|
||||
undo.className = 'undo';
|
||||
undo.title = 'Undo last action (Ctrl+Z)';
|
||||
undo.onclick = function () {
|
||||
editor._onUndo();
|
||||
};
|
||||
this.menu.appendChild(undo);
|
||||
this.dom.undo = undo;
|
||||
|
||||
// create redo button
|
||||
var redo = document.createElement('button');
|
||||
redo.className = 'redo';
|
||||
redo.title = 'Redo (Ctrl+Shift+Z)';
|
||||
redo.onclick = function () {
|
||||
editor._onRedo();
|
||||
};
|
||||
this.menu.appendChild(redo);
|
||||
this.dom.redo = redo;
|
||||
|
||||
// register handler for onchange of history
|
||||
this.history.onChange = function () {
|
||||
undo.disabled = !editor.history.canUndo();
|
||||
redo.disabled = !editor.history.canRedo();
|
||||
};
|
||||
this.history.onChange();
|
||||
}
|
||||
|
||||
// create search box
|
||||
if (this.options.search) {
|
||||
this.searchBox = new SearchBox(this, this.menu);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Perform an undo action
|
||||
* @private
|
||||
*/
|
||||
TreeEditor.prototype._onUndo = function () {
|
||||
if (this.history) {
|
||||
// undo last action
|
||||
this.history.undo();
|
||||
|
||||
// trigger change callback
|
||||
if (this.options.change) {
|
||||
this.options.change();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Perform a redo action
|
||||
* @private
|
||||
*/
|
||||
TreeEditor.prototype._onRedo = function () {
|
||||
if (this.history) {
|
||||
// redo last action
|
||||
this.history.redo();
|
||||
|
||||
// trigger change callback
|
||||
if (this.options.change) {
|
||||
this.options.change();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Event handler
|
||||
* @param event
|
||||
* @private
|
||||
*/
|
||||
TreeEditor.prototype._onEvent = function (event) {
|
||||
event = event || window.event;
|
||||
var target = event.target || event.srcElement;
|
||||
|
||||
if (event.type == 'keydown') {
|
||||
this._onKeyDown(event);
|
||||
}
|
||||
|
||||
if (event.type == 'focus') {
|
||||
TreeEditor.domFocus = target;
|
||||
}
|
||||
|
||||
var node = Node.getNodeFromTarget(target);
|
||||
if (node) {
|
||||
node.onEvent(event);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Event handler for keydown. Handles shortcut keys
|
||||
* @param {Event} event
|
||||
* @private
|
||||
*/
|
||||
TreeEditor.prototype._onKeyDown = function (event) {
|
||||
var keynum = event.which || event.keyCode;
|
||||
var ctrlKey = event.ctrlKey;
|
||||
var shiftKey = event.shiftKey;
|
||||
var handled = false;
|
||||
|
||||
if (keynum == 9) { // Tab or Shift+Tab
|
||||
// FIXME: selecting all text on tab key does not work on IE8 (-> put selectContentEditable() in keyup too?)
|
||||
//Node.select(TreeEditor.domFocus);
|
||||
setTimeout(function () {
|
||||
// select all text when moving focus to an editable div
|
||||
util.selectContentEditable(TreeEditor.domFocus);
|
||||
}, 0);
|
||||
}
|
||||
|
||||
if (this.searchBox) {
|
||||
if (ctrlKey && keynum == 70) { // Ctrl+F
|
||||
this.searchBox.dom.search.focus();
|
||||
this.searchBox.dom.search.select();
|
||||
handled = true;
|
||||
}
|
||||
else if (keynum == 114 || (ctrlKey && keynum == 71)) { // F3 or Ctrl+G
|
||||
var focus = true;
|
||||
if (!shiftKey) {
|
||||
// select next search result (F3 or Ctrl+G)
|
||||
this.searchBox.next(focus);
|
||||
}
|
||||
else {
|
||||
// select previous search result (Shift+F3 or Ctrl+Shift+G)
|
||||
this.searchBox.previous(focus);
|
||||
}
|
||||
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.history) {
|
||||
if (ctrlKey && !shiftKey && keynum == 90) { // Ctrl+Z
|
||||
// undo
|
||||
this._onUndo();
|
||||
handled = true;
|
||||
}
|
||||
else if (ctrlKey && shiftKey && keynum == 90) { // Ctrl+Shift+Z
|
||||
// redo
|
||||
this._onRedo();
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (handled) {
|
||||
util.preventDefault(event);
|
||||
util.stopPropagation(event);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Create main table
|
||||
* @private
|
||||
*/
|
||||
TreeEditor.prototype._createTable = function () {
|
||||
var contentOuter = document.createElement('div');
|
||||
contentOuter.className = 'outer';
|
||||
this.contentOuter = contentOuter;
|
||||
|
||||
this.content = document.createElement('div');
|
||||
this.content.className = 'content';
|
||||
contentOuter.appendChild(this.content);
|
||||
|
||||
this.table = document.createElement('table');
|
||||
this.table.className = 'content';
|
||||
this.content.appendChild(this.table);
|
||||
|
||||
// IE8 does not handle overflow='auto' correctly.
|
||||
// Therefore, set overflow to 'scroll'
|
||||
var ieVersion = util.getInternetExplorerVersion();
|
||||
if (ieVersion == 8) {
|
||||
this.content.style.overflow = 'scroll';
|
||||
}
|
||||
|
||||
// create colgroup where the first two columns don't have a fixed
|
||||
// width, and the edit columns do have a fixed width
|
||||
var col;
|
||||
this.colgroupContent = document.createElement('colgroup');
|
||||
if (this.mode.edit) {
|
||||
col = document.createElement('col');
|
||||
col.width = "24px";
|
||||
this.colgroupContent.appendChild(col);
|
||||
}
|
||||
col = document.createElement('col');
|
||||
col.width = "24px";
|
||||
this.colgroupContent.appendChild(col);
|
||||
col = document.createElement('col');
|
||||
this.colgroupContent.appendChild(col);
|
||||
this.table.appendChild(this.colgroupContent);
|
||||
|
||||
this.tbody = document.createElement('tbody');
|
||||
this.table.appendChild(this.tbody);
|
||||
|
||||
this.frame.appendChild(contentOuter);
|
||||
};
|
||||
|
||||
// register modes at the JSONEditor
|
||||
JSONEditor.modes.tree = {
|
||||
editor: TreeEditor,
|
||||
data: 'json'
|
||||
};
|
||||
JSONEditor.modes.view = {
|
||||
editor: TreeEditor,
|
||||
data: 'json'
|
||||
};
|
||||
JSONEditor.modes.form = {
|
||||
editor: TreeEditor,
|
||||
data: 'json'
|
||||
};
|
||||
// Deprecated modes (deprecated since version 2.2.0)
|
||||
JSONEditor.modes.editor = {
|
||||
editor: TreeEditor,
|
||||
data: 'json'
|
||||
};
|
||||
JSONEditor.modes.viewer = {
|
||||
editor: TreeEditor,
|
||||
data: 'json'
|
||||
};
|
|
@ -1,25 +1,5 @@
|
|||
/**
|
||||
* @license
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy
|
||||
* of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*
|
||||
* Copyright (c) 2011-2013 Jos de Jong, http://jsoneditoronline.org
|
||||
*
|
||||
* @author Jos de Jong, <wjosdejong@gmail.com>
|
||||
*/
|
||||
|
||||
// create namespace
|
||||
var jsoneditor = jsoneditor || {};
|
||||
jsoneditor.util = {};
|
||||
util = {};
|
||||
|
||||
// Internet Explorer 8 and older does not support Array.indexOf,
|
||||
// so we define it here in that case
|
||||
|
@ -58,13 +38,13 @@ if (typeof console === 'undefined') {
|
|||
* On exception, the jsonString is validated and a detailed error is thrown.
|
||||
* @param {String} jsonString
|
||||
*/
|
||||
jsoneditor.util.parse = function (jsonString) {
|
||||
util.parse = function (jsonString) {
|
||||
try {
|
||||
return JSON.parse(jsonString);
|
||||
}
|
||||
catch (err) {
|
||||
// get a detailed error message using validate
|
||||
var message = jsoneditor.util.validate(jsonString) || err;
|
||||
var message = util.validate(jsonString) || err;
|
||||
throw new Error(message);
|
||||
}
|
||||
};
|
||||
|
@ -79,7 +59,7 @@ jsoneditor.util.parse = function (jsonString) {
|
|||
* the data is invalid. This message is HTML
|
||||
* formatted.
|
||||
*/
|
||||
jsoneditor.util.validate = function (jsonString) {
|
||||
util.validate = function (jsonString) {
|
||||
var message = undefined;
|
||||
|
||||
try {
|
||||
|
@ -103,13 +83,42 @@ jsoneditor.util.validate = function (jsonString) {
|
|||
return message;
|
||||
};
|
||||
|
||||
/**
|
||||
* Extend object a with the properties of object b
|
||||
* @param {Object} a
|
||||
* @param {Object} b
|
||||
* @return {Object} a
|
||||
*/
|
||||
util.extend = function (a, b) {
|
||||
for (var prop in b) {
|
||||
if (b.hasOwnProperty(prop)) {
|
||||
a[prop] = b[prop];
|
||||
}
|
||||
}
|
||||
return a;
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove all properties from object a
|
||||
* @param {Object} a
|
||||
* @return {Object} a
|
||||
*/
|
||||
util.clear = function (a) {
|
||||
for (var prop in a) {
|
||||
if (a.hasOwnProperty(prop)) {
|
||||
delete a[prop];
|
||||
}
|
||||
}
|
||||
return a;
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve the absolute left value of a DOM element
|
||||
* @param {Element} elem A dom element, for example a div
|
||||
* @return {Number} left The absolute left position of this element
|
||||
* in the browser page.
|
||||
*/
|
||||
jsoneditor.util.getAbsoluteLeft = function (elem) {
|
||||
util.getAbsoluteLeft = function (elem) {
|
||||
var left = elem.offsetLeft;
|
||||
var body = document.body;
|
||||
var e = elem.offsetParent;
|
||||
|
@ -127,7 +136,7 @@ jsoneditor.util.getAbsoluteLeft = function (elem) {
|
|||
* @return {Number} top The absolute top position of this element
|
||||
* in the browser page.
|
||||
*/
|
||||
jsoneditor.util.getAbsoluteTop = function (elem) {
|
||||
util.getAbsoluteTop = function (elem) {
|
||||
var top = elem.offsetTop;
|
||||
var body = document.body;
|
||||
var e = elem.offsetParent;
|
||||
|
@ -144,7 +153,7 @@ jsoneditor.util.getAbsoluteTop = function (elem) {
|
|||
* @param {Event} event
|
||||
* @return {Number} mouseY
|
||||
*/
|
||||
jsoneditor.util.getMouseY = function (event) {
|
||||
util.getMouseY = function (event) {
|
||||
var mouseY;
|
||||
if ('pageY' in event) {
|
||||
mouseY = event.pageY;
|
||||
|
@ -162,7 +171,7 @@ jsoneditor.util.getMouseY = function (event) {
|
|||
* @param {Event} event
|
||||
* @return {Number} mouseX
|
||||
*/
|
||||
jsoneditor.util.getMouseX = function (event) {
|
||||
util.getMouseX = function (event) {
|
||||
var mouseX;
|
||||
if ('pageX' in event) {
|
||||
mouseX = event.pageX;
|
||||
|
@ -179,7 +188,7 @@ jsoneditor.util.getMouseX = function (event) {
|
|||
* Get the window height
|
||||
* @return {Number} windowHeight
|
||||
*/
|
||||
jsoneditor.util.getWindowHeight = function () {
|
||||
util.getWindowHeight = function () {
|
||||
if ('innerHeight' in window) {
|
||||
return window.innerHeight;
|
||||
}
|
||||
|
@ -195,7 +204,7 @@ jsoneditor.util.getWindowHeight = function () {
|
|||
* @param {Element} elem
|
||||
* @param {String} className
|
||||
*/
|
||||
jsoneditor.util.addClassName = function(elem, className) {
|
||||
util.addClassName = function(elem, className) {
|
||||
var classes = elem.className.split(' ');
|
||||
if (classes.indexOf(className) == -1) {
|
||||
classes.push(className); // add the class to the array
|
||||
|
@ -208,7 +217,7 @@ jsoneditor.util.addClassName = function(elem, className) {
|
|||
* @param {Element} elem
|
||||
* @param {String} className
|
||||
*/
|
||||
jsoneditor.util.removeClassName = function(elem, className) {
|
||||
util.removeClassName = function(elem, className) {
|
||||
var classes = elem.className.split(' ');
|
||||
var index = classes.indexOf(className);
|
||||
if (index != -1) {
|
||||
|
@ -222,7 +231,7 @@ jsoneditor.util.removeClassName = function(elem, className) {
|
|||
* the formatting from the div itself is not stripped, only from its childs.
|
||||
* @param {Element} divElement
|
||||
*/
|
||||
jsoneditor.util.stripFormatting = function (divElement) {
|
||||
util.stripFormatting = function (divElement) {
|
||||
var childs = divElement.childNodes;
|
||||
for (var i = 0, iMax = childs.length; i < iMax; i++) {
|
||||
var child = childs[i];
|
||||
|
@ -245,7 +254,7 @@ jsoneditor.util.stripFormatting = function (divElement) {
|
|||
}
|
||||
|
||||
// recursively strip childs
|
||||
jsoneditor.util.stripFormatting(child);
|
||||
util.stripFormatting(child);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -256,7 +265,7 @@ jsoneditor.util.stripFormatting = function (divElement) {
|
|||
* http://stackoverflow.com/questions/1125292/how-to-move-cursor-to-end-of-contenteditable-entity
|
||||
* @param {Element} contentEditableElement A content editable div
|
||||
*/
|
||||
jsoneditor.util.setEndOfContentEditable = function (contentEditableElement) {
|
||||
util.setEndOfContentEditable = function (contentEditableElement) {
|
||||
var range, selection;
|
||||
if(document.createRange) {//Firefox, Chrome, Opera, Safari, IE 9+
|
||||
range = document.createRange();//Create a range (a range is a like the selection but invisible)
|
||||
|
@ -279,7 +288,7 @@ jsoneditor.util.setEndOfContentEditable = function (contentEditableElement) {
|
|||
* http://stackoverflow.com/a/3806004/1262753
|
||||
* @param {Element} contentEditableElement A content editable div
|
||||
*/
|
||||
jsoneditor.util.selectContentEditable = function (contentEditableElement) {
|
||||
util.selectContentEditable = function (contentEditableElement) {
|
||||
if (!contentEditableElement || contentEditableElement.nodeName != 'DIV') {
|
||||
return;
|
||||
}
|
||||
|
@ -303,7 +312,7 @@ jsoneditor.util.selectContentEditable = function (contentEditableElement) {
|
|||
* http://stackoverflow.com/questions/4687808/contenteditable-selected-text-save-and-restore
|
||||
* @return {Range | TextRange | null} range
|
||||
*/
|
||||
jsoneditor.util.getSelection = function () {
|
||||
util.getSelection = function () {
|
||||
if (window.getSelection) {
|
||||
var sel = window.getSelection();
|
||||
if (sel.getRangeAt && sel.rangeCount) {
|
||||
|
@ -320,7 +329,7 @@ jsoneditor.util.getSelection = function () {
|
|||
* http://stackoverflow.com/questions/4687808/contenteditable-selected-text-save-and-restore
|
||||
* @param {Range | TextRange | null} range
|
||||
*/
|
||||
jsoneditor.util.setSelection = function (range) {
|
||||
util.setSelection = function (range) {
|
||||
if (range) {
|
||||
if (window.getSelection) {
|
||||
var sel = window.getSelection();
|
||||
|
@ -341,8 +350,8 @@ jsoneditor.util.setSelection = function (range) {
|
|||
* selected text element
|
||||
* Returns null if no text selection is found
|
||||
*/
|
||||
jsoneditor.util.getSelectionOffset = function () {
|
||||
var range = jsoneditor.util.getSelection();
|
||||
util.getSelectionOffset = function () {
|
||||
var range = util.getSelection();
|
||||
|
||||
if (range && 'startOffset' in range && 'endOffset' in range &&
|
||||
range.startContainer && (range.startContainer == range.endContainer)) {
|
||||
|
@ -366,7 +375,7 @@ jsoneditor.util.getSelectionOffset = function () {
|
|||
* {Number} startOffset
|
||||
* {Number} endOffset
|
||||
*/
|
||||
jsoneditor.util.setSelectionOffset = function (params) {
|
||||
util.setSelectionOffset = function (params) {
|
||||
if (document.createRange && window.getSelection) {
|
||||
var selection = window.getSelection();
|
||||
if(selection) {
|
||||
|
@ -376,7 +385,7 @@ jsoneditor.util.setSelectionOffset = function (params) {
|
|||
range.setStart(params.container.firstChild, params.startOffset);
|
||||
range.setEnd(params.container.firstChild, params.endOffset);
|
||||
|
||||
jsoneditor.util.setSelection(range);
|
||||
util.setSelection(range);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -390,7 +399,7 @@ jsoneditor.util.setSelectionOffset = function (params) {
|
|||
* @param {Object} [buffer]
|
||||
* @return {String} innerText
|
||||
*/
|
||||
jsoneditor.util.getInnerText = function (element, buffer) {
|
||||
util.getInnerText = function (element, buffer) {
|
||||
var first = (buffer == undefined);
|
||||
if (first) {
|
||||
buffer = {
|
||||
|
@ -426,7 +435,7 @@ jsoneditor.util.getInnerText = function (element, buffer) {
|
|||
innerText += '\n';
|
||||
buffer.flush();
|
||||
}
|
||||
innerText += jsoneditor.util.getInnerText(child, buffer);
|
||||
innerText += util.getInnerText(child, buffer);
|
||||
buffer.set('\n');
|
||||
}
|
||||
else if (child.nodeName == 'BR') {
|
||||
|
@ -434,14 +443,14 @@ jsoneditor.util.getInnerText = function (element, buffer) {
|
|||
buffer.set('\n');
|
||||
}
|
||||
else {
|
||||
innerText += jsoneditor.util.getInnerText(child, buffer);
|
||||
innerText += util.getInnerText(child, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
return innerText;
|
||||
}
|
||||
else {
|
||||
if (element.nodeName == 'P' && jsoneditor.util.getInternetExplorerVersion() != -1) {
|
||||
if (element.nodeName == 'P' && util.getInternetExplorerVersion() != -1) {
|
||||
// On Internet Explorer, a <p> with hasChildNodes()==false is
|
||||
// rendered with a new line. Note that a <p> with
|
||||
// hasChildNodes()==true is rendered without a new line
|
||||
|
@ -461,7 +470,7 @@ jsoneditor.util.getInnerText = function (element, buffer) {
|
|||
* Source: http://msdn.microsoft.com/en-us/library/ms537509(v=vs.85).aspx
|
||||
* @return {Number} Internet Explorer version, or -1 in case of an other browser
|
||||
*/
|
||||
jsoneditor.util.getInternetExplorerVersion = function() {
|
||||
util.getInternetExplorerVersion = function() {
|
||||
if (_ieVersion == -1) {
|
||||
var rv = -1; // Return value assumes failure.
|
||||
if (navigator.appName == 'Microsoft Internet Explorer')
|
||||
|
@ -495,7 +504,7 @@ var _ieVersion = -1;
|
|||
* @param {boolean} [useCapture] false by default
|
||||
* @return {function} the created event listener
|
||||
*/
|
||||
jsoneditor.util.addEventListener = function (element, action, listener, useCapture) {
|
||||
util.addEventListener = function (element, action, listener, useCapture) {
|
||||
if (element.addEventListener) {
|
||||
if (useCapture === undefined)
|
||||
useCapture = false;
|
||||
|
@ -523,7 +532,7 @@ jsoneditor.util.addEventListener = function (element, action, listener, useCaptu
|
|||
* @param {function} listener The listener function
|
||||
* @param {boolean} [useCapture] false by default
|
||||
*/
|
||||
jsoneditor.util.removeEventListener = function(element, action, listener, useCapture) {
|
||||
util.removeEventListener = function(element, action, listener, useCapture) {
|
||||
if (element.removeEventListener) {
|
||||
// non-IE browsers
|
||||
if (useCapture === undefined)
|
||||
|
@ -545,7 +554,7 @@ jsoneditor.util.removeEventListener = function(element, action, listener, useCap
|
|||
* Stop event propagation
|
||||
* @param {Event} event
|
||||
*/
|
||||
jsoneditor.util.stopPropagation = function (event) {
|
||||
util.stopPropagation = function (event) {
|
||||
if (!event) {
|
||||
event = window.event;
|
||||
}
|
||||
|
@ -563,7 +572,7 @@ jsoneditor.util.stopPropagation = function (event) {
|
|||
* Cancels the event if it is cancelable, without stopping further propagation of the event.
|
||||
* @param {Event} event
|
||||
*/
|
||||
jsoneditor.util.preventDefault = function (event) {
|
||||
util.preventDefault = function (event) {
|
||||
if (!event) {
|
||||
event = window.event;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue