diff --git a/HISTORY.md b/HISTORY.md index 1fb8337..3fa3894 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -3,6 +3,11 @@ https://github.com/josdejong/jsoneditor +## not yet released, version 5.7.0 + +- Implemented support for template items. Thanks @israelito3000. + + ## 2017-04-15, version 5.6.0 - Implemented readonly option for modes `text` and `code.` diff --git a/examples/10_templates.html b/examples/10_templates.html new file mode 100644 index 0000000..3e45f90 --- /dev/null +++ b/examples/10_templates.html @@ -0,0 +1,69 @@ + + + + JSONEditor | Item templates + + + + + + + +

Item templates

+

+ Using item templates, the options in the context menu under "insert" and "append" can be extended with extra options, containing a domain specific template like a "Person", "Contact", "Order", "Address", etc. +

+ +
+ + + + diff --git a/src/js/ContextMenu.js b/src/js/ContextMenu.js index 216a1bc..6bb1b1f 100644 --- a/src/js/ContextMenu.js +++ b/src/js/ContextMenu.js @@ -321,7 +321,11 @@ ContextMenu.prototype._onExpandItem = function (domItem) { var height = ul.clientHeight; // force a reflow in Firefox setTimeout(function () { if (me.expandedItem == domItem) { - ul.style.height = (ul.childNodes.length * 24) + 'px'; + var childsHeight = 0; + for (var i = 0; i < ul.childNodes.length; i++) { + childsHeight += ul.childNodes[i].clientHeight; + } + ul.style.height = childsHeight + 'px'; ul.style.padding = '5px 10px'; } }, 0); diff --git a/src/js/JSONEditor.js b/src/js/JSONEditor.js index 7420d49..fd2c2c3 100644 --- a/src/js/JSONEditor.js +++ b/src/js/JSONEditor.js @@ -80,7 +80,7 @@ function JSONEditor (container, options, json) { if (options) { var VALID_OPTIONS = [ 'ace', 'theme', - 'ajv', 'schema', + 'ajv', 'schema','templates', 'onChange', 'onEditable', 'onError', 'onModeChange', 'escapeUnicode', 'history', 'search', 'mode', 'modes', 'name', 'indentation', 'sortObjectKeys' ]; @@ -288,11 +288,11 @@ JSONEditor.prototype.setSchema = function (schema) { } if (ajv) { - this.validateSchema = ajv.compile(schema); + this.validateSchema = ajv.compile(schema); - // add schema to the options, so that when switching to an other mode, - // the set schema is not lost - this.options.schema = schema; + // add schema to the options, so that when switching to an other mode, + // the set schema is not lost + this.options.schema = schema; // validate now this.validate(); diff --git a/src/js/Node.js b/src/js/Node.js index beb5565..b762a5b 100644 --- a/src/js/Node.js +++ b/src/js/Node.js @@ -3175,6 +3175,32 @@ Node.TYPE_TITLES = { 'but always returned as string.' }; +Node.prototype.addTemplates = function (menu, append) { + var node = this; + var templates = node.editor.options.templates; + if (templates == null) return; + if (templates.length) { + // create a separator + menu.push({ + 'type': 'separator' + }); + } + var appendData = function (name, data) { + node._onAppend(name, data); + }; + var insertData = function (name, data) { + node._onInsertBefore(name, data); + }; + templates.forEach(function (template) { + menu.push({ + text: template.menu, + className: (template.class || 'jsoneditor-type-object'), + title: template.menu, + click: (append ? appendData.bind(this, template.name, template.data) : insertData.bind(this, template.name, template.data)) + }); + }); +}; + /** * Show a contextmenu for this node * @param {HTMLElement} anchor Anchor element to attach the context menu to @@ -3274,52 +3300,91 @@ Node.prototype.showContextMenu = function (anchor, onClose) { // create append button (for last child node only) var childs = node.parent.childs; if (node == childs[childs.length - 1]) { - items.push({ - text: 'Append', - title: 'Append a new field with type \'auto\' after this field (Ctrl+Shift+Ins)', - submenuTitle: 'Select the type of the field to be appended', - className: 'jsoneditor-append', - click: function () { - node._onAppend('', '', 'auto'); - }, - submenu: [ - { + var appendSubmenu = [ + { + text: 'Auto', + className: 'jsoneditor-type-auto', + title: titles.auto, + click: function () { + node._onAppend('', '', 'auto'); + } + }, + { + text: 'Array', + className: 'jsoneditor-type-array', + title: titles.array, + click: function () { + node._onAppend('', []); + } + }, + { + text: 'Object', + className: 'jsoneditor-type-object', + title: titles.object, + click: function () { + node._onAppend('', {}); + } + }, + { + text: 'String', + className: 'jsoneditor-type-string', + title: titles.string, + click: function () { + node._onAppend('', '', 'string'); + } + } + ]; + node.addTemplates(appendSubmenu, true); + items.push({ + text: 'Append', + title: 'Append a new field with type \'auto\' after this field (Ctrl+Shift+Ins)', + submenuTitle: 'Select the type of the field to be appended', + className: 'jsoneditor-append', + click: function () { + node._onAppend('', '', 'auto'); + }, + submenu: appendSubmenu + }); + } + + + + // create insert button + var insertSubmenu = [ + { text: 'Auto', className: 'jsoneditor-type-auto', title: titles.auto, click: function () { - node._onAppend('', '', 'auto'); + node._onInsertBefore('', '', 'auto'); } - }, - { + }, + { text: 'Array', className: 'jsoneditor-type-array', title: titles.array, click: function () { - node._onAppend('', []); + node._onInsertBefore('', []); } - }, - { + }, + { text: 'Object', className: 'jsoneditor-type-object', title: titles.object, click: function () { - node._onAppend('', {}); + node._onInsertBefore('', {}); } - }, - { + }, + { text: 'String', className: 'jsoneditor-type-string', title: titles.string, click: function () { - node._onAppend('', '', 'string'); + node._onInsertBefore('', '', 'string'); } - } - ] - }); - } - - // create insert button + } + ]; + node.addTemplates(insertSubmenu, false); items.push({ text: 'Insert', title: 'Insert a new field with type \'auto\' before this field (Ctrl+Ins)', @@ -3328,40 +3393,7 @@ Node.prototype.showContextMenu = function (anchor, onClose) { click: function () { node._onInsertBefore('', '', 'auto'); }, - submenu: [ - { - text: 'Auto', - className: 'jsoneditor-type-auto', - title: titles.auto, - click: function () { - node._onInsertBefore('', '', 'auto'); - } - }, - { - text: 'Array', - className: 'jsoneditor-type-array', - title: titles.array, - click: function () { - node._onInsertBefore('', []); - } - }, - { - text: 'Object', - className: 'jsoneditor-type-object', - title: titles.object, - click: function () { - node._onInsertBefore('', {}); - } - }, - { - text: 'String', - className: 'jsoneditor-type-string', - title: titles.string, - click: function () { - node._onInsertBefore('', '', 'string'); - } - } - ] + submenu: insertSubmenu }); if (this.editable.field) { diff --git a/src/js/appendNodeFactory.js b/src/js/appendNodeFactory.js index 494dcb6..bb900cc 100644 --- a/src/js/appendNodeFactory.js +++ b/src/js/appendNodeFactory.js @@ -134,50 +134,52 @@ function appendNodeFactory(Node) { AppendNode.prototype.showContextMenu = function (anchor, onClose) { var node = this; var titles = Node.TYPE_TITLES; + var appendSubmenu = [ + { + text: 'Auto', + className: 'jsoneditor-type-auto', + title: titles.auto, + click: function () { + node._onAppend('', '', 'auto'); + } + }, + { + text: 'Array', + className: 'jsoneditor-type-array', + title: titles.array, + click: function () { + node._onAppend('', []); + } + }, + { + text: 'Object', + className: 'jsoneditor-type-object', + title: titles.object, + click: function () { + node._onAppend('', {}); + } + }, + { + text: 'String', + className: 'jsoneditor-type-string', + title: titles.string, + click: function () { + node._onAppend('', '', 'string'); + } + } + ]; + node.addTemplates(appendSubmenu, true); var items = [ // create append button { - 'text': 'Append', + 'text': 'Append!', 'title': 'Append a new field with type \'auto\' (Ctrl+Shift+Ins)', 'submenuTitle': 'Select the type of the field to be appended', 'className': 'jsoneditor-insert', 'click': function () { node._onAppend('', '', 'auto'); }, - 'submenu': [ - { - 'text': 'Auto', - 'className': 'jsoneditor-type-auto', - 'title': titles.auto, - 'click': function () { - node._onAppend('', '', 'auto'); - } - }, - { - 'text': 'Array', - 'className': 'jsoneditor-type-array', - 'title': titles.array, - 'click': function () { - node._onAppend('', []); - } - }, - { - 'text': 'Object', - 'className': 'jsoneditor-type-object', - 'title': titles.object, - 'click': function () { - node._onAppend('', {}); - } - }, - { - 'text': 'String', - 'className': 'jsoneditor-type-string', - 'title': titles.string, - 'click': function () { - node._onAppend('', '', 'string'); - } - } - ] + 'submenu': appendSubmenu } ];