'use strict'; var util = require('./util'); var ContextMenu = require('./ContextMenu'); /** * A factory function to create an AppendNode, which depends on a Node * @param {Node} Node */ function appendNodeFactory(Node) { /** * @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 */ function AppendNode (editor) { /** @type {TreeEditor} */ this.editor = editor; this.dom = {}; } AppendNode.prototype = new Node(); /** * Return a table row with an append button. * @return {Element} dom TR element */ AppendNode.prototype.getDom = function () { // TODO: implement a new solution for the append node var dom = this.dom; if (dom.tr) { return dom.tr; } this._updateEditability(); // a row for the append button var trAppend = document.createElement('tr'); trAppend.node = this; dom.tr = trAppend; // TODO: consistent naming if (this.editor.options.mode === 'tree') { // a cell for the dragarea column dom.tdDrag = document.createElement('td'); // create context menu var tdMenu = document.createElement('td'); dom.tdMenu = tdMenu; var menu = document.createElement('button'); menu.className = 'jsoneditor-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'); var domText = document.createElement('div'); domText.innerHTML = '(empty)'; domText.className = 'jsoneditor-readonly'; tdAppend.appendChild(domText); dom.td = tdAppend; dom.text = domText; this.updateDom(); return trAppend; }; /** * Update the HTML dom of the Node */ AppendNode.prototype.updateDom = function () { var dom = this.dom; var tdAppend = dom.td; if (tdAppend) { tdAppend.style.paddingLeft = (this.getLevel() * 24 + 26) + 'px'; // TODO: not so nice hard coded offset } var domText = dom.text; if (domText) { domText.innerHTML = '(empty ' + this.parent.type + ')'; } // attach or detach the contents of the append node: // hide when the parent has childs, show when the parent has no childs var trAppend = dom.tr; if (!this.isVisible()) { if (dom.tr.firstChild) { if (dom.tdDrag) { trAppend.removeChild(dom.tdDrag); } if (dom.tdMenu) { trAppend.removeChild(dom.tdMenu); } trAppend.removeChild(tdAppend); } } else { if (!dom.tr.firstChild) { if (dom.tdDrag) { trAppend.appendChild(dom.tdDrag); } if (dom.tdMenu) { trAppend.appendChild(dom.tdMenu); } trAppend.appendChild(tdAppend); } } }; /** * Check whether the AppendNode is currently visible. * the AppendNode is visible when its parent has no childs (i.e. is empty). * @return {boolean} isVisible */ AppendNode.prototype.isVisible = function () { return (this.parent.childs.length == 0); }; /** * Show a contextmenu for this node * @param {HTMLElement} anchor The element to attach the menu to. * @param {function} [onClose] Callback method called when the context menu * is being closed. */ AppendNode.prototype.showContextMenu = function (anchor, onClose) { var node = this; var titles = Node.TYPE_TITLES; var items = [ // create append button { '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'); } } ] } ]; var menu = new ContextMenu(items, {close: onClose}); menu.show(anchor, this.editor.content); }; /** * Handle an event. The event is catched centrally by the editor * @param {Event} event */ AppendNode.prototype.onEvent = function (event) { var type = event.type; var target = event.target || event.srcElement; var dom = this.dom; // highlight the append nodes parent var menu = dom.menu; if (target == menu) { if (type == 'mouseover') { this.editor.highlighter.highlight(this.parent); } else if (type == 'mouseout') { this.editor.highlighter.unhighlight(); } } // context menu events if (type == 'click' && target == dom.menu) { var highlighter = this.editor.highlighter; highlighter.highlight(this.parent); highlighter.lock(); util.addClassName(dom.menu, 'jsoneditor-selected'); this.showContextMenu(dom.menu, function () { util.removeClassName(dom.menu, 'jsoneditor-selected'); highlighter.unlock(); highlighter.unhighlight(); }); } if (type == 'keydown') { this.onKeyDown(event); } }; return AppendNode; } module.exports = appendNodeFactory;