jsoneditor
Version:
A web-based tool to view, edit, format, and validate JSON
1,184 lines (1,109 loc) • 731 kB
JavaScript
/*!
* jsoneditor.js
*
* @brief
* JSONEditor is a web-based tool to view, edit, format, and validate JSON.
* It has various modes such as a tree editor, a code editor, and a plain text
* editor.
*
* Supported browsers: Chrome, Firefox, Safari, Opera, Internet Explorer 8+
*
* @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-2023 Jos de Jong, http://jsoneditoronline.org
*
* @author Jos de Jong, <wjosdejong@gmail.com>
* @version 9.10.3
* @date 2023-09-21
*/
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define([], factory);
else if(typeof exports === 'object')
exports["JSONEditor"] = factory();
else
root["JSONEditor"] = factory();
})(self, function() {
return /******/ (function() { // webpackBootstrap
/******/ var __webpack_modules__ = ({
/***/ 897:
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
"use strict";
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ x: function() { return /* binding */ ContextMenu; }
/* harmony export */ });
/* harmony import */ var _createAbsoluteAnchor__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(602);
/* harmony import */ var _util__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(791);
/* harmony import */ var _i18n__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(907);
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); }
function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
/**
* A context menu
* @param {Object[]} items Array containing the menu structure
* TODO: describe structure
* @param {Object} [options] Object with options. Available options:
* {function} close Callback called when the
* context menu is being closed.
* {boolean} limitHeight Whether ContextMenu height should be
* limited or not.
* @constructor
*/
var ContextMenu = /*#__PURE__*/function () {
function ContextMenu(items, options) {
_classCallCheck(this, ContextMenu);
this.dom = {};
var me = this;
var dom = this.dom;
this.anchor = undefined;
this.items = items;
this.eventListeners = {};
this.selection = undefined; // holds the selection before the menu was opened
this.onClose = options ? options.close : undefined;
this.limitHeight = options ? options.limitHeight : false;
// create root element
var root = document.createElement('div');
root.className = 'jsoneditor-contextmenu-root';
dom.root = root;
// create a container element
var menu = document.createElement('div');
menu.className = 'jsoneditor-contextmenu';
dom.menu = menu;
root.appendChild(menu);
// create a list to hold the menu items
var list = document.createElement('ul');
list.className = 'jsoneditor-menu';
menu.appendChild(list);
dom.list = list;
dom.items = []; // list with all buttons
// create a (non-visible) button to set the focus to the menu
var focusButton = document.createElement('button');
focusButton.type = 'button';
dom.focusButton = focusButton;
var li = document.createElement('li');
li.style.overflow = 'hidden';
li.style.height = '0';
li.appendChild(focusButton);
list.appendChild(li);
function createMenuItems(list, domItems, items) {
items.forEach(function (item) {
if (item.type === 'separator') {
// create a separator
var separator = document.createElement('div');
separator.className = 'jsoneditor-separator';
var _li = document.createElement('li');
_li.appendChild(separator);
list.appendChild(_li);
} else {
var domItem = {};
// create a menu item
var _li2 = document.createElement('li');
list.appendChild(_li2);
// create a button in the menu item
var button = document.createElement('button');
button.type = 'button';
button.className = item.className;
domItem.button = button;
if (item.title) {
button.title = item.title;
}
if (item.click) {
button.onclick = function (event) {
event.preventDefault();
me.hide();
item.click();
};
}
_li2.appendChild(button);
// create the contents of the button
if (item.submenu) {
// add the icon to the button
var divIcon = document.createElement('div');
divIcon.className = 'jsoneditor-icon';
button.appendChild(divIcon);
var divText = document.createElement('div');
divText.className = 'jsoneditor-text' + (item.click ? '' : ' jsoneditor-right-margin');
divText.appendChild(document.createTextNode(item.text));
button.appendChild(divText);
var buttonSubmenu;
if (item.click) {
// submenu and a button with a click handler
button.className += ' jsoneditor-default';
var buttonExpand = document.createElement('button');
buttonExpand.type = 'button';
domItem.buttonExpand = buttonExpand;
buttonExpand.className = 'jsoneditor-expand';
var buttonExpandInner = document.createElement('div');
buttonExpandInner.className = 'jsoneditor-expand';
buttonExpand.appendChild(buttonExpandInner);
_li2.appendChild(buttonExpand);
if (item.submenuTitle) {
buttonExpand.title = item.submenuTitle;
}
buttonSubmenu = buttonExpand;
} else {
// submenu and a button without a click handler
var divExpand = document.createElement('div');
divExpand.className = 'jsoneditor-expand';
button.appendChild(divExpand);
buttonSubmenu = button;
}
// attach a handler to expand/collapse the submenu
buttonSubmenu.onclick = function (event) {
event.preventDefault();
me._onExpandItem(domItem);
buttonSubmenu.focus();
};
// create the submenu
var domSubItems = [];
domItem.subItems = domSubItems;
var ul = document.createElement('ul');
domItem.ul = ul;
ul.className = 'jsoneditor-menu';
ul.style.height = '0';
_li2.appendChild(ul);
createMenuItems(ul, domSubItems, item.submenu);
} else {
// no submenu, just a button with clickhandler
var icon = document.createElement('div');
icon.className = 'jsoneditor-icon';
button.appendChild(icon);
var text = document.createElement('div');
text.className = 'jsoneditor-text';
text.appendChild(document.createTextNode((0,_i18n__WEBPACK_IMPORTED_MODULE_2__/* .translate */ .Iu)(item.text)));
button.appendChild(text);
}
domItems.push(domItem);
}
});
}
createMenuItems(list, this.dom.items, items);
// TODO: when the editor is small, show the submenu on the right instead of inline?
// calculate the max height of the menu with one submenu expanded
this.maxHeight = 0; // height in pixels
items.forEach(function (item) {
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
*/
_createClass(ContextMenu, [{
key: "_getVisibleButtons",
value: function _getVisibleButtons() {
var buttons = [];
var me = this;
this.dom.items.forEach(function (item) {
buttons.push(item.button);
if (item.buttonExpand) {
buttons.push(item.buttonExpand);
}
if (item.subItems && item === me.expandedItem) {
item.subItems.forEach(function (subItem) {
buttons.push(subItem.button);
if (subItem.buttonExpand) {
buttons.push(subItem.buttonExpand);
}
// TODO: change to fully recursive method
});
}
});
return buttons;
}
/**
* Attach the menu to an anchor
* @param {HTMLElement} anchor Anchor where the menu will be attached as sibling.
* @param {HTMLElement} frame The root of the JSONEditor window
* @param {Boolean=} ignoreParent ignore anchor parent in regard to the calculation of the position, needed when the parent position is absolute
*/
}, {
key: "show",
value: function show(anchor, frame, ignoreParent) {
this.hide();
// determine whether to display the menu below or above the anchor
var showBelow = true;
var parent = anchor.parentNode;
var anchorRect = anchor.getBoundingClientRect();
var parentRect = parent.getBoundingClientRect();
var frameRect = frame.getBoundingClientRect();
var me = this;
this.dom.absoluteAnchor = (0,_createAbsoluteAnchor__WEBPACK_IMPORTED_MODULE_0__/* .createAbsoluteAnchor */ .w)(anchor, frame, function () {
me.hide();
});
if (anchorRect.bottom + this.maxHeight < frameRect.bottom) {
// fits below -> show below
} else if (anchorRect.top - this.maxHeight > frameRect.top) {
// fits above -> show above
showBelow = false;
} else {
// doesn't fit above nor below -> show below
}
var topGap = ignoreParent ? 0 : anchorRect.top - parentRect.top;
// position the menu
if (showBelow) {
// display the menu below the anchor
var anchorHeight = anchor.offsetHeight;
this.dom.menu.style.left = '0';
this.dom.menu.style.top = topGap + anchorHeight + 'px';
this.dom.menu.style.bottom = '';
} else {
// display the menu above the anchor
this.dom.menu.style.left = '0';
this.dom.menu.style.top = '';
this.dom.menu.style.bottom = '0px';
}
if (this.limitHeight) {
var margin = 10; // make sure there is a little margin left
var maxPossibleMenuHeight = showBelow ? frameRect.bottom - anchorRect.bottom - margin : anchorRect.top - frameRect.top - margin;
this.dom.list.style.maxHeight = maxPossibleMenuHeight + 'px';
this.dom.list.style.overflowY = 'auto';
}
// attach the menu to the temporary, absolute anchor
// parent.insertBefore(this.dom.root, anchor);
this.dom.absoluteAnchor.appendChild(this.dom.root);
// move focus to the first button in the context menu
this.selection = (0,_util__WEBPACK_IMPORTED_MODULE_1__.getSelection)();
this.anchor = anchor;
setTimeout(function () {
me.dom.focusButton.focus();
}, 0);
if (ContextMenu.visibleMenu) {
ContextMenu.visibleMenu.hide();
}
ContextMenu.visibleMenu = this;
}
/**
* Hide the context menu if visible
*/
}, {
key: "hide",
value: function hide() {
// remove temporary absolutely positioned anchor
if (this.dom.absoluteAnchor) {
this.dom.absoluteAnchor.destroy();
delete this.dom.absoluteAnchor;
}
// remove the menu from the DOM
if (this.dom.root.parentNode) {
this.dom.root.parentNode.removeChild(this.dom.root);
if (this.onClose) {
this.onClose();
}
}
if (ContextMenu.visibleMenu === this) {
ContextMenu.visibleMenu = undefined;
}
}
/**
* Expand a submenu
* Any currently expanded submenu will be hided.
* @param {Object} domItem
* @private
*/
}, {
key: "_onExpandItem",
value: function _onExpandItem(domItem) {
var me = this;
var alreadyVisible = domItem === this.expandedItem;
// hide the currently visible submenu
var expandedItem = this.expandedItem;
if (expandedItem) {
// var ul = expandedItem.ul;
expandedItem.ul.style.height = '0';
expandedItem.ul.style.padding = '';
setTimeout(function () {
if (me.expandedItem !== expandedItem) {
expandedItem.ul.style.display = '';
(0,_util__WEBPACK_IMPORTED_MODULE_1__.removeClassName)(expandedItem.ul.parentNode, 'jsoneditor-selected');
}
}, 300); // timeout duration must match the css transition duration
this.expandedItem = undefined;
}
if (!alreadyVisible) {
var ul = domItem.ul;
ul.style.display = 'block';
// eslint-disable-next-line no-unused-expressions
ul.clientHeight; // force a reflow in Firefox
setTimeout(function () {
if (me.expandedItem === domItem) {
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);
(0,_util__WEBPACK_IMPORTED_MODULE_1__.addClassName)(ul.parentNode, 'jsoneditor-selected');
this.expandedItem = domItem;
}
}
/**
* Handle onkeydown event
* @param {Event} event
* @private
*/
}, {
key: "_onKeyDown",
value: function _onKeyDown(event) {
var target = event.target;
var keynum = event.which;
var handled = false;
var buttons, targetIndex, prevButton, nextButton;
if (keynum === 27) {
// ESC
// hide the menu on ESC key
// restore previous selection and focus
if (this.selection) {
(0,_util__WEBPACK_IMPORTED_MODULE_1__.setSelection)(this.selection);
}
if (this.anchor) {
this.anchor.focus();
}
this.hide();
handled = true;
} else if (keynum === 9) {
// Tab
if (!event.shiftKey) {
// Tab
buttons = this._getVisibleButtons();
targetIndex = buttons.indexOf(target);
if (targetIndex === buttons.length - 1) {
// move to first button
buttons[0].focus();
handled = true;
}
} else {
// Shift+Tab
buttons = this._getVisibleButtons();
targetIndex = buttons.indexOf(target);
if (targetIndex === 0) {
// move to last button
buttons[buttons.length - 1].focus();
handled = true;
}
}
} else if (keynum === 37) {
// Arrow Left
if (target.className === 'jsoneditor-expand') {
buttons = this._getVisibleButtons();
targetIndex = buttons.indexOf(target);
prevButton = buttons[targetIndex - 1];
if (prevButton) {
prevButton.focus();
}
}
handled = true;
} else if (keynum === 38) {
// Arrow Up
buttons = this._getVisibleButtons();
targetIndex = buttons.indexOf(target);
prevButton = buttons[targetIndex - 1];
if (prevButton && prevButton.className === 'jsoneditor-expand') {
// skip expand button
prevButton = buttons[targetIndex - 2];
}
if (!prevButton) {
// move to last button
prevButton = buttons[buttons.length - 1];
}
if (prevButton) {
prevButton.focus();
}
handled = true;
} else if (keynum === 39) {
// Arrow Right
buttons = this._getVisibleButtons();
targetIndex = buttons.indexOf(target);
nextButton = buttons[targetIndex + 1];
if (nextButton && nextButton.className === 'jsoneditor-expand') {
nextButton.focus();
}
handled = true;
} else if (keynum === 40) {
// Arrow Down
buttons = this._getVisibleButtons();
targetIndex = buttons.indexOf(target);
nextButton = buttons[targetIndex + 1];
if (nextButton && nextButton.className === 'jsoneditor-expand') {
// skip expand button
nextButton = buttons[targetIndex + 2];
}
if (!nextButton) {
// move to first button
nextButton = buttons[0];
}
if (nextButton) {
nextButton.focus();
handled = true;
}
handled = true;
}
// TODO: arrow left and right
if (handled) {
event.stopPropagation();
event.preventDefault();
}
}
}]);
return ContextMenu;
}();
// currently displayed context menu, a singleton. We may only have one visible context menu
ContextMenu.visibleMenu = undefined;
/***/ }),
/***/ 436:
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
"use strict";
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ Q: function() { return /* binding */ ErrorTable; }
/* harmony export */ });
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); }
function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
/**
* Show errors and schema warnings in a clickable table view
* @param {Object} config
* @property {boolean} errorTableVisible
* @property {function (boolean) : void} onToggleVisibility
* @property {function (number)} [onFocusLine]
* @property {function (number)} onChangeHeight
* @constructor
*/
var ErrorTable = /*#__PURE__*/function () {
function ErrorTable(config) {
_classCallCheck(this, ErrorTable);
this.errorTableVisible = config.errorTableVisible;
this.onToggleVisibility = config.onToggleVisibility;
this.onFocusLine = config.onFocusLine || function () {};
this.onChangeHeight = config.onChangeHeight;
this.dom = {};
var validationErrorsContainer = document.createElement('div');
validationErrorsContainer.className = 'jsoneditor-validation-errors-container';
this.dom.validationErrorsContainer = validationErrorsContainer;
var additionalErrorsIndication = document.createElement('div');
additionalErrorsIndication.style.display = 'none';
additionalErrorsIndication.className = 'jsoneditor-additional-errors fadein';
additionalErrorsIndication.textContent = "Scroll for more \u25BF";
this.dom.additionalErrorsIndication = additionalErrorsIndication;
validationErrorsContainer.appendChild(additionalErrorsIndication);
var validationErrorIcon = document.createElement('span');
validationErrorIcon.className = 'jsoneditor-validation-error-icon';
validationErrorIcon.style.display = 'none';
this.dom.validationErrorIcon = validationErrorIcon;
var validationErrorCount = document.createElement('span');
validationErrorCount.className = 'jsoneditor-validation-error-count';
validationErrorCount.style.display = 'none';
this.dom.validationErrorCount = validationErrorCount;
this.dom.parseErrorIndication = document.createElement('span');
this.dom.parseErrorIndication.className = 'jsoneditor-parse-error-icon';
this.dom.parseErrorIndication.style.display = 'none';
}
_createClass(ErrorTable, [{
key: "getErrorTable",
value: function getErrorTable() {
return this.dom.validationErrorsContainer;
}
}, {
key: "getErrorCounter",
value: function getErrorCounter() {
return this.dom.validationErrorCount;
}
}, {
key: "getWarningIcon",
value: function getWarningIcon() {
return this.dom.validationErrorIcon;
}
}, {
key: "getErrorIcon",
value: function getErrorIcon() {
return this.dom.parseErrorIndication;
}
}, {
key: "toggleTableVisibility",
value: function toggleTableVisibility() {
this.errorTableVisible = !this.errorTableVisible;
this.onToggleVisibility(this.errorTableVisible);
}
}, {
key: "setErrors",
value: function setErrors(errors, errorLocations) {
var _this = this;
// clear any previous errors
if (this.dom.validationErrors) {
this.dom.validationErrors.parentNode.removeChild(this.dom.validationErrors);
this.dom.validationErrors = null;
this.dom.additionalErrorsIndication.style.display = 'none';
}
// create the table with errors
// keep default behavior for parse errors
if (this.errorTableVisible && errors.length > 0) {
var validationErrors = document.createElement('div');
validationErrors.className = 'jsoneditor-validation-errors';
var table = document.createElement('table');
table.className = 'jsoneditor-text-errors';
validationErrors.appendChild(table);
var tbody = document.createElement('tbody');
table.appendChild(tbody);
errors.forEach(function (error) {
var line;
if (!isNaN(error.line)) {
line = error.line;
} else if (error.dataPath) {
var errLoc = errorLocations.find(function (loc) {
return loc.path === error.dataPath;
});
if (errLoc) {
line = errLoc.line + 1;
}
}
var trEl = document.createElement('tr');
trEl.className = !isNaN(line) ? 'jump-to-line' : '';
if (error.type === 'error') {
trEl.className += ' parse-error';
} else {
trEl.className += ' validation-error';
}
var td1 = document.createElement('td');
var button = document.createElement('button');
button.className = 'jsoneditor-schema-error';
td1.appendChild(button);
trEl.appendChild(td1);
var td2 = document.createElement('td');
td2.style = 'white-space: nowrap;';
td2.textContent = !isNaN(line) ? 'Ln ' + line : '';
trEl.appendChild(td2);
if (typeof error === 'string') {
var td34 = document.createElement('td');
td34.colSpan = 2;
var pre = document.createElement('pre');
pre.appendChild(document.createTextNode(error));
td34.appendChild(pre);
trEl.appendChild(td34);
} else {
var td3 = document.createElement('td');
td3.appendChild(document.createTextNode(error.dataPath || ''));
trEl.appendChild(td3);
var td4 = document.createElement('td');
var _pre = document.createElement('pre');
_pre.appendChild(document.createTextNode(error.message.replace(/<br>/gi, '\n')));
td4.appendChild(_pre);
trEl.appendChild(td4);
}
trEl.onclick = function () {
_this.onFocusLine(line);
};
tbody.appendChild(trEl);
});
this.dom.validationErrors = validationErrors;
this.dom.validationErrorsContainer.appendChild(validationErrors);
this.dom.additionalErrorsIndication.title = errors.length + ' errors total';
if (this.dom.validationErrorsContainer.clientHeight < this.dom.validationErrorsContainer.scrollHeight) {
this.dom.additionalErrorsIndication.style.display = 'block';
this.dom.validationErrorsContainer.onscroll = function () {
_this.dom.additionalErrorsIndication.style.display = _this.dom.validationErrorsContainer.clientHeight > 0 && _this.dom.validationErrorsContainer.scrollTop === 0 ? 'block' : 'none';
};
} else {
this.dom.validationErrorsContainer.onscroll = undefined;
}
var height = this.dom.validationErrorsContainer.clientHeight + (this.dom.statusBar ? this.dom.statusBar.clientHeight : 0);
// this.content.style.marginBottom = (-height) + 'px';
// this.content.style.paddingBottom = height + 'px';
this.onChangeHeight(height);
} else {
this.onChangeHeight(0);
}
// update the status bar
var validationErrorsCount = errors.filter(function (error) {
return error.type !== 'error';
}).length;
if (validationErrorsCount > 0) {
this.dom.validationErrorCount.style.display = 'inline';
this.dom.validationErrorCount.innerText = validationErrorsCount;
this.dom.validationErrorCount.onclick = this.toggleTableVisibility.bind(this);
this.dom.validationErrorIcon.style.display = 'inline';
this.dom.validationErrorIcon.title = validationErrorsCount + ' schema validation error(s) found';
this.dom.validationErrorIcon.onclick = this.toggleTableVisibility.bind(this);
} else {
this.dom.validationErrorCount.style.display = 'none';
this.dom.validationErrorIcon.style.display = 'none';
}
// update the parse error icon
var hasParseErrors = errors.some(function (error) {
return error.type === 'error';
});
if (hasParseErrors) {
var line = errors[0].line;
this.dom.parseErrorIndication.style.display = 'block';
this.dom.parseErrorIndication.title = !isNaN(line) ? 'parse error on line ' + line : 'parse error - check that the json is valid';
this.dom.parseErrorIndication.onclick = this.toggleTableVisibility.bind(this);
} else {
this.dom.parseErrorIndication.style.display = 'none';
}
}
}]);
return ErrorTable;
}();
/***/ }),
/***/ 474:
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
"use strict";
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ R: function() { return /* binding */ FocusTracker; }
/* harmony export */ });
/**
* @constructor FocusTracker
* A custom focus tracker for a DOM element with complex internal DOM structure
* @param {[Object]} config A set of configurations for the FocusTracker
* {DOM Object} target * The DOM object to track (required)
* {Function} onFocus onFocus callback
* {Function} onBlur onBlur callback
*
* @return
*/
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); }
function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
var FocusTracker = /*#__PURE__*/function () {
function FocusTracker(config) {
_classCallCheck(this, FocusTracker);
this.target = config.target || null;
if (!this.target) {
throw new Error('FocusTracker constructor called without a "target" to track.');
}
this.onFocus = typeof config.onFocus === 'function' ? config.onFocus : null;
this.onBlur = typeof config.onBlur === 'function' ? config.onBlur : null;
this._onClick = this._onEvent.bind(this);
this._onKeyUp = function (event) {
if (event.which === 9 || event.keyCode === 9) {
this._onEvent(event);
}
}.bind(this);
this._onBlur = this._onEvent.bind(this);
this.focusFlag = false;
this.firstEventFlag = true;
/*
Adds required (click and keyup) event listeners to the 'document' object
to track the focus of the given 'target'
*/
if (this.onFocus || this.onBlur) {
document.addEventListener('click', this._onClick);
document.addEventListener('keyup', this._onKeyUp);
document.addEventListener('blur', this._onBlur);
}
}
/**
* Removes the event listeners on the 'document' object
* that were added to track the focus of the given 'target'
*/
_createClass(FocusTracker, [{
key: "destroy",
value: function destroy() {
document.removeEventListener('click', this._onClick);
document.removeEventListener('keyup', this._onKeyUp);
document.removeEventListener('blur', this._onBlur);
this._onEvent({
target: document.body
}); // calling _onEvent with body element in the hope that the FocusTracker is added to an element inside the body tag
}
/**
* Tracks the focus of the target and calls the onFocus and onBlur
* event callbacks if available.
* @param {Event} [event] The 'click' or 'keyup' event object,
* from the respective events set on
* document object
* @private
*/
}, {
key: "_onEvent",
value: function _onEvent(event) {
var target = event.target;
var focusFlag;
if (target === this.target) {
focusFlag = true;
} else if (this.target.contains(target) || this.target.contains(document.activeElement)) {
focusFlag = true;
} else {
focusFlag = false;
}
if (focusFlag) {
if (!this.focusFlag) {
// trigger the onFocus callback
if (this.onFocus) {
this.onFocus({
type: 'focus',
target: this.target
});
}
this.focusFlag = true;
}
} else {
if (this.focusFlag || this.firstEventFlag) {
// trigger the onBlur callback
if (this.onBlur) {
this.onBlur({
type: 'blur',
target: this.target
});
}
this.focusFlag = false;
/*
When switching from one mode to another in the editor, the FocusTracker gets recreated.
At that time, this.focusFlag will be init to 'false' and will fail the above if condition, when blur occurs
this.firstEventFlag is added to overcome that issue
*/
if (this.firstEventFlag) {
this.firstEventFlag = false;
}
}
}
}
}]);
return FocusTracker;
}();
/***/ }),
/***/ 161:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var ace = __webpack_require__(170); // may be undefined in case of minimalist bundle
var VanillaPicker = __webpack_require__(37); // may be undefined in case of minimalist bundle
var _require = __webpack_require__(38),
treeModeMixins = _require.treeModeMixins;
var _require2 = __webpack_require__(458),
textModeMixins = _require2.textModeMixins;
var _require3 = __webpack_require__(341),
previewModeMixins = _require3.previewModeMixins;
var _require4 = __webpack_require__(791),
clear = _require4.clear,
extend = _require4.extend,
getInnerText = _require4.getInnerText,
getInternetExplorerVersion = _require4.getInternetExplorerVersion,
parse = _require4.parse;
var _require5 = __webpack_require__(744),
tryRequireAjv = _require5.tryRequireAjv;
var _require6 = __webpack_require__(558),
showTransformModal = _require6.showTransformModal;
var _require7 = __webpack_require__(210),
showSortModal = _require7.showSortModal;
var Ajv = tryRequireAjv();
if (typeof Promise === 'undefined') {
console.error('Promise undefined. Please load a Promise polyfill in the browser in order to use JSONEditor');
}
/**
* @constructor JSONEditor
* @param {Element} container Container element
* @param {Object} [options] Object with options. available options:
* {String} mode Editor mode. Available values:
* 'tree' (default), 'view',
* 'form', 'text', and 'code'.
* {function} onChange Callback method, triggered
* on change of contents.
* Does not pass the contents itself.
* See also `onChangeJSON` and
* `onChangeText`.
* {function} onChangeJSON Callback method, triggered
* in modes on change of contents,
* passing the changed contents
* as JSON.
* Only applicable for modes
* 'tree', 'view', and 'form'.
* {function} onChangeText Callback method, triggered
* in modes on change of contents,
* passing the changed contents
* as stringified JSON.
* {function} onError Callback method, triggered
* when an error occurs
* {Boolean} search Enable search box.
* True by default
* Only applicable for modes
* 'tree', 'view', and 'form'
* {Boolean} history Enable history (undo/redo).
* True by default
* Only applicable for modes
* 'tree', 'view', and 'form'
* {String} name Field name for the root node.
* Only applicable for modes
* 'tree', 'view', and 'form'
* {Number} indentation Number of indentation
* spaces. 4 by default.
* Only applicable for
* modes 'text' and 'code'
* {boolean} escapeUnicode If true, unicode
* characters are escaped.
* false by default.
* {boolean} sortObjectKeys If true, object keys are
* sorted before display.
* false by default.
* {function} onSelectionChange Callback method,
* triggered on node selection change
* Only applicable for modes
* 'tree', 'view', and 'form'
* {function} onTextSelectionChange Callback method,
* triggered on text selection change
* Only applicable for modes
* {HTMLElement} modalAnchor The anchor element to apply an
* overlay and display the modals in a
* centered location.
* Defaults to document.body
* 'text' and 'code'
* {function} onEvent Callback method, triggered
* when an event occurs in
* a JSON field or value.
* Only applicable for
* modes 'form', 'tree' and
* 'view'
* {function} onFocus Callback method, triggered
* when the editor comes into focus,
* passing an object {type, target},
* Applicable for all modes
* {function} onBlur Callback method, triggered
* when the editor goes out of focus,
* passing an object {type, target},
* Applicable for all modes
* {function} onClassName Callback method, triggered
* when a Node DOM is rendered. Function returns
* a css class name to be set on a node.
* Only applicable for
* modes 'form', 'tree' and
* 'view'
* {Number} maxVisibleChilds Number of children allowed for a node
* in 'tree', 'view', or 'form' mode before
* the "show more/show all" buttons appear.
* 100 by default.
*
* @param {Object | undefined} json JSON object
*/
function JSONEditor(container, options, json) {
if (!(this instanceof JSONEditor)) {
throw new Error('JSONEditor constructor called without "new".');
}
// check for unsupported browser (IE8 and older)
var ieVersion = getInternetExplorerVersion();
if (ieVersion !== -1 && ieVersion < 9) {
throw new Error('Unsupported browser, IE9 or newer required. ' + 'Please install the newest version of your browser.');
}
if (options) {
// check for deprecated options
if (options.error) {
console.warn('Option "error" has been renamed to "onError"');
options.onError = options.error;
delete options.error;
}
if (options.change) {
console.warn('Option "change" has been renamed to "onChange"');
options.onChange = options.change;
delete options.change;
}
if (options.editable) {
console.warn('Option "editable" has been renamed to "onEditable"');
options.onEditable = options.editable;
delete options.editable;
}
// warn if onChangeJSON is used when mode can be `text` or `code`
if (options.onChangeJSON) {
if (options.mode === 'text' || options.mode === 'code' || options.modes && (options.modes.indexOf('text') !== -1 || options.modes.indexOf('code') !== -1)) {
console.warn('Option "onChangeJSON" is not applicable to modes "text" and "code". ' + 'Use "onChangeText" or "onChange" instead.');
}
}
// validate options
if (options) {
Object.keys(options).forEach(function (option) {
if (JSONEditor.VALID_OPTIONS.indexOf(option) === -1) {
console.warn('Unknown option "' + option + '". This option will be ignored');
}
});
}
}
if (arguments.length) {
this._create(container, options, json);
}
}
/**
* Configuration for all registered modes. Example:
* {
* tree: {
* mixin: TreeEditor,
* data: 'json'
* },
* text: {
* mixin: TextEditor,
* data: 'text'
* }
* }
*
* @type { Object.<String, {mixin: Object, data: String} > }
*/
JSONEditor.modes = {};
// debounce interval for JSON schema validation in milliseconds
JSONEditor.prototype.DEBOUNCE_INTERVAL = 150;
JSONEditor.VALID_OPTIONS = ['ajv', 'schema', 'schemaRefs', 'templates', 'ace', 'theme', 'autocomplete', 'onChange', 'onChangeJSON', 'onChangeText', 'onExpand', 'onEditable', 'onError', 'onEvent', 'onModeChange', 'onNodeName', 'onValidate', 'onCreateMenu', 'onSelectionChange', 'onTextSelectionChange', 'onClassName', 'onFocus', 'onBlur', 'colorPicker', 'onColorPicker', 'timestampTag', 'timestampFormat', 'escapeUnicode', 'history', 'search', 'mode', 'modes', 'name', 'indentation', 'sortObjectKeys', 'navigationBar', 'statusBar', 'mainMenuBar', 'languages', 'language', 'enableSort', 'enableTransform', 'limitDragging', 'maxVisibleChilds', 'onValidationError', 'modalAnchor', 'popupAnchor', 'createQuery', 'executeQuery', 'queryDescription', 'allowSchemaSuggestions', 'showErrorTable'];
/**
* 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.options = options || {};
this.json = json || {};
var mode = this.options.mode || this.options.modes && this.options.modes[0] || 'tree';
this.setMode(mode);
};
/**
* Destroy the editor. Clean up DOM, event listeners, and web workers.
*/
JSONEditor.prototype.destroy = function () {};
/**
* Set JSON object in editor
* @param {Object | undefined} json JSON data
*/
JSONEditor.prototype.set = function (json) {
this.json = json;
};
/**
* Get JSON from the editor
* @returns {Object} json
*/
JSONEditor.prototype.get = function () {
return this.json;
};
/**
* Set string containing JSON for the editor
* @param {String | undefined} jsonText
*/
JSONEditor.prototype.setText = function (jsonText) {
this.json = 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.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.prototype.getName = function () {
return this.options && this.options.name;
};
/**
* Change the mode of the editor.
* JSONEditor will be extended with all methods needed for the chosen mode.
* @param {String} mode Available modes: 'tree' (default), 'view', 'form',
* 'text', and 'code'.
*/
JSONEditor.prototype.setMode = function (mode) {
// if the mode is the same as current mode (and it's not the first time), do nothing.
if (mode === this.options.mode && this.create) {
return;
}
var container = this.container;
var options = extend({}, this.options);
var oldMode = options.mode;
options.mode = mode;
var config = JSONEditor.modes[mode];
if (!config) {
throw new Error('Unknown mode "' + options.mode + '"');
}
var asText = config.data === 'text';
var name = this.getName();
var data = this[asText ? 'getText' : 'get'](); // get text or json
this.destroy();
clear(this);
extend(this, config.mixin);
this.create(container, options);
this.setName(name);
this[asText ? 'setText' : 'set'](data); // set text or json
if (typeof config.load === 'function') {
try {
config.load.call(this);
} catch (err) {
console.error(err);
}
}
if (typeof options.onModeChange === 'function' && mode !== oldMode) {
try {
options.onModeChange(mode, oldMode);
} catch (err) {
console.error(err);
}
}
};
/**
* Get the current mode
* @return {string}
*/
JSONEditor.prototype.getMode = function () {
return this.options.mode;
};
/**
* Throw an error. If an error callback is configured in options.error, this
* callback will be invoked. Else, a basic alert window with the error message
* will be shown to the user.
* @param {Error} err
* @private
*/
JSONEditor.prototype._onError = function (err) {
if (this.options && typeof this.options.onError === 'function') {
this.options.onError(err);
} else {
window.alert(err.toString());
}
};
/**
* Set a JSON schema for validation of the JSON object.
* To remove the schema, call JSONEditor.setSchema(null)
* @param {Object | null} schema
* @param {Object.<string, Object>=} schemaRefs Schemas that are referenced using the `$ref` property from the JSON schema that are set in the `schema` option,
+ the object structure in the form of `{reference_key: schemaObject}`
*/
JSONEditor.prototype.setSchema = function (schema, schemaRefs) {
// compile a JSON schema validator if a JSON schema is provided
if (schema) {
var ajv;
try {
// grab ajv from options if provided, else create a new instance
if (this.options.ajv) {
ajv = this.options.ajv;
} else {
ajv = Ajv({
allErrors: true,
verbose: true