- * @version 6.4.0
- * @date 2019-08-28
- */
-(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();
-})(window, function() {
-return /******/ (function(modules) { // webpackBootstrap
-/******/ // The module cache
-/******/ var installedModules = {};
-/******/
-/******/ // The require function
-/******/ function __webpack_require__(moduleId) {
-/******/
-/******/ // Check if module is in cache
-/******/ if(installedModules[moduleId]) {
-/******/ return installedModules[moduleId].exports;
-/******/ }
-/******/ // Create a new module (and put it into the cache)
-/******/ var module = installedModules[moduleId] = {
-/******/ i: moduleId,
-/******/ l: false,
-/******/ exports: {}
-/******/ };
-/******/
-/******/ // Execute the module function
-/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
-/******/
-/******/ // Flag the module as loaded
-/******/ module.l = true;
-/******/
-/******/ // Return the exports of the module
-/******/ return module.exports;
-/******/ }
-/******/
-/******/
-/******/ // expose the modules object (__webpack_modules__)
-/******/ __webpack_require__.m = modules;
-/******/
-/******/ // expose the module cache
-/******/ __webpack_require__.c = installedModules;
-/******/
-/******/ // define getter function for harmony exports
-/******/ __webpack_require__.d = function(exports, name, getter) {
-/******/ if(!__webpack_require__.o(exports, name)) {
-/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
-/******/ }
-/******/ };
-/******/
-/******/ // define __esModule on exports
-/******/ __webpack_require__.r = function(exports) {
-/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
-/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
-/******/ }
-/******/ Object.defineProperty(exports, '__esModule', { value: true });
-/******/ };
-/******/
-/******/ // create a fake namespace object
-/******/ // mode & 1: value is a module id, require it
-/******/ // mode & 2: merge all properties of value into the ns
-/******/ // mode & 4: return value when already ns object
-/******/ // mode & 8|1: behave like require
-/******/ __webpack_require__.t = function(value, mode) {
-/******/ if(mode & 1) value = __webpack_require__(value);
-/******/ if(mode & 8) return value;
-/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
-/******/ var ns = Object.create(null);
-/******/ __webpack_require__.r(ns);
-/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
-/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
-/******/ return ns;
-/******/ };
-/******/
-/******/ // getDefaultExport function for compatibility with non-harmony modules
-/******/ __webpack_require__.n = function(module) {
-/******/ var getter = module && module.__esModule ?
-/******/ function getDefault() { return module['default']; } :
-/******/ function getModuleExports() { return module; };
-/******/ __webpack_require__.d(getter, 'a', getter);
-/******/ return getter;
-/******/ };
-/******/
-/******/ // Object.prototype.hasOwnProperty.call
-/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
-/******/
-/******/ // __webpack_public_path__
-/******/ __webpack_require__.p = "";
-/******/
-/******/
-/******/ // Load entry module and return exports
-/******/ return __webpack_require__(__webpack_require__.s = 16);
-/******/ })
-/************************************************************************/
-/******/ ([
-/* 0 */
-/***/ (function(module, exports, __webpack_require__) {
-
-"use strict";
-
-
-__webpack_require__(10);
-var naturalSort = __webpack_require__(11);
-var jsonlint = __webpack_require__(23);
-var jsonMap = __webpack_require__(24);
-var translate = __webpack_require__(1).translate;
-
-var MAX_ITEMS_FIELDS_COLLECTION = 10000;
-
-/**
- * Parse JSON using the parser built-in in the browser.
- * On exception, the jsonString is validated and a detailed error is thrown.
- * @param {String} jsonString
- * @return {JSON} json
- */
-exports.parse = function parse(jsonString) {
- try {
- return JSON.parse(jsonString);
- }
- catch (err) {
- // try to throw a more detailed error message using validate
- exports.validate(jsonString);
-
- // rethrow the original error
- throw err;
- }
-};
-
-/**
- * Repair a JSON-like string containing. For example changes JavaScript
- * notation into JSON notation.
- * This function for example changes a string like "{a: 2, 'b': {c: 'd'}"
- * into '{"a": 2, "b": {"c": "d"}'
- * @param {string} jsString
- * @returns {string} json
- */
-exports.repair = function (jsString) {
- // TODO: refactor this function, it's too large and complicated now
-
- // escape all single and double quotes inside strings
- var chars = [];
- var i = 0;
-
- //If JSON starts with a function (characters/digits/"_-"), remove this function.
- //This is useful for "stripping" JSONP objects to become JSON
- //For example: /* some comment */ function_12321321 ( [{"a":"b"}] ); => [{"a":"b"}]
- var match = jsString.match(/^\s*(\/\*(.|[\r\n])*?\*\/)?\s*[\da-zA-Z_$]+\s*\(([\s\S]*)\)\s*;?\s*$/);
- if (match) {
- jsString = match[3];
- }
-
- var controlChars = {
- '\b': '\\b',
- '\f': '\\f',
- '\n': '\\n',
- '\r': '\\r',
- '\t': '\\t'
- };
-
- var quote = '\'';
- var quoteDbl = '"';
- var quoteLeft = '\u2018';
- var quoteRight = '\u2019';
- var quoteDblLeft = '\u201C';
- var quoteDblRight = '\u201D';
- var graveAccent = '\u0060';
- var acuteAccent = '\u00B4';
-
- // helper functions to get the current/prev/next character
- function curr () { return jsString.charAt(i); }
- function next() { return jsString.charAt(i + 1); }
- function prev() { return jsString.charAt(i - 1); }
-
- function isWhiteSpace(c) {
- return c === ' ' || c === '\n' || c === '\r' || c === '\t';
- }
-
- // get the last parsed non-whitespace character
- function lastNonWhitespace () {
- var p = chars.length - 1;
-
- while (p >= 0) {
- var pp = chars[p];
- if (!isWhiteSpace(pp)) {
- return pp;
- }
- p--;
- }
-
- return '';
- }
-
- // get at the first next non-white space character
- function nextNonWhiteSpace() {
- var iNext = i + 1;
- while (iNext < jsString.length && isWhiteSpace(jsString[iNext])) {
- iNext++;
- }
-
- return jsString[iNext];
- }
-
- // skip a block comment '/* ... */'
- function skipBlockComment () {
- i += 2;
- while (i < jsString.length && (curr() !== '*' || next() !== '/')) {
- i++;
- }
- i += 2;
- }
-
- // skip a comment '// ...'
- function skipComment () {
- i += 2;
- while (i < jsString.length && (curr() !== '\n')) {
- i++;
- }
- }
-
- /**
- * parse single or double quoted string. Returns the parsed string
- * @param {string} endQuote
- * @return {string}
- */
- function parseString(endQuote) {
- var string = '';
-
- string += '"';
- i++;
- var c = curr();
- while (i < jsString.length && c !== endQuote) {
- if (c === '"' && prev() !== '\\') {
- // unescaped double quote, escape it
- string += '\\"';
- }
- else if (controlChars.hasOwnProperty(c)) {
- // replace unescaped control characters with escaped ones
- string += controlChars[c]
- }
- else if (c === '\\') {
- // remove the escape character when followed by a single quote ', not needed
- i++;
- c = curr();
- if (c !== '\'') {
- string += '\\';
- }
- string += c;
- }
- else {
- // regular character
- string += c;
- }
-
- i++;
- c = curr();
- }
- if (c === endQuote) {
- string += '"';
- i++;
- }
-
- return string;
- }
-
- // parse an unquoted key
- function parseKey() {
- var specialValues = ['null', 'true', 'false'];
- var key = '';
- var c = curr();
-
- var regexp = /[a-zA-Z_$\d]/; // letter, number, underscore, dollar character
- while (regexp.test(c)) {
- key += c;
- i++;
- c = curr();
- }
-
- if (specialValues.indexOf(key) === -1) {
- return '"' + key + '"';
- }
- else {
- return key;
- }
- }
-
- function parseMongoDataType () {
- var c = curr();
- var value;
- var dataType = '';
- while (/[a-zA-Z_$]/.test(c)) {
- dataType += c
- i++;
- c = curr();
- }
-
- if (dataType.length > 0 && c === '(') {
- // This is an MongoDB data type like {"_id": ObjectId("123")}
- i++;
- c = curr();
- if (c === '"') {
- // a data type containing a string, like ISODate("2012-12-19T06:01:17.171Z")
- value = parseString(c);
- c = curr();
- }
- else {
- // a data type containing a value, like 'NumberLong(2)'
- value = '';
- while(c !== ')' && c !== '') {
- value += c;
- i++;
- c = curr();
- }
- }
-
- if (c === ')') {
- // skip the closing bracket at the end
- i++;
-
- // return the value (strip the data type object)
- return value;
- }
- else {
- // huh? that's unexpected. don't touch it
- return dataType + '(' + value + c;
- }
- }
- else {
- // hm, no Mongo data type after all
- return dataType;
- }
- }
-
- function isSpecialWhiteSpace (c) {
- return (
- c === '\u00A0' ||
- (c >= '\u2000' && c <= '\u200A') ||
- c === '\u202F' ||
- c === '\u205F' ||
- c === '\u3000')
- }
-
- while(i < jsString.length) {
- var c = curr();
-
- if (c === '/' && next() === '*') {
- skipBlockComment();
- }
- else if (c === '/' && next() === '/') {
- skipComment();
- }
- else if (isSpecialWhiteSpace(c)) {
- // special white spaces (like non breaking space)
- chars.push(' ');
- i++
- }
- else if (c === quote) {
- chars.push(parseString(c));
- }
- else if (c === quoteDbl) {
- chars.push(parseString(quoteDbl));
- }
- else if (c === graveAccent) {
- chars.push(parseString(acuteAccent));
- }
- else if (c === quoteLeft) {
- chars.push(parseString(quoteRight));
- }
- else if (c === quoteDblLeft) {
- chars.push(parseString(quoteDblRight));
- }
- else if (c === ',' && [']', '}'].indexOf(nextNonWhiteSpace()) !== -1) {
- // skip trailing commas
- i++;
- }
- else if (/[a-zA-Z_$]/.test(c) && ['{', ','].indexOf(lastNonWhitespace()) !== -1) {
- // an unquoted object key (like a in '{a:2}')
- chars.push(parseKey());
- }
- else {
- if (/[a-zA-Z_$]/.test(c)) {
- chars.push(parseMongoDataType());
- }
- else {
- chars.push(c);
- i++;
- }
- }
- }
-
- return chars.join('');
-};
-
-/**
- * Escape unicode characters.
- * For example input '\u2661' (length 1) will output '\\u2661' (length 5).
- * @param {string} text
- * @return {string}
- */
-exports.escapeUnicodeChars = function (text) {
- // see https://www.wikiwand.com/en/UTF-16
- // note: we leave surrogate pairs as two individual chars,
- // as JSON doesn't interpret them as a single unicode char.
- return text.replace(/[\u007F-\uFFFF]/g, function(c) {
- return '\\u'+('0000' + c.charCodeAt(0).toString(16)).slice(-4);
- })
-};
-
-/**
- * Validate a string containing a JSON object
- * This method uses JSONLint to validate the String. If JSONLint is not
- * available, the built-in JSON parser of the browser is used.
- * @param {String} jsonString String with an (invalid) JSON object
- * @throws Error
- */
-exports.validate = function validate(jsonString) {
- if (typeof(jsonlint) != 'undefined') {
- jsonlint.parse(jsonString);
- }
- else {
- JSON.parse(jsonString);
- }
-};
-
-/**
- * Extend object a with the properties of object b
- * @param {Object} a
- * @param {Object} b
- * @return {Object} a
- */
-exports.extend = function extend(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
- */
-exports.clear = function clear (a) {
- for (var prop in a) {
- if (a.hasOwnProperty(prop)) {
- delete a[prop];
- }
- }
- return a;
-};
-
-/**
- * Get the type of an object
- * @param {*} object
- * @return {String} type
- */
-exports.type = function type (object) {
- if (object === null) {
- return 'null';
- }
- if (object === undefined) {
- return 'undefined';
- }
- if ((object instanceof Number) || (typeof object === 'number')) {
- return 'number';
- }
- if ((object instanceof String) || (typeof object === 'string')) {
- return 'string';
- }
- if ((object instanceof Boolean) || (typeof object === 'boolean')) {
- return 'boolean';
- }
- if ((object instanceof RegExp) || (typeof object === 'regexp')) {
- return 'regexp';
- }
- if (exports.isArray(object)) {
- return 'array';
- }
-
- return 'object';
-};
-
-/**
- * Test whether a text contains a url (matches when a string starts
- * with 'http://*' or 'https://*' and has no whitespace characters)
- * @param {String} text
- */
-var isUrlRegex = /^https?:\/\/\S+$/;
-exports.isUrl = function isUrl (text) {
- return (typeof text == 'string' || text instanceof String) &&
- isUrlRegex.test(text);
-};
-
-/**
- * Tes whether given object is an Array
- * @param {*} obj
- * @returns {boolean} returns true when obj is an array
- */
-exports.isArray = function (obj) {
- return Object.prototype.toString.call(obj) === '[object Array]';
-};
-
-/**
- * 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.
- */
-exports.getAbsoluteLeft = function getAbsoluteLeft(elem) {
- var rect = elem.getBoundingClientRect();
- return rect.left + window.pageXOffset || document.scrollLeft || 0;
-};
-
-/**
- * Retrieve the absolute top value of a DOM element
- * @param {Element} elem A dom element, for example a div
- * @return {Number} top The absolute top position of this element
- * in the browser page.
- */
-exports.getAbsoluteTop = function getAbsoluteTop(elem) {
- var rect = elem.getBoundingClientRect();
- return rect.top + window.pageYOffset || document.scrollTop || 0;
-};
-
-/**
- * add a className to the given elements style
- * @param {Element} elem
- * @param {String} className
- */
-exports.addClassName = function addClassName(elem, className) {
- var classes = elem.className.split(' ');
- if (classes.indexOf(className) == -1) {
- classes.push(className); // add the class to the array
- elem.className = classes.join(' ');
- }
-};
-
-/**
- * remove all classes from the given elements style
- * @param {Element} elem
- */
-exports.removeAllClassNames = function removeAllClassNames(elem) {
- elem.className = "";
-};
-
-/**
- * add a className to the given elements style
- * @param {Element} elem
- * @param {String} className
- */
-exports.removeClassName = function removeClassName(elem, className) {
- var classes = elem.className.split(' ');
- var index = classes.indexOf(className);
- if (index != -1) {
- classes.splice(index, 1); // remove the class from the array
- elem.className = classes.join(' ');
- }
-};
-
-/**
- * Strip the formatting from the contents of a div
- * the formatting from the div itself is not stripped, only from its childs.
- * @param {Element} divElement
- */
-exports.stripFormatting = function stripFormatting(divElement) {
- var childs = divElement.childNodes;
- for (var i = 0, iMax = childs.length; i < iMax; i++) {
- var child = childs[i];
-
- // remove the style
- if (child.style) {
- // TODO: test if child.attributes does contain style
- child.removeAttribute('style');
- }
-
- // remove all attributes
- var attributes = child.attributes;
- if (attributes) {
- for (var j = attributes.length - 1; j >= 0; j--) {
- var attribute = attributes[j];
- if (attribute.specified === true) {
- child.removeAttribute(attribute.name);
- }
- }
- }
-
- // recursively strip childs
- exports.stripFormatting(child);
- }
-};
-
-/**
- * Set focus to the end of an editable div
- * code from Nico Burns
- * http://stackoverflow.com/users/140293/nico-burns
- * http://stackoverflow.com/questions/1125292/how-to-move-cursor-to-end-of-contenteditable-entity
- * @param {Element} contentEditableElement A content editable div
- */
-exports.setEndOfContentEditable = function setEndOfContentEditable(contentEditableElement) {
- var range, selection;
- if(document.createRange) {
- range = document.createRange();//Create a range (a range is a like the selection but invisible)
- range.selectNodeContents(contentEditableElement);//Select the entire contents of the element with the range
- range.collapse(false);//collapse the range to the end point. false means collapse to end rather than the start
- selection = window.getSelection();//get the selection object (allows you to change selection)
- selection.removeAllRanges();//remove any selections already made
- selection.addRange(range);//make the range you have just created the visible selection
- }
-};
-
-/**
- * Select all text of a content editable div.
- * http://stackoverflow.com/a/3806004/1262753
- * @param {Element} contentEditableElement A content editable div
- */
-exports.selectContentEditable = function selectContentEditable(contentEditableElement) {
- if (!contentEditableElement || contentEditableElement.nodeName != 'DIV') {
- return;
- }
-
- var sel, range;
- if (window.getSelection && document.createRange) {
- range = document.createRange();
- range.selectNodeContents(contentEditableElement);
- sel = window.getSelection();
- sel.removeAllRanges();
- sel.addRange(range);
- }
-};
-
-/**
- * Get text selection
- * http://stackoverflow.com/questions/4687808/contenteditable-selected-text-save-and-restore
- * @return {Range | TextRange | null} range
- */
-exports.getSelection = function getSelection() {
- if (window.getSelection) {
- var sel = window.getSelection();
- if (sel.getRangeAt && sel.rangeCount) {
- return sel.getRangeAt(0);
- }
- }
- return null;
-};
-
-/**
- * Set text selection
- * http://stackoverflow.com/questions/4687808/contenteditable-selected-text-save-and-restore
- * @param {Range | TextRange | null} range
- */
-exports.setSelection = function setSelection(range) {
- if (range) {
- if (window.getSelection) {
- var sel = window.getSelection();
- sel.removeAllRanges();
- sel.addRange(range);
- }
- }
-};
-
-/**
- * Get selected text range
- * @return {Object} params object containing parameters:
- * {Number} startOffset
- * {Number} endOffset
- * {Element} container HTML element holding the
- * selected text element
- * Returns null if no text selection is found
- */
-exports.getSelectionOffset = function getSelectionOffset() {
- var range = exports.getSelection();
-
- if (range && 'startOffset' in range && 'endOffset' in range &&
- range.startContainer && (range.startContainer == range.endContainer)) {
- return {
- startOffset: range.startOffset,
- endOffset: range.endOffset,
- container: range.startContainer.parentNode
- };
- }
-
- return null;
-};
-
-/**
- * Set selected text range in given element
- * @param {Object} params An object containing:
- * {Element} container
- * {Number} startOffset
- * {Number} endOffset
- */
-exports.setSelectionOffset = function setSelectionOffset(params) {
- if (document.createRange && window.getSelection) {
- var selection = window.getSelection();
- if(selection) {
- var range = document.createRange();
-
- if (!params.container.firstChild) {
- params.container.appendChild(document.createTextNode(''));
- }
-
- // TODO: do not suppose that the first child of the container is a textnode,
- // but recursively find the textnodes
- range.setStart(params.container.firstChild, params.startOffset);
- range.setEnd(params.container.firstChild, params.endOffset);
-
- exports.setSelection(range);
- }
- }
-};
-
-/**
- * Get the inner text of an HTML element (for example a div element)
- * @param {Element} element
- * @param {Object} [buffer]
- * @return {String} innerText
- */
-exports.getInnerText = function getInnerText(element, buffer) {
- var first = (buffer == undefined);
- if (first) {
- buffer = {
- 'text': '',
- 'flush': function () {
- var text = this.text;
- this.text = '';
- return text;
- },
- 'set': function (text) {
- this.text = text;
- }
- };
- }
-
- // text node
- if (element.nodeValue) {
- return buffer.flush() + element.nodeValue;
- }
-
- // divs or other HTML elements
- if (element.hasChildNodes()) {
- var childNodes = element.childNodes;
- var innerText = '';
-
- for (var i = 0, iMax = childNodes.length; i < iMax; i++) {
- var child = childNodes[i];
-
- if (child.nodeName == 'DIV' || child.nodeName == 'P') {
- var prevChild = childNodes[i - 1];
- var prevName = prevChild ? prevChild.nodeName : undefined;
- if (prevName && prevName != 'DIV' && prevName != 'P' && prevName != 'BR') {
- innerText += '\n';
- buffer.flush();
- }
- innerText += exports.getInnerText(child, buffer);
- buffer.set('\n');
- }
- else if (child.nodeName == 'BR') {
- innerText += buffer.flush();
- buffer.set('\n');
- }
- else {
- innerText += exports.getInnerText(child, buffer);
- }
- }
-
- return innerText;
- }
- else {
- if (element.nodeName == 'P' && exports.getInternetExplorerVersion() != -1) {
- // On Internet Explorer, a with hasChildNodes()==false is
- // rendered with a new line. Note that a
with
- // hasChildNodes()==true is rendered without a new line
- // Other browsers always ensure there is a
inside the
,
- // and if not, the
does not render a new line
- return buffer.flush();
- }
- }
-
- // br or unknown
- return '';
-};
-
-/**
- * Test whether an element has the provided parent node somewhere up the node tree.
- * @param {Element} elem
- * @param {Element} parent
- * @return {boolean}
- */
-exports.hasParentNode = function (elem, parent) {
- var e = elem ? elem.parentNode : undefined;
-
- while (e) {
- if (e === parent) {
- return true;
- }
- e = e.parentNode;
- }
-
- return false;
-}
-
-/**
- * Returns the version of Internet Explorer or a -1
- * (indicating the use of another browser).
- * 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
- */
-exports.getInternetExplorerVersion = function getInternetExplorerVersion() {
- if (_ieVersion == -1) {
- var rv = -1; // Return value assumes failure.
- if (typeof navigator !== 'undefined' && navigator.appName == 'Microsoft Internet Explorer') {
- var ua = navigator.userAgent;
- var re = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})");
- if (re.exec(ua) != null) {
- rv = parseFloat( RegExp.$1 );
- }
- }
-
- _ieVersion = rv;
- }
-
- return _ieVersion;
-};
-
-/**
- * Test whether the current browser is Firefox
- * @returns {boolean} isFirefox
- */
-exports.isFirefox = function isFirefox () {
- return (typeof navigator !== 'undefined' && navigator.userAgent.indexOf("Firefox") !== -1);
-};
-
-/**
- * cached internet explorer version
- * @type {Number}
- * @private
- */
-var _ieVersion = -1;
-
-/**
- * Add and event listener. Works for all browsers
- * @param {Element} element An html element
- * @param {string} action The action, for example "click",
- * without the prefix "on"
- * @param {function} listener The callback function to be executed
- * @param {boolean} [useCapture] false by default
- * @return {function} the created event listener
- */
-exports.addEventListener = function addEventListener(element, action, listener, useCapture) {
- if (element.addEventListener) {
- if (useCapture === undefined)
- useCapture = false;
-
- if (action === "mousewheel" && exports.isFirefox()) {
- action = "DOMMouseScroll"; // For Firefox
- }
-
- element.addEventListener(action, listener, useCapture);
- return listener;
- } else if (element.attachEvent) {
- // Old IE browsers
- var f = function () {
- return listener.call(element, window.event);
- };
- element.attachEvent("on" + action, f);
- return f;
- }
-};
-
-/**
- * Remove an event listener from an element
- * @param {Element} element An html dom element
- * @param {string} action The name of the event, for example "mousedown"
- * @param {function} listener The listener function
- * @param {boolean} [useCapture] false by default
- */
-exports.removeEventListener = function removeEventListener(element, action, listener, useCapture) {
- if (element.removeEventListener) {
- if (useCapture === undefined)
- useCapture = false;
-
- if (action === "mousewheel" && exports.isFirefox()) {
- action = "DOMMouseScroll"; // For Firefox
- }
-
- element.removeEventListener(action, listener, useCapture);
- } else if (element.detachEvent) {
- // Old IE browsers
- element.detachEvent("on" + action, listener);
- }
-};
-
-/**
- * Test if an element is a child of a parent element.
- * @param {Element} elem
- * @param {Element} parent
- * @return {boolean} returns true if elem is a child of the parent
- */
-exports.isChildOf = function (elem, parent) {
- var e = elem.parentNode;
- while (e) {
- if (e === parent) {
- return true;
- }
- e = e.parentNode;
- }
-
- return false;
-};
-
-/**
- * Parse a JSON path like '.items[3].name' into an array
- * @param {string} jsonPath
- * @return {Array}
- */
-exports.parsePath = function parsePath(jsonPath) {
- var path = [];
- var i = 0;
-
- function parseProperty () {
- var prop = ''
- while (jsonPath[i] !== undefined && /[\w$]/.test(jsonPath[i])) {
- prop += jsonPath[i];
- i++;
- }
-
- if (prop === '') {
- throw new Error('Invalid JSON path: property name expected at index ' + i);
- }
-
- return prop;
- }
-
- function parseIndex (end) {
- var name = ''
- while (jsonPath[i] !== undefined && jsonPath[i] !== end) {
- name += jsonPath[i];
- i++;
- }
-
- if (jsonPath[i] !== end) {
- throw new Error('Invalid JSON path: unexpected end, character ' + end + ' expected')
- }
-
- return name;
- }
-
- while (jsonPath[i] !== undefined) {
- if (jsonPath[i] === '.') {
- i++;
- path.push(parseProperty());
- }
- else if (jsonPath[i] === '[') {
- i++;
-
- if (jsonPath[i] === '\'' || jsonPath[i] === '"') {
- var end = jsonPath[i]
- i++;
-
- path.push(parseIndex(end));
-
- if (jsonPath[i] !== end) {
- throw new Error('Invalid JSON path: closing quote \' expected at index ' + i)
- }
- i++;
- }
- else {
- var index = parseIndex(']').trim()
- if (index.length === 0) {
- throw new Error('Invalid JSON path: array value expected at index ' + i)
- }
- // Coerce numeric indices to numbers, but ignore star
- index = index === '*' ? index : JSON.parse(index);
- path.push(index);
- }
-
- if (jsonPath[i] !== ']') {
- throw new Error('Invalid JSON path: closing bracket ] expected at index ' + i)
- }
- i++;
- }
- else {
- throw new Error('Invalid JSON path: unexpected character "' + jsonPath[i] + '" at index ' + i);
- }
- }
-
- return path;
-};
-
-/**
- * Stringify an array with a path in a JSON path like '.items[3].name'
- * @param {Array.} path
- * @returns {string}
- */
-exports.stringifyPath = function stringifyPath(path) {
- return path
- .map(function (p) {
- if (typeof p === 'number'){
- return ('[' + p + ']');
- } else if(typeof p === 'string' && p.match(/^[A-Za-z0-9_$]+$/)) {
- return '.' + p;
- } else {
- return '["' + p + '"]';
- }
- })
- .join('');
-};
-
-/**
- * Improve the error message of a JSON schema error
- * @param {Object} error
- * @return {Object} The error
- */
-exports.improveSchemaError = function (error) {
- if (error.keyword === 'enum' && Array.isArray(error.schema)) {
- var enums = error.schema;
- if (enums) {
- enums = enums.map(function (value) {
- return JSON.stringify(value);
- });
-
- if (enums.length > 5) {
- var more = ['(' + (enums.length - 5) + ' more...)'];
- enums = enums.slice(0, 5);
- enums.push(more);
- }
- error.message = 'should be equal to one of: ' + enums.join(', ');
- }
- }
-
- if (error.keyword === 'additionalProperties') {
- error.message = 'should NOT have additional property: ' + error.params.additionalProperty;
- }
-
- return error;
-};
-
-/**
- * Test whether something is a Promise
- * @param {*} object
- * @returns {boolean} Returns true when object is a promise, false otherwise
- */
-exports.isPromise = function (object) {
- return object && typeof object.then === 'function' && typeof object.catch === 'function';
-};
-
-/**
- * Test whether a custom validation error has the correct structure
- * @param {*} validationError The error to be checked.
- * @returns {boolean} Returns true if the structure is ok, false otherwise
- */
-exports.isValidValidationError = function (validationError) {
- return typeof validationError === 'object' &&
- Array.isArray(validationError.path) &&
- typeof validationError.message === 'string';
-};
-
-/**
- * Test whether the child rect fits completely inside the parent rect.
- * @param {ClientRect} parent
- * @param {ClientRect} child
- * @param {number} margin
- */
-exports.insideRect = function (parent, child, margin) {
- var _margin = margin !== undefined ? margin : 0;
- return child.left - _margin >= parent.left
- && child.right + _margin <= parent.right
- && child.top - _margin >= parent.top
- && child.bottom + _margin <= parent.bottom;
-};
-
-/**
- * Returns a function, that, as long as it continues to be invoked, will not
- * be triggered. The function will be called after it stops being called for
- * N milliseconds.
- *
- * Source: https://davidwalsh.name/javascript-debounce-function
- *
- * @param {function} func
- * @param {number} wait Number in milliseconds
- * @param {boolean} [immediate=false] If `immediate` is passed, trigger the
- * function on the leading edge, instead
- * of the trailing.
- * @return {function} Return the debounced function
- */
-exports.debounce = function debounce(func, wait, immediate) {
- var timeout;
- return function() {
- var context = this, args = arguments;
- var later = function() {
- timeout = null;
- if (!immediate) func.apply(context, args);
- };
- var callNow = immediate && !timeout;
- clearTimeout(timeout);
- timeout = setTimeout(later, wait);
- if (callNow) func.apply(context, args);
- };
-};
-
-/**
- * Determines the difference between two texts.
- * Can only detect one removed or inserted block of characters.
- * @param {string} oldText
- * @param {string} newText
- * @return {{start: number, end: number}} Returns the start and end
- * of the changed part in newText.
- */
-exports.textDiff = function textDiff(oldText, newText) {
- var len = newText.length;
- var start = 0;
- var oldEnd = oldText.length;
- var newEnd = newText.length;
-
- while (newText.charAt(start) === oldText.charAt(start)
- && start < len) {
- start++;
- }
-
- while (newText.charAt(newEnd - 1) === oldText.charAt(oldEnd - 1)
- && newEnd > start && oldEnd > 0) {
- newEnd--;
- oldEnd--;
- }
-
- return {start: start, end: newEnd};
-};
-
-
-/**
- * Return an object with the selection range or cursor position (if both have the same value)
- * Support also old browsers (IE8-)
- * Source: http://ourcodeworld.com/articles/read/282/how-to-get-the-current-cursor-position-and-selection-within-a-text-input-or-textarea-in-javascript
- * @param {DOMElement} el A dom element of a textarea or input text.
- * @return {Object} reference Object with 2 properties (start and end) with the identifier of the location of the cursor and selected text.
- **/
-exports.getInputSelection = function(el) {
- var startIndex = 0, endIndex = 0, normalizedValue, range, textInputRange, len, endRange;
-
- if (typeof el.selectionStart == "number" && typeof el.selectionEnd == "number") {
- startIndex = el.selectionStart;
- endIndex = el.selectionEnd;
- } else {
- range = document.selection.createRange();
-
- if (range && range.parentElement() == el) {
- len = el.value.length;
- normalizedValue = el.value.replace(/\r\n/g, "\n");
-
- // Create a working TextRange that lives only in the input
- textInputRange = el.createTextRange();
- textInputRange.moveToBookmark(range.getBookmark());
-
- // Check if the startIndex and endIndex of the selection are at the very end
- // of the input, since moveStart/moveEnd doesn't return what we want
- // in those cases
- endRange = el.createTextRange();
- endRange.collapse(false);
-
- if (textInputRange.compareEndPoints("StartToEnd", endRange) > -1) {
- startIndex = endIndex = len;
- } else {
- startIndex = -textInputRange.moveStart("character", -len);
- startIndex += normalizedValue.slice(0, startIndex).split("\n").length - 1;
-
- if (textInputRange.compareEndPoints("EndToEnd", endRange) > -1) {
- endIndex = len;
- } else {
- endIndex = -textInputRange.moveEnd("character", -len);
- endIndex += normalizedValue.slice(0, endIndex).split("\n").length - 1;
- }
- }
- }
- }
-
- return {
- startIndex: startIndex,
- endIndex: endIndex,
- start: _positionForIndex(startIndex),
- end: _positionForIndex(endIndex)
- };
-
- /**
- * Returns textarea row and column position for certain index
- * @param {Number} index text index
- * @returns {{row: Number, col: Number}}
- */
- function _positionForIndex(index) {
- var textTillIndex = el.value.substring(0,index);
- var row = (textTillIndex.match(/\n/g) || []).length + 1;
- var col = textTillIndex.length - textTillIndex.lastIndexOf("\n");
-
- return {
- row: row,
- column: col
- }
- }
-}
-
-/**
- * Returns the index for certaion position in text element
- * @param {DOMElement} el A dom element of a textarea or input text.
- * @param {Number} row row value, > 0, if exceeds rows number - last row will be returned
- * @param {Number} column column value, > 0, if exceeds column length - end of column will be returned
- * @returns {Number} index of position in text, -1 if not found
- */
-exports.getIndexForPosition = function(el, row, column) {
- var text = el.value || '';
- if (row > 0 && column > 0) {
- var rows = text.split('\n', row);
- row = Math.min(rows.length, row);
- column = Math.min(rows[row - 1].length, column - 1);
- var columnCount = (row == 1 ? column : column + 1); // count new line on multiple rows
- return rows.slice(0, row - 1).join('\n').length + columnCount;
- }
- return -1;
-}
-
-/**
- * Returns location of json paths in certain json string
- * @param {String} text json string
- * @param {Array} paths array of json paths
- * @returns {Array<{path: String, line: Number, row: Number}>}
- */
-exports.getPositionForPath = function(text, paths) {
- var me = this;
- var result = [];
- var jsmap;
- if (!paths || !paths.length) {
- return result;
- }
-
- try {
- jsmap = jsonMap.parse(text);
- } catch (err) {
- return result;
- }
-
- paths.forEach(function (path) {
- var pathArr = me.parsePath(path);
- var pointerName = exports.compileJSONPointer(pathArr);
- var pointer = jsmap.pointers[pointerName];
- if (pointer) {
- result.push({
- path: path,
- line: pointer.key ? pointer.key.line : (pointer.value ? pointer.value.line : 0),
- column: pointer.key ? pointer.key.column : (pointer.value ? pointer.value.column : 0)
- });
- }
- });
-
- return result;
-
-}
-
-/**
- * Compile a JSON Pointer
- * WARNING: this is an incomplete implementation
- * @param {Array.} path
- * @return {string}
- */
-exports.compileJSONPointer = function (path) {
- return path
- .map(function (p) {
- return ('/' + String(p)
- .replace(/~/g, '~0')
- .replace(/\//g, '~1')
- );
- })
- .join('');
-};
-
-/**
- * Get the applied color given a color name or code
- * Source: https://stackoverflow.com/questions/6386090/validating-css-color-names/33184805
- * @param {string} color
- * @returns {string | null} returns the color if the input is a valid
- * color, and returns null otherwise. Example output:
- * 'rgba(255,0,0,0.7)' or 'rgb(255,0,0)'
- */
-exports.getColorCSS = function (color) {
- var ele = document.createElement('div');
- ele.style.color = color;
- return ele.style.color.split(/\s+/).join('').toLowerCase() || null;
-}
-
-/**
- * Test if a string contains a valid color name or code.
- * @param {string} color
- * @returns {boolean} returns true if a valid color, false otherwise
- */
-exports.isValidColor = function (color) {
- return !!exports.getColorCSS(color);
-}
-
-/**
- * Make a tooltip for a field based on the field's schema.
- * @param {object} schema JSON schema
- * @param {string} [locale] Locale code (for example, zh-CN)
- * @returns {string} Field tooltip, may be empty string if all relevant schema properties are missing
- */
-exports.makeFieldTooltip = function (schema, locale) {
- if (!schema) {
- return '';
- }
-
- var tooltip = '';
- if (schema.title) {
- tooltip += schema.title;
- }
-
- if (schema.description) {
- if (tooltip.length > 0) {
- tooltip += '\n';
- }
- tooltip += schema.description;
- }
-
- if (schema.default) {
- if (tooltip.length > 0) {
- tooltip += '\n\n';
- }
- tooltip += translate('default', undefined, locale) + '\n';
- tooltip += JSON.stringify(schema.default, null, 2);
- }
-
- if (Array.isArray(schema.examples) && schema.examples.length > 0) {
- if (tooltip.length > 0) {
- tooltip += '\n\n';
- }
- tooltip += translate('examples', undefined, locale) + '\n';
- schema.examples.forEach(function (example, index) {
- tooltip += JSON.stringify(example, null, 2);
- if (index !== schema.examples.length - 1) {
- tooltip += '\n';
- }
- });
- }
-
- return tooltip;
-}
-
-/**
- * Get a nested property from an object.
- * Returns undefined when the property does not exist.
- * @param {Object} object
- * @param {string[]} path
- * @return {*}
- */
-exports.get = function (object, path) {
- var value = object
-
- for (var i = 0; i < path.length && value !== undefined && value !== null; i++) {
- value = value[path[i]]
- }
-
- return value;
-}
-
-/**
- * Find a unique name. Suffix the name with ' (copy)', '(copy 2)', etc
- * until a unique name is found
- * @param {string} name
- * @param {Array} existingPropNames Array with existing prop names
- */
-exports.findUniqueName = function(name, existingPropNames) {
- var strippedName = name.replace(/ \(copy( \d+)?\)$/, '')
- var validName = strippedName
- var i = 1
-
- while (existingPropNames.indexOf(validName) !== -1) {
- var copy = 'copy' + (i > 1 ? (' ' + i) : '')
- validName = strippedName + ' (' + copy + ')'
- i++
- }
-
- return validName
-}
-
-/**
- * Get the child paths of an array
- * @param {JSON} json
- * @param {boolean} [includeObjects=false] If true, object and array paths are returned as well
- * @return {string[]}
- */
-exports.getChildPaths = function (json, includeObjects) {
- var pathsMap = {};
-
- function getObjectChildPaths (json, pathsMap, rootPath, includeObjects) {
- var isValue = !Array.isArray(json) && !exports.isObject(json)
-
- if (isValue || includeObjects) {
- pathsMap[rootPath || ''] = true;
- }
-
- if (exports.isObject(json)) {
- Object.keys(json).forEach(function (field) {
- getObjectChildPaths(json[field], pathsMap, rootPath + '.' + field, includeObjects);
- });
- }
- }
-
- if (Array.isArray(json)) {
- var max = Math.min(json.length, MAX_ITEMS_FIELDS_COLLECTION);
- for (var i = 0; i < max; i++) {
- var item = json[i];
- getObjectChildPaths(item, pathsMap, '', includeObjects);
- }
- }
- else {
- pathsMap[''] = true;
- }
-
- return Object.keys(pathsMap).sort();
-}
-
-/**
- * Sort object keys using natural sort
- * @param {Array} array
- * @param {String} [path] JSON pointer
- * @param {'asc' | 'desc'} [direction]
- */
-exports.sort = function (array, path, direction) {
- var parsedPath = path && path !== '.' ? exports.parsePath(path) : []
- var sign = direction === 'desc' ? -1: 1
-
- var sortedArray = array.slice()
- sortedArray.sort(function (a, b) {
- var aValue = exports.get(a, parsedPath);
- var bValue = exports.get(b, parsedPath);
-
- return sign * (aValue > bValue ? 1 : aValue < bValue ? -1 : 0);
- })
-
- return sortedArray;
-}
-
-/**
- * Sort object keys using natural sort
- * @param {Object} object
- * @param {'asc' | 'desc'} [direction]
- */
-exports.sortObjectKeys = function (object, direction) {
- var sign = (direction === 'desc') ? -1 : 1;
- var sortedFields = Object.keys(object).sort(function (a, b) {
- return sign * naturalSort(a, b);
- });
-
- var sortedObject = {};
- sortedFields.forEach(function (field) {
- sortedObject[field] = object[field];
- });
-
- return sortedObject;
-}
-
-/**
- * Cast contents of a string to the correct type.
- * This can be a string, a number, a boolean, etc
- * @param {String} str
- * @return {*} castedStr
- * @private
- */
-exports.parseString = function(str) {
- var lower = str.toLowerCase();
- var num = Number(str); // will nicely fail with '123ab'
- var numFloat = parseFloat(str); // will nicely fail with ' '
-
- if (str === '') {
- return '';
- }
- else if (lower === 'null') {
- return null;
- }
- else if (lower === 'true') {
- return true;
- }
- else if (lower === 'false') {
- return false;
- }
- else if (!isNaN(num) && !isNaN(numFloat)) {
- return num;
- }
- else {
- return str;
- }
-};
-
-/**
- * Return a human readable document size
- * For example formatSize(7570718) outputs '7.2 MiB'
- * @param {number} size
- * @return {string} Returns a human readable size
- */
-exports.formatSize = function (size) {
- if (size < 900) {
- return size.toFixed() + ' B';
- }
-
- var KiB = size / 1024;
- if (KiB < 900) {
- return KiB.toFixed(1) + ' KiB';
- }
-
- var MiB = KiB / 1024;
- if (MiB < 900) {
- return MiB.toFixed(1) + ' MiB';
- }
-
- var GiB = MiB / 1024;
- if (GiB < 900) {
- return GiB.toFixed(1) + ' GiB';
- }
-
- var TiB = GiB / 1024;
- return TiB.toFixed(1) + ' TiB';
-}
-
-/**
- * Limit text to a maximum number of characters
- * @param {string} text
- * @param {number} maxCharacterCount
- * @return {string} Returns the limited text,
- * ending with '...' if the max was exceeded
- */
-exports.limitCharacters = function (text, maxCharacterCount) {
- if (text.length <= maxCharacterCount) {
- return text;
- }
-
- return text.slice(0, maxCharacterCount) + '...';
-}
-
-/**
- * Test whether a value is an Object
- * @param {*} value
- * @return {boolean}
- */
-exports.isObject = function (value) {
- return typeof value === 'object' && value !== null && !Array.isArray(value)
-}
-
-/**
- * Helper function to test whether an array contains an item
- * @param {Array} array
- * @param {*} item
- * @return {boolean} Returns true if `item` is in `array`, returns false otherwise.
- */
-exports.contains = function (array, item) {
- return array.indexOf(item) !== -1;
-}
-
-
-/***/ }),
-/* 1 */
-/***/ (function(module, exports, __webpack_require__) {
-
-"use strict";
-
-
-__webpack_require__(10);
-
-var _locales = ['en', 'pt-BR', 'zh-CN', 'tr'];
-var _defs = {
- en: {
- array: 'Array',
- auto: 'Auto',
- appendText: 'Append',
- appendTitle: 'Append a new field with type \'auto\' after this field (Ctrl+Shift+Ins)',
- appendSubmenuTitle: 'Select the type of the field to be appended',
- appendTitleAuto: 'Append a new field with type \'auto\' (Ctrl+Shift+Ins)',
- ascending: 'Ascending',
- ascendingTitle: 'Sort the childs of this ${type} in ascending order',
- actionsMenu: 'Click to open the actions menu (Ctrl+M)',
- collapseAll: 'Collapse all fields',
- descending: 'Descending',
- descendingTitle: 'Sort the childs of this ${type} in descending order',
- drag: 'Drag to move this field (Alt+Shift+Arrows)',
- duplicateKey: 'duplicate key',
- duplicateText: 'Duplicate',
- duplicateTitle: 'Duplicate selected fields (Ctrl+D)',
- duplicateField: 'Duplicate this field (Ctrl+D)',
- duplicateFieldError: 'Duplicate field name',
- cannotParseFieldError: 'Cannot parse field into JSON',
- cannotParseValueError: 'Cannot parse value into JSON',
- empty: 'empty',
- expandAll: 'Expand all fields',
- expandTitle: 'Click to expand/collapse this field (Ctrl+E). \n' +
- 'Ctrl+Click to expand/collapse including all childs.',
- insert: 'Insert',
- insertTitle: 'Insert a new field with type \'auto\' before this field (Ctrl+Ins)',
- insertSub: 'Select the type of the field to be inserted',
- object: 'Object',
- ok: 'Ok',
- redo: 'Redo (Ctrl+Shift+Z)',
- removeText: 'Remove',
- removeTitle: 'Remove selected fields (Ctrl+Del)',
- removeField: 'Remove this field (Ctrl+Del)',
- selectNode: 'Select a node...',
- showAll: 'show all',
- showMore: 'show more',
- showMoreStatus: 'displaying ${visibleChilds} of ${totalChilds} items.',
- sort: 'Sort',
- sortTitle: 'Sort the childs of this ${type}',
- sortTitleShort: 'Sort contents',
- sortFieldLabel: 'Field:',
- sortDirectionLabel: 'Direction:',
- sortFieldTitle: 'Select the nested field by which to sort the array or object',
- sortAscending: 'Ascending',
- sortAscendingTitle: 'Sort the selected field in ascending order',
- sortDescending: 'Descending',
- sortDescendingTitle: 'Sort the selected field in descending order',
- string: 'String',
- transform: 'Transform',
- transformTitle: 'Filter, sort, or transform the childs of this ${type}',
- transformTitleShort: 'Filter, sort, or transform contents',
- extract: 'Extract',
- extractTitle: 'Extract this ${type}',
- transformQueryTitle: 'Enter a JMESPath query',
- transformWizardLabel: 'Wizard',
- transformWizardFilter: 'Filter',
- transformWizardSortBy: 'Sort by',
- transformWizardSelectFields: 'Select fields',
- transformQueryLabel: 'Query',
- transformPreviewLabel: 'Preview',
- type: 'Type',
- typeTitle: 'Change the type of this field',
- openUrl: 'Ctrl+Click or Ctrl+Enter to open url in new window',
- undo: 'Undo last action (Ctrl+Z)',
- validationCannotMove: 'Cannot move a field into a child of itself',
- autoType: 'Field type "auto". ' +
- 'The field type is automatically determined from the value ' +
- 'and can be a string, number, boolean, or null.',
- objectType: 'Field type "object". ' +
- 'An object contains an unordered set of key/value pairs.',
- arrayType: 'Field type "array". ' +
- 'An array contains an ordered collection of values.',
- stringType: 'Field type "string". ' +
- 'Field type is not determined from the value, ' +
- 'but always returned as string.',
- modeCodeText: 'Code',
- modeCodeTitle: 'Switch to code highlighter',
- modeFormText: 'Form',
- modeFormTitle: 'Switch to form editor',
- modeTextText: 'Text',
- modeTextTitle: 'Switch to plain text editor',
- modeTreeText: 'Tree',
- modeTreeTitle: 'Switch to tree editor',
- modeViewText: 'View',
- modeViewTitle: 'Switch to tree view',
- modePreviewText: 'Preview',
- modePreviewTitle: 'Switch to preview mode',
- examples: 'Examples',
- default: 'Default',
- },
- 'zh-CN': {
- array: '数组',
- auto: '自动',
- appendText: '追加',
- appendTitle: '在此字段后追加一个类型为“auto”的新字段 (Ctrl+Shift+Ins)',
- appendSubmenuTitle: '选择要追加的字段类型',
- appendTitleAuto: '追加类型为“auto”的新字段 (Ctrl+Shift+Ins)',
- ascending: '升序',
- ascendingTitle: '升序排列${type}的子节点',
- actionsMenu: '点击打开动作菜单(Ctrl+M)',
- collapseAll: '缩进所有字段',
- descending: '降序',
- descendingTitle: '降序排列${type}的子节点',
- drag: '拖拽移动该节点(Alt+Shift+Arrows)',
- duplicateKey: '重复键',
- duplicateText: '复制',
- duplicateTitle: '复制选中字段(Ctrl+D)',
- duplicateField: '复制该字段(Ctrl+D)',
- duplicateFieldError: '重复的字段名称',
- cannotParseFieldError: '无法将字段解析为JSON',
- cannotParseValueError: '无法将值解析为JSON',
- empty: '清空',
- expandAll: '展开所有字段',
- expandTitle: '点击 展开/收缩 该字段(Ctrl+E). \n' +
- 'Ctrl+Click 展开/收缩 包含所有子节点.',
- insert: '插入',
- insertTitle: '在此字段前插入类型为“auto”的新字段 (Ctrl+Ins)',
- insertSub: '选择要插入的字段类型',
- object: '对象',
- ok: 'Ok',
- redo: '重做 (Ctrl+Shift+Z)',
- removeText: '移除',
- removeTitle: '移除选中字段 (Ctrl+Del)',
- removeField: '移除该字段 (Ctrl+Del)',
- selectNode: '选择一个节点...',
- showAll: '展示全部',
- showMore: '展示更多',
- showMoreStatus: '显示${totalChilds}的${visibleChilds}项目.',
- sort: '排序',
- sortTitle: '排序${type}的子节点',
- sortTitleShort: '内容排序',
- sortFieldLabel: '字段:',
- sortDirectionLabel: '方向:',
- sortFieldTitle: '选择用于对数组或对象排序的嵌套字段',
- sortAscending: '升序排序',
- sortAscendingTitle: '按照该字段升序排序',
- sortDescending: '降序排序',
- sortDescendingTitle: '按照该字段降序排序',
- string: '字符串',
- transform: '变换',
- transformTitle: '筛选,排序,或者转换${type}的子节点',
- transformTitleShort: '筛选,排序,或者转换内容',
- extract: '提取',
- extractTitle: '提取这个 ${type}',
- transformQueryTitle: '输入JMESPath查询',
- transformWizardLabel: '向导',
- transformWizardFilter: '筛选',
- transformWizardSortBy: '排序',
- transformWizardSelectFields: '选择字段',
- transformQueryLabel: '查询',
- transformPreviewLabel: '预览',
- type: '类型',
- typeTitle: '更改字段类型',
- openUrl: 'Ctrl+Click 或者 Ctrl+Enter 在新窗口打开链接',
- undo: '撤销上次动作 (Ctrl+Z)',
- validationCannotMove: '无法将字段移入其子节点',
- autoType: '字段类型 "auto". ' +
- '字段类型由值自动确定 ' +
- '可以为 string,number,boolean,或者 null.',
- objectType: '字段类型 "object". ' +
- '对象包含一组无序的键/值对.',
- arrayType: '字段类型 "array". ' +
- '数组包含值的有序集合.',
- stringType: '字段类型 "string". ' +
- '字段类型由值自动确定,' +
- '但始终作为字符串返回.',
- modeCodeText: '代码',
- modeCodeTitle: '切换至代码高亮',
- modeFormText: '表单',
- modeFormTitle: '切换至表单编辑',
- modeTextText: '文本',
- modeTextTitle: '切换至文本编辑',
- modeTreeText: '树',
- modeTreeTitle: '切换至树编辑',
- modeViewText: '视图',
- modeViewTitle: '切换至树视图',
- modePreviewText: '预览',
- modePreviewTitle: '切换至预览模式',
- examples: '例子',
- default: '缺省',
- },
- 'pt-BR': {
- array: 'Lista',
- auto: 'Automatico',
- appendText: 'Adicionar',
- appendTitle: 'Adicionar novo campo com tipo \'auto\' depois deste campo (Ctrl+Shift+Ins)',
- appendSubmenuTitle: 'Selecione o tipo do campo a ser adicionado',
- appendTitleAuto: 'Adicionar novo campo com tipo \'auto\' (Ctrl+Shift+Ins)',
- ascending: 'Ascendente',
- ascendingTitle: 'Organizar filhor do tipo ${type} em crescente',
- actionsMenu: 'Clique para abrir o menu de ações (Ctrl+M)',
- collapseAll: 'Fechar todos campos',
- descending: 'Descendente',
- descendingTitle: 'Organizar o filhos do tipo ${type} em decrescente',
- duplicateKey: 'chave duplicada',
- drag: 'Arraste para mover este campo (Alt+Shift+Arrows)',
- duplicateText: 'Duplicar',
- duplicateTitle: 'Duplicar campos selecionados (Ctrl+D)',
- duplicateField: 'Duplicar este campo (Ctrl+D)',
- duplicateFieldError: 'Nome do campo duplicado',
- cannotParseFieldError: 'Não é possível analisar o campo no JSON',
- cannotParseValueError: 'Não é possível analisar o valor em JSON',
- empty: 'vazio',
- expandAll: 'Expandir todos campos',
- expandTitle: 'Clique para expandir/encolher este campo (Ctrl+E). \n' +
- 'Ctrl+Click para expandir/encolher incluindo todos os filhos.',
- insert: 'Inserir',
- insertTitle: 'Inserir um novo campo do tipo \'auto\' antes deste campo (Ctrl+Ins)',
- insertSub: 'Selecionar o tipo de campo a ser inserido',
- object: 'Objeto',
- ok: 'Ok',
- redo: 'Refazer (Ctrl+Shift+Z)',
- removeText: 'Remover',
- removeTitle: 'Remover campos selecionados (Ctrl+Del)',
- removeField: 'Remover este campo (Ctrl+Del)',
- // TODO: correctly translate
- selectNode: 'Select a node...',
- // TODO: correctly translate
- showAll: 'mostre tudo',
- // TODO: correctly translate
- showMore: 'mostre mais',
- // TODO: correctly translate
- showMoreStatus: 'exibindo ${visibleChilds} de ${totalChilds} itens.',
- sort: 'Organizar',
- sortTitle: 'Organizar os filhos deste ${type}',
- // TODO: correctly translate
- sortTitleShort: 'Organizar os filhos',
- // TODO: correctly translate
- sortFieldLabel: 'Field:',
- // TODO: correctly translate
- sortDirectionLabel: 'Direction:',
- // TODO: correctly translate
- sortFieldTitle: 'Select the nested field by which to sort the array or object',
- // TODO: correctly translate
- sortAscending: 'Ascending',
- // TODO: correctly translate
- sortAscendingTitle: 'Sort the selected field in ascending order',
- // TODO: correctly translate
- sortDescending: 'Descending',
- // TODO: correctly translate
- sortDescendingTitle: 'Sort the selected field in descending order',
- string: 'Texto',
- // TODO: correctly translate
- transform: 'Transform',
- // TODO: correctly translate
- transformTitle: 'Filter, sort, or transform the childs of this ${type}',
- // TODO: correctly translate
- transformTitleShort: 'Filter, sort, or transform contents',
- // TODO: correctly translate
- transformQueryTitle: 'Enter a JMESPath query',
- // TODO: correctly translate
- transformWizardLabel: 'Wizard',
- // TODO: correctly translate
- transformWizardFilter: 'Filter',
- // TODO: correctly translate
- transformWizardSortBy: 'Sort by',
- // TODO: correctly translate
- transformWizardSelectFields: 'Select fields',
- // TODO: correctly translate
- transformQueryLabel: 'Query',
- // TODO: correctly translate
- transformPreviewLabel: 'Preview',
- type: 'Tipo',
- typeTitle: 'Mudar o tipo deste campo',
- openUrl: 'Ctrl+Click ou Ctrl+Enter para abrir link em nova janela',
- undo: 'Desfazer último ação (Ctrl+Z)',
- validationCannotMove: 'Não pode mover um campo como filho dele mesmo',
- autoType: 'Campo do tipo "auto". ' +
- 'O tipo do campo é determinao automaticamente a partir do seu valor ' +
- 'e pode ser texto, número, verdade/falso ou nulo.',
- objectType: 'Campo do tipo "objeto". ' +
- 'Um objeto contém uma lista de pares com chave e valor.',
- arrayType: 'Campo do tipo "lista". ' +
- 'Uma lista contem uma coleção de valores ordenados.',
- stringType: 'Campo do tipo "string". ' +
- 'Campo do tipo nao é determinado através do seu valor, ' +
- 'mas sempre retornara um texto.',
- examples: 'Exemplos',
- default: 'Revelia',
- },
- tr: {
- array: 'Dizin',
- auto: 'Otomatik',
- appendText: 'Ekle',
- appendTitle: 'Bu alanın altına \'otomatik\' tipinde yeni bir alan ekle (Ctrl+Shift+Ins)',
- appendSubmenuTitle: 'Eklenecek alanın tipini seç',
- appendTitleAuto: '\'Otomatik\' tipinde yeni bir alan ekle (Ctrl+Shift+Ins)',
- ascending: 'Artan',
- ascendingTitle: '${type}\'ın alt tiplerini artan düzende sırala',
- actionsMenu: 'Aksiyon menüsünü açmak için tıklayın (Ctrl+M)',
- collapseAll: 'Tüm alanları kapat',
- descending: 'Azalan',
- descendingTitle: '${type}\'ın alt tiplerini azalan düzende sırala',
- drag: 'Bu alanı taşımak için sürükleyin (Alt+Shift+Arrows)',
- duplicateKey: 'Var olan anahtar',
- duplicateText: 'Aşağıya kopyala',
- duplicateTitle: 'Seçili alanlardan bir daha oluştur (Ctrl+D)',
- duplicateField: 'Bu alandan bir daha oluştur (Ctrl+D)',
- duplicateFieldError: 'Duplicate field name',
- cannotParseFieldError: 'Alan JSON\'a ayrıştırılamıyor',
- cannotParseValueError: 'JSON\'a değer ayrıştırılamıyor',
- empty: 'boş',
- expandAll: 'Tüm alanları aç',
- expandTitle: 'Bu alanı açmak/kapatmak için tıkla (Ctrl+E). \n' +
- 'Alt alanlarda dahil tüm alanları açmak için Ctrl+Click ',
- insert: 'Ekle',
- insertTitle: 'Bu alanın üstüne \'otomatik\' tipinde yeni bir alan ekle (Ctrl+Ins)',
- insertSub: 'Araya eklenecek alanın tipini seç',
- object: 'Nesne',
- ok: 'Tamam',
- redo: 'Yeniden yap (Ctrl+Shift+Z)',
- removeText: 'Kaldır',
- removeTitle: 'Seçilen alanları kaldır (Ctrl+Del)',
- removeField: 'Bu alanı kaldır (Ctrl+Del)',
- selectNode: 'Bir nesne seç...',
- showAll: 'tümünü göster',
- showMore: 'daha fazla göster',
- showMoreStatus: '${totalChilds} alanın ${visibleChilds} alt alanları gösteriliyor',
- sort: 'Sırala',
- sortTitle: '${type}\'ın alt alanlarını sırala',
- sortTitleShort: 'İçerikleri sırala',
- sortFieldLabel: 'Alan:',
- sortDirectionLabel: 'Yön:',
- sortFieldTitle: 'Diziyi veya nesneyi sıralamak için iç içe geçmiş alanı seçin',
- sortAscending: 'Artan',
- sortAscendingTitle: 'Seçili alanı artan düzende sırala',
- sortDescending: 'Azalan',
- sortDescendingTitle: 'Seçili alanı azalan düzende sırala',
- string: 'Karakter Dizisi',
- transform: 'Dönüştür',
- transformTitle: '${type}\'ın alt alanlarını filtrele, sırala veya dönüştür',
- transformTitleShort: 'İçerikleri filterele, sırala veya dönüştür',
- transformQueryTitle: 'JMESPath sorgusu gir',
- transformWizardLabel: 'Sihirbaz',
- transformWizardFilter: 'Filtre',
- transformWizardSortBy: 'Sırala',
- transformWizardSelectFields: 'Alanları seç',
- transformQueryLabel: 'Sorgu',
- transformPreviewLabel: 'Önizleme',
- type: 'Tip',
- typeTitle: 'Bu alanın tipini değiştir',
- openUrl: 'URL\'i yeni bir pencerede açmak için Ctrl+Click veya Ctrl+Enter',
- undo: 'Son değişikliği geri al (Ctrl+Z)',
- validationCannotMove: 'Alt alan olarak taşınamıyor',
- autoType: 'Alan tipi "otomatik". ' +
- 'Alan türü otomatik olarak değerden belirlenir' +
- 've bir dize, sayı, boolean veya null olabilir.',
- objectType: 'Alan tipi "nesne". ' +
- 'Bir nesne, sıralanmamış bir anahtar / değer çifti kümesi içerir.',
- arrayType: 'Alan tipi "dizi". ' +
- 'Bir dizi, düzenli değerler koleksiyonu içerir.',
- stringType: 'Alan tipi "karakter dizisi". ' +
- 'Alan türü değerden belirlenmez,' +
- 'ancak her zaman karakter dizisi olarak döndürülür.',
- modeCodeText: 'Kod',
- modeCodeTitle: 'Kod vurgulayıcıya geç',
- modeFormText: 'Form',
- modeFormTitle: 'Form düzenleyiciye geç',
- modeTextText: 'Metin',
- modeTextTitle: 'Düz metin düzenleyiciye geç',
- modeTreeText: 'Ağaç',
- modeTreeTitle: 'Ağaç düzenleyiciye geç',
- modeViewText: 'Görünüm',
- modeViewTitle: 'Ağaç görünümüne geç',
- examples: 'Örnekler',
- default: 'Varsayılan',
- }
-};
-
-var _defaultLang = 'en';
-var _lang;
-var userLang = typeof navigator !== 'undefined' ?
- navigator.language || navigator.userLanguage :
- undefined;
-_lang = _locales.find(function (l) {
- return l === userLang;
-});
-if (!_lang) {
- _lang = _defaultLang;
-}
-
-module.exports = {
- // supported locales
- _locales: _locales,
- _defs: _defs,
- _lang: _lang,
- setLanguage: function (lang) {
- if (!lang) {
- return;
- }
- var langFound = _locales.find(function (l) {
- return l === lang;
- });
- if (langFound) {
- _lang = langFound;
- } else {
- console.error('Language not found');
- }
- },
- setLanguages: function (languages) {
- if (!languages) {
- return;
- }
- for (var key in languages) {
- var langFound = _locales.find(function (l) {
- return l === key;
- });
- if (!langFound) {
- _locales.push(key);
- }
- _defs[key] = Object.assign({}, _defs[_defaultLang], _defs[key], languages[key]);
- }
- },
- translate: function (key, data, lang) {
- if (!lang) {
- lang = _lang;
- }
- var text = _defs[lang][key];
- if (data) {
- for (key in data) {
- text = text.replace('${' + key + '}', data[key]);
- }
- }
- return text || key;
- }
-};
-
-/***/ }),
-/* 2 */
-/***/ (function(module, exports) {
-
-
-exports.DEFAULT_MODAL_ANCHOR = document.body;
-exports.SIZE_LARGE = 10 * 1024 * 1024; // 10 MB
-
-exports.MAX_PREVIEW_CHARACTERS = 20000;
-
-exports.PREVIEW_HISTORY_LIMIT = 2 * 1024 * 1024 * 1024; // 2 GB
-
-
-/***/ }),
-/* 3 */
-/***/ (function(module, exports, __webpack_require__) {
-
-"use strict";
-
-
-var createAbsoluteAnchor = __webpack_require__(12).createAbsoluteAnchor;
-var util = __webpack_require__(0);
-var translate = __webpack_require__(1).translate;
-
-/**
- * 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.
- * @constructor
- */
-function ContextMenu (items, options) {
- 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;
-
- // 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';
- li = document.createElement('li');
- li.appendChild(separator);
- list.appendChild(li);
- }
- else {
- var domItem = {};
-
- // create a menu item
- var li = document.createElement('li');
- list.appendChild(li);
-
- // 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();
- };
- }
- li.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';
- buttonExpand.innerHTML = '';
- li.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';
- li.appendChild(ul);
- createMenuItems(ul, domSubItems, item.submenu);
- }
- else {
- // no submenu, just a button with clickhandler
- button.innerHTML = '' +
- '' + translate(item.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.} buttons
- * @private
- */
-ContextMenu.prototype._getVisibleButtons = function () {
- 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;
-};
-
-// currently displayed context menu, a singleton. We may only have one visible context menu
-ContextMenu.visibleMenu = undefined;
-
-/**
- * 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
- */
-ContextMenu.prototype.show = function (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 = createAbsoluteAnchor(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';
- }
-
- // 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 = util.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
- */
-ContextMenu.prototype.hide = function () {
- // 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
- */
-ContextMenu.prototype._onExpandItem = function (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 = '';
- util.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';
- var height = 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);
- util.addClassName(ul.parentNode, 'jsoneditor-selected');
- this.expandedItem = domItem;
- }
-};
-
-/**
- * Handle onkeydown event
- * @param {Event} event
- * @private
- */
-ContextMenu.prototype._onKeyDown = function (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) {
- util.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();
- }
-};
-
-module.exports = ContextMenu;
-
-
-/***/ }),
-/* 4 */
-/***/ (function(module, exports, __webpack_require__) {
-
-(function(exports) {
- "use strict";
-
- function isArray(obj) {
- if (obj !== null) {
- return Object.prototype.toString.call(obj) === "[object Array]";
- } else {
- return false;
- }
- }
-
- function isObject(obj) {
- if (obj !== null) {
- return Object.prototype.toString.call(obj) === "[object Object]";
- } else {
- return false;
- }
- }
-
- function strictDeepEqual(first, second) {
- // Check the scalar case first.
- if (first === second) {
- return true;
- }
-
- // Check if they are the same type.
- var firstType = Object.prototype.toString.call(first);
- if (firstType !== Object.prototype.toString.call(second)) {
- return false;
- }
- // We know that first and second have the same type so we can just check the
- // first type from now on.
- if (isArray(first) === true) {
- // Short circuit if they're not the same length;
- if (first.length !== second.length) {
- return false;
- }
- for (var i = 0; i < first.length; i++) {
- if (strictDeepEqual(first[i], second[i]) === false) {
- return false;
- }
- }
- return true;
- }
- if (isObject(first) === true) {
- // An object is equal if it has the same key/value pairs.
- var keysSeen = {};
- for (var key in first) {
- if (hasOwnProperty.call(first, key)) {
- if (strictDeepEqual(first[key], second[key]) === false) {
- return false;
- }
- keysSeen[key] = true;
- }
- }
- // Now check that there aren't any keys in second that weren't
- // in first.
- for (var key2 in second) {
- if (hasOwnProperty.call(second, key2)) {
- if (keysSeen[key2] !== true) {
- return false;
- }
- }
- }
- return true;
- }
- return false;
- }
-
- function isFalse(obj) {
- // From the spec:
- // A false value corresponds to the following values:
- // Empty list
- // Empty object
- // Empty string
- // False boolean
- // null value
-
- // First check the scalar values.
- if (obj === "" || obj === false || obj === null) {
- return true;
- } else if (isArray(obj) && obj.length === 0) {
- // Check for an empty array.
- return true;
- } else if (isObject(obj)) {
- // Check for an empty object.
- for (var key in obj) {
- // If there are any keys, then
- // the object is not empty so the object
- // is not false.
- if (obj.hasOwnProperty(key)) {
- return false;
- }
- }
- return true;
- } else {
- return false;
- }
- }
-
- function objValues(obj) {
- var keys = Object.keys(obj);
- var values = [];
- for (var i = 0; i < keys.length; i++) {
- values.push(obj[keys[i]]);
- }
- return values;
- }
-
- function merge(a, b) {
- var merged = {};
- for (var key in a) {
- merged[key] = a[key];
- }
- for (var key2 in b) {
- merged[key2] = b[key2];
- }
- return merged;
- }
-
- var trimLeft;
- if (typeof String.prototype.trimLeft === "function") {
- trimLeft = function(str) {
- return str.trimLeft();
- };
- } else {
- trimLeft = function(str) {
- return str.match(/^\s*(.*)/)[1];
- };
- }
-
- // Type constants used to define functions.
- var TYPE_NUMBER = 0;
- var TYPE_ANY = 1;
- var TYPE_STRING = 2;
- var TYPE_ARRAY = 3;
- var TYPE_OBJECT = 4;
- var TYPE_BOOLEAN = 5;
- var TYPE_EXPREF = 6;
- var TYPE_NULL = 7;
- var TYPE_ARRAY_NUMBER = 8;
- var TYPE_ARRAY_STRING = 9;
-
- var TOK_EOF = "EOF";
- var TOK_UNQUOTEDIDENTIFIER = "UnquotedIdentifier";
- var TOK_QUOTEDIDENTIFIER = "QuotedIdentifier";
- var TOK_RBRACKET = "Rbracket";
- var TOK_RPAREN = "Rparen";
- var TOK_COMMA = "Comma";
- var TOK_COLON = "Colon";
- var TOK_RBRACE = "Rbrace";
- var TOK_NUMBER = "Number";
- var TOK_CURRENT = "Current";
- var TOK_EXPREF = "Expref";
- var TOK_PIPE = "Pipe";
- var TOK_OR = "Or";
- var TOK_AND = "And";
- var TOK_EQ = "EQ";
- var TOK_GT = "GT";
- var TOK_LT = "LT";
- var TOK_GTE = "GTE";
- var TOK_LTE = "LTE";
- var TOK_NE = "NE";
- var TOK_FLATTEN = "Flatten";
- var TOK_STAR = "Star";
- var TOK_FILTER = "Filter";
- var TOK_DOT = "Dot";
- var TOK_NOT = "Not";
- var TOK_LBRACE = "Lbrace";
- var TOK_LBRACKET = "Lbracket";
- var TOK_LPAREN= "Lparen";
- var TOK_LITERAL= "Literal";
-
- // The "&", "[", "<", ">" tokens
- // are not in basicToken because
- // there are two token variants
- // ("&&", "[?", "<=", ">="). This is specially handled
- // below.
-
- var basicTokens = {
- ".": TOK_DOT,
- "*": TOK_STAR,
- ",": TOK_COMMA,
- ":": TOK_COLON,
- "{": TOK_LBRACE,
- "}": TOK_RBRACE,
- "]": TOK_RBRACKET,
- "(": TOK_LPAREN,
- ")": TOK_RPAREN,
- "@": TOK_CURRENT
- };
-
- var operatorStartToken = {
- "<": true,
- ">": true,
- "=": true,
- "!": true
- };
-
- var skipChars = {
- " ": true,
- "\t": true,
- "\n": true
- };
-
-
- function isAlpha(ch) {
- return (ch >= "a" && ch <= "z") ||
- (ch >= "A" && ch <= "Z") ||
- ch === "_";
- }
-
- function isNum(ch) {
- return (ch >= "0" && ch <= "9") ||
- ch === "-";
- }
- function isAlphaNum(ch) {
- return (ch >= "a" && ch <= "z") ||
- (ch >= "A" && ch <= "Z") ||
- (ch >= "0" && ch <= "9") ||
- ch === "_";
- }
-
- function Lexer() {
- }
- Lexer.prototype = {
- tokenize: function(stream) {
- var tokens = [];
- this._current = 0;
- var start;
- var identifier;
- var token;
- while (this._current < stream.length) {
- if (isAlpha(stream[this._current])) {
- start = this._current;
- identifier = this._consumeUnquotedIdentifier(stream);
- tokens.push({type: TOK_UNQUOTEDIDENTIFIER,
- value: identifier,
- start: start});
- } else if (basicTokens[stream[this._current]] !== undefined) {
- tokens.push({type: basicTokens[stream[this._current]],
- value: stream[this._current],
- start: this._current});
- this._current++;
- } else if (isNum(stream[this._current])) {
- token = this._consumeNumber(stream);
- tokens.push(token);
- } else if (stream[this._current] === "[") {
- // No need to increment this._current. This happens
- // in _consumeLBracket
- token = this._consumeLBracket(stream);
- tokens.push(token);
- } else if (stream[this._current] === "\"") {
- start = this._current;
- identifier = this._consumeQuotedIdentifier(stream);
- tokens.push({type: TOK_QUOTEDIDENTIFIER,
- value: identifier,
- start: start});
- } else if (stream[this._current] === "'") {
- start = this._current;
- identifier = this._consumeRawStringLiteral(stream);
- tokens.push({type: TOK_LITERAL,
- value: identifier,
- start: start});
- } else if (stream[this._current] === "`") {
- start = this._current;
- var literal = this._consumeLiteral(stream);
- tokens.push({type: TOK_LITERAL,
- value: literal,
- start: start});
- } else if (operatorStartToken[stream[this._current]] !== undefined) {
- tokens.push(this._consumeOperator(stream));
- } else if (skipChars[stream[this._current]] !== undefined) {
- // Ignore whitespace.
- this._current++;
- } else if (stream[this._current] === "&") {
- start = this._current;
- this._current++;
- if (stream[this._current] === "&") {
- this._current++;
- tokens.push({type: TOK_AND, value: "&&", start: start});
- } else {
- tokens.push({type: TOK_EXPREF, value: "&", start: start});
- }
- } else if (stream[this._current] === "|") {
- start = this._current;
- this._current++;
- if (stream[this._current] === "|") {
- this._current++;
- tokens.push({type: TOK_OR, value: "||", start: start});
- } else {
- tokens.push({type: TOK_PIPE, value: "|", start: start});
- }
- } else {
- var error = new Error("Unknown character:" + stream[this._current]);
- error.name = "LexerError";
- throw error;
- }
- }
- return tokens;
- },
-
- _consumeUnquotedIdentifier: function(stream) {
- var start = this._current;
- this._current++;
- while (this._current < stream.length && isAlphaNum(stream[this._current])) {
- this._current++;
- }
- return stream.slice(start, this._current);
- },
-
- _consumeQuotedIdentifier: function(stream) {
- var start = this._current;
- this._current++;
- var maxLength = stream.length;
- while (stream[this._current] !== "\"" && this._current < maxLength) {
- // You can escape a double quote and you can escape an escape.
- var current = this._current;
- if (stream[current] === "\\" && (stream[current + 1] === "\\" ||
- stream[current + 1] === "\"")) {
- current += 2;
- } else {
- current++;
- }
- this._current = current;
- }
- this._current++;
- return JSON.parse(stream.slice(start, this._current));
- },
-
- _consumeRawStringLiteral: function(stream) {
- var start = this._current;
- this._current++;
- var maxLength = stream.length;
- while (stream[this._current] !== "'" && this._current < maxLength) {
- // You can escape a single quote and you can escape an escape.
- var current = this._current;
- if (stream[current] === "\\" && (stream[current + 1] === "\\" ||
- stream[current + 1] === "'")) {
- current += 2;
- } else {
- current++;
- }
- this._current = current;
- }
- this._current++;
- var literal = stream.slice(start + 1, this._current - 1);
- return literal.replace("\\'", "'");
- },
-
- _consumeNumber: function(stream) {
- var start = this._current;
- this._current++;
- var maxLength = stream.length;
- while (isNum(stream[this._current]) && this._current < maxLength) {
- this._current++;
- }
- var value = parseInt(stream.slice(start, this._current));
- return {type: TOK_NUMBER, value: value, start: start};
- },
-
- _consumeLBracket: function(stream) {
- var start = this._current;
- this._current++;
- if (stream[this._current] === "?") {
- this._current++;
- return {type: TOK_FILTER, value: "[?", start: start};
- } else if (stream[this._current] === "]") {
- this._current++;
- return {type: TOK_FLATTEN, value: "[]", start: start};
- } else {
- return {type: TOK_LBRACKET, value: "[", start: start};
- }
- },
-
- _consumeOperator: function(stream) {
- var start = this._current;
- var startingChar = stream[start];
- this._current++;
- if (startingChar === "!") {
- if (stream[this._current] === "=") {
- this._current++;
- return {type: TOK_NE, value: "!=", start: start};
- } else {
- return {type: TOK_NOT, value: "!", start: start};
- }
- } else if (startingChar === "<") {
- if (stream[this._current] === "=") {
- this._current++;
- return {type: TOK_LTE, value: "<=", start: start};
- } else {
- return {type: TOK_LT, value: "<", start: start};
- }
- } else if (startingChar === ">") {
- if (stream[this._current] === "=") {
- this._current++;
- return {type: TOK_GTE, value: ">=", start: start};
- } else {
- return {type: TOK_GT, value: ">", start: start};
- }
- } else if (startingChar === "=") {
- if (stream[this._current] === "=") {
- this._current++;
- return {type: TOK_EQ, value: "==", start: start};
- }
- }
- },
-
- _consumeLiteral: function(stream) {
- this._current++;
- var start = this._current;
- var maxLength = stream.length;
- var literal;
- while(stream[this._current] !== "`" && this._current < maxLength) {
- // You can escape a literal char or you can escape the escape.
- var current = this._current;
- if (stream[current] === "\\" && (stream[current + 1] === "\\" ||
- stream[current + 1] === "`")) {
- current += 2;
- } else {
- current++;
- }
- this._current = current;
- }
- var literalString = trimLeft(stream.slice(start, this._current));
- literalString = literalString.replace("\\`", "`");
- if (this._looksLikeJSON(literalString)) {
- literal = JSON.parse(literalString);
- } else {
- // Try to JSON parse it as ""
- literal = JSON.parse("\"" + literalString + "\"");
- }
- // +1 gets us to the ending "`", +1 to move on to the next char.
- this._current++;
- return literal;
- },
-
- _looksLikeJSON: function(literalString) {
- var startingChars = "[{\"";
- var jsonLiterals = ["true", "false", "null"];
- var numberLooking = "-0123456789";
-
- if (literalString === "") {
- return false;
- } else if (startingChars.indexOf(literalString[0]) >= 0) {
- return true;
- } else if (jsonLiterals.indexOf(literalString) >= 0) {
- return true;
- } else if (numberLooking.indexOf(literalString[0]) >= 0) {
- try {
- JSON.parse(literalString);
- return true;
- } catch (ex) {
- return false;
- }
- } else {
- return false;
- }
- }
- };
-
- var bindingPower = {};
- bindingPower[TOK_EOF] = 0;
- bindingPower[TOK_UNQUOTEDIDENTIFIER] = 0;
- bindingPower[TOK_QUOTEDIDENTIFIER] = 0;
- bindingPower[TOK_RBRACKET] = 0;
- bindingPower[TOK_RPAREN] = 0;
- bindingPower[TOK_COMMA] = 0;
- bindingPower[TOK_RBRACE] = 0;
- bindingPower[TOK_NUMBER] = 0;
- bindingPower[TOK_CURRENT] = 0;
- bindingPower[TOK_EXPREF] = 0;
- bindingPower[TOK_PIPE] = 1;
- bindingPower[TOK_OR] = 2;
- bindingPower[TOK_AND] = 3;
- bindingPower[TOK_EQ] = 5;
- bindingPower[TOK_GT] = 5;
- bindingPower[TOK_LT] = 5;
- bindingPower[TOK_GTE] = 5;
- bindingPower[TOK_LTE] = 5;
- bindingPower[TOK_NE] = 5;
- bindingPower[TOK_FLATTEN] = 9;
- bindingPower[TOK_STAR] = 20;
- bindingPower[TOK_FILTER] = 21;
- bindingPower[TOK_DOT] = 40;
- bindingPower[TOK_NOT] = 45;
- bindingPower[TOK_LBRACE] = 50;
- bindingPower[TOK_LBRACKET] = 55;
- bindingPower[TOK_LPAREN] = 60;
-
- function Parser() {
- }
-
- Parser.prototype = {
- parse: function(expression) {
- this._loadTokens(expression);
- this.index = 0;
- var ast = this.expression(0);
- if (this._lookahead(0) !== TOK_EOF) {
- var t = this._lookaheadToken(0);
- var error = new Error(
- "Unexpected token type: " + t.type + ", value: " + t.value);
- error.name = "ParserError";
- throw error;
- }
- return ast;
- },
-
- _loadTokens: function(expression) {
- var lexer = new Lexer();
- var tokens = lexer.tokenize(expression);
- tokens.push({type: TOK_EOF, value: "", start: expression.length});
- this.tokens = tokens;
- },
-
- expression: function(rbp) {
- var leftToken = this._lookaheadToken(0);
- this._advance();
- var left = this.nud(leftToken);
- var currentToken = this._lookahead(0);
- while (rbp < bindingPower[currentToken]) {
- this._advance();
- left = this.led(currentToken, left);
- currentToken = this._lookahead(0);
- }
- return left;
- },
-
- _lookahead: function(number) {
- return this.tokens[this.index + number].type;
- },
-
- _lookaheadToken: function(number) {
- return this.tokens[this.index + number];
- },
-
- _advance: function() {
- this.index++;
- },
-
- nud: function(token) {
- var left;
- var right;
- var expression;
- switch (token.type) {
- case TOK_LITERAL:
- return {type: "Literal", value: token.value};
- case TOK_UNQUOTEDIDENTIFIER:
- return {type: "Field", name: token.value};
- case TOK_QUOTEDIDENTIFIER:
- var node = {type: "Field", name: token.value};
- if (this._lookahead(0) === TOK_LPAREN) {
- throw new Error("Quoted identifier not allowed for function names.");
- } else {
- return node;
- }
- break;
- case TOK_NOT:
- right = this.expression(bindingPower.Not);
- return {type: "NotExpression", children: [right]};
- case TOK_STAR:
- left = {type: "Identity"};
- right = null;
- if (this._lookahead(0) === TOK_RBRACKET) {
- // This can happen in a multiselect,
- // [a, b, *]
- right = {type: "Identity"};
- } else {
- right = this._parseProjectionRHS(bindingPower.Star);
- }
- return {type: "ValueProjection", children: [left, right]};
- case TOK_FILTER:
- return this.led(token.type, {type: "Identity"});
- case TOK_LBRACE:
- return this._parseMultiselectHash();
- case TOK_FLATTEN:
- left = {type: TOK_FLATTEN, children: [{type: "Identity"}]};
- right = this._parseProjectionRHS(bindingPower.Flatten);
- return {type: "Projection", children: [left, right]};
- case TOK_LBRACKET:
- if (this._lookahead(0) === TOK_NUMBER || this._lookahead(0) === TOK_COLON) {
- right = this._parseIndexExpression();
- return this._projectIfSlice({type: "Identity"}, right);
- } else if (this._lookahead(0) === TOK_STAR &&
- this._lookahead(1) === TOK_RBRACKET) {
- this._advance();
- this._advance();
- right = this._parseProjectionRHS(bindingPower.Star);
- return {type: "Projection",
- children: [{type: "Identity"}, right]};
- } else {
- return this._parseMultiselectList();
- }
- break;
- case TOK_CURRENT:
- return {type: TOK_CURRENT};
- case TOK_EXPREF:
- expression = this.expression(bindingPower.Expref);
- return {type: "ExpressionReference", children: [expression]};
- case TOK_LPAREN:
- var args = [];
- while (this._lookahead(0) !== TOK_RPAREN) {
- if (this._lookahead(0) === TOK_CURRENT) {
- expression = {type: TOK_CURRENT};
- this._advance();
- } else {
- expression = this.expression(0);
- }
- args.push(expression);
- }
- this._match(TOK_RPAREN);
- return args[0];
- default:
- this._errorToken(token);
- }
- },
-
- led: function(tokenName, left) {
- var right;
- switch(tokenName) {
- case TOK_DOT:
- var rbp = bindingPower.Dot;
- if (this._lookahead(0) !== TOK_STAR) {
- right = this._parseDotRHS(rbp);
- return {type: "Subexpression", children: [left, right]};
- } else {
- // Creating a projection.
- this._advance();
- right = this._parseProjectionRHS(rbp);
- return {type: "ValueProjection", children: [left, right]};
- }
- break;
- case TOK_PIPE:
- right = this.expression(bindingPower.Pipe);
- return {type: TOK_PIPE, children: [left, right]};
- case TOK_OR:
- right = this.expression(bindingPower.Or);
- return {type: "OrExpression", children: [left, right]};
- case TOK_AND:
- right = this.expression(bindingPower.And);
- return {type: "AndExpression", children: [left, right]};
- case TOK_LPAREN:
- var name = left.name;
- var args = [];
- var expression, node;
- while (this._lookahead(0) !== TOK_RPAREN) {
- if (this._lookahead(0) === TOK_CURRENT) {
- expression = {type: TOK_CURRENT};
- this._advance();
- } else {
- expression = this.expression(0);
- }
- if (this._lookahead(0) === TOK_COMMA) {
- this._match(TOK_COMMA);
- }
- args.push(expression);
- }
- this._match(TOK_RPAREN);
- node = {type: "Function", name: name, children: args};
- return node;
- case TOK_FILTER:
- var condition = this.expression(0);
- this._match(TOK_RBRACKET);
- if (this._lookahead(0) === TOK_FLATTEN) {
- right = {type: "Identity"};
- } else {
- right = this._parseProjectionRHS(bindingPower.Filter);
- }
- return {type: "FilterProjection", children: [left, right, condition]};
- case TOK_FLATTEN:
- var leftNode = {type: TOK_FLATTEN, children: [left]};
- var rightNode = this._parseProjectionRHS(bindingPower.Flatten);
- return {type: "Projection", children: [leftNode, rightNode]};
- case TOK_EQ:
- case TOK_NE:
- case TOK_GT:
- case TOK_GTE:
- case TOK_LT:
- case TOK_LTE:
- return this._parseComparator(left, tokenName);
- case TOK_LBRACKET:
- var token = this._lookaheadToken(0);
- if (token.type === TOK_NUMBER || token.type === TOK_COLON) {
- right = this._parseIndexExpression();
- return this._projectIfSlice(left, right);
- } else {
- this._match(TOK_STAR);
- this._match(TOK_RBRACKET);
- right = this._parseProjectionRHS(bindingPower.Star);
- return {type: "Projection", children: [left, right]};
- }
- break;
- default:
- this._errorToken(this._lookaheadToken(0));
- }
- },
-
- _match: function(tokenType) {
- if (this._lookahead(0) === tokenType) {
- this._advance();
- } else {
- var t = this._lookaheadToken(0);
- var error = new Error("Expected " + tokenType + ", got: " + t.type);
- error.name = "ParserError";
- throw error;
- }
- },
-
- _errorToken: function(token) {
- var error = new Error("Invalid token (" +
- token.type + "): \"" +
- token.value + "\"");
- error.name = "ParserError";
- throw error;
- },
-
-
- _parseIndexExpression: function() {
- if (this._lookahead(0) === TOK_COLON || this._lookahead(1) === TOK_COLON) {
- return this._parseSliceExpression();
- } else {
- var node = {
- type: "Index",
- value: this._lookaheadToken(0).value};
- this._advance();
- this._match(TOK_RBRACKET);
- return node;
- }
- },
-
- _projectIfSlice: function(left, right) {
- var indexExpr = {type: "IndexExpression", children: [left, right]};
- if (right.type === "Slice") {
- return {
- type: "Projection",
- children: [indexExpr, this._parseProjectionRHS(bindingPower.Star)]
- };
- } else {
- return indexExpr;
- }
- },
-
- _parseSliceExpression: function() {
- // [start:end:step] where each part is optional, as well as the last
- // colon.
- var parts = [null, null, null];
- var index = 0;
- var currentToken = this._lookahead(0);
- while (currentToken !== TOK_RBRACKET && index < 3) {
- if (currentToken === TOK_COLON) {
- index++;
- this._advance();
- } else if (currentToken === TOK_NUMBER) {
- parts[index] = this._lookaheadToken(0).value;
- this._advance();
- } else {
- var t = this._lookahead(0);
- var error = new Error("Syntax error, unexpected token: " +
- t.value + "(" + t.type + ")");
- error.name = "Parsererror";
- throw error;
- }
- currentToken = this._lookahead(0);
- }
- this._match(TOK_RBRACKET);
- return {
- type: "Slice",
- children: parts
- };
- },
-
- _parseComparator: function(left, comparator) {
- var right = this.expression(bindingPower[comparator]);
- return {type: "Comparator", name: comparator, children: [left, right]};
- },
-
- _parseDotRHS: function(rbp) {
- var lookahead = this._lookahead(0);
- var exprTokens = [TOK_UNQUOTEDIDENTIFIER, TOK_QUOTEDIDENTIFIER, TOK_STAR];
- if (exprTokens.indexOf(lookahead) >= 0) {
- return this.expression(rbp);
- } else if (lookahead === TOK_LBRACKET) {
- this._match(TOK_LBRACKET);
- return this._parseMultiselectList();
- } else if (lookahead === TOK_LBRACE) {
- this._match(TOK_LBRACE);
- return this._parseMultiselectHash();
- }
- },
-
- _parseProjectionRHS: function(rbp) {
- var right;
- if (bindingPower[this._lookahead(0)] < 10) {
- right = {type: "Identity"};
- } else if (this._lookahead(0) === TOK_LBRACKET) {
- right = this.expression(rbp);
- } else if (this._lookahead(0) === TOK_FILTER) {
- right = this.expression(rbp);
- } else if (this._lookahead(0) === TOK_DOT) {
- this._match(TOK_DOT);
- right = this._parseDotRHS(rbp);
- } else {
- var t = this._lookaheadToken(0);
- var error = new Error("Sytanx error, unexpected token: " +
- t.value + "(" + t.type + ")");
- error.name = "ParserError";
- throw error;
- }
- return right;
- },
-
- _parseMultiselectList: function() {
- var expressions = [];
- while (this._lookahead(0) !== TOK_RBRACKET) {
- var expression = this.expression(0);
- expressions.push(expression);
- if (this._lookahead(0) === TOK_COMMA) {
- this._match(TOK_COMMA);
- if (this._lookahead(0) === TOK_RBRACKET) {
- throw new Error("Unexpected token Rbracket");
- }
- }
- }
- this._match(TOK_RBRACKET);
- return {type: "MultiSelectList", children: expressions};
- },
-
- _parseMultiselectHash: function() {
- var pairs = [];
- var identifierTypes = [TOK_UNQUOTEDIDENTIFIER, TOK_QUOTEDIDENTIFIER];
- var keyToken, keyName, value, node;
- for (;;) {
- keyToken = this._lookaheadToken(0);
- if (identifierTypes.indexOf(keyToken.type) < 0) {
- throw new Error("Expecting an identifier token, got: " +
- keyToken.type);
- }
- keyName = keyToken.value;
- this._advance();
- this._match(TOK_COLON);
- value = this.expression(0);
- node = {type: "KeyValuePair", name: keyName, value: value};
- pairs.push(node);
- if (this._lookahead(0) === TOK_COMMA) {
- this._match(TOK_COMMA);
- } else if (this._lookahead(0) === TOK_RBRACE) {
- this._match(TOK_RBRACE);
- break;
- }
- }
- return {type: "MultiSelectHash", children: pairs};
- }
- };
-
-
- function TreeInterpreter(runtime) {
- this.runtime = runtime;
- }
-
- TreeInterpreter.prototype = {
- search: function(node, value) {
- return this.visit(node, value);
- },
-
- visit: function(node, value) {
- var matched, current, result, first, second, field, left, right, collected, i;
- switch (node.type) {
- case "Field":
- if (value === null ) {
- return null;
- } else if (isObject(value)) {
- field = value[node.name];
- if (field === undefined) {
- return null;
- } else {
- return field;
- }
- } else {
- return null;
- }
- break;
- case "Subexpression":
- result = this.visit(node.children[0], value);
- for (i = 1; i < node.children.length; i++) {
- result = this.visit(node.children[1], result);
- if (result === null) {
- return null;
- }
- }
- return result;
- case "IndexExpression":
- left = this.visit(node.children[0], value);
- right = this.visit(node.children[1], left);
- return right;
- case "Index":
- if (!isArray(value)) {
- return null;
- }
- var index = node.value;
- if (index < 0) {
- index = value.length + index;
- }
- result = value[index];
- if (result === undefined) {
- result = null;
- }
- return result;
- case "Slice":
- if (!isArray(value)) {
- return null;
- }
- var sliceParams = node.children.slice(0);
- var computed = this.computeSliceParams(value.length, sliceParams);
- var start = computed[0];
- var stop = computed[1];
- var step = computed[2];
- result = [];
- if (step > 0) {
- for (i = start; i < stop; i += step) {
- result.push(value[i]);
- }
- } else {
- for (i = start; i > stop; i += step) {
- result.push(value[i]);
- }
- }
- return result;
- case "Projection":
- // Evaluate left child.
- var base = this.visit(node.children[0], value);
- if (!isArray(base)) {
- return null;
- }
- collected = [];
- for (i = 0; i < base.length; i++) {
- current = this.visit(node.children[1], base[i]);
- if (current !== null) {
- collected.push(current);
- }
- }
- return collected;
- case "ValueProjection":
- // Evaluate left child.
- base = this.visit(node.children[0], value);
- if (!isObject(base)) {
- return null;
- }
- collected = [];
- var values = objValues(base);
- for (i = 0; i < values.length; i++) {
- current = this.visit(node.children[1], values[i]);
- if (current !== null) {
- collected.push(current);
- }
- }
- return collected;
- case "FilterProjection":
- base = this.visit(node.children[0], value);
- if (!isArray(base)) {
- return null;
- }
- var filtered = [];
- var finalResults = [];
- for (i = 0; i < base.length; i++) {
- matched = this.visit(node.children[2], base[i]);
- if (!isFalse(matched)) {
- filtered.push(base[i]);
- }
- }
- for (var j = 0; j < filtered.length; j++) {
- current = this.visit(node.children[1], filtered[j]);
- if (current !== null) {
- finalResults.push(current);
- }
- }
- return finalResults;
- case "Comparator":
- first = this.visit(node.children[0], value);
- second = this.visit(node.children[1], value);
- switch(node.name) {
- case TOK_EQ:
- result = strictDeepEqual(first, second);
- break;
- case TOK_NE:
- result = !strictDeepEqual(first, second);
- break;
- case TOK_GT:
- result = first > second;
- break;
- case TOK_GTE:
- result = first >= second;
- break;
- case TOK_LT:
- result = first < second;
- break;
- case TOK_LTE:
- result = first <= second;
- break;
- default:
- throw new Error("Unknown comparator: " + node.name);
- }
- return result;
- case TOK_FLATTEN:
- var original = this.visit(node.children[0], value);
- if (!isArray(original)) {
- return null;
- }
- var merged = [];
- for (i = 0; i < original.length; i++) {
- current = original[i];
- if (isArray(current)) {
- merged.push.apply(merged, current);
- } else {
- merged.push(current);
- }
- }
- return merged;
- case "Identity":
- return value;
- case "MultiSelectList":
- if (value === null) {
- return null;
- }
- collected = [];
- for (i = 0; i < node.children.length; i++) {
- collected.push(this.visit(node.children[i], value));
- }
- return collected;
- case "MultiSelectHash":
- if (value === null) {
- return null;
- }
- collected = {};
- var child;
- for (i = 0; i < node.children.length; i++) {
- child = node.children[i];
- collected[child.name] = this.visit(child.value, value);
- }
- return collected;
- case "OrExpression":
- matched = this.visit(node.children[0], value);
- if (isFalse(matched)) {
- matched = this.visit(node.children[1], value);
- }
- return matched;
- case "AndExpression":
- first = this.visit(node.children[0], value);
-
- if (isFalse(first) === true) {
- return first;
- }
- return this.visit(node.children[1], value);
- case "NotExpression":
- first = this.visit(node.children[0], value);
- return isFalse(first);
- case "Literal":
- return node.value;
- case TOK_PIPE:
- left = this.visit(node.children[0], value);
- return this.visit(node.children[1], left);
- case TOK_CURRENT:
- return value;
- case "Function":
- var resolvedArgs = [];
- for (i = 0; i < node.children.length; i++) {
- resolvedArgs.push(this.visit(node.children[i], value));
- }
- return this.runtime.callFunction(node.name, resolvedArgs);
- case "ExpressionReference":
- var refNode = node.children[0];
- // Tag the node with a specific attribute so the type
- // checker verify the type.
- refNode.jmespathType = TOK_EXPREF;
- return refNode;
- default:
- throw new Error("Unknown node type: " + node.type);
- }
- },
-
- computeSliceParams: function(arrayLength, sliceParams) {
- var start = sliceParams[0];
- var stop = sliceParams[1];
- var step = sliceParams[2];
- var computed = [null, null, null];
- if (step === null) {
- step = 1;
- } else if (step === 0) {
- var error = new Error("Invalid slice, step cannot be 0");
- error.name = "RuntimeError";
- throw error;
- }
- var stepValueNegative = step < 0 ? true : false;
-
- if (start === null) {
- start = stepValueNegative ? arrayLength - 1 : 0;
- } else {
- start = this.capSliceRange(arrayLength, start, step);
- }
-
- if (stop === null) {
- stop = stepValueNegative ? -1 : arrayLength;
- } else {
- stop = this.capSliceRange(arrayLength, stop, step);
- }
- computed[0] = start;
- computed[1] = stop;
- computed[2] = step;
- return computed;
- },
-
- capSliceRange: function(arrayLength, actualValue, step) {
- if (actualValue < 0) {
- actualValue += arrayLength;
- if (actualValue < 0) {
- actualValue = step < 0 ? -1 : 0;
- }
- } else if (actualValue >= arrayLength) {
- actualValue = step < 0 ? arrayLength - 1 : arrayLength;
- }
- return actualValue;
- }
-
- };
-
- function Runtime(interpreter) {
- this._interpreter = interpreter;
- this.functionTable = {
- // name: [function, ]
- // The can be:
- //
- // {
- // args: [[type1, type2], [type1, type2]],
- // variadic: true|false
- // }
- //
- // Each arg in the arg list is a list of valid types
- // (if the function is overloaded and supports multiple
- // types. If the type is "any" then no type checking
- // occurs on the argument. Variadic is optional
- // and if not provided is assumed to be false.
- abs: {_func: this._functionAbs, _signature: [{types: [TYPE_NUMBER]}]},
- avg: {_func: this._functionAvg, _signature: [{types: [TYPE_ARRAY_NUMBER]}]},
- ceil: {_func: this._functionCeil, _signature: [{types: [TYPE_NUMBER]}]},
- contains: {
- _func: this._functionContains,
- _signature: [{types: [TYPE_STRING, TYPE_ARRAY]},
- {types: [TYPE_ANY]}]},
- "ends_with": {
- _func: this._functionEndsWith,
- _signature: [{types: [TYPE_STRING]}, {types: [TYPE_STRING]}]},
- floor: {_func: this._functionFloor, _signature: [{types: [TYPE_NUMBER]}]},
- length: {
- _func: this._functionLength,
- _signature: [{types: [TYPE_STRING, TYPE_ARRAY, TYPE_OBJECT]}]},
- map: {
- _func: this._functionMap,
- _signature: [{types: [TYPE_EXPREF]}, {types: [TYPE_ARRAY]}]},
- max: {
- _func: this._functionMax,
- _signature: [{types: [TYPE_ARRAY_NUMBER, TYPE_ARRAY_STRING]}]},
- "merge": {
- _func: this._functionMerge,
- _signature: [{types: [TYPE_OBJECT], variadic: true}]
- },
- "max_by": {
- _func: this._functionMaxBy,
- _signature: [{types: [TYPE_ARRAY]}, {types: [TYPE_EXPREF]}]
- },
- sum: {_func: this._functionSum, _signature: [{types: [TYPE_ARRAY_NUMBER]}]},
- "starts_with": {
- _func: this._functionStartsWith,
- _signature: [{types: [TYPE_STRING]}, {types: [TYPE_STRING]}]},
- min: {
- _func: this._functionMin,
- _signature: [{types: [TYPE_ARRAY_NUMBER, TYPE_ARRAY_STRING]}]},
- "min_by": {
- _func: this._functionMinBy,
- _signature: [{types: [TYPE_ARRAY]}, {types: [TYPE_EXPREF]}]
- },
- type: {_func: this._functionType, _signature: [{types: [TYPE_ANY]}]},
- keys: {_func: this._functionKeys, _signature: [{types: [TYPE_OBJECT]}]},
- values: {_func: this._functionValues, _signature: [{types: [TYPE_OBJECT]}]},
- sort: {_func: this._functionSort, _signature: [{types: [TYPE_ARRAY_STRING, TYPE_ARRAY_NUMBER]}]},
- "sort_by": {
- _func: this._functionSortBy,
- _signature: [{types: [TYPE_ARRAY]}, {types: [TYPE_EXPREF]}]
- },
- join: {
- _func: this._functionJoin,
- _signature: [
- {types: [TYPE_STRING]},
- {types: [TYPE_ARRAY_STRING]}
- ]
- },
- reverse: {
- _func: this._functionReverse,
- _signature: [{types: [TYPE_STRING, TYPE_ARRAY]}]},
- "to_array": {_func: this._functionToArray, _signature: [{types: [TYPE_ANY]}]},
- "to_string": {_func: this._functionToString, _signature: [{types: [TYPE_ANY]}]},
- "to_number": {_func: this._functionToNumber, _signature: [{types: [TYPE_ANY]}]},
- "not_null": {
- _func: this._functionNotNull,
- _signature: [{types: [TYPE_ANY], variadic: true}]
- }
- };
- }
-
- Runtime.prototype = {
- callFunction: function(name, resolvedArgs) {
- var functionEntry = this.functionTable[name];
- if (functionEntry === undefined) {
- throw new Error("Unknown function: " + name + "()");
- }
- this._validateArgs(name, resolvedArgs, functionEntry._signature);
- return functionEntry._func.call(this, resolvedArgs);
- },
-
- _validateArgs: function(name, args, signature) {
- // Validating the args requires validating
- // the correct arity and the correct type of each arg.
- // If the last argument is declared as variadic, then we need
- // a minimum number of args to be required. Otherwise it has to
- // be an exact amount.
- var pluralized;
- if (signature[signature.length - 1].variadic) {
- if (args.length < signature.length) {
- pluralized = signature.length === 1 ? " argument" : " arguments";
- throw new Error("ArgumentError: " + name + "() " +
- "takes at least" + signature.length + pluralized +
- " but received " + args.length);
- }
- } else if (args.length !== signature.length) {
- pluralized = signature.length === 1 ? " argument" : " arguments";
- throw new Error("ArgumentError: " + name + "() " +
- "takes " + signature.length + pluralized +
- " but received " + args.length);
- }
- var currentSpec;
- var actualType;
- var typeMatched;
- for (var i = 0; i < signature.length; i++) {
- typeMatched = false;
- currentSpec = signature[i].types;
- actualType = this._getTypeName(args[i]);
- for (var j = 0; j < currentSpec.length; j++) {
- if (this._typeMatches(actualType, currentSpec[j], args[i])) {
- typeMatched = true;
- break;
- }
- }
- if (!typeMatched) {
- throw new Error("TypeError: " + name + "() " +
- "expected argument " + (i + 1) +
- " to be type " + currentSpec +
- " but received type " + actualType +
- " instead.");
- }
- }
- },
-
- _typeMatches: function(actual, expected, argValue) {
- if (expected === TYPE_ANY) {
- return true;
- }
- if (expected === TYPE_ARRAY_STRING ||
- expected === TYPE_ARRAY_NUMBER ||
- expected === TYPE_ARRAY) {
- // The expected type can either just be array,
- // or it can require a specific subtype (array of numbers).
- //
- // The simplest case is if "array" with no subtype is specified.
- if (expected === TYPE_ARRAY) {
- return actual === TYPE_ARRAY;
- } else if (actual === TYPE_ARRAY) {
- // Otherwise we need to check subtypes.
- // I think this has potential to be improved.
- var subtype;
- if (expected === TYPE_ARRAY_NUMBER) {
- subtype = TYPE_NUMBER;
- } else if (expected === TYPE_ARRAY_STRING) {
- subtype = TYPE_STRING;
- }
- for (var i = 0; i < argValue.length; i++) {
- if (!this._typeMatches(
- this._getTypeName(argValue[i]), subtype,
- argValue[i])) {
- return false;
- }
- }
- return true;
- }
- } else {
- return actual === expected;
- }
- },
- _getTypeName: function(obj) {
- switch (Object.prototype.toString.call(obj)) {
- case "[object String]":
- return TYPE_STRING;
- case "[object Number]":
- return TYPE_NUMBER;
- case "[object Array]":
- return TYPE_ARRAY;
- case "[object Boolean]":
- return TYPE_BOOLEAN;
- case "[object Null]":
- return TYPE_NULL;
- case "[object Object]":
- // Check if it's an expref. If it has, it's been
- // tagged with a jmespathType attr of 'Expref';
- if (obj.jmespathType === TOK_EXPREF) {
- return TYPE_EXPREF;
- } else {
- return TYPE_OBJECT;
- }
- }
- },
-
- _functionStartsWith: function(resolvedArgs) {
- return resolvedArgs[0].lastIndexOf(resolvedArgs[1]) === 0;
- },
-
- _functionEndsWith: function(resolvedArgs) {
- var searchStr = resolvedArgs[0];
- var suffix = resolvedArgs[1];
- return searchStr.indexOf(suffix, searchStr.length - suffix.length) !== -1;
- },
-
- _functionReverse: function(resolvedArgs) {
- var typeName = this._getTypeName(resolvedArgs[0]);
- if (typeName === TYPE_STRING) {
- var originalStr = resolvedArgs[0];
- var reversedStr = "";
- for (var i = originalStr.length - 1; i >= 0; i--) {
- reversedStr += originalStr[i];
- }
- return reversedStr;
- } else {
- var reversedArray = resolvedArgs[0].slice(0);
- reversedArray.reverse();
- return reversedArray;
- }
- },
-
- _functionAbs: function(resolvedArgs) {
- return Math.abs(resolvedArgs[0]);
- },
-
- _functionCeil: function(resolvedArgs) {
- return Math.ceil(resolvedArgs[0]);
- },
-
- _functionAvg: function(resolvedArgs) {
- var sum = 0;
- var inputArray = resolvedArgs[0];
- for (var i = 0; i < inputArray.length; i++) {
- sum += inputArray[i];
- }
- return sum / inputArray.length;
- },
-
- _functionContains: function(resolvedArgs) {
- return resolvedArgs[0].indexOf(resolvedArgs[1]) >= 0;
- },
-
- _functionFloor: function(resolvedArgs) {
- return Math.floor(resolvedArgs[0]);
- },
-
- _functionLength: function(resolvedArgs) {
- if (!isObject(resolvedArgs[0])) {
- return resolvedArgs[0].length;
- } else {
- // As far as I can tell, there's no way to get the length
- // of an object without O(n) iteration through the object.
- return Object.keys(resolvedArgs[0]).length;
- }
- },
-
- _functionMap: function(resolvedArgs) {
- var mapped = [];
- var interpreter = this._interpreter;
- var exprefNode = resolvedArgs[0];
- var elements = resolvedArgs[1];
- for (var i = 0; i < elements.length; i++) {
- mapped.push(interpreter.visit(exprefNode, elements[i]));
- }
- return mapped;
- },
-
- _functionMerge: function(resolvedArgs) {
- var merged = {};
- for (var i = 0; i < resolvedArgs.length; i++) {
- var current = resolvedArgs[i];
- for (var key in current) {
- merged[key] = current[key];
- }
- }
- return merged;
- },
-
- _functionMax: function(resolvedArgs) {
- if (resolvedArgs[0].length > 0) {
- var typeName = this._getTypeName(resolvedArgs[0][0]);
- if (typeName === TYPE_NUMBER) {
- return Math.max.apply(Math, resolvedArgs[0]);
- } else {
- var elements = resolvedArgs[0];
- var maxElement = elements[0];
- for (var i = 1; i < elements.length; i++) {
- if (maxElement.localeCompare(elements[i]) < 0) {
- maxElement = elements[i];
- }
- }
- return maxElement;
- }
- } else {
- return null;
- }
- },
-
- _functionMin: function(resolvedArgs) {
- if (resolvedArgs[0].length > 0) {
- var typeName = this._getTypeName(resolvedArgs[0][0]);
- if (typeName === TYPE_NUMBER) {
- return Math.min.apply(Math, resolvedArgs[0]);
- } else {
- var elements = resolvedArgs[0];
- var minElement = elements[0];
- for (var i = 1; i < elements.length; i++) {
- if (elements[i].localeCompare(minElement) < 0) {
- minElement = elements[i];
- }
- }
- return minElement;
- }
- } else {
- return null;
- }
- },
-
- _functionSum: function(resolvedArgs) {
- var sum = 0;
- var listToSum = resolvedArgs[0];
- for (var i = 0; i < listToSum.length; i++) {
- sum += listToSum[i];
- }
- return sum;
- },
-
- _functionType: function(resolvedArgs) {
- switch (this._getTypeName(resolvedArgs[0])) {
- case TYPE_NUMBER:
- return "number";
- case TYPE_STRING:
- return "string";
- case TYPE_ARRAY:
- return "array";
- case TYPE_OBJECT:
- return "object";
- case TYPE_BOOLEAN:
- return "boolean";
- case TYPE_EXPREF:
- return "expref";
- case TYPE_NULL:
- return "null";
- }
- },
-
- _functionKeys: function(resolvedArgs) {
- return Object.keys(resolvedArgs[0]);
- },
-
- _functionValues: function(resolvedArgs) {
- var obj = resolvedArgs[0];
- var keys = Object.keys(obj);
- var values = [];
- for (var i = 0; i < keys.length; i++) {
- values.push(obj[keys[i]]);
- }
- return values;
- },
-
- _functionJoin: function(resolvedArgs) {
- var joinChar = resolvedArgs[0];
- var listJoin = resolvedArgs[1];
- return listJoin.join(joinChar);
- },
-
- _functionToArray: function(resolvedArgs) {
- if (this._getTypeName(resolvedArgs[0]) === TYPE_ARRAY) {
- return resolvedArgs[0];
- } else {
- return [resolvedArgs[0]];
- }
- },
-
- _functionToString: function(resolvedArgs) {
- if (this._getTypeName(resolvedArgs[0]) === TYPE_STRING) {
- return resolvedArgs[0];
- } else {
- return JSON.stringify(resolvedArgs[0]);
- }
- },
-
- _functionToNumber: function(resolvedArgs) {
- var typeName = this._getTypeName(resolvedArgs[0]);
- var convertedValue;
- if (typeName === TYPE_NUMBER) {
- return resolvedArgs[0];
- } else if (typeName === TYPE_STRING) {
- convertedValue = +resolvedArgs[0];
- if (!isNaN(convertedValue)) {
- return convertedValue;
- }
- }
- return null;
- },
-
- _functionNotNull: function(resolvedArgs) {
- for (var i = 0; i < resolvedArgs.length; i++) {
- if (this._getTypeName(resolvedArgs[i]) !== TYPE_NULL) {
- return resolvedArgs[i];
- }
- }
- return null;
- },
-
- _functionSort: function(resolvedArgs) {
- var sortedArray = resolvedArgs[0].slice(0);
- sortedArray.sort();
- return sortedArray;
- },
-
- _functionSortBy: function(resolvedArgs) {
- var sortedArray = resolvedArgs[0].slice(0);
- if (sortedArray.length === 0) {
- return sortedArray;
- }
- var interpreter = this._interpreter;
- var exprefNode = resolvedArgs[1];
- var requiredType = this._getTypeName(
- interpreter.visit(exprefNode, sortedArray[0]));
- if ([TYPE_NUMBER, TYPE_STRING].indexOf(requiredType) < 0) {
- throw new Error("TypeError");
- }
- var that = this;
- // In order to get a stable sort out of an unstable
- // sort algorithm, we decorate/sort/undecorate (DSU)
- // by creating a new list of [index, element] pairs.
- // In the cmp function, if the evaluated elements are
- // equal, then the index will be used as the tiebreaker.
- // After the decorated list has been sorted, it will be
- // undecorated to extract the original elements.
- var decorated = [];
- for (var i = 0; i < sortedArray.length; i++) {
- decorated.push([i, sortedArray[i]]);
- }
- decorated.sort(function(a, b) {
- var exprA = interpreter.visit(exprefNode, a[1]);
- var exprB = interpreter.visit(exprefNode, b[1]);
- if (that._getTypeName(exprA) !== requiredType) {
- throw new Error(
- "TypeError: expected " + requiredType + ", received " +
- that._getTypeName(exprA));
- } else if (that._getTypeName(exprB) !== requiredType) {
- throw new Error(
- "TypeError: expected " + requiredType + ", received " +
- that._getTypeName(exprB));
- }
- if (exprA > exprB) {
- return 1;
- } else if (exprA < exprB) {
- return -1;
- } else {
- // If they're equal compare the items by their
- // order to maintain relative order of equal keys
- // (i.e. to get a stable sort).
- return a[0] - b[0];
- }
- });
- // Undecorate: extract out the original list elements.
- for (var j = 0; j < decorated.length; j++) {
- sortedArray[j] = decorated[j][1];
- }
- return sortedArray;
- },
-
- _functionMaxBy: function(resolvedArgs) {
- var exprefNode = resolvedArgs[1];
- var resolvedArray = resolvedArgs[0];
- var keyFunction = this.createKeyFunction(exprefNode, [TYPE_NUMBER, TYPE_STRING]);
- var maxNumber = -Infinity;
- var maxRecord;
- var current;
- for (var i = 0; i < resolvedArray.length; i++) {
- current = keyFunction(resolvedArray[i]);
- if (current > maxNumber) {
- maxNumber = current;
- maxRecord = resolvedArray[i];
- }
- }
- return maxRecord;
- },
-
- _functionMinBy: function(resolvedArgs) {
- var exprefNode = resolvedArgs[1];
- var resolvedArray = resolvedArgs[0];
- var keyFunction = this.createKeyFunction(exprefNode, [TYPE_NUMBER, TYPE_STRING]);
- var minNumber = Infinity;
- var minRecord;
- var current;
- for (var i = 0; i < resolvedArray.length; i++) {
- current = keyFunction(resolvedArray[i]);
- if (current < minNumber) {
- minNumber = current;
- minRecord = resolvedArray[i];
- }
- }
- return minRecord;
- },
-
- createKeyFunction: function(exprefNode, allowedTypes) {
- var that = this;
- var interpreter = this._interpreter;
- var keyFunc = function(x) {
- var current = interpreter.visit(exprefNode, x);
- if (allowedTypes.indexOf(that._getTypeName(current)) < 0) {
- var msg = "TypeError: expected one of " + allowedTypes +
- ", received " + that._getTypeName(current);
- throw new Error(msg);
- }
- return current;
- };
- return keyFunc;
- }
-
- };
-
- function compile(stream) {
- var parser = new Parser();
- var ast = parser.parse(stream);
- return ast;
- }
-
- function tokenize(stream) {
- var lexer = new Lexer();
- return lexer.tokenize(stream);
- }
-
- function search(data, expression) {
- var parser = new Parser();
- // This needs to be improved. Both the interpreter and runtime depend on
- // each other. The runtime needs the interpreter to support exprefs.
- // There's likely a clean way to avoid the cyclic dependency.
- var runtime = new Runtime();
- var interpreter = new TreeInterpreter(runtime);
- runtime._interpreter = interpreter;
- var node = parser.parse(expression);
- return interpreter.search(node, data);
- }
-
- exports.tokenize = tokenize;
- exports.compile = compile;
- exports.search = search;
- exports.strictDeepEqual = strictDeepEqual;
-})( false ? undefined : exports);
-
-
-/***/ }),
-/* 5 */
-/***/ (function(module, exports, __webpack_require__) {
-
-var picoModal = __webpack_require__(13);
-var translate = __webpack_require__(1).translate;
-var util = __webpack_require__(0);
-
-/**
- * Show advanced sorting modal
- * @param {HTMLElement} container The container where to center
- * the modal and create an overlay
- * @param {JSON} json The JSON data to be sorted.
- * @param {function} onSort Callback function, invoked with
- * an object containing the selected
- * path and direction
- * @param {Object} options
- * Available options:
- * - {string} path The selected path
- * - {'asc' | 'desc'} direction The selected direction
- */
-function showSortModal (container, json, onSort, options) {
- var paths = Array.isArray(json)
- ? util.getChildPaths(json)
- : [''];
- var selectedPath = options && options.path && util.contains(paths, options.path)
- ? options.path
- : paths[0]
- var selectedDirection = options && options.direction || 'asc'
-
- var content = '';
-
- picoModal({
- parent: container,
- content: content,
- overlayClass: 'jsoneditor-modal-overlay',
- overlayStyles: {
- backgroundColor: "rgb(1,1,1)",
- opacity: 0.3
- },
- modalClass: 'jsoneditor-modal jsoneditor-modal-sort'
- })
- .afterCreate(function (modal) {
- var form = modal.modalElem().querySelector('form');
- var ok = modal.modalElem().querySelector('#ok');
- var field = modal.modalElem().querySelector('#field');
- var direction = modal.modalElem().querySelector('#direction');
-
- function preprocessPath(path) {
- return (path === '')
- ? '@'
- : (path[0] === '.')
- ? path.slice(1)
- : path;
- }
-
- paths.forEach(function (path) {
- var option = document.createElement('option');
- option.text = preprocessPath(path);
- option.value = path;
- field.appendChild(option);
- });
-
- function setDirection(value) {
- direction.value = value;
- direction.className = 'jsoneditor-button-group jsoneditor-button-group-value-' + direction.value;
- }
-
- field.value = selectedPath || paths[0];
- setDirection(selectedDirection || 'asc');
-
- direction.onclick = function (event) {
- setDirection(event.target.getAttribute('data-value'));
- };
-
- ok.onclick = function (event) {
- event.preventDefault();
- event.stopPropagation();
-
- modal.close();
-
- onSort({
- path: field.value,
- direction: direction.value
- })
- };
-
- if (form) { // form is not available when JSONEditor is created inside a form
- form.onsubmit = ok.onclick;
- }
- })
- .afterClose(function (modal) {
- modal.destroy();
- })
- .show();
-}
-
-module.exports = showSortModal;
-
-
-/***/ }),
-/* 6 */
-/***/ (function(module, exports, __webpack_require__) {
-
-var jmespath = __webpack_require__(4);
-var picoModal = __webpack_require__(13);
-var Selectr = __webpack_require__(30);
-var translate = __webpack_require__(1).translate;
-var stringifyPartial = __webpack_require__(31).stringifyPartial;
-var util = __webpack_require__(0);
-var MAX_PREVIEW_CHARACTERS = __webpack_require__(2).MAX_PREVIEW_CHARACTERS
-var debounce = util.debounce;
-
-/**
- * Show advanced filter and transform modal using JMESPath
- * @param {HTMLElement} container The container where to center
- * the modal and create an overlay
- * @param {JSON} json The json data to be transformed
- * @param {function} onTransform Callback invoked with the created
- * query as callback
- */
-function showTransformModal (container, json, onTransform) {
- var value = json;
-
- var content = '