Implemented setting editable/readonly nodes individually via config function `editable`

This commit is contained in:
jos 2014-07-27 15:46:42 +02:00
parent c72ea9b6e1
commit 1133024ae7
8 changed files with 450 additions and 286 deletions

View File

@ -1,6 +1,7 @@
# JSON Editor
https://github.com/josdejong/jsoneditor
http://jsoneditoronline.org/
Website: http://jsoneditoronline.org/
Github: https://github.com/josdejong/jsoneditor
### Description

View File

@ -0,0 +1,56 @@
<!DOCTYPE HTML>
<html>
<head>
<title>JSONEditor | Basic usage</title>
<link rel="stylesheet" type="text/css" href="../jsoneditor.css">
<script type="text/javascript" src="../jsoneditor.js"></script>
<style type="text/css">
#jsoneditor {
width: 500px;
}
</style>
</head>
<body>
<p>
In this example:
</p>
<ul>
<li>the field <code>_id</code> and its value are read-only</li>
<li>the field <code>name</code> is read-only but has an editable value</li>
<li>the field <code>age</code> and its value are editable</li>
</ul>
<div id="jsoneditor"></div>
<script type="text/javascript" >
var container = document.getElementById('jsoneditor');
var options = {
editable: function (node) {
// node is an object {field: 'FIELD'}
switch (node.field) {
case '_id':
return false;
case 'name':
return {
field: false,
value: true
};
default:
return true;
}
}
};
var json = {
_id: 123456,
name: 'John',
age: 32
};
var editor = new JSONEditor(container, options, json);
</script>
</body>
</html>

View File

@ -24,7 +24,7 @@
*
* @author Jos de Jong, <wjosdejong@gmail.com>
* @version 3.1.0-SNAPSHOT
* @date 2014-07-26
* @date 2014-07-27
*/
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
@ -348,7 +348,7 @@ return /******/ (function(modules) { // webpackBootstrap
/* 1 */
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(4), __webpack_require__(5), __webpack_require__(6), __webpack_require__(7), __webpack_require__(8), __webpack_require__(3)], __WEBPACK_AMD_DEFINE_RESULT__ = (function (Highlighter, History, SearchBox, Node, modeswitcher, util) {
var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(5), __webpack_require__(6), __webpack_require__(7), __webpack_require__(8), __webpack_require__(4), __webpack_require__(3)], __WEBPACK_AMD_DEFINE_RESULT__ = (function (Highlighter, History, SearchBox, Node, modeswitcher, util) {
// create a mixin with the functions for tree mode
var treemode = {};
@ -1074,7 +1074,7 @@ return /******/ (function(modules) { // webpackBootstrap
/* 2 */
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(8), __webpack_require__(3)], __WEBPACK_AMD_DEFINE_RESULT__ = (function (modeswitcher, util) {
var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(4), __webpack_require__(3)], __WEBPACK_AMD_DEFINE_RESULT__ = (function (modeswitcher, util) {
// create a mixin with the functions for text mode
var textmode = {};
@ -1871,6 +1871,115 @@ return /******/ (function(modules) { // webpackBootstrap
/***/ },
/* 4 */
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(9)], __WEBPACK_AMD_DEFINE_RESULT__ = (function (ContextMenu) {
/**
* Create a select box to be used in the editor menu's, which allows to switch mode
* @param {Object} editor
* @param {String[]} modes Available modes: 'code', 'form', 'text', 'tree', 'view'
* @param {String} current Available modes: 'code', 'form', 'text', 'tree', 'view'
* @returns {HTMLElement} box
*/
function createModeSwitcher(editor, modes, current) {
// TODO: decouple mode switcher from editor
/**
* Switch the mode of the editor
* @param {String} mode
*/
function switchMode(mode) {
// switch mode
editor.setMode(mode);
// restore focus on mode box
var modeBox = editor.dom && editor.dom.modeBox;
if (modeBox) {
modeBox.focus();
}
}
// available modes
var availableModes = {
code: {
'text': 'Code',
'title': 'Switch to code highlighter',
'click': function () {
switchMode('code')
}
},
form: {
'text': 'Form',
'title': 'Switch to form editor',
'click': function () {
switchMode('form');
}
},
text: {
'text': 'Text',
'title': 'Switch to plain text editor',
'click': function () {
switchMode('text');
}
},
tree: {
'text': 'Tree',
'title': 'Switch to tree editor',
'click': function () {
switchMode('tree');
}
},
view: {
'text': 'View',
'title': 'Switch to tree view',
'click': function () {
switchMode('view');
}
}
};
// list the selected modes
var items = [];
for (var i = 0; i < modes.length; i++) {
var mode = modes[i];
var item = availableModes[mode];
if (!item) {
throw new Error('Unknown mode "' + mode + '"');
}
item.className = 'type-modes' + ((current == mode) ? ' selected' : '');
items.push(item);
}
// retrieve the title of current mode
var currentMode = availableModes[current];
if (!currentMode) {
throw new Error('Unknown mode "' + current + '"');
}
var currentTitle = currentMode.text;
// create the html element
var box = document.createElement('button');
box.className = 'modes separator';
box.innerHTML = currentTitle + ' &#x25BE;';
box.title = 'Switch editor mode';
box.onclick = function () {
var menu = new ContextMenu(items);
menu.show(box);
};
return box;
}
return {
create: createModeSwitcher
}
}.apply(null, __WEBPACK_AMD_DEFINE_ARRAY__)), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
/***/ },
/* 5 */
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_RESULT__ = (function () {
@ -1962,7 +2071,7 @@ return /******/ (function(modules) { // webpackBootstrap
}.call(exports, __webpack_require__, exports, module)), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
/***/ },
/* 5 */
/* 6 */
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(3)], __WEBPACK_AMD_DEFINE_RESULT__ = (function (util) {
@ -2191,7 +2300,7 @@ return /******/ (function(modules) { // webpackBootstrap
/***/ },
/* 6 */
/* 7 */
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_RESULT__ = (function () {
@ -2490,7 +2599,7 @@ return /******/ (function(modules) { // webpackBootstrap
/***/ },
/* 7 */
/* 8 */
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(9), __webpack_require__(10), __webpack_require__(3)], __WEBPACK_AMD_DEFINE_RESULT__ = (function (ContextMenu, appendNodeFactory, util) {
@ -2520,8 +2629,42 @@ return /******/ (function(modules) { // webpackBootstrap
this.setField('');
this.setValue(null);
}
this._setEditability(editor);
}
/**
* Determine whether the field and/or value of this node are editable
* @param editor
* @private
*/
Node.prototype._setEditability = function (editor) {
this.editable = {
field: true,
value: true
};
if (editor) {
this.editable.field = (this.editor.options.mode != 'view' && this.editor.options.mode != 'form');
this.editable.value = (this.editor.options.mode != 'view');
if (typeof editor.options.editable === 'function') {
var editable = editor.options.editable({
field: this.field
});
if (typeof editable === 'boolean') {
this.editable.field = editable;
this.editable.value = editable;
}
else {
if (typeof editable.field === 'boolean') this.editable.field = editable.field;
if (typeof editable.value === 'boolean') this.editable.value = editable.value;
}
}
}
};
/**
* Set parent node
* @param {Node} parent
@ -3472,7 +3615,7 @@ return /******/ (function(modules) { // webpackBootstrap
var t = (this.type == 'auto') ? util.type(v) : this.type;
var isUrl = (t == 'string' && util.isUrl(v));
var color = '';
if (isUrl && !this.editor.mode.edit) {
if (isUrl && !this.editable.value) { // TODO: when to apply this?
color = '';
}
else if (t == 'string') {
@ -3519,7 +3662,7 @@ return /******/ (function(modules) { // webpackBootstrap
domValue.title = this.type + ' containing ' + count + ' items';
}
else if (t == 'string' && util.isUrl(v)) {
if (this.editor.mode.edit) {
if (this.editable.value) {
domValue.title = 'Ctrl+Click or Ctrl+Enter to open url in new window';
}
}
@ -3647,15 +3790,17 @@ return /******/ (function(modules) { // webpackBootstrap
dom.tr = document.createElement('tr');
dom.tr.node = this;
if (this.editor.mode.edit) {
// create draggable area
if (this.editor.options.mode != 'view' && this.editor.options.mode != 'form') {
var tdDrag = document.createElement('td');
if (this.parent) {
var domDrag = document.createElement('button');
dom.drag = domDrag;
domDrag.className = 'dragarea';
domDrag.title = 'Drag to move this field (Alt+Shift+Arrows)';
tdDrag.appendChild(domDrag);
if (this.editable.field) {
// create draggable area
if (this.parent) {
var domDrag = document.createElement('button');
dom.drag = domDrag;
domDrag.className = 'dragarea';
domDrag.title = 'Drag to move this field (Alt+Shift+Arrows)';
tdDrag.appendChild(domDrag);
}
}
dom.tr.appendChild(tdDrag);
@ -3980,9 +4125,9 @@ return /******/ (function(modules) { // webpackBootstrap
// update field
var domField = this.dom.field;
if (domField) {
if (this.fieldEditable == true) {
if (this.fieldEditable) {
// parent is an object
domField.contentEditable = this.editor.mode.edit;
domField.contentEditable = this.editable.field;
domField.spellcheck = false;
domField.className = 'field';
}
@ -4098,7 +4243,7 @@ return /******/ (function(modules) { // webpackBootstrap
domValue.innerHTML = '{...}';
}
else {
if (!this.editor.mode.edit && util.isUrl(this.value)) {
if (!this.editable.value && util.isUrl(this.value)) {
// create a link in case of read-only editor and value containing an url
domValue = document.createElement('a');
domValue.className = 'value';
@ -4107,9 +4252,9 @@ return /******/ (function(modules) { // webpackBootstrap
domValue.innerHTML = this._escapeHTML(this.value);
}
else {
// create and editable or read-only div
// create an editable or read-only div
domValue = document.createElement('div');
domValue.contentEditable = !this.editor.mode.view;
domValue.contentEditable = this.editable.value;
domValue.spellcheck = false;
domValue.className = 'value';
domValue.innerHTML = this._escapeHTML(this.value);
@ -4272,7 +4417,7 @@ return /******/ (function(modules) { // webpackBootstrap
break;
case 'click':
if (event.ctrlKey && this.editor.mode.edit) {
if (event.ctrlKey || !this.editable.value) {
if (util.isUrl(this.value)) {
window.open(this.value, '_blank');
}
@ -4394,7 +4539,7 @@ return /******/ (function(modules) { // webpackBootstrap
// util.log(ctrlKey, keynum, event.charCode); // TODO: cleanup
if (keynum == 13) { // Enter
if (target == this.dom.value) {
if (!this.editor.mode.edit || event.ctrlKey) {
if (!this.editable.value || event.ctrlKey) {
if (util.isUrl(this.value)) {
window.open(this.value, '_blank');
handled = true;
@ -5032,49 +5177,51 @@ return /******/ (function(modules) { // webpackBootstrap
var titles = Node.TYPE_TITLES;
var items = [];
items.push({
'text': 'Type',
'title': 'Change the type of this field',
'className': 'type-' + this.type,
'submenu': [
{
'text': 'Auto',
'className': 'type-auto' +
(this.type == 'auto' ? ' selected' : ''),
'title': titles.auto,
'click': function () {
node._onChangeType('auto');
if (this.editable.value) {
items.push({
'text': 'Type',
'title': 'Change the type of this field',
'className': 'type-' + this.type,
'submenu': [
{
'text': 'Auto',
'className': 'type-auto' +
(this.type == 'auto' ? ' selected' : ''),
'title': titles.auto,
'click': function () {
node._onChangeType('auto');
}
},
{
'text': 'Array',
'className': 'type-array' +
(this.type == 'array' ? ' selected' : ''),
'title': titles.array,
'click': function () {
node._onChangeType('array');
}
},
{
'text': 'Object',
'className': 'type-object' +
(this.type == 'object' ? ' selected' : ''),
'title': titles.object,
'click': function () {
node._onChangeType('object');
}
},
{
'text': 'String',
'className': 'type-string' +
(this.type == 'string' ? ' selected' : ''),
'title': titles.string,
'click': function () {
node._onChangeType('string');
}
}
},
{
'text': 'Array',
'className': 'type-array' +
(this.type == 'array' ? ' selected' : ''),
'title': titles.array,
'click': function () {
node._onChangeType('array');
}
},
{
'text': 'Object',
'className': 'type-object' +
(this.type == 'object' ? ' selected' : ''),
'title': titles.object,
'click': function () {
node._onChangeType('object');
}
},
{
'text': 'String',
'className': 'type-string' +
(this.type == 'string' ? ' selected' : ''),
'title': titles.string,
'click': function () {
node._onChangeType('string');
}
}
]
});
]
});
}
if (this._hasChilds()) {
var direction = ((this.sort == 'asc') ? 'desc': 'asc');
@ -5107,10 +5254,12 @@ return /******/ (function(modules) { // webpackBootstrap
}
if (this.parent && this.parent._hasChilds()) {
// create a separator
items.push({
'type': 'separator'
});
if (items.length) {
// create a separator
items.push({
'type': 'separator'
});
}
// create append button (for last child node only)
var childs = node.parent.childs;
@ -5205,25 +5354,27 @@ return /******/ (function(modules) { // webpackBootstrap
]
});
// create duplicate button
items.push({
'text': 'Duplicate',
'title': 'Duplicate this field (Ctrl+D)',
'className': 'duplicate',
'click': function () {
node._onDuplicate();
}
});
if (this.editable.field) {
// create duplicate button
items.push({
'text': 'Duplicate',
'title': 'Duplicate this field (Ctrl+D)',
'className': 'duplicate',
'click': function () {
node._onDuplicate();
}
});
// create remove button
items.push({
'text': 'Remove',
'title': 'Remove this field (Ctrl+Del)',
'className': 'remove',
'click': function () {
node._onRemove();
}
});
// create remove button
items.push({
'text': 'Remove',
'title': 'Remove this field (Ctrl+Del)',
'className': 'remove',
'click': function () {
node._onRemove();
}
});
}
}
var menu = new ContextMenu(items, {close: onClose});
@ -5361,115 +5512,6 @@ return /******/ (function(modules) { // webpackBootstrap
return Node;
}.apply(null, __WEBPACK_AMD_DEFINE_ARRAY__)), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
/***/ },
/* 8 */
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(9)], __WEBPACK_AMD_DEFINE_RESULT__ = (function (ContextMenu) {
/**
* Create a select box to be used in the editor menu's, which allows to switch mode
* @param {Object} editor
* @param {String[]} modes Available modes: 'code', 'form', 'text', 'tree', 'view'
* @param {String} current Available modes: 'code', 'form', 'text', 'tree', 'view'
* @returns {HTMLElement} box
*/
function createModeSwitcher(editor, modes, current) {
// TODO: decouple mode switcher from editor
/**
* Switch the mode of the editor
* @param {String} mode
*/
function switchMode(mode) {
// switch mode
editor.setMode(mode);
// restore focus on mode box
var modeBox = editor.dom && editor.dom.modeBox;
if (modeBox) {
modeBox.focus();
}
}
// available modes
var availableModes = {
code: {
'text': 'Code',
'title': 'Switch to code highlighter',
'click': function () {
switchMode('code')
}
},
form: {
'text': 'Form',
'title': 'Switch to form editor',
'click': function () {
switchMode('form');
}
},
text: {
'text': 'Text',
'title': 'Switch to plain text editor',
'click': function () {
switchMode('text');
}
},
tree: {
'text': 'Tree',
'title': 'Switch to tree editor',
'click': function () {
switchMode('tree');
}
},
view: {
'text': 'View',
'title': 'Switch to tree view',
'click': function () {
switchMode('view');
}
}
};
// list the selected modes
var items = [];
for (var i = 0; i < modes.length; i++) {
var mode = modes[i];
var item = availableModes[mode];
if (!item) {
throw new Error('Unknown mode "' + mode + '"');
}
item.className = 'type-modes' + ((current == mode) ? ' selected' : '');
items.push(item);
}
// retrieve the title of current mode
var currentMode = availableModes[current];
if (!currentMode) {
throw new Error('Unknown mode "' + current + '"');
}
var currentTitle = currentMode.text;
// create the html element
var box = document.createElement('button');
box.className = 'modes separator';
box.innerHTML = currentTitle + ' &#x25BE;';
box.title = 'Switch editor mode';
box.onclick = function () {
var menu = new ContextMenu(items);
menu.show(box);
};
return box;
}
return {
create: createModeSwitcher
}
}.apply(null, __WEBPACK_AMD_DEFINE_ARRAY__)), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
/***/ },
/* 9 */
/***/ function(module, exports, __webpack_require__) {
@ -5942,6 +5984,8 @@ return /******/ (function(modules) { // webpackBootstrap
/** @type {TreeEditor} */
this.editor = editor;
this.dom = {};
this._setEditability(editor);
}
AppendNode.prototype = new Node();
@ -5965,7 +6009,7 @@ return /******/ (function(modules) { // webpackBootstrap
// TODO: consistent naming
if (this.editor.mode.edit) {
if (this.editable.field) {
// a cell for the dragarea column
dom.tdDrag = document.createElement('td');

File diff suppressed because one or more lines are too long

6
jsoneditor.min.js vendored

File diff suppressed because one or more lines are too long

View File

@ -25,8 +25,42 @@ define(['./ContextMenu', './appendNodeFactory', './util'], function (ContextMenu
this.setField('');
this.setValue(null);
}
this._setEditability(editor);
}
/**
* Determine whether the field and/or value of this node are editable
* @param editor
* @private
*/
Node.prototype._setEditability = function (editor) {
this.editable = {
field: true,
value: true
};
if (editor) {
this.editable.field = (this.editor.options.mode != 'view' && this.editor.options.mode != 'form');
this.editable.value = (this.editor.options.mode != 'view');
if (typeof editor.options.editable === 'function') {
var editable = editor.options.editable({
field: this.field
});
if (typeof editable === 'boolean') {
this.editable.field = editable;
this.editable.value = editable;
}
else {
if (typeof editable.field === 'boolean') this.editable.field = editable.field;
if (typeof editable.value === 'boolean') this.editable.value = editable.value;
}
}
}
};
/**
* Set parent node
* @param {Node} parent
@ -977,7 +1011,7 @@ define(['./ContextMenu', './appendNodeFactory', './util'], function (ContextMenu
var t = (this.type == 'auto') ? util.type(v) : this.type;
var isUrl = (t == 'string' && util.isUrl(v));
var color = '';
if (isUrl && !this.editor.mode.edit) {
if (isUrl && !this.editable.value) { // TODO: when to apply this?
color = '';
}
else if (t == 'string') {
@ -1024,7 +1058,7 @@ define(['./ContextMenu', './appendNodeFactory', './util'], function (ContextMenu
domValue.title = this.type + ' containing ' + count + ' items';
}
else if (t == 'string' && util.isUrl(v)) {
if (this.editor.mode.edit) {
if (this.editable.value) {
domValue.title = 'Ctrl+Click or Ctrl+Enter to open url in new window';
}
}
@ -1152,15 +1186,17 @@ define(['./ContextMenu', './appendNodeFactory', './util'], function (ContextMenu
dom.tr = document.createElement('tr');
dom.tr.node = this;
if (this.editor.mode.edit) {
// create draggable area
if (this.editor.options.mode != 'view' && this.editor.options.mode != 'form') {
var tdDrag = document.createElement('td');
if (this.parent) {
var domDrag = document.createElement('button');
dom.drag = domDrag;
domDrag.className = 'dragarea';
domDrag.title = 'Drag to move this field (Alt+Shift+Arrows)';
tdDrag.appendChild(domDrag);
if (this.editable.field) {
// create draggable area
if (this.parent) {
var domDrag = document.createElement('button');
dom.drag = domDrag;
domDrag.className = 'dragarea';
domDrag.title = 'Drag to move this field (Alt+Shift+Arrows)';
tdDrag.appendChild(domDrag);
}
}
dom.tr.appendChild(tdDrag);
@ -1485,9 +1521,9 @@ define(['./ContextMenu', './appendNodeFactory', './util'], function (ContextMenu
// update field
var domField = this.dom.field;
if (domField) {
if (this.fieldEditable == true) {
if (this.fieldEditable) {
// parent is an object
domField.contentEditable = this.editor.mode.edit;
domField.contentEditable = this.editable.field;
domField.spellcheck = false;
domField.className = 'field';
}
@ -1603,7 +1639,7 @@ define(['./ContextMenu', './appendNodeFactory', './util'], function (ContextMenu
domValue.innerHTML = '{...}';
}
else {
if (!this.editor.mode.edit && util.isUrl(this.value)) {
if (!this.editable.value && util.isUrl(this.value)) {
// create a link in case of read-only editor and value containing an url
domValue = document.createElement('a');
domValue.className = 'value';
@ -1612,9 +1648,9 @@ define(['./ContextMenu', './appendNodeFactory', './util'], function (ContextMenu
domValue.innerHTML = this._escapeHTML(this.value);
}
else {
// create and editable or read-only div
// create an editable or read-only div
domValue = document.createElement('div');
domValue.contentEditable = !this.editor.mode.view;
domValue.contentEditable = this.editable.value;
domValue.spellcheck = false;
domValue.className = 'value';
domValue.innerHTML = this._escapeHTML(this.value);
@ -1777,7 +1813,7 @@ define(['./ContextMenu', './appendNodeFactory', './util'], function (ContextMenu
break;
case 'click':
if (event.ctrlKey && this.editor.mode.edit) {
if (event.ctrlKey || !this.editable.value) {
if (util.isUrl(this.value)) {
window.open(this.value, '_blank');
}
@ -1899,7 +1935,7 @@ define(['./ContextMenu', './appendNodeFactory', './util'], function (ContextMenu
// util.log(ctrlKey, keynum, event.charCode); // TODO: cleanup
if (keynum == 13) { // Enter
if (target == this.dom.value) {
if (!this.editor.mode.edit || event.ctrlKey) {
if (!this.editable.value || event.ctrlKey) {
if (util.isUrl(this.value)) {
window.open(this.value, '_blank');
handled = true;
@ -2537,49 +2573,51 @@ define(['./ContextMenu', './appendNodeFactory', './util'], function (ContextMenu
var titles = Node.TYPE_TITLES;
var items = [];
items.push({
'text': 'Type',
'title': 'Change the type of this field',
'className': 'type-' + this.type,
'submenu': [
{
'text': 'Auto',
'className': 'type-auto' +
(this.type == 'auto' ? ' selected' : ''),
'title': titles.auto,
'click': function () {
node._onChangeType('auto');
if (this.editable.value) {
items.push({
'text': 'Type',
'title': 'Change the type of this field',
'className': 'type-' + this.type,
'submenu': [
{
'text': 'Auto',
'className': 'type-auto' +
(this.type == 'auto' ? ' selected' : ''),
'title': titles.auto,
'click': function () {
node._onChangeType('auto');
}
},
{
'text': 'Array',
'className': 'type-array' +
(this.type == 'array' ? ' selected' : ''),
'title': titles.array,
'click': function () {
node._onChangeType('array');
}
},
{
'text': 'Object',
'className': 'type-object' +
(this.type == 'object' ? ' selected' : ''),
'title': titles.object,
'click': function () {
node._onChangeType('object');
}
},
{
'text': 'String',
'className': 'type-string' +
(this.type == 'string' ? ' selected' : ''),
'title': titles.string,
'click': function () {
node._onChangeType('string');
}
}
},
{
'text': 'Array',
'className': 'type-array' +
(this.type == 'array' ? ' selected' : ''),
'title': titles.array,
'click': function () {
node._onChangeType('array');
}
},
{
'text': 'Object',
'className': 'type-object' +
(this.type == 'object' ? ' selected' : ''),
'title': titles.object,
'click': function () {
node._onChangeType('object');
}
},
{
'text': 'String',
'className': 'type-string' +
(this.type == 'string' ? ' selected' : ''),
'title': titles.string,
'click': function () {
node._onChangeType('string');
}
}
]
});
]
});
}
if (this._hasChilds()) {
var direction = ((this.sort == 'asc') ? 'desc': 'asc');
@ -2612,10 +2650,12 @@ define(['./ContextMenu', './appendNodeFactory', './util'], function (ContextMenu
}
if (this.parent && this.parent._hasChilds()) {
// create a separator
items.push({
'type': 'separator'
});
if (items.length) {
// create a separator
items.push({
'type': 'separator'
});
}
// create append button (for last child node only)
var childs = node.parent.childs;
@ -2710,25 +2750,27 @@ define(['./ContextMenu', './appendNodeFactory', './util'], function (ContextMenu
]
});
// create duplicate button
items.push({
'text': 'Duplicate',
'title': 'Duplicate this field (Ctrl+D)',
'className': 'duplicate',
'click': function () {
node._onDuplicate();
}
});
if (this.editable.field) {
// create duplicate button
items.push({
'text': 'Duplicate',
'title': 'Duplicate this field (Ctrl+D)',
'className': 'duplicate',
'click': function () {
node._onDuplicate();
}
});
// create remove button
items.push({
'text': 'Remove',
'title': 'Remove this field (Ctrl+Del)',
'className': 'remove',
'click': function () {
node._onRemove();
}
});
// create remove button
items.push({
'text': 'Remove',
'title': 'Remove this field (Ctrl+Del)',
'className': 'remove',
'click': function () {
node._onRemove();
}
});
}
}
var menu = new ContextMenu(items, {close: onClose});

View File

@ -16,6 +16,8 @@ define(['./ContextMenu', './util'], function (ContextMenu, util) {
/** @type {TreeEditor} */
this.editor = editor;
this.dom = {};
this._setEditability(editor);
}
AppendNode.prototype = new Node();
@ -39,7 +41,7 @@ define(['./ContextMenu', './util'], function (ContextMenu, util) {
// TODO: consistent naming
if (this.editor.mode.edit) {
if (this.editable.field) {
// a cell for the dragarea column
dom.tdDrag = document.createElement('td');

View File

@ -68,16 +68,35 @@
modes: ['code', 'form', 'text', 'tree', 'view'], // allowed modes
error: function (err) {
alert(err.toString());
},
editable: function (node) {
console.log(node);
switch(node.field) {
case '_id':
return false;
case '_field':
return {
field: false,
value: true
};
default:
return true;
}
}
};
json = {
"_id": "1234",
"_field": "ABCD",
"array": [1, 2, 3],
"boolean": true,
"null": null,
"number": 123,
"object": {"a": "b", "c": "d"},
"string": "Hello World"
"string": "Hello World",
"url": "http://jsoneditorononline.org"
};
editor = new JSONEditor(container, options, json);