/*!
|
|
* jsoneditor.js
|
|
*
|
|
* @brief
|
|
* JSONEditor is a web-based tool to view, edit, format, and validate JSON.
|
|
* It has various modes such as a tree editor, a code editor, and a plain text
|
|
* editor.
|
|
*
|
|
* Supported browsers: Chrome, Firefox, Safari, Opera, Internet Explorer 8+
|
|
*
|
|
* @license
|
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
|
* use this file except in compliance with the License. You may obtain a copy
|
|
* of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
* License for the specific language governing permissions and limitations under
|
|
* the License.
|
|
*
|
|
* Copyright (c) 2011-2021 Jos de Jong, http://jsoneditoronline.org
|
|
*
|
|
* @author Jos de Jong, <wjosdejong@gmail.com>
|
|
* @version 9.1.8
|
|
* @date 2021-01-16
|
|
*/
|
|
|
|
(function webpackUniversalModuleDefinition(root, factory) {
|
|
if(typeof exports === 'object' && typeof module === 'object')
|
|
module.exports = factory();
|
|
else if(typeof define === 'function' && define.amd)
|
|
define([], factory);
|
|
else if(typeof exports === 'object')
|
|
exports["JSONEditor"] = factory();
|
|
else
|
|
root["JSONEditor"] = factory();
|
|
})(self, function() {
|
|
return /******/ (function() { // webpackBootstrap
|
|
/******/ var __webpack_modules__ = ({
|
|
|
|
/***/ 6835:
|
|
/***/ (function(module) {
|
|
|
|
"use strict";
|
|
module.exports = JSON.parse("{\"$schema\":\"http://json-schema.org/draft-07/schema#\",\"$id\":\"https://raw.githubusercontent.com/ajv-validator/ajv/master/lib/refs/data.json#\",\"description\":\"Meta-schema for $data reference (JSON Schema extension proposal)\",\"type\":\"object\",\"required\":[\"$data\"],\"properties\":{\"$data\":{\"type\":\"string\",\"anyOf\":[{\"format\":\"relative-json-pointer\"},{\"format\":\"json-pointer\"}]}},\"additionalProperties\":false}");
|
|
|
|
/***/ }),
|
|
|
|
/***/ 2689:
|
|
/***/ (function(module) {
|
|
|
|
"use strict";
|
|
module.exports = JSON.parse("{\"id\":\"http://json-schema.org/draft-04/schema#\",\"$schema\":\"http://json-schema.org/draft-04/schema#\",\"description\":\"Core schema meta-schema\",\"definitions\":{\"schemaArray\":{\"type\":\"array\",\"minItems\":1,\"items\":{\"$ref\":\"#\"}},\"positiveInteger\":{\"type\":\"integer\",\"minimum\":0},\"positiveIntegerDefault0\":{\"allOf\":[{\"$ref\":\"#/definitions/positiveInteger\"},{\"default\":0}]},\"simpleTypes\":{\"enum\":[\"array\",\"boolean\",\"integer\",\"null\",\"number\",\"object\",\"string\"]},\"stringArray\":{\"type\":\"array\",\"items\":{\"type\":\"string\"},\"minItems\":1,\"uniqueItems\":true}},\"type\":\"object\",\"properties\":{\"id\":{\"type\":\"string\"},\"$schema\":{\"type\":\"string\"},\"title\":{\"type\":\"string\"},\"description\":{\"type\":\"string\"},\"default\":{},\"multipleOf\":{\"type\":\"number\",\"minimum\":0,\"exclusiveMinimum\":true},\"maximum\":{\"type\":\"number\"},\"exclusiveMaximum\":{\"type\":\"boolean\",\"default\":false},\"minimum\":{\"type\":\"number\"},\"exclusiveMinimum\":{\"type\":\"boolean\",\"default\":false},\"maxLength\":{\"$ref\":\"#/definitions/positiveInteger\"},\"minLength\":{\"$ref\":\"#/definitions/positiveIntegerDefault0\"},\"pattern\":{\"type\":\"string\",\"format\":\"regex\"},\"additionalItems\":{\"anyOf\":[{\"type\":\"boolean\"},{\"$ref\":\"#\"}],\"default\":{}},\"items\":{\"anyOf\":[{\"$ref\":\"#\"},{\"$ref\":\"#/definitions/schemaArray\"}],\"default\":{}},\"maxItems\":{\"$ref\":\"#/definitions/positiveInteger\"},\"minItems\":{\"$ref\":\"#/definitions/positiveIntegerDefault0\"},\"uniqueItems\":{\"type\":\"boolean\",\"default\":false},\"maxProperties\":{\"$ref\":\"#/definitions/positiveInteger\"},\"minProperties\":{\"$ref\":\"#/definitions/positiveIntegerDefault0\"},\"required\":{\"$ref\":\"#/definitions/stringArray\"},\"additionalProperties\":{\"anyOf\":[{\"type\":\"boolean\"},{\"$ref\":\"#\"}],\"default\":{}},\"definitions\":{\"type\":\"object\",\"additionalProperties\":{\"$ref\":\"#\"},\"default\":{}},\"properties\":{\"type\":\"object\",\"additionalProperties\":{\"$ref\":\"#\"},\"default\":{}},\"patternProperties\":{\"type\":\"object\",\"additionalProperties\":{\"$ref\":\"#\"},\"default\":{}},\"dependencies\":{\"type\":\"object\",\"additionalProperties\":{\"anyOf\":[{\"$ref\":\"#\"},{\"$ref\":\"#/definitions/stringArray\"}]}},\"enum\":{\"type\":\"array\",\"minItems\":1,\"uniqueItems\":true},\"type\":{\"anyOf\":[{\"$ref\":\"#/definitions/simpleTypes\"},{\"type\":\"array\",\"items\":{\"$ref\":\"#/definitions/simpleTypes\"},\"minItems\":1,\"uniqueItems\":true}]},\"format\":{\"type\":\"string\"},\"allOf\":{\"$ref\":\"#/definitions/schemaArray\"},\"anyOf\":{\"$ref\":\"#/definitions/schemaArray\"},\"oneOf\":{\"$ref\":\"#/definitions/schemaArray\"},\"not\":{\"$ref\":\"#\"}},\"dependencies\":{\"exclusiveMaximum\":[\"maximum\"],\"exclusiveMinimum\":[\"minimum\"]},\"default\":{}}");
|
|
|
|
/***/ }),
|
|
|
|
/***/ 1030:
|
|
/***/ (function(module) {
|
|
|
|
"use strict";
|
|
module.exports = JSON.parse("{\"$schema\":\"http://json-schema.org/draft-06/schema#\",\"$id\":\"http://json-schema.org/draft-06/schema#\",\"title\":\"Core schema meta-schema\",\"definitions\":{\"schemaArray\":{\"type\":\"array\",\"minItems\":1,\"items\":{\"$ref\":\"#\"}},\"nonNegativeInteger\":{\"type\":\"integer\",\"minimum\":0},\"nonNegativeIntegerDefault0\":{\"allOf\":[{\"$ref\":\"#/definitions/nonNegativeInteger\"},{\"default\":0}]},\"simpleTypes\":{\"enum\":[\"array\",\"boolean\",\"integer\",\"null\",\"number\",\"object\",\"string\"]},\"stringArray\":{\"type\":\"array\",\"items\":{\"type\":\"string\"},\"uniqueItems\":true,\"default\":[]}},\"type\":[\"object\",\"boolean\"],\"properties\":{\"$id\":{\"type\":\"string\",\"format\":\"uri-reference\"},\"$schema\":{\"type\":\"string\",\"format\":\"uri\"},\"$ref\":{\"type\":\"string\",\"format\":\"uri-reference\"},\"title\":{\"type\":\"string\"},\"description\":{\"type\":\"string\"},\"default\":{},\"examples\":{\"type\":\"array\",\"items\":{}},\"multipleOf\":{\"type\":\"number\",\"exclusiveMinimum\":0},\"maximum\":{\"type\":\"number\"},\"exclusiveMaximum\":{\"type\":\"number\"},\"minimum\":{\"type\":\"number\"},\"exclusiveMinimum\":{\"type\":\"number\"},\"maxLength\":{\"$ref\":\"#/definitions/nonNegativeInteger\"},\"minLength\":{\"$ref\":\"#/definitions/nonNegativeIntegerDefault0\"},\"pattern\":{\"type\":\"string\",\"format\":\"regex\"},\"additionalItems\":{\"$ref\":\"#\"},\"items\":{\"anyOf\":[{\"$ref\":\"#\"},{\"$ref\":\"#/definitions/schemaArray\"}],\"default\":{}},\"maxItems\":{\"$ref\":\"#/definitions/nonNegativeInteger\"},\"minItems\":{\"$ref\":\"#/definitions/nonNegativeIntegerDefault0\"},\"uniqueItems\":{\"type\":\"boolean\",\"default\":false},\"contains\":{\"$ref\":\"#\"},\"maxProperties\":{\"$ref\":\"#/definitions/nonNegativeInteger\"},\"minProperties\":{\"$ref\":\"#/definitions/nonNegativeIntegerDefault0\"},\"required\":{\"$ref\":\"#/definitions/stringArray\"},\"additionalProperties\":{\"$ref\":\"#\"},\"definitions\":{\"type\":\"object\",\"additionalProperties\":{\"$ref\":\"#\"},\"default\":{}},\"properties\":{\"type\":\"object\",\"additionalProperties\":{\"$ref\":\"#\"},\"default\":{}},\"patternProperties\":{\"type\":\"object\",\"additionalProperties\":{\"$ref\":\"#\"},\"default\":{}},\"dependencies\":{\"type\":\"object\",\"additionalProperties\":{\"anyOf\":[{\"$ref\":\"#\"},{\"$ref\":\"#/definitions/stringArray\"}]}},\"propertyNames\":{\"$ref\":\"#\"},\"const\":{},\"enum\":{\"type\":\"array\",\"minItems\":1,\"uniqueItems\":true},\"type\":{\"anyOf\":[{\"$ref\":\"#/definitions/simpleTypes\"},{\"type\":\"array\",\"items\":{\"$ref\":\"#/definitions/simpleTypes\"},\"minItems\":1,\"uniqueItems\":true}]},\"format\":{\"type\":\"string\"},\"allOf\":{\"$ref\":\"#/definitions/schemaArray\"},\"anyOf\":{\"$ref\":\"#/definitions/schemaArray\"},\"oneOf\":{\"$ref\":\"#/definitions/schemaArray\"},\"not\":{\"$ref\":\"#\"}},\"default\":{}}");
|
|
|
|
/***/ }),
|
|
|
|
/***/ 38:
|
|
/***/ (function(module) {
|
|
|
|
"use strict";
|
|
module.exports = JSON.parse("{\"$schema\":\"http://json-schema.org/draft-07/schema#\",\"$id\":\"http://json-schema.org/draft-07/schema#\",\"title\":\"Core schema meta-schema\",\"definitions\":{\"schemaArray\":{\"type\":\"array\",\"minItems\":1,\"items\":{\"$ref\":\"#\"}},\"nonNegativeInteger\":{\"type\":\"integer\",\"minimum\":0},\"nonNegativeIntegerDefault0\":{\"allOf\":[{\"$ref\":\"#/definitions/nonNegativeInteger\"},{\"default\":0}]},\"simpleTypes\":{\"enum\":[\"array\",\"boolean\",\"integer\",\"null\",\"number\",\"object\",\"string\"]},\"stringArray\":{\"type\":\"array\",\"items\":{\"type\":\"string\"},\"uniqueItems\":true,\"default\":[]}},\"type\":[\"object\",\"boolean\"],\"properties\":{\"$id\":{\"type\":\"string\",\"format\":\"uri-reference\"},\"$schema\":{\"type\":\"string\",\"format\":\"uri\"},\"$ref\":{\"type\":\"string\",\"format\":\"uri-reference\"},\"$comment\":{\"type\":\"string\"},\"title\":{\"type\":\"string\"},\"description\":{\"type\":\"string\"},\"default\":true,\"readOnly\":{\"type\":\"boolean\",\"default\":false},\"examples\":{\"type\":\"array\",\"items\":true},\"multipleOf\":{\"type\":\"number\",\"exclusiveMinimum\":0},\"maximum\":{\"type\":\"number\"},\"exclusiveMaximum\":{\"type\":\"number\"},\"minimum\":{\"type\":\"number\"},\"exclusiveMinimum\":{\"type\":\"number\"},\"maxLength\":{\"$ref\":\"#/definitions/nonNegativeInteger\"},\"minLength\":{\"$ref\":\"#/definitions/nonNegativeIntegerDefault0\"},\"pattern\":{\"type\":\"string\",\"format\":\"regex\"},\"additionalItems\":{\"$ref\":\"#\"},\"items\":{\"anyOf\":[{\"$ref\":\"#\"},{\"$ref\":\"#/definitions/schemaArray\"}],\"default\":true},\"maxItems\":{\"$ref\":\"#/definitions/nonNegativeInteger\"},\"minItems\":{\"$ref\":\"#/definitions/nonNegativeIntegerDefault0\"},\"uniqueItems\":{\"type\":\"boolean\",\"default\":false},\"contains\":{\"$ref\":\"#\"},\"maxProperties\":{\"$ref\":\"#/definitions/nonNegativeInteger\"},\"minProperties\":{\"$ref\":\"#/definitions/nonNegativeIntegerDefault0\"},\"required\":{\"$ref\":\"#/definitions/stringArray\"},\"additionalProperties\":{\"$ref\":\"#\"},\"definitions\":{\"type\":\"object\",\"additionalProperties\":{\"$ref\":\"#\"},\"default\":{}},\"properties\":{\"type\":\"object\",\"additionalProperties\":{\"$ref\":\"#\"},\"default\":{}},\"patternProperties\":{\"type\":\"object\",\"additionalProperties\":{\"$ref\":\"#\"},\"propertyNames\":{\"format\":\"regex\"},\"default\":{}},\"dependencies\":{\"type\":\"object\",\"additionalProperties\":{\"anyOf\":[{\"$ref\":\"#\"},{\"$ref\":\"#/definitions/stringArray\"}]}},\"propertyNames\":{\"$ref\":\"#\"},\"const\":true,\"enum\":{\"type\":\"array\",\"items\":true,\"minItems\":1,\"uniqueItems\":true},\"type\":{\"anyOf\":[{\"$ref\":\"#/definitions/simpleTypes\"},{\"type\":\"array\",\"items\":{\"$ref\":\"#/definitions/simpleTypes\"},\"minItems\":1,\"uniqueItems\":true}]},\"format\":{\"type\":\"string\"},\"contentMediaType\":{\"type\":\"string\"},\"contentEncoding\":{\"type\":\"string\"},\"if\":{\"$ref\":\"#\"},\"then\":{\"$ref\":\"#\"},\"else\":{\"$ref\":\"#\"},\"allOf\":{\"$ref\":\"#/definitions/schemaArray\"},\"anyOf\":{\"$ref\":\"#/definitions/schemaArray\"},\"oneOf\":{\"$ref\":\"#/definitions/schemaArray\"},\"not\":{\"$ref\":\"#\"}},\"default\":true}");
|
|
|
|
/***/ }),
|
|
|
|
/***/ 897:
|
|
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
|
|
|
"use strict";
|
|
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
/* harmony export */ "x": function() { return /* binding */ ContextMenu; }
|
|
/* harmony export */ });
|
|
/* harmony import */ var _createAbsoluteAnchor__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2602);
|
|
/* harmony import */ var _util__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(9791);
|
|
/* harmony import */ var _i18n__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(7907);
|
|
|
|
|
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
|
|
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
|
|
|
|
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
|
|
|
|
|
|
|
|
|
|
/**
|
|
* A context menu
|
|
* @param {Object[]} items Array containing the menu structure
|
|
* TODO: describe structure
|
|
* @param {Object} [options] Object with options. Available options:
|
|
* {function} close Callback called when the
|
|
* context menu is being closed.
|
|
* {boolean} limitHeight Whether ContextMenu height should be
|
|
* limited or not.
|
|
* @constructor
|
|
*/
|
|
|
|
var ContextMenu = /*#__PURE__*/function () {
|
|
function ContextMenu(items, options) {
|
|
_classCallCheck(this, ContextMenu);
|
|
|
|
this.dom = {};
|
|
var me = this;
|
|
var dom = this.dom;
|
|
this.anchor = undefined;
|
|
this.items = items;
|
|
this.eventListeners = {};
|
|
this.selection = undefined; // holds the selection before the menu was opened
|
|
|
|
this.onClose = options ? options.close : undefined;
|
|
this.limitHeight = options ? options.limitHeight : false; // create root element
|
|
|
|
var root = document.createElement('div');
|
|
root.className = 'jsoneditor-contextmenu-root';
|
|
dom.root = root; // create a container element
|
|
|
|
var menu = document.createElement('div');
|
|
menu.className = 'jsoneditor-contextmenu';
|
|
dom.menu = menu;
|
|
root.appendChild(menu); // create a list to hold the menu items
|
|
|
|
var list = document.createElement('ul');
|
|
list.className = 'jsoneditor-menu';
|
|
menu.appendChild(list);
|
|
dom.list = list;
|
|
dom.items = []; // list with all buttons
|
|
// create a (non-visible) button to set the focus to the menu
|
|
|
|
var focusButton = document.createElement('button');
|
|
focusButton.type = 'button';
|
|
dom.focusButton = focusButton;
|
|
var li = document.createElement('li');
|
|
li.style.overflow = 'hidden';
|
|
li.style.height = '0';
|
|
li.appendChild(focusButton);
|
|
list.appendChild(li);
|
|
|
|
function createMenuItems(list, domItems, items) {
|
|
items.forEach(function (item) {
|
|
if (item.type === 'separator') {
|
|
// create a separator
|
|
var separator = document.createElement('div');
|
|
separator.className = 'jsoneditor-separator';
|
|
|
|
var _li = document.createElement('li');
|
|
|
|
_li.appendChild(separator);
|
|
|
|
list.appendChild(_li);
|
|
} else {
|
|
var domItem = {}; // create a menu item
|
|
|
|
var _li2 = document.createElement('li');
|
|
|
|
list.appendChild(_li2); // create a button in the menu item
|
|
|
|
var button = document.createElement('button');
|
|
button.type = 'button';
|
|
button.className = item.className;
|
|
domItem.button = button;
|
|
|
|
if (item.title) {
|
|
button.title = item.title;
|
|
}
|
|
|
|
if (item.click) {
|
|
button.onclick = function (event) {
|
|
event.preventDefault();
|
|
me.hide();
|
|
item.click();
|
|
};
|
|
}
|
|
|
|
_li2.appendChild(button); // create the contents of the button
|
|
|
|
|
|
if (item.submenu) {
|
|
// add the icon to the button
|
|
var divIcon = document.createElement('div');
|
|
divIcon.className = 'jsoneditor-icon';
|
|
button.appendChild(divIcon);
|
|
var divText = document.createElement('div');
|
|
divText.className = 'jsoneditor-text' + (item.click ? '' : ' jsoneditor-right-margin');
|
|
divText.appendChild(document.createTextNode(item.text));
|
|
button.appendChild(divText);
|
|
var buttonSubmenu;
|
|
|
|
if (item.click) {
|
|
// submenu and a button with a click handler
|
|
button.className += ' jsoneditor-default';
|
|
var buttonExpand = document.createElement('button');
|
|
buttonExpand.type = 'button';
|
|
domItem.buttonExpand = buttonExpand;
|
|
buttonExpand.className = 'jsoneditor-expand';
|
|
var buttonExpandInner = document.createElement('div');
|
|
buttonExpandInner.className = 'jsoneditor-expand';
|
|
buttonExpand.appendChild(buttonExpandInner);
|
|
|
|
_li2.appendChild(buttonExpand);
|
|
|
|
if (item.submenuTitle) {
|
|
buttonExpand.title = item.submenuTitle;
|
|
}
|
|
|
|
buttonSubmenu = buttonExpand;
|
|
} else {
|
|
// submenu and a button without a click handler
|
|
var divExpand = document.createElement('div');
|
|
divExpand.className = 'jsoneditor-expand';
|
|
button.appendChild(divExpand);
|
|
buttonSubmenu = button;
|
|
} // attach a handler to expand/collapse the submenu
|
|
|
|
|
|
buttonSubmenu.onclick = function (event) {
|
|
event.preventDefault();
|
|
|
|
me._onExpandItem(domItem);
|
|
|
|
buttonSubmenu.focus();
|
|
}; // create the submenu
|
|
|
|
|
|
var domSubItems = [];
|
|
domItem.subItems = domSubItems;
|
|
var ul = document.createElement('ul');
|
|
domItem.ul = ul;
|
|
ul.className = 'jsoneditor-menu';
|
|
ul.style.height = '0';
|
|
|
|
_li2.appendChild(ul);
|
|
|
|
createMenuItems(ul, domSubItems, item.submenu);
|
|
} else {
|
|
// no submenu, just a button with clickhandler
|
|
var icon = document.createElement('div');
|
|
icon.className = 'jsoneditor-icon';
|
|
button.appendChild(icon);
|
|
var text = document.createElement('div');
|
|
text.className = 'jsoneditor-text';
|
|
text.appendChild(document.createTextNode((0,_i18n__WEBPACK_IMPORTED_MODULE_2__/* .translate */ .Iu)(item.text)));
|
|
button.appendChild(text);
|
|
}
|
|
|
|
domItems.push(domItem);
|
|
}
|
|
});
|
|
}
|
|
|
|
createMenuItems(list, this.dom.items, items); // TODO: when the editor is small, show the submenu on the right instead of inline?
|
|
// calculate the max height of the menu with one submenu expanded
|
|
|
|
this.maxHeight = 0; // height in pixels
|
|
|
|
items.forEach(function (item) {
|
|
var height = (items.length + (item.submenu ? item.submenu.length : 0)) * 24;
|
|
me.maxHeight = Math.max(me.maxHeight, height);
|
|
});
|
|
}
|
|
/**
|
|
* Get the currently visible buttons
|
|
* @return {Array.<HTMLElement>} buttons
|
|
* @private
|
|
*/
|
|
|
|
|
|
_createClass(ContextMenu, [{
|
|
key: "_getVisibleButtons",
|
|
value: function _getVisibleButtons() {
|
|
var buttons = [];
|
|
var me = this;
|
|
this.dom.items.forEach(function (item) {
|
|
buttons.push(item.button);
|
|
|
|
if (item.buttonExpand) {
|
|
buttons.push(item.buttonExpand);
|
|
}
|
|
|
|
if (item.subItems && item === me.expandedItem) {
|
|
item.subItems.forEach(function (subItem) {
|
|
buttons.push(subItem.button);
|
|
|
|
if (subItem.buttonExpand) {
|
|
buttons.push(subItem.buttonExpand);
|
|
} // TODO: change to fully recursive method
|
|
|
|
});
|
|
}
|
|
});
|
|
return buttons;
|
|
}
|
|
/**
|
|
* Attach the menu to an anchor
|
|
* @param {HTMLElement} anchor Anchor where the menu will be attached as sibling.
|
|
* @param {HTMLElement} frame The root of the JSONEditor window
|
|
* @param {Boolean=} ignoreParent ignore anchor parent in regard to the calculation of the position, needed when the parent position is absolute
|
|
*/
|
|
|
|
}, {
|
|
key: "show",
|
|
value: function show(anchor, frame, ignoreParent) {
|
|
this.hide(); // determine whether to display the menu below or above the anchor
|
|
|
|
var showBelow = true;
|
|
var parent = anchor.parentNode;
|
|
var anchorRect = anchor.getBoundingClientRect();
|
|
var parentRect = parent.getBoundingClientRect();
|
|
var frameRect = frame.getBoundingClientRect();
|
|
var me = this;
|
|
this.dom.absoluteAnchor = (0,_createAbsoluteAnchor__WEBPACK_IMPORTED_MODULE_0__/* .createAbsoluteAnchor */ .w)(anchor, frame, function () {
|
|
me.hide();
|
|
});
|
|
|
|
if (anchorRect.bottom + this.maxHeight < frameRect.bottom) {// fits below -> show below
|
|
} else if (anchorRect.top - this.maxHeight > frameRect.top) {
|
|
// fits above -> show above
|
|
showBelow = false;
|
|
} else {// doesn't fit above nor below -> show below
|
|
}
|
|
|
|
var topGap = ignoreParent ? 0 : anchorRect.top - parentRect.top; // position the menu
|
|
|
|
if (showBelow) {
|
|
// display the menu below the anchor
|
|
var anchorHeight = anchor.offsetHeight;
|
|
this.dom.menu.style.left = '0';
|
|
this.dom.menu.style.top = topGap + anchorHeight + 'px';
|
|
this.dom.menu.style.bottom = '';
|
|
} else {
|
|
// display the menu above the anchor
|
|
this.dom.menu.style.left = '0';
|
|
this.dom.menu.style.top = '';
|
|
this.dom.menu.style.bottom = '0px';
|
|
}
|
|
|
|
if (this.limitHeight) {
|
|
var margin = 10; // make sure there is a little margin left
|
|
|
|
var maxPossibleMenuHeight = showBelow ? frameRect.bottom - anchorRect.bottom - margin : anchorRect.top - frameRect.top - margin;
|
|
this.dom.list.style.maxHeight = maxPossibleMenuHeight + 'px';
|
|
this.dom.list.style.overflowY = 'auto';
|
|
} // attach the menu to the temporary, absolute anchor
|
|
// parent.insertBefore(this.dom.root, anchor);
|
|
|
|
|
|
this.dom.absoluteAnchor.appendChild(this.dom.root); // move focus to the first button in the context menu
|
|
|
|
this.selection = (0,_util__WEBPACK_IMPORTED_MODULE_1__.getSelection)();
|
|
this.anchor = anchor;
|
|
setTimeout(function () {
|
|
me.dom.focusButton.focus();
|
|
}, 0);
|
|
|
|
if (ContextMenu.visibleMenu) {
|
|
ContextMenu.visibleMenu.hide();
|
|
}
|
|
|
|
ContextMenu.visibleMenu = this;
|
|
}
|
|
/**
|
|
* Hide the context menu if visible
|
|
*/
|
|
|
|
}, {
|
|
key: "hide",
|
|
value: function hide() {
|
|
// remove temporary absolutely positioned anchor
|
|
if (this.dom.absoluteAnchor) {
|
|
this.dom.absoluteAnchor.destroy();
|
|
delete this.dom.absoluteAnchor;
|
|
} // remove the menu from the DOM
|
|
|
|
|
|
if (this.dom.root.parentNode) {
|
|
this.dom.root.parentNode.removeChild(this.dom.root);
|
|
|
|
if (this.onClose) {
|
|
this.onClose();
|
|
}
|
|
}
|
|
|
|
if (ContextMenu.visibleMenu === this) {
|
|
ContextMenu.visibleMenu = undefined;
|
|
}
|
|
}
|
|
/**
|
|
* Expand a submenu
|
|
* Any currently expanded submenu will be hided.
|
|
* @param {Object} domItem
|
|
* @private
|
|
*/
|
|
|
|
}, {
|
|
key: "_onExpandItem",
|
|
value: function _onExpandItem(domItem) {
|
|
var me = this;
|
|
var alreadyVisible = domItem === this.expandedItem; // hide the currently visible submenu
|
|
|
|
var expandedItem = this.expandedItem;
|
|
|
|
if (expandedItem) {
|
|
// var ul = expandedItem.ul;
|
|
expandedItem.ul.style.height = '0';
|
|
expandedItem.ul.style.padding = '';
|
|
setTimeout(function () {
|
|
if (me.expandedItem !== expandedItem) {
|
|
expandedItem.ul.style.display = '';
|
|
(0,_util__WEBPACK_IMPORTED_MODULE_1__.removeClassName)(expandedItem.ul.parentNode, 'jsoneditor-selected');
|
|
}
|
|
}, 300); // timeout duration must match the css transition duration
|
|
|
|
this.expandedItem = undefined;
|
|
}
|
|
|
|
if (!alreadyVisible) {
|
|
var ul = domItem.ul;
|
|
ul.style.display = 'block'; // eslint-disable-next-line no-unused-expressions
|
|
|
|
ul.clientHeight; // force a reflow in Firefox
|
|
|
|
setTimeout(function () {
|
|
if (me.expandedItem === domItem) {
|
|
var childsHeight = 0;
|
|
|
|
for (var i = 0; i < ul.childNodes.length; i++) {
|
|
childsHeight += ul.childNodes[i].clientHeight;
|
|
}
|
|
|
|
ul.style.height = childsHeight + 'px';
|
|
ul.style.padding = '5px 10px';
|
|
}
|
|
}, 0);
|
|
(0,_util__WEBPACK_IMPORTED_MODULE_1__.addClassName)(ul.parentNode, 'jsoneditor-selected');
|
|
this.expandedItem = domItem;
|
|
}
|
|
}
|
|
/**
|
|
* Handle onkeydown event
|
|
* @param {Event} event
|
|
* @private
|
|
*/
|
|
|
|
}, {
|
|
key: "_onKeyDown",
|
|
value: function _onKeyDown(event) {
|
|
var target = event.target;
|
|
var keynum = event.which;
|
|
var handled = false;
|
|
var buttons, targetIndex, prevButton, nextButton;
|
|
|
|
if (keynum === 27) {
|
|
// ESC
|
|
// hide the menu on ESC key
|
|
// restore previous selection and focus
|
|
if (this.selection) {
|
|
(0,_util__WEBPACK_IMPORTED_MODULE_1__.setSelection)(this.selection);
|
|
}
|
|
|
|
if (this.anchor) {
|
|
this.anchor.focus();
|
|
}
|
|
|
|
this.hide();
|
|
handled = true;
|
|
} else if (keynum === 9) {
|
|
// Tab
|
|
if (!event.shiftKey) {
|
|
// Tab
|
|
buttons = this._getVisibleButtons();
|
|
targetIndex = buttons.indexOf(target);
|
|
|
|
if (targetIndex === buttons.length - 1) {
|
|
// move to first button
|
|
buttons[0].focus();
|
|
handled = true;
|
|
}
|
|
} else {
|
|
// Shift+Tab
|
|
buttons = this._getVisibleButtons();
|
|
targetIndex = buttons.indexOf(target);
|
|
|
|
if (targetIndex === 0) {
|
|
// move to last button
|
|
buttons[buttons.length - 1].focus();
|
|
handled = true;
|
|
}
|
|
}
|
|
} else if (keynum === 37) {
|
|
// Arrow Left
|
|
if (target.className === 'jsoneditor-expand') {
|
|
buttons = this._getVisibleButtons();
|
|
targetIndex = buttons.indexOf(target);
|
|
prevButton = buttons[targetIndex - 1];
|
|
|
|
if (prevButton) {
|
|
prevButton.focus();
|
|
}
|
|
}
|
|
|
|
handled = true;
|
|
} else if (keynum === 38) {
|
|
// Arrow Up
|
|
buttons = this._getVisibleButtons();
|
|
targetIndex = buttons.indexOf(target);
|
|
prevButton = buttons[targetIndex - 1];
|
|
|
|
if (prevButton && prevButton.className === 'jsoneditor-expand') {
|
|
// skip expand button
|
|
prevButton = buttons[targetIndex - 2];
|
|
}
|
|
|
|
if (!prevButton) {
|
|
// move to last button
|
|
prevButton = buttons[buttons.length - 1];
|
|
}
|
|
|
|
if (prevButton) {
|
|
prevButton.focus();
|
|
}
|
|
|
|
handled = true;
|
|
} else if (keynum === 39) {
|
|
// Arrow Right
|
|
buttons = this._getVisibleButtons();
|
|
targetIndex = buttons.indexOf(target);
|
|
nextButton = buttons[targetIndex + 1];
|
|
|
|
if (nextButton && nextButton.className === 'jsoneditor-expand') {
|
|
nextButton.focus();
|
|
}
|
|
|
|
handled = true;
|
|
} else if (keynum === 40) {
|
|
// Arrow Down
|
|
buttons = this._getVisibleButtons();
|
|
targetIndex = buttons.indexOf(target);
|
|
nextButton = buttons[targetIndex + 1];
|
|
|
|
if (nextButton && nextButton.className === 'jsoneditor-expand') {
|
|
// skip expand button
|
|
nextButton = buttons[targetIndex + 2];
|
|
}
|
|
|
|
if (!nextButton) {
|
|
// move to first button
|
|
nextButton = buttons[0];
|
|
}
|
|
|
|
if (nextButton) {
|
|
nextButton.focus();
|
|
handled = true;
|
|
}
|
|
|
|
handled = true;
|
|
} // TODO: arrow left and right
|
|
|
|
|
|
if (handled) {
|
|
event.stopPropagation();
|
|
event.preventDefault();
|
|
}
|
|
}
|
|
}]);
|
|
|
|
return ContextMenu;
|
|
}(); // currently displayed context menu, a singleton. We may only have one visible context menu
|
|
|
|
ContextMenu.visibleMenu = undefined;
|
|
|
|
/***/ }),
|
|
|
|
/***/ 6436:
|
|
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
|
|
|
"use strict";
|
|
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
/* harmony export */ "Q": function() { return /* binding */ ErrorTable; }
|
|
/* harmony export */ });
|
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
|
|
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
|
|
|
|
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
|
|
|
|
/**
|
|
* Show errors and schema warnings in a clickable table view
|
|
* @param {Object} config
|
|
* @property {boolean} errorTableVisible
|
|
* @property {function (boolean) : void} onToggleVisibility
|
|
* @property {function (number)} [onFocusLine]
|
|
* @property {function (number)} onChangeHeight
|
|
* @constructor
|
|
*/
|
|
var ErrorTable = /*#__PURE__*/function () {
|
|
function ErrorTable(config) {
|
|
_classCallCheck(this, ErrorTable);
|
|
|
|
this.errorTableVisible = config.errorTableVisible;
|
|
this.onToggleVisibility = config.onToggleVisibility;
|
|
|
|
this.onFocusLine = config.onFocusLine || function () {};
|
|
|
|
this.onChangeHeight = config.onChangeHeight;
|
|
this.dom = {};
|
|
var validationErrorsContainer = document.createElement('div');
|
|
validationErrorsContainer.className = 'jsoneditor-validation-errors-container';
|
|
this.dom.validationErrorsContainer = validationErrorsContainer;
|
|
var additionalErrorsIndication = document.createElement('div');
|
|
additionalErrorsIndication.style.display = 'none';
|
|
additionalErrorsIndication.className = 'jsoneditor-additional-errors fadein';
|
|
additionalErrorsIndication.textContent = "Scroll for more \u25BF";
|
|
this.dom.additionalErrorsIndication = additionalErrorsIndication;
|
|
validationErrorsContainer.appendChild(additionalErrorsIndication);
|
|
var validationErrorIcon = document.createElement('span');
|
|
validationErrorIcon.className = 'jsoneditor-validation-error-icon';
|
|
validationErrorIcon.style.display = 'none';
|
|
this.dom.validationErrorIcon = validationErrorIcon;
|
|
var validationErrorCount = document.createElement('span');
|
|
validationErrorCount.className = 'jsoneditor-validation-error-count';
|
|
validationErrorCount.style.display = 'none';
|
|
this.dom.validationErrorCount = validationErrorCount;
|
|
this.dom.parseErrorIndication = document.createElement('span');
|
|
this.dom.parseErrorIndication.className = 'jsoneditor-parse-error-icon';
|
|
this.dom.parseErrorIndication.style.display = 'none';
|
|
}
|
|
|
|
_createClass(ErrorTable, [{
|
|
key: "getErrorTable",
|
|
value: function getErrorTable() {
|
|
return this.dom.validationErrorsContainer;
|
|
}
|
|
}, {
|
|
key: "getErrorCounter",
|
|
value: function getErrorCounter() {
|
|
return this.dom.validationErrorCount;
|
|
}
|
|
}, {
|
|
key: "getWarningIcon",
|
|
value: function getWarningIcon() {
|
|
return this.dom.validationErrorIcon;
|
|
}
|
|
}, {
|
|
key: "getErrorIcon",
|
|
value: function getErrorIcon() {
|
|
return this.dom.parseErrorIndication;
|
|
}
|
|
}, {
|
|
key: "toggleTableVisibility",
|
|
value: function toggleTableVisibility() {
|
|
this.errorTableVisible = !this.errorTableVisible;
|
|
this.onToggleVisibility(this.errorTableVisible);
|
|
}
|
|
}, {
|
|
key: "setErrors",
|
|
value: function setErrors(errors, errorLocations) {
|
|
var _this = this;
|
|
|
|
// clear any previous errors
|
|
if (this.dom.validationErrors) {
|
|
this.dom.validationErrors.parentNode.removeChild(this.dom.validationErrors);
|
|
this.dom.validationErrors = null;
|
|
this.dom.additionalErrorsIndication.style.display = 'none';
|
|
} // create the table with errors
|
|
// keep default behavior for parse errors
|
|
|
|
|
|
if (this.errorTableVisible && errors.length > 0) {
|
|
var validationErrors = document.createElement('div');
|
|
validationErrors.className = 'jsoneditor-validation-errors';
|
|
var table = document.createElement('table');
|
|
table.className = 'jsoneditor-text-errors';
|
|
validationErrors.appendChild(table);
|
|
var tbody = document.createElement('tbody');
|
|
table.appendChild(tbody);
|
|
errors.forEach(function (error) {
|
|
var line;
|
|
|
|
if (!isNaN(error.line)) {
|
|
line = error.line;
|
|
} else if (error.dataPath) {
|
|
var errLoc = errorLocations.find(function (loc) {
|
|
return loc.path === error.dataPath;
|
|
});
|
|
|
|
if (errLoc) {
|
|
line = errLoc.line + 1;
|
|
}
|
|
}
|
|
|
|
var trEl = document.createElement('tr');
|
|
trEl.className = !isNaN(line) ? 'jump-to-line' : '';
|
|
|
|
if (error.type === 'error') {
|
|
trEl.className += ' parse-error';
|
|
} else {
|
|
trEl.className += ' validation-error';
|
|
}
|
|
|
|
var td1 = document.createElement('td');
|
|
var button = document.createElement('button');
|
|
button.className = 'jsoneditor-schema-error';
|
|
td1.appendChild(button);
|
|
trEl.appendChild(td1);
|
|
var td2 = document.createElement('td');
|
|
td2.style = 'white-space: nowrap;';
|
|
td2.textContent = !isNaN(line) ? 'Ln ' + line : '';
|
|
trEl.appendChild(td2);
|
|
|
|
if (typeof error === 'string') {
|
|
var td34 = document.createElement('td');
|
|
td34.colSpan = 2;
|
|
var pre = document.createElement('pre');
|
|
pre.appendChild(document.createTextNode(error));
|
|
td34.appendChild(pre);
|
|
trEl.appendChild(td34);
|
|
} else {
|
|
var td3 = document.createElement('td');
|
|
td3.appendChild(document.createTextNode(error.dataPath || ''));
|
|
trEl.appendChild(td3);
|
|
var td4 = document.createElement('td');
|
|
|
|
var _pre = document.createElement('pre');
|
|
|
|
_pre.appendChild(document.createTextNode(error.message));
|
|
|
|
td4.appendChild(_pre);
|
|
trEl.appendChild(td4);
|
|
}
|
|
|
|
trEl.onclick = function () {
|
|
_this.onFocusLine(line);
|
|
};
|
|
|
|
tbody.appendChild(trEl);
|
|
});
|
|
this.dom.validationErrors = validationErrors;
|
|
this.dom.validationErrorsContainer.appendChild(validationErrors);
|
|
this.dom.additionalErrorsIndication.title = errors.length + ' errors total';
|
|
|
|
if (this.dom.validationErrorsContainer.clientHeight < this.dom.validationErrorsContainer.scrollHeight) {
|
|
this.dom.additionalErrorsIndication.style.display = 'block';
|
|
|
|
this.dom.validationErrorsContainer.onscroll = function () {
|
|
_this.dom.additionalErrorsIndication.style.display = _this.dom.validationErrorsContainer.clientHeight > 0 && _this.dom.validationErrorsContainer.scrollTop === 0 ? 'block' : 'none';
|
|
};
|
|
} else {
|
|
this.dom.validationErrorsContainer.onscroll = undefined;
|
|
}
|
|
|
|
var height = this.dom.validationErrorsContainer.clientHeight + (this.dom.statusBar ? this.dom.statusBar.clientHeight : 0); // this.content.style.marginBottom = (-height) + 'px';
|
|
// this.content.style.paddingBottom = height + 'px';
|
|
|
|
this.onChangeHeight(height);
|
|
} else {
|
|
this.onChangeHeight(0);
|
|
} // update the status bar
|
|
|
|
|
|
var validationErrorsCount = errors.filter(function (error) {
|
|
return error.type !== 'error';
|
|
}).length;
|
|
|
|
if (validationErrorsCount > 0) {
|
|
this.dom.validationErrorCount.style.display = 'inline';
|
|
this.dom.validationErrorCount.innerText = validationErrorsCount;
|
|
this.dom.validationErrorCount.onclick = this.toggleTableVisibility.bind(this);
|
|
this.dom.validationErrorIcon.style.display = 'inline';
|
|
this.dom.validationErrorIcon.title = validationErrorsCount + ' schema validation error(s) found';
|
|
this.dom.validationErrorIcon.onclick = this.toggleTableVisibility.bind(this);
|
|
} else {
|
|
this.dom.validationErrorCount.style.display = 'none';
|
|
this.dom.validationErrorIcon.style.display = 'none';
|
|
} // update the parse error icon
|
|
|
|
|
|
var hasParseErrors = errors.some(function (error) {
|
|
return error.type === 'error';
|
|
});
|
|
|
|
if (hasParseErrors) {
|
|
var line = errors[0].line;
|
|
this.dom.parseErrorIndication.style.display = 'block';
|
|
this.dom.parseErrorIndication.title = !isNaN(line) ? 'parse error on line ' + line : 'parse error - check that the json is valid';
|
|
this.dom.parseErrorIndication.onclick = this.toggleTableVisibility.bind(this);
|
|
} else {
|
|
this.dom.parseErrorIndication.style.display = 'none';
|
|
}
|
|
}
|
|
}]);
|
|
|
|
return ErrorTable;
|
|
}();
|
|
|
|
/***/ }),
|
|
|
|
/***/ 2474:
|
|
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
|
|
|
"use strict";
|
|
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
/* harmony export */ "R": function() { return /* binding */ FocusTracker; }
|
|
/* harmony export */ });
|
|
|
|
/**
|
|
* @constructor FocusTracker
|
|
* A custom focus tracker for a DOM element with complex internal DOM structure
|
|
* @param {[Object]} config A set of configurations for the FocusTracker
|
|
* {DOM Object} target * The DOM object to track (required)
|
|
* {Function} onFocus onFocus callback
|
|
* {Function} onBlur onBlur callback
|
|
*
|
|
* @return
|
|
*/
|
|
|
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
|
|
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
|
|
|
|
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
|
|
|
|
var FocusTracker = /*#__PURE__*/function () {
|
|
function FocusTracker(config) {
|
|
_classCallCheck(this, FocusTracker);
|
|
|
|
this.target = config.target || null;
|
|
|
|
if (!this.target) {
|
|
throw new Error('FocusTracker constructor called without a "target" to track.');
|
|
}
|
|
|
|
this.onFocus = typeof config.onFocus === 'function' ? config.onFocus : null;
|
|
this.onBlur = typeof config.onBlur === 'function' ? config.onBlur : null;
|
|
this._onClick = this._onEvent.bind(this);
|
|
|
|
this._onKeyUp = function (event) {
|
|
if (event.which === 9 || event.keyCode === 9) {
|
|
this._onEvent(event);
|
|
}
|
|
}.bind(this);
|
|
|
|
this.focusFlag = false;
|
|
this.firstEventFlag = true;
|
|
/*
|
|
Adds required (click and keyup) event listeners to the 'document' object
|
|
to track the focus of the given 'target'
|
|
*/
|
|
|
|
if (this.onFocus || this.onBlur) {
|
|
document.addEventListener('click', this._onClick);
|
|
document.addEventListener('keyup', this._onKeyUp);
|
|
}
|
|
}
|
|
/**
|
|
* Removes the event listeners on the 'document' object
|
|
* that were added to track the focus of the given 'target'
|
|
*/
|
|
|
|
|
|
_createClass(FocusTracker, [{
|
|
key: "destroy",
|
|
value: function destroy() {
|
|
document.removeEventListener('click', this._onClick);
|
|
document.removeEventListener('keyup', this._onKeyUp);
|
|
|
|
this._onEvent({
|
|
target: document.body
|
|
}); // calling _onEvent with body element in the hope that the FocusTracker is added to an element inside the body tag
|
|
|
|
}
|
|
/**
|
|
* Tracks the focus of the target and calls the onFocus and onBlur
|
|
* event callbacks if available.
|
|
* @param {Event} [event] The 'click' or 'keyup' event object,
|
|
* from the respective events set on
|
|
* document object
|
|
* @private
|
|
*/
|
|
|
|
}, {
|
|
key: "_onEvent",
|
|
value: function _onEvent(event) {
|
|
var target = event.target;
|
|
var focusFlag;
|
|
|
|
if (target === this.target) {
|
|
focusFlag = true;
|
|
} else if (this.target.contains(target) || this.target.contains(document.activeElement)) {
|
|
focusFlag = true;
|
|
} else {
|
|
focusFlag = false;
|
|
}
|
|
|
|
if (focusFlag) {
|
|
if (!this.focusFlag) {
|
|
// trigger the onFocus callback
|
|
if (this.onFocus) {
|
|
this.onFocus({
|
|
type: 'focus',
|
|
target: this.target
|
|
});
|
|
}
|
|
|
|
this.focusFlag = true;
|
|
}
|
|
} else {
|
|
if (this.focusFlag || this.firstEventFlag) {
|
|
// trigger the onBlur callback
|
|
if (this.onBlur) {
|
|
this.onBlur({
|
|
type: 'blur',
|
|
target: this.target
|
|
});
|
|
}
|
|
|
|
this.focusFlag = false;
|
|
/*
|
|
When switching from one mode to another in the editor, the FocusTracker gets recreated.
|
|
At that time, this.focusFlag will be init to 'false' and will fail the above if condition, when blur occurs
|
|
this.firstEventFlag is added to overcome that issue
|
|
*/
|
|
|
|
if (this.firstEventFlag) {
|
|
this.firstEventFlag = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}]);
|
|
|
|
return FocusTracker;
|
|
}();
|
|
|
|
/***/ }),
|
|
|
|
/***/ 3161:
|
|
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
|
|
|
|
"use strict";
|
|
|
|
|
|
var ace = __webpack_require__(8170); // may be undefined in case of minimalist bundle
|
|
|
|
|
|
var VanillaPicker = __webpack_require__(8037); // may be undefined in case of minimalist bundle
|
|
|
|
|
|
var _require = __webpack_require__(8038),
|
|
treeModeMixins = _require.treeModeMixins;
|
|
|
|
var _require2 = __webpack_require__(5956),
|
|
textModeMixins = _require2.textModeMixins;
|
|
|
|
var _require3 = __webpack_require__(341),
|
|
previewModeMixins = _require3.previewModeMixins;
|
|
|
|
var _require4 = __webpack_require__(9791),
|
|
clear = _require4.clear,
|
|
extend = _require4.extend,
|
|
getInnerText = _require4.getInnerText,
|
|
getInternetExplorerVersion = _require4.getInternetExplorerVersion,
|
|
parse = _require4.parse;
|
|
|
|
var _require5 = __webpack_require__(2744),
|
|
tryRequireAjv = _require5.tryRequireAjv;
|
|
|
|
var _require6 = __webpack_require__(2558),
|
|
showTransformModal = _require6.showTransformModal;
|
|
|
|
var _require7 = __webpack_require__(6210),
|
|
showSortModal = _require7.showSortModal;
|
|
|
|
var Ajv = tryRequireAjv();
|
|
|
|
if (typeof Promise === 'undefined') {
|
|
console.error('Promise undefined. Please load a Promise polyfill in the browser in order to use JSONEditor');
|
|
}
|
|
/**
|
|
* @constructor JSONEditor
|
|
* @param {Element} container Container element
|
|
* @param {Object} [options] Object with options. available options:
|
|
* {String} mode Editor mode. Available values:
|
|
* 'tree' (default), 'view',
|
|
* 'form', 'text', and 'code'.
|
|
* {function} onChange Callback method, triggered
|
|
* on change of contents.
|
|
* Does not pass the contents itself.
|
|
* See also `onChangeJSON` and
|
|
* `onChangeText`.
|
|
* {function} onChangeJSON Callback method, triggered
|
|
* in modes on change of contents,
|
|
* passing the changed contents
|
|
* as JSON.
|
|
* Only applicable for modes
|
|
* 'tree', 'view', and 'form'.
|
|
* {function} onChangeText Callback method, triggered
|
|
* in modes on change of contents,
|
|
* passing the changed contents
|
|
* as stringified JSON.
|
|
* {function} onError Callback method, triggered
|
|
* when an error occurs
|
|
* {Boolean} search Enable search box.
|
|
* True by default
|
|
* Only applicable for modes
|
|
* 'tree', 'view', and 'form'
|
|
* {Boolean} history Enable history (undo/redo).
|
|
* True by default
|
|
* Only applicable for modes
|
|
* 'tree', 'view', and 'form'
|
|
* {String} name Field name for the root node.
|
|
* Only applicable for modes
|
|
* 'tree', 'view', and 'form'
|
|
* {Number} indentation Number of indentation
|
|
* spaces. 4 by default.
|
|
* Only applicable for
|
|
* modes 'text' and 'code'
|
|
* {boolean} escapeUnicode If true, unicode
|
|
* characters are escaped.
|
|
* false by default.
|
|
* {boolean} sortObjectKeys If true, object keys are
|
|
* sorted before display.
|
|
* false by default.
|
|
* {function} onSelectionChange Callback method,
|
|
* triggered on node selection change
|
|
* Only applicable for modes
|
|
* 'tree', 'view', and 'form'
|
|
* {function} onTextSelectionChange Callback method,
|
|
* triggered on text selection change
|
|
* Only applicable for modes
|
|
* {HTMLElement} modalAnchor The anchor element to apply an
|
|
* overlay and display the modals in a
|
|
* centered location.
|
|
* Defaults to document.body
|
|
* 'text' and 'code'
|
|
* {function} onEvent Callback method, triggered
|
|
* when an event occurs in
|
|
* a JSON field or value.
|
|
* Only applicable for
|
|
* modes 'form', 'tree' and
|
|
* 'view'
|
|
* {function} onFocus Callback method, triggered
|
|
* when the editor comes into focus,
|
|
* passing an object {type, target},
|
|
* Applicable for all modes
|
|
* {function} onBlur Callback method, triggered
|
|
* when the editor goes out of focus,
|
|
* passing an object {type, target},
|
|
* Applicable for all modes
|
|
* {function} onClassName Callback method, triggered
|
|
* when a Node DOM is rendered. Function returns
|
|
* a css class name to be set on a node.
|
|
* Only applicable for
|
|
* modes 'form', 'tree' and
|
|
* 'view'
|
|
* {Number} maxVisibleChilds Number of children allowed for a node
|
|
* in 'tree', 'view', or 'form' mode before
|
|
* the "show more/show all" buttons appear.
|
|
* 100 by default.
|
|
*
|
|
* @param {Object | undefined} json JSON object
|
|
*/
|
|
|
|
|
|
function JSONEditor(container, options, json) {
|
|
if (!(this instanceof JSONEditor)) {
|
|
throw new Error('JSONEditor constructor called without "new".');
|
|
} // check for unsupported browser (IE8 and older)
|
|
|
|
|
|
var ieVersion = getInternetExplorerVersion();
|
|
|
|
if (ieVersion !== -1 && ieVersion < 9) {
|
|
throw new Error('Unsupported browser, IE9 or newer required. ' + 'Please install the newest version of your browser.');
|
|
}
|
|
|
|
if (options) {
|
|
// check for deprecated options
|
|
if (options.error) {
|
|
console.warn('Option "error" has been renamed to "onError"');
|
|
options.onError = options.error;
|
|
delete options.error;
|
|
}
|
|
|
|
if (options.change) {
|
|
console.warn('Option "change" has been renamed to "onChange"');
|
|
options.onChange = options.change;
|
|
delete options.change;
|
|
}
|
|
|
|
if (options.editable) {
|
|
console.warn('Option "editable" has been renamed to "onEditable"');
|
|
options.onEditable = options.editable;
|
|
delete options.editable;
|
|
} // warn if onChangeJSON is used when mode can be `text` or `code`
|
|
|
|
|
|
if (options.onChangeJSON) {
|
|
if (options.mode === 'text' || options.mode === 'code' || options.modes && (options.modes.indexOf('text') !== -1 || options.modes.indexOf('code') !== -1)) {
|
|
console.warn('Option "onChangeJSON" is not applicable to modes "text" and "code". ' + 'Use "onChangeText" or "onChange" instead.');
|
|
}
|
|
} // validate options
|
|
|
|
|
|
if (options) {
|
|
Object.keys(options).forEach(function (option) {
|
|
if (JSONEditor.VALID_OPTIONS.indexOf(option) === -1) {
|
|
console.warn('Unknown option "' + option + '". This option will be ignored');
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
if (arguments.length) {
|
|
this._create(container, options, json);
|
|
}
|
|
}
|
|
/**
|
|
* Configuration for all registered modes. Example:
|
|
* {
|
|
* tree: {
|
|
* mixin: TreeEditor,
|
|
* data: 'json'
|
|
* },
|
|
* text: {
|
|
* mixin: TextEditor,
|
|
* data: 'text'
|
|
* }
|
|
* }
|
|
*
|
|
* @type { Object.<String, {mixin: Object, data: String} > }
|
|
*/
|
|
|
|
|
|
JSONEditor.modes = {}; // debounce interval for JSON schema validation in milliseconds
|
|
|
|
JSONEditor.prototype.DEBOUNCE_INTERVAL = 150;
|
|
JSONEditor.VALID_OPTIONS = ['ajv', 'schema', 'schemaRefs', 'templates', 'ace', 'theme', 'autocomplete', 'onChange', 'onChangeJSON', 'onChangeText', 'onEditable', 'onError', 'onEvent', 'onModeChange', 'onNodeName', 'onValidate', 'onCreateMenu', 'onSelectionChange', 'onTextSelectionChange', 'onClassName', 'onFocus', 'onBlur', 'colorPicker', 'onColorPicker', 'timestampTag', 'timestampFormat', 'escapeUnicode', 'history', 'search', 'mode', 'modes', 'name', 'indentation', 'sortObjectKeys', 'navigationBar', 'statusBar', 'mainMenuBar', 'languages', 'language', 'enableSort', 'enableTransform', 'limitDragging', 'maxVisibleChilds', 'onValidationError', 'modalAnchor', 'popupAnchor', 'createQuery', 'executeQuery', 'queryDescription'];
|
|
/**
|
|
* Create the JSONEditor
|
|
* @param {Element} container Container element
|
|
* @param {Object} [options] See description in constructor
|
|
* @param {Object | undefined} json JSON object
|
|
* @private
|
|
*/
|
|
|
|
JSONEditor.prototype._create = function (container, options, json) {
|
|
this.container = container;
|
|
this.options = options || {};
|
|
this.json = json || {};
|
|
var mode = this.options.mode || this.options.modes && this.options.modes[0] || 'tree';
|
|
this.setMode(mode);
|
|
};
|
|
/**
|
|
* Destroy the editor. Clean up DOM, event listeners, and web workers.
|
|
*/
|
|
|
|
|
|
JSONEditor.prototype.destroy = function () {};
|
|
/**
|
|
* Set JSON object in editor
|
|
* @param {Object | undefined} json JSON data
|
|
*/
|
|
|
|
|
|
JSONEditor.prototype.set = function (json) {
|
|
this.json = json;
|
|
};
|
|
/**
|
|
* Get JSON from the editor
|
|
* @returns {Object} json
|
|
*/
|
|
|
|
|
|
JSONEditor.prototype.get = function () {
|
|
return this.json;
|
|
};
|
|
/**
|
|
* Set string containing JSON for the editor
|
|
* @param {String | undefined} jsonText
|
|
*/
|
|
|
|
|
|
JSONEditor.prototype.setText = function (jsonText) {
|
|
this.json = parse(jsonText);
|
|
};
|
|
/**
|
|
* Get stringified JSON contents from the editor
|
|
* @returns {String} jsonText
|
|
*/
|
|
|
|
|
|
JSONEditor.prototype.getText = function () {
|
|
return JSON.stringify(this.json);
|
|
};
|
|
/**
|
|
* Set a field name for the root node.
|
|
* @param {String | undefined} name
|
|
*/
|
|
|
|
|
|
JSONEditor.prototype.setName = function (name) {
|
|
if (!this.options) {
|
|
this.options = {};
|
|
}
|
|
|
|
this.options.name = name;
|
|
};
|
|
/**
|
|
* Get the field name for the root node.
|
|
* @return {String | undefined} name
|
|
*/
|
|
|
|
|
|
JSONEditor.prototype.getName = function () {
|
|
return this.options && this.options.name;
|
|
};
|
|
/**
|
|
* Change the mode of the editor.
|
|
* JSONEditor will be extended with all methods needed for the chosen mode.
|
|
* @param {String} mode Available modes: 'tree' (default), 'view', 'form',
|
|
* 'text', and 'code'.
|
|
*/
|
|
|
|
|
|
JSONEditor.prototype.setMode = function (mode) {
|
|
// if the mode is the same as current mode (and it's not the first time), do nothing.
|
|
if (mode === this.options.mode && this.create) {
|
|
return;
|
|
}
|
|
|
|
var container = this.container;
|
|
var options = extend({}, this.options);
|
|
var oldMode = options.mode;
|
|
var data;
|
|
var name;
|
|
options.mode = mode;
|
|
var config = JSONEditor.modes[mode];
|
|
|
|
if (config) {
|
|
try {
|
|
var asText = config.data === 'text';
|
|
name = this.getName();
|
|
data = this[asText ? 'getText' : 'get'](); // get text or json
|
|
|
|
this.destroy();
|
|
clear(this);
|
|
extend(this, config.mixin);
|
|
this.create(container, options);
|
|
this.setName(name);
|
|
this[asText ? 'setText' : 'set'](data); // set text or json
|
|
|
|
if (typeof config.load === 'function') {
|
|
try {
|
|
config.load.call(this);
|
|
} catch (err) {
|
|
console.error(err);
|
|
}
|
|
}
|
|
|
|
if (typeof options.onModeChange === 'function' && mode !== oldMode) {
|
|
try {
|
|
options.onModeChange(mode, oldMode);
|
|
} catch (err) {
|
|
console.error(err);
|
|
}
|
|
}
|
|
} catch (err) {
|
|
this._onError(err);
|
|
}
|
|
} else {
|
|
throw new Error('Unknown mode "' + options.mode + '"');
|
|
}
|
|
};
|
|
/**
|
|
* Get the current mode
|
|
* @return {string}
|
|
*/
|
|
|
|
|
|
JSONEditor.prototype.getMode = function () {
|
|
return this.options.mode;
|
|
};
|
|
/**
|
|
* Throw an error. If an error callback is configured in options.error, this
|
|
* callback will be invoked. Else, a regular error is thrown.
|
|
* @param {Error} err
|
|
* @private
|
|
*/
|
|
|
|
|
|
JSONEditor.prototype._onError = function (err) {
|
|
if (this.options && typeof this.options.onError === 'function') {
|
|
this.options.onError(err);
|
|
} else {
|
|
throw err;
|
|
}
|
|
};
|
|
/**
|
|
* Set a JSON schema for validation of the JSON object.
|
|
* To remove the schema, call JSONEditor.setSchema(null)
|
|
* @param {Object | null} schema
|
|
* @param {Object.<string, Object>=} schemaRefs Schemas that are referenced using the `$ref` property from the JSON schema that are set in the `schema` option,
|
|
+ the object structure in the form of `{reference_key: schemaObject}`
|
|
*/
|
|
|
|
|
|
JSONEditor.prototype.setSchema = function (schema, schemaRefs) {
|
|
// compile a JSON schema validator if a JSON schema is provided
|
|
if (schema) {
|
|
var ajv;
|
|
|
|
try {
|
|
// grab ajv from options if provided, else create a new instance
|
|
if (this.options.ajv) {
|
|
ajv = this.options.ajv;
|
|
} else {
|
|
ajv = Ajv({
|
|
allErrors: true,
|
|
verbose: true,
|
|
schemaId: 'auto',
|
|
$data: true
|
|
}); // support both draft-04 and draft-06 alongside the latest draft-07
|
|
|
|
ajv.addMetaSchema(__webpack_require__(2689));
|
|
ajv.addMetaSchema(__webpack_require__(1030));
|
|
}
|
|
} catch (err) {
|
|
console.warn('Failed to create an instance of Ajv, JSON Schema validation is not available. Please use a JSONEditor bundle including Ajv, or pass an instance of Ajv as via the configuration option `ajv`.');
|
|
}
|
|
|
|
if (ajv) {
|
|
if (schemaRefs) {
|
|
for (var ref in schemaRefs) {
|
|
ajv.removeSchema(ref); // When updating a schema - old refs has to be removed first
|
|
|
|
if (schemaRefs[ref]) {
|
|
ajv.addSchema(schemaRefs[ref], ref);
|
|
}
|
|
}
|
|
|
|
this.options.schemaRefs = schemaRefs;
|
|
}
|
|
|
|
this.validateSchema = ajv.compile(schema); // add schema to the options, so that when switching to an other mode,
|
|
// the set schema is not lost
|
|
|
|
this.options.schema = schema; // validate now
|
|
|
|
this.validate();
|
|
}
|
|
|
|
this.refresh(); // update DOM
|
|
} else {
|
|
// remove current schema
|
|
this.validateSchema = null;
|
|
this.options.schema = null;
|
|
this.options.schemaRefs = null;
|
|
this.validate(); // to clear current error messages
|
|
|
|
this.refresh(); // update DOM
|
|
}
|
|
};
|
|
/**
|
|
* Validate current JSON object against the configured JSON schema
|
|
* Throws an exception when no JSON schema is configured
|
|
*/
|
|
|
|
|
|
JSONEditor.prototype.validate = function () {// must be implemented by treemode and textmode
|
|
};
|
|
/**
|
|
* Refresh the rendered contents
|
|
*/
|
|
|
|
|
|
JSONEditor.prototype.refresh = function () {// can be implemented by treemode and textmode
|
|
};
|
|
/**
|
|
* Register a plugin with one ore multiple modes for the JSON Editor.
|
|
*
|
|
* A mode is described as an object with properties:
|
|
*
|
|
* - `mode: String` The name of the mode.
|
|
* - `mixin: Object` An object containing the mixin functions which
|
|
* will be added to the JSONEditor. Must contain functions
|
|
* create, get, getText, set, and setText. May have
|
|
* additional functions.
|
|
* When the JSONEditor switches to a mixin, all mixin
|
|
* functions are added to the JSONEditor, and then
|
|
* the function `create(container, options)` is executed.
|
|
* - `data: 'text' | 'json'` The type of data that will be used to load the mixin.
|
|
* - `[load: function]` An optional function called after the mixin
|
|
* has been loaded.
|
|
*
|
|
* @param {Object | Array} mode A mode object or an array with multiple mode objects.
|
|
*/
|
|
|
|
|
|
JSONEditor.registerMode = function (mode) {
|
|
var i, prop;
|
|
|
|
if (Array.isArray(mode)) {
|
|
// multiple modes
|
|
for (i = 0; i < mode.length; i++) {
|
|
JSONEditor.registerMode(mode[i]);
|
|
}
|
|
} else {
|
|
// validate the new mode
|
|
if (!('mode' in mode)) throw new Error('Property "mode" missing');
|
|
if (!('mixin' in mode)) throw new Error('Property "mixin" missing');
|
|
if (!('data' in mode)) throw new Error('Property "data" missing');
|
|
var name = mode.mode;
|
|
|
|
if (name in JSONEditor.modes) {
|
|
throw new Error('Mode "' + name + '" already registered');
|
|
} // validate the mixin
|
|
|
|
|
|
if (typeof mode.mixin.create !== 'function') {
|
|
throw new Error('Required function "create" missing on mixin');
|
|
}
|
|
|
|
var reserved = ['setMode', 'registerMode', 'modes'];
|
|
|
|
for (i = 0; i < reserved.length; i++) {
|
|
prop = reserved[i];
|
|
|
|
if (prop in mode.mixin) {
|
|
throw new Error('Reserved property "' + prop + '" not allowed in mixin');
|
|
}
|
|
}
|
|
|
|
JSONEditor.modes[name] = mode;
|
|
}
|
|
}; // register tree, text, and preview modes
|
|
|
|
|
|
JSONEditor.registerMode(treeModeMixins);
|
|
JSONEditor.registerMode(textModeMixins);
|
|
JSONEditor.registerMode(previewModeMixins); // expose some of the libraries that can be used customized
|
|
|
|
JSONEditor.ace = ace;
|
|
JSONEditor.Ajv = Ajv;
|
|
JSONEditor.VanillaPicker = VanillaPicker; // expose some utils (this is undocumented, unofficial)
|
|
|
|
JSONEditor.showTransformModal = showTransformModal;
|
|
JSONEditor.showSortModal = showSortModal;
|
|
JSONEditor.getInnerText = getInnerText; // default export for TypeScript ES6 projects
|
|
|
|
JSONEditor["default"] = JSONEditor;
|
|
module.exports = JSONEditor;
|
|
|
|
/***/ }),
|
|
|
|
/***/ 6617:
|
|
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
|
|
|
"use strict";
|
|
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
/* harmony export */ "x": function() { return /* binding */ ModeSwitcher; }
|
|
/* harmony export */ });
|
|
/* harmony import */ var _ContextMenu__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(897);
|
|
/* harmony import */ var _i18n__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(7907);
|
|
|
|
|
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
|
|
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
|
|
|
|
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
|
|
|
|
|
|
|
|
/**
|
|
* Create a select box to be used in the editor menu's, which allows to switch mode
|
|
* @param {HTMLElement} container
|
|
* @param {String[]} modes Available modes: 'code', 'form', 'text', 'tree', 'view', 'preview'
|
|
* @param {String} current Available modes: 'code', 'form', 'text', 'tree', 'view', 'preview'
|
|
* @param {function(mode: string)} onSwitch Callback invoked on switch
|
|
* @constructor
|
|
*/
|
|
|
|
var ModeSwitcher = /*#__PURE__*/function () {
|
|
function ModeSwitcher(container, modes, current, onSwitch) {
|
|
_classCallCheck(this, ModeSwitcher);
|
|
|
|
// available modes
|
|
var availableModes = {
|
|
code: {
|
|
text: (0,_i18n__WEBPACK_IMPORTED_MODULE_1__/* .translate */ .Iu)('modeCodeText'),
|
|
title: (0,_i18n__WEBPACK_IMPORTED_MODULE_1__/* .translate */ .Iu)('modeCodeTitle'),
|
|
click: function click() {
|
|
onSwitch('code');
|
|
}
|
|
},
|
|
form: {
|
|
text: (0,_i18n__WEBPACK_IMPORTED_MODULE_1__/* .translate */ .Iu)('modeFormText'),
|
|
title: (0,_i18n__WEBPACK_IMPORTED_MODULE_1__/* .translate */ .Iu)('modeFormTitle'),
|
|
click: function click() {
|
|
onSwitch('form');
|
|
}
|
|
},
|
|
text: {
|
|
text: (0,_i18n__WEBPACK_IMPORTED_MODULE_1__/* .translate */ .Iu)('modeTextText'),
|
|
title: (0,_i18n__WEBPACK_IMPORTED_MODULE_1__/* .translate */ .Iu)('modeTextTitle'),
|
|
click: function click() {
|
|
onSwitch('text');
|
|
}
|
|
},
|
|
tree: {
|
|
text: (0,_i18n__WEBPACK_IMPORTED_MODULE_1__/* .translate */ .Iu)('modeTreeText'),
|
|
title: (0,_i18n__WEBPACK_IMPORTED_MODULE_1__/* .translate */ .Iu)('modeTreeTitle'),
|
|
click: function click() {
|
|
onSwitch('tree');
|
|
}
|
|
},
|
|
view: {
|
|
text: (0,_i18n__WEBPACK_IMPORTED_MODULE_1__/* .translate */ .Iu)('modeViewText'),
|
|
title: (0,_i18n__WEBPACK_IMPORTED_MODULE_1__/* .translate */ .Iu)('modeViewTitle'),
|
|
click: function click() {
|
|
onSwitch('view');
|
|
}
|
|
},
|
|
preview: {
|
|
text: (0,_i18n__WEBPACK_IMPORTED_MODULE_1__/* .translate */ .Iu)('modePreviewText'),
|
|
title: (0,_i18n__WEBPACK_IMPORTED_MODULE_1__/* .translate */ .Iu)('modePreviewTitle'),
|
|
click: function click() {
|
|
onSwitch('preview');
|
|
}
|
|
}
|
|
}; // list the selected modes
|
|
|
|
var items = [];
|
|
|
|
for (var i = 0; i < modes.length; i++) {
|
|
var mode = modes[i];
|
|
var item = availableModes[mode];
|
|
|
|
if (!item) {
|
|
throw new Error('Unknown mode "' + mode + '"');
|
|
}
|
|
|
|
item.className = 'jsoneditor-type-modes' + (current === mode ? ' jsoneditor-selected' : '');
|
|
items.push(item);
|
|
} // retrieve the title of current mode
|
|
|
|
|
|
var currentMode = availableModes[current];
|
|
|
|
if (!currentMode) {
|
|
throw new Error('Unknown mode "' + current + '"');
|
|
}
|
|
|
|
var currentTitle = currentMode.text; // create the html element
|
|
|
|
var box = document.createElement('button');
|
|
box.type = 'button';
|
|
box.className = 'jsoneditor-modes jsoneditor-separator';
|
|
box.textContent = currentTitle + " \u25BE";
|
|
box.title = (0,_i18n__WEBPACK_IMPORTED_MODULE_1__/* .translate */ .Iu)('modeEditorTitle');
|
|
|
|
box.onclick = function () {
|
|
var menu = new _ContextMenu__WEBPACK_IMPORTED_MODULE_0__/* .ContextMenu */ .x(items);
|
|
menu.show(box, container);
|
|
};
|
|
|
|
var frame = document.createElement('div');
|
|
frame.className = 'jsoneditor-modes';
|
|
frame.style.position = 'relative';
|
|
frame.appendChild(box);
|
|
container.appendChild(frame);
|
|
this.dom = {
|
|
container: container,
|
|
box: box,
|
|
frame: frame
|
|
};
|
|
}
|
|
/**
|
|
* Set focus to switcher
|
|
*/
|
|
|
|
|
|
_createClass(ModeSwitcher, [{
|
|
key: "focus",
|
|
value: function focus() {
|
|
this.dom.box.focus();
|
|
}
|
|
/**
|
|
* Destroy the ModeSwitcher, remove from DOM
|
|
*/
|
|
|
|
}, {
|
|
key: "destroy",
|
|
value: function destroy() {
|
|
if (this.dom && this.dom.frame && this.dom.frame.parentNode) {
|
|
this.dom.frame.parentNode.removeChild(this.dom.frame);
|
|
}
|
|
|
|
this.dom = null;
|
|
}
|
|
}]);
|
|
|
|
return ModeSwitcher;
|
|
}();
|
|
|
|
/***/ }),
|
|
|
|
/***/ 8170:
|
|
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
|
|
|
|
var ace;
|
|
|
|
if (window.ace) {
|
|
// use the already loaded instance of Ace
|
|
ace = window.ace;
|
|
} else {
|
|
try {
|
|
// load Ace editor
|
|
ace = __webpack_require__(6225); // load required Ace plugins
|
|
|
|
__webpack_require__(4091);
|
|
|
|
__webpack_require__(3330); // embed Ace json worker
|
|
// https://github.com/ajaxorg/ace/issues/3913
|
|
|
|
|
|
var jsonWorkerDataUrl = __webpack_require__(7923);
|
|
|
|
ace.config.setModuleUrl('ace/mode/json_worker', jsonWorkerDataUrl);
|
|
} catch (err) {// failed to load Ace (can be minimalist bundle).
|
|
// No worries, the editor will fall back to plain text if needed.
|
|
}
|
|
}
|
|
|
|
module.exports = ace;
|
|
|
|
/***/ }),
|
|
|
|
/***/ 4864:
|
|
/***/ (function() {
|
|
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
* Distributed under the BSD license:
|
|
*
|
|
* Copyright (c) 2010, Ajax.org B.V.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
* * Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* * Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* * Neither the name of Ajax.org B.V. nor the
|
|
* names of its contributors may be used to endorse or promote products
|
|
* derived from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
* ***** END LICENSE BLOCK ***** */
|
|
window.ace.define('ace/theme/jsoneditor', ['require', 'exports', 'module', 'ace/lib/dom'], function (acequire, exports, module) {
|
|
exports.isDark = false;
|
|
exports.cssClass = 'ace-jsoneditor';
|
|
exports.cssText = ".ace-jsoneditor .ace_gutter {\nbackground: #ebebeb;\ncolor: #333\n}\n\n.ace-jsoneditor.ace_editor {\nfont-family: \"dejavu sans mono\", \"droid sans mono\", consolas, monaco, \"lucida console\", \"courier new\", courier, monospace, sans-serif;\nline-height: 1.3;\nbackground-color: #fff;\n}\n.ace-jsoneditor .ace_print-margin {\nwidth: 1px;\nbackground: #e8e8e8\n}\n.ace-jsoneditor .ace_scroller {\nbackground-color: #FFFFFF\n}\n.ace-jsoneditor .ace_text-layer {\ncolor: gray\n}\n.ace-jsoneditor .ace_variable {\ncolor: #1a1a1a\n}\n.ace-jsoneditor .ace_cursor {\nborder-left: 2px solid #000000\n}\n.ace-jsoneditor .ace_overwrite-cursors .ace_cursor {\nborder-left: 0px;\nborder-bottom: 1px solid #000000\n}\n.ace-jsoneditor .ace_marker-layer .ace_selection {\nbackground: lightgray\n}\n.ace-jsoneditor.ace_multiselect .ace_selection.ace_start {\nbox-shadow: 0 0 3px 0px #FFFFFF;\nborder-radius: 2px\n}\n.ace-jsoneditor .ace_marker-layer .ace_step {\nbackground: rgb(255, 255, 0)\n}\n.ace-jsoneditor .ace_marker-layer .ace_bracket {\nmargin: -1px 0 0 -1px;\nborder: 1px solid #BFBFBF\n}\n.ace-jsoneditor .ace_marker-layer .ace_active-line {\nbackground: #FFFBD1\n}\n.ace-jsoneditor .ace_gutter-active-line {\nbackground-color : #dcdcdc\n}\n.ace-jsoneditor .ace_marker-layer .ace_selected-word {\nborder: 1px solid lightgray\n}\n.ace-jsoneditor .ace_invisible {\ncolor: #BFBFBF\n}\n.ace-jsoneditor .ace_keyword,\n.ace-jsoneditor .ace_meta,\n.ace-jsoneditor .ace_support.ace_constant.ace_property-value {\ncolor: #AF956F\n}\n.ace-jsoneditor .ace_keyword.ace_operator {\ncolor: #484848\n}\n.ace-jsoneditor .ace_keyword.ace_other.ace_unit {\ncolor: #96DC5F\n}\n.ace-jsoneditor .ace_constant.ace_language {\ncolor: darkorange\n}\n.ace-jsoneditor .ace_constant.ace_numeric {\ncolor: red\n}\n.ace-jsoneditor .ace_constant.ace_character.ace_entity {\ncolor: #BF78CC\n}\n.ace-jsoneditor .ace_invalid {\ncolor: #FFFFFF;\nbackground-color: #FF002A;\n}\n.ace-jsoneditor .ace_fold {\nbackground-color: #AF956F;\nborder-color: #000000\n}\n.ace-jsoneditor .ace_storage,\n.ace-jsoneditor .ace_support.ace_class,\n.ace-jsoneditor .ace_support.ace_function,\n.ace-jsoneditor .ace_support.ace_other,\n.ace-jsoneditor .ace_support.ace_type {\ncolor: #C52727\n}\n.ace-jsoneditor .ace_string {\ncolor: green\n}\n.ace-jsoneditor .ace_comment {\ncolor: #BCC8BA\n}\n.ace-jsoneditor .ace_entity.ace_name.ace_tag,\n.ace-jsoneditor .ace_entity.ace_other.ace_attribute-name {\ncolor: #606060\n}\n.ace-jsoneditor .ace_markup.ace_underline {\ntext-decoration: underline\n}\n.ace-jsoneditor .ace_indent-guide {\nbackground: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAE0lEQVQImWP4////f4bLly//BwAmVgd1/w11/gAAAABJRU5ErkJggg==\") right repeat-y\n}";
|
|
var dom = acequire('../lib/dom');
|
|
dom.importCssString(exports.cssText, exports.cssClass);
|
|
});
|
|
|
|
/***/ }),
|
|
|
|
/***/ 6589:
|
|
/***/ (function(__unused_webpack_module, exports) {
|
|
|
|
/* Jison generated parser */
|
|
var jsonlint = function () {
|
|
var parser = {
|
|
trace: function trace() {},
|
|
yy: {},
|
|
symbols_: {
|
|
"error": 2,
|
|
"JSONString": 3,
|
|
"STRING": 4,
|
|
"JSONNumber": 5,
|
|
"NUMBER": 6,
|
|
"JSONNullLiteral": 7,
|
|
"NULL": 8,
|
|
"JSONBooleanLiteral": 9,
|
|
"TRUE": 10,
|
|
"FALSE": 11,
|
|
"JSONText": 12,
|
|
"JSONValue": 13,
|
|
"EOF": 14,
|
|
"JSONObject": 15,
|
|
"JSONArray": 16,
|
|
"{": 17,
|
|
"}": 18,
|
|
"JSONMemberList": 19,
|
|
"JSONMember": 20,
|
|
":": 21,
|
|
",": 22,
|
|
"[": 23,
|
|
"]": 24,
|
|
"JSONElementList": 25,
|
|
"$accept": 0,
|
|
"$end": 1
|
|
},
|
|
terminals_: {
|
|
2: "error",
|
|
4: "STRING",
|
|
6: "NUMBER",
|
|
8: "NULL",
|
|
10: "TRUE",
|
|
11: "FALSE",
|
|
14: "EOF",
|
|
17: "{",
|
|
18: "}",
|
|
21: ":",
|
|
22: ",",
|
|
23: "[",
|
|
24: "]"
|
|
},
|
|
productions_: [0, [3, 1], [5, 1], [7, 1], [9, 1], [9, 1], [12, 2], [13, 1], [13, 1], [13, 1], [13, 1], [13, 1], [13, 1], [15, 2], [15, 3], [20, 3], [19, 1], [19, 3], [16, 2], [16, 3], [25, 1], [25, 3]],
|
|
performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate, $$, _$) {
|
|
var $0 = $$.length - 1;
|
|
|
|
switch (yystate) {
|
|
case 1:
|
|
// replace escaped characters with actual character
|
|
this.$ = yytext.replace(/\\(\\|")/g, "$" + "1").replace(/\\n/g, '\n').replace(/\\r/g, '\r').replace(/\\t/g, '\t').replace(/\\v/g, '\v').replace(/\\f/g, '\f').replace(/\\b/g, '\b');
|
|
break;
|
|
|
|
case 2:
|
|
this.$ = Number(yytext);
|
|
break;
|
|
|
|
case 3:
|
|
this.$ = null;
|
|
break;
|
|
|
|
case 4:
|
|
this.$ = true;
|
|
break;
|
|
|
|
case 5:
|
|
this.$ = false;
|
|
break;
|
|
|
|
case 6:
|
|
return this.$ = $$[$0 - 1];
|
|
break;
|
|
|
|
case 13:
|
|
this.$ = {};
|
|
break;
|
|
|
|
case 14:
|
|
this.$ = $$[$0 - 1];
|
|
break;
|
|
|
|
case 15:
|
|
this.$ = [$$[$0 - 2], $$[$0]];
|
|
break;
|
|
|
|
case 16:
|
|
this.$ = {};
|
|
this.$[$$[$0][0]] = $$[$0][1];
|
|
break;
|
|
|
|
case 17:
|
|
this.$ = $$[$0 - 2];
|
|
$$[$0 - 2][$$[$0][0]] = $$[$0][1];
|
|
break;
|
|
|
|
case 18:
|
|
this.$ = [];
|
|
break;
|
|
|
|
case 19:
|
|
this.$ = $$[$0 - 1];
|
|
break;
|
|
|
|
case 20:
|
|
this.$ = [$$[$0]];
|
|
break;
|
|
|
|
case 21:
|
|
this.$ = $$[$0 - 2];
|
|
$$[$0 - 2].push($$[$0]);
|
|
break;
|
|
}
|
|
},
|
|
table: [{
|
|
3: 5,
|
|
4: [1, 12],
|
|
5: 6,
|
|
6: [1, 13],
|
|
7: 3,
|
|
8: [1, 9],
|
|
9: 4,
|
|
10: [1, 10],
|
|
11: [1, 11],
|
|
12: 1,
|
|
13: 2,
|
|
15: 7,
|
|
16: 8,
|
|
17: [1, 14],
|
|
23: [1, 15]
|
|
}, {
|
|
1: [3]
|
|
}, {
|
|
14: [1, 16]
|
|
}, {
|
|
14: [2, 7],
|
|
18: [2, 7],
|
|
22: [2, 7],
|
|
24: [2, 7]
|
|
}, {
|
|
14: [2, 8],
|
|
18: [2, 8],
|
|
22: [2, 8],
|
|
24: [2, 8]
|
|
}, {
|
|
14: [2, 9],
|
|
18: [2, 9],
|
|
22: [2, 9],
|
|
24: [2, 9]
|
|
}, {
|
|
14: [2, 10],
|
|
18: [2, 10],
|
|
22: [2, 10],
|
|
24: [2, 10]
|
|
}, {
|
|
14: [2, 11],
|
|
18: [2, 11],
|
|
22: [2, 11],
|
|
24: [2, 11]
|
|
}, {
|
|
14: [2, 12],
|
|
18: [2, 12],
|
|
22: [2, 12],
|
|
24: [2, 12]
|
|
}, {
|
|
14: [2, 3],
|
|
18: [2, 3],
|
|
22: [2, 3],
|
|
24: [2, 3]
|
|
}, {
|
|
14: [2, 4],
|
|
18: [2, 4],
|
|
22: [2, 4],
|
|
24: [2, 4]
|
|
}, {
|
|
14: [2, 5],
|
|
18: [2, 5],
|
|
22: [2, 5],
|
|
24: [2, 5]
|
|
}, {
|
|
14: [2, 1],
|
|
18: [2, 1],
|
|
21: [2, 1],
|
|
22: [2, 1],
|
|
24: [2, 1]
|
|
}, {
|
|
14: [2, 2],
|
|
18: [2, 2],
|
|
22: [2, 2],
|
|
24: [2, 2]
|
|
}, {
|
|
3: 20,
|
|
4: [1, 12],
|
|
18: [1, 17],
|
|
19: 18,
|
|
20: 19
|
|
}, {
|
|
3: 5,
|
|
4: [1, 12],
|
|
5: 6,
|
|
6: [1, 13],
|
|
7: 3,
|
|
8: [1, 9],
|
|
9: 4,
|
|
10: [1, 10],
|
|
11: [1, 11],
|
|
13: 23,
|
|
15: 7,
|
|
16: 8,
|
|
17: [1, 14],
|
|
23: [1, 15],
|
|
24: [1, 21],
|
|
25: 22
|
|
}, {
|
|
1: [2, 6]
|
|
}, {
|
|
14: [2, 13],
|
|
18: [2, 13],
|
|
22: [2, 13],
|
|
24: [2, 13]
|
|
}, {
|
|
18: [1, 24],
|
|
22: [1, 25]
|
|
}, {
|
|
18: [2, 16],
|
|
22: [2, 16]
|
|
}, {
|
|
21: [1, 26]
|
|
}, {
|
|
14: [2, 18],
|
|
18: [2, 18],
|
|
22: [2, 18],
|
|
24: [2, 18]
|
|
}, {
|
|
22: [1, 28],
|
|
24: [1, 27]
|
|
}, {
|
|
22: [2, 20],
|
|
24: [2, 20]
|
|
}, {
|
|
14: [2, 14],
|
|
18: [2, 14],
|
|
22: [2, 14],
|
|
24: [2, 14]
|
|
}, {
|
|
3: 20,
|
|
4: [1, 12],
|
|
20: 29
|
|
}, {
|
|
3: 5,
|
|
4: [1, 12],
|
|
5: 6,
|
|
6: [1, 13],
|
|
7: 3,
|
|
8: [1, 9],
|
|
9: 4,
|
|
10: [1, 10],
|
|
11: [1, 11],
|
|
13: 30,
|
|
15: 7,
|
|
16: 8,
|
|
17: [1, 14],
|
|
23: [1, 15]
|
|
}, {
|
|
14: [2, 19],
|
|
18: [2, 19],
|
|
22: [2, 19],
|
|
24: [2, 19]
|
|
}, {
|
|
3: 5,
|
|
4: [1, 12],
|
|
5: 6,
|
|
6: [1, 13],
|
|
7: 3,
|
|
8: [1, 9],
|
|
9: 4,
|
|
10: [1, 10],
|
|
11: [1, 11],
|
|
13: 31,
|
|
15: 7,
|
|
16: 8,
|
|
17: [1, 14],
|
|
23: [1, 15]
|
|
}, {
|
|
18: [2, 17],
|
|
22: [2, 17]
|
|
}, {
|
|
18: [2, 15],
|
|
22: [2, 15]
|
|
}, {
|
|
22: [2, 21],
|
|
24: [2, 21]
|
|
}],
|
|
defaultActions: {
|
|
16: [2, 6]
|
|
},
|
|
parseError: function parseError(str, hash) {
|
|
throw new Error(str);
|
|
},
|
|
parse: function parse(input) {
|
|
var self = this,
|
|
stack = [0],
|
|
vstack = [null],
|
|
// semantic value stack
|
|
lstack = [],
|
|
// location stack
|
|
table = this.table,
|
|
yytext = '',
|
|
yylineno = 0,
|
|
yyleng = 0,
|
|
recovering = 0,
|
|
TERROR = 2,
|
|
EOF = 1; //this.reductionCount = this.shiftCount = 0;
|
|
|
|
this.lexer.setInput(input);
|
|
this.lexer.yy = this.yy;
|
|
this.yy.lexer = this.lexer;
|
|
if (typeof this.lexer.yylloc == 'undefined') this.lexer.yylloc = {};
|
|
var yyloc = this.lexer.yylloc;
|
|
lstack.push(yyloc);
|
|
if (typeof this.yy.parseError === 'function') this.parseError = this.yy.parseError;
|
|
|
|
function popStack(n) {
|
|
stack.length = stack.length - 2 * n;
|
|
vstack.length = vstack.length - n;
|
|
lstack.length = lstack.length - n;
|
|
}
|
|
|
|
function lex() {
|
|
var token;
|
|
token = self.lexer.lex() || 1; // $end = 1
|
|
// if token isn't its numeric value, convert
|
|
|
|
if (typeof token !== 'number') {
|
|
token = self.symbols_[token] || token;
|
|
}
|
|
|
|
return token;
|
|
}
|
|
|
|
var symbol,
|
|
preErrorSymbol,
|
|
state,
|
|
action,
|
|
a,
|
|
r,
|
|
yyval = {},
|
|
p,
|
|
len,
|
|
newState,
|
|
expected;
|
|
|
|
while (true) {
|
|
// retreive state number from top of stack
|
|
state = stack[stack.length - 1]; // use default actions if available
|
|
|
|
if (this.defaultActions[state]) {
|
|
action = this.defaultActions[state];
|
|
} else {
|
|
if (symbol == null) symbol = lex(); // read action for current state and first input
|
|
|
|
action = table[state] && table[state][symbol];
|
|
} // handle parse error
|
|
|
|
|
|
_handle_error: if (typeof action === 'undefined' || !action.length || !action[0]) {
|
|
if (!recovering) {
|
|
// Report error
|
|
expected = [];
|
|
|
|
for (p in table[state]) {
|
|
if (this.terminals_[p] && p > 2) {
|
|
expected.push("'" + this.terminals_[p] + "'");
|
|
}
|
|
}
|
|
|
|
var errStr = '';
|
|
|
|
if (this.lexer.showPosition) {
|
|
errStr = 'Parse error on line ' + (yylineno + 1) + ":\n" + this.lexer.showPosition() + "\nExpecting " + expected.join(', ') + ", got '" + this.terminals_[symbol] + "'";
|
|
} else {
|
|
errStr = 'Parse error on line ' + (yylineno + 1) + ": Unexpected " + (symbol == 1
|
|
/*EOF*/
|
|
? "end of input" : "'" + (this.terminals_[symbol] || symbol) + "'");
|
|
}
|
|
|
|
this.parseError(errStr, {
|
|
text: this.lexer.match,
|
|
token: this.terminals_[symbol] || symbol,
|
|
line: this.lexer.yylineno,
|
|
loc: yyloc,
|
|
expected: expected
|
|
});
|
|
} // just recovered from another error
|
|
|
|
|
|
if (recovering == 3) {
|
|
if (symbol == EOF) {
|
|
throw new Error(errStr || 'Parsing halted.');
|
|
} // discard current lookahead and grab another
|
|
|
|
|
|
yyleng = this.lexer.yyleng;
|
|
yytext = this.lexer.yytext;
|
|
yylineno = this.lexer.yylineno;
|
|
yyloc = this.lexer.yylloc;
|
|
symbol = lex();
|
|
} // try to recover from error
|
|
|
|
|
|
while (1) {
|
|
// check for error recovery rule in this state
|
|
if (TERROR.toString() in table[state]) {
|
|
break;
|
|
}
|
|
|
|
if (state == 0) {
|
|
throw new Error(errStr || 'Parsing halted.');
|
|
}
|
|
|
|
popStack(1);
|
|
state = stack[stack.length - 1];
|
|
}
|
|
|
|
preErrorSymbol = symbol; // save the lookahead token
|
|
|
|
symbol = TERROR; // insert generic error symbol as new lookahead
|
|
|
|
state = stack[stack.length - 1];
|
|
action = table[state] && table[state][TERROR];
|
|
recovering = 3; // allow 3 real symbols to be shifted before reporting a new error
|
|
} // this shouldn't happen, unless resolve defaults are off
|
|
|
|
|
|
if (action[0] instanceof Array && action.length > 1) {
|
|
throw new Error('Parse Error: multiple actions possible at state: ' + state + ', token: ' + symbol);
|
|
}
|
|
|
|
switch (action[0]) {
|
|
case 1:
|
|
// shift
|
|
//this.shiftCount++;
|
|
stack.push(symbol);
|
|
vstack.push(this.lexer.yytext);
|
|
lstack.push(this.lexer.yylloc);
|
|
stack.push(action[1]); // push state
|
|
|
|
symbol = null;
|
|
|
|
if (!preErrorSymbol) {
|
|
// normal execution/no error
|
|
yyleng = this.lexer.yyleng;
|
|
yytext = this.lexer.yytext;
|
|
yylineno = this.lexer.yylineno;
|
|
yyloc = this.lexer.yylloc;
|
|
if (recovering > 0) recovering--;
|
|
} else {
|
|
// error just occurred, resume old lookahead f/ before error
|
|
symbol = preErrorSymbol;
|
|
preErrorSymbol = null;
|
|
}
|
|
|
|
break;
|
|
|
|
case 2:
|
|
// reduce
|
|
//this.reductionCount++;
|
|
len = this.productions_[action[1]][1]; // perform semantic action
|
|
|
|
yyval.$ = vstack[vstack.length - len]; // default to $$ = $1
|
|
// default location, uses first token for firsts, last for lasts
|
|
|
|
yyval._$ = {
|
|
first_line: lstack[lstack.length - (len || 1)].first_line,
|
|
last_line: lstack[lstack.length - 1].last_line,
|
|
first_column: lstack[lstack.length - (len || 1)].first_column,
|
|
last_column: lstack[lstack.length - 1].last_column
|
|
};
|
|
r = this.performAction.call(yyval, yytext, yyleng, yylineno, this.yy, action[1], vstack, lstack);
|
|
|
|
if (typeof r !== 'undefined') {
|
|
return r;
|
|
} // pop off stack
|
|
|
|
|
|
if (len) {
|
|
stack = stack.slice(0, -1 * len * 2);
|
|
vstack = vstack.slice(0, -1 * len);
|
|
lstack = lstack.slice(0, -1 * len);
|
|
}
|
|
|
|
stack.push(this.productions_[action[1]][0]); // push nonterminal (reduce)
|
|
|
|
vstack.push(yyval.$);
|
|
lstack.push(yyval._$); // goto new state = table[STATE][NONTERMINAL]
|
|
|
|
newState = table[stack[stack.length - 2]][stack[stack.length - 1]];
|
|
stack.push(newState);
|
|
break;
|
|
|
|
case 3:
|
|
// accept
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
};
|
|
/* Jison generated lexer */
|
|
|
|
var lexer = function () {
|
|
var lexer = {
|
|
EOF: 1,
|
|
parseError: function parseError(str, hash) {
|
|
if (this.yy.parseError) {
|
|
this.yy.parseError(str, hash);
|
|
} else {
|
|
throw new Error(str);
|
|
}
|
|
},
|
|
setInput: function setInput(input) {
|
|
this._input = input;
|
|
this._more = this._less = this.done = false;
|
|
this.yylineno = this.yyleng = 0;
|
|
this.yytext = this.matched = this.match = '';
|
|
this.conditionStack = ['INITIAL'];
|
|
this.yylloc = {
|
|
first_line: 1,
|
|
first_column: 0,
|
|
last_line: 1,
|
|
last_column: 0
|
|
};
|
|
return this;
|
|
},
|
|
input: function input() {
|
|
var ch = this._input[0];
|
|
this.yytext += ch;
|
|
this.yyleng++;
|
|
this.match += ch;
|
|
this.matched += ch;
|
|
var lines = ch.match(/\n/);
|
|
if (lines) this.yylineno++;
|
|
this._input = this._input.slice(1);
|
|
return ch;
|
|
},
|
|
unput: function unput(ch) {
|
|
this._input = ch + this._input;
|
|
return this;
|
|
},
|
|
more: function more() {
|
|
this._more = true;
|
|
return this;
|
|
},
|
|
less: function less(n) {
|
|
this._input = this.match.slice(n) + this._input;
|
|
},
|
|
pastInput: function pastInput() {
|
|
var past = this.matched.substr(0, this.matched.length - this.match.length);
|
|
return (past.length > 20 ? '...' : '') + past.substr(-20).replace(/\n/g, "");
|
|
},
|
|
upcomingInput: function upcomingInput() {
|
|
var next = this.match;
|
|
|
|
if (next.length < 20) {
|
|
next += this._input.substr(0, 20 - next.length);
|
|
}
|
|
|
|
return (next.substr(0, 20) + (next.length > 20 ? '...' : '')).replace(/\n/g, "");
|
|
},
|
|
showPosition: function showPosition() {
|
|
var pre = this.pastInput();
|
|
var c = new Array(pre.length + 1).join("-");
|
|
return pre + this.upcomingInput() + "\n" + c + "^";
|
|
},
|
|
next: function next() {
|
|
if (this.done) {
|
|
return this.EOF;
|
|
}
|
|
|
|
if (!this._input) this.done = true;
|
|
var token, match, tempMatch, index, col, lines;
|
|
|
|
if (!this._more) {
|
|
this.yytext = '';
|
|
this.match = '';
|
|
}
|
|
|
|
var rules = this._currentRules();
|
|
|
|
for (var i = 0; i < rules.length; i++) {
|
|
tempMatch = this._input.match(this.rules[rules[i]]);
|
|
|
|
if (tempMatch && (!match || tempMatch[0].length > match[0].length)) {
|
|
match = tempMatch;
|
|
index = i;
|
|
if (!this.options.flex) break;
|
|
}
|
|
}
|
|
|
|
if (match) {
|
|
lines = match[0].match(/\n.*/g);
|
|
if (lines) this.yylineno += lines.length;
|
|
this.yylloc = {
|
|
first_line: this.yylloc.last_line,
|
|
last_line: this.yylineno + 1,
|
|
first_column: this.yylloc.last_column,
|
|
last_column: lines ? lines[lines.length - 1].length - 1 : this.yylloc.last_column + match[0].length
|
|
};
|
|
this.yytext += match[0];
|
|
this.match += match[0];
|
|
this.yyleng = this.yytext.length;
|
|
this._more = false;
|
|
this._input = this._input.slice(match[0].length);
|
|
this.matched += match[0];
|
|
token = this.performAction.call(this, this.yy, this, rules[index], this.conditionStack[this.conditionStack.length - 1]);
|
|
if (this.done && this._input) this.done = false;
|
|
if (token) return token;else return;
|
|
}
|
|
|
|
if (this._input === "") {
|
|
return this.EOF;
|
|
} else {
|
|
this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. Unrecognized text.\n' + this.showPosition(), {
|
|
text: "",
|
|
token: null,
|
|
line: this.yylineno
|
|
});
|
|
}
|
|
},
|
|
lex: function lex() {
|
|
var r = this.next();
|
|
|
|
if (typeof r !== 'undefined') {
|
|
return r;
|
|
} else {
|
|
return this.lex();
|
|
}
|
|
},
|
|
begin: function begin(condition) {
|
|
this.conditionStack.push(condition);
|
|
},
|
|
popState: function popState() {
|
|
return this.conditionStack.pop();
|
|
},
|
|
_currentRules: function _currentRules() {
|
|
return this.conditions[this.conditionStack[this.conditionStack.length - 1]].rules;
|
|
},
|
|
topState: function topState() {
|
|
return this.conditionStack[this.conditionStack.length - 2];
|
|
},
|
|
pushState: function begin(condition) {
|
|
this.begin(condition);
|
|
}
|
|
};
|
|
lexer.options = {};
|
|
|
|
lexer.performAction = function anonymous(yy, yy_, $avoiding_name_collisions, YY_START) {
|
|
var YYSTATE = YY_START;
|
|
|
|
switch ($avoiding_name_collisions) {
|
|
case 0:
|
|
/* skip whitespace */
|
|
break;
|
|
|
|
case 1:
|
|
return 6;
|
|
break;
|
|
|
|
case 2:
|
|
yy_.yytext = yy_.yytext.substr(1, yy_.yyleng - 2);
|
|
return 4;
|
|
break;
|
|
|
|
case 3:
|
|
return 17;
|
|
break;
|
|
|
|
case 4:
|
|
return 18;
|
|
break;
|
|
|
|
case 5:
|
|
return 23;
|
|
break;
|
|
|
|
case 6:
|
|
return 24;
|
|
break;
|
|
|
|
case 7:
|
|
return 22;
|
|
break;
|
|
|
|
case 8:
|
|
return 21;
|
|
break;
|
|
|
|
case 9:
|
|
return 10;
|
|
break;
|
|
|
|
case 10:
|
|
return 11;
|
|
break;
|
|
|
|
case 11:
|
|
return 8;
|
|
break;
|
|
|
|
case 12:
|
|
return 14;
|
|
break;
|
|
|
|
case 13:
|
|
return 'INVALID';
|
|
break;
|
|
}
|
|
};
|
|
|
|
lexer.rules = [/^(?:\s+)/, /^(?:(-?([0-9]|[1-9][0-9]+))(\.[0-9]+)?([eE][-+]?[0-9]+)?\b)/, /^(?:"(?:\\[\\"bfnrt/]|\\u[a-fA-F0-9]{4}|[^\\\0-\x09\x0a-\x1f"])*")/, /^(?:\{)/, /^(?:\})/, /^(?:\[)/, /^(?:\])/, /^(?:,)/, /^(?::)/, /^(?:true\b)/, /^(?:false\b)/, /^(?:null\b)/, /^(?:$)/, /^(?:.)/];
|
|
lexer.conditions = {
|
|
"INITIAL": {
|
|
"rules": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13],
|
|
"inclusive": true
|
|
}
|
|
};
|
|
;
|
|
return lexer;
|
|
}();
|
|
|
|
parser.lexer = lexer;
|
|
return parser;
|
|
}();
|
|
|
|
if (true) {
|
|
exports.parser = jsonlint;
|
|
exports.parse = jsonlint.parse.bind(jsonlint);
|
|
}
|
|
|
|
/***/ }),
|
|
|
|
/***/ 3879:
|
|
/***/ (function(module) {
|
|
|
|
"use strict";
|
|
/*!
|
|
* Selectr 2.4.0
|
|
* https://github.com/Mobius1/Selectr
|
|
*
|
|
* Released under the MIT license
|
|
*/
|
|
|
|
/**
|
|
* Default configuration options
|
|
* @type {Object}
|
|
*/
|
|
|
|
var defaultConfig = {
|
|
/**
|
|
* Emulates browser behaviour by selecting the first option by default
|
|
* @type {Boolean}
|
|
*/
|
|
defaultSelected: true,
|
|
|
|
/**
|
|
* Sets the width of the container
|
|
* @type {String}
|
|
*/
|
|
width: "auto",
|
|
|
|
/**
|
|
* Enables/ disables the container
|
|
* @type {Boolean}
|
|
*/
|
|
disabled: false,
|
|
|
|
/**
|
|
* Enables / disables the search function
|
|
* @type {Boolean}
|
|
*/
|
|
searchable: true,
|
|
|
|
/**
|
|
* Enable disable the clear button
|
|
* @type {Boolean}
|
|
*/
|
|
clearable: false,
|
|
|
|
/**
|
|
* Sort the tags / multiselect options
|
|
* @type {Boolean}
|
|
*/
|
|
sortSelected: false,
|
|
|
|
/**
|
|
* Allow deselecting of select-one options
|
|
* @type {Boolean}
|
|
*/
|
|
allowDeselect: false,
|
|
|
|
/**
|
|
* Close the dropdown when scrolling (@AlexanderReiswich, #11)
|
|
* @type {Boolean}
|
|
*/
|
|
closeOnScroll: false,
|
|
|
|
/**
|
|
* Allow the use of the native dropdown (@jonnyscholes, #14)
|
|
* @type {Boolean}
|
|
*/
|
|
nativeDropdown: false,
|
|
|
|
/**
|
|
* Set the main placeholder
|
|
* @type {String}
|
|
*/
|
|
placeholder: "Select an option...",
|
|
|
|
/**
|
|
* Allow the tagging feature
|
|
* @type {Boolean}
|
|
*/
|
|
taggable: false,
|
|
|
|
/**
|
|
* Set the tag input placeholder (@labikmartin, #21, #22)
|
|
* @type {String}
|
|
*/
|
|
tagPlaceholder: "Enter a tag..."
|
|
};
|
|
/**
|
|
* Event Emitter
|
|
*/
|
|
|
|
var Events = function Events() {};
|
|
/**
|
|
* Event Prototype
|
|
* @type {Object}
|
|
*/
|
|
|
|
|
|
Events.prototype = {
|
|
/**
|
|
* Add custom event listener
|
|
* @param {String} event Event type
|
|
* @param {Function} func Callback
|
|
* @return {Void}
|
|
*/
|
|
on: function on(event, func) {
|
|
this._events = this._events || {};
|
|
this._events[event] = this._events[event] || [];
|
|
|
|
this._events[event].push(func);
|
|
},
|
|
|
|
/**
|
|
* Remove custom event listener
|
|
* @param {String} event Event type
|
|
* @param {Function} func Callback
|
|
* @return {Void}
|
|
*/
|
|
off: function off(event, func) {
|
|
this._events = this._events || {};
|
|
if (event in this._events === false) return;
|
|
|
|
this._events[event].splice(this._events[event].indexOf(func), 1);
|
|
},
|
|
|
|
/**
|
|
* Fire a custom event
|
|
* @param {String} event Event type
|
|
* @return {Void}
|
|
*/
|
|
emit: function emit(event
|
|
/* , args... */
|
|
) {
|
|
this._events = this._events || {};
|
|
if (event in this._events === false) return;
|
|
|
|
for (var i = 0; i < this._events[event].length; i++) {
|
|
this._events[event][i].apply(this, Array.prototype.slice.call(arguments, 1));
|
|
}
|
|
}
|
|
};
|
|
/**
|
|
* Event mixin
|
|
* @param {Object} obj
|
|
* @return {Object}
|
|
*/
|
|
|
|
Events.mixin = function (obj) {
|
|
var props = ['on', 'off', 'emit'];
|
|
|
|
for (var i = 0; i < props.length; i++) {
|
|
if (typeof obj === 'function') {
|
|
obj.prototype[props[i]] = Events.prototype[props[i]];
|
|
} else {
|
|
obj[props[i]] = Events.prototype[props[i]];
|
|
}
|
|
}
|
|
|
|
return obj;
|
|
};
|
|
/**
|
|
* Helpers
|
|
* @type {Object}
|
|
*/
|
|
|
|
|
|
var util = {
|
|
extend: function extend(src, props) {
|
|
props = props || {};
|
|
var p;
|
|
|
|
for (p in src) {
|
|
if (src.hasOwnProperty(p)) {
|
|
if (!props.hasOwnProperty(p)) {
|
|
props[p] = src[p];
|
|
}
|
|
}
|
|
}
|
|
|
|
return props;
|
|
},
|
|
each: function each(a, b, c) {
|
|
if ("[object Object]" === Object.prototype.toString.call(a)) {
|
|
for (var d in a) {
|
|
if (Object.prototype.hasOwnProperty.call(a, d)) {
|
|
b.call(c, d, a[d], a);
|
|
}
|
|
}
|
|
} else {
|
|
for (var e = 0, f = a.length; e < f; e++) {
|
|
b.call(c, e, a[e], a);
|
|
}
|
|
}
|
|
},
|
|
createElement: function createElement(e, a) {
|
|
var d = document,
|
|
el = d.createElement(e);
|
|
|
|
if (a && "[object Object]" === Object.prototype.toString.call(a)) {
|
|
var i;
|
|
|
|
for (i in a) {
|
|
if (i in el) el[i] = a[i];else if ("html" === i) el.textContent = a[i];else if ("text" === i) {
|
|
var t = d.createTextNode(a[i]);
|
|
el.appendChild(t);
|
|
} else el.setAttribute(i, a[i]);
|
|
}
|
|
}
|
|
|
|
return el;
|
|
},
|
|
hasClass: function hasClass(a, b) {
|
|
if (a) return a.classList ? a.classList.contains(b) : !!a.className && !!a.className.match(new RegExp("(\\s|^)" + b + "(\\s|$)"));
|
|
},
|
|
addClass: function addClass(a, b) {
|
|
if (!util.hasClass(a, b)) {
|
|
if (a.classList) {
|
|
a.classList.add(b);
|
|
} else {
|
|
a.className = a.className.trim() + " " + b;
|
|
}
|
|
}
|
|
},
|
|
removeClass: function removeClass(a, b) {
|
|
if (util.hasClass(a, b)) {
|
|
if (a.classList) {
|
|
a.classList.remove(b);
|
|
} else {
|
|
a.className = a.className.replace(new RegExp("(^|\\s)" + b.split(" ").join("|") + "(\\s|$)", "gi"), " ");
|
|
}
|
|
}
|
|
},
|
|
closest: function closest(el, fn) {
|
|
return el && el !== document.body && (fn(el) ? el : util.closest(el.parentNode, fn));
|
|
},
|
|
isInt: function isInt(val) {
|
|
return typeof val === 'number' && isFinite(val) && Math.floor(val) === val;
|
|
},
|
|
debounce: function debounce(a, b, c) {
|
|
var d;
|
|
return function () {
|
|
var e = this,
|
|
f = arguments,
|
|
g = function g() {
|
|
d = null;
|
|
if (!c) a.apply(e, f);
|
|
},
|
|
h = c && !d;
|
|
|
|
clearTimeout(d);
|
|
d = setTimeout(g, b);
|
|
|
|
if (h) {
|
|
a.apply(e, f);
|
|
}
|
|
};
|
|
},
|
|
rect: function rect(el, abs) {
|
|
var w = window;
|
|
var r = el.getBoundingClientRect();
|
|
var x = abs ? w.pageXOffset : 0;
|
|
var y = abs ? w.pageYOffset : 0;
|
|
return {
|
|
bottom: r.bottom + y,
|
|
height: r.height,
|
|
left: r.left + x,
|
|
right: r.right + x,
|
|
top: r.top + y,
|
|
width: r.width
|
|
};
|
|
},
|
|
includes: function includes(a, b) {
|
|
return a.indexOf(b) > -1;
|
|
},
|
|
truncate: function truncate(el) {
|
|
while (el.firstChild) {
|
|
el.removeChild(el.firstChild);
|
|
}
|
|
}
|
|
};
|
|
|
|
function isset(obj, prop) {
|
|
return obj.hasOwnProperty(prop) && (obj[prop] === true || obj[prop].length);
|
|
}
|
|
/**
|
|
* Append an item to the list
|
|
* @param {Object} item
|
|
* @param {Object} custom
|
|
* @return {Void}
|
|
*/
|
|
|
|
|
|
function appendItem(item, parent, custom) {
|
|
if (item.parentNode) {
|
|
if (!item.parentNode.parentNode) {
|
|
parent.appendChild(item.parentNode);
|
|
}
|
|
} else {
|
|
parent.appendChild(item);
|
|
}
|
|
|
|
util.removeClass(item, "excluded");
|
|
|
|
if (!custom) {
|
|
item.textContent = item.textContent + ''; // clear highlighting
|
|
}
|
|
}
|
|
/**
|
|
* Render the item list
|
|
* @return {Void}
|
|
*/
|
|
|
|
|
|
var render = function render() {
|
|
if (this.items.length) {
|
|
var f = document.createDocumentFragment();
|
|
|
|
if (this.config.pagination) {
|
|
var pages = this.pages.slice(0, this.pageIndex);
|
|
util.each(pages, function (i, items) {
|
|
util.each(items, function (j, item) {
|
|
appendItem(item, f, this.customOption);
|
|
}, this);
|
|
}, this);
|
|
} else {
|
|
util.each(this.items, function (i, item) {
|
|
appendItem(item, f, this.customOption);
|
|
}, this);
|
|
}
|
|
|
|
if (f.childElementCount) {
|
|
util.removeClass(this.items[this.navIndex], "active");
|
|
this.navIndex = f.querySelector(".selectr-option").idx;
|
|
util.addClass(this.items[this.navIndex], "active");
|
|
}
|
|
|
|
this.tree.appendChild(f);
|
|
}
|
|
};
|
|
/**
|
|
* Dismiss / close the dropdown
|
|
* @param {obj} e
|
|
* @return {void}
|
|
*/
|
|
|
|
|
|
var dismiss = function dismiss(e) {
|
|
var target = e.target;
|
|
|
|
if (!this.container.contains(target) && (this.opened || util.hasClass(this.container, "notice"))) {
|
|
this.close();
|
|
}
|
|
};
|
|
/**
|
|
* Build a list item from the HTMLOptionElement
|
|
* @param {int} i HTMLOptionElement index
|
|
* @param {HTMLOptionElement} option
|
|
* @param {bool} group Has parent optgroup
|
|
* @return {void}
|
|
*/
|
|
|
|
|
|
var createItem = function createItem(option, data) {
|
|
data = data || option;
|
|
var content = this.customOption ? this.config.renderOption(data) : option.textContent;
|
|
var opt = util.createElement("li", {
|
|
"class": "selectr-option",
|
|
html: content,
|
|
role: "treeitem",
|
|
"aria-selected": false
|
|
});
|
|
opt.idx = option.idx;
|
|
this.items.push(opt);
|
|
|
|
if (option.defaultSelected) {
|
|
this.defaultSelected.push(option.idx);
|
|
}
|
|
|
|
if (option.disabled) {
|
|
opt.disabled = true;
|
|
util.addClass(opt, "disabled");
|
|
}
|
|
|
|
return opt;
|
|
};
|
|
/**
|
|
* Build the container
|
|
* @return {Void}
|
|
*/
|
|
|
|
|
|
var build = function build() {
|
|
this.requiresPagination = this.config.pagination && this.config.pagination > 0; // Set width
|
|
|
|
if (isset(this.config, "width")) {
|
|
if (util.isInt(this.config.width)) {
|
|
this.width = this.config.width + "px";
|
|
} else {
|
|
if (this.config.width === "auto") {
|
|
this.width = "100%";
|
|
} else if (util.includes(this.config.width, "%")) {
|
|
this.width = this.config.width;
|
|
}
|
|
}
|
|
}
|
|
|
|
this.container = util.createElement("div", {
|
|
"class": "selectr-container"
|
|
}); // Custom className
|
|
|
|
if (this.config.customClass) {
|
|
util.addClass(this.container, this.config.customClass);
|
|
} // Mobile device
|
|
|
|
|
|
if (this.mobileDevice) {
|
|
util.addClass(this.container, "selectr-mobile");
|
|
} else {
|
|
util.addClass(this.container, "selectr-desktop");
|
|
} // Hide the HTMLSelectElement and prevent focus
|
|
|
|
|
|
this.el.tabIndex = -1; // Native dropdown
|
|
|
|
if (this.config.nativeDropdown || this.mobileDevice) {
|
|
util.addClass(this.el, "selectr-visible");
|
|
} else {
|
|
util.addClass(this.el, "selectr-hidden");
|
|
}
|
|
|
|
this.selected = util.createElement("div", {
|
|
"class": "selectr-selected",
|
|
disabled: this.disabled,
|
|
tabIndex: 1,
|
|
// enable tabIndex (#9)
|
|
"aria-expanded": false
|
|
});
|
|
this.label = util.createElement(this.el.multiple ? "ul" : "span", {
|
|
"class": "selectr-label"
|
|
});
|
|
var dropdown = util.createElement("div", {
|
|
"class": "selectr-options-container"
|
|
});
|
|
this.tree = util.createElement("ul", {
|
|
"class": "selectr-options",
|
|
role: "tree",
|
|
"aria-hidden": true,
|
|
"aria-expanded": false
|
|
});
|
|
this.notice = util.createElement("div", {
|
|
"class": "selectr-notice"
|
|
});
|
|
this.el.setAttribute("aria-hidden", true);
|
|
|
|
if (this.disabled) {
|
|
this.el.disabled = true;
|
|
}
|
|
|
|
if (this.el.multiple) {
|
|
util.addClass(this.label, "selectr-tags");
|
|
util.addClass(this.container, "multiple"); // Collection of tags
|
|
|
|
this.tags = []; // Collection of selected values
|
|
|
|
this.selectedValues = this.getSelectedProperties('value'); // Collection of selected indexes
|
|
|
|
this.selectedIndexes = this.getSelectedProperties('idx');
|
|
}
|
|
|
|
this.selected.appendChild(this.label);
|
|
|
|
if (this.config.clearable) {
|
|
this.selectClear = util.createElement("button", {
|
|
"class": "selectr-clear",
|
|
type: "button"
|
|
});
|
|
this.container.appendChild(this.selectClear);
|
|
util.addClass(this.container, "clearable");
|
|
}
|
|
|
|
if (this.config.taggable) {
|
|
var li = util.createElement('li', {
|
|
"class": 'input-tag'
|
|
});
|
|
this.input = util.createElement("input", {
|
|
"class": "selectr-tag-input",
|
|
placeholder: this.config.tagPlaceholder,
|
|
tagIndex: 0,
|
|
autocomplete: "off",
|
|
autocorrect: "off",
|
|
autocapitalize: "off",
|
|
spellcheck: "false",
|
|
role: "textbox",
|
|
type: "search"
|
|
});
|
|
li.appendChild(this.input);
|
|
this.label.appendChild(li);
|
|
util.addClass(this.container, "taggable");
|
|
this.tagSeperators = [","];
|
|
|
|
if (this.config.tagSeperators) {
|
|
this.tagSeperators = this.tagSeperators.concat(this.config.tagSeperators);
|
|
}
|
|
}
|
|
|
|
if (this.config.searchable) {
|
|
this.input = util.createElement("input", {
|
|
"class": "selectr-input",
|
|
tagIndex: -1,
|
|
autocomplete: "off",
|
|
autocorrect: "off",
|
|
autocapitalize: "off",
|
|
spellcheck: "false",
|
|
role: "textbox",
|
|
type: "search"
|
|
});
|
|
this.inputClear = util.createElement("button", {
|
|
"class": "selectr-input-clear",
|
|
type: "button"
|
|
});
|
|
this.inputContainer = util.createElement("div", {
|
|
"class": "selectr-input-container"
|
|
});
|
|
this.inputContainer.appendChild(this.input);
|
|
this.inputContainer.appendChild(this.inputClear);
|
|
dropdown.appendChild(this.inputContainer);
|
|
}
|
|
|
|
dropdown.appendChild(this.notice);
|
|
dropdown.appendChild(this.tree); // List of items for the dropdown
|
|
|
|
this.items = []; // Establish options
|
|
|
|
this.options = []; // Check for options in the element
|
|
|
|
if (this.el.options.length) {
|
|
this.options = [].slice.call(this.el.options);
|
|
} // Element may have optgroups so
|
|
// iterate element.children instead of element.options
|
|
|
|
|
|
var group = false,
|
|
j = 0;
|
|
|
|
if (this.el.children.length) {
|
|
util.each(this.el.children, function (i, element) {
|
|
if (element.nodeName === "OPTGROUP") {
|
|
group = util.createElement("ul", {
|
|
"class": "selectr-optgroup",
|
|
role: "group",
|
|
html: "<li class='selectr-optgroup--label'>" + element.label + "</li>"
|
|
});
|
|
util.each(element.children, function (x, el) {
|
|
el.idx = j;
|
|
group.appendChild(createItem.call(this, el, group));
|
|
j++;
|
|
}, this);
|
|
} else {
|
|
element.idx = j;
|
|
createItem.call(this, element);
|
|
j++;
|
|
}
|
|
}, this);
|
|
} // Options defined by the data option
|
|
|
|
|
|
if (this.config.data && Array.isArray(this.config.data)) {
|
|
this.data = [];
|
|
var optgroup = false,
|
|
option;
|
|
group = false;
|
|
j = 0;
|
|
util.each(this.config.data, function (i, opt) {
|
|
// Check for group options
|
|
if (isset(opt, "children")) {
|
|
optgroup = util.createElement("optgroup", {
|
|
label: opt.text
|
|
});
|
|
group = util.createElement("ul", {
|
|
"class": "selectr-optgroup",
|
|
role: "group",
|
|
html: "<li class='selectr-optgroup--label'>" + opt.text + "</li>"
|
|
});
|
|
util.each(opt.children, function (x, data) {
|
|
option = new Option(data.text, data.value, false, data.hasOwnProperty("selected") && data.selected === true);
|
|
option.disabled = isset(data, "disabled");
|
|
this.options.push(option);
|
|
optgroup.appendChild(option);
|
|
option.idx = j;
|
|
group.appendChild(createItem.call(this, option, data));
|
|
this.data[j] = data;
|
|
j++;
|
|
}, this);
|
|
} else {
|
|
option = new Option(opt.text, opt.value, false, opt.hasOwnProperty("selected") && opt.selected === true);
|
|
option.disabled = isset(opt, "disabled");
|
|
this.options.push(option);
|
|
option.idx = j;
|
|
createItem.call(this, option, opt);
|
|
this.data[j] = opt;
|
|
j++;
|
|
}
|
|
}, this);
|
|
}
|
|
|
|
this.setSelected(true);
|
|
var first;
|
|
this.navIndex = 0;
|
|
|
|
for (var i = 0; i < this.items.length; i++) {
|
|
first = this.items[i];
|
|
|
|
if (!util.hasClass(first, "disabled")) {
|
|
util.addClass(first, "active");
|
|
this.navIndex = i;
|
|
break;
|
|
}
|
|
} // Check for pagination / infinite scroll
|
|
|
|
|
|
if (this.requiresPagination) {
|
|
this.pageIndex = 1; // Create the pages
|
|
|
|
this.paginate();
|
|
}
|
|
|
|
this.container.appendChild(this.selected);
|
|
this.container.appendChild(dropdown);
|
|
this.placeEl = util.createElement("div", {
|
|
"class": "selectr-placeholder"
|
|
}); // Set the placeholder
|
|
|
|
this.setPlaceholder();
|
|
this.selected.appendChild(this.placeEl); // Disable if required
|
|
|
|
if (this.disabled) {
|
|
this.disable();
|
|
}
|
|
|
|
this.el.parentNode.insertBefore(this.container, this.el);
|
|
this.container.appendChild(this.el);
|
|
};
|
|
/**
|
|
* Navigate through the dropdown
|
|
* @param {obj} e
|
|
* @return {void}
|
|
*/
|
|
|
|
|
|
var navigate = function navigate(e) {
|
|
e = e || window.event; // Filter out the keys we don"t want
|
|
|
|
if (!this.items.length || !this.opened || !util.includes([13, 38, 40], e.which)) {
|
|
this.navigating = false;
|
|
return;
|
|
}
|
|
|
|
e.preventDefault();
|
|
|
|
if (e.which === 13) {
|
|
if (this.config.taggable && this.input.value.length > 0) {
|
|
return false;
|
|
}
|
|
|
|
return this.change(this.navIndex);
|
|
}
|
|
|
|
var direction,
|
|
prevEl = this.items[this.navIndex];
|
|
|
|
switch (e.which) {
|
|
case 38:
|
|
direction = 0;
|
|
|
|
if (this.navIndex > 0) {
|
|
this.navIndex--;
|
|
}
|
|
|
|
break;
|
|
|
|
case 40:
|
|
direction = 1;
|
|
|
|
if (this.navIndex < this.items.length - 1) {
|
|
this.navIndex++;
|
|
}
|
|
|
|
}
|
|
|
|
this.navigating = true; // Instead of wasting memory holding a copy of this.items
|
|
// with disabled / excluded options omitted, skip them instead
|
|
|
|
while (util.hasClass(this.items[this.navIndex], "disabled") || util.hasClass(this.items[this.navIndex], "excluded")) {
|
|
if (direction) {
|
|
this.navIndex++;
|
|
} else {
|
|
this.navIndex--;
|
|
}
|
|
|
|
if (this.searching) {
|
|
if (this.navIndex > this.tree.lastElementChild.idx) {
|
|
this.navIndex = this.tree.lastElementChild.idx;
|
|
break;
|
|
} else if (this.navIndex < this.tree.firstElementChild.idx) {
|
|
this.navIndex = this.tree.firstElementChild.idx;
|
|
break;
|
|
}
|
|
}
|
|
} // Autoscroll the dropdown during navigation
|
|
|
|
|
|
var r = util.rect(this.items[this.navIndex]);
|
|
|
|
if (!direction) {
|
|
if (this.navIndex === 0) {
|
|
this.tree.scrollTop = 0;
|
|
} else if (r.top - this.optsRect.top < 0) {
|
|
this.tree.scrollTop = this.tree.scrollTop + (r.top - this.optsRect.top);
|
|
}
|
|
} else {
|
|
if (this.navIndex === 0) {
|
|
this.tree.scrollTop = 0;
|
|
} else if (r.top + r.height > this.optsRect.top + this.optsRect.height) {
|
|
this.tree.scrollTop = this.tree.scrollTop + (r.top + r.height - (this.optsRect.top + this.optsRect.height));
|
|
} // Load another page if needed
|
|
|
|
|
|
if (this.navIndex === this.tree.childElementCount - 1 && this.requiresPagination) {
|
|
load.call(this);
|
|
}
|
|
}
|
|
|
|
if (prevEl) {
|
|
util.removeClass(prevEl, "active");
|
|
}
|
|
|
|
util.addClass(this.items[this.navIndex], "active");
|
|
};
|
|
/**
|
|
* Add a tag
|
|
* @param {HTMLElement} item
|
|
*/
|
|
|
|
|
|
var addTag = function addTag(item) {
|
|
var that = this,
|
|
r;
|
|
var docFrag = document.createDocumentFragment();
|
|
var option = this.options[item.idx];
|
|
var data = this.data ? this.data[item.idx] : option;
|
|
var content = this.customSelected ? this.config.renderSelection(data) : option.textContent;
|
|
var tag = util.createElement("li", {
|
|
"class": "selectr-tag",
|
|
html: content
|
|
});
|
|
var btn = util.createElement("button", {
|
|
"class": "selectr-tag-remove",
|
|
type: "button"
|
|
});
|
|
tag.appendChild(btn); // Set property to check against later
|
|
|
|
tag.idx = item.idx;
|
|
tag.tag = option.value;
|
|
this.tags.push(tag);
|
|
|
|
if (this.config.sortSelected) {
|
|
var tags = this.tags.slice(); // Deal with values that contain numbers
|
|
|
|
r = function r(val, arr) {
|
|
val.replace(/(\d+)|(\D+)/g, function (that, $1, $2) {
|
|
arr.push([$1 || Infinity, $2 || ""]);
|
|
});
|
|
};
|
|
|
|
tags.sort(function (a, b) {
|
|
var x = [],
|
|
y = [],
|
|
ac,
|
|
bc;
|
|
|
|
if (that.config.sortSelected === true) {
|
|
ac = a.tag;
|
|
bc = b.tag;
|
|
} else if (that.config.sortSelected === 'text') {
|
|
ac = a.textContent;
|
|
bc = b.textContent;
|
|
}
|
|
|
|
r(ac, x);
|
|
r(bc, y);
|
|
|
|
while (x.length && y.length) {
|
|
var ax = x.shift();
|
|
var by = y.shift();
|
|
var nn = ax[0] - by[0] || ax[1].localeCompare(by[1]);
|
|
if (nn) return nn;
|
|
}
|
|
|
|
return x.length - y.length;
|
|
});
|
|
util.each(tags, function (i, tg) {
|
|
docFrag.appendChild(tg);
|
|
});
|
|
this.label.textContent = "";
|
|
} else {
|
|
docFrag.appendChild(tag);
|
|
}
|
|
|
|
if (this.config.taggable) {
|
|
this.label.insertBefore(docFrag, this.input.parentNode);
|
|
} else {
|
|
this.label.appendChild(docFrag);
|
|
}
|
|
};
|
|
/**
|
|
* Remove a tag
|
|
* @param {HTMLElement} item
|
|
* @return {void}
|
|
*/
|
|
|
|
|
|
var removeTag = function removeTag(item) {
|
|
var tag = false;
|
|
util.each(this.tags, function (i, t) {
|
|
if (t.idx === item.idx) {
|
|
tag = t;
|
|
}
|
|
}, this);
|
|
|
|
if (tag) {
|
|
this.label.removeChild(tag);
|
|
this.tags.splice(this.tags.indexOf(tag), 1);
|
|
}
|
|
};
|
|
/**
|
|
* Load the next page of items
|
|
* @return {void}
|
|
*/
|
|
|
|
|
|
var load = function load() {
|
|
var tree = this.tree;
|
|
var scrollTop = tree.scrollTop;
|
|
var scrollHeight = tree.scrollHeight;
|
|
var offsetHeight = tree.offsetHeight;
|
|
var atBottom = scrollTop >= scrollHeight - offsetHeight;
|
|
|
|
if (atBottom && this.pageIndex < this.pages.length) {
|
|
var f = document.createDocumentFragment();
|
|
util.each(this.pages[this.pageIndex], function (i, item) {
|
|
appendItem(item, f, this.customOption);
|
|
}, this);
|
|
tree.appendChild(f);
|
|
this.pageIndex++;
|
|
this.emit("selectr.paginate", {
|
|
items: this.items.length,
|
|
total: this.data.length,
|
|
page: this.pageIndex,
|
|
pages: this.pages.length
|
|
});
|
|
}
|
|
};
|
|
/**
|
|
* Clear a search
|
|
* @return {void}
|
|
*/
|
|
|
|
|
|
var clearSearch = function clearSearch() {
|
|
if (this.config.searchable || this.config.taggable) {
|
|
this.input.value = null;
|
|
this.searching = false;
|
|
|
|
if (this.config.searchable) {
|
|
util.removeClass(this.inputContainer, "active");
|
|
}
|
|
|
|
if (util.hasClass(this.container, "notice")) {
|
|
util.removeClass(this.container, "notice");
|
|
util.addClass(this.container, "open");
|
|
this.input.focus();
|
|
}
|
|
|
|
util.each(this.items, function (i, item) {
|
|
// Items that didn't match need the class
|
|
// removing to make them visible again
|
|
util.removeClass(item, "excluded"); // Remove the span element for underlining matched items
|
|
|
|
if (!this.customOption) {
|
|
item.textContent = item.textContent + ''; // clear highlighting
|
|
}
|
|
}, this);
|
|
}
|
|
};
|
|
/**
|
|
* Query matching for searches
|
|
* @param {string} query
|
|
* @param {string} text
|
|
*/
|
|
|
|
|
|
var match = function match(query, text) {
|
|
var result = new RegExp(query, "i").exec(text);
|
|
|
|
if (result) {
|
|
var start = result.index;
|
|
var end = result.index + result[0].length;
|
|
return {
|
|
before: text.substring(0, start),
|
|
match: text.substring(start, end),
|
|
after: text.substring(end)
|
|
};
|
|
}
|
|
|
|
return null;
|
|
}; // Main Lib
|
|
|
|
|
|
var Selectr = function Selectr(el, config) {
|
|
config = config || {};
|
|
|
|
if (!el) {
|
|
throw new Error("You must supply either a HTMLSelectElement or a CSS3 selector string.");
|
|
}
|
|
|
|
this.el = el; // CSS3 selector string
|
|
|
|
if (typeof el === "string") {
|
|
this.el = document.querySelector(el);
|
|
}
|
|
|
|
if (this.el === null) {
|
|
throw new Error("The element you passed to Selectr can not be found.");
|
|
}
|
|
|
|
if (this.el.nodeName.toLowerCase() !== "select") {
|
|
throw new Error("The element you passed to Selectr is not a HTMLSelectElement.");
|
|
}
|
|
|
|
this.render(config);
|
|
};
|
|
/**
|
|
* Render the instance
|
|
* @param {object} config
|
|
* @return {void}
|
|
*/
|
|
|
|
|
|
Selectr.prototype.render = function (config) {
|
|
if (this.rendered) return; // Merge defaults with user set config
|
|
|
|
this.config = util.extend(defaultConfig, config); // Store type
|
|
|
|
this.originalType = this.el.type; // Store tabIndex
|
|
|
|
this.originalIndex = this.el.tabIndex; // Store defaultSelected options for form reset
|
|
|
|
this.defaultSelected = []; // Store the original option count
|
|
|
|
this.originalOptionCount = this.el.options.length;
|
|
|
|
if (this.config.multiple || this.config.taggable) {
|
|
this.el.multiple = true;
|
|
} // Disabled?
|
|
|
|
|
|
this.disabled = isset(this.config, "disabled");
|
|
this.opened = false;
|
|
|
|
if (this.config.taggable) {
|
|
this.config.searchable = false;
|
|
}
|
|
|
|
this.navigating = false;
|
|
this.mobileDevice = false;
|
|
|
|
if (/Android|webOS|iPhone|iPad|BlackBerry|Windows Phone|Opera Mini|IEMobile|Mobile/i.test(navigator.userAgent)) {
|
|
this.mobileDevice = true;
|
|
}
|
|
|
|
this.customOption = this.config.hasOwnProperty("renderOption") && typeof this.config.renderOption === "function";
|
|
this.customSelected = this.config.hasOwnProperty("renderSelection") && typeof this.config.renderSelection === "function"; // Enable event emitter
|
|
|
|
Events.mixin(this);
|
|
build.call(this);
|
|
this.bindEvents();
|
|
this.update();
|
|
this.optsRect = util.rect(this.tree);
|
|
this.rendered = true; // Fixes macOS Safari bug #28
|
|
|
|
if (!this.el.multiple) {
|
|
this.el.selectedIndex = this.selectedIndex;
|
|
}
|
|
|
|
var that = this;
|
|
setTimeout(function () {
|
|
that.emit("selectr.init");
|
|
}, 20);
|
|
};
|
|
|
|
Selectr.prototype.getSelected = function () {
|
|
var selected = this.el.querySelectorAll('option:checked');
|
|
return selected;
|
|
};
|
|
|
|
Selectr.prototype.getSelectedProperties = function (prop) {
|
|
var selected = this.getSelected();
|
|
var values = [].slice.call(selected).map(function (option) {
|
|
return option[prop];
|
|
}).filter(function (i) {
|
|
return i !== null && i !== undefined;
|
|
});
|
|
return values;
|
|
};
|
|
/**
|
|
* Attach the required event listeners
|
|
*/
|
|
|
|
|
|
Selectr.prototype.bindEvents = function () {
|
|
var that = this;
|
|
this.events = {};
|
|
this.events.dismiss = dismiss.bind(this);
|
|
this.events.navigate = navigate.bind(this);
|
|
this.events.reset = this.reset.bind(this);
|
|
|
|
if (this.config.nativeDropdown || this.mobileDevice) {
|
|
this.container.addEventListener("touchstart", function (e) {
|
|
if (e.changedTouches[0].target === that.el) {
|
|
that.toggle();
|
|
}
|
|
});
|
|
|
|
if (this.config.nativeDropdown || this.mobileDevice) {
|
|
this.container.addEventListener("click", function (e) {
|
|
e.preventDefault(); // Jos: Added to prevent emitting clear directly after select
|
|
|
|
e.stopPropagation(); // Jos: Added to prevent emitting clear directly after select
|
|
|
|
if (e.target === that.el) {
|
|
that.toggle();
|
|
}
|
|
});
|
|
}
|
|
|
|
var getChangedOptions = function getChangedOptions(last, current) {
|
|
var added = [],
|
|
removed = last.slice(0);
|
|
var idx;
|
|
|
|
for (var i = 0; i < current.length; i++) {
|
|
idx = removed.indexOf(current[i]);
|
|
if (idx > -1) removed.splice(idx, 1);else added.push(current[i]);
|
|
}
|
|
|
|
return [added, removed];
|
|
}; // Listen for the change on the native select
|
|
// and update accordingly
|
|
|
|
|
|
this.el.addEventListener("change", function (e) {
|
|
if (that.el.multiple) {
|
|
var indexes = that.getSelectedProperties('idx');
|
|
var changes = getChangedOptions(that.selectedIndexes, indexes);
|
|
util.each(changes[0], function (i, idx) {
|
|
that.select(idx);
|
|
}, that);
|
|
util.each(changes[1], function (i, idx) {
|
|
that.deselect(idx);
|
|
}, that);
|
|
} else {
|
|
if (that.el.selectedIndex > -1) {
|
|
that.select(that.el.selectedIndex);
|
|
}
|
|
}
|
|
});
|
|
} // Open the dropdown with Enter key if focused
|
|
|
|
|
|
if (this.config.nativeDropdown) {
|
|
this.container.addEventListener("keydown", function (e) {
|
|
if (e.key === "Enter" && that.selected === document.activeElement) {
|
|
// Show the native
|
|
that.toggle(); // Focus on the native multiselect
|
|
|
|
setTimeout(function () {
|
|
that.el.focus();
|
|
}, 200);
|
|
}
|
|
});
|
|
} // Non-native dropdown
|
|
|
|
|
|
this.selected.addEventListener("click", function (e) {
|
|
if (!that.disabled) {
|
|
that.toggle();
|
|
}
|
|
|
|
e.preventDefault();
|
|
e.stopPropagation(); // Jos: Added to prevent emitting clear directly after select
|
|
}); // Remove tag
|
|
|
|
this.label.addEventListener("click", function (e) {
|
|
if (util.hasClass(e.target, "selectr-tag-remove")) {
|
|
that.deselect(e.target.parentNode.idx);
|
|
}
|
|
}); // Clear input
|
|
|
|
if (this.selectClear) {
|
|
this.selectClear.addEventListener("click", this.clear.bind(this));
|
|
} // Prevent text selection
|
|
|
|
|
|
this.tree.addEventListener("mousedown", function (e) {
|
|
e.preventDefault();
|
|
}); // Select / deselect items
|
|
|
|
this.tree.addEventListener("click", function (e) {
|
|
e.preventDefault(); // Jos: Added to prevent emitting clear directly after select
|
|
|
|
e.stopPropagation(); // Jos: Added to prevent emitting clear directly after select
|
|
|
|
var item = util.closest(e.target, function (el) {
|
|
return el && util.hasClass(el, "selectr-option");
|
|
});
|
|
|
|
if (item) {
|
|
if (!util.hasClass(item, "disabled")) {
|
|
if (util.hasClass(item, "selected")) {
|
|
if (that.el.multiple || !that.el.multiple && that.config.allowDeselect) {
|
|
that.deselect(item.idx);
|
|
}
|
|
} else {
|
|
that.select(item.idx);
|
|
}
|
|
|
|
if (that.opened && !that.el.multiple) {
|
|
that.close();
|
|
}
|
|
}
|
|
}
|
|
}); // Mouseover list items
|
|
|
|
this.tree.addEventListener("mouseover", function (e) {
|
|
if (util.hasClass(e.target, "selectr-option")) {
|
|
if (!util.hasClass(e.target, "disabled")) {
|
|
util.removeClass(that.items[that.navIndex], "active");
|
|
util.addClass(e.target, "active");
|
|
that.navIndex = [].slice.call(that.items).indexOf(e.target);
|
|
}
|
|
}
|
|
}); // Searchable
|
|
|
|
if (this.config.searchable) {
|
|
// Show / hide the search input clear button
|
|
this.input.addEventListener("focus", function (e) {
|
|
that.searching = true;
|
|
});
|
|
this.input.addEventListener("blur", function (e) {
|
|
that.searching = false;
|
|
});
|
|
this.input.addEventListener("keyup", function (e) {
|
|
that.search();
|
|
|
|
if (!that.config.taggable) {
|
|
// Show / hide the search input clear button
|
|
if (this.value.length) {
|
|
util.addClass(this.parentNode, "active");
|
|
} else {
|
|
util.removeClass(this.parentNode, "active");
|
|
}
|
|
}
|
|
}); // Clear the search input
|
|
|
|
this.inputClear.addEventListener("click", function (e) {
|
|
that.input.value = null;
|
|
clearSearch.call(that);
|
|
|
|
if (!that.tree.childElementCount) {
|
|
render.call(that);
|
|
}
|
|
});
|
|
}
|
|
|
|
if (this.config.taggable) {
|
|
this.input.addEventListener("keyup", function (e) {
|
|
that.search();
|
|
|
|
if (that.config.taggable && this.value.length) {
|
|
var val = this.value.trim();
|
|
|
|
if (e.which === 13 || util.includes(that.tagSeperators, e.key)) {
|
|
util.each(that.tagSeperators, function (i, k) {
|
|
val = val.replace(k, '');
|
|
});
|
|
var option = that.add({
|
|
value: val,
|
|
text: val,
|
|
selected: true
|
|
}, true);
|
|
|
|
if (!option) {
|
|
this.value = '';
|
|
that.setMessage('That tag is already in use.');
|
|
} else {
|
|
that.close();
|
|
clearSearch.call(that);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
this.update = util.debounce(function () {
|
|
// Optionally close dropdown on scroll / resize (#11)
|
|
if (that.opened && that.config.closeOnScroll) {
|
|
that.close();
|
|
}
|
|
|
|
if (that.width) {
|
|
that.container.style.width = that.width;
|
|
}
|
|
|
|
that.invert();
|
|
}, 50);
|
|
|
|
if (this.requiresPagination) {
|
|
this.paginateItems = util.debounce(function () {
|
|
load.call(this);
|
|
}, 50);
|
|
this.tree.addEventListener("scroll", this.paginateItems.bind(this));
|
|
} // Dismiss when clicking outside the container
|
|
|
|
|
|
document.addEventListener("click", this.events.dismiss);
|
|
window.addEventListener("keydown", this.events.navigate);
|
|
window.addEventListener("resize", this.update);
|
|
window.addEventListener("scroll", this.update); // Listen for form.reset() (@ambrooks, #13)
|
|
|
|
if (this.el.form) {
|
|
this.el.form.addEventListener("reset", this.events.reset);
|
|
}
|
|
};
|
|
/**
|
|
* Check for selected options
|
|
* @param {bool} reset
|
|
*/
|
|
|
|
|
|
Selectr.prototype.setSelected = function (reset) {
|
|
// Select first option as with a native select-one element - #21, #24
|
|
if (!this.config.data && !this.el.multiple && this.el.options.length) {
|
|
// Browser has selected the first option by default
|
|
if (this.el.selectedIndex === 0) {
|
|
if (!this.el.options[0].defaultSelected && !this.config.defaultSelected) {
|
|
this.el.selectedIndex = -1;
|
|
}
|
|
}
|
|
|
|
this.selectedIndex = this.el.selectedIndex;
|
|
|
|
if (this.selectedIndex > -1) {
|
|
this.select(this.selectedIndex);
|
|
}
|
|
} // If we're changing a select-one to select-multiple via the config
|
|
// and there are no selected options, the first option will be selected by the browser
|
|
// Let's prevent that here.
|
|
|
|
|
|
if (this.config.multiple && this.originalType === "select-one" && !this.config.data) {
|
|
if (this.el.options[0].selected && !this.el.options[0].defaultSelected) {
|
|
this.el.options[0].selected = false;
|
|
}
|
|
}
|
|
|
|
util.each(this.options, function (i, option) {
|
|
if (option.selected && option.defaultSelected) {
|
|
this.select(option.idx);
|
|
}
|
|
}, this);
|
|
|
|
if (this.config.selectedValue) {
|
|
this.setValue(this.config.selectedValue);
|
|
}
|
|
|
|
if (this.config.data) {
|
|
if (!this.el.multiple && this.config.defaultSelected && this.el.selectedIndex < 0) {
|
|
this.select(0);
|
|
}
|
|
|
|
var j = 0;
|
|
util.each(this.config.data, function (i, opt) {
|
|
// Check for group options
|
|
if (isset(opt, "children")) {
|
|
util.each(opt.children, function (x, item) {
|
|
if (item.hasOwnProperty("selected") && item.selected === true) {
|
|
this.select(j);
|
|
}
|
|
|
|
j++;
|
|
}, this);
|
|
} else {
|
|
if (opt.hasOwnProperty("selected") && opt.selected === true) {
|
|
this.select(j);
|
|
}
|
|
|
|
j++;
|
|
}
|
|
}, this);
|
|
}
|
|
};
|
|
/**
|
|
* Destroy the instance
|
|
* @return {void}
|
|
*/
|
|
|
|
|
|
Selectr.prototype.destroy = function () {
|
|
if (!this.rendered) return;
|
|
this.emit("selectr.destroy"); // Revert to select-single if programtically set to multiple
|
|
|
|
if (this.originalType === 'select-one') {
|
|
this.el.multiple = false;
|
|
}
|
|
|
|
if (this.config.data) {
|
|
this.el.textContent = "";
|
|
} // Remove the className from select element
|
|
|
|
|
|
util.removeClass(this.el, 'selectr-hidden'); // Remove reset listener from parent form
|
|
|
|
if (this.el.form) {
|
|
util.off(this.el.form, "reset", this.events.reset);
|
|
} // Remove event listeners attached to doc and win
|
|
|
|
|
|
util.off(document, "click", this.events.dismiss);
|
|
util.off(document, "keydown", this.events.navigate);
|
|
util.off(window, "resize", this.update);
|
|
util.off(window, "scroll", this.update); // Replace the container with the original select element
|
|
|
|
this.container.parentNode.replaceChild(this.el, this.container);
|
|
this.rendered = false;
|
|
};
|
|
/**
|
|
* Change an options state
|
|
* @param {Number} index
|
|
* @return {void}
|
|
*/
|
|
|
|
|
|
Selectr.prototype.change = function (index) {
|
|
var item = this.items[index],
|
|
option = this.options[index];
|
|
|
|
if (option.disabled) {
|
|
return;
|
|
}
|
|
|
|
if (option.selected && util.hasClass(item, "selected")) {
|
|
this.deselect(index);
|
|
} else {
|
|
this.select(index);
|
|
}
|
|
|
|
if (this.opened && !this.el.multiple) {
|
|
this.close();
|
|
}
|
|
};
|
|
/**
|
|
* Select an option
|
|
* @param {Number} index
|
|
* @return {void}
|
|
*/
|
|
|
|
|
|
Selectr.prototype.select = function (index) {
|
|
var item = this.items[index],
|
|
options = [].slice.call(this.el.options),
|
|
option = this.options[index];
|
|
|
|
if (this.el.multiple) {
|
|
if (util.includes(this.selectedIndexes, index)) {
|
|
return false;
|
|
}
|
|
|
|
if (this.config.maxSelections && this.tags.length === this.config.maxSelections) {
|
|
this.setMessage("A maximum of " + this.config.maxSelections + " items can be selected.", true);
|
|
return false;
|
|
}
|
|
|
|
this.selectedValues.push(option.value);
|
|
this.selectedIndexes.push(index);
|
|
addTag.call(this, item);
|
|
} else {
|
|
var data = this.data ? this.data[index] : option;
|
|
this.label.textContent = this.customSelected ? this.config.renderSelection(data) : option.textContent;
|
|
this.selectedValue = option.value;
|
|
this.selectedIndex = index;
|
|
util.each(this.options, function (i, o) {
|
|
var opt = this.items[i];
|
|
|
|
if (i !== index) {
|
|
if (opt) {
|
|
util.removeClass(opt, "selected");
|
|
}
|
|
|
|
o.selected = false;
|
|
o.removeAttribute("selected");
|
|
}
|
|
}, this);
|
|
}
|
|
|
|
if (!util.includes(options, option)) {
|
|
this.el.add(option);
|
|
}
|
|
|
|
item.setAttribute("aria-selected", true);
|
|
util.addClass(item, "selected");
|
|
util.addClass(this.container, "has-selected");
|
|
option.selected = true;
|
|
option.setAttribute("selected", "");
|
|
this.emit("selectr.change", option);
|
|
this.emit("selectr.select", option);
|
|
};
|
|
/**
|
|
* Deselect an option
|
|
* @param {Number} index
|
|
* @return {void}
|
|
*/
|
|
|
|
|
|
Selectr.prototype.deselect = function (index, force) {
|
|
var item = this.items[index],
|
|
option = this.options[index];
|
|
|
|
if (this.el.multiple) {
|
|
var selIndex = this.selectedIndexes.indexOf(index);
|
|
this.selectedIndexes.splice(selIndex, 1);
|
|
var valIndex = this.selectedValues.indexOf(option.value);
|
|
this.selectedValues.splice(valIndex, 1);
|
|
removeTag.call(this, item);
|
|
|
|
if (!this.tags.length) {
|
|
util.removeClass(this.container, "has-selected");
|
|
}
|
|
} else {
|
|
if (!force && !this.config.clearable && !this.config.allowDeselect) {
|
|
return false;
|
|
}
|
|
|
|
this.label.textContent = "";
|
|
this.selectedValue = null;
|
|
this.el.selectedIndex = this.selectedIndex = -1;
|
|
util.removeClass(this.container, "has-selected");
|
|
}
|
|
|
|
this.items[index].setAttribute("aria-selected", false);
|
|
util.removeClass(this.items[index], "selected");
|
|
option.selected = false;
|
|
option.removeAttribute("selected");
|
|
this.emit("selectr.change", null);
|
|
this.emit("selectr.deselect", option);
|
|
};
|
|
/**
|
|
* Programmatically set selected values
|
|
* @param {String|Array} value - A string or an array of strings
|
|
*/
|
|
|
|
|
|
Selectr.prototype.setValue = function (value) {
|
|
var isArray = Array.isArray(value);
|
|
|
|
if (!isArray) {
|
|
value = value.toString().trim();
|
|
} // Can't pass array to select-one
|
|
|
|
|
|
if (!this.el.multiple && isArray) {
|
|
return false;
|
|
}
|
|
|
|
util.each(this.options, function (i, option) {
|
|
if (isArray && util.includes(value.toString(), option.value) || option.value === value) {
|
|
this.change(option.idx);
|
|
}
|
|
}, this);
|
|
};
|
|
/**
|
|
* Set the selected value(s)
|
|
* @param {bool} toObject Return only the raw values or an object
|
|
* @param {bool} toJson Return the object as a JSON string
|
|
* @return {mixed} Array or String
|
|
*/
|
|
|
|
|
|
Selectr.prototype.getValue = function (toObject, toJson) {
|
|
var value;
|
|
|
|
if (this.el.multiple) {
|
|
if (toObject) {
|
|
if (this.selectedIndexes.length) {
|
|
value = {};
|
|
value.values = [];
|
|
util.each(this.selectedIndexes, function (i, index) {
|
|
var option = this.options[index];
|
|
value.values[i] = {
|
|
value: option.value,
|
|
text: option.textContent
|
|
};
|
|
}, this);
|
|
}
|
|
} else {
|
|
value = this.selectedValues.slice();
|
|
}
|
|
} else {
|
|
if (toObject) {
|
|
var option = this.options[this.selectedIndex];
|
|
value = {
|
|
value: option.value,
|
|
text: option.textContent
|
|
};
|
|
} else {
|
|
value = this.selectedValue;
|
|
}
|
|
}
|
|
|
|
if (toObject && toJson) {
|
|
value = JSON.stringify(value);
|
|
}
|
|
|
|
return value;
|
|
};
|
|
/**
|
|
* Add a new option or options
|
|
* @param {object} data
|
|
*/
|
|
|
|
|
|
Selectr.prototype.add = function (data, checkDuplicate) {
|
|
if (data) {
|
|
this.data = this.data || [];
|
|
this.items = this.items || [];
|
|
this.options = this.options || [];
|
|
|
|
if (Array.isArray(data)) {
|
|
// We have an array on items
|
|
util.each(data, function (i, obj) {
|
|
this.add(obj, checkDuplicate);
|
|
}, this);
|
|
} // User passed a single object to the method
|
|
// or Selectr passed an object from an array
|
|
else if ("[object Object]" === Object.prototype.toString.call(data)) {
|
|
if (checkDuplicate) {
|
|
var dupe = false;
|
|
util.each(this.options, function (i, option) {
|
|
if (option.value.toLowerCase() === data.value.toLowerCase()) {
|
|
dupe = true;
|
|
}
|
|
});
|
|
|
|
if (dupe) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
var option = util.createElement('option', data);
|
|
this.data.push(data); // Add the new option to the list
|
|
|
|
this.options.push(option); // Add the index for later use
|
|
|
|
option.idx = this.options.length > 0 ? this.options.length - 1 : 0; // Create a new item
|
|
|
|
createItem.call(this, option); // Select the item if required
|
|
|
|
if (data.selected) {
|
|
this.select(option.idx);
|
|
}
|
|
|
|
return option;
|
|
} // We may have had an empty select so update
|
|
// the placeholder to reflect the changes.
|
|
|
|
|
|
this.setPlaceholder(); // Recount the pages
|
|
|
|
if (this.config.pagination) {
|
|
this.paginate();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
};
|
|
/**
|
|
* Remove an option or options
|
|
* @param {Mixed} o Array, integer (index) or string (value)
|
|
* @return {Void}
|
|
*/
|
|
|
|
|
|
Selectr.prototype.remove = function (o) {
|
|
var options = [];
|
|
|
|
if (Array.isArray(o)) {
|
|
util.each(o, function (i, opt) {
|
|
if (util.isInt(opt)) {
|
|
options.push(this.getOptionByIndex(opt));
|
|
} else if (typeof o === "string") {
|
|
options.push(this.getOptionByValue(opt));
|
|
}
|
|
}, this);
|
|
} else if (util.isInt(o)) {
|
|
options.push(this.getOptionByIndex(o));
|
|
} else if (typeof o === "string") {
|
|
options.push(this.getOptionByValue(o));
|
|
}
|
|
|
|
if (options.length) {
|
|
var index;
|
|
util.each(options, function (i, option) {
|
|
index = option.idx; // Remove the HTMLOptionElement
|
|
|
|
this.el.remove(option); // Remove the reference from the option array
|
|
|
|
this.options.splice(index, 1); // If the item has a parentNode (group element) it needs to be removed
|
|
// otherwise the render function will still append it to the dropdown
|
|
|
|
var parentNode = this.items[index].parentNode;
|
|
|
|
if (parentNode) {
|
|
parentNode.removeChild(this.items[index]);
|
|
} // Remove reference from the items array
|
|
|
|
|
|
this.items.splice(index, 1); // Reset the indexes
|
|
|
|
util.each(this.options, function (i, opt) {
|
|
opt.idx = i;
|
|
this.items[i].idx = i;
|
|
}, this);
|
|
}, this); // We may have had an empty select now so update
|
|
// the placeholder to reflect the changes.
|
|
|
|
this.setPlaceholder(); // Recount the pages
|
|
|
|
if (this.config.pagination) {
|
|
this.paginate();
|
|
}
|
|
}
|
|
};
|
|
/**
|
|
* Remove all options
|
|
*/
|
|
|
|
|
|
Selectr.prototype.removeAll = function () {
|
|
// Clear any selected options
|
|
this.clear(true); // Remove the HTMLOptionElements
|
|
|
|
util.each(this.el.options, function (i, option) {
|
|
this.el.remove(option);
|
|
}, this); // Empty the dropdown
|
|
|
|
util.truncate(this.tree); // Reset variables
|
|
|
|
this.items = [];
|
|
this.options = [];
|
|
this.data = [];
|
|
this.navIndex = 0;
|
|
|
|
if (this.requiresPagination) {
|
|
this.requiresPagination = false;
|
|
this.pageIndex = 1;
|
|
this.pages = [];
|
|
} // Update the placeholder
|
|
|
|
|
|
this.setPlaceholder();
|
|
};
|
|
/**
|
|
* Perform a search
|
|
* @param {string} query The query string
|
|
*/
|
|
|
|
|
|
Selectr.prototype.search = function (string) {
|
|
if (this.navigating) return;
|
|
string = string || this.input.value;
|
|
var f = document.createDocumentFragment(); // Remove message
|
|
|
|
this.removeMessage(); // Clear the dropdown
|
|
|
|
util.truncate(this.tree);
|
|
|
|
if (string.length > 1) {
|
|
// Check the options for the matching string
|
|
util.each(this.options, function (i, option) {
|
|
var item = this.items[option.idx];
|
|
var includes = util.includes(option.textContent.toLowerCase(), string.toLowerCase());
|
|
|
|
if (includes && !option.disabled) {
|
|
appendItem(item, f, this.customOption);
|
|
util.removeClass(item, "excluded"); // Underline the matching results
|
|
|
|
if (!this.customOption) {
|
|
item.textContent = '';
|
|
var result = match(string, option.textContent);
|
|
|
|
if (result) {
|
|
item.appendChild(document.createTextNode(result.before));
|
|
var highlight = document.createElement('span');
|
|
highlight.className = 'selectr-match';
|
|
highlight.appendChild(document.createTextNode(result.match));
|
|
item.appendChild(highlight);
|
|
item.appendChild(document.createTextNode(result.after));
|
|
}
|
|
}
|
|
} else {
|
|
util.addClass(item, "excluded");
|
|
}
|
|
}, this);
|
|
|
|
if (!f.childElementCount) {
|
|
if (!this.config.taggable) {
|
|
this.setMessage("no results.");
|
|
}
|
|
} else {
|
|
// Highlight top result (@binary-koan #26)
|
|
var prevEl = this.items[this.navIndex];
|
|
var firstEl = f.firstElementChild;
|
|
util.removeClass(prevEl, "active");
|
|
this.navIndex = firstEl.idx;
|
|
util.addClass(firstEl, "active");
|
|
}
|
|
} else {
|
|
render.call(this);
|
|
}
|
|
|
|
this.tree.appendChild(f);
|
|
};
|
|
/**
|
|
* Toggle the dropdown
|
|
* @return {void}
|
|
*/
|
|
|
|
|
|
Selectr.prototype.toggle = function () {
|
|
if (!this.disabled) {
|
|
if (this.opened) {
|
|
this.close();
|
|
} else {
|
|
this.open();
|
|
}
|
|
}
|
|
};
|
|
/**
|
|
* Open the dropdown
|
|
* @return {void}
|
|
*/
|
|
|
|
|
|
Selectr.prototype.open = function () {
|
|
var that = this;
|
|
|
|
if (!this.options.length) {
|
|
return false;
|
|
}
|
|
|
|
if (!this.opened) {
|
|
this.emit("selectr.open");
|
|
}
|
|
|
|
this.opened = true;
|
|
|
|
if (this.mobileDevice || this.config.nativeDropdown) {
|
|
util.addClass(this.container, "native-open");
|
|
|
|
if (this.config.data) {
|
|
// Dump the options into the select
|
|
// otherwise the native dropdown will be empty
|
|
util.each(this.options, function (i, option) {
|
|
this.el.add(option);
|
|
}, this);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
util.addClass(this.container, "open");
|
|
render.call(this);
|
|
this.invert();
|
|
this.tree.scrollTop = 0;
|
|
util.removeClass(this.container, "notice");
|
|
this.selected.setAttribute("aria-expanded", true);
|
|
this.tree.setAttribute("aria-hidden", false);
|
|
this.tree.setAttribute("aria-expanded", true);
|
|
|
|
if (this.config.searchable && !this.config.taggable) {
|
|
setTimeout(function () {
|
|
that.input.focus(); // Allow tab focus
|
|
|
|
that.input.tabIndex = 0;
|
|
}, 10);
|
|
}
|
|
};
|
|
/**
|
|
* Close the dropdown
|
|
* @return {void}
|
|
*/
|
|
|
|
|
|
Selectr.prototype.close = function () {
|
|
if (this.opened) {
|
|
this.emit("selectr.close");
|
|
}
|
|
|
|
this.opened = false;
|
|
|
|
if (this.mobileDevice || this.config.nativeDropdown) {
|
|
util.removeClass(this.container, "native-open");
|
|
return;
|
|
}
|
|
|
|
var notice = util.hasClass(this.container, "notice");
|
|
|
|
if (this.config.searchable && !notice) {
|
|
this.input.blur(); // Disable tab focus
|
|
|
|
this.input.tabIndex = -1;
|
|
this.searching = false;
|
|
}
|
|
|
|
if (notice) {
|
|
util.removeClass(this.container, "notice");
|
|
this.notice.textContent = "";
|
|
}
|
|
|
|
util.removeClass(this.container, "open");
|
|
util.removeClass(this.container, "native-open");
|
|
this.selected.setAttribute("aria-expanded", false);
|
|
this.tree.setAttribute("aria-hidden", true);
|
|
this.tree.setAttribute("aria-expanded", false);
|
|
util.truncate(this.tree);
|
|
clearSearch.call(this);
|
|
};
|
|
/**
|
|
* Enable the element
|
|
* @return {void}
|
|
*/
|
|
|
|
|
|
Selectr.prototype.enable = function () {
|
|
this.disabled = false;
|
|
this.el.disabled = false;
|
|
this.selected.tabIndex = this.originalIndex;
|
|
|
|
if (this.el.multiple) {
|
|
util.each(this.tags, function (i, t) {
|
|
t.lastElementChild.tabIndex = 0;
|
|
});
|
|
}
|
|
|
|
util.removeClass(this.container, "selectr-disabled");
|
|
};
|
|
/**
|
|
* Disable the element
|
|
* @param {boolean} container Disable the container only (allow value submit with form)
|
|
* @return {void}
|
|
*/
|
|
|
|
|
|
Selectr.prototype.disable = function (container) {
|
|
if (!container) {
|
|
this.el.disabled = true;
|
|
}
|
|
|
|
this.selected.tabIndex = -1;
|
|
|
|
if (this.el.multiple) {
|
|
util.each(this.tags, function (i, t) {
|
|
t.lastElementChild.tabIndex = -1;
|
|
});
|
|
}
|
|
|
|
this.disabled = true;
|
|
util.addClass(this.container, "selectr-disabled");
|
|
};
|
|
/**
|
|
* Reset to initial state
|
|
* @return {void}
|
|
*/
|
|
|
|
|
|
Selectr.prototype.reset = function () {
|
|
if (!this.disabled) {
|
|
this.clear();
|
|
this.setSelected(true);
|
|
util.each(this.defaultSelected, function (i, idx) {
|
|
this.select(idx);
|
|
}, this);
|
|
this.emit("selectr.reset");
|
|
}
|
|
};
|
|
/**
|
|
* Clear all selections
|
|
* @return {void}
|
|
*/
|
|
|
|
|
|
Selectr.prototype.clear = function (force) {
|
|
if (this.el.multiple) {
|
|
// Loop over the selectedIndexes so we don't have to loop over all the options
|
|
// which can be costly if there are a lot of them
|
|
if (this.selectedIndexes.length) {
|
|
// Copy the array or we'll get an error
|
|
var indexes = this.selectedIndexes.slice();
|
|
util.each(indexes, function (i, idx) {
|
|
this.deselect(idx);
|
|
}, this);
|
|
}
|
|
} else {
|
|
if (this.selectedIndex > -1) {
|
|
this.deselect(this.selectedIndex, force);
|
|
}
|
|
}
|
|
|
|
this.emit("selectr.clear");
|
|
};
|
|
/**
|
|
* Return serialised data
|
|
* @param {boolean} toJson
|
|
* @return {mixed} Returns either an object or JSON string
|
|
*/
|
|
|
|
|
|
Selectr.prototype.serialise = function (toJson) {
|
|
var data = [];
|
|
util.each(this.options, function (i, option) {
|
|
var obj = {
|
|
value: option.value,
|
|
text: option.textContent
|
|
};
|
|
|
|
if (option.selected) {
|
|
obj.selected = true;
|
|
}
|
|
|
|
if (option.disabled) {
|
|
obj.disabled = true;
|
|
}
|
|
|
|
data[i] = obj;
|
|
});
|
|
return toJson ? JSON.stringify(data) : data;
|
|
};
|
|
/**
|
|
* Localised version of serialise() method
|
|
*/
|
|
|
|
|
|
Selectr.prototype.serialize = function (toJson) {
|
|
return this.serialise(toJson);
|
|
};
|
|
/**
|
|
* Sets the placeholder
|
|
* @param {String} placeholder
|
|
*/
|
|
|
|
|
|
Selectr.prototype.setPlaceholder = function (placeholder) {
|
|
// Set the placeholder
|
|
placeholder = placeholder || this.config.placeholder || this.el.getAttribute("placeholder");
|
|
|
|
if (!this.options.length) {
|
|
placeholder = "No options available";
|
|
}
|
|
|
|
this.placeEl.textContent = placeholder;
|
|
};
|
|
/**
|
|
* Paginate the option list
|
|
* @return {Array}
|
|
*/
|
|
|
|
|
|
Selectr.prototype.paginate = function () {
|
|
if (this.items.length) {
|
|
var that = this;
|
|
this.pages = this.items.map(function (v, i) {
|
|
return i % that.config.pagination === 0 ? that.items.slice(i, i + that.config.pagination) : null;
|
|
}).filter(function (pages) {
|
|
return pages;
|
|
});
|
|
return this.pages;
|
|
}
|
|
};
|
|
/**
|
|
* Display a message
|
|
* @param {String} message The message
|
|
*/
|
|
|
|
|
|
Selectr.prototype.setMessage = function (message, close) {
|
|
if (close) {
|
|
this.close();
|
|
}
|
|
|
|
util.addClass(this.container, "notice");
|
|
this.notice.textContent = message;
|
|
};
|
|
/**
|
|
* Dismiss the current message
|
|
*/
|
|
|
|
|
|
Selectr.prototype.removeMessage = function () {
|
|
util.removeClass(this.container, "notice");
|
|
this.notice.textContent = "";
|
|
};
|
|
/**
|
|
* Keep the dropdown within the window
|
|
* @return {void}
|
|
*/
|
|
|
|
|
|
Selectr.prototype.invert = function () {
|
|
var rt = util.rect(this.selected),
|
|
oh = this.tree.parentNode.offsetHeight,
|
|
wh = window.innerHeight,
|
|
doInvert = rt.top + rt.height + oh > wh;
|
|
|
|
if (doInvert) {
|
|
util.addClass(this.container, "inverted");
|
|
this.isInverted = true;
|
|
} else {
|
|
util.removeClass(this.container, "inverted");
|
|
this.isInverted = false;
|
|
}
|
|
|
|
this.optsRect = util.rect(this.tree);
|
|
};
|
|
/**
|
|
* Get an option via it's index
|
|
* @param {Integer} index The index of the HTMLOptionElement required
|
|
* @return {HTMLOptionElement}
|
|
*/
|
|
|
|
|
|
Selectr.prototype.getOptionByIndex = function (index) {
|
|
return this.options[index];
|
|
};
|
|
/**
|
|
* Get an option via it's value
|
|
* @param {String} value The value of the HTMLOptionElement required
|
|
* @return {HTMLOptionElement}
|
|
*/
|
|
|
|
|
|
Selectr.prototype.getOptionByValue = function (value) {
|
|
var option = false;
|
|
|
|
for (var i = 0, l = this.options.length; i < l; i++) {
|
|
if (this.options[i].value.trim() === value.toString().trim()) {
|
|
option = this.options[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
return option;
|
|
};
|
|
|
|
module.exports = Selectr;
|
|
|
|
/***/ }),
|
|
|
|
/***/ 4188:
|
|
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
|
|
|
"use strict";
|
|
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
/* harmony export */ "qD": function() { return /* binding */ DEFAULT_MODAL_ANCHOR; },
|
|
/* harmony export */ "EX": function() { return /* binding */ SIZE_LARGE; },
|
|
/* harmony export */ "WF": function() { return /* binding */ MAX_PREVIEW_CHARACTERS; },
|
|
/* harmony export */ "oW": function() { return /* binding */ PREVIEW_HISTORY_LIMIT; }
|
|
/* harmony export */ });
|
|
var DEFAULT_MODAL_ANCHOR = document.body;
|
|
var SIZE_LARGE = 10 * 1024 * 1024; // 10 MB
|
|
|
|
var MAX_PREVIEW_CHARACTERS = 20000;
|
|
var PREVIEW_HISTORY_LIMIT = 2 * 1024 * 1024 * 1024; // 2 GB
|
|
|
|
/***/ }),
|
|
|
|
/***/ 2602:
|
|
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
|
|
|
"use strict";
|
|
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
/* harmony export */ "w": function() { return /* binding */ createAbsoluteAnchor; }
|
|
/* harmony export */ });
|
|
/* harmony import */ var _util__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(9791);
|
|
|
|
/**
|
|
* Create an anchor element absolutely positioned in the `parent`
|
|
* element.
|
|
* @param {HTMLElement} anchor
|
|
* @param {HTMLElement} parent
|
|
* @param {function(HTMLElement)} [onDestroy] Callback when the anchor is destroyed
|
|
* @param {boolean} [destroyOnMouseOut=false] If true, anchor will be removed on mouse out
|
|
* @returns {HTMLElement}
|
|
*/
|
|
|
|
function createAbsoluteAnchor(anchor, parent, onDestroy) {
|
|
var destroyOnMouseOut = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
|
|
var root = getRootNode(anchor);
|
|
var eventListeners = {};
|
|
var anchorRect = anchor.getBoundingClientRect();
|
|
var parentRect = parent.getBoundingClientRect();
|
|
var absoluteAnchor = document.createElement('div');
|
|
absoluteAnchor.className = 'jsoneditor-anchor';
|
|
absoluteAnchor.style.position = 'absolute';
|
|
absoluteAnchor.style.left = anchorRect.left - parentRect.left + 'px';
|
|
absoluteAnchor.style.top = anchorRect.top - parentRect.top + 'px';
|
|
absoluteAnchor.style.width = anchorRect.width - 2 + 'px';
|
|
absoluteAnchor.style.height = anchorRect.height - 2 + 'px';
|
|
absoluteAnchor.style.boxSizing = 'border-box';
|
|
parent.appendChild(absoluteAnchor);
|
|
|
|
function destroy() {
|
|
// remove temporary absolutely positioned anchor
|
|
if (absoluteAnchor && absoluteAnchor.parentNode) {
|
|
absoluteAnchor.parentNode.removeChild(absoluteAnchor); // remove all event listeners
|
|
// all event listeners are supposed to be attached to document.
|
|
|
|
for (var name in eventListeners) {
|
|
if (hasOwnProperty(eventListeners, name)) {
|
|
var fn = eventListeners[name];
|
|
|
|
if (fn) {
|
|
(0,_util__WEBPACK_IMPORTED_MODULE_0__.removeEventListener)(root, name, fn);
|
|
}
|
|
|
|
delete eventListeners[name];
|
|
}
|
|
}
|
|
|
|
if (typeof onDestroy === 'function') {
|
|
onDestroy(anchor);
|
|
}
|
|
}
|
|
}
|
|
|
|
function isOutside(target) {
|
|
return target !== absoluteAnchor && !(0,_util__WEBPACK_IMPORTED_MODULE_0__.isChildOf)(target, absoluteAnchor);
|
|
} // create and attach event listeners
|
|
|
|
|
|
function destroyIfOutside(event) {
|
|
if (isOutside(event.target)) {
|
|
destroy();
|
|
}
|
|
}
|
|
|
|
eventListeners.mousedown = (0,_util__WEBPACK_IMPORTED_MODULE_0__.addEventListener)(root, 'mousedown', destroyIfOutside);
|
|
eventListeners.mousewheel = (0,_util__WEBPACK_IMPORTED_MODULE_0__.addEventListener)(root, 'mousewheel', destroyIfOutside);
|
|
|
|
if (destroyOnMouseOut) {
|
|
var destroyTimer = null;
|
|
|
|
absoluteAnchor.onmouseover = function () {
|
|
clearTimeout(destroyTimer);
|
|
destroyTimer = null;
|
|
};
|
|
|
|
absoluteAnchor.onmouseout = function () {
|
|
if (!destroyTimer) {
|
|
destroyTimer = setTimeout(destroy, 200);
|
|
}
|
|
};
|
|
}
|
|
|
|
absoluteAnchor.destroy = destroy;
|
|
return absoluteAnchor;
|
|
}
|
|
/**
|
|
* Node.getRootNode shim
|
|
* @param {HTMLElement} node node to check
|
|
* @return {HTMLElement} node's rootNode or `window` if there is ShadowDOM is not supported.
|
|
*/
|
|
|
|
function getRootNode(node) {
|
|
return typeof node.getRootNode === 'function' ? node.getRootNode() : window;
|
|
}
|
|
|
|
function hasOwnProperty(object, key) {
|
|
return Object.prototype.hasOwnProperty.call(object, key);
|
|
}
|
|
|
|
/***/ }),
|
|
|
|
/***/ 7923:
|
|
/***/ (function(module) {
|
|
|
|
module.exports = 'data:application/javascript;base64,Im5vIHVzZSBzdHJpY3QiOwohKGZ1bmN0aW9uKHdpbmRvdykgewppZiAodHlwZW9mIHdpbmRvdy53aW5kb3cgIT0gInVuZGVmaW5lZCIgJiYgd2luZG93LmRvY3VtZW50KQogICAgcmV0dXJuOwppZiAod2luZG93LnJlcXVpcmUgJiYgd2luZG93LmRlZmluZSkKICAgIHJldHVybjsKCmlmICghd2luZG93LmNvbnNvbGUpIHsKICAgIHdpbmRvdy5jb25zb2xlID0gZnVuY3Rpb24oKSB7CiAgICAgICAgdmFyIG1zZ3MgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMsIDApOwogICAgICAgIHBvc3RNZXNzYWdlKHt0eXBlOiAibG9nIiwgZGF0YTogbXNnc30pOwogICAgfTsKICAgIHdpbmRvdy5jb25zb2xlLmVycm9yID0KICAgIHdpbmRvdy5jb25zb2xlLndhcm4gPSAKICAgIHdpbmRvdy5jb25zb2xlLmxvZyA9CiAgICB3aW5kb3cuY29uc29sZS50cmFjZSA9IHdpbmRvdy5jb25zb2xlOwp9CndpbmRvdy53aW5kb3cgPSB3aW5kb3c7CndpbmRvdy5hY2UgPSB3aW5kb3c7Cgp3aW5kb3cub25lcnJvciA9IGZ1bmN0aW9uKG1lc3NhZ2UsIGZpbGUsIGxpbmUsIGNvbCwgZXJyKSB7CiAgICBwb3N0TWVzc2FnZSh7dHlwZTogImVycm9yIiwgZGF0YTogewogICAgICAgIG1lc3NhZ2U6IG1lc3NhZ2UsCiAgICAgICAgZGF0YTogZXJyLmRhdGEsCiAgICAgICAgZmlsZTogZmlsZSwKICAgICAgICBsaW5lOiBsaW5lLCAKICAgICAgICBjb2w6IGNvbCwKICAgICAgICBzdGFjazogZXJyLnN0YWNrCiAgICB9fSk7Cn07Cgp3aW5kb3cubm9ybWFsaXplTW9kdWxlID0gZnVuY3Rpb24ocGFyZW50SWQsIG1vZHVsZU5hbWUpIHsKICAgIC8vIG5vcm1hbGl6ZSBwbHVnaW4gcmVxdWlyZXMKICAgIGlmIChtb2R1bGVOYW1lLmluZGV4T2YoIiEiKSAhPT0gLTEpIHsKICAgICAgICB2YXIgY2h1bmtzID0gbW9kdWxlTmFtZS5zcGxpdCgiISIpOwogICAgICAgIHJldHVybiB3aW5kb3cubm9ybWFsaXplTW9kdWxlKHBhcmVudElkLCBjaHVua3NbMF0pICsgIiEiICsgd2luZG93Lm5vcm1hbGl6ZU1vZHVsZShwYXJlbnRJZCwgY2h1bmtzWzFdKTsKICAgIH0KICAgIC8vIG5vcm1hbGl6ZSByZWxhdGl2ZSByZXF1aXJlcwogICAgaWYgKG1vZHVsZU5hbWUuY2hhckF0KDApID09ICIuIikgewogICAgICAgIHZhciBiYXNlID0gcGFyZW50SWQuc3BsaXQoIi8iKS5zbGljZSgwLCAtMSkuam9pbigiLyIpOwogICAgICAgIG1vZHVsZU5hbWUgPSAoYmFzZSA/IGJhc2UgKyAiLyIgOiAiIikgKyBtb2R1bGVOYW1lOwogICAgICAgIAogICAgICAgIHdoaWxlIChtb2R1bGVOYW1lLmluZGV4T2YoIi4iKSAhPT0gLTEgJiYgcHJldmlvdXMgIT0gbW9kdWxlTmFtZSkgewogICAgICAgICAgICB2YXIgcHJldmlvdXMgPSBtb2R1bGVOYW1lOwogICAgICAgICAgICBtb2R1bGVOYW1lID0gbW9kdWxlTmFtZS5yZXBsYWNlKC9eXC5cLy8sICIiKS5yZXBsYWNlKC9cL1wuXC8vLCAiLyIpLnJlcGxhY2UoL1teXC9dK1wvXC5cLlwvLywgIiIpOwogICAgICAgIH0KICAgIH0KICAgIAogICAgcmV0dXJuIG1vZHVsZU5hbWU7Cn07Cgp3aW5kb3cucmVxdWlyZSA9IGZ1bmN0aW9uIHJlcXVpcmUocGFyZW50SWQsIGlkKSB7CiAgICBpZiAoIWlkKSB7CiAgICAgICAgaWQgPSBwYXJlbnRJZDsKICAgICAgICBwYXJlbnRJZCA9IG51bGw7CiAgICB9CiAgICBpZiAoIWlkLmNoYXJBdCkKICAgICAgICB0aHJvdyBuZXcgRXJyb3IoIndvcmtlci5qcyByZXF1aXJlKCkgYWNjZXB0cyBvbmx5IChwYXJlbnRJZCwgaWQpIGFzIGFyZ3VtZW50cyIpOwoKICAgIGlkID0gd2luZG93Lm5vcm1hbGl6ZU1vZHVsZShwYXJlbnRJZCwgaWQpOwoKICAgIHZhciBtb2R1bGUgPSB3aW5kb3cucmVxdWlyZS5tb2R1bGVzW2lkXTsKICAgIGlmIChtb2R1bGUpIHsKICAgICAgICBpZiAoIW1vZHVsZS5pbml0aWFsaXplZCkgewogICAgICAgICAgICBtb2R1bGUuaW5pdGlhbGl6ZWQgPSB0cnVlOwogICAgICAgICAgICBtb2R1bGUuZXhwb3J0cyA9IG1vZHVsZS5mYWN0b3J5KCkuZXhwb3J0czsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIG1vZHVsZS5leHBvcnRzOwogICAgfQogICAKICAgIGlmICghd2luZG93LnJlcXVpcmUudGxucykKICAgICAgICByZXR1cm4gY29uc29sZS5sb2coInVuYWJsZSB0byBsb2FkICIgKyBpZCk7CiAgICAKICAgIHZhciBwYXRoID0gcmVzb2x2ZU1vZHVsZUlkKGlkLCB3aW5kb3cucmVxdWlyZS50bG5zKTsKICAgIGlmIChwYXRoLnNsaWNlKC0zKSAhPSAiLmpzIikgcGF0aCArPSAiLmpzIjsKICAgIAogICAgd2luZG93LnJlcXVpcmUuaWQgPSBpZDsKICAgIHdpbmRvdy5yZXF1aXJlLm1vZHVsZXNbaWRdID0ge307IC8vIHByZXZlbnQgaW5maW5pdGUgbG9vcCBvbiBicm9rZW4gbW9kdWxlcwogICAgaW1wb3J0U2NyaXB0cyhwYXRoKTsKICAgIHJldHVybiB3aW5kb3cucmVxdWlyZShwYXJlbnRJZCwgaWQpOwp9OwpmdW5jdGlvbiByZXNvbHZlTW9kdWxlSWQoaWQsIHBhdGhzKSB7CiAgICB2YXIgdGVzdFBhdGggPSBpZCwgdGFpbCA9ICIiOwogICAgd2hpbGUgKHRlc3RQYXRoKSB7CiAgICAgICAgdmFyIGFsaWFzID0gcGF0aHNbdGVzdFBhdGhdOwogICAgICAgIGlmICh0eXBlb2YgYWxpYXMgPT0gInN0cmluZyIpIHsKICAgICAgICAgICAgcmV0dXJuIGFsaWFzICsgdGFpbDsKICAgICAgICB9IGVsc2UgaWYgKGFsaWFzKSB7CiAgICAgICAgICAgIHJldHVybiAgYWxpYXMubG9jYXRpb24ucmVwbGFjZSgvXC8qJC8sICIvIikgKyAodGFpbCB8fCBhbGlhcy5tYWluIHx8IGFsaWFzLm5hbWUpOwogICAgICAgIH0gZWxzZSBpZiAoYWxpYXMgPT09IGZhbHNlKSB7CiAgICAgICAgICAgIHJldHVybiAiIjsKICAgICAgICB9CiAgICAgICAgdmFyIGkgPSB0ZXN0UGF0aC5sYXN0SW5kZXhPZigiLyIpOwogICAgICAgIGlmIChpID09PSAtMSkgYnJlYWs7CiAgICAgICAgdGFpbCA9IHRlc3RQYXRoLnN1YnN0cihpKSArIHRhaWw7CiAgICAgICAgdGVzdFBhdGggPSB0ZXN0UGF0aC5zbGljZSgwLCBpKTsKICAgIH0KICAgIHJldHVybiBpZDsKfQp3aW5kb3cucmVxdWlyZS5tb2R1bGVzID0ge307CndpbmRvdy5yZXF1aXJlLnRsbnMgPSB7fTsKCndpbmRvdy5kZWZpbmUgPSBmdW5jdGlvbihpZCwgZGVwcywgZmFjdG9yeSkgewogICAgaWYgKGFyZ3VtZW50cy5sZW5ndGggPT0gMikgewogICAgICAgIGZhY3RvcnkgPSBkZXBzOwogICAgICAgIGlmICh0eXBlb2YgaWQgIT0gInN0cmluZyIpIHsKICAgICAgICAgICAgZGVwcyA9IGlkOwogICAgICAgICAgICBpZCA9IHdpbmRvdy5yZXF1aXJlLmlkOwogICAgICAgIH0KICAgIH0gZWxzZSBpZiAoYXJndW1lbnRzLmxlbmd0aCA9PSAxKSB7CiAgICAgICAgZmFjdG9yeSA9IGlkOwogICAgICAgIGRlcHMgPSBbXTsKICAgICAgICBpZCA9IHdpbmRvdy5yZXF1aXJlLmlkOwogICAgfQogICAgCiAgICBpZiAodHlwZW9mIGZhY3RvcnkgIT0gImZ1bmN0aW9uIikgewogICAgICAgIHdpbmRvdy5yZXF1aXJlLm1vZHVsZXNbaWRdID0gewogICAgICAgICAgICBleHBvcnRzOiBmYWN0b3J5LAogICAgICAgICAgICBpbml0aWFsaXplZDogdHJ1ZQogICAgICAgIH07CiAgICAgICAgcmV0dXJuOwogICAgfQoKICAgIGlmICghZGVwcy5sZW5ndGgpCiAgICAgICAgLy8gSWYgdGhlcmUgaXMgbm8gZGVwZW5kZW5jaWVzLCB3ZSBpbmplY3QgInJlcXVpcmUiLCAiZXhwb3J0cyIgYW5kCiAgICAgICAgLy8gIm1vZHVsZSIgYXMgZGVwZW5kZW5jaWVzLCB0byBwcm92aWRlIENvbW1vbkpTIGNvbXBhdGliaWxpdHkuCiAgICAgICAgZGVwcyA9IFsicmVxdWlyZSIsICJleHBvcnRzIiwgIm1vZHVsZSJdOwoKICAgIHZhciByZXEgPSBmdW5jdGlvbihjaGlsZElkKSB7CiAgICAgICAgcmV0dXJuIHdpbmRvdy5yZXF1aXJlKGlkLCBjaGlsZElkKTsKICAgIH07CgogICAgd2luZG93LnJlcXVpcmUubW9kdWxlc1tpZF0gPSB7CiAgICAgICAgZXhwb3J0czoge30sCiAgICAgICAgZmFjdG9yeTogZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHZhciBtb2R1bGUgPSB0aGlzOwogICAgICAgICAgICB2YXIgcmV0dXJuRXhwb3J0cyA9IGZhY3RvcnkuYXBwbHkodGhpcywgZGVwcy5zbGljZSgwLCBmYWN0b3J5Lmxlbmd0aCkubWFwKGZ1bmN0aW9uKGRlcCkgewogICAgICAgICAgICAgICAgc3dpdGNoIChkZXApIHsKICAgICAgICAgICAgICAgICAgICAvLyBCZWNhdXNlICJyZXF1aXJlIiwgImV4cG9ydHMiIGFuZCAibW9kdWxlIiBhcmVuJ3QgYWN0dWFsCiAgICAgICAgICAgICAgICAgICAgLy8gZGVwZW5kZW5jaWVzLCB3ZSBtdXN0IGhhbmRsZSB0aGVtIHNlcGVyYXRlbHkuCiAgICAgICAgICAgICAgICAgICAgY2FzZSAicmVxdWlyZSI6IHJldHVybiByZXE7CiAgICAgICAgICAgICAgICAgICAgY2FzZSAiZXhwb3J0cyI6IHJldHVybiBtb2R1bGUuZXhwb3J0czsKICAgICAgICAgICAgICAgICAgICBjYXNlICJtb2R1bGUiOiAgcmV0dXJuIG1vZHVsZTsKICAgICAgICAgICAgICAgICAgICAvLyBCdXQgZm9yIGFsbCBvdGhlciBkZXBlbmRlbmNpZXMsIHdlIGNhbiBqdXN0IGdvIGFoZWFkIGFuZAogICAgICAgICAgICAgICAgICAgIC8vIHJlcXVpcmUgdGhlbS4KICAgICAgICAgICAgICAgICAgICBkZWZhdWx0OiAgICAgICAgcmV0dXJuIHJlcShkZXApOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9KSk7CiAgICAgICAgICAgIGlmIChyZXR1cm5FeHBvcnRzKQogICAgICAgICAgICAgICAgbW9kdWxlLmV4cG9ydHMgPSByZXR1cm5FeHBvcnRzOwogICAgICAgICAgICByZXR1cm4gbW9kdWxlOwogICAgICAgIH0KICAgIH07Cn07CndpbmRvdy5kZWZpbmUuYW1kID0ge307CnJlcXVpcmUudGxucyA9IHt9Owp3aW5kb3cuaW5pdEJhc2VVcmxzICA9IGZ1bmN0aW9uIGluaXRCYXNlVXJscyh0b3BMZXZlbE5hbWVzcGFjZXMpIHsKICAgIGZvciAodmFyIGkgaW4gdG9wTGV2ZWxOYW1lc3BhY2VzKQogICAgICAgIHJlcXVpcmUudGxuc1tpXSA9IHRvcExldmVsTmFtZXNwYWNlc1tpXTsKfTsKCndpbmRvdy5pbml0U2VuZGVyID0gZnVuY3Rpb24gaW5pdFNlbmRlcigpIHsKCiAgICB2YXIgRXZlbnRFbWl0dGVyID0gd2luZG93LnJlcXVpcmUoImFjZS9saWIvZXZlbnRfZW1pdHRlciIpLkV2ZW50RW1pdHRlcjsKICAgIHZhciBvb3AgPSB3aW5kb3cucmVxdWlyZSgiYWNlL2xpYi9vb3AiKTsKICAgIAogICAgdmFyIFNlbmRlciA9IGZ1bmN0aW9uKCkge307CiAgICAKICAgIChmdW5jdGlvbigpIHsKICAgICAgICAKICAgICAgICBvb3AuaW1wbGVtZW50KHRoaXMsIEV2ZW50RW1pdHRlcik7CiAgICAgICAgICAgICAgICAKICAgICAgICB0aGlzLmNhbGxiYWNrID0gZnVuY3Rpb24oZGF0YSwgY2FsbGJhY2tJZCkgewogICAgICAgICAgICBwb3N0TWVzc2FnZSh7CiAgICAgICAgICAgICAgICB0eXBlOiAiY2FsbCIsCiAgICAgICAgICAgICAgICBpZDogY2FsbGJhY2tJZCwKICAgICAgICAgICAgICAgIGRhdGE6IGRhdGEKICAgICAgICAgICAgfSk7CiAgICAgICAgfTsKICAgIAogICAgICAgIHRoaXMuZW1pdCA9IGZ1bmN0aW9uKG5hbWUsIGRhdGEpIHsKICAgICAgICAgICAgcG9zdE1lc3NhZ2UoewogICAgICAgICAgICAgICAgdHlwZTogImV2ZW50IiwKICAgICAgICAgICAgICAgIG5hbWU6IG5hbWUsCiAgICAgICAgICAgICAgICBkYXRhOiBkYXRhCiAgICAgICAgICAgIH0pOwogICAgICAgIH07CiAgICAgICAgCiAgICB9KS5jYWxsKFNlbmRlci5wcm90b3R5cGUpOwogICAgCiAgICByZXR1cm4gbmV3IFNlbmRlcigpOwp9OwoKdmFyIG1haW4gPSB3aW5kb3cubWFpbiA9IG51bGw7CnZhciBzZW5kZXIgPSB3aW5kb3cuc2VuZGVyID0gbnVsbDsKCndpbmRvdy5vbm1lc3NhZ2UgPSBmdW5jdGlvbihlKSB7CiAgICB2YXIgbXNnID0gZS5kYXRhOwogICAgaWYgKG1zZy5ldmVudCAmJiBzZW5kZXIpIHsKICAgICAgICBzZW5kZXIuX3NpZ25hbChtc2cuZXZlbnQsIG1zZy5kYXRhKTsKICAgIH0KICAgIGVsc2UgaWYgKG1zZy5jb21tYW5kKSB7CiAgICAgICAgaWYgKG1haW5bbXNnLmNvbW1hbmRdKQogICAgICAgICAgICBtYWluW21zZy5jb21tYW5kXS5hcHBseShtYWluLCBtc2cuYXJncyk7CiAgICAgICAgZWxzZSBpZiAod2luZG93W21zZy5jb21tYW5kXSkKICAgICAgICAgICAgd2luZG93W21zZy5jb21tYW5kXS5hcHBseSh3aW5kb3csIG1zZy5hcmdzKTsKICAgICAgICBlbHNlCiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcigiVW5rbm93biBjb21tYW5kOiIgKyBtc2cuY29tbWFuZCk7CiAgICB9CiAgICBlbHNlIGlmIChtc2cuaW5pdCkgewogICAgICAgIHdpbmRvdy5pbml0QmFzZVVybHMobXNnLnRsbnMpOwogICAgICAgIHNlbmRlciA9IHdpbmRvdy5zZW5kZXIgPSB3aW5kb3cuaW5pdFNlbmRlcigpOwogICAgICAgIHZhciBjbGF6eiA9IHJlcXVpcmUobXNnLm1vZHVsZSlbbXNnLmNsYXNzbmFtZV07CiAgICAgICAgbWFpbiA9IHdpbmRvdy5tYWluID0gbmV3IGNsYXp6KHNlbmRlcik7CiAgICB9Cn07Cn0pKHRoaXMpOwoKYWNlLmRlZmluZSgiYWNlL2xpYi9vb3AiLFtdLCBmdW5jdGlvbihyZXF1aXJlLCBleHBvcnRzLCBtb2R1bGUpIHsKInVzZSBzdHJpY3QiOwoKZXhwb3J0cy5pbmhlcml0cyA9IGZ1bmN0aW9uKGN0b3IsIHN1cGVyQ3RvcikgewogICAgY3Rvci5zdXBlcl8gPSBzdXBlckN0b3I7CiAgICBjdG9yLnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUoc3VwZXJDdG9yLnByb3RvdHlwZSwgewogICAgICAgIGNvbnN0cnVjdG9yOiB7CiAgICAgICAgICAgIHZhbHVlOiBjdG9yLAogICAgICAgICAgICBlbnVtZXJhYmxlOiBmYWxzZSwKICAgICAgICAgICAgd3JpdGFibGU6IHRydWUsCiAgICAgICAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZQogICAgICAgIH0KICAgIH0pOwp9OwoKZXhwb3J0cy5taXhpbiA9IGZ1bmN0aW9uKG9iaiwgbWl4aW4pIHsKICAgIGZvciAodmFyIGtleSBpbiBtaXhpbikgewogICAgICAgIG9ialtrZXldID0gbWl4aW5ba2V5XTsKICAgIH0KICAgIHJldHVybiBvYmo7Cn07CgpleHBvcnRzLmltcGxlbWVudCA9IGZ1bmN0aW9uKHByb3RvLCBtaXhpbikgewogICAgZXhwb3J0cy5taXhpbihwcm90bywgbWl4aW4pOwp9OwoKfSk7CgphY2UuZGVmaW5lKCJhY2UvcmFuZ2UiLFtdLCBmdW5jdGlvbihyZXF1aXJlLCBleHBvcnRzLCBtb2R1bGUpIHsKInVzZSBzdHJpY3QiOwp2YXIgY29tcGFyZVBvaW50cyA9IGZ1bmN0aW9uKHAxLCBwMikgewogICAgcmV0dXJuIHAxLnJvdyAtIHAyLnJvdyB8fCBwMS5jb2x1bW4gLSBwMi5jb2x1bW47Cn07CnZhciBSYW5nZSA9IGZ1bmN0aW9uKHN0YXJ0Um93LCBzdGFydENvbHVtbiwgZW5kUm93LCBlbmRDb2x1bW4pIHsKICAgIHRoaXMuc3RhcnQgPSB7CiAgICAgICAgcm93OiBzdGFydFJvdywKICAgICAgICBjb2x1bW46IHN0YXJ0Q29sdW1uCiAgICB9OwoKICAgIHRoaXMuZW5kID0gewogICAgICAgIHJvdzogZW5kUm93LAogICAgICAgIGNvbHVtbjogZW5kQ29sdW1uCiAgICB9Owp9OwoKKGZ1bmN0aW9uKCkgewogICAgdGhpcy5pc0VxdWFsID0gZnVuY3Rpb24ocmFuZ2UpIHsKICAgICAgICByZXR1cm4gdGhpcy5zdGFydC5yb3cgPT09IHJhbmdlLnN0YXJ0LnJvdyAmJgogICAgICAgICAgICB0aGlzLmVuZC5yb3cgPT09IHJhbmdlLmVuZC5yb3cgJiYKICAgICAgICAgICAgdGhpcy5zdGFydC5jb2x1bW4gPT09IHJhbmdlLnN0YXJ0LmNvbHVtbiAmJgogICAgICAgICAgICB0aGlzLmVuZC5jb2x1bW4gPT09IHJhbmdlLmVuZC5jb2x1bW47CiAgICB9OwogICAgdGhpcy50b1N0cmluZyA9IGZ1bmN0aW9uKCkgewogICAgICAgIHJldHVybiAoIlJhbmdlOiBbIiArIHRoaXMuc3RhcnQucm93ICsgIi8iICsgdGhpcy5zdGFydC5jb2x1bW4gKwogICAgICAgICAgICAiXSAtPiBbIiArIHRoaXMuZW5kLnJvdyArICIvIiArIHRoaXMuZW5kLmNvbHVtbiArICJdIik7CiAgICB9OwoKICAgIHRoaXMuY29udGFpbnMgPSBmdW5jdGlvbihyb3csIGNvbHVtbikgewogICAgICAgIHJldHVybiB0aGlzLmNvbXBhcmUocm93LCBjb2x1bW4pID09IDA7CiAgICB9OwogICAgdGhpcy5jb21wYXJlUmFuZ2UgPSBmdW5jdGlvbihyYW5nZSkgewogICAgICAgIHZhciBjbXAsCiAgICAgICAgICAgIGVuZCA9IHJhbmdlLmVuZCwKICAgICAgICAgICAgc3RhcnQgPSByYW5nZS5zdGFydDsKCiAgICAgICAgY21wID0gdGhpcy5jb21wYXJlKGVuZC5yb3csIGVuZC5jb2x1bW4pOwogICAgICAgIGlmIChjbXAgPT0gMSkgewogICAgICAgICAgICBjbXAgPSB0aGlzLmNvbXBhcmUoc3RhcnQucm93LCBzdGFydC5jb2x1bW4pOwogICAgICAgICAgICBpZiAoY21wID09IDEpIHsKICAgICAgICAgICAgICAgIHJldHVybiAyOwogICAgICAgICAgICB9IGVsc2UgaWYgKGNtcCA9PSAwKSB7CiAgICAgICAgICAgICAgICByZXR1cm4gMTsKICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgIHJldHVybiAwOwogICAgICAgICAgICB9CiAgICAgICAgfSBlbHNlIGlmIChjbXAgPT0gLTEpIHsKICAgICAgICAgICAgcmV0dXJuIC0yOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIGNtcCA9IHRoaXMuY29tcGFyZShzdGFydC5yb3csIHN0YXJ0LmNvbHVtbik7CiAgICAgICAgICAgIGlmIChjbXAgPT0gLTEpIHsKICAgICAgICAgICAgICAgIHJldHVybiAtMTsKICAgICAgICAgICAgfSBlbHNlIGlmIChjbXAgPT0gMSkgewogICAgICAgICAgICAgICAgcmV0dXJuIDQyOwogICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgcmV0dXJuIDA7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICB9OwogICAgdGhpcy5jb21wYXJlUG9pbnQgPSBmdW5jdGlvbihwKSB7CiAgICAgICAgcmV0dXJuIHRoaXMuY29tcGFyZShwLnJvdywgcC5jb2x1bW4pOwogICAgfTsKICAgIHRoaXMuY29udGFpbnNSYW5nZSA9IGZ1bmN0aW9uKHJhbmdlKSB7CiAgICAgICAgcmV0dXJuIHRoaXMuY29tcGFyZVBvaW50KHJhbmdlLnN0YXJ0KSA9PSAwICYmIHRoaXMuY29tcGFyZVBvaW50KHJhbmdlLmVuZCkgPT0gMDsKICAgIH07CiAgICB0aGlzLmludGVyc2VjdHMgPSBmdW5jdGlvbihyYW5nZSkgewogICAgICAgIHZhciBjbXAgPSB0aGlzLmNvbXBhcmVSYW5nZShyYW5nZSk7CiAgICAgICAgcmV0dXJuIChjbXAgPT0gLTEgfHwgY21wID09IDAgfHwgY21wID09IDEpOwogICAgfTsKICAgIHRoaXMuaXNFbmQgPSBmdW5jdGlvbihyb3csIGNvbHVtbikgewogICAgICAgIHJldHVybiB0aGlzLmVuZC5yb3cgPT0gcm93ICYmIHRoaXMuZW5kLmNvbHVtbiA9PSBjb2x1bW47CiAgICB9OwogICAgdGhpcy5pc1N0YXJ0ID0gZnVuY3Rpb24ocm93LCBjb2x1bW4pIHsKICAgICAgICByZXR1cm4gdGhpcy5zdGFydC5yb3cgPT0gcm93ICYmIHRoaXMuc3RhcnQuY29sdW1uID09IGNvbHVtbjsKICAgIH07CiAgICB0aGlzLnNldFN0YXJ0ID0gZnVuY3Rpb24ocm93LCBjb2x1bW4pIHsKICAgICAgICBpZiAodHlwZW9mIHJvdyA9PSAib2JqZWN0IikgewogICAgICAgICAgICB0aGlzLnN0YXJ0LmNvbHVtbiA9IHJvdy5jb2x1bW47CiAgICAgICAgICAgIHRoaXMuc3RhcnQucm93ID0gcm93LnJvdzsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgICB0aGlzLnN0YXJ0LnJvdyA9IHJvdzsKICAgICAgICAgICAgdGhpcy5zdGFydC5jb2x1bW4gPSBjb2x1bW47CiAgICAgICAgfQogICAgfTsKICAgIHRoaXMuc2V0RW5kID0gZnVuY3Rpb24ocm93LCBjb2x1bW4pIHsKICAgICAgICBpZiAodHlwZW9mIHJvdyA9PSAib2JqZWN0IikgewogICAgICAgICAgICB0aGlzLmVuZC5jb2x1bW4gPSByb3cuY29sdW1uOwogICAgICAgICAgICB0aGlzLmVuZC5yb3cgPSByb3cucm93OwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIHRoaXMuZW5kLnJvdyA9IHJvdzsKICAgICAgICAgICAgdGhpcy5lbmQuY29sdW1uID0gY29sdW1uOwogICAgICAgIH0KICAgIH07CiAgICB0aGlzLmluc2lkZSA9IGZ1bmN0aW9uKHJvdywgY29sdW1uKSB7CiAgICAgICAgaWYgKHRoaXMuY29tcGFyZShyb3csIGNvbHVtbikgPT0gMCkgewogICAgICAgICAgICBpZiAodGhpcy5pc0VuZChyb3csIGNvbHVtbikgfHwgdGhpcy5pc1N0YXJ0KHJvdywgY29sdW1uKSkgewogICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOwogICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgcmV0dXJuIGZhbHNlOwogICAgfTsKICAgIHRoaXMuaW5zaWRlU3RhcnQgPSBmdW5jdGlvbihyb3csIGNvbHVtbikgewogICAgICAgIGlmICh0aGlzLmNvbXBhcmUocm93LCBjb2x1bW4pID09IDApIHsKICAgICAgICAgICAgaWYgKHRoaXMuaXNFbmQocm93LCBjb2x1bW4pKSB7CiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICByZXR1cm4gZmFsc2U7CiAgICB9OwogICAgdGhpcy5pbnNpZGVFbmQgPSBmdW5jdGlvbihyb3csIGNvbHVtbikgewogICAgICAgIGlmICh0aGlzLmNvbXBhcmUocm93LCBjb2x1bW4pID09IDApIHsKICAgICAgICAgICAgaWYgKHRoaXMuaXNTdGFydChyb3csIGNvbHVtbikpIHsKICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsKICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgIHJldHVybiB0cnVlOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIHJldHVybiBmYWxzZTsKICAgIH07CiAgICB0aGlzLmNvbXBhcmUgPSBmdW5jdGlvbihyb3csIGNvbHVtbikgewogICAgICAgIGlmICghdGhpcy5pc011bHRpTGluZSgpKSB7CiAgICAgICAgICAgIGlmIChyb3cgPT09IHRoaXMuc3RhcnQucm93KSB7CiAgICAgICAgICAgICAgICByZXR1cm4gY29sdW1uIDwgdGhpcy5zdGFydC5jb2x1bW4gPyAtMSA6IChjb2x1bW4gPiB0aGlzLmVuZC5jb2x1bW4gPyAxIDogMCk7CiAgICAgICAgICAgIH0KICAgICAgICB9CgogICAgICAgIGlmIChyb3cgPCB0aGlzLnN0YXJ0LnJvdykKICAgICAgICAgICAgcmV0dXJuIC0xOwoKICAgICAgICBpZiAocm93ID4gdGhpcy5lbmQucm93KQogICAgICAgICAgICByZXR1cm4gMTsKCiAgICAgICAgaWYgKHRoaXMuc3RhcnQucm93ID09PSByb3cpCiAgICAgICAgICAgIHJldHVybiBjb2x1bW4gPj0gdGhpcy5zdGFydC5jb2x1bW4gPyAwIDogLTE7CgogICAgICAgIGlmICh0aGlzLmVuZC5yb3cgPT09IHJvdykKICAgICAgICAgICAgcmV0dXJuIGNvbHVtbiA8PSB0aGlzLmVuZC5jb2x1bW4gPyAwIDogMTsKCiAgICAgICAgcmV0dXJuIDA7CiAgICB9OwogICAgdGhpcy5jb21wYXJlU3RhcnQgPSBmdW5jdGlvbihyb3csIGNvbHVtbikgewogICAgICAgIGlmICh0aGlzLnN0YXJ0LnJvdyA9PSByb3cgJiYgdGhpcy5zdGFydC5jb2x1bW4gPT0gY29sdW1uKSB7CiAgICAgICAgICAgIHJldHVybiAtMTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgICByZXR1cm4gdGhpcy5jb21wYXJlKHJvdywgY29sdW1uKTsKICAgICAgICB9CiAgICB9OwogICAgdGhpcy5jb21wYXJlRW5kID0gZnVuY3Rpb24ocm93LCBjb2x1bW4pIHsKICAgICAgICBpZiAodGhpcy5lbmQucm93ID09IHJvdyAmJiB0aGlzLmVuZC5jb2x1bW4gPT0gY29sdW1uKSB7CiAgICAgICAgICAgIHJldHVybiAxOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIHJldHVybiB0aGlzLmNvbXBhcmUocm93LCBjb2x1bW4pOwogICAgICAgIH0KICAgIH07CiAgICB0aGlzLmNvbXBhcmVJbnNpZGUgPSBmdW5jdGlvbihyb3csIGNvbHVtbikgewogICAgICAgIGlmICh0aGlzLmVuZC5yb3cgPT0gcm93ICYmIHRoaXMuZW5kLmNvbHVtbiA9PSBjb2x1bW4pIHsKICAgICAgICAgICAgcmV0dXJuIDE7CiAgICAgICAgfSBlbHNlIGlmICh0aGlzLnN0YXJ0LnJvdyA9PSByb3cgJiYgdGhpcy5zdGFydC5jb2x1bW4gPT0gY29sdW1uKSB7CiAgICAgICAgICAgIHJldHVybiAtMTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgICByZXR1cm4gdGhpcy5jb21wYXJlKHJvdywgY29sdW1uKTsKICAgICAgICB9CiAgICB9OwogICAgdGhpcy5jbGlwUm93cyA9IGZ1bmN0aW9uKGZpcnN0Um93LCBsYXN0Um93KSB7CiAgICAgICAgaWYgKHRoaXMuZW5kLnJvdyA+IGxhc3RSb3cpCiAgICAgICAgICAgIHZhciBlbmQgPSB7cm93OiBsYXN0Um93ICsgMSwgY29sdW1uOiAwfTsKICAgICAgICBlbHNlIGlmICh0aGlzLmVuZC5yb3cgPCBmaXJzdFJvdykKICAgICAgICAgICAgdmFyIGVuZCA9IHtyb3c6IGZpcnN0Um93LCBjb2x1bW46IDB9OwoKICAgICAgICBpZiAodGhpcy5zdGFydC5yb3cgPiBsYXN0Um93KQogICAgICAgICAgICB2YXIgc3RhcnQgPSB7cm93OiBsYXN0Um93ICsgMSwgY29sdW1uOiAwfTsKICAgICAgICBlbHNlIGlmICh0aGlzLnN0YXJ0LnJvdyA8IGZpcnN0Um93KQogICAgICAgICAgICB2YXIgc3RhcnQgPSB7cm93OiBmaXJzdFJvdywgY29sdW1uOiAwfTsKCiAgICAgICAgcmV0dXJuIFJhbmdlLmZyb21Qb2ludHMoc3RhcnQgfHwgdGhpcy5zdGFydCwgZW5kIHx8IHRoaXMuZW5kKTsKICAgIH07CiAgICB0aGlzLmV4dGVuZCA9IGZ1bmN0aW9uKHJvdywgY29sdW1uKSB7CiAgICAgICAgdmFyIGNtcCA9IHRoaXMuY29tcGFyZShyb3csIGNvbHVtbik7CgogICAgICAgIGlmIChjbXAgPT0gMCkKICAgICAgICAgICAgcmV0dXJuIHRoaXM7CiAgICAgICAgZWxzZSBpZiAoY21wID09IC0xKQogICAgICAgICAgICB2YXIgc3RhcnQgPSB7cm93OiByb3csIGNvbHVtbjogY29sdW1ufTsKICAgICAgICBlbHNlCiAgICAgICAgICAgIHZhciBlbmQgPSB7cm93OiByb3csIGNvbHVtbjogY29sdW1ufTsKCiAgICAgICAgcmV0dXJuIFJhbmdlLmZyb21Qb2ludHMoc3RhcnQgfHwgdGhpcy5zdGFydCwgZW5kIHx8IHRoaXMuZW5kKTsKICAgIH07CgogICAgdGhpcy5pc0VtcHR5ID0gZnVuY3Rpb24oKSB7CiAgICAgICAgcmV0dXJuICh0aGlzLnN0YXJ0LnJvdyA9PT0gdGhpcy5lbmQucm93ICYmIHRoaXMuc3RhcnQuY29sdW1uID09PSB0aGlzLmVuZC5jb2x1bW4pOwogICAgfTsKICAgIHRoaXMuaXNNdWx0aUxpbmUgPSBmdW5jdGlvbigpIHsKICAgICAgICByZXR1cm4gKHRoaXMuc3RhcnQucm93ICE9PSB0aGlzLmVuZC5yb3cpOwogICAgfTsKICAgIHRoaXMuY2xvbmUgPSBmdW5jdGlvbigpIHsKICAgICAgICByZXR1cm4gUmFuZ2UuZnJvbVBvaW50cyh0aGlzLnN0YXJ0LCB0aGlzLmVuZCk7CiAgICB9OwogICAgdGhpcy5jb2xsYXBzZVJvd3MgPSBmdW5jdGlvbigpIHsKICAgICAgICBpZiAodGhpcy5lbmQuY29sdW1uID09IDApCiAgICAgICAgICAgIHJldHVybiBuZXcgUmFuZ2UodGhpcy5zdGFydC5yb3csIDAsIE1hdGgubWF4KHRoaXMuc3RhcnQucm93LCB0aGlzLmVuZC5yb3ctMSksIDApOwogICAgICAgIGVsc2UKICAgICAgICAgICAgcmV0dXJuIG5ldyBSYW5nZSh0aGlzLnN0YXJ0LnJvdywgMCwgdGhpcy5lbmQucm93LCAwKTsKICAgIH07CiAgICB0aGlzLnRvU2NyZWVuUmFuZ2UgPSBmdW5jdGlvbihzZXNzaW9uKSB7CiAgICAgICAgdmFyIHNjcmVlblBvc1N0YXJ0ID0gc2Vzc2lvbi5kb2N1bWVudFRvU2NyZWVuUG9zaXRpb24odGhpcy5zdGFydCk7CiAgICAgICAgdmFyIHNjcmVlblBvc0VuZCA9IHNlc3Npb24uZG9jdW1lbnRUb1NjcmVlblBvc2l0aW9uKHRoaXMuZW5kKTsKCiAgICAgICAgcmV0dXJuIG5ldyBSYW5nZSgKICAgICAgICAgICAgc2NyZWVuUG9zU3RhcnQucm93LCBzY3JlZW5Qb3NTdGFydC5jb2x1bW4sCiAgICAgICAgICAgIHNjcmVlblBvc0VuZC5yb3csIHNjcmVlblBvc0VuZC5jb2x1bW4KICAgICAgICApOwogICAgfTsKICAgIHRoaXMubW92ZUJ5ID0gZnVuY3Rpb24ocm93LCBjb2x1bW4pIHsKICAgICAgICB0aGlzLnN0YXJ0LnJvdyArPSByb3c7CiAgICAgICAgdGhpcy5zdGFydC5jb2x1bW4gKz0gY29sdW1uOwogICAgICAgIHRoaXMuZW5kLnJvdyArPSByb3c7CiAgICAgICAgdGhpcy5lbmQuY29sdW1uICs9IGNvbHVtbjsKICAgIH07Cgp9KS5jYWxsKFJhbmdlLnByb3RvdHlwZSk7ClJhbmdlLmZyb21Qb2ludHMgPSBmdW5jdGlvbihzdGFydCwgZW5kKSB7CiAgICByZXR1cm4gbmV3IFJhbmdlKHN0YXJ0LnJvdywgc3RhcnQuY29sdW1uLCBlbmQucm93LCBlbmQuY29sdW1uKTsKfTsKUmFuZ2UuY29tcGFyZVBvaW50cyA9IGNvbXBhcmVQb2ludHM7CgpSYW5nZS5jb21wYXJlUG9pbnRzID0gZnVuY3Rpb24ocDEsIHAyKSB7CiAgICByZXR1cm4gcDEucm93IC0gcDIucm93IHx8IHAxLmNvbHVtbiAtIHAyLmNvbHVtbjsKfTsKCgpleHBvcnRzLlJhbmdlID0gUmFuZ2U7Cn0pOwoKYWNlLmRlZmluZSgiYWNlL2FwcGx5X2RlbHRhIixbXSwgZnVuY3Rpb24ocmVxdWlyZSwgZXhwb3J0cywgbW9kdWxlKSB7CiJ1c2Ugc3RyaWN0IjsKCmZ1bmN0aW9uIHRocm93RGVsdGFFcnJvcihkZWx0YSwgZXJyb3JUZXh0KXsKICAgIGNvbnNvbGUubG9nKCJJbnZhbGlkIERlbHRhOiIsIGRlbHRhKTsKICAgIHRocm93ICJJbnZhbGlkIERlbHRhOiAiICsgZXJyb3JUZXh0Owp9CgpmdW5jdGlvbiBwb3NpdGlvbkluRG9jdW1lbnQoZG9jTGluZXMsIHBvc2l0aW9uKSB7CiAgICByZXR1cm4gcG9zaXRpb24ucm93ICAgID49IDAgJiYgcG9zaXRpb24ucm93ICAgIDwgIGRvY0xpbmVzLmxlbmd0aCAmJgogICAgICAgICAgIHBvc2l0aW9uLmNvbHVtbiA+PSAwICYmIHBvc2l0aW9uLmNvbHVtbiA8PSBkb2NMaW5lc1twb3NpdGlvbi5yb3ddLmxlbmd0aDsKfQoKZnVuY3Rpb24gdmFsaWRhdGVEZWx0YShkb2NMaW5lcywgZGVsdGEpIHsKICAgIGlmIChkZWx0YS5hY3Rpb24gIT0gImluc2VydCIgJiYgZGVsdGEuYWN0aW9uICE9ICJyZW1vdmUiKQogICAgICAgIHRocm93RGVsdGFFcnJvcihkZWx0YSwgImRlbHRhLmFjdGlvbiBtdXN0IGJlICdpbnNlcnQnIG9yICdyZW1vdmUnIik7CiAgICBpZiAoIShkZWx0YS5saW5lcyBpbnN0YW5jZW9mIEFycmF5KSkKICAgICAgICB0aHJvd0RlbHRhRXJyb3IoZGVsdGEsICJkZWx0YS5saW5lcyBtdXN0IGJlIGFuIEFycmF5Iik7CiAgICBpZiAoIWRlbHRhLnN0YXJ0IHx8ICFkZWx0YS5lbmQpCiAgICAgICB0aHJvd0RlbHRhRXJyb3IoZGVsdGEsICJkZWx0YS5zdGFydC9lbmQgbXVzdCBiZSBhbiBwcmVzZW50Iik7CiAgICB2YXIgc3RhcnQgPSBkZWx0YS5zdGFydDsKICAgIGlmICghcG9zaXRpb25JbkRvY3VtZW50KGRvY0xpbmVzLCBkZWx0YS5zdGFydCkpCiAgICAgICAgdGhyb3dEZWx0YUVycm9yKGRlbHRhLCAiZGVsdGEuc3RhcnQgbXVzdCBiZSBjb250YWluZWQgaW4gZG9jdW1lbnQiKTsKICAgIHZhciBlbmQgPSBkZWx0YS5lbmQ7CiAgICBpZiAoZGVsdGEuYWN0aW9uID09ICJyZW1vdmUiICYmICFwb3NpdGlvbkluRG9jdW1lbnQoZG9jTGluZXMsIGVuZCkpCiAgICAgICAgdGhyb3dEZWx0YUVycm9yKGRlbHRhLCAiZGVsdGEuZW5kIG11c3QgY29udGFpbmVkIGluIGRvY3VtZW50IGZvciAncmVtb3ZlJyBhY3Rpb25zIik7CiAgICB2YXIgbnVtUmFuZ2VSb3dzID0gZW5kLnJvdyAtIHN0YXJ0LnJvdzsKICAgIHZhciBudW1SYW5nZUxhc3RMaW5lQ2hhcnMgPSAoZW5kLmNvbHVtbiAtIChudW1SYW5nZVJvd3MgPT0gMCA/IHN0YXJ0LmNvbHVtbiA6IDApKTsKICAgIGlmIChudW1SYW5nZVJvd3MgIT0gZGVsdGEubGluZXMubGVuZ3RoIC0gMSB8fCBkZWx0YS5saW5lc1tudW1SYW5nZVJvd3NdLmxlbmd0aCAhPSBudW1SYW5nZUxhc3RMaW5lQ2hhcnMpCiAgICAgICAgdGhyb3dEZWx0YUVycm9yKGRlbHRhLCAiZGVsdGEucmFuZ2UgbXVzdCBtYXRjaCBkZWx0YSBsaW5lcyIpOwp9CgpleHBvcnRzLmFwcGx5RGVsdGEgPSBmdW5jdGlvbihkb2NMaW5lcywgZGVsdGEsIGRvTm90VmFsaWRhdGUpIHsKICAgIAogICAgdmFyIHJvdyA9IGRlbHRhLnN0YXJ0LnJvdzsKICAgIHZhciBzdGFydENvbHVtbiA9IGRlbHRhLnN0YXJ0LmNvbHVtbjsKICAgIHZhciBsaW5lID0gZG9jTGluZXNbcm93XSB8fCAiIjsKICAgIHN3aXRjaCAoZGVsdGEuYWN0aW9uKSB7CiAgICAgICAgY2FzZSAiaW5zZXJ0IjoKICAgICAgICAgICAgdmFyIGxpbmVzID0gZGVsdGEubGluZXM7CiAgICAgICAgICAgIGlmIChsaW5lcy5sZW5ndGggPT09IDEpIHsKICAgICAgICAgICAgICAgIGRvY0xpbmVzW3Jvd10gPSBsaW5lLnN1YnN0cmluZygwLCBzdGFydENvbHVtbikgKyBkZWx0YS5saW5lc1swXSArIGxpbmUuc3Vic3RyaW5nKHN0YXJ0Q29sdW1uKTsKICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgIHZhciBhcmdzID0gW3JvdywgMV0uY29uY2F0KGRlbHRhLmxpbmVzKTsKICAgICAgICAgICAgICAgIGRvY0xpbmVzLnNwbGljZS5hcHBseShkb2NMaW5lcywgYXJncyk7CiAgICAgICAgICAgICAgICBkb2NMaW5lc1tyb3ddID0gbGluZS5zdWJzdHJpbmcoMCwgc3RhcnRDb2x1bW4pICsgZG9jTGluZXNbcm93XTsKICAgICAgICAgICAgICAgIGRvY0xpbmVzW3JvdyArIGRlbHRhLmxpbmVzLmxlbmd0aCAtIDFdICs9IGxpbmUuc3Vic3RyaW5nKHN0YXJ0Q29sdW1uKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBicmVhazsKICAgICAgICBjYXNlICJyZW1vdmUiOgogICAgICAgICAgICB2YXIgZW5kQ29sdW1uID0gZGVsdGEuZW5kLmNvbHVtbjsKICAgICAgICAgICAgdmFyIGVuZFJvdyA9IGRlbHRhLmVuZC5yb3c7CiAgICAgICAgICAgIGlmIChyb3cgPT09IGVuZFJvdykgewogICAgICAgICAgICAgICAgZG9jTGluZXNbcm93XSA9IGxpbmUuc3Vic3RyaW5nKDAsIHN0YXJ0Q29sdW1uKSArIGxpbmUuc3Vic3RyaW5nKGVuZENvbHVtbik7CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICBkb2NMaW5lcy5zcGxpY2UoCiAgICAgICAgICAgICAgICAgICAgcm93LCBlbmRSb3cgLSByb3cgKyAxLAogICAgICAgICAgICAgICAgICAgIGxpbmUuc3Vic3RyaW5nKDAsIHN0YXJ0Q29sdW1uKSArIGRvY0xpbmVzW2VuZFJvd10uc3Vic3RyaW5nKGVuZENvbHVtbikKICAgICAgICAgICAgICAgICk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgYnJlYWs7CiAgICB9Cn07Cn0pOwoKYWNlLmRlZmluZSgiYWNlL2xpYi9ldmVudF9lbWl0dGVyIixbXSwgZnVuY3Rpb24ocmVxdWlyZSwgZXhwb3J0cywgbW9kdWxlKSB7CiJ1c2Ugc3RyaWN0IjsKCnZhciBFdmVudEVtaXR0ZXIgPSB7fTsKdmFyIHN0b3BQcm9wYWdhdGlvbiA9IGZ1bmN0aW9uKCkgeyB0aGlzLnByb3BhZ2F0aW9uU3RvcHBlZCA9IHRydWU7IH07CnZhciBwcmV2ZW50RGVmYXVsdCA9IGZ1bmN0aW9uKCkgeyB0aGlzLmRlZmF1bHRQcmV2ZW50ZWQgPSB0cnVlOyB9OwoKRXZlbnRFbWl0dGVyLl9lbWl0ID0KRXZlbnRFbWl0dGVyLl9kaXNwYXRjaEV2ZW50ID0gZnVuY3Rpb24oZXZlbnROYW1lLCBlKSB7CiAgICB0aGlzLl9ldmVudFJlZ2lzdHJ5IHx8ICh0aGlzLl9ldmVudFJlZ2lzdHJ5ID0ge30pOwogICAgdGhpcy5fZGVmYXVsdEhhbmRsZXJzIHx8ICh0aGlzLl9kZWZhdWx0SGFuZGxlcnMgPSB7fSk7CgogICAgdmFyIGxpc3RlbmVycyA9IHRoaXMuX2V2ZW50UmVnaXN0cnlbZXZlbnROYW1lXSB8fCBbXTsKICAgIHZhciBkZWZhdWx0SGFuZGxlciA9IHRoaXMuX2RlZmF1bHRIYW5kbGVyc1tldmVudE5hbWVdOwogICAgaWYgKCFsaXN0ZW5lcnMubGVuZ3RoICYmICFkZWZhdWx0SGFuZGxlcikKICAgICAgICByZXR1cm47CgogICAgaWYgKHR5cGVvZiBlICE9ICJvYmplY3QiIHx8ICFlKQogICAgICAgIGUgPSB7fTsKCiAgICBpZiAoIWUudHlwZSkKICAgICAgICBlLnR5cGUgPSBldmVudE5hbWU7CiAgICBpZiAoIWUuc3RvcFByb3BhZ2F0aW9uKQogICAgICAgIGUuc3RvcFByb3BhZ2F0aW9uID0gc3RvcFByb3BhZ2F0aW9uOwogICAgaWYgKCFlLnByZXZlbnREZWZhdWx0KQogICAgICAgIGUucHJldmVudERlZmF1bHQgPSBwcmV2ZW50RGVmYXVsdDsKCiAgICBsaXN0ZW5lcnMgPSBsaXN0ZW5lcnMuc2xpY2UoKTsKICAgIGZvciAodmFyIGk9MDsgaTxsaXN0ZW5lcnMubGVuZ3RoOyBpKyspIHsKICAgICAgICBsaXN0ZW5lcnNbaV0oZSwgdGhpcyk7CiAgICAgICAgaWYgKGUucHJvcGFnYXRpb25TdG9wcGVkKQogICAgICAgICAgICBicmVhazsKICAgIH0KICAgIAogICAgaWYgKGRlZmF1bHRIYW5kbGVyICYmICFlLmRlZmF1bHRQcmV2ZW50ZWQpCiAgICAgICAgcmV0dXJuIGRlZmF1bHRIYW5kbGVyKGUsIHRoaXMpOwp9OwoKCkV2ZW50RW1pdHRlci5fc2lnbmFsID0gZnVuY3Rpb24oZXZlbnROYW1lLCBlKSB7CiAgICB2YXIgbGlzdGVuZXJzID0gKHRoaXMuX2V2ZW50UmVnaXN0cnkgfHwge30pW2V2ZW50TmFtZV07CiAgICBpZiAoIWxpc3RlbmVycykKICAgICAgICByZXR1cm47CiAgICBsaXN0ZW5lcnMgPSBsaXN0ZW5lcnMuc2xpY2UoKTsKICAgIGZvciAodmFyIGk9MDsgaTxsaXN0ZW5lcnMubGVuZ3RoOyBpKyspCiAgICAgICAgbGlzdGVuZXJzW2ldKGUsIHRoaXMpOwp9OwoKRXZlbnRFbWl0dGVyLm9uY2UgPSBmdW5jdGlvbihldmVudE5hbWUsIGNhbGxiYWNrKSB7CiAgICB2YXIgX3NlbGYgPSB0aGlzOwogICAgdGhpcy5vbihldmVudE5hbWUsIGZ1bmN0aW9uIG5ld0NhbGxiYWNrKCkgewogICAgICAgIF9zZWxmLm9mZihldmVudE5hbWUsIG5ld0NhbGxiYWNrKTsKICAgICAgICBjYWxsYmFjay5hcHBseShudWxsLCBhcmd1bWVudHMpOwogICAgfSk7CiAgICBpZiAoIWNhbGxiYWNrKSB7CiAgICAgICAgcmV0dXJuIG5ldyBQcm9taXNlKGZ1bmN0aW9uKHJlc29sdmUpIHsKICAgICAgICAgICAgY2FsbGJhY2sgPSByZXNvbHZlOwogICAgICAgIH0pOwogICAgfQp9OwoKCkV2ZW50RW1pdHRlci5zZXREZWZhdWx0SGFuZGxlciA9IGZ1bmN0aW9uKGV2ZW50TmFtZSwgY2FsbGJhY2spIHsKICAgIHZhciBoYW5kbGVycyA9IHRoaXMuX2RlZmF1bHRIYW5kbGVyczsKICAgIGlmICghaGFuZGxlcnMpCiAgICAgICAgaGFuZGxlcnMgPSB0aGlzLl9kZWZhdWx0SGFuZGxlcnMgPSB7X2Rpc2FibGVkXzoge319OwogICAgCiAgICBpZiAoaGFuZGxlcnNbZXZlbnROYW1lXSkgewogICAgICAgIHZhciBvbGQgPSBoYW5kbGVyc1tldmVudE5hbWVdOwogICAgICAgIHZhciBkaXNhYmxlZCA9IGhhbmRsZXJzLl9kaXNhYmxlZF9bZXZlbnROYW1lXTsKICAgICAgICBpZiAoIWRpc2FibGVkKQogICAgICAgICAgICBoYW5kbGVycy5fZGlzYWJsZWRfW2V2ZW50TmFtZV0gPSBkaXNhYmxlZCA9IFtdOwogICAgICAgIGRpc2FibGVkLnB1c2gob2xkKTsKICAgICAgICB2YXIgaSA9IGRpc2FibGVkLmluZGV4T2YoY2FsbGJhY2spOwogICAgICAgIGlmIChpICE9IC0xKSAKICAgICAgICAgICAgZGlzYWJsZWQuc3BsaWNlKGksIDEpOwogICAgfQogICAgaGFuZGxlcnNbZXZlbnROYW1lXSA9IGNhbGxiYWNrOwp9OwpFdmVudEVtaXR0ZXIucmVtb3ZlRGVmYXVsdEhhbmRsZXIgPSBmdW5jdGlvbihldmVudE5hbWUsIGNhbGxiYWNrKSB7CiAgICB2YXIgaGFuZGxlcnMgPSB0aGlzLl9kZWZhdWx0SGFuZGxlcnM7CiAgICBpZiAoIWhhbmRsZXJzKQogICAgICAgIHJldHVybjsKICAgIHZhciBkaXNhYmxlZCA9IGhhbmRsZXJzLl9kaXNhYmxlZF9bZXZlbnROYW1lXTsKICAgIAogICAgaWYgKGhhbmRsZXJzW2V2ZW50TmFtZV0gPT0gY2FsbGJhY2spIHsKICAgICAgICBpZiAoZGlzYWJsZWQpCiAgICAgICAgICAgIHRoaXMuc2V0RGVmYXVsdEhhbmRsZXIoZXZlbnROYW1lLCBkaXNhYmxlZC5wb3AoKSk7CiAgICB9IGVsc2UgaWYgKGRpc2FibGVkKSB7CiAgICAgICAgdmFyIGkgPSBkaXNhYmxlZC5pbmRleE9mKGNhbGxiYWNrKTsKICAgICAgICBpZiAoaSAhPSAtMSkKICAgICAgICAgICAgZGlzYWJsZWQuc3BsaWNlKGksIDEpOwogICAgfQp9OwoKRXZlbnRFbWl0dGVyLm9uID0KRXZlbnRFbWl0dGVyLmFkZEV2ZW50TGlzdGVuZXIgPSBmdW5jdGlvbihldmVudE5hbWUsIGNhbGxiYWNrLCBjYXB0dXJpbmcpIHsKICAgIHRoaXMuX2V2ZW50UmVnaXN0cnkgPSB0aGlzLl9ldmVudFJlZ2lzdHJ5IHx8IHt9OwoKICAgIHZhciBsaXN0ZW5lcnMgPSB0aGlzLl9ldmVudFJlZ2lzdHJ5W2V2ZW50TmFtZV07CiAgICBpZiAoIWxpc3RlbmVycykKICAgICAgICBsaXN0ZW5lcnMgPSB0aGlzLl9ldmVudFJlZ2lzdHJ5W2V2ZW50TmFtZV0gPSBbXTsKCiAgICBpZiAobGlzdGVuZXJzLmluZGV4T2YoY2FsbGJhY2spID09IC0xKQogICAgICAgIGxpc3RlbmVyc1tjYXB0dXJpbmcgPyAidW5zaGlmdCIgOiAicHVzaCJdKGNhbGxiYWNrKTsKICAgIHJldHVybiBjYWxsYmFjazsKfTsKCkV2ZW50RW1pdHRlci5vZmYgPQpFdmVudEVtaXR0ZXIucmVtb3ZlTGlzdGVuZXIgPQpFdmVudEVtaXR0ZXIucmVtb3ZlRXZlbnRMaXN0ZW5lciA9IGZ1bmN0aW9uKGV2ZW50TmFtZSwgY2FsbGJhY2spIHsKICAgIHRoaXMuX2V2ZW50UmVnaXN0cnkgPSB0aGlzLl9ldmVudFJlZ2lzdHJ5IHx8IHt9OwoKICAgIHZhciBsaXN0ZW5lcnMgPSB0aGlzLl9ldmVudFJlZ2lzdHJ5W2V2ZW50TmFtZV07CiAgICBpZiAoIWxpc3RlbmVycykKICAgICAgICByZXR1cm47CgogICAgdmFyIGluZGV4ID0gbGlzdGVuZXJzLmluZGV4T2YoY2FsbGJhY2spOwogICAgaWYgKGluZGV4ICE9PSAtMSkKICAgICAgICBsaXN0ZW5lcnMuc3BsaWNlKGluZGV4LCAxKTsKfTsKCkV2ZW50RW1pdHRlci5yZW1vdmVBbGxMaXN0ZW5lcnMgPSBmdW5jdGlvbihldmVudE5hbWUpIHsKICAgIGlmICghZXZlbnROYW1lKSB0aGlzLl9ldmVudFJlZ2lzdHJ5ID0gdGhpcy5fZGVmYXVsdEhhbmRsZXJzID0gdW5kZWZpbmVkOwogICAgaWYgKHRoaXMuX2V2ZW50UmVnaXN0cnkpIHRoaXMuX2V2ZW50UmVnaXN0cnlbZXZlbnROYW1lXSA9IHVuZGVmaW5lZDsKICAgIGlmICh0aGlzLl9kZWZhdWx0SGFuZGxlcnMpIHRoaXMuX2RlZmF1bHRIYW5kbGVyc1tldmVudE5hbWVdID0gdW5kZWZpbmVkOwp9OwoKZXhwb3J0cy5FdmVudEVtaXR0ZXIgPSBFdmVudEVtaXR0ZXI7Cgp9KTsKCmFjZS5kZWZpbmUoImFjZS9hbmNob3IiLFtdLCBmdW5jdGlvbihyZXF1aXJlLCBleHBvcnRzLCBtb2R1bGUpIHsKInVzZSBzdHJpY3QiOwoKdmFyIG9vcCA9IHJlcXVpcmUoIi4vbGliL29vcCIpOwp2YXIgRXZlbnRFbWl0dGVyID0gcmVxdWlyZSgiLi9saWIvZXZlbnRfZW1pdHRlciIpLkV2ZW50RW1pdHRlcjsKCnZhciBBbmNob3IgPSBleHBvcnRzLkFuY2hvciA9IGZ1bmN0aW9uKGRvYywgcm93LCBjb2x1bW4pIHsKICAgIHRoaXMuJG9uQ2hhbmdlID0gdGhpcy5vbkNoYW5nZS5iaW5kKHRoaXMpOwogICAgdGhpcy5hdHRhY2goZG9jKTsKICAgIAogICAgaWYgKHR5cGVvZiBjb2x1bW4gPT0gInVuZGVmaW5lZCIpCiAgICAgICAgdGhpcy5zZXRQb3NpdGlvbihyb3cucm93LCByb3cuY29sdW1uKTsKICAgIGVsc2UKICAgICAgICB0aGlzLnNldFBvc2l0aW9uKHJvdywgY29sdW1uKTsKfTsKCihmdW5jdGlvbigpIHsKCiAgICBvb3AuaW1wbGVtZW50KHRoaXMsIEV2ZW50RW1pdHRlcik7CiAgICB0aGlzLmdldFBvc2l0aW9uID0gZnVuY3Rpb24oKSB7CiAgICAgICAgcmV0dXJuIHRoaXMuJGNsaXBQb3NpdGlvblRvRG9jdW1lbnQodGhpcy5yb3csIHRoaXMuY29sdW1uKTsKICAgIH07CiAgICB0aGlzLmdldERvY3VtZW50ID0gZnVuY3Rpb24oKSB7CiAgICAgICAgcmV0dXJuIHRoaXMuZG9jdW1lbnQ7CiAgICB9OwogICAgdGhpcy4kaW5zZXJ0UmlnaHQgPSBmYWxzZTsKICAgIHRoaXMub25DaGFuZ2UgPSBmdW5jdGlvbihkZWx0YSkgewogICAgICAgIGlmIChkZWx0YS5zdGFydC5yb3cgPT0gZGVsdGEuZW5kLnJvdyAmJiBkZWx0YS5zdGFydC5yb3cgIT0gdGhpcy5yb3cpCiAgICAgICAgICAgIHJldHVybjsKCiAgICAgICAgaWYgKGRlbHRhLnN0YXJ0LnJvdyA+IHRoaXMucm93KQogICAgICAgICAgICByZXR1cm47CiAgICAgICAgICAgIAogICAgICAgIHZhciBwb2ludCA9ICRnZXRUcmFuc2Zvcm1lZFBvaW50KGRlbHRhLCB7cm93OiB0aGlzLnJvdywgY29sdW1uOiB0aGlzLmNvbHVtbn0sIHRoaXMuJGluc2VydFJpZ2h0KTsKICAgICAgICB0aGlzLnNldFBvc2l0aW9uKHBvaW50LnJvdywgcG9pbnQuY29sdW1uLCB0cnVlKTsKICAgIH07CiAgICAKICAgIGZ1bmN0aW9uICRwb2ludHNJbk9yZGVyKHBvaW50MSwgcG9pbnQyLCBlcXVhbFBvaW50c0luT3JkZXIpIHsKICAgICAgICB2YXIgYkNvbElzQWZ0ZXIgPSBlcXVhbFBvaW50c0luT3JkZXIgPyBwb2ludDEuY29sdW1uIDw9IHBvaW50Mi5jb2x1bW4gOiBwb2ludDEuY29sdW1uIDwgcG9pbnQyLmNvbHVtbjsKICAgICAgICByZXR1cm4gKHBvaW50MS5yb3cgPCBwb2ludDIucm93KSB8fCAocG9pbnQxLnJvdyA9PSBwb2ludDIucm93ICYmIGJDb2xJc0FmdGVyKTsKICAgIH0KICAgICAgICAgICAgCiAgICBmdW5jdGlvbiAkZ2V0VHJhbnNmb3JtZWRQb2ludChkZWx0YSwgcG9pbnQsIG1vdmVJZkVxdWFsKSB7CiAgICAgICAgdmFyIGRlbHRhSXNJbnNlcnQgPSBkZWx0YS5hY3Rpb24gPT0gImluc2VydCI7CiAgICAgICAgdmFyIGRlbHRhUm93U2hpZnQgPSAoZGVsdGFJc0luc2VydCA/IDEgOiAtMSkgKiAoZGVsdGEuZW5kLnJvdyAgICAtIGRlbHRhLnN0YXJ0LnJvdyk7CiAgICAgICAgdmFyIGRlbHRhQ29sU2hpZnQgPSAoZGVsdGFJc0luc2VydCA/IDEgOiAtMSkgKiAoZGVsdGEuZW5kLmNvbHVtbiAtIGRlbHRhLnN0YXJ0LmNvbHVtbik7CiAgICAgICAgdmFyIGRlbHRhU3RhcnQgPSBkZWx0YS5zdGFydDsKICAgICAgICB2YXIgZGVsdGFFbmQgPSBkZWx0YUlzSW5zZXJ0ID8gZGVsdGFTdGFydCA6IGRlbHRhLmVuZDsgLy8gQ29sbGFwc2UgaW5zZXJ0IHJhbmdlLgogICAgICAgIGlmICgkcG9pbnRzSW5PcmRlcihwb2ludCwgZGVsdGFTdGFydCwgbW92ZUlmRXF1YWwpKSB7CiAgICAgICAgICAgIHJldHVybiB7CiAgICAgICAgICAgICAgICByb3c6IHBvaW50LnJvdywKICAgICAgICAgICAgICAgIGNvbHVtbjogcG9pbnQuY29sdW1uCiAgICAgICAgICAgIH07CiAgICAgICAgfQogICAgICAgIGlmICgkcG9pbnRzSW5PcmRlcihkZWx0YUVuZCwgcG9pbnQsICFtb3ZlSWZFcXVhbCkpIHsKICAgICAgICAgICAgcmV0dXJuIHsKICAgICAgICAgICAgICAgIHJvdzogcG9pbnQucm93ICsgZGVsdGFSb3dTaGlmdCwKICAgICAgICAgICAgICAgIGNvbHVtbjogcG9pbnQuY29sdW1uICsgKHBvaW50LnJvdyA9PSBkZWx0YUVuZC5yb3cgPyBkZWx0YUNvbFNoaWZ0IDogMCkKICAgICAgICAgICAgfTsKICAgICAgICB9CiAgICAgICAgCiAgICAgICAgcmV0dXJuIHsKICAgICAgICAgICAgcm93OiBkZWx0YVN0YXJ0LnJvdywKICAgICAgICAgICAgY29sdW1uOiBkZWx0YVN0YXJ0LmNvbHVtbgogICAgICAgIH07CiAgICB9CiAgICB0aGlzLnNldFBvc2l0aW9uID0gZnVuY3Rpb24ocm93LCBjb2x1bW4sIG5vQ2xpcCkgewogICAgICAgIHZhciBwb3M7CiAgICAgICAgaWYgKG5vQ2xpcCkgewogICAgICAgICAgICBwb3MgPSB7CiAgICAgICAgICAgICAgICByb3c6IHJvdywKICAgICAgICAgICAgICAgIGNvbHVtbjogY29sdW1uCiAgICAgICAgICAgIH07CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgcG9zID0gdGhpcy4kY2xpcFBvc2l0aW9uVG9Eb2N1bWVudChyb3csIGNvbHVtbik7CiAgICAgICAgfQoKICAgICAgICBpZiAodGhpcy5yb3cgPT0gcG9zLnJvdyAmJiB0aGlzLmNvbHVtbiA9PSBwb3MuY29sdW1uKQogICAgICAgICAgICByZXR1cm47CgogICAgICAgIHZhciBvbGQgPSB7CiAgICAgICAgICAgIHJvdzogdGhpcy5yb3csCiAgICAgICAgICAgIGNvbHVtbjogdGhpcy5jb2x1bW4KICAgICAgICB9OwoKICAgICAgICB0aGlzLnJvdyA9IHBvcy5yb3c7CiAgICAgICAgdGhpcy5jb2x1bW4gPSBwb3MuY29sdW1uOwogICAgICAgIHRoaXMuX3NpZ25hbCgiY2hhbmdlIiwgewogICAgICAgICAgICBvbGQ6IG9sZCwKICAgICAgICAgICAgdmFsdWU6IHBvcwogICAgICAgIH0pOwogICAgfTsKICAgIHRoaXMuZGV0YWNoID0gZnVuY3Rpb24oKSB7CiAgICAgICAgdGhpcy5kb2N1bWVudC5vZmYoImNoYW5nZSIsIHRoaXMuJG9uQ2hhbmdlKTsKICAgIH07CiAgICB0aGlzLmF0dGFjaCA9IGZ1bmN0aW9uKGRvYykgewogICAgICAgIHRoaXMuZG9jdW1lbnQgPSBkb2MgfHwgdGhpcy5kb2N1bWVudDsKICAgICAgICB0aGlzLmRvY3VtZW50Lm9uKCJjaGFuZ2UiLCB0aGlzLiRvbkNoYW5nZSk7CiAgICB9OwogICAgdGhpcy4kY2xpcFBvc2l0aW9uVG9Eb2N1bWVudCA9IGZ1bmN0aW9uKHJvdywgY29sdW1uKSB7CiAgICAgICAgdmFyIHBvcyA9IHt9OwoKICAgICAgICBpZiAocm93ID49IHRoaXMuZG9jdW1lbnQuZ2V0TGVuZ3RoKCkpIHsKICAgICAgICAgICAgcG9zLnJvdyA9IE1hdGgubWF4KDAsIHRoaXMuZG9jdW1lbnQuZ2V0TGVuZ3RoKCkgLSAxKTsKICAgICAgICAgICAgcG9zLmNvbHVtbiA9IHRoaXMuZG9jdW1lbnQuZ2V0TGluZShwb3Mucm93KS5sZW5ndGg7CiAgICAgICAgfQogICAgICAgIGVsc2UgaWYgKHJvdyA8IDApIHsKICAgICAgICAgICAgcG9zLnJvdyA9IDA7CiAgICAgICAgICAgIHBvcy5jb2x1bW4gPSAwOwogICAgICAgIH0KICAgICAgICBlbHNlIHsKICAgICAgICAgICAgcG9zLnJvdyA9IHJvdzsKICAgICAgICAgICAgcG9zLmNvbHVtbiA9IE1hdGgubWluKHRoaXMuZG9jdW1lbnQuZ2V0TGluZShwb3Mucm93KS5sZW5ndGgsIE1hdGgubWF4KDAsIGNvbHVtbikpOwogICAgICAgIH0KCiAgICAgICAgaWYgKGNvbHVtbiA8IDApCiAgICAgICAgICAgIHBvcy5jb2x1bW4gPSAwOwoKICAgICAgICByZXR1cm4gcG9zOwogICAgfTsKCn0pLmNhbGwoQW5jaG9yLnByb3RvdHlwZSk7Cgp9KTsKCmFjZS5kZWZpbmUoImFjZS9kb2N1bWVudCIsW10sIGZ1bmN0aW9uKHJlcXVpcmUsIGV4cG9ydHMsIG1vZHVsZSkgewoidXNlIHN0cmljdCI7Cgp2YXIgb29wID0gcmVxdWlyZSgiLi9saWIvb29wIik7CnZhciBhcHBseURlbHRhID0gcmVxdWlyZSgiLi9hcHBseV9kZWx0YSIpLmFwcGx5RGVsdGE7CnZhciBFdmVudEVtaXR0ZXIgPSByZXF1aXJlKCIuL2xpYi9ldmVudF9lbWl0dGVyIikuRXZlbnRFbWl0dGVyOwp2YXIgUmFuZ2UgPSByZXF1aXJlKCIuL3JhbmdlIikuUmFuZ2U7CnZhciBBbmNob3IgPSByZXF1aXJlKCIuL2FuY2hvciIpLkFuY2hvcjsKCnZhciBEb2N1bWVudCA9IGZ1bmN0aW9uKHRleHRPckxpbmVzKSB7CiAgICB0aGlzLiRsaW5lcyA9IFsiIl07CiAgICBpZiAodGV4dE9yTGluZXMubGVuZ3RoID09PSAwKSB7CiAgICAgICAgdGhpcy4kbGluZXMgPSBbIiJdOwogICAgfSBlbHNlIGlmIChBcnJheS5pc0FycmF5KHRleHRPckxpbmVzKSkgewogICAgICAgIHRoaXMuaW5zZXJ0TWVyZ2VkTGluZXMoe3JvdzogMCwgY29sdW1uOiAwfSwgdGV4dE9yTGluZXMpOwogICAgfSBlbHNlIHsKICAgICAgICB0aGlzLmluc2VydCh7cm93OiAwLCBjb2x1bW46MH0sIHRleHRPckxpbmVzKTsKICAgIH0KfTsKCihmdW5jdGlvbigpIHsKCiAgICBvb3AuaW1wbGVtZW50KHRoaXMsIEV2ZW50RW1pdHRlcik7CiAgICB0aGlzLnNldFZhbHVlID0gZnVuY3Rpb24odGV4dCkgewogICAgICAgIHZhciBsZW4gPSB0aGlzLmdldExlbmd0aCgpIC0gMTsKICAgICAgICB0aGlzLnJlbW92ZShuZXcgUmFuZ2UoMCwgMCwgbGVuLCB0aGlzLmdldExpbmUobGVuKS5sZW5ndGgpKTsKICAgICAgICB0aGlzLmluc2VydCh7cm93OiAwLCBjb2x1bW46IDB9LCB0ZXh0KTsKICAgIH07CiAgICB0aGlzLmdldFZhbHVlID0gZnVuY3Rpb24oKSB7CiAgICAgICAgcmV0dXJuIHRoaXMuZ2V0QWxsTGluZXMoKS5qb2luKHRoaXMuZ2V0TmV3TGluZUNoYXJhY3RlcigpKTsKICAgIH07CiAgICB0aGlzLmNyZWF0ZUFuY2hvciA9IGZ1bmN0aW9uKHJvdywgY29sdW1uKSB7CiAgICAgICAgcmV0dXJuIG5ldyBBbmNob3IodGhpcywgcm93LCBjb2x1bW4pOwogICAgfTsKICAgIGlmICgiYWFhIi5zcGxpdCgvYS8pLmxlbmd0aCA9PT0gMCkgewogICAgICAgIHRoaXMuJHNwbGl0ID0gZnVuY3Rpb24odGV4dCkgewogICAgICAgICAgICByZXR1cm4gdGV4dC5yZXBsYWNlKC9cclxufFxyL2csICJcbiIpLnNwbGl0KCJcbiIpOwogICAgICAgIH07CiAgICB9IGVsc2UgewogICAgICAgIHRoaXMuJHNwbGl0ID0gZnVuY3Rpb24odGV4dCkgewogICAgICAgICAgICByZXR1cm4gdGV4dC5zcGxpdCgvXHJcbnxccnxcbi8pOwogICAgICAgIH07CiAgICB9CgoKICAgIHRoaXMuJGRldGVjdE5ld0xpbmUgPSBmdW5jdGlvbih0ZXh0KSB7CiAgICAgICAgdmFyIG1hdGNoID0gdGV4dC5tYXRjaCgvXi4qPyhcclxufFxyfFxuKS9tKTsKICAgICAgICB0aGlzLiRhdXRvTmV3TGluZSA9IG1hdGNoID8gbWF0Y2hbMV0gOiAiXG4iOwogICAgICAgIHRoaXMuX3NpZ25hbCgiY2hhbmdlTmV3TGluZU1vZGUiKTsKICAgIH07CiAgICB0aGlzLmdldE5ld0xpbmVDaGFyYWN0ZXIgPSBmdW5jdGlvbigpIHsKICAgICAgICBzd2l0Y2ggKHRoaXMuJG5ld0xpbmVNb2RlKSB7CiAgICAgICAgICBjYXNlICJ3aW5kb3dzIjoKICAgICAgICAgICAgcmV0dXJuICJcclxuIjsKICAgICAgICAgIGNhc2UgInVuaXgiOgogICAgICAgICAgICByZXR1cm4gIlxuIjsKICAgICAgICAgIGRlZmF1bHQ6CiAgICAgICAgICAgIHJldHVybiB0aGlzLiRhdXRvTmV3TGluZSB8fCAiXG4iOwogICAgICAgIH0KICAgIH07CgogICAgdGhpcy4kYXV0b05ld0xpbmUgPSAiIjsKICAgIHRoaXMuJG5ld0xpbmVNb2RlID0gImF1dG8iOwogICAgdGhpcy5zZXROZXdMaW5lTW9kZSA9IGZ1bmN0aW9uKG5ld0xpbmVNb2RlKSB7CiAgICAgICAgaWYgKHRoaXMuJG5ld0xpbmVNb2RlID09PSBuZXdMaW5lTW9kZSkKICAgICAgICAgICAgcmV0dXJuOwoKICAgICAgICB0aGlzLiRuZXdMaW5lTW9kZSA9IG5ld0xpbmVNb2RlOwogICAgICAgIHRoaXMuX3NpZ25hbCgiY2hhbmdlTmV3TGluZU1vZGUiKTsKICAgIH07CiAgICB0aGlzLmdldE5ld0xpbmVNb2RlID0gZnVuY3Rpb24oKSB7CiAgICAgICAgcmV0dXJuIHRoaXMuJG5ld0xpbmVNb2RlOwogICAgfTsKICAgIHRoaXMuaXNOZXdMaW5lID0gZnVuY3Rpb24odGV4dCkgewogICAgICAgIHJldHVybiAodGV4dCA9PSAiXHJcbiIgfHwgdGV4dCA9PSAiXHIiIHx8IHRleHQgPT0gIlxuIik7CiAgICB9OwogICAgdGhpcy5nZXRMaW5lID0gZnVuY3Rpb24ocm93KSB7CiAgICAgICAgcmV0dXJuIHRoaXMuJGxpbmVzW3Jvd10gfHwgIiI7CiAgICB9OwogICAgdGhpcy5nZXRMaW5lcyA9IGZ1bmN0aW9uKGZpcnN0Um93LCBsYXN0Um93KSB7CiAgICAgICAgcmV0dXJuIHRoaXMuJGxpbmVzLnNsaWNlKGZpcnN0Um93LCBsYXN0Um93ICsgMSk7CiAgICB9OwogICAgdGhpcy5nZXRBbGxMaW5lcyA9IGZ1bmN0aW9uKCkgewogICAgICAgIHJldHVybiB0aGlzLmdldExpbmVzKDAsIHRoaXMuZ2V0TGVuZ3RoKCkpOwogICAgfTsKICAgIHRoaXMuZ2V0TGVuZ3RoID0gZnVuY3Rpb24oKSB7CiAgICAgICAgcmV0dXJuIHRoaXMuJGxpbmVzLmxlbmd0aDsKICAgIH07CiAgICB0aGlzLmdldFRleHRSYW5nZSA9IGZ1bmN0aW9uKHJhbmdlKSB7CiAgICAgICAgcmV0dXJuIHRoaXMuZ2V0TGluZXNGb3JSYW5nZShyYW5nZSkuam9pbih0aGlzLmdldE5ld0xpbmVDaGFyYWN0ZXIoKSk7CiAgICB9OwogICAgdGhpcy5nZXRMaW5lc0ZvclJhbmdlID0gZnVuY3Rpb24ocmFuZ2UpIHsKICAgICAgICB2YXIgbGluZXM7CiAgICAgICAgaWYgKHJhbmdlLnN0YXJ0LnJvdyA9PT0gcmFuZ2UuZW5kLnJvdykgewogICAgICAgICAgICBsaW5lcyA9IFt0aGlzLmdldExpbmUocmFuZ2Uuc3RhcnQucm93KS5zdWJzdHJpbmcocmFuZ2Uuc3RhcnQuY29sdW1uLCByYW5nZS5lbmQuY29sdW1uKV07CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgbGluZXMgPSB0aGlzLmdldExpbmVzKHJhbmdlLnN0YXJ0LnJvdywgcmFuZ2UuZW5kLnJvdyk7CiAgICAgICAgICAgIGxpbmVzWzBdID0gKGxpbmVzWzBdIHx8ICIiKS5zdWJzdHJpbmcocmFuZ2Uuc3RhcnQuY29sdW1uKTsKICAgICAgICAgICAgdmFyIGwgPSBsaW5lcy5sZW5ndGggLSAxOwogICAgICAgICAgICBpZiAocmFuZ2UuZW5kLnJvdyAtIHJhbmdlLnN0YXJ0LnJvdyA9PSBsKQogICAgICAgICAgICAgICAgbGluZXNbbF0gPSBsaW5lc1tsXS5zdWJzdHJpbmcoMCwgcmFuZ2UuZW5kLmNvbHVtbik7CiAgICAgICAgfQogICAgICAgIHJldHVybiBsaW5lczsKICAgIH07CiAgICB0aGlzLmluc2VydExpbmVzID0gZnVuY3Rpb24ocm93LCBsaW5lcykgewogICAgICAgIGNvbnNvbGUud2FybigiVXNlIG9mIGRvY3VtZW50Lmluc2VydExpbmVzIGlzIGRlcHJlY2F0ZWQuIFVzZSB0aGUgaW5zZXJ0RnVsbExpbmVzIG1ldGhvZCBpbnN0ZWFkLiIpOwogICAgICAgIHJldHVybiB0aGlzLmluc2VydEZ1bGxMaW5lcyhyb3csIGxpbmVzKTsKICAgIH07CiAgICB0aGlzLnJlbW92ZUxpbmVzID0gZnVuY3Rpb24oZmlyc3RSb3csIGxhc3RSb3cpIHsKICAgICAgICBjb25zb2xlLndhcm4oIlVzZSBvZiBkb2N1bWVudC5yZW1vdmVMaW5lcyBpcyBkZXByZWNhdGVkLiBVc2UgdGhlIHJlbW92ZUZ1bGxMaW5lcyBtZXRob2QgaW5zdGVhZC4iKTsKICAgICAgICByZXR1cm4gdGhpcy5yZW1vdmVGdWxsTGluZXMoZmlyc3RSb3csIGxhc3RSb3cpOwogICAgfTsKICAgIHRoaXMuaW5zZXJ0TmV3TGluZSA9IGZ1bmN0aW9uKHBvc2l0aW9uKSB7CiAgICAgICAgY29uc29sZS53YXJuKCJVc2Ugb2YgZG9jdW1lbnQuaW5zZXJ0TmV3TGluZSBpcyBkZXByZWNhdGVkLiBVc2UgaW5zZXJ0TWVyZ2VkTGluZXMocG9zaXRpb24sIFsnJywgJyddKSBpbnN0ZWFkLiIpOwogICAgICAgIHJldHVybiB0aGlzLmluc2VydE1lcmdlZExpbmVzKHBvc2l0aW9uLCBbIiIsICIiXSk7CiAgICB9OwogICAgdGhpcy5pbnNlcnQgPSBmdW5jdGlvbihwb3NpdGlvbiwgdGV4dCkgewogICAgICAgIGlmICh0aGlzLmdldExlbmd0aCgpIDw9IDEpCiAgICAgICAgICAgIHRoaXMuJGRldGVjdE5ld0xpbmUodGV4dCk7CiAgICAgICAgCiAgICAgICAgcmV0dXJuIHRoaXMuaW5zZXJ0TWVyZ2VkTGluZXMocG9zaXRpb24sIHRoaXMuJHNwbGl0KHRleHQpKTsKICAgIH07CiAgICB0aGlzLmluc2VydEluTGluZSA9IGZ1bmN0aW9uKHBvc2l0aW9uLCB0ZXh0KSB7CiAgICAgICAgdmFyIHN0YXJ0ID0gdGhpcy5jbGlwcGVkUG9zKHBvc2l0aW9uLnJvdywgcG9zaXRpb24uY29sdW1uKTsKICAgICAgICB2YXIgZW5kID0gdGhpcy5wb3MocG9zaXRpb24ucm93LCBwb3NpdGlvbi5jb2x1bW4gKyB0ZXh0Lmxlbmd0aCk7CiAgICAgICAgCiAgICAgICAgdGhpcy5hcHBseURlbHRhKHsKICAgICAgICAgICAgc3RhcnQ6IHN0YXJ0LAogICAgICAgICAgICBlbmQ6IGVuZCwKICAgICAgICAgICAgYWN0aW9uOiAiaW5zZXJ0IiwKICAgICAgICAgICAgbGluZXM6IFt0ZXh0XQogICAgICAgIH0sIHRydWUpOwogICAgICAgIAogICAgICAgIHJldHVybiB0aGlzLmNsb25lUG9zKGVuZCk7CiAgICB9OwogICAgCiAgICB0aGlzLmNsaXBwZWRQb3MgPSBmdW5jdGlvbihyb3csIGNvbHVtbikgewogICAgICAgIHZhciBsZW5ndGggPSB0aGlzLmdldExlbmd0aCgpOwogICAgICAgIGlmIChyb3cgPT09IHVuZGVmaW5lZCkgewogICAgICAgICAgICByb3cgPSBsZW5ndGg7CiAgICAgICAgfSBlbHNlIGlmIChyb3cgPCAwKSB7CiAgICAgICAgICAgIHJvdyA9IDA7CiAgICAgICAgfSBlbHNlIGlmIChyb3cgPj0gbGVuZ3RoKSB7CiAgICAgICAgICAgIHJvdyA9IGxlbmd0aCAtIDE7CiAgICAgICAgICAgIGNvbHVtbiA9IHVuZGVmaW5lZDsKICAgICAgICB9CiAgICAgICAgdmFyIGxpbmUgPSB0aGlzLmdldExpbmUocm93KTsKICAgICAgICBpZiAoY29sdW1uID09IHVuZGVmaW5lZCkKICAgICAgICAgICAgY29sdW1uID0gbGluZS5sZW5ndGg7CiAgICAgICAgY29sdW1uID0gTWF0aC5taW4oTWF0aC5tYXgoY29sdW1uLCAwKSwgbGluZS5sZW5ndGgpOwogICAgICAgIHJldHVybiB7cm93OiByb3csIGNvbHVtbjogY29sdW1ufTsKICAgIH07CiAgICAKICAgIHRoaXMuY2xvbmVQb3MgPSBmdW5jdGlvbihwb3MpIHsKICAgICAgICByZXR1cm4ge3JvdzogcG9zLnJvdywgY29sdW1uOiBwb3MuY29sdW1ufTsKICAgIH07CiAgICAKICAgIHRoaXMucG9zID0gZnVuY3Rpb24ocm93LCBjb2x1bW4pIHsKICAgICAgICByZXR1cm4ge3Jvdzogcm93LCBjb2x1bW46IGNvbHVtbn07CiAgICB9OwogICAgCiAgICB0aGlzLiRjbGlwUG9zaXRpb24gPSBmdW5jdGlvbihwb3NpdGlvbikgewogICAgICAgIHZhciBsZW5ndGggPSB0aGlzLmdldExlbmd0aCgpOwogICAgICAgIGlmIChwb3NpdGlvbi5yb3cgPj0gbGVuZ3RoKSB7CiAgICAgICAgICAgIHBvc2l0aW9uLnJvdyA9IE1hdGgubWF4KDAsIGxlbmd0aCAtIDEpOwogICAgICAgICAgICBwb3NpdGlvbi5jb2x1bW4gPSB0aGlzLmdldExpbmUobGVuZ3RoIC0gMSkubGVuZ3RoOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIHBvc2l0aW9uLnJvdyA9IE1hdGgubWF4KDAsIHBvc2l0aW9uLnJvdyk7CiAgICAgICAgICAgIHBvc2l0aW9uLmNvbHVtbiA9IE1hdGgubWluKE1hdGgubWF4KHBvc2l0aW9uLmNvbHVtbiwgMCksIHRoaXMuZ2V0TGluZShwb3NpdGlvbi5yb3cpLmxlbmd0aCk7CiAgICAgICAgfQogICAgICAgIHJldHVybiBwb3NpdGlvbjsKICAgIH07CiAgICB0aGlzLmluc2VydEZ1bGxMaW5lcyA9IGZ1bmN0aW9uKHJvdywgbGluZXMpIHsKICAgICAgICByb3cgPSBNYXRoLm1pbihNYXRoLm1heChyb3csIDApLCB0aGlzLmdldExlbmd0aCgpKTsKICAgICAgICB2YXIgY29sdW1uID0gMDsKICAgICAgICBpZiAocm93IDwgdGhpcy5nZXRMZW5ndGgoKSkgewogICAgICAgICAgICBsaW5lcyA9IGxpbmVzLmNvbmNhdChbIiJdKTsKICAgICAgICAgICAgY29sdW1uID0gMDsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgICBsaW5lcyA9IFsiIl0uY29uY2F0KGxpbmVzKTsKICAgICAgICAgICAgcm93LS07CiAgICAgICAgICAgIGNvbHVtbiA9IHRoaXMuJGxpbmVzW3Jvd10ubGVuZ3RoOwogICAgICAgIH0KICAgICAgICB0aGlzLmluc2VydE1lcmdlZExpbmVzKHtyb3c6IHJvdywgY29sdW1uOiBjb2x1bW59LCBsaW5lcyk7CiAgICB9OyAgICAKICAgIHRoaXMuaW5zZXJ0TWVyZ2VkTGluZXMgPSBmdW5jdGlvbihwb3NpdGlvbiwgbGluZXMpIHsKICAgICAgICB2YXIgc3RhcnQgPSB0aGlzLmNsaXBwZWRQb3MocG9zaXRpb24ucm93LCBwb3NpdGlvbi5jb2x1bW4pOwogICAgICAgIHZhciBlbmQgPSB7CiAgICAgICAgICAgIHJvdzogc3RhcnQucm93ICsgbGluZXMubGVuZ3RoIC0gMSwKICAgICAgICAgICAgY29sdW1uOiAobGluZXMubGVuZ3RoID09IDEgPyBzdGFydC5jb2x1bW4gOiAwKSArIGxpbmVzW2xpbmVzLmxlbmd0aCAtIDFdLmxlbmd0aAogICAgICAgIH07CiAgICAgICAgCiAgICAgICAgdGhpcy5hcHBseURlbHRhKHsKICAgICAgICAgICAgc3RhcnQ6IHN0YXJ0LAogICAgICAgICAgICBlbmQ6IGVuZCwKICAgICAgICAgICAgYWN0aW9uOiAiaW5zZXJ0IiwKICAgICAgICAgICAgbGluZXM6IGxpbmVzCiAgICAgICAgfSk7CiAgICAgICAgCiAgICAgICAgcmV0dXJuIHRoaXMuY2xvbmVQb3MoZW5kKTsKICAgIH07CiAgICB0aGlzLnJlbW92ZSA9IGZ1bmN0aW9uKHJhbmdlKSB7CiAgICAgICAgdmFyIHN0YXJ0ID0gdGhpcy5jbGlwcGVkUG9zKHJhbmdlLnN0YXJ0LnJvdywgcmFuZ2Uuc3RhcnQuY29sdW1uKTsKICAgICAgICB2YXIgZW5kID0gdGhpcy5jbGlwcGVkUG9zKHJhbmdlLmVuZC5yb3csIHJhbmdlLmVuZC5jb2x1bW4pOwogICAgICAgIHRoaXMuYXBwbHlEZWx0YSh7CiAgICAgICAgICAgIHN0YXJ0OiBzdGFydCwKICAgICAgICAgICAgZW5kOiBlbmQsCiAgICAgICAgICAgIGFjdGlvbjogInJlbW92ZSIsCiAgICAgICAgICAgIGxpbmVzOiB0aGlzLmdldExpbmVzRm9yUmFuZ2Uoe3N0YXJ0OiBzdGFydCwgZW5kOiBlbmR9KQogICAgICAgIH0pOwogICAgICAgIHJldHVybiB0aGlzLmNsb25lUG9zKHN0YXJ0KTsKICAgIH07CiAgICB0aGlzLnJlbW92ZUluTGluZSA9IGZ1bmN0aW9uKHJvdywgc3RhcnRDb2x1bW4sIGVuZENvbHVtbikgewogICAgICAgIHZhciBzdGFydCA9IHRoaXMuY2xpcHBlZFBvcyhyb3csIHN0YXJ0Q29sdW1uKTsKICAgICAgICB2YXIgZW5kID0gdGhpcy5jbGlwcGVkUG9zKHJvdywgZW5kQ29sdW1uKTsKICAgICAgICAKICAgICAgICB0aGlzLmFwcGx5RGVsdGEoewogICAgICAgICAgICBzdGFydDogc3RhcnQsCiAgICAgICAgICAgIGVuZDogZW5kLAogICAgICAgICAgICBhY3Rpb246ICJyZW1vdmUiLAogICAgICAgICAgICBsaW5lczogdGhpcy5nZXRMaW5lc0ZvclJhbmdlKHtzdGFydDogc3RhcnQsIGVuZDogZW5kfSkKICAgICAgICB9LCB0cnVlKTsKICAgICAgICAKICAgICAgICByZXR1cm4gdGhpcy5jbG9uZVBvcyhzdGFydCk7CiAgICB9OwogICAgdGhpcy5yZW1vdmVGdWxsTGluZXMgPSBmdW5jdGlvbihmaXJzdFJvdywgbGFzdFJvdykgewogICAgICAgIGZpcnN0Um93ID0gTWF0aC5taW4oTWF0aC5tYXgoMCwgZmlyc3RSb3cpLCB0aGlzLmdldExlbmd0aCgpIC0gMSk7CiAgICAgICAgbGFzdFJvdyAgPSBNYXRoLm1pbihNYXRoLm1heCgwLCBsYXN0Um93ICksIHRoaXMuZ2V0TGVuZ3RoKCkgLSAxKTsKICAgICAgICB2YXIgZGVsZXRlRmlyc3ROZXdMaW5lID0gbGFzdFJvdyA9PSB0aGlzLmdldExlbmd0aCgpIC0gMSAmJiBmaXJzdFJvdyA+IDA7CiAgICAgICAgdmFyIGRlbGV0ZUxhc3ROZXdMaW5lICA9IGxhc3RSb3cgIDwgdGhpcy5nZXRMZW5ndGgoKSAtIDE7CiAgICAgICAgdmFyIHN0YXJ0Um93ID0gKCBkZWxldGVGaXJzdE5ld0xpbmUgPyBmaXJzdFJvdyAtIDEgICAgICAgICAgICAgICAgICA6IGZpcnN0Um93ICAgICAgICAgICAgICAgICAgICApOwogICAgICAgIHZhciBzdGFydENvbCA9ICggZGVsZXRlRmlyc3ROZXdMaW5lID8gdGhpcy5nZXRMaW5lKHN0YXJ0Um93KS5sZW5ndGggOiAwICAgICAgICAgICAgICAgICAgICAgICAgICAgKTsKICAgICAgICB2YXIgZW5kUm93ICAgPSAoIGRlbGV0ZUxhc3ROZXdMaW5lICA/IGxhc3RSb3cgKyAxICAgICAgICAgICAgICAgICAgIDogbGFzdFJvdyAgICAgICAgICAgICAgICAgICAgICk7CiAgICAgICAgdmFyIGVuZENvbCAgID0gKCBkZWxldGVMYXN0TmV3TGluZSAgPyAwICAgICAgICAgICAgICAgICAgICAgICAgICAgICA6IHRoaXMuZ2V0TGluZShlbmRSb3cpLmxlbmd0aCApOyAKICAgICAgICB2YXIgcmFuZ2UgPSBuZXcgUmFuZ2Uoc3RhcnRSb3csIHN0YXJ0Q29sLCBlbmRSb3csIGVuZENvbCk7CiAgICAgICAgdmFyIGRlbGV0ZWRMaW5lcyA9IHRoaXMuJGxpbmVzLnNsaWNlKGZpcnN0Um93LCBsYXN0Um93ICsgMSk7CiAgICAgICAgCiAgICAgICAgdGhpcy5hcHBseURlbHRhKHsKICAgICAgICAgICAgc3RhcnQ6IHJhbmdlLnN0YXJ0LAogICAgICAgICAgICBlbmQ6IHJhbmdlLmVuZCwKICAgICAgICAgICAgYWN0aW9uOiAicmVtb3ZlIiwKICAgICAgICAgICAgbGluZXM6IHRoaXMuZ2V0TGluZXNGb3JSYW5nZShyYW5nZSkKICAgICAgICB9KTsKICAgICAgICByZXR1cm4gZGVsZXRlZExpbmVzOwogICAgfTsKICAgIHRoaXMucmVtb3ZlTmV3TGluZSA9IGZ1bmN0aW9uKHJvdykgewogICAgICAgIGlmIChyb3cgPCB0aGlzLmdldExlbmd0aCgpIC0gMSAmJiByb3cgPj0gMCkgewogICAgICAgICAgICB0aGlzLmFwcGx5RGVsdGEoewogICAgICAgICAgICAgICAgc3RhcnQ6IHRoaXMucG9zKHJvdywgdGhpcy5nZXRMaW5lKHJvdykubGVuZ3RoKSwKICAgICAgICAgICAgICAgIGVuZDogdGhpcy5wb3Mocm93ICsgMSwgMCksCiAgICAgICAgICAgICAgICBhY3Rpb246ICJyZW1vdmUiLAogICAgICAgICAgICAgICAgbGluZXM6IFsiIiwgIiJdCiAgICAgICAgICAgIH0pOwogICAgICAgIH0KICAgIH07CiAgICB0aGlzLnJlcGxhY2UgPSBmdW5jdGlvbihyYW5nZSwgdGV4dCkgewogICAgICAgIGlmICghKHJhbmdlIGluc3RhbmNlb2YgUmFuZ2UpKQogICAgICAgICAgICByYW5nZSA9IFJhbmdlLmZyb21Qb2ludHMocmFuZ2Uuc3RhcnQsIHJhbmdlLmVuZCk7CiAgICAgICAgaWYgKHRleHQubGVuZ3RoID09PSAwICYmIHJhbmdlLmlzRW1wdHkoKSkKICAgICAgICAgICAgcmV0dXJuIHJhbmdlLnN0YXJ0OwogICAgICAgIGlmICh0ZXh0ID09IHRoaXMuZ2V0VGV4dFJhbmdlKHJhbmdlKSkKICAgICAgICAgICAgcmV0dXJuIHJhbmdlLmVuZDsKCiAgICAgICAgdGhpcy5yZW1vdmUocmFuZ2UpOwogICAgICAgIHZhciBlbmQ7CiAgICAgICAgaWYgKHRleHQpIHsKICAgICAgICAgICAgZW5kID0gdGhpcy5pbnNlcnQocmFuZ2Uuc3RhcnQsIHRleHQpOwogICAgICAgIH0KICAgICAgICBlbHNlIHsKICAgICAgICAgICAgZW5kID0gcmFuZ2Uuc3RhcnQ7CiAgICAgICAgfQogICAgICAgIAogICAgICAgIHJldHVybiBlbmQ7CiAgICB9OwogICAgdGhpcy5hcHBseURlbHRhcyA9IGZ1bmN0aW9uKGRlbHRhcykgewogICAgICAgIGZvciAodmFyIGk9MDsgaTxkZWx0YXMubGVuZ3RoOyBpKyspIHsKICAgICAgICAgICAgdGhpcy5hcHBseURlbHRhKGRlbHRhc1tpXSk7CiAgICAgICAgfQogICAgfTsKICAgIHRoaXMucmV2ZXJ0RGVsdGFzID0gZnVuY3Rpb24oZGVsdGFzKSB7CiAgICAgICAgZm9yICh2YXIgaT1kZWx0YXMubGVuZ3RoLTE7IGk+PTA7IGktLSkgewogICAgICAgICAgICB0aGlzLnJldmVydERlbHRhKGRlbHRhc1tpXSk7CiAgICAgICAgfQogICAgfTsKICAgIHRoaXMuYXBwbHlEZWx0YSA9IGZ1bmN0aW9uKGRlbHRhLCBkb05vdFZhbGlkYXRlKSB7CiAgICAgICAgdmFyIGlzSW5zZXJ0ID0gZGVsdGEuYWN0aW9uID09ICJpbnNlcnQiOwogICAgICAgIGlmIChpc0luc2VydCA/IGRlbHRhLmxpbmVzLmxlbmd0aCA8PSAxICYmICFkZWx0YS5saW5lc1swXQogICAgICAgICAgICA6ICFSYW5nZS5jb21wYXJlUG9pbnRzKGRlbHRhLnN0YXJ0LCBkZWx0YS5lbmQpKSB7CiAgICAgICAgICAgIHJldHVybjsKICAgICAgICB9CiAgICAgICAgCiAgICAgICAgaWYgKGlzSW5zZXJ0ICYmIGRlbHRhLmxpbmVzLmxlbmd0aCA+IDIwMDAwKSB7CiAgICAgICAgICAgIHRoaXMuJHNwbGl0QW5kYXBwbHlMYXJnZURlbHRhKGRlbHRhLCAyMDAwMCk7CiAgICAgICAgfQogICAgICAgIGVsc2UgewogICAgICAgICAgICBhcHBseURlbHRhKHRoaXMuJGxpbmVzLCBkZWx0YSwgZG9Ob3RWYWxpZGF0ZSk7CiAgICAgICAgICAgIHRoaXMuX3NpZ25hbCgiY2hhbmdlIiwgZGVsdGEpOwogICAgICAgIH0KICAgIH07CiAgICAKICAgIHRoaXMuJHNhZmVBcHBseURlbHRhID0gZnVuY3Rpb24oZGVsdGEpIHsKICAgICAgICB2YXIgZG9jTGVuZ3RoID0gdGhpcy4kbGluZXMubGVuZ3RoOwogICAgICAgIGlmICgKICAgICAgICAgICAgZGVsdGEuYWN0aW9uID09ICJyZW1vdmUiICYmIGRlbHRhLnN0YXJ0LnJvdyA8IGRvY0xlbmd0aCAmJiBkZWx0YS5lbmQucm93IDwgZG9jTGVuZ3RoCiAgICAgICAgICAgIHx8IGRlbHRhLmFjdGlvbiA9PSAiaW5zZXJ0IiAmJiBkZWx0YS5zdGFydC5yb3cgPD0gZG9jTGVuZ3RoCiAgICAgICAgKSB7CiAgICAgICAgICAgIHRoaXMuYXBwbHlEZWx0YShkZWx0YSk7CiAgICAgICAgfQogICAgfTsKICAgIAogICAgdGhpcy4kc3BsaXRBbmRhcHBseUxhcmdlRGVsdGEgPSBmdW5jdGlvbihkZWx0YSwgTUFYKSB7CiAgICAgICAgdmFyIGxpbmVzID0gZGVsdGEubGluZXM7CiAgICAgICAgdmFyIGwgPSBsaW5lcy5sZW5ndGggLSBNQVggKyAxOwogICAgICAgIHZhciByb3cgPSBkZWx0YS5zdGFydC5yb3c7IAogICAgICAgIHZhciBjb2x1bW4gPSBkZWx0YS5zdGFydC5jb2x1bW47CiAgICAgICAgZm9yICh2YXIgZnJvbSA9IDAsIHRvID0gMDsgZnJvbSA8IGw7IGZyb20gPSB0bykgewogICAgICAgICAgICB0byArPSBNQVggLSAxOwogICAgICAgICAgICB2YXIgY2h1bmsgPSBsaW5lcy5zbGljZShmcm9tLCB0byk7CiAgICAgICAgICAgIGNodW5rLnB1c2goIiIpOwogICAgICAgICAgICB0aGlzLmFwcGx5RGVsdGEoewogICAgICAgICAgICAgICAgc3RhcnQ6IHRoaXMucG9zKHJvdyArIGZyb20sIGNvbHVtbiksCiAgICAgICAgICAgICAgICBlbmQ6IHRoaXMucG9zKHJvdyArIHRvLCBjb2x1bW4gPSAwKSwKICAgICAgICAgICAgICAgIGFjdGlvbjogZGVsdGEuYWN0aW9uLAogICAgICAgICAgICAgICAgbGluZXM6IGNodW5rCiAgICAgICAgICAgIH0sIHRydWUpOwogICAgICAgIH0KICAgICAgICBkZWx0YS5saW5lcyA9IGxpbmVzLnNsaWNlKGZyb20pOwogICAgICAgIGRlbHRhLnN0YXJ0LnJvdyA9IHJvdyArIGZyb207CiAgICAgICAgZGVsdGEuc3RhcnQuY29sdW1uID0gY29sdW1uOwogICAgICAgIHRoaXMuYXBwbHlEZWx0YShkZWx0YSwgdHJ1ZSk7CiAgICB9OwogICAgdGhpcy5yZXZlcnREZWx0YSA9IGZ1bmN0aW9uKGRlbHRhKSB7CiAgICAgICAgdGhpcy4kc2FmZUFwcGx5RGVsdGEoewogICAgICAgICAgICBzdGFydDogdGhpcy5jbG9uZVBvcyhkZWx0YS5zdGFydCksCiAgICAgICAgICAgIGVuZDogdGhpcy5jbG9uZVBvcyhkZWx0YS5lbmQpLAogICAgICAgICAgICBhY3Rpb246IChkZWx0YS5hY3Rpb24gPT0gImluc2VydCIgPyAicmVtb3ZlIiA6ICJpbnNlcnQiKSwKICAgICAgICAgICAgbGluZXM6IGRlbHRhLmxpbmVzLnNsaWNlKCkKICAgICAgICB9KTsKICAgIH07CiAgICB0aGlzLmluZGV4VG9Qb3NpdGlvbiA9IGZ1bmN0aW9uKGluZGV4LCBzdGFydFJvdykgewogICAgICAgIHZhciBsaW5lcyA9IHRoaXMuJGxpbmVzIHx8IHRoaXMuZ2V0QWxsTGluZXMoKTsKICAgICAgICB2YXIgbmV3bGluZUxlbmd0aCA9IHRoaXMuZ2V0TmV3TGluZUNoYXJhY3RlcigpLmxlbmd0aDsKICAgICAgICBmb3IgKHZhciBpID0gc3RhcnRSb3cgfHwgMCwgbCA9IGxpbmVzLmxlbmd0aDsgaSA8IGw7IGkrKykgewogICAgICAgICAgICBpbmRleCAtPSBsaW5lc1tpXS5sZW5ndGggKyBuZXdsaW5lTGVuZ3RoOwogICAgICAgICAgICBpZiAoaW5kZXggPCAwKQogICAgICAgICAgICAgICAgcmV0dXJuIHtyb3c6IGksIGNvbHVtbjogaW5kZXggKyBsaW5lc1tpXS5sZW5ndGggKyBuZXdsaW5lTGVuZ3RofTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIHtyb3c6IGwtMSwgY29sdW1uOiBpbmRleCArIGxpbmVzW2wtMV0ubGVuZ3RoICsgbmV3bGluZUxlbmd0aH07CiAgICB9OwogICAgdGhpcy5wb3NpdGlvblRvSW5kZXggPSBmdW5jdGlvbihwb3MsIHN0YXJ0Um93KSB7CiAgICAgICAgdmFyIGxpbmVzID0gdGhpcy4kbGluZXMgfHwgdGhpcy5nZXRBbGxMaW5lcygpOwogICAgICAgIHZhciBuZXdsaW5lTGVuZ3RoID0gdGhpcy5nZXROZXdMaW5lQ2hhcmFjdGVyKCkubGVuZ3RoOwogICAgICAgIHZhciBpbmRleCA9IDA7CiAgICAgICAgdmFyIHJvdyA9IE1hdGgubWluKHBvcy5yb3csIGxpbmVzLmxlbmd0aCk7CiAgICAgICAgZm9yICh2YXIgaSA9IHN0YXJ0Um93IHx8IDA7IGkgPCByb3c7ICsraSkKICAgICAgICAgICAgaW5kZXggKz0gbGluZXNbaV0ubGVuZ3RoICsgbmV3bGluZUxlbmd0aDsKCiAgICAgICAgcmV0dXJuIGluZGV4ICsgcG9zLmNvbHVtbjsKICAgIH07Cgp9KS5jYWxsKERvY3VtZW50LnByb3RvdHlwZSk7CgpleHBvcnRzLkRvY3VtZW50ID0gRG9jdW1lbnQ7Cn0pOwoKYWNlLmRlZmluZSgiYWNlL2xpYi9sYW5nIixbXSwgZnVuY3Rpb24ocmVxdWlyZSwgZXhwb3J0cywgbW9kdWxlKSB7CiJ1c2Ugc3RyaWN0IjsKCmV4cG9ydHMubGFzdCA9IGZ1bmN0aW9uKGEpIHsKICAgIHJldHVybiBhW2EubGVuZ3RoIC0gMV07Cn07CgpleHBvcnRzLnN0cmluZ1JldmVyc2UgPSBmdW5jdGlvbihzdHJpbmcpIHsKICAgIHJldHVybiBzdHJpbmcuc3BsaXQoIiIpLnJldmVyc2UoKS5qb2luKCIiKTsKfTsKCmV4cG9ydHMuc3RyaW5nUmVwZWF0ID0gZnVuY3Rpb24gKHN0cmluZywgY291bnQpIHsKICAgIHZhciByZXN1bHQgPSAnJzsKICAgIHdoaWxlIChjb3VudCA+IDApIHsKICAgICAgICBpZiAoY291bnQgJiAxKQogICAgICAgICAgICByZXN1bHQgKz0gc3RyaW5nOwoKICAgICAgICBpZiAoY291bnQgPj49IDEpCiAgICAgICAgICAgIHN0cmluZyArPSBzdHJpbmc7CiAgICB9CiAgICByZXR1cm4gcmVzdWx0Owp9OwoKdmFyIHRyaW1CZWdpblJlZ2V4cCA9IC9eXHNccyovOwp2YXIgdHJpbUVuZFJlZ2V4cCA9IC9cc1xzKiQvOwoKZXhwb3J0cy5zdHJpbmdUcmltTGVmdCA9IGZ1bmN0aW9uIChzdHJpbmcpIHsKICAgIHJldHVybiBzdHJpbmcucmVwbGFjZSh0cmltQmVnaW5SZWdleHAsICcnKTsKfTsKCmV4cG9ydHMuc3RyaW5nVHJpbVJpZ2h0ID0gZnVuY3Rpb24gKHN0cmluZykgewogICAgcmV0dXJuIHN0cmluZy5yZXBsYWNlKHRyaW1FbmRSZWdleHAsICcnKTsKfTsKCmV4cG9ydHMuY29weU9iamVjdCA9IGZ1bmN0aW9uKG9iaikgewogICAgdmFyIGNvcHkgPSB7fTsKICAgIGZvciAodmFyIGtleSBpbiBvYmopIHsKICAgICAgICBjb3B5W2tleV0gPSBvYmpba2V5XTsKICAgIH0KICAgIHJldHVybiBjb3B5Owp9OwoKZXhwb3J0cy5jb3B5QXJyYXkgPSBmdW5jdGlvbihhcnJheSl7CiAgICB2YXIgY29weSA9IFtdOwogICAgZm9yICh2YXIgaT0wLCBsPWFycmF5Lmxlbmd0aDsgaTxsOyBpKyspIHsKICAgICAgICBpZiAoYXJyYXlbaV0gJiYgdHlwZW9mIGFycmF5W2ldID09ICJvYmplY3QiKQogICAgICAgICAgICBjb3B5W2ldID0gdGhpcy5jb3B5T2JqZWN0KGFycmF5W2ldKTsKICAgICAgICBlbHNlIAogICAgICAgICAgICBjb3B5W2ldID0gYXJyYXlbaV07CiAgICB9CiAgICByZXR1cm4gY29weTsKfTsKCmV4cG9ydHMuZGVlcENvcHkgPSBmdW5jdGlvbiBkZWVwQ29weShvYmopIHsKICAgIGlmICh0eXBlb2Ygb2JqICE9PSAib2JqZWN0IiB8fCAhb2JqKQogICAgICAgIHJldHVybiBvYmo7CiAgICB2YXIgY29weTsKICAgIGlmIChBcnJheS5pc0FycmF5KG9iaikpIHsKICAgICAgICBjb3B5ID0gW107CiAgICAgICAgZm9yICh2YXIga2V5ID0gMDsga2V5IDwgb2JqLmxlbmd0aDsga2V5KyspIHsKICAgICAgICAgICAgY29weVtrZXldID0gZGVlcENvcHkob2JqW2tleV0pOwogICAgICAgIH0KICAgICAgICByZXR1cm4gY29weTsKICAgIH0KICAgIGlmIChPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwob2JqKSAhPT0gIltvYmplY3QgT2JqZWN0XSIpCiAgICAgICAgcmV0dXJuIG9iajsKICAgIAogICAgY29weSA9IHt9OwogICAgZm9yICh2YXIga2V5IGluIG9iaikKICAgICAgICBjb3B5W2tleV0gPSBkZWVwQ29weShvYmpba2V5XSk7CiAgICByZXR1cm4gY29weTsKfTsKCmV4cG9ydHMuYXJyYXlUb01hcCA9IGZ1bmN0aW9uKGFycikgewogICAgdmFyIG1hcCA9IHt9OwogICAgZm9yICh2YXIgaT0wOyBpPGFyci5sZW5ndGg7IGkrKykgewogICAgICAgIG1hcFthcnJbaV1dID0gMTsKICAgIH0KICAgIHJldHVybiBtYXA7Cgp9OwoKZXhwb3J0cy5jcmVhdGVNYXAgPSBmdW5jdGlvbihwcm9wcykgewogICAgdmFyIG1hcCA9IE9iamVjdC5jcmVhdGUobnVsbCk7CiAgICBmb3IgKHZhciBpIGluIHByb3BzKSB7CiAgICAgICAgbWFwW2ldID0gcHJvcHNbaV07CiAgICB9CiAgICByZXR1cm4gbWFwOwp9OwpleHBvcnRzLmFycmF5UmVtb3ZlID0gZnVuY3Rpb24oYXJyYXksIHZhbHVlKSB7CiAgZm9yICh2YXIgaSA9IDA7IGkgPD0gYXJyYXkubGVuZ3RoOyBpKyspIHsKICAgIGlmICh2YWx1ZSA9PT0gYXJyYXlbaV0pIHsKICAgICAgYXJyYXkuc3BsaWNlKGksIDEpOwogICAgfQogIH0KfTsKCmV4cG9ydHMuZXNjYXBlUmVnRXhwID0gZnVuY3Rpb24oc3RyKSB7CiAgICByZXR1cm4gc3RyLnJlcGxhY2UoLyhbLiorP14ke30oKXxbXF1cL1xcXSkvZywgJ1xcJDEnKTsKfTsKCmV4cG9ydHMuZXNjYXBlSFRNTCA9IGZ1bmN0aW9uKHN0cikgewogICAgcmV0dXJuICgiIiArIHN0cikucmVwbGFjZSgvJi9nLCAiJiMzODsiKS5yZXBsYWNlKC8iL2csICImIzM0OyIpLnJlcGxhY2UoLycvZywgIiYjMzk7IikucmVwbGFjZSgvPC9nLCAiJiM2MDsiKTsKfTsKCmV4cG9ydHMuZ2V0TWF0Y2hPZmZzZXRzID0gZnVuY3Rpb24oc3RyaW5nLCByZWdFeHApIHsKICAgIHZhciBtYXRjaGVzID0gW107CgogICAgc3RyaW5nLnJlcGxhY2UocmVnRXhwLCBmdW5jdGlvbihzdHIpIHsKICAgICAgICBtYXRjaGVzLnB1c2goewogICAgICAgICAgICBvZmZzZXQ6IGFyZ3VtZW50c1thcmd1bWVudHMubGVuZ3RoLTJdLAogICAgICAgICAgICBsZW5ndGg6IHN0ci5sZW5ndGgKICAgICAgICB9KTsKICAgIH0pOwoKICAgIHJldHVybiBtYXRjaGVzOwp9OwpleHBvcnRzLmRlZmVycmVkQ2FsbCA9IGZ1bmN0aW9uKGZjbikgewogICAgdmFyIHRpbWVyID0gbnVsbDsKICAgIHZhciBjYWxsYmFjayA9IGZ1bmN0aW9uKCkgewogICAgICAgIHRpbWVyID0gbnVsbDsKICAgICAgICBmY24oKTsKICAgIH07CgogICAgdmFyIGRlZmVycmVkID0gZnVuY3Rpb24odGltZW91dCkgewogICAgICAgIGRlZmVycmVkLmNhbmNlbCgpOwogICAgICAgIHRpbWVyID0gc2V0VGltZW91dChjYWxsYmFjaywgdGltZW91dCB8fCAwKTsKICAgICAgICByZXR1cm4gZGVmZXJyZWQ7CiAgICB9OwoKICAgIGRlZmVycmVkLnNjaGVkdWxlID0gZGVmZXJyZWQ7CgogICAgZGVmZXJyZWQuY2FsbCA9IGZ1bmN0aW9uKCkgewogICAgICAgIHRoaXMuY2FuY2VsKCk7CiAgICAgICAgZmNuKCk7CiAgICAgICAgcmV0dXJuIGRlZmVycmVkOwogICAgfTsKCiAgICBkZWZlcnJlZC5jYW5jZWwgPSBmdW5jdGlvbigpIHsKICAgICAgICBjbGVhclRpbWVvdXQodGltZXIpOwogICAgICAgIHRpbWVyID0gbnVsbDsKICAgICAgICByZXR1cm4gZGVmZXJyZWQ7CiAgICB9OwogICAgCiAgICBkZWZlcnJlZC5pc1BlbmRpbmcgPSBmdW5jdGlvbigpIHsKICAgICAgICByZXR1cm4gdGltZXI7CiAgICB9OwoKICAgIHJldHVybiBkZWZlcnJlZDsKfTsKCgpleHBvcnRzLmRlbGF5ZWRDYWxsID0gZnVuY3Rpb24oZmNuLCBkZWZhdWx0VGltZW91dCkgewogICAgdmFyIHRpbWVyID0gbnVsbDsKICAgIHZhciBjYWxsYmFjayA9IGZ1bmN0aW9uKCkgewogICAgICAgIHRpbWVyID0gbnVsbDsKICAgICAgICBmY24oKTsKICAgIH07CgogICAgdmFyIF9zZWxmID0gZnVuY3Rpb24odGltZW91dCkgewogICAgICAgIGlmICh0aW1lciA9PSBudWxsKQogICAgICAgICAgICB0aW1lciA9IHNldFRpbWVvdXQoY2FsbGJhY2ssIHRpbWVvdXQgfHwgZGVmYXVsdFRpbWVvdXQpOwogICAgfTsKCiAgICBfc2VsZi5kZWxheSA9IGZ1bmN0aW9uKHRpbWVvdXQpIHsKICAgICAgICB0aW1lciAmJiBjbGVhclRpbWVvdXQodGltZXIpOwogICAgICAgIHRpbWVyID0gc2V0VGltZW91dChjYWxsYmFjaywgdGltZW91dCB8fCBkZWZhdWx0VGltZW91dCk7CiAgICB9OwogICAgX3NlbGYuc2NoZWR1bGUgPSBfc2VsZjsKCiAgICBfc2VsZi5jYWxsID0gZnVuY3Rpb24oKSB7CiAgICAgICAgdGhpcy5jYW5jZWwoKTsKICAgICAgICBmY24oKTsKICAgIH07CgogICAgX3NlbGYuY2FuY2VsID0gZnVuY3Rpb24oKSB7CiAgICAgICAgdGltZXIgJiYgY2xlYXJUaW1lb3V0KHRpbWVyKTsKICAgICAgICB0aW1lciA9IG51bGw7CiAgICB9OwoKICAgIF9zZWxmLmlzUGVuZGluZyA9IGZ1bmN0aW9uKCkgewogICAgICAgIHJldHVybiB0aW1lcjsKICAgIH07CgogICAgcmV0dXJuIF9zZWxmOwp9Owp9KTsKCmFjZS5kZWZpbmUoImFjZS93b3JrZXIvbWlycm9yIixbXSwgZnVuY3Rpb24ocmVxdWlyZSwgZXhwb3J0cywgbW9kdWxlKSB7CiJ1c2Ugc3RyaWN0IjsKCnZhciBSYW5nZSA9IHJlcXVpcmUoIi4uL3JhbmdlIikuUmFuZ2U7CnZhciBEb2N1bWVudCA9IHJlcXVpcmUoIi4uL2RvY3VtZW50IikuRG9jdW1lbnQ7CnZhciBsYW5nID0gcmVxdWlyZSgiLi4vbGliL2xhbmciKTsKICAgIAp2YXIgTWlycm9yID0gZXhwb3J0cy5NaXJyb3IgPSBmdW5jdGlvbihzZW5kZXIpIHsKICAgIHRoaXMuc2VuZGVyID0gc2VuZGVyOwogICAgdmFyIGRvYyA9IHRoaXMuZG9jID0gbmV3IERvY3VtZW50KCIiKTsKICAgIAogICAgdmFyIGRlZmVycmVkVXBkYXRlID0gdGhpcy5kZWZlcnJlZFVwZGF0ZSA9IGxhbmcuZGVsYXllZENhbGwodGhpcy5vblVwZGF0ZS5iaW5kKHRoaXMpKTsKICAgIAogICAgdmFyIF9zZWxmID0gdGhpczsKICAgIHNlbmRlci5vbigiY2hhbmdlIiwgZnVuY3Rpb24oZSkgewogICAgICAgIHZhciBkYXRhID0gZS5kYXRhOwogICAgICAgIGlmIChkYXRhWzBdLnN0YXJ0KSB7CiAgICAgICAgICAgIGRvYy5hcHBseURlbHRhcyhkYXRhKTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGRhdGEubGVuZ3RoOyBpICs9IDIpIHsKICAgICAgICAgICAgICAgIGlmIChBcnJheS5pc0FycmF5KGRhdGFbaSsxXSkpIHsKICAgICAgICAgICAgICAgICAgICB2YXIgZCA9IHthY3Rpb246ICJpbnNlcnQiLCBzdGFydDogZGF0YVtpXSwgbGluZXM6IGRhdGFbaSsxXX07CiAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICAgIHZhciBkID0ge2FjdGlvbjogInJlbW92ZSIsIHN0YXJ0OiBkYXRhW2ldLCBlbmQ6IGRhdGFbaSsxXX07CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBkb2MuYXBwbHlEZWx0YShkLCB0cnVlKTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBpZiAoX3NlbGYuJHRpbWVvdXQpCiAgICAgICAgICAgIHJldHVybiBkZWZlcnJlZFVwZGF0ZS5zY2hlZHVsZShfc2VsZi4kdGltZW91dCk7CiAgICAgICAgX3NlbGYub25VcGRhdGUoKTsKICAgIH0pOwp9OwoKKGZ1bmN0aW9uKCkgewogICAgCiAgICB0aGlzLiR0aW1lb3V0ID0gNTAwOwogICAgCiAgICB0aGlzLnNldFRpbWVvdXQgPSBmdW5jdGlvbih0aW1lb3V0KSB7CiAgICAgICAgdGhpcy4kdGltZW91dCA9IHRpbWVvdXQ7CiAgICB9OwogICAgCiAgICB0aGlzLnNldFZhbHVlID0gZnVuY3Rpb24odmFsdWUpIHsKICAgICAgICB0aGlzLmRvYy5zZXRWYWx1ZSh2YWx1ZSk7CiAgICAgICAgdGhpcy5kZWZlcnJlZFVwZGF0ZS5zY2hlZHVsZSh0aGlzLiR0aW1lb3V0KTsKICAgIH07CiAgICAKICAgIHRoaXMuZ2V0VmFsdWUgPSBmdW5jdGlvbihjYWxsYmFja0lkKSB7CiAgICAgICAgdGhpcy5zZW5kZXIuY2FsbGJhY2sodGhpcy5kb2MuZ2V0VmFsdWUoKSwgY2FsbGJhY2tJZCk7CiAgICB9OwogICAgCiAgICB0aGlzLm9uVXBkYXRlID0gZnVuY3Rpb24oKSB7CiAgICB9OwogICAgCiAgICB0aGlzLmlzUGVuZGluZyA9IGZ1bmN0aW9uKCkgewogICAgICAgIHJldHVybiB0aGlzLmRlZmVycmVkVXBkYXRlLmlzUGVuZGluZygpOwogICAgfTsKICAgIAp9KS5jYWxsKE1pcnJvci5wcm90b3R5cGUpOwoKfSk7CgphY2UuZGVmaW5lKCJhY2UvbW9kZS9qc29uL2pzb25fcGFyc2UiLFtdLCBmdW5jdGlvbihyZXF1aXJlLCBleHBvcnRzLCBtb2R1bGUpIHsKInVzZSBzdHJpY3QiOwoKICAgIHZhciBhdCwgICAgIC8vIFRoZSBpbmRleCBvZiB0aGUgY3VycmVudCBjaGFyYWN0ZXIKICAgICAgICBjaCwgICAgIC8vIFRoZSBjdXJyZW50IGNoYXJhY3RlcgogICAgICAgIGVzY2FwZWUgPSB7CiAgICAgICAgICAgICciJzogICciJywKICAgICAgICAgICAgJ1xcJzogJ1xcJywKICAgICAgICAgICAgJy8nOiAgJy8nLAogICAgICAgICAgICBiOiAgICAnXGInLAogICAgICAgICAgICBmOiAgICAnXGYnLAogICAgICAgICAgICBuOiAgICAnXG4nLAogICAgICAgICAgICByOiAgICAnXHInLAogICAgICAgICAgICB0OiAgICAnXHQnCiAgICAgICAgfSwKICAgICAgICB0ZXh0LAoKICAgICAgICBlcnJvciA9IGZ1bmN0aW9uIChtKSB7CgogICAgICAgICAgICB0aHJvdyB7CiAgICAgICAgICAgICAgICBuYW1lOiAgICAnU3ludGF4RXJyb3InLAogICAgICAgICAgICAgICAgbWVzc2FnZTogbSwKICAgICAgICAgICAgICAgIGF0OiAgICAgIGF0LAogICAgICAgICAgICAgICAgdGV4dDogICAgdGV4dAogICAgICAgICAgICB9OwogICAgICAgIH0sCgogICAgICAgIG5leHQgPSBmdW5jdGlvbiAoYykgewoKICAgICAgICAgICAgaWYgKGMgJiYgYyAhPT0gY2gpIHsKICAgICAgICAgICAgICAgIGVycm9yKCJFeHBlY3RlZCAnIiArIGMgKyAiJyBpbnN0ZWFkIG9mICciICsgY2ggKyAiJyIpOwogICAgICAgICAgICB9CgogICAgICAgICAgICBjaCA9IHRleHQuY2hhckF0KGF0KTsKICAgICAgICAgICAgYXQgKz0gMTsKICAgICAgICAgICAgcmV0dXJuIGNoOwogICAgICAgIH0sCgogICAgICAgIG51bWJlciA9IGZ1bmN0aW9uICgpIHsKCiAgICAgICAgICAgIHZhciBudW1iZXIsCiAgICAgICAgICAgICAgICBzdHJpbmcgPSAnJzsKCiAgICAgICAgICAgIGlmIChjaCA9PT0gJy0nKSB7CiAgICAgICAgICAgICAgICBzdHJpbmcgPSAnLSc7CiAgICAgICAgICAgICAgICBuZXh0KCctJyk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgd2hpbGUgKGNoID49ICcwJyAmJiBjaCA8PSAnOScpIHsKICAgICAgICAgICAgICAgIHN0cmluZyArPSBjaDsKICAgICAgICAgICAgICAgIG5leHQoKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAoY2ggPT09ICcuJykgewogICAgICAgICAgICAgICAgc3RyaW5nICs9ICcuJzsKICAgICAgICAgICAgICAgIHdoaWxlIChuZXh0KCkgJiYgY2ggPj0gJzAnICYmIGNoIDw9ICc5JykgewogICAgICAgICAgICAgICAgICAgIHN0cmluZyArPSBjaDsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAoY2ggPT09ICdlJyB8fCBjaCA9PT0gJ0UnKSB7CiAgICAgICAgICAgICAgICBzdHJpbmcgKz0gY2g7CiAgICAgICAgICAgICAgICBuZXh0KCk7CiAgICAgICAgICAgICAgICBpZiAoY2ggPT09ICctJyB8fCBjaCA9PT0gJysnKSB7CiAgICAgICAgICAgICAgICAgICAgc3RyaW5nICs9IGNoOwogICAgICAgICAgICAgICAgICAgIG5leHQoKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIHdoaWxlIChjaCA+PSAnMCcgJiYgY2ggPD0gJzknKSB7CiAgICAgICAgICAgICAgICAgICAgc3RyaW5nICs9IGNoOwogICAgICAgICAgICAgICAgICAgIG5leHQoKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICBudW1iZXIgPSArc3RyaW5nOwogICAgICAgICAgICBpZiAoaXNOYU4obnVtYmVyKSkgewogICAgICAgICAgICAgICAgZXJyb3IoIkJhZCBudW1iZXIiKTsKICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgIHJldHVybiBudW1iZXI7CiAgICAgICAgICAgIH0KICAgICAgICB9LAoKICAgICAgICBzdHJpbmcgPSBmdW5jdGlvbiAoKSB7CgogICAgICAgICAgICB2YXIgaGV4LAogICAgICAgICAgICAgICAgaSwKICAgICAgICAgICAgICAgIHN0cmluZyA9ICcnLAogICAgICAgICAgICAgICAgdWZmZmY7CgogICAgICAgICAgICBpZiAoY2ggPT09ICciJykgewogICAgICAgICAgICAgICAgd2hpbGUgKG5leHQoKSkgewogICAgICAgICAgICAgICAgICAgIGlmIChjaCA9PT0gJyInKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIG5leHQoKTsKICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHN0cmluZzsKICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKGNoID09PSAnXFwnKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIG5leHQoKTsKICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGNoID09PSAndScpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVmZmZmID0gMDsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvciAoaSA9IDA7IGkgPCA0OyBpICs9IDEpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoZXggPSBwYXJzZUludChuZXh0KCksIDE2KTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoIWlzRmluaXRlKGhleCkpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVmZmZmID0gdWZmZmYgKiAxNiArIGhleDsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0cmluZyArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKHVmZmZmKTsKICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIGlmICh0eXBlb2YgZXNjYXBlZVtjaF0gPT09ICdzdHJpbmcnKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJpbmcgKz0gZXNjYXBlZVtjaF07CiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoY2ggPT0gIlxuIiB8fCBjaCA9PSAiXHIiKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgICAgIHN0cmluZyArPSBjaDsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgZXJyb3IoIkJhZCBzdHJpbmciKTsKICAgICAgICB9LAoKICAgICAgICB3aGl0ZSA9IGZ1bmN0aW9uICgpIHsKCiAgICAgICAgICAgIHdoaWxlIChjaCAmJiBjaCA8PSAnICcpIHsKICAgICAgICAgICAgICAgIG5leHQoKTsKICAgICAgICAgICAgfQogICAgICAgIH0sCgogICAgICAgIHdvcmQgPSBmdW5jdGlvbiAoKSB7CgogICAgICAgICAgICBzd2l0Y2ggKGNoKSB7CiAgICAgICAgICAgIGNhc2UgJ3QnOgogICAgICAgICAgICAgICAgbmV4dCgndCcpOwogICAgICAgICAgICAgICAgbmV4dCgncicpOwogICAgICAgICAgICAgICAgbmV4dCgndScpOwogICAgICAgICAgICAgICAgbmV4dCgnZScpOwogICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7CiAgICAgICAgICAgIGNhc2UgJ2YnOgogICAgICAgICAgICAgICAgbmV4dCgnZicpOwogICAgICAgICAgICAgICAgbmV4dCgnYScpOwogICAgICAgICAgICAgICAgbmV4dCgnbCcpOwogICAgICAgICAgICAgICAgbmV4dCgncycpOwogICAgICAgICAgICAgICAgbmV4dCgnZScpOwogICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOwogICAgICAgICAgICBjYXNlICduJzoKICAgICAgICAgICAgICAgIG5leHQoJ24nKTsKICAgICAgICAgICAgICAgIG5leHQoJ3UnKTsKICAgICAgICAgICAgICAgIG5leHQoJ2wnKTsKICAgICAgICAgICAgICAgIG5leHQoJ2wnKTsKICAgICAgICAgICAgICAgIHJldHVybiBudWxsOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGVycm9yKCJVbmV4cGVjdGVkICciICsgY2ggKyAiJyIpOwogICAgICAgIH0sCgogICAgICAgIHZhbHVlLCAgLy8gUGxhY2UgaG9sZGVyIGZvciB0aGUgdmFsdWUgZnVuY3Rpb24uCgogICAgICAgIGFycmF5ID0gZnVuY3Rpb24gKCkgewoKICAgICAgICAgICAgdmFyIGFycmF5ID0gW107CgogICAgICAgICAgICBpZiAoY2ggPT09ICdbJykgewogICAgICAgICAgICAgICAgbmV4dCgnWycpOwogICAgICAgICAgICAgICAgd2hpdGUoKTsKICAgICAgICAgICAgICAgIGlmIChjaCA9PT0gJ10nKSB7CiAgICAgICAgICAgICAgICAgICAgbmV4dCgnXScpOwogICAgICAgICAgICAgICAgICAgIHJldHVybiBhcnJheTsgICAvLyBlbXB0eSBhcnJheQogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgd2hpbGUgKGNoKSB7CiAgICAgICAgICAgICAgICAgICAgYXJyYXkucHVzaCh2YWx1ZSgpKTsKICAgICAgICAgICAgICAgICAgICB3aGl0ZSgpOwogICAgICAgICAgICAgICAgICAgIGlmIChjaCA9PT0gJ10nKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIG5leHQoJ10nKTsKICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGFycmF5OwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICBuZXh0KCcsJyk7CiAgICAgICAgICAgICAgICAgICAgd2hpdGUoKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICBlcnJvcigiQmFkIGFycmF5Iik7CiAgICAgICAgfSwKCiAgICAgICAgb2JqZWN0ID0gZnVuY3Rpb24gKCkgewoKICAgICAgICAgICAgdmFyIGtleSwKICAgICAgICAgICAgICAgIG9iamVjdCA9IHt9OwoKICAgICAgICAgICAgaWYgKGNoID09PSAneycpIHsKICAgICAgICAgICAgICAgIG5leHQoJ3snKTsKICAgICAgICAgICAgICAgIHdoaXRlKCk7CiAgICAgICAgICAgICAgICBpZiAoY2ggPT09ICd9JykgewogICAgICAgICAgICAgICAgICAgIG5leHQoJ30nKTsKICAgICAgICAgICAgICAgICAgICByZXR1cm4gb2JqZWN0OyAgIC8vIGVtcHR5IG9iamVjdAogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgd2hpbGUgKGNoKSB7CiAgICAgICAgICAgICAgICAgICAga2V5ID0gc3RyaW5nKCk7CiAgICAgICAgICAgICAgICAgICAgd2hpdGUoKTsKICAgICAgICAgICAgICAgICAgICBuZXh0KCc6Jyk7CiAgICAgICAgICAgICAgICAgICAgaWYgKE9iamVjdC5oYXNPd25Qcm9wZXJ0eS5jYWxsKG9iamVjdCwga2V5KSkgewogICAgICAgICAgICAgICAgICAgICAgICBlcnJvcignRHVwbGljYXRlIGtleSAiJyArIGtleSArICciJyk7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgIG9iamVjdFtrZXldID0gdmFsdWUoKTsKICAgICAgICAgICAgICAgICAgICB3aGl0ZSgpOwogICAgICAgICAgICAgICAgICAgIGlmIChjaCA9PT0gJ30nKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIG5leHQoJ30nKTsKICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG9iamVjdDsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgbmV4dCgnLCcpOwogICAgICAgICAgICAgICAgICAgIHdoaXRlKCk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgZXJyb3IoIkJhZCBvYmplY3QiKTsKICAgICAgICB9OwoKICAgIHZhbHVlID0gZnVuY3Rpb24gKCkgewoKICAgICAgICB3aGl0ZSgpOwogICAgICAgIHN3aXRjaCAoY2gpIHsKICAgICAgICBjYXNlICd7JzoKICAgICAgICAgICAgcmV0dXJuIG9iamVjdCgpOwogICAgICAgIGNhc2UgJ1snOgogICAgICAgICAgICByZXR1cm4gYXJyYXkoKTsKICAgICAgICBjYXNlICciJzoKICAgICAgICAgICAgcmV0dXJuIHN0cmluZygpOwogICAgICAgIGNhc2UgJy0nOgogICAgICAgICAgICByZXR1cm4gbnVtYmVyKCk7CiAgICAgICAgZGVmYXVsdDoKICAgICAgICAgICAgcmV0dXJuIGNoID49ICcwJyAmJiBjaCA8PSAnOScgPyBudW1iZXIoKSA6IHdvcmQoKTsKICAgICAgICB9CiAgICB9OwoKICAgIHJldHVybiBmdW5jdGlvbiAoc291cmNlLCByZXZpdmVyKSB7CiAgICAgICAgdmFyIHJlc3VsdDsKCiAgICAgICAgdGV4dCA9IHNvdXJjZTsKICAgICAgICBhdCA9IDA7CiAgICAgICAgY2ggPSAnICc7CiAgICAgICAgcmVzdWx0ID0gdmFsdWUoKTsKICAgICAgICB3aGl0ZSgpOwogICAgICAgIGlmIChjaCkgewogICAgICAgICAgICBlcnJvcigiU3ludGF4IGVycm9yIik7CiAgICAgICAgfQoKICAgICAgICByZXR1cm4gdHlwZW9mIHJldml2ZXIgPT09ICdmdW5jdGlvbicgPyBmdW5jdGlvbiB3YWxrKGhvbGRlciwga2V5KSB7CiAgICAgICAgICAgIHZhciBrLCB2LCB2YWx1ZSA9IGhvbGRlcltrZXldOwogICAgICAgICAgICBpZiAodmFsdWUgJiYgdHlwZW9mIHZhbHVlID09PSAnb2JqZWN0JykgewogICAgICAgICAgICAgICAgZm9yIChrIGluIHZhbHVlKSB7CiAgICAgICAgICAgICAgICAgICAgaWYgKE9iamVjdC5oYXNPd25Qcm9wZXJ0eS5jYWxsKHZhbHVlLCBrKSkgewogICAgICAgICAgICAgICAgICAgICAgICB2ID0gd2Fsayh2YWx1ZSwgayk7CiAgICAgICAgICAgICAgICAgICAgICAgIGlmICh2ICE9PSB1bmRlZmluZWQpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlW2tdID0gdjsKICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlbGV0ZSB2YWx1ZVtrXTsKICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gcmV2aXZlci5jYWxsKGhvbGRlciwga2V5LCB2YWx1ZSk7CiAgICAgICAgfSh7Jyc6IHJlc3VsdH0sICcnKSA6IHJlc3VsdDsKICAgIH07Cn0pOwoKYWNlLmRlZmluZSgiYWNlL21vZGUvanNvbl93b3JrZXIiLFtdLCBmdW5jdGlvbihyZXF1aXJlLCBleHBvcnRzLCBtb2R1bGUpIHsKInVzZSBzdHJpY3QiOwoKdmFyIG9vcCA9IHJlcXVpcmUoIi4uL2xpYi9vb3AiKTsKdmFyIE1pcnJvciA9IHJlcXVpcmUoIi4uL3dvcmtlci9taXJyb3IiKS5NaXJyb3I7CnZhciBwYXJzZSA9IHJlcXVpcmUoIi4vanNvbi9qc29uX3BhcnNlIik7Cgp2YXIgSnNvbldvcmtlciA9IGV4cG9ydHMuSnNvbldvcmtlciA9IGZ1bmN0aW9uKHNlbmRlcikgewogICAgTWlycm9yLmNhbGwodGhpcywgc2VuZGVyKTsKICAgIHRoaXMuc2V0VGltZW91dCgyMDApOwp9OwoKb29wLmluaGVyaXRzKEpzb25Xb3JrZXIsIE1pcnJvcik7CgooZnVuY3Rpb24oKSB7CgogICAgdGhpcy5vblVwZGF0ZSA9IGZ1bmN0aW9uKCkgewogICAgICAgIHZhciB2YWx1ZSA9IHRoaXMuZG9jLmdldFZhbHVlKCk7CiAgICAgICAgdmFyIGVycm9ycyA9IFtdOwogICAgICAgIHRyeSB7CiAgICAgICAgICAgIGlmICh2YWx1ZSkKICAgICAgICAgICAgICAgIHBhcnNlKHZhbHVlKTsKICAgICAgICB9IGNhdGNoIChlKSB7CiAgICAgICAgICAgIHZhciBwb3MgPSB0aGlzLmRvYy5pbmRleFRvUG9zaXRpb24oZS5hdC0xKTsKICAgICAgICAgICAgZXJyb3JzLnB1c2goewogICAgICAgICAgICAgICAgcm93OiBwb3Mucm93LAogICAgICAgICAgICAgICAgY29sdW1uOiBwb3MuY29sdW1uLAogICAgICAgICAgICAgICAgdGV4dDogZS5tZXNzYWdlLAogICAgICAgICAgICAgICAgdHlwZTogImVycm9yIgogICAgICAgICAgICB9KTsKICAgICAgICB9CiAgICAgICAgdGhpcy5zZW5kZXIuZW1pdCgiYW5ub3RhdGUiLCBlcnJvcnMpOwogICAgfTsKCn0pLmNhbGwoSnNvbldvcmtlci5wcm90b3R5cGUpOwoKfSk7Cg==';
|
|
|
|
/***/ }),
|
|
|
|
/***/ 7907:
|
|
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
|
|
|
"use strict";
|
|
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
/* harmony export */ "m0": function() { return /* binding */ setLanguage; },
|
|
/* harmony export */ "cC": function() { return /* binding */ setLanguages; },
|
|
/* harmony export */ "Iu": function() { return /* binding */ translate; }
|
|
/* harmony export */ });
|
|
/* harmony import */ var _polyfills__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(4987);
|
|
/* harmony import */ var _polyfills__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_polyfills__WEBPACK_IMPORTED_MODULE_0__);
|
|
|
|
/* eslint-disable no-template-curly-in-string */
|
|
|
|
|
|
var _locales = ['en', 'pt-BR', 'zh-CN', 'tr', 'ja', 'fr-FR', 'de'];
|
|
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)',
|
|
cannotParseFieldError: 'Cannot parse field into JSON',
|
|
cannotParseValueError: 'Cannot parse value into JSON',
|
|
collapseAll: 'Collapse all fields',
|
|
compactTitle: 'Compact JSON data, remove all whitespaces (Ctrl+Shift+\\)',
|
|
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',
|
|
empty: 'empty',
|
|
expandAll: 'Expand all fields',
|
|
expandTitle: 'Click to expand/collapse this field (Ctrl+E). \n' + 'Ctrl+Click to expand/collapse including all childs.',
|
|
formatTitle: 'Format JSON data, with proper indentation and line feeds (Ctrl+\\)',
|
|
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)',
|
|
repairTitle: 'Repair JSON: fix quotes and escape characters, remove comments and JSONP notation, turn JavaScript objects into JSON.',
|
|
searchTitle: 'Search fields and values',
|
|
searchNextResultTitle: 'Next result (Enter)',
|
|
searchPreviousResultTitle: 'Previous result (Shift + Enter)',
|
|
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.',
|
|
modeEditorTitle: 'Switch Editor Mode',
|
|
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',
|
|
containsInvalidProperties: 'Contains invalid properties',
|
|
containsInvalidItems: 'Contains invalid items'
|
|
},
|
|
'zh-CN': {
|
|
array: '数组',
|
|
auto: '自动',
|
|
appendText: '追加',
|
|
appendTitle: '在此字段后追加一个类型为“auto”的新字段 (Ctrl+Shift+Ins)',
|
|
appendSubmenuTitle: '选择要追加的字段类型',
|
|
appendTitleAuto: '追加类型为“auto”的新字段 (Ctrl+Shift+Ins)',
|
|
ascending: '升序',
|
|
ascendingTitle: '升序排列${type}的子节点',
|
|
actionsMenu: '点击打开动作菜单(Ctrl+M)',
|
|
cannotParseFieldError: '无法将字段解析为JSON',
|
|
cannotParseValueError: '无法将值解析为JSON',
|
|
collapseAll: '缩进所有字段',
|
|
compactTitle: '压缩JSON数据,删除所有空格 (Ctrl+Shift+\\)',
|
|
descending: '降序',
|
|
descendingTitle: '降序排列${type}的子节点',
|
|
drag: '拖拽移动该节点(Alt+Shift+Arrows)',
|
|
duplicateKey: '重复键',
|
|
duplicateText: '复制',
|
|
duplicateTitle: '复制选中字段(Ctrl+D)',
|
|
duplicateField: '复制该字段(Ctrl+D)',
|
|
duplicateFieldError: '重复的字段名称',
|
|
empty: '清空',
|
|
expandAll: '展开所有字段',
|
|
expandTitle: '点击 展开/收缩 该字段(Ctrl+E). \n' + 'Ctrl+Click 展开/收缩 包含所有子节点.',
|
|
formatTitle: '使用适当的缩进和换行符格式化JSON数据 (Ctrl+\\)',
|
|
insert: '插入',
|
|
insertTitle: '在此字段前插入类型为“auto”的新字段 (Ctrl+Ins)',
|
|
insertSub: '选择要插入的字段类型',
|
|
object: '对象',
|
|
ok: 'Ok',
|
|
redo: '重做 (Ctrl+Shift+Z)',
|
|
removeText: '移除',
|
|
removeTitle: '移除选中字段 (Ctrl+Del)',
|
|
removeField: '移除该字段 (Ctrl+Del)',
|
|
repairTitle: '修复JSON:修复引号和转义符,删除注释和JSONP表示法,将JavaScript对象转换为JSON。',
|
|
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": '缺省',
|
|
containsInvalidProperties: '包含无效的属性',
|
|
containsInvalidItems: '包含无效项目'
|
|
},
|
|
'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)',
|
|
cannotParseFieldError: 'Não é possível analisar o campo no JSON',
|
|
cannotParseValueError: 'Não é possível analisar o valor em JSON',
|
|
collapseAll: 'Fechar todos campos',
|
|
compactTitle: 'Dados JSON compactos, remova todos os espaços em branco (Ctrl+Shift+\\)',
|
|
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',
|
|
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.',
|
|
formatTitle: 'Formate dados JSON, com recuo e feeds de linha adequados (Ctrl+\\)',
|
|
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)',
|
|
repairTitle: 'Repare JSON: corrija aspas e caracteres de escape, remova comentários e notação JSONP, transforme objetos JavaScript em JSON.',
|
|
selectNode: 'Selecione um nódulo...',
|
|
showAll: 'mostrar todos',
|
|
showMore: 'mostrar mais',
|
|
showMoreStatus: 'exibindo ${visibleChilds} de ${totalChilds} itens.',
|
|
sort: 'Organizar',
|
|
sortTitle: 'Organizar os filhos deste ${type}',
|
|
sortTitleShort: 'Organizar os filhos',
|
|
sortFieldLabel: 'Campo:',
|
|
sortDirectionLabel: 'Direção:',
|
|
sortFieldTitle: 'Selecione um campo filho pelo qual ordenar o array ou objeto',
|
|
sortAscending: 'Ascendente',
|
|
sortAscendingTitle: 'Ordenar o campo selecionado por ordem ascendente',
|
|
sortDescending: 'Descendente',
|
|
sortDescendingTitle: 'Ordenar o campo selecionado por ordem descendente',
|
|
string: 'Texto',
|
|
transform: 'Transformar',
|
|
transformTitle: 'Filtrar, ordenar ou transformar os filhos deste ${type}',
|
|
transformTitleShort: 'Filtrar, ordenar ou transformar conteúdos',
|
|
transformQueryTitle: 'Insira uma expressão JMESPath',
|
|
transformWizardLabel: 'Assistente',
|
|
transformWizardFilter: 'Filtro',
|
|
transformWizardSortBy: 'Ordenar por',
|
|
transformWizardSelectFields: 'Selecionar campos',
|
|
transformQueryLabel: 'Expressão',
|
|
transformPreviewLabel: 'Visualizar',
|
|
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',
|
|
containsInvalidProperties: 'Contém propriedades inválidas',
|
|
containsInvalidItems: 'Contém itens inválidos'
|
|
},
|
|
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',
|
|
containsInvalidProperties: 'Geçersiz özellikler içeriyor',
|
|
containsInvalidItems: 'Geçersiz öğeler içeriyor'
|
|
},
|
|
ja: {
|
|
array: '配列',
|
|
auto: 'オート',
|
|
appendText: '追加',
|
|
appendTitle: '次のフィールドに"オート"のフィールドを追加 (Ctrl+Shift+Ins)',
|
|
appendSubmenuTitle: '追加するフィールドの型を選択してください',
|
|
appendTitleAuto: '"オート"のフィールドを追加 (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: '選択中のフィールドの前に新しいフィールドを挿入 (Ctrl+Ins)',
|
|
insertSub: '挿入するフィールドの型を選択',
|
|
object: 'オブジェクト',
|
|
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 で 新規ウィンドウでURLを開く',
|
|
undo: '元に戻す (Ctrl+Z)',
|
|
validationCannotMove: '子要素に移動できません ',
|
|
autoType: 'オート: ' + 'フィールドの型は値から自動的に決定されます。 ' + '(文字列・数値・ブール・null)',
|
|
objectType: 'オブジェクト: ' + 'オブジェクトは順序が決まっていないキーと値のペア組み合わせです。',
|
|
arrayType: '配列: ' + '配列は順序が決まっている値の集合体です。',
|
|
stringType: '文字列: ' + 'フィールド型は値から決定されませんが、' + '常に文字列として返されます。',
|
|
modeCodeText: 'コードモード',
|
|
modeCodeTitle: 'ハイライトモードに切り替え',
|
|
modeFormText: 'フォームモード',
|
|
modeFormTitle: 'フォームモードに切り替え',
|
|
modeTextText: 'テキストモード',
|
|
modeTextTitle: 'テキストモードに切り替え',
|
|
modeTreeText: 'ツリーモード',
|
|
modeTreeTitle: 'ツリーモードに切り替え',
|
|
modeViewText: 'ビューモード',
|
|
modeViewTitle: 'ビューモードに切り替え',
|
|
modePreviewText: 'プレビュー',
|
|
modePreviewTitle: 'プレビューに切り替え',
|
|
examples: '例',
|
|
"default": 'デフォルト',
|
|
containsInvalidProperties: '無効なプロパティが含まれています',
|
|
containsInvalidItems: '無効なアイテムが含まれています'
|
|
},
|
|
'fr-FR': {
|
|
array: 'Liste',
|
|
auto: 'Auto',
|
|
appendText: 'Ajouter',
|
|
appendTitle: 'Ajouter un champ de type \'auto\' après ce champ (Ctrl+Shift+Ins)',
|
|
appendSubmenuTitle: 'Sélectionner le type du champ à ajouter',
|
|
appendTitleAuto: 'Ajouter un champ de type \'auto\' (Ctrl+Shift+Ins)',
|
|
ascending: 'Ascendant',
|
|
ascendingTitle: 'Trier les enfants de ce ${type} par ordre ascendant',
|
|
actionsMenu: 'Ouvrir le menu des actions (Ctrl+M)',
|
|
collapseAll: 'Regrouper',
|
|
descending: 'Descendant',
|
|
descendingTitle: 'Trier les enfants de ce ${type} par ordre descendant',
|
|
drag: 'Déplacer (Alt+Shift+Arrows)',
|
|
duplicateKey: 'Dupliquer la clé',
|
|
duplicateText: 'Dupliquer',
|
|
duplicateTitle: 'Dupliquer les champs sélectionnés (Ctrl+D)',
|
|
duplicateField: 'Dupliquer ce champ (Ctrl+D)',
|
|
duplicateFieldError: 'Dupliquer le nom de champ',
|
|
cannotParseFieldError: 'Champ impossible à parser en JSON',
|
|
cannotParseValueError: 'Valeur impossible à parser en JSON',
|
|
empty: 'vide',
|
|
expandAll: 'Étendre',
|
|
expandTitle: 'Étendre/regrouper ce champ (Ctrl+E). \n' + 'Ctrl+Click pour étendre/regrouper avec tous les champs.',
|
|
insert: 'Insérer',
|
|
insertTitle: 'Insérer un champ de type \'auto\' avant ce champ (Ctrl+Ins)',
|
|
insertSub: 'Sélectionner le type de champ à insérer',
|
|
object: 'Objet',
|
|
ok: 'Ok',
|
|
redo: 'Rejouer (Ctrl+Shift+Z)',
|
|
removeText: 'Supprimer',
|
|
removeTitle: 'Supprimer les champs sélectionnés (Ctrl+Del)',
|
|
removeField: 'Supprimer ce champ (Ctrl+Del)',
|
|
searchTitle: 'Rechercher champs et valeurs',
|
|
searchNextResultTitle: 'Résultat suivant (Enter)',
|
|
searchPreviousResultTitle: 'Résultat précédent (Shift + Enter)',
|
|
selectNode: 'Sélectionner un nœud...',
|
|
showAll: 'voir tout',
|
|
showMore: 'voir plus',
|
|
showMoreStatus: '${visibleChilds} éléments affichés de ${totalChilds}.',
|
|
sort: 'Trier',
|
|
sortTitle: 'Trier les champs de ce ${type}',
|
|
sortTitleShort: 'Trier',
|
|
sortFieldLabel: 'Champ:',
|
|
sortDirectionLabel: 'Direction:',
|
|
sortFieldTitle: 'Sélectionner les champs permettant de trier les listes et objet',
|
|
sortAscending: 'Ascendant',
|
|
sortAscendingTitle: 'Trier les champs sélectionnés par ordre ascendant',
|
|
sortDescending: 'Descendant',
|
|
sortDescendingTitle: 'Trier les champs sélectionnés par ordre descendant',
|
|
string: 'Chaîne',
|
|
transform: 'Transformer',
|
|
transformTitle: 'Filtrer, trier, or transformer les enfants de ce ${type}',
|
|
transformTitleShort: 'Filtrer, trier ou transformer le contenu',
|
|
extract: 'Extraire',
|
|
extractTitle: 'Extraire ce ${type}',
|
|
transformQueryTitle: 'Saisir une requête JMESPath',
|
|
transformWizardLabel: 'Assistant',
|
|
transformWizardFilter: 'Filtrer',
|
|
transformWizardSortBy: 'Trier par',
|
|
transformWizardSelectFields: 'Sélectionner les champs',
|
|
transformQueryLabel: 'Requête',
|
|
transformPreviewLabel: 'Prévisualisation',
|
|
type: 'Type',
|
|
typeTitle: 'Changer le type de ce champ',
|
|
openUrl: 'Ctrl+Click ou Ctrl+Enter pour ouvrir l\'url dans une autre fenêtre',
|
|
undo: 'Annuler la dernière action (Ctrl+Z)',
|
|
validationCannotMove: 'Cannot move a field into a child of itself',
|
|
autoType: 'Champe de type "auto". ' + 'Ce type de champ est automatiquement déterminé en fonction de la valeur ' + 'et peut être de type "chaîne", "nombre", "booléen" ou null.',
|
|
objectType: 'Champ de type "objet". ' + 'Un objet contient un ensemble non ordonné de paires clé/valeur.',
|
|
arrayType: 'Champ de type "liste". ' + 'Une liste contient une collection ordonnée de valeurs.',
|
|
stringType: 'Champ de type "chaîne". ' + 'Ce type de champ n\'est pas déterminé en fonction de la valeur, ' + 'mais retourne systématiquement une chaîne de caractères.',
|
|
modeEditorTitle: 'Changer mode d\'édition',
|
|
modeCodeText: 'Code',
|
|
modeCodeTitle: 'Activer surlignage code',
|
|
modeFormText: 'Formulaire',
|
|
modeFormTitle: 'Activer formulaire',
|
|
modeTextText: 'Texte',
|
|
modeTextTitle: 'Activer éditeur texte',
|
|
modeTreeText: 'Arbre',
|
|
modeTreeTitle: 'Activer éditeur arbre',
|
|
modeViewText: 'Lecture seule',
|
|
modeViewTitle: 'Activer vue arbre',
|
|
modePreviewText: 'Prévisualisation',
|
|
modePreviewTitle: 'Activer mode prévisualiser',
|
|
examples: 'Exemples',
|
|
"default": 'Défaut',
|
|
containsInvalidProperties: 'Contient des propriétés non valides',
|
|
containsInvalidItems: 'Contient des éléments invalides'
|
|
},
|
|
de: {
|
|
array: 'Auflistung',
|
|
auto: 'Auto',
|
|
appendText: 'anhängen',
|
|
appendTitle: 'Fügen Sie nach diesem Feld ein neues Feld mit dem Typ \'auto\' ein (Strg+Umschalt+Ein)',
|
|
appendSubmenuTitle: 'Wählen Sie den Typ des neuen Feldes',
|
|
appendTitleAuto: 'Ein neues Feld vom Typ \'auto\' hinzufügen (Strg+Umschalt+Ein)',
|
|
ascending: 'Aufsteigend',
|
|
ascendingTitle: 'Sortieren Sie die Elemente dieses ${type} in aufsteigender Reihenfolge',
|
|
actionsMenu: 'Klicken Sie zum Öffnen des Aktionsmenüs (Strg+M)',
|
|
cannotParseFieldError: 'Feld kann nicht in JSON geparst werden',
|
|
cannotParseValueError: 'Wert kann nicht in JSON geparst werden',
|
|
collapseAll: 'Alle Felder zuklappen',
|
|
compactTitle: 'JSON-Daten verdichten, alle Leerzeichen entfernen (Strg+Umschalt+\\)',
|
|
descending: 'Absteigend',
|
|
descendingTitle: 'Sortieren Sie die Elemente dieses ${type} in absteigender Reihenfolge',
|
|
drag: 'Ziehen, um dieses Feld zu verschieben (Alt+Umschalt+Pfeile)',
|
|
duplicateKey: 'Doppelter Schlüssel',
|
|
duplicateText: 'Duplikat',
|
|
duplicateTitle: 'Ausgewählte Felder duplizieren (Strg+D)',
|
|
duplicateField: 'Dieses Feld duplizieren (Strg+D)',
|
|
duplicateFieldError: 'Doppelter Feldname',
|
|
empty: 'leer',
|
|
expandAll: 'Alle Felder anzeigen',
|
|
expandTitle: 'Klicken Sie, um dieses Feld zu erweitern/zu kollabieren (Strg+E). \nStrg+Klicken Sie, um dieses Feld einschließlich aller Elemente zu erweitern/zu kollabieren.',
|
|
formatTitle: 'JSON-Daten mit korrekter Einrückung und Zeilenvorschüben formatieren (Strg+\\)',
|
|
insert: 'einfügen',
|
|
insertTitle: 'Fügen Sie vor diesem Feld ein neues Feld mit dem Typ \'auto\' ein (Strg+Einfg)',
|
|
insertSub: 'Wählen Sie den Typ des neuen Feldes',
|
|
object: 'Objekt',
|
|
ok: 'Ok',
|
|
redo: 'Wiederholen (Strg+Umschalt+Z)',
|
|
removeText: 'entfernen',
|
|
removeTitle: 'Ausgewählte Felder entfernen (Strg+Entf)',
|
|
removeField: 'Dieses Feld entfernen (Strg+Entf)',
|
|
repairTitle: 'JSON reparieren: Anführungszeichen und Escape-Zeichen korrigieren, Kommentare und JSONP-Notation entfernen, JavaScript-Objekte in JSON umwandeln.',
|
|
searchTitle: 'Suchfelder und Werte',
|
|
searchNextResultTitle: 'Nächstes Ergebnis (Enter)',
|
|
searchPreviousResultTitle: 'Vorheriges Ergebnis (Umschalt + Eingabe)',
|
|
selectNode: 'Wählen Sie einen Knoten aus...',
|
|
showAll: 'alle anzeigen',
|
|
showMore: 'mehr anzeigen',
|
|
showMoreStatus: 'Anzeige von ${visibleChilds} von ${totalChilds}-Elementen.',
|
|
sort: 'Sortieren',
|
|
sortTitle: 'Sortieren Sie die Elemente dieses ${type}',
|
|
sortTitleShort: 'Inhalt sortieren',
|
|
sortFieldLabel: 'Feld:',
|
|
sortDirectionLabel: 'Richtung:',
|
|
sortFieldTitle: 'Wählen Sie das verschachtelte Feld, nach dem das Array oder Objekt sortiert werden soll.',
|
|
sortAscending: 'Aufsteigend',
|
|
sortAscendingTitle: 'Sortieren Sie das ausgewählte Feld in aufsteigender Reihenfolge',
|
|
sortDescending: 'Absteigend',
|
|
sortDescendingTitle: 'Sortieren Sie das ausgewählte Feld in absteigender Reihenfolge',
|
|
string: 'Zeichenfolge',
|
|
transform: 'Verwandeln',
|
|
transformTitle: 'Die Elemente dieses ${type} filtern, sortieren oder transformieren',
|
|
transformTitleShort: 'Inhalte filtern, sortieren oder transformieren',
|
|
extract: 'Auszug',
|
|
extractTitle: 'Extrahieren Sie diesen ${type}',
|
|
transformQueryTitle: 'Eine JMESPath-Abfrage eingeben',
|
|
transformWizardLabel: 'Zauberer',
|
|
transformWizardFilter: 'Filter',
|
|
transformWizardSortBy: 'Sortieren nach',
|
|
transformWizardSelectFields: 'Felder auswählen',
|
|
transformQueryLabel: 'Anfrage',
|
|
transformPreviewLabel: 'Vorschau',
|
|
type: 'Geben Sie ein.',
|
|
typeTitle: 'Ändern Sie den Typ dieses Feldes',
|
|
openUrl: 'Strg+Klicken oder Strg+Eingabe, um die URL in einem neuen Fenster zu öffnen',
|
|
undo: 'Letzte Aktion rückgängig machen (Strg+Z)',
|
|
validationCannotMove: 'Kann ein Feld nicht in ein Kind seiner selbst verschieben',
|
|
autoType: 'Feldtyp "auto". Der Feldtyp wird automatisch aus dem Wert bestimmt und kann ein String, eine Zahl, boolesch oder null sein.',
|
|
objectType: 'Feldtyp "Objekt". Ein Objekt enthält eine ungeordnete Menge von Schlüssel/Wert-Paaren.',
|
|
arrayType: 'Feldtyp "Array". Ein Array enthält eine geordnete Sammlung von Werten.',
|
|
stringType: 'Feldtyp "Zeichenfolge". Der Feldtyp wird nicht aus dem Wert bestimmt, sondern immer als Zeichenfolge zurückgegeben.',
|
|
modeEditorTitle: 'Editor-Modus umschalten',
|
|
modeCodeText: 'Code',
|
|
modeCodeTitle: 'Umschalten auf Code-Highlighter',
|
|
modeFormText: 'Formular',
|
|
modeFormTitle: 'Zum Formular-Editor wechseln',
|
|
modeTextText: 'Text',
|
|
modeTextTitle: 'Zum Editor für einfachen Text wechseln',
|
|
modeTreeText: 'Baum',
|
|
modeTreeTitle: 'Zum Baum-Editor wechseln',
|
|
modeViewText: 'Siehe',
|
|
modeViewTitle: 'Zur Baumansicht wechseln',
|
|
modePreviewText: 'Vorschau',
|
|
modePreviewTitle: 'In den Vorschau-Modus wechseln',
|
|
examples: 'Beispiele',
|
|
"default": 'Standardmäßig',
|
|
containsInvalidProperties: 'Enthält ungültige Eigenschaften',
|
|
containsInvalidItems: 'Enthält ungültige Elemente'
|
|
}
|
|
};
|
|
var _defaultLang = 'en';
|
|
var userLang = typeof navigator !== 'undefined' ? navigator.language || navigator.userLanguage : undefined;
|
|
|
|
var _lang = _locales.find(function (l) {
|
|
return l === userLang;
|
|
}) || _defaultLang;
|
|
|
|
function setLanguage(lang) {
|
|
if (!lang) {
|
|
return;
|
|
}
|
|
|
|
var langFound = _locales.find(function (l) {
|
|
return l === lang;
|
|
});
|
|
|
|
if (langFound) {
|
|
_lang = langFound;
|
|
} else {
|
|
console.error('Language not found');
|
|
}
|
|
}
|
|
function setLanguages(languages) {
|
|
if (!languages) {
|
|
return;
|
|
}
|
|
|
|
var _loop = function _loop(language) {
|
|
var langFound = _locales.find(function (l) {
|
|
return l === language;
|
|
});
|
|
|
|
if (!langFound) {
|
|
_locales.push(language);
|
|
}
|
|
|
|
_defs[language] = Object.assign({}, _defs[_defaultLang], _defs[language], languages[language]);
|
|
};
|
|
|
|
for (var language in languages) {
|
|
_loop(language);
|
|
}
|
|
}
|
|
function translate(key, data, lang) {
|
|
if (!lang) {
|
|
lang = _lang;
|
|
}
|
|
|
|
var text = _defs[lang][key] || _defs[_defaultLang][key] || key;
|
|
|
|
if (data) {
|
|
for (var dataKey in data) {
|
|
text = text.replace('${' + dataKey + '}', data[dataKey]);
|
|
}
|
|
}
|
|
|
|
return text;
|
|
}
|
|
|
|
/***/ }),
|
|
|
|
/***/ 6056:
|
|
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
|
|
|
"use strict";
|
|
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
/* harmony export */ "r": function() { return /* binding */ createQuery; },
|
|
/* harmony export */ "J": function() { return /* binding */ executeQuery; }
|
|
/* harmony export */ });
|
|
/* harmony import */ var jmespath__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(5156);
|
|
/* harmony import */ var jmespath__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(jmespath__WEBPACK_IMPORTED_MODULE_0__);
|
|
/* harmony import */ var _util__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(9791);
|
|
|
|
|
|
/**
|
|
* Build a JMESPath query based on query options coming from the wizard
|
|
* @param {JSON} json The JSON document for which to build the query.
|
|
* Used for context information like determining
|
|
* the type of values (string or number)
|
|
* @param {QueryOptions} queryOptions
|
|
* @return {string} Returns a query (as string)
|
|
*/
|
|
|
|
function createQuery(json, queryOptions) {
|
|
var sort = queryOptions.sort,
|
|
filter = queryOptions.filter,
|
|
projection = queryOptions.projection;
|
|
var query = '';
|
|
|
|
if (filter) {
|
|
var examplePath = filter.field !== '@' ? ['0'].concat((0,_util__WEBPACK_IMPORTED_MODULE_1__.parsePath)('.' + filter.field)) : ['0'];
|
|
var exampleValue = (0,_util__WEBPACK_IMPORTED_MODULE_1__.get)(json, examplePath);
|
|
var value1 = typeof exampleValue === 'string' ? filter.value : (0,_util__WEBPACK_IMPORTED_MODULE_1__.parseString)(filter.value);
|
|
query += '[? ' + filter.field + ' ' + filter.relation + ' ' + '`' + JSON.stringify(value1) + '`' + ']';
|
|
} else {
|
|
query += Array.isArray(json) ? '[*]' : '@';
|
|
}
|
|
|
|
if (sort) {
|
|
if (sort.direction === 'desc') {
|
|
query += ' | reverse(sort_by(@, &' + sort.field + '))';
|
|
} else {
|
|
query += ' | sort_by(@, &' + sort.field + ')';
|
|
}
|
|
}
|
|
|
|
if (projection) {
|
|
if (query[query.length - 1] !== ']') {
|
|
query += ' | [*]';
|
|
}
|
|
|
|
if (projection.fields.length === 1) {
|
|
query += '.' + projection.fields[0];
|
|
} else if (projection.fields.length > 1) {
|
|
query += '.{' + projection.fields.map(function (value) {
|
|
var parts = value.split('.');
|
|
var last = parts[parts.length - 1];
|
|
return last + ': ' + value;
|
|
}).join(', ') + '}';
|
|
} else {// values.length === 0
|
|
// ignore
|
|
}
|
|
}
|
|
|
|
return query;
|
|
}
|
|
/**
|
|
* Execute a JMESPath query
|
|
* @param {JSON} json
|
|
* @param {string} query
|
|
* @return {JSON} Returns the transformed JSON
|
|
*/
|
|
|
|
function executeQuery(json, query) {
|
|
return jmespath__WEBPACK_IMPORTED_MODULE_0___default().search(json, query);
|
|
}
|
|
|
|
/***/ }),
|
|
|
|
/***/ 4987:
|
|
/***/ (function() {
|
|
|
|
if (typeof Element !== 'undefined') {
|
|
// Polyfill for array remove
|
|
(function () {
|
|
function polyfill(item) {
|
|
if ('remove' in item) {
|
|
return;
|
|
}
|
|
|
|
Object.defineProperty(item, 'remove', {
|
|
configurable: true,
|
|
enumerable: true,
|
|
writable: true,
|
|
value: function remove() {
|
|
if (this.parentNode !== undefined) {
|
|
this.parentNode.removeChild(this);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
if (typeof window.Element !== 'undefined') {
|
|
polyfill(window.Element.prototype);
|
|
}
|
|
|
|
if (typeof window.CharacterData !== 'undefined') {
|
|
polyfill(window.CharacterData.prototype);
|
|
}
|
|
|
|
if (typeof window.DocumentType !== 'undefined') {
|
|
polyfill(window.DocumentType.prototype);
|
|
}
|
|
})();
|
|
} // simple polyfill for Array.findIndex
|
|
|
|
|
|
if (!Array.prototype.findIndex) {
|
|
// eslint-disable-next-line no-extend-native
|
|
Object.defineProperty(Array.prototype, 'findIndex', {
|
|
value: function value(predicate) {
|
|
for (var i = 0; i < this.length; i++) {
|
|
var element = this[i];
|
|
|
|
if (predicate.call(this, element, i, this)) {
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
},
|
|
configurable: true,
|
|
writable: true
|
|
});
|
|
} // Polyfill for Array.find
|
|
|
|
|
|
if (!Array.prototype.find) {
|
|
// eslint-disable-next-line no-extend-native
|
|
Object.defineProperty(Array.prototype, 'find', {
|
|
value: function value(predicate) {
|
|
var i = this.findIndex(predicate);
|
|
return this[i];
|
|
},
|
|
configurable: true,
|
|
writable: true
|
|
});
|
|
} // Polyfill for String.trim
|
|
|
|
|
|
if (!String.prototype.trim) {
|
|
// eslint-disable-next-line no-extend-native
|
|
String.prototype.trim = function () {
|
|
return this.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
|
|
};
|
|
}
|
|
|
|
/***/ }),
|
|
|
|
/***/ 341:
|
|
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
|
|
|
"use strict";
|
|
// ESM COMPAT FLAG
|
|
__webpack_require__.r(__webpack_exports__);
|
|
|
|
// EXPORTS
|
|
__webpack_require__.d(__webpack_exports__, {
|
|
"previewModeMixins": function() { return /* binding */ previewModeMixins; }
|
|
});
|
|
|
|
// EXTERNAL MODULE: ./node_modules/jsonrepair/lib/cjs/index-commonjs.js
|
|
var index_commonjs = __webpack_require__(8909);
|
|
var index_commonjs_default = /*#__PURE__*/__webpack_require__.n(index_commonjs);
|
|
// EXTERNAL MODULE: ./src/js/constants.js
|
|
var constants = __webpack_require__(4188);
|
|
// EXTERNAL MODULE: ./src/js/ErrorTable.js
|
|
var ErrorTable = __webpack_require__(6436);
|
|
// EXTERNAL MODULE: ./src/js/FocusTracker.js
|
|
var FocusTracker = __webpack_require__(2474);
|
|
;// CONCATENATED MODULE: ./src/js/History.js
|
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
|
|
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
|
|
|
|
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
|
|
|
|
/**
|
|
* Keep track on any history, be able
|
|
* @param {function} onChange
|
|
* @param {function} calculateItemSize
|
|
* @param {number} limit Maximum size of all items in history
|
|
* @constructor
|
|
*/
|
|
var History = /*#__PURE__*/function () {
|
|
function History(onChange, calculateItemSize, limit) {
|
|
_classCallCheck(this, History);
|
|
|
|
this.onChange = onChange;
|
|
|
|
this.calculateItemSize = calculateItemSize || function () {
|
|
return 1;
|
|
};
|
|
|
|
this.limit = limit;
|
|
this.items = [];
|
|
this.index = -1;
|
|
}
|
|
|
|
_createClass(History, [{
|
|
key: "add",
|
|
value: function add(item) {
|
|
// limit number of items in history so that the total size doesn't
|
|
// always keep at least one item in memory
|
|
while (this._calculateHistorySize() > this.limit && this.items.length > 1) {
|
|
this.items.shift();
|
|
this.index--;
|
|
} // cleanup any redo action that are not valid anymore
|
|
|
|
|
|
this.items = this.items.slice(0, this.index + 1);
|
|
this.items.push(item);
|
|
this.index++;
|
|
this.onChange();
|
|
}
|
|
}, {
|
|
key: "_calculateHistorySize",
|
|
value: function _calculateHistorySize() {
|
|
var calculateItemSize = this.calculateItemSize;
|
|
var totalSize = 0;
|
|
this.items.forEach(function (item) {
|
|
totalSize += calculateItemSize(item);
|
|
});
|
|
return totalSize;
|
|
}
|
|
}, {
|
|
key: "undo",
|
|
value: function undo() {
|
|
if (!this.canUndo()) {
|
|
return;
|
|
}
|
|
|
|
this.index--;
|
|
this.onChange();
|
|
return this.items[this.index];
|
|
}
|
|
}, {
|
|
key: "redo",
|
|
value: function redo() {
|
|
if (!this.canRedo()) {
|
|
return;
|
|
}
|
|
|
|
this.index++;
|
|
this.onChange();
|
|
return this.items[this.index];
|
|
}
|
|
}, {
|
|
key: "canUndo",
|
|
value: function canUndo() {
|
|
return this.index > 0;
|
|
}
|
|
}, {
|
|
key: "canRedo",
|
|
value: function canRedo() {
|
|
return this.index < this.items.length - 1;
|
|
}
|
|
}, {
|
|
key: "clear",
|
|
value: function clear() {
|
|
this.items = [];
|
|
this.index = -1;
|
|
this.onChange();
|
|
}
|
|
}]);
|
|
|
|
return History;
|
|
}();
|
|
// EXTERNAL MODULE: ./src/js/i18n.js
|
|
var i18n = __webpack_require__(7907);
|
|
// EXTERNAL MODULE: ./src/js/jmespathQuery.js
|
|
var jmespathQuery = __webpack_require__(6056);
|
|
// EXTERNAL MODULE: ./src/js/ModeSwitcher.js
|
|
var ModeSwitcher = __webpack_require__(6617);
|
|
// EXTERNAL MODULE: ./src/js/showSortModal.js
|
|
var showSortModal = __webpack_require__(6210);
|
|
// EXTERNAL MODULE: ./src/js/showTransformModal.js + 1 modules
|
|
var showTransformModal = __webpack_require__(2558);
|
|
// EXTERNAL MODULE: ./src/js/textmode.js + 1 modules
|
|
var textmode = __webpack_require__(5956);
|
|
// EXTERNAL MODULE: ./src/js/util.js
|
|
var util = __webpack_require__(9791);
|
|
;// CONCATENATED MODULE: ./src/js/previewmode.js
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var previewmode_textmode = textmode.textModeMixins[0].mixin; // create a mixin with the functions for text mode
|
|
|
|
var previewmode = {};
|
|
/**
|
|
* Create a JSON document preview, suitable for processing of large documents
|
|
* @param {Element} container
|
|
* @param {Object} [options] Object with options. See docs for details.
|
|
* @private
|
|
*/
|
|
|
|
previewmode.create = function (container) {
|
|
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
|
|
if (typeof options.statusBar === 'undefined') {
|
|
options.statusBar = true;
|
|
} // setting default for previewmode
|
|
|
|
|
|
options.mainMenuBar = options.mainMenuBar !== false;
|
|
options.enableSort = options.enableSort !== false;
|
|
options.enableTransform = options.enableTransform !== false;
|
|
options.createQuery = options.createQuery || jmespathQuery/* createQuery */.r;
|
|
options.executeQuery = options.executeQuery || jmespathQuery/* executeQuery */.J;
|
|
this.options = options; // indentation
|
|
|
|
if (typeof options.indentation === 'number') {
|
|
this.indentation = Number(options.indentation);
|
|
} else {
|
|
this.indentation = 2; // number of spaces
|
|
} // language
|
|
|
|
|
|
(0,i18n/* setLanguages */.cC)(this.options.languages);
|
|
(0,i18n/* setLanguage */.m0)(this.options.language); // determine mode
|
|
|
|
this.mode = 'preview';
|
|
var me = this;
|
|
this.container = container;
|
|
this.dom = {};
|
|
this.json = undefined;
|
|
this.text = ''; // TODO: JSON Schema support
|
|
// create a debounced validate function
|
|
|
|
this._debouncedValidate = (0,util.debounce)(this.validate.bind(this), this.DEBOUNCE_INTERVAL);
|
|
this.width = container.clientWidth;
|
|
this.height = container.clientHeight;
|
|
this.frame = document.createElement('div');
|
|
this.frame.className = 'jsoneditor jsoneditor-mode-preview';
|
|
|
|
this.frame.onclick = function (event) {
|
|
// prevent default submit action when the editor is located inside a form
|
|
event.preventDefault();
|
|
}; // setting the FocusTracker on 'this.frame' to track the editor's focus event
|
|
|
|
|
|
var focusTrackerConfig = {
|
|
target: this.frame,
|
|
onFocus: this.options.onFocus || null,
|
|
onBlur: this.options.onBlur || null
|
|
};
|
|
this.frameFocusTracker = new FocusTracker/* FocusTracker */.R(focusTrackerConfig);
|
|
this.content = document.createElement('div');
|
|
this.content.className = 'jsoneditor-outer';
|
|
this.dom.busy = document.createElement('div');
|
|
this.dom.busy.className = 'jsoneditor-busy';
|
|
this.dom.busyContent = document.createElement('span');
|
|
this.dom.busyContent.textContent = 'busy...';
|
|
this.dom.busy.appendChild(this.dom.busyContent);
|
|
this.content.appendChild(this.dom.busy);
|
|
this.dom.previewContent = document.createElement('pre');
|
|
this.dom.previewContent.className = 'jsoneditor-preview';
|
|
this.dom.previewText = document.createTextNode('');
|
|
this.dom.previewContent.appendChild(this.dom.previewText);
|
|
this.content.appendChild(this.dom.previewContent);
|
|
|
|
if (this.options.mainMenuBar) {
|
|
(0,util.addClassName)(this.content, 'has-main-menu-bar'); // create menu
|
|
|
|
this.menu = document.createElement('div');
|
|
this.menu.className = 'jsoneditor-menu';
|
|
this.frame.appendChild(this.menu); // create format button
|
|
|
|
var buttonFormat = document.createElement('button');
|
|
buttonFormat.type = 'button';
|
|
buttonFormat.className = 'jsoneditor-format';
|
|
buttonFormat.title = (0,i18n/* translate */.Iu)('formatTitle');
|
|
this.menu.appendChild(buttonFormat);
|
|
|
|
buttonFormat.onclick = function handleFormat() {
|
|
me.executeWithBusyMessage(function () {
|
|
try {
|
|
me.format();
|
|
} catch (err) {
|
|
me._onError(err);
|
|
}
|
|
}, 'formatting...');
|
|
}; // create compact button
|
|
|
|
|
|
var buttonCompact = document.createElement('button');
|
|
buttonCompact.type = 'button';
|
|
buttonCompact.className = 'jsoneditor-compact';
|
|
buttonCompact.title = (0,i18n/* translate */.Iu)('compactTitle');
|
|
this.menu.appendChild(buttonCompact);
|
|
|
|
buttonCompact.onclick = function handleCompact() {
|
|
me.executeWithBusyMessage(function () {
|
|
try {
|
|
me.compact();
|
|
} catch (err) {
|
|
me._onError(err);
|
|
}
|
|
}, 'compacting...');
|
|
}; // create sort button
|
|
|
|
|
|
if (this.options.enableSort) {
|
|
var _sort = document.createElement('button');
|
|
|
|
_sort.type = 'button';
|
|
_sort.className = 'jsoneditor-sort';
|
|
_sort.title = (0,i18n/* translate */.Iu)('sortTitleShort');
|
|
|
|
_sort.onclick = function () {
|
|
me._showSortModal();
|
|
};
|
|
|
|
this.menu.appendChild(_sort);
|
|
} // create transform button
|
|
|
|
|
|
if (this.options.enableTransform) {
|
|
var transform = document.createElement('button');
|
|
transform.type = 'button';
|
|
transform.title = (0,i18n/* translate */.Iu)('transformTitleShort');
|
|
transform.className = 'jsoneditor-transform';
|
|
|
|
transform.onclick = function () {
|
|
me._showTransformModal();
|
|
};
|
|
|
|
this.dom.transform = transform;
|
|
this.menu.appendChild(transform);
|
|
} // create repair button
|
|
|
|
|
|
var buttonRepair = document.createElement('button');
|
|
buttonRepair.type = 'button';
|
|
buttonRepair.className = 'jsoneditor-repair';
|
|
buttonRepair.title = (0,i18n/* translate */.Iu)('repairTitle');
|
|
this.menu.appendChild(buttonRepair);
|
|
|
|
buttonRepair.onclick = function () {
|
|
if (me.json === undefined) {
|
|
// only repair if we don't have valid JSON
|
|
me.executeWithBusyMessage(function () {
|
|
try {
|
|
me.repair();
|
|
} catch (err) {
|
|
me._onError(err);
|
|
}
|
|
}, 'repairing...');
|
|
}
|
|
}; // create history and undo/redo buttons
|
|
|
|
|
|
if (this.options.history !== false) {
|
|
// default option value is true
|
|
var onHistoryChange = function onHistoryChange() {
|
|
me.dom.undo.disabled = !me.history.canUndo();
|
|
me.dom.redo.disabled = !me.history.canRedo();
|
|
};
|
|
|
|
var calculateItemSize = function calculateItemSize(item) {
|
|
return (// times two to account for the json object
|
|
item.text.length * 2
|
|
);
|
|
};
|
|
|
|
this.history = new History(onHistoryChange, calculateItemSize, constants/* PREVIEW_HISTORY_LIMIT */.oW); // create undo button
|
|
|
|
var undo = document.createElement('button');
|
|
undo.type = 'button';
|
|
undo.className = 'jsoneditor-undo jsoneditor-separator';
|
|
undo.title = (0,i18n/* translate */.Iu)('undo');
|
|
|
|
undo.onclick = function () {
|
|
var action = me.history.undo();
|
|
|
|
if (action) {
|
|
me._applyHistory(action);
|
|
}
|
|
};
|
|
|
|
this.menu.appendChild(undo);
|
|
this.dom.undo = undo; // create redo button
|
|
|
|
var redo = document.createElement('button');
|
|
redo.type = 'button';
|
|
redo.className = 'jsoneditor-redo';
|
|
redo.title = (0,i18n/* translate */.Iu)('redo');
|
|
|
|
redo.onclick = function () {
|
|
var action = me.history.redo();
|
|
|
|
if (action) {
|
|
me._applyHistory(action);
|
|
}
|
|
};
|
|
|
|
this.menu.appendChild(redo);
|
|
this.dom.redo = redo; // force enabling/disabling the undo/redo button
|
|
|
|
this.history.onChange();
|
|
} // create mode box
|
|
|
|
|
|
if (this.options && this.options.modes && this.options.modes.length) {
|
|
this.modeSwitcher = new ModeSwitcher/* ModeSwitcher */.x(this.menu, this.options.modes, this.options.mode, function onSwitch(mode) {
|
|
// switch mode and restore focus
|
|
me.setMode(mode);
|
|
me.modeSwitcher.focus();
|
|
});
|
|
}
|
|
}
|
|
|
|
this.errorTable = new ErrorTable/* ErrorTable */.Q({
|
|
errorTableVisible: true,
|
|
onToggleVisibility: function onToggleVisibility() {
|
|
me.validate();
|
|
},
|
|
onFocusLine: null,
|
|
onChangeHeight: function onChangeHeight(height) {
|
|
// TODO: change CSS to using flex box, remove setting height using JavaScript
|
|
var statusBarHeight = me.dom.statusBar ? me.dom.statusBar.clientHeight : 0;
|
|
var totalHeight = height + statusBarHeight + 1;
|
|
me.content.style.marginBottom = -totalHeight + 'px';
|
|
me.content.style.paddingBottom = totalHeight + 'px';
|
|
}
|
|
});
|
|
this.frame.appendChild(this.content);
|
|
this.frame.appendChild(this.errorTable.getErrorTable());
|
|
this.container.appendChild(this.frame);
|
|
|
|
if (options.statusBar) {
|
|
(0,util.addClassName)(this.content, 'has-status-bar');
|
|
var statusBar = document.createElement('div');
|
|
this.dom.statusBar = statusBar;
|
|
statusBar.className = 'jsoneditor-statusbar';
|
|
this.frame.appendChild(statusBar);
|
|
this.dom.fileSizeInfo = document.createElement('span');
|
|
this.dom.fileSizeInfo.className = 'jsoneditor-size-info';
|
|
this.dom.fileSizeInfo.innerText = '';
|
|
statusBar.appendChild(this.dom.fileSizeInfo);
|
|
this.dom.arrayInfo = document.createElement('span');
|
|
this.dom.arrayInfo.className = 'jsoneditor-size-info';
|
|
this.dom.arrayInfo.innerText = '';
|
|
statusBar.appendChild(this.dom.arrayInfo);
|
|
statusBar.appendChild(this.errorTable.getErrorCounter());
|
|
statusBar.appendChild(this.errorTable.getWarningIcon());
|
|
statusBar.appendChild(this.errorTable.getErrorIcon());
|
|
}
|
|
|
|
this._renderPreview();
|
|
|
|
this.setSchema(this.options.schema, this.options.schemaRefs);
|
|
};
|
|
|
|
previewmode._renderPreview = function () {
|
|
var text = this.getText();
|
|
this.dom.previewText.nodeValue = (0,util.limitCharacters)(text, constants/* MAX_PREVIEW_CHARACTERS */.WF);
|
|
|
|
if (this.dom.fileSizeInfo) {
|
|
this.dom.fileSizeInfo.innerText = 'Size: ' + (0,util.formatSize)(text.length);
|
|
}
|
|
|
|
if (this.dom.arrayInfo) {
|
|
if (Array.isArray(this.json)) {
|
|
this.dom.arrayInfo.innerText = 'Array: ' + this.json.length + ' items';
|
|
} else {
|
|
this.dom.arrayInfo.innerText = '';
|
|
}
|
|
}
|
|
};
|
|
/**
|
|
* Handle a change:
|
|
* - Validate JSON schema
|
|
* - Send a callback to the onChange listener if provided
|
|
* @private
|
|
*/
|
|
|
|
|
|
previewmode._onChange = function () {
|
|
// validate JSON schema (if configured)
|
|
this._debouncedValidate(); // trigger the onChange callback
|
|
|
|
|
|
if (this.options.onChange) {
|
|
try {
|
|
this.options.onChange();
|
|
} catch (err) {
|
|
console.error('Error in onChange callback: ', err);
|
|
}
|
|
} // trigger the onChangeJSON callback
|
|
|
|
|
|
if (this.options.onChangeJSON) {
|
|
try {
|
|
this.options.onChangeJSON(this.get());
|
|
} catch (err) {
|
|
console.error('Error in onChangeJSON callback: ', err);
|
|
}
|
|
} // trigger the onChangeText callback
|
|
|
|
|
|
if (this.options.onChangeText) {
|
|
try {
|
|
this.options.onChangeText(this.getText());
|
|
} catch (err) {
|
|
console.error('Error in onChangeText callback: ', err);
|
|
}
|
|
}
|
|
};
|
|
/**
|
|
* Open a sort modal
|
|
* @private
|
|
*/
|
|
|
|
|
|
previewmode._showSortModal = function () {
|
|
var me = this;
|
|
|
|
function onSort(json, sortedBy) {
|
|
if (Array.isArray(json)) {
|
|
var sortedArray = (0,util.sort)(json, sortedBy.path, sortedBy.direction);
|
|
me.sortedBy = sortedBy;
|
|
|
|
me._setAndFireOnChange(sortedArray);
|
|
}
|
|
|
|
if ((0,util.isObject)(json)) {
|
|
var sortedObject = (0,util.sortObjectKeys)(json, sortedBy.direction);
|
|
me.sortedBy = sortedBy;
|
|
|
|
me._setAndFireOnChange(sortedObject);
|
|
}
|
|
}
|
|
|
|
this.executeWithBusyMessage(function () {
|
|
var container = me.options.modalAnchor || constants/* DEFAULT_MODAL_ANCHOR */.qD;
|
|
var json = me.get();
|
|
|
|
me._renderPreview(); // update array count
|
|
|
|
|
|
(0,showSortModal.showSortModal)(container, json, function (sortedBy) {
|
|
me.executeWithBusyMessage(function () {
|
|
onSort(json, sortedBy);
|
|
}, 'sorting...');
|
|
}, me.sortedBy);
|
|
}, 'parsing...');
|
|
};
|
|
/**
|
|
* Open a transform modal
|
|
* @private
|
|
*/
|
|
|
|
|
|
previewmode._showTransformModal = function () {
|
|
var _this = this;
|
|
|
|
this.executeWithBusyMessage(function () {
|
|
var _this$options = _this.options,
|
|
createQuery = _this$options.createQuery,
|
|
executeQuery = _this$options.executeQuery,
|
|
modalAnchor = _this$options.modalAnchor,
|
|
queryDescription = _this$options.queryDescription;
|
|
|
|
var json = _this.get();
|
|
|
|
_this._renderPreview(); // update array count
|
|
|
|
|
|
(0,showTransformModal.showTransformModal)({
|
|
container: modalAnchor || constants/* DEFAULT_MODAL_ANCHOR */.qD,
|
|
json: json,
|
|
queryDescription: queryDescription,
|
|
// can be undefined
|
|
createQuery: createQuery,
|
|
executeQuery: executeQuery,
|
|
onTransform: function onTransform(query) {
|
|
_this.executeWithBusyMessage(function () {
|
|
var updatedJson = executeQuery(json, query);
|
|
|
|
_this._setAndFireOnChange(updatedJson);
|
|
}, 'transforming...');
|
|
}
|
|
});
|
|
}, 'parsing...');
|
|
};
|
|
/**
|
|
* Destroy the editor. Clean up DOM, event listeners, and web workers.
|
|
*/
|
|
|
|
|
|
previewmode.destroy = function () {
|
|
if (this.frame && this.container && this.frame.parentNode === this.container) {
|
|
this.container.removeChild(this.frame);
|
|
}
|
|
|
|
if (this.modeSwitcher) {
|
|
this.modeSwitcher.destroy();
|
|
this.modeSwitcher = null;
|
|
}
|
|
|
|
this._debouncedValidate = null;
|
|
|
|
if (this.history) {
|
|
this.history.clear();
|
|
this.history = null;
|
|
} // Removing the FocusTracker set to track the editor's focus event
|
|
|
|
|
|
this.frameFocusTracker.destroy();
|
|
};
|
|
/**
|
|
* Compact the code in the text editor
|
|
*/
|
|
|
|
|
|
previewmode.compact = function () {
|
|
var json = this.get();
|
|
var text = JSON.stringify(json); // we know that in this case the json is still the same, so we pass json too
|
|
|
|
this._setTextAndFireOnChange(text, json);
|
|
};
|
|
/**
|
|
* Format the code in the text editor
|
|
*/
|
|
|
|
|
|
previewmode.format = function () {
|
|
var json = this.get();
|
|
var text = JSON.stringify(json, null, this.indentation); // we know that in this case the json is still the same, so we pass json too
|
|
|
|
this._setTextAndFireOnChange(text, json);
|
|
};
|
|
/**
|
|
* Repair the code in the text editor
|
|
*/
|
|
|
|
|
|
previewmode.repair = function () {
|
|
var text = this.getText();
|
|
|
|
try {
|
|
var repairedText = index_commonjs_default()(text);
|
|
|
|
this._setTextAndFireOnChange(repairedText);
|
|
} catch (err) {// repair was not successful, do nothing
|
|
}
|
|
};
|
|
/**
|
|
* Set focus to the editor
|
|
*/
|
|
|
|
|
|
previewmode.focus = function () {
|
|
// we don't really have a place to focus,
|
|
// let's focus on the transform button
|
|
this.dom.transform.focus();
|
|
};
|
|
/**
|
|
* Set json data in the editor
|
|
* @param {*} json
|
|
*/
|
|
|
|
|
|
previewmode.set = function (json) {
|
|
if (this.history) {
|
|
this.history.clear();
|
|
}
|
|
|
|
this._set(json);
|
|
};
|
|
/**
|
|
* Update data. Same as calling `set` in text/code mode.
|
|
* @param {*} json
|
|
*/
|
|
|
|
|
|
previewmode.update = function (json) {
|
|
this._set(json);
|
|
};
|
|
/**
|
|
* Set json data
|
|
* @param {*} json
|
|
*/
|
|
|
|
|
|
previewmode._set = function (json) {
|
|
this.text = undefined;
|
|
this.json = json;
|
|
|
|
this._renderPreview();
|
|
|
|
this._pushHistory(); // validate JSON schema
|
|
|
|
|
|
this._debouncedValidate();
|
|
};
|
|
|
|
previewmode._setAndFireOnChange = function (json) {
|
|
this._set(json);
|
|
|
|
this._onChange();
|
|
};
|
|
/**
|
|
* Get json data
|
|
* @return {*} json
|
|
*/
|
|
|
|
|
|
previewmode.get = function () {
|
|
if (this.json === undefined) {
|
|
var text = this.getText();
|
|
this.json = (0,util.parse)(text); // this can throw an error
|
|
}
|
|
|
|
return this.json;
|
|
};
|
|
/**
|
|
* Get the text contents of the editor
|
|
* @return {String} jsonText
|
|
*/
|
|
|
|
|
|
previewmode.getText = function () {
|
|
if (this.text === undefined) {
|
|
this.text = JSON.stringify(this.json, null, this.indentation);
|
|
|
|
if (this.options.escapeUnicode === true) {
|
|
this.text = (0,util.escapeUnicodeChars)(this.text);
|
|
}
|
|
}
|
|
|
|
return this.text;
|
|
};
|
|
/**
|
|
* Set the text contents of the editor
|
|
* @param {String} jsonText
|
|
*/
|
|
|
|
|
|
previewmode.setText = function (jsonText) {
|
|
if (this.history) {
|
|
this.history.clear();
|
|
}
|
|
|
|
this._setText(jsonText);
|
|
};
|
|
/**
|
|
* Update the text contents
|
|
* @param {string} jsonText
|
|
*/
|
|
|
|
|
|
previewmode.updateText = function (jsonText) {
|
|
// don't update if there are no changes
|
|
if (this.getText() === jsonText) {
|
|
return;
|
|
}
|
|
|
|
this._setText(jsonText);
|
|
};
|
|
/**
|
|
* Set the text contents of the editor
|
|
* @param {string} jsonText
|
|
* @param {*} [json] Optional JSON instance of the text
|
|
* @private
|
|
*/
|
|
|
|
|
|
previewmode._setText = function (jsonText, json) {
|
|
if (this.options.escapeUnicode === true) {
|
|
this.text = (0,util.escapeUnicodeChars)(jsonText);
|
|
} else {
|
|
this.text = jsonText;
|
|
}
|
|
|
|
this.json = json;
|
|
|
|
this._renderPreview();
|
|
|
|
if (this.json === undefined) {
|
|
var me = this;
|
|
this.executeWithBusyMessage(function () {
|
|
try {
|
|
// force parsing the json now, else it will be done in validate without feedback
|
|
me.json = me.get();
|
|
|
|
me._renderPreview();
|
|
|
|
me._pushHistory();
|
|
} catch (err) {// no need to throw an error, validation will show an error
|
|
}
|
|
}, 'parsing...');
|
|
} else {
|
|
this._pushHistory();
|
|
}
|
|
|
|
this._debouncedValidate();
|
|
};
|
|
/**
|
|
* Set text and fire onChange callback
|
|
* @param {string} jsonText
|
|
* @param {*} [json] Optional JSON instance of the text
|
|
* @private
|
|
*/
|
|
|
|
|
|
previewmode._setTextAndFireOnChange = function (jsonText, json) {
|
|
this._setText(jsonText, json);
|
|
|
|
this._onChange();
|
|
};
|
|
/**
|
|
* Apply history to the current state
|
|
* @param {{json?: JSON, text?: string}} action
|
|
* @private
|
|
*/
|
|
|
|
|
|
previewmode._applyHistory = function (action) {
|
|
this.json = action.json;
|
|
this.text = action.text;
|
|
|
|
this._renderPreview();
|
|
|
|
this._debouncedValidate();
|
|
};
|
|
/**
|
|
* Push the current state to history
|
|
* @private
|
|
*/
|
|
|
|
|
|
previewmode._pushHistory = function () {
|
|
if (!this.history) {
|
|
return;
|
|
}
|
|
|
|
var action = {
|
|
text: this.text,
|
|
json: this.json
|
|
};
|
|
this.history.add(action);
|
|
};
|
|
/**
|
|
* Execute a heavy, blocking action.
|
|
* Before starting the action, show a message on screen like "parsing..."
|
|
* @param {function} fn
|
|
* @param {string} message
|
|
*/
|
|
|
|
|
|
previewmode.executeWithBusyMessage = function (fn, message) {
|
|
var size = this.getText().length;
|
|
|
|
if (size > constants/* SIZE_LARGE */.EX) {
|
|
var me = this;
|
|
(0,util.addClassName)(me.frame, 'busy');
|
|
me.dom.busyContent.innerText = message;
|
|
setTimeout(function () {
|
|
fn();
|
|
(0,util.removeClassName)(me.frame, 'busy');
|
|
me.dom.busyContent.innerText = '';
|
|
}, 100);
|
|
} else {
|
|
fn();
|
|
}
|
|
}; // TODO: refactor into composable functions instead of this shaky mixin-like structure
|
|
|
|
|
|
previewmode.validate = previewmode_textmode.validate;
|
|
previewmode._renderErrors = previewmode_textmode._renderErrors; // define modes
|
|
|
|
var previewModeMixins = [{
|
|
mode: 'preview',
|
|
mixin: previewmode,
|
|
data: 'json'
|
|
}];
|
|
|
|
/***/ }),
|
|
|
|
/***/ 6210:
|
|
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
|
|
|
"use strict";
|
|
__webpack_require__.r(__webpack_exports__);
|
|
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
/* harmony export */ "showSortModal": function() { return /* binding */ showSortModal; }
|
|
/* harmony export */ });
|
|
/* harmony import */ var picomodal__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(483);
|
|
/* harmony import */ var picomodal__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(picomodal__WEBPACK_IMPORTED_MODULE_0__);
|
|
/* harmony import */ var _i18n__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(7907);
|
|
/* harmony import */ var _util__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(9791);
|
|
|
|
|
|
|
|
/**
|
|
* 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) ? (0,_util__WEBPACK_IMPORTED_MODULE_2__.getChildPaths)(json) : [''];
|
|
var selectedPath = options && options.path && (0,_util__WEBPACK_IMPORTED_MODULE_2__.contains)(paths, options.path) ? options.path : paths[0];
|
|
var selectedDirection = options && options.direction || 'asc';
|
|
var content = '<div class="pico-modal-contents">' + '<div class="pico-modal-header">' + (0,_i18n__WEBPACK_IMPORTED_MODULE_1__/* .translate */ .Iu)('sort') + '</div>' + '<form>' + '<table>' + '<tbody>' + '<tr>' + ' <td>' + (0,_i18n__WEBPACK_IMPORTED_MODULE_1__/* .translate */ .Iu)('sortFieldLabel') + ' </td>' + ' <td class="jsoneditor-modal-input">' + ' <div class="jsoneditor-select-wrapper">' + ' <select id="field" title="' + (0,_i18n__WEBPACK_IMPORTED_MODULE_1__/* .translate */ .Iu)('sortFieldTitle') + '">' + ' </select>' + ' </div>' + ' </td>' + '</tr>' + '<tr>' + ' <td>' + (0,_i18n__WEBPACK_IMPORTED_MODULE_1__/* .translate */ .Iu)('sortDirectionLabel') + ' </td>' + ' <td class="jsoneditor-modal-input">' + ' <div id="direction" class="jsoneditor-button-group">' + '<input type="button" ' + 'value="' + (0,_i18n__WEBPACK_IMPORTED_MODULE_1__/* .translate */ .Iu)('sortAscending') + '" ' + 'title="' + (0,_i18n__WEBPACK_IMPORTED_MODULE_1__/* .translate */ .Iu)('sortAscendingTitle') + '" ' + 'data-value="asc" ' + 'class="jsoneditor-button-first jsoneditor-button-asc"/>' + '<input type="button" ' + 'value="' + (0,_i18n__WEBPACK_IMPORTED_MODULE_1__/* .translate */ .Iu)('sortDescending') + '" ' + 'title="' + (0,_i18n__WEBPACK_IMPORTED_MODULE_1__/* .translate */ .Iu)('sortDescendingTitle') + '" ' + 'data-value="desc" ' + 'class="jsoneditor-button-last jsoneditor-button-desc"/>' + ' </div>' + ' </td>' + '</tr>' + '<tr>' + '<td colspan="2" class="jsoneditor-modal-input jsoneditor-modal-actions">' + ' <input type="submit" id="ok" value="' + (0,_i18n__WEBPACK_IMPORTED_MODULE_1__/* .translate */ .Iu)('ok') + '" />' + '</td>' + '</tr>' + '</tbody>' + '</table>' + '</form>' + '</div>';
|
|
picomodal__WEBPACK_IMPORTED_MODULE_0___default()({
|
|
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();
|
|
}
|
|
|
|
/***/ }),
|
|
|
|
/***/ 2558:
|
|
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
|
|
|
"use strict";
|
|
// ESM COMPAT FLAG
|
|
__webpack_require__.r(__webpack_exports__);
|
|
|
|
// EXPORTS
|
|
__webpack_require__.d(__webpack_exports__, {
|
|
"showTransformModal": function() { return /* binding */ showTransformModal; }
|
|
});
|
|
|
|
// EXTERNAL MODULE: ./node_modules/picomodal/src/picoModal.js
|
|
var picoModal = __webpack_require__(483);
|
|
var picoModal_default = /*#__PURE__*/__webpack_require__.n(picoModal);
|
|
// EXTERNAL MODULE: ./src/js/assets/selectr/selectr.js
|
|
var selectr = __webpack_require__(3879);
|
|
var selectr_default = /*#__PURE__*/__webpack_require__.n(selectr);
|
|
// EXTERNAL MODULE: ./src/js/i18n.js
|
|
var i18n = __webpack_require__(7907);
|
|
;// CONCATENATED MODULE: ./src/js/jsonUtils.js
|
|
|
|
/**
|
|
* Convert part of a JSON object to a JSON string.
|
|
* Use case is to stringify a small part of a large JSON object so you can see
|
|
* a preview.
|
|
*
|
|
* @param {*} value
|
|
* The value to convert to a JSON string.
|
|
*
|
|
* @param {number | string | null} [space]
|
|
* A String or Number object that's used to insert white space into the output
|
|
* JSON string for readability purposes. If this is a Number, it indicates the
|
|
* number of space characters to use as white space; this number is capped at 10
|
|
* if it's larger than that. Values less than 1 indicate that no space should be
|
|
* used. If this is a String, the string (or the first 10 characters of the string,
|
|
* if it's longer than that) is used as white space. If this parameter is not
|
|
* provided (or is null), no white space is used.
|
|
*
|
|
* @param {number} [limit] Maximum size of the string output.
|
|
*
|
|
* @returns {string | undefined} Returns the string representation of the JSON object.
|
|
*/
|
|
|
|
function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
|
|
|
|
function stringifyPartial(value, space, limit) {
|
|
var _space; // undefined by default
|
|
|
|
|
|
if (typeof space === 'number') {
|
|
if (space > 10) {
|
|
_space = repeat(' ', 10);
|
|
} else if (space >= 1) {
|
|
_space = repeat(' ', space);
|
|
} // else ignore
|
|
|
|
} else if (typeof space === 'string' && space !== '') {
|
|
_space = space;
|
|
}
|
|
|
|
var output = stringifyValue(value, _space, '', limit);
|
|
return output.length > limit ? slice(output, limit) + '...' : output;
|
|
}
|
|
/**
|
|
* Stringify a value
|
|
* @param {*} value
|
|
* @param {string} space
|
|
* @param {string} indent
|
|
* @param {number} limit
|
|
* @return {string | undefined}
|
|
*/
|
|
|
|
function stringifyValue(value, space, indent, limit) {
|
|
// boolean, null, number, string, or date
|
|
if (typeof value === 'boolean' || value instanceof Boolean || value === null || typeof value === 'number' || value instanceof Number || typeof value === 'string' || value instanceof String || value instanceof Date) {
|
|
return JSON.stringify(value);
|
|
} // array
|
|
|
|
|
|
if (Array.isArray(value)) {
|
|
return stringifyArray(value, space, indent, limit);
|
|
} // object (test lastly!)
|
|
|
|
|
|
if (value && _typeof(value) === 'object') {
|
|
return stringifyObject(value, space, indent, limit);
|
|
}
|
|
|
|
return undefined;
|
|
}
|
|
/**
|
|
* Stringify an array
|
|
* @param {Array} array
|
|
* @param {string} space
|
|
* @param {string} indent
|
|
* @param {number} limit
|
|
* @return {string}
|
|
*/
|
|
|
|
|
|
function stringifyArray(array, space, indent, limit) {
|
|
var childIndent = space ? indent + space : undefined;
|
|
var str = space ? '[\n' : '[';
|
|
|
|
for (var i = 0; i < array.length; i++) {
|
|
var item = array[i];
|
|
|
|
if (space) {
|
|
str += childIndent;
|
|
}
|
|
|
|
if (typeof item !== 'undefined' && typeof item !== 'function') {
|
|
str += stringifyValue(item, space, childIndent, limit);
|
|
} else {
|
|
str += 'null';
|
|
}
|
|
|
|
if (i < array.length - 1) {
|
|
str += space ? ',\n' : ',';
|
|
} // stop as soon as we're exceeding the limit
|
|
|
|
|
|
if (str.length > limit) {
|
|
return str + '...';
|
|
}
|
|
}
|
|
|
|
str += space ? '\n' + indent + ']' : ']';
|
|
return str;
|
|
}
|
|
/**
|
|
* Stringify an object
|
|
* @param {Object} object
|
|
* @param {string} space
|
|
* @param {string} indent
|
|
* @param {number} limit
|
|
* @return {string}
|
|
*/
|
|
|
|
|
|
function stringifyObject(object, space, indent, limit) {
|
|
var childIndent = space ? indent + space : undefined;
|
|
var first = true;
|
|
var str = space ? '{\n' : '{';
|
|
|
|
if (typeof object.toJSON === 'function') {
|
|
return stringifyValue(object.toJSON(), space, indent, limit);
|
|
}
|
|
|
|
for (var key in object) {
|
|
if (jsonUtils_hasOwnProperty(object, key)) {
|
|
var value = object[key];
|
|
|
|
if (first) {
|
|
first = false;
|
|
} else {
|
|
str += space ? ',\n' : ',';
|
|
}
|
|
|
|
str += space ? childIndent + '"' + key + '": ' : '"' + key + '":';
|
|
str += stringifyValue(value, space, childIndent, limit); // stop as soon as we're exceeding the limit
|
|
|
|
if (str.length > limit) {
|
|
return str + '...';
|
|
}
|
|
}
|
|
}
|
|
|
|
str += space ? '\n' + indent + '}' : '}';
|
|
return str;
|
|
}
|
|
/**
|
|
* Repeat a string a number of times.
|
|
* Simple linear solution, we only need up to 10 iterations in practice
|
|
* @param {string} text
|
|
* @param {number} times
|
|
* @return {string}
|
|
*/
|
|
|
|
|
|
function repeat(text, times) {
|
|
var res = '';
|
|
|
|
while (times-- > 0) {
|
|
res += text;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
/**
|
|
* Limit the length of text
|
|
* @param {string} text
|
|
* @param {number} [limit]
|
|
* @return {string}
|
|
*/
|
|
|
|
|
|
function slice(text, limit) {
|
|
return typeof limit === 'number' ? text.slice(0, limit) : text;
|
|
}
|
|
/**
|
|
* Test whether some text contains a JSON array, i.e. the first
|
|
* non-white space character is a [
|
|
* @param {string} jsonText
|
|
* @return {boolean}
|
|
*/
|
|
|
|
|
|
function containsArray(jsonText) {
|
|
return /^\s*\[/.test(jsonText);
|
|
}
|
|
|
|
function jsonUtils_hasOwnProperty(object, key) {
|
|
return Object.prototype.hasOwnProperty.call(object, key);
|
|
}
|
|
// EXTERNAL MODULE: ./src/js/util.js
|
|
var util = __webpack_require__(9791);
|
|
// EXTERNAL MODULE: ./src/js/constants.js
|
|
var constants = __webpack_require__(4188);
|
|
;// CONCATENATED MODULE: ./src/js/showTransformModal.js
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var DEFAULT_DESCRIPTION = 'Enter a <a href="http://jmespath.org" target="_blank">JMESPath</a> query to filter, sort, or transform the JSON data.<br/>' + 'To learn JMESPath, go to <a href="http://jmespath.org/tutorial.html" target="_blank">the interactive tutorial</a>.';
|
|
/**
|
|
* Show advanced filter and transform modal using JMESPath
|
|
* @param {Object} params
|
|
* @property {HTMLElement} container The container where to center
|
|
* the modal and create an overlay
|
|
* @property {JSON} json The json data to be transformed
|
|
* @property {string} [queryDescription] Optional custom description explaining
|
|
* the transform functionality
|
|
* @property {function} createQuery Function called to create a query
|
|
* from the wizard form
|
|
* @property {function} executeQuery Execute a query for the preview pane
|
|
* @property {function} onTransform Callback invoked with the created
|
|
* query as callback
|
|
*/
|
|
|
|
function showTransformModal(_ref) {
|
|
var container = _ref.container,
|
|
json = _ref.json,
|
|
_ref$queryDescription = _ref.queryDescription,
|
|
queryDescription = _ref$queryDescription === void 0 ? DEFAULT_DESCRIPTION : _ref$queryDescription,
|
|
createQuery = _ref.createQuery,
|
|
executeQuery = _ref.executeQuery,
|
|
onTransform = _ref.onTransform;
|
|
var value = json;
|
|
var content = '<label class="pico-modal-contents">' + '<div class="pico-modal-header">' + (0,i18n/* translate */.Iu)('transform') + '</div>' + '<p>' + queryDescription + '</p>' + '<div class="jsoneditor-jmespath-label">' + (0,i18n/* translate */.Iu)('transformWizardLabel') + ' </div>' + '<div id="wizard" class="jsoneditor-jmespath-block jsoneditor-jmespath-wizard">' + ' <table class="jsoneditor-jmespath-wizard-table">' + ' <tbody>' + ' <tr>' + ' <th>' + (0,i18n/* translate */.Iu)('transformWizardFilter') + '</th>' + ' <td class="jsoneditor-jmespath-filter">' + ' <div class="jsoneditor-inline jsoneditor-jmespath-filter-field" >' + ' <select id="filterField">' + ' </select>' + ' </div>' + ' <div class="jsoneditor-inline jsoneditor-jmespath-filter-relation" >' + ' <select id="filterRelation">' + ' <option value="==">==</option>' + ' <option value="!=">!=</option>' + ' <option value="<"><</option>' + ' <option value="<="><=</option>' + ' <option value=">">></option>' + ' <option value=">=">>=</option>' + ' </select>' + ' </div>' + ' <div class="jsoneditor-inline jsoneditor-jmespath-filter-value" >' + ' <input type="text" class="value" placeholder="value..." id="filterValue" />' + ' </div>' + ' </td>' + ' </tr>' + ' <tr>' + ' <th>' + (0,i18n/* translate */.Iu)('transformWizardSortBy') + '</th>' + ' <td class="jsoneditor-jmespath-filter">' + ' <div class="jsoneditor-inline jsoneditor-jmespath-sort-field">' + ' <select id="sortField">' + ' </select>' + ' </div>' + ' <div class="jsoneditor-inline jsoneditor-jmespath-sort-order" >' + ' <select id="sortOrder">' + ' <option value="asc">Ascending</option>' + ' <option value="desc">Descending</option>' + ' </select>' + ' </div>' + ' </td>' + ' </tr>' + ' <tr id="selectFieldsPart">' + ' <th>' + (0,i18n/* translate */.Iu)('transformWizardSelectFields') + '</th>' + ' <td class="jsoneditor-jmespath-filter">' + ' <select class="jsoneditor-jmespath-select-fields" id="selectFields" multiple></select>' + ' </td>' + ' </tr>' + ' </tbody>' + ' </table>' + '</div>' + '<div class="jsoneditor-jmespath-label">' + (0,i18n/* translate */.Iu)('transformQueryLabel') + ' </div>' + '<div class="jsoneditor-jmespath-block">' + ' <textarea id="query" ' + ' rows="4" ' + ' autocomplete="off" ' + ' autocorrect="off" ' + ' autocapitalize="off" ' + ' spellcheck="false"' + ' title="' + (0,i18n/* translate */.Iu)('transformQueryTitle') + '">[*]</textarea>' + '</div>' + '<div class="jsoneditor-jmespath-label">' + (0,i18n/* translate */.Iu)('transformPreviewLabel') + ' </div>' + '<div class="jsoneditor-jmespath-block">' + ' <textarea id="preview" ' + ' class="jsoneditor-transform-preview"' + ' readonly> </textarea>' + '</div>' + '<div class="jsoneditor-jmespath-block jsoneditor-modal-actions">' + ' <input type="submit" id="ok" value="' + (0,i18n/* translate */.Iu)('ok') + '" autofocus />' + '</div>' + '</div>';
|
|
picoModal_default()({
|
|
parent: container,
|
|
content: content,
|
|
overlayClass: 'jsoneditor-modal-overlay',
|
|
overlayStyles: {
|
|
backgroundColor: 'rgb(1,1,1)',
|
|
opacity: 0.3
|
|
},
|
|
modalClass: 'jsoneditor-modal jsoneditor-modal-transform',
|
|
focus: false
|
|
}).afterCreate(function (modal) {
|
|
var elem = modal.modalElem();
|
|
var wizard = elem.querySelector('#wizard');
|
|
var ok = elem.querySelector('#ok');
|
|
var filterField = elem.querySelector('#filterField');
|
|
var filterRelation = elem.querySelector('#filterRelation');
|
|
var filterValue = elem.querySelector('#filterValue');
|
|
var sortField = elem.querySelector('#sortField');
|
|
var sortOrder = elem.querySelector('#sortOrder');
|
|
var selectFields = elem.querySelector('#selectFields');
|
|
var query = elem.querySelector('#query');
|
|
var preview = elem.querySelector('#preview');
|
|
|
|
if (!Array.isArray(value)) {
|
|
wizard.style.fontStyle = 'italic';
|
|
wizard.textContent = '(wizard not available for objects, only for arrays)';
|
|
}
|
|
|
|
var sortablePaths = (0,util.getChildPaths)(json);
|
|
sortablePaths.forEach(function (path) {
|
|
var formattedPath = preprocessPath(path);
|
|
var filterOption = document.createElement('option');
|
|
filterOption.text = formattedPath;
|
|
filterOption.value = formattedPath;
|
|
filterField.appendChild(filterOption);
|
|
var sortOption = document.createElement('option');
|
|
sortOption.text = formattedPath;
|
|
sortOption.value = formattedPath;
|
|
sortField.appendChild(sortOption);
|
|
});
|
|
var selectablePaths = (0,util.getChildPaths)(json, true).filter(function (path) {
|
|
return path !== '';
|
|
});
|
|
|
|
if (selectablePaths.length > 0) {
|
|
selectablePaths.forEach(function (path) {
|
|
var formattedPath = preprocessPath(path);
|
|
var option = document.createElement('option');
|
|
option.text = formattedPath;
|
|
option.value = formattedPath;
|
|
selectFields.appendChild(option);
|
|
});
|
|
} else {
|
|
var selectFieldsPart = elem.querySelector('#selectFieldsPart');
|
|
|
|
if (selectFieldsPart) {
|
|
selectFieldsPart.style.display = 'none';
|
|
}
|
|
}
|
|
|
|
var selectrFilterField = new (selectr_default())(filterField, {
|
|
defaultSelected: false,
|
|
clearable: true,
|
|
allowDeselect: true,
|
|
placeholder: 'field...'
|
|
});
|
|
var selectrFilterRelation = new (selectr_default())(filterRelation, {
|
|
defaultSelected: false,
|
|
clearable: true,
|
|
allowDeselect: true,
|
|
placeholder: 'compare...'
|
|
});
|
|
var selectrSortField = new (selectr_default())(sortField, {
|
|
defaultSelected: false,
|
|
clearable: true,
|
|
allowDeselect: true,
|
|
placeholder: 'field...'
|
|
});
|
|
var selectrSortOrder = new (selectr_default())(sortOrder, {
|
|
defaultSelected: false,
|
|
clearable: true,
|
|
allowDeselect: true,
|
|
placeholder: 'order...'
|
|
});
|
|
var selectrSelectFields = new (selectr_default())(selectFields, {
|
|
multiple: true,
|
|
clearable: true,
|
|
defaultSelected: false,
|
|
placeholder: 'select fields...'
|
|
});
|
|
selectrFilterField.on('selectr.change', generateQueryFromWizard);
|
|
selectrFilterRelation.on('selectr.change', generateQueryFromWizard);
|
|
filterValue.oninput = generateQueryFromWizard;
|
|
selectrSortField.on('selectr.change', generateQueryFromWizard);
|
|
selectrSortOrder.on('selectr.change', generateQueryFromWizard);
|
|
selectrSelectFields.on('selectr.change', generateQueryFromWizard);
|
|
|
|
elem.querySelector('.pico-modal-contents').onclick = function (event) {
|
|
// prevent the first clear button (in any select box) from getting
|
|
// focus when clicking anywhere in the modal. Only allow clicking links.
|
|
if (event.target.nodeName !== 'A') {
|
|
event.preventDefault();
|
|
}
|
|
};
|
|
|
|
function preprocessPath(path) {
|
|
return path === '' ? '@' : path[0] === '.' ? path.slice(1) : path;
|
|
}
|
|
|
|
function updatePreview() {
|
|
try {
|
|
var transformed = executeQuery(value, query.value);
|
|
preview.className = 'jsoneditor-transform-preview';
|
|
preview.value = stringifyPartial(transformed, 2, constants/* MAX_PREVIEW_CHARACTERS */.WF);
|
|
ok.disabled = false;
|
|
} catch (err) {
|
|
preview.className = 'jsoneditor-transform-preview jsoneditor-error';
|
|
preview.value = err.toString();
|
|
ok.disabled = true;
|
|
}
|
|
}
|
|
|
|
var debouncedUpdatePreview = (0,util.debounce)(updatePreview, 300);
|
|
|
|
function tryCreateQuery(json, queryOptions) {
|
|
try {
|
|
query.value = createQuery(json, queryOptions);
|
|
ok.disabled = false;
|
|
debouncedUpdatePreview();
|
|
} catch (err) {
|
|
var message = 'Error: an error happened when executing "createQuery": ' + (err.message || err.toString());
|
|
query.value = '';
|
|
ok.disabled = true;
|
|
preview.className = 'jsoneditor-transform-preview jsoneditor-error';
|
|
preview.value = message;
|
|
}
|
|
}
|
|
|
|
function generateQueryFromWizard() {
|
|
var queryOptions = {};
|
|
|
|
if (filterField.value && filterRelation.value && filterValue.value) {
|
|
queryOptions.filter = {
|
|
field: filterField.value,
|
|
relation: filterRelation.value,
|
|
value: filterValue.value
|
|
};
|
|
}
|
|
|
|
if (sortField.value && sortOrder.value) {
|
|
queryOptions.sort = {
|
|
field: sortField.value,
|
|
direction: sortOrder.value
|
|
};
|
|
}
|
|
|
|
if (selectFields.value) {
|
|
var fields = [];
|
|
|
|
for (var i = 0; i < selectFields.options.length; i++) {
|
|
if (selectFields.options[i].selected) {
|
|
var selectedField = selectFields.options[i].value;
|
|
fields.push(selectedField);
|
|
}
|
|
}
|
|
|
|
queryOptions.projection = {
|
|
fields: fields
|
|
};
|
|
}
|
|
|
|
tryCreateQuery(json, queryOptions);
|
|
}
|
|
|
|
query.oninput = debouncedUpdatePreview;
|
|
|
|
ok.onclick = function (event) {
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
modal.close();
|
|
onTransform(query.value);
|
|
}; // initialize with empty query
|
|
|
|
|
|
tryCreateQuery(json, {});
|
|
setTimeout(function () {
|
|
query.select();
|
|
query.focus();
|
|
query.selectionStart = 3;
|
|
query.selectionEnd = 3;
|
|
});
|
|
}).afterClose(function (modal) {
|
|
modal.destroy();
|
|
}).show();
|
|
}
|
|
|
|
/***/ }),
|
|
|
|
/***/ 5956:
|
|
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
|
|
|
"use strict";
|
|
// ESM COMPAT FLAG
|
|
__webpack_require__.r(__webpack_exports__);
|
|
|
|
// EXPORTS
|
|
__webpack_require__.d(__webpack_exports__, {
|
|
"textModeMixins": function() { return /* binding */ textModeMixins; }
|
|
});
|
|
|
|
// EXTERNAL MODULE: ./node_modules/jsonrepair/lib/cjs/index-commonjs.js
|
|
var index_commonjs = __webpack_require__(8909);
|
|
var index_commonjs_default = /*#__PURE__*/__webpack_require__.n(index_commonjs);
|
|
// EXTERNAL MODULE: ./src/js/ace/index.js
|
|
var ace = __webpack_require__(8170);
|
|
var ace_default = /*#__PURE__*/__webpack_require__.n(ace);
|
|
// EXTERNAL MODULE: ./src/js/constants.js
|
|
var constants = __webpack_require__(4188);
|
|
// EXTERNAL MODULE: ./src/js/ErrorTable.js
|
|
var ErrorTable = __webpack_require__(6436);
|
|
// EXTERNAL MODULE: ./src/js/FocusTracker.js
|
|
var FocusTracker = __webpack_require__(2474);
|
|
// EXTERNAL MODULE: ./src/js/i18n.js
|
|
var i18n = __webpack_require__(7907);
|
|
// EXTERNAL MODULE: ./src/js/jmespathQuery.js
|
|
var jmespathQuery = __webpack_require__(6056);
|
|
// EXTERNAL MODULE: ./src/js/ModeSwitcher.js
|
|
var ModeSwitcher = __webpack_require__(6617);
|
|
// EXTERNAL MODULE: ./src/js/showSortModal.js
|
|
var showSortModal = __webpack_require__(6210);
|
|
// EXTERNAL MODULE: ./src/js/showTransformModal.js + 1 modules
|
|
var showTransformModal = __webpack_require__(2558);
|
|
// EXTERNAL MODULE: ./src/js/tryRequireThemeJsonEditor.js
|
|
var tryRequireThemeJsonEditor = __webpack_require__(9125);
|
|
// EXTERNAL MODULE: ./src/js/util.js
|
|
var util = __webpack_require__(9791);
|
|
;// CONCATENATED MODULE: ./src/js/validationUtils.js
|
|
|
|
/**
|
|
* Execute custom validation if configured.
|
|
*
|
|
* Returns a promise resolving with the custom errors (or an empty array).
|
|
*/
|
|
|
|
function validateCustom(json, onValidate) {
|
|
if (!onValidate) {
|
|
return Promise.resolve([]);
|
|
}
|
|
|
|
try {
|
|
var customValidateResults = onValidate(json);
|
|
var resultPromise = (0,util.isPromise)(customValidateResults) ? customValidateResults : Promise.resolve(customValidateResults);
|
|
return resultPromise.then(function (customValidationPathErrors) {
|
|
if (Array.isArray(customValidationPathErrors)) {
|
|
return customValidationPathErrors.filter(function (error) {
|
|
var valid = (0,util.isValidValidationError)(error);
|
|
|
|
if (!valid) {
|
|
console.warn('Ignoring a custom validation error with invalid structure. ' + 'Expected structure: {path: [...], message: "..."}. ' + 'Actual error:', error);
|
|
}
|
|
|
|
return valid;
|
|
}).map(function (error) {
|
|
return (// change data structure into the structure matching the JSON schema errors
|
|
{
|
|
dataPath: (0,util.stringifyPath)(error.path),
|
|
message: error.message,
|
|
type: 'customValidation'
|
|
}
|
|
);
|
|
});
|
|
} else {
|
|
return [];
|
|
}
|
|
});
|
|
} catch (err) {
|
|
return Promise.reject(err);
|
|
}
|
|
}
|
|
;// CONCATENATED MODULE: ./src/js/textmode.js
|
|
|
|
|
|
function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// create a mixin with the functions for text mode
|
|
|
|
var textmode = {};
|
|
var DEFAULT_THEME = 'ace/theme/jsoneditor';
|
|
/**
|
|
* Create a text editor
|
|
* @param {Element} container
|
|
* @param {Object} [options] Object with options. See docs for details.
|
|
* @private
|
|
*/
|
|
|
|
textmode.create = function (container) {
|
|
var _this = this;
|
|
|
|
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
|
|
if (typeof options.statusBar === 'undefined') {
|
|
options.statusBar = true;
|
|
} // setting default for textmode
|
|
|
|
|
|
options.mainMenuBar = options.mainMenuBar !== false;
|
|
options.enableSort = options.enableSort !== false;
|
|
options.enableTransform = options.enableTransform !== false;
|
|
options.createQuery = options.createQuery || jmespathQuery/* createQuery */.r;
|
|
options.executeQuery = options.executeQuery || jmespathQuery/* executeQuery */.J;
|
|
this.options = options; // indentation
|
|
|
|
if (typeof options.indentation === 'number') {
|
|
this.indentation = Number(options.indentation);
|
|
} else {
|
|
this.indentation = 2; // number of spaces
|
|
} // language
|
|
|
|
|
|
(0,i18n/* setLanguages */.cC)(this.options.languages);
|
|
(0,i18n/* setLanguage */.m0)(this.options.language); // grab ace from options if provided
|
|
|
|
var _ace = options.ace ? options.ace : (ace_default()); // TODO: make the option options.ace deprecated, it's not needed anymore (see #309)
|
|
// determine mode
|
|
|
|
|
|
this.mode = options.mode === 'code' ? 'code' : 'text';
|
|
|
|
if (this.mode === 'code') {
|
|
// verify whether Ace editor is available and supported
|
|
if (typeof _ace === 'undefined') {
|
|
this.mode = 'text';
|
|
console.warn('Failed to load Ace editor, falling back to plain text mode. Please use a JSONEditor bundle including Ace, or pass Ace as via the configuration option `ace`.');
|
|
}
|
|
} // determine theme
|
|
|
|
|
|
this.theme = options.theme || DEFAULT_THEME;
|
|
|
|
if (this.theme === DEFAULT_THEME && _ace) {
|
|
(0,tryRequireThemeJsonEditor/* tryRequireThemeJsonEditor */.O)();
|
|
}
|
|
|
|
if (options.onTextSelectionChange) {
|
|
this.onTextSelectionChange(options.onTextSelectionChange);
|
|
}
|
|
|
|
var me = this;
|
|
this.container = container;
|
|
this.dom = {};
|
|
this.aceEditor = undefined; // ace code editor
|
|
|
|
this.textarea = undefined; // plain text editor (fallback when Ace is not available)
|
|
|
|
this.validateSchema = null;
|
|
this.annotations = [];
|
|
this.lastSchemaErrors = undefined; // create a debounced validate function
|
|
|
|
this._debouncedValidate = (0,util.debounce)(this.validate.bind(this), this.DEBOUNCE_INTERVAL);
|
|
this.width = container.clientWidth;
|
|
this.height = container.clientHeight;
|
|
this.frame = document.createElement('div');
|
|
this.frame.className = 'jsoneditor jsoneditor-mode-' + this.options.mode;
|
|
|
|
this.frame.onclick = function (event) {
|
|
// prevent default submit action when the editor is located inside a form
|
|
event.preventDefault();
|
|
};
|
|
|
|
this.frame.onkeydown = function (event) {
|
|
me._onKeyDown(event);
|
|
}; // setting the FocusTracker on 'this.frame' to track the editor's focus event
|
|
|
|
|
|
var focusTrackerConfig = {
|
|
target: this.frame,
|
|
onFocus: this.options.onFocus || null,
|
|
onBlur: this.options.onBlur || null
|
|
};
|
|
this.frameFocusTracker = new FocusTracker/* FocusTracker */.R(focusTrackerConfig);
|
|
this.content = document.createElement('div');
|
|
this.content.className = 'jsoneditor-outer';
|
|
|
|
if (this.options.mainMenuBar) {
|
|
(0,util.addClassName)(this.content, 'has-main-menu-bar'); // create menu
|
|
|
|
this.menu = document.createElement('div');
|
|
this.menu.className = 'jsoneditor-menu';
|
|
this.frame.appendChild(this.menu); // create format button
|
|
|
|
var buttonFormat = document.createElement('button');
|
|
buttonFormat.type = 'button';
|
|
buttonFormat.className = 'jsoneditor-format';
|
|
buttonFormat.title = (0,i18n/* translate */.Iu)('formatTitle');
|
|
this.menu.appendChild(buttonFormat);
|
|
|
|
buttonFormat.onclick = function () {
|
|
try {
|
|
me.format();
|
|
|
|
me._onChange();
|
|
} catch (err) {
|
|
me._onError(err);
|
|
}
|
|
}; // create compact button
|
|
|
|
|
|
var buttonCompact = document.createElement('button');
|
|
buttonCompact.type = 'button';
|
|
buttonCompact.className = 'jsoneditor-compact';
|
|
buttonCompact.title = (0,i18n/* translate */.Iu)('compactTitle');
|
|
this.menu.appendChild(buttonCompact);
|
|
|
|
buttonCompact.onclick = function () {
|
|
try {
|
|
me.compact();
|
|
|
|
me._onChange();
|
|
} catch (err) {
|
|
me._onError(err);
|
|
}
|
|
}; // create sort button
|
|
|
|
|
|
if (this.options.enableSort) {
|
|
var _sort = document.createElement('button');
|
|
|
|
_sort.type = 'button';
|
|
_sort.className = 'jsoneditor-sort';
|
|
_sort.title = (0,i18n/* translate */.Iu)('sortTitleShort');
|
|
|
|
_sort.onclick = function () {
|
|
me._showSortModal();
|
|
};
|
|
|
|
this.menu.appendChild(_sort);
|
|
} // create transform button
|
|
|
|
|
|
if (this.options.enableTransform) {
|
|
var transform = document.createElement('button');
|
|
transform.type = 'button';
|
|
transform.title = (0,i18n/* translate */.Iu)('transformTitleShort');
|
|
transform.className = 'jsoneditor-transform';
|
|
|
|
transform.onclick = function () {
|
|
me._showTransformModal();
|
|
};
|
|
|
|
this.menu.appendChild(transform);
|
|
} // create repair button
|
|
|
|
|
|
var buttonRepair = document.createElement('button');
|
|
buttonRepair.type = 'button';
|
|
buttonRepair.className = 'jsoneditor-repair';
|
|
buttonRepair.title = (0,i18n/* translate */.Iu)('repairTitle');
|
|
this.menu.appendChild(buttonRepair);
|
|
|
|
buttonRepair.onclick = function () {
|
|
try {
|
|
me.repair();
|
|
|
|
me._onChange();
|
|
} catch (err) {
|
|
me._onError(err);
|
|
}
|
|
}; // create undo/redo buttons
|
|
|
|
|
|
if (this.mode === 'code') {
|
|
// create undo button
|
|
var undo = document.createElement('button');
|
|
undo.type = 'button';
|
|
undo.className = 'jsoneditor-undo jsoneditor-separator';
|
|
undo.title = (0,i18n/* translate */.Iu)('undo');
|
|
|
|
undo.onclick = function () {
|
|
_this.aceEditor.getSession().getUndoManager().undo();
|
|
};
|
|
|
|
this.menu.appendChild(undo);
|
|
this.dom.undo = undo; // create redo button
|
|
|
|
var redo = document.createElement('button');
|
|
redo.type = 'button';
|
|
redo.className = 'jsoneditor-redo';
|
|
redo.title = (0,i18n/* translate */.Iu)('redo');
|
|
|
|
redo.onclick = function () {
|
|
_this.aceEditor.getSession().getUndoManager().redo();
|
|
};
|
|
|
|
this.menu.appendChild(redo);
|
|
this.dom.redo = redo;
|
|
} // create mode box
|
|
|
|
|
|
if (this.options && this.options.modes && this.options.modes.length) {
|
|
this.modeSwitcher = new ModeSwitcher/* ModeSwitcher */.x(this.menu, this.options.modes, this.options.mode, function onSwitch(mode) {
|
|
// switch mode and restore focus
|
|
me.setMode(mode);
|
|
me.modeSwitcher.focus();
|
|
});
|
|
}
|
|
|
|
if (this.mode === 'code') {
|
|
var poweredBy = document.createElement('a');
|
|
poweredBy.appendChild(document.createTextNode('powered by ace'));
|
|
poweredBy.href = 'https://ace.c9.io/';
|
|
poweredBy.target = '_blank';
|
|
poweredBy.className = 'jsoneditor-poweredBy';
|
|
|
|
poweredBy.onclick = function () {
|
|
// TODO: this anchor falls below the margin of the content,
|
|
// therefore the normal a.href does not work. We use a click event
|
|
// for now, but this should be fixed.
|
|
window.open(poweredBy.href, poweredBy.target, 'noopener');
|
|
};
|
|
|
|
this.menu.appendChild(poweredBy);
|
|
}
|
|
}
|
|
|
|
var emptyNode = {};
|
|
var isReadOnly = this.options.onEditable && _typeof(this.options.onEditable === 'function') && !this.options.onEditable(emptyNode);
|
|
this.frame.appendChild(this.content);
|
|
this.container.appendChild(this.frame);
|
|
|
|
if (this.mode === 'code') {
|
|
this.editorDom = document.createElement('div');
|
|
this.editorDom.style.height = '100%'; // TODO: move to css
|
|
|
|
this.editorDom.style.width = '100%'; // TODO: move to css
|
|
|
|
this.content.appendChild(this.editorDom);
|
|
|
|
var aceEditor = _ace.edit(this.editorDom);
|
|
|
|
var aceSession = aceEditor.getSession();
|
|
aceEditor.$blockScrolling = Infinity;
|
|
aceEditor.setTheme(this.theme);
|
|
aceEditor.setOptions({
|
|
readOnly: isReadOnly
|
|
});
|
|
aceEditor.setShowPrintMargin(false);
|
|
aceEditor.setFontSize('13px');
|
|
aceSession.setMode('ace/mode/json');
|
|
aceSession.setTabSize(this.indentation);
|
|
aceSession.setUseSoftTabs(true);
|
|
aceSession.setUseWrapMode(true); // replace ace setAnnotations with custom function that also covers jsoneditor annotations
|
|
|
|
var originalSetAnnotations = aceSession.setAnnotations;
|
|
|
|
aceSession.setAnnotations = function (annotations) {
|
|
originalSetAnnotations.call(this, annotations && annotations.length ? annotations : me.annotations);
|
|
}; // disable Ctrl+L quickkey of Ace (is used by the browser to select the address bar)
|
|
|
|
|
|
aceEditor.commands.bindKey('Ctrl-L', null);
|
|
aceEditor.commands.bindKey('Command-L', null); // disable the quickkeys we want to use for Format and Compact
|
|
|
|
aceEditor.commands.bindKey('Ctrl-\\', null);
|
|
aceEditor.commands.bindKey('Command-\\', null);
|
|
aceEditor.commands.bindKey('Ctrl-Shift-\\', null);
|
|
aceEditor.commands.bindKey('Command-Shift-\\', null);
|
|
this.aceEditor = aceEditor; // register onchange event
|
|
|
|
aceEditor.on('change', this._onChange.bind(this));
|
|
aceEditor.on('changeSelection', this._onSelect.bind(this));
|
|
} else {
|
|
// load a plain text textarea
|
|
var textarea = document.createElement('textarea');
|
|
textarea.className = 'jsoneditor-text';
|
|
textarea.spellcheck = false;
|
|
this.content.appendChild(textarea);
|
|
this.textarea = textarea;
|
|
this.textarea.readOnly = isReadOnly; // register onchange event
|
|
|
|
if (this.textarea.oninput === null) {
|
|
this.textarea.oninput = this._onChange.bind(this);
|
|
} else {
|
|
// oninput is undefined. For IE8-
|
|
this.textarea.onchange = this._onChange.bind(this);
|
|
}
|
|
|
|
textarea.onselect = this._onSelect.bind(this);
|
|
textarea.onmousedown = this._onMouseDown.bind(this);
|
|
textarea.onblur = this._onBlur.bind(this);
|
|
}
|
|
|
|
this._updateHistoryButtons();
|
|
|
|
this.errorTable = new ErrorTable/* ErrorTable */.Q({
|
|
errorTableVisible: this.mode === 'text',
|
|
onToggleVisibility: function onToggleVisibility() {
|
|
me.validate();
|
|
},
|
|
onFocusLine: function onFocusLine(line) {
|
|
me.isFocused = true;
|
|
|
|
if (!isNaN(line)) {
|
|
me.setTextSelection({
|
|
row: line,
|
|
column: 1
|
|
}, {
|
|
row: line,
|
|
column: 1000
|
|
});
|
|
}
|
|
},
|
|
onChangeHeight: function onChangeHeight(height) {
|
|
// TODO: change CSS to using flex box, remove setting height using JavaScript
|
|
var statusBarHeight = me.dom.statusBar ? me.dom.statusBar.clientHeight : 0;
|
|
var totalHeight = height + statusBarHeight + 1;
|
|
me.content.style.marginBottom = -totalHeight + 'px';
|
|
me.content.style.paddingBottom = totalHeight + 'px';
|
|
}
|
|
});
|
|
this.frame.appendChild(this.errorTable.getErrorTable());
|
|
|
|
if (options.statusBar) {
|
|
(0,util.addClassName)(this.content, 'has-status-bar');
|
|
this.curserInfoElements = {};
|
|
var statusBar = document.createElement('div');
|
|
this.dom.statusBar = statusBar;
|
|
statusBar.className = 'jsoneditor-statusbar';
|
|
this.frame.appendChild(statusBar);
|
|
var lnLabel = document.createElement('span');
|
|
lnLabel.className = 'jsoneditor-curserinfo-label';
|
|
lnLabel.innerText = 'Ln:';
|
|
var lnVal = document.createElement('span');
|
|
lnVal.className = 'jsoneditor-curserinfo-val';
|
|
lnVal.innerText = '1';
|
|
statusBar.appendChild(lnLabel);
|
|
statusBar.appendChild(lnVal);
|
|
var colLabel = document.createElement('span');
|
|
colLabel.className = 'jsoneditor-curserinfo-label';
|
|
colLabel.innerText = 'Col:';
|
|
var colVal = document.createElement('span');
|
|
colVal.className = 'jsoneditor-curserinfo-val';
|
|
colVal.innerText = '1';
|
|
statusBar.appendChild(colLabel);
|
|
statusBar.appendChild(colVal);
|
|
this.curserInfoElements.colVal = colVal;
|
|
this.curserInfoElements.lnVal = lnVal;
|
|
var countLabel = document.createElement('span');
|
|
countLabel.className = 'jsoneditor-curserinfo-label';
|
|
countLabel.innerText = 'characters selected';
|
|
countLabel.style.display = 'none';
|
|
var countVal = document.createElement('span');
|
|
countVal.className = 'jsoneditor-curserinfo-count';
|
|
countVal.innerText = '0';
|
|
countVal.style.display = 'none';
|
|
this.curserInfoElements.countLabel = countLabel;
|
|
this.curserInfoElements.countVal = countVal;
|
|
statusBar.appendChild(countVal);
|
|
statusBar.appendChild(countLabel);
|
|
statusBar.appendChild(this.errorTable.getErrorCounter());
|
|
statusBar.appendChild(this.errorTable.getWarningIcon());
|
|
statusBar.appendChild(this.errorTable.getErrorIcon());
|
|
}
|
|
|
|
this.setSchema(this.options.schema, this.options.schemaRefs);
|
|
};
|
|
/**
|
|
* Handle a change:
|
|
* - Validate JSON schema
|
|
* - Send a callback to the onChange listener if provided
|
|
* @private
|
|
*/
|
|
|
|
|
|
textmode._onChange = function () {
|
|
var _this2 = this;
|
|
|
|
if (this.onChangeDisabled) {
|
|
return;
|
|
} // enable/disable undo/redo buttons
|
|
|
|
|
|
setTimeout(function () {
|
|
return _this2._updateHistoryButtons();
|
|
}); // validate JSON schema (if configured)
|
|
|
|
this._debouncedValidate(); // trigger the onChange callback
|
|
|
|
|
|
if (this.options.onChange) {
|
|
try {
|
|
this.options.onChange();
|
|
} catch (err) {
|
|
console.error('Error in onChange callback: ', err);
|
|
}
|
|
} // trigger the onChangeText callback
|
|
|
|
|
|
if (this.options.onChangeText) {
|
|
try {
|
|
this.options.onChangeText(this.getText());
|
|
} catch (err) {
|
|
console.error('Error in onChangeText callback: ', err);
|
|
}
|
|
}
|
|
};
|
|
|
|
textmode._updateHistoryButtons = function () {
|
|
if (this.aceEditor && this.dom.undo && this.dom.redo) {
|
|
var undoManager = this.aceEditor.getSession().getUndoManager();
|
|
|
|
if (undoManager && undoManager.hasUndo && undoManager.hasRedo) {
|
|
this.dom.undo.disabled = !undoManager.hasUndo();
|
|
this.dom.redo.disabled = !undoManager.hasRedo();
|
|
}
|
|
}
|
|
};
|
|
/**
|
|
* Open a sort modal
|
|
* @private
|
|
*/
|
|
|
|
|
|
textmode._showSortModal = function () {
|
|
var me = this;
|
|
var container = this.options.modalAnchor || constants/* DEFAULT_MODAL_ANCHOR */.qD;
|
|
var json = this.get();
|
|
|
|
function onSort(sortedBy) {
|
|
if (Array.isArray(json)) {
|
|
var sortedJson = (0,util.sort)(json, sortedBy.path, sortedBy.direction);
|
|
me.sortedBy = sortedBy;
|
|
me.update(sortedJson);
|
|
}
|
|
|
|
if ((0,util.isObject)(json)) {
|
|
var _sortedJson = (0,util.sortObjectKeys)(json, sortedBy.direction);
|
|
|
|
me.sortedBy = sortedBy;
|
|
me.update(_sortedJson);
|
|
}
|
|
}
|
|
|
|
(0,showSortModal.showSortModal)(container, json, onSort, me.sortedBy);
|
|
};
|
|
/**
|
|
* Open a transform modal
|
|
* @private
|
|
*/
|
|
|
|
|
|
textmode._showTransformModal = function () {
|
|
var _this3 = this;
|
|
|
|
var _this$options = this.options,
|
|
modalAnchor = _this$options.modalAnchor,
|
|
createQuery = _this$options.createQuery,
|
|
executeQuery = _this$options.executeQuery,
|
|
queryDescription = _this$options.queryDescription;
|
|
var json = this.get();
|
|
(0,showTransformModal.showTransformModal)({
|
|
container: modalAnchor || constants/* DEFAULT_MODAL_ANCHOR */.qD,
|
|
json: json,
|
|
queryDescription: queryDescription,
|
|
// can be undefined
|
|
createQuery: createQuery,
|
|
executeQuery: executeQuery,
|
|
onTransform: function onTransform(query) {
|
|
var updatedJson = executeQuery(json, query);
|
|
|
|
_this3.update(updatedJson);
|
|
}
|
|
});
|
|
};
|
|
/**
|
|
* Handle text selection
|
|
* Calculates the cursor position and selection range and updates menu
|
|
* @private
|
|
*/
|
|
|
|
|
|
textmode._onSelect = function () {
|
|
this._updateCursorInfo();
|
|
|
|
this._emitSelectionChange();
|
|
};
|
|
/**
|
|
* Event handler for keydown. Handles shortcut keys
|
|
* @param {Event} event
|
|
* @private
|
|
*/
|
|
|
|
|
|
textmode._onKeyDown = function (event) {
|
|
var keynum = event.which || event.keyCode;
|
|
var handled = false;
|
|
|
|
if (keynum === 220 && event.ctrlKey) {
|
|
if (event.shiftKey) {
|
|
// Ctrl+Shift+\
|
|
this.compact();
|
|
|
|
this._onChange();
|
|
} else {
|
|
// Ctrl+\
|
|
this.format();
|
|
|
|
this._onChange();
|
|
}
|
|
|
|
handled = true;
|
|
}
|
|
|
|
if (handled) {
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
}
|
|
|
|
this._updateCursorInfo();
|
|
|
|
this._emitSelectionChange();
|
|
};
|
|
/**
|
|
* Event handler for mousedown.
|
|
* @private
|
|
*/
|
|
|
|
|
|
textmode._onMouseDown = function () {
|
|
this._updateCursorInfo();
|
|
|
|
this._emitSelectionChange();
|
|
};
|
|
/**
|
|
* Event handler for blur.
|
|
* @private
|
|
*/
|
|
|
|
|
|
textmode._onBlur = function () {
|
|
var me = this; // this allows to avoid blur when clicking inner elements (like the errors panel)
|
|
// just make sure to set the isFocused to true on the inner element onclick callback
|
|
|
|
setTimeout(function () {
|
|
if (!me.isFocused) {
|
|
me._updateCursorInfo();
|
|
|
|
me._emitSelectionChange();
|
|
}
|
|
|
|
me.isFocused = false;
|
|
});
|
|
};
|
|
/**
|
|
* Update the cursor info and the status bar, if presented
|
|
*/
|
|
|
|
|
|
textmode._updateCursorInfo = function () {
|
|
var me = this;
|
|
var line, col, count;
|
|
|
|
if (this.textarea) {
|
|
setTimeout(function () {
|
|
// this to verify we get the most updated textarea cursor selection
|
|
var selectionRange = (0,util.getInputSelection)(me.textarea);
|
|
|
|
if (selectionRange.startIndex !== selectionRange.endIndex) {
|
|
count = selectionRange.endIndex - selectionRange.startIndex;
|
|
}
|
|
|
|
if (count && me.cursorInfo && me.cursorInfo.line === selectionRange.end.row && me.cursorInfo.column === selectionRange.end.column) {
|
|
line = selectionRange.start.row;
|
|
col = selectionRange.start.column;
|
|
} else {
|
|
line = selectionRange.end.row;
|
|
col = selectionRange.end.column;
|
|
}
|
|
|
|
me.cursorInfo = {
|
|
line: line,
|
|
column: col,
|
|
count: count
|
|
};
|
|
|
|
if (me.options.statusBar) {
|
|
updateDisplay();
|
|
}
|
|
}, 0);
|
|
} else if (this.aceEditor && this.curserInfoElements) {
|
|
var curserPos = this.aceEditor.getCursorPosition();
|
|
var selectedText = this.aceEditor.getSelectedText();
|
|
line = curserPos.row + 1;
|
|
col = curserPos.column + 1;
|
|
count = selectedText.length;
|
|
me.cursorInfo = {
|
|
line: line,
|
|
column: col,
|
|
count: count
|
|
};
|
|
|
|
if (this.options.statusBar) {
|
|
updateDisplay();
|
|
}
|
|
}
|
|
|
|
function updateDisplay() {
|
|
if (me.curserInfoElements.countVal.innerText !== count) {
|
|
me.curserInfoElements.countVal.innerText = count;
|
|
me.curserInfoElements.countVal.style.display = count ? 'inline' : 'none';
|
|
me.curserInfoElements.countLabel.style.display = count ? 'inline' : 'none';
|
|
}
|
|
|
|
me.curserInfoElements.lnVal.innerText = line;
|
|
me.curserInfoElements.colVal.innerText = col;
|
|
}
|
|
};
|
|
/**
|
|
* emits selection change callback, if given
|
|
* @private
|
|
*/
|
|
|
|
|
|
textmode._emitSelectionChange = function () {
|
|
if (this._selectionChangedHandler) {
|
|
var currentSelection = this.getTextSelection();
|
|
|
|
this._selectionChangedHandler(currentSelection.start, currentSelection.end, currentSelection.text);
|
|
}
|
|
};
|
|
/**
|
|
* refresh ERROR annotations state
|
|
* error annotations are handled by the ace json mode (ace/mode/json)
|
|
* validation annotations are handled by this mode
|
|
* therefore in order to refresh we send only the annotations of error type in order to maintain its state
|
|
* @private
|
|
*/
|
|
|
|
|
|
textmode._refreshAnnotations = function () {
|
|
var session = this.aceEditor && this.aceEditor.getSession();
|
|
|
|
if (session) {
|
|
var errEnnotations = session.getAnnotations().filter(function (annotation) {
|
|
return annotation.type === 'error';
|
|
});
|
|
session.setAnnotations(errEnnotations);
|
|
}
|
|
};
|
|
/**
|
|
* Destroy the editor. Clean up DOM, event listeners, and web workers.
|
|
*/
|
|
|
|
|
|
textmode.destroy = function () {
|
|
// remove old ace editor
|
|
if (this.aceEditor) {
|
|
this.aceEditor.destroy();
|
|
this.aceEditor = null;
|
|
}
|
|
|
|
if (this.frame && this.container && this.frame.parentNode === this.container) {
|
|
this.container.removeChild(this.frame);
|
|
}
|
|
|
|
if (this.modeSwitcher) {
|
|
this.modeSwitcher.destroy();
|
|
this.modeSwitcher = null;
|
|
}
|
|
|
|
this.textarea = null;
|
|
this._debouncedValidate = null; // Removing the FocusTracker set to track the editor's focus event
|
|
|
|
this.frameFocusTracker.destroy();
|
|
};
|
|
/**
|
|
* Compact the code in the text editor
|
|
*/
|
|
|
|
|
|
textmode.compact = function () {
|
|
var json = this.get();
|
|
var text = JSON.stringify(json);
|
|
this.updateText(text);
|
|
};
|
|
/**
|
|
* Format the code in the text editor
|
|
*/
|
|
|
|
|
|
textmode.format = function () {
|
|
var json = this.get();
|
|
var text = JSON.stringify(json, null, this.indentation);
|
|
this.updateText(text);
|
|
};
|
|
/**
|
|
* Repair the code in the text editor
|
|
*/
|
|
|
|
|
|
textmode.repair = function () {
|
|
var text = this.getText();
|
|
|
|
try {
|
|
var repairedText = index_commonjs_default()(text);
|
|
this.updateText(repairedText);
|
|
} catch (err) {// repair was not successful, do nothing
|
|
}
|
|
};
|
|
/**
|
|
* Set focus to the formatter
|
|
*/
|
|
|
|
|
|
textmode.focus = function () {
|
|
if (this.textarea) {
|
|
this.textarea.focus();
|
|
}
|
|
|
|
if (this.aceEditor) {
|
|
this.aceEditor.focus();
|
|
}
|
|
};
|
|
/**
|
|
* Resize the formatter
|
|
*/
|
|
|
|
|
|
textmode.resize = function () {
|
|
if (this.aceEditor) {
|
|
var force = false;
|
|
this.aceEditor.resize(force);
|
|
}
|
|
};
|
|
/**
|
|
* Set json data in the formatter
|
|
* @param {*} json
|
|
*/
|
|
|
|
|
|
textmode.set = function (json) {
|
|
this.setText(JSON.stringify(json, null, this.indentation));
|
|
};
|
|
/**
|
|
* Update data. Same as calling `set` in text/code mode.
|
|
* @param {*} json
|
|
*/
|
|
|
|
|
|
textmode.update = function (json) {
|
|
this.updateText(JSON.stringify(json, null, this.indentation));
|
|
};
|
|
/**
|
|
* Get json data from the formatter
|
|
* @return {*} json
|
|
*/
|
|
|
|
|
|
textmode.get = function () {
|
|
var text = this.getText();
|
|
return (0,util.parse)(text); // this can throw an error
|
|
};
|
|
/**
|
|
* Get the text contents of the editor
|
|
* @return {String} jsonText
|
|
*/
|
|
|
|
|
|
textmode.getText = function () {
|
|
if (this.textarea) {
|
|
return this.textarea.value;
|
|
}
|
|
|
|
if (this.aceEditor) {
|
|
return this.aceEditor.getValue();
|
|
}
|
|
|
|
return '';
|
|
};
|
|
/**
|
|
* Set the text contents of the editor and optionally clear the history
|
|
* @param {String} jsonText
|
|
* @param {boolean} clearHistory Only applicable for mode 'code'
|
|
* @private
|
|
*/
|
|
|
|
|
|
textmode._setText = function (jsonText, clearHistory) {
|
|
var _this4 = this;
|
|
|
|
var text = this.options.escapeUnicode === true ? (0,util.escapeUnicodeChars)(jsonText) : jsonText;
|
|
|
|
if (this.textarea) {
|
|
this.textarea.value = text;
|
|
}
|
|
|
|
if (this.aceEditor) {
|
|
// prevent emitting onChange events while setting new text
|
|
this.onChangeDisabled = true;
|
|
this.aceEditor.setValue(text, -1);
|
|
this.onChangeDisabled = false;
|
|
|
|
if (clearHistory) {
|
|
// prevent initial undo action clearing the initial contents
|
|
var me = this;
|
|
setTimeout(function () {
|
|
if (me.aceEditor) {
|
|
me.aceEditor.session.getUndoManager().reset();
|
|
}
|
|
});
|
|
}
|
|
|
|
setTimeout(function () {
|
|
return _this4._updateHistoryButtons();
|
|
});
|
|
} // validate JSON schema
|
|
|
|
|
|
this._debouncedValidate();
|
|
};
|
|
/**
|
|
* Set the text contents of the editor
|
|
* @param {String} jsonText
|
|
*/
|
|
|
|
|
|
textmode.setText = function (jsonText) {
|
|
this._setText(jsonText, true);
|
|
};
|
|
/**
|
|
* Update the text contents
|
|
* @param {string} jsonText
|
|
*/
|
|
|
|
|
|
textmode.updateText = function (jsonText) {
|
|
// don't update if there are no changes
|
|
if (this.getText() === jsonText) {
|
|
return;
|
|
}
|
|
|
|
this._setText(jsonText, false);
|
|
};
|
|
/**
|
|
* Validate current JSON object against the configured JSON schema
|
|
* Throws an exception when no JSON schema is configured
|
|
*/
|
|
|
|
|
|
textmode.validate = function () {
|
|
var _this5 = this;
|
|
|
|
var schemaErrors = [];
|
|
var parseErrors = [];
|
|
var json;
|
|
|
|
try {
|
|
json = this.get(); // this can fail when there is no valid json
|
|
// execute JSON schema validation (ajv)
|
|
|
|
if (this.validateSchema) {
|
|
var valid = this.validateSchema(json);
|
|
|
|
if (!valid) {
|
|
schemaErrors = this.validateSchema.errors.map(function (error) {
|
|
error.type = 'validation';
|
|
return (0,util.improveSchemaError)(error);
|
|
});
|
|
}
|
|
} // execute custom validation and after than merge and render all errors
|
|
// TODO: implement a better mechanism for only using the last validation action
|
|
|
|
|
|
this.validationSequence = (this.validationSequence || 0) + 1;
|
|
var me = this;
|
|
var seq = this.validationSequence;
|
|
validateCustom(json, this.options.onValidate).then(function (customValidationErrors) {
|
|
// only apply when there was no other validation started whilst resolving async results
|
|
if (seq === me.validationSequence) {
|
|
var errors = schemaErrors.concat(parseErrors).concat(customValidationErrors);
|
|
|
|
me._renderErrors(errors);
|
|
|
|
if (typeof _this5.options.onValidationError === 'function') {
|
|
if ((0,util.isValidationErrorChanged)(errors, _this5.lastSchemaErrors)) {
|
|
_this5.options.onValidationError.call(_this5, errors);
|
|
}
|
|
|
|
_this5.lastSchemaErrors = errors;
|
|
}
|
|
}
|
|
})["catch"](function (err) {
|
|
console.error('Custom validation function did throw an error', err);
|
|
});
|
|
} catch (err) {
|
|
if (this.getText()) {
|
|
// try to extract the line number from the jsonlint error message
|
|
var match = /\w*line\s*(\d+)\w*/g.exec(err.message);
|
|
var line;
|
|
|
|
if (match) {
|
|
line = +match[1];
|
|
}
|
|
|
|
parseErrors = [{
|
|
type: 'error',
|
|
message: err.message.replace(/\n/g, '<br>'),
|
|
line: line
|
|
}];
|
|
}
|
|
|
|
this._renderErrors(parseErrors);
|
|
|
|
if (typeof this.options.onValidationError === 'function') {
|
|
if ((0,util.isValidationErrorChanged)(parseErrors, this.lastSchemaErrors)) {
|
|
this.options.onValidationError.call(this, parseErrors);
|
|
}
|
|
|
|
this.lastSchemaErrors = parseErrors;
|
|
}
|
|
}
|
|
};
|
|
|
|
textmode._renderErrors = function (errors) {
|
|
var jsonText = this.getText();
|
|
var errorPaths = [];
|
|
errors.reduce(function (acc, curr) {
|
|
if (typeof curr.dataPath === 'string' && acc.indexOf(curr.dataPath) === -1) {
|
|
acc.push(curr.dataPath);
|
|
}
|
|
|
|
return acc;
|
|
}, errorPaths);
|
|
var errorLocations = (0,util.getPositionForPath)(jsonText, errorPaths); // render annotations in Ace Editor (if any)
|
|
|
|
if (this.aceEditor) {
|
|
this.annotations = errorLocations.map(function (errLoc) {
|
|
var validationErrors = errors.filter(function (err) {
|
|
return err.dataPath === errLoc.path;
|
|
});
|
|
var message = validationErrors.map(function (err) {
|
|
return err.message;
|
|
}).join('\n');
|
|
|
|
if (message) {
|
|
return {
|
|
row: errLoc.line,
|
|
column: errLoc.column,
|
|
text: 'Schema validation error' + (validationErrors.length !== 1 ? 's' : '') + ': \n' + message,
|
|
type: 'warning',
|
|
source: 'jsoneditor'
|
|
};
|
|
}
|
|
|
|
return {};
|
|
});
|
|
|
|
this._refreshAnnotations();
|
|
} // render errors in the errors table (if any)
|
|
|
|
|
|
this.errorTable.setErrors(errors, errorLocations); // update the height of the ace editor
|
|
|
|
if (this.aceEditor) {
|
|
var force = false;
|
|
this.aceEditor.resize(force);
|
|
}
|
|
};
|
|
/**
|
|
* Get the selection details
|
|
* @returns {{start:{row:Number, column:Number},end:{row:Number, column:Number},text:String}}
|
|
*/
|
|
|
|
|
|
textmode.getTextSelection = function () {
|
|
var selection = {};
|
|
|
|
if (this.textarea) {
|
|
var selectionRange = (0,util.getInputSelection)(this.textarea);
|
|
|
|
if (this.cursorInfo && this.cursorInfo.line === selectionRange.end.row && this.cursorInfo.column === selectionRange.end.column) {
|
|
// selection direction is bottom => up
|
|
selection.start = selectionRange.end;
|
|
selection.end = selectionRange.start;
|
|
} else {
|
|
selection = selectionRange;
|
|
}
|
|
|
|
return {
|
|
start: selection.start,
|
|
end: selection.end,
|
|
text: this.textarea.value.substring(selectionRange.startIndex, selectionRange.endIndex)
|
|
};
|
|
}
|
|
|
|
if (this.aceEditor) {
|
|
var aceSelection = this.aceEditor.getSelection();
|
|
var selectedText = this.aceEditor.getSelectedText();
|
|
var range = aceSelection.getRange();
|
|
var lead = aceSelection.getSelectionLead();
|
|
|
|
if (lead.row === range.end.row && lead.column === range.end.column) {
|
|
selection = range;
|
|
} else {
|
|
// selection direction is bottom => up
|
|
selection.start = range.end;
|
|
selection.end = range.start;
|
|
}
|
|
|
|
return {
|
|
start: {
|
|
row: selection.start.row + 1,
|
|
column: selection.start.column + 1
|
|
},
|
|
end: {
|
|
row: selection.end.row + 1,
|
|
column: selection.end.column + 1
|
|
},
|
|
text: selectedText
|
|
};
|
|
}
|
|
};
|
|
/**
|
|
* Callback registration for selection change
|
|
* @param {selectionCallback} callback
|
|
*
|
|
* @callback selectionCallback
|
|
*/
|
|
|
|
|
|
textmode.onTextSelectionChange = function (callback) {
|
|
if (typeof callback === 'function') {
|
|
this._selectionChangedHandler = (0,util.debounce)(callback, this.DEBOUNCE_INTERVAL);
|
|
}
|
|
};
|
|
/**
|
|
* Set selection on editor's text
|
|
* @param {{row:Number, column:Number}} startPos selection start position
|
|
* @param {{row:Number, column:Number}} endPos selected end position
|
|
*/
|
|
|
|
|
|
textmode.setTextSelection = function (startPos, endPos) {
|
|
if (!startPos || !endPos) return;
|
|
|
|
if (this.textarea) {
|
|
var startIndex = (0,util.getIndexForPosition)(this.textarea, startPos.row, startPos.column);
|
|
var endIndex = (0,util.getIndexForPosition)(this.textarea, endPos.row, endPos.column);
|
|
|
|
if (startIndex > -1 && endIndex > -1) {
|
|
if (this.textarea.setSelectionRange) {
|
|
this.textarea.focus();
|
|
this.textarea.setSelectionRange(startIndex, endIndex);
|
|
} else if (this.textarea.createTextRange) {
|
|
// IE < 9
|
|
var range = this.textarea.createTextRange();
|
|
range.collapse(true);
|
|
range.moveEnd('character', endIndex);
|
|
range.moveStart('character', startIndex);
|
|
range.select();
|
|
}
|
|
|
|
var rows = (this.textarea.value.match(/\n/g) || []).length + 1;
|
|
var lineHeight = this.textarea.scrollHeight / rows;
|
|
var selectionScrollPos = startPos.row * lineHeight;
|
|
this.textarea.scrollTop = selectionScrollPos > this.textarea.clientHeight ? selectionScrollPos - this.textarea.clientHeight / 2 : 0;
|
|
}
|
|
} else if (this.aceEditor) {
|
|
var _range = {
|
|
start: {
|
|
row: startPos.row - 1,
|
|
column: startPos.column - 1
|
|
},
|
|
end: {
|
|
row: endPos.row - 1,
|
|
column: endPos.column - 1
|
|
}
|
|
};
|
|
this.aceEditor.selection.setRange(_range);
|
|
this.aceEditor.scrollToLine(startPos.row - 1, true);
|
|
}
|
|
};
|
|
|
|
function load() {
|
|
try {
|
|
this.format();
|
|
} catch (err) {// in case of an error, just move on, failing formatting is not a big deal
|
|
}
|
|
} // define modes
|
|
|
|
|
|
var textModeMixins = [{
|
|
mode: 'text',
|
|
mixin: textmode,
|
|
data: 'text',
|
|
load: load
|
|
}, {
|
|
mode: 'code',
|
|
mixin: textmode,
|
|
data: 'text',
|
|
load: load
|
|
}];
|
|
|
|
/***/ }),
|
|
|
|
/***/ 8038:
|
|
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
|
|
|
"use strict";
|
|
// ESM COMPAT FLAG
|
|
__webpack_require__.r(__webpack_exports__);
|
|
|
|
// EXPORTS
|
|
__webpack_require__.d(__webpack_exports__, {
|
|
"treeModeMixins": function() { return /* binding */ treeModeMixins; }
|
|
});
|
|
|
|
;// CONCATENATED MODULE: ./src/js/autocomplete.js
|
|
|
|
|
|
var defaultFilterFunction = {
|
|
start: function start(token, match, config) {
|
|
return match.indexOf(token) === 0;
|
|
},
|
|
contain: function contain(token, match, config) {
|
|
return match.indexOf(token) > -1;
|
|
}
|
|
};
|
|
function autocomplete(config) {
|
|
config = config || {};
|
|
config.filter = config.filter || 'start';
|
|
config.trigger = config.trigger || 'keydown';
|
|
config.confirmKeys = config.confirmKeys || [39, 35, 9]; // right, end, tab
|
|
|
|
config.caseSensitive = config.caseSensitive || false; // autocomplete case sensitive
|
|
|
|
var fontSize = '';
|
|
var fontFamily = '';
|
|
var wrapper = document.createElement('div');
|
|
wrapper.style.position = 'relative';
|
|
wrapper.style.outline = '0';
|
|
wrapper.style.border = '0';
|
|
wrapper.style.margin = '0';
|
|
wrapper.style.padding = '0';
|
|
var dropDown = document.createElement('div');
|
|
dropDown.className = 'autocomplete dropdown';
|
|
dropDown.style.position = 'absolute';
|
|
dropDown.style.visibility = 'hidden';
|
|
var spacer;
|
|
var leftSide; // <-- it will contain the leftSide part of the textfield (the bit that was already autocompleted)
|
|
|
|
var createDropDownController = function createDropDownController(elem, rs) {
|
|
var rows = [];
|
|
var ix = 0;
|
|
var oldIndex = -1; // TODO: move this styling in JS to SCSS
|
|
|
|
var onMouseOver = function onMouseOver() {
|
|
this.style.backgroundColor = '#ddd';
|
|
};
|
|
|
|
var onMouseOut = function onMouseOut() {
|
|
this.style.backgroundColor = '';
|
|
};
|
|
|
|
var onMouseDown = function onMouseDown() {
|
|
p.hide();
|
|
p.onmouseselection(this.__hint, p.rs);
|
|
};
|
|
|
|
var p = {
|
|
rs: rs,
|
|
hide: function hide() {
|
|
elem.style.visibility = 'hidden'; // rs.hideDropDown();
|
|
},
|
|
refresh: function refresh(token, array) {
|
|
elem.style.visibility = 'hidden';
|
|
ix = 0;
|
|
elem.textContent = '';
|
|
var vph = window.innerHeight || document.documentElement.clientHeight;
|
|
var rect = elem.parentNode.getBoundingClientRect();
|
|
var distanceToTop = rect.top - 6; // heuristic give 6px
|
|
|
|
var distanceToBottom = vph - rect.bottom - 6; // distance from the browser border.
|
|
|
|
rows = [];
|
|
var filterFn = typeof config.filter === 'function' ? config.filter : defaultFilterFunction[config.filter];
|
|
var filtered = !filterFn ? [] : array.filter(function (match) {
|
|
return filterFn(config.caseSensitive ? token : token.toLowerCase(), config.caseSensitive ? match : match.toLowerCase(), config);
|
|
});
|
|
rows = filtered.map(function (row) {
|
|
var divRow = document.createElement('div');
|
|
divRow.className = 'item'; // divRow.style.color = config.color;
|
|
|
|
divRow.onmouseover = onMouseOver;
|
|
divRow.onmouseout = onMouseOut;
|
|
divRow.onmousedown = onMouseDown;
|
|
divRow.__hint = row;
|
|
divRow.textContent = '';
|
|
divRow.appendChild(document.createTextNode(row.substring(0, token.length)));
|
|
var b = document.createElement('b');
|
|
b.appendChild(document.createTextNode(row.substring(token.length)));
|
|
divRow.appendChild(b);
|
|
elem.appendChild(divRow);
|
|
return divRow;
|
|
});
|
|
|
|
if (rows.length === 0) {
|
|
return; // nothing to show.
|
|
}
|
|
|
|
if (rows.length === 1 && (token.toLowerCase() === rows[0].__hint.toLowerCase() && !config.caseSensitive || token === rows[0].__hint && config.caseSensitive)) {
|
|
return; // do not show the dropDown if it has only one element which matches what we have just displayed.
|
|
}
|
|
|
|
if (rows.length < 2) return;
|
|
p.highlight(0);
|
|
|
|
if (distanceToTop > distanceToBottom * 3) {
|
|
// Heuristic (only when the distance to the to top is 4 times more than distance to the bottom
|
|
elem.style.maxHeight = distanceToTop + 'px'; // we display the dropDown on the top of the input text
|
|
|
|
elem.style.top = '';
|
|
elem.style.bottom = '100%';
|
|
} else {
|
|
elem.style.top = '100%';
|
|
elem.style.bottom = '';
|
|
elem.style.maxHeight = distanceToBottom + 'px';
|
|
}
|
|
|
|
elem.style.visibility = 'visible';
|
|
},
|
|
highlight: function highlight(index) {
|
|
if (oldIndex !== -1 && rows[oldIndex]) {
|
|
rows[oldIndex].className = 'item';
|
|
}
|
|
|
|
rows[index].className = 'item hover';
|
|
oldIndex = index;
|
|
},
|
|
move: function move(step) {
|
|
// moves the selection either up or down (unless it's not possible) step is either +1 or -1.
|
|
if (elem.style.visibility === 'hidden') return ''; // nothing to move if there is no dropDown. (this happens if the user hits escape and then down or up)
|
|
|
|
if (ix + step === -1 || ix + step === rows.length) return rows[ix].__hint; // NO CIRCULAR SCROLLING.
|
|
|
|
ix += step;
|
|
p.highlight(ix);
|
|
return rows[ix].__hint; // txtShadow.value = uRows[uIndex].__hint ;
|
|
},
|
|
onmouseselection: function onmouseselection() {} // it will be overwritten.
|
|
|
|
};
|
|
return p;
|
|
};
|
|
|
|
function setEndOfContenteditable(contentEditableElement) {
|
|
var range, selection;
|
|
|
|
if (document.createRange) {
|
|
// Firefox, Chrome, Opera, Safari, IE 9+
|
|
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
|
|
} else if (document.selection) {
|
|
// IE 8 and lower
|
|
range = document.body.createTextRange(); // Create a range (a range is a like the selection but invisible)
|
|
|
|
range.moveToElementText(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
|
|
|
|
range.select(); // Select the range (make it the visible selection
|
|
}
|
|
}
|
|
|
|
function calculateWidthForText(text) {
|
|
if (spacer === undefined) {
|
|
// on first call only.
|
|
spacer = document.createElement('span');
|
|
spacer.style.visibility = 'hidden';
|
|
spacer.style.position = 'fixed';
|
|
spacer.style.outline = '0';
|
|
spacer.style.margin = '0';
|
|
spacer.style.padding = '0';
|
|
spacer.style.border = '0';
|
|
spacer.style.left = '0';
|
|
spacer.style.whiteSpace = 'pre';
|
|
spacer.style.fontSize = fontSize;
|
|
spacer.style.fontFamily = fontFamily;
|
|
spacer.style.fontWeight = 'normal';
|
|
document.body.appendChild(spacer);
|
|
}
|
|
|
|
spacer.textContent = text;
|
|
return spacer.getBoundingClientRect().right;
|
|
}
|
|
|
|
var rs = {
|
|
onArrowDown: function onArrowDown() {},
|
|
// defaults to no action.
|
|
onArrowUp: function onArrowUp() {},
|
|
// defaults to no action.
|
|
onEnter: function onEnter() {},
|
|
// defaults to no action.
|
|
onTab: function onTab() {},
|
|
// defaults to no action.
|
|
startFrom: 0,
|
|
options: [],
|
|
element: null,
|
|
elementHint: null,
|
|
elementStyle: null,
|
|
wrapper: wrapper,
|
|
// Only to allow easy access to the HTML elements to the final user (possibly for minor customizations)
|
|
show: function show(element, startPos, options) {
|
|
var _this = this;
|
|
|
|
this.startFrom = startPos;
|
|
this.wrapper.remove();
|
|
|
|
if (this.elementHint) {
|
|
this.elementHint.remove();
|
|
this.elementHint = null;
|
|
}
|
|
|
|
if (fontSize === '') {
|
|
fontSize = window.getComputedStyle(element).getPropertyValue('font-size');
|
|
}
|
|
|
|
if (fontFamily === '') {
|
|
fontFamily = window.getComputedStyle(element).getPropertyValue('font-family');
|
|
}
|
|
|
|
dropDown.style.marginLeft = '0';
|
|
dropDown.style.marginTop = element.getBoundingClientRect().height + 'px';
|
|
this.options = options.map(String);
|
|
|
|
if (this.element !== element) {
|
|
this.element = element;
|
|
this.elementStyle = {
|
|
zIndex: this.element.style.zIndex,
|
|
position: this.element.style.position,
|
|
backgroundColor: this.element.style.backgroundColor,
|
|
borderColor: this.element.style.borderColor
|
|
};
|
|
}
|
|
|
|
this.element.style.zIndex = 3;
|
|
this.element.style.position = 'relative';
|
|
this.element.style.backgroundColor = 'transparent';
|
|
this.element.style.borderColor = 'transparent';
|
|
this.elementHint = element.cloneNode();
|
|
this.elementHint.className = 'autocomplete hint';
|
|
this.elementHint.style.zIndex = 2;
|
|
this.elementHint.style.position = 'absolute';
|
|
|
|
this.elementHint.onfocus = function () {
|
|
_this.element.focus();
|
|
};
|
|
|
|
if (this.element.addEventListener) {
|
|
this.element.removeEventListener('keydown', keyDownHandler);
|
|
this.element.addEventListener('keydown', keyDownHandler, false);
|
|
this.element.removeEventListener('blur', onBlurHandler);
|
|
this.element.addEventListener('blur', onBlurHandler, false);
|
|
}
|
|
|
|
wrapper.appendChild(this.elementHint);
|
|
wrapper.appendChild(dropDown);
|
|
element.parentElement.appendChild(wrapper);
|
|
this.repaint(element);
|
|
},
|
|
setText: function setText(text) {
|
|
this.element.innerText = text;
|
|
},
|
|
getText: function getText() {
|
|
return this.element.innerText;
|
|
},
|
|
hideDropDown: function hideDropDown() {
|
|
this.wrapper.remove();
|
|
|
|
if (this.elementHint) {
|
|
this.elementHint.remove();
|
|
this.elementHint = null;
|
|
dropDownController.hide();
|
|
this.element.style.zIndex = this.elementStyle.zIndex;
|
|
this.element.style.position = this.elementStyle.position;
|
|
this.element.style.backgroundColor = this.elementStyle.backgroundColor;
|
|
this.element.style.borderColor = this.elementStyle.borderColor;
|
|
}
|
|
},
|
|
repaint: function repaint(element) {
|
|
var text = element.innerText;
|
|
text = text.replace('\n', '');
|
|
var optionsLength = this.options.length; // breaking text in leftSide and token.
|
|
|
|
var token = text.substring(this.startFrom);
|
|
leftSide = text.substring(0, this.startFrom);
|
|
|
|
for (var i = 0; i < optionsLength; i++) {
|
|
var opt = this.options[i];
|
|
|
|
if (!config.caseSensitive && opt.toLowerCase().indexOf(token.toLowerCase()) === 0 || config.caseSensitive && opt.indexOf(token) === 0) {
|
|
// <-- how about upperCase vs. lowercase
|
|
this.elementHint.innerText = leftSide + token + opt.substring(token.length);
|
|
this.elementHint.realInnerText = leftSide + opt;
|
|
break;
|
|
}
|
|
} // moving the dropDown and refreshing it.
|
|
|
|
|
|
dropDown.style.left = calculateWidthForText(leftSide) + 'px';
|
|
dropDownController.refresh(token, this.options);
|
|
this.elementHint.style.width = calculateWidthForText(this.elementHint.innerText) + 10 + 'px';
|
|
var wasDropDownHidden = dropDown.style.visibility === 'hidden';
|
|
|
|
if (!wasDropDownHidden) {
|
|
this.elementHint.style.width = calculateWidthForText(this.elementHint.innerText) + dropDown.clientWidth + 'px';
|
|
}
|
|
}
|
|
};
|
|
var dropDownController = createDropDownController(dropDown, rs);
|
|
|
|
var keyDownHandler = function (e) {
|
|
// console.log("Keydown:" + e.keyCode);
|
|
e = e || window.event;
|
|
var keyCode = e.keyCode;
|
|
if (this.elementHint == null) return;
|
|
|
|
if (keyCode === 33) {
|
|
return;
|
|
} // page up (do nothing)
|
|
|
|
|
|
if (keyCode === 34) {
|
|
return;
|
|
} // page down (do nothing);
|
|
|
|
|
|
if (keyCode === 27) {
|
|
// escape
|
|
rs.hideDropDown();
|
|
rs.element.focus();
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
return;
|
|
}
|
|
|
|
var text = this.element.innerText;
|
|
text = text.replace('\n', '');
|
|
|
|
if (config.confirmKeys.indexOf(keyCode) >= 0) {
|
|
// (autocomplete triggered)
|
|
if (keyCode === 9) {
|
|
if (this.elementHint.innerText.length === 0) {
|
|
rs.onTab();
|
|
}
|
|
}
|
|
|
|
if (this.elementHint.innerText.length > 0) {
|
|
// if there is a hint
|
|
if (this.element.innerText !== this.elementHint.realInnerText) {
|
|
this.element.innerText = this.elementHint.realInnerText;
|
|
rs.hideDropDown();
|
|
setEndOfContenteditable(this.element);
|
|
|
|
if (keyCode === 9) {
|
|
rs.element.focus();
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
}
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if (keyCode === 13) {
|
|
// enter (autocomplete triggered)
|
|
if (this.elementHint.innerText.length === 0) {
|
|
// if there is a hint
|
|
rs.onEnter();
|
|
} else {
|
|
var wasDropDownHidden = dropDown.style.visibility === 'hidden';
|
|
dropDownController.hide();
|
|
|
|
if (wasDropDownHidden) {
|
|
rs.hideDropDown();
|
|
rs.element.focus();
|
|
rs.onEnter();
|
|
return;
|
|
}
|
|
|
|
this.element.innerText = this.elementHint.realInnerText;
|
|
rs.hideDropDown();
|
|
setEndOfContenteditable(this.element);
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if (keyCode === 40) {
|
|
// down
|
|
var token = text.substring(this.startFrom);
|
|
var m = dropDownController.move(+1);
|
|
|
|
if (m === '') {
|
|
rs.onArrowDown();
|
|
}
|
|
|
|
this.elementHint.innerText = leftSide + token + m.substring(token.length);
|
|
this.elementHint.realInnerText = leftSide + m;
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
return;
|
|
}
|
|
|
|
if (keyCode === 38) {
|
|
// up
|
|
var _token = text.substring(this.startFrom);
|
|
|
|
var _m = dropDownController.move(-1);
|
|
|
|
if (_m === '') {
|
|
rs.onArrowUp();
|
|
}
|
|
|
|
this.elementHint.innerText = leftSide + _token + _m.substring(_token.length);
|
|
this.elementHint.realInnerText = leftSide + _m;
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
}
|
|
}.bind(rs);
|
|
|
|
var onBlurHandler = function onBlurHandler(e) {
|
|
rs.hideDropDown(); // console.log("Lost focus.");
|
|
};
|
|
|
|
dropDownController.onmouseselection = function (text, rs) {
|
|
rs.element.innerText = rs.elementHint.innerText = leftSide + text;
|
|
rs.hideDropDown();
|
|
window.setTimeout(function () {
|
|
rs.element.focus();
|
|
setEndOfContenteditable(rs.element);
|
|
}, 1);
|
|
};
|
|
|
|
return rs;
|
|
}
|
|
// EXTERNAL MODULE: ./src/js/ContextMenu.js
|
|
var ContextMenu = __webpack_require__(897);
|
|
// EXTERNAL MODULE: ./src/js/FocusTracker.js
|
|
var FocusTracker = __webpack_require__(2474);
|
|
;// CONCATENATED MODULE: ./src/js/Highlighter.js
|
|
|
|
/**
|
|
* The highlighter can highlight/unhighlight a node, and
|
|
* animate the visibility of a context menu.
|
|
* @constructor Highlighter
|
|
*/
|
|
|
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
|
|
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
|
|
|
|
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
|
|
|
|
var Highlighter = /*#__PURE__*/function () {
|
|
function Highlighter() {
|
|
_classCallCheck(this, Highlighter);
|
|
|
|
this.locked = false;
|
|
}
|
|
/**
|
|
* Hightlight given node and its childs
|
|
* @param {Node} node
|
|
*/
|
|
|
|
|
|
_createClass(Highlighter, [{
|
|
key: "highlight",
|
|
value: function highlight(node) {
|
|
if (this.locked) {
|
|
return;
|
|
}
|
|
|
|
if (this.node !== node) {
|
|
// unhighlight current node
|
|
if (this.node) {
|
|
this.node.setHighlight(false);
|
|
} // highlight new node
|
|
|
|
|
|
this.node = node;
|
|
this.node.setHighlight(true);
|
|
} // cancel any current timeout
|
|
|
|
|
|
this._cancelUnhighlight();
|
|
}
|
|
/**
|
|
* Unhighlight currently highlighted node.
|
|
* Will be done after a delay
|
|
*/
|
|
|
|
}, {
|
|
key: "unhighlight",
|
|
value: function unhighlight() {
|
|
if (this.locked) {
|
|
return;
|
|
}
|
|
|
|
var me = this;
|
|
|
|
if (this.node) {
|
|
this._cancelUnhighlight(); // do the unhighlighting after a small delay, to prevent re-highlighting
|
|
// the same node when moving from the drag-icon to the contextmenu-icon
|
|
// or vice versa.
|
|
|
|
|
|
this.unhighlightTimer = setTimeout(function () {
|
|
me.node.setHighlight(false);
|
|
me.node = undefined;
|
|
me.unhighlightTimer = undefined;
|
|
}, 0);
|
|
}
|
|
}
|
|
/**
|
|
* Cancel an unhighlight action (if before the timeout of the unhighlight action)
|
|
* @private
|
|
*/
|
|
|
|
}, {
|
|
key: "_cancelUnhighlight",
|
|
value: function _cancelUnhighlight() {
|
|
if (this.unhighlightTimer) {
|
|
clearTimeout(this.unhighlightTimer);
|
|
this.unhighlightTimer = undefined;
|
|
}
|
|
}
|
|
/**
|
|
* Lock highlighting or unhighlighting nodes.
|
|
* methods highlight and unhighlight do not work while locked.
|
|
*/
|
|
|
|
}, {
|
|
key: "lock",
|
|
value: function lock() {
|
|
this.locked = true;
|
|
}
|
|
/**
|
|
* Unlock highlighting or unhighlighting nodes
|
|
*/
|
|
|
|
}, {
|
|
key: "unlock",
|
|
value: function unlock() {
|
|
this.locked = false;
|
|
}
|
|
}]);
|
|
|
|
return Highlighter;
|
|
}();
|
|
// EXTERNAL MODULE: ./src/js/i18n.js
|
|
var i18n = __webpack_require__(7907);
|
|
// EXTERNAL MODULE: ./src/js/jmespathQuery.js
|
|
var jmespathQuery = __webpack_require__(6056);
|
|
// EXTERNAL MODULE: ./src/js/ModeSwitcher.js
|
|
var ModeSwitcher = __webpack_require__(6617);
|
|
// EXTERNAL MODULE: ./node_modules/javascript-natural-sort/naturalSort.js
|
|
var naturalSort = __webpack_require__(233);
|
|
var naturalSort_default = /*#__PURE__*/__webpack_require__.n(naturalSort);
|
|
// EXTERNAL MODULE: ./src/js/createAbsoluteAnchor.js
|
|
var createAbsoluteAnchor = __webpack_require__(2602);
|
|
// EXTERNAL MODULE: ./src/js/util.js
|
|
var util = __webpack_require__(9791);
|
|
;// CONCATENATED MODULE: ./src/js/appendNodeFactory.js
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
* A factory function to create an AppendNode, which depends on a Node
|
|
* @param {Node} Node
|
|
*/
|
|
|
|
function appendNodeFactory(Node) {
|
|
/**
|
|
* @constructor AppendNode
|
|
* @extends Node
|
|
* @param {TreeEditor} editor
|
|
* Create a new AppendNode. This is a special node which is created at the
|
|
* end of the list with childs for an object or array
|
|
*/
|
|
function AppendNode(editor) {
|
|
/** @type {TreeEditor} */
|
|
this.editor = editor;
|
|
this.dom = {};
|
|
}
|
|
|
|
AppendNode.prototype = new Node();
|
|
/**
|
|
* Return a table row with an append button.
|
|
* @return {Element} dom TR element
|
|
*/
|
|
|
|
AppendNode.prototype.getDom = function () {
|
|
// TODO: implement a new solution for the append node
|
|
var dom = this.dom;
|
|
|
|
if (dom.tr) {
|
|
return dom.tr;
|
|
}
|
|
|
|
this._updateEditability(); // a row for the append button
|
|
|
|
|
|
var trAppend = document.createElement('tr');
|
|
trAppend.className = 'jsoneditor-append';
|
|
trAppend.node = this;
|
|
dom.tr = trAppend; // TODO: consistent naming
|
|
|
|
if (this.editor.options.mode === 'tree') {
|
|
// a cell for the dragarea column
|
|
dom.tdDrag = document.createElement('td'); // create context menu
|
|
|
|
var tdMenu = document.createElement('td');
|
|
dom.tdMenu = tdMenu;
|
|
var menu = document.createElement('button');
|
|
menu.type = 'button';
|
|
menu.className = 'jsoneditor-button jsoneditor-contextmenu-button';
|
|
menu.title = 'Click to open the actions menu (Ctrl+M)';
|
|
dom.menu = menu;
|
|
tdMenu.appendChild(dom.menu);
|
|
} // a cell for the contents (showing text 'empty')
|
|
|
|
|
|
var tdAppend = document.createElement('td');
|
|
var domText = document.createElement('div');
|
|
domText.appendChild(document.createTextNode('(' + (0,i18n/* translate */.Iu)('empty') + ')'));
|
|
domText.className = 'jsoneditor-readonly';
|
|
tdAppend.appendChild(domText);
|
|
dom.td = tdAppend;
|
|
dom.text = domText;
|
|
this.updateDom();
|
|
return trAppend;
|
|
};
|
|
/**
|
|
* Append node doesn't have a path
|
|
* @returns {null}
|
|
*/
|
|
|
|
|
|
AppendNode.prototype.getPath = function () {
|
|
return null;
|
|
};
|
|
/**
|
|
* Append node doesn't have an index
|
|
* @returns {null}
|
|
*/
|
|
|
|
|
|
AppendNode.prototype.getIndex = function () {
|
|
return null;
|
|
};
|
|
/**
|
|
* Update the HTML dom of the Node
|
|
*/
|
|
|
|
|
|
AppendNode.prototype.updateDom = function (options) {
|
|
var dom = this.dom;
|
|
var tdAppend = dom.td;
|
|
|
|
if (tdAppend) {
|
|
tdAppend.style.paddingLeft = this.getLevel() * 24 + 26 + 'px'; // TODO: not so nice hard coded offset
|
|
}
|
|
|
|
var domText = dom.text;
|
|
|
|
if (domText) {
|
|
domText.firstChild.nodeValue = '(' + (0,i18n/* translate */.Iu)('empty') + ' ' + this.parent.type + ')';
|
|
} // attach or detach the contents of the append node:
|
|
// hide when the parent has childs, show when the parent has no childs
|
|
|
|
|
|
var trAppend = dom.tr;
|
|
|
|
if (!this.isVisible()) {
|
|
if (dom.tr.firstChild) {
|
|
if (dom.tdDrag) {
|
|
trAppend.removeChild(dom.tdDrag);
|
|
}
|
|
|
|
if (dom.tdMenu) {
|
|
trAppend.removeChild(dom.tdMenu);
|
|
}
|
|
|
|
trAppend.removeChild(tdAppend);
|
|
}
|
|
} else {
|
|
if (!dom.tr.firstChild) {
|
|
if (dom.tdDrag) {
|
|
trAppend.appendChild(dom.tdDrag);
|
|
}
|
|
|
|
if (dom.tdMenu) {
|
|
trAppend.appendChild(dom.tdMenu);
|
|
}
|
|
|
|
trAppend.appendChild(tdAppend);
|
|
}
|
|
}
|
|
};
|
|
/**
|
|
* Check whether the AppendNode is currently visible.
|
|
* the AppendNode is visible when its parent has no childs (i.e. is empty).
|
|
* @return {boolean} isVisible
|
|
*/
|
|
|
|
|
|
AppendNode.prototype.isVisible = function () {
|
|
return this.parent.childs.length === 0;
|
|
};
|
|
/**
|
|
* Show a contextmenu for this node
|
|
* @param {HTMLElement} anchor The element to attach the menu to.
|
|
* @param {function} [onClose] Callback method called when the context menu
|
|
* is being closed.
|
|
*/
|
|
|
|
|
|
AppendNode.prototype.showContextMenu = function (anchor, onClose) {
|
|
var node = this;
|
|
var appendSubmenu = [{
|
|
text: (0,i18n/* translate */.Iu)('auto'),
|
|
className: 'jsoneditor-type-auto',
|
|
title: (0,i18n/* translate */.Iu)('autoType'),
|
|
click: function click() {
|
|
node._onAppend('', '', 'auto');
|
|
}
|
|
}, {
|
|
text: (0,i18n/* translate */.Iu)('array'),
|
|
className: 'jsoneditor-type-array',
|
|
title: (0,i18n/* translate */.Iu)('arrayType'),
|
|
click: function click() {
|
|
node._onAppend('', []);
|
|
}
|
|
}, {
|
|
text: (0,i18n/* translate */.Iu)('object'),
|
|
className: 'jsoneditor-type-object',
|
|
title: (0,i18n/* translate */.Iu)('objectType'),
|
|
click: function click() {
|
|
node._onAppend('', {});
|
|
}
|
|
}, {
|
|
text: (0,i18n/* translate */.Iu)('string'),
|
|
className: 'jsoneditor-type-string',
|
|
title: (0,i18n/* translate */.Iu)('stringType'),
|
|
click: function click() {
|
|
node._onAppend('', '', 'string');
|
|
}
|
|
}];
|
|
node.addTemplates(appendSubmenu, true);
|
|
var items = [// create append button
|
|
{
|
|
text: (0,i18n/* translate */.Iu)('appendText'),
|
|
title: (0,i18n/* translate */.Iu)('appendTitleAuto'),
|
|
submenuTitle: (0,i18n/* translate */.Iu)('appendSubmenuTitle'),
|
|
className: 'jsoneditor-insert',
|
|
click: function click() {
|
|
node._onAppend('', '', 'auto');
|
|
},
|
|
submenu: appendSubmenu
|
|
}];
|
|
|
|
if (this.editor.options.onCreateMenu) {
|
|
var path = node.parent.getPath();
|
|
items = this.editor.options.onCreateMenu(items, {
|
|
type: 'append',
|
|
path: path,
|
|
paths: [path]
|
|
});
|
|
}
|
|
|
|
var menu = new ContextMenu/* ContextMenu */.x(items, {
|
|
close: onClose
|
|
});
|
|
menu.show(anchor, this.editor.getPopupAnchor());
|
|
};
|
|
/**
|
|
* Handle an event. The event is caught centrally by the editor
|
|
* @param {Event} event
|
|
*/
|
|
|
|
|
|
AppendNode.prototype.onEvent = function (event) {
|
|
var type = event.type;
|
|
var target = event.target || event.srcElement;
|
|
var dom = this.dom; // highlight the append nodes parent
|
|
|
|
var menu = dom.menu;
|
|
|
|
if (target === menu) {
|
|
if (type === 'mouseover') {
|
|
this.editor.highlighter.highlight(this.parent);
|
|
} else if (type === 'mouseout') {
|
|
this.editor.highlighter.unhighlight();
|
|
}
|
|
} // context menu events
|
|
|
|
|
|
if (type === 'click' && target === dom.menu) {
|
|
var highlighter = this.editor.highlighter;
|
|
highlighter.highlight(this.parent);
|
|
highlighter.lock();
|
|
(0,util.addClassName)(dom.menu, 'jsoneditor-selected');
|
|
this.showContextMenu(dom.menu, function () {
|
|
(0,util.removeClassName)(dom.menu, 'jsoneditor-selected');
|
|
highlighter.unlock();
|
|
highlighter.unhighlight();
|
|
});
|
|
}
|
|
|
|
if (type === 'keydown') {
|
|
this.onKeyDown(event);
|
|
}
|
|
};
|
|
|
|
return AppendNode;
|
|
}
|
|
;// CONCATENATED MODULE: ./src/js/showMoreNodeFactory.js
|
|
|
|
|
|
|
|
/**
|
|
* A factory function to create an ShowMoreNode, which depends on a Node
|
|
* @param {function} Node
|
|
*/
|
|
|
|
function showMoreNodeFactory(Node) {
|
|
/**
|
|
* @constructor ShowMoreNode
|
|
* @extends Node
|
|
* @param {TreeEditor} editor
|
|
* @param {Node} parent
|
|
* Create a new ShowMoreNode. This is a special node which is created
|
|
* for arrays or objects having more than 100 items
|
|
*/
|
|
function ShowMoreNode(editor, parent) {
|
|
/** @type {TreeEditor} */
|
|
this.editor = editor;
|
|
this.parent = parent;
|
|
this.dom = {};
|
|
}
|
|
|
|
ShowMoreNode.prototype = new Node();
|
|
/**
|
|
* Return a table row with an append button.
|
|
* @return {Element} dom TR element
|
|
*/
|
|
|
|
ShowMoreNode.prototype.getDom = function () {
|
|
if (this.dom.tr) {
|
|
return this.dom.tr;
|
|
}
|
|
|
|
this._updateEditability(); // display "show more"
|
|
|
|
|
|
if (!this.dom.tr) {
|
|
var me = this;
|
|
var parent = this.parent;
|
|
var showMoreButton = document.createElement('a');
|
|
showMoreButton.appendChild(document.createTextNode((0,i18n/* translate */.Iu)('showMore')));
|
|
showMoreButton.href = '#';
|
|
|
|
showMoreButton.onclick = function (event) {
|
|
// TODO: use callback instead of accessing a method of the parent
|
|
parent.visibleChilds = Math.floor(parent.visibleChilds / parent.getMaxVisibleChilds() + 1) * parent.getMaxVisibleChilds();
|
|
me.updateDom();
|
|
parent.showChilds();
|
|
event.preventDefault();
|
|
return false;
|
|
};
|
|
|
|
var showAllButton = document.createElement('a');
|
|
showAllButton.appendChild(document.createTextNode((0,i18n/* translate */.Iu)('showAll')));
|
|
showAllButton.href = '#';
|
|
|
|
showAllButton.onclick = function (event) {
|
|
// TODO: use callback instead of accessing a method of the parent
|
|
parent.visibleChilds = Infinity;
|
|
me.updateDom();
|
|
parent.showChilds();
|
|
event.preventDefault();
|
|
return false;
|
|
};
|
|
|
|
var moreContents = document.createElement('div');
|
|
var moreText = document.createTextNode(this._getShowMoreText());
|
|
moreContents.className = 'jsoneditor-show-more';
|
|
moreContents.appendChild(moreText);
|
|
moreContents.appendChild(showMoreButton);
|
|
moreContents.appendChild(document.createTextNode('. '));
|
|
moreContents.appendChild(showAllButton);
|
|
moreContents.appendChild(document.createTextNode('. '));
|
|
var tdContents = document.createElement('td');
|
|
tdContents.appendChild(moreContents);
|
|
var moreTr = document.createElement('tr');
|
|
|
|
if (this.editor.options.mode === 'tree') {
|
|
moreTr.appendChild(document.createElement('td'));
|
|
moreTr.appendChild(document.createElement('td'));
|
|
}
|
|
|
|
moreTr.appendChild(tdContents);
|
|
moreTr.className = 'jsoneditor-show-more';
|
|
this.dom.tr = moreTr;
|
|
this.dom.moreContents = moreContents;
|
|
this.dom.moreText = moreText;
|
|
}
|
|
|
|
this.updateDom();
|
|
return this.dom.tr;
|
|
};
|
|
/**
|
|
* Update the HTML dom of the Node
|
|
*/
|
|
|
|
|
|
ShowMoreNode.prototype.updateDom = function (options) {
|
|
if (this.isVisible()) {
|
|
// attach to the right child node (the first non-visible child)
|
|
this.dom.tr.node = this.parent.childs[this.parent.visibleChilds];
|
|
|
|
if (!this.dom.tr.parentNode) {
|
|
var nextTr = this.parent._getNextTr();
|
|
|
|
if (nextTr) {
|
|
nextTr.parentNode.insertBefore(this.dom.tr, nextTr);
|
|
}
|
|
} // update the counts in the text
|
|
|
|
|
|
this.dom.moreText.nodeValue = this._getShowMoreText(); // update left margin
|
|
|
|
this.dom.moreContents.style.marginLeft = (this.getLevel() + 1) * 24 + 'px';
|
|
} else {
|
|
if (this.dom.tr && this.dom.tr.parentNode) {
|
|
this.dom.tr.parentNode.removeChild(this.dom.tr);
|
|
}
|
|
}
|
|
};
|
|
|
|
ShowMoreNode.prototype._getShowMoreText = function () {
|
|
return (0,i18n/* translate */.Iu)('showMoreStatus', {
|
|
visibleChilds: this.parent.visibleChilds,
|
|
totalChilds: this.parent.childs.length
|
|
}) + ' ';
|
|
};
|
|
/**
|
|
* Check whether the ShowMoreNode is currently visible.
|
|
* the ShowMoreNode is visible when it's parent has more childs than
|
|
* the current visibleChilds
|
|
* @return {boolean} isVisible
|
|
*/
|
|
|
|
|
|
ShowMoreNode.prototype.isVisible = function () {
|
|
return this.parent.expanded && this.parent.childs.length > this.parent.visibleChilds;
|
|
};
|
|
/**
|
|
* Handle an event. The event is caught centrally by the editor
|
|
* @param {Event} event
|
|
*/
|
|
|
|
|
|
ShowMoreNode.prototype.onEvent = function (event) {
|
|
var type = event.type;
|
|
|
|
if (type === 'keydown') {
|
|
this.onKeyDown(event);
|
|
}
|
|
};
|
|
|
|
return ShowMoreNode;
|
|
}
|
|
// EXTERNAL MODULE: ./src/js/showSortModal.js
|
|
var js_showSortModal = __webpack_require__(6210);
|
|
// EXTERNAL MODULE: ./src/js/showTransformModal.js + 1 modules
|
|
var js_showTransformModal = __webpack_require__(2558);
|
|
// EXTERNAL MODULE: ./src/js/constants.js
|
|
var constants = __webpack_require__(4188);
|
|
;// CONCATENATED MODULE: ./src/js/Node.js
|
|
|
|
|
|
function _createForOfIteratorHelper(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
|
|
|
|
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
|
|
|
|
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
|
|
|
|
function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
|
|
|
|
function Node_classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
|
|
function Node_defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
|
|
|
|
function Node_createClass(Constructor, protoProps, staticProps) { if (protoProps) Node_defineProperties(Constructor.prototype, protoProps); if (staticProps) Node_defineProperties(Constructor, staticProps); return Constructor; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
* @constructor Node
|
|
* Create a new Node
|
|
* @param {./treemode} editor
|
|
* @param {Object} [params] Can contain parameters:
|
|
* {string} field
|
|
* {boolean} fieldEditable
|
|
* {*} value
|
|
* {String} type Can have values 'auto', 'array',
|
|
* 'object', or 'string'.
|
|
*/
|
|
|
|
var Node = /*#__PURE__*/function () {
|
|
function Node(editor, params) {
|
|
Node_classCallCheck(this, Node);
|
|
|
|
/** @type {./treemode} */
|
|
this.editor = editor;
|
|
this.dom = {};
|
|
this.expanded = false;
|
|
|
|
if (params && params instanceof Object) {
|
|
this.setField(params.field, params.fieldEditable);
|
|
|
|
if ('value' in params) {
|
|
this.setValue(params.value, params.type);
|
|
}
|
|
|
|
if ('internalValue' in params) {
|
|
this.setInternalValue(params.internalValue);
|
|
}
|
|
} else {
|
|
this.setField('');
|
|
this.setValue(null);
|
|
}
|
|
|
|
this._debouncedOnChangeValue = (0,util.debounce)(this._onChangeValue.bind(this), Node.prototype.DEBOUNCE_INTERVAL);
|
|
this._debouncedOnChangeField = (0,util.debounce)(this._onChangeField.bind(this), Node.prototype.DEBOUNCE_INTERVAL); // starting value for visible children
|
|
|
|
this.visibleChilds = this.getMaxVisibleChilds();
|
|
}
|
|
|
|
Node_createClass(Node, [{
|
|
key: "getMaxVisibleChilds",
|
|
value: function getMaxVisibleChilds() {
|
|
return this.editor && this.editor.options && this.editor.options.maxVisibleChilds ? this.editor.options.maxVisibleChilds : DEFAULT_MAX_VISIBLE_CHILDS;
|
|
}
|
|
/**
|
|
* Determine whether the field and/or value of this node are editable
|
|
* @private
|
|
*/
|
|
|
|
}, {
|
|
key: "_updateEditability",
|
|
value: function _updateEditability() {
|
|
this.editable = {
|
|
field: true,
|
|
value: true
|
|
};
|
|
|
|
if (this.editor) {
|
|
this.editable.field = this.editor.options.mode === 'tree';
|
|
this.editable.value = this.editor.options.mode !== 'view';
|
|
|
|
if ((this.editor.options.mode === 'tree' || this.editor.options.mode === 'form') && typeof this.editor.options.onEditable === 'function') {
|
|
var editable = this.editor.options.onEditable({
|
|
field: this.field,
|
|
value: this.value,
|
|
path: this.getPath()
|
|
});
|
|
|
|
if (typeof editable === 'boolean') {
|
|
this.editable.field = editable;
|
|
this.editable.value = editable;
|
|
} else if (_typeof(editable) === 'object' && editable !== null) {
|
|
if (typeof editable.field === 'boolean') this.editable.field = editable.field;
|
|
if (typeof editable.value === 'boolean') this.editable.value = editable.value;
|
|
} else {
|
|
console.error('Invalid return value for function onEditable.', 'Actual value:', editable, '.', 'Either a boolean or object { field: boolean, value: boolean } expected.');
|
|
this.editable.field = false;
|
|
this.editable.value = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Get the path of this node
|
|
* @return {{string|number}[]} Array containing the path to this node.
|
|
* Element is a number if is the index of an array, a string otherwise.
|
|
*/
|
|
|
|
}, {
|
|
key: "getPath",
|
|
value: function getPath() {
|
|
var node = this;
|
|
var path = [];
|
|
|
|
while (node) {
|
|
var field = node.getName();
|
|
|
|
if (field !== undefined) {
|
|
path.unshift(field);
|
|
}
|
|
|
|
node = node.parent;
|
|
}
|
|
|
|
return path;
|
|
}
|
|
/**
|
|
* Get the internal path of this node, a list with the child indexes.
|
|
* @return {String[]} Array containing the internal path to this node
|
|
*/
|
|
|
|
}, {
|
|
key: "getInternalPath",
|
|
value: function getInternalPath() {
|
|
var node = this;
|
|
var internalPath = [];
|
|
|
|
while (node) {
|
|
if (node.parent) {
|
|
internalPath.unshift(node.getIndex());
|
|
}
|
|
|
|
node = node.parent;
|
|
}
|
|
|
|
return internalPath;
|
|
}
|
|
/**
|
|
* Get node serializable name
|
|
* @returns {String|Number}
|
|
*/
|
|
|
|
}, {
|
|
key: "getName",
|
|
value: function getName() {
|
|
return !this.parent ? undefined // do not add an (optional) field name of the root node
|
|
: this.parent.type !== 'array' ? this.field : this.index;
|
|
}
|
|
/**
|
|
* Find child node by serializable path
|
|
* @param {Array<String>} path
|
|
*/
|
|
|
|
}, {
|
|
key: "findNodeByPath",
|
|
value: function findNodeByPath(path) {
|
|
if (!path) {
|
|
return;
|
|
}
|
|
|
|
if (path.length === 0) {
|
|
return this;
|
|
}
|
|
|
|
if (path.length && this.childs && this.childs.length) {
|
|
for (var i = 0; i < this.childs.length; ++i) {
|
|
if ('' + path[0] === '' + this.childs[i].getName()) {
|
|
return this.childs[i].findNodeByPath(path.slice(1));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Find child node by an internal path: the indexes of the childs nodes
|
|
* @param {Array<String>} internalPath
|
|
* @return {Node | undefined} Returns the node if the path exists.
|
|
* Returns undefined otherwise.
|
|
*/
|
|
|
|
}, {
|
|
key: "findNodeByInternalPath",
|
|
value: function findNodeByInternalPath(internalPath) {
|
|
if (!internalPath) {
|
|
return undefined;
|
|
}
|
|
|
|
var node = this;
|
|
|
|
for (var i = 0; i < internalPath.length && node; i++) {
|
|
var childIndex = internalPath[i];
|
|
node = node.childs[childIndex];
|
|
}
|
|
|
|
return node;
|
|
}
|
|
/**
|
|
* @typedef {{value: String|Object|Number|Boolean, path: Array.<String|Number>}} SerializableNode
|
|
*
|
|
* Returns serializable representation for the node
|
|
* @return {SerializableNode}
|
|
*/
|
|
|
|
}, {
|
|
key: "serialize",
|
|
value: function serialize() {
|
|
return {
|
|
value: this.getValue(),
|
|
path: this.getPath()
|
|
};
|
|
}
|
|
/**
|
|
* Find a Node from a JSON path like '.items[3].name'
|
|
* @param {string} jsonPath
|
|
* @return {Node | null} Returns the Node when found, returns null if not found
|
|
*/
|
|
|
|
}, {
|
|
key: "findNode",
|
|
value: function findNode(jsonPath) {
|
|
var path = (0,util.parsePath)(jsonPath);
|
|
var node = this;
|
|
|
|
var _loop = function _loop() {
|
|
var prop = path.shift();
|
|
|
|
if (typeof prop === 'number') {
|
|
if (node.type !== 'array') {
|
|
throw new Error('Cannot get child node at index ' + prop + ': node is no array');
|
|
}
|
|
|
|
node = node.childs[prop];
|
|
} else {
|
|
// string
|
|
if (node.type !== 'object') {
|
|
throw new Error('Cannot get child node ' + prop + ': node is no object');
|
|
}
|
|
|
|
node = node.childs.filter(function (child) {
|
|
return child.field === prop;
|
|
})[0];
|
|
}
|
|
};
|
|
|
|
while (node && path.length > 0) {
|
|
_loop();
|
|
}
|
|
|
|
return node;
|
|
}
|
|
/**
|
|
* Find all parents of this node. The parents are ordered from root node towards
|
|
* the original node.
|
|
* @return {Array.<Node>}
|
|
*/
|
|
|
|
}, {
|
|
key: "findParents",
|
|
value: function findParents() {
|
|
var parents = [];
|
|
var parent = this.parent;
|
|
|
|
while (parent) {
|
|
parents.unshift(parent);
|
|
parent = parent.parent;
|
|
}
|
|
|
|
return parents;
|
|
}
|
|
/**
|
|
*
|
|
* @param {{dataPath: string, keyword: string, message: string, params: Object, schemaPath: string} | null} error
|
|
* @param {Node} [child] When this is the error of a parent node, pointing
|
|
* to an invalid child node, the child node itself
|
|
* can be provided. If provided, clicking the error
|
|
* icon will set focus to the invalid child node.
|
|
*/
|
|
|
|
}, {
|
|
key: "setError",
|
|
value: function setError(error, child) {
|
|
this.error = error;
|
|
this.errorChild = child;
|
|
|
|
if (this.dom && this.dom.tr) {
|
|
this.updateError();
|
|
}
|
|
}
|
|
/**
|
|
* Render the error
|
|
*/
|
|
|
|
}, {
|
|
key: "updateError",
|
|
value: function updateError() {
|
|
var _this = this;
|
|
|
|
var error = this.fieldError || this.valueError || this.error;
|
|
var tdError = this.dom.tdError;
|
|
|
|
if (error && this.dom && this.dom.tr) {
|
|
(0,util.addClassName)(this.dom.tr, 'jsoneditor-validation-error');
|
|
|
|
if (!tdError) {
|
|
tdError = document.createElement('td');
|
|
this.dom.tdError = tdError;
|
|
this.dom.tdValue.parentNode.appendChild(tdError);
|
|
}
|
|
|
|
var button = document.createElement('button');
|
|
button.type = 'button';
|
|
button.className = 'jsoneditor-button jsoneditor-schema-error';
|
|
|
|
var destroy = function destroy() {
|
|
if (_this.dom.popupAnchor) {
|
|
_this.dom.popupAnchor.destroy(); // this will trigger the onDestroy callback
|
|
|
|
}
|
|
};
|
|
|
|
var onDestroy = function onDestroy() {
|
|
delete _this.dom.popupAnchor;
|
|
};
|
|
|
|
var createPopup = function createPopup(destroyOnMouseOut) {
|
|
var frame = _this.editor.frame;
|
|
_this.dom.popupAnchor = (0,createAbsoluteAnchor/* createAbsoluteAnchor */.w)(button, _this.editor.getPopupAnchor(), onDestroy, destroyOnMouseOut);
|
|
var popupWidth = 200; // must correspond to what's configured in the CSS
|
|
|
|
var buttonRect = button.getBoundingClientRect();
|
|
var frameRect = frame.getBoundingClientRect();
|
|
var position = frameRect.width - buttonRect.x > popupWidth / 2 + 20 ? 'jsoneditor-above' : 'jsoneditor-left';
|
|
var popover = document.createElement('div');
|
|
popover.className = 'jsoneditor-popover ' + position;
|
|
popover.appendChild(document.createTextNode(error.message));
|
|
|
|
_this.dom.popupAnchor.appendChild(popover);
|
|
};
|
|
|
|
button.onmouseover = function () {
|
|
if (!_this.dom.popupAnchor) {
|
|
createPopup(true);
|
|
}
|
|
};
|
|
|
|
button.onfocus = function () {
|
|
destroy();
|
|
createPopup(false);
|
|
};
|
|
|
|
button.onblur = function () {
|
|
destroy();
|
|
}; // when clicking the error icon, expand all nodes towards the invalid
|
|
// child node, and set focus to the child node
|
|
|
|
|
|
var child = this.errorChild;
|
|
|
|
if (child) {
|
|
button.onclick = function showInvalidNode() {
|
|
child.findParents().forEach(function (parent) {
|
|
parent.expand(false);
|
|
});
|
|
child.scrollTo(function () {
|
|
child.focus();
|
|
});
|
|
};
|
|
} // apply the error message to the node
|
|
|
|
|
|
while (tdError.firstChild) {
|
|
tdError.removeChild(tdError.firstChild);
|
|
}
|
|
|
|
tdError.appendChild(button);
|
|
} else {
|
|
if (this.dom.tr) {
|
|
(0,util.removeClassName)(this.dom.tr, 'jsoneditor-validation-error');
|
|
}
|
|
|
|
if (tdError) {
|
|
this.dom.tdError.parentNode.removeChild(this.dom.tdError);
|
|
delete this.dom.tdError;
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Get the index of this node: the index in the list of childs where this
|
|
* node is part of
|
|
* @return {number | null} Returns the index, or null if this is the root node
|
|
*/
|
|
|
|
}, {
|
|
key: "getIndex",
|
|
value: function getIndex() {
|
|
if (this.parent) {
|
|
var index = this.parent.childs.indexOf(this);
|
|
return index !== -1 ? index : null;
|
|
} else {
|
|
return -1;
|
|
}
|
|
}
|
|
/**
|
|
* Set parent node
|
|
* @param {Node} parent
|
|
*/
|
|
|
|
}, {
|
|
key: "setParent",
|
|
value: function setParent(parent) {
|
|
this.parent = parent;
|
|
}
|
|
/**
|
|
* Set field
|
|
* @param {String} field
|
|
* @param {boolean} [fieldEditable]
|
|
*/
|
|
|
|
}, {
|
|
key: "setField",
|
|
value: function setField(field, fieldEditable) {
|
|
this.field = field;
|
|
this.previousField = field;
|
|
this.fieldEditable = fieldEditable === true;
|
|
}
|
|
/**
|
|
* Get field
|
|
* @return {String}
|
|
*/
|
|
|
|
}, {
|
|
key: "getField",
|
|
value: function getField() {
|
|
if (this.field === undefined) {
|
|
this._getDomField();
|
|
}
|
|
|
|
return this.field;
|
|
}
|
|
/**
|
|
* Set value. Value is a JSON structure or an element String, Boolean, etc.
|
|
* @param {*} value
|
|
* @param {String} [type] Specify the type of the value. Can be 'auto',
|
|
* 'array', 'object', or 'string'
|
|
*/
|
|
|
|
}, {
|
|
key: "setValue",
|
|
value: function setValue(value, type) {
|
|
var childValue, child;
|
|
var i, j;
|
|
var updateDom = false;
|
|
var previousChilds = this.childs;
|
|
this.type = this._getType(value); // check if type corresponds with the provided type
|
|
|
|
if (type && type !== this.type) {
|
|
if (type === 'string' && this.type === 'auto') {
|
|
this.type = type;
|
|
} else {
|
|
throw new Error('Type mismatch: ' + 'cannot cast value of type "' + this.type + ' to the specified type "' + type + '"');
|
|
}
|
|
}
|
|
|
|
if (this.type === 'array') {
|
|
// array
|
|
if (!this.childs) {
|
|
this.childs = [];
|
|
}
|
|
|
|
for (i = 0; i < value.length; i++) {
|
|
childValue = value[i];
|
|
|
|
if (childValue !== undefined && !(childValue instanceof Function)) {
|
|
if (i < this.childs.length) {
|
|
// reuse existing child, keep its state
|
|
child = this.childs[i];
|
|
child.fieldEditable = false;
|
|
child.index = i;
|
|
child.setValue(childValue);
|
|
} else {
|
|
// create a new child
|
|
child = new Node(this.editor, {
|
|
value: childValue
|
|
});
|
|
var visible = i < this.getMaxVisibleChilds();
|
|
this.appendChild(child, visible, updateDom);
|
|
}
|
|
}
|
|
} // cleanup redundant childs
|
|
// we loop backward to prevent issues with shifting index numbers
|
|
|
|
|
|
for (j = this.childs.length; j >= value.length; j--) {
|
|
this.removeChild(this.childs[j], updateDom);
|
|
}
|
|
} else if (this.type === 'object') {
|
|
// object
|
|
if (!this.childs) {
|
|
this.childs = [];
|
|
} // cleanup redundant childs
|
|
// we loop backward to prevent issues with shifting index numbers
|
|
|
|
|
|
for (j = this.childs.length - 1; j >= 0; j--) {
|
|
if (!Node_hasOwnProperty(value, this.childs[j].field)) {
|
|
this.removeChild(this.childs[j], updateDom);
|
|
}
|
|
}
|
|
|
|
i = 0;
|
|
|
|
for (var childField in value) {
|
|
if (Node_hasOwnProperty(value, childField)) {
|
|
childValue = value[childField];
|
|
|
|
if (childValue !== undefined && !(childValue instanceof Function)) {
|
|
var _child = this.findChildByProperty(childField);
|
|
|
|
if (_child) {
|
|
// reuse existing child, keep its state
|
|
_child.setField(childField, true);
|
|
|
|
_child.setValue(childValue);
|
|
} else {
|
|
// create a new child, append to the end
|
|
var newChild = new Node(this.editor, {
|
|
field: childField,
|
|
value: childValue
|
|
});
|
|
|
|
var _visible = i < this.getMaxVisibleChilds();
|
|
|
|
this.appendChild(newChild, _visible, updateDom);
|
|
}
|
|
}
|
|
|
|
i++;
|
|
}
|
|
}
|
|
|
|
this.value = ''; // sort object keys during initialization. Must not trigger an onChange action
|
|
|
|
if (this.editor.options.sortObjectKeys === true) {
|
|
var triggerAction = false;
|
|
this.sort([], 'asc', triggerAction);
|
|
}
|
|
} else {
|
|
// value
|
|
this.hideChilds();
|
|
delete this.append;
|
|
delete this.showMore;
|
|
delete this.expanded;
|
|
delete this.childs;
|
|
this.value = value;
|
|
} // recreate the DOM if switching from an object/array to auto/string or vice versa
|
|
// needed to recreated the expand button for example
|
|
|
|
|
|
if (Array.isArray(previousChilds) !== Array.isArray(this.childs)) {
|
|
this.recreateDom();
|
|
}
|
|
|
|
this.updateDom({
|
|
updateIndexes: true
|
|
});
|
|
this.previousValue = this.value; // used only to check for changes in DOM vs JS model
|
|
}
|
|
/**
|
|
* Set internal value
|
|
* @param {*} internalValue Internal value structure keeping type,
|
|
* order and duplicates in objects
|
|
*/
|
|
|
|
}, {
|
|
key: "setInternalValue",
|
|
value: function setInternalValue(internalValue) {
|
|
var childValue, child, visible;
|
|
var i, j;
|
|
var notUpdateDom = false;
|
|
var previousChilds = this.childs;
|
|
this.type = internalValue.type;
|
|
|
|
if (internalValue.type === 'array') {
|
|
// array
|
|
if (!this.childs) {
|
|
this.childs = [];
|
|
}
|
|
|
|
for (i = 0; i < internalValue.childs.length; i++) {
|
|
childValue = internalValue.childs[i];
|
|
|
|
if (childValue !== undefined && !(childValue instanceof Function)) {
|
|
if (i < this.childs.length) {
|
|
// reuse existing child, keep its state
|
|
child = this.childs[i];
|
|
child.fieldEditable = false;
|
|
child.index = i;
|
|
child.setInternalValue(childValue);
|
|
} else {
|
|
// create a new child
|
|
child = new Node(this.editor, {
|
|
internalValue: childValue
|
|
});
|
|
visible = i < this.getMaxVisibleChilds();
|
|
this.appendChild(child, visible, notUpdateDom);
|
|
}
|
|
}
|
|
} // cleanup redundant childs
|
|
// we loop backward to prevent issues with shifting index numbers
|
|
|
|
|
|
for (j = this.childs.length; j >= internalValue.childs.length; j--) {
|
|
this.removeChild(this.childs[j], notUpdateDom);
|
|
}
|
|
} else if (internalValue.type === 'object') {
|
|
// object
|
|
if (!this.childs) {
|
|
this.childs = [];
|
|
}
|
|
|
|
for (i = 0; i < internalValue.childs.length; i++) {
|
|
childValue = internalValue.childs[i];
|
|
|
|
if (childValue !== undefined && !(childValue instanceof Function)) {
|
|
if (i < this.childs.length) {
|
|
// reuse existing child, keep its state
|
|
child = this.childs[i];
|
|
delete child.index;
|
|
child.setField(childValue.field, true);
|
|
child.setInternalValue(childValue.value);
|
|
} else {
|
|
// create a new child
|
|
child = new Node(this.editor, {
|
|
field: childValue.field,
|
|
internalValue: childValue.value
|
|
});
|
|
visible = i < this.getMaxVisibleChilds();
|
|
this.appendChild(child, visible, notUpdateDom);
|
|
}
|
|
}
|
|
} // cleanup redundant childs
|
|
// we loop backward to prevent issues with shifting index numbers
|
|
|
|
|
|
for (j = this.childs.length; j >= internalValue.childs.length; j--) {
|
|
this.removeChild(this.childs[j], notUpdateDom);
|
|
}
|
|
} else {
|
|
// value
|
|
this.hideChilds();
|
|
delete this.append;
|
|
delete this.showMore;
|
|
delete this.expanded;
|
|
delete this.childs;
|
|
this.value = internalValue.value;
|
|
} // recreate the DOM if switching from an object/array to auto/string or vice versa
|
|
// needed to recreated the expand button for example
|
|
|
|
|
|
if (Array.isArray(previousChilds) !== Array.isArray(this.childs)) {
|
|
this.recreateDom();
|
|
}
|
|
|
|
this.updateDom({
|
|
updateIndexes: true
|
|
});
|
|
this.previousValue = this.value; // used only to check for changes in DOM vs JS model
|
|
}
|
|
/**
|
|
* Remove the DOM of this node and it's childs and recreate it again
|
|
*/
|
|
|
|
}, {
|
|
key: "recreateDom",
|
|
value: function recreateDom() {
|
|
if (this.dom && this.dom.tr && this.dom.tr.parentNode) {
|
|
var domAnchor = this._detachFromDom();
|
|
|
|
this.clearDom();
|
|
|
|
this._attachToDom(domAnchor);
|
|
} else {
|
|
this.clearDom();
|
|
}
|
|
}
|
|
/**
|
|
* Get value. Value is a JSON structure
|
|
* @return {*} value
|
|
*/
|
|
|
|
}, {
|
|
key: "getValue",
|
|
value: function getValue() {
|
|
if (this.type === 'array') {
|
|
var arr = [];
|
|
this.childs.forEach(function (child) {
|
|
arr.push(child.getValue());
|
|
});
|
|
return arr;
|
|
} else if (this.type === 'object') {
|
|
var obj = {};
|
|
this.childs.forEach(function (child) {
|
|
obj[child.getField()] = child.getValue();
|
|
});
|
|
return obj;
|
|
} else {
|
|
if (this.value === undefined) {
|
|
this._getDomValue();
|
|
}
|
|
|
|
return this.value;
|
|
}
|
|
}
|
|
/**
|
|
* Get internal value, a structure which maintains ordering and duplicates in objects
|
|
* @return {*} value
|
|
*/
|
|
|
|
}, {
|
|
key: "getInternalValue",
|
|
value: function getInternalValue() {
|
|
if (this.type === 'array') {
|
|
return {
|
|
type: this.type,
|
|
childs: this.childs.map(function (child) {
|
|
return child.getInternalValue();
|
|
})
|
|
};
|
|
} else if (this.type === 'object') {
|
|
return {
|
|
type: this.type,
|
|
childs: this.childs.map(function (child) {
|
|
return {
|
|
field: child.getField(),
|
|
value: child.getInternalValue()
|
|
};
|
|
})
|
|
};
|
|
} else {
|
|
if (this.value === undefined) {
|
|
this._getDomValue();
|
|
}
|
|
|
|
return {
|
|
type: this.type,
|
|
value: this.value
|
|
};
|
|
}
|
|
}
|
|
/**
|
|
* Get the nesting level of this node
|
|
* @return {Number} level
|
|
*/
|
|
|
|
}, {
|
|
key: "getLevel",
|
|
value: function getLevel() {
|
|
return this.parent ? this.parent.getLevel() + 1 : 0;
|
|
}
|
|
/**
|
|
* Get jsonpath of the current node
|
|
* @return {Node[]} Returns an array with nodes
|
|
*/
|
|
|
|
}, {
|
|
key: "getNodePath",
|
|
value: function getNodePath() {
|
|
var path = this.parent ? this.parent.getNodePath() : [];
|
|
path.push(this);
|
|
return path;
|
|
}
|
|
/**
|
|
* Create a clone of a node
|
|
* The complete state of a clone is copied, including whether it is expanded or
|
|
* not. The DOM elements are not cloned.
|
|
* @return {Node} clone
|
|
*/
|
|
|
|
}, {
|
|
key: "clone",
|
|
value: function clone() {
|
|
var clone = new Node(this.editor);
|
|
clone.type = this.type;
|
|
clone.field = this.field;
|
|
clone.fieldInnerText = this.fieldInnerText;
|
|
clone.fieldEditable = this.fieldEditable;
|
|
clone.previousField = this.previousField;
|
|
clone.value = this.value;
|
|
clone.valueInnerText = this.valueInnerText;
|
|
clone.previousValue = this.previousValue;
|
|
clone.expanded = this.expanded;
|
|
clone.visibleChilds = this.visibleChilds;
|
|
|
|
if (this.childs) {
|
|
// an object or array
|
|
var cloneChilds = [];
|
|
this.childs.forEach(function (child) {
|
|
var childClone = child.clone();
|
|
childClone.setParent(clone);
|
|
cloneChilds.push(childClone);
|
|
});
|
|
clone.childs = cloneChilds;
|
|
} else {
|
|
// a value
|
|
clone.childs = undefined;
|
|
}
|
|
|
|
return clone;
|
|
}
|
|
/**
|
|
* Expand this node and optionally its childs.
|
|
* @param {boolean} [recurse] Optional recursion, true by default. When
|
|
* true, all childs will be expanded recursively
|
|
*/
|
|
|
|
}, {
|
|
key: "expand",
|
|
value: function expand(recurse) {
|
|
if (!this.childs) {
|
|
return;
|
|
} // set this node expanded
|
|
|
|
|
|
this.expanded = true;
|
|
|
|
if (this.dom.expand) {
|
|
this.dom.expand.className = 'jsoneditor-button jsoneditor-expanded';
|
|
}
|
|
|
|
this.showChilds();
|
|
|
|
if (recurse !== false) {
|
|
this.childs.forEach(function (child) {
|
|
child.expand(recurse);
|
|
});
|
|
} // update the css classes of table row, and fire onClassName etc
|
|
|
|
|
|
this.updateDom({
|
|
recurse: false
|
|
});
|
|
}
|
|
/**
|
|
* Collapse this node and optionally its childs.
|
|
* @param {boolean} [recurse] Optional recursion, true by default. When
|
|
* true, all childs will be collapsed recursively
|
|
*/
|
|
|
|
}, {
|
|
key: "collapse",
|
|
value: function collapse(recurse) {
|
|
if (!this.childs) {
|
|
return;
|
|
}
|
|
|
|
this.hideChilds(); // collapse childs in case of recurse
|
|
|
|
if (recurse !== false) {
|
|
this.childs.forEach(function (child) {
|
|
child.collapse(recurse);
|
|
});
|
|
} // make this node collapsed
|
|
|
|
|
|
if (this.dom.expand) {
|
|
this.dom.expand.className = 'jsoneditor-button jsoneditor-collapsed';
|
|
}
|
|
|
|
this.expanded = false; // update the css classes of table row, and fire onClassName etc
|
|
|
|
this.updateDom({
|
|
recurse: false
|
|
});
|
|
}
|
|
/**
|
|
* Recursively show all childs when they are expanded
|
|
*/
|
|
|
|
}, {
|
|
key: "showChilds",
|
|
value: function showChilds() {
|
|
var childs = this.childs;
|
|
|
|
if (!childs) {
|
|
return;
|
|
}
|
|
|
|
if (!this.expanded) {
|
|
return;
|
|
}
|
|
|
|
var tr = this.dom.tr;
|
|
var nextTr;
|
|
var table = tr ? tr.parentNode : undefined;
|
|
|
|
if (table) {
|
|
// show row with append button
|
|
var append = this.getAppendDom();
|
|
|
|
if (!append.parentNode) {
|
|
nextTr = tr.nextSibling;
|
|
|
|
if (nextTr) {
|
|
table.insertBefore(append, nextTr);
|
|
} else {
|
|
table.appendChild(append);
|
|
}
|
|
} // show childs
|
|
|
|
|
|
var iMax = Math.min(this.childs.length, this.visibleChilds);
|
|
nextTr = this._getNextTr();
|
|
|
|
for (var i = 0; i < iMax; i++) {
|
|
var child = this.childs[i];
|
|
|
|
if (!child.getDom().parentNode) {
|
|
table.insertBefore(child.getDom(), nextTr);
|
|
}
|
|
|
|
child.showChilds();
|
|
} // show "show more childs" if limited
|
|
|
|
|
|
var showMore = this.getShowMoreDom();
|
|
nextTr = this._getNextTr();
|
|
|
|
if (!showMore.parentNode) {
|
|
table.insertBefore(showMore, nextTr);
|
|
}
|
|
|
|
this.showMore.updateDom(); // to update the counter
|
|
}
|
|
}
|
|
}, {
|
|
key: "_getNextTr",
|
|
value: function _getNextTr() {
|
|
if (this.showMore && this.showMore.getDom().parentNode) {
|
|
return this.showMore.getDom();
|
|
}
|
|
|
|
if (this.append && this.append.getDom().parentNode) {
|
|
return this.append.getDom();
|
|
}
|
|
}
|
|
/**
|
|
* Hide the node with all its childs
|
|
* @param {{resetVisibleChilds: boolean}} [options]
|
|
*/
|
|
|
|
}, {
|
|
key: "hide",
|
|
value: function hide(options) {
|
|
var tr = this.dom.tr;
|
|
var table = tr ? tr.parentNode : undefined;
|
|
|
|
if (table) {
|
|
table.removeChild(tr);
|
|
}
|
|
|
|
if (this.dom.popupAnchor) {
|
|
this.dom.popupAnchor.destroy();
|
|
}
|
|
|
|
this.hideChilds(options);
|
|
}
|
|
/**
|
|
* Recursively hide all childs
|
|
* @param {{resetVisibleChilds: boolean}} [options]
|
|
*/
|
|
|
|
}, {
|
|
key: "hideChilds",
|
|
value: function hideChilds(options) {
|
|
var childs = this.childs;
|
|
|
|
if (!childs) {
|
|
return;
|
|
}
|
|
|
|
if (!this.expanded) {
|
|
return;
|
|
} // hide append row
|
|
|
|
|
|
var append = this.getAppendDom();
|
|
|
|
if (append.parentNode) {
|
|
append.parentNode.removeChild(append);
|
|
} // hide childs
|
|
|
|
|
|
this.childs.forEach(function (child) {
|
|
child.hide();
|
|
}); // hide "show more" row
|
|
|
|
var showMore = this.getShowMoreDom();
|
|
|
|
if (showMore.parentNode) {
|
|
showMore.parentNode.removeChild(showMore);
|
|
} // reset max visible childs
|
|
|
|
|
|
if (!options || options.resetVisibleChilds) {
|
|
this.visibleChilds = this.getMaxVisibleChilds();
|
|
}
|
|
}
|
|
/**
|
|
* set custom css classes on a node
|
|
*/
|
|
|
|
}, {
|
|
key: "_updateCssClassName",
|
|
value: function _updateCssClassName() {
|
|
if (this.dom.field && this.editor && this.editor.options && typeof this.editor.options.onClassName === 'function' && this.dom.tree) {
|
|
(0,util.removeAllClassNames)(this.dom.tree);
|
|
var addClasses = this.editor.options.onClassName({
|
|
path: this.getPath(),
|
|
field: this.field,
|
|
value: this.value
|
|
}) || '';
|
|
(0,util.addClassName)(this.dom.tree, 'jsoneditor-values ' + addClasses);
|
|
}
|
|
}
|
|
}, {
|
|
key: "recursivelyUpdateCssClassesOnNodes",
|
|
value: function recursivelyUpdateCssClassesOnNodes() {
|
|
this._updateCssClassName();
|
|
|
|
if (Array.isArray(this.childs)) {
|
|
for (var i = 0; i < this.childs.length; i++) {
|
|
this.childs[i].recursivelyUpdateCssClassesOnNodes();
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Goes through the path from the node to the root and ensures that it is expanded
|
|
*/
|
|
|
|
}, {
|
|
key: "expandTo",
|
|
value: function expandTo() {
|
|
var currentNode = this.parent;
|
|
|
|
while (currentNode) {
|
|
if (!currentNode.expanded) {
|
|
currentNode.expand();
|
|
}
|
|
|
|
currentNode = currentNode.parent;
|
|
}
|
|
}
|
|
/**
|
|
* Add a new child to the node.
|
|
* Only applicable when Node value is of type array or object
|
|
* @param {Node} node
|
|
* @param {boolean} [visible] If true (default), the child will be rendered
|
|
* @param {boolean} [updateDom] If true (default), the DOM of both parent
|
|
* node and appended node will be updated
|
|
* (child count, indexes)
|
|
*/
|
|
|
|
}, {
|
|
key: "appendChild",
|
|
value: function appendChild(node, visible, updateDom) {
|
|
if (this._hasChilds()) {
|
|
// adjust the link to the parent
|
|
node.setParent(this);
|
|
node.fieldEditable = this.type === 'object';
|
|
|
|
if (this.type === 'array') {
|
|
node.index = this.childs.length;
|
|
}
|
|
|
|
if (this.type === 'object' && node.field === undefined) {
|
|
// initialize field value if needed
|
|
node.setField('');
|
|
}
|
|
|
|
this.childs.push(node);
|
|
|
|
if (this.expanded && visible !== false) {
|
|
// insert into the DOM, before the appendRow
|
|
var newTr = node.getDom();
|
|
|
|
var nextTr = this._getNextTr();
|
|
|
|
var table = nextTr ? nextTr.parentNode : undefined;
|
|
|
|
if (nextTr && table) {
|
|
table.insertBefore(newTr, nextTr);
|
|
}
|
|
|
|
node.showChilds();
|
|
this.visibleChilds++;
|
|
}
|
|
|
|
if (updateDom !== false) {
|
|
this.updateDom({
|
|
updateIndexes: true
|
|
});
|
|
node.updateDom({
|
|
recurse: true
|
|
});
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Move a node from its current parent to this node
|
|
* Only applicable when Node value is of type array or object
|
|
* @param {Node} node
|
|
* @param {Node} beforeNode
|
|
* @param {boolean} [updateDom] If true (default), the DOM of both parent
|
|
* node and appended node will be updated
|
|
* (child count, indexes)
|
|
*/
|
|
|
|
}, {
|
|
key: "moveBefore",
|
|
value: function moveBefore(node, beforeNode, updateDom) {
|
|
if (this._hasChilds()) {
|
|
// create a temporary row, to prevent the scroll position from jumping
|
|
// when removing the node
|
|
var tbody = this.dom.tr ? this.dom.tr.parentNode : undefined;
|
|
var trTemp;
|
|
|
|
if (tbody) {
|
|
trTemp = document.createElement('tr');
|
|
trTemp.style.height = tbody.clientHeight + 'px';
|
|
tbody.appendChild(trTemp);
|
|
}
|
|
|
|
if (node.parent) {
|
|
node.parent.removeChild(node);
|
|
}
|
|
|
|
if (beforeNode instanceof AppendNode || !beforeNode) {
|
|
// the this.childs.length + 1 is to reckon with the node that we're about to add
|
|
if (this.childs.length + 1 > this.visibleChilds) {
|
|
var lastVisibleNode = this.childs[this.visibleChilds - 1];
|
|
this.insertBefore(node, lastVisibleNode, updateDom);
|
|
} else {
|
|
var visible = true;
|
|
this.appendChild(node, visible, updateDom);
|
|
}
|
|
} else {
|
|
this.insertBefore(node, beforeNode, updateDom);
|
|
}
|
|
|
|
if (tbody && trTemp) {
|
|
tbody.removeChild(trTemp);
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Insert a new child before a given node
|
|
* Only applicable when Node value is of type array or object
|
|
* @param {Node} node
|
|
* @param {Node} beforeNode
|
|
* @param {boolean} [updateDom] If true (default), the DOM of both parent
|
|
* node and appended node will be updated
|
|
* (child count, indexes)
|
|
*/
|
|
|
|
}, {
|
|
key: "insertBefore",
|
|
value: function insertBefore(node, beforeNode, updateDom) {
|
|
if (this._hasChilds()) {
|
|
this.visibleChilds++; // initialize field value if needed
|
|
|
|
if (this.type === 'object' && node.field === undefined) {
|
|
node.setField('');
|
|
}
|
|
|
|
if (beforeNode === this.append) {
|
|
// append to the child nodes
|
|
// adjust the link to the parent
|
|
node.setParent(this);
|
|
node.fieldEditable = this.type === 'object';
|
|
this.childs.push(node);
|
|
} else {
|
|
// insert before a child node
|
|
var index = this.childs.indexOf(beforeNode);
|
|
|
|
if (index === -1) {
|
|
throw new Error('Node not found');
|
|
} // adjust the link to the parent
|
|
|
|
|
|
node.setParent(this);
|
|
node.fieldEditable = this.type === 'object';
|
|
this.childs.splice(index, 0, node);
|
|
}
|
|
|
|
if (this.expanded) {
|
|
// insert into the DOM
|
|
var newTr = node.getDom();
|
|
var nextTr = beforeNode.getDom();
|
|
var table = nextTr ? nextTr.parentNode : undefined;
|
|
|
|
if (nextTr && table) {
|
|
table.insertBefore(newTr, nextTr);
|
|
}
|
|
|
|
node.showChilds();
|
|
this.showChilds();
|
|
}
|
|
|
|
if (updateDom !== false) {
|
|
this.updateDom({
|
|
updateIndexes: true
|
|
});
|
|
node.updateDom({
|
|
recurse: true
|
|
});
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Insert a new child before a given node
|
|
* Only applicable when Node value is of type array or object
|
|
* @param {Node} node
|
|
* @param {Node} afterNode
|
|
*/
|
|
|
|
}, {
|
|
key: "insertAfter",
|
|
value: function insertAfter(node, afterNode) {
|
|
if (this._hasChilds()) {
|
|
var index = this.childs.indexOf(afterNode);
|
|
var beforeNode = this.childs[index + 1];
|
|
|
|
if (beforeNode) {
|
|
this.insertBefore(node, beforeNode);
|
|
} else {
|
|
this.appendChild(node);
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Search in this node
|
|
* Searches are case insensitive.
|
|
* @param {String} text
|
|
* @param {Node[]} [results] Array where search results will be added
|
|
* used to count and limit the results whilst iterating
|
|
* @return {Node[]} results Array with nodes containing the search text
|
|
*/
|
|
|
|
}, {
|
|
key: "search",
|
|
value: function search(text, results) {
|
|
if (!Array.isArray(results)) {
|
|
results = [];
|
|
}
|
|
|
|
var index;
|
|
var search = text ? text.toLowerCase() : undefined; // delete old search data
|
|
|
|
delete this.searchField;
|
|
delete this.searchValue; // search in field
|
|
|
|
if (this.field !== undefined && results.length <= this.MAX_SEARCH_RESULTS) {
|
|
var field = String(this.field).toLowerCase();
|
|
index = field.indexOf(search);
|
|
|
|
if (index !== -1) {
|
|
this.searchField = true;
|
|
results.push({
|
|
node: this,
|
|
elem: 'field'
|
|
});
|
|
} // update dom
|
|
|
|
|
|
this._updateDomField();
|
|
} // search in value
|
|
|
|
|
|
if (this._hasChilds()) {
|
|
// array, object
|
|
// search the nodes childs
|
|
if (this.childs) {
|
|
this.childs.forEach(function (child) {
|
|
child.search(text, results);
|
|
});
|
|
}
|
|
} else {
|
|
// string, auto
|
|
if (this.value !== undefined && results.length <= this.MAX_SEARCH_RESULTS) {
|
|
var value = String(this.value).toLowerCase();
|
|
index = value.indexOf(search);
|
|
|
|
if (index !== -1) {
|
|
this.searchValue = true;
|
|
results.push({
|
|
node: this,
|
|
elem: 'value'
|
|
});
|
|
} // update dom
|
|
|
|
|
|
this._updateDomValue();
|
|
}
|
|
}
|
|
|
|
return results;
|
|
}
|
|
/**
|
|
* Move the scroll position such that this node is in the visible area.
|
|
* The node will not get the focus
|
|
* @param {function(boolean)} [callback]
|
|
*/
|
|
|
|
}, {
|
|
key: "scrollTo",
|
|
value: function scrollTo(callback) {
|
|
this.expandPathToNode();
|
|
|
|
if (this.dom.tr && this.dom.tr.parentNode) {
|
|
this.editor.scrollTo(this.dom.tr.offsetTop, callback);
|
|
}
|
|
}
|
|
/**
|
|
* if the node is not visible, expand its parents
|
|
*/
|
|
|
|
}, {
|
|
key: "expandPathToNode",
|
|
value: function expandPathToNode() {
|
|
var node = this;
|
|
var recurse = false;
|
|
|
|
while (node && node.parent) {
|
|
// expand visible childs of the parent if needed
|
|
var index = node.parent.type === 'array' ? node.index : node.parent.childs.indexOf(node);
|
|
|
|
while (node.parent.visibleChilds < index + 1) {
|
|
node.parent.visibleChilds += this.getMaxVisibleChilds();
|
|
} // expand the parent itself
|
|
|
|
|
|
node.parent.expand(recurse);
|
|
node = node.parent;
|
|
}
|
|
}
|
|
/**
|
|
* Set focus to this node
|
|
* @param {String} [elementName] The field name of the element to get the
|
|
* focus available values: 'drag', 'menu',
|
|
* 'expand', 'field', 'value' (default)
|
|
*/
|
|
|
|
}, {
|
|
key: "focus",
|
|
value: function focus(elementName) {
|
|
Node.focusElement = elementName;
|
|
|
|
if (this.dom.tr && this.dom.tr.parentNode) {
|
|
var dom = this.dom;
|
|
|
|
switch (elementName) {
|
|
case 'drag':
|
|
if (dom.drag) {
|
|
dom.drag.focus();
|
|
} else {
|
|
dom.menu.focus();
|
|
}
|
|
|
|
break;
|
|
|
|
case 'menu':
|
|
dom.menu.focus();
|
|
break;
|
|
|
|
case 'expand':
|
|
if (this._hasChilds()) {
|
|
dom.expand.focus();
|
|
} else if (dom.field && this.fieldEditable) {
|
|
dom.field.focus();
|
|
(0,util.selectContentEditable)(dom.field);
|
|
} else if (dom.value && !this._hasChilds()) {
|
|
dom.value.focus();
|
|
(0,util.selectContentEditable)(dom.value);
|
|
} else {
|
|
dom.menu.focus();
|
|
}
|
|
|
|
break;
|
|
|
|
case 'field':
|
|
if (dom.field && this.fieldEditable) {
|
|
dom.field.focus();
|
|
(0,util.selectContentEditable)(dom.field);
|
|
} else if (dom.value && !this._hasChilds()) {
|
|
dom.value.focus();
|
|
(0,util.selectContentEditable)(dom.value);
|
|
} else if (this._hasChilds()) {
|
|
dom.expand.focus();
|
|
} else {
|
|
dom.menu.focus();
|
|
}
|
|
|
|
break;
|
|
|
|
case 'value':
|
|
default:
|
|
if (dom.select) {
|
|
// enum select box
|
|
dom.select.focus();
|
|
} else if (dom.value && !this._hasChilds()) {
|
|
dom.value.focus();
|
|
(0,util.selectContentEditable)(dom.value);
|
|
} else if (dom.field && this.fieldEditable) {
|
|
dom.field.focus();
|
|
(0,util.selectContentEditable)(dom.field);
|
|
} else if (this._hasChilds()) {
|
|
dom.expand.focus();
|
|
} else {
|
|
dom.menu.focus();
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Check if given node is a child. The method will check recursively to find
|
|
* this node.
|
|
* @param {Node} node
|
|
* @return {boolean} containsNode
|
|
*/
|
|
|
|
}, {
|
|
key: "containsNode",
|
|
value: function containsNode(node) {
|
|
if (this === node) {
|
|
return true;
|
|
}
|
|
|
|
var childs = this.childs;
|
|
|
|
if (childs) {
|
|
// TODO: use the js5 Array.some() here?
|
|
for (var i = 0, iMax = childs.length; i < iMax; i++) {
|
|
if (childs[i].containsNode(node)) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
/**
|
|
* Remove a child from the node.
|
|
* Only applicable when Node value is of type array or object
|
|
* @param {Node} node The child node to be removed;
|
|
* @param {boolean} [updateDom] If true (default), the DOM of the parent
|
|
* node will be updated (like child count)
|
|
* @return {Node | undefined} node The removed node on success,
|
|
* else undefined
|
|
*/
|
|
|
|
}, {
|
|
key: "removeChild",
|
|
value: function removeChild(node, updateDom) {
|
|
if (this.childs) {
|
|
var index = this.childs.indexOf(node);
|
|
|
|
if (index !== -1) {
|
|
if (index < this.visibleChilds && this.expanded) {
|
|
this.visibleChilds--;
|
|
}
|
|
|
|
node.hide(); // delete old search results
|
|
|
|
delete node.searchField;
|
|
delete node.searchValue;
|
|
var removedNode = this.childs.splice(index, 1)[0];
|
|
removedNode.parent = null;
|
|
|
|
if (updateDom !== false) {
|
|
this.updateDom({
|
|
updateIndexes: true
|
|
});
|
|
}
|
|
|
|
return removedNode;
|
|
}
|
|
}
|
|
|
|
return undefined;
|
|
}
|
|
/**
|
|
* Remove a child node node from this node
|
|
* This method is equal to Node.removeChild, except that _remove fire an
|
|
* onChange event.
|
|
* @param {Node} node
|
|
* @private
|
|
*/
|
|
|
|
}, {
|
|
key: "_remove",
|
|
value: function _remove(node) {
|
|
this.removeChild(node);
|
|
}
|
|
/**
|
|
* Change the type of the value of this Node
|
|
* @param {String} newType
|
|
*/
|
|
|
|
}, {
|
|
key: "changeType",
|
|
value: function changeType(newType) {
|
|
var oldType = this.type;
|
|
|
|
if (oldType === newType) {
|
|
// type is not changed
|
|
return;
|
|
}
|
|
|
|
if ((newType === 'string' || newType === 'auto') && (oldType === 'string' || oldType === 'auto')) {
|
|
// this is an easy change
|
|
this.type = newType;
|
|
} else {
|
|
// change from array to object, or from string/auto to object/array
|
|
var domAnchor = this._detachFromDom(); // delete the old DOM
|
|
|
|
|
|
this.clearDom(); // adjust the field and the value
|
|
|
|
this.type = newType; // adjust childs
|
|
|
|
if (newType === 'object') {
|
|
if (!this.childs) {
|
|
this.childs = [];
|
|
}
|
|
|
|
this.childs.forEach(function (child) {
|
|
child.clearDom();
|
|
delete child.index;
|
|
child.fieldEditable = true;
|
|
|
|
if (child.field === undefined) {
|
|
child.field = '';
|
|
}
|
|
});
|
|
|
|
if (oldType === 'string' || oldType === 'auto') {
|
|
this.expanded = true;
|
|
}
|
|
} else if (newType === 'array') {
|
|
if (!this.childs) {
|
|
this.childs = [];
|
|
}
|
|
|
|
this.childs.forEach(function (child, index) {
|
|
child.clearDom();
|
|
child.fieldEditable = false;
|
|
child.index = index;
|
|
});
|
|
|
|
if (oldType === 'string' || oldType === 'auto') {
|
|
this.expanded = true;
|
|
}
|
|
} else {
|
|
this.expanded = false;
|
|
}
|
|
|
|
this._attachToDom(domAnchor);
|
|
}
|
|
|
|
if (newType === 'auto' || newType === 'string') {
|
|
// cast value to the correct type
|
|
if (newType === 'string') {
|
|
this.value = String(this.value);
|
|
} else {
|
|
this.value = (0,util.parseString)(String(this.value));
|
|
}
|
|
|
|
this.focus();
|
|
}
|
|
|
|
this.updateDom({
|
|
updateIndexes: true
|
|
});
|
|
}
|
|
/**
|
|
* Test whether the JSON contents of this node are deep equal to provided JSON object.
|
|
* @param {*} json
|
|
*/
|
|
|
|
}, {
|
|
key: "deepEqual",
|
|
value: function deepEqual(json) {
|
|
var i;
|
|
|
|
if (this.type === 'array') {
|
|
if (!Array.isArray(json)) {
|
|
return false;
|
|
}
|
|
|
|
if (this.childs.length !== json.length) {
|
|
return false;
|
|
}
|
|
|
|
for (i = 0; i < this.childs.length; i++) {
|
|
if (!this.childs[i].deepEqual(json[i])) {
|
|
return false;
|
|
}
|
|
}
|
|
} else if (this.type === 'object') {
|
|
if (_typeof(json) !== 'object' || !json) {
|
|
return false;
|
|
} // we reckon with the order of the properties too.
|
|
|
|
|
|
var props = Object.keys(json);
|
|
|
|
if (this.childs.length !== props.length) {
|
|
return false;
|
|
}
|
|
|
|
for (i = 0; i < props.length; i++) {
|
|
var child = this.childs[i];
|
|
|
|
if (child.field !== props[i] || !child.deepEqual(json[child.field])) {
|
|
return false;
|
|
}
|
|
}
|
|
} else {
|
|
if (this.value !== json) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
/**
|
|
* Retrieve value from DOM
|
|
* @private
|
|
*/
|
|
|
|
}, {
|
|
key: "_getDomValue",
|
|
value: function _getDomValue() {
|
|
this._clearValueError();
|
|
|
|
if (this.dom.value && this.type !== 'array' && this.type !== 'object') {
|
|
this.valueInnerText = (0,util.getInnerText)(this.dom.value);
|
|
|
|
if (this.valueInnerText === '' && this.dom.value.innerHTML !== '') {
|
|
// When clearing the contents, often a <br/> remains, messing up the
|
|
// styling of the empty text box. Therefore we remove the <br/>
|
|
this.dom.value.textContent = '';
|
|
}
|
|
}
|
|
|
|
if (this.valueInnerText !== undefined) {
|
|
try {
|
|
// retrieve the value
|
|
var value;
|
|
|
|
if (this.type === 'string') {
|
|
value = this._unescapeHTML(this.valueInnerText);
|
|
} else {
|
|
var str = this._unescapeHTML(this.valueInnerText);
|
|
|
|
value = (0,util.parseString)(str);
|
|
}
|
|
|
|
if (value !== this.value) {
|
|
this.value = value;
|
|
|
|
this._debouncedOnChangeValue();
|
|
}
|
|
} catch (err) {
|
|
// keep the previous value
|
|
this._setValueError((0,i18n/* translate */.Iu)('cannotParseValueError'));
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Show a local error in case of invalid value
|
|
* @param {string} message
|
|
* @private
|
|
*/
|
|
|
|
}, {
|
|
key: "_setValueError",
|
|
value: function _setValueError(message) {
|
|
this.valueError = {
|
|
message: message
|
|
};
|
|
this.updateError();
|
|
}
|
|
}, {
|
|
key: "_clearValueError",
|
|
value: function _clearValueError() {
|
|
if (this.valueError) {
|
|
this.valueError = null;
|
|
this.updateError();
|
|
}
|
|
}
|
|
/**
|
|
* Show a local error in case of invalid or duplicate field
|
|
* @param {string} message
|
|
* @private
|
|
*/
|
|
|
|
}, {
|
|
key: "_setFieldError",
|
|
value: function _setFieldError(message) {
|
|
this.fieldError = {
|
|
message: message
|
|
};
|
|
this.updateError();
|
|
}
|
|
}, {
|
|
key: "_clearFieldError",
|
|
value: function _clearFieldError() {
|
|
if (this.fieldError) {
|
|
this.fieldError = null;
|
|
this.updateError();
|
|
}
|
|
}
|
|
/**
|
|
* Handle a changed value
|
|
* @private
|
|
*/
|
|
|
|
}, {
|
|
key: "_onChangeValue",
|
|
value: function _onChangeValue() {
|
|
// get current selection, then override the range such that we can select
|
|
// the added/removed text on undo/redo
|
|
var oldSelection = this.editor.getDomSelection();
|
|
|
|
if (oldSelection.range) {
|
|
var undoDiff = (0,util.textDiff)(String(this.value), String(this.previousValue));
|
|
oldSelection.range.startOffset = undoDiff.start;
|
|
oldSelection.range.endOffset = undoDiff.end;
|
|
}
|
|
|
|
var newSelection = this.editor.getDomSelection();
|
|
|
|
if (newSelection.range) {
|
|
var redoDiff = (0,util.textDiff)(String(this.previousValue), String(this.value));
|
|
newSelection.range.startOffset = redoDiff.start;
|
|
newSelection.range.endOffset = redoDiff.end;
|
|
}
|
|
|
|
this.editor._onAction('editValue', {
|
|
path: this.getInternalPath(),
|
|
oldValue: this.previousValue,
|
|
newValue: this.value,
|
|
oldSelection: oldSelection,
|
|
newSelection: newSelection
|
|
});
|
|
|
|
this.previousValue = this.value;
|
|
}
|
|
/**
|
|
* Handle a changed field
|
|
* @private
|
|
*/
|
|
|
|
}, {
|
|
key: "_onChangeField",
|
|
value: function _onChangeField() {
|
|
// get current selection, then override the range such that we can select
|
|
// the added/removed text on undo/redo
|
|
var oldSelection = this.editor.getDomSelection();
|
|
var previous = this.previousField || '';
|
|
|
|
if (oldSelection.range) {
|
|
var undoDiff = (0,util.textDiff)(this.field, previous);
|
|
oldSelection.range.startOffset = undoDiff.start;
|
|
oldSelection.range.endOffset = undoDiff.end;
|
|
}
|
|
|
|
var newSelection = this.editor.getDomSelection();
|
|
|
|
if (newSelection.range) {
|
|
var redoDiff = (0,util.textDiff)(previous, this.field);
|
|
newSelection.range.startOffset = redoDiff.start;
|
|
newSelection.range.endOffset = redoDiff.end;
|
|
}
|
|
|
|
this.editor._onAction('editField', {
|
|
parentPath: this.parent.getInternalPath(),
|
|
index: this.getIndex(),
|
|
oldValue: this.previousField,
|
|
newValue: this.field,
|
|
oldSelection: oldSelection,
|
|
newSelection: newSelection
|
|
});
|
|
|
|
this.previousField = this.field;
|
|
}
|
|
/**
|
|
* Update dom value:
|
|
* - the text color of the value, depending on the type of the value
|
|
* - the height of the field, depending on the width
|
|
* - background color in case it is empty
|
|
* @private
|
|
*/
|
|
|
|
}, {
|
|
key: "_updateDomValue",
|
|
value: function _updateDomValue() {
|
|
var domValue = this.dom.value;
|
|
|
|
if (domValue) {
|
|
var classNames = ['jsoneditor-value']; // set text color depending on value type
|
|
|
|
var value = this.value;
|
|
var valueType = this.type === 'auto' ? (0,util.getType)(value) : this.type;
|
|
var valueIsUrl = valueType === 'string' && (0,util.isUrl)(value);
|
|
classNames.push('jsoneditor-' + valueType);
|
|
|
|
if (valueIsUrl) {
|
|
classNames.push('jsoneditor-url');
|
|
} // visual styling when empty
|
|
|
|
|
|
var isEmpty = String(this.value) === '' && this.type !== 'array' && this.type !== 'object';
|
|
|
|
if (isEmpty) {
|
|
classNames.push('jsoneditor-empty');
|
|
} // highlight when there is a search result
|
|
|
|
|
|
if (this.searchValueActive) {
|
|
classNames.push('jsoneditor-highlight-active');
|
|
}
|
|
|
|
if (this.searchValue) {
|
|
classNames.push('jsoneditor-highlight');
|
|
}
|
|
|
|
domValue.className = classNames.join(' '); // update title
|
|
|
|
if (valueType === 'array' || valueType === 'object') {
|
|
var count = this.childs ? this.childs.length : 0;
|
|
domValue.title = this.type + ' containing ' + count + ' items';
|
|
} else if (valueIsUrl && this.editable.value) {
|
|
domValue.title = (0,i18n/* translate */.Iu)('openUrl');
|
|
} else {
|
|
domValue.title = '';
|
|
} // show checkbox when the value is a boolean
|
|
|
|
|
|
if (valueType === 'boolean' && this.editable.value) {
|
|
if (!this.dom.checkbox) {
|
|
this.dom.checkbox = document.createElement('input');
|
|
this.dom.checkbox.type = 'checkbox';
|
|
this.dom.tdCheckbox = document.createElement('td');
|
|
this.dom.tdCheckbox.className = 'jsoneditor-tree';
|
|
this.dom.tdCheckbox.appendChild(this.dom.checkbox);
|
|
this.dom.tdValue.parentNode.insertBefore(this.dom.tdCheckbox, this.dom.tdValue);
|
|
}
|
|
|
|
this.dom.checkbox.checked = this.value;
|
|
} else {
|
|
// cleanup checkbox when displayed
|
|
if (this.dom.tdCheckbox) {
|
|
this.dom.tdCheckbox.parentNode.removeChild(this.dom.tdCheckbox);
|
|
delete this.dom.tdCheckbox;
|
|
delete this.dom.checkbox;
|
|
}
|
|
} // create select box when this node has an enum object
|
|
|
|
|
|
if (this["enum"] && this.editable.value) {
|
|
if (!this.dom.select) {
|
|
this.dom.select = document.createElement('select');
|
|
this.id = this.field + '_' + new Date().getUTCMilliseconds();
|
|
this.dom.select.id = this.id;
|
|
this.dom.select.name = this.dom.select.id; // Create the default empty option
|
|
|
|
var defaultOption = document.createElement('option');
|
|
defaultOption.value = '';
|
|
defaultOption.textContent = '--';
|
|
this.dom.select.appendChild(defaultOption); // Iterate all enum values and add them as options
|
|
|
|
for (var i = 0; i < this["enum"].length; i++) {
|
|
var option = document.createElement('option');
|
|
option.value = this["enum"][i];
|
|
option.textContent = this["enum"][i];
|
|
this.dom.select.appendChild(option);
|
|
}
|
|
|
|
this.dom.tdSelect = document.createElement('td');
|
|
this.dom.tdSelect.className = 'jsoneditor-tree';
|
|
this.dom.tdSelect.appendChild(this.dom.select);
|
|
this.dom.tdValue.parentNode.insertBefore(this.dom.tdSelect, this.dom.tdValue);
|
|
} // Select the matching value
|
|
|
|
|
|
this.dom.select.value = this["enum"].indexOf(this.value) !== -1 ? this.value : ''; // default
|
|
// If the enum is inside a composite type display
|
|
// both the simple input and the dropdown field
|
|
|
|
if (this.schema && !Node_hasOwnProperty(this.schema, 'oneOf') && !Node_hasOwnProperty(this.schema, 'anyOf') && !Node_hasOwnProperty(this.schema, 'allOf')) {
|
|
this.valueFieldHTML = this.dom.tdValue.innerHTML;
|
|
this.dom.tdValue.style.visibility = 'hidden';
|
|
this.dom.tdValue.textContent = '';
|
|
} else {
|
|
delete this.valueFieldHTML;
|
|
}
|
|
} else {
|
|
// cleanup select box when displayed
|
|
if (this.dom.tdSelect) {
|
|
this.dom.tdSelect.parentNode.removeChild(this.dom.tdSelect);
|
|
delete this.dom.tdSelect;
|
|
delete this.dom.select;
|
|
this.dom.tdValue.innerHTML = this.valueFieldHTML;
|
|
this.dom.tdValue.style.visibility = '';
|
|
delete this.valueFieldHTML;
|
|
}
|
|
} // show color picker when value is a color
|
|
|
|
|
|
if (this.editable.value && this.editor.options.colorPicker && typeof value === 'string' && (0,util.isValidColor)(value)) {
|
|
if (!this.dom.color) {
|
|
this.dom.color = document.createElement('div');
|
|
this.dom.color.className = 'jsoneditor-color';
|
|
this.dom.tdColor = document.createElement('td');
|
|
this.dom.tdColor.className = 'jsoneditor-tree';
|
|
this.dom.tdColor.appendChild(this.dom.color);
|
|
this.dom.tdValue.parentNode.insertBefore(this.dom.tdColor, this.dom.tdValue);
|
|
} // update styling of value and color background
|
|
|
|
|
|
(0,util.addClassName)(this.dom.value, 'jsoneditor-color-value');
|
|
this.dom.color.style.backgroundColor = value;
|
|
} else {
|
|
// cleanup color picker when displayed
|
|
this._deleteDomColor();
|
|
} // show date tag when value is a timestamp in milliseconds
|
|
|
|
|
|
if (this._showTimestampTag()) {
|
|
if (!this.dom.date) {
|
|
this.dom.date = document.createElement('div');
|
|
this.dom.date.className = 'jsoneditor-date';
|
|
this.dom.value.parentNode.appendChild(this.dom.date);
|
|
}
|
|
|
|
var title = null;
|
|
|
|
if (typeof this.editor.options.timestampFormat === 'function') {
|
|
title = this.editor.options.timestampFormat({
|
|
field: this.field,
|
|
value: this.value,
|
|
path: this.getPath()
|
|
});
|
|
}
|
|
|
|
if (!title) {
|
|
this.dom.date.textContent = new Date(value).toISOString();
|
|
} else {
|
|
while (this.dom.date.firstChild) {
|
|
this.dom.date.removeChild(this.dom.date.firstChild);
|
|
}
|
|
|
|
this.dom.date.appendChild(document.createTextNode(title));
|
|
}
|
|
|
|
this.dom.date.title = new Date(value).toString();
|
|
} else {
|
|
// cleanup date tag
|
|
if (this.dom.date) {
|
|
this.dom.date.parentNode.removeChild(this.dom.date);
|
|
delete this.dom.date;
|
|
}
|
|
} // strip formatting from the contents of the editable div
|
|
|
|
|
|
(0,util.stripFormatting)(domValue);
|
|
|
|
this._updateDomDefault();
|
|
}
|
|
}
|
|
}, {
|
|
key: "_deleteDomColor",
|
|
value: function _deleteDomColor() {
|
|
if (this.dom.color) {
|
|
this.dom.tdColor.parentNode.removeChild(this.dom.tdColor);
|
|
delete this.dom.tdColor;
|
|
delete this.dom.color;
|
|
(0,util.removeClassName)(this.dom.value, 'jsoneditor-color-value');
|
|
}
|
|
}
|
|
/**
|
|
* Update dom field:
|
|
* - the text color of the field, depending on the text
|
|
* - the height of the field, depending on the width
|
|
* - background color in case it is empty
|
|
* @private
|
|
*/
|
|
|
|
}, {
|
|
key: "_updateDomField",
|
|
value: function _updateDomField() {
|
|
var domField = this.dom.field;
|
|
|
|
if (domField) {
|
|
var tooltip = (0,util.makeFieldTooltip)(this.schema, this.editor.options.language);
|
|
|
|
if (tooltip) {
|
|
domField.title = tooltip;
|
|
} // make background color lightgray when empty
|
|
|
|
|
|
var isEmpty = String(this.field) === '' && this.parent && this.parent.type !== 'array';
|
|
|
|
if (isEmpty) {
|
|
(0,util.addClassName)(domField, 'jsoneditor-empty');
|
|
} else {
|
|
(0,util.removeClassName)(domField, 'jsoneditor-empty');
|
|
} // highlight when there is a search result
|
|
|
|
|
|
if (this.searchFieldActive) {
|
|
(0,util.addClassName)(domField, 'jsoneditor-highlight-active');
|
|
} else {
|
|
(0,util.removeClassName)(domField, 'jsoneditor-highlight-active');
|
|
}
|
|
|
|
if (this.searchField) {
|
|
(0,util.addClassName)(domField, 'jsoneditor-highlight');
|
|
} else {
|
|
(0,util.removeClassName)(domField, 'jsoneditor-highlight');
|
|
} // strip formatting from the contents of the editable div
|
|
|
|
|
|
(0,util.stripFormatting)(domField);
|
|
}
|
|
}
|
|
/**
|
|
* Retrieve field from DOM
|
|
* @param {boolean} [forceUnique] If true, the field name will be changed
|
|
* into a unique name in case it is a duplicate.
|
|
* @private
|
|
*/
|
|
|
|
}, {
|
|
key: "_getDomField",
|
|
value: function _getDomField(forceUnique) {
|
|
this._clearFieldError();
|
|
|
|
if (this.dom.field && this.fieldEditable) {
|
|
this.fieldInnerText = (0,util.getInnerText)(this.dom.field);
|
|
|
|
if (this.fieldInnerText === '' && this.dom.field.innerHTML !== '') {
|
|
// When clearing the contents, often a <br/> remains, messing up the
|
|
// styling of the empty text box. Therefore we remove the <br/>
|
|
this.dom.field.textContent = '';
|
|
}
|
|
}
|
|
|
|
if (this.fieldInnerText !== undefined) {
|
|
try {
|
|
var field = this._unescapeHTML(this.fieldInnerText);
|
|
|
|
var existingFieldNames = this.parent.getFieldNames(this);
|
|
var isDuplicate = existingFieldNames.indexOf(field) !== -1;
|
|
|
|
if (!isDuplicate) {
|
|
if (field !== this.field) {
|
|
this.field = field;
|
|
|
|
this._debouncedOnChangeField();
|
|
}
|
|
} else {
|
|
if (forceUnique) {
|
|
// fix duplicate field: change it into a unique name
|
|
field = (0,util.findUniqueName)(field, existingFieldNames);
|
|
|
|
if (field !== this.field) {
|
|
this.field = field; // TODO: don't debounce but resolve right away, and cancel current debounce
|
|
|
|
this._debouncedOnChangeField();
|
|
}
|
|
} else {
|
|
this._setFieldError((0,i18n/* translate */.Iu)('duplicateFieldError'));
|
|
}
|
|
}
|
|
} catch (err) {
|
|
// keep the previous field value
|
|
this._setFieldError((0,i18n/* translate */.Iu)('cannotParseFieldError'));
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Update the value of the schema default element in the DOM.
|
|
* @private
|
|
* @returns {undefined}
|
|
*/
|
|
|
|
}, {
|
|
key: "_updateDomDefault",
|
|
value: function _updateDomDefault() {
|
|
// Short-circuit if schema is missing, has no default, or if Node has children
|
|
if (!this.schema || this.schema["default"] === undefined || this._hasChilds()) {
|
|
return;
|
|
} // select either enum dropdown (select) or input value
|
|
|
|
|
|
var inputElement = this.dom.select ? this.dom.select : this.dom.value;
|
|
|
|
if (!inputElement) {
|
|
return;
|
|
}
|
|
|
|
if (this.value === this.schema["default"]) {
|
|
inputElement.title = (0,i18n/* translate */.Iu)('default');
|
|
(0,util.addClassName)(inputElement, 'jsoneditor-is-default');
|
|
(0,util.removeClassName)(inputElement, 'jsoneditor-is-not-default');
|
|
} else {
|
|
inputElement.removeAttribute('title');
|
|
(0,util.removeClassName)(inputElement, 'jsoneditor-is-default');
|
|
(0,util.addClassName)(inputElement, 'jsoneditor-is-not-default');
|
|
}
|
|
}
|
|
/**
|
|
* Test whether to show a timestamp tag or not
|
|
* @return {boolean} Returns true when the value is a timestamp
|
|
*/
|
|
|
|
}, {
|
|
key: "_showTimestampTag",
|
|
value: function _showTimestampTag() {
|
|
if (typeof this.value !== 'number') {
|
|
return false;
|
|
}
|
|
|
|
var timestampTag = this.editor.options.timestampTag;
|
|
|
|
if (typeof timestampTag === 'function') {
|
|
var result = timestampTag({
|
|
field: this.field,
|
|
value: this.value,
|
|
path: this.getPath()
|
|
});
|
|
|
|
if (typeof result === 'boolean') {
|
|
return result;
|
|
} else {
|
|
return (0,util.isTimestamp)(this.field, this.value);
|
|
}
|
|
} else if (timestampTag === true) {
|
|
return (0,util.isTimestamp)(this.field, this.value);
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
/**
|
|
* Clear the dom of the node
|
|
*/
|
|
|
|
}, {
|
|
key: "clearDom",
|
|
value: function clearDom() {
|
|
// TODO: hide the node first?
|
|
// this.hide();
|
|
// TODO: recursively clear dom?
|
|
this.dom = {};
|
|
}
|
|
/**
|
|
* Get the HTML DOM TR element of the node.
|
|
* The dom will be generated when not yet created
|
|
* @return {Element} tr HTML DOM TR Element
|
|
*/
|
|
|
|
}, {
|
|
key: "getDom",
|
|
value: function getDom() {
|
|
var dom = this.dom;
|
|
|
|
if (dom.tr) {
|
|
return dom.tr;
|
|
}
|
|
|
|
this._updateEditability(); // create row
|
|
|
|
|
|
dom.tr = document.createElement('tr');
|
|
dom.tr.node = this;
|
|
|
|
if (this.editor.options.mode === 'tree') {
|
|
// note: we take here the global setting
|
|
var tdDrag = document.createElement('td');
|
|
|
|
if (this.editable.field) {
|
|
// create draggable area
|
|
if (this.parent) {
|
|
var domDrag = document.createElement('button');
|
|
domDrag.type = 'button';
|
|
dom.drag = domDrag;
|
|
domDrag.className = 'jsoneditor-button jsoneditor-dragarea';
|
|
domDrag.title = (0,i18n/* translate */.Iu)('drag');
|
|
tdDrag.appendChild(domDrag);
|
|
}
|
|
}
|
|
|
|
dom.tr.appendChild(tdDrag); // create context menu
|
|
|
|
var tdMenu = document.createElement('td');
|
|
var menu = document.createElement('button');
|
|
menu.type = 'button';
|
|
dom.menu = menu;
|
|
menu.className = 'jsoneditor-button jsoneditor-contextmenu-button';
|
|
menu.title = (0,i18n/* translate */.Iu)('actionsMenu');
|
|
tdMenu.appendChild(dom.menu);
|
|
dom.tr.appendChild(tdMenu);
|
|
} // create tree and field
|
|
|
|
|
|
var tdField = document.createElement('td');
|
|
dom.tr.appendChild(tdField);
|
|
dom.tree = this._createDomTree();
|
|
tdField.appendChild(dom.tree);
|
|
this.updateDom({
|
|
updateIndexes: true
|
|
});
|
|
return dom.tr;
|
|
}
|
|
/**
|
|
* Test whether a Node is rendered and visible
|
|
* @returns {boolean}
|
|
*/
|
|
|
|
}, {
|
|
key: "isVisible",
|
|
value: function isVisible() {
|
|
return this.dom && this.dom.tr && this.dom.tr.parentNode || false;
|
|
}
|
|
/**
|
|
* Test if this node is a sescendant of an other node
|
|
* @param {Node} node
|
|
* @return {boolean} isDescendant
|
|
* @private
|
|
*/
|
|
|
|
}, {
|
|
key: "isDescendantOf",
|
|
value: function isDescendantOf(node) {
|
|
var n = this.parent;
|
|
|
|
while (n) {
|
|
if (n === node) {
|
|
return true;
|
|
}
|
|
|
|
n = n.parent;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
/**
|
|
* Create an editable field
|
|
* @return {Element} domField
|
|
* @private
|
|
*/
|
|
|
|
}, {
|
|
key: "_createDomField",
|
|
value: function _createDomField() {
|
|
return document.createElement('div');
|
|
}
|
|
/**
|
|
* Set highlighting for this node and all its childs.
|
|
* Only applied to the currently visible (expanded childs)
|
|
* @param {boolean} highlight
|
|
*/
|
|
|
|
}, {
|
|
key: "setHighlight",
|
|
value: function setHighlight(highlight) {
|
|
if (this.dom.tr) {
|
|
if (highlight) {
|
|
(0,util.addClassName)(this.dom.tr, 'jsoneditor-highlight');
|
|
} else {
|
|
(0,util.removeClassName)(this.dom.tr, 'jsoneditor-highlight');
|
|
}
|
|
|
|
if (this.append) {
|
|
this.append.setHighlight(highlight);
|
|
}
|
|
|
|
if (this.childs) {
|
|
this.childs.forEach(function (child) {
|
|
child.setHighlight(highlight);
|
|
});
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Select or deselect a node
|
|
* @param {boolean} selected
|
|
* @param {boolean} [isFirst]
|
|
*/
|
|
|
|
}, {
|
|
key: "setSelected",
|
|
value: function setSelected(selected, isFirst) {
|
|
this.selected = selected;
|
|
|
|
if (this.dom.tr) {
|
|
if (selected) {
|
|
(0,util.addClassName)(this.dom.tr, 'jsoneditor-selected');
|
|
} else {
|
|
(0,util.removeClassName)(this.dom.tr, 'jsoneditor-selected');
|
|
}
|
|
|
|
if (isFirst) {
|
|
(0,util.addClassName)(this.dom.tr, 'jsoneditor-first');
|
|
} else {
|
|
(0,util.removeClassName)(this.dom.tr, 'jsoneditor-first');
|
|
}
|
|
|
|
if (this.append) {
|
|
this.append.setSelected(selected);
|
|
}
|
|
|
|
if (this.showMore) {
|
|
this.showMore.setSelected(selected);
|
|
}
|
|
|
|
if (this.childs) {
|
|
this.childs.forEach(function (child) {
|
|
child.setSelected(selected);
|
|
});
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Update the value of the node. Only primitive types are allowed, no Object
|
|
* or Array is allowed.
|
|
* @param {String | Number | Boolean | null} value
|
|
*/
|
|
|
|
}, {
|
|
key: "updateValue",
|
|
value: function updateValue(value) {
|
|
this.value = value;
|
|
this.previousValue = value;
|
|
this.valueError = undefined;
|
|
this.updateDom();
|
|
}
|
|
/**
|
|
* Update the field of the node.
|
|
* @param {String} field
|
|
*/
|
|
|
|
}, {
|
|
key: "updateField",
|
|
value: function updateField(field) {
|
|
this.field = field;
|
|
this.previousField = field;
|
|
this.fieldError = undefined;
|
|
this.updateDom();
|
|
}
|
|
/**
|
|
* Update the HTML DOM, optionally recursing through the childs
|
|
* @param {Object} [options] Available parameters:
|
|
* {boolean} [recurse] If true, the
|
|
* DOM of the childs will be updated recursively.
|
|
* False by default.
|
|
* {boolean} [updateIndexes] If true, the childs
|
|
* indexes of the node will be updated too. False by
|
|
* default.
|
|
*/
|
|
|
|
}, {
|
|
key: "updateDom",
|
|
value: function updateDom(options) {
|
|
// update level indentation
|
|
var domTree = this.dom.tree;
|
|
|
|
if (domTree) {
|
|
domTree.style.marginLeft = this.getLevel() * 24 + 'px';
|
|
} // apply field to DOM
|
|
|
|
|
|
var domField = this.dom.field;
|
|
|
|
if (domField) {
|
|
if (this.fieldEditable) {
|
|
// parent is an object
|
|
domField.contentEditable = this.editable.field;
|
|
domField.spellcheck = false;
|
|
domField.className = 'jsoneditor-field';
|
|
} else {
|
|
// parent is an array this is the root node
|
|
domField.contentEditable = false;
|
|
domField.className = 'jsoneditor-readonly';
|
|
}
|
|
|
|
var fieldText;
|
|
|
|
if (this.index !== undefined) {
|
|
fieldText = this.index;
|
|
} else if (this.field !== undefined) {
|
|
fieldText = this.field;
|
|
} else {
|
|
var schema = this.editor.options.schema ? Node._findSchema(this.editor.options.schema, this.editor.options.schemaRefs || {}, this.getPath()) : undefined;
|
|
|
|
if (schema && schema.title) {
|
|
fieldText = schema.title;
|
|
} else if (this._hasChilds()) {
|
|
fieldText = this.type;
|
|
} else {
|
|
fieldText = '';
|
|
}
|
|
}
|
|
|
|
var escapedField = this._escapeHTML(fieldText);
|
|
|
|
if (document.activeElement !== domField || escapedField !== this._unescapeHTML((0,util.getInnerText)(domField))) {
|
|
// only update if it not has the focus or when there is an actual change,
|
|
// else you would needlessly loose the caret position when changing tabs
|
|
// or whilst typing
|
|
domField.innerHTML = escapedField;
|
|
}
|
|
|
|
this._updateSchema();
|
|
} // apply value to DOM
|
|
|
|
|
|
var domValue = this.dom.value;
|
|
|
|
if (domValue) {
|
|
if (this.type === 'array' || this.type === 'object') {
|
|
this.updateNodeName();
|
|
} else {
|
|
var escapedValue = this._escapeHTML(this.value);
|
|
|
|
if (document.activeElement !== domValue || escapedValue !== this._unescapeHTML((0,util.getInnerText)(domValue))) {
|
|
// only update if it not has the focus or when there is an actual change,
|
|
// else you would needlessly loose the caret position when changing tabs
|
|
// or whilst typing
|
|
domValue.innerHTML = escapedValue;
|
|
}
|
|
}
|
|
} // apply styling to the table row
|
|
|
|
|
|
var tr = this.dom.tr;
|
|
|
|
if (tr) {
|
|
if (this.type === 'array' || this.type === 'object') {
|
|
(0,util.addClassName)(tr, 'jsoneditor-expandable');
|
|
|
|
if (this.expanded) {
|
|
(0,util.addClassName)(tr, 'jsoneditor-expanded');
|
|
(0,util.removeClassName)(tr, 'jsoneditor-collapsed');
|
|
} else {
|
|
(0,util.addClassName)(tr, 'jsoneditor-collapsed');
|
|
(0,util.removeClassName)(tr, 'jsoneditor-expanded');
|
|
}
|
|
} else {
|
|
(0,util.removeClassName)(tr, 'jsoneditor-expandable');
|
|
(0,util.removeClassName)(tr, 'jsoneditor-expanded');
|
|
(0,util.removeClassName)(tr, 'jsoneditor-collapsed');
|
|
}
|
|
} // update field and value
|
|
|
|
|
|
this._updateDomField();
|
|
|
|
this._updateDomValue(); // update childs indexes
|
|
|
|
|
|
if (options && options.updateIndexes === true) {
|
|
// updateIndexes is true or undefined
|
|
this._updateDomIndexes();
|
|
} // update childs recursively
|
|
|
|
|
|
if (options && options.recurse === true) {
|
|
if (this.childs) {
|
|
this.childs.forEach(function (child) {
|
|
child.updateDom(options);
|
|
});
|
|
}
|
|
} // update rendering of error
|
|
|
|
|
|
if (this.error) {
|
|
this.updateError();
|
|
} // update row with append button
|
|
|
|
|
|
if (this.append) {
|
|
this.append.updateDom();
|
|
} // update "show more" text at the bottom of large arrays
|
|
|
|
|
|
if (this.showMore) {
|
|
this.showMore.updateDom();
|
|
} // fire onClassName
|
|
|
|
|
|
this._updateCssClassName();
|
|
}
|
|
/**
|
|
* Locate the JSON schema of the node and check for any enum type
|
|
* @private
|
|
*/
|
|
|
|
}, {
|
|
key: "_updateSchema",
|
|
value: function _updateSchema() {
|
|
// Locating the schema of the node and checking for any enum type
|
|
if (this.editor && this.editor.options) {
|
|
// find the part of the json schema matching this nodes path
|
|
this.schema = this.editor.options.schema // fix childSchema with $ref, and not display the select element on the child schema because of not found enum
|
|
? Node._findSchema(this.editor.options.schema, this.editor.options.schemaRefs || {}, this.getPath()) : null;
|
|
|
|
if (this.schema) {
|
|
this["enum"] = Node._findEnum(this.schema);
|
|
} else {
|
|
delete this["enum"];
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Update the DOM of the childs of a node: update indexes and undefined field
|
|
* names.
|
|
* Only applicable when structure is an array or object
|
|
* @private
|
|
*/
|
|
|
|
}, {
|
|
key: "_updateDomIndexes",
|
|
value: function _updateDomIndexes() {
|
|
var domValue = this.dom.value;
|
|
var childs = this.childs;
|
|
|
|
if (domValue && childs) {
|
|
if (this.type === 'array') {
|
|
childs.forEach(function (child, index) {
|
|
child.index = index;
|
|
var childField = child.dom.field;
|
|
|
|
if (childField) {
|
|
childField.textContent = index;
|
|
}
|
|
});
|
|
} else if (this.type === 'object') {
|
|
childs.forEach(function (child) {
|
|
if (child.index !== undefined) {
|
|
delete child.index;
|
|
|
|
if (child.field === undefined) {
|
|
child.field = '';
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Create an editable value
|
|
* @private
|
|
*/
|
|
|
|
}, {
|
|
key: "_createDomValue",
|
|
value: function _createDomValue() {
|
|
var domValue;
|
|
|
|
if (this.type === 'array') {
|
|
domValue = document.createElement('div');
|
|
domValue.textContent = '[...]';
|
|
} else if (this.type === 'object') {
|
|
domValue = document.createElement('div');
|
|
domValue.textContent = '{...}';
|
|
} else {
|
|
if (!this.editable.value && (0,util.isUrl)(this.value)) {
|
|
// create a link in case of read-only editor and value containing an url
|
|
domValue = document.createElement('a');
|
|
domValue.href = this.value;
|
|
domValue.target = "_blank";
|
|
domValue.innerHTML = this._escapeHTML(this.value);
|
|
} else {
|
|
// create an editable or read-only div
|
|
domValue = document.createElement('div');
|
|
domValue.contentEditable = this.editable.value;
|
|
domValue.spellcheck = false;
|
|
domValue.innerHTML = this._escapeHTML(this.value);
|
|
}
|
|
}
|
|
|
|
return domValue;
|
|
}
|
|
/**
|
|
* Create an expand/collapse button
|
|
* @return {Element} expand
|
|
* @private
|
|
*/
|
|
|
|
}, {
|
|
key: "_createDomExpandButton",
|
|
value: function _createDomExpandButton() {
|
|
// create expand button
|
|
var expand = document.createElement('button');
|
|
expand.type = 'button';
|
|
|
|
if (this._hasChilds()) {
|
|
expand.className = this.expanded ? 'jsoneditor-button jsoneditor-expanded' : 'jsoneditor-button jsoneditor-collapsed';
|
|
expand.title = (0,i18n/* translate */.Iu)('expandTitle');
|
|
} else {
|
|
expand.className = 'jsoneditor-button jsoneditor-invisible';
|
|
expand.title = '';
|
|
}
|
|
|
|
return expand;
|
|
}
|
|
/**
|
|
* Create a DOM tree element, containing the expand/collapse button
|
|
* @return {Element} domTree
|
|
* @private
|
|
*/
|
|
|
|
}, {
|
|
key: "_createDomTree",
|
|
value: function _createDomTree() {
|
|
var dom = this.dom;
|
|
var domTree = document.createElement('table');
|
|
var tbody = document.createElement('tbody');
|
|
domTree.style.borderCollapse = 'collapse'; // TODO: put in css
|
|
|
|
domTree.className = 'jsoneditor-values';
|
|
domTree.appendChild(tbody);
|
|
var tr = document.createElement('tr');
|
|
tbody.appendChild(tr); // create expand button
|
|
|
|
var tdExpand = document.createElement('td');
|
|
tdExpand.className = 'jsoneditor-tree';
|
|
tr.appendChild(tdExpand);
|
|
dom.expand = this._createDomExpandButton();
|
|
tdExpand.appendChild(dom.expand);
|
|
dom.tdExpand = tdExpand; // create the field
|
|
|
|
var tdField = document.createElement('td');
|
|
tdField.className = 'jsoneditor-tree';
|
|
tr.appendChild(tdField);
|
|
dom.field = this._createDomField();
|
|
tdField.appendChild(dom.field);
|
|
dom.tdField = tdField; // create a separator
|
|
|
|
var tdSeparator = document.createElement('td');
|
|
tdSeparator.className = 'jsoneditor-tree';
|
|
tr.appendChild(tdSeparator);
|
|
|
|
if (this.type !== 'object' && this.type !== 'array') {
|
|
tdSeparator.appendChild(document.createTextNode(':'));
|
|
tdSeparator.className = 'jsoneditor-separator';
|
|
}
|
|
|
|
dom.tdSeparator = tdSeparator; // create the value
|
|
|
|
var tdValue = document.createElement('td');
|
|
tdValue.className = 'jsoneditor-tree';
|
|
tr.appendChild(tdValue);
|
|
dom.value = this._createDomValue();
|
|
tdValue.appendChild(dom.value);
|
|
dom.tdValue = tdValue;
|
|
return domTree;
|
|
}
|
|
/**
|
|
* Handle an event. The event is caught centrally by the editor
|
|
* @param {Event} event
|
|
*/
|
|
|
|
}, {
|
|
key: "onEvent",
|
|
value: function onEvent(event) {
|
|
var type = event.type;
|
|
var target = event.target || event.srcElement;
|
|
var dom = this.dom;
|
|
var node = this;
|
|
|
|
var expandable = this._hasChilds(); // check if mouse is on menu or on dragarea.
|
|
// If so, highlight current row and its childs
|
|
|
|
|
|
if (target === dom.drag || target === dom.menu) {
|
|
if (type === 'mouseover') {
|
|
this.editor.highlighter.highlight(this);
|
|
} else if (type === 'mouseout') {
|
|
this.editor.highlighter.unhighlight();
|
|
}
|
|
} // context menu events
|
|
|
|
|
|
if (type === 'click' && target === dom.menu) {
|
|
var highlighter = node.editor.highlighter;
|
|
highlighter.highlight(node);
|
|
highlighter.lock();
|
|
(0,util.addClassName)(dom.menu, 'jsoneditor-selected');
|
|
this.showContextMenu(dom.menu, function () {
|
|
(0,util.removeClassName)(dom.menu, 'jsoneditor-selected');
|
|
highlighter.unlock();
|
|
highlighter.unhighlight();
|
|
});
|
|
} // expand events
|
|
|
|
|
|
if (type === 'click') {
|
|
if (target === dom.expand) {
|
|
if (expandable) {
|
|
var recurse = event.ctrlKey; // with ctrl-key, expand/collapse all
|
|
|
|
this._onExpand(recurse);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (type === 'click' && (event.target === node.dom.tdColor || event.target === node.dom.color)) {
|
|
this._showColorPicker();
|
|
} // swap the value of a boolean when the checkbox displayed left is clicked
|
|
|
|
|
|
if (type === 'change' && target === dom.checkbox) {
|
|
this.dom.value.textContent = String(!this.value);
|
|
|
|
this._getDomValue();
|
|
|
|
this._updateDomDefault();
|
|
} // update the value of the node based on the selected option
|
|
|
|
|
|
if (type === 'change' && target === dom.select) {
|
|
this.dom.value.innerHTML = this._escapeHTML(dom.select.value);
|
|
|
|
this._getDomValue();
|
|
|
|
this._updateDomValue();
|
|
} // value events
|
|
|
|
|
|
var domValue = dom.value;
|
|
|
|
if (target === domValue) {
|
|
// noinspection FallthroughInSwitchStatementJS
|
|
switch (type) {
|
|
case 'blur':
|
|
case 'change':
|
|
{
|
|
this._getDomValue();
|
|
|
|
this._clearValueError();
|
|
|
|
this._updateDomValue();
|
|
|
|
var escapedValue = this._escapeHTML(this.value);
|
|
|
|
if (escapedValue !== this._unescapeHTML((0,util.getInnerText)(domValue))) {
|
|
// only update when there is an actual change, else you loose the
|
|
// caret position when changing tabs or whilst typing
|
|
domValue.innerHTML = escapedValue;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case 'input':
|
|
// this._debouncedGetDomValue(true); // TODO
|
|
this._getDomValue();
|
|
|
|
this._updateDomValue();
|
|
|
|
break;
|
|
|
|
case 'keydown':
|
|
case 'mousedown':
|
|
// TODO: cleanup
|
|
this.editor.selection = this.editor.getDomSelection();
|
|
break;
|
|
|
|
case 'click':
|
|
if (event.ctrlKey && this.editable.value) {
|
|
// if read-only, we use the regular click behavior of an anchor
|
|
if ((0,util.isUrl)(this.value)) {
|
|
event.preventDefault();
|
|
window.open(this.value, '_blank', 'noopener');
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case 'keyup':
|
|
// this._debouncedGetDomValue(true); // TODO
|
|
this._getDomValue();
|
|
|
|
this._updateDomValue();
|
|
|
|
break;
|
|
|
|
case 'cut':
|
|
case 'paste':
|
|
setTimeout(function () {
|
|
node._getDomValue();
|
|
|
|
node._updateDomValue();
|
|
}, 1);
|
|
break;
|
|
}
|
|
} // field events
|
|
|
|
|
|
var domField = dom.field;
|
|
|
|
if (target === domField) {
|
|
switch (type) {
|
|
case 'blur':
|
|
{
|
|
this._getDomField(true);
|
|
|
|
this._updateDomField();
|
|
|
|
var escapedField = this._escapeHTML(this.field);
|
|
|
|
if (escapedField !== this._unescapeHTML((0,util.getInnerText)(domField))) {
|
|
// only update when there is an actual change, else you loose the
|
|
// caret position when changing tabs or whilst typing
|
|
domField.innerHTML = escapedField;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case 'input':
|
|
this._getDomField();
|
|
|
|
this._updateSchema();
|
|
|
|
this._updateDomField();
|
|
|
|
this._updateDomValue();
|
|
|
|
break;
|
|
|
|
case 'keydown':
|
|
case 'mousedown':
|
|
this.editor.selection = this.editor.getDomSelection();
|
|
break;
|
|
|
|
case 'keyup':
|
|
this._getDomField();
|
|
|
|
this._updateDomField();
|
|
|
|
break;
|
|
|
|
case 'cut':
|
|
case 'paste':
|
|
setTimeout(function () {
|
|
node._getDomField();
|
|
|
|
node._updateDomField();
|
|
}, 1);
|
|
break;
|
|
}
|
|
} // focus
|
|
// when clicked in whitespace left or right from the field or value, set focus
|
|
|
|
|
|
var domTree = dom.tree;
|
|
|
|
if (domTree && target === domTree.parentNode && type === 'click' && !event.hasMoved) {
|
|
var left = event.offsetX !== undefined ? event.offsetX < (this.getLevel() + 1) * 24 : event.pageX < (0,util.getAbsoluteLeft)(dom.tdSeparator); // for FF
|
|
|
|
if (left || expandable) {
|
|
// node is expandable when it is an object or array
|
|
if (domField) {
|
|
(0,util.setEndOfContentEditable)(domField);
|
|
domField.focus();
|
|
}
|
|
} else {
|
|
if (domValue && !this["enum"]) {
|
|
(0,util.setEndOfContentEditable)(domValue);
|
|
domValue.focus();
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((target === dom.tdExpand && !expandable || target === dom.tdField || target === dom.tdSeparator) && type === 'click' && !event.hasMoved) {
|
|
if (domField) {
|
|
(0,util.setEndOfContentEditable)(domField);
|
|
domField.focus();
|
|
}
|
|
}
|
|
|
|
if (type === 'keydown') {
|
|
this.onKeyDown(event);
|
|
} // fire after applying for example a change by clicking a checkbox
|
|
|
|
|
|
if (typeof this.editor.options.onEvent === 'function') {
|
|
this._onEvent(event);
|
|
}
|
|
}
|
|
/**
|
|
* Trigger external onEvent provided in options if node is a JSON field or
|
|
* value.
|
|
* Information provided depends on the element, value is only included if
|
|
* event occurs in a JSON value:
|
|
* {field: string, path: {string|number}[] [, value: string]}
|
|
* @param {Event} event
|
|
* @private
|
|
*/
|
|
|
|
}, {
|
|
key: "_onEvent",
|
|
value: function _onEvent(event) {
|
|
var element = event.target;
|
|
var isField = element === this.dom.field;
|
|
var isValue = element === this.dom.value || element === this.dom.checkbox || element === this.dom.select;
|
|
|
|
if (isField || isValue) {
|
|
var info = {
|
|
field: this.getField(),
|
|
path: this.getPath()
|
|
}; // For leaf values, include value
|
|
|
|
if (isValue && !this._hasChilds()) {
|
|
info.value = this.getValue();
|
|
}
|
|
|
|
this.editor.options.onEvent(info, event);
|
|
}
|
|
}
|
|
/**
|
|
* Key down event handler
|
|
* @param {Event} event
|
|
*/
|
|
|
|
}, {
|
|
key: "onKeyDown",
|
|
value: function onKeyDown(event) {
|
|
var keynum = event.which || event.keyCode;
|
|
var target = event.target || event.srcElement;
|
|
var ctrlKey = event.ctrlKey;
|
|
var shiftKey = event.shiftKey;
|
|
var altKey = event.altKey;
|
|
var handled = false;
|
|
var prevNode, nextNode, nextDom, nextDom2;
|
|
var editable = this.editor.options.mode === 'tree';
|
|
var oldSelection;
|
|
var oldNextNode;
|
|
var oldParent;
|
|
var oldIndexRedo;
|
|
var newIndexRedo;
|
|
var oldParentPathRedo;
|
|
var newParentPathRedo;
|
|
var nodes;
|
|
var multiselection;
|
|
var selectedNodes = this.editor.multiselection.nodes.length > 0 ? this.editor.multiselection.nodes : [this];
|
|
var firstNode = selectedNodes[0];
|
|
var lastNode = selectedNodes[selectedNodes.length - 1]; // console.log(ctrlKey, keynum, event.charCode); // TODO: cleanup
|
|
|
|
if (keynum === 13) {
|
|
// Enter
|
|
if (target === this.dom.value) {
|
|
if (!this.editable.value || event.ctrlKey) {
|
|
if ((0,util.isUrl)(this.value)) {
|
|
window.open(this.value, '_blank', 'noopener');
|
|
handled = true;
|
|
}
|
|
}
|
|
} else if (target === this.dom.expand) {
|
|
var expandable = this._hasChilds();
|
|
|
|
if (expandable) {
|
|
var recurse = event.ctrlKey; // with ctrl-key, expand/collapse all
|
|
|
|
this._onExpand(recurse);
|
|
|
|
target.focus();
|
|
handled = true;
|
|
}
|
|
}
|
|
} else if (keynum === 68) {
|
|
// D
|
|
if (ctrlKey && editable) {
|
|
// Ctrl+D
|
|
Node.onDuplicate(selectedNodes);
|
|
handled = true;
|
|
}
|
|
} else if (keynum === 69) {
|
|
// E
|
|
if (ctrlKey) {
|
|
// Ctrl+E and Ctrl+Shift+E
|
|
this._onExpand(shiftKey); // recurse = shiftKey
|
|
|
|
|
|
target.focus(); // TODO: should restore focus in case of recursing expand (which takes DOM offline)
|
|
|
|
handled = true;
|
|
}
|
|
} else if (keynum === 77 && editable) {
|
|
// M
|
|
if (ctrlKey) {
|
|
// Ctrl+M
|
|
this.showContextMenu(target);
|
|
handled = true;
|
|
}
|
|
} else if (keynum === 46 && editable) {
|
|
// Del
|
|
if (ctrlKey) {
|
|
// Ctrl+Del
|
|
Node.onRemove(selectedNodes);
|
|
handled = true;
|
|
}
|
|
} else if (keynum === 45 && editable) {
|
|
// Ins
|
|
if (ctrlKey && !shiftKey) {
|
|
// Ctrl+Ins
|
|
this._onInsertBefore();
|
|
|
|
handled = true;
|
|
} else if (ctrlKey && shiftKey) {
|
|
// Ctrl+Shift+Ins
|
|
this._onInsertAfter();
|
|
|
|
handled = true;
|
|
}
|
|
} else if (keynum === 35) {
|
|
// End
|
|
if (altKey) {
|
|
// Alt+End
|
|
// find the last node
|
|
var endNode = this._lastNode();
|
|
|
|
if (endNode) {
|
|
endNode.focus(Node.focusElement || this._getElementName(target));
|
|
}
|
|
|
|
handled = true;
|
|
}
|
|
} else if (keynum === 36) {
|
|
// Home
|
|
if (altKey) {
|
|
// Alt+Home
|
|
// find the first node
|
|
var homeNode = this._firstNode();
|
|
|
|
if (homeNode) {
|
|
homeNode.focus(Node.focusElement || this._getElementName(target));
|
|
}
|
|
|
|
handled = true;
|
|
}
|
|
} else if (keynum === 37) {
|
|
// Arrow Left
|
|
if (altKey && !shiftKey) {
|
|
// Alt + Arrow Left
|
|
// move to left element
|
|
var prevElement = this._previousElement(target);
|
|
|
|
if (prevElement) {
|
|
this.focus(this._getElementName(prevElement));
|
|
}
|
|
|
|
handled = true;
|
|
} else if (altKey && shiftKey && editable) {
|
|
// Alt + Shift + Arrow left
|
|
if (lastNode.expanded) {
|
|
var appendDom = lastNode.getAppendDom();
|
|
nextDom = appendDom ? appendDom.nextSibling : undefined;
|
|
} else {
|
|
var dom = lastNode.getDom();
|
|
nextDom = dom.nextSibling;
|
|
}
|
|
|
|
if (nextDom) {
|
|
nextNode = Node.getNodeFromTarget(nextDom);
|
|
nextDom2 = nextDom.nextSibling;
|
|
var nextNode2 = Node.getNodeFromTarget(nextDom2);
|
|
|
|
if (nextNode && nextNode instanceof AppendNode && !(lastNode.parent.childs.length === 1) && nextNode2 && nextNode2.parent) {
|
|
oldSelection = this.editor.getDomSelection();
|
|
oldParent = firstNode.parent;
|
|
oldNextNode = oldParent.childs[lastNode.getIndex() + 1] || oldParent.append;
|
|
oldIndexRedo = firstNode.getIndex();
|
|
newIndexRedo = nextNode2.getIndex();
|
|
oldParentPathRedo = oldParent.getInternalPath();
|
|
newParentPathRedo = nextNode2.parent.getInternalPath();
|
|
selectedNodes.forEach(function (node) {
|
|
nextNode2.parent.moveBefore(node, nextNode2);
|
|
});
|
|
this.focus(Node.focusElement || this._getElementName(target));
|
|
|
|
this.editor._onAction('moveNodes', {
|
|
count: selectedNodes.length,
|
|
fieldNames: selectedNodes.map(getField),
|
|
oldParentPath: oldParent.getInternalPath(),
|
|
newParentPath: firstNode.parent.getInternalPath(),
|
|
oldIndex: oldNextNode.getIndex(),
|
|
newIndex: firstNode.getIndex(),
|
|
oldIndexRedo: oldIndexRedo,
|
|
newIndexRedo: newIndexRedo,
|
|
oldParentPathRedo: oldParentPathRedo,
|
|
newParentPathRedo: newParentPathRedo,
|
|
oldSelection: oldSelection,
|
|
newSelection: this.editor.getDomSelection()
|
|
});
|
|
}
|
|
}
|
|
}
|
|
} else if (keynum === 38) {
|
|
// Arrow Up
|
|
if (altKey && !shiftKey) {
|
|
// Alt + Arrow Up
|
|
// find the previous node
|
|
prevNode = this._previousNode();
|
|
|
|
if (prevNode) {
|
|
this.editor.deselect(true);
|
|
prevNode.focus(Node.focusElement || this._getElementName(target));
|
|
}
|
|
|
|
handled = true;
|
|
} else if (!altKey && ctrlKey && shiftKey && editable) {
|
|
// Ctrl + Shift + Arrow Up
|
|
// select multiple nodes
|
|
prevNode = this._previousNode();
|
|
|
|
if (prevNode) {
|
|
multiselection = this.editor.multiselection;
|
|
multiselection.start = multiselection.start || this;
|
|
multiselection.end = prevNode;
|
|
nodes = this.editor._findTopLevelNodes(multiselection.start, multiselection.end);
|
|
this.editor.select(nodes);
|
|
prevNode.focus('field'); // select field as we know this always exists
|
|
}
|
|
|
|
handled = true;
|
|
} else if (altKey && shiftKey && editable) {
|
|
// Alt + Shift + Arrow Up
|
|
// find the previous node
|
|
prevNode = firstNode._previousNode();
|
|
|
|
if (prevNode && prevNode.parent) {
|
|
oldSelection = this.editor.getDomSelection();
|
|
oldParent = firstNode.parent;
|
|
oldNextNode = oldParent.childs[lastNode.getIndex() + 1] || oldParent.append;
|
|
oldIndexRedo = firstNode.getIndex();
|
|
newIndexRedo = prevNode.getIndex();
|
|
oldParentPathRedo = oldParent.getInternalPath();
|
|
newParentPathRedo = prevNode.parent.getInternalPath();
|
|
selectedNodes.forEach(function (node) {
|
|
prevNode.parent.moveBefore(node, prevNode);
|
|
});
|
|
this.focus(Node.focusElement || this._getElementName(target));
|
|
|
|
this.editor._onAction('moveNodes', {
|
|
count: selectedNodes.length,
|
|
fieldNames: selectedNodes.map(getField),
|
|
oldParentPath: oldParent.getInternalPath(),
|
|
newParentPath: firstNode.parent.getInternalPath(),
|
|
oldIndex: oldNextNode.getIndex(),
|
|
newIndex: firstNode.getIndex(),
|
|
oldIndexRedo: oldIndexRedo,
|
|
newIndexRedo: newIndexRedo,
|
|
oldParentPathRedo: oldParentPathRedo,
|
|
newParentPathRedo: newParentPathRedo,
|
|
oldSelection: oldSelection,
|
|
newSelection: this.editor.getDomSelection()
|
|
});
|
|
}
|
|
|
|
handled = true;
|
|
}
|
|
} else if (keynum === 39) {
|
|
// Arrow Right
|
|
if (altKey && !shiftKey) {
|
|
// Alt + Arrow Right
|
|
// move to right element
|
|
var nextElement = this._nextElement(target);
|
|
|
|
if (nextElement) {
|
|
this.focus(this._getElementName(nextElement));
|
|
}
|
|
|
|
handled = true;
|
|
} else if (altKey && shiftKey && editable) {
|
|
// Alt + Shift + Arrow Right
|
|
var _dom = firstNode.getDom();
|
|
|
|
var prevDom = _dom.previousSibling;
|
|
|
|
if (prevDom) {
|
|
prevNode = Node.getNodeFromTarget(prevDom);
|
|
|
|
if (prevNode && prevNode.parent && !prevNode.isVisible()) {
|
|
oldSelection = this.editor.getDomSelection();
|
|
oldParent = firstNode.parent;
|
|
oldNextNode = oldParent.childs[lastNode.getIndex() + 1] || oldParent.append;
|
|
oldIndexRedo = firstNode.getIndex();
|
|
newIndexRedo = prevNode.getIndex();
|
|
oldParentPathRedo = oldParent.getInternalPath();
|
|
newParentPathRedo = prevNode.parent.getInternalPath();
|
|
selectedNodes.forEach(function (node) {
|
|
prevNode.parent.moveBefore(node, prevNode);
|
|
});
|
|
this.focus(Node.focusElement || this._getElementName(target));
|
|
|
|
this.editor._onAction('moveNodes', {
|
|
count: selectedNodes.length,
|
|
fieldNames: selectedNodes.map(getField),
|
|
oldParentPath: oldParent.getInternalPath(),
|
|
newParentPath: firstNode.parent.getInternalPath(),
|
|
oldIndex: oldNextNode.getIndex(),
|
|
newIndex: firstNode.getIndex(),
|
|
oldIndexRedo: oldIndexRedo,
|
|
newIndexRedo: newIndexRedo,
|
|
oldParentPathRedo: oldParentPathRedo,
|
|
newParentPathRedo: newParentPathRedo,
|
|
oldSelection: oldSelection,
|
|
newSelection: this.editor.getDomSelection()
|
|
});
|
|
}
|
|
}
|
|
}
|
|
} else if (keynum === 40) {
|
|
// Arrow Down
|
|
if (altKey && !shiftKey) {
|
|
// Alt + Arrow Down
|
|
// find the next node
|
|
nextNode = this._nextNode();
|
|
|
|
if (nextNode) {
|
|
this.editor.deselect(true);
|
|
nextNode.focus(Node.focusElement || this._getElementName(target));
|
|
}
|
|
|
|
handled = true;
|
|
} else if (!altKey && ctrlKey && shiftKey && editable) {
|
|
// Ctrl + Shift + Arrow Down
|
|
// select multiple nodes
|
|
nextNode = this._nextNode();
|
|
|
|
if (nextNode) {
|
|
multiselection = this.editor.multiselection;
|
|
multiselection.start = multiselection.start || this;
|
|
multiselection.end = nextNode;
|
|
nodes = this.editor._findTopLevelNodes(multiselection.start, multiselection.end);
|
|
this.editor.select(nodes);
|
|
nextNode.focus('field'); // select field as we know this always exists
|
|
}
|
|
|
|
handled = true;
|
|
} else if (altKey && shiftKey && editable) {
|
|
// Alt + Shift + Arrow Down
|
|
// find the 2nd next node and move before that one
|
|
if (lastNode.expanded) {
|
|
nextNode = lastNode.append ? lastNode.append._nextNode() : undefined;
|
|
} else {
|
|
nextNode = lastNode._nextNode();
|
|
} // when the next node is not visible, we've reached the "showMore" buttons
|
|
|
|
|
|
if (nextNode && !nextNode.isVisible()) {
|
|
nextNode = nextNode.parent.showMore;
|
|
}
|
|
|
|
if (nextNode && nextNode instanceof AppendNode) {
|
|
nextNode = lastNode;
|
|
}
|
|
|
|
var _nextNode2 = nextNode && (nextNode._nextNode() || nextNode.parent.append);
|
|
|
|
if (_nextNode2 && _nextNode2.parent) {
|
|
oldSelection = this.editor.getDomSelection();
|
|
oldParent = firstNode.parent;
|
|
oldNextNode = oldParent.childs[lastNode.getIndex() + 1] || oldParent.append;
|
|
oldIndexRedo = firstNode.getIndex();
|
|
newIndexRedo = _nextNode2.getIndex();
|
|
oldParentPathRedo = oldParent.getInternalPath();
|
|
newParentPathRedo = _nextNode2.parent.getInternalPath();
|
|
selectedNodes.forEach(function (node) {
|
|
_nextNode2.parent.moveBefore(node, _nextNode2);
|
|
});
|
|
this.focus(Node.focusElement || this._getElementName(target));
|
|
|
|
this.editor._onAction('moveNodes', {
|
|
count: selectedNodes.length,
|
|
fieldNames: selectedNodes.map(getField),
|
|
oldParentPath: oldParent.getInternalPath(),
|
|
newParentPath: firstNode.parent.getInternalPath(),
|
|
oldParentPathRedo: oldParentPathRedo,
|
|
newParentPathRedo: newParentPathRedo,
|
|
oldIndexRedo: oldIndexRedo,
|
|
newIndexRedo: newIndexRedo,
|
|
oldIndex: oldNextNode.getIndex(),
|
|
newIndex: firstNode.getIndex(),
|
|
oldSelection: oldSelection,
|
|
newSelection: this.editor.getDomSelection()
|
|
});
|
|
}
|
|
|
|
handled = true;
|
|
}
|
|
}
|
|
|
|
if (handled) {
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
}
|
|
}
|
|
/**
|
|
* Handle the expand event, when clicked on the expand button
|
|
* @param {boolean} recurse If true, child nodes will be expanded too
|
|
* @private
|
|
*/
|
|
|
|
}, {
|
|
key: "_onExpand",
|
|
value: function _onExpand(recurse) {
|
|
var table;
|
|
var frame;
|
|
var scrollTop;
|
|
|
|
if (recurse) {
|
|
// Take the table offline
|
|
table = this.dom.tr.parentNode; // TODO: not nice to access the main table like this
|
|
|
|
frame = table.parentNode;
|
|
scrollTop = frame.scrollTop;
|
|
frame.removeChild(table);
|
|
}
|
|
|
|
if (this.expanded) {
|
|
this.collapse(recurse);
|
|
} else {
|
|
this.expand(recurse);
|
|
}
|
|
|
|
if (recurse) {
|
|
// Put the table online again
|
|
frame.appendChild(table);
|
|
frame.scrollTop = scrollTop;
|
|
}
|
|
}
|
|
/**
|
|
* Open a color picker to select a new color
|
|
* @private
|
|
*/
|
|
|
|
}, {
|
|
key: "_showColorPicker",
|
|
value: function _showColorPicker() {
|
|
if (typeof this.editor.options.onColorPicker === 'function' && this.dom.color) {
|
|
var node = this; // force deleting current color picker (if any)
|
|
|
|
node._deleteDomColor();
|
|
|
|
node.updateDom();
|
|
var colorAnchor = (0,createAbsoluteAnchor/* createAbsoluteAnchor */.w)(this.dom.color, this.editor.getPopupAnchor());
|
|
this.editor.options.onColorPicker(colorAnchor, this.value, function onChange(value) {
|
|
if (typeof value === 'string' && value !== node.value) {
|
|
// force recreating the color block, to cleanup any attached color picker
|
|
node._deleteDomColor();
|
|
|
|
node.value = value;
|
|
node.updateDom();
|
|
|
|
node._debouncedOnChangeValue();
|
|
}
|
|
});
|
|
}
|
|
}
|
|
/**
|
|
* Get all field names of an object
|
|
* @param {Node} [excludeNode] Optional node to be excluded from the returned field names
|
|
* @return {string[]}
|
|
*/
|
|
|
|
}, {
|
|
key: "getFieldNames",
|
|
value: function getFieldNames(excludeNode) {
|
|
if (this.type === 'object') {
|
|
return this.childs.filter(function (child) {
|
|
return child !== excludeNode;
|
|
}).map(function (child) {
|
|
return child.field;
|
|
});
|
|
}
|
|
|
|
return [];
|
|
}
|
|
/**
|
|
* Handle insert before event
|
|
* @param {String} [field]
|
|
* @param {*} [value]
|
|
* @param {String} [type] Can be 'auto', 'array', 'object', or 'string'
|
|
* @private
|
|
*/
|
|
|
|
}, {
|
|
key: "_onInsertBefore",
|
|
value: function _onInsertBefore(field, value, type) {
|
|
var oldSelection = this.editor.getDomSelection();
|
|
var newNode = new Node(this.editor, {
|
|
field: field !== undefined ? field : '',
|
|
value: value !== undefined ? value : '',
|
|
type: type
|
|
});
|
|
newNode.expand(true);
|
|
var beforePath = this.getInternalPath();
|
|
this.parent.insertBefore(newNode, this);
|
|
this.editor.highlighter.unhighlight();
|
|
newNode.focus('field');
|
|
var newSelection = this.editor.getDomSelection();
|
|
|
|
this.editor._onAction('insertBeforeNodes', {
|
|
nodes: [newNode],
|
|
paths: [newNode.getInternalPath()],
|
|
beforePath: beforePath,
|
|
parentPath: this.parent.getInternalPath(),
|
|
oldSelection: oldSelection,
|
|
newSelection: newSelection
|
|
});
|
|
}
|
|
/**
|
|
* Handle insert after event
|
|
* @param {String} [field]
|
|
* @param {*} [value]
|
|
* @param {String} [type] Can be 'auto', 'array', 'object', or 'string'
|
|
* @private
|
|
*/
|
|
|
|
}, {
|
|
key: "_onInsertAfter",
|
|
value: function _onInsertAfter(field, value, type) {
|
|
var oldSelection = this.editor.getDomSelection();
|
|
var newNode = new Node(this.editor, {
|
|
field: field !== undefined ? field : '',
|
|
value: value !== undefined ? value : '',
|
|
type: type
|
|
});
|
|
newNode.expand(true);
|
|
this.parent.insertAfter(newNode, this);
|
|
this.editor.highlighter.unhighlight();
|
|
newNode.focus('field');
|
|
var newSelection = this.editor.getDomSelection();
|
|
|
|
this.editor._onAction('insertAfterNodes', {
|
|
nodes: [newNode],
|
|
paths: [newNode.getInternalPath()],
|
|
afterPath: this.getInternalPath(),
|
|
parentPath: this.parent.getInternalPath(),
|
|
oldSelection: oldSelection,
|
|
newSelection: newSelection
|
|
});
|
|
}
|
|
/**
|
|
* Handle append event
|
|
* @param {String} [field]
|
|
* @param {*} [value]
|
|
* @param {String} [type] Can be 'auto', 'array', 'object', or 'string'
|
|
* @private
|
|
*/
|
|
|
|
}, {
|
|
key: "_onAppend",
|
|
value: function _onAppend(field, value, type) {
|
|
var oldSelection = this.editor.getDomSelection();
|
|
var newNode = new Node(this.editor, {
|
|
field: field !== undefined ? field : '',
|
|
value: value !== undefined ? value : '',
|
|
type: type
|
|
});
|
|
newNode.expand(true);
|
|
this.parent.appendChild(newNode);
|
|
this.editor.highlighter.unhighlight();
|
|
newNode.focus('field');
|
|
var newSelection = this.editor.getDomSelection();
|
|
|
|
this.editor._onAction('appendNodes', {
|
|
nodes: [newNode],
|
|
paths: [newNode.getInternalPath()],
|
|
parentPath: this.parent.getInternalPath(),
|
|
oldSelection: oldSelection,
|
|
newSelection: newSelection
|
|
});
|
|
}
|
|
/**
|
|
* Change the type of the node's value
|
|
* @param {String} newType
|
|
* @private
|
|
*/
|
|
|
|
}, {
|
|
key: "_onChangeType",
|
|
value: function _onChangeType(newType) {
|
|
var oldType = this.type;
|
|
|
|
if (newType !== oldType) {
|
|
var oldSelection = this.editor.getDomSelection();
|
|
this.changeType(newType);
|
|
var newSelection = this.editor.getDomSelection();
|
|
|
|
this.editor._onAction('changeType', {
|
|
path: this.getInternalPath(),
|
|
oldType: oldType,
|
|
newType: newType,
|
|
oldSelection: oldSelection,
|
|
newSelection: newSelection
|
|
});
|
|
}
|
|
}
|
|
/**
|
|
* Sort the child's of the node. Only applicable when the node has type 'object'
|
|
* or 'array'.
|
|
* @param {String[] | string} path Path of the child value to be compared
|
|
* @param {String} direction Sorting direction. Available values: "asc", "desc"
|
|
* @param {boolean} [triggerAction=true] If true (default), a user action will be
|
|
* triggered, creating an entry in history
|
|
* and invoking onChange.
|
|
* @private
|
|
*/
|
|
|
|
}, {
|
|
key: "sort",
|
|
value: function sort(path, direction) {
|
|
var triggerAction = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
|
|
|
|
if (typeof path === 'string') {
|
|
path = (0,util.parsePath)(path);
|
|
}
|
|
|
|
if (!this._hasChilds()) {
|
|
return;
|
|
}
|
|
|
|
this.hideChilds(); // sorting is faster when the childs are not attached to the dom
|
|
// copy the childs array (the old one will be kept for an undo action
|
|
|
|
var oldChilds = this.childs;
|
|
this.childs = this.childs.concat(); // sort the childs array
|
|
|
|
var order = direction === 'desc' ? -1 : 1;
|
|
|
|
if (this.type === 'object') {
|
|
this.childs.sort(function (a, b) {
|
|
return order * naturalSort_default()(a.field, b.field);
|
|
});
|
|
} else {
|
|
// this.type === 'array'
|
|
this.childs.sort(function (a, b) {
|
|
var nodeA = a.getNestedChild(path);
|
|
var nodeB = b.getNestedChild(path);
|
|
|
|
if (!nodeA) {
|
|
return order;
|
|
}
|
|
|
|
if (!nodeB) {
|
|
return -order;
|
|
}
|
|
|
|
var valueA = nodeA.value;
|
|
var valueB = nodeB.value;
|
|
|
|
if (typeof valueA !== 'string' && typeof valueB !== 'string') {
|
|
// both values are a number, boolean, or null -> use simple, fast sorting
|
|
return valueA > valueB ? order : valueA < valueB ? -order : 0;
|
|
}
|
|
|
|
return order * naturalSort_default()(valueA, valueB);
|
|
});
|
|
} // update the index numbering
|
|
|
|
|
|
this._updateDomIndexes();
|
|
|
|
this.showChilds();
|
|
|
|
if (triggerAction === true) {
|
|
this.editor._onAction('sort', {
|
|
path: this.getInternalPath(),
|
|
oldChilds: oldChilds,
|
|
newChilds: this.childs
|
|
});
|
|
}
|
|
}
|
|
/**
|
|
* Replace the value of the node, keep it's state
|
|
* @param {*} newValue
|
|
*/
|
|
|
|
}, {
|
|
key: "update",
|
|
value: function update(newValue) {
|
|
var oldValue = this.getInternalValue();
|
|
this.setValue(newValue);
|
|
|
|
this.editor._onAction('transform', {
|
|
path: this.getInternalPath(),
|
|
oldValue: oldValue,
|
|
newValue: this.getInternalValue()
|
|
});
|
|
}
|
|
/**
|
|
* Remove this node from the DOM
|
|
* @returns {{table: Element, nextTr?: Element}}
|
|
* Returns the DOM elements that which be used to attach the node
|
|
* to the DOM again, see _attachToDom.
|
|
* @private
|
|
*/
|
|
|
|
}, {
|
|
key: "_detachFromDom",
|
|
value: function _detachFromDom() {
|
|
var table = this.dom.tr ? this.dom.tr.parentNode : undefined;
|
|
var lastTr;
|
|
|
|
if (this.expanded) {
|
|
lastTr = this.getAppendDom();
|
|
} else {
|
|
lastTr = this.getDom();
|
|
}
|
|
|
|
var nextTr = lastTr && lastTr.parentNode ? lastTr.nextSibling : undefined;
|
|
this.hide({
|
|
resetVisibleChilds: false
|
|
});
|
|
return {
|
|
table: table,
|
|
nextTr: nextTr
|
|
};
|
|
}
|
|
/**
|
|
* Attach this node to the DOM again
|
|
* @param {{table: Element, nextTr?: Element}} domAnchor
|
|
* The DOM elements returned by _detachFromDom.
|
|
* @private
|
|
*/
|
|
|
|
}, {
|
|
key: "_attachToDom",
|
|
value: function _attachToDom(domAnchor) {
|
|
if (domAnchor.table) {
|
|
if (domAnchor.nextTr) {
|
|
domAnchor.table.insertBefore(this.getDom(), domAnchor.nextTr);
|
|
} else {
|
|
domAnchor.table.appendChild(this.getDom());
|
|
}
|
|
}
|
|
|
|
if (this.expanded) {
|
|
this.showChilds();
|
|
}
|
|
}
|
|
/**
|
|
* Transform the node given a JMESPath query.
|
|
* @param {String} query JMESPath query to apply
|
|
* @private
|
|
*/
|
|
|
|
}, {
|
|
key: "transform",
|
|
value: function transform(query) {
|
|
if (!this._hasChilds()) {
|
|
return;
|
|
}
|
|
|
|
this.hideChilds(); // sorting is faster when the childs are not attached to the dom
|
|
|
|
try {
|
|
var oldInternalValue = this.getInternalValue(); // apply the JMESPath query
|
|
|
|
var oldValue = this.getValue();
|
|
var newValue = this.editor.options.executeQuery(oldValue, query);
|
|
this.setValue(newValue);
|
|
var newInternalValue = this.getInternalValue();
|
|
|
|
this.editor._onAction('transform', {
|
|
path: this.getInternalPath(),
|
|
oldValue: oldInternalValue,
|
|
newValue: newInternalValue
|
|
});
|
|
|
|
this.showChilds();
|
|
} catch (err) {
|
|
this.showChilds();
|
|
|
|
this.editor._onError(err);
|
|
}
|
|
}
|
|
/**
|
|
* Make this object the root object of the ditor
|
|
*/
|
|
|
|
}, {
|
|
key: "extract",
|
|
value: function extract() {
|
|
this.editor.node.hideChilds();
|
|
this.hideChilds();
|
|
|
|
try {
|
|
var oldInternalValue = this.editor.node.getInternalValue();
|
|
|
|
this.editor._setRoot(this);
|
|
|
|
var newInternalValue = this.editor.node.getInternalValue();
|
|
|
|
this.editor._onAction('transform', {
|
|
path: this.editor.node.getInternalPath(),
|
|
oldValue: oldInternalValue,
|
|
newValue: newInternalValue
|
|
});
|
|
} catch (err) {
|
|
this.editor._onError(err);
|
|
} finally {
|
|
this.updateDom({
|
|
recurse: true
|
|
});
|
|
this.showChilds();
|
|
}
|
|
}
|
|
/**
|
|
* Get a nested child given a path with properties
|
|
* @param {String[]} path
|
|
* @returns {Node}
|
|
*/
|
|
|
|
}, {
|
|
key: "getNestedChild",
|
|
value: function getNestedChild(path) {
|
|
var i = 0;
|
|
var child = this;
|
|
|
|
while (child && i < path.length) {
|
|
child = child.findChildByProperty(path[i]);
|
|
i++;
|
|
}
|
|
|
|
return child;
|
|
}
|
|
/**
|
|
* Find a child by property name
|
|
* @param {string} prop
|
|
* @return {Node | undefined} Returns the child node when found, or undefined otherwise
|
|
*/
|
|
|
|
}, {
|
|
key: "findChildByProperty",
|
|
value: function findChildByProperty(prop) {
|
|
if (this.type !== 'object') {
|
|
return undefined;
|
|
}
|
|
|
|
return this.childs.find(function (child) {
|
|
return child.field === prop;
|
|
});
|
|
}
|
|
/**
|
|
* Create a table row with an append button.
|
|
* @return {HTMLElement | undefined} tr with the AppendNode contents
|
|
*/
|
|
|
|
}, {
|
|
key: "getAppendDom",
|
|
value: function getAppendDom() {
|
|
if (!this.append) {
|
|
this.append = new AppendNode(this.editor);
|
|
this.append.setParent(this);
|
|
}
|
|
|
|
return this.append.getDom();
|
|
}
|
|
/**
|
|
* Create a table row with an showMore button and text
|
|
* @return {HTMLElement | undefined} tr with the AppendNode contents
|
|
*/
|
|
|
|
}, {
|
|
key: "getShowMoreDom",
|
|
value: function getShowMoreDom() {
|
|
if (!this.showMore) {
|
|
this.showMore = new ShowMoreNode(this.editor, this);
|
|
}
|
|
|
|
return this.showMore.getDom();
|
|
}
|
|
/**
|
|
* Get the next sibling of current node
|
|
* @return {Node} nextSibling
|
|
*/
|
|
|
|
}, {
|
|
key: "nextSibling",
|
|
value: function nextSibling() {
|
|
var index = this.parent.childs.indexOf(this);
|
|
return this.parent.childs[index + 1] || this.parent.append;
|
|
}
|
|
/**
|
|
* Get the previously rendered node
|
|
* @return {Node | null} previousNode
|
|
*/
|
|
|
|
}, {
|
|
key: "_previousNode",
|
|
value: function _previousNode() {
|
|
var prevNode = null;
|
|
var dom = this.getDom();
|
|
|
|
if (dom && dom.parentNode) {
|
|
// find the previous field
|
|
var prevDom = dom;
|
|
|
|
do {
|
|
prevDom = prevDom.previousSibling;
|
|
prevNode = Node.getNodeFromTarget(prevDom);
|
|
} while (prevDom && prevNode && prevNode instanceof AppendNode && !prevNode.isVisible());
|
|
}
|
|
|
|
return prevNode;
|
|
}
|
|
/**
|
|
* Get the next rendered node
|
|
* @return {Node | null} nextNode
|
|
* @private
|
|
*/
|
|
|
|
}, {
|
|
key: "_nextNode",
|
|
value: function _nextNode() {
|
|
var nextNode = null;
|
|
var dom = this.getDom();
|
|
|
|
if (dom && dom.parentNode) {
|
|
// find the previous field
|
|
var nextDom = dom;
|
|
|
|
do {
|
|
nextDom = nextDom.nextSibling;
|
|
nextNode = Node.getNodeFromTarget(nextDom);
|
|
} while (nextDom && nextNode && nextNode instanceof AppendNode && !nextNode.isVisible());
|
|
}
|
|
|
|
return nextNode;
|
|
}
|
|
/**
|
|
* Get the first rendered node
|
|
* @return {Node | null} firstNode
|
|
* @private
|
|
*/
|
|
|
|
}, {
|
|
key: "_firstNode",
|
|
value: function _firstNode() {
|
|
var firstNode = null;
|
|
var dom = this.getDom();
|
|
|
|
if (dom && dom.parentNode) {
|
|
var firstDom = dom.parentNode.firstChild;
|
|
firstNode = Node.getNodeFromTarget(firstDom);
|
|
}
|
|
|
|
return firstNode;
|
|
}
|
|
/**
|
|
* Get the last rendered node
|
|
* @return {Node | null} lastNode
|
|
* @private
|
|
*/
|
|
|
|
}, {
|
|
key: "_lastNode",
|
|
value: function _lastNode() {
|
|
var lastNode = null;
|
|
var dom = this.getDom();
|
|
|
|
if (dom && dom.parentNode) {
|
|
var lastDom = dom.parentNode.lastChild;
|
|
lastNode = Node.getNodeFromTarget(lastDom);
|
|
|
|
while (lastDom && lastNode && !lastNode.isVisible()) {
|
|
lastDom = lastDom.previousSibling;
|
|
lastNode = Node.getNodeFromTarget(lastDom);
|
|
}
|
|
}
|
|
|
|
return lastNode;
|
|
}
|
|
/**
|
|
* Get the next element which can have focus.
|
|
* @param {Element} elem
|
|
* @return {Element | null} nextElem
|
|
* @private
|
|
*/
|
|
|
|
}, {
|
|
key: "_previousElement",
|
|
value: function _previousElement(elem) {
|
|
var dom = this.dom; // noinspection FallthroughInSwitchStatementJS
|
|
|
|
switch (elem) {
|
|
case dom.value:
|
|
if (this.fieldEditable) {
|
|
return dom.field;
|
|
}
|
|
|
|
// intentional fall through
|
|
|
|
case dom.field:
|
|
if (this._hasChilds()) {
|
|
return dom.expand;
|
|
}
|
|
|
|
// intentional fall through
|
|
|
|
case dom.expand:
|
|
return dom.menu;
|
|
|
|
case dom.menu:
|
|
if (dom.drag) {
|
|
return dom.drag;
|
|
}
|
|
|
|
// intentional fall through
|
|
|
|
default:
|
|
return null;
|
|
}
|
|
}
|
|
/**
|
|
* Get the next element which can have focus.
|
|
* @param {Element} elem
|
|
* @return {Element | null} nextElem
|
|
* @private
|
|
*/
|
|
|
|
}, {
|
|
key: "_nextElement",
|
|
value: function _nextElement(elem) {
|
|
var dom = this.dom; // noinspection FallthroughInSwitchStatementJS
|
|
|
|
switch (elem) {
|
|
case dom.drag:
|
|
return dom.menu;
|
|
|
|
case dom.menu:
|
|
if (this._hasChilds()) {
|
|
return dom.expand;
|
|
}
|
|
|
|
// intentional fall through
|
|
|
|
case dom.expand:
|
|
if (this.fieldEditable) {
|
|
return dom.field;
|
|
}
|
|
|
|
// intentional fall through
|
|
|
|
case dom.field:
|
|
if (!this._hasChilds()) {
|
|
return dom.value;
|
|
}
|
|
|
|
// intentional fall through
|
|
|
|
default:
|
|
return null;
|
|
}
|
|
}
|
|
/**
|
|
* Get the dom name of given element. returns null if not found.
|
|
* For example when element === dom.field, "field" is returned.
|
|
* @param {Element} element
|
|
* @return {String | null} elementName Available elements with name: 'drag',
|
|
* 'menu', 'expand', 'field', 'value'
|
|
* @private
|
|
*/
|
|
|
|
}, {
|
|
key: "_getElementName",
|
|
value: function _getElementName(element) {
|
|
var _this2 = this;
|
|
|
|
return Object.keys(this.dom).find(function (name) {
|
|
return _this2.dom[name] === element;
|
|
});
|
|
}
|
|
/**
|
|
* Test if this node has childs. This is the case when the node is an object
|
|
* or array.
|
|
* @return {boolean} hasChilds
|
|
* @private
|
|
*/
|
|
|
|
}, {
|
|
key: "_hasChilds",
|
|
value: function _hasChilds() {
|
|
return this.type === 'array' || this.type === 'object';
|
|
}
|
|
}, {
|
|
key: "addTemplates",
|
|
value: function addTemplates(menu, append) {
|
|
var node = this;
|
|
var templates = node.editor.options.templates;
|
|
if (templates == null) return;
|
|
|
|
if (templates.length) {
|
|
// create a separator
|
|
menu.push({
|
|
type: 'separator'
|
|
});
|
|
}
|
|
|
|
var appendData = function appendData(name, data) {
|
|
node._onAppend(name, data);
|
|
};
|
|
|
|
var insertData = function insertData(name, data) {
|
|
node._onInsertBefore(name, data);
|
|
};
|
|
|
|
templates.forEach(function (template) {
|
|
menu.push({
|
|
text: template.text,
|
|
className: template.className || 'jsoneditor-type-object',
|
|
title: template.title,
|
|
click: append ? appendData.bind(this, template.field, template.value) : insertData.bind(this, template.field, template.value)
|
|
});
|
|
});
|
|
}
|
|
/**
|
|
* Show a contextmenu for this node
|
|
* @param {HTMLElement} anchor Anchor element to attach the context menu to
|
|
* as sibling.
|
|
* @param {function} [onClose] Callback method called when the context menu
|
|
* is being closed.
|
|
*/
|
|
|
|
}, {
|
|
key: "showContextMenu",
|
|
value: function showContextMenu(anchor, onClose) {
|
|
var node = this;
|
|
var items = [];
|
|
|
|
if (this.editable.value) {
|
|
items.push({
|
|
text: (0,i18n/* translate */.Iu)('type'),
|
|
title: (0,i18n/* translate */.Iu)('typeTitle'),
|
|
className: 'jsoneditor-type-' + this.type,
|
|
submenu: [{
|
|
text: (0,i18n/* translate */.Iu)('auto'),
|
|
className: 'jsoneditor-type-auto' + (this.type === 'auto' ? ' jsoneditor-selected' : ''),
|
|
title: (0,i18n/* translate */.Iu)('autoType'),
|
|
click: function click() {
|
|
node._onChangeType('auto');
|
|
}
|
|
}, {
|
|
text: (0,i18n/* translate */.Iu)('array'),
|
|
className: 'jsoneditor-type-array' + (this.type === 'array' ? ' jsoneditor-selected' : ''),
|
|
title: (0,i18n/* translate */.Iu)('arrayType'),
|
|
click: function click() {
|
|
node._onChangeType('array');
|
|
}
|
|
}, {
|
|
text: (0,i18n/* translate */.Iu)('object'),
|
|
className: 'jsoneditor-type-object' + (this.type === 'object' ? ' jsoneditor-selected' : ''),
|
|
title: (0,i18n/* translate */.Iu)('objectType'),
|
|
click: function click() {
|
|
node._onChangeType('object');
|
|
}
|
|
}, {
|
|
text: (0,i18n/* translate */.Iu)('string'),
|
|
className: 'jsoneditor-type-string' + (this.type === 'string' ? ' jsoneditor-selected' : ''),
|
|
title: (0,i18n/* translate */.Iu)('stringType'),
|
|
click: function click() {
|
|
node._onChangeType('string');
|
|
}
|
|
}]
|
|
});
|
|
}
|
|
|
|
if (this._hasChilds()) {
|
|
if (this.editor.options.enableSort) {
|
|
items.push({
|
|
text: (0,i18n/* translate */.Iu)('sort'),
|
|
title: (0,i18n/* translate */.Iu)('sortTitle', {
|
|
type: this.type
|
|
}),
|
|
className: 'jsoneditor-sort-asc',
|
|
click: function click() {
|
|
node.showSortModal();
|
|
}
|
|
});
|
|
}
|
|
|
|
if (this.editor.options.enableTransform) {
|
|
items.push({
|
|
text: (0,i18n/* translate */.Iu)('transform'),
|
|
title: (0,i18n/* translate */.Iu)('transformTitle', {
|
|
type: this.type
|
|
}),
|
|
className: 'jsoneditor-transform',
|
|
click: function click() {
|
|
node.showTransformModal();
|
|
}
|
|
});
|
|
}
|
|
|
|
if (this.parent) {
|
|
items.push({
|
|
text: (0,i18n/* translate */.Iu)('extract'),
|
|
title: (0,i18n/* translate */.Iu)('extractTitle', {
|
|
type: this.type
|
|
}),
|
|
className: 'jsoneditor-extract',
|
|
click: function click() {
|
|
node.extract();
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
if (this.parent && this.parent._hasChilds()) {
|
|
if (items.length) {
|
|
// create a separator
|
|
items.push({
|
|
type: 'separator'
|
|
});
|
|
} // create append button (for last child node only)
|
|
|
|
|
|
var childs = node.parent.childs;
|
|
|
|
if (node === childs[childs.length - 1]) {
|
|
var appendSubmenu = [{
|
|
text: (0,i18n/* translate */.Iu)('auto'),
|
|
className: 'jsoneditor-type-auto',
|
|
title: (0,i18n/* translate */.Iu)('autoType'),
|
|
click: function click() {
|
|
node._onAppend('', '', 'auto');
|
|
}
|
|
}, {
|
|
text: (0,i18n/* translate */.Iu)('array'),
|
|
className: 'jsoneditor-type-array',
|
|
title: (0,i18n/* translate */.Iu)('arrayType'),
|
|
click: function click() {
|
|
node._onAppend('', []);
|
|
}
|
|
}, {
|
|
text: (0,i18n/* translate */.Iu)('object'),
|
|
className: 'jsoneditor-type-object',
|
|
title: (0,i18n/* translate */.Iu)('objectType'),
|
|
click: function click() {
|
|
node._onAppend('', {});
|
|
}
|
|
}, {
|
|
text: (0,i18n/* translate */.Iu)('string'),
|
|
className: 'jsoneditor-type-string',
|
|
title: (0,i18n/* translate */.Iu)('stringType'),
|
|
click: function click() {
|
|
node._onAppend('', '', 'string');
|
|
}
|
|
}];
|
|
node.addTemplates(appendSubmenu, true);
|
|
items.push({
|
|
text: (0,i18n/* translate */.Iu)('appendText'),
|
|
title: (0,i18n/* translate */.Iu)('appendTitle'),
|
|
submenuTitle: (0,i18n/* translate */.Iu)('appendSubmenuTitle'),
|
|
className: 'jsoneditor-append',
|
|
click: function click() {
|
|
node._onAppend('', '', 'auto');
|
|
},
|
|
submenu: appendSubmenu
|
|
});
|
|
} // create insert button
|
|
|
|
|
|
var insertSubmenu = [{
|
|
text: (0,i18n/* translate */.Iu)('auto'),
|
|
className: 'jsoneditor-type-auto',
|
|
title: (0,i18n/* translate */.Iu)('autoType'),
|
|
click: function click() {
|
|
node._onInsertBefore('', '', 'auto');
|
|
}
|
|
}, {
|
|
text: (0,i18n/* translate */.Iu)('array'),
|
|
className: 'jsoneditor-type-array',
|
|
title: (0,i18n/* translate */.Iu)('arrayType'),
|
|
click: function click() {
|
|
node._onInsertBefore('', []);
|
|
}
|
|
}, {
|
|
text: (0,i18n/* translate */.Iu)('object'),
|
|
className: 'jsoneditor-type-object',
|
|
title: (0,i18n/* translate */.Iu)('objectType'),
|
|
click: function click() {
|
|
node._onInsertBefore('', {});
|
|
}
|
|
}, {
|
|
text: (0,i18n/* translate */.Iu)('string'),
|
|
className: 'jsoneditor-type-string',
|
|
title: (0,i18n/* translate */.Iu)('stringType'),
|
|
click: function click() {
|
|
node._onInsertBefore('', '', 'string');
|
|
}
|
|
}];
|
|
node.addTemplates(insertSubmenu, false);
|
|
items.push({
|
|
text: (0,i18n/* translate */.Iu)('insert'),
|
|
title: (0,i18n/* translate */.Iu)('insertTitle'),
|
|
submenuTitle: (0,i18n/* translate */.Iu)('insertSub'),
|
|
className: 'jsoneditor-insert',
|
|
click: function click() {
|
|
node._onInsertBefore('', '', 'auto');
|
|
},
|
|
submenu: insertSubmenu
|
|
});
|
|
|
|
if (this.editable.field) {
|
|
// create duplicate button
|
|
items.push({
|
|
text: (0,i18n/* translate */.Iu)('duplicateText'),
|
|
title: (0,i18n/* translate */.Iu)('duplicateField'),
|
|
className: 'jsoneditor-duplicate',
|
|
click: function click() {
|
|
Node.onDuplicate(node);
|
|
}
|
|
}); // create remove button
|
|
|
|
items.push({
|
|
text: (0,i18n/* translate */.Iu)('removeText'),
|
|
title: (0,i18n/* translate */.Iu)('removeField'),
|
|
className: 'jsoneditor-remove',
|
|
click: function click() {
|
|
Node.onRemove(node);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
if (this.editor.options.onCreateMenu) {
|
|
var path = node.getPath();
|
|
items = this.editor.options.onCreateMenu(items, {
|
|
type: 'single',
|
|
path: path,
|
|
paths: [path]
|
|
});
|
|
}
|
|
|
|
var menu = new ContextMenu/* ContextMenu */.x(items, {
|
|
close: onClose
|
|
});
|
|
menu.show(anchor, this.editor.getPopupAnchor());
|
|
}
|
|
/**
|
|
* Show sorting modal
|
|
*/
|
|
|
|
}, {
|
|
key: "showSortModal",
|
|
value: function showSortModal() {
|
|
var node = this;
|
|
var container = this.editor.options.modalAnchor || constants/* DEFAULT_MODAL_ANCHOR */.qD;
|
|
var json = this.getValue();
|
|
|
|
function onSort(sortedBy) {
|
|
var path = sortedBy.path;
|
|
var pathArray = (0,util.parsePath)(path);
|
|
node.sortedBy = sortedBy;
|
|
node.sort(pathArray, sortedBy.direction);
|
|
}
|
|
|
|
(0,js_showSortModal.showSortModal)(container, json, onSort, node.sortedBy);
|
|
}
|
|
/**
|
|
* Show transform modal
|
|
*/
|
|
|
|
}, {
|
|
key: "showTransformModal",
|
|
value: function showTransformModal() {
|
|
var _this3 = this;
|
|
|
|
var _this$editor$options = this.editor.options,
|
|
modalAnchor = _this$editor$options.modalAnchor,
|
|
createQuery = _this$editor$options.createQuery,
|
|
executeQuery = _this$editor$options.executeQuery,
|
|
queryDescription = _this$editor$options.queryDescription;
|
|
var json = this.getValue();
|
|
|
|
(0,js_showTransformModal.showTransformModal)({
|
|
container: modalAnchor || constants/* DEFAULT_MODAL_ANCHOR */.qD,
|
|
json: json,
|
|
queryDescription: queryDescription,
|
|
// can be undefined
|
|
createQuery: createQuery,
|
|
executeQuery: executeQuery,
|
|
onTransform: function onTransform(query) {
|
|
_this3.transform(query);
|
|
}
|
|
});
|
|
}
|
|
/**
|
|
* get the type of a value
|
|
* @param {*} value
|
|
* @return {String} type Can be 'object', 'array', 'string', 'auto'
|
|
* @private
|
|
*/
|
|
|
|
}, {
|
|
key: "_getType",
|
|
value: function _getType(value) {
|
|
if (value instanceof Array) {
|
|
return 'array';
|
|
}
|
|
|
|
if (value instanceof Object) {
|
|
return 'object';
|
|
}
|
|
|
|
if (typeof value === 'string' && typeof (0,util.parseString)(value) !== 'string') {
|
|
return 'string';
|
|
}
|
|
|
|
return 'auto';
|
|
}
|
|
/**
|
|
* escape a text, such that it can be displayed safely in an HTML element
|
|
* @param {String} text
|
|
* @return {String} escapedText
|
|
* @private
|
|
*/
|
|
|
|
}, {
|
|
key: "_escapeHTML",
|
|
value: function _escapeHTML(text) {
|
|
if (typeof text !== 'string') {
|
|
return String(text);
|
|
} else {
|
|
var htmlEscaped = String(text).replace(/&/g, '&') // must be replaced first!
|
|
.replace(/</g, '<').replace(/>/g, '>').replace(/ {2}/g, ' ') // replace double space with an nbsp and space
|
|
.replace(/^ /, ' ') // space at start
|
|
.replace(/ $/, ' '); // space at end
|
|
|
|
var json = JSON.stringify(htmlEscaped);
|
|
var html = json.substring(1, json.length - 1);
|
|
|
|
if (this.editor.options.escapeUnicode === true) {
|
|
html = (0,util.escapeUnicodeChars)(html);
|
|
}
|
|
|
|
return html;
|
|
}
|
|
}
|
|
/**
|
|
* unescape a string.
|
|
* @param {String} escapedText
|
|
* @return {String} text
|
|
* @private
|
|
*/
|
|
|
|
}, {
|
|
key: "_unescapeHTML",
|
|
value: function _unescapeHTML(escapedText) {
|
|
var json = '"' + this._escapeJSON(escapedText) + '"';
|
|
var htmlEscaped = (0,util.parse)(json);
|
|
return htmlEscaped.replace(/</g, '<').replace(/>/g, '>').replace(/ |\u00A0/g, ' ').replace(/&/g, '&'); // must be replaced last
|
|
}
|
|
/**
|
|
* escape a text to make it a valid JSON string. The method will:
|
|
* - replace unescaped double quotes with '\"'
|
|
* - replace unescaped backslash with '\\'
|
|
* - replace returns with '\n'
|
|
* @param {String} text
|
|
* @return {String} escapedText
|
|
* @private
|
|
*/
|
|
|
|
}, {
|
|
key: "_escapeJSON",
|
|
value: function _escapeJSON(text) {
|
|
// TODO: replace with some smart regex (only when a new solution is faster!)
|
|
var escaped = '';
|
|
var i = 0;
|
|
|
|
while (i < text.length) {
|
|
var c = text.charAt(i);
|
|
|
|
if (c === '\n') {
|
|
escaped += '\\n';
|
|
} else if (c === '\\') {
|
|
escaped += c;
|
|
i++;
|
|
c = text.charAt(i);
|
|
|
|
if (c === '' || '"\\/bfnrtu'.indexOf(c) === -1) {
|
|
escaped += '\\'; // no valid escape character
|
|
}
|
|
|
|
escaped += c;
|
|
} else if (c === '"') {
|
|
escaped += '\\"';
|
|
} else {
|
|
escaped += c;
|
|
}
|
|
|
|
i++;
|
|
}
|
|
|
|
return escaped;
|
|
}
|
|
/**
|
|
* update the object name according to the callback onNodeName
|
|
* @private
|
|
*/
|
|
|
|
}, {
|
|
key: "updateNodeName",
|
|
value: function updateNodeName() {
|
|
var count = this.childs ? this.childs.length : 0;
|
|
var nodeName;
|
|
|
|
if (this.type === 'object' || this.type === 'array') {
|
|
if (this.editor.options.onNodeName) {
|
|
try {
|
|
nodeName = this.editor.options.onNodeName({
|
|
path: this.getPath(),
|
|
size: count,
|
|
type: this.type
|
|
});
|
|
} catch (err) {
|
|
console.error('Error in onNodeName callback: ', err);
|
|
}
|
|
}
|
|
|
|
this.dom.value.textContent = this.type === 'object' ? '{' + (nodeName || count) + '}' : '[' + (nodeName || count) + ']';
|
|
}
|
|
}
|
|
/**
|
|
* update recursively the object's and its children's name.
|
|
* @private
|
|
*/
|
|
|
|
}, {
|
|
key: "recursivelyUpdateNodeName",
|
|
value: function recursivelyUpdateNodeName() {
|
|
if (this.expanded) {
|
|
this.updateNodeName();
|
|
|
|
if (this.childs !== 'undefined') {
|
|
var i;
|
|
|
|
for (i in this.childs) {
|
|
this.childs[i].recursivelyUpdateNodeName();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}]);
|
|
|
|
return Node;
|
|
}(); // debounce interval for keyboard input in milliseconds
|
|
|
|
Node.prototype.DEBOUNCE_INTERVAL = 150; // search will stop iterating as soon as the max is reached
|
|
|
|
Node.prototype.MAX_SEARCH_RESULTS = 999; // default number of child nodes to display
|
|
|
|
var DEFAULT_MAX_VISIBLE_CHILDS = 100; // stores the element name currently having the focus
|
|
|
|
Node.focusElement = undefined;
|
|
/**
|
|
* Select all text in an editable div after a delay of 0 ms
|
|
* @param {Element} editableDiv
|
|
*/
|
|
|
|
Node.select = function (editableDiv) {
|
|
setTimeout(function () {
|
|
(0,util.selectContentEditable)(editableDiv);
|
|
}, 0);
|
|
};
|
|
/**
|
|
* DragStart event, fired on mousedown on the dragarea at the left side of a Node
|
|
* @param {Node[] | Node} nodes
|
|
* @param {Event} event
|
|
*/
|
|
|
|
|
|
Node.onDragStart = function (nodes, event) {
|
|
if (!Array.isArray(nodes)) {
|
|
return Node.onDragStart([nodes], event);
|
|
}
|
|
|
|
if (nodes.length === 0) {
|
|
return;
|
|
}
|
|
|
|
var firstNode = nodes[0];
|
|
var lastNode = nodes[nodes.length - 1];
|
|
var parent = firstNode.parent;
|
|
var draggedNode = Node.getNodeFromTarget(event.target);
|
|
var editor = firstNode.editor; // in case of multiple selected nodes, offsetY prevents the selection from
|
|
// jumping when you start dragging one of the lower down nodes in the selection
|
|
|
|
var offsetY = (0,util.getAbsoluteTop)(draggedNode.dom.tr) - (0,util.getAbsoluteTop)(firstNode.dom.tr);
|
|
|
|
if (!editor.mousemove) {
|
|
editor.mousemove = (0,util.addEventListener)(event.view, 'mousemove', function (event) {
|
|
Node.onDrag(nodes, event);
|
|
});
|
|
}
|
|
|
|
if (!editor.mouseup) {
|
|
editor.mouseup = (0,util.addEventListener)(event.view, 'mouseup', function (event) {
|
|
Node.onDragEnd(nodes, event);
|
|
});
|
|
}
|
|
|
|
editor.highlighter.lock();
|
|
editor.drag = {
|
|
oldCursor: document.body.style.cursor,
|
|
oldSelection: editor.getDomSelection(),
|
|
oldPaths: nodes.map(getInternalPath),
|
|
oldParent: parent,
|
|
oldNextNode: parent.childs[lastNode.getIndex() + 1] || parent.append,
|
|
oldParentPathRedo: parent.getInternalPath(),
|
|
oldIndexRedo: firstNode.getIndex(),
|
|
mouseX: event.pageX,
|
|
offsetY: offsetY,
|
|
level: firstNode.getLevel()
|
|
};
|
|
document.body.style.cursor = 'move';
|
|
event.preventDefault();
|
|
};
|
|
/**
|
|
* Drag event, fired when moving the mouse while dragging a Node
|
|
* @param {Node[] | Node} nodes
|
|
* @param {Event} event
|
|
*/
|
|
|
|
|
|
Node.onDrag = function (nodes, event) {
|
|
if (!Array.isArray(nodes)) {
|
|
return Node.onDrag([nodes], event);
|
|
}
|
|
|
|
if (nodes.length === 0) {
|
|
return;
|
|
} // TODO: this method has grown too large. Split it in a number of methods
|
|
|
|
|
|
var editor = nodes[0].editor;
|
|
var mouseY = event.pageY - editor.drag.offsetY;
|
|
var mouseX = event.pageX;
|
|
var trPrev, trNext, trFirst, trLast, trRoot;
|
|
var nodePrev, nodeNext;
|
|
var topPrev, topFirst, bottomNext, heightNext;
|
|
var moved = false; // TODO: add an ESC option, which resets to the original position
|
|
// move up/down
|
|
|
|
var firstNode = nodes[0];
|
|
var trThis = firstNode.dom.tr;
|
|
var topThis = (0,util.getAbsoluteTop)(trThis);
|
|
var heightThis = trThis.offsetHeight;
|
|
|
|
if (mouseY < topThis) {
|
|
// move up
|
|
trPrev = trThis;
|
|
|
|
do {
|
|
trPrev = trPrev.previousSibling;
|
|
nodePrev = Node.getNodeFromTarget(trPrev);
|
|
topPrev = trPrev ? (0,util.getAbsoluteTop)(trPrev) : 0;
|
|
} while (trPrev && mouseY < topPrev);
|
|
|
|
if (nodePrev && !nodePrev.parent) {
|
|
nodePrev = undefined;
|
|
}
|
|
|
|
if (!nodePrev) {
|
|
// move to the first node
|
|
trRoot = trThis.parentNode.firstChild;
|
|
trPrev = trRoot ? trRoot.nextSibling : undefined;
|
|
nodePrev = Node.getNodeFromTarget(trPrev);
|
|
|
|
if (nodePrev === firstNode) {
|
|
nodePrev = undefined;
|
|
}
|
|
}
|
|
|
|
if (nodePrev && nodePrev.isVisible()) {
|
|
// check if mouseY is really inside the found node
|
|
trPrev = nodePrev.dom.tr;
|
|
topPrev = trPrev ? (0,util.getAbsoluteTop)(trPrev) : 0;
|
|
|
|
if (mouseY > topPrev + heightThis) {
|
|
nodePrev = undefined;
|
|
}
|
|
}
|
|
|
|
if (nodePrev && (editor.options.limitDragging === false || nodePrev.parent === nodes[0].parent)) {
|
|
nodes.forEach(function (node) {
|
|
nodePrev.parent.moveBefore(node, nodePrev);
|
|
});
|
|
moved = true;
|
|
}
|
|
} else {
|
|
// move down
|
|
var lastNode = nodes[nodes.length - 1];
|
|
trLast = lastNode.expanded && lastNode.append ? lastNode.append.getDom() : lastNode.dom.tr;
|
|
trFirst = trLast ? trLast.nextSibling : undefined;
|
|
|
|
if (trFirst) {
|
|
topFirst = (0,util.getAbsoluteTop)(trFirst);
|
|
trNext = trFirst;
|
|
|
|
do {
|
|
nodeNext = Node.getNodeFromTarget(trNext);
|
|
|
|
if (trNext) {
|
|
bottomNext = trNext.nextSibling ? (0,util.getAbsoluteTop)(trNext.nextSibling) : 0;
|
|
heightNext = trNext ? bottomNext - topFirst : 0;
|
|
|
|
if (nodeNext && nodeNext.parent.childs.length === nodes.length && nodeNext.parent.childs[nodes.length - 1] === lastNode) {
|
|
// We are about to remove the last child of this parent,
|
|
// which will make the parents appendNode visible.
|
|
topThis += 27; // TODO: dangerous to suppose the height of the appendNode a constant of 27 px.
|
|
}
|
|
|
|
trNext = trNext.nextSibling;
|
|
}
|
|
} while (trNext && mouseY > topThis + heightNext);
|
|
|
|
if (nodeNext && nodeNext.parent) {
|
|
// calculate the desired level
|
|
var diffX = mouseX - editor.drag.mouseX;
|
|
var diffLevel = Math.round(diffX / 24 / 2);
|
|
var level = editor.drag.level + diffLevel; // desired level
|
|
|
|
var levelNext = nodeNext.getLevel(); // level to be
|
|
// find the best fitting level (move upwards over the append nodes)
|
|
|
|
trPrev = nodeNext.dom.tr && nodeNext.dom.tr.previousSibling;
|
|
|
|
while (levelNext < level && trPrev) {
|
|
nodePrev = Node.getNodeFromTarget(trPrev);
|
|
var isDraggedNode = nodes.some(function (node) {
|
|
return node === nodePrev || nodePrev.isDescendantOf(node);
|
|
});
|
|
|
|
if (isDraggedNode) {// neglect the dragged nodes themselves and their childs
|
|
} else if (nodePrev instanceof AppendNode) {
|
|
var childs = nodePrev.parent.childs;
|
|
|
|
if (childs.length !== nodes.length || childs[nodes.length - 1] !== lastNode) {
|
|
// non-visible append node of a list of childs
|
|
// consisting of not only this node (else the
|
|
// append node will change into a visible "empty"
|
|
// text when removing this node).
|
|
nodeNext = Node.getNodeFromTarget(trPrev);
|
|
levelNext = nodeNext.getLevel();
|
|
} else {
|
|
break;
|
|
}
|
|
} else {
|
|
break;
|
|
}
|
|
|
|
trPrev = trPrev.previousSibling;
|
|
}
|
|
|
|
if (nodeNext instanceof AppendNode && !nodeNext.isVisible() && nodeNext.parent.showMore.isVisible()) {
|
|
nodeNext = nodeNext._nextNode();
|
|
} // move the node when its position is changed
|
|
|
|
|
|
if (nodeNext && (editor.options.limitDragging === false || nodeNext.parent === nodes[0].parent) && nodeNext.dom.tr && nodeNext.dom.tr !== trLast.nextSibling) {
|
|
nodes.forEach(function (node) {
|
|
nodeNext.parent.moveBefore(node, nodeNext);
|
|
});
|
|
moved = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (moved) {
|
|
// update the dragging parameters when moved
|
|
editor.drag.mouseX = mouseX;
|
|
editor.drag.level = firstNode.getLevel();
|
|
} // auto scroll when hovering around the top of the editor
|
|
|
|
|
|
editor.startAutoScroll(mouseY);
|
|
event.preventDefault();
|
|
};
|
|
/**
|
|
* Drag event, fired on mouseup after having dragged a node
|
|
* @param {Node[] | Node} nodes
|
|
* @param {Event} event
|
|
*/
|
|
|
|
|
|
Node.onDragEnd = function (nodes, event) {
|
|
if (!Array.isArray(nodes)) {
|
|
return Node.onDrag([nodes], event);
|
|
}
|
|
|
|
if (nodes.length === 0) {
|
|
return;
|
|
}
|
|
|
|
var firstNode = nodes[0];
|
|
var editor = firstNode.editor; // set focus to the context menu button of the first node
|
|
|
|
if (nodes[0]) {
|
|
nodes[0].dom.menu.focus();
|
|
}
|
|
|
|
var oldParentPath = editor.drag.oldParent.getInternalPath();
|
|
var newParentPath = firstNode.parent.getInternalPath();
|
|
var sameParent = editor.drag.oldParent === firstNode.parent;
|
|
var oldIndex = editor.drag.oldNextNode.getIndex();
|
|
var newIndex = firstNode.getIndex();
|
|
var oldParentPathRedo = editor.drag.oldParentPathRedo;
|
|
var oldIndexRedo = editor.drag.oldIndexRedo;
|
|
var newIndexRedo = sameParent && oldIndexRedo < newIndex ? newIndex + nodes.length : newIndex;
|
|
|
|
if (!sameParent || oldIndexRedo !== newIndex) {
|
|
// only register this action if the node is actually moved to another place
|
|
editor._onAction('moveNodes', {
|
|
count: nodes.length,
|
|
fieldNames: nodes.map(getField),
|
|
oldParentPath: oldParentPath,
|
|
newParentPath: newParentPath,
|
|
oldIndex: oldIndex,
|
|
newIndex: newIndex,
|
|
oldIndexRedo: oldIndexRedo,
|
|
newIndexRedo: newIndexRedo,
|
|
oldParentPathRedo: oldParentPathRedo,
|
|
newParentPathRedo: null,
|
|
// This is a hack, value will be filled in during undo
|
|
oldSelection: editor.drag.oldSelection,
|
|
newSelection: editor.getDomSelection()
|
|
});
|
|
}
|
|
|
|
document.body.style.cursor = editor.drag.oldCursor;
|
|
editor.highlighter.unlock();
|
|
nodes.forEach(function (node) {
|
|
node.updateDom();
|
|
|
|
if (event.target !== node.dom.drag && event.target !== node.dom.menu) {
|
|
editor.highlighter.unhighlight();
|
|
}
|
|
});
|
|
delete editor.drag;
|
|
|
|
if (editor.mousemove) {
|
|
(0,util.removeEventListener)(event.view, 'mousemove', editor.mousemove);
|
|
delete editor.mousemove;
|
|
}
|
|
|
|
if (editor.mouseup) {
|
|
(0,util.removeEventListener)(event.view, 'mouseup', editor.mouseup);
|
|
delete editor.mouseup;
|
|
} // Stop any running auto scroll
|
|
|
|
|
|
editor.stopAutoScroll();
|
|
event.preventDefault();
|
|
};
|
|
/**
|
|
* find an enum definition in a JSON schema, as property `enum` or inside
|
|
* one of the schemas composites (`oneOf`, `anyOf`, `allOf`)
|
|
* @param {Object} schema
|
|
* @return {Array | null} Returns the enum when found, null otherwise.
|
|
* @private
|
|
*/
|
|
|
|
|
|
Node._findEnum = function (schema) {
|
|
if (schema["enum"]) {
|
|
return schema["enum"];
|
|
}
|
|
|
|
var composite = schema.oneOf || schema.anyOf || schema.allOf;
|
|
|
|
if (composite) {
|
|
var match = composite.filter(function (entry) {
|
|
return entry["enum"];
|
|
});
|
|
|
|
if (match.length > 0) {
|
|
return match[0]["enum"];
|
|
}
|
|
}
|
|
|
|
return null;
|
|
};
|
|
/**
|
|
* Return the part of a JSON schema matching given path.
|
|
* @param {Object} topLevelSchema
|
|
* @param {Object} schemaRefs
|
|
* @param {Array.<string | number>} path
|
|
* @param {Object} currentSchema
|
|
* @return {Object | null}
|
|
* @private
|
|
*/
|
|
|
|
|
|
Node._findSchema = function (topLevelSchema, schemaRefs, path) {
|
|
var currentSchema = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : topLevelSchema;
|
|
var nextPath = path.slice(1, path.length);
|
|
var nextKey = path[0];
|
|
var possibleSchemas = currentSchema.oneOf || currentSchema.anyOf || currentSchema.allOf || [currentSchema];
|
|
|
|
var _iterator = _createForOfIteratorHelper(possibleSchemas),
|
|
_step;
|
|
|
|
try {
|
|
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
var schema = _step.value;
|
|
currentSchema = schema;
|
|
|
|
if ('$ref' in currentSchema && typeof currentSchema.$ref === 'string') {
|
|
var ref = currentSchema.$ref;
|
|
|
|
if (ref in schemaRefs) {
|
|
currentSchema = schemaRefs[ref];
|
|
} else if (ref.startsWith('#/')) {
|
|
var refPath = ref.substring(2).split('/');
|
|
currentSchema = topLevelSchema;
|
|
|
|
var _iterator2 = _createForOfIteratorHelper(refPath),
|
|
_step2;
|
|
|
|
try {
|
|
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
var segment = _step2.value;
|
|
|
|
if (segment in currentSchema) {
|
|
currentSchema = currentSchema[segment];
|
|
} else {
|
|
throw Error("Unable to resovle reference ".concat(ref));
|
|
}
|
|
}
|
|
} catch (err) {
|
|
_iterator2.e(err);
|
|
} finally {
|
|
_iterator2.f();
|
|
}
|
|
} else {
|
|
throw Error("Unable to resolve reference ".concat(ref));
|
|
}
|
|
} // We have no more path segments to resolve, return the currently found schema
|
|
// We do this here, after resolving references, in case of the leaf schema beeing a reference
|
|
|
|
|
|
if (nextKey === undefined) {
|
|
return currentSchema;
|
|
}
|
|
|
|
if (typeof nextKey === 'string') {
|
|
if (_typeof(currentSchema.properties) === 'object' && currentSchema.properties !== null && nextKey in currentSchema.properties) {
|
|
currentSchema = currentSchema.properties[nextKey];
|
|
return Node._findSchema(topLevelSchema, schemaRefs, nextPath, currentSchema);
|
|
}
|
|
|
|
if (_typeof(currentSchema.patternProperties) === 'object' && currentSchema.patternProperties !== null) {
|
|
for (var prop in currentSchema.patternProperties) {
|
|
if (nextKey.match(prop)) {
|
|
currentSchema = currentSchema.patternProperties[prop];
|
|
return Node._findSchema(topLevelSchema, schemaRefs, nextPath, currentSchema);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (_typeof(currentSchema.additionalProperties) === 'object') {
|
|
currentSchema = currentSchema.additionalProperties;
|
|
return Node._findSchema(topLevelSchema, schemaRefs, nextPath, currentSchema);
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
if (typeof nextKey === 'number' && _typeof(currentSchema.items) === 'object' && currentSchema.items !== null) {
|
|
currentSchema = currentSchema.items;
|
|
return Node._findSchema(topLevelSchema, schemaRefs, nextPath, currentSchema);
|
|
}
|
|
}
|
|
} catch (err) {
|
|
_iterator.e(err);
|
|
} finally {
|
|
_iterator.f();
|
|
}
|
|
|
|
return null;
|
|
};
|
|
/**
|
|
* Remove nodes
|
|
* @param {Node[] | Node} nodes
|
|
*/
|
|
|
|
|
|
Node.onRemove = function (nodes) {
|
|
if (!Array.isArray(nodes)) {
|
|
return Node.onRemove([nodes]);
|
|
}
|
|
|
|
if (nodes && nodes.length > 0) {
|
|
var firstNode = nodes[0];
|
|
var parent = firstNode.parent;
|
|
var editor = firstNode.editor;
|
|
var firstIndex = firstNode.getIndex();
|
|
editor.highlighter.unhighlight(); // adjust the focus
|
|
|
|
var oldSelection = editor.getDomSelection();
|
|
Node.blurNodes(nodes);
|
|
var newSelection = editor.getDomSelection(); // store the paths before removing them (needed for history)
|
|
|
|
var paths = nodes.map(getInternalPath); // remove the nodes
|
|
|
|
nodes.forEach(function (node) {
|
|
node.parent._remove(node);
|
|
}); // store history action
|
|
|
|
editor._onAction('removeNodes', {
|
|
nodes: nodes,
|
|
paths: paths,
|
|
parentPath: parent.getInternalPath(),
|
|
index: firstIndex,
|
|
oldSelection: oldSelection,
|
|
newSelection: newSelection
|
|
});
|
|
}
|
|
};
|
|
/**
|
|
* Duplicate nodes
|
|
* duplicated nodes will be added right after the original nodes
|
|
* @param {Node[] | Node} nodes
|
|
*/
|
|
|
|
|
|
Node.onDuplicate = function (nodes) {
|
|
if (!Array.isArray(nodes)) {
|
|
return Node.onDuplicate([nodes]);
|
|
}
|
|
|
|
if (nodes && nodes.length > 0) {
|
|
var lastNode = nodes[nodes.length - 1];
|
|
var parent = lastNode.parent;
|
|
var editor = lastNode.editor;
|
|
editor.deselect(editor.multiselection.nodes); // duplicate the nodes
|
|
|
|
var oldSelection = editor.getDomSelection();
|
|
var afterNode = lastNode;
|
|
var clones = nodes.map(function (node) {
|
|
var clone = node.clone();
|
|
|
|
if (node.parent.type === 'object') {
|
|
var existingFieldNames = node.parent.getFieldNames();
|
|
clone.field = (0,util.findUniqueName)(node.field, existingFieldNames);
|
|
}
|
|
|
|
parent.insertAfter(clone, afterNode);
|
|
afterNode = clone;
|
|
return clone;
|
|
}); // set selection to the duplicated nodes
|
|
|
|
if (nodes.length === 1) {
|
|
if (clones[0].parent.type === 'object') {
|
|
// when duplicating a single object property,
|
|
// set focus to the field and keep the original field name
|
|
clones[0].dom.field.innerHTML = nodes[0]._escapeHTML(nodes[0].field);
|
|
clones[0].focus('field');
|
|
} else {
|
|
clones[0].focus();
|
|
}
|
|
} else {
|
|
editor.select(clones);
|
|
}
|
|
|
|
var newSelection = editor.getDomSelection();
|
|
|
|
editor._onAction('duplicateNodes', {
|
|
paths: nodes.map(getInternalPath),
|
|
clonePaths: clones.map(getInternalPath),
|
|
afterPath: lastNode.getInternalPath(),
|
|
parentPath: parent.getInternalPath(),
|
|
oldSelection: oldSelection,
|
|
newSelection: newSelection
|
|
});
|
|
}
|
|
};
|
|
/**
|
|
* Find the node from an event target
|
|
* @param {HTMLElement} target
|
|
* @return {Node | undefined} node or undefined when not found
|
|
* @static
|
|
*/
|
|
|
|
|
|
Node.getNodeFromTarget = function (target) {
|
|
while (target) {
|
|
if (target.node) {
|
|
return target.node;
|
|
}
|
|
|
|
target = target.parentNode;
|
|
}
|
|
|
|
return undefined;
|
|
};
|
|
/**
|
|
* Test whether target is a child of the color DOM of a node
|
|
* @param {HTMLElement} target
|
|
* @returns {boolean}
|
|
*/
|
|
|
|
|
|
Node.targetIsColorPicker = function (target) {
|
|
var node = Node.getNodeFromTarget(target);
|
|
|
|
if (node) {
|
|
var parent = target && target.parentNode;
|
|
|
|
while (parent) {
|
|
if (parent === node.dom.color) {
|
|
return true;
|
|
}
|
|
|
|
parent = parent.parentNode;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
};
|
|
/**
|
|
* Remove the focus of given nodes, and move the focus to the (a) node before,
|
|
* (b) the node after, or (c) the parent node.
|
|
* @param {Array.<Node> | Node} nodes
|
|
*/
|
|
|
|
|
|
Node.blurNodes = function (nodes) {
|
|
if (!Array.isArray(nodes)) {
|
|
Node.blurNodes([nodes]);
|
|
return;
|
|
}
|
|
|
|
var firstNode = nodes[0];
|
|
var parent = firstNode.parent;
|
|
var firstIndex = firstNode.getIndex();
|
|
|
|
if (parent.childs[firstIndex + nodes.length]) {
|
|
parent.childs[firstIndex + nodes.length].focus();
|
|
} else if (parent.childs[firstIndex - 1]) {
|
|
parent.childs[firstIndex - 1].focus();
|
|
} else {
|
|
parent.focus();
|
|
}
|
|
}; // helper function to get the internal path of a node
|
|
|
|
|
|
function getInternalPath(node) {
|
|
return node.getInternalPath();
|
|
} // helper function to get the field of a node
|
|
|
|
|
|
function getField(node) {
|
|
return node.getField();
|
|
}
|
|
|
|
function Node_hasOwnProperty(object, key) {
|
|
return Object.prototype.hasOwnProperty.call(object, key);
|
|
} // TODO: find a nicer solution to resolve this circular dependency between Node and AppendNode
|
|
// idea: introduce properties .isAppendNode and .isNode and use that instead of instanceof AppendNode checks
|
|
|
|
|
|
var AppendNode = appendNodeFactory(Node);
|
|
var ShowMoreNode = showMoreNodeFactory(Node);
|
|
;// CONCATENATED MODULE: ./src/js/NodeHistory.js
|
|
|
|
|
|
function NodeHistory_classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
|
|
function NodeHistory_defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
|
|
|
|
function NodeHistory_createClass(Constructor, protoProps, staticProps) { if (protoProps) NodeHistory_defineProperties(Constructor.prototype, protoProps); if (staticProps) NodeHistory_defineProperties(Constructor, staticProps); return Constructor; }
|
|
|
|
|
|
/**
|
|
* @constructor History
|
|
* Store action history, enables undo and redo
|
|
* @param {JSONEditor} editor
|
|
*/
|
|
|
|
var NodeHistory = /*#__PURE__*/function () {
|
|
function NodeHistory(editor) {
|
|
NodeHistory_classCallCheck(this, NodeHistory);
|
|
|
|
this.editor = editor;
|
|
this.history = [];
|
|
this.index = -1;
|
|
this.clear(); // helper function to find a Node from a path
|
|
|
|
function findNode(path) {
|
|
return editor.node.findNodeByInternalPath(path);
|
|
} // map with all supported actions
|
|
|
|
|
|
this.actions = {
|
|
editField: {
|
|
undo: function undo(params) {
|
|
var parentNode = findNode(params.parentPath);
|
|
var node = parentNode.childs[params.index];
|
|
node.updateField(params.oldValue);
|
|
},
|
|
redo: function redo(params) {
|
|
var parentNode = findNode(params.parentPath);
|
|
var node = parentNode.childs[params.index];
|
|
node.updateField(params.newValue);
|
|
}
|
|
},
|
|
editValue: {
|
|
undo: function undo(params) {
|
|
findNode(params.path).updateValue(params.oldValue);
|
|
},
|
|
redo: function redo(params) {
|
|
findNode(params.path).updateValue(params.newValue);
|
|
}
|
|
},
|
|
changeType: {
|
|
undo: function undo(params) {
|
|
findNode(params.path).changeType(params.oldType);
|
|
},
|
|
redo: function redo(params) {
|
|
findNode(params.path).changeType(params.newType);
|
|
}
|
|
},
|
|
appendNodes: {
|
|
undo: function undo(params) {
|
|
var parentNode = findNode(params.parentPath);
|
|
params.paths.map(findNode).forEach(function (node) {
|
|
parentNode.removeChild(node);
|
|
});
|
|
},
|
|
redo: function redo(params) {
|
|
var parentNode = findNode(params.parentPath);
|
|
params.nodes.forEach(function (node) {
|
|
parentNode.appendChild(node);
|
|
});
|
|
}
|
|
},
|
|
insertBeforeNodes: {
|
|
undo: function undo(params) {
|
|
var parentNode = findNode(params.parentPath);
|
|
params.paths.map(findNode).forEach(function (node) {
|
|
parentNode.removeChild(node);
|
|
});
|
|
},
|
|
redo: function redo(params) {
|
|
var parentNode = findNode(params.parentPath);
|
|
var beforeNode = findNode(params.beforePath);
|
|
params.nodes.forEach(function (node) {
|
|
parentNode.insertBefore(node, beforeNode);
|
|
});
|
|
}
|
|
},
|
|
insertAfterNodes: {
|
|
undo: function undo(params) {
|
|
var parentNode = findNode(params.parentPath);
|
|
params.paths.map(findNode).forEach(function (node) {
|
|
parentNode.removeChild(node);
|
|
});
|
|
},
|
|
redo: function redo(params) {
|
|
var parentNode = findNode(params.parentPath);
|
|
var afterNode = findNode(params.afterPath);
|
|
params.nodes.forEach(function (node) {
|
|
parentNode.insertAfter(node, afterNode);
|
|
afterNode = node;
|
|
});
|
|
}
|
|
},
|
|
removeNodes: {
|
|
undo: function undo(params) {
|
|
var parentNode = findNode(params.parentPath);
|
|
var beforeNode = parentNode.childs[params.index] || parentNode.append;
|
|
params.nodes.forEach(function (node) {
|
|
parentNode.insertBefore(node, beforeNode);
|
|
});
|
|
},
|
|
redo: function redo(params) {
|
|
var parentNode = findNode(params.parentPath);
|
|
params.paths.map(findNode).forEach(function (node) {
|
|
parentNode.removeChild(node);
|
|
});
|
|
}
|
|
},
|
|
duplicateNodes: {
|
|
undo: function undo(params) {
|
|
var parentNode = findNode(params.parentPath);
|
|
params.clonePaths.map(findNode).forEach(function (node) {
|
|
parentNode.removeChild(node);
|
|
});
|
|
},
|
|
redo: function redo(params) {
|
|
var parentNode = findNode(params.parentPath);
|
|
var afterNode = findNode(params.afterPath);
|
|
var nodes = params.paths.map(findNode);
|
|
nodes.forEach(function (node) {
|
|
var clone = node.clone();
|
|
|
|
if (parentNode.type === 'object') {
|
|
var existingFieldNames = parentNode.getFieldNames();
|
|
clone.field = (0,util.findUniqueName)(node.field, existingFieldNames);
|
|
}
|
|
|
|
parentNode.insertAfter(clone, afterNode);
|
|
afterNode = clone;
|
|
});
|
|
}
|
|
},
|
|
moveNodes: {
|
|
undo: function undo(params) {
|
|
var oldParentNode = findNode(params.oldParentPath);
|
|
var newParentNode = findNode(params.newParentPath);
|
|
var oldBeforeNode = oldParentNode.childs[params.oldIndex] || oldParentNode.append; // first copy the nodes, then move them
|
|
|
|
var nodes = newParentNode.childs.slice(params.newIndex, params.newIndex + params.count);
|
|
nodes.forEach(function (node, index) {
|
|
node.field = params.fieldNames[index];
|
|
oldParentNode.moveBefore(node, oldBeforeNode);
|
|
}); // This is a hack to work around an issue that we don't know tha original
|
|
// path of the new parent after dragging, as the node is already moved at that time.
|
|
|
|
if (params.newParentPathRedo === null) {
|
|
params.newParentPathRedo = newParentNode.getInternalPath();
|
|
}
|
|
},
|
|
redo: function redo(params) {
|
|
var oldParentNode = findNode(params.oldParentPathRedo);
|
|
var newParentNode = findNode(params.newParentPathRedo);
|
|
var newBeforeNode = newParentNode.childs[params.newIndexRedo] || newParentNode.append; // first copy the nodes, then move them
|
|
|
|
var nodes = oldParentNode.childs.slice(params.oldIndexRedo, params.oldIndexRedo + params.count);
|
|
nodes.forEach(function (node, index) {
|
|
node.field = params.fieldNames[index];
|
|
newParentNode.moveBefore(node, newBeforeNode);
|
|
});
|
|
}
|
|
},
|
|
sort: {
|
|
undo: function undo(params) {
|
|
var node = findNode(params.path);
|
|
node.hideChilds();
|
|
node.childs = params.oldChilds;
|
|
node.updateDom({
|
|
updateIndexes: true
|
|
});
|
|
node.showChilds();
|
|
},
|
|
redo: function redo(params) {
|
|
var node = findNode(params.path);
|
|
node.hideChilds();
|
|
node.childs = params.newChilds;
|
|
node.updateDom({
|
|
updateIndexes: true
|
|
});
|
|
node.showChilds();
|
|
}
|
|
},
|
|
transform: {
|
|
undo: function undo(params) {
|
|
findNode(params.path).setInternalValue(params.oldValue); // TODO: would be nice to restore the state of the node and childs
|
|
},
|
|
redo: function redo(params) {
|
|
findNode(params.path).setInternalValue(params.newValue); // TODO: would be nice to restore the state of the node and childs
|
|
}
|
|
} // TODO: restore the original caret position and selection with each undo
|
|
// TODO: implement history for actions "expand", "collapse", "scroll", "setDocument"
|
|
|
|
};
|
|
}
|
|
/**
|
|
* The method onChange is executed when the History is changed, and can
|
|
* be overloaded.
|
|
*/
|
|
|
|
|
|
NodeHistory_createClass(NodeHistory, [{
|
|
key: "onChange",
|
|
value: function onChange() {}
|
|
/**
|
|
* Add a new action to the history
|
|
* @param {String} action The executed action. Available actions: "editField",
|
|
* "editValue", "changeType", "appendNode",
|
|
* "removeNode", "duplicateNode", "moveNode"
|
|
* @param {Object} params Object containing parameters describing the change.
|
|
* The parameters in params depend on the action (for
|
|
* example for "editValue" the Node, old value, and new
|
|
* value are provided). params contains all information
|
|
* needed to undo or redo the action.
|
|
*/
|
|
|
|
}, {
|
|
key: "add",
|
|
value: function add(action, params) {
|
|
this.index++;
|
|
this.history[this.index] = {
|
|
action: action,
|
|
params: params,
|
|
timestamp: new Date()
|
|
}; // remove redo actions which are invalid now
|
|
|
|
if (this.index < this.history.length - 1) {
|
|
this.history.splice(this.index + 1, this.history.length - this.index - 1);
|
|
} // fire onchange event
|
|
|
|
|
|
this.onChange();
|
|
}
|
|
/**
|
|
* Clear history
|
|
*/
|
|
|
|
}, {
|
|
key: "clear",
|
|
value: function clear() {
|
|
this.history = [];
|
|
this.index = -1; // fire onchange event
|
|
|
|
this.onChange();
|
|
}
|
|
/**
|
|
* Check if there is an action available for undo
|
|
* @return {Boolean} canUndo
|
|
*/
|
|
|
|
}, {
|
|
key: "canUndo",
|
|
value: function canUndo() {
|
|
return this.index >= 0;
|
|
}
|
|
/**
|
|
* Check if there is an action available for redo
|
|
* @return {Boolean} canRedo
|
|
*/
|
|
|
|
}, {
|
|
key: "canRedo",
|
|
value: function canRedo() {
|
|
return this.index < this.history.length - 1;
|
|
}
|
|
/**
|
|
* Undo the last action
|
|
*/
|
|
|
|
}, {
|
|
key: "undo",
|
|
value: function undo() {
|
|
if (this.canUndo()) {
|
|
var obj = this.history[this.index];
|
|
|
|
if (obj) {
|
|
var action = this.actions[obj.action];
|
|
|
|
if (action && action.undo) {
|
|
action.undo(obj.params);
|
|
|
|
if (obj.params.oldSelection) {
|
|
try {
|
|
this.editor.setDomSelection(obj.params.oldSelection);
|
|
} catch (err) {
|
|
console.error(err);
|
|
}
|
|
}
|
|
} else {
|
|
console.error(new Error('unknown action "' + obj.action + '"'));
|
|
}
|
|
}
|
|
|
|
this.index--; // fire onchange event
|
|
|
|
this.onChange();
|
|
}
|
|
}
|
|
/**
|
|
* Redo the last action
|
|
*/
|
|
|
|
}, {
|
|
key: "redo",
|
|
value: function redo() {
|
|
if (this.canRedo()) {
|
|
this.index++;
|
|
var obj = this.history[this.index];
|
|
|
|
if (obj) {
|
|
var action = this.actions[obj.action];
|
|
|
|
if (action && action.redo) {
|
|
action.redo(obj.params);
|
|
|
|
if (obj.params.newSelection) {
|
|
try {
|
|
this.editor.setDomSelection(obj.params.newSelection);
|
|
} catch (err) {
|
|
console.error(err);
|
|
}
|
|
}
|
|
} else {
|
|
console.error(new Error('unknown action "' + obj.action + '"'));
|
|
}
|
|
} // fire onchange event
|
|
|
|
|
|
this.onChange();
|
|
}
|
|
}
|
|
/**
|
|
* Destroy history
|
|
*/
|
|
|
|
}, {
|
|
key: "destroy",
|
|
value: function destroy() {
|
|
this.editor = null;
|
|
this.history = [];
|
|
this.index = -1;
|
|
}
|
|
}]);
|
|
|
|
return NodeHistory;
|
|
}();
|
|
;// CONCATENATED MODULE: ./src/js/SearchBox.js
|
|
|
|
|
|
function SearchBox_classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
|
|
function SearchBox_defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
|
|
|
|
function SearchBox_createClass(Constructor, protoProps, staticProps) { if (protoProps) SearchBox_defineProperties(Constructor.prototype, protoProps); if (staticProps) SearchBox_defineProperties(Constructor, staticProps); return Constructor; }
|
|
|
|
|
|
/**
|
|
* @constructor SearchBox
|
|
* Create a search box in given HTML container
|
|
* @param {JSONEditor} editor The JSON Editor to attach to
|
|
* @param {Element} container HTML container element of where to
|
|
* create the search box
|
|
*/
|
|
|
|
var SearchBox = /*#__PURE__*/function () {
|
|
function SearchBox(editor, container) {
|
|
SearchBox_classCallCheck(this, SearchBox);
|
|
|
|
var searchBox = this;
|
|
this.editor = editor;
|
|
this.timeout = undefined;
|
|
this.delay = 200; // ms
|
|
|
|
this.lastText = undefined;
|
|
this.results = null;
|
|
this.dom = {};
|
|
this.dom.container = container;
|
|
var wrapper = document.createElement('div');
|
|
this.dom.wrapper = wrapper;
|
|
wrapper.className = 'jsoneditor-search';
|
|
container.appendChild(wrapper);
|
|
var results = document.createElement('div');
|
|
this.dom.results = results;
|
|
results.className = 'jsoneditor-results';
|
|
wrapper.appendChild(results);
|
|
var divInput = document.createElement('div');
|
|
this.dom.input = divInput;
|
|
divInput.className = 'jsoneditor-frame';
|
|
divInput.title = (0,i18n/* translate */.Iu)('searchTitle');
|
|
wrapper.appendChild(divInput);
|
|
var refreshSearch = document.createElement('button');
|
|
refreshSearch.type = 'button';
|
|
refreshSearch.className = 'jsoneditor-refresh';
|
|
divInput.appendChild(refreshSearch);
|
|
var search = document.createElement('input');
|
|
search.type = 'text';
|
|
this.dom.search = search;
|
|
|
|
search.oninput = function (event) {
|
|
searchBox._onDelayedSearch(event);
|
|
};
|
|
|
|
search.onchange = function (event) {
|
|
// For IE 9
|
|
searchBox._onSearch();
|
|
};
|
|
|
|
search.onkeydown = function (event) {
|
|
searchBox._onKeyDown(event);
|
|
};
|
|
|
|
search.onkeyup = function (event) {
|
|
searchBox._onKeyUp(event);
|
|
};
|
|
|
|
refreshSearch.onclick = function (event) {
|
|
search.select();
|
|
}; // TODO: ESC in FF restores the last input, is a FF bug, https://bugzilla.mozilla.org/show_bug.cgi?id=598819
|
|
|
|
|
|
divInput.appendChild(search);
|
|
var searchNext = document.createElement('button');
|
|
searchNext.type = 'button';
|
|
searchNext.title = (0,i18n/* translate */.Iu)('searchNextResultTitle');
|
|
searchNext.className = 'jsoneditor-next';
|
|
|
|
searchNext.onclick = function () {
|
|
searchBox.next();
|
|
};
|
|
|
|
divInput.appendChild(searchNext);
|
|
var searchPrevious = document.createElement('button');
|
|
searchPrevious.type = 'button';
|
|
searchPrevious.title = (0,i18n/* translate */.Iu)('searchPreviousResultTitle');
|
|
searchPrevious.className = 'jsoneditor-previous';
|
|
|
|
searchPrevious.onclick = function () {
|
|
searchBox.previous();
|
|
};
|
|
|
|
divInput.appendChild(searchPrevious);
|
|
}
|
|
/**
|
|
* Go to the next search result
|
|
* @param {boolean} [focus] If true, focus will be set to the next result
|
|
* focus is false by default.
|
|
*/
|
|
|
|
|
|
SearchBox_createClass(SearchBox, [{
|
|
key: "next",
|
|
value: function next(focus) {
|
|
if (this.results) {
|
|
var index = this.resultIndex !== null ? this.resultIndex + 1 : 0;
|
|
|
|
if (index > this.results.length - 1) {
|
|
index = 0;
|
|
}
|
|
|
|
this._setActiveResult(index, focus);
|
|
}
|
|
}
|
|
/**
|
|
* Go to the prevous search result
|
|
* @param {boolean} [focus] If true, focus will be set to the next result
|
|
* focus is false by default.
|
|
*/
|
|
|
|
}, {
|
|
key: "previous",
|
|
value: function previous(focus) {
|
|
if (this.results) {
|
|
var max = this.results.length - 1;
|
|
var index = this.resultIndex !== null ? this.resultIndex - 1 : max;
|
|
|
|
if (index < 0) {
|
|
index = max;
|
|
}
|
|
|
|
this._setActiveResult(index, focus);
|
|
}
|
|
}
|
|
/**
|
|
* Set new value for the current active result
|
|
* @param {Number} index
|
|
* @param {boolean} [focus] If true, focus will be set to the next result.
|
|
* focus is false by default.
|
|
* @private
|
|
*/
|
|
|
|
}, {
|
|
key: "_setActiveResult",
|
|
value: function _setActiveResult(index, focus) {
|
|
// de-activate current active result
|
|
if (this.activeResult) {
|
|
var prevNode = this.activeResult.node;
|
|
var prevElem = this.activeResult.elem;
|
|
|
|
if (prevElem === 'field') {
|
|
delete prevNode.searchFieldActive;
|
|
} else {
|
|
delete prevNode.searchValueActive;
|
|
}
|
|
|
|
prevNode.updateDom();
|
|
}
|
|
|
|
if (!this.results || !this.results[index]) {
|
|
// out of range, set to undefined
|
|
this.resultIndex = undefined;
|
|
this.activeResult = undefined;
|
|
return;
|
|
}
|
|
|
|
this.resultIndex = index; // set new node active
|
|
|
|
var node = this.results[this.resultIndex].node;
|
|
var elem = this.results[this.resultIndex].elem;
|
|
|
|
if (elem === 'field') {
|
|
node.searchFieldActive = true;
|
|
} else {
|
|
node.searchValueActive = true;
|
|
}
|
|
|
|
this.activeResult = this.results[this.resultIndex];
|
|
node.updateDom(); // TODO: not so nice that the focus is only set after the animation is finished
|
|
|
|
node.scrollTo(function () {
|
|
if (focus) {
|
|
node.focus(elem);
|
|
}
|
|
});
|
|
}
|
|
/**
|
|
* Cancel any running onDelayedSearch.
|
|
* @private
|
|
*/
|
|
|
|
}, {
|
|
key: "_clearDelay",
|
|
value: function _clearDelay() {
|
|
if (this.timeout !== undefined) {
|
|
clearTimeout(this.timeout);
|
|
delete this.timeout;
|
|
}
|
|
}
|
|
/**
|
|
* Start a timer to execute a search after a short delay.
|
|
* Used for reducing the number of searches while typing.
|
|
* @param {Event} event
|
|
* @private
|
|
*/
|
|
|
|
}, {
|
|
key: "_onDelayedSearch",
|
|
value: function _onDelayedSearch(event) {
|
|
// execute the search after a short delay (reduces the number of
|
|
// search actions while typing in the search text box)
|
|
this._clearDelay();
|
|
|
|
var searchBox = this;
|
|
this.timeout = setTimeout(function (event) {
|
|
searchBox._onSearch();
|
|
}, this.delay);
|
|
}
|
|
/**
|
|
* Handle onSearch event
|
|
* @param {boolean} [forceSearch] If true, search will be executed again even
|
|
* when the search text is not changed.
|
|
* Default is false.
|
|
* @private
|
|
*/
|
|
|
|
}, {
|
|
key: "_onSearch",
|
|
value: function _onSearch(forceSearch) {
|
|
this._clearDelay();
|
|
|
|
var value = this.dom.search.value;
|
|
var text = value.length > 0 ? value : undefined;
|
|
|
|
if (text !== this.lastText || forceSearch) {
|
|
// only search again when changed
|
|
this.lastText = text;
|
|
this.results = this.editor.search(text);
|
|
var MAX_SEARCH_RESULTS = this.results[0] ? this.results[0].node.MAX_SEARCH_RESULTS : Infinity; // try to maintain the current active result if this is still part of the new search results
|
|
|
|
var activeResultIndex = 0;
|
|
|
|
if (this.activeResult) {
|
|
for (var i = 0; i < this.results.length; i++) {
|
|
if (this.results[i].node === this.activeResult.node) {
|
|
activeResultIndex = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
this._setActiveResult(activeResultIndex, false); // display search results
|
|
|
|
|
|
if (text !== undefined) {
|
|
var resultCount = this.results.length;
|
|
|
|
if (resultCount === 0) {
|
|
this.dom.results.textContent = "no\xA0results";
|
|
} else if (resultCount === 1) {
|
|
this.dom.results.textContent = "1\xA0result";
|
|
} else if (resultCount > MAX_SEARCH_RESULTS) {
|
|
this.dom.results.textContent = MAX_SEARCH_RESULTS + "+\xA0results";
|
|
} else {
|
|
this.dom.results.textContent = resultCount + "\xA0results";
|
|
}
|
|
} else {
|
|
this.dom.results.textContent = '';
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Handle onKeyDown event in the input box
|
|
* @param {Event} event
|
|
* @private
|
|
*/
|
|
|
|
}, {
|
|
key: "_onKeyDown",
|
|
value: function _onKeyDown(event) {
|
|
var keynum = event.which;
|
|
|
|
if (keynum === 27) {
|
|
// ESC
|
|
this.dom.search.value = ''; // clear search
|
|
|
|
this._onSearch();
|
|
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
} else if (keynum === 13) {
|
|
// Enter
|
|
if (event.ctrlKey) {
|
|
// force to search again
|
|
this._onSearch(true);
|
|
} else if (event.shiftKey) {
|
|
// move to the previous search result
|
|
this.previous();
|
|
} else {
|
|
// move to the next search result
|
|
this.next();
|
|
}
|
|
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
}
|
|
}
|
|
/**
|
|
* Handle onKeyUp event in the input box
|
|
* @param {Event} event
|
|
* @private
|
|
*/
|
|
|
|
}, {
|
|
key: "_onKeyUp",
|
|
value: function _onKeyUp(event) {
|
|
var keynum = event.keyCode;
|
|
|
|
if (keynum !== 27 && keynum !== 13) {
|
|
// !show and !Enter
|
|
this._onDelayedSearch(event); // For IE 9
|
|
|
|
}
|
|
}
|
|
/**
|
|
* Clear the search results
|
|
*/
|
|
|
|
}, {
|
|
key: "clear",
|
|
value: function clear() {
|
|
this.dom.search.value = '';
|
|
|
|
this._onSearch();
|
|
}
|
|
/**
|
|
* Refresh searchResults if there is a search value
|
|
*/
|
|
|
|
}, {
|
|
key: "forceSearch",
|
|
value: function forceSearch() {
|
|
this._onSearch(true);
|
|
}
|
|
/**
|
|
* Test whether the search box value is empty
|
|
* @returns {boolean} Returns true when empty.
|
|
*/
|
|
|
|
}, {
|
|
key: "isEmpty",
|
|
value: function isEmpty() {
|
|
return this.dom.search.value === '';
|
|
}
|
|
/**
|
|
* Destroy the search box
|
|
*/
|
|
|
|
}, {
|
|
key: "destroy",
|
|
value: function destroy() {
|
|
this.editor = null;
|
|
this.dom.container.removeChild(this.dom.wrapper);
|
|
this.dom = null;
|
|
this.results = null;
|
|
this.activeResult = null;
|
|
|
|
this._clearDelay();
|
|
}
|
|
}]);
|
|
|
|
return SearchBox;
|
|
}();
|
|
;// CONCATENATED MODULE: ./src/js/TreePath.js
|
|
|
|
|
|
function TreePath_classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
|
|
function TreePath_defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
|
|
|
|
function TreePath_createClass(Constructor, protoProps, staticProps) { if (protoProps) TreePath_defineProperties(Constructor.prototype, protoProps); if (staticProps) TreePath_defineProperties(Constructor, staticProps); return Constructor; }
|
|
|
|
|
|
|
|
|
|
/**
|
|
* Creates a component that visualize path selection in tree based editors
|
|
* @param {HTMLElement} container
|
|
* @param {HTMLElement} root
|
|
* @constructor
|
|
*/
|
|
|
|
var TreePath = /*#__PURE__*/function () {
|
|
function TreePath(container, root) {
|
|
TreePath_classCallCheck(this, TreePath);
|
|
|
|
if (container) {
|
|
this.root = root;
|
|
this.path = document.createElement('div');
|
|
this.path.className = 'jsoneditor-treepath';
|
|
this.path.setAttribute('tabindex', 0);
|
|
this.contentMenuClicked = false;
|
|
container.appendChild(this.path);
|
|
this.reset();
|
|
}
|
|
}
|
|
/**
|
|
* Reset component to initial status
|
|
*/
|
|
|
|
|
|
TreePath_createClass(TreePath, [{
|
|
key: "reset",
|
|
value: function reset() {
|
|
this.path.textContent = (0,i18n/* translate */.Iu)('selectNode');
|
|
}
|
|
/**
|
|
* Renders the component UI according to a given path objects
|
|
* @param {Array<{name: String, childs: Array}>} pathObjs a list of path objects
|
|
*
|
|
*/
|
|
|
|
}, {
|
|
key: "setPath",
|
|
value: function setPath(pathObjs) {
|
|
var me = this;
|
|
this.path.textContent = '';
|
|
|
|
if (pathObjs && pathObjs.length) {
|
|
pathObjs.forEach(function (pathObj, idx) {
|
|
var pathEl = document.createElement('span');
|
|
var sepEl;
|
|
pathEl.className = 'jsoneditor-treepath-element';
|
|
pathEl.innerText = pathObj.name;
|
|
pathEl.onclick = _onSegmentClick.bind(me, pathObj);
|
|
me.path.appendChild(pathEl);
|
|
|
|
if (pathObj.children.length) {
|
|
sepEl = document.createElement('span');
|
|
sepEl.className = 'jsoneditor-treepath-seperator';
|
|
sepEl.textContent = "\u25BA";
|
|
|
|
sepEl.onclick = function () {
|
|
me.contentMenuClicked = true;
|
|
var items = [];
|
|
pathObj.children.forEach(function (child) {
|
|
items.push({
|
|
text: child.name,
|
|
className: 'jsoneditor-type-modes' + (pathObjs[idx + 1] + 1 && pathObjs[idx + 1].name === child.name ? ' jsoneditor-selected' : ''),
|
|
click: _onContextMenuItemClick.bind(me, pathObj, child.name)
|
|
});
|
|
});
|
|
var menu = new ContextMenu/* ContextMenu */.x(items, {
|
|
limitHeight: true
|
|
});
|
|
menu.show(sepEl, me.root, true);
|
|
};
|
|
|
|
me.path.appendChild(sepEl);
|
|
}
|
|
|
|
if (idx === pathObjs.length - 1) {
|
|
var leftRectPos = (sepEl || pathEl).getBoundingClientRect().right;
|
|
|
|
if (me.path.offsetWidth < leftRectPos) {
|
|
me.path.scrollLeft = leftRectPos;
|
|
}
|
|
|
|
if (me.path.scrollLeft) {
|
|
var showAllBtn = document.createElement('span');
|
|
showAllBtn.className = 'jsoneditor-treepath-show-all-btn';
|
|
showAllBtn.title = 'show all path';
|
|
showAllBtn.textContent = '...';
|
|
showAllBtn.onclick = _onShowAllClick.bind(me, pathObjs);
|
|
me.path.insertBefore(showAllBtn, me.path.firstChild);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
function _onShowAllClick(pathObjs) {
|
|
me.contentMenuClicked = false;
|
|
(0,util.addClassName)(me.path, 'show-all');
|
|
me.path.style.width = me.path.parentNode.getBoundingClientRect().width - 10 + 'px';
|
|
|
|
me.path.onblur = function () {
|
|
if (me.contentMenuClicked) {
|
|
me.contentMenuClicked = false;
|
|
me.path.focus();
|
|
return;
|
|
}
|
|
|
|
(0,util.removeClassName)(me.path, 'show-all');
|
|
me.path.onblur = undefined;
|
|
me.path.style.width = '';
|
|
me.setPath(pathObjs);
|
|
};
|
|
}
|
|
|
|
function _onSegmentClick(pathObj) {
|
|
if (this.selectionCallback) {
|
|
this.selectionCallback(pathObj);
|
|
}
|
|
}
|
|
|
|
function _onContextMenuItemClick(pathObj, selection) {
|
|
if (this.contextMenuCallback) {
|
|
this.contextMenuCallback(pathObj, selection);
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* set a callback function for selection of path section
|
|
* @param {Function} callback function to invoke when section is selected
|
|
*/
|
|
|
|
}, {
|
|
key: "onSectionSelected",
|
|
value: function onSectionSelected(callback) {
|
|
if (typeof callback === 'function') {
|
|
this.selectionCallback = callback;
|
|
}
|
|
}
|
|
/**
|
|
* set a callback function for selection of path section
|
|
* @param {Function} callback function to invoke when section is selected
|
|
*/
|
|
|
|
}, {
|
|
key: "onContextMenuItemSelected",
|
|
value: function onContextMenuItemSelected(callback) {
|
|
if (typeof callback === 'function') {
|
|
this.contextMenuCallback = callback;
|
|
}
|
|
}
|
|
}]);
|
|
|
|
return TreePath;
|
|
}();
|
|
// EXTERNAL MODULE: ./src/js/vanilla-picker/index.js
|
|
var vanilla_picker = __webpack_require__(8037);
|
|
var vanilla_picker_default = /*#__PURE__*/__webpack_require__.n(vanilla_picker);
|
|
;// CONCATENATED MODULE: ./src/js/treemode.js
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// create a mixin with the functions for tree mode
|
|
|
|
var treemode = {};
|
|
/**
|
|
* Create a tree editor
|
|
* @param {Element} container Container element
|
|
* @param {Object} [options] Object with options. See docs for details.
|
|
* @private
|
|
*/
|
|
|
|
treemode.create = function (container, options) {
|
|
if (!container) {
|
|
throw new Error('No container element provided.');
|
|
}
|
|
|
|
this.container = container;
|
|
this.dom = {};
|
|
this.highlighter = new Highlighter();
|
|
this.selection = undefined; // will hold the last input selection
|
|
|
|
this.multiselection = {
|
|
nodes: []
|
|
};
|
|
this.validateSchema = null; // will be set in .setSchema(schema)
|
|
|
|
this.validationSequence = 0;
|
|
this.errorNodes = [];
|
|
this.lastSchemaErrors = undefined;
|
|
this.node = null;
|
|
this.focusTarget = null;
|
|
|
|
this._setOptions(options);
|
|
|
|
if (options.autocomplete) {
|
|
this.autocomplete = autocomplete(options.autocomplete);
|
|
}
|
|
|
|
if (this.options.history && this.options.mode !== 'view') {
|
|
this.history = new NodeHistory(this);
|
|
}
|
|
|
|
this._createFrame();
|
|
|
|
this._createTable();
|
|
};
|
|
/**
|
|
* Destroy the editor. Clean up DOM, event listeners, and web workers.
|
|
*/
|
|
|
|
|
|
treemode.destroy = function () {
|
|
if (this.frame && this.container && this.frame.parentNode === this.container) {
|
|
this.container.removeChild(this.frame);
|
|
this.frame = null;
|
|
}
|
|
|
|
this.container = null;
|
|
this.dom = null;
|
|
this.clear();
|
|
this.node = null;
|
|
this.focusTarget = null;
|
|
this.selection = null;
|
|
this.multiselection = null;
|
|
this.errorNodes = null;
|
|
this.validateSchema = null;
|
|
this._debouncedValidate = null;
|
|
|
|
if (this.history) {
|
|
this.history.destroy();
|
|
this.history = null;
|
|
}
|
|
|
|
if (this.searchBox) {
|
|
this.searchBox.destroy();
|
|
this.searchBox = null;
|
|
}
|
|
|
|
if (this.modeSwitcher) {
|
|
this.modeSwitcher.destroy();
|
|
this.modeSwitcher = null;
|
|
} // Removing the FocusTracker set to track the editor's focus event
|
|
|
|
|
|
this.frameFocusTracker.destroy();
|
|
};
|
|
/**
|
|
* Initialize and set default options
|
|
* @param {Object} [options] See description in constructor
|
|
* @private
|
|
*/
|
|
|
|
|
|
treemode._setOptions = function (options) {
|
|
var _this = this;
|
|
|
|
this.options = {
|
|
search: true,
|
|
history: true,
|
|
mode: 'tree',
|
|
name: undefined,
|
|
// field name of root node
|
|
schema: null,
|
|
schemaRefs: null,
|
|
autocomplete: null,
|
|
navigationBar: true,
|
|
mainMenuBar: true,
|
|
limitDragging: false,
|
|
onSelectionChange: null,
|
|
colorPicker: true,
|
|
onColorPicker: function onColorPicker(parent, color, onChange) {
|
|
if ((vanilla_picker_default())) {
|
|
// we'll render the color picker on top
|
|
// when there is not enough space below, and there is enough space above
|
|
var pickerHeight = 300; // estimated height of the color picker
|
|
|
|
var top = parent.getBoundingClientRect().top;
|
|
var windowHeight = (0,util.getWindow)(parent).innerHeight;
|
|
var showOnTop = windowHeight - top < pickerHeight && top > pickerHeight;
|
|
new (vanilla_picker_default())({
|
|
parent: parent,
|
|
color: color,
|
|
popup: showOnTop ? 'top' : 'bottom',
|
|
onDone: function onDone(color) {
|
|
var alpha = color.rgba[3];
|
|
var hex = alpha === 1 ? color.hex.substr(0, 7) // return #RRGGBB
|
|
: color.hex; // return #RRGGBBAA
|
|
|
|
onChange(hex);
|
|
}
|
|
}).show();
|
|
} else {
|
|
console.warn('Cannot open color picker: the `vanilla-picker` library is not included in the bundle. ' + 'Either use the full bundle or implement your own color picker using `onColorPicker`.');
|
|
}
|
|
},
|
|
timestampTag: true,
|
|
timestampFormat: null,
|
|
createQuery: jmespathQuery/* createQuery */.r,
|
|
executeQuery: jmespathQuery/* executeQuery */.J,
|
|
onEvent: null,
|
|
enableSort: true,
|
|
enableTransform: true
|
|
}; // copy all options
|
|
|
|
if (options) {
|
|
Object.keys(options).forEach(function (prop) {
|
|
_this.options[prop] = options[prop];
|
|
}); // default limitDragging to true when a JSON schema is defined
|
|
|
|
if (options.limitDragging == null && options.schema != null) {
|
|
this.options.limitDragging = true;
|
|
}
|
|
} // compile a JSON schema validator if a JSON schema is provided
|
|
|
|
|
|
this.setSchema(this.options.schema, this.options.schemaRefs); // create a debounced validate function
|
|
|
|
this._debouncedValidate = (0,util.debounce)(this.validate.bind(this), this.DEBOUNCE_INTERVAL);
|
|
|
|
if (options.onSelectionChange) {
|
|
this.onSelectionChange(options.onSelectionChange);
|
|
}
|
|
|
|
(0,i18n/* setLanguages */.cC)(this.options.languages);
|
|
(0,i18n/* setLanguage */.m0)(this.options.language);
|
|
};
|
|
/**
|
|
* Set new JSON object in editor.
|
|
* Resets the state of the editor (expanded nodes, search, selection).
|
|
*
|
|
* @param {*} json
|
|
*/
|
|
|
|
|
|
treemode.set = function (json) {
|
|
// verify if json is valid JSON, ignore when a function
|
|
if (json instanceof Function || json === undefined) {
|
|
this.clear();
|
|
} else {
|
|
this.content.removeChild(this.table); // Take the table offline
|
|
// replace the root node
|
|
|
|
var params = {
|
|
field: this.options.name,
|
|
value: json
|
|
};
|
|
var node = new Node(this, params);
|
|
|
|
this._setRoot(node); // validate JSON schema (if configured)
|
|
|
|
|
|
this.validate(); // expand
|
|
|
|
var recurse = false;
|
|
this.node.expand(recurse);
|
|
this.content.appendChild(this.table); // Put the table online again
|
|
} // TODO: maintain history, store last state and previous document
|
|
|
|
|
|
if (this.history) {
|
|
this.history.clear();
|
|
} // clear search
|
|
|
|
|
|
if (this.searchBox) {
|
|
this.searchBox.clear();
|
|
}
|
|
};
|
|
/**
|
|
* Update JSON object in editor.
|
|
* Maintains the state of the editor (expanded nodes, search, selection).
|
|
*
|
|
* @param {*} json
|
|
*/
|
|
|
|
|
|
treemode.update = function (json) {
|
|
// don't update if there are no changes
|
|
if (this.node.deepEqual(json)) {
|
|
return;
|
|
}
|
|
|
|
var selection = this.getSelection(); // apply the changed json
|
|
|
|
this.onChangeDisabled = true; // don't fire an onChange event
|
|
|
|
this.node.update(json);
|
|
this.onChangeDisabled = false; // validate JSON schema
|
|
|
|
this.validate(); // update search result if any
|
|
|
|
if (this.searchBox && !this.searchBox.isEmpty()) {
|
|
this.searchBox.forceSearch();
|
|
} // update selection if any
|
|
|
|
|
|
if (selection && selection.start && selection.end) {
|
|
// only keep/update the selection if both start and end node still exists,
|
|
// else we clear the selection
|
|
var startNode = this.node.findNodeByPath(selection.start.path);
|
|
var endNode = this.node.findNodeByPath(selection.end.path);
|
|
|
|
if (startNode && endNode) {
|
|
this.setSelection(selection.start, selection.end);
|
|
} else {
|
|
this.setSelection({}, {}); // clear selection
|
|
}
|
|
} else {
|
|
this.setSelection({}, {}); // clear selection
|
|
}
|
|
};
|
|
/**
|
|
* Get JSON object from editor
|
|
* @return {Object | undefined} json
|
|
*/
|
|
|
|
|
|
treemode.get = function () {
|
|
// TODO: resolve pending debounced input changes if any, but do not resolve invalid inputs
|
|
if (this.node) {
|
|
return this.node.getValue();
|
|
} else {
|
|
return undefined;
|
|
}
|
|
};
|
|
/**
|
|
* Get the text contents of the editor
|
|
* @return {String} jsonText
|
|
*/
|
|
|
|
|
|
treemode.getText = function () {
|
|
return JSON.stringify(this.get());
|
|
};
|
|
/**
|
|
* Set the text contents of the editor.
|
|
* Resets the state of the editor (expanded nodes, search, selection).
|
|
* @param {String} jsonText
|
|
*/
|
|
|
|
|
|
treemode.setText = function (jsonText) {
|
|
try {
|
|
this.set((0,util.parse)(jsonText)); // this can throw an error
|
|
} catch (err) {
|
|
// try to repair json, replace JavaScript notation with JSON notation
|
|
var repairedJsonText = (0,util.tryJsonRepair)(jsonText); // try to parse again
|
|
|
|
this.set((0,util.parse)(repairedJsonText)); // this can throw an error
|
|
}
|
|
};
|
|
/**
|
|
* Update the text contents of the editor.
|
|
* Maintains the state of the editor (expanded nodes, search, selection).
|
|
* @param {String} jsonText
|
|
*/
|
|
|
|
|
|
treemode.updateText = function (jsonText) {
|
|
try {
|
|
this.update((0,util.parse)(jsonText)); // this can throw an error
|
|
} catch (err) {
|
|
// try to repair json, replace JavaScript notation with JSON notation
|
|
var repairJsonText = (0,util.tryJsonRepair)(jsonText); // try to parse again
|
|
|
|
this.update((0,util.parse)(repairJsonText)); // this can throw an error
|
|
}
|
|
};
|
|
/**
|
|
* Set a field name for the root node.
|
|
* @param {String | undefined} name
|
|
*/
|
|
|
|
|
|
treemode.setName = function (name) {
|
|
this.options.name = name;
|
|
|
|
if (this.node) {
|
|
this.node.updateField(this.options.name);
|
|
}
|
|
};
|
|
/**
|
|
* Get the field name for the root node.
|
|
* @return {String | undefined} name
|
|
*/
|
|
|
|
|
|
treemode.getName = function () {
|
|
return this.options.name;
|
|
};
|
|
/**
|
|
* Set focus to the editor. Focus will be set to:
|
|
* - the first editable field or value, or else
|
|
* - to the expand button of the root node, or else
|
|
* - to the context menu button of the root node, or else
|
|
* - to the first button in the top menu
|
|
*/
|
|
|
|
|
|
treemode.focus = function () {
|
|
var input = this.scrollableContent.querySelector('[contenteditable=true]');
|
|
|
|
if (input) {
|
|
input.focus();
|
|
} else if (this.node.dom.expand) {
|
|
this.node.dom.expand.focus();
|
|
} else if (this.node.dom.menu) {
|
|
this.node.dom.menu.focus();
|
|
} else {
|
|
// focus to the first button in the menu
|
|
input = this.frame.querySelector('button');
|
|
|
|
if (input) {
|
|
input.focus();
|
|
}
|
|
}
|
|
};
|
|
/**
|
|
* Remove the root node from the editor
|
|
*/
|
|
|
|
|
|
treemode.clear = function () {
|
|
if (this.node) {
|
|
this.node.hide();
|
|
delete this.node;
|
|
}
|
|
|
|
if (this.treePath) {
|
|
this.treePath.reset();
|
|
}
|
|
};
|
|
/**
|
|
* Set the root node for the json editor
|
|
* @param {Node} node
|
|
* @private
|
|
*/
|
|
|
|
|
|
treemode._setRoot = function (node) {
|
|
this.clear();
|
|
this.node = node;
|
|
node.setParent(null);
|
|
node.setField(this.getName(), false);
|
|
delete node.index; // append to the dom
|
|
|
|
this.tbody.appendChild(node.getDom());
|
|
};
|
|
/**
|
|
* Search text in all nodes
|
|
* The nodes will be expanded when the text is found one of its childs,
|
|
* else it will be collapsed. Searches are case insensitive.
|
|
* @param {String} text
|
|
* @return {Object[]} results Array with nodes containing the search results
|
|
* The result objects contains fields:
|
|
* - {Node} node,
|
|
* - {String} elem the dom element name where
|
|
* the result is found ('field' or
|
|
* 'value')
|
|
*/
|
|
|
|
|
|
treemode.search = function (text) {
|
|
var results;
|
|
|
|
if (this.node) {
|
|
this.content.removeChild(this.table); // Take the table offline
|
|
|
|
results = this.node.search(text);
|
|
this.content.appendChild(this.table); // Put the table online again
|
|
} else {
|
|
results = [];
|
|
}
|
|
|
|
return results;
|
|
};
|
|
/**
|
|
* Expand all nodes
|
|
*/
|
|
|
|
|
|
treemode.expandAll = function () {
|
|
if (this.node) {
|
|
this.content.removeChild(this.table); // Take the table offline
|
|
|
|
this.node.expand();
|
|
this.content.appendChild(this.table); // Put the table online again
|
|
}
|
|
};
|
|
/**
|
|
* Collapse all nodes
|
|
*/
|
|
|
|
|
|
treemode.collapseAll = function () {
|
|
if (this.node) {
|
|
this.content.removeChild(this.table); // Take the table offline
|
|
|
|
this.node.collapse();
|
|
this.content.appendChild(this.table); // Put the table online again
|
|
}
|
|
};
|
|
/**
|
|
* The method onChange is called whenever a field or value is changed, created,
|
|
* deleted, duplicated, etc.
|
|
* @param {String} action Change action. Available values: "editField",
|
|
* "editValue", "changeType", "appendNode",
|
|
* "removeNode", "duplicateNode", "moveNode", "expand",
|
|
* "collapse".
|
|
* @param {Object} params Object containing parameters describing the change.
|
|
* The parameters in params depend on the action (for
|
|
* example for "editValue" the Node, old value, and new
|
|
* value are provided). params contains all information
|
|
* needed to undo or redo the action.
|
|
* @private
|
|
*/
|
|
|
|
|
|
treemode._onAction = function (action, params) {
|
|
// add an action to the history
|
|
if (this.history) {
|
|
this.history.add(action, params);
|
|
}
|
|
|
|
this._onChange();
|
|
};
|
|
/**
|
|
* Handle a change:
|
|
* - Validate JSON schema
|
|
* - Send a callback to the onChange listener if provided
|
|
* @private
|
|
*/
|
|
|
|
|
|
treemode._onChange = function () {
|
|
if (this.onChangeDisabled) {
|
|
return;
|
|
} // selection can be changed after undo/redo
|
|
|
|
|
|
this.selection = this.getDomSelection(); // validate JSON schema (if configured)
|
|
|
|
this._debouncedValidate();
|
|
|
|
if (this.treePath) {
|
|
var selectedNode = this.node && this.selection ? this.node.findNodeByInternalPath(this.selection.path) : this.multiselection ? this.multiselection.nodes[0] : undefined;
|
|
|
|
if (selectedNode) {
|
|
this._updateTreePath(selectedNode.getNodePath());
|
|
} else {
|
|
this.treePath.reset();
|
|
}
|
|
} // trigger the onChange callback
|
|
|
|
|
|
if (this.options.onChange) {
|
|
try {
|
|
this.options.onChange();
|
|
} catch (err) {
|
|
console.error('Error in onChange callback: ', err);
|
|
}
|
|
} // trigger the onChangeJSON callback
|
|
|
|
|
|
if (this.options.onChangeJSON) {
|
|
try {
|
|
this.options.onChangeJSON(this.get());
|
|
} catch (err) {
|
|
console.error('Error in onChangeJSON callback: ', err);
|
|
}
|
|
} // trigger the onChangeText callback
|
|
|
|
|
|
if (this.options.onChangeText) {
|
|
try {
|
|
this.options.onChangeText(this.getText());
|
|
} catch (err) {
|
|
console.error('Error in onChangeText callback: ', err);
|
|
}
|
|
} // trigger the onClassName callback
|
|
|
|
|
|
if (this.options.onClassName) {
|
|
this.node.recursivelyUpdateCssClassesOnNodes();
|
|
} // trigger the onNodeName callback
|
|
|
|
|
|
if (this.options.onNodeName && this.node.childs) {
|
|
try {
|
|
this.node.recursivelyUpdateNodeName();
|
|
} catch (err) {
|
|
console.error('Error in onNodeName callback: ', err);
|
|
}
|
|
}
|
|
};
|
|
/**
|
|
* Validate current JSON object against the configured JSON schema
|
|
* Throws an exception when no JSON schema is configured
|
|
*/
|
|
|
|
|
|
treemode.validate = function () {
|
|
var _this2 = this;
|
|
|
|
var root = this.node;
|
|
|
|
if (!root) {
|
|
// TODO: this should be redundant but is needed on mode switch
|
|
return;
|
|
}
|
|
|
|
var json = root.getValue(); // execute JSON schema validation
|
|
|
|
var schemaErrors = [];
|
|
|
|
if (this.validateSchema) {
|
|
var valid = this.validateSchema(json);
|
|
|
|
if (!valid) {
|
|
// apply all new errors
|
|
schemaErrors = this.validateSchema.errors.map(function (error) {
|
|
return (0,util.improveSchemaError)(error);
|
|
}).map(function findNode(error) {
|
|
return {
|
|
node: root.findNode(error.dataPath),
|
|
error: error,
|
|
type: 'validation'
|
|
};
|
|
}).filter(function hasNode(entry) {
|
|
return entry.node != null;
|
|
});
|
|
}
|
|
} // execute custom validation and after than merge and render all errors
|
|
|
|
|
|
try {
|
|
this.validationSequence++;
|
|
var me = this;
|
|
var seq = this.validationSequence;
|
|
|
|
this._validateCustom(json).then(function (customValidationErrors) {
|
|
// only apply when there was no other validation started whilst resolving async results
|
|
if (seq === me.validationSequence) {
|
|
var errorNodes = [].concat(schemaErrors, customValidationErrors || []);
|
|
|
|
me._renderValidationErrors(errorNodes);
|
|
|
|
if (typeof _this2.options.onValidationError === 'function') {
|
|
if ((0,util.isValidationErrorChanged)(errorNodes, _this2.lastSchemaErrors)) {
|
|
_this2.options.onValidationError.call(_this2, errorNodes);
|
|
}
|
|
|
|
_this2.lastSchemaErrors = errorNodes;
|
|
}
|
|
}
|
|
})["catch"](function (err) {
|
|
console.error(err);
|
|
});
|
|
} catch (err) {
|
|
console.error(err);
|
|
}
|
|
};
|
|
|
|
treemode._renderValidationErrors = function (errorNodes) {
|
|
// clear all current errors
|
|
if (this.errorNodes) {
|
|
this.errorNodes.forEach(function (node) {
|
|
node.setError(null);
|
|
});
|
|
} // render the new errors
|
|
|
|
|
|
var parentPairs = errorNodes.reduce(function (all, entry) {
|
|
return entry.node.findParents().filter(function (parent) {
|
|
return !all.some(function (pair) {
|
|
return pair[0] === parent;
|
|
});
|
|
}).map(function (parent) {
|
|
return [parent, entry.node];
|
|
}).concat(all);
|
|
}, []);
|
|
this.errorNodes = parentPairs.map(function (pair) {
|
|
return {
|
|
node: pair[0],
|
|
child: pair[1],
|
|
error: {
|
|
message: pair[0].type === 'object' ? (0,i18n/* translate */.Iu)('containsInvalidProperties') // object
|
|
: (0,i18n/* translate */.Iu)('containsInvalidItems') // array
|
|
|
|
}
|
|
};
|
|
}).concat(errorNodes).map(function setError(entry) {
|
|
entry.node.setError(entry.error, entry.child);
|
|
return entry.node;
|
|
});
|
|
};
|
|
/**
|
|
* Execute custom validation if configured.
|
|
*
|
|
* Returns a promise resolving with the custom errors (or nothing).
|
|
*/
|
|
|
|
|
|
treemode._validateCustom = function (json) {
|
|
try {
|
|
if (this.options.onValidate) {
|
|
var root = this.node;
|
|
var customValidateResults = this.options.onValidate(json);
|
|
var resultPromise = (0,util.isPromise)(customValidateResults) ? customValidateResults : Promise.resolve(customValidateResults);
|
|
return resultPromise.then(function (customValidationPathErrors) {
|
|
if (Array.isArray(customValidationPathErrors)) {
|
|
return customValidationPathErrors.filter(function (error) {
|
|
var valid = (0,util.isValidValidationError)(error);
|
|
|
|
if (!valid) {
|
|
console.warn('Ignoring a custom validation error with invalid structure. ' + 'Expected structure: {path: [...], message: "..."}. ' + 'Actual error:', error);
|
|
}
|
|
|
|
return valid;
|
|
}).map(function (error) {
|
|
var node;
|
|
|
|
try {
|
|
node = error && error.path ? root.findNodeByPath(error.path) : null;
|
|
} catch (err) {// stay silent here, we throw a generic warning if no node is found
|
|
}
|
|
|
|
if (!node) {
|
|
console.warn('Ignoring validation error: node not found. Path:', error.path, 'Error:', error);
|
|
}
|
|
|
|
return {
|
|
node: node,
|
|
error: error,
|
|
type: 'customValidation'
|
|
};
|
|
}).filter(function (entry) {
|
|
return entry && entry.node && entry.error && entry.error.message;
|
|
});
|
|
} else {
|
|
return null;
|
|
}
|
|
});
|
|
}
|
|
} catch (err) {
|
|
return Promise.reject(err);
|
|
}
|
|
|
|
return Promise.resolve(null);
|
|
};
|
|
/**
|
|
* Refresh the rendered contents
|
|
*/
|
|
|
|
|
|
treemode.refresh = function () {
|
|
if (this.node) {
|
|
this.node.updateDom({
|
|
recurse: true
|
|
});
|
|
}
|
|
};
|
|
/**
|
|
* Start autoscrolling when given mouse position is above the top of the
|
|
* editor contents, or below the bottom.
|
|
* @param {Number} mouseY Absolute mouse position in pixels
|
|
*/
|
|
|
|
|
|
treemode.startAutoScroll = function (mouseY) {
|
|
var me = this;
|
|
var content = this.scrollableContent;
|
|
var top = (0,util.getAbsoluteTop)(content);
|
|
var height = content.clientHeight;
|
|
var bottom = top + height;
|
|
var margin = 24;
|
|
var interval = 50; // ms
|
|
|
|
if (mouseY < top + margin && content.scrollTop > 0) {
|
|
this.autoScrollStep = (top + margin - mouseY) / 3;
|
|
} else if (mouseY > bottom - margin && height + content.scrollTop < content.scrollHeight) {
|
|
this.autoScrollStep = (bottom - margin - mouseY) / 3;
|
|
} else {
|
|
this.autoScrollStep = undefined;
|
|
}
|
|
|
|
if (this.autoScrollStep) {
|
|
if (!this.autoScrollTimer) {
|
|
this.autoScrollTimer = setInterval(function () {
|
|
if (me.autoScrollStep) {
|
|
content.scrollTop -= me.autoScrollStep;
|
|
} else {
|
|
me.stopAutoScroll();
|
|
}
|
|
}, interval);
|
|
}
|
|
} else {
|
|
this.stopAutoScroll();
|
|
}
|
|
};
|
|
/**
|
|
* Stop auto scrolling. Only applicable when scrolling
|
|
*/
|
|
|
|
|
|
treemode.stopAutoScroll = function () {
|
|
if (this.autoScrollTimer) {
|
|
clearTimeout(this.autoScrollTimer);
|
|
delete this.autoScrollTimer;
|
|
}
|
|
|
|
if (this.autoScrollStep) {
|
|
delete this.autoScrollStep;
|
|
}
|
|
};
|
|
/**
|
|
* Set the focus to an element in the editor, set text selection, and
|
|
* set scroll position.
|
|
* @param {Object} selection An object containing fields:
|
|
* {Element | undefined} dom The dom element
|
|
* which has focus
|
|
* {Range | TextRange} range A text selection
|
|
* {Node[]} nodes Nodes in case of multi selection
|
|
* {Number} scrollTop Scroll position
|
|
*/
|
|
|
|
|
|
treemode.setDomSelection = function (selection) {
|
|
if (!selection) {
|
|
return;
|
|
}
|
|
|
|
if ('scrollTop' in selection && this.scrollableContent) {
|
|
// TODO: animated scroll
|
|
this.scrollableContent.scrollTop = selection.scrollTop;
|
|
}
|
|
|
|
if (selection.paths) {
|
|
// multi-select
|
|
var me = this;
|
|
var nodes = selection.paths.map(function (path) {
|
|
return me.node.findNodeByInternalPath(path);
|
|
});
|
|
this.select(nodes);
|
|
} else {
|
|
// find the actual DOM element where to apply the focus
|
|
var node = selection.path ? this.node.findNodeByInternalPath(selection.path) : null;
|
|
var container = node && selection.domName ? node.dom[selection.domName] : null;
|
|
|
|
if (selection.range && container) {
|
|
var range = Object.assign({}, selection.range, {
|
|
container: container
|
|
});
|
|
(0,util.setSelectionOffset)(range);
|
|
} else if (node) {
|
|
// just a fallback
|
|
node.focus();
|
|
}
|
|
}
|
|
};
|
|
/**
|
|
* Get the current focus
|
|
* @return {Object} selection An object containing fields:
|
|
* {Element | undefined} dom The dom element
|
|
* which has focus
|
|
* {Range | TextRange} range A text selection
|
|
* {Node[]} nodes Nodes in case of multi selection
|
|
* {Number} scrollTop Scroll position
|
|
*/
|
|
|
|
|
|
treemode.getDomSelection = function () {
|
|
// find the node and field name of the current target,
|
|
// so we can store the current selection in a serializable
|
|
// way (internal node path and domName)
|
|
var node = Node.getNodeFromTarget(this.focusTarget);
|
|
var focusTarget = this.focusTarget;
|
|
var domName = node ? Object.keys(node.dom).find(function (domName) {
|
|
return node.dom[domName] === focusTarget;
|
|
}) : null;
|
|
var range = (0,util.getSelectionOffset)();
|
|
|
|
if (range && range.container.nodeName !== 'DIV') {
|
|
// filter on (editable) divs)
|
|
range = null;
|
|
}
|
|
|
|
if (range && range.container !== focusTarget) {
|
|
range = null;
|
|
}
|
|
|
|
if (range) {
|
|
// we cannot rely on the current instance of the container,
|
|
// we need to store the internal node path and field and
|
|
// find the actual DOM field when applying the selection
|
|
delete range.container;
|
|
}
|
|
|
|
return {
|
|
path: node ? node.getInternalPath() : null,
|
|
domName: domName,
|
|
range: range,
|
|
paths: this.multiselection.length > 0 ? this.multiselection.nodes.map(function (node) {
|
|
return node.getInternalPath();
|
|
}) : null,
|
|
scrollTop: this.scrollableContent ? this.scrollableContent.scrollTop : 0
|
|
};
|
|
};
|
|
/**
|
|
* Adjust the scroll position such that given top position is shown at 1/4
|
|
* of the window height.
|
|
* @param {Number} top
|
|
* @param {function(boolean)} [animateCallback] Callback, executed when animation is
|
|
* finished. The callback returns true
|
|
* when animation is finished, or false
|
|
* when not.
|
|
*/
|
|
|
|
|
|
treemode.scrollTo = function (top, animateCallback) {
|
|
var content = this.scrollableContent;
|
|
|
|
if (content) {
|
|
var editor = this; // cancel any running animation
|
|
|
|
if (editor.animateTimeout) {
|
|
clearTimeout(editor.animateTimeout);
|
|
delete editor.animateTimeout;
|
|
}
|
|
|
|
if (editor.animateCallback) {
|
|
editor.animateCallback(false);
|
|
delete editor.animateCallback;
|
|
} // calculate final scroll position
|
|
|
|
|
|
var height = content.clientHeight;
|
|
var bottom = content.scrollHeight - height;
|
|
var finalScrollTop = Math.min(Math.max(top - height / 4, 0), bottom); // animate towards the new scroll position
|
|
|
|
var animate = function animate() {
|
|
var scrollTop = content.scrollTop;
|
|
var diff = finalScrollTop - scrollTop;
|
|
|
|
if (Math.abs(diff) > 3) {
|
|
content.scrollTop += diff / 3;
|
|
editor.animateCallback = animateCallback;
|
|
editor.animateTimeout = setTimeout(animate, 50);
|
|
} else {
|
|
// finished
|
|
if (animateCallback) {
|
|
animateCallback(true);
|
|
}
|
|
|
|
content.scrollTop = finalScrollTop;
|
|
delete editor.animateTimeout;
|
|
delete editor.animateCallback;
|
|
}
|
|
};
|
|
|
|
animate();
|
|
} else {
|
|
if (animateCallback) {
|
|
animateCallback(false);
|
|
}
|
|
}
|
|
};
|
|
/**
|
|
* Create main frame
|
|
* @private
|
|
*/
|
|
|
|
|
|
treemode._createFrame = function () {
|
|
// create the frame
|
|
this.frame = document.createElement('div');
|
|
this.frame.className = 'jsoneditor jsoneditor-mode-' + this.options.mode; // this.frame.setAttribute("tabindex","0");
|
|
|
|
this.container.appendChild(this.frame);
|
|
this.contentOuter = document.createElement('div');
|
|
this.contentOuter.className = 'jsoneditor-outer'; // create one global event listener to handle all events from all nodes
|
|
|
|
var editor = this;
|
|
|
|
function onEvent(event) {
|
|
// when switching to mode "code" or "text" via the menu, some events
|
|
// are still fired whilst the _onEvent methods is already removed.
|
|
if (editor._onEvent) {
|
|
editor._onEvent(event);
|
|
}
|
|
} // setting the FocusTracker on 'this.frame' to track the editor's focus event
|
|
|
|
|
|
var focusTrackerConfig = {
|
|
target: this.frame,
|
|
onFocus: this.options.onFocus || null,
|
|
onBlur: this.options.onBlur || null
|
|
};
|
|
this.frameFocusTracker = new FocusTracker/* FocusTracker */.R(focusTrackerConfig);
|
|
|
|
this.frame.onclick = function (event) {
|
|
var target = event.target; // || event.srcElement;
|
|
|
|
onEvent(event); // prevent default submit action of buttons when editor is located
|
|
// inside a form
|
|
|
|
if (target.nodeName === 'BUTTON') {
|
|
event.preventDefault();
|
|
}
|
|
};
|
|
|
|
this.frame.oninput = onEvent;
|
|
this.frame.onchange = onEvent;
|
|
this.frame.onkeydown = onEvent;
|
|
this.frame.onkeyup = onEvent;
|
|
this.frame.oncut = onEvent;
|
|
this.frame.onpaste = onEvent;
|
|
this.frame.onmousedown = onEvent;
|
|
this.frame.onmouseup = onEvent;
|
|
this.frame.onmouseover = onEvent;
|
|
this.frame.onmouseout = onEvent; // Note: focus and blur events do not propagate, therefore they defined
|
|
// using an eventListener with useCapture=true
|
|
// see http://www.quirksmode.org/blog/archives/2008/04/delegating_the.html
|
|
|
|
(0,util.addEventListener)(this.frame, 'focus', onEvent, true);
|
|
(0,util.addEventListener)(this.frame, 'blur', onEvent, true);
|
|
this.frame.onfocusin = onEvent; // for IE
|
|
|
|
this.frame.onfocusout = onEvent; // for IE
|
|
|
|
if (this.options.mainMenuBar) {
|
|
(0,util.addClassName)(this.contentOuter, 'has-main-menu-bar'); // create menu
|
|
|
|
this.menu = document.createElement('div');
|
|
this.menu.className = 'jsoneditor-menu';
|
|
this.frame.appendChild(this.menu); // create expand all button
|
|
|
|
var expandAll = document.createElement('button');
|
|
expandAll.type = 'button';
|
|
expandAll.className = 'jsoneditor-expand-all';
|
|
expandAll.title = (0,i18n/* translate */.Iu)('expandAll');
|
|
|
|
expandAll.onclick = function () {
|
|
editor.expandAll();
|
|
};
|
|
|
|
this.menu.appendChild(expandAll); // create collapse all button
|
|
|
|
var collapseAll = document.createElement('button');
|
|
collapseAll.type = 'button';
|
|
collapseAll.title = (0,i18n/* translate */.Iu)('collapseAll');
|
|
collapseAll.className = 'jsoneditor-collapse-all';
|
|
|
|
collapseAll.onclick = function () {
|
|
editor.collapseAll();
|
|
};
|
|
|
|
this.menu.appendChild(collapseAll); // create sort button
|
|
|
|
if (this.options.enableSort) {
|
|
var sort = document.createElement('button');
|
|
sort.type = 'button';
|
|
sort.className = 'jsoneditor-sort';
|
|
sort.title = (0,i18n/* translate */.Iu)('sortTitleShort');
|
|
|
|
sort.onclick = function () {
|
|
editor.node.showSortModal();
|
|
};
|
|
|
|
this.menu.appendChild(sort);
|
|
} // create transform button
|
|
|
|
|
|
if (this.options.enableTransform) {
|
|
var transform = document.createElement('button');
|
|
transform.type = 'button';
|
|
transform.title = (0,i18n/* translate */.Iu)('transformTitleShort');
|
|
transform.className = 'jsoneditor-transform';
|
|
|
|
transform.onclick = function () {
|
|
editor.node.showTransformModal();
|
|
};
|
|
|
|
this.menu.appendChild(transform);
|
|
} // create undo/redo buttons
|
|
|
|
|
|
if (this.history) {
|
|
// create undo button
|
|
var undo = document.createElement('button');
|
|
undo.type = 'button';
|
|
undo.className = 'jsoneditor-undo jsoneditor-separator';
|
|
undo.title = (0,i18n/* translate */.Iu)('undo');
|
|
|
|
undo.onclick = function () {
|
|
editor._onUndo();
|
|
};
|
|
|
|
this.menu.appendChild(undo);
|
|
this.dom.undo = undo; // create redo button
|
|
|
|
var redo = document.createElement('button');
|
|
redo.type = 'button';
|
|
redo.className = 'jsoneditor-redo';
|
|
redo.title = (0,i18n/* translate */.Iu)('redo');
|
|
|
|
redo.onclick = function () {
|
|
editor._onRedo();
|
|
};
|
|
|
|
this.menu.appendChild(redo);
|
|
this.dom.redo = redo; // register handler for onchange of history
|
|
|
|
this.history.onChange = function () {
|
|
undo.disabled = !editor.history.canUndo();
|
|
redo.disabled = !editor.history.canRedo();
|
|
};
|
|
|
|
this.history.onChange();
|
|
} // create mode box
|
|
|
|
|
|
if (this.options && this.options.modes && this.options.modes.length) {
|
|
var me = this;
|
|
this.modeSwitcher = new ModeSwitcher/* ModeSwitcher */.x(this.menu, this.options.modes, this.options.mode, function onSwitch(mode) {
|
|
// switch mode and restore focus
|
|
me.setMode(mode);
|
|
me.modeSwitcher.focus();
|
|
});
|
|
} // create search box
|
|
|
|
|
|
if (this.options.search) {
|
|
this.searchBox = new SearchBox(this, this.menu);
|
|
}
|
|
}
|
|
|
|
if (this.options.navigationBar) {
|
|
// create second menu row for treepath
|
|
this.navBar = document.createElement('div');
|
|
this.navBar.className = 'jsoneditor-navigation-bar nav-bar-empty';
|
|
this.frame.appendChild(this.navBar);
|
|
this.treePath = new TreePath(this.navBar, this.getPopupAnchor());
|
|
this.treePath.onSectionSelected(this._onTreePathSectionSelected.bind(this));
|
|
this.treePath.onContextMenuItemSelected(this._onTreePathMenuItemSelected.bind(this));
|
|
}
|
|
};
|
|
/**
|
|
* Perform an undo action
|
|
* @private
|
|
*/
|
|
|
|
|
|
treemode._onUndo = function () {
|
|
if (this.history) {
|
|
// undo last action
|
|
this.history.undo(); // fire change event
|
|
|
|
this._onChange();
|
|
}
|
|
};
|
|
/**
|
|
* Perform a redo action
|
|
* @private
|
|
*/
|
|
|
|
|
|
treemode._onRedo = function () {
|
|
if (this.history) {
|
|
// redo last action
|
|
this.history.redo(); // fire change event
|
|
|
|
this._onChange();
|
|
}
|
|
};
|
|
/**
|
|
* Event handler
|
|
* @param event
|
|
* @private
|
|
*/
|
|
|
|
|
|
treemode._onEvent = function (event) {
|
|
// don't process events when coming from the color picker
|
|
if (Node.targetIsColorPicker(event.target)) {
|
|
return;
|
|
}
|
|
|
|
var node = Node.getNodeFromTarget(event.target);
|
|
|
|
if (event.type === 'keydown') {
|
|
this._onKeyDown(event);
|
|
}
|
|
|
|
if (node && event.type === 'focus') {
|
|
this.focusTarget = event.target;
|
|
|
|
if (this.options.autocomplete && this.options.autocomplete.trigger === 'focus') {
|
|
this._showAutoComplete(event.target);
|
|
}
|
|
}
|
|
|
|
if (event.type === 'mousedown') {
|
|
this._startDragDistance(event);
|
|
}
|
|
|
|
if (event.type === 'mousemove' || event.type === 'mouseup' || event.type === 'click') {
|
|
this._updateDragDistance(event);
|
|
}
|
|
|
|
if (node && this.options && this.options.navigationBar && node && (event.type === 'keydown' || event.type === 'mousedown')) {
|
|
// apply on next tick, right after the new key press is applied
|
|
var me = this;
|
|
setTimeout(function () {
|
|
me._updateTreePath(node.getNodePath());
|
|
});
|
|
}
|
|
|
|
if (node && node.selected) {
|
|
if (event.type === 'click') {
|
|
if (event.target === node.dom.menu) {
|
|
this.showContextMenu(event.target); // stop propagation (else we will open the context menu of a single node)
|
|
|
|
return;
|
|
} // deselect a multi selection
|
|
|
|
|
|
if (!event.hasMoved) {
|
|
this.deselect();
|
|
}
|
|
}
|
|
|
|
if (event.type === 'mousedown') {
|
|
// drag multiple nodes
|
|
Node.onDragStart(this.multiselection.nodes, event);
|
|
}
|
|
} else {
|
|
// filter mouse events in the contents part of the editor (not the main menu)
|
|
if (event.type === 'mousedown' && (0,util.hasParentNode)(event.target, this.content)) {
|
|
this.deselect();
|
|
|
|
if (node && event.target === node.dom.drag) {
|
|
// drag a singe node
|
|
Node.onDragStart(node, event);
|
|
} else if (!node || event.target !== node.dom.field && event.target !== node.dom.value && event.target !== node.dom.select) {
|
|
// select multiple nodes
|
|
this._onMultiSelectStart(event);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (node) {
|
|
node.onEvent(event);
|
|
}
|
|
};
|
|
/**
|
|
* Update TreePath components
|
|
* @param {Array<Node>} pathNodes list of nodes in path from root to selection
|
|
* @private
|
|
*/
|
|
|
|
|
|
treemode._updateTreePath = function (pathNodes) {
|
|
if (pathNodes && pathNodes.length) {
|
|
(0,util.removeClassName)(this.navBar, 'nav-bar-empty');
|
|
var pathObjs = [];
|
|
pathNodes.forEach(function (node) {
|
|
var pathObj = {
|
|
name: getName(node),
|
|
node: node,
|
|
children: []
|
|
};
|
|
|
|
if (node.childs && node.childs.length) {
|
|
node.childs.forEach(function (childNode) {
|
|
pathObj.children.push({
|
|
name: getName(childNode),
|
|
node: childNode
|
|
});
|
|
});
|
|
}
|
|
|
|
pathObjs.push(pathObj);
|
|
});
|
|
this.treePath.setPath(pathObjs);
|
|
} else {
|
|
(0,util.addClassName)(this.navBar, 'nav-bar-empty');
|
|
}
|
|
|
|
function getName(node) {
|
|
return node.parent ? node.parent.type === 'array' ? node.index : node.field : node.field || node.type;
|
|
}
|
|
};
|
|
/**
|
|
* Callback for tree path section selection - focus the selected node in the tree
|
|
* @param {Object} pathObj path object that was represents the selected section node
|
|
* @private
|
|
*/
|
|
|
|
|
|
treemode._onTreePathSectionSelected = function (pathObj) {
|
|
if (pathObj && pathObj.node) {
|
|
pathObj.node.expandTo();
|
|
pathObj.node.focus();
|
|
}
|
|
};
|
|
/**
|
|
* Callback for tree path menu item selection - rebuild the path accrding to the new selection and focus the selected node in the tree
|
|
* @param {Object} pathObj path object that was represents the parent section node
|
|
* @param {String} selection selected section child
|
|
* @private
|
|
*/
|
|
|
|
|
|
treemode._onTreePathMenuItemSelected = function (pathObj, selection) {
|
|
if (pathObj && pathObj.children.length) {
|
|
var selectionObj = pathObj.children.find(function (obj) {
|
|
return obj.name === selection;
|
|
});
|
|
|
|
if (selectionObj && selectionObj.node) {
|
|
this._updateTreePath(selectionObj.node.getNodePath());
|
|
|
|
selectionObj.node.expandTo();
|
|
selectionObj.node.focus();
|
|
}
|
|
}
|
|
};
|
|
|
|
treemode._startDragDistance = function (event) {
|
|
this.dragDistanceEvent = {
|
|
initialTarget: event.target,
|
|
initialPageX: event.pageX,
|
|
initialPageY: event.pageY,
|
|
dragDistance: 0,
|
|
hasMoved: false
|
|
};
|
|
};
|
|
|
|
treemode._updateDragDistance = function (event) {
|
|
if (!this.dragDistanceEvent) {
|
|
this._startDragDistance(event);
|
|
}
|
|
|
|
var diffX = event.pageX - this.dragDistanceEvent.initialPageX;
|
|
var diffY = event.pageY - this.dragDistanceEvent.initialPageY;
|
|
this.dragDistanceEvent.dragDistance = Math.sqrt(diffX * diffX + diffY * diffY);
|
|
this.dragDistanceEvent.hasMoved = this.dragDistanceEvent.hasMoved || this.dragDistanceEvent.dragDistance > 10;
|
|
event.dragDistance = this.dragDistanceEvent.dragDistance;
|
|
event.hasMoved = this.dragDistanceEvent.hasMoved;
|
|
return event.dragDistance;
|
|
};
|
|
/**
|
|
* Start multi selection of nodes by dragging the mouse
|
|
* @param {MouseEvent} event
|
|
* @private
|
|
*/
|
|
|
|
|
|
treemode._onMultiSelectStart = function (event) {
|
|
var node = Node.getNodeFromTarget(event.target);
|
|
|
|
if (this.options.mode !== 'tree' || this.options.onEditable !== undefined) {
|
|
// dragging not allowed in modes 'view' and 'form'
|
|
// TODO: allow multiselection of items when option onEditable is specified
|
|
return;
|
|
}
|
|
|
|
this.multiselection = {
|
|
start: node || null,
|
|
end: null,
|
|
nodes: []
|
|
};
|
|
|
|
this._startDragDistance(event);
|
|
|
|
var editor = this;
|
|
|
|
if (!this.mousemove) {
|
|
this.mousemove = (0,util.addEventListener)(event.view, 'mousemove', function (event) {
|
|
editor._onMultiSelect(event);
|
|
});
|
|
}
|
|
|
|
if (!this.mouseup) {
|
|
this.mouseup = (0,util.addEventListener)(event.view, 'mouseup', function (event) {
|
|
editor._onMultiSelectEnd(event);
|
|
});
|
|
}
|
|
|
|
event.preventDefault();
|
|
};
|
|
/**
|
|
* Multiselect nodes by dragging
|
|
* @param {MouseEvent} event
|
|
* @private
|
|
*/
|
|
|
|
|
|
treemode._onMultiSelect = function (event) {
|
|
event.preventDefault();
|
|
|
|
this._updateDragDistance(event);
|
|
|
|
if (!event.hasMoved) {
|
|
return;
|
|
}
|
|
|
|
var node = Node.getNodeFromTarget(event.target);
|
|
|
|
if (node) {
|
|
if (this.multiselection.start == null) {
|
|
this.multiselection.start = node;
|
|
}
|
|
|
|
this.multiselection.end = node;
|
|
} // deselect previous selection
|
|
|
|
|
|
this.deselect(); // find the selected nodes in the range from first to last
|
|
|
|
var start = this.multiselection.start;
|
|
var end = this.multiselection.end || this.multiselection.start;
|
|
|
|
if (start && end) {
|
|
// find the top level childs, all having the same parent
|
|
this.multiselection.nodes = this._findTopLevelNodes(start, end);
|
|
|
|
if (this.multiselection.nodes && this.multiselection.nodes.length) {
|
|
var firstNode = this.multiselection.nodes[0];
|
|
|
|
if (this.multiselection.start === firstNode || this.multiselection.start.isDescendantOf(firstNode)) {
|
|
this.multiselection.direction = 'down';
|
|
} else {
|
|
this.multiselection.direction = 'up';
|
|
}
|
|
}
|
|
|
|
this.select(this.multiselection.nodes);
|
|
}
|
|
};
|
|
/**
|
|
* End of multiselect nodes by dragging
|
|
* @param {MouseEvent} event
|
|
* @private
|
|
*/
|
|
|
|
|
|
treemode._onMultiSelectEnd = function (event) {
|
|
// set focus to the context menu button of the first node
|
|
if (this.multiselection.nodes[0]) {
|
|
this.multiselection.nodes[0].dom.menu.focus();
|
|
}
|
|
|
|
this.multiselection.start = null;
|
|
this.multiselection.end = null; // cleanup global event listeners
|
|
|
|
if (this.mousemove) {
|
|
(0,util.removeEventListener)(event.view, 'mousemove', this.mousemove);
|
|
delete this.mousemove;
|
|
}
|
|
|
|
if (this.mouseup) {
|
|
(0,util.removeEventListener)(event.view, 'mouseup', this.mouseup);
|
|
delete this.mouseup;
|
|
}
|
|
};
|
|
/**
|
|
* deselect currently selected nodes
|
|
* @param {boolean} [clearStartAndEnd=false] If true, the `start` and `end`
|
|
* state is cleared too.
|
|
*/
|
|
|
|
|
|
treemode.deselect = function (clearStartAndEnd) {
|
|
var selectionChanged = !!this.multiselection.nodes.length;
|
|
this.multiselection.nodes.forEach(function (node) {
|
|
node.setSelected(false);
|
|
});
|
|
this.multiselection.nodes = [];
|
|
|
|
if (clearStartAndEnd) {
|
|
this.multiselection.start = null;
|
|
this.multiselection.end = null;
|
|
}
|
|
|
|
if (selectionChanged) {
|
|
if (this._selectionChangedHandler) {
|
|
this._selectionChangedHandler();
|
|
}
|
|
}
|
|
};
|
|
/**
|
|
* select nodes
|
|
* @param {Node[] | Node} nodes
|
|
*/
|
|
|
|
|
|
treemode.select = function (nodes) {
|
|
if (!Array.isArray(nodes)) {
|
|
return this.select([nodes]);
|
|
}
|
|
|
|
if (nodes) {
|
|
this.deselect();
|
|
this.multiselection.nodes = nodes.slice(0);
|
|
var first = nodes[0];
|
|
nodes.forEach(function (node) {
|
|
node.expandPathToNode();
|
|
node.setSelected(true, node === first);
|
|
});
|
|
|
|
if (this._selectionChangedHandler) {
|
|
var selection = this.getSelection();
|
|
|
|
this._selectionChangedHandler(selection.start, selection.end);
|
|
}
|
|
}
|
|
};
|
|
/**
|
|
* From two arbitrary selected nodes, find their shared parent node.
|
|
* From that parent node, select the two child nodes in the brances going to
|
|
* nodes `start` and `end`, and select all childs in between.
|
|
* @param {Node} start
|
|
* @param {Node} end
|
|
* @return {Array.<Node>} Returns an ordered list with child nodes
|
|
* @private
|
|
*/
|
|
|
|
|
|
treemode._findTopLevelNodes = function (start, end) {
|
|
var startPath = start.getNodePath();
|
|
var endPath = end.getNodePath();
|
|
var i = 0;
|
|
|
|
while (i < startPath.length && startPath[i] === endPath[i]) {
|
|
i++;
|
|
}
|
|
|
|
var root = startPath[i - 1];
|
|
var startChild = startPath[i];
|
|
var endChild = endPath[i];
|
|
|
|
if (!startChild || !endChild) {
|
|
if (root.parent) {
|
|
// startChild is a parent of endChild or vice versa
|
|
startChild = root;
|
|
endChild = root;
|
|
root = root.parent;
|
|
} else {
|
|
// we have selected the root node (which doesn't have a parent)
|
|
startChild = root.childs[0];
|
|
endChild = root.childs[root.childs.length - 1];
|
|
}
|
|
}
|
|
|
|
if (root && startChild && endChild) {
|
|
var startIndex = root.childs.indexOf(startChild);
|
|
var endIndex = root.childs.indexOf(endChild);
|
|
var firstIndex = Math.min(startIndex, endIndex);
|
|
var lastIndex = Math.max(startIndex, endIndex);
|
|
return root.childs.slice(firstIndex, lastIndex + 1);
|
|
} else {
|
|
return [];
|
|
}
|
|
};
|
|
/**
|
|
* Show autocomplete menu
|
|
* @param {HTMLElement} element
|
|
* @private
|
|
*/
|
|
|
|
|
|
treemode._showAutoComplete = function (element) {
|
|
var node = Node.getNodeFromTarget(element);
|
|
var jsonElementType = '';
|
|
if (element.className.indexOf('jsoneditor-value') >= 0) jsonElementType = 'value';
|
|
if (element.className.indexOf('jsoneditor-field') >= 0) jsonElementType = 'field';
|
|
|
|
if (jsonElementType === '') {
|
|
// Unknown element field. Could be a button or something else
|
|
return;
|
|
}
|
|
|
|
var self = this;
|
|
setTimeout(function () {
|
|
if (node && (self.options.autocomplete.trigger === 'focus' || element.innerText.length > 0)) {
|
|
var result = self.options.autocomplete.getOptions(element.innerText, node.getPath(), jsonElementType, node.editor);
|
|
|
|
if (result === null) {
|
|
self.autocomplete.hideDropDown();
|
|
} else if (typeof result.then === 'function') {
|
|
// probably a promise
|
|
result.then(function (obj) {
|
|
if (obj === null) {
|
|
self.autocomplete.hideDropDown();
|
|
} else if (obj.options) {
|
|
self.autocomplete.show(element, obj.startFrom, obj.options);
|
|
} else {
|
|
self.autocomplete.show(element, 0, obj);
|
|
}
|
|
})["catch"](function (err) {
|
|
console.error(err);
|
|
});
|
|
} else {
|
|
// definitely not a promise
|
|
if (result.options) {
|
|
self.autocomplete.show(element, result.startFrom, result.options);
|
|
} else {
|
|
self.autocomplete.show(element, 0, result);
|
|
}
|
|
}
|
|
} else {
|
|
self.autocomplete.hideDropDown();
|
|
}
|
|
}, 50);
|
|
};
|
|
/**
|
|
* Event handler for keydown. Handles shortcut keys
|
|
* @param {Event} event
|
|
* @private
|
|
*/
|
|
|
|
|
|
treemode._onKeyDown = function (event) {
|
|
var keynum = event.which || event.keyCode;
|
|
var altKey = event.altKey;
|
|
var ctrlKey = event.ctrlKey;
|
|
var metaKey = event.metaKey;
|
|
var shiftKey = event.shiftKey;
|
|
var handled = false;
|
|
var currentTarget = this.focusTarget;
|
|
|
|
if (keynum === 9) {
|
|
// Tab or Shift+Tab
|
|
var me = this;
|
|
setTimeout(function () {
|
|
/*
|
|
- Checking for change in focusTarget
|
|
- Without the check,
|
|
pressing tab after reaching the final DOM element in the editor will
|
|
set the focus back to it than passing focus outside the editor
|
|
*/
|
|
if (me.focusTarget !== currentTarget) {
|
|
// select all text when moving focus to an editable div
|
|
(0,util.selectContentEditable)(me.focusTarget);
|
|
}
|
|
}, 0);
|
|
}
|
|
|
|
if (this.searchBox) {
|
|
if (ctrlKey && keynum === 70) {
|
|
// Ctrl+F
|
|
this.searchBox.dom.search.focus();
|
|
this.searchBox.dom.search.select();
|
|
handled = true;
|
|
} else if (keynum === 114 || ctrlKey && keynum === 71) {
|
|
// F3 or Ctrl+G
|
|
var focus = true;
|
|
|
|
if (!shiftKey) {
|
|
// select next search result (F3 or Ctrl+G)
|
|
this.searchBox.next(focus);
|
|
} else {
|
|
// select previous search result (Shift+F3 or Ctrl+Shift+G)
|
|
this.searchBox.previous(focus);
|
|
}
|
|
|
|
handled = true;
|
|
}
|
|
}
|
|
|
|
if (this.history) {
|
|
if (ctrlKey && !shiftKey && keynum === 90) {
|
|
// Ctrl+Z
|
|
// undo
|
|
this._onUndo();
|
|
|
|
handled = true;
|
|
} else if (ctrlKey && shiftKey && keynum === 90) {
|
|
// Ctrl+Shift+Z
|
|
// redo
|
|
this._onRedo();
|
|
|
|
handled = true;
|
|
}
|
|
}
|
|
|
|
if (this.options.autocomplete && !handled) {
|
|
if (!ctrlKey && !altKey && !metaKey && (event.key.length === 1 || keynum === 8 || keynum === 46)) {
|
|
handled = false; // Activate autocomplete
|
|
|
|
this._showAutoComplete(event.target);
|
|
}
|
|
}
|
|
|
|
if (handled) {
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
}
|
|
};
|
|
/**
|
|
* Create main table
|
|
* @private
|
|
*/
|
|
|
|
|
|
treemode._createTable = function () {
|
|
if (this.options.navigationBar) {
|
|
(0,util.addClassName)(this.contentOuter, 'has-nav-bar');
|
|
}
|
|
|
|
this.scrollableContent = document.createElement('div');
|
|
this.scrollableContent.className = 'jsoneditor-tree';
|
|
this.contentOuter.appendChild(this.scrollableContent); // the jsoneditor-tree-inner div with bottom padding is here to
|
|
// keep space for the action menu dropdown. It's created as a
|
|
// separate div instead of using scrollableContent to work around
|
|
// and issue in the Chrome browser showing scrollable contents outside of the div
|
|
// see https://github.com/josdejong/jsoneditor/issues/557
|
|
|
|
this.content = document.createElement('div');
|
|
this.content.className = 'jsoneditor-tree-inner';
|
|
this.scrollableContent.appendChild(this.content);
|
|
this.table = document.createElement('table');
|
|
this.table.className = 'jsoneditor-tree';
|
|
this.content.appendChild(this.table); // create colgroup where the first two columns don't have a fixed
|
|
// width, and the edit columns do have a fixed width
|
|
|
|
var col;
|
|
this.colgroupContent = document.createElement('colgroup');
|
|
|
|
if (this.options.mode === 'tree') {
|
|
col = document.createElement('col');
|
|
col.width = '24px';
|
|
this.colgroupContent.appendChild(col);
|
|
}
|
|
|
|
col = document.createElement('col');
|
|
col.width = '24px';
|
|
this.colgroupContent.appendChild(col);
|
|
col = document.createElement('col');
|
|
this.colgroupContent.appendChild(col);
|
|
this.table.appendChild(this.colgroupContent);
|
|
this.tbody = document.createElement('tbody');
|
|
this.table.appendChild(this.tbody);
|
|
this.frame.appendChild(this.contentOuter);
|
|
};
|
|
/**
|
|
* Show a contextmenu for this node.
|
|
* Used for multiselection
|
|
* @param {HTMLElement} anchor Anchor element to attach the context menu to.
|
|
* @param {function} [onClose] Callback method called when the context menu
|
|
* is being closed.
|
|
*/
|
|
|
|
|
|
treemode.showContextMenu = function (anchor, onClose) {
|
|
var items = [];
|
|
var selectedNodes = this.multiselection.nodes.slice(); // create duplicate button
|
|
|
|
items.push({
|
|
text: (0,i18n/* translate */.Iu)('duplicateText'),
|
|
title: (0,i18n/* translate */.Iu)('duplicateTitle'),
|
|
className: 'jsoneditor-duplicate',
|
|
click: function click() {
|
|
Node.onDuplicate(selectedNodes);
|
|
}
|
|
}); // create remove button
|
|
|
|
items.push({
|
|
text: (0,i18n/* translate */.Iu)('remove'),
|
|
title: (0,i18n/* translate */.Iu)('removeTitle'),
|
|
className: 'jsoneditor-remove',
|
|
click: function click() {
|
|
Node.onRemove(selectedNodes);
|
|
}
|
|
});
|
|
|
|
if (this.options.onCreateMenu) {
|
|
var paths = selectedNodes.map(function (node) {
|
|
return node.getPath();
|
|
});
|
|
items = this.options.onCreateMenu(items, {
|
|
type: 'multiple',
|
|
path: paths[0],
|
|
paths: paths
|
|
});
|
|
}
|
|
|
|
var menu = new ContextMenu/* ContextMenu */.x(items, {
|
|
close: onClose
|
|
});
|
|
menu.show(anchor, this.getPopupAnchor());
|
|
};
|
|
|
|
treemode.getPopupAnchor = function () {
|
|
return this.options.popupAnchor || this.frame;
|
|
};
|
|
/**
|
|
* Get current selected nodes
|
|
* @return {{start:SerializableNode, end: SerializableNode}}
|
|
*/
|
|
|
|
|
|
treemode.getSelection = function () {
|
|
var selection = {
|
|
start: null,
|
|
end: null
|
|
};
|
|
|
|
if (this.multiselection.nodes && this.multiselection.nodes.length) {
|
|
if (this.multiselection.nodes.length) {
|
|
var selection1 = this.multiselection.nodes[0];
|
|
var selection2 = this.multiselection.nodes[this.multiselection.nodes.length - 1];
|
|
|
|
if (this.multiselection.direction === 'down') {
|
|
selection.start = selection1.serialize();
|
|
selection.end = selection2.serialize();
|
|
} else {
|
|
selection.start = selection2.serialize();
|
|
selection.end = selection1.serialize();
|
|
}
|
|
}
|
|
}
|
|
|
|
return selection;
|
|
};
|
|
/**
|
|
* Callback registration for selection change
|
|
* @param {selectionCallback} callback
|
|
*
|
|
* @callback selectionCallback
|
|
*/
|
|
|
|
|
|
treemode.onSelectionChange = function (callback) {
|
|
if (typeof callback === 'function') {
|
|
this._selectionChangedHandler = (0,util.debounce)(callback, this.DEBOUNCE_INTERVAL);
|
|
}
|
|
};
|
|
/**
|
|
* Select range of nodes.
|
|
* For selecting single node send only the start parameter
|
|
* For clear the selection do not send any parameter
|
|
* If the nodes are not from the same level the first common parent will be selected
|
|
* @param {{path: Array.<String>}} start object contains the path for selection start
|
|
* @param {{path: Array.<String>}} end object contains the path for selection end
|
|
*/
|
|
|
|
|
|
treemode.setSelection = function (start, end) {
|
|
// check for old usage
|
|
if (start && start.dom && start.range) {
|
|
console.warn('setSelection/getSelection usage for text selection is deprecated and should not be used, see documentation for supported selection options');
|
|
this.setDomSelection(start);
|
|
}
|
|
|
|
var nodes = this._getNodeInstancesByRange(start, end);
|
|
|
|
nodes.forEach(function (node) {
|
|
node.expandTo();
|
|
});
|
|
this.select(nodes);
|
|
};
|
|
/**
|
|
* Returns a set of Nodes according to a range of selection
|
|
* @param {{path: Array.<String>}} start object contains the path for range start
|
|
* @param {{path: Array.<String>}=} end object contains the path for range end
|
|
* @return {Array.<Node>} Node instances on the given range
|
|
* @private
|
|
*/
|
|
|
|
|
|
treemode._getNodeInstancesByRange = function (start, end) {
|
|
var startNode, endNode;
|
|
|
|
if (start && start.path) {
|
|
startNode = this.node.findNodeByPath(start.path);
|
|
|
|
if (end && end.path) {
|
|
endNode = this.node.findNodeByPath(end.path);
|
|
}
|
|
}
|
|
|
|
var nodes = [];
|
|
|
|
if (startNode instanceof Node) {
|
|
if (endNode instanceof Node && endNode !== startNode) {
|
|
if (startNode.parent === endNode.parent) {
|
|
if (startNode.getIndex() < endNode.getIndex()) {
|
|
start = startNode;
|
|
end = endNode;
|
|
} else {
|
|
start = endNode;
|
|
end = startNode;
|
|
}
|
|
|
|
var current = start;
|
|
nodes.push(current);
|
|
|
|
do {
|
|
current = current.nextSibling();
|
|
nodes.push(current);
|
|
} while (current && current !== end);
|
|
} else {
|
|
nodes = this._findTopLevelNodes(startNode, endNode);
|
|
}
|
|
} else {
|
|
nodes.push(startNode);
|
|
}
|
|
}
|
|
|
|
return nodes;
|
|
};
|
|
|
|
treemode.getNodesByRange = function (start, end) {
|
|
var nodes = this._getNodeInstancesByRange(start, end);
|
|
|
|
var serializableNodes = [];
|
|
nodes.forEach(function (node) {
|
|
serializableNodes.push(node.serialize());
|
|
});
|
|
return serializableNodes;
|
|
}; // define modes
|
|
|
|
|
|
var treeModeMixins = [{
|
|
mode: 'tree',
|
|
mixin: treemode,
|
|
data: 'json'
|
|
}, {
|
|
mode: 'view',
|
|
mixin: treemode,
|
|
data: 'json'
|
|
}, {
|
|
mode: 'form',
|
|
mixin: treemode,
|
|
data: 'json'
|
|
}];
|
|
|
|
/***/ }),
|
|
|
|
/***/ 2744:
|
|
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
|
|
|
|
exports.tryRequireAjv = function () {
|
|
try {
|
|
return __webpack_require__(8903);
|
|
} catch (err) {// no problem... when we need Ajv we will throw a neat exception
|
|
}
|
|
};
|
|
|
|
/***/ }),
|
|
|
|
/***/ 9125:
|
|
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
|
|
|
|
exports.O = function () {
|
|
try {
|
|
__webpack_require__(4864);
|
|
} catch (err) {
|
|
console.error(err);
|
|
}
|
|
};
|
|
|
|
/***/ }),
|
|
|
|
/***/ 9791:
|
|
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
|
|
|
"use strict";
|
|
__webpack_require__.r(__webpack_exports__);
|
|
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
/* harmony export */ "parse": function() { return /* binding */ parse; },
|
|
/* harmony export */ "tryJsonRepair": function() { return /* binding */ tryJsonRepair; },
|
|
/* harmony export */ "escapeUnicodeChars": function() { return /* binding */ escapeUnicodeChars; },
|
|
/* harmony export */ "validate": function() { return /* binding */ validate; },
|
|
/* harmony export */ "extend": function() { return /* binding */ extend; },
|
|
/* harmony export */ "clear": function() { return /* binding */ clear; },
|
|
/* harmony export */ "getType": function() { return /* binding */ getType; },
|
|
/* harmony export */ "isUrl": function() { return /* binding */ isUrl; },
|
|
/* harmony export */ "isArray": function() { return /* binding */ isArray; },
|
|
/* harmony export */ "getWindow": function() { return /* binding */ getWindow; },
|
|
/* harmony export */ "getAbsoluteLeft": function() { return /* binding */ getAbsoluteLeft; },
|
|
/* harmony export */ "getAbsoluteTop": function() { return /* binding */ getAbsoluteTop; },
|
|
/* harmony export */ "addClassName": function() { return /* binding */ addClassName; },
|
|
/* harmony export */ "removeAllClassNames": function() { return /* binding */ removeAllClassNames; },
|
|
/* harmony export */ "removeClassName": function() { return /* binding */ removeClassName; },
|
|
/* harmony export */ "stripFormatting": function() { return /* binding */ stripFormatting; },
|
|
/* harmony export */ "setEndOfContentEditable": function() { return /* binding */ setEndOfContentEditable; },
|
|
/* harmony export */ "selectContentEditable": function() { return /* binding */ selectContentEditable; },
|
|
/* harmony export */ "getSelection": function() { return /* binding */ getSelection; },
|
|
/* harmony export */ "setSelection": function() { return /* binding */ setSelection; },
|
|
/* harmony export */ "getSelectionOffset": function() { return /* binding */ getSelectionOffset; },
|
|
/* harmony export */ "setSelectionOffset": function() { return /* binding */ setSelectionOffset; },
|
|
/* harmony export */ "getInnerText": function() { return /* binding */ getInnerText; },
|
|
/* harmony export */ "hasParentNode": function() { return /* binding */ hasParentNode; },
|
|
/* harmony export */ "getInternetExplorerVersion": function() { return /* binding */ getInternetExplorerVersion; },
|
|
/* harmony export */ "isFirefox": function() { return /* binding */ isFirefox; },
|
|
/* harmony export */ "addEventListener": function() { return /* binding */ addEventListener; },
|
|
/* harmony export */ "removeEventListener": function() { return /* binding */ removeEventListener; },
|
|
/* harmony export */ "isChildOf": function() { return /* binding */ isChildOf; },
|
|
/* harmony export */ "parsePath": function() { return /* binding */ parsePath; },
|
|
/* harmony export */ "stringifyPath": function() { return /* binding */ stringifyPath; },
|
|
/* harmony export */ "improveSchemaError": function() { return /* binding */ improveSchemaError; },
|
|
/* harmony export */ "isPromise": function() { return /* binding */ isPromise; },
|
|
/* harmony export */ "isValidValidationError": function() { return /* binding */ isValidValidationError; },
|
|
/* harmony export */ "insideRect": function() { return /* binding */ insideRect; },
|
|
/* harmony export */ "debounce": function() { return /* binding */ debounce; },
|
|
/* harmony export */ "textDiff": function() { return /* binding */ textDiff; },
|
|
/* harmony export */ "getInputSelection": function() { return /* binding */ getInputSelection; },
|
|
/* harmony export */ "getIndexForPosition": function() { return /* binding */ getIndexForPosition; },
|
|
/* harmony export */ "getPositionForPath": function() { return /* binding */ getPositionForPath; },
|
|
/* harmony export */ "compileJSONPointer": function() { return /* binding */ compileJSONPointer; },
|
|
/* harmony export */ "getColorCSS": function() { return /* binding */ getColorCSS; },
|
|
/* harmony export */ "isValidColor": function() { return /* binding */ isValidColor; },
|
|
/* harmony export */ "makeFieldTooltip": function() { return /* binding */ makeFieldTooltip; },
|
|
/* harmony export */ "get": function() { return /* binding */ get; },
|
|
/* harmony export */ "findUniqueName": function() { return /* binding */ findUniqueName; },
|
|
/* harmony export */ "getChildPaths": function() { return /* binding */ getChildPaths; },
|
|
/* harmony export */ "sort": function() { return /* binding */ sort; },
|
|
/* harmony export */ "sortObjectKeys": function() { return /* binding */ sortObjectKeys; },
|
|
/* harmony export */ "parseString": function() { return /* binding */ parseString; },
|
|
/* harmony export */ "isTimestamp": function() { return /* binding */ isTimestamp; },
|
|
/* harmony export */ "formatSize": function() { return /* binding */ formatSize; },
|
|
/* harmony export */ "limitCharacters": function() { return /* binding */ limitCharacters; },
|
|
/* harmony export */ "isObject": function() { return /* binding */ isObject; },
|
|
/* harmony export */ "contains": function() { return /* binding */ contains; },
|
|
/* harmony export */ "isValidationErrorChanged": function() { return /* binding */ isValidationErrorChanged; }
|
|
/* harmony export */ });
|
|
/* harmony import */ var _polyfills__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(4987);
|
|
/* harmony import */ var _polyfills__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_polyfills__WEBPACK_IMPORTED_MODULE_0__);
|
|
/* harmony import */ var javascript_natural_sort__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(233);
|
|
/* harmony import */ var javascript_natural_sort__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(javascript_natural_sort__WEBPACK_IMPORTED_MODULE_1__);
|
|
/* harmony import */ var jsonrepair__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(8909);
|
|
/* harmony import */ var jsonrepair__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(jsonrepair__WEBPACK_IMPORTED_MODULE_2__);
|
|
/* harmony import */ var _assets_jsonlint_jsonlint__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(6589);
|
|
/* harmony import */ var json_source_map__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(7026);
|
|
/* harmony import */ var _i18n__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(7907);
|
|
|
|
|
|
function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var MAX_ITEMS_FIELDS_COLLECTION = 10000;
|
|
var YEAR_2000 = 946684800000;
|
|
/**
|
|
* 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
|
|
*/
|
|
|
|
function parse(jsonString) {
|
|
try {
|
|
return JSON.parse(jsonString);
|
|
} catch (err) {
|
|
// try to throw a more detailed error message using validate
|
|
validate(jsonString); // rethrow the original error
|
|
|
|
throw err;
|
|
}
|
|
}
|
|
/**
|
|
* Try to fix the JSON string. If not successful, return the original string
|
|
* @param {string} jsonString
|
|
*/
|
|
|
|
function tryJsonRepair(jsonString) {
|
|
try {
|
|
return jsonrepair__WEBPACK_IMPORTED_MODULE_2___default()(jsonString);
|
|
} catch (err) {
|
|
// repair was not successful, return original text
|
|
return jsonString;
|
|
}
|
|
}
|
|
/**
|
|
* Escape unicode characters.
|
|
* For example input '\u2661' (length 1) will output '\\u2661' (length 5).
|
|
* @param {string} text
|
|
* @return {string}
|
|
*/
|
|
|
|
function escapeUnicodeChars( // see https://www.wikiwand.com/en/UTF-16
|
|
text) {
|
|
return (// note: we leave surrogate pairs as two individual chars,
|
|
// as JSON doesn't interpret them as a single unicode char.
|
|
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
|
|
*/
|
|
|
|
function validate(jsonString) {
|
|
if (typeof _assets_jsonlint_jsonlint__WEBPACK_IMPORTED_MODULE_3__ !== 'undefined') {
|
|
_assets_jsonlint_jsonlint__WEBPACK_IMPORTED_MODULE_3__.parse(jsonString);
|
|
} else {
|
|
JSON.parse(jsonString);
|
|
}
|
|
}
|
|
/**
|
|
* Extend object a with the properties of object b
|
|
* @param {Object} a
|
|
* @param {Object} b
|
|
* @return {Object} a
|
|
*/
|
|
|
|
function extend(a, b) {
|
|
for (var prop in b) {
|
|
if (hasOwnProperty(b, prop)) {
|
|
a[prop] = b[prop];
|
|
}
|
|
}
|
|
|
|
return a;
|
|
}
|
|
/**
|
|
* Remove all properties from object a
|
|
* @param {Object} a
|
|
* @return {Object} a
|
|
*/
|
|
|
|
function clear(a) {
|
|
for (var prop in a) {
|
|
if (hasOwnProperty(a, prop)) {
|
|
delete a[prop];
|
|
}
|
|
}
|
|
|
|
return a;
|
|
}
|
|
/**
|
|
* Get the type of an object
|
|
* @param {*} object
|
|
* @return {String} type
|
|
*/
|
|
|
|
function getType(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) {
|
|
return 'regexp';
|
|
}
|
|
|
|
if (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+$/;
|
|
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
|
|
*/
|
|
|
|
function isArray(obj) {
|
|
return Object.prototype.toString.call(obj) === '[object Array]';
|
|
}
|
|
/**
|
|
* Gets a DOM element's Window. This is normally just the global `window`
|
|
* variable, but if we opened a child window, it may be different.
|
|
* @param {HTMLElement} element
|
|
* @return {Window}
|
|
*/
|
|
|
|
function getWindow(element) {
|
|
return element.ownerDocument.defaultView;
|
|
}
|
|
/**
|
|
* 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.
|
|
*/
|
|
|
|
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.
|
|
*/
|
|
|
|
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
|
|
*/
|
|
|
|
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
|
|
*/
|
|
|
|
function removeAllClassNames(elem) {
|
|
elem.className = '';
|
|
}
|
|
/**
|
|
* add a className to the given elements style
|
|
* @param {Element} elem
|
|
* @param {String} className
|
|
*/
|
|
|
|
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
|
|
*/
|
|
|
|
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
|
|
|
|
|
|
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
|
|
*/
|
|
|
|
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
|
|
*/
|
|
|
|
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
|
|
*/
|
|
|
|
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
|
|
*/
|
|
|
|
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
|
|
*/
|
|
|
|
function getSelectionOffset() {
|
|
var range = 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
|
|
*/
|
|
|
|
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);
|
|
setSelection(range);
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Get the inner text of an HTML element (for example a div element)
|
|
* @param {Element} element
|
|
* @param {Object} [buffer]
|
|
* @return {String} innerText
|
|
*/
|
|
|
|
function getInnerText(element, buffer) {
|
|
var first = buffer === undefined;
|
|
|
|
if (first) {
|
|
buffer = {
|
|
_text: '',
|
|
flush: function flush() {
|
|
var text = this._text;
|
|
this._text = '';
|
|
return text;
|
|
},
|
|
set: function set(text) {
|
|
this._text = text;
|
|
}
|
|
};
|
|
} // text node
|
|
|
|
|
|
if (element.nodeValue) {
|
|
// remove return characters and the whitespace surrounding return characters
|
|
var trimmedValue = element.nodeValue.replace(/\s*\n\s*/g, '');
|
|
|
|
if (trimmedValue !== '') {
|
|
return buffer.flush() + trimmedValue;
|
|
} else {
|
|
// ignore empty text
|
|
return '';
|
|
}
|
|
} // 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') {
|
|
if (innerText !== '') {
|
|
innerText += '\n';
|
|
}
|
|
|
|
buffer.flush();
|
|
}
|
|
|
|
innerText += getInnerText(child, buffer);
|
|
buffer.set('\n');
|
|
} else if (child.nodeName === 'BR') {
|
|
innerText += buffer.flush();
|
|
buffer.set('\n');
|
|
} else {
|
|
innerText += getInnerText(child, buffer);
|
|
}
|
|
}
|
|
|
|
return innerText;
|
|
} // 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}
|
|
*/
|
|
|
|
function hasParentNode(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
|
|
*/
|
|
|
|
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 = /MSIE ([0-9]+[.0-9]+)/;
|
|
|
|
if (re.exec(ua) != null) {
|
|
rv = parseFloat(RegExp.$1);
|
|
}
|
|
}
|
|
|
|
_ieVersion = rv;
|
|
}
|
|
|
|
return _ieVersion;
|
|
}
|
|
/**
|
|
* cached internet explorer version
|
|
* @type {Number}
|
|
* @private
|
|
*/
|
|
|
|
var _ieVersion = -1;
|
|
/**
|
|
* Test whether the current browser is Firefox
|
|
* @returns {boolean} isFirefox
|
|
*/
|
|
|
|
|
|
function isFirefox() {
|
|
return typeof navigator !== 'undefined' && navigator.userAgent.indexOf('Firefox') !== -1;
|
|
}
|
|
/**
|
|
* Add an 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
|
|
*/
|
|
|
|
function addEventListener(element, action, listener, useCapture) {
|
|
if (element.addEventListener) {
|
|
if (useCapture === undefined) {
|
|
useCapture = false;
|
|
}
|
|
|
|
if (action === 'mousewheel' && isFirefox()) {
|
|
action = 'DOMMouseScroll'; // For Firefox
|
|
}
|
|
|
|
element.addEventListener(action, listener, useCapture);
|
|
return listener;
|
|
} else if (element.attachEvent) {
|
|
// Old IE browsers
|
|
var f = function f() {
|
|
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
|
|
*/
|
|
|
|
function removeEventListener(element, action, listener, useCapture) {
|
|
if (element.removeEventListener) {
|
|
if (useCapture === undefined) {
|
|
useCapture = false;
|
|
}
|
|
|
|
if (action === 'mousewheel' && 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
|
|
*/
|
|
|
|
function isChildOf(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}
|
|
*/
|
|
|
|
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.<string | number>} path
|
|
* @returns {string}
|
|
*/
|
|
|
|
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
|
|
*/
|
|
|
|
function improveSchemaError(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
|
|
*/
|
|
|
|
function isPromise(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
|
|
*/
|
|
|
|
function isValidValidationError(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
|
|
*/
|
|
|
|
function insideRect(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
|
|
*/
|
|
|
|
function debounce(func, wait, immediate) {
|
|
var timeout;
|
|
return function () {
|
|
var context = this;
|
|
var args = arguments;
|
|
|
|
var later = function later() {
|
|
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.
|
|
*/
|
|
|
|
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.
|
|
**/
|
|
|
|
function getInputSelection(el) {
|
|
var startIndex = 0;
|
|
var endIndex = 0;
|
|
var normalizedValue;
|
|
var range;
|
|
var textInputRange;
|
|
var len;
|
|
var 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, column: 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 certain 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
|
|
*/
|
|
|
|
function getIndexForPosition(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<String>} paths array of json paths
|
|
* @returns {Array<{path: String, line: Number, row: Number}>}
|
|
*/
|
|
|
|
function getPositionForPath(text, paths) {
|
|
var result = [];
|
|
var jsmap;
|
|
|
|
if (!paths || !paths.length) {
|
|
return result;
|
|
}
|
|
|
|
try {
|
|
jsmap = json_source_map__WEBPACK_IMPORTED_MODULE_4__/* .parse */ .Q(text);
|
|
} catch (err) {
|
|
return result;
|
|
}
|
|
|
|
paths.forEach(function (path) {
|
|
var pathArr = parsePath(path);
|
|
var pointerName = 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.<string | number>} path
|
|
* @return {string}
|
|
*/
|
|
|
|
function compileJSONPointer(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)'
|
|
*/
|
|
|
|
function getColorCSS(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
|
|
*/
|
|
|
|
function isValidColor(color) {
|
|
return !!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
|
|
*/
|
|
|
|
function makeFieldTooltip(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 += (0,_i18n__WEBPACK_IMPORTED_MODULE_5__/* .translate */ .Iu)('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 += (0,_i18n__WEBPACK_IMPORTED_MODULE_5__/* .translate */ .Iu)('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 {*}
|
|
*/
|
|
|
|
function get(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
|
|
*/
|
|
|
|
function findUniqueName(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[]}
|
|
*/
|
|
|
|
function getChildPaths(json, includeObjects) {
|
|
var pathsMap = {};
|
|
|
|
function getObjectChildPaths(json, pathsMap, rootPath, includeObjects) {
|
|
var isValue = !Array.isArray(json) && !isObject(json);
|
|
|
|
if (isValue || includeObjects) {
|
|
pathsMap[rootPath || ''] = true;
|
|
}
|
|
|
|
if (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]
|
|
*/
|
|
|
|
function sort(array, path, direction) {
|
|
var parsedPath = path && path !== '.' ? parsePath(path) : [];
|
|
var sign = direction === 'desc' ? -1 : 1;
|
|
var sortedArray = array.slice();
|
|
sortedArray.sort(function (a, b) {
|
|
var aValue = get(a, parsedPath);
|
|
var bValue = 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]
|
|
*/
|
|
|
|
function sortObjectKeys(object, direction) {
|
|
var sign = direction === 'desc' ? -1 : 1;
|
|
var sortedFields = Object.keys(object).sort(function (a, b) {
|
|
return sign * javascript_natural_sort__WEBPACK_IMPORTED_MODULE_1___default()(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
|
|
*/
|
|
|
|
function parseString(str) {
|
|
if (str === '') {
|
|
return '';
|
|
}
|
|
|
|
var lower = str.toLowerCase();
|
|
|
|
if (lower === 'null') {
|
|
return null;
|
|
}
|
|
|
|
if (lower === 'true') {
|
|
return true;
|
|
}
|
|
|
|
if (lower === 'false') {
|
|
return false;
|
|
}
|
|
|
|
var num = Number(str); // will nicely fail with '123ab'
|
|
|
|
var numFloat = parseFloat(str); // will nicely fail with ' '
|
|
|
|
if (!isNaN(num) && !isNaN(numFloat)) {
|
|
return num;
|
|
}
|
|
|
|
return str;
|
|
}
|
|
/**
|
|
* Test whether some field contains a timestamp in milliseconds after the year 2000.
|
|
* @param {string} field
|
|
* @param {number} value
|
|
* @return {boolean}
|
|
*/
|
|
|
|
function isTimestamp(field, value) {
|
|
return typeof value === 'number' && value > YEAR_2000 && isFinite(value) && Math.floor(value) === value && !isNaN(new Date(value).valueOf());
|
|
}
|
|
/**
|
|
* Return a human readable document size
|
|
* For example formatSize(7570718) outputs '7.6 MB'
|
|
* @param {number} size
|
|
* @return {string} Returns a human readable size
|
|
*/
|
|
|
|
function formatSize(size) {
|
|
if (size < 900) {
|
|
return size.toFixed() + ' B';
|
|
}
|
|
|
|
var KB = size / 1000;
|
|
|
|
if (KB < 900) {
|
|
return KB.toFixed(1) + ' KB';
|
|
}
|
|
|
|
var MB = KB / 1000;
|
|
|
|
if (MB < 900) {
|
|
return MB.toFixed(1) + ' MB';
|
|
}
|
|
|
|
var GB = MB / 1000;
|
|
|
|
if (GB < 900) {
|
|
return GB.toFixed(1) + ' GB';
|
|
}
|
|
|
|
var TB = GB / 1000;
|
|
return TB.toFixed(1) + ' TB';
|
|
}
|
|
/**
|
|
* 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
|
|
*/
|
|
|
|
function limitCharacters(text, maxCharacterCount) {
|
|
if (text.length <= maxCharacterCount) {
|
|
return text;
|
|
}
|
|
|
|
return text.slice(0, maxCharacterCount) + '...';
|
|
}
|
|
/**
|
|
* Test whether a value is an Object
|
|
* @param {*} value
|
|
* @return {boolean}
|
|
*/
|
|
|
|
function isObject(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.
|
|
*/
|
|
|
|
function contains(array, item) {
|
|
return array.indexOf(item) !== -1;
|
|
}
|
|
/**
|
|
* Checks if validation has changed from the previous execution
|
|
* @param {Array} currErr current validation errors
|
|
* @param {Array} prevErr previous validation errors
|
|
*/
|
|
|
|
function isValidationErrorChanged(currErr, prevErr) {
|
|
if (!prevErr && !currErr) {
|
|
return false;
|
|
}
|
|
|
|
if (prevErr && !currErr || !prevErr && currErr) {
|
|
return true;
|
|
}
|
|
|
|
if (prevErr.length !== currErr.length) {
|
|
return true;
|
|
}
|
|
|
|
var _loop = function _loop(i) {
|
|
var pErr = void 0;
|
|
|
|
if (currErr[i].type === 'error') {
|
|
pErr = prevErr.find(function (p) {
|
|
return p.line === currErr[i].line;
|
|
});
|
|
} else {
|
|
pErr = prevErr.find(function (p) {
|
|
return p.dataPath === currErr[i].dataPath && p.schemaPath === currErr[i].schemaPath;
|
|
});
|
|
}
|
|
|
|
if (!pErr) {
|
|
return {
|
|
v: true
|
|
};
|
|
}
|
|
};
|
|
|
|
for (var i = 0; i < currErr.length; ++i) {
|
|
var _ret = _loop(i);
|
|
|
|
if (_typeof(_ret) === "object") return _ret.v;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
function hasOwnProperty(object, key) {
|
|
return Object.prototype.hasOwnProperty.call(object, key);
|
|
}
|
|
|
|
/***/ }),
|
|
|
|
/***/ 8037:
|
|
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
|
|
|
|
var VanillaPicker;
|
|
|
|
if (window.Picker) {
|
|
// use the already loaded instance of VanillaPicker
|
|
VanillaPicker = window.Picker;
|
|
} else {
|
|
try {
|
|
// load color picker
|
|
VanillaPicker = __webpack_require__(4049);
|
|
} catch (err) {// probably running the minimalist bundle
|
|
}
|
|
}
|
|
|
|
module.exports = VanillaPicker;
|
|
|
|
/***/ }),
|
|
|
|
/***/ 6225:
|
|
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
|
|
|
|
/* module decorator */ module = __webpack_require__.nmd(module);
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
* Distributed under the BSD license:
|
|
*
|
|
* Copyright (c) 2010, Ajax.org B.V.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
* * Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* * Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* * Neither the name of Ajax.org B.V. nor the
|
|
* names of its contributors may be used to endorse or promote products
|
|
* derived from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
/**
|
|
* Define a module along with a payload
|
|
* @param module a name for the payload
|
|
* @param payload a function to call with (require, exports, module) params
|
|
*/
|
|
|
|
(function() {
|
|
|
|
var ACE_NAMESPACE = "ace";
|
|
|
|
var global = (function() { return this; })();
|
|
if (!global && typeof window != "undefined") global = window; // strict mode
|
|
|
|
|
|
if (!ACE_NAMESPACE && typeof requirejs !== "undefined")
|
|
return;
|
|
|
|
|
|
var define = function(module, deps, payload) {
|
|
if (typeof module !== "string") {
|
|
if (define.original)
|
|
define.original.apply(this, arguments);
|
|
else {
|
|
console.error("dropping module because define wasn\'t a string.");
|
|
console.trace();
|
|
}
|
|
return;
|
|
}
|
|
if (arguments.length == 2)
|
|
payload = deps;
|
|
if (!define.modules[module]) {
|
|
define.payloads[module] = payload;
|
|
define.modules[module] = null;
|
|
}
|
|
};
|
|
|
|
define.modules = {};
|
|
define.payloads = {};
|
|
|
|
/**
|
|
* Get at functionality define()ed using the function above
|
|
*/
|
|
var _require = function(parentId, module, callback) {
|
|
if (typeof module === "string") {
|
|
var payload = lookup(parentId, module);
|
|
if (payload != undefined) {
|
|
callback && callback();
|
|
return payload;
|
|
}
|
|
} else if (Object.prototype.toString.call(module) === "[object Array]") {
|
|
var params = [];
|
|
for (var i = 0, l = module.length; i < l; ++i) {
|
|
var dep = lookup(parentId, module[i]);
|
|
if (dep == undefined && require.original)
|
|
return;
|
|
params.push(dep);
|
|
}
|
|
return callback && callback.apply(null, params) || true;
|
|
}
|
|
};
|
|
|
|
var require = function(module, callback) {
|
|
var packagedModule = _require("", module, callback);
|
|
if (packagedModule == undefined && require.original)
|
|
return require.original.apply(this, arguments);
|
|
return packagedModule;
|
|
};
|
|
|
|
var normalizeModule = function(parentId, moduleName) {
|
|
// normalize plugin requires
|
|
if (moduleName.indexOf("!") !== -1) {
|
|
var chunks = moduleName.split("!");
|
|
return normalizeModule(parentId, chunks[0]) + "!" + normalizeModule(parentId, chunks[1]);
|
|
}
|
|
// normalize relative requires
|
|
if (moduleName.charAt(0) == ".") {
|
|
var base = parentId.split("/").slice(0, -1).join("/");
|
|
moduleName = base + "/" + moduleName;
|
|
|
|
while(moduleName.indexOf(".") !== -1 && previous != moduleName) {
|
|
var previous = moduleName;
|
|
moduleName = moduleName.replace(/\/\.\//, "/").replace(/[^\/]+\/\.\.\//, "");
|
|
}
|
|
}
|
|
return moduleName;
|
|
};
|
|
|
|
/**
|
|
* Internal function to lookup moduleNames and resolve them by calling the
|
|
* definition function if needed.
|
|
*/
|
|
var lookup = function(parentId, moduleName) {
|
|
moduleName = normalizeModule(parentId, moduleName);
|
|
|
|
var module = define.modules[moduleName];
|
|
if (!module) {
|
|
module = define.payloads[moduleName];
|
|
if (typeof module === 'function') {
|
|
var exports = {};
|
|
var mod = {
|
|
id: moduleName,
|
|
uri: '',
|
|
exports: exports,
|
|
packaged: true
|
|
};
|
|
|
|
var req = function(module, callback) {
|
|
return _require(moduleName, module, callback);
|
|
};
|
|
|
|
var returnValue = module(req, exports, mod);
|
|
exports = returnValue || mod.exports;
|
|
define.modules[moduleName] = exports;
|
|
delete define.payloads[moduleName];
|
|
}
|
|
module = define.modules[moduleName] = exports || module;
|
|
}
|
|
return module;
|
|
};
|
|
|
|
function exportAce(ns) {
|
|
var root = global;
|
|
if (ns) {
|
|
if (!global[ns])
|
|
global[ns] = {};
|
|
root = global[ns];
|
|
}
|
|
|
|
if (!root.define || !root.define.packaged) {
|
|
define.original = root.define;
|
|
root.define = define;
|
|
root.define.packaged = true;
|
|
}
|
|
|
|
if (!root.require || !root.require.packaged) {
|
|
require.original = root.require;
|
|
root.require = require;
|
|
root.require.packaged = true;
|
|
}
|
|
}
|
|
|
|
exportAce(ACE_NAMESPACE);
|
|
|
|
})();
|
|
|
|
ace.define("ace/lib/fixoldbrowsers",["require","exports","module"], function(require, exports, module) {
|
|
"use strict";
|
|
if (typeof Element != "undefined" && !Element.prototype.remove) {
|
|
Object.defineProperty(Element.prototype, "remove", {
|
|
enumerable: false,
|
|
writable: true,
|
|
configurable: true,
|
|
value: function() { this.parentNode && this.parentNode.removeChild(this); }
|
|
});
|
|
}
|
|
|
|
|
|
});
|
|
|
|
ace.define("ace/lib/useragent",["require","exports","module"], function(require, exports, module) {
|
|
"use strict";
|
|
exports.OS = {
|
|
LINUX: "LINUX",
|
|
MAC: "MAC",
|
|
WINDOWS: "WINDOWS"
|
|
};
|
|
exports.getOS = function() {
|
|
if (exports.isMac) {
|
|
return exports.OS.MAC;
|
|
} else if (exports.isLinux) {
|
|
return exports.OS.LINUX;
|
|
} else {
|
|
return exports.OS.WINDOWS;
|
|
}
|
|
};
|
|
var _navigator = typeof navigator == "object" ? navigator : {};
|
|
|
|
var os = (/mac|win|linux/i.exec(_navigator.platform) || ["other"])[0].toLowerCase();
|
|
var ua = _navigator.userAgent || "";
|
|
var appName = _navigator.appName || "";
|
|
exports.isWin = (os == "win");
|
|
exports.isMac = (os == "mac");
|
|
exports.isLinux = (os == "linux");
|
|
exports.isIE =
|
|
(appName == "Microsoft Internet Explorer" || appName.indexOf("MSAppHost") >= 0)
|
|
? parseFloat((ua.match(/(?:MSIE |Trident\/[0-9]+[\.0-9]+;.*rv:)([0-9]+[\.0-9]+)/)||[])[1])
|
|
: parseFloat((ua.match(/(?:Trident\/[0-9]+[\.0-9]+;.*rv:)([0-9]+[\.0-9]+)/)||[])[1]); // for ie
|
|
|
|
exports.isOldIE = exports.isIE && exports.isIE < 9;
|
|
exports.isGecko = exports.isMozilla = ua.match(/ Gecko\/\d+/);
|
|
exports.isOpera = typeof opera == "object" && Object.prototype.toString.call(window.opera) == "[object Opera]";
|
|
exports.isWebKit = parseFloat(ua.split("WebKit/")[1]) || undefined;
|
|
|
|
exports.isChrome = parseFloat(ua.split(" Chrome/")[1]) || undefined;
|
|
|
|
exports.isEdge = parseFloat(ua.split(" Edge/")[1]) || undefined;
|
|
|
|
exports.isAIR = ua.indexOf("AdobeAIR") >= 0;
|
|
|
|
exports.isAndroid = ua.indexOf("Android") >= 0;
|
|
|
|
exports.isChromeOS = ua.indexOf(" CrOS ") >= 0;
|
|
|
|
exports.isIOS = /iPad|iPhone|iPod/.test(ua) && !window.MSStream;
|
|
|
|
if (exports.isIOS) exports.isMac = true;
|
|
|
|
exports.isMobile = exports.isIOS || exports.isAndroid;
|
|
|
|
});
|
|
|
|
ace.define("ace/lib/dom",["require","exports","module","ace/lib/useragent"], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var useragent = require("./useragent");
|
|
var XHTML_NS = "http://www.w3.org/1999/xhtml";
|
|
|
|
exports.buildDom = function buildDom(arr, parent, refs) {
|
|
if (typeof arr == "string" && arr) {
|
|
var txt = document.createTextNode(arr);
|
|
if (parent)
|
|
parent.appendChild(txt);
|
|
return txt;
|
|
}
|
|
|
|
if (!Array.isArray(arr)) {
|
|
if (arr && arr.appendChild && parent)
|
|
parent.appendChild(arr);
|
|
return arr;
|
|
}
|
|
if (typeof arr[0] != "string" || !arr[0]) {
|
|
var els = [];
|
|
for (var i = 0; i < arr.length; i++) {
|
|
var ch = buildDom(arr[i], parent, refs);
|
|
ch && els.push(ch);
|
|
}
|
|
return els;
|
|
}
|
|
|
|
var el = document.createElement(arr[0]);
|
|
var options = arr[1];
|
|
var childIndex = 1;
|
|
if (options && typeof options == "object" && !Array.isArray(options))
|
|
childIndex = 2;
|
|
for (var i = childIndex; i < arr.length; i++)
|
|
buildDom(arr[i], el, refs);
|
|
if (childIndex == 2) {
|
|
Object.keys(options).forEach(function(n) {
|
|
var val = options[n];
|
|
if (n === "class") {
|
|
el.className = Array.isArray(val) ? val.join(" ") : val;
|
|
} else if (typeof val == "function" || n == "value" || n[0] == "$") {
|
|
el[n] = val;
|
|
} else if (n === "ref") {
|
|
if (refs) refs[val] = el;
|
|
} else if (val != null) {
|
|
el.setAttribute(n, val);
|
|
}
|
|
});
|
|
}
|
|
if (parent)
|
|
parent.appendChild(el);
|
|
return el;
|
|
};
|
|
|
|
exports.getDocumentHead = function(doc) {
|
|
if (!doc)
|
|
doc = document;
|
|
return doc.head || doc.getElementsByTagName("head")[0] || doc.documentElement;
|
|
};
|
|
|
|
exports.createElement = function(tag, ns) {
|
|
return document.createElementNS ?
|
|
document.createElementNS(ns || XHTML_NS, tag) :
|
|
document.createElement(tag);
|
|
};
|
|
|
|
exports.removeChildren = function(element) {
|
|
element.innerHTML = "";
|
|
};
|
|
|
|
exports.createTextNode = function(textContent, element) {
|
|
var doc = element ? element.ownerDocument : document;
|
|
return doc.createTextNode(textContent);
|
|
};
|
|
|
|
exports.createFragment = function(element) {
|
|
var doc = element ? element.ownerDocument : document;
|
|
return doc.createDocumentFragment();
|
|
};
|
|
|
|
exports.hasCssClass = function(el, name) {
|
|
var classes = (el.className + "").split(/\s+/g);
|
|
return classes.indexOf(name) !== -1;
|
|
};
|
|
exports.addCssClass = function(el, name) {
|
|
if (!exports.hasCssClass(el, name)) {
|
|
el.className += " " + name;
|
|
}
|
|
};
|
|
exports.removeCssClass = function(el, name) {
|
|
var classes = el.className.split(/\s+/g);
|
|
while (true) {
|
|
var index = classes.indexOf(name);
|
|
if (index == -1) {
|
|
break;
|
|
}
|
|
classes.splice(index, 1);
|
|
}
|
|
el.className = classes.join(" ");
|
|
};
|
|
|
|
exports.toggleCssClass = function(el, name) {
|
|
var classes = el.className.split(/\s+/g), add = true;
|
|
while (true) {
|
|
var index = classes.indexOf(name);
|
|
if (index == -1) {
|
|
break;
|
|
}
|
|
add = false;
|
|
classes.splice(index, 1);
|
|
}
|
|
if (add)
|
|
classes.push(name);
|
|
|
|
el.className = classes.join(" ");
|
|
return add;
|
|
};
|
|
exports.setCssClass = function(node, className, include) {
|
|
if (include) {
|
|
exports.addCssClass(node, className);
|
|
} else {
|
|
exports.removeCssClass(node, className);
|
|
}
|
|
};
|
|
|
|
exports.hasCssString = function(id, doc) {
|
|
var index = 0, sheets;
|
|
doc = doc || document;
|
|
if ((sheets = doc.querySelectorAll("style"))) {
|
|
while (index < sheets.length)
|
|
if (sheets[index++].id === id)
|
|
return true;
|
|
}
|
|
};
|
|
|
|
exports.importCssString = function importCssString(cssText, id, target) {
|
|
var container = target;
|
|
if (!target || !target.getRootNode) {
|
|
container = document;
|
|
} else {
|
|
container = target.getRootNode();
|
|
if (!container || container == target)
|
|
container = document;
|
|
}
|
|
|
|
var doc = container.ownerDocument || container;
|
|
if (id && exports.hasCssString(id, container))
|
|
return null;
|
|
|
|
if (id)
|
|
cssText += "\n/*# sourceURL=ace/css/" + id + " */";
|
|
|
|
var style = exports.createElement("style");
|
|
style.appendChild(doc.createTextNode(cssText));
|
|
if (id)
|
|
style.id = id;
|
|
|
|
if (container == doc)
|
|
container = exports.getDocumentHead(doc);
|
|
container.insertBefore(style, container.firstChild);
|
|
};
|
|
|
|
exports.importCssStylsheet = function(uri, doc) {
|
|
exports.buildDom(["link", {rel: "stylesheet", href: uri}], exports.getDocumentHead(doc));
|
|
};
|
|
exports.scrollbarWidth = function(document) {
|
|
var inner = exports.createElement("ace_inner");
|
|
inner.style.width = "100%";
|
|
inner.style.minWidth = "0px";
|
|
inner.style.height = "200px";
|
|
inner.style.display = "block";
|
|
|
|
var outer = exports.createElement("ace_outer");
|
|
var style = outer.style;
|
|
|
|
style.position = "absolute";
|
|
style.left = "-10000px";
|
|
style.overflow = "hidden";
|
|
style.width = "200px";
|
|
style.minWidth = "0px";
|
|
style.height = "150px";
|
|
style.display = "block";
|
|
|
|
outer.appendChild(inner);
|
|
|
|
var body = document.documentElement;
|
|
body.appendChild(outer);
|
|
|
|
var noScrollbar = inner.offsetWidth;
|
|
|
|
style.overflow = "scroll";
|
|
var withScrollbar = inner.offsetWidth;
|
|
|
|
if (noScrollbar == withScrollbar) {
|
|
withScrollbar = outer.clientWidth;
|
|
}
|
|
|
|
body.removeChild(outer);
|
|
|
|
return noScrollbar-withScrollbar;
|
|
};
|
|
|
|
if (typeof document == "undefined") {
|
|
exports.importCssString = function() {};
|
|
}
|
|
|
|
exports.computedStyle = function(element, style) {
|
|
return window.getComputedStyle(element, "") || {};
|
|
};
|
|
|
|
exports.setStyle = function(styles, property, value) {
|
|
if (styles[property] !== value) {
|
|
styles[property] = value;
|
|
}
|
|
};
|
|
|
|
exports.HAS_CSS_ANIMATION = false;
|
|
exports.HAS_CSS_TRANSFORMS = false;
|
|
exports.HI_DPI = useragent.isWin
|
|
? typeof window !== "undefined" && window.devicePixelRatio >= 1.5
|
|
: true;
|
|
|
|
if (typeof document !== "undefined") {
|
|
var div = document.createElement("div");
|
|
if (exports.HI_DPI && div.style.transform !== undefined)
|
|
exports.HAS_CSS_TRANSFORMS = true;
|
|
if (!useragent.isEdge && typeof div.style.animationName !== "undefined")
|
|
exports.HAS_CSS_ANIMATION = true;
|
|
div = null;
|
|
}
|
|
|
|
if (exports.HAS_CSS_TRANSFORMS) {
|
|
exports.translate = function(element, tx, ty) {
|
|
element.style.transform = "translate(" + Math.round(tx) + "px, " + Math.round(ty) +"px)";
|
|
};
|
|
} else {
|
|
exports.translate = function(element, tx, ty) {
|
|
element.style.top = Math.round(ty) + "px";
|
|
element.style.left = Math.round(tx) + "px";
|
|
};
|
|
}
|
|
|
|
});
|
|
|
|
ace.define("ace/lib/oop",["require","exports","module"], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
exports.inherits = function(ctor, superCtor) {
|
|
ctor.super_ = superCtor;
|
|
ctor.prototype = Object.create(superCtor.prototype, {
|
|
constructor: {
|
|
value: ctor,
|
|
enumerable: false,
|
|
writable: true,
|
|
configurable: true
|
|
}
|
|
});
|
|
};
|
|
|
|
exports.mixin = function(obj, mixin) {
|
|
for (var key in mixin) {
|
|
obj[key] = mixin[key];
|
|
}
|
|
return obj;
|
|
};
|
|
|
|
exports.implement = function(proto, mixin) {
|
|
exports.mixin(proto, mixin);
|
|
};
|
|
|
|
});
|
|
|
|
ace.define("ace/lib/keys",["require","exports","module","ace/lib/oop"], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var oop = require("./oop");
|
|
var Keys = (function() {
|
|
var ret = {
|
|
MODIFIER_KEYS: {
|
|
16: 'Shift', 17: 'Ctrl', 18: 'Alt', 224: 'Meta',
|
|
91: 'MetaLeft', 92: 'MetaRight', 93: 'ContextMenu'
|
|
},
|
|
|
|
KEY_MODS: {
|
|
"ctrl": 1, "alt": 2, "option" : 2, "shift": 4,
|
|
"super": 8, "meta": 8, "command": 8, "cmd": 8,
|
|
"control": 1
|
|
},
|
|
|
|
FUNCTION_KEYS : {
|
|
8 : "Backspace",
|
|
9 : "Tab",
|
|
13 : "Return",
|
|
19 : "Pause",
|
|
27 : "Esc",
|
|
32 : "Space",
|
|
33 : "PageUp",
|
|
34 : "PageDown",
|
|
35 : "End",
|
|
36 : "Home",
|
|
37 : "Left",
|
|
38 : "Up",
|
|
39 : "Right",
|
|
40 : "Down",
|
|
44 : "Print",
|
|
45 : "Insert",
|
|
46 : "Delete",
|
|
96 : "Numpad0",
|
|
97 : "Numpad1",
|
|
98 : "Numpad2",
|
|
99 : "Numpad3",
|
|
100: "Numpad4",
|
|
101: "Numpad5",
|
|
102: "Numpad6",
|
|
103: "Numpad7",
|
|
104: "Numpad8",
|
|
105: "Numpad9",
|
|
'-13': "NumpadEnter",
|
|
112: "F1",
|
|
113: "F2",
|
|
114: "F3",
|
|
115: "F4",
|
|
116: "F5",
|
|
117: "F6",
|
|
118: "F7",
|
|
119: "F8",
|
|
120: "F9",
|
|
121: "F10",
|
|
122: "F11",
|
|
123: "F12",
|
|
144: "Numlock",
|
|
145: "Scrolllock"
|
|
},
|
|
|
|
PRINTABLE_KEYS: {
|
|
32: ' ', 48: '0', 49: '1', 50: '2', 51: '3', 52: '4', 53: '5',
|
|
54: '6', 55: '7', 56: '8', 57: '9', 59: ';', 61: '=', 65: 'a',
|
|
66: 'b', 67: 'c', 68: 'd', 69: 'e', 70: 'f', 71: 'g', 72: 'h',
|
|
73: 'i', 74: 'j', 75: 'k', 76: 'l', 77: 'm', 78: 'n', 79: 'o',
|
|
80: 'p', 81: 'q', 82: 'r', 83: 's', 84: 't', 85: 'u', 86: 'v',
|
|
87: 'w', 88: 'x', 89: 'y', 90: 'z', 107: '+', 109: '-', 110: '.',
|
|
186: ';', 187: '=', 188: ',', 189: '-', 190: '.', 191: '/', 192: '`',
|
|
219: '[', 220: '\\',221: ']', 222: "'", 111: '/', 106: '*'
|
|
}
|
|
};
|
|
var name, i;
|
|
for (i in ret.FUNCTION_KEYS) {
|
|
name = ret.FUNCTION_KEYS[i].toLowerCase();
|
|
ret[name] = parseInt(i, 10);
|
|
}
|
|
for (i in ret.PRINTABLE_KEYS) {
|
|
name = ret.PRINTABLE_KEYS[i].toLowerCase();
|
|
ret[name] = parseInt(i, 10);
|
|
}
|
|
oop.mixin(ret, ret.MODIFIER_KEYS);
|
|
oop.mixin(ret, ret.PRINTABLE_KEYS);
|
|
oop.mixin(ret, ret.FUNCTION_KEYS);
|
|
ret.enter = ret["return"];
|
|
ret.escape = ret.esc;
|
|
ret.del = ret["delete"];
|
|
ret[173] = '-';
|
|
|
|
(function() {
|
|
var mods = ["cmd", "ctrl", "alt", "shift"];
|
|
for (var i = Math.pow(2, mods.length); i--;) {
|
|
ret.KEY_MODS[i] = mods.filter(function(x) {
|
|
return i & ret.KEY_MODS[x];
|
|
}).join("-") + "-";
|
|
}
|
|
})();
|
|
|
|
ret.KEY_MODS[0] = "";
|
|
ret.KEY_MODS[-1] = "input-";
|
|
|
|
return ret;
|
|
})();
|
|
oop.mixin(exports, Keys);
|
|
|
|
exports.keyCodeToString = function(keyCode) {
|
|
var keyString = Keys[keyCode];
|
|
if (typeof keyString != "string")
|
|
keyString = String.fromCharCode(keyCode);
|
|
return keyString.toLowerCase();
|
|
};
|
|
|
|
});
|
|
|
|
ace.define("ace/lib/event",["require","exports","module","ace/lib/keys","ace/lib/useragent"], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var keys = require("./keys");
|
|
var useragent = require("./useragent");
|
|
|
|
var pressedKeys = null;
|
|
var ts = 0;
|
|
|
|
var activeListenerOptions;
|
|
function detectListenerOptionsSupport() {
|
|
activeListenerOptions = false;
|
|
try {
|
|
document.createComment("").addEventListener("test", function() {}, {
|
|
get passive() {
|
|
activeListenerOptions = {passive: false};
|
|
}
|
|
});
|
|
} catch(e) {}
|
|
}
|
|
|
|
function getListenerOptions() {
|
|
if (activeListenerOptions == undefined)
|
|
detectListenerOptionsSupport();
|
|
return activeListenerOptions;
|
|
}
|
|
|
|
function EventListener(elem, type, callback) {
|
|
this.elem = elem;
|
|
this.type = type;
|
|
this.callback = callback;
|
|
}
|
|
EventListener.prototype.destroy = function() {
|
|
removeListener(this.elem, this.type, this.callback);
|
|
this.elem = this.type = this.callback = undefined;
|
|
};
|
|
|
|
var addListener = exports.addListener = function(elem, type, callback, destroyer) {
|
|
elem.addEventListener(type, callback, getListenerOptions());
|
|
if (destroyer)
|
|
destroyer.$toDestroy.push(new EventListener(elem, type, callback));
|
|
};
|
|
|
|
var removeListener = exports.removeListener = function(elem, type, callback) {
|
|
elem.removeEventListener(type, callback, getListenerOptions());
|
|
};
|
|
exports.stopEvent = function(e) {
|
|
exports.stopPropagation(e);
|
|
exports.preventDefault(e);
|
|
return false;
|
|
};
|
|
|
|
exports.stopPropagation = function(e) {
|
|
if (e.stopPropagation)
|
|
e.stopPropagation();
|
|
};
|
|
|
|
exports.preventDefault = function(e) {
|
|
if (e.preventDefault)
|
|
e.preventDefault();
|
|
};
|
|
exports.getButton = function(e) {
|
|
if (e.type == "dblclick")
|
|
return 0;
|
|
if (e.type == "contextmenu" || (useragent.isMac && (e.ctrlKey && !e.altKey && !e.shiftKey)))
|
|
return 2;
|
|
return e.button;
|
|
};
|
|
|
|
exports.capture = function(el, eventHandler, releaseCaptureHandler) {
|
|
var ownerDocument = el && el.ownerDocument || document;
|
|
function onMouseUp(e) {
|
|
eventHandler && eventHandler(e);
|
|
releaseCaptureHandler && releaseCaptureHandler(e);
|
|
|
|
removeListener(ownerDocument, "mousemove", eventHandler);
|
|
removeListener(ownerDocument, "mouseup", onMouseUp);
|
|
removeListener(ownerDocument, "dragstart", onMouseUp);
|
|
}
|
|
|
|
addListener(ownerDocument, "mousemove", eventHandler);
|
|
addListener(ownerDocument, "mouseup", onMouseUp);
|
|
addListener(ownerDocument, "dragstart", onMouseUp);
|
|
|
|
return onMouseUp;
|
|
};
|
|
|
|
exports.addMouseWheelListener = function(el, callback, destroyer) {
|
|
if ("onmousewheel" in el) {
|
|
addListener(el, "mousewheel", function(e) {
|
|
var factor = 8;
|
|
if (e.wheelDeltaX !== undefined) {
|
|
e.wheelX = -e.wheelDeltaX / factor;
|
|
e.wheelY = -e.wheelDeltaY / factor;
|
|
} else {
|
|
e.wheelX = 0;
|
|
e.wheelY = -e.wheelDelta / factor;
|
|
}
|
|
callback(e);
|
|
}, destroyer);
|
|
} else if ("onwheel" in el) {
|
|
addListener(el, "wheel", function(e) {
|
|
var factor = 0.35;
|
|
switch (e.deltaMode) {
|
|
case e.DOM_DELTA_PIXEL:
|
|
e.wheelX = e.deltaX * factor || 0;
|
|
e.wheelY = e.deltaY * factor || 0;
|
|
break;
|
|
case e.DOM_DELTA_LINE:
|
|
case e.DOM_DELTA_PAGE:
|
|
e.wheelX = (e.deltaX || 0) * 5;
|
|
e.wheelY = (e.deltaY || 0) * 5;
|
|
break;
|
|
}
|
|
|
|
callback(e);
|
|
}, destroyer);
|
|
} else {
|
|
addListener(el, "DOMMouseScroll", function(e) {
|
|
if (e.axis && e.axis == e.HORIZONTAL_AXIS) {
|
|
e.wheelX = (e.detail || 0) * 5;
|
|
e.wheelY = 0;
|
|
} else {
|
|
e.wheelX = 0;
|
|
e.wheelY = (e.detail || 0) * 5;
|
|
}
|
|
callback(e);
|
|
}, destroyer);
|
|
}
|
|
};
|
|
|
|
exports.addMultiMouseDownListener = function(elements, timeouts, eventHandler, callbackName, destroyer) {
|
|
var clicks = 0;
|
|
var startX, startY, timer;
|
|
var eventNames = {
|
|
2: "dblclick",
|
|
3: "tripleclick",
|
|
4: "quadclick"
|
|
};
|
|
|
|
function onMousedown(e) {
|
|
if (exports.getButton(e) !== 0) {
|
|
clicks = 0;
|
|
} else if (e.detail > 1) {
|
|
clicks++;
|
|
if (clicks > 4)
|
|
clicks = 1;
|
|
} else {
|
|
clicks = 1;
|
|
}
|
|
if (useragent.isIE) {
|
|
var isNewClick = Math.abs(e.clientX - startX) > 5 || Math.abs(e.clientY - startY) > 5;
|
|
if (!timer || isNewClick)
|
|
clicks = 1;
|
|
if (timer)
|
|
clearTimeout(timer);
|
|
timer = setTimeout(function() {timer = null;}, timeouts[clicks - 1] || 600);
|
|
|
|
if (clicks == 1) {
|
|
startX = e.clientX;
|
|
startY = e.clientY;
|
|
}
|
|
}
|
|
|
|
e._clicks = clicks;
|
|
|
|
eventHandler[callbackName]("mousedown", e);
|
|
|
|
if (clicks > 4)
|
|
clicks = 0;
|
|
else if (clicks > 1)
|
|
return eventHandler[callbackName](eventNames[clicks], e);
|
|
}
|
|
if (!Array.isArray(elements))
|
|
elements = [elements];
|
|
elements.forEach(function(el) {
|
|
addListener(el, "mousedown", onMousedown, destroyer);
|
|
});
|
|
};
|
|
|
|
var getModifierHash = function(e) {
|
|
return 0 | (e.ctrlKey ? 1 : 0) | (e.altKey ? 2 : 0) | (e.shiftKey ? 4 : 0) | (e.metaKey ? 8 : 0);
|
|
};
|
|
|
|
exports.getModifierString = function(e) {
|
|
return keys.KEY_MODS[getModifierHash(e)];
|
|
};
|
|
|
|
function normalizeCommandKeys(callback, e, keyCode) {
|
|
var hashId = getModifierHash(e);
|
|
|
|
if (!useragent.isMac && pressedKeys) {
|
|
if (e.getModifierState && (e.getModifierState("OS") || e.getModifierState("Win")))
|
|
hashId |= 8;
|
|
if (pressedKeys.altGr) {
|
|
if ((3 & hashId) != 3)
|
|
pressedKeys.altGr = 0;
|
|
else
|
|
return;
|
|
}
|
|
if (keyCode === 18 || keyCode === 17) {
|
|
var location = "location" in e ? e.location : e.keyLocation;
|
|
if (keyCode === 17 && location === 1) {
|
|
if (pressedKeys[keyCode] == 1)
|
|
ts = e.timeStamp;
|
|
} else if (keyCode === 18 && hashId === 3 && location === 2) {
|
|
var dt = e.timeStamp - ts;
|
|
if (dt < 50)
|
|
pressedKeys.altGr = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (keyCode in keys.MODIFIER_KEYS) {
|
|
keyCode = -1;
|
|
}
|
|
|
|
if (!hashId && keyCode === 13) {
|
|
var location = "location" in e ? e.location : e.keyLocation;
|
|
if (location === 3) {
|
|
callback(e, hashId, -keyCode);
|
|
if (e.defaultPrevented)
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (useragent.isChromeOS && hashId & 8) {
|
|
callback(e, hashId, keyCode);
|
|
if (e.defaultPrevented)
|
|
return;
|
|
else
|
|
hashId &= ~8;
|
|
}
|
|
if (!hashId && !(keyCode in keys.FUNCTION_KEYS) && !(keyCode in keys.PRINTABLE_KEYS)) {
|
|
return false;
|
|
}
|
|
|
|
return callback(e, hashId, keyCode);
|
|
}
|
|
|
|
|
|
exports.addCommandKeyListener = function(el, callback, destroyer) {
|
|
if (useragent.isOldGecko || (useragent.isOpera && !("KeyboardEvent" in window))) {
|
|
var lastKeyDownKeyCode = null;
|
|
addListener(el, "keydown", function(e) {
|
|
lastKeyDownKeyCode = e.keyCode;
|
|
}, destroyer);
|
|
addListener(el, "keypress", function(e) {
|
|
return normalizeCommandKeys(callback, e, lastKeyDownKeyCode);
|
|
}, destroyer);
|
|
} else {
|
|
var lastDefaultPrevented = null;
|
|
|
|
addListener(el, "keydown", function(e) {
|
|
pressedKeys[e.keyCode] = (pressedKeys[e.keyCode] || 0) + 1;
|
|
var result = normalizeCommandKeys(callback, e, e.keyCode);
|
|
lastDefaultPrevented = e.defaultPrevented;
|
|
return result;
|
|
}, destroyer);
|
|
|
|
addListener(el, "keypress", function(e) {
|
|
if (lastDefaultPrevented && (e.ctrlKey || e.altKey || e.shiftKey || e.metaKey)) {
|
|
exports.stopEvent(e);
|
|
lastDefaultPrevented = null;
|
|
}
|
|
}, destroyer);
|
|
|
|
addListener(el, "keyup", function(e) {
|
|
pressedKeys[e.keyCode] = null;
|
|
}, destroyer);
|
|
|
|
if (!pressedKeys) {
|
|
resetPressedKeys();
|
|
addListener(window, "focus", resetPressedKeys);
|
|
}
|
|
}
|
|
};
|
|
function resetPressedKeys() {
|
|
pressedKeys = Object.create(null);
|
|
}
|
|
|
|
if (typeof window == "object" && window.postMessage && !useragent.isOldIE) {
|
|
var postMessageId = 1;
|
|
exports.nextTick = function(callback, win) {
|
|
win = win || window;
|
|
var messageName = "zero-timeout-message-" + (postMessageId++);
|
|
|
|
var listener = function(e) {
|
|
if (e.data == messageName) {
|
|
exports.stopPropagation(e);
|
|
removeListener(win, "message", listener);
|
|
callback();
|
|
}
|
|
};
|
|
|
|
addListener(win, "message", listener);
|
|
win.postMessage(messageName, "*");
|
|
};
|
|
}
|
|
|
|
exports.$idleBlocked = false;
|
|
exports.onIdle = function(cb, timeout) {
|
|
return setTimeout(function handler() {
|
|
if (!exports.$idleBlocked) {
|
|
cb();
|
|
} else {
|
|
setTimeout(handler, 100);
|
|
}
|
|
}, timeout);
|
|
};
|
|
|
|
exports.$idleBlockId = null;
|
|
exports.blockIdle = function(delay) {
|
|
if (exports.$idleBlockId)
|
|
clearTimeout(exports.$idleBlockId);
|
|
|
|
exports.$idleBlocked = true;
|
|
exports.$idleBlockId = setTimeout(function() {
|
|
exports.$idleBlocked = false;
|
|
}, delay || 100);
|
|
};
|
|
|
|
exports.nextFrame = typeof window == "object" && (window.requestAnimationFrame
|
|
|| window.mozRequestAnimationFrame
|
|
|| window.webkitRequestAnimationFrame
|
|
|| window.msRequestAnimationFrame
|
|
|| window.oRequestAnimationFrame);
|
|
|
|
if (exports.nextFrame)
|
|
exports.nextFrame = exports.nextFrame.bind(window);
|
|
else
|
|
exports.nextFrame = function(callback) {
|
|
setTimeout(callback, 17);
|
|
};
|
|
});
|
|
|
|
ace.define("ace/range",["require","exports","module"], function(require, exports, module) {
|
|
"use strict";
|
|
var comparePoints = function(p1, p2) {
|
|
return p1.row - p2.row || p1.column - p2.column;
|
|
};
|
|
var Range = function(startRow, startColumn, endRow, endColumn) {
|
|
this.start = {
|
|
row: startRow,
|
|
column: startColumn
|
|
};
|
|
|
|
this.end = {
|
|
row: endRow,
|
|
column: endColumn
|
|
};
|
|
};
|
|
|
|
(function() {
|
|
this.isEqual = function(range) {
|
|
return this.start.row === range.start.row &&
|
|
this.end.row === range.end.row &&
|
|
this.start.column === range.start.column &&
|
|
this.end.column === range.end.column;
|
|
};
|
|
this.toString = function() {
|
|
return ("Range: [" + this.start.row + "/" + this.start.column +
|
|
"] -> [" + this.end.row + "/" + this.end.column + "]");
|
|
};
|
|
|
|
this.contains = function(row, column) {
|
|
return this.compare(row, column) == 0;
|
|
};
|
|
this.compareRange = function(range) {
|
|
var cmp,
|
|
end = range.end,
|
|
start = range.start;
|
|
|
|
cmp = this.compare(end.row, end.column);
|
|
if (cmp == 1) {
|
|
cmp = this.compare(start.row, start.column);
|
|
if (cmp == 1) {
|
|
return 2;
|
|
} else if (cmp == 0) {
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
} else if (cmp == -1) {
|
|
return -2;
|
|
} else {
|
|
cmp = this.compare(start.row, start.column);
|
|
if (cmp == -1) {
|
|
return -1;
|
|
} else if (cmp == 1) {
|
|
return 42;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
};
|
|
this.comparePoint = function(p) {
|
|
return this.compare(p.row, p.column);
|
|
};
|
|
this.containsRange = function(range) {
|
|
return this.comparePoint(range.start) == 0 && this.comparePoint(range.end) == 0;
|
|
};
|
|
this.intersects = function(range) {
|
|
var cmp = this.compareRange(range);
|
|
return (cmp == -1 || cmp == 0 || cmp == 1);
|
|
};
|
|
this.isEnd = function(row, column) {
|
|
return this.end.row == row && this.end.column == column;
|
|
};
|
|
this.isStart = function(row, column) {
|
|
return this.start.row == row && this.start.column == column;
|
|
};
|
|
this.setStart = function(row, column) {
|
|
if (typeof row == "object") {
|
|
this.start.column = row.column;
|
|
this.start.row = row.row;
|
|
} else {
|
|
this.start.row = row;
|
|
this.start.column = column;
|
|
}
|
|
};
|
|
this.setEnd = function(row, column) {
|
|
if (typeof row == "object") {
|
|
this.end.column = row.column;
|
|
this.end.row = row.row;
|
|
} else {
|
|
this.end.row = row;
|
|
this.end.column = column;
|
|
}
|
|
};
|
|
this.inside = function(row, column) {
|
|
if (this.compare(row, column) == 0) {
|
|
if (this.isEnd(row, column) || this.isStart(row, column)) {
|
|
return false;
|
|
} else {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
this.insideStart = function(row, column) {
|
|
if (this.compare(row, column) == 0) {
|
|
if (this.isEnd(row, column)) {
|
|
return false;
|
|
} else {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
this.insideEnd = function(row, column) {
|
|
if (this.compare(row, column) == 0) {
|
|
if (this.isStart(row, column)) {
|
|
return false;
|
|
} else {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
this.compare = function(row, column) {
|
|
if (!this.isMultiLine()) {
|
|
if (row === this.start.row) {
|
|
return column < this.start.column ? -1 : (column > this.end.column ? 1 : 0);
|
|
}
|
|
}
|
|
|
|
if (row < this.start.row)
|
|
return -1;
|
|
|
|
if (row > this.end.row)
|
|
return 1;
|
|
|
|
if (this.start.row === row)
|
|
return column >= this.start.column ? 0 : -1;
|
|
|
|
if (this.end.row === row)
|
|
return column <= this.end.column ? 0 : 1;
|
|
|
|
return 0;
|
|
};
|
|
this.compareStart = function(row, column) {
|
|
if (this.start.row == row && this.start.column == column) {
|
|
return -1;
|
|
} else {
|
|
return this.compare(row, column);
|
|
}
|
|
};
|
|
this.compareEnd = function(row, column) {
|
|
if (this.end.row == row && this.end.column == column) {
|
|
return 1;
|
|
} else {
|
|
return this.compare(row, column);
|
|
}
|
|
};
|
|
this.compareInside = function(row, column) {
|
|
if (this.end.row == row && this.end.column == column) {
|
|
return 1;
|
|
} else if (this.start.row == row && this.start.column == column) {
|
|
return -1;
|
|
} else {
|
|
return this.compare(row, column);
|
|
}
|
|
};
|
|
this.clipRows = function(firstRow, lastRow) {
|
|
if (this.end.row > lastRow)
|
|
var end = {row: lastRow + 1, column: 0};
|
|
else if (this.end.row < firstRow)
|
|
var end = {row: firstRow, column: 0};
|
|
|
|
if (this.start.row > lastRow)
|
|
var start = {row: lastRow + 1, column: 0};
|
|
else if (this.start.row < firstRow)
|
|
var start = {row: firstRow, column: 0};
|
|
|
|
return Range.fromPoints(start || this.start, end || this.end);
|
|
};
|
|
this.extend = function(row, column) {
|
|
var cmp = this.compare(row, column);
|
|
|
|
if (cmp == 0)
|
|
return this;
|
|
else if (cmp == -1)
|
|
var start = {row: row, column: column};
|
|
else
|
|
var end = {row: row, column: column};
|
|
|
|
return Range.fromPoints(start || this.start, end || this.end);
|
|
};
|
|
|
|
this.isEmpty = function() {
|
|
return (this.start.row === this.end.row && this.start.column === this.end.column);
|
|
};
|
|
this.isMultiLine = function() {
|
|
return (this.start.row !== this.end.row);
|
|
};
|
|
this.clone = function() {
|
|
return Range.fromPoints(this.start, this.end);
|
|
};
|
|
this.collapseRows = function() {
|
|
if (this.end.column == 0)
|
|
return new Range(this.start.row, 0, Math.max(this.start.row, this.end.row-1), 0);
|
|
else
|
|
return new Range(this.start.row, 0, this.end.row, 0);
|
|
};
|
|
this.toScreenRange = function(session) {
|
|
var screenPosStart = session.documentToScreenPosition(this.start);
|
|
var screenPosEnd = session.documentToScreenPosition(this.end);
|
|
|
|
return new Range(
|
|
screenPosStart.row, screenPosStart.column,
|
|
screenPosEnd.row, screenPosEnd.column
|
|
);
|
|
};
|
|
this.moveBy = function(row, column) {
|
|
this.start.row += row;
|
|
this.start.column += column;
|
|
this.end.row += row;
|
|
this.end.column += column;
|
|
};
|
|
|
|
}).call(Range.prototype);
|
|
Range.fromPoints = function(start, end) {
|
|
return new Range(start.row, start.column, end.row, end.column);
|
|
};
|
|
Range.comparePoints = comparePoints;
|
|
|
|
Range.comparePoints = function(p1, p2) {
|
|
return p1.row - p2.row || p1.column - p2.column;
|
|
};
|
|
|
|
|
|
exports.Range = Range;
|
|
});
|
|
|
|
ace.define("ace/lib/lang",["require","exports","module"], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
exports.last = function(a) {
|
|
return a[a.length - 1];
|
|
};
|
|
|
|
exports.stringReverse = function(string) {
|
|
return string.split("").reverse().join("");
|
|
};
|
|
|
|
exports.stringRepeat = function (string, count) {
|
|
var result = '';
|
|
while (count > 0) {
|
|
if (count & 1)
|
|
result += string;
|
|
|
|
if (count >>= 1)
|
|
string += string;
|
|
}
|
|
return result;
|
|
};
|
|
|
|
var trimBeginRegexp = /^\s\s*/;
|
|
var trimEndRegexp = /\s\s*$/;
|
|
|
|
exports.stringTrimLeft = function (string) {
|
|
return string.replace(trimBeginRegexp, '');
|
|
};
|
|
|
|
exports.stringTrimRight = function (string) {
|
|
return string.replace(trimEndRegexp, '');
|
|
};
|
|
|
|
exports.copyObject = function(obj) {
|
|
var copy = {};
|
|
for (var key in obj) {
|
|
copy[key] = obj[key];
|
|
}
|
|
return copy;
|
|
};
|
|
|
|
exports.copyArray = function(array){
|
|
var copy = [];
|
|
for (var i=0, l=array.length; i<l; i++) {
|
|
if (array[i] && typeof array[i] == "object")
|
|
copy[i] = this.copyObject(array[i]);
|
|
else
|
|
copy[i] = array[i];
|
|
}
|
|
return copy;
|
|
};
|
|
|
|
exports.deepCopy = function deepCopy(obj) {
|
|
if (typeof obj !== "object" || !obj)
|
|
return obj;
|
|
var copy;
|
|
if (Array.isArray(obj)) {
|
|
copy = [];
|
|
for (var key = 0; key < obj.length; key++) {
|
|
copy[key] = deepCopy(obj[key]);
|
|
}
|
|
return copy;
|
|
}
|
|
if (Object.prototype.toString.call(obj) !== "[object Object]")
|
|
return obj;
|
|
|
|
copy = {};
|
|
for (var key in obj)
|
|
copy[key] = deepCopy(obj[key]);
|
|
return copy;
|
|
};
|
|
|
|
exports.arrayToMap = function(arr) {
|
|
var map = {};
|
|
for (var i=0; i<arr.length; i++) {
|
|
map[arr[i]] = 1;
|
|
}
|
|
return map;
|
|
|
|
};
|
|
|
|
exports.createMap = function(props) {
|
|
var map = Object.create(null);
|
|
for (var i in props) {
|
|
map[i] = props[i];
|
|
}
|
|
return map;
|
|
};
|
|
exports.arrayRemove = function(array, value) {
|
|
for (var i = 0; i <= array.length; i++) {
|
|
if (value === array[i]) {
|
|
array.splice(i, 1);
|
|
}
|
|
}
|
|
};
|
|
|
|
exports.escapeRegExp = function(str) {
|
|
return str.replace(/([.*+?^${}()|[\]\/\\])/g, '\\$1');
|
|
};
|
|
|
|
exports.escapeHTML = function(str) {
|
|
return ("" + str).replace(/&/g, "&").replace(/"/g, """).replace(/'/g, "'").replace(/</g, "<");
|
|
};
|
|
|
|
exports.getMatchOffsets = function(string, regExp) {
|
|
var matches = [];
|
|
|
|
string.replace(regExp, function(str) {
|
|
matches.push({
|
|
offset: arguments[arguments.length-2],
|
|
length: str.length
|
|
});
|
|
});
|
|
|
|
return matches;
|
|
};
|
|
exports.deferredCall = function(fcn) {
|
|
var timer = null;
|
|
var callback = function() {
|
|
timer = null;
|
|
fcn();
|
|
};
|
|
|
|
var deferred = function(timeout) {
|
|
deferred.cancel();
|
|
timer = setTimeout(callback, timeout || 0);
|
|
return deferred;
|
|
};
|
|
|
|
deferred.schedule = deferred;
|
|
|
|
deferred.call = function() {
|
|
this.cancel();
|
|
fcn();
|
|
return deferred;
|
|
};
|
|
|
|
deferred.cancel = function() {
|
|
clearTimeout(timer);
|
|
timer = null;
|
|
return deferred;
|
|
};
|
|
|
|
deferred.isPending = function() {
|
|
return timer;
|
|
};
|
|
|
|
return deferred;
|
|
};
|
|
|
|
|
|
exports.delayedCall = function(fcn, defaultTimeout) {
|
|
var timer = null;
|
|
var callback = function() {
|
|
timer = null;
|
|
fcn();
|
|
};
|
|
|
|
var _self = function(timeout) {
|
|
if (timer == null)
|
|
timer = setTimeout(callback, timeout || defaultTimeout);
|
|
};
|
|
|
|
_self.delay = function(timeout) {
|
|
timer && clearTimeout(timer);
|
|
timer = setTimeout(callback, timeout || defaultTimeout);
|
|
};
|
|
_self.schedule = _self;
|
|
|
|
_self.call = function() {
|
|
this.cancel();
|
|
fcn();
|
|
};
|
|
|
|
_self.cancel = function() {
|
|
timer && clearTimeout(timer);
|
|
timer = null;
|
|
};
|
|
|
|
_self.isPending = function() {
|
|
return timer;
|
|
};
|
|
|
|
return _self;
|
|
};
|
|
});
|
|
|
|
ace.define("ace/clipboard",["require","exports","module"], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var $cancelT;
|
|
module.exports = {
|
|
lineMode: false,
|
|
pasteCancelled: function() {
|
|
if ($cancelT && $cancelT > Date.now() - 50)
|
|
return true;
|
|
return $cancelT = false;
|
|
},
|
|
cancel: function() {
|
|
$cancelT = Date.now();
|
|
}
|
|
};
|
|
|
|
});
|
|
|
|
ace.define("ace/keyboard/textinput",["require","exports","module","ace/lib/event","ace/lib/useragent","ace/lib/dom","ace/lib/lang","ace/clipboard","ace/lib/keys"], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var event = require("../lib/event");
|
|
var useragent = require("../lib/useragent");
|
|
var dom = require("../lib/dom");
|
|
var lang = require("../lib/lang");
|
|
var clipboard = require("../clipboard");
|
|
var BROKEN_SETDATA = useragent.isChrome < 18;
|
|
var USE_IE_MIME_TYPE = useragent.isIE;
|
|
var HAS_FOCUS_ARGS = useragent.isChrome > 63;
|
|
var MAX_LINE_LENGTH = 400;
|
|
|
|
var KEYS = require("../lib/keys");
|
|
var MODS = KEYS.KEY_MODS;
|
|
var isIOS = useragent.isIOS;
|
|
var valueResetRegex = isIOS ? /\s/ : /\n/;
|
|
var isMobile = useragent.isMobile;
|
|
|
|
var TextInput = function(parentNode, host) {
|
|
var text = dom.createElement("textarea");
|
|
text.className = "ace_text-input";
|
|
|
|
text.setAttribute("wrap", "off");
|
|
text.setAttribute("autocorrect", "off");
|
|
text.setAttribute("autocapitalize", "off");
|
|
text.setAttribute("spellcheck", false);
|
|
|
|
text.style.opacity = "0";
|
|
parentNode.insertBefore(text, parentNode.firstChild);
|
|
|
|
var copied = false;
|
|
var pasted = false;
|
|
var inComposition = false;
|
|
var sendingText = false;
|
|
var tempStyle = '';
|
|
|
|
if (!isMobile)
|
|
text.style.fontSize = "1px";
|
|
|
|
var commandMode = false;
|
|
var ignoreFocusEvents = false;
|
|
|
|
var lastValue = "";
|
|
var lastSelectionStart = 0;
|
|
var lastSelectionEnd = 0;
|
|
var lastRestoreEnd = 0;
|
|
try { var isFocused = document.activeElement === text; } catch(e) {}
|
|
|
|
event.addListener(text, "blur", function(e) {
|
|
if (ignoreFocusEvents) return;
|
|
host.onBlur(e);
|
|
isFocused = false;
|
|
}, host);
|
|
event.addListener(text, "focus", function(e) {
|
|
if (ignoreFocusEvents) return;
|
|
isFocused = true;
|
|
if (useragent.isEdge) {
|
|
try {
|
|
if (!document.hasFocus())
|
|
return;
|
|
} catch(e) {}
|
|
}
|
|
host.onFocus(e);
|
|
if (useragent.isEdge)
|
|
setTimeout(resetSelection);
|
|
else
|
|
resetSelection();
|
|
}, host);
|
|
this.$focusScroll = false;
|
|
this.focus = function() {
|
|
if (tempStyle || HAS_FOCUS_ARGS || this.$focusScroll == "browser")
|
|
return text.focus({ preventScroll: true });
|
|
|
|
var top = text.style.top;
|
|
text.style.position = "fixed";
|
|
text.style.top = "0px";
|
|
try {
|
|
var isTransformed = text.getBoundingClientRect().top != 0;
|
|
} catch(e) {
|
|
return;
|
|
}
|
|
var ancestors = [];
|
|
if (isTransformed) {
|
|
var t = text.parentElement;
|
|
while (t && t.nodeType == 1) {
|
|
ancestors.push(t);
|
|
t.setAttribute("ace_nocontext", true);
|
|
if (!t.parentElement && t.getRootNode)
|
|
t = t.getRootNode().host;
|
|
else
|
|
t = t.parentElement;
|
|
}
|
|
}
|
|
text.focus({ preventScroll: true });
|
|
if (isTransformed) {
|
|
ancestors.forEach(function(p) {
|
|
p.removeAttribute("ace_nocontext");
|
|
});
|
|
}
|
|
setTimeout(function() {
|
|
text.style.position = "";
|
|
if (text.style.top == "0px")
|
|
text.style.top = top;
|
|
}, 0);
|
|
};
|
|
this.blur = function() {
|
|
text.blur();
|
|
};
|
|
this.isFocused = function() {
|
|
return isFocused;
|
|
};
|
|
|
|
host.on("beforeEndOperation", function() {
|
|
var curOp = host.curOp;
|
|
var commandName = curOp && curOp.command && curOp.command.name;
|
|
if (commandName == "insertstring")
|
|
return;
|
|
var isUserAction = commandName && (curOp.docChanged || curOp.selectionChanged);
|
|
if (inComposition && isUserAction) {
|
|
lastValue = text.value = "";
|
|
onCompositionEnd();
|
|
}
|
|
resetSelection();
|
|
});
|
|
|
|
var resetSelection = isIOS
|
|
? function(value) {
|
|
if (!isFocused || (copied && !value) || sendingText) return;
|
|
if (!value)
|
|
value = "";
|
|
var newValue = "\n ab" + value + "cde fg\n";
|
|
if (newValue != text.value)
|
|
text.value = lastValue = newValue;
|
|
|
|
var selectionStart = 4;
|
|
var selectionEnd = 4 + (value.length || (host.selection.isEmpty() ? 0 : 1));
|
|
|
|
if (lastSelectionStart != selectionStart || lastSelectionEnd != selectionEnd) {
|
|
text.setSelectionRange(selectionStart, selectionEnd);
|
|
}
|
|
lastSelectionStart = selectionStart;
|
|
lastSelectionEnd = selectionEnd;
|
|
}
|
|
: function() {
|
|
if (inComposition || sendingText)
|
|
return;
|
|
if (!isFocused && !afterContextMenu)
|
|
return;
|
|
inComposition = true;
|
|
|
|
var selectionStart = 0;
|
|
var selectionEnd = 0;
|
|
var line = "";
|
|
|
|
if (host.session) {
|
|
var selection = host.selection;
|
|
var range = selection.getRange();
|
|
var row = selection.cursor.row;
|
|
selectionStart = range.start.column;
|
|
selectionEnd = range.end.column;
|
|
line = host.session.getLine(row);
|
|
|
|
if (range.start.row != row) {
|
|
var prevLine = host.session.getLine(row - 1);
|
|
selectionStart = range.start.row < row - 1 ? 0 : selectionStart;
|
|
selectionEnd += prevLine.length + 1;
|
|
line = prevLine + "\n" + line;
|
|
}
|
|
else if (range.end.row != row) {
|
|
var nextLine = host.session.getLine(row + 1);
|
|
selectionEnd = range.end.row > row + 1 ? nextLine.length : selectionEnd;
|
|
selectionEnd += line.length + 1;
|
|
line = line + "\n" + nextLine;
|
|
}
|
|
else if (isMobile && row > 0) {
|
|
line = "\n" + line;
|
|
selectionEnd += 1;
|
|
selectionStart += 1;
|
|
}
|
|
|
|
if (line.length > MAX_LINE_LENGTH) {
|
|
if (selectionStart < MAX_LINE_LENGTH && selectionEnd < MAX_LINE_LENGTH) {
|
|
line = line.slice(0, MAX_LINE_LENGTH);
|
|
} else {
|
|
line = "\n";
|
|
if (selectionStart == selectionEnd) {
|
|
selectionStart = selectionEnd = 0;
|
|
}
|
|
else {
|
|
selectionStart = 0;
|
|
selectionEnd = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
var newValue = line + "\n\n";
|
|
if (newValue != lastValue) {
|
|
text.value = lastValue = newValue;
|
|
lastSelectionStart = lastSelectionEnd = newValue.length;
|
|
}
|
|
if (afterContextMenu) {
|
|
lastSelectionStart = text.selectionStart;
|
|
lastSelectionEnd = text.selectionEnd;
|
|
}
|
|
if (
|
|
lastSelectionEnd != selectionEnd
|
|
|| lastSelectionStart != selectionStart
|
|
|| text.selectionEnd != lastSelectionEnd // on ie edge selectionEnd changes silently after the initialization
|
|
) {
|
|
try {
|
|
text.setSelectionRange(selectionStart, selectionEnd);
|
|
lastSelectionStart = selectionStart;
|
|
lastSelectionEnd = selectionEnd;
|
|
} catch(e){}
|
|
}
|
|
inComposition = false;
|
|
};
|
|
this.resetSelection = resetSelection;
|
|
|
|
if (isFocused)
|
|
host.onFocus();
|
|
|
|
|
|
var isAllSelected = function(text) {
|
|
return text.selectionStart === 0 && text.selectionEnd >= lastValue.length
|
|
&& text.value === lastValue && lastValue
|
|
&& text.selectionEnd !== lastSelectionEnd;
|
|
};
|
|
|
|
var onSelect = function(e) {
|
|
if (inComposition)
|
|
return;
|
|
if (copied) {
|
|
copied = false;
|
|
} else if (isAllSelected(text)) {
|
|
host.selectAll();
|
|
resetSelection();
|
|
} else if (isMobile && text.selectionStart != lastSelectionStart) {
|
|
resetSelection();
|
|
}
|
|
};
|
|
|
|
var inputHandler = null;
|
|
this.setInputHandler = function(cb) {inputHandler = cb;};
|
|
this.getInputHandler = function() {return inputHandler;};
|
|
var afterContextMenu = false;
|
|
|
|
var sendText = function(value, fromInput) {
|
|
if (afterContextMenu)
|
|
afterContextMenu = false;
|
|
if (pasted) {
|
|
resetSelection();
|
|
if (value)
|
|
host.onPaste(value);
|
|
pasted = false;
|
|
return "";
|
|
} else {
|
|
var selectionStart = text.selectionStart;
|
|
var selectionEnd = text.selectionEnd;
|
|
|
|
var extendLeft = lastSelectionStart;
|
|
var extendRight = lastValue.length - lastSelectionEnd;
|
|
|
|
var inserted = value;
|
|
var restoreStart = value.length - selectionStart;
|
|
var restoreEnd = value.length - selectionEnd;
|
|
|
|
var i = 0;
|
|
while (extendLeft > 0 && lastValue[i] == value[i]) {
|
|
i++;
|
|
extendLeft--;
|
|
}
|
|
inserted = inserted.slice(i);
|
|
i = 1;
|
|
while (extendRight > 0 && lastValue.length - i > lastSelectionStart - 1 && lastValue[lastValue.length - i] == value[value.length - i]) {
|
|
i++;
|
|
extendRight--;
|
|
}
|
|
restoreStart -= i-1;
|
|
restoreEnd -= i-1;
|
|
var endIndex = inserted.length - i + 1;
|
|
if (endIndex < 0) {
|
|
extendLeft = -endIndex;
|
|
endIndex = 0;
|
|
}
|
|
inserted = inserted.slice(0, endIndex);
|
|
if (!fromInput && !inserted && !restoreStart && !extendLeft && !extendRight && !restoreEnd)
|
|
return "";
|
|
sendingText = true;
|
|
var shouldReset = false;
|
|
if (useragent.isAndroid && inserted == ". ") {
|
|
inserted = " ";
|
|
shouldReset = true;
|
|
}
|
|
|
|
if (inserted && !extendLeft && !extendRight && !restoreStart && !restoreEnd || commandMode) {
|
|
host.onTextInput(inserted);
|
|
} else {
|
|
host.onTextInput(inserted, {
|
|
extendLeft: extendLeft,
|
|
extendRight: extendRight,
|
|
restoreStart: restoreStart,
|
|
restoreEnd: restoreEnd
|
|
});
|
|
}
|
|
sendingText = false;
|
|
|
|
lastValue = value;
|
|
lastSelectionStart = selectionStart;
|
|
lastSelectionEnd = selectionEnd;
|
|
lastRestoreEnd = restoreEnd;
|
|
return shouldReset ? "\n" : inserted;
|
|
}
|
|
};
|
|
var onInput = function(e) {
|
|
if (inComposition)
|
|
return onCompositionUpdate();
|
|
if (e && e.inputType) {
|
|
if (e.inputType == "historyUndo") return host.execCommand("undo");
|
|
if (e.inputType == "historyRedo") return host.execCommand("redo");
|
|
}
|
|
var data = text.value;
|
|
var inserted = sendText(data, true);
|
|
if (
|
|
data.length > MAX_LINE_LENGTH + 100
|
|
|| valueResetRegex.test(inserted)
|
|
|| isMobile && lastSelectionStart < 1 && lastSelectionStart == lastSelectionEnd
|
|
) {
|
|
resetSelection();
|
|
}
|
|
};
|
|
|
|
var handleClipboardData = function(e, data, forceIEMime) {
|
|
var clipboardData = e.clipboardData || window.clipboardData;
|
|
if (!clipboardData || BROKEN_SETDATA)
|
|
return;
|
|
var mime = USE_IE_MIME_TYPE || forceIEMime ? "Text" : "text/plain";
|
|
try {
|
|
if (data) {
|
|
return clipboardData.setData(mime, data) !== false;
|
|
} else {
|
|
return clipboardData.getData(mime);
|
|
}
|
|
} catch(e) {
|
|
if (!forceIEMime)
|
|
return handleClipboardData(e, data, true);
|
|
}
|
|
};
|
|
|
|
var doCopy = function(e, isCut) {
|
|
var data = host.getCopyText();
|
|
if (!data)
|
|
return event.preventDefault(e);
|
|
|
|
if (handleClipboardData(e, data)) {
|
|
if (isIOS) {
|
|
resetSelection(data);
|
|
copied = data;
|
|
setTimeout(function () {
|
|
copied = false;
|
|
}, 10);
|
|
}
|
|
isCut ? host.onCut() : host.onCopy();
|
|
event.preventDefault(e);
|
|
} else {
|
|
copied = true;
|
|
text.value = data;
|
|
text.select();
|
|
setTimeout(function(){
|
|
copied = false;
|
|
resetSelection();
|
|
isCut ? host.onCut() : host.onCopy();
|
|
});
|
|
}
|
|
};
|
|
|
|
var onCut = function(e) {
|
|
doCopy(e, true);
|
|
};
|
|
|
|
var onCopy = function(e) {
|
|
doCopy(e, false);
|
|
};
|
|
|
|
var onPaste = function(e) {
|
|
var data = handleClipboardData(e);
|
|
if (clipboard.pasteCancelled())
|
|
return;
|
|
if (typeof data == "string") {
|
|
if (data)
|
|
host.onPaste(data, e);
|
|
if (useragent.isIE)
|
|
setTimeout(resetSelection);
|
|
event.preventDefault(e);
|
|
}
|
|
else {
|
|
text.value = "";
|
|
pasted = true;
|
|
}
|
|
};
|
|
|
|
event.addCommandKeyListener(text, host.onCommandKey.bind(host), host);
|
|
|
|
event.addListener(text, "select", onSelect, host);
|
|
event.addListener(text, "input", onInput, host);
|
|
|
|
event.addListener(text, "cut", onCut, host);
|
|
event.addListener(text, "copy", onCopy, host);
|
|
event.addListener(text, "paste", onPaste, host);
|
|
if (!('oncut' in text) || !('oncopy' in text) || !('onpaste' in text)) {
|
|
event.addListener(parentNode, "keydown", function(e) {
|
|
if ((useragent.isMac && !e.metaKey) || !e.ctrlKey)
|
|
return;
|
|
|
|
switch (e.keyCode) {
|
|
case 67:
|
|
onCopy(e);
|
|
break;
|
|
case 86:
|
|
onPaste(e);
|
|
break;
|
|
case 88:
|
|
onCut(e);
|
|
break;
|
|
}
|
|
}, host);
|
|
}
|
|
var onCompositionStart = function(e) {
|
|
if (inComposition || !host.onCompositionStart || host.$readOnly)
|
|
return;
|
|
|
|
inComposition = {};
|
|
|
|
if (commandMode)
|
|
return;
|
|
|
|
if (e.data)
|
|
inComposition.useTextareaForIME = false;
|
|
|
|
setTimeout(onCompositionUpdate, 0);
|
|
host._signal("compositionStart");
|
|
host.on("mousedown", cancelComposition);
|
|
|
|
var range = host.getSelectionRange();
|
|
range.end.row = range.start.row;
|
|
range.end.column = range.start.column;
|
|
inComposition.markerRange = range;
|
|
inComposition.selectionStart = lastSelectionStart;
|
|
host.onCompositionStart(inComposition);
|
|
|
|
if (inComposition.useTextareaForIME) {
|
|
lastValue = text.value = "";
|
|
lastSelectionStart = 0;
|
|
lastSelectionEnd = 0;
|
|
}
|
|
else {
|
|
if (text.msGetInputContext)
|
|
inComposition.context = text.msGetInputContext();
|
|
if (text.getInputContext)
|
|
inComposition.context = text.getInputContext();
|
|
}
|
|
};
|
|
|
|
var onCompositionUpdate = function() {
|
|
if (!inComposition || !host.onCompositionUpdate || host.$readOnly)
|
|
return;
|
|
if (commandMode)
|
|
return cancelComposition();
|
|
|
|
if (inComposition.useTextareaForIME) {
|
|
host.onCompositionUpdate(text.value);
|
|
}
|
|
else {
|
|
var data = text.value;
|
|
sendText(data);
|
|
if (inComposition.markerRange) {
|
|
if (inComposition.context) {
|
|
inComposition.markerRange.start.column = inComposition.selectionStart
|
|
= inComposition.context.compositionStartOffset;
|
|
}
|
|
inComposition.markerRange.end.column = inComposition.markerRange.start.column
|
|
+ lastSelectionEnd - inComposition.selectionStart + lastRestoreEnd;
|
|
}
|
|
}
|
|
};
|
|
|
|
var onCompositionEnd = function(e) {
|
|
if (!host.onCompositionEnd || host.$readOnly) return;
|
|
inComposition = false;
|
|
host.onCompositionEnd();
|
|
host.off("mousedown", cancelComposition);
|
|
if (e) onInput();
|
|
};
|
|
|
|
|
|
function cancelComposition() {
|
|
ignoreFocusEvents = true;
|
|
text.blur();
|
|
text.focus();
|
|
ignoreFocusEvents = false;
|
|
}
|
|
|
|
var syncComposition = lang.delayedCall(onCompositionUpdate, 50).schedule.bind(null, null);
|
|
|
|
function onKeyup(e) {
|
|
if (e.keyCode == 27 && text.value.length < text.selectionStart) {
|
|
if (!inComposition)
|
|
lastValue = text.value;
|
|
lastSelectionStart = lastSelectionEnd = -1;
|
|
resetSelection();
|
|
}
|
|
syncComposition();
|
|
}
|
|
|
|
event.addListener(text, "compositionstart", onCompositionStart, host);
|
|
event.addListener(text, "compositionupdate", onCompositionUpdate, host);
|
|
event.addListener(text, "keyup", onKeyup, host);
|
|
event.addListener(text, "keydown", syncComposition, host);
|
|
event.addListener(text, "compositionend", onCompositionEnd, host);
|
|
|
|
this.getElement = function() {
|
|
return text;
|
|
};
|
|
this.setCommandMode = function(value) {
|
|
commandMode = value;
|
|
text.readOnly = false;
|
|
};
|
|
|
|
this.setReadOnly = function(readOnly) {
|
|
if (!commandMode)
|
|
text.readOnly = readOnly;
|
|
};
|
|
|
|
this.setCopyWithEmptySelection = function(value) {
|
|
};
|
|
|
|
this.onContextMenu = function(e) {
|
|
afterContextMenu = true;
|
|
resetSelection();
|
|
host._emit("nativecontextmenu", {target: host, domEvent: e});
|
|
this.moveToMouse(e, true);
|
|
};
|
|
|
|
this.moveToMouse = function(e, bringToFront) {
|
|
if (!tempStyle)
|
|
tempStyle = text.style.cssText;
|
|
text.style.cssText = (bringToFront ? "z-index:100000;" : "")
|
|
+ (useragent.isIE ? "opacity:0.1;" : "")
|
|
+ "text-indent: -" + (lastSelectionStart + lastSelectionEnd) * host.renderer.characterWidth * 0.5 + "px;";
|
|
|
|
var rect = host.container.getBoundingClientRect();
|
|
var style = dom.computedStyle(host.container);
|
|
var top = rect.top + (parseInt(style.borderTopWidth) || 0);
|
|
var left = rect.left + (parseInt(rect.borderLeftWidth) || 0);
|
|
var maxTop = rect.bottom - top - text.clientHeight -2;
|
|
var move = function(e) {
|
|
dom.translate(text, e.clientX - left - 2, Math.min(e.clientY - top - 2, maxTop));
|
|
};
|
|
move(e);
|
|
|
|
if (e.type != "mousedown")
|
|
return;
|
|
|
|
host.renderer.$isMousePressed = true;
|
|
|
|
clearTimeout(closeTimeout);
|
|
if (useragent.isWin)
|
|
event.capture(host.container, move, onContextMenuClose);
|
|
};
|
|
|
|
this.onContextMenuClose = onContextMenuClose;
|
|
var closeTimeout;
|
|
function onContextMenuClose() {
|
|
clearTimeout(closeTimeout);
|
|
closeTimeout = setTimeout(function () {
|
|
if (tempStyle) {
|
|
text.style.cssText = tempStyle;
|
|
tempStyle = '';
|
|
}
|
|
host.renderer.$isMousePressed = false;
|
|
if (host.renderer.$keepTextAreaAtCursor)
|
|
host.renderer.$moveTextAreaToCursor();
|
|
}, 0);
|
|
}
|
|
|
|
var onContextMenu = function(e) {
|
|
host.textInput.onContextMenu(e);
|
|
onContextMenuClose();
|
|
};
|
|
event.addListener(text, "mouseup", onContextMenu, host);
|
|
event.addListener(text, "mousedown", function(e) {
|
|
e.preventDefault();
|
|
onContextMenuClose();
|
|
}, host);
|
|
event.addListener(host.renderer.scroller, "contextmenu", onContextMenu, host);
|
|
event.addListener(text, "contextmenu", onContextMenu, host);
|
|
|
|
if (isIOS)
|
|
addIosSelectionHandler(parentNode, host, text);
|
|
|
|
function addIosSelectionHandler(parentNode, host, text) {
|
|
var typingResetTimeout = null;
|
|
var typing = false;
|
|
|
|
text.addEventListener("keydown", function (e) {
|
|
if (typingResetTimeout) clearTimeout(typingResetTimeout);
|
|
typing = true;
|
|
}, true);
|
|
|
|
text.addEventListener("keyup", function (e) {
|
|
typingResetTimeout = setTimeout(function () {
|
|
typing = false;
|
|
}, 100);
|
|
}, true);
|
|
var detectArrowKeys = function(e) {
|
|
if (document.activeElement !== text) return;
|
|
if (typing || inComposition || host.$mouseHandler.isMousePressed) return;
|
|
|
|
if (copied) {
|
|
return;
|
|
}
|
|
var selectionStart = text.selectionStart;
|
|
var selectionEnd = text.selectionEnd;
|
|
|
|
var key = null;
|
|
var modifier = 0;
|
|
if (selectionStart == 0) {
|
|
key = KEYS.up;
|
|
} else if (selectionStart == 1) {
|
|
key = KEYS.home;
|
|
} else if (selectionEnd > lastSelectionEnd && lastValue[selectionEnd] == "\n") {
|
|
key = KEYS.end;
|
|
} else if (selectionStart < lastSelectionStart && lastValue[selectionStart - 1] == " ") {
|
|
key = KEYS.left;
|
|
modifier = MODS.option;
|
|
} else if (
|
|
selectionStart < lastSelectionStart
|
|
|| (
|
|
selectionStart == lastSelectionStart
|
|
&& lastSelectionEnd != lastSelectionStart
|
|
&& selectionStart == selectionEnd
|
|
)
|
|
) {
|
|
key = KEYS.left;
|
|
} else if (selectionEnd > lastSelectionEnd && lastValue.slice(0, selectionEnd).split("\n").length > 2) {
|
|
key = KEYS.down;
|
|
} else if (selectionEnd > lastSelectionEnd && lastValue[selectionEnd - 1] == " ") {
|
|
key = KEYS.right;
|
|
modifier = MODS.option;
|
|
} else if (
|
|
selectionEnd > lastSelectionEnd
|
|
|| (
|
|
selectionEnd == lastSelectionEnd
|
|
&& lastSelectionEnd != lastSelectionStart
|
|
&& selectionStart == selectionEnd
|
|
)
|
|
) {
|
|
key = KEYS.right;
|
|
}
|
|
|
|
if (selectionStart !== selectionEnd)
|
|
modifier |= MODS.shift;
|
|
|
|
if (key) {
|
|
var result = host.onCommandKey({}, modifier, key);
|
|
if (!result && host.commands) {
|
|
key = KEYS.keyCodeToString(key);
|
|
var command = host.commands.findKeyCommand(modifier, key);
|
|
if (command)
|
|
host.execCommand(command);
|
|
}
|
|
lastSelectionStart = selectionStart;
|
|
lastSelectionEnd = selectionEnd;
|
|
resetSelection("");
|
|
}
|
|
};
|
|
document.addEventListener("selectionchange", detectArrowKeys);
|
|
host.on("destroy", function() {
|
|
document.removeEventListener("selectionchange", detectArrowKeys);
|
|
});
|
|
}
|
|
};
|
|
|
|
exports.TextInput = TextInput;
|
|
exports.$setUserAgentForTests = function(_isMobile, _isIOS) {
|
|
isMobile = _isMobile;
|
|
isIOS = _isIOS;
|
|
};
|
|
});
|
|
|
|
ace.define("ace/mouse/default_handlers",["require","exports","module","ace/lib/useragent"], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var useragent = require("../lib/useragent");
|
|
|
|
var DRAG_OFFSET = 0; // pixels
|
|
var SCROLL_COOLDOWN_T = 550; // milliseconds
|
|
|
|
function DefaultHandlers(mouseHandler) {
|
|
mouseHandler.$clickSelection = null;
|
|
|
|
var editor = mouseHandler.editor;
|
|
editor.setDefaultHandler("mousedown", this.onMouseDown.bind(mouseHandler));
|
|
editor.setDefaultHandler("dblclick", this.onDoubleClick.bind(mouseHandler));
|
|
editor.setDefaultHandler("tripleclick", this.onTripleClick.bind(mouseHandler));
|
|
editor.setDefaultHandler("quadclick", this.onQuadClick.bind(mouseHandler));
|
|
editor.setDefaultHandler("mousewheel", this.onMouseWheel.bind(mouseHandler));
|
|
|
|
var exports = ["select", "startSelect", "selectEnd", "selectAllEnd", "selectByWordsEnd",
|
|
"selectByLinesEnd", "dragWait", "dragWaitEnd", "focusWait"];
|
|
|
|
exports.forEach(function(x) {
|
|
mouseHandler[x] = this[x];
|
|
}, this);
|
|
|
|
mouseHandler.selectByLines = this.extendSelectionBy.bind(mouseHandler, "getLineRange");
|
|
mouseHandler.selectByWords = this.extendSelectionBy.bind(mouseHandler, "getWordRange");
|
|
}
|
|
|
|
(function() {
|
|
|
|
this.onMouseDown = function(ev) {
|
|
var inSelection = ev.inSelection();
|
|
var pos = ev.getDocumentPosition();
|
|
this.mousedownEvent = ev;
|
|
var editor = this.editor;
|
|
|
|
var button = ev.getButton();
|
|
if (button !== 0) {
|
|
var selectionRange = editor.getSelectionRange();
|
|
var selectionEmpty = selectionRange.isEmpty();
|
|
if (selectionEmpty || button == 1)
|
|
editor.selection.moveToPosition(pos);
|
|
if (button == 2) {
|
|
editor.textInput.onContextMenu(ev.domEvent);
|
|
if (!useragent.isMozilla)
|
|
ev.preventDefault();
|
|
}
|
|
return;
|
|
}
|
|
|
|
this.mousedownEvent.time = Date.now();
|
|
if (inSelection && !editor.isFocused()) {
|
|
editor.focus();
|
|
if (this.$focusTimeout && !this.$clickSelection && !editor.inMultiSelectMode) {
|
|
this.setState("focusWait");
|
|
this.captureMouse(ev);
|
|
return;
|
|
}
|
|
}
|
|
|
|
this.captureMouse(ev);
|
|
this.startSelect(pos, ev.domEvent._clicks > 1);
|
|
return ev.preventDefault();
|
|
};
|
|
|
|
this.startSelect = function(pos, waitForClickSelection) {
|
|
pos = pos || this.editor.renderer.screenToTextCoordinates(this.x, this.y);
|
|
var editor = this.editor;
|
|
if (!this.mousedownEvent) return;
|
|
if (this.mousedownEvent.getShiftKey())
|
|
editor.selection.selectToPosition(pos);
|
|
else if (!waitForClickSelection)
|
|
editor.selection.moveToPosition(pos);
|
|
if (!waitForClickSelection)
|
|
this.select();
|
|
if (editor.renderer.scroller.setCapture) {
|
|
editor.renderer.scroller.setCapture();
|
|
}
|
|
editor.setStyle("ace_selecting");
|
|
this.setState("select");
|
|
};
|
|
|
|
this.select = function() {
|
|
var anchor, editor = this.editor;
|
|
var cursor = editor.renderer.screenToTextCoordinates(this.x, this.y);
|
|
if (this.$clickSelection) {
|
|
var cmp = this.$clickSelection.comparePoint(cursor);
|
|
|
|
if (cmp == -1) {
|
|
anchor = this.$clickSelection.end;
|
|
} else if (cmp == 1) {
|
|
anchor = this.$clickSelection.start;
|
|
} else {
|
|
var orientedRange = calcRangeOrientation(this.$clickSelection, cursor);
|
|
cursor = orientedRange.cursor;
|
|
anchor = orientedRange.anchor;
|
|
}
|
|
editor.selection.setSelectionAnchor(anchor.row, anchor.column);
|
|
}
|
|
editor.selection.selectToPosition(cursor);
|
|
editor.renderer.scrollCursorIntoView();
|
|
};
|
|
|
|
this.extendSelectionBy = function(unitName) {
|
|
var anchor, editor = this.editor;
|
|
var cursor = editor.renderer.screenToTextCoordinates(this.x, this.y);
|
|
var range = editor.selection[unitName](cursor.row, cursor.column);
|
|
if (this.$clickSelection) {
|
|
var cmpStart = this.$clickSelection.comparePoint(range.start);
|
|
var cmpEnd = this.$clickSelection.comparePoint(range.end);
|
|
|
|
if (cmpStart == -1 && cmpEnd <= 0) {
|
|
anchor = this.$clickSelection.end;
|
|
if (range.end.row != cursor.row || range.end.column != cursor.column)
|
|
cursor = range.start;
|
|
} else if (cmpEnd == 1 && cmpStart >= 0) {
|
|
anchor = this.$clickSelection.start;
|
|
if (range.start.row != cursor.row || range.start.column != cursor.column)
|
|
cursor = range.end;
|
|
} else if (cmpStart == -1 && cmpEnd == 1) {
|
|
cursor = range.end;
|
|
anchor = range.start;
|
|
} else {
|
|
var orientedRange = calcRangeOrientation(this.$clickSelection, cursor);
|
|
cursor = orientedRange.cursor;
|
|
anchor = orientedRange.anchor;
|
|
}
|
|
editor.selection.setSelectionAnchor(anchor.row, anchor.column);
|
|
}
|
|
editor.selection.selectToPosition(cursor);
|
|
editor.renderer.scrollCursorIntoView();
|
|
};
|
|
|
|
this.selectEnd =
|
|
this.selectAllEnd =
|
|
this.selectByWordsEnd =
|
|
this.selectByLinesEnd = function() {
|
|
this.$clickSelection = null;
|
|
this.editor.unsetStyle("ace_selecting");
|
|
if (this.editor.renderer.scroller.releaseCapture) {
|
|
this.editor.renderer.scroller.releaseCapture();
|
|
}
|
|
};
|
|
|
|
this.focusWait = function() {
|
|
var distance = calcDistance(this.mousedownEvent.x, this.mousedownEvent.y, this.x, this.y);
|
|
var time = Date.now();
|
|
|
|
if (distance > DRAG_OFFSET || time - this.mousedownEvent.time > this.$focusTimeout)
|
|
this.startSelect(this.mousedownEvent.getDocumentPosition());
|
|
};
|
|
|
|
this.onDoubleClick = function(ev) {
|
|
var pos = ev.getDocumentPosition();
|
|
var editor = this.editor;
|
|
var session = editor.session;
|
|
|
|
var range = session.getBracketRange(pos);
|
|
if (range) {
|
|
if (range.isEmpty()) {
|
|
range.start.column--;
|
|
range.end.column++;
|
|
}
|
|
this.setState("select");
|
|
} else {
|
|
range = editor.selection.getWordRange(pos.row, pos.column);
|
|
this.setState("selectByWords");
|
|
}
|
|
this.$clickSelection = range;
|
|
this.select();
|
|
};
|
|
|
|
this.onTripleClick = function(ev) {
|
|
var pos = ev.getDocumentPosition();
|
|
var editor = this.editor;
|
|
|
|
this.setState("selectByLines");
|
|
var range = editor.getSelectionRange();
|
|
if (range.isMultiLine() && range.contains(pos.row, pos.column)) {
|
|
this.$clickSelection = editor.selection.getLineRange(range.start.row);
|
|
this.$clickSelection.end = editor.selection.getLineRange(range.end.row).end;
|
|
} else {
|
|
this.$clickSelection = editor.selection.getLineRange(pos.row);
|
|
}
|
|
this.select();
|
|
};
|
|
|
|
this.onQuadClick = function(ev) {
|
|
var editor = this.editor;
|
|
|
|
editor.selectAll();
|
|
this.$clickSelection = editor.getSelectionRange();
|
|
this.setState("selectAll");
|
|
};
|
|
|
|
this.onMouseWheel = function(ev) {
|
|
if (ev.getAccelKey())
|
|
return;
|
|
if (ev.getShiftKey() && ev.wheelY && !ev.wheelX) {
|
|
ev.wheelX = ev.wheelY;
|
|
ev.wheelY = 0;
|
|
}
|
|
|
|
var editor = this.editor;
|
|
|
|
if (!this.$lastScroll)
|
|
this.$lastScroll = { t: 0, vx: 0, vy: 0, allowed: 0 };
|
|
|
|
var prevScroll = this.$lastScroll;
|
|
var t = ev.domEvent.timeStamp;
|
|
var dt = t - prevScroll.t;
|
|
var vx = dt ? ev.wheelX / dt : prevScroll.vx;
|
|
var vy = dt ? ev.wheelY / dt : prevScroll.vy;
|
|
if (dt < SCROLL_COOLDOWN_T) {
|
|
vx = (vx + prevScroll.vx) / 2;
|
|
vy = (vy + prevScroll.vy) / 2;
|
|
}
|
|
|
|
var direction = Math.abs(vx / vy);
|
|
|
|
var canScroll = false;
|
|
if (direction >= 1 && editor.renderer.isScrollableBy(ev.wheelX * ev.speed, 0))
|
|
canScroll = true;
|
|
if (direction <= 1 && editor.renderer.isScrollableBy(0, ev.wheelY * ev.speed))
|
|
canScroll = true;
|
|
|
|
if (canScroll) {
|
|
prevScroll.allowed = t;
|
|
} else if (t - prevScroll.allowed < SCROLL_COOLDOWN_T) {
|
|
var isSlower = Math.abs(vx) <= 1.5 * Math.abs(prevScroll.vx)
|
|
&& Math.abs(vy) <= 1.5 * Math.abs(prevScroll.vy);
|
|
if (isSlower) {
|
|
canScroll = true;
|
|
prevScroll.allowed = t;
|
|
}
|
|
else {
|
|
prevScroll.allowed = 0;
|
|
}
|
|
}
|
|
|
|
prevScroll.t = t;
|
|
prevScroll.vx = vx;
|
|
prevScroll.vy = vy;
|
|
|
|
if (canScroll) {
|
|
editor.renderer.scrollBy(ev.wheelX * ev.speed, ev.wheelY * ev.speed);
|
|
return ev.stop();
|
|
}
|
|
};
|
|
|
|
}).call(DefaultHandlers.prototype);
|
|
|
|
exports.DefaultHandlers = DefaultHandlers;
|
|
|
|
function calcDistance(ax, ay, bx, by) {
|
|
return Math.sqrt(Math.pow(bx - ax, 2) + Math.pow(by - ay, 2));
|
|
}
|
|
|
|
function calcRangeOrientation(range, cursor) {
|
|
if (range.start.row == range.end.row)
|
|
var cmp = 2 * cursor.column - range.start.column - range.end.column;
|
|
else if (range.start.row == range.end.row - 1 && !range.start.column && !range.end.column)
|
|
var cmp = cursor.column - 4;
|
|
else
|
|
var cmp = 2 * cursor.row - range.start.row - range.end.row;
|
|
|
|
if (cmp < 0)
|
|
return {cursor: range.start, anchor: range.end};
|
|
else
|
|
return {cursor: range.end, anchor: range.start};
|
|
}
|
|
|
|
});
|
|
|
|
ace.define("ace/tooltip",["require","exports","module","ace/lib/oop","ace/lib/dom"], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var oop = require("./lib/oop");
|
|
var dom = require("./lib/dom");
|
|
function Tooltip (parentNode) {
|
|
this.isOpen = false;
|
|
this.$element = null;
|
|
this.$parentNode = parentNode;
|
|
}
|
|
|
|
(function() {
|
|
this.$init = function() {
|
|
this.$element = dom.createElement("div");
|
|
this.$element.className = "ace_tooltip";
|
|
this.$element.style.display = "none";
|
|
this.$parentNode.appendChild(this.$element);
|
|
return this.$element;
|
|
};
|
|
this.getElement = function() {
|
|
return this.$element || this.$init();
|
|
};
|
|
this.setText = function(text) {
|
|
this.getElement().textContent = text;
|
|
};
|
|
this.setHtml = function(html) {
|
|
this.getElement().innerHTML = html;
|
|
};
|
|
this.setPosition = function(x, y) {
|
|
this.getElement().style.left = x + "px";
|
|
this.getElement().style.top = y + "px";
|
|
};
|
|
this.setClassName = function(className) {
|
|
dom.addCssClass(this.getElement(), className);
|
|
};
|
|
this.show = function(text, x, y) {
|
|
if (text != null)
|
|
this.setText(text);
|
|
if (x != null && y != null)
|
|
this.setPosition(x, y);
|
|
if (!this.isOpen) {
|
|
this.getElement().style.display = "block";
|
|
this.isOpen = true;
|
|
}
|
|
};
|
|
|
|
this.hide = function() {
|
|
if (this.isOpen) {
|
|
this.getElement().style.display = "none";
|
|
this.isOpen = false;
|
|
}
|
|
};
|
|
this.getHeight = function() {
|
|
return this.getElement().offsetHeight;
|
|
};
|
|
this.getWidth = function() {
|
|
return this.getElement().offsetWidth;
|
|
};
|
|
|
|
this.destroy = function() {
|
|
this.isOpen = false;
|
|
if (this.$element && this.$element.parentNode) {
|
|
this.$element.parentNode.removeChild(this.$element);
|
|
}
|
|
};
|
|
|
|
}).call(Tooltip.prototype);
|
|
|
|
exports.Tooltip = Tooltip;
|
|
});
|
|
|
|
ace.define("ace/mouse/default_gutter_handler",["require","exports","module","ace/lib/dom","ace/lib/oop","ace/lib/event","ace/tooltip"], function(require, exports, module) {
|
|
"use strict";
|
|
var dom = require("../lib/dom");
|
|
var oop = require("../lib/oop");
|
|
var event = require("../lib/event");
|
|
var Tooltip = require("../tooltip").Tooltip;
|
|
|
|
function GutterHandler(mouseHandler) {
|
|
var editor = mouseHandler.editor;
|
|
var gutter = editor.renderer.$gutterLayer;
|
|
var tooltip = new GutterTooltip(editor.container);
|
|
|
|
mouseHandler.editor.setDefaultHandler("guttermousedown", function(e) {
|
|
if (!editor.isFocused() || e.getButton() != 0)
|
|
return;
|
|
var gutterRegion = gutter.getRegion(e);
|
|
|
|
if (gutterRegion == "foldWidgets")
|
|
return;
|
|
|
|
var row = e.getDocumentPosition().row;
|
|
var selection = editor.session.selection;
|
|
|
|
if (e.getShiftKey())
|
|
selection.selectTo(row, 0);
|
|
else {
|
|
if (e.domEvent.detail == 2) {
|
|
editor.selectAll();
|
|
return e.preventDefault();
|
|
}
|
|
mouseHandler.$clickSelection = editor.selection.getLineRange(row);
|
|
}
|
|
mouseHandler.setState("selectByLines");
|
|
mouseHandler.captureMouse(e);
|
|
return e.preventDefault();
|
|
});
|
|
|
|
|
|
var tooltipTimeout, mouseEvent, tooltipAnnotation;
|
|
|
|
function showTooltip() {
|
|
var row = mouseEvent.getDocumentPosition().row;
|
|
var annotation = gutter.$annotations[row];
|
|
if (!annotation)
|
|
return hideTooltip();
|
|
|
|
var maxRow = editor.session.getLength();
|
|
if (row == maxRow) {
|
|
var screenRow = editor.renderer.pixelToScreenCoordinates(0, mouseEvent.y).row;
|
|
var pos = mouseEvent.$pos;
|
|
if (screenRow > editor.session.documentToScreenRow(pos.row, pos.column))
|
|
return hideTooltip();
|
|
}
|
|
|
|
if (tooltipAnnotation == annotation)
|
|
return;
|
|
tooltipAnnotation = annotation.text.join("<br/>");
|
|
|
|
tooltip.setHtml(tooltipAnnotation);
|
|
tooltip.show();
|
|
editor._signal("showGutterTooltip", tooltip);
|
|
editor.on("mousewheel", hideTooltip);
|
|
|
|
if (mouseHandler.$tooltipFollowsMouse) {
|
|
moveTooltip(mouseEvent);
|
|
} else {
|
|
var gutterElement = mouseEvent.domEvent.target;
|
|
var rect = gutterElement.getBoundingClientRect();
|
|
var style = tooltip.getElement().style;
|
|
style.left = rect.right + "px";
|
|
style.top = rect.bottom + "px";
|
|
}
|
|
}
|
|
|
|
function hideTooltip() {
|
|
if (tooltipTimeout)
|
|
tooltipTimeout = clearTimeout(tooltipTimeout);
|
|
if (tooltipAnnotation) {
|
|
tooltip.hide();
|
|
tooltipAnnotation = null;
|
|
editor._signal("hideGutterTooltip", tooltip);
|
|
editor.off("mousewheel", hideTooltip);
|
|
}
|
|
}
|
|
|
|
function moveTooltip(e) {
|
|
tooltip.setPosition(e.x, e.y);
|
|
}
|
|
|
|
mouseHandler.editor.setDefaultHandler("guttermousemove", function(e) {
|
|
var target = e.domEvent.target || e.domEvent.srcElement;
|
|
if (dom.hasCssClass(target, "ace_fold-widget"))
|
|
return hideTooltip();
|
|
|
|
if (tooltipAnnotation && mouseHandler.$tooltipFollowsMouse)
|
|
moveTooltip(e);
|
|
|
|
mouseEvent = e;
|
|
if (tooltipTimeout)
|
|
return;
|
|
tooltipTimeout = setTimeout(function() {
|
|
tooltipTimeout = null;
|
|
if (mouseEvent && !mouseHandler.isMousePressed)
|
|
showTooltip();
|
|
else
|
|
hideTooltip();
|
|
}, 50);
|
|
});
|
|
|
|
event.addListener(editor.renderer.$gutter, "mouseout", function(e) {
|
|
mouseEvent = null;
|
|
if (!tooltipAnnotation || tooltipTimeout)
|
|
return;
|
|
|
|
tooltipTimeout = setTimeout(function() {
|
|
tooltipTimeout = null;
|
|
hideTooltip();
|
|
}, 50);
|
|
}, editor);
|
|
|
|
editor.on("changeSession", hideTooltip);
|
|
}
|
|
|
|
function GutterTooltip(parentNode) {
|
|
Tooltip.call(this, parentNode);
|
|
}
|
|
|
|
oop.inherits(GutterTooltip, Tooltip);
|
|
|
|
(function(){
|
|
this.setPosition = function(x, y) {
|
|
var windowWidth = window.innerWidth || document.documentElement.clientWidth;
|
|
var windowHeight = window.innerHeight || document.documentElement.clientHeight;
|
|
var width = this.getWidth();
|
|
var height = this.getHeight();
|
|
x += 15;
|
|
y += 15;
|
|
if (x + width > windowWidth) {
|
|
x -= (x + width) - windowWidth;
|
|
}
|
|
if (y + height > windowHeight) {
|
|
y -= 20 + height;
|
|
}
|
|
Tooltip.prototype.setPosition.call(this, x, y);
|
|
};
|
|
|
|
}).call(GutterTooltip.prototype);
|
|
|
|
|
|
|
|
exports.GutterHandler = GutterHandler;
|
|
|
|
});
|
|
|
|
ace.define("ace/mouse/mouse_event",["require","exports","module","ace/lib/event","ace/lib/useragent"], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var event = require("../lib/event");
|
|
var useragent = require("../lib/useragent");
|
|
var MouseEvent = exports.MouseEvent = function(domEvent, editor) {
|
|
this.domEvent = domEvent;
|
|
this.editor = editor;
|
|
|
|
this.x = this.clientX = domEvent.clientX;
|
|
this.y = this.clientY = domEvent.clientY;
|
|
|
|
this.$pos = null;
|
|
this.$inSelection = null;
|
|
|
|
this.propagationStopped = false;
|
|
this.defaultPrevented = false;
|
|
};
|
|
|
|
(function() {
|
|
|
|
this.stopPropagation = function() {
|
|
event.stopPropagation(this.domEvent);
|
|
this.propagationStopped = true;
|
|
};
|
|
|
|
this.preventDefault = function() {
|
|
event.preventDefault(this.domEvent);
|
|
this.defaultPrevented = true;
|
|
};
|
|
|
|
this.stop = function() {
|
|
this.stopPropagation();
|
|
this.preventDefault();
|
|
};
|
|
this.getDocumentPosition = function() {
|
|
if (this.$pos)
|
|
return this.$pos;
|
|
|
|
this.$pos = this.editor.renderer.screenToTextCoordinates(this.clientX, this.clientY);
|
|
return this.$pos;
|
|
};
|
|
this.inSelection = function() {
|
|
if (this.$inSelection !== null)
|
|
return this.$inSelection;
|
|
|
|
var editor = this.editor;
|
|
|
|
|
|
var selectionRange = editor.getSelectionRange();
|
|
if (selectionRange.isEmpty())
|
|
this.$inSelection = false;
|
|
else {
|
|
var pos = this.getDocumentPosition();
|
|
this.$inSelection = selectionRange.contains(pos.row, pos.column);
|
|
}
|
|
|
|
return this.$inSelection;
|
|
};
|
|
this.getButton = function() {
|
|
return event.getButton(this.domEvent);
|
|
};
|
|
this.getShiftKey = function() {
|
|
return this.domEvent.shiftKey;
|
|
};
|
|
|
|
this.getAccelKey = useragent.isMac
|
|
? function() { return this.domEvent.metaKey; }
|
|
: function() { return this.domEvent.ctrlKey; };
|
|
|
|
}).call(MouseEvent.prototype);
|
|
|
|
});
|
|
|
|
ace.define("ace/mouse/dragdrop_handler",["require","exports","module","ace/lib/dom","ace/lib/event","ace/lib/useragent"], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var dom = require("../lib/dom");
|
|
var event = require("../lib/event");
|
|
var useragent = require("../lib/useragent");
|
|
|
|
var AUTOSCROLL_DELAY = 200;
|
|
var SCROLL_CURSOR_DELAY = 200;
|
|
var SCROLL_CURSOR_HYSTERESIS = 5;
|
|
|
|
function DragdropHandler(mouseHandler) {
|
|
|
|
var editor = mouseHandler.editor;
|
|
|
|
var blankImage = dom.createElement("img");
|
|
blankImage.src = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==";
|
|
if (useragent.isOpera)
|
|
blankImage.style.cssText = "width:1px;height:1px;position:fixed;top:0;left:0;z-index:2147483647;opacity:0;";
|
|
|
|
var exports = ["dragWait", "dragWaitEnd", "startDrag", "dragReadyEnd", "onMouseDrag"];
|
|
|
|
exports.forEach(function(x) {
|
|
mouseHandler[x] = this[x];
|
|
}, this);
|
|
editor.on("mousedown", this.onMouseDown.bind(mouseHandler));
|
|
|
|
|
|
var mouseTarget = editor.container;
|
|
var dragSelectionMarker, x, y;
|
|
var timerId, range;
|
|
var dragCursor, counter = 0;
|
|
var dragOperation;
|
|
var isInternal;
|
|
var autoScrollStartTime;
|
|
var cursorMovedTime;
|
|
var cursorPointOnCaretMoved;
|
|
|
|
this.onDragStart = function(e) {
|
|
if (this.cancelDrag || !mouseTarget.draggable) {
|
|
var self = this;
|
|
setTimeout(function(){
|
|
self.startSelect();
|
|
self.captureMouse(e);
|
|
}, 0);
|
|
return e.preventDefault();
|
|
}
|
|
range = editor.getSelectionRange();
|
|
|
|
var dataTransfer = e.dataTransfer;
|
|
dataTransfer.effectAllowed = editor.getReadOnly() ? "copy" : "copyMove";
|
|
if (useragent.isOpera) {
|
|
editor.container.appendChild(blankImage);
|
|
blankImage.scrollTop = 0;
|
|
}
|
|
dataTransfer.setDragImage && dataTransfer.setDragImage(blankImage, 0, 0);
|
|
if (useragent.isOpera) {
|
|
editor.container.removeChild(blankImage);
|
|
}
|
|
dataTransfer.clearData();
|
|
dataTransfer.setData("Text", editor.session.getTextRange());
|
|
|
|
isInternal = true;
|
|
this.setState("drag");
|
|
};
|
|
|
|
this.onDragEnd = function(e) {
|
|
mouseTarget.draggable = false;
|
|
isInternal = false;
|
|
this.setState(null);
|
|
if (!editor.getReadOnly()) {
|
|
var dropEffect = e.dataTransfer.dropEffect;
|
|
if (!dragOperation && dropEffect == "move")
|
|
editor.session.remove(editor.getSelectionRange());
|
|
editor.$resetCursorStyle();
|
|
}
|
|
this.editor.unsetStyle("ace_dragging");
|
|
this.editor.renderer.setCursorStyle("");
|
|
};
|
|
|
|
this.onDragEnter = function(e) {
|
|
if (editor.getReadOnly() || !canAccept(e.dataTransfer))
|
|
return;
|
|
x = e.clientX;
|
|
y = e.clientY;
|
|
if (!dragSelectionMarker)
|
|
addDragMarker();
|
|
counter++;
|
|
e.dataTransfer.dropEffect = dragOperation = getDropEffect(e);
|
|
return event.preventDefault(e);
|
|
};
|
|
|
|
this.onDragOver = function(e) {
|
|
if (editor.getReadOnly() || !canAccept(e.dataTransfer))
|
|
return;
|
|
x = e.clientX;
|
|
y = e.clientY;
|
|
if (!dragSelectionMarker) {
|
|
addDragMarker();
|
|
counter++;
|
|
}
|
|
if (onMouseMoveTimer !== null)
|
|
onMouseMoveTimer = null;
|
|
|
|
e.dataTransfer.dropEffect = dragOperation = getDropEffect(e);
|
|
return event.preventDefault(e);
|
|
};
|
|
|
|
this.onDragLeave = function(e) {
|
|
counter--;
|
|
if (counter <= 0 && dragSelectionMarker) {
|
|
clearDragMarker();
|
|
dragOperation = null;
|
|
return event.preventDefault(e);
|
|
}
|
|
};
|
|
|
|
this.onDrop = function(e) {
|
|
if (!dragCursor)
|
|
return;
|
|
var dataTransfer = e.dataTransfer;
|
|
if (isInternal) {
|
|
switch (dragOperation) {
|
|
case "move":
|
|
if (range.contains(dragCursor.row, dragCursor.column)) {
|
|
range = {
|
|
start: dragCursor,
|
|
end: dragCursor
|
|
};
|
|
} else {
|
|
range = editor.moveText(range, dragCursor);
|
|
}
|
|
break;
|
|
case "copy":
|
|
range = editor.moveText(range, dragCursor, true);
|
|
break;
|
|
}
|
|
} else {
|
|
var dropData = dataTransfer.getData('Text');
|
|
range = {
|
|
start: dragCursor,
|
|
end: editor.session.insert(dragCursor, dropData)
|
|
};
|
|
editor.focus();
|
|
dragOperation = null;
|
|
}
|
|
clearDragMarker();
|
|
return event.preventDefault(e);
|
|
};
|
|
|
|
event.addListener(mouseTarget, "dragstart", this.onDragStart.bind(mouseHandler), editor);
|
|
event.addListener(mouseTarget, "dragend", this.onDragEnd.bind(mouseHandler), editor);
|
|
event.addListener(mouseTarget, "dragenter", this.onDragEnter.bind(mouseHandler), editor);
|
|
event.addListener(mouseTarget, "dragover", this.onDragOver.bind(mouseHandler), editor);
|
|
event.addListener(mouseTarget, "dragleave", this.onDragLeave.bind(mouseHandler), editor);
|
|
event.addListener(mouseTarget, "drop", this.onDrop.bind(mouseHandler), editor);
|
|
|
|
function scrollCursorIntoView(cursor, prevCursor) {
|
|
var now = Date.now();
|
|
var vMovement = !prevCursor || cursor.row != prevCursor.row;
|
|
var hMovement = !prevCursor || cursor.column != prevCursor.column;
|
|
if (!cursorMovedTime || vMovement || hMovement) {
|
|
editor.moveCursorToPosition(cursor);
|
|
cursorMovedTime = now;
|
|
cursorPointOnCaretMoved = {x: x, y: y};
|
|
} else {
|
|
var distance = calcDistance(cursorPointOnCaretMoved.x, cursorPointOnCaretMoved.y, x, y);
|
|
if (distance > SCROLL_CURSOR_HYSTERESIS) {
|
|
cursorMovedTime = null;
|
|
} else if (now - cursorMovedTime >= SCROLL_CURSOR_DELAY) {
|
|
editor.renderer.scrollCursorIntoView();
|
|
cursorMovedTime = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
function autoScroll(cursor, prevCursor) {
|
|
var now = Date.now();
|
|
var lineHeight = editor.renderer.layerConfig.lineHeight;
|
|
var characterWidth = editor.renderer.layerConfig.characterWidth;
|
|
var editorRect = editor.renderer.scroller.getBoundingClientRect();
|
|
var offsets = {
|
|
x: {
|
|
left: x - editorRect.left,
|
|
right: editorRect.right - x
|
|
},
|
|
y: {
|
|
top: y - editorRect.top,
|
|
bottom: editorRect.bottom - y
|
|
}
|
|
};
|
|
var nearestXOffset = Math.min(offsets.x.left, offsets.x.right);
|
|
var nearestYOffset = Math.min(offsets.y.top, offsets.y.bottom);
|
|
var scrollCursor = {row: cursor.row, column: cursor.column};
|
|
if (nearestXOffset / characterWidth <= 2) {
|
|
scrollCursor.column += (offsets.x.left < offsets.x.right ? -3 : +2);
|
|
}
|
|
if (nearestYOffset / lineHeight <= 1) {
|
|
scrollCursor.row += (offsets.y.top < offsets.y.bottom ? -1 : +1);
|
|
}
|
|
var vScroll = cursor.row != scrollCursor.row;
|
|
var hScroll = cursor.column != scrollCursor.column;
|
|
var vMovement = !prevCursor || cursor.row != prevCursor.row;
|
|
if (vScroll || (hScroll && !vMovement)) {
|
|
if (!autoScrollStartTime)
|
|
autoScrollStartTime = now;
|
|
else if (now - autoScrollStartTime >= AUTOSCROLL_DELAY)
|
|
editor.renderer.scrollCursorIntoView(scrollCursor);
|
|
} else {
|
|
autoScrollStartTime = null;
|
|
}
|
|
}
|
|
|
|
function onDragInterval() {
|
|
var prevCursor = dragCursor;
|
|
dragCursor = editor.renderer.screenToTextCoordinates(x, y);
|
|
scrollCursorIntoView(dragCursor, prevCursor);
|
|
autoScroll(dragCursor, prevCursor);
|
|
}
|
|
|
|
function addDragMarker() {
|
|
range = editor.selection.toOrientedRange();
|
|
dragSelectionMarker = editor.session.addMarker(range, "ace_selection", editor.getSelectionStyle());
|
|
editor.clearSelection();
|
|
if (editor.isFocused())
|
|
editor.renderer.$cursorLayer.setBlinking(false);
|
|
clearInterval(timerId);
|
|
onDragInterval();
|
|
timerId = setInterval(onDragInterval, 20);
|
|
counter = 0;
|
|
event.addListener(document, "mousemove", onMouseMove);
|
|
}
|
|
|
|
function clearDragMarker() {
|
|
clearInterval(timerId);
|
|
editor.session.removeMarker(dragSelectionMarker);
|
|
dragSelectionMarker = null;
|
|
editor.selection.fromOrientedRange(range);
|
|
if (editor.isFocused() && !isInternal)
|
|
editor.$resetCursorStyle();
|
|
range = null;
|
|
dragCursor = null;
|
|
counter = 0;
|
|
autoScrollStartTime = null;
|
|
cursorMovedTime = null;
|
|
event.removeListener(document, "mousemove", onMouseMove);
|
|
}
|
|
var onMouseMoveTimer = null;
|
|
function onMouseMove() {
|
|
if (onMouseMoveTimer == null) {
|
|
onMouseMoveTimer = setTimeout(function() {
|
|
if (onMouseMoveTimer != null && dragSelectionMarker)
|
|
clearDragMarker();
|
|
}, 20);
|
|
}
|
|
}
|
|
|
|
function canAccept(dataTransfer) {
|
|
var types = dataTransfer.types;
|
|
return !types || Array.prototype.some.call(types, function(type) {
|
|
return type == 'text/plain' || type == 'Text';
|
|
});
|
|
}
|
|
|
|
function getDropEffect(e) {
|
|
var copyAllowed = ['copy', 'copymove', 'all', 'uninitialized'];
|
|
var moveAllowed = ['move', 'copymove', 'linkmove', 'all', 'uninitialized'];
|
|
|
|
var copyModifierState = useragent.isMac ? e.altKey : e.ctrlKey;
|
|
var effectAllowed = "uninitialized";
|
|
try {
|
|
effectAllowed = e.dataTransfer.effectAllowed.toLowerCase();
|
|
} catch (e) {}
|
|
var dropEffect = "none";
|
|
|
|
if (copyModifierState && copyAllowed.indexOf(effectAllowed) >= 0)
|
|
dropEffect = "copy";
|
|
else if (moveAllowed.indexOf(effectAllowed) >= 0)
|
|
dropEffect = "move";
|
|
else if (copyAllowed.indexOf(effectAllowed) >= 0)
|
|
dropEffect = "copy";
|
|
|
|
return dropEffect;
|
|
}
|
|
}
|
|
|
|
(function() {
|
|
|
|
this.dragWait = function() {
|
|
var interval = Date.now() - this.mousedownEvent.time;
|
|
if (interval > this.editor.getDragDelay())
|
|
this.startDrag();
|
|
};
|
|
|
|
this.dragWaitEnd = function() {
|
|
var target = this.editor.container;
|
|
target.draggable = false;
|
|
this.startSelect(this.mousedownEvent.getDocumentPosition());
|
|
this.selectEnd();
|
|
};
|
|
|
|
this.dragReadyEnd = function(e) {
|
|
this.editor.$resetCursorStyle();
|
|
this.editor.unsetStyle("ace_dragging");
|
|
this.editor.renderer.setCursorStyle("");
|
|
this.dragWaitEnd();
|
|
};
|
|
|
|
this.startDrag = function(){
|
|
this.cancelDrag = false;
|
|
var editor = this.editor;
|
|
var target = editor.container;
|
|
target.draggable = true;
|
|
editor.renderer.$cursorLayer.setBlinking(false);
|
|
editor.setStyle("ace_dragging");
|
|
var cursorStyle = useragent.isWin ? "default" : "move";
|
|
editor.renderer.setCursorStyle(cursorStyle);
|
|
this.setState("dragReady");
|
|
};
|
|
|
|
this.onMouseDrag = function(e) {
|
|
var target = this.editor.container;
|
|
if (useragent.isIE && this.state == "dragReady") {
|
|
var distance = calcDistance(this.mousedownEvent.x, this.mousedownEvent.y, this.x, this.y);
|
|
if (distance > 3)
|
|
target.dragDrop();
|
|
}
|
|
if (this.state === "dragWait") {
|
|
var distance = calcDistance(this.mousedownEvent.x, this.mousedownEvent.y, this.x, this.y);
|
|
if (distance > 0) {
|
|
target.draggable = false;
|
|
this.startSelect(this.mousedownEvent.getDocumentPosition());
|
|
}
|
|
}
|
|
};
|
|
|
|
this.onMouseDown = function(e) {
|
|
if (!this.$dragEnabled)
|
|
return;
|
|
this.mousedownEvent = e;
|
|
var editor = this.editor;
|
|
|
|
var inSelection = e.inSelection();
|
|
var button = e.getButton();
|
|
var clickCount = e.domEvent.detail || 1;
|
|
if (clickCount === 1 && button === 0 && inSelection) {
|
|
if (e.editor.inMultiSelectMode && (e.getAccelKey() || e.getShiftKey()))
|
|
return;
|
|
this.mousedownEvent.time = Date.now();
|
|
var eventTarget = e.domEvent.target || e.domEvent.srcElement;
|
|
if ("unselectable" in eventTarget)
|
|
eventTarget.unselectable = "on";
|
|
if (editor.getDragDelay()) {
|
|
if (useragent.isWebKit) {
|
|
this.cancelDrag = true;
|
|
var mouseTarget = editor.container;
|
|
mouseTarget.draggable = true;
|
|
}
|
|
this.setState("dragWait");
|
|
} else {
|
|
this.startDrag();
|
|
}
|
|
this.captureMouse(e, this.onMouseDrag.bind(this));
|
|
e.defaultPrevented = true;
|
|
}
|
|
};
|
|
|
|
}).call(DragdropHandler.prototype);
|
|
|
|
|
|
function calcDistance(ax, ay, bx, by) {
|
|
return Math.sqrt(Math.pow(bx - ax, 2) + Math.pow(by - ay, 2));
|
|
}
|
|
|
|
exports.DragdropHandler = DragdropHandler;
|
|
|
|
});
|
|
|
|
ace.define("ace/mouse/touch_handler",["require","exports","module","ace/mouse/mouse_event","ace/lib/event","ace/lib/dom"], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var MouseEvent = require("./mouse_event").MouseEvent;
|
|
var event = require("../lib/event");
|
|
var dom = require("../lib/dom");
|
|
|
|
exports.addTouchListeners = function(el, editor) {
|
|
var mode = "scroll";
|
|
var startX;
|
|
var startY;
|
|
var touchStartT;
|
|
var lastT;
|
|
var longTouchTimer;
|
|
var animationTimer;
|
|
var animationSteps = 0;
|
|
var pos;
|
|
var clickCount = 0;
|
|
var vX = 0;
|
|
var vY = 0;
|
|
var pressed;
|
|
var contextMenu;
|
|
|
|
function createContextMenu() {
|
|
var clipboard = window.navigator && window.navigator.clipboard;
|
|
var isOpen = false;
|
|
var updateMenu = function() {
|
|
var selected = editor.getCopyText();
|
|
var hasUndo = editor.session.getUndoManager().hasUndo();
|
|
contextMenu.replaceChild(
|
|
dom.buildDom(isOpen ? ["span",
|
|
!selected && ["span", { class: "ace_mobile-button", action: "selectall" }, "Select All"],
|
|
selected && ["span", { class: "ace_mobile-button", action: "copy" }, "Copy"],
|
|
selected && ["span", { class: "ace_mobile-button", action: "cut" }, "Cut"],
|
|
clipboard && ["span", { class: "ace_mobile-button", action: "paste" }, "Paste"],
|
|
hasUndo && ["span", { class: "ace_mobile-button", action: "undo" }, "Undo"],
|
|
["span", { class: "ace_mobile-button", action: "find" }, "Find"],
|
|
["span", { class: "ace_mobile-button", action: "openCommandPallete" }, "Pallete"]
|
|
] : ["span"]),
|
|
contextMenu.firstChild
|
|
);
|
|
};
|
|
var handleClick = function(e) {
|
|
var action = e.target.getAttribute("action");
|
|
|
|
if (action == "more" || !isOpen) {
|
|
isOpen = !isOpen;
|
|
return updateMenu();
|
|
}
|
|
if (action == "paste") {
|
|
clipboard.readText().then(function (text) {
|
|
editor.execCommand(action, text);
|
|
});
|
|
}
|
|
else if (action) {
|
|
if (action == "cut" || action == "copy") {
|
|
if (clipboard)
|
|
clipboard.writeText(editor.getCopyText());
|
|
else
|
|
document.execCommand("copy");
|
|
}
|
|
editor.execCommand(action);
|
|
}
|
|
contextMenu.firstChild.style.display = "none";
|
|
isOpen = false;
|
|
if (action != "openCommandPallete")
|
|
editor.focus();
|
|
};
|
|
contextMenu = dom.buildDom(["div",
|
|
{
|
|
class: "ace_mobile-menu",
|
|
ontouchstart: function(e) {
|
|
mode = "menu";
|
|
e.stopPropagation();
|
|
e.preventDefault();
|
|
editor.textInput.focus();
|
|
},
|
|
ontouchend: function(e) {
|
|
e.stopPropagation();
|
|
e.preventDefault();
|
|
handleClick(e);
|
|
},
|
|
onclick: handleClick
|
|
},
|
|
["span"],
|
|
["span", { class: "ace_mobile-button", action: "more" }, "..."]
|
|
], editor.container);
|
|
}
|
|
function showContextMenu() {
|
|
if (!contextMenu) createContextMenu();
|
|
var cursor = editor.selection.cursor;
|
|
var pagePos = editor.renderer.textToScreenCoordinates(cursor.row, cursor.column);
|
|
var leftOffset = editor.renderer.textToScreenCoordinates(0, 0).pageX;
|
|
var scrollLeft = editor.renderer.scrollLeft;
|
|
var rect = editor.container.getBoundingClientRect();
|
|
contextMenu.style.top = pagePos.pageY - rect.top - 3 + "px";
|
|
if (pagePos.pageX - rect.left < rect.width - 70) {
|
|
contextMenu.style.left = "";
|
|
contextMenu.style.right = "10px";
|
|
} else {
|
|
contextMenu.style.right = "";
|
|
contextMenu.style.left = leftOffset + scrollLeft - rect.left + "px";
|
|
}
|
|
contextMenu.style.display = "";
|
|
contextMenu.firstChild.style.display = "none";
|
|
editor.on("input", hideContextMenu);
|
|
}
|
|
function hideContextMenu(e) {
|
|
if (contextMenu)
|
|
contextMenu.style.display = "none";
|
|
editor.off("input", hideContextMenu);
|
|
}
|
|
|
|
function handleLongTap() {
|
|
longTouchTimer = null;
|
|
clearTimeout(longTouchTimer);
|
|
var range = editor.selection.getRange();
|
|
var inSelection = range.contains(pos.row, pos.column);
|
|
if (range.isEmpty() || !inSelection) {
|
|
editor.selection.moveToPosition(pos);
|
|
editor.selection.selectWord();
|
|
}
|
|
mode = "wait";
|
|
showContextMenu();
|
|
}
|
|
function switchToSelectionMode() {
|
|
longTouchTimer = null;
|
|
clearTimeout(longTouchTimer);
|
|
editor.selection.moveToPosition(pos);
|
|
var range = clickCount >= 2
|
|
? editor.selection.getLineRange(pos.row)
|
|
: editor.session.getBracketRange(pos);
|
|
if (range && !range.isEmpty()) {
|
|
editor.selection.setRange(range);
|
|
} else {
|
|
editor.selection.selectWord();
|
|
}
|
|
mode = "wait";
|
|
}
|
|
event.addListener(el, "contextmenu", function(e) {
|
|
if (!pressed) return;
|
|
var textarea = editor.textInput.getElement();
|
|
textarea.focus();
|
|
}, editor);
|
|
event.addListener(el, "touchstart", function (e) {
|
|
var touches = e.touches;
|
|
if (longTouchTimer || touches.length > 1) {
|
|
clearTimeout(longTouchTimer);
|
|
longTouchTimer = null;
|
|
touchStartT = -1;
|
|
mode = "zoom";
|
|
return;
|
|
}
|
|
|
|
pressed = editor.$mouseHandler.isMousePressed = true;
|
|
var h = editor.renderer.layerConfig.lineHeight;
|
|
var w = editor.renderer.layerConfig.lineHeight;
|
|
var t = e.timeStamp;
|
|
lastT = t;
|
|
var touchObj = touches[0];
|
|
var x = touchObj.clientX;
|
|
var y = touchObj.clientY;
|
|
if (Math.abs(startX - x) + Math.abs(startY - y) > h)
|
|
touchStartT = -1;
|
|
|
|
startX = e.clientX = x;
|
|
startY = e.clientY = y;
|
|
vX = vY = 0;
|
|
|
|
var ev = new MouseEvent(e, editor);
|
|
pos = ev.getDocumentPosition();
|
|
|
|
if (t - touchStartT < 500 && touches.length == 1 && !animationSteps) {
|
|
clickCount++;
|
|
e.preventDefault();
|
|
e.button = 0;
|
|
switchToSelectionMode();
|
|
} else {
|
|
clickCount = 0;
|
|
var cursor = editor.selection.cursor;
|
|
var anchor = editor.selection.isEmpty() ? cursor : editor.selection.anchor;
|
|
|
|
var cursorPos = editor.renderer.$cursorLayer.getPixelPosition(cursor, true);
|
|
var anchorPos = editor.renderer.$cursorLayer.getPixelPosition(anchor, true);
|
|
var rect = editor.renderer.scroller.getBoundingClientRect();
|
|
var offsetTop = editor.renderer.layerConfig.offset;
|
|
var offsetLeft = editor.renderer.scrollLeft;
|
|
var weightedDistance = function(x, y) {
|
|
x = x / w;
|
|
y = y / h - 0.75;
|
|
return x * x + y * y;
|
|
};
|
|
|
|
if (e.clientX < rect.left) {
|
|
mode = "zoom";
|
|
return;
|
|
}
|
|
|
|
var diff1 = weightedDistance(
|
|
e.clientX - rect.left - cursorPos.left + offsetLeft,
|
|
e.clientY - rect.top - cursorPos.top + offsetTop
|
|
);
|
|
var diff2 = weightedDistance(
|
|
e.clientX - rect.left - anchorPos.left + offsetLeft,
|
|
e.clientY - rect.top - anchorPos.top + offsetTop
|
|
);
|
|
if (diff1 < 3.5 && diff2 < 3.5)
|
|
mode = diff1 > diff2 ? "cursor" : "anchor";
|
|
|
|
if (diff2 < 3.5)
|
|
mode = "anchor";
|
|
else if (diff1 < 3.5)
|
|
mode = "cursor";
|
|
else
|
|
mode = "scroll";
|
|
longTouchTimer = setTimeout(handleLongTap, 450);
|
|
}
|
|
touchStartT = t;
|
|
}, editor);
|
|
|
|
event.addListener(el, "touchend", function (e) {
|
|
pressed = editor.$mouseHandler.isMousePressed = false;
|
|
if (animationTimer) clearInterval(animationTimer);
|
|
if (mode == "zoom") {
|
|
mode = "";
|
|
animationSteps = 0;
|
|
} else if (longTouchTimer) {
|
|
editor.selection.moveToPosition(pos);
|
|
animationSteps = 0;
|
|
showContextMenu();
|
|
} else if (mode == "scroll") {
|
|
animate();
|
|
hideContextMenu();
|
|
} else {
|
|
showContextMenu();
|
|
}
|
|
clearTimeout(longTouchTimer);
|
|
longTouchTimer = null;
|
|
}, editor);
|
|
event.addListener(el, "touchmove", function (e) {
|
|
if (longTouchTimer) {
|
|
clearTimeout(longTouchTimer);
|
|
longTouchTimer = null;
|
|
}
|
|
var touches = e.touches;
|
|
if (touches.length > 1 || mode == "zoom") return;
|
|
|
|
var touchObj = touches[0];
|
|
|
|
var wheelX = startX - touchObj.clientX;
|
|
var wheelY = startY - touchObj.clientY;
|
|
|
|
if (mode == "wait") {
|
|
if (wheelX * wheelX + wheelY * wheelY > 4)
|
|
mode = "cursor";
|
|
else
|
|
return e.preventDefault();
|
|
}
|
|
|
|
startX = touchObj.clientX;
|
|
startY = touchObj.clientY;
|
|
|
|
e.clientX = touchObj.clientX;
|
|
e.clientY = touchObj.clientY;
|
|
|
|
var t = e.timeStamp;
|
|
var dt = t - lastT;
|
|
lastT = t;
|
|
if (mode == "scroll") {
|
|
var mouseEvent = new MouseEvent(e, editor);
|
|
mouseEvent.speed = 1;
|
|
mouseEvent.wheelX = wheelX;
|
|
mouseEvent.wheelY = wheelY;
|
|
if (10 * Math.abs(wheelX) < Math.abs(wheelY)) wheelX = 0;
|
|
if (10 * Math.abs(wheelY) < Math.abs(wheelX)) wheelY = 0;
|
|
if (dt != 0) {
|
|
vX = wheelX / dt;
|
|
vY = wheelY / dt;
|
|
}
|
|
editor._emit("mousewheel", mouseEvent);
|
|
if (!mouseEvent.propagationStopped) {
|
|
vX = vY = 0;
|
|
}
|
|
}
|
|
else {
|
|
var ev = new MouseEvent(e, editor);
|
|
var pos = ev.getDocumentPosition();
|
|
if (mode == "cursor")
|
|
editor.selection.moveCursorToPosition(pos);
|
|
else if (mode == "anchor")
|
|
editor.selection.setSelectionAnchor(pos.row, pos.column);
|
|
editor.renderer.scrollCursorIntoView(pos);
|
|
e.preventDefault();
|
|
}
|
|
}, editor);
|
|
|
|
function animate() {
|
|
animationSteps += 60;
|
|
animationTimer = setInterval(function() {
|
|
if (animationSteps-- <= 0) {
|
|
clearInterval(animationTimer);
|
|
animationTimer = null;
|
|
}
|
|
if (Math.abs(vX) < 0.01) vX = 0;
|
|
if (Math.abs(vY) < 0.01) vY = 0;
|
|
if (animationSteps < 20) vX = 0.9 * vX;
|
|
if (animationSteps < 20) vY = 0.9 * vY;
|
|
var oldScrollTop = editor.session.getScrollTop();
|
|
editor.renderer.scrollBy(10 * vX, 10 * vY);
|
|
if (oldScrollTop == editor.session.getScrollTop())
|
|
animationSteps = 0;
|
|
}, 10);
|
|
}
|
|
};
|
|
|
|
});
|
|
|
|
ace.define("ace/lib/net",["require","exports","module","ace/lib/dom"], function(require, exports, module) {
|
|
"use strict";
|
|
var dom = require("./dom");
|
|
|
|
exports.get = function (url, callback) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open('GET', url, true);
|
|
xhr.onreadystatechange = function () {
|
|
if (xhr.readyState === 4) {
|
|
callback(xhr.responseText);
|
|
}
|
|
};
|
|
xhr.send(null);
|
|
};
|
|
|
|
exports.loadScript = function(path, callback) {
|
|
var head = dom.getDocumentHead();
|
|
var s = document.createElement('script');
|
|
|
|
s.src = path;
|
|
head.appendChild(s);
|
|
|
|
s.onload = s.onreadystatechange = function(_, isAbort) {
|
|
if (isAbort || !s.readyState || s.readyState == "loaded" || s.readyState == "complete") {
|
|
s = s.onload = s.onreadystatechange = null;
|
|
if (!isAbort)
|
|
callback();
|
|
}
|
|
};
|
|
};
|
|
exports.qualifyURL = function(url) {
|
|
var a = document.createElement('a');
|
|
a.href = url;
|
|
return a.href;
|
|
};
|
|
|
|
});
|
|
|
|
ace.define("ace/lib/event_emitter",["require","exports","module"], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var EventEmitter = {};
|
|
var stopPropagation = function() { this.propagationStopped = true; };
|
|
var preventDefault = function() { this.defaultPrevented = true; };
|
|
|
|
EventEmitter._emit =
|
|
EventEmitter._dispatchEvent = function(eventName, e) {
|
|
this._eventRegistry || (this._eventRegistry = {});
|
|
this._defaultHandlers || (this._defaultHandlers = {});
|
|
|
|
var listeners = this._eventRegistry[eventName] || [];
|
|
var defaultHandler = this._defaultHandlers[eventName];
|
|
if (!listeners.length && !defaultHandler)
|
|
return;
|
|
|
|
if (typeof e != "object" || !e)
|
|
e = {};
|
|
|
|
if (!e.type)
|
|
e.type = eventName;
|
|
if (!e.stopPropagation)
|
|
e.stopPropagation = stopPropagation;
|
|
if (!e.preventDefault)
|
|
e.preventDefault = preventDefault;
|
|
|
|
listeners = listeners.slice();
|
|
for (var i=0; i<listeners.length; i++) {
|
|
listeners[i](e, this);
|
|
if (e.propagationStopped)
|
|
break;
|
|
}
|
|
|
|
if (defaultHandler && !e.defaultPrevented)
|
|
return defaultHandler(e, this);
|
|
};
|
|
|
|
|
|
EventEmitter._signal = function(eventName, e) {
|
|
var listeners = (this._eventRegistry || {})[eventName];
|
|
if (!listeners)
|
|
return;
|
|
listeners = listeners.slice();
|
|
for (var i=0; i<listeners.length; i++)
|
|
listeners[i](e, this);
|
|
};
|
|
|
|
EventEmitter.once = function(eventName, callback) {
|
|
var _self = this;
|
|
this.on(eventName, function newCallback() {
|
|
_self.off(eventName, newCallback);
|
|
callback.apply(null, arguments);
|
|
});
|
|
if (!callback) {
|
|
return new Promise(function(resolve) {
|
|
callback = resolve;
|
|
});
|
|
}
|
|
};
|
|
|
|
|
|
EventEmitter.setDefaultHandler = function(eventName, callback) {
|
|
var handlers = this._defaultHandlers;
|
|
if (!handlers)
|
|
handlers = this._defaultHandlers = {_disabled_: {}};
|
|
|
|
if (handlers[eventName]) {
|
|
var old = handlers[eventName];
|
|
var disabled = handlers._disabled_[eventName];
|
|
if (!disabled)
|
|
handlers._disabled_[eventName] = disabled = [];
|
|
disabled.push(old);
|
|
var i = disabled.indexOf(callback);
|
|
if (i != -1)
|
|
disabled.splice(i, 1);
|
|
}
|
|
handlers[eventName] = callback;
|
|
};
|
|
EventEmitter.removeDefaultHandler = function(eventName, callback) {
|
|
var handlers = this._defaultHandlers;
|
|
if (!handlers)
|
|
return;
|
|
var disabled = handlers._disabled_[eventName];
|
|
|
|
if (handlers[eventName] == callback) {
|
|
if (disabled)
|
|
this.setDefaultHandler(eventName, disabled.pop());
|
|
} else if (disabled) {
|
|
var i = disabled.indexOf(callback);
|
|
if (i != -1)
|
|
disabled.splice(i, 1);
|
|
}
|
|
};
|
|
|
|
EventEmitter.on =
|
|
EventEmitter.addEventListener = function(eventName, callback, capturing) {
|
|
this._eventRegistry = this._eventRegistry || {};
|
|
|
|
var listeners = this._eventRegistry[eventName];
|
|
if (!listeners)
|
|
listeners = this._eventRegistry[eventName] = [];
|
|
|
|
if (listeners.indexOf(callback) == -1)
|
|
listeners[capturing ? "unshift" : "push"](callback);
|
|
return callback;
|
|
};
|
|
|
|
EventEmitter.off =
|
|
EventEmitter.removeListener =
|
|
EventEmitter.removeEventListener = function(eventName, callback) {
|
|
this._eventRegistry = this._eventRegistry || {};
|
|
|
|
var listeners = this._eventRegistry[eventName];
|
|
if (!listeners)
|
|
return;
|
|
|
|
var index = listeners.indexOf(callback);
|
|
if (index !== -1)
|
|
listeners.splice(index, 1);
|
|
};
|
|
|
|
EventEmitter.removeAllListeners = function(eventName) {
|
|
if (!eventName) this._eventRegistry = this._defaultHandlers = undefined;
|
|
if (this._eventRegistry) this._eventRegistry[eventName] = undefined;
|
|
if (this._defaultHandlers) this._defaultHandlers[eventName] = undefined;
|
|
};
|
|
|
|
exports.EventEmitter = EventEmitter;
|
|
|
|
});
|
|
|
|
ace.define("ace/lib/app_config",["require","exports","module","ace/lib/oop","ace/lib/event_emitter"], function(require, exports, module) {
|
|
"no use strict";
|
|
|
|
var oop = require("./oop");
|
|
var EventEmitter = require("./event_emitter").EventEmitter;
|
|
|
|
var optionsProvider = {
|
|
setOptions: function(optList) {
|
|
Object.keys(optList).forEach(function(key) {
|
|
this.setOption(key, optList[key]);
|
|
}, this);
|
|
},
|
|
getOptions: function(optionNames) {
|
|
var result = {};
|
|
if (!optionNames) {
|
|
var options = this.$options;
|
|
optionNames = Object.keys(options).filter(function(key) {
|
|
return !options[key].hidden;
|
|
});
|
|
} else if (!Array.isArray(optionNames)) {
|
|
result = optionNames;
|
|
optionNames = Object.keys(result);
|
|
}
|
|
optionNames.forEach(function(key) {
|
|
result[key] = this.getOption(key);
|
|
}, this);
|
|
return result;
|
|
},
|
|
setOption: function(name, value) {
|
|
if (this["$" + name] === value)
|
|
return;
|
|
var opt = this.$options[name];
|
|
if (!opt) {
|
|
return warn('misspelled option "' + name + '"');
|
|
}
|
|
if (opt.forwardTo)
|
|
return this[opt.forwardTo] && this[opt.forwardTo].setOption(name, value);
|
|
|
|
if (!opt.handlesSet)
|
|
this["$" + name] = value;
|
|
if (opt && opt.set)
|
|
opt.set.call(this, value);
|
|
},
|
|
getOption: function(name) {
|
|
var opt = this.$options[name];
|
|
if (!opt) {
|
|
return warn('misspelled option "' + name + '"');
|
|
}
|
|
if (opt.forwardTo)
|
|
return this[opt.forwardTo] && this[opt.forwardTo].getOption(name);
|
|
return opt && opt.get ? opt.get.call(this) : this["$" + name];
|
|
}
|
|
};
|
|
|
|
function warn(message) {
|
|
if (typeof console != "undefined" && console.warn)
|
|
console.warn.apply(console, arguments);
|
|
}
|
|
|
|
function reportError(msg, data) {
|
|
var e = new Error(msg);
|
|
e.data = data;
|
|
if (typeof console == "object" && console.error)
|
|
console.error(e);
|
|
setTimeout(function() { throw e; });
|
|
}
|
|
|
|
var AppConfig = function() {
|
|
this.$defaultOptions = {};
|
|
};
|
|
|
|
(function() {
|
|
oop.implement(this, EventEmitter);
|
|
this.defineOptions = function(obj, path, options) {
|
|
if (!obj.$options)
|
|
this.$defaultOptions[path] = obj.$options = {};
|
|
|
|
Object.keys(options).forEach(function(key) {
|
|
var opt = options[key];
|
|
if (typeof opt == "string")
|
|
opt = {forwardTo: opt};
|
|
|
|
opt.name || (opt.name = key);
|
|
obj.$options[opt.name] = opt;
|
|
if ("initialValue" in opt)
|
|
obj["$" + opt.name] = opt.initialValue;
|
|
});
|
|
oop.implement(obj, optionsProvider);
|
|
|
|
return this;
|
|
};
|
|
|
|
this.resetOptions = function(obj) {
|
|
Object.keys(obj.$options).forEach(function(key) {
|
|
var opt = obj.$options[key];
|
|
if ("value" in opt)
|
|
obj.setOption(key, opt.value);
|
|
});
|
|
};
|
|
|
|
this.setDefaultValue = function(path, name, value) {
|
|
if (!path) {
|
|
for (path in this.$defaultOptions)
|
|
if (this.$defaultOptions[path][name])
|
|
break;
|
|
if (!this.$defaultOptions[path][name])
|
|
return false;
|
|
}
|
|
var opts = this.$defaultOptions[path] || (this.$defaultOptions[path] = {});
|
|
if (opts[name]) {
|
|
if (opts.forwardTo)
|
|
this.setDefaultValue(opts.forwardTo, name, value);
|
|
else
|
|
opts[name].value = value;
|
|
}
|
|
};
|
|
|
|
this.setDefaultValues = function(path, optionHash) {
|
|
Object.keys(optionHash).forEach(function(key) {
|
|
this.setDefaultValue(path, key, optionHash[key]);
|
|
}, this);
|
|
};
|
|
|
|
this.warn = warn;
|
|
this.reportError = reportError;
|
|
|
|
}).call(AppConfig.prototype);
|
|
|
|
exports.AppConfig = AppConfig;
|
|
|
|
});
|
|
|
|
ace.define("ace/config",["require","exports","module","ace/lib/lang","ace/lib/oop","ace/lib/net","ace/lib/app_config"], function(require, exports, module) {
|
|
"no use strict";
|
|
|
|
var lang = require("./lib/lang");
|
|
var oop = require("./lib/oop");
|
|
var net = require("./lib/net");
|
|
var AppConfig = require("./lib/app_config").AppConfig;
|
|
|
|
module.exports = exports = new AppConfig();
|
|
|
|
var global = (function() {
|
|
return this || typeof window != "undefined" && window;
|
|
})();
|
|
|
|
var options = {
|
|
packaged: false,
|
|
workerPath: null,
|
|
modePath: null,
|
|
themePath: null,
|
|
basePath: "",
|
|
suffix: ".js",
|
|
$moduleUrls: {},
|
|
loadWorkerFromBlob: true,
|
|
sharedPopups: false
|
|
};
|
|
|
|
exports.get = function(key) {
|
|
if (!options.hasOwnProperty(key))
|
|
throw new Error("Unknown config key: " + key);
|
|
|
|
return options[key];
|
|
};
|
|
|
|
exports.set = function(key, value) {
|
|
if (options.hasOwnProperty(key))
|
|
options[key] = value;
|
|
else if (this.setDefaultValue("", key, value) == false)
|
|
throw new Error("Unknown config key: " + key);
|
|
};
|
|
|
|
exports.all = function() {
|
|
return lang.copyObject(options);
|
|
};
|
|
|
|
exports.$modes = {};
|
|
exports.moduleUrl = function(name, component) {
|
|
if (options.$moduleUrls[name])
|
|
return options.$moduleUrls[name];
|
|
|
|
var parts = name.split("/");
|
|
component = component || parts[parts.length - 2] || "";
|
|
var sep = component == "snippets" ? "/" : "-";
|
|
var base = parts[parts.length - 1];
|
|
if (component == "worker" && sep == "-") {
|
|
var re = new RegExp("^" + component + "[\\-_]|[\\-_]" + component + "$", "g");
|
|
base = base.replace(re, "");
|
|
}
|
|
|
|
if ((!base || base == component) && parts.length > 1)
|
|
base = parts[parts.length - 2];
|
|
var path = options[component + "Path"];
|
|
if (path == null) {
|
|
path = options.basePath;
|
|
} else if (sep == "/") {
|
|
component = sep = "";
|
|
}
|
|
if (path && path.slice(-1) != "/")
|
|
path += "/";
|
|
return path + component + sep + base + this.get("suffix");
|
|
};
|
|
|
|
exports.setModuleUrl = function(name, subst) {
|
|
return options.$moduleUrls[name] = subst;
|
|
};
|
|
|
|
exports.$loading = {};
|
|
exports.loadModule = function(moduleName, onLoad) {
|
|
var module, moduleType;
|
|
if (Array.isArray(moduleName)) {
|
|
moduleType = moduleName[0];
|
|
moduleName = moduleName[1];
|
|
}
|
|
|
|
try {
|
|
module = require(moduleName);
|
|
} catch (e) {}
|
|
if (module && !exports.$loading[moduleName])
|
|
return onLoad && onLoad(module);
|
|
|
|
if (!exports.$loading[moduleName])
|
|
exports.$loading[moduleName] = [];
|
|
|
|
exports.$loading[moduleName].push(onLoad);
|
|
|
|
if (exports.$loading[moduleName].length > 1)
|
|
return;
|
|
|
|
var afterLoad = function() {
|
|
require([moduleName], function(module) {
|
|
exports._emit("load.module", {name: moduleName, module: module});
|
|
var listeners = exports.$loading[moduleName];
|
|
exports.$loading[moduleName] = null;
|
|
listeners.forEach(function(onLoad) {
|
|
onLoad && onLoad(module);
|
|
});
|
|
});
|
|
};
|
|
|
|
if (!exports.get("packaged"))
|
|
return afterLoad();
|
|
|
|
net.loadScript(exports.moduleUrl(moduleName, moduleType), afterLoad);
|
|
reportErrorIfPathIsNotConfigured();
|
|
};
|
|
|
|
var reportErrorIfPathIsNotConfigured = function() {
|
|
if (
|
|
!options.basePath && !options.workerPath
|
|
&& !options.modePath && !options.themePath
|
|
&& !Object.keys(options.$moduleUrls).length
|
|
) {
|
|
console.error(
|
|
"Unable to infer path to ace from script src,",
|
|
"use ace.config.set('basePath', 'path') to enable dynamic loading of modes and themes",
|
|
"or with webpack use ace/webpack-resolver"
|
|
);
|
|
reportErrorIfPathIsNotConfigured = function() {};
|
|
}
|
|
};
|
|
init(true);function init(packaged) {
|
|
|
|
if (!global || !global.document)
|
|
return;
|
|
|
|
options.packaged = packaged || require.packaged || module.packaged || (global.define && __webpack_require__.amdD.packaged);
|
|
|
|
var scriptOptions = {};
|
|
var scriptUrl = "";
|
|
var currentScript = (document.currentScript || document._currentScript ); // native or polyfill
|
|
var currentDocument = currentScript && currentScript.ownerDocument || document;
|
|
|
|
var scripts = currentDocument.getElementsByTagName("script");
|
|
for (var i=0; i<scripts.length; i++) {
|
|
var script = scripts[i];
|
|
|
|
var src = script.src || script.getAttribute("src");
|
|
if (!src)
|
|
continue;
|
|
|
|
var attributes = script.attributes;
|
|
for (var j=0, l=attributes.length; j < l; j++) {
|
|
var attr = attributes[j];
|
|
if (attr.name.indexOf("data-ace-") === 0) {
|
|
scriptOptions[deHyphenate(attr.name.replace(/^data-ace-/, ""))] = attr.value;
|
|
}
|
|
}
|
|
|
|
var m = src.match(/^(.*)\/ace(\-\w+)?\.js(\?|$)/);
|
|
if (m)
|
|
scriptUrl = m[1];
|
|
}
|
|
|
|
if (scriptUrl) {
|
|
scriptOptions.base = scriptOptions.base || scriptUrl;
|
|
scriptOptions.packaged = true;
|
|
}
|
|
|
|
scriptOptions.basePath = scriptOptions.base;
|
|
scriptOptions.workerPath = scriptOptions.workerPath || scriptOptions.base;
|
|
scriptOptions.modePath = scriptOptions.modePath || scriptOptions.base;
|
|
scriptOptions.themePath = scriptOptions.themePath || scriptOptions.base;
|
|
delete scriptOptions.base;
|
|
|
|
for (var key in scriptOptions)
|
|
if (typeof scriptOptions[key] !== "undefined")
|
|
exports.set(key, scriptOptions[key]);
|
|
}
|
|
|
|
exports.init = init;
|
|
|
|
function deHyphenate(str) {
|
|
return str.replace(/-(.)/g, function(m, m1) { return m1.toUpperCase(); });
|
|
}
|
|
|
|
exports.version = "1.4.12";
|
|
|
|
});
|
|
|
|
ace.define("ace/mouse/mouse_handler",["require","exports","module","ace/lib/event","ace/lib/useragent","ace/mouse/default_handlers","ace/mouse/default_gutter_handler","ace/mouse/mouse_event","ace/mouse/dragdrop_handler","ace/mouse/touch_handler","ace/config"], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var event = require("../lib/event");
|
|
var useragent = require("../lib/useragent");
|
|
var DefaultHandlers = require("./default_handlers").DefaultHandlers;
|
|
var DefaultGutterHandler = require("./default_gutter_handler").GutterHandler;
|
|
var MouseEvent = require("./mouse_event").MouseEvent;
|
|
var DragdropHandler = require("./dragdrop_handler").DragdropHandler;
|
|
var addTouchListeners = require("./touch_handler").addTouchListeners;
|
|
var config = require("../config");
|
|
|
|
var MouseHandler = function(editor) {
|
|
var _self = this;
|
|
this.editor = editor;
|
|
|
|
new DefaultHandlers(this);
|
|
new DefaultGutterHandler(this);
|
|
new DragdropHandler(this);
|
|
|
|
var focusEditor = function(e) {
|
|
var windowBlurred = !document.hasFocus || !document.hasFocus()
|
|
|| !editor.isFocused() && document.activeElement == (editor.textInput && editor.textInput.getElement());
|
|
if (windowBlurred)
|
|
window.focus();
|
|
editor.focus();
|
|
};
|
|
|
|
var mouseTarget = editor.renderer.getMouseEventTarget();
|
|
event.addListener(mouseTarget, "click", this.onMouseEvent.bind(this, "click"), editor);
|
|
event.addListener(mouseTarget, "mousemove", this.onMouseMove.bind(this, "mousemove"), editor);
|
|
event.addMultiMouseDownListener([
|
|
mouseTarget,
|
|
editor.renderer.scrollBarV && editor.renderer.scrollBarV.inner,
|
|
editor.renderer.scrollBarH && editor.renderer.scrollBarH.inner,
|
|
editor.textInput && editor.textInput.getElement()
|
|
].filter(Boolean), [400, 300, 250], this, "onMouseEvent", editor);
|
|
event.addMouseWheelListener(editor.container, this.onMouseWheel.bind(this, "mousewheel"), editor);
|
|
addTouchListeners(editor.container, editor);
|
|
|
|
var gutterEl = editor.renderer.$gutter;
|
|
event.addListener(gutterEl, "mousedown", this.onMouseEvent.bind(this, "guttermousedown"), editor);
|
|
event.addListener(gutterEl, "click", this.onMouseEvent.bind(this, "gutterclick"), editor);
|
|
event.addListener(gutterEl, "dblclick", this.onMouseEvent.bind(this, "gutterdblclick"), editor);
|
|
event.addListener(gutterEl, "mousemove", this.onMouseEvent.bind(this, "guttermousemove"), editor);
|
|
|
|
event.addListener(mouseTarget, "mousedown", focusEditor, editor);
|
|
event.addListener(gutterEl, "mousedown", focusEditor, editor);
|
|
if (useragent.isIE && editor.renderer.scrollBarV) {
|
|
event.addListener(editor.renderer.scrollBarV.element, "mousedown", focusEditor, editor);
|
|
event.addListener(editor.renderer.scrollBarH.element, "mousedown", focusEditor, editor);
|
|
}
|
|
|
|
editor.on("mousemove", function(e){
|
|
if (_self.state || _self.$dragDelay || !_self.$dragEnabled)
|
|
return;
|
|
|
|
var character = editor.renderer.screenToTextCoordinates(e.x, e.y);
|
|
var range = editor.session.selection.getRange();
|
|
var renderer = editor.renderer;
|
|
|
|
if (!range.isEmpty() && range.insideStart(character.row, character.column)) {
|
|
renderer.setCursorStyle("default");
|
|
} else {
|
|
renderer.setCursorStyle("");
|
|
}
|
|
}, editor);
|
|
};
|
|
|
|
(function() {
|
|
this.onMouseEvent = function(name, e) {
|
|
this.editor._emit(name, new MouseEvent(e, this.editor));
|
|
};
|
|
|
|
this.onMouseMove = function(name, e) {
|
|
var listeners = this.editor._eventRegistry && this.editor._eventRegistry.mousemove;
|
|
if (!listeners || !listeners.length)
|
|
return;
|
|
|
|
this.editor._emit(name, new MouseEvent(e, this.editor));
|
|
};
|
|
|
|
this.onMouseWheel = function(name, e) {
|
|
var mouseEvent = new MouseEvent(e, this.editor);
|
|
mouseEvent.speed = this.$scrollSpeed * 2;
|
|
mouseEvent.wheelX = e.wheelX;
|
|
mouseEvent.wheelY = e.wheelY;
|
|
|
|
this.editor._emit(name, mouseEvent);
|
|
};
|
|
|
|
this.setState = function(state) {
|
|
this.state = state;
|
|
};
|
|
|
|
this.captureMouse = function(ev, mouseMoveHandler) {
|
|
this.x = ev.x;
|
|
this.y = ev.y;
|
|
|
|
this.isMousePressed = true;
|
|
var editor = this.editor;
|
|
var renderer = this.editor.renderer;
|
|
renderer.$isMousePressed = true;
|
|
|
|
var self = this;
|
|
var onMouseMove = function(e) {
|
|
if (!e) return;
|
|
if (useragent.isWebKit && !e.which && self.releaseMouse)
|
|
return self.releaseMouse();
|
|
|
|
self.x = e.clientX;
|
|
self.y = e.clientY;
|
|
mouseMoveHandler && mouseMoveHandler(e);
|
|
self.mouseEvent = new MouseEvent(e, self.editor);
|
|
self.$mouseMoved = true;
|
|
};
|
|
|
|
var onCaptureEnd = function(e) {
|
|
editor.off("beforeEndOperation", onOperationEnd);
|
|
clearInterval(timerId);
|
|
onCaptureInterval();
|
|
self[self.state + "End"] && self[self.state + "End"](e);
|
|
self.state = "";
|
|
self.isMousePressed = renderer.$isMousePressed = false;
|
|
if (renderer.$keepTextAreaAtCursor)
|
|
renderer.$moveTextAreaToCursor();
|
|
self.$onCaptureMouseMove = self.releaseMouse = null;
|
|
e && self.onMouseEvent("mouseup", e);
|
|
editor.endOperation();
|
|
};
|
|
|
|
var onCaptureInterval = function() {
|
|
self[self.state] && self[self.state]();
|
|
self.$mouseMoved = false;
|
|
};
|
|
|
|
if (useragent.isOldIE && ev.domEvent.type == "dblclick") {
|
|
return setTimeout(function() {onCaptureEnd(ev);});
|
|
}
|
|
|
|
var onOperationEnd = function(e) {
|
|
if (!self.releaseMouse) return;
|
|
if (editor.curOp.command.name && editor.curOp.selectionChanged) {
|
|
self[self.state + "End"] && self[self.state + "End"]();
|
|
self.state = "";
|
|
self.releaseMouse();
|
|
}
|
|
};
|
|
|
|
editor.on("beforeEndOperation", onOperationEnd);
|
|
editor.startOperation({command: {name: "mouse"}});
|
|
|
|
self.$onCaptureMouseMove = onMouseMove;
|
|
self.releaseMouse = event.capture(this.editor.container, onMouseMove, onCaptureEnd);
|
|
var timerId = setInterval(onCaptureInterval, 20);
|
|
};
|
|
this.releaseMouse = null;
|
|
this.cancelContextMenu = function() {
|
|
var stop = function(e) {
|
|
if (e && e.domEvent && e.domEvent.type != "contextmenu")
|
|
return;
|
|
this.editor.off("nativecontextmenu", stop);
|
|
if (e && e.domEvent)
|
|
event.stopEvent(e.domEvent);
|
|
}.bind(this);
|
|
setTimeout(stop, 10);
|
|
this.editor.on("nativecontextmenu", stop);
|
|
};
|
|
this.destroy = function() {
|
|
if (this.releaseMouse) this.releaseMouse();
|
|
};
|
|
}).call(MouseHandler.prototype);
|
|
|
|
config.defineOptions(MouseHandler.prototype, "mouseHandler", {
|
|
scrollSpeed: {initialValue: 2},
|
|
dragDelay: {initialValue: (useragent.isMac ? 150 : 0)},
|
|
dragEnabled: {initialValue: true},
|
|
focusTimeout: {initialValue: 0},
|
|
tooltipFollowsMouse: {initialValue: true}
|
|
});
|
|
|
|
|
|
exports.MouseHandler = MouseHandler;
|
|
});
|
|
|
|
ace.define("ace/mouse/fold_handler",["require","exports","module","ace/lib/dom"], function(require, exports, module) {
|
|
"use strict";
|
|
var dom = require("../lib/dom");
|
|
|
|
function FoldHandler(editor) {
|
|
|
|
editor.on("click", function(e) {
|
|
var position = e.getDocumentPosition();
|
|
var session = editor.session;
|
|
var fold = session.getFoldAt(position.row, position.column, 1);
|
|
if (fold) {
|
|
if (e.getAccelKey())
|
|
session.removeFold(fold);
|
|
else
|
|
session.expandFold(fold);
|
|
|
|
e.stop();
|
|
}
|
|
|
|
var target = e.domEvent && e.domEvent.target;
|
|
if (target && dom.hasCssClass(target, "ace_inline_button")) {
|
|
if (dom.hasCssClass(target, "ace_toggle_wrap")) {
|
|
session.setOption("wrap", !session.getUseWrapMode());
|
|
editor.renderer.scrollCursorIntoView();
|
|
}
|
|
}
|
|
});
|
|
|
|
editor.on("gutterclick", function(e) {
|
|
var gutterRegion = editor.renderer.$gutterLayer.getRegion(e);
|
|
|
|
if (gutterRegion == "foldWidgets") {
|
|
var row = e.getDocumentPosition().row;
|
|
var session = editor.session;
|
|
if (session.foldWidgets && session.foldWidgets[row])
|
|
editor.session.onFoldWidgetClick(row, e);
|
|
if (!editor.isFocused())
|
|
editor.focus();
|
|
e.stop();
|
|
}
|
|
});
|
|
|
|
editor.on("gutterdblclick", function(e) {
|
|
var gutterRegion = editor.renderer.$gutterLayer.getRegion(e);
|
|
|
|
if (gutterRegion == "foldWidgets") {
|
|
var row = e.getDocumentPosition().row;
|
|
var session = editor.session;
|
|
var data = session.getParentFoldRangeData(row, true);
|
|
var range = data.range || data.firstRange;
|
|
|
|
if (range) {
|
|
row = range.start.row;
|
|
var fold = session.getFoldAt(row, session.getLine(row).length, 1);
|
|
|
|
if (fold) {
|
|
session.removeFold(fold);
|
|
} else {
|
|
session.addFold("...", range);
|
|
editor.renderer.scrollCursorIntoView({row: range.start.row, column: 0});
|
|
}
|
|
}
|
|
e.stop();
|
|
}
|
|
});
|
|
}
|
|
|
|
exports.FoldHandler = FoldHandler;
|
|
|
|
});
|
|
|
|
ace.define("ace/keyboard/keybinding",["require","exports","module","ace/lib/keys","ace/lib/event"], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var keyUtil = require("../lib/keys");
|
|
var event = require("../lib/event");
|
|
|
|
var KeyBinding = function(editor) {
|
|
this.$editor = editor;
|
|
this.$data = {editor: editor};
|
|
this.$handlers = [];
|
|
this.setDefaultHandler(editor.commands);
|
|
};
|
|
|
|
(function() {
|
|
this.setDefaultHandler = function(kb) {
|
|
this.removeKeyboardHandler(this.$defaultHandler);
|
|
this.$defaultHandler = kb;
|
|
this.addKeyboardHandler(kb, 0);
|
|
};
|
|
|
|
this.setKeyboardHandler = function(kb) {
|
|
var h = this.$handlers;
|
|
if (h[h.length - 1] == kb)
|
|
return;
|
|
|
|
while (h[h.length - 1] && h[h.length - 1] != this.$defaultHandler)
|
|
this.removeKeyboardHandler(h[h.length - 1]);
|
|
|
|
this.addKeyboardHandler(kb, 1);
|
|
};
|
|
|
|
this.addKeyboardHandler = function(kb, pos) {
|
|
if (!kb)
|
|
return;
|
|
if (typeof kb == "function" && !kb.handleKeyboard)
|
|
kb.handleKeyboard = kb;
|
|
var i = this.$handlers.indexOf(kb);
|
|
if (i != -1)
|
|
this.$handlers.splice(i, 1);
|
|
|
|
if (pos == undefined)
|
|
this.$handlers.push(kb);
|
|
else
|
|
this.$handlers.splice(pos, 0, kb);
|
|
|
|
if (i == -1 && kb.attach)
|
|
kb.attach(this.$editor);
|
|
};
|
|
|
|
this.removeKeyboardHandler = function(kb) {
|
|
var i = this.$handlers.indexOf(kb);
|
|
if (i == -1)
|
|
return false;
|
|
this.$handlers.splice(i, 1);
|
|
kb.detach && kb.detach(this.$editor);
|
|
return true;
|
|
};
|
|
|
|
this.getKeyboardHandler = function() {
|
|
return this.$handlers[this.$handlers.length - 1];
|
|
};
|
|
|
|
this.getStatusText = function() {
|
|
var data = this.$data;
|
|
var editor = data.editor;
|
|
return this.$handlers.map(function(h) {
|
|
return h.getStatusText && h.getStatusText(editor, data) || "";
|
|
}).filter(Boolean).join(" ");
|
|
};
|
|
|
|
this.$callKeyboardHandlers = function(hashId, keyString, keyCode, e) {
|
|
var toExecute;
|
|
var success = false;
|
|
var commands = this.$editor.commands;
|
|
|
|
for (var i = this.$handlers.length; i--;) {
|
|
toExecute = this.$handlers[i].handleKeyboard(
|
|
this.$data, hashId, keyString, keyCode, e
|
|
);
|
|
if (!toExecute || !toExecute.command)
|
|
continue;
|
|
if (toExecute.command == "null") {
|
|
success = true;
|
|
} else {
|
|
success = commands.exec(toExecute.command, this.$editor, toExecute.args, e);
|
|
}
|
|
if (success && e && hashId != -1 &&
|
|
toExecute.passEvent != true && toExecute.command.passEvent != true
|
|
) {
|
|
event.stopEvent(e);
|
|
}
|
|
if (success)
|
|
break;
|
|
}
|
|
|
|
if (!success && hashId == -1) {
|
|
toExecute = {command: "insertstring"};
|
|
success = commands.exec("insertstring", this.$editor, keyString);
|
|
}
|
|
|
|
if (success && this.$editor._signal)
|
|
this.$editor._signal("keyboardActivity", toExecute);
|
|
|
|
return success;
|
|
};
|
|
|
|
this.onCommandKey = function(e, hashId, keyCode) {
|
|
var keyString = keyUtil.keyCodeToString(keyCode);
|
|
return this.$callKeyboardHandlers(hashId, keyString, keyCode, e);
|
|
};
|
|
|
|
this.onTextInput = function(text) {
|
|
return this.$callKeyboardHandlers(-1, text);
|
|
};
|
|
|
|
}).call(KeyBinding.prototype);
|
|
|
|
exports.KeyBinding = KeyBinding;
|
|
});
|
|
|
|
ace.define("ace/lib/bidiutil",["require","exports","module"], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var ArabicAlefBetIntervalsBegine = ['\u0621', '\u0641'];
|
|
var ArabicAlefBetIntervalsEnd = ['\u063A', '\u064a'];
|
|
var dir = 0, hiLevel = 0;
|
|
var lastArabic = false, hasUBAT_AL = false, hasUBAT_B = false, hasUBAT_S = false, hasBlockSep = false, hasSegSep = false;
|
|
|
|
var impTab_LTR = [ [ 0, 3, 0, 1, 0, 0, 0 ], [ 0, 3, 0, 1, 2, 2, 0 ], [ 0, 3, 0, 0x11, 2, 0, 1 ], [ 0, 3, 5, 5, 4, 1, 0 ], [ 0, 3, 0x15, 0x15, 4, 0, 1 ], [ 0, 3, 5, 5, 4, 2, 0 ]
|
|
];
|
|
|
|
var impTab_RTL = [ [ 2, 0, 1, 1, 0, 1, 0 ], [ 2, 0, 1, 1, 0, 2, 0 ], [ 2, 0, 2, 1, 3, 2, 0 ], [ 2, 0, 2, 0x21, 3, 1, 1 ]
|
|
];
|
|
|
|
var LTR = 0, RTL = 1;
|
|
|
|
var L = 0;
|
|
var R = 1;
|
|
var EN = 2;
|
|
var AN = 3;
|
|
var ON = 4;
|
|
var B = 5;
|
|
var S = 6;
|
|
var AL = 7;
|
|
var WS = 8;
|
|
var CS = 9;
|
|
var ES = 10;
|
|
var ET = 11;
|
|
var NSM = 12;
|
|
var LRE = 13;
|
|
var RLE = 14;
|
|
var PDF = 15;
|
|
var LRO = 16;
|
|
var RLO = 17;
|
|
var BN = 18;
|
|
|
|
var UnicodeTBL00 = [
|
|
BN,BN,BN,BN,BN,BN,BN,BN,BN,S,B,S,WS,B,BN,BN,
|
|
BN,BN,BN,BN,BN,BN,BN,BN,BN,BN,BN,BN,B,B,B,S,
|
|
WS,ON,ON,ET,ET,ET,ON,ON,ON,ON,ON,ES,CS,ES,CS,CS,
|
|
EN,EN,EN,EN,EN,EN,EN,EN,EN,EN,CS,ON,ON,ON,ON,ON,
|
|
ON,L,L,L,L,L,L,L,L,L,L,L,L,L,L,L,
|
|
L,L,L,L,L,L,L,L,L,L,L,ON,ON,ON,ON,ON,
|
|
ON,L,L,L,L,L,L,L,L,L,L,L,L,L,L,L,
|
|
L,L,L,L,L,L,L,L,L,L,L,ON,ON,ON,ON,BN,
|
|
BN,BN,BN,BN,BN,B,BN,BN,BN,BN,BN,BN,BN,BN,BN,BN,
|
|
BN,BN,BN,BN,BN,BN,BN,BN,BN,BN,BN,BN,BN,BN,BN,BN,
|
|
CS,ON,ET,ET,ET,ET,ON,ON,ON,ON,L,ON,ON,BN,ON,ON,
|
|
ET,ET,EN,EN,ON,L,ON,ON,ON,EN,L,ON,ON,ON,ON,ON
|
|
];
|
|
|
|
var UnicodeTBL20 = [
|
|
WS,WS,WS,WS,WS,WS,WS,WS,WS,WS,WS,BN,BN,BN,L,R ,
|
|
ON,ON,ON,ON,ON,ON,ON,ON,ON,ON,ON,ON,ON,ON,ON,ON,
|
|
ON,ON,ON,ON,ON,ON,ON,ON,WS,B,LRE,RLE,PDF,LRO,RLO,CS,
|
|
ET,ET,ET,ET,ET,ON,ON,ON,ON,ON,ON,ON,ON,ON,ON,ON,
|
|
ON,ON,ON,ON,CS,ON,ON,ON,ON,ON,ON,ON,ON,ON,ON,ON,
|
|
ON,ON,ON,ON,ON,ON,ON,ON,ON,ON,ON,ON,ON,ON,ON,WS
|
|
];
|
|
|
|
function _computeLevels(chars, levels, len, charTypes) {
|
|
var impTab = dir ? impTab_RTL : impTab_LTR
|
|
, prevState = null, newClass = null, newLevel = null, newState = 0
|
|
, action = null, cond = null, condPos = -1, i = null, ix = null, classes = [];
|
|
|
|
if (!charTypes) {
|
|
for (i = 0, charTypes = []; i < len; i++) {
|
|
charTypes[i] = _getCharacterType(chars[i]);
|
|
}
|
|
}
|
|
hiLevel = dir;
|
|
lastArabic = false;
|
|
hasUBAT_AL = false;
|
|
hasUBAT_B = false;
|
|
hasUBAT_S = false;
|
|
for (ix = 0; ix < len; ix++){
|
|
prevState = newState;
|
|
classes[ix] = newClass = _getCharClass(chars, charTypes, classes, ix);
|
|
newState = impTab[prevState][newClass];
|
|
action = newState & 0xF0;
|
|
newState &= 0x0F;
|
|
levels[ix] = newLevel = impTab[newState][5];
|
|
if (action > 0){
|
|
if (action == 0x10){
|
|
for(i = condPos; i < ix; i++){
|
|
levels[i] = 1;
|
|
}
|
|
condPos = -1;
|
|
} else {
|
|
condPos = -1;
|
|
}
|
|
}
|
|
cond = impTab[newState][6];
|
|
if (cond){
|
|
if(condPos == -1){
|
|
condPos = ix;
|
|
}
|
|
}else{
|
|
if (condPos > -1){
|
|
for(i = condPos; i < ix; i++){
|
|
levels[i] = newLevel;
|
|
}
|
|
condPos = -1;
|
|
}
|
|
}
|
|
if (charTypes[ix] == B){
|
|
levels[ix] = 0;
|
|
}
|
|
hiLevel |= newLevel;
|
|
}
|
|
if (hasUBAT_S){
|
|
for(i = 0; i < len; i++){
|
|
if(charTypes[i] == S){
|
|
levels[i] = dir;
|
|
for(var j = i - 1; j >= 0; j--){
|
|
if(charTypes[j] == WS){
|
|
levels[j] = dir;
|
|
}else{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function _invertLevel(lev, levels, _array) {
|
|
if (hiLevel < lev){
|
|
return;
|
|
}
|
|
if (lev == 1 && dir == RTL && !hasUBAT_B){
|
|
_array.reverse();
|
|
return;
|
|
}
|
|
var len = _array.length, start = 0, end, lo, hi, tmp;
|
|
while(start < len){
|
|
if (levels[start] >= lev){
|
|
end = start + 1;
|
|
while(end < len && levels[end] >= lev){
|
|
end++;
|
|
}
|
|
for(lo = start, hi = end - 1 ; lo < hi; lo++, hi--){
|
|
tmp = _array[lo];
|
|
_array[lo] = _array[hi];
|
|
_array[hi] = tmp;
|
|
}
|
|
start = end;
|
|
}
|
|
start++;
|
|
}
|
|
}
|
|
|
|
function _getCharClass(chars, types, classes, ix) {
|
|
var cType = types[ix], wType, nType, len, i;
|
|
switch(cType){
|
|
case L:
|
|
case R:
|
|
lastArabic = false;
|
|
case ON:
|
|
case AN:
|
|
return cType;
|
|
case EN:
|
|
return lastArabic ? AN : EN;
|
|
case AL:
|
|
lastArabic = true;
|
|
hasUBAT_AL = true;
|
|
return R;
|
|
case WS:
|
|
return ON;
|
|
case CS:
|
|
if (ix < 1 || (ix + 1) >= types.length ||
|
|
((wType = classes[ix - 1]) != EN && wType != AN) ||
|
|
((nType = types[ix + 1]) != EN && nType != AN)){
|
|
return ON;
|
|
}
|
|
if (lastArabic){nType = AN;}
|
|
return nType == wType ? nType : ON;
|
|
case ES:
|
|
wType = ix > 0 ? classes[ix - 1] : B;
|
|
if (wType == EN && (ix + 1) < types.length && types[ix + 1] == EN){
|
|
return EN;
|
|
}
|
|
return ON;
|
|
case ET:
|
|
if (ix > 0 && classes[ix - 1] == EN){
|
|
return EN;
|
|
}
|
|
if (lastArabic){
|
|
return ON;
|
|
}
|
|
i = ix + 1;
|
|
len = types.length;
|
|
while (i < len && types[i] == ET){
|
|
i++;
|
|
}
|
|
if (i < len && types[i] == EN){
|
|
return EN;
|
|
}
|
|
return ON;
|
|
case NSM:
|
|
len = types.length;
|
|
i = ix + 1;
|
|
while (i < len && types[i] == NSM){
|
|
i++;
|
|
}
|
|
if (i < len){
|
|
var c = chars[ix], rtlCandidate = (c >= 0x0591 && c <= 0x08FF) || c == 0xFB1E;
|
|
|
|
wType = types[i];
|
|
if (rtlCandidate && (wType == R || wType == AL)){
|
|
return R;
|
|
}
|
|
}
|
|
|
|
if (ix < 1 || (wType = types[ix - 1]) == B){
|
|
return ON;
|
|
}
|
|
return classes[ix - 1];
|
|
case B:
|
|
lastArabic = false;
|
|
hasUBAT_B = true;
|
|
return dir;
|
|
case S:
|
|
hasUBAT_S = true;
|
|
return ON;
|
|
case LRE:
|
|
case RLE:
|
|
case LRO:
|
|
case RLO:
|
|
case PDF:
|
|
lastArabic = false;
|
|
case BN:
|
|
return ON;
|
|
}
|
|
}
|
|
|
|
function _getCharacterType( ch ) {
|
|
var uc = ch.charCodeAt(0), hi = uc >> 8;
|
|
|
|
if (hi == 0) {
|
|
return ((uc > 0x00BF) ? L : UnicodeTBL00[uc]);
|
|
} else if (hi == 5) {
|
|
return (/[\u0591-\u05f4]/.test(ch) ? R : L);
|
|
} else if (hi == 6) {
|
|
if (/[\u0610-\u061a\u064b-\u065f\u06d6-\u06e4\u06e7-\u06ed]/.test(ch))
|
|
return NSM;
|
|
else if (/[\u0660-\u0669\u066b-\u066c]/.test(ch))
|
|
return AN;
|
|
else if (uc == 0x066A)
|
|
return ET;
|
|
else if (/[\u06f0-\u06f9]/.test(ch))
|
|
return EN;
|
|
else
|
|
return AL;
|
|
} else if (hi == 0x20 && uc <= 0x205F) {
|
|
return UnicodeTBL20[uc & 0xFF];
|
|
} else if (hi == 0xFE) {
|
|
return (uc >= 0xFE70 ? AL : ON);
|
|
}
|
|
return ON;
|
|
}
|
|
|
|
function _isArabicDiacritics( ch ) {
|
|
return (ch >= '\u064b' && ch <= '\u0655');
|
|
}
|
|
exports.L = L;
|
|
exports.R = R;
|
|
exports.EN = EN;
|
|
exports.ON_R = 3;
|
|
exports.AN = 4;
|
|
exports.R_H = 5;
|
|
exports.B = 6;
|
|
exports.RLE = 7;
|
|
|
|
exports.DOT = "\xB7";
|
|
exports.doBidiReorder = function(text, textCharTypes, isRtl) {
|
|
if (text.length < 2)
|
|
return {};
|
|
|
|
var chars = text.split(""), logicalFromVisual = new Array(chars.length),
|
|
bidiLevels = new Array(chars.length), levels = [];
|
|
|
|
dir = isRtl ? RTL : LTR;
|
|
|
|
_computeLevels(chars, levels, chars.length, textCharTypes);
|
|
|
|
for (var i = 0; i < logicalFromVisual.length; logicalFromVisual[i] = i, i++);
|
|
|
|
_invertLevel(2, levels, logicalFromVisual);
|
|
_invertLevel(1, levels, logicalFromVisual);
|
|
|
|
for (var i = 0; i < logicalFromVisual.length - 1; i++) { //fix levels to reflect character width
|
|
if (textCharTypes[i] === AN) {
|
|
levels[i] = exports.AN;
|
|
} else if (levels[i] === R && ((textCharTypes[i] > AL && textCharTypes[i] < LRE)
|
|
|| textCharTypes[i] === ON || textCharTypes[i] === BN)) {
|
|
levels[i] = exports.ON_R;
|
|
} else if ((i > 0 && chars[i - 1] === '\u0644') && /\u0622|\u0623|\u0625|\u0627/.test(chars[i])) {
|
|
levels[i - 1] = levels[i] = exports.R_H;
|
|
i++;
|
|
}
|
|
}
|
|
if (chars[chars.length - 1] === exports.DOT)
|
|
levels[chars.length - 1] = exports.B;
|
|
|
|
if (chars[0] === '\u202B')
|
|
levels[0] = exports.RLE;
|
|
|
|
for (var i = 0; i < logicalFromVisual.length; i++) {
|
|
bidiLevels[i] = levels[logicalFromVisual[i]];
|
|
}
|
|
|
|
return {'logicalFromVisual': logicalFromVisual, 'bidiLevels': bidiLevels};
|
|
};
|
|
exports.hasBidiCharacters = function(text, textCharTypes){
|
|
var ret = false;
|
|
for (var i = 0; i < text.length; i++){
|
|
textCharTypes[i] = _getCharacterType(text.charAt(i));
|
|
if (!ret && (textCharTypes[i] == R || textCharTypes[i] == AL || textCharTypes[i] == AN))
|
|
ret = true;
|
|
}
|
|
return ret;
|
|
};
|
|
exports.getVisualFromLogicalIdx = function(logIdx, rowMap) {
|
|
for (var i = 0; i < rowMap.logicalFromVisual.length; i++) {
|
|
if (rowMap.logicalFromVisual[i] == logIdx)
|
|
return i;
|
|
}
|
|
return 0;
|
|
};
|
|
|
|
});
|
|
|
|
ace.define("ace/bidihandler",["require","exports","module","ace/lib/bidiutil","ace/lib/lang"], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var bidiUtil = require("./lib/bidiutil");
|
|
var lang = require("./lib/lang");
|
|
var bidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac\u202B]/;
|
|
var BidiHandler = function(session) {
|
|
this.session = session;
|
|
this.bidiMap = {};
|
|
this.currentRow = null;
|
|
this.bidiUtil = bidiUtil;
|
|
this.charWidths = [];
|
|
this.EOL = "\xAC";
|
|
this.showInvisibles = true;
|
|
this.isRtlDir = false;
|
|
this.$isRtl = false;
|
|
this.line = "";
|
|
this.wrapIndent = 0;
|
|
this.EOF = "\xB6";
|
|
this.RLE = "\u202B";
|
|
this.contentWidth = 0;
|
|
this.fontMetrics = null;
|
|
this.rtlLineOffset = 0;
|
|
this.wrapOffset = 0;
|
|
this.isMoveLeftOperation = false;
|
|
this.seenBidi = bidiRE.test(session.getValue());
|
|
};
|
|
|
|
(function() {
|
|
this.isBidiRow = function(screenRow, docRow, splitIndex) {
|
|
if (!this.seenBidi)
|
|
return false;
|
|
if (screenRow !== this.currentRow) {
|
|
this.currentRow = screenRow;
|
|
this.updateRowLine(docRow, splitIndex);
|
|
this.updateBidiMap();
|
|
}
|
|
return this.bidiMap.bidiLevels;
|
|
};
|
|
|
|
this.onChange = function(delta) {
|
|
if (!this.seenBidi) {
|
|
if (delta.action == "insert" && bidiRE.test(delta.lines.join("\n"))) {
|
|
this.seenBidi = true;
|
|
this.currentRow = null;
|
|
}
|
|
}
|
|
else {
|
|
this.currentRow = null;
|
|
}
|
|
};
|
|
|
|
this.getDocumentRow = function() {
|
|
var docRow = 0;
|
|
var rowCache = this.session.$screenRowCache;
|
|
if (rowCache.length) {
|
|
var index = this.session.$getRowCacheIndex(rowCache, this.currentRow);
|
|
if (index >= 0)
|
|
docRow = this.session.$docRowCache[index];
|
|
}
|
|
|
|
return docRow;
|
|
};
|
|
|
|
this.getSplitIndex = function() {
|
|
var splitIndex = 0;
|
|
var rowCache = this.session.$screenRowCache;
|
|
if (rowCache.length) {
|
|
var currentIndex, prevIndex = this.session.$getRowCacheIndex(rowCache, this.currentRow);
|
|
while (this.currentRow - splitIndex > 0) {
|
|
currentIndex = this.session.$getRowCacheIndex(rowCache, this.currentRow - splitIndex - 1);
|
|
if (currentIndex !== prevIndex)
|
|
break;
|
|
|
|
prevIndex = currentIndex;
|
|
splitIndex++;
|
|
}
|
|
} else {
|
|
splitIndex = this.currentRow;
|
|
}
|
|
|
|
return splitIndex;
|
|
};
|
|
|
|
this.updateRowLine = function(docRow, splitIndex) {
|
|
if (docRow === undefined)
|
|
docRow = this.getDocumentRow();
|
|
|
|
var isLastRow = (docRow === this.session.getLength() - 1),
|
|
endOfLine = isLastRow ? this.EOF : this.EOL;
|
|
|
|
this.wrapIndent = 0;
|
|
this.line = this.session.getLine(docRow);
|
|
this.isRtlDir = this.$isRtl || this.line.charAt(0) === this.RLE;
|
|
if (this.session.$useWrapMode) {
|
|
var splits = this.session.$wrapData[docRow];
|
|
if (splits) {
|
|
if (splitIndex === undefined)
|
|
splitIndex = this.getSplitIndex();
|
|
|
|
if(splitIndex > 0 && splits.length) {
|
|
this.wrapIndent = splits.indent;
|
|
this.wrapOffset = this.wrapIndent * this.charWidths[bidiUtil.L];
|
|
this.line = (splitIndex < splits.length) ?
|
|
this.line.substring(splits[splitIndex - 1], splits[splitIndex]) :
|
|
this.line.substring(splits[splits.length - 1]);
|
|
} else {
|
|
this.line = this.line.substring(0, splits[splitIndex]);
|
|
}
|
|
}
|
|
if (splitIndex == splits.length)
|
|
this.line += (this.showInvisibles) ? endOfLine : bidiUtil.DOT;
|
|
} else {
|
|
this.line += this.showInvisibles ? endOfLine : bidiUtil.DOT;
|
|
}
|
|
var session = this.session, shift = 0, size;
|
|
this.line = this.line.replace(/\t|[\u1100-\u2029, \u202F-\uFFE6]/g, function(ch, i){
|
|
if (ch === '\t' || session.isFullWidth(ch.charCodeAt(0))) {
|
|
size = (ch === '\t') ? session.getScreenTabSize(i + shift) : 2;
|
|
shift += size - 1;
|
|
return lang.stringRepeat(bidiUtil.DOT, size);
|
|
}
|
|
return ch;
|
|
});
|
|
|
|
if (this.isRtlDir) {
|
|
this.fontMetrics.$main.textContent = (this.line.charAt(this.line.length - 1) == bidiUtil.DOT) ? this.line.substr(0, this.line.length - 1) : this.line;
|
|
this.rtlLineOffset = this.contentWidth - this.fontMetrics.$main.getBoundingClientRect().width;
|
|
}
|
|
};
|
|
|
|
this.updateBidiMap = function() {
|
|
var textCharTypes = [];
|
|
if (bidiUtil.hasBidiCharacters(this.line, textCharTypes) || this.isRtlDir) {
|
|
this.bidiMap = bidiUtil.doBidiReorder(this.line, textCharTypes, this.isRtlDir);
|
|
} else {
|
|
this.bidiMap = {};
|
|
}
|
|
};
|
|
this.markAsDirty = function() {
|
|
this.currentRow = null;
|
|
};
|
|
this.updateCharacterWidths = function(fontMetrics) {
|
|
if (this.characterWidth === fontMetrics.$characterSize.width)
|
|
return;
|
|
|
|
this.fontMetrics = fontMetrics;
|
|
var characterWidth = this.characterWidth = fontMetrics.$characterSize.width;
|
|
var bidiCharWidth = fontMetrics.$measureCharWidth("\u05d4");
|
|
|
|
this.charWidths[bidiUtil.L] = this.charWidths[bidiUtil.EN] = this.charWidths[bidiUtil.ON_R] = characterWidth;
|
|
this.charWidths[bidiUtil.R] = this.charWidths[bidiUtil.AN] = bidiCharWidth;
|
|
this.charWidths[bidiUtil.R_H] = bidiCharWidth * 0.45;
|
|
this.charWidths[bidiUtil.B] = this.charWidths[bidiUtil.RLE] = 0;
|
|
|
|
this.currentRow = null;
|
|
};
|
|
|
|
this.setShowInvisibles = function(showInvisibles) {
|
|
this.showInvisibles = showInvisibles;
|
|
this.currentRow = null;
|
|
};
|
|
|
|
this.setEolChar = function(eolChar) {
|
|
this.EOL = eolChar;
|
|
};
|
|
|
|
this.setContentWidth = function(width) {
|
|
this.contentWidth = width;
|
|
};
|
|
|
|
this.isRtlLine = function(row) {
|
|
if (this.$isRtl) return true;
|
|
if (row != undefined)
|
|
return (this.session.getLine(row).charAt(0) == this.RLE);
|
|
else
|
|
return this.isRtlDir;
|
|
};
|
|
|
|
this.setRtlDirection = function(editor, isRtlDir) {
|
|
var cursor = editor.getCursorPosition();
|
|
for (var row = editor.selection.getSelectionAnchor().row; row <= cursor.row; row++) {
|
|
if (!isRtlDir && editor.session.getLine(row).charAt(0) === editor.session.$bidiHandler.RLE)
|
|
editor.session.doc.removeInLine(row, 0, 1);
|
|
else if (isRtlDir && editor.session.getLine(row).charAt(0) !== editor.session.$bidiHandler.RLE)
|
|
editor.session.doc.insert({column: 0, row: row}, editor.session.$bidiHandler.RLE);
|
|
}
|
|
};
|
|
this.getPosLeft = function(col) {
|
|
col -= this.wrapIndent;
|
|
var leftBoundary = (this.line.charAt(0) === this.RLE) ? 1 : 0;
|
|
var logicalIdx = (col > leftBoundary) ? (this.session.getOverwrite() ? col : col - 1) : leftBoundary;
|
|
var visualIdx = bidiUtil.getVisualFromLogicalIdx(logicalIdx, this.bidiMap),
|
|
levels = this.bidiMap.bidiLevels, left = 0;
|
|
|
|
if (!this.session.getOverwrite() && col <= leftBoundary && levels[visualIdx] % 2 !== 0)
|
|
visualIdx++;
|
|
|
|
for (var i = 0; i < visualIdx; i++) {
|
|
left += this.charWidths[levels[i]];
|
|
}
|
|
|
|
if (!this.session.getOverwrite() && (col > leftBoundary) && (levels[visualIdx] % 2 === 0))
|
|
left += this.charWidths[levels[visualIdx]];
|
|
|
|
if (this.wrapIndent)
|
|
left += this.isRtlDir ? (-1 * this.wrapOffset) : this.wrapOffset;
|
|
|
|
if (this.isRtlDir)
|
|
left += this.rtlLineOffset;
|
|
|
|
return left;
|
|
};
|
|
this.getSelections = function(startCol, endCol) {
|
|
var map = this.bidiMap, levels = map.bidiLevels, level, selections = [], offset = 0,
|
|
selColMin = Math.min(startCol, endCol) - this.wrapIndent, selColMax = Math.max(startCol, endCol) - this.wrapIndent,
|
|
isSelected = false, isSelectedPrev = false, selectionStart = 0;
|
|
|
|
if (this.wrapIndent)
|
|
offset += this.isRtlDir ? (-1 * this.wrapOffset) : this.wrapOffset;
|
|
|
|
for (var logIdx, visIdx = 0; visIdx < levels.length; visIdx++) {
|
|
logIdx = map.logicalFromVisual[visIdx];
|
|
level = levels[visIdx];
|
|
isSelected = (logIdx >= selColMin) && (logIdx < selColMax);
|
|
if (isSelected && !isSelectedPrev) {
|
|
selectionStart = offset;
|
|
} else if (!isSelected && isSelectedPrev) {
|
|
selections.push({left: selectionStart, width: offset - selectionStart});
|
|
}
|
|
offset += this.charWidths[level];
|
|
isSelectedPrev = isSelected;
|
|
}
|
|
|
|
if (isSelected && (visIdx === levels.length)) {
|
|
selections.push({left: selectionStart, width: offset - selectionStart});
|
|
}
|
|
|
|
if(this.isRtlDir) {
|
|
for (var i = 0; i < selections.length; i++) {
|
|
selections[i].left += this.rtlLineOffset;
|
|
}
|
|
}
|
|
return selections;
|
|
};
|
|
this.offsetToCol = function(posX) {
|
|
if(this.isRtlDir)
|
|
posX -= this.rtlLineOffset;
|
|
|
|
var logicalIdx = 0, posX = Math.max(posX, 0),
|
|
offset = 0, visualIdx = 0, levels = this.bidiMap.bidiLevels,
|
|
charWidth = this.charWidths[levels[visualIdx]];
|
|
|
|
if (this.wrapIndent)
|
|
posX -= this.isRtlDir ? (-1 * this.wrapOffset) : this.wrapOffset;
|
|
|
|
while(posX > offset + charWidth/2) {
|
|
offset += charWidth;
|
|
if(visualIdx === levels.length - 1) {
|
|
charWidth = 0;
|
|
break;
|
|
}
|
|
charWidth = this.charWidths[levels[++visualIdx]];
|
|
}
|
|
|
|
if (visualIdx > 0 && (levels[visualIdx - 1] % 2 !== 0) && (levels[visualIdx] % 2 === 0)){
|
|
if(posX < offset)
|
|
visualIdx--;
|
|
logicalIdx = this.bidiMap.logicalFromVisual[visualIdx];
|
|
|
|
} else if (visualIdx > 0 && (levels[visualIdx - 1] % 2 === 0) && (levels[visualIdx] % 2 !== 0)){
|
|
logicalIdx = 1 + ((posX > offset) ? this.bidiMap.logicalFromVisual[visualIdx]
|
|
: this.bidiMap.logicalFromVisual[visualIdx - 1]);
|
|
|
|
} else if ((this.isRtlDir && visualIdx === levels.length - 1 && charWidth === 0 && (levels[visualIdx - 1] % 2 === 0))
|
|
|| (!this.isRtlDir && visualIdx === 0 && (levels[visualIdx] % 2 !== 0))){
|
|
logicalIdx = 1 + this.bidiMap.logicalFromVisual[visualIdx];
|
|
} else {
|
|
if (visualIdx > 0 && (levels[visualIdx - 1] % 2 !== 0) && charWidth !== 0)
|
|
visualIdx--;
|
|
logicalIdx = this.bidiMap.logicalFromVisual[visualIdx];
|
|
}
|
|
|
|
if (logicalIdx === 0 && this.isRtlDir)
|
|
logicalIdx++;
|
|
|
|
return (logicalIdx + this.wrapIndent);
|
|
};
|
|
|
|
}).call(BidiHandler.prototype);
|
|
|
|
exports.BidiHandler = BidiHandler;
|
|
});
|
|
|
|
ace.define("ace/selection",["require","exports","module","ace/lib/oop","ace/lib/lang","ace/lib/event_emitter","ace/range"], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var oop = require("./lib/oop");
|
|
var lang = require("./lib/lang");
|
|
var EventEmitter = require("./lib/event_emitter").EventEmitter;
|
|
var Range = require("./range").Range;
|
|
var Selection = function(session) {
|
|
this.session = session;
|
|
this.doc = session.getDocument();
|
|
|
|
this.clearSelection();
|
|
this.cursor = this.lead = this.doc.createAnchor(0, 0);
|
|
this.anchor = this.doc.createAnchor(0, 0);
|
|
this.$silent = false;
|
|
|
|
var self = this;
|
|
this.cursor.on("change", function(e) {
|
|
self.$cursorChanged = true;
|
|
if (!self.$silent)
|
|
self._emit("changeCursor");
|
|
if (!self.$isEmpty && !self.$silent)
|
|
self._emit("changeSelection");
|
|
if (!self.$keepDesiredColumnOnChange && e.old.column != e.value.column)
|
|
self.$desiredColumn = null;
|
|
});
|
|
|
|
this.anchor.on("change", function() {
|
|
self.$anchorChanged = true;
|
|
if (!self.$isEmpty && !self.$silent)
|
|
self._emit("changeSelection");
|
|
});
|
|
};
|
|
|
|
(function() {
|
|
|
|
oop.implement(this, EventEmitter);
|
|
this.isEmpty = function() {
|
|
return this.$isEmpty || (
|
|
this.anchor.row == this.lead.row &&
|
|
this.anchor.column == this.lead.column
|
|
);
|
|
};
|
|
this.isMultiLine = function() {
|
|
return !this.$isEmpty && this.anchor.row != this.cursor.row;
|
|
};
|
|
this.getCursor = function() {
|
|
return this.lead.getPosition();
|
|
};
|
|
this.setSelectionAnchor = function(row, column) {
|
|
this.$isEmpty = false;
|
|
this.anchor.setPosition(row, column);
|
|
};
|
|
this.getAnchor =
|
|
this.getSelectionAnchor = function() {
|
|
if (this.$isEmpty)
|
|
return this.getSelectionLead();
|
|
|
|
return this.anchor.getPosition();
|
|
};
|
|
this.getSelectionLead = function() {
|
|
return this.lead.getPosition();
|
|
};
|
|
this.isBackwards = function() {
|
|
var anchor = this.anchor;
|
|
var lead = this.lead;
|
|
return (anchor.row > lead.row || (anchor.row == lead.row && anchor.column > lead.column));
|
|
};
|
|
this.getRange = function() {
|
|
var anchor = this.anchor;
|
|
var lead = this.lead;
|
|
|
|
if (this.$isEmpty)
|
|
return Range.fromPoints(lead, lead);
|
|
|
|
return this.isBackwards()
|
|
? Range.fromPoints(lead, anchor)
|
|
: Range.fromPoints(anchor, lead);
|
|
};
|
|
this.clearSelection = function() {
|
|
if (!this.$isEmpty) {
|
|
this.$isEmpty = true;
|
|
this._emit("changeSelection");
|
|
}
|
|
};
|
|
this.selectAll = function() {
|
|
this.$setSelection(0, 0, Number.MAX_VALUE, Number.MAX_VALUE);
|
|
};
|
|
this.setRange =
|
|
this.setSelectionRange = function(range, reverse) {
|
|
var start = reverse ? range.end : range.start;
|
|
var end = reverse ? range.start : range.end;
|
|
this.$setSelection(start.row, start.column, end.row, end.column);
|
|
};
|
|
|
|
this.$setSelection = function(anchorRow, anchorColumn, cursorRow, cursorColumn) {
|
|
if (this.$silent)
|
|
return;
|
|
var wasEmpty = this.$isEmpty;
|
|
var wasMultiselect = this.inMultiSelectMode;
|
|
this.$silent = true;
|
|
this.$cursorChanged = this.$anchorChanged = false;
|
|
this.anchor.setPosition(anchorRow, anchorColumn);
|
|
this.cursor.setPosition(cursorRow, cursorColumn);
|
|
this.$isEmpty = !Range.comparePoints(this.anchor, this.cursor);
|
|
this.$silent = false;
|
|
if (this.$cursorChanged)
|
|
this._emit("changeCursor");
|
|
if (this.$cursorChanged || this.$anchorChanged || wasEmpty != this.$isEmpty || wasMultiselect)
|
|
this._emit("changeSelection");
|
|
};
|
|
|
|
this.$moveSelection = function(mover) {
|
|
var lead = this.lead;
|
|
if (this.$isEmpty)
|
|
this.setSelectionAnchor(lead.row, lead.column);
|
|
|
|
mover.call(this);
|
|
};
|
|
this.selectTo = function(row, column) {
|
|
this.$moveSelection(function() {
|
|
this.moveCursorTo(row, column);
|
|
});
|
|
};
|
|
this.selectToPosition = function(pos) {
|
|
this.$moveSelection(function() {
|
|
this.moveCursorToPosition(pos);
|
|
});
|
|
};
|
|
this.moveTo = function(row, column) {
|
|
this.clearSelection();
|
|
this.moveCursorTo(row, column);
|
|
};
|
|
this.moveToPosition = function(pos) {
|
|
this.clearSelection();
|
|
this.moveCursorToPosition(pos);
|
|
};
|
|
this.selectUp = function() {
|
|
this.$moveSelection(this.moveCursorUp);
|
|
};
|
|
this.selectDown = function() {
|
|
this.$moveSelection(this.moveCursorDown);
|
|
};
|
|
this.selectRight = function() {
|
|
this.$moveSelection(this.moveCursorRight);
|
|
};
|
|
this.selectLeft = function() {
|
|
this.$moveSelection(this.moveCursorLeft);
|
|
};
|
|
this.selectLineStart = function() {
|
|
this.$moveSelection(this.moveCursorLineStart);
|
|
};
|
|
this.selectLineEnd = function() {
|
|
this.$moveSelection(this.moveCursorLineEnd);
|
|
};
|
|
this.selectFileEnd = function() {
|
|
this.$moveSelection(this.moveCursorFileEnd);
|
|
};
|
|
this.selectFileStart = function() {
|
|
this.$moveSelection(this.moveCursorFileStart);
|
|
};
|
|
this.selectWordRight = function() {
|
|
this.$moveSelection(this.moveCursorWordRight);
|
|
};
|
|
this.selectWordLeft = function() {
|
|
this.$moveSelection(this.moveCursorWordLeft);
|
|
};
|
|
this.getWordRange = function(row, column) {
|
|
if (typeof column == "undefined") {
|
|
var cursor = row || this.lead;
|
|
row = cursor.row;
|
|
column = cursor.column;
|
|
}
|
|
return this.session.getWordRange(row, column);
|
|
};
|
|
this.selectWord = function() {
|
|
this.setSelectionRange(this.getWordRange());
|
|
};
|
|
this.selectAWord = function() {
|
|
var cursor = this.getCursor();
|
|
var range = this.session.getAWordRange(cursor.row, cursor.column);
|
|
this.setSelectionRange(range);
|
|
};
|
|
|
|
this.getLineRange = function(row, excludeLastChar) {
|
|
var rowStart = typeof row == "number" ? row : this.lead.row;
|
|
var rowEnd;
|
|
|
|
var foldLine = this.session.getFoldLine(rowStart);
|
|
if (foldLine) {
|
|
rowStart = foldLine.start.row;
|
|
rowEnd = foldLine.end.row;
|
|
} else {
|
|
rowEnd = rowStart;
|
|
}
|
|
if (excludeLastChar === true)
|
|
return new Range(rowStart, 0, rowEnd, this.session.getLine(rowEnd).length);
|
|
else
|
|
return new Range(rowStart, 0, rowEnd + 1, 0);
|
|
};
|
|
this.selectLine = function() {
|
|
this.setSelectionRange(this.getLineRange());
|
|
};
|
|
this.moveCursorUp = function() {
|
|
this.moveCursorBy(-1, 0);
|
|
};
|
|
this.moveCursorDown = function() {
|
|
this.moveCursorBy(1, 0);
|
|
};
|
|
this.wouldMoveIntoSoftTab = function(cursor, tabSize, direction) {
|
|
var start = cursor.column;
|
|
var end = cursor.column + tabSize;
|
|
|
|
if (direction < 0) {
|
|
start = cursor.column - tabSize;
|
|
end = cursor.column;
|
|
}
|
|
return this.session.isTabStop(cursor) && this.doc.getLine(cursor.row).slice(start, end).split(" ").length-1 == tabSize;
|
|
};
|
|
this.moveCursorLeft = function() {
|
|
var cursor = this.lead.getPosition(),
|
|
fold;
|
|
|
|
if (fold = this.session.getFoldAt(cursor.row, cursor.column, -1)) {
|
|
this.moveCursorTo(fold.start.row, fold.start.column);
|
|
} else if (cursor.column === 0) {
|
|
if (cursor.row > 0) {
|
|
this.moveCursorTo(cursor.row - 1, this.doc.getLine(cursor.row - 1).length);
|
|
}
|
|
}
|
|
else {
|
|
var tabSize = this.session.getTabSize();
|
|
if (this.wouldMoveIntoSoftTab(cursor, tabSize, -1) && !this.session.getNavigateWithinSoftTabs()) {
|
|
this.moveCursorBy(0, -tabSize);
|
|
} else {
|
|
this.moveCursorBy(0, -1);
|
|
}
|
|
}
|
|
};
|
|
this.moveCursorRight = function() {
|
|
var cursor = this.lead.getPosition(),
|
|
fold;
|
|
if (fold = this.session.getFoldAt(cursor.row, cursor.column, 1)) {
|
|
this.moveCursorTo(fold.end.row, fold.end.column);
|
|
}
|
|
else if (this.lead.column == this.doc.getLine(this.lead.row).length) {
|
|
if (this.lead.row < this.doc.getLength() - 1) {
|
|
this.moveCursorTo(this.lead.row + 1, 0);
|
|
}
|
|
}
|
|
else {
|
|
var tabSize = this.session.getTabSize();
|
|
var cursor = this.lead;
|
|
if (this.wouldMoveIntoSoftTab(cursor, tabSize, 1) && !this.session.getNavigateWithinSoftTabs()) {
|
|
this.moveCursorBy(0, tabSize);
|
|
} else {
|
|
this.moveCursorBy(0, 1);
|
|
}
|
|
}
|
|
};
|
|
this.moveCursorLineStart = function() {
|
|
var row = this.lead.row;
|
|
var column = this.lead.column;
|
|
var screenRow = this.session.documentToScreenRow(row, column);
|
|
var firstColumnPosition = this.session.screenToDocumentPosition(screenRow, 0);
|
|
var beforeCursor = this.session.getDisplayLine(
|
|
row, null, firstColumnPosition.row,
|
|
firstColumnPosition.column
|
|
);
|
|
|
|
var leadingSpace = beforeCursor.match(/^\s*/);
|
|
if (leadingSpace[0].length != column && !this.session.$useEmacsStyleLineStart)
|
|
firstColumnPosition.column += leadingSpace[0].length;
|
|
this.moveCursorToPosition(firstColumnPosition);
|
|
};
|
|
this.moveCursorLineEnd = function() {
|
|
var lead = this.lead;
|
|
var lineEnd = this.session.getDocumentLastRowColumnPosition(lead.row, lead.column);
|
|
if (this.lead.column == lineEnd.column) {
|
|
var line = this.session.getLine(lineEnd.row);
|
|
if (lineEnd.column == line.length) {
|
|
var textEnd = line.search(/\s+$/);
|
|
if (textEnd > 0)
|
|
lineEnd.column = textEnd;
|
|
}
|
|
}
|
|
|
|
this.moveCursorTo(lineEnd.row, lineEnd.column);
|
|
};
|
|
this.moveCursorFileEnd = function() {
|
|
var row = this.doc.getLength() - 1;
|
|
var column = this.doc.getLine(row).length;
|
|
this.moveCursorTo(row, column);
|
|
};
|
|
this.moveCursorFileStart = function() {
|
|
this.moveCursorTo(0, 0);
|
|
};
|
|
this.moveCursorLongWordRight = function() {
|
|
var row = this.lead.row;
|
|
var column = this.lead.column;
|
|
var line = this.doc.getLine(row);
|
|
var rightOfCursor = line.substring(column);
|
|
|
|
this.session.nonTokenRe.lastIndex = 0;
|
|
this.session.tokenRe.lastIndex = 0;
|
|
var fold = this.session.getFoldAt(row, column, 1);
|
|
if (fold) {
|
|
this.moveCursorTo(fold.end.row, fold.end.column);
|
|
return;
|
|
}
|
|
if (this.session.nonTokenRe.exec(rightOfCursor)) {
|
|
column += this.session.nonTokenRe.lastIndex;
|
|
this.session.nonTokenRe.lastIndex = 0;
|
|
rightOfCursor = line.substring(column);
|
|
}
|
|
if (column >= line.length) {
|
|
this.moveCursorTo(row, line.length);
|
|
this.moveCursorRight();
|
|
if (row < this.doc.getLength() - 1)
|
|
this.moveCursorWordRight();
|
|
return;
|
|
}
|
|
if (this.session.tokenRe.exec(rightOfCursor)) {
|
|
column += this.session.tokenRe.lastIndex;
|
|
this.session.tokenRe.lastIndex = 0;
|
|
}
|
|
|
|
this.moveCursorTo(row, column);
|
|
};
|
|
this.moveCursorLongWordLeft = function() {
|
|
var row = this.lead.row;
|
|
var column = this.lead.column;
|
|
var fold;
|
|
if (fold = this.session.getFoldAt(row, column, -1)) {
|
|
this.moveCursorTo(fold.start.row, fold.start.column);
|
|
return;
|
|
}
|
|
|
|
var str = this.session.getFoldStringAt(row, column, -1);
|
|
if (str == null) {
|
|
str = this.doc.getLine(row).substring(0, column);
|
|
}
|
|
|
|
var leftOfCursor = lang.stringReverse(str);
|
|
this.session.nonTokenRe.lastIndex = 0;
|
|
this.session.tokenRe.lastIndex = 0;
|
|
if (this.session.nonTokenRe.exec(leftOfCursor)) {
|
|
column -= this.session.nonTokenRe.lastIndex;
|
|
leftOfCursor = leftOfCursor.slice(this.session.nonTokenRe.lastIndex);
|
|
this.session.nonTokenRe.lastIndex = 0;
|
|
}
|
|
if (column <= 0) {
|
|
this.moveCursorTo(row, 0);
|
|
this.moveCursorLeft();
|
|
if (row > 0)
|
|
this.moveCursorWordLeft();
|
|
return;
|
|
}
|
|
if (this.session.tokenRe.exec(leftOfCursor)) {
|
|
column -= this.session.tokenRe.lastIndex;
|
|
this.session.tokenRe.lastIndex = 0;
|
|
}
|
|
|
|
this.moveCursorTo(row, column);
|
|
};
|
|
|
|
this.$shortWordEndIndex = function(rightOfCursor) {
|
|
var index = 0, ch;
|
|
var whitespaceRe = /\s/;
|
|
var tokenRe = this.session.tokenRe;
|
|
|
|
tokenRe.lastIndex = 0;
|
|
if (this.session.tokenRe.exec(rightOfCursor)) {
|
|
index = this.session.tokenRe.lastIndex;
|
|
} else {
|
|
while ((ch = rightOfCursor[index]) && whitespaceRe.test(ch))
|
|
index ++;
|
|
|
|
if (index < 1) {
|
|
tokenRe.lastIndex = 0;
|
|
while ((ch = rightOfCursor[index]) && !tokenRe.test(ch)) {
|
|
tokenRe.lastIndex = 0;
|
|
index ++;
|
|
if (whitespaceRe.test(ch)) {
|
|
if (index > 2) {
|
|
index--;
|
|
break;
|
|
} else {
|
|
while ((ch = rightOfCursor[index]) && whitespaceRe.test(ch))
|
|
index ++;
|
|
if (index > 2)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
tokenRe.lastIndex = 0;
|
|
|
|
return index;
|
|
};
|
|
|
|
this.moveCursorShortWordRight = function() {
|
|
var row = this.lead.row;
|
|
var column = this.lead.column;
|
|
var line = this.doc.getLine(row);
|
|
var rightOfCursor = line.substring(column);
|
|
|
|
var fold = this.session.getFoldAt(row, column, 1);
|
|
if (fold)
|
|
return this.moveCursorTo(fold.end.row, fold.end.column);
|
|
|
|
if (column == line.length) {
|
|
var l = this.doc.getLength();
|
|
do {
|
|
row++;
|
|
rightOfCursor = this.doc.getLine(row);
|
|
} while (row < l && /^\s*$/.test(rightOfCursor));
|
|
|
|
if (!/^\s+/.test(rightOfCursor))
|
|
rightOfCursor = "";
|
|
column = 0;
|
|
}
|
|
|
|
var index = this.$shortWordEndIndex(rightOfCursor);
|
|
|
|
this.moveCursorTo(row, column + index);
|
|
};
|
|
|
|
this.moveCursorShortWordLeft = function() {
|
|
var row = this.lead.row;
|
|
var column = this.lead.column;
|
|
|
|
var fold;
|
|
if (fold = this.session.getFoldAt(row, column, -1))
|
|
return this.moveCursorTo(fold.start.row, fold.start.column);
|
|
|
|
var line = this.session.getLine(row).substring(0, column);
|
|
if (column === 0) {
|
|
do {
|
|
row--;
|
|
line = this.doc.getLine(row);
|
|
} while (row > 0 && /^\s*$/.test(line));
|
|
|
|
column = line.length;
|
|
if (!/\s+$/.test(line))
|
|
line = "";
|
|
}
|
|
|
|
var leftOfCursor = lang.stringReverse(line);
|
|
var index = this.$shortWordEndIndex(leftOfCursor);
|
|
|
|
return this.moveCursorTo(row, column - index);
|
|
};
|
|
|
|
this.moveCursorWordRight = function() {
|
|
if (this.session.$selectLongWords)
|
|
this.moveCursorLongWordRight();
|
|
else
|
|
this.moveCursorShortWordRight();
|
|
};
|
|
|
|
this.moveCursorWordLeft = function() {
|
|
if (this.session.$selectLongWords)
|
|
this.moveCursorLongWordLeft();
|
|
else
|
|
this.moveCursorShortWordLeft();
|
|
};
|
|
this.moveCursorBy = function(rows, chars) {
|
|
var screenPos = this.session.documentToScreenPosition(
|
|
this.lead.row,
|
|
this.lead.column
|
|
);
|
|
|
|
var offsetX;
|
|
|
|
if (chars === 0) {
|
|
if (rows !== 0) {
|
|
if (this.session.$bidiHandler.isBidiRow(screenPos.row, this.lead.row)) {
|
|
offsetX = this.session.$bidiHandler.getPosLeft(screenPos.column);
|
|
screenPos.column = Math.round(offsetX / this.session.$bidiHandler.charWidths[0]);
|
|
} else {
|
|
offsetX = screenPos.column * this.session.$bidiHandler.charWidths[0];
|
|
}
|
|
}
|
|
|
|
if (this.$desiredColumn)
|
|
screenPos.column = this.$desiredColumn;
|
|
else
|
|
this.$desiredColumn = screenPos.column;
|
|
}
|
|
|
|
if (rows != 0 && this.session.lineWidgets && this.session.lineWidgets[this.lead.row]) {
|
|
var widget = this.session.lineWidgets[this.lead.row];
|
|
if (rows < 0)
|
|
rows -= widget.rowsAbove || 0;
|
|
else if (rows > 0)
|
|
rows += widget.rowCount - (widget.rowsAbove || 0);
|
|
}
|
|
|
|
var docPos = this.session.screenToDocumentPosition(screenPos.row + rows, screenPos.column, offsetX);
|
|
|
|
if (rows !== 0 && chars === 0 && docPos.row === this.lead.row && docPos.column === this.lead.column) {
|
|
|
|
}
|
|
this.moveCursorTo(docPos.row, docPos.column + chars, chars === 0);
|
|
};
|
|
this.moveCursorToPosition = function(position) {
|
|
this.moveCursorTo(position.row, position.column);
|
|
};
|
|
this.moveCursorTo = function(row, column, keepDesiredColumn) {
|
|
var fold = this.session.getFoldAt(row, column, 1);
|
|
if (fold) {
|
|
row = fold.start.row;
|
|
column = fold.start.column;
|
|
}
|
|
|
|
this.$keepDesiredColumnOnChange = true;
|
|
var line = this.session.getLine(row);
|
|
if (/[\uDC00-\uDFFF]/.test(line.charAt(column)) && line.charAt(column - 1)) {
|
|
if (this.lead.row == row && this.lead.column == column + 1)
|
|
column = column - 1;
|
|
else
|
|
column = column + 1;
|
|
}
|
|
this.lead.setPosition(row, column);
|
|
this.$keepDesiredColumnOnChange = false;
|
|
|
|
if (!keepDesiredColumn)
|
|
this.$desiredColumn = null;
|
|
};
|
|
this.moveCursorToScreen = function(row, column, keepDesiredColumn) {
|
|
var pos = this.session.screenToDocumentPosition(row, column);
|
|
this.moveCursorTo(pos.row, pos.column, keepDesiredColumn);
|
|
};
|
|
this.detach = function() {
|
|
this.lead.detach();
|
|
this.anchor.detach();
|
|
this.session = this.doc = null;
|
|
};
|
|
|
|
this.fromOrientedRange = function(range) {
|
|
this.setSelectionRange(range, range.cursor == range.start);
|
|
this.$desiredColumn = range.desiredColumn || this.$desiredColumn;
|
|
};
|
|
|
|
this.toOrientedRange = function(range) {
|
|
var r = this.getRange();
|
|
if (range) {
|
|
range.start.column = r.start.column;
|
|
range.start.row = r.start.row;
|
|
range.end.column = r.end.column;
|
|
range.end.row = r.end.row;
|
|
} else {
|
|
range = r;
|
|
}
|
|
|
|
range.cursor = this.isBackwards() ? range.start : range.end;
|
|
range.desiredColumn = this.$desiredColumn;
|
|
return range;
|
|
};
|
|
this.getRangeOfMovements = function(func) {
|
|
var start = this.getCursor();
|
|
try {
|
|
func(this);
|
|
var end = this.getCursor();
|
|
return Range.fromPoints(start, end);
|
|
} catch(e) {
|
|
return Range.fromPoints(start, start);
|
|
} finally {
|
|
this.moveCursorToPosition(start);
|
|
}
|
|
};
|
|
|
|
this.toJSON = function() {
|
|
if (this.rangeCount) {
|
|
var data = this.ranges.map(function(r) {
|
|
var r1 = r.clone();
|
|
r1.isBackwards = r.cursor == r.start;
|
|
return r1;
|
|
});
|
|
} else {
|
|
var data = this.getRange();
|
|
data.isBackwards = this.isBackwards();
|
|
}
|
|
return data;
|
|
};
|
|
|
|
this.fromJSON = function(data) {
|
|
if (data.start == undefined) {
|
|
if (this.rangeList && data.length > 1) {
|
|
this.toSingleRange(data[0]);
|
|
for (var i = data.length; i--; ) {
|
|
var r = Range.fromPoints(data[i].start, data[i].end);
|
|
if (data[i].isBackwards)
|
|
r.cursor = r.start;
|
|
this.addRange(r, true);
|
|
}
|
|
return;
|
|
} else {
|
|
data = data[0];
|
|
}
|
|
}
|
|
if (this.rangeList)
|
|
this.toSingleRange(data);
|
|
this.setSelectionRange(data, data.isBackwards);
|
|
};
|
|
|
|
this.isEqual = function(data) {
|
|
if ((data.length || this.rangeCount) && data.length != this.rangeCount)
|
|
return false;
|
|
if (!data.length || !this.ranges)
|
|
return this.getRange().isEqual(data);
|
|
|
|
for (var i = this.ranges.length; i--; ) {
|
|
if (!this.ranges[i].isEqual(data[i]))
|
|
return false;
|
|
}
|
|
return true;
|
|
};
|
|
|
|
}).call(Selection.prototype);
|
|
|
|
exports.Selection = Selection;
|
|
});
|
|
|
|
ace.define("ace/tokenizer",["require","exports","module","ace/config"], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var config = require("./config");
|
|
var MAX_TOKEN_COUNT = 2000;
|
|
var Tokenizer = function(rules) {
|
|
this.states = rules;
|
|
|
|
this.regExps = {};
|
|
this.matchMappings = {};
|
|
for (var key in this.states) {
|
|
var state = this.states[key];
|
|
var ruleRegExps = [];
|
|
var matchTotal = 0;
|
|
var mapping = this.matchMappings[key] = {defaultToken: "text"};
|
|
var flag = "g";
|
|
|
|
var splitterRurles = [];
|
|
for (var i = 0; i < state.length; i++) {
|
|
var rule = state[i];
|
|
if (rule.defaultToken)
|
|
mapping.defaultToken = rule.defaultToken;
|
|
if (rule.caseInsensitive)
|
|
flag = "gi";
|
|
if (rule.regex == null)
|
|
continue;
|
|
|
|
if (rule.regex instanceof RegExp)
|
|
rule.regex = rule.regex.toString().slice(1, -1);
|
|
var adjustedregex = rule.regex;
|
|
var matchcount = new RegExp("(?:(" + adjustedregex + ")|(.))").exec("a").length - 2;
|
|
if (Array.isArray(rule.token)) {
|
|
if (rule.token.length == 1 || matchcount == 1) {
|
|
rule.token = rule.token[0];
|
|
} else if (matchcount - 1 != rule.token.length) {
|
|
this.reportError("number of classes and regexp groups doesn't match", {
|
|
rule: rule,
|
|
groupCount: matchcount - 1
|
|
});
|
|
rule.token = rule.token[0];
|
|
} else {
|
|
rule.tokenArray = rule.token;
|
|
rule.token = null;
|
|
rule.onMatch = this.$arrayTokens;
|
|
}
|
|
} else if (typeof rule.token == "function" && !rule.onMatch) {
|
|
if (matchcount > 1)
|
|
rule.onMatch = this.$applyToken;
|
|
else
|
|
rule.onMatch = rule.token;
|
|
}
|
|
|
|
if (matchcount > 1) {
|
|
if (/\\\d/.test(rule.regex)) {
|
|
adjustedregex = rule.regex.replace(/\\([0-9]+)/g, function(match, digit) {
|
|
return "\\" + (parseInt(digit, 10) + matchTotal + 1);
|
|
});
|
|
} else {
|
|
matchcount = 1;
|
|
adjustedregex = this.removeCapturingGroups(rule.regex);
|
|
}
|
|
if (!rule.splitRegex && typeof rule.token != "string")
|
|
splitterRurles.push(rule); // flag will be known only at the very end
|
|
}
|
|
|
|
mapping[matchTotal] = i;
|
|
matchTotal += matchcount;
|
|
|
|
ruleRegExps.push(adjustedregex);
|
|
if (!rule.onMatch)
|
|
rule.onMatch = null;
|
|
}
|
|
|
|
if (!ruleRegExps.length) {
|
|
mapping[0] = 0;
|
|
ruleRegExps.push("$");
|
|
}
|
|
|
|
splitterRurles.forEach(function(rule) {
|
|
rule.splitRegex = this.createSplitterRegexp(rule.regex, flag);
|
|
}, this);
|
|
|
|
this.regExps[key] = new RegExp("(" + ruleRegExps.join(")|(") + ")|($)", flag);
|
|
}
|
|
};
|
|
|
|
(function() {
|
|
this.$setMaxTokenCount = function(m) {
|
|
MAX_TOKEN_COUNT = m | 0;
|
|
};
|
|
|
|
this.$applyToken = function(str) {
|
|
var values = this.splitRegex.exec(str).slice(1);
|
|
var types = this.token.apply(this, values);
|
|
if (typeof types === "string")
|
|
return [{type: types, value: str}];
|
|
|
|
var tokens = [];
|
|
for (var i = 0, l = types.length; i < l; i++) {
|
|
if (values[i])
|
|
tokens[tokens.length] = {
|
|
type: types[i],
|
|
value: values[i]
|
|
};
|
|
}
|
|
return tokens;
|
|
};
|
|
|
|
this.$arrayTokens = function(str) {
|
|
if (!str)
|
|
return [];
|
|
var values = this.splitRegex.exec(str);
|
|
if (!values)
|
|
return "text";
|
|
var tokens = [];
|
|
var types = this.tokenArray;
|
|
for (var i = 0, l = types.length; i < l; i++) {
|
|
if (values[i + 1])
|
|
tokens[tokens.length] = {
|
|
type: types[i],
|
|
value: values[i + 1]
|
|
};
|
|
}
|
|
return tokens;
|
|
};
|
|
|
|
this.removeCapturingGroups = function(src) {
|
|
var r = src.replace(
|
|
/\\.|\[(?:\\.|[^\\\]])*|\(\?[:=!]|(\()/g,
|
|
function(x, y) {return y ? "(?:" : x;}
|
|
);
|
|
return r;
|
|
};
|
|
|
|
this.createSplitterRegexp = function(src, flag) {
|
|
if (src.indexOf("(?=") != -1) {
|
|
var stack = 0;
|
|
var inChClass = false;
|
|
var lastCapture = {};
|
|
src.replace(/(\\.)|(\((?:\?[=!])?)|(\))|([\[\]])/g, function(
|
|
m, esc, parenOpen, parenClose, square, index
|
|
) {
|
|
if (inChClass) {
|
|
inChClass = square != "]";
|
|
} else if (square) {
|
|
inChClass = true;
|
|
} else if (parenClose) {
|
|
if (stack == lastCapture.stack) {
|
|
lastCapture.end = index+1;
|
|
lastCapture.stack = -1;
|
|
}
|
|
stack--;
|
|
} else if (parenOpen) {
|
|
stack++;
|
|
if (parenOpen.length != 1) {
|
|
lastCapture.stack = stack;
|
|
lastCapture.start = index;
|
|
}
|
|
}
|
|
return m;
|
|
});
|
|
|
|
if (lastCapture.end != null && /^\)*$/.test(src.substr(lastCapture.end)))
|
|
src = src.substring(0, lastCapture.start) + src.substr(lastCapture.end);
|
|
}
|
|
if (src.charAt(0) != "^") src = "^" + src;
|
|
if (src.charAt(src.length - 1) != "$") src += "$";
|
|
|
|
return new RegExp(src, (flag||"").replace("g", ""));
|
|
};
|
|
this.getLineTokens = function(line, startState) {
|
|
if (startState && typeof startState != "string") {
|
|
var stack = startState.slice(0);
|
|
startState = stack[0];
|
|
if (startState === "#tmp") {
|
|
stack.shift();
|
|
startState = stack.shift();
|
|
}
|
|
} else
|
|
var stack = [];
|
|
|
|
var currentState = startState || "start";
|
|
var state = this.states[currentState];
|
|
if (!state) {
|
|
currentState = "start";
|
|
state = this.states[currentState];
|
|
}
|
|
var mapping = this.matchMappings[currentState];
|
|
var re = this.regExps[currentState];
|
|
re.lastIndex = 0;
|
|
|
|
var match, tokens = [];
|
|
var lastIndex = 0;
|
|
var matchAttempts = 0;
|
|
|
|
var token = {type: null, value: ""};
|
|
|
|
while (match = re.exec(line)) {
|
|
var type = mapping.defaultToken;
|
|
var rule = null;
|
|
var value = match[0];
|
|
var index = re.lastIndex;
|
|
|
|
if (index - value.length > lastIndex) {
|
|
var skipped = line.substring(lastIndex, index - value.length);
|
|
if (token.type == type) {
|
|
token.value += skipped;
|
|
} else {
|
|
if (token.type)
|
|
tokens.push(token);
|
|
token = {type: type, value: skipped};
|
|
}
|
|
}
|
|
|
|
for (var i = 0; i < match.length-2; i++) {
|
|
if (match[i + 1] === undefined)
|
|
continue;
|
|
|
|
rule = state[mapping[i]];
|
|
|
|
if (rule.onMatch)
|
|
type = rule.onMatch(value, currentState, stack, line);
|
|
else
|
|
type = rule.token;
|
|
|
|
if (rule.next) {
|
|
if (typeof rule.next == "string") {
|
|
currentState = rule.next;
|
|
} else {
|
|
currentState = rule.next(currentState, stack);
|
|
}
|
|
|
|
state = this.states[currentState];
|
|
if (!state) {
|
|
this.reportError("state doesn't exist", currentState);
|
|
currentState = "start";
|
|
state = this.states[currentState];
|
|
}
|
|
mapping = this.matchMappings[currentState];
|
|
lastIndex = index;
|
|
re = this.regExps[currentState];
|
|
re.lastIndex = index;
|
|
}
|
|
if (rule.consumeLineEnd)
|
|
lastIndex = index;
|
|
break;
|
|
}
|
|
|
|
if (value) {
|
|
if (typeof type === "string") {
|
|
if ((!rule || rule.merge !== false) && token.type === type) {
|
|
token.value += value;
|
|
} else {
|
|
if (token.type)
|
|
tokens.push(token);
|
|
token = {type: type, value: value};
|
|
}
|
|
} else if (type) {
|
|
if (token.type)
|
|
tokens.push(token);
|
|
token = {type: null, value: ""};
|
|
for (var i = 0; i < type.length; i++)
|
|
tokens.push(type[i]);
|
|
}
|
|
}
|
|
|
|
if (lastIndex == line.length)
|
|
break;
|
|
|
|
lastIndex = index;
|
|
|
|
if (matchAttempts++ > MAX_TOKEN_COUNT) {
|
|
if (matchAttempts > 2 * line.length) {
|
|
this.reportError("infinite loop with in ace tokenizer", {
|
|
startState: startState,
|
|
line: line
|
|
});
|
|
}
|
|
while (lastIndex < line.length) {
|
|
if (token.type)
|
|
tokens.push(token);
|
|
token = {
|
|
value: line.substring(lastIndex, lastIndex += 500),
|
|
type: "overflow"
|
|
};
|
|
}
|
|
currentState = "start";
|
|
stack = [];
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (token.type)
|
|
tokens.push(token);
|
|
|
|
if (stack.length > 1) {
|
|
if (stack[0] !== currentState)
|
|
stack.unshift("#tmp", currentState);
|
|
}
|
|
return {
|
|
tokens : tokens,
|
|
state : stack.length ? stack : currentState
|
|
};
|
|
};
|
|
|
|
this.reportError = config.reportError;
|
|
|
|
}).call(Tokenizer.prototype);
|
|
|
|
exports.Tokenizer = Tokenizer;
|
|
});
|
|
|
|
ace.define("ace/mode/text_highlight_rules",["require","exports","module","ace/lib/lang"], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var lang = require("../lib/lang");
|
|
|
|
var TextHighlightRules = function() {
|
|
|
|
this.$rules = {
|
|
"start" : [{
|
|
token : "empty_line",
|
|
regex : '^$'
|
|
}, {
|
|
defaultToken : "text"
|
|
}]
|
|
};
|
|
};
|
|
|
|
(function() {
|
|
|
|
this.addRules = function(rules, prefix) {
|
|
if (!prefix) {
|
|
for (var key in rules)
|
|
this.$rules[key] = rules[key];
|
|
return;
|
|
}
|
|
for (var key in rules) {
|
|
var state = rules[key];
|
|
for (var i = 0; i < state.length; i++) {
|
|
var rule = state[i];
|
|
if (rule.next || rule.onMatch) {
|
|
if (typeof rule.next == "string") {
|
|
if (rule.next.indexOf(prefix) !== 0)
|
|
rule.next = prefix + rule.next;
|
|
}
|
|
if (rule.nextState && rule.nextState.indexOf(prefix) !== 0)
|
|
rule.nextState = prefix + rule.nextState;
|
|
}
|
|
}
|
|
this.$rules[prefix + key] = state;
|
|
}
|
|
};
|
|
|
|
this.getRules = function() {
|
|
return this.$rules;
|
|
};
|
|
|
|
this.embedRules = function (HighlightRules, prefix, escapeRules, states, append) {
|
|
var embedRules = typeof HighlightRules == "function"
|
|
? new HighlightRules().getRules()
|
|
: HighlightRules;
|
|
if (states) {
|
|
for (var i = 0; i < states.length; i++)
|
|
states[i] = prefix + states[i];
|
|
} else {
|
|
states = [];
|
|
for (var key in embedRules)
|
|
states.push(prefix + key);
|
|
}
|
|
|
|
this.addRules(embedRules, prefix);
|
|
|
|
if (escapeRules) {
|
|
var addRules = Array.prototype[append ? "push" : "unshift"];
|
|
for (var i = 0; i < states.length; i++)
|
|
addRules.apply(this.$rules[states[i]], lang.deepCopy(escapeRules));
|
|
}
|
|
|
|
if (!this.$embeds)
|
|
this.$embeds = [];
|
|
this.$embeds.push(prefix);
|
|
};
|
|
|
|
this.getEmbeds = function() {
|
|
return this.$embeds;
|
|
};
|
|
|
|
var pushState = function(currentState, stack) {
|
|
if (currentState != "start" || stack.length)
|
|
stack.unshift(this.nextState, currentState);
|
|
return this.nextState;
|
|
};
|
|
var popState = function(currentState, stack) {
|
|
stack.shift();
|
|
return stack.shift() || "start";
|
|
};
|
|
|
|
this.normalizeRules = function() {
|
|
var id = 0;
|
|
var rules = this.$rules;
|
|
function processState(key) {
|
|
var state = rules[key];
|
|
state.processed = true;
|
|
for (var i = 0; i < state.length; i++) {
|
|
var rule = state[i];
|
|
var toInsert = null;
|
|
if (Array.isArray(rule)) {
|
|
toInsert = rule;
|
|
rule = {};
|
|
}
|
|
if (!rule.regex && rule.start) {
|
|
rule.regex = rule.start;
|
|
if (!rule.next)
|
|
rule.next = [];
|
|
rule.next.push({
|
|
defaultToken: rule.token
|
|
}, {
|
|
token: rule.token + ".end",
|
|
regex: rule.end || rule.start,
|
|
next: "pop"
|
|
});
|
|
rule.token = rule.token + ".start";
|
|
rule.push = true;
|
|
}
|
|
var next = rule.next || rule.push;
|
|
if (next && Array.isArray(next)) {
|
|
var stateName = rule.stateName;
|
|
if (!stateName) {
|
|
stateName = rule.token;
|
|
if (typeof stateName != "string")
|
|
stateName = stateName[0] || "";
|
|
if (rules[stateName])
|
|
stateName += id++;
|
|
}
|
|
rules[stateName] = next;
|
|
rule.next = stateName;
|
|
processState(stateName);
|
|
} else if (next == "pop") {
|
|
rule.next = popState;
|
|
}
|
|
|
|
if (rule.push) {
|
|
rule.nextState = rule.next || rule.push;
|
|
rule.next = pushState;
|
|
delete rule.push;
|
|
}
|
|
|
|
if (rule.rules) {
|
|
for (var r in rule.rules) {
|
|
if (rules[r]) {
|
|
if (rules[r].push)
|
|
rules[r].push.apply(rules[r], rule.rules[r]);
|
|
} else {
|
|
rules[r] = rule.rules[r];
|
|
}
|
|
}
|
|
}
|
|
var includeName = typeof rule == "string" ? rule : rule.include;
|
|
if (includeName) {
|
|
if (Array.isArray(includeName))
|
|
toInsert = includeName.map(function(x) { return rules[x]; });
|
|
else
|
|
toInsert = rules[includeName];
|
|
}
|
|
|
|
if (toInsert) {
|
|
var args = [i, 1].concat(toInsert);
|
|
if (rule.noEscape)
|
|
args = args.filter(function(x) {return !x.next;});
|
|
state.splice.apply(state, args);
|
|
i--;
|
|
}
|
|
|
|
if (rule.keywordMap) {
|
|
rule.token = this.createKeywordMapper(
|
|
rule.keywordMap, rule.defaultToken || "text", rule.caseInsensitive
|
|
);
|
|
delete rule.defaultToken;
|
|
}
|
|
}
|
|
}
|
|
Object.keys(rules).forEach(processState, this);
|
|
};
|
|
|
|
this.createKeywordMapper = function(map, defaultToken, ignoreCase, splitChar) {
|
|
var keywords = Object.create(null);
|
|
this.$keywordList = [];
|
|
Object.keys(map).forEach(function(className) {
|
|
var a = map[className];
|
|
var list = a.split(splitChar || "|");
|
|
for (var i = list.length; i--; ) {
|
|
var word = list[i];
|
|
this.$keywordList.push(word);
|
|
if (ignoreCase)
|
|
word = word.toLowerCase();
|
|
keywords[word] = className;
|
|
}
|
|
}, this);
|
|
map = null;
|
|
return ignoreCase
|
|
? function(value) {return keywords[value.toLowerCase()] || defaultToken; }
|
|
: function(value) {return keywords[value] || defaultToken; };
|
|
};
|
|
|
|
this.getKeywords = function() {
|
|
return this.$keywords;
|
|
};
|
|
|
|
}).call(TextHighlightRules.prototype);
|
|
|
|
exports.TextHighlightRules = TextHighlightRules;
|
|
});
|
|
|
|
ace.define("ace/mode/behaviour",["require","exports","module"], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var Behaviour = function() {
|
|
this.$behaviours = {};
|
|
};
|
|
|
|
(function () {
|
|
|
|
this.add = function (name, action, callback) {
|
|
switch (undefined) {
|
|
case this.$behaviours:
|
|
this.$behaviours = {};
|
|
case this.$behaviours[name]:
|
|
this.$behaviours[name] = {};
|
|
}
|
|
this.$behaviours[name][action] = callback;
|
|
};
|
|
|
|
this.addBehaviours = function (behaviours) {
|
|
for (var key in behaviours) {
|
|
for (var action in behaviours[key]) {
|
|
this.add(key, action, behaviours[key][action]);
|
|
}
|
|
}
|
|
};
|
|
|
|
this.remove = function (name) {
|
|
if (this.$behaviours && this.$behaviours[name]) {
|
|
delete this.$behaviours[name];
|
|
}
|
|
};
|
|
|
|
this.inherit = function (mode, filter) {
|
|
if (typeof mode === "function") {
|
|
var behaviours = new mode().getBehaviours(filter);
|
|
} else {
|
|
var behaviours = mode.getBehaviours(filter);
|
|
}
|
|
this.addBehaviours(behaviours);
|
|
};
|
|
|
|
this.getBehaviours = function (filter) {
|
|
if (!filter) {
|
|
return this.$behaviours;
|
|
} else {
|
|
var ret = {};
|
|
for (var i = 0; i < filter.length; i++) {
|
|
if (this.$behaviours[filter[i]]) {
|
|
ret[filter[i]] = this.$behaviours[filter[i]];
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
};
|
|
|
|
}).call(Behaviour.prototype);
|
|
|
|
exports.Behaviour = Behaviour;
|
|
});
|
|
|
|
ace.define("ace/token_iterator",["require","exports","module","ace/range"], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var Range = require("./range").Range;
|
|
var TokenIterator = function(session, initialRow, initialColumn) {
|
|
this.$session = session;
|
|
this.$row = initialRow;
|
|
this.$rowTokens = session.getTokens(initialRow);
|
|
|
|
var token = session.getTokenAt(initialRow, initialColumn);
|
|
this.$tokenIndex = token ? token.index : -1;
|
|
};
|
|
|
|
(function() {
|
|
this.stepBackward = function() {
|
|
this.$tokenIndex -= 1;
|
|
|
|
while (this.$tokenIndex < 0) {
|
|
this.$row -= 1;
|
|
if (this.$row < 0) {
|
|
this.$row = 0;
|
|
return null;
|
|
}
|
|
|
|
this.$rowTokens = this.$session.getTokens(this.$row);
|
|
this.$tokenIndex = this.$rowTokens.length - 1;
|
|
}
|
|
|
|
return this.$rowTokens[this.$tokenIndex];
|
|
};
|
|
this.stepForward = function() {
|
|
this.$tokenIndex += 1;
|
|
var rowCount;
|
|
while (this.$tokenIndex >= this.$rowTokens.length) {
|
|
this.$row += 1;
|
|
if (!rowCount)
|
|
rowCount = this.$session.getLength();
|
|
if (this.$row >= rowCount) {
|
|
this.$row = rowCount - 1;
|
|
return null;
|
|
}
|
|
|
|
this.$rowTokens = this.$session.getTokens(this.$row);
|
|
this.$tokenIndex = 0;
|
|
}
|
|
|
|
return this.$rowTokens[this.$tokenIndex];
|
|
};
|
|
this.getCurrentToken = function () {
|
|
return this.$rowTokens[this.$tokenIndex];
|
|
};
|
|
this.getCurrentTokenRow = function () {
|
|
return this.$row;
|
|
};
|
|
this.getCurrentTokenColumn = function() {
|
|
var rowTokens = this.$rowTokens;
|
|
var tokenIndex = this.$tokenIndex;
|
|
var column = rowTokens[tokenIndex].start;
|
|
if (column !== undefined)
|
|
return column;
|
|
|
|
column = 0;
|
|
while (tokenIndex > 0) {
|
|
tokenIndex -= 1;
|
|
column += rowTokens[tokenIndex].value.length;
|
|
}
|
|
|
|
return column;
|
|
};
|
|
this.getCurrentTokenPosition = function() {
|
|
return {row: this.$row, column: this.getCurrentTokenColumn()};
|
|
};
|
|
this.getCurrentTokenRange = function() {
|
|
var token = this.$rowTokens[this.$tokenIndex];
|
|
var column = this.getCurrentTokenColumn();
|
|
return new Range(this.$row, column, this.$row, column + token.value.length);
|
|
};
|
|
|
|
}).call(TokenIterator.prototype);
|
|
|
|
exports.TokenIterator = TokenIterator;
|
|
});
|
|
|
|
ace.define("ace/mode/behaviour/cstyle",["require","exports","module","ace/lib/oop","ace/mode/behaviour","ace/token_iterator","ace/lib/lang"], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var oop = require("../../lib/oop");
|
|
var Behaviour = require("../behaviour").Behaviour;
|
|
var TokenIterator = require("../../token_iterator").TokenIterator;
|
|
var lang = require("../../lib/lang");
|
|
|
|
var SAFE_INSERT_IN_TOKENS =
|
|
["text", "paren.rparen", "rparen", "paren", "punctuation.operator"];
|
|
var SAFE_INSERT_BEFORE_TOKENS =
|
|
["text", "paren.rparen", "rparen", "paren", "punctuation.operator", "comment"];
|
|
|
|
var context;
|
|
var contextCache = {};
|
|
var defaultQuotes = {'"' : '"', "'" : "'"};
|
|
|
|
var initContext = function(editor) {
|
|
var id = -1;
|
|
if (editor.multiSelect) {
|
|
id = editor.selection.index;
|
|
if (contextCache.rangeCount != editor.multiSelect.rangeCount)
|
|
contextCache = {rangeCount: editor.multiSelect.rangeCount};
|
|
}
|
|
if (contextCache[id])
|
|
return context = contextCache[id];
|
|
context = contextCache[id] = {
|
|
autoInsertedBrackets: 0,
|
|
autoInsertedRow: -1,
|
|
autoInsertedLineEnd: "",
|
|
maybeInsertedBrackets: 0,
|
|
maybeInsertedRow: -1,
|
|
maybeInsertedLineStart: "",
|
|
maybeInsertedLineEnd: ""
|
|
};
|
|
};
|
|
|
|
var getWrapped = function(selection, selected, opening, closing) {
|
|
var rowDiff = selection.end.row - selection.start.row;
|
|
return {
|
|
text: opening + selected + closing,
|
|
selection: [
|
|
0,
|
|
selection.start.column + 1,
|
|
rowDiff,
|
|
selection.end.column + (rowDiff ? 0 : 1)
|
|
]
|
|
};
|
|
};
|
|
|
|
var CstyleBehaviour = function(options) {
|
|
this.add("braces", "insertion", function(state, action, editor, session, text) {
|
|
var cursor = editor.getCursorPosition();
|
|
var line = session.doc.getLine(cursor.row);
|
|
if (text == '{') {
|
|
initContext(editor);
|
|
var selection = editor.getSelectionRange();
|
|
var selected = session.doc.getTextRange(selection);
|
|
if (selected !== "" && selected !== "{" && editor.getWrapBehavioursEnabled()) {
|
|
return getWrapped(selection, selected, '{', '}');
|
|
} else if (CstyleBehaviour.isSaneInsertion(editor, session)) {
|
|
if (/[\]\}\)]/.test(line[cursor.column]) || editor.inMultiSelectMode || options && options.braces) {
|
|
CstyleBehaviour.recordAutoInsert(editor, session, "}");
|
|
return {
|
|
text: '{}',
|
|
selection: [1, 1]
|
|
};
|
|
} else {
|
|
CstyleBehaviour.recordMaybeInsert(editor, session, "{");
|
|
return {
|
|
text: '{',
|
|
selection: [1, 1]
|
|
};
|
|
}
|
|
}
|
|
} else if (text == '}') {
|
|
initContext(editor);
|
|
var rightChar = line.substring(cursor.column, cursor.column + 1);
|
|
if (rightChar == '}') {
|
|
var matching = session.$findOpeningBracket('}', {column: cursor.column + 1, row: cursor.row});
|
|
if (matching !== null && CstyleBehaviour.isAutoInsertedClosing(cursor, line, text)) {
|
|
CstyleBehaviour.popAutoInsertedClosing();
|
|
return {
|
|
text: '',
|
|
selection: [1, 1]
|
|
};
|
|
}
|
|
}
|
|
} else if (text == "\n" || text == "\r\n") {
|
|
initContext(editor);
|
|
var closing = "";
|
|
if (CstyleBehaviour.isMaybeInsertedClosing(cursor, line)) {
|
|
closing = lang.stringRepeat("}", context.maybeInsertedBrackets);
|
|
CstyleBehaviour.clearMaybeInsertedClosing();
|
|
}
|
|
var rightChar = line.substring(cursor.column, cursor.column + 1);
|
|
if (rightChar === '}') {
|
|
var openBracePos = session.findMatchingBracket({row: cursor.row, column: cursor.column+1}, '}');
|
|
if (!openBracePos)
|
|
return null;
|
|
var next_indent = this.$getIndent(session.getLine(openBracePos.row));
|
|
} else if (closing) {
|
|
var next_indent = this.$getIndent(line);
|
|
} else {
|
|
CstyleBehaviour.clearMaybeInsertedClosing();
|
|
return;
|
|
}
|
|
var indent = next_indent + session.getTabString();
|
|
|
|
return {
|
|
text: '\n' + indent + '\n' + next_indent + closing,
|
|
selection: [1, indent.length, 1, indent.length]
|
|
};
|
|
} else {
|
|
CstyleBehaviour.clearMaybeInsertedClosing();
|
|
}
|
|
});
|
|
|
|
this.add("braces", "deletion", function(state, action, editor, session, range) {
|
|
var selected = session.doc.getTextRange(range);
|
|
if (!range.isMultiLine() && selected == '{') {
|
|
initContext(editor);
|
|
var line = session.doc.getLine(range.start.row);
|
|
var rightChar = line.substring(range.end.column, range.end.column + 1);
|
|
if (rightChar == '}') {
|
|
range.end.column++;
|
|
return range;
|
|
} else {
|
|
context.maybeInsertedBrackets--;
|
|
}
|
|
}
|
|
});
|
|
|
|
this.add("parens", "insertion", function(state, action, editor, session, text) {
|
|
if (text == '(') {
|
|
initContext(editor);
|
|
var selection = editor.getSelectionRange();
|
|
var selected = session.doc.getTextRange(selection);
|
|
if (selected !== "" && editor.getWrapBehavioursEnabled()) {
|
|
return getWrapped(selection, selected, '(', ')');
|
|
} else if (CstyleBehaviour.isSaneInsertion(editor, session)) {
|
|
CstyleBehaviour.recordAutoInsert(editor, session, ")");
|
|
return {
|
|
text: '()',
|
|
selection: [1, 1]
|
|
};
|
|
}
|
|
} else if (text == ')') {
|
|
initContext(editor);
|
|
var cursor = editor.getCursorPosition();
|
|
var line = session.doc.getLine(cursor.row);
|
|
var rightChar = line.substring(cursor.column, cursor.column + 1);
|
|
if (rightChar == ')') {
|
|
var matching = session.$findOpeningBracket(')', {column: cursor.column + 1, row: cursor.row});
|
|
if (matching !== null && CstyleBehaviour.isAutoInsertedClosing(cursor, line, text)) {
|
|
CstyleBehaviour.popAutoInsertedClosing();
|
|
return {
|
|
text: '',
|
|
selection: [1, 1]
|
|
};
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
this.add("parens", "deletion", function(state, action, editor, session, range) {
|
|
var selected = session.doc.getTextRange(range);
|
|
if (!range.isMultiLine() && selected == '(') {
|
|
initContext(editor);
|
|
var line = session.doc.getLine(range.start.row);
|
|
var rightChar = line.substring(range.start.column + 1, range.start.column + 2);
|
|
if (rightChar == ')') {
|
|
range.end.column++;
|
|
return range;
|
|
}
|
|
}
|
|
});
|
|
|
|
this.add("brackets", "insertion", function(state, action, editor, session, text) {
|
|
if (text == '[') {
|
|
initContext(editor);
|
|
var selection = editor.getSelectionRange();
|
|
var selected = session.doc.getTextRange(selection);
|
|
if (selected !== "" && editor.getWrapBehavioursEnabled()) {
|
|
return getWrapped(selection, selected, '[', ']');
|
|
} else if (CstyleBehaviour.isSaneInsertion(editor, session)) {
|
|
CstyleBehaviour.recordAutoInsert(editor, session, "]");
|
|
return {
|
|
text: '[]',
|
|
selection: [1, 1]
|
|
};
|
|
}
|
|
} else if (text == ']') {
|
|
initContext(editor);
|
|
var cursor = editor.getCursorPosition();
|
|
var line = session.doc.getLine(cursor.row);
|
|
var rightChar = line.substring(cursor.column, cursor.column + 1);
|
|
if (rightChar == ']') {
|
|
var matching = session.$findOpeningBracket(']', {column: cursor.column + 1, row: cursor.row});
|
|
if (matching !== null && CstyleBehaviour.isAutoInsertedClosing(cursor, line, text)) {
|
|
CstyleBehaviour.popAutoInsertedClosing();
|
|
return {
|
|
text: '',
|
|
selection: [1, 1]
|
|
};
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
this.add("brackets", "deletion", function(state, action, editor, session, range) {
|
|
var selected = session.doc.getTextRange(range);
|
|
if (!range.isMultiLine() && selected == '[') {
|
|
initContext(editor);
|
|
var line = session.doc.getLine(range.start.row);
|
|
var rightChar = line.substring(range.start.column + 1, range.start.column + 2);
|
|
if (rightChar == ']') {
|
|
range.end.column++;
|
|
return range;
|
|
}
|
|
}
|
|
});
|
|
|
|
this.add("string_dquotes", "insertion", function(state, action, editor, session, text) {
|
|
var quotes = session.$mode.$quotes || defaultQuotes;
|
|
if (text.length == 1 && quotes[text]) {
|
|
if (this.lineCommentStart && this.lineCommentStart.indexOf(text) != -1)
|
|
return;
|
|
initContext(editor);
|
|
var quote = text;
|
|
var selection = editor.getSelectionRange();
|
|
var selected = session.doc.getTextRange(selection);
|
|
if (selected !== "" && (selected.length != 1 || !quotes[selected]) && editor.getWrapBehavioursEnabled()) {
|
|
return getWrapped(selection, selected, quote, quote);
|
|
} else if (!selected) {
|
|
var cursor = editor.getCursorPosition();
|
|
var line = session.doc.getLine(cursor.row);
|
|
var leftChar = line.substring(cursor.column-1, cursor.column);
|
|
var rightChar = line.substring(cursor.column, cursor.column + 1);
|
|
|
|
var token = session.getTokenAt(cursor.row, cursor.column);
|
|
var rightToken = session.getTokenAt(cursor.row, cursor.column + 1);
|
|
if (leftChar == "\\" && token && /escape/.test(token.type))
|
|
return null;
|
|
|
|
var stringBefore = token && /string|escape/.test(token.type);
|
|
var stringAfter = !rightToken || /string|escape/.test(rightToken.type);
|
|
|
|
var pair;
|
|
if (rightChar == quote) {
|
|
pair = stringBefore !== stringAfter;
|
|
if (pair && /string\.end/.test(rightToken.type))
|
|
pair = false;
|
|
} else {
|
|
if (stringBefore && !stringAfter)
|
|
return null; // wrap string with different quote
|
|
if (stringBefore && stringAfter)
|
|
return null; // do not pair quotes inside strings
|
|
var wordRe = session.$mode.tokenRe;
|
|
wordRe.lastIndex = 0;
|
|
var isWordBefore = wordRe.test(leftChar);
|
|
wordRe.lastIndex = 0;
|
|
var isWordAfter = wordRe.test(leftChar);
|
|
if (isWordBefore || isWordAfter)
|
|
return null; // before or after alphanumeric
|
|
if (rightChar && !/[\s;,.})\]\\]/.test(rightChar))
|
|
return null; // there is rightChar and it isn't closing
|
|
var charBefore = line[cursor.column - 2];
|
|
if (leftChar == quote && (charBefore == quote || wordRe.test(charBefore)))
|
|
return null;
|
|
pair = true;
|
|
}
|
|
return {
|
|
text: pair ? quote + quote : "",
|
|
selection: [1,1]
|
|
};
|
|
}
|
|
}
|
|
});
|
|
|
|
this.add("string_dquotes", "deletion", function(state, action, editor, session, range) {
|
|
var quotes = session.$mode.$quotes || defaultQuotes;
|
|
|
|
var selected = session.doc.getTextRange(range);
|
|
if (!range.isMultiLine() && quotes.hasOwnProperty(selected)) {
|
|
initContext(editor);
|
|
var line = session.doc.getLine(range.start.row);
|
|
var rightChar = line.substring(range.start.column + 1, range.start.column + 2);
|
|
if (rightChar == selected) {
|
|
range.end.column++;
|
|
return range;
|
|
}
|
|
}
|
|
});
|
|
|
|
};
|
|
|
|
|
|
CstyleBehaviour.isSaneInsertion = function(editor, session) {
|
|
var cursor = editor.getCursorPosition();
|
|
var iterator = new TokenIterator(session, cursor.row, cursor.column);
|
|
if (!this.$matchTokenType(iterator.getCurrentToken() || "text", SAFE_INSERT_IN_TOKENS)) {
|
|
if (/[)}\]]/.test(editor.session.getLine(cursor.row)[cursor.column]))
|
|
return true;
|
|
var iterator2 = new TokenIterator(session, cursor.row, cursor.column + 1);
|
|
if (!this.$matchTokenType(iterator2.getCurrentToken() || "text", SAFE_INSERT_IN_TOKENS))
|
|
return false;
|
|
}
|
|
iterator.stepForward();
|
|
return iterator.getCurrentTokenRow() !== cursor.row ||
|
|
this.$matchTokenType(iterator.getCurrentToken() || "text", SAFE_INSERT_BEFORE_TOKENS);
|
|
};
|
|
|
|
CstyleBehaviour.$matchTokenType = function(token, types) {
|
|
return types.indexOf(token.type || token) > -1;
|
|
};
|
|
|
|
CstyleBehaviour.recordAutoInsert = function(editor, session, bracket) {
|
|
var cursor = editor.getCursorPosition();
|
|
var line = session.doc.getLine(cursor.row);
|
|
if (!this.isAutoInsertedClosing(cursor, line, context.autoInsertedLineEnd[0]))
|
|
context.autoInsertedBrackets = 0;
|
|
context.autoInsertedRow = cursor.row;
|
|
context.autoInsertedLineEnd = bracket + line.substr(cursor.column);
|
|
context.autoInsertedBrackets++;
|
|
};
|
|
|
|
CstyleBehaviour.recordMaybeInsert = function(editor, session, bracket) {
|
|
var cursor = editor.getCursorPosition();
|
|
var line = session.doc.getLine(cursor.row);
|
|
if (!this.isMaybeInsertedClosing(cursor, line))
|
|
context.maybeInsertedBrackets = 0;
|
|
context.maybeInsertedRow = cursor.row;
|
|
context.maybeInsertedLineStart = line.substr(0, cursor.column) + bracket;
|
|
context.maybeInsertedLineEnd = line.substr(cursor.column);
|
|
context.maybeInsertedBrackets++;
|
|
};
|
|
|
|
CstyleBehaviour.isAutoInsertedClosing = function(cursor, line, bracket) {
|
|
return context.autoInsertedBrackets > 0 &&
|
|
cursor.row === context.autoInsertedRow &&
|
|
bracket === context.autoInsertedLineEnd[0] &&
|
|
line.substr(cursor.column) === context.autoInsertedLineEnd;
|
|
};
|
|
|
|
CstyleBehaviour.isMaybeInsertedClosing = function(cursor, line) {
|
|
return context.maybeInsertedBrackets > 0 &&
|
|
cursor.row === context.maybeInsertedRow &&
|
|
line.substr(cursor.column) === context.maybeInsertedLineEnd &&
|
|
line.substr(0, cursor.column) == context.maybeInsertedLineStart;
|
|
};
|
|
|
|
CstyleBehaviour.popAutoInsertedClosing = function() {
|
|
context.autoInsertedLineEnd = context.autoInsertedLineEnd.substr(1);
|
|
context.autoInsertedBrackets--;
|
|
};
|
|
|
|
CstyleBehaviour.clearMaybeInsertedClosing = function() {
|
|
if (context) {
|
|
context.maybeInsertedBrackets = 0;
|
|
context.maybeInsertedRow = -1;
|
|
}
|
|
};
|
|
|
|
|
|
|
|
oop.inherits(CstyleBehaviour, Behaviour);
|
|
|
|
exports.CstyleBehaviour = CstyleBehaviour;
|
|
});
|
|
|
|
ace.define("ace/unicode",["require","exports","module"], function(require, exports, module) {
|
|
"use strict";
|
|
var wordChars = [48,9,8,25,5,0,2,25,48,0,11,0,5,0,6,22,2,30,2,457,5,11,15,4,8,0,2,0,18,116,2,1,3,3,9,0,2,2,2,0,2,19,2,82,2,138,2,4,3,155,12,37,3,0,8,38,10,44,2,0,2,1,2,1,2,0,9,26,6,2,30,10,7,61,2,9,5,101,2,7,3,9,2,18,3,0,17,58,3,100,15,53,5,0,6,45,211,57,3,18,2,5,3,11,3,9,2,1,7,6,2,2,2,7,3,1,3,21,2,6,2,0,4,3,3,8,3,1,3,3,9,0,5,1,2,4,3,11,16,2,2,5,5,1,3,21,2,6,2,1,2,1,2,1,3,0,2,4,5,1,3,2,4,0,8,3,2,0,8,15,12,2,2,8,2,2,2,21,2,6,2,1,2,4,3,9,2,2,2,2,3,0,16,3,3,9,18,2,2,7,3,1,3,21,2,6,2,1,2,4,3,8,3,1,3,2,9,1,5,1,2,4,3,9,2,0,17,1,2,5,4,2,2,3,4,1,2,0,2,1,4,1,4,2,4,11,5,4,4,2,2,3,3,0,7,0,15,9,18,2,2,7,2,2,2,22,2,9,2,4,4,7,2,2,2,3,8,1,2,1,7,3,3,9,19,1,2,7,2,2,2,22,2,9,2,4,3,8,2,2,2,3,8,1,8,0,2,3,3,9,19,1,2,7,2,2,2,22,2,15,4,7,2,2,2,3,10,0,9,3,3,9,11,5,3,1,2,17,4,23,2,8,2,0,3,6,4,0,5,5,2,0,2,7,19,1,14,57,6,14,2,9,40,1,2,0,3,1,2,0,3,0,7,3,2,6,2,2,2,0,2,0,3,1,2,12,2,2,3,4,2,0,2,5,3,9,3,1,35,0,24,1,7,9,12,0,2,0,2,0,5,9,2,35,5,19,2,5,5,7,2,35,10,0,58,73,7,77,3,37,11,42,2,0,4,328,2,3,3,6,2,0,2,3,3,40,2,3,3,32,2,3,3,6,2,0,2,3,3,14,2,56,2,3,3,66,5,0,33,15,17,84,13,619,3,16,2,25,6,74,22,12,2,6,12,20,12,19,13,12,2,2,2,1,13,51,3,29,4,0,5,1,3,9,34,2,3,9,7,87,9,42,6,69,11,28,4,11,5,11,11,39,3,4,12,43,5,25,7,10,38,27,5,62,2,28,3,10,7,9,14,0,89,75,5,9,18,8,13,42,4,11,71,55,9,9,4,48,83,2,2,30,14,230,23,280,3,5,3,37,3,5,3,7,2,0,2,0,2,0,2,30,3,52,2,6,2,0,4,2,2,6,4,3,3,5,5,12,6,2,2,6,67,1,20,0,29,0,14,0,17,4,60,12,5,0,4,11,18,0,5,0,3,9,2,0,4,4,7,0,2,0,2,0,2,3,2,10,3,3,6,4,5,0,53,1,2684,46,2,46,2,132,7,6,15,37,11,53,10,0,17,22,10,6,2,6,2,6,2,6,2,6,2,6,2,6,2,6,2,31,48,0,470,1,36,5,2,4,6,1,5,85,3,1,3,2,2,89,2,3,6,40,4,93,18,23,57,15,513,6581,75,20939,53,1164,68,45,3,268,4,27,21,31,3,13,13,1,2,24,9,69,11,1,38,8,3,102,3,1,111,44,25,51,13,68,12,9,7,23,4,0,5,45,3,35,13,28,4,64,15,10,39,54,10,13,3,9,7,22,4,1,5,66,25,2,227,42,2,1,3,9,7,11171,13,22,5,48,8453,301,3,61,3,105,39,6,13,4,6,11,2,12,2,4,2,0,2,1,2,1,2,107,34,362,19,63,3,53,41,11,5,15,17,6,13,1,25,2,33,4,2,134,20,9,8,25,5,0,2,25,12,88,4,5,3,5,3,5,3,2];
|
|
|
|
var code = 0;
|
|
var str = [];
|
|
for (var i = 0; i < wordChars.length; i += 2) {
|
|
str.push(code += wordChars[i]);
|
|
if (wordChars[i + 1])
|
|
str.push(45, code += wordChars[i + 1]);
|
|
}
|
|
|
|
exports.wordChars = String.fromCharCode.apply(null, str);
|
|
|
|
});
|
|
|
|
ace.define("ace/mode/text",["require","exports","module","ace/config","ace/tokenizer","ace/mode/text_highlight_rules","ace/mode/behaviour/cstyle","ace/unicode","ace/lib/lang","ace/token_iterator","ace/range"], function(require, exports, module) {
|
|
"use strict";
|
|
var config = require("../config");
|
|
|
|
var Tokenizer = require("../tokenizer").Tokenizer;
|
|
var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules;
|
|
var CstyleBehaviour = require("./behaviour/cstyle").CstyleBehaviour;
|
|
var unicode = require("../unicode");
|
|
var lang = require("../lib/lang");
|
|
var TokenIterator = require("../token_iterator").TokenIterator;
|
|
var Range = require("../range").Range;
|
|
|
|
var Mode = function() {
|
|
this.HighlightRules = TextHighlightRules;
|
|
};
|
|
|
|
(function() {
|
|
this.$defaultBehaviour = new CstyleBehaviour();
|
|
|
|
this.tokenRe = new RegExp("^[" + unicode.wordChars + "\\$_]+", "g");
|
|
|
|
this.nonTokenRe = new RegExp("^(?:[^" + unicode.wordChars + "\\$_]|\\s])+", "g");
|
|
|
|
this.getTokenizer = function() {
|
|
if (!this.$tokenizer) {
|
|
this.$highlightRules = this.$highlightRules || new this.HighlightRules(this.$highlightRuleConfig);
|
|
this.$tokenizer = new Tokenizer(this.$highlightRules.getRules());
|
|
}
|
|
return this.$tokenizer;
|
|
};
|
|
|
|
this.lineCommentStart = "";
|
|
this.blockComment = "";
|
|
|
|
this.toggleCommentLines = function(state, session, startRow, endRow) {
|
|
var doc = session.doc;
|
|
|
|
var ignoreBlankLines = true;
|
|
var shouldRemove = true;
|
|
var minIndent = Infinity;
|
|
var tabSize = session.getTabSize();
|
|
var insertAtTabStop = false;
|
|
|
|
if (!this.lineCommentStart) {
|
|
if (!this.blockComment)
|
|
return false;
|
|
var lineCommentStart = this.blockComment.start;
|
|
var lineCommentEnd = this.blockComment.end;
|
|
var regexpStart = new RegExp("^(\\s*)(?:" + lang.escapeRegExp(lineCommentStart) + ")");
|
|
var regexpEnd = new RegExp("(?:" + lang.escapeRegExp(lineCommentEnd) + ")\\s*$");
|
|
|
|
var comment = function(line, i) {
|
|
if (testRemove(line, i))
|
|
return;
|
|
if (!ignoreBlankLines || /\S/.test(line)) {
|
|
doc.insertInLine({row: i, column: line.length}, lineCommentEnd);
|
|
doc.insertInLine({row: i, column: minIndent}, lineCommentStart);
|
|
}
|
|
};
|
|
|
|
var uncomment = function(line, i) {
|
|
var m;
|
|
if (m = line.match(regexpEnd))
|
|
doc.removeInLine(i, line.length - m[0].length, line.length);
|
|
if (m = line.match(regexpStart))
|
|
doc.removeInLine(i, m[1].length, m[0].length);
|
|
};
|
|
|
|
var testRemove = function(line, row) {
|
|
if (regexpStart.test(line))
|
|
return true;
|
|
var tokens = session.getTokens(row);
|
|
for (var i = 0; i < tokens.length; i++) {
|
|
if (tokens[i].type === "comment")
|
|
return true;
|
|
}
|
|
};
|
|
} else {
|
|
if (Array.isArray(this.lineCommentStart)) {
|
|
var regexpStart = this.lineCommentStart.map(lang.escapeRegExp).join("|");
|
|
var lineCommentStart = this.lineCommentStart[0];
|
|
} else {
|
|
var regexpStart = lang.escapeRegExp(this.lineCommentStart);
|
|
var lineCommentStart = this.lineCommentStart;
|
|
}
|
|
regexpStart = new RegExp("^(\\s*)(?:" + regexpStart + ") ?");
|
|
|
|
insertAtTabStop = session.getUseSoftTabs();
|
|
|
|
var uncomment = function(line, i) {
|
|
var m = line.match(regexpStart);
|
|
if (!m) return;
|
|
var start = m[1].length, end = m[0].length;
|
|
if (!shouldInsertSpace(line, start, end) && m[0][end - 1] == " ")
|
|
end--;
|
|
doc.removeInLine(i, start, end);
|
|
};
|
|
var commentWithSpace = lineCommentStart + " ";
|
|
var comment = function(line, i) {
|
|
if (!ignoreBlankLines || /\S/.test(line)) {
|
|
if (shouldInsertSpace(line, minIndent, minIndent))
|
|
doc.insertInLine({row: i, column: minIndent}, commentWithSpace);
|
|
else
|
|
doc.insertInLine({row: i, column: minIndent}, lineCommentStart);
|
|
}
|
|
};
|
|
var testRemove = function(line, i) {
|
|
return regexpStart.test(line);
|
|
};
|
|
|
|
var shouldInsertSpace = function(line, before, after) {
|
|
var spaces = 0;
|
|
while (before-- && line.charAt(before) == " ")
|
|
spaces++;
|
|
if (spaces % tabSize != 0)
|
|
return false;
|
|
var spaces = 0;
|
|
while (line.charAt(after++) == " ")
|
|
spaces++;
|
|
if (tabSize > 2)
|
|
return spaces % tabSize != tabSize - 1;
|
|
else
|
|
return spaces % tabSize == 0;
|
|
};
|
|
}
|
|
|
|
function iter(fun) {
|
|
for (var i = startRow; i <= endRow; i++)
|
|
fun(doc.getLine(i), i);
|
|
}
|
|
|
|
|
|
var minEmptyLength = Infinity;
|
|
iter(function(line, i) {
|
|
var indent = line.search(/\S/);
|
|
if (indent !== -1) {
|
|
if (indent < minIndent)
|
|
minIndent = indent;
|
|
if (shouldRemove && !testRemove(line, i))
|
|
shouldRemove = false;
|
|
} else if (minEmptyLength > line.length) {
|
|
minEmptyLength = line.length;
|
|
}
|
|
});
|
|
|
|
if (minIndent == Infinity) {
|
|
minIndent = minEmptyLength;
|
|
ignoreBlankLines = false;
|
|
shouldRemove = false;
|
|
}
|
|
|
|
if (insertAtTabStop && minIndent % tabSize != 0)
|
|
minIndent = Math.floor(minIndent / tabSize) * tabSize;
|
|
|
|
iter(shouldRemove ? uncomment : comment);
|
|
};
|
|
|
|
this.toggleBlockComment = function(state, session, range, cursor) {
|
|
var comment = this.blockComment;
|
|
if (!comment)
|
|
return;
|
|
if (!comment.start && comment[0])
|
|
comment = comment[0];
|
|
|
|
var iterator = new TokenIterator(session, cursor.row, cursor.column);
|
|
var token = iterator.getCurrentToken();
|
|
|
|
var sel = session.selection;
|
|
var initialRange = session.selection.toOrientedRange();
|
|
var startRow, colDiff;
|
|
|
|
if (token && /comment/.test(token.type)) {
|
|
var startRange, endRange;
|
|
while (token && /comment/.test(token.type)) {
|
|
var i = token.value.indexOf(comment.start);
|
|
if (i != -1) {
|
|
var row = iterator.getCurrentTokenRow();
|
|
var column = iterator.getCurrentTokenColumn() + i;
|
|
startRange = new Range(row, column, row, column + comment.start.length);
|
|
break;
|
|
}
|
|
token = iterator.stepBackward();
|
|
}
|
|
|
|
var iterator = new TokenIterator(session, cursor.row, cursor.column);
|
|
var token = iterator.getCurrentToken();
|
|
while (token && /comment/.test(token.type)) {
|
|
var i = token.value.indexOf(comment.end);
|
|
if (i != -1) {
|
|
var row = iterator.getCurrentTokenRow();
|
|
var column = iterator.getCurrentTokenColumn() + i;
|
|
endRange = new Range(row, column, row, column + comment.end.length);
|
|
break;
|
|
}
|
|
token = iterator.stepForward();
|
|
}
|
|
if (endRange)
|
|
session.remove(endRange);
|
|
if (startRange) {
|
|
session.remove(startRange);
|
|
startRow = startRange.start.row;
|
|
colDiff = -comment.start.length;
|
|
}
|
|
} else {
|
|
colDiff = comment.start.length;
|
|
startRow = range.start.row;
|
|
session.insert(range.end, comment.end);
|
|
session.insert(range.start, comment.start);
|
|
}
|
|
if (initialRange.start.row == startRow)
|
|
initialRange.start.column += colDiff;
|
|
if (initialRange.end.row == startRow)
|
|
initialRange.end.column += colDiff;
|
|
session.selection.fromOrientedRange(initialRange);
|
|
};
|
|
|
|
this.getNextLineIndent = function(state, line, tab) {
|
|
return this.$getIndent(line);
|
|
};
|
|
|
|
this.checkOutdent = function(state, line, input) {
|
|
return false;
|
|
};
|
|
|
|
this.autoOutdent = function(state, doc, row) {
|
|
};
|
|
|
|
this.$getIndent = function(line) {
|
|
return line.match(/^\s*/)[0];
|
|
};
|
|
|
|
this.createWorker = function(session) {
|
|
return null;
|
|
};
|
|
|
|
this.createModeDelegates = function (mapping) {
|
|
this.$embeds = [];
|
|
this.$modes = {};
|
|
for (var i in mapping) {
|
|
if (mapping[i]) {
|
|
var Mode = mapping[i];
|
|
var id = Mode.prototype.$id;
|
|
var mode = config.$modes[id];
|
|
if (!mode)
|
|
config.$modes[id] = mode = new Mode();
|
|
if (!config.$modes[i])
|
|
config.$modes[i] = mode;
|
|
this.$embeds.push(i);
|
|
this.$modes[i] = mode;
|
|
}
|
|
}
|
|
|
|
var delegations = ["toggleBlockComment", "toggleCommentLines", "getNextLineIndent",
|
|
"checkOutdent", "autoOutdent", "transformAction", "getCompletions"];
|
|
|
|
for (var i = 0; i < delegations.length; i++) {
|
|
(function(scope) {
|
|
var functionName = delegations[i];
|
|
var defaultHandler = scope[functionName];
|
|
scope[delegations[i]] = function() {
|
|
return this.$delegator(functionName, arguments, defaultHandler);
|
|
};
|
|
}(this));
|
|
}
|
|
};
|
|
|
|
this.$delegator = function(method, args, defaultHandler) {
|
|
var state = args[0] || "start";
|
|
if (typeof state != "string") {
|
|
if (Array.isArray(state[2])) {
|
|
var language = state[2][state[2].length - 1];
|
|
var mode = this.$modes[language];
|
|
if (mode)
|
|
return mode[method].apply(mode, [state[1]].concat([].slice.call(args, 1)));
|
|
}
|
|
state = state[0] || "start";
|
|
}
|
|
|
|
for (var i = 0; i < this.$embeds.length; i++) {
|
|
if (!this.$modes[this.$embeds[i]]) continue;
|
|
|
|
var split = state.split(this.$embeds[i]);
|
|
if (!split[0] && split[1]) {
|
|
args[0] = split[1];
|
|
var mode = this.$modes[this.$embeds[i]];
|
|
return mode[method].apply(mode, args);
|
|
}
|
|
}
|
|
var ret = defaultHandler.apply(this, args);
|
|
return defaultHandler ? ret : undefined;
|
|
};
|
|
|
|
this.transformAction = function(state, action, editor, session, param) {
|
|
if (this.$behaviour) {
|
|
var behaviours = this.$behaviour.getBehaviours();
|
|
for (var key in behaviours) {
|
|
if (behaviours[key][action]) {
|
|
var ret = behaviours[key][action].apply(this, arguments);
|
|
if (ret) {
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
this.getKeywords = function(append) {
|
|
if (!this.completionKeywords) {
|
|
var rules = this.$tokenizer.rules;
|
|
var completionKeywords = [];
|
|
for (var rule in rules) {
|
|
var ruleItr = rules[rule];
|
|
for (var r = 0, l = ruleItr.length; r < l; r++) {
|
|
if (typeof ruleItr[r].token === "string") {
|
|
if (/keyword|support|storage/.test(ruleItr[r].token))
|
|
completionKeywords.push(ruleItr[r].regex);
|
|
}
|
|
else if (typeof ruleItr[r].token === "object") {
|
|
for (var a = 0, aLength = ruleItr[r].token.length; a < aLength; a++) {
|
|
if (/keyword|support|storage/.test(ruleItr[r].token[a])) {
|
|
var rule = ruleItr[r].regex.match(/\(.+?\)/g)[a];
|
|
completionKeywords.push(rule.substr(1, rule.length - 2));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
this.completionKeywords = completionKeywords;
|
|
}
|
|
if (!append)
|
|
return this.$keywordList;
|
|
return completionKeywords.concat(this.$keywordList || []);
|
|
};
|
|
|
|
this.$createKeywordList = function() {
|
|
if (!this.$highlightRules)
|
|
this.getTokenizer();
|
|
return this.$keywordList = this.$highlightRules.$keywordList || [];
|
|
};
|
|
|
|
this.getCompletions = function(state, session, pos, prefix) {
|
|
var keywords = this.$keywordList || this.$createKeywordList();
|
|
return keywords.map(function(word) {
|
|
return {
|
|
name: word,
|
|
value: word,
|
|
score: 0,
|
|
meta: "keyword"
|
|
};
|
|
});
|
|
};
|
|
|
|
this.$id = "ace/mode/text";
|
|
}).call(Mode.prototype);
|
|
|
|
exports.Mode = Mode;
|
|
});
|
|
|
|
ace.define("ace/apply_delta",["require","exports","module"], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
function throwDeltaError(delta, errorText){
|
|
console.log("Invalid Delta:", delta);
|
|
throw "Invalid Delta: " + errorText;
|
|
}
|
|
|
|
function positionInDocument(docLines, position) {
|
|
return position.row >= 0 && position.row < docLines.length &&
|
|
position.column >= 0 && position.column <= docLines[position.row].length;
|
|
}
|
|
|
|
function validateDelta(docLines, delta) {
|
|
if (delta.action != "insert" && delta.action != "remove")
|
|
throwDeltaError(delta, "delta.action must be 'insert' or 'remove'");
|
|
if (!(delta.lines instanceof Array))
|
|
throwDeltaError(delta, "delta.lines must be an Array");
|
|
if (!delta.start || !delta.end)
|
|
throwDeltaError(delta, "delta.start/end must be an present");
|
|
var start = delta.start;
|
|
if (!positionInDocument(docLines, delta.start))
|
|
throwDeltaError(delta, "delta.start must be contained in document");
|
|
var end = delta.end;
|
|
if (delta.action == "remove" && !positionInDocument(docLines, end))
|
|
throwDeltaError(delta, "delta.end must contained in document for 'remove' actions");
|
|
var numRangeRows = end.row - start.row;
|
|
var numRangeLastLineChars = (end.column - (numRangeRows == 0 ? start.column : 0));
|
|
if (numRangeRows != delta.lines.length - 1 || delta.lines[numRangeRows].length != numRangeLastLineChars)
|
|
throwDeltaError(delta, "delta.range must match delta lines");
|
|
}
|
|
|
|
exports.applyDelta = function(docLines, delta, doNotValidate) {
|
|
|
|
var row = delta.start.row;
|
|
var startColumn = delta.start.column;
|
|
var line = docLines[row] || "";
|
|
switch (delta.action) {
|
|
case "insert":
|
|
var lines = delta.lines;
|
|
if (lines.length === 1) {
|
|
docLines[row] = line.substring(0, startColumn) + delta.lines[0] + line.substring(startColumn);
|
|
} else {
|
|
var args = [row, 1].concat(delta.lines);
|
|
docLines.splice.apply(docLines, args);
|
|
docLines[row] = line.substring(0, startColumn) + docLines[row];
|
|
docLines[row + delta.lines.length - 1] += line.substring(startColumn);
|
|
}
|
|
break;
|
|
case "remove":
|
|
var endColumn = delta.end.column;
|
|
var endRow = delta.end.row;
|
|
if (row === endRow) {
|
|
docLines[row] = line.substring(0, startColumn) + line.substring(endColumn);
|
|
} else {
|
|
docLines.splice(
|
|
row, endRow - row + 1,
|
|
line.substring(0, startColumn) + docLines[endRow].substring(endColumn)
|
|
);
|
|
}
|
|
break;
|
|
}
|
|
};
|
|
});
|
|
|
|
ace.define("ace/anchor",["require","exports","module","ace/lib/oop","ace/lib/event_emitter"], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var oop = require("./lib/oop");
|
|
var EventEmitter = require("./lib/event_emitter").EventEmitter;
|
|
|
|
var Anchor = exports.Anchor = function(doc, row, column) {
|
|
this.$onChange = this.onChange.bind(this);
|
|
this.attach(doc);
|
|
|
|
if (typeof column == "undefined")
|
|
this.setPosition(row.row, row.column);
|
|
else
|
|
this.setPosition(row, column);
|
|
};
|
|
|
|
(function() {
|
|
|
|
oop.implement(this, EventEmitter);
|
|
this.getPosition = function() {
|
|
return this.$clipPositionToDocument(this.row, this.column);
|
|
};
|
|
this.getDocument = function() {
|
|
return this.document;
|
|
};
|
|
this.$insertRight = false;
|
|
this.onChange = function(delta) {
|
|
if (delta.start.row == delta.end.row && delta.start.row != this.row)
|
|
return;
|
|
|
|
if (delta.start.row > this.row)
|
|
return;
|
|
|
|
var point = $getTransformedPoint(delta, {row: this.row, column: this.column}, this.$insertRight);
|
|
this.setPosition(point.row, point.column, true);
|
|
};
|
|
|
|
function $pointsInOrder(point1, point2, equalPointsInOrder) {
|
|
var bColIsAfter = equalPointsInOrder ? point1.column <= point2.column : point1.column < point2.column;
|
|
return (point1.row < point2.row) || (point1.row == point2.row && bColIsAfter);
|
|
}
|
|
|
|
function $getTransformedPoint(delta, point, moveIfEqual) {
|
|
var deltaIsInsert = delta.action == "insert";
|
|
var deltaRowShift = (deltaIsInsert ? 1 : -1) * (delta.end.row - delta.start.row);
|
|
var deltaColShift = (deltaIsInsert ? 1 : -1) * (delta.end.column - delta.start.column);
|
|
var deltaStart = delta.start;
|
|
var deltaEnd = deltaIsInsert ? deltaStart : delta.end; // Collapse insert range.
|
|
if ($pointsInOrder(point, deltaStart, moveIfEqual)) {
|
|
return {
|
|
row: point.row,
|
|
column: point.column
|
|
};
|
|
}
|
|
if ($pointsInOrder(deltaEnd, point, !moveIfEqual)) {
|
|
return {
|
|
row: point.row + deltaRowShift,
|
|
column: point.column + (point.row == deltaEnd.row ? deltaColShift : 0)
|
|
};
|
|
}
|
|
|
|
return {
|
|
row: deltaStart.row,
|
|
column: deltaStart.column
|
|
};
|
|
}
|
|
this.setPosition = function(row, column, noClip) {
|
|
var pos;
|
|
if (noClip) {
|
|
pos = {
|
|
row: row,
|
|
column: column
|
|
};
|
|
} else {
|
|
pos = this.$clipPositionToDocument(row, column);
|
|
}
|
|
|
|
if (this.row == pos.row && this.column == pos.column)
|
|
return;
|
|
|
|
var old = {
|
|
row: this.row,
|
|
column: this.column
|
|
};
|
|
|
|
this.row = pos.row;
|
|
this.column = pos.column;
|
|
this._signal("change", {
|
|
old: old,
|
|
value: pos
|
|
});
|
|
};
|
|
this.detach = function() {
|
|
this.document.off("change", this.$onChange);
|
|
};
|
|
this.attach = function(doc) {
|
|
this.document = doc || this.document;
|
|
this.document.on("change", this.$onChange);
|
|
};
|
|
this.$clipPositionToDocument = function(row, column) {
|
|
var pos = {};
|
|
|
|
if (row >= this.document.getLength()) {
|
|
pos.row = Math.max(0, this.document.getLength() - 1);
|
|
pos.column = this.document.getLine(pos.row).length;
|
|
}
|
|
else if (row < 0) {
|
|
pos.row = 0;
|
|
pos.column = 0;
|
|
}
|
|
else {
|
|
pos.row = row;
|
|
pos.column = Math.min(this.document.getLine(pos.row).length, Math.max(0, column));
|
|
}
|
|
|
|
if (column < 0)
|
|
pos.column = 0;
|
|
|
|
return pos;
|
|
};
|
|
|
|
}).call(Anchor.prototype);
|
|
|
|
});
|
|
|
|
ace.define("ace/document",["require","exports","module","ace/lib/oop","ace/apply_delta","ace/lib/event_emitter","ace/range","ace/anchor"], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var oop = require("./lib/oop");
|
|
var applyDelta = require("./apply_delta").applyDelta;
|
|
var EventEmitter = require("./lib/event_emitter").EventEmitter;
|
|
var Range = require("./range").Range;
|
|
var Anchor = require("./anchor").Anchor;
|
|
|
|
var Document = function(textOrLines) {
|
|
this.$lines = [""];
|
|
if (textOrLines.length === 0) {
|
|
this.$lines = [""];
|
|
} else if (Array.isArray(textOrLines)) {
|
|
this.insertMergedLines({row: 0, column: 0}, textOrLines);
|
|
} else {
|
|
this.insert({row: 0, column:0}, textOrLines);
|
|
}
|
|
};
|
|
|
|
(function() {
|
|
|
|
oop.implement(this, EventEmitter);
|
|
this.setValue = function(text) {
|
|
var len = this.getLength() - 1;
|
|
this.remove(new Range(0, 0, len, this.getLine(len).length));
|
|
this.insert({row: 0, column: 0}, text);
|
|
};
|
|
this.getValue = function() {
|
|
return this.getAllLines().join(this.getNewLineCharacter());
|
|
};
|
|
this.createAnchor = function(row, column) {
|
|
return new Anchor(this, row, column);
|
|
};
|
|
if ("aaa".split(/a/).length === 0) {
|
|
this.$split = function(text) {
|
|
return text.replace(/\r\n|\r/g, "\n").split("\n");
|
|
};
|
|
} else {
|
|
this.$split = function(text) {
|
|
return text.split(/\r\n|\r|\n/);
|
|
};
|
|
}
|
|
|
|
|
|
this.$detectNewLine = function(text) {
|
|
var match = text.match(/^.*?(\r\n|\r|\n)/m);
|
|
this.$autoNewLine = match ? match[1] : "\n";
|
|
this._signal("changeNewLineMode");
|
|
};
|
|
this.getNewLineCharacter = function() {
|
|
switch (this.$newLineMode) {
|
|
case "windows":
|
|
return "\r\n";
|
|
case "unix":
|
|
return "\n";
|
|
default:
|
|
return this.$autoNewLine || "\n";
|
|
}
|
|
};
|
|
|
|
this.$autoNewLine = "";
|
|
this.$newLineMode = "auto";
|
|
this.setNewLineMode = function(newLineMode) {
|
|
if (this.$newLineMode === newLineMode)
|
|
return;
|
|
|
|
this.$newLineMode = newLineMode;
|
|
this._signal("changeNewLineMode");
|
|
};
|
|
this.getNewLineMode = function() {
|
|
return this.$newLineMode;
|
|
};
|
|
this.isNewLine = function(text) {
|
|
return (text == "\r\n" || text == "\r" || text == "\n");
|
|
};
|
|
this.getLine = function(row) {
|
|
return this.$lines[row] || "";
|
|
};
|
|
this.getLines = function(firstRow, lastRow) {
|
|
return this.$lines.slice(firstRow, lastRow + 1);
|
|
};
|
|
this.getAllLines = function() {
|
|
return this.getLines(0, this.getLength());
|
|
};
|
|
this.getLength = function() {
|
|
return this.$lines.length;
|
|
};
|
|
this.getTextRange = function(range) {
|
|
return this.getLinesForRange(range).join(this.getNewLineCharacter());
|
|
};
|
|
this.getLinesForRange = function(range) {
|
|
var lines;
|
|
if (range.start.row === range.end.row) {
|
|
lines = [this.getLine(range.start.row).substring(range.start.column, range.end.column)];
|
|
} else {
|
|
lines = this.getLines(range.start.row, range.end.row);
|
|
lines[0] = (lines[0] || "").substring(range.start.column);
|
|
var l = lines.length - 1;
|
|
if (range.end.row - range.start.row == l)
|
|
lines[l] = lines[l].substring(0, range.end.column);
|
|
}
|
|
return lines;
|
|
};
|
|
this.insertLines = function(row, lines) {
|
|
console.warn("Use of document.insertLines is deprecated. Use the insertFullLines method instead.");
|
|
return this.insertFullLines(row, lines);
|
|
};
|
|
this.removeLines = function(firstRow, lastRow) {
|
|
console.warn("Use of document.removeLines is deprecated. Use the removeFullLines method instead.");
|
|
return this.removeFullLines(firstRow, lastRow);
|
|
};
|
|
this.insertNewLine = function(position) {
|
|
console.warn("Use of document.insertNewLine is deprecated. Use insertMergedLines(position, ['', '']) instead.");
|
|
return this.insertMergedLines(position, ["", ""]);
|
|
};
|
|
this.insert = function(position, text) {
|
|
if (this.getLength() <= 1)
|
|
this.$detectNewLine(text);
|
|
|
|
return this.insertMergedLines(position, this.$split(text));
|
|
};
|
|
this.insertInLine = function(position, text) {
|
|
var start = this.clippedPos(position.row, position.column);
|
|
var end = this.pos(position.row, position.column + text.length);
|
|
|
|
this.applyDelta({
|
|
start: start,
|
|
end: end,
|
|
action: "insert",
|
|
lines: [text]
|
|
}, true);
|
|
|
|
return this.clonePos(end);
|
|
};
|
|
|
|
this.clippedPos = function(row, column) {
|
|
var length = this.getLength();
|
|
if (row === undefined) {
|
|
row = length;
|
|
} else if (row < 0) {
|
|
row = 0;
|
|
} else if (row >= length) {
|
|
row = length - 1;
|
|
column = undefined;
|
|
}
|
|
var line = this.getLine(row);
|
|
if (column == undefined)
|
|
column = line.length;
|
|
column = Math.min(Math.max(column, 0), line.length);
|
|
return {row: row, column: column};
|
|
};
|
|
|
|
this.clonePos = function(pos) {
|
|
return {row: pos.row, column: pos.column};
|
|
};
|
|
|
|
this.pos = function(row, column) {
|
|
return {row: row, column: column};
|
|
};
|
|
|
|
this.$clipPosition = function(position) {
|
|
var length = this.getLength();
|
|
if (position.row >= length) {
|
|
position.row = Math.max(0, length - 1);
|
|
position.column = this.getLine(length - 1).length;
|
|
} else {
|
|
position.row = Math.max(0, position.row);
|
|
position.column = Math.min(Math.max(position.column, 0), this.getLine(position.row).length);
|
|
}
|
|
return position;
|
|
};
|
|
this.insertFullLines = function(row, lines) {
|
|
row = Math.min(Math.max(row, 0), this.getLength());
|
|
var column = 0;
|
|
if (row < this.getLength()) {
|
|
lines = lines.concat([""]);
|
|
column = 0;
|
|
} else {
|
|
lines = [""].concat(lines);
|
|
row--;
|
|
column = this.$lines[row].length;
|
|
}
|
|
this.insertMergedLines({row: row, column: column}, lines);
|
|
};
|
|
this.insertMergedLines = function(position, lines) {
|
|
var start = this.clippedPos(position.row, position.column);
|
|
var end = {
|
|
row: start.row + lines.length - 1,
|
|
column: (lines.length == 1 ? start.column : 0) + lines[lines.length - 1].length
|
|
};
|
|
|
|
this.applyDelta({
|
|
start: start,
|
|
end: end,
|
|
action: "insert",
|
|
lines: lines
|
|
});
|
|
|
|
return this.clonePos(end);
|
|
};
|
|
this.remove = function(range) {
|
|
var start = this.clippedPos(range.start.row, range.start.column);
|
|
var end = this.clippedPos(range.end.row, range.end.column);
|
|
this.applyDelta({
|
|
start: start,
|
|
end: end,
|
|
action: "remove",
|
|
lines: this.getLinesForRange({start: start, end: end})
|
|
});
|
|
return this.clonePos(start);
|
|
};
|
|
this.removeInLine = function(row, startColumn, endColumn) {
|
|
var start = this.clippedPos(row, startColumn);
|
|
var end = this.clippedPos(row, endColumn);
|
|
|
|
this.applyDelta({
|
|
start: start,
|
|
end: end,
|
|
action: "remove",
|
|
lines: this.getLinesForRange({start: start, end: end})
|
|
}, true);
|
|
|
|
return this.clonePos(start);
|
|
};
|
|
this.removeFullLines = function(firstRow, lastRow) {
|
|
firstRow = Math.min(Math.max(0, firstRow), this.getLength() - 1);
|
|
lastRow = Math.min(Math.max(0, lastRow ), this.getLength() - 1);
|
|
var deleteFirstNewLine = lastRow == this.getLength() - 1 && firstRow > 0;
|
|
var deleteLastNewLine = lastRow < this.getLength() - 1;
|
|
var startRow = ( deleteFirstNewLine ? firstRow - 1 : firstRow );
|
|
var startCol = ( deleteFirstNewLine ? this.getLine(startRow).length : 0 );
|
|
var endRow = ( deleteLastNewLine ? lastRow + 1 : lastRow );
|
|
var endCol = ( deleteLastNewLine ? 0 : this.getLine(endRow).length );
|
|
var range = new Range(startRow, startCol, endRow, endCol);
|
|
var deletedLines = this.$lines.slice(firstRow, lastRow + 1);
|
|
|
|
this.applyDelta({
|
|
start: range.start,
|
|
end: range.end,
|
|
action: "remove",
|
|
lines: this.getLinesForRange(range)
|
|
});
|
|
return deletedLines;
|
|
};
|
|
this.removeNewLine = function(row) {
|
|
if (row < this.getLength() - 1 && row >= 0) {
|
|
this.applyDelta({
|
|
start: this.pos(row, this.getLine(row).length),
|
|
end: this.pos(row + 1, 0),
|
|
action: "remove",
|
|
lines: ["", ""]
|
|
});
|
|
}
|
|
};
|
|
this.replace = function(range, text) {
|
|
if (!(range instanceof Range))
|
|
range = Range.fromPoints(range.start, range.end);
|
|
if (text.length === 0 && range.isEmpty())
|
|
return range.start;
|
|
if (text == this.getTextRange(range))
|
|
return range.end;
|
|
|
|
this.remove(range);
|
|
var end;
|
|
if (text) {
|
|
end = this.insert(range.start, text);
|
|
}
|
|
else {
|
|
end = range.start;
|
|
}
|
|
|
|
return end;
|
|
};
|
|
this.applyDeltas = function(deltas) {
|
|
for (var i=0; i<deltas.length; i++) {
|
|
this.applyDelta(deltas[i]);
|
|
}
|
|
};
|
|
this.revertDeltas = function(deltas) {
|
|
for (var i=deltas.length-1; i>=0; i--) {
|
|
this.revertDelta(deltas[i]);
|
|
}
|
|
};
|
|
this.applyDelta = function(delta, doNotValidate) {
|
|
var isInsert = delta.action == "insert";
|
|
if (isInsert ? delta.lines.length <= 1 && !delta.lines[0]
|
|
: !Range.comparePoints(delta.start, delta.end)) {
|
|
return;
|
|
}
|
|
|
|
if (isInsert && delta.lines.length > 20000) {
|
|
this.$splitAndapplyLargeDelta(delta, 20000);
|
|
}
|
|
else {
|
|
applyDelta(this.$lines, delta, doNotValidate);
|
|
this._signal("change", delta);
|
|
}
|
|
};
|
|
|
|
this.$safeApplyDelta = function(delta) {
|
|
var docLength = this.$lines.length;
|
|
if (
|
|
delta.action == "remove" && delta.start.row < docLength && delta.end.row < docLength
|
|
|| delta.action == "insert" && delta.start.row <= docLength
|
|
) {
|
|
this.applyDelta(delta);
|
|
}
|
|
};
|
|
|
|
this.$splitAndapplyLargeDelta = function(delta, MAX) {
|
|
var lines = delta.lines;
|
|
var l = lines.length - MAX + 1;
|
|
var row = delta.start.row;
|
|
var column = delta.start.column;
|
|
for (var from = 0, to = 0; from < l; from = to) {
|
|
to += MAX - 1;
|
|
var chunk = lines.slice(from, to);
|
|
chunk.push("");
|
|
this.applyDelta({
|
|
start: this.pos(row + from, column),
|
|
end: this.pos(row + to, column = 0),
|
|
action: delta.action,
|
|
lines: chunk
|
|
}, true);
|
|
}
|
|
delta.lines = lines.slice(from);
|
|
delta.start.row = row + from;
|
|
delta.start.column = column;
|
|
this.applyDelta(delta, true);
|
|
};
|
|
this.revertDelta = function(delta) {
|
|
this.$safeApplyDelta({
|
|
start: this.clonePos(delta.start),
|
|
end: this.clonePos(delta.end),
|
|
action: (delta.action == "insert" ? "remove" : "insert"),
|
|
lines: delta.lines.slice()
|
|
});
|
|
};
|
|
this.indexToPosition = function(index, startRow) {
|
|
var lines = this.$lines || this.getAllLines();
|
|
var newlineLength = this.getNewLineCharacter().length;
|
|
for (var i = startRow || 0, l = lines.length; i < l; i++) {
|
|
index -= lines[i].length + newlineLength;
|
|
if (index < 0)
|
|
return {row: i, column: index + lines[i].length + newlineLength};
|
|
}
|
|
return {row: l-1, column: index + lines[l-1].length + newlineLength};
|
|
};
|
|
this.positionToIndex = function(pos, startRow) {
|
|
var lines = this.$lines || this.getAllLines();
|
|
var newlineLength = this.getNewLineCharacter().length;
|
|
var index = 0;
|
|
var row = Math.min(pos.row, lines.length);
|
|
for (var i = startRow || 0; i < row; ++i)
|
|
index += lines[i].length + newlineLength;
|
|
|
|
return index + pos.column;
|
|
};
|
|
|
|
}).call(Document.prototype);
|
|
|
|
exports.Document = Document;
|
|
});
|
|
|
|
ace.define("ace/background_tokenizer",["require","exports","module","ace/lib/oop","ace/lib/event_emitter"], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var oop = require("./lib/oop");
|
|
var EventEmitter = require("./lib/event_emitter").EventEmitter;
|
|
|
|
var BackgroundTokenizer = function(tokenizer, editor) {
|
|
this.running = false;
|
|
this.lines = [];
|
|
this.states = [];
|
|
this.currentLine = 0;
|
|
this.tokenizer = tokenizer;
|
|
|
|
var self = this;
|
|
|
|
this.$worker = function() {
|
|
if (!self.running) { return; }
|
|
|
|
var workerStart = new Date();
|
|
var currentLine = self.currentLine;
|
|
var endLine = -1;
|
|
var doc = self.doc;
|
|
|
|
var startLine = currentLine;
|
|
while (self.lines[currentLine])
|
|
currentLine++;
|
|
|
|
var len = doc.getLength();
|
|
var processedLines = 0;
|
|
self.running = false;
|
|
while (currentLine < len) {
|
|
self.$tokenizeRow(currentLine);
|
|
endLine = currentLine;
|
|
do {
|
|
currentLine++;
|
|
} while (self.lines[currentLine]);
|
|
processedLines ++;
|
|
if ((processedLines % 5 === 0) && (new Date() - workerStart) > 20) {
|
|
self.running = setTimeout(self.$worker, 20);
|
|
break;
|
|
}
|
|
}
|
|
self.currentLine = currentLine;
|
|
|
|
if (endLine == -1)
|
|
endLine = currentLine;
|
|
|
|
if (startLine <= endLine)
|
|
self.fireUpdateEvent(startLine, endLine);
|
|
};
|
|
};
|
|
|
|
(function(){
|
|
|
|
oop.implement(this, EventEmitter);
|
|
this.setTokenizer = function(tokenizer) {
|
|
this.tokenizer = tokenizer;
|
|
this.lines = [];
|
|
this.states = [];
|
|
|
|
this.start(0);
|
|
};
|
|
this.setDocument = function(doc) {
|
|
this.doc = doc;
|
|
this.lines = [];
|
|
this.states = [];
|
|
|
|
this.stop();
|
|
};
|
|
this.fireUpdateEvent = function(firstRow, lastRow) {
|
|
var data = {
|
|
first: firstRow,
|
|
last: lastRow
|
|
};
|
|
this._signal("update", {data: data});
|
|
};
|
|
this.start = function(startRow) {
|
|
this.currentLine = Math.min(startRow || 0, this.currentLine, this.doc.getLength());
|
|
this.lines.splice(this.currentLine, this.lines.length);
|
|
this.states.splice(this.currentLine, this.states.length);
|
|
|
|
this.stop();
|
|
this.running = setTimeout(this.$worker, 700);
|
|
};
|
|
|
|
this.scheduleStart = function() {
|
|
if (!this.running)
|
|
this.running = setTimeout(this.$worker, 700);
|
|
};
|
|
|
|
this.$updateOnChange = function(delta) {
|
|
var startRow = delta.start.row;
|
|
var len = delta.end.row - startRow;
|
|
|
|
if (len === 0) {
|
|
this.lines[startRow] = null;
|
|
} else if (delta.action == "remove") {
|
|
this.lines.splice(startRow, len + 1, null);
|
|
this.states.splice(startRow, len + 1, null);
|
|
} else {
|
|
var args = Array(len + 1);
|
|
args.unshift(startRow, 1);
|
|
this.lines.splice.apply(this.lines, args);
|
|
this.states.splice.apply(this.states, args);
|
|
}
|
|
|
|
this.currentLine = Math.min(startRow, this.currentLine, this.doc.getLength());
|
|
|
|
this.stop();
|
|
};
|
|
this.stop = function() {
|
|
if (this.running)
|
|
clearTimeout(this.running);
|
|
this.running = false;
|
|
};
|
|
this.getTokens = function(row) {
|
|
return this.lines[row] || this.$tokenizeRow(row);
|
|
};
|
|
this.getState = function(row) {
|
|
if (this.currentLine == row)
|
|
this.$tokenizeRow(row);
|
|
return this.states[row] || "start";
|
|
};
|
|
|
|
this.$tokenizeRow = function(row) {
|
|
var line = this.doc.getLine(row);
|
|
var state = this.states[row - 1];
|
|
|
|
var data = this.tokenizer.getLineTokens(line, state, row);
|
|
|
|
if (this.states[row] + "" !== data.state + "") {
|
|
this.states[row] = data.state;
|
|
this.lines[row + 1] = null;
|
|
if (this.currentLine > row + 1)
|
|
this.currentLine = row + 1;
|
|
} else if (this.currentLine == row) {
|
|
this.currentLine = row + 1;
|
|
}
|
|
|
|
return this.lines[row] = data.tokens;
|
|
};
|
|
|
|
}).call(BackgroundTokenizer.prototype);
|
|
|
|
exports.BackgroundTokenizer = BackgroundTokenizer;
|
|
});
|
|
|
|
ace.define("ace/search_highlight",["require","exports","module","ace/lib/lang","ace/lib/oop","ace/range"], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var lang = require("./lib/lang");
|
|
var oop = require("./lib/oop");
|
|
var Range = require("./range").Range;
|
|
|
|
var SearchHighlight = function(regExp, clazz, type) {
|
|
this.setRegexp(regExp);
|
|
this.clazz = clazz;
|
|
this.type = type || "text";
|
|
};
|
|
|
|
(function() {
|
|
this.MAX_RANGES = 500;
|
|
|
|
this.setRegexp = function(regExp) {
|
|
if (this.regExp+"" == regExp+"")
|
|
return;
|
|
this.regExp = regExp;
|
|
this.cache = [];
|
|
};
|
|
|
|
this.update = function(html, markerLayer, session, config) {
|
|
if (!this.regExp)
|
|
return;
|
|
var start = config.firstRow, end = config.lastRow;
|
|
|
|
for (var i = start; i <= end; i++) {
|
|
var ranges = this.cache[i];
|
|
if (ranges == null) {
|
|
ranges = lang.getMatchOffsets(session.getLine(i), this.regExp);
|
|
if (ranges.length > this.MAX_RANGES)
|
|
ranges = ranges.slice(0, this.MAX_RANGES);
|
|
ranges = ranges.map(function(match) {
|
|
return new Range(i, match.offset, i, match.offset + match.length);
|
|
});
|
|
this.cache[i] = ranges.length ? ranges : "";
|
|
}
|
|
|
|
for (var j = ranges.length; j --; ) {
|
|
markerLayer.drawSingleLineMarker(
|
|
html, ranges[j].toScreenRange(session), this.clazz, config);
|
|
}
|
|
}
|
|
};
|
|
|
|
}).call(SearchHighlight.prototype);
|
|
|
|
exports.SearchHighlight = SearchHighlight;
|
|
});
|
|
|
|
ace.define("ace/edit_session/fold_line",["require","exports","module","ace/range"], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var Range = require("../range").Range;
|
|
function FoldLine(foldData, folds) {
|
|
this.foldData = foldData;
|
|
if (Array.isArray(folds)) {
|
|
this.folds = folds;
|
|
} else {
|
|
folds = this.folds = [ folds ];
|
|
}
|
|
|
|
var last = folds[folds.length - 1];
|
|
this.range = new Range(folds[0].start.row, folds[0].start.column,
|
|
last.end.row, last.end.column);
|
|
this.start = this.range.start;
|
|
this.end = this.range.end;
|
|
|
|
this.folds.forEach(function(fold) {
|
|
fold.setFoldLine(this);
|
|
}, this);
|
|
}
|
|
|
|
(function() {
|
|
this.shiftRow = function(shift) {
|
|
this.start.row += shift;
|
|
this.end.row += shift;
|
|
this.folds.forEach(function(fold) {
|
|
fold.start.row += shift;
|
|
fold.end.row += shift;
|
|
});
|
|
};
|
|
|
|
this.addFold = function(fold) {
|
|
if (fold.sameRow) {
|
|
if (fold.start.row < this.startRow || fold.endRow > this.endRow) {
|
|
throw new Error("Can't add a fold to this FoldLine as it has no connection");
|
|
}
|
|
this.folds.push(fold);
|
|
this.folds.sort(function(a, b) {
|
|
return -a.range.compareEnd(b.start.row, b.start.column);
|
|
});
|
|
if (this.range.compareEnd(fold.start.row, fold.start.column) > 0) {
|
|
this.end.row = fold.end.row;
|
|
this.end.column = fold.end.column;
|
|
} else if (this.range.compareStart(fold.end.row, fold.end.column) < 0) {
|
|
this.start.row = fold.start.row;
|
|
this.start.column = fold.start.column;
|
|
}
|
|
} else if (fold.start.row == this.end.row) {
|
|
this.folds.push(fold);
|
|
this.end.row = fold.end.row;
|
|
this.end.column = fold.end.column;
|
|
} else if (fold.end.row == this.start.row) {
|
|
this.folds.unshift(fold);
|
|
this.start.row = fold.start.row;
|
|
this.start.column = fold.start.column;
|
|
} else {
|
|
throw new Error("Trying to add fold to FoldRow that doesn't have a matching row");
|
|
}
|
|
fold.foldLine = this;
|
|
};
|
|
|
|
this.containsRow = function(row) {
|
|
return row >= this.start.row && row <= this.end.row;
|
|
};
|
|
|
|
this.walk = function(callback, endRow, endColumn) {
|
|
var lastEnd = 0,
|
|
folds = this.folds,
|
|
fold,
|
|
cmp, stop, isNewRow = true;
|
|
|
|
if (endRow == null) {
|
|
endRow = this.end.row;
|
|
endColumn = this.end.column;
|
|
}
|
|
|
|
for (var i = 0; i < folds.length; i++) {
|
|
fold = folds[i];
|
|
|
|
cmp = fold.range.compareStart(endRow, endColumn);
|
|
if (cmp == -1) {
|
|
callback(null, endRow, endColumn, lastEnd, isNewRow);
|
|
return;
|
|
}
|
|
|
|
stop = callback(null, fold.start.row, fold.start.column, lastEnd, isNewRow);
|
|
stop = !stop && callback(fold.placeholder, fold.start.row, fold.start.column, lastEnd);
|
|
if (stop || cmp === 0) {
|
|
return;
|
|
}
|
|
isNewRow = !fold.sameRow;
|
|
lastEnd = fold.end.column;
|
|
}
|
|
callback(null, endRow, endColumn, lastEnd, isNewRow);
|
|
};
|
|
|
|
this.getNextFoldTo = function(row, column) {
|
|
var fold, cmp;
|
|
for (var i = 0; i < this.folds.length; i++) {
|
|
fold = this.folds[i];
|
|
cmp = fold.range.compareEnd(row, column);
|
|
if (cmp == -1) {
|
|
return {
|
|
fold: fold,
|
|
kind: "after"
|
|
};
|
|
} else if (cmp === 0) {
|
|
return {
|
|
fold: fold,
|
|
kind: "inside"
|
|
};
|
|
}
|
|
}
|
|
return null;
|
|
};
|
|
|
|
this.addRemoveChars = function(row, column, len) {
|
|
var ret = this.getNextFoldTo(row, column),
|
|
fold, folds;
|
|
if (ret) {
|
|
fold = ret.fold;
|
|
if (ret.kind == "inside"
|
|
&& fold.start.column != column
|
|
&& fold.start.row != row)
|
|
{
|
|
window.console && window.console.log(row, column, fold);
|
|
} else if (fold.start.row == row) {
|
|
folds = this.folds;
|
|
var i = folds.indexOf(fold);
|
|
if (i === 0) {
|
|
this.start.column += len;
|
|
}
|
|
for (i; i < folds.length; i++) {
|
|
fold = folds[i];
|
|
fold.start.column += len;
|
|
if (!fold.sameRow) {
|
|
return;
|
|
}
|
|
fold.end.column += len;
|
|
}
|
|
this.end.column += len;
|
|
}
|
|
}
|
|
};
|
|
|
|
this.split = function(row, column) {
|
|
var pos = this.getNextFoldTo(row, column);
|
|
|
|
if (!pos || pos.kind == "inside")
|
|
return null;
|
|
|
|
var fold = pos.fold;
|
|
var folds = this.folds;
|
|
var foldData = this.foldData;
|
|
|
|
var i = folds.indexOf(fold);
|
|
var foldBefore = folds[i - 1];
|
|
this.end.row = foldBefore.end.row;
|
|
this.end.column = foldBefore.end.column;
|
|
folds = folds.splice(i, folds.length - i);
|
|
|
|
var newFoldLine = new FoldLine(foldData, folds);
|
|
foldData.splice(foldData.indexOf(this) + 1, 0, newFoldLine);
|
|
return newFoldLine;
|
|
};
|
|
|
|
this.merge = function(foldLineNext) {
|
|
var folds = foldLineNext.folds;
|
|
for (var i = 0; i < folds.length; i++) {
|
|
this.addFold(folds[i]);
|
|
}
|
|
var foldData = this.foldData;
|
|
foldData.splice(foldData.indexOf(foldLineNext), 1);
|
|
};
|
|
|
|
this.toString = function() {
|
|
var ret = [this.range.toString() + ": [" ];
|
|
|
|
this.folds.forEach(function(fold) {
|
|
ret.push(" " + fold.toString());
|
|
});
|
|
ret.push("]");
|
|
return ret.join("\n");
|
|
};
|
|
|
|
this.idxToPosition = function(idx) {
|
|
var lastFoldEndColumn = 0;
|
|
|
|
for (var i = 0; i < this.folds.length; i++) {
|
|
var fold = this.folds[i];
|
|
|
|
idx -= fold.start.column - lastFoldEndColumn;
|
|
if (idx < 0) {
|
|
return {
|
|
row: fold.start.row,
|
|
column: fold.start.column + idx
|
|
};
|
|
}
|
|
|
|
idx -= fold.placeholder.length;
|
|
if (idx < 0) {
|
|
return fold.start;
|
|
}
|
|
|
|
lastFoldEndColumn = fold.end.column;
|
|
}
|
|
|
|
return {
|
|
row: this.end.row,
|
|
column: this.end.column + idx
|
|
};
|
|
};
|
|
}).call(FoldLine.prototype);
|
|
|
|
exports.FoldLine = FoldLine;
|
|
});
|
|
|
|
ace.define("ace/range_list",["require","exports","module","ace/range"], function(require, exports, module) {
|
|
"use strict";
|
|
var Range = require("./range").Range;
|
|
var comparePoints = Range.comparePoints;
|
|
|
|
var RangeList = function() {
|
|
this.ranges = [];
|
|
this.$bias = 1;
|
|
};
|
|
|
|
(function() {
|
|
this.comparePoints = comparePoints;
|
|
|
|
this.pointIndex = function(pos, excludeEdges, startIndex) {
|
|
var list = this.ranges;
|
|
|
|
for (var i = startIndex || 0; i < list.length; i++) {
|
|
var range = list[i];
|
|
var cmpEnd = comparePoints(pos, range.end);
|
|
if (cmpEnd > 0)
|
|
continue;
|
|
var cmpStart = comparePoints(pos, range.start);
|
|
if (cmpEnd === 0)
|
|
return excludeEdges && cmpStart !== 0 ? -i-2 : i;
|
|
if (cmpStart > 0 || (cmpStart === 0 && !excludeEdges))
|
|
return i;
|
|
|
|
return -i-1;
|
|
}
|
|
return -i - 1;
|
|
};
|
|
|
|
this.add = function(range) {
|
|
var excludeEdges = !range.isEmpty();
|
|
var startIndex = this.pointIndex(range.start, excludeEdges);
|
|
if (startIndex < 0)
|
|
startIndex = -startIndex - 1;
|
|
|
|
var endIndex = this.pointIndex(range.end, excludeEdges, startIndex);
|
|
|
|
if (endIndex < 0)
|
|
endIndex = -endIndex - 1;
|
|
else
|
|
endIndex++;
|
|
return this.ranges.splice(startIndex, endIndex - startIndex, range);
|
|
};
|
|
|
|
this.addList = function(list) {
|
|
var removed = [];
|
|
for (var i = list.length; i--; ) {
|
|
removed.push.apply(removed, this.add(list[i]));
|
|
}
|
|
return removed;
|
|
};
|
|
|
|
this.substractPoint = function(pos) {
|
|
var i = this.pointIndex(pos);
|
|
|
|
if (i >= 0)
|
|
return this.ranges.splice(i, 1);
|
|
};
|
|
this.merge = function() {
|
|
var removed = [];
|
|
var list = this.ranges;
|
|
|
|
list = list.sort(function(a, b) {
|
|
return comparePoints(a.start, b.start);
|
|
});
|
|
|
|
var next = list[0], range;
|
|
for (var i = 1; i < list.length; i++) {
|
|
range = next;
|
|
next = list[i];
|
|
var cmp = comparePoints(range.end, next.start);
|
|
if (cmp < 0)
|
|
continue;
|
|
|
|
if (cmp == 0 && !range.isEmpty() && !next.isEmpty())
|
|
continue;
|
|
|
|
if (comparePoints(range.end, next.end) < 0) {
|
|
range.end.row = next.end.row;
|
|
range.end.column = next.end.column;
|
|
}
|
|
|
|
list.splice(i, 1);
|
|
removed.push(next);
|
|
next = range;
|
|
i--;
|
|
}
|
|
|
|
this.ranges = list;
|
|
|
|
return removed;
|
|
};
|
|
|
|
this.contains = function(row, column) {
|
|
return this.pointIndex({row: row, column: column}) >= 0;
|
|
};
|
|
|
|
this.containsPoint = function(pos) {
|
|
return this.pointIndex(pos) >= 0;
|
|
};
|
|
|
|
this.rangeAtPoint = function(pos) {
|
|
var i = this.pointIndex(pos);
|
|
if (i >= 0)
|
|
return this.ranges[i];
|
|
};
|
|
|
|
|
|
this.clipRows = function(startRow, endRow) {
|
|
var list = this.ranges;
|
|
if (list[0].start.row > endRow || list[list.length - 1].start.row < startRow)
|
|
return [];
|
|
|
|
var startIndex = this.pointIndex({row: startRow, column: 0});
|
|
if (startIndex < 0)
|
|
startIndex = -startIndex - 1;
|
|
var endIndex = this.pointIndex({row: endRow, column: 0}, startIndex);
|
|
if (endIndex < 0)
|
|
endIndex = -endIndex - 1;
|
|
|
|
var clipped = [];
|
|
for (var i = startIndex; i < endIndex; i++) {
|
|
clipped.push(list[i]);
|
|
}
|
|
return clipped;
|
|
};
|
|
|
|
this.removeAll = function() {
|
|
return this.ranges.splice(0, this.ranges.length);
|
|
};
|
|
|
|
this.attach = function(session) {
|
|
if (this.session)
|
|
this.detach();
|
|
|
|
this.session = session;
|
|
this.onChange = this.$onChange.bind(this);
|
|
|
|
this.session.on('change', this.onChange);
|
|
};
|
|
|
|
this.detach = function() {
|
|
if (!this.session)
|
|
return;
|
|
this.session.removeListener('change', this.onChange);
|
|
this.session = null;
|
|
};
|
|
|
|
this.$onChange = function(delta) {
|
|
var start = delta.start;
|
|
var end = delta.end;
|
|
var startRow = start.row;
|
|
var endRow = end.row;
|
|
var ranges = this.ranges;
|
|
for (var i = 0, n = ranges.length; i < n; i++) {
|
|
var r = ranges[i];
|
|
if (r.end.row >= startRow)
|
|
break;
|
|
}
|
|
|
|
if (delta.action == "insert") {
|
|
var lineDif = endRow - startRow;
|
|
var colDiff = -start.column + end.column;
|
|
for (; i < n; i++) {
|
|
var r = ranges[i];
|
|
if (r.start.row > startRow)
|
|
break;
|
|
|
|
if (r.start.row == startRow && r.start.column >= start.column) {
|
|
if (r.start.column == start.column && this.$bias <= 0) {
|
|
} else {
|
|
r.start.column += colDiff;
|
|
r.start.row += lineDif;
|
|
}
|
|
}
|
|
if (r.end.row == startRow && r.end.column >= start.column) {
|
|
if (r.end.column == start.column && this.$bias < 0) {
|
|
continue;
|
|
}
|
|
if (r.end.column == start.column && colDiff > 0 && i < n - 1) {
|
|
if (r.end.column > r.start.column && r.end.column == ranges[i+1].start.column)
|
|
r.end.column -= colDiff;
|
|
}
|
|
r.end.column += colDiff;
|
|
r.end.row += lineDif;
|
|
}
|
|
}
|
|
} else {
|
|
var lineDif = startRow - endRow;
|
|
var colDiff = start.column - end.column;
|
|
for (; i < n; i++) {
|
|
var r = ranges[i];
|
|
|
|
if (r.start.row > endRow)
|
|
break;
|
|
|
|
if (r.end.row < endRow
|
|
&& (
|
|
startRow < r.end.row
|
|
|| startRow == r.end.row && start.column < r.end.column
|
|
)
|
|
) {
|
|
r.end.row = startRow;
|
|
r.end.column = start.column;
|
|
}
|
|
else if (r.end.row == endRow) {
|
|
if (r.end.column <= end.column) {
|
|
if (lineDif || r.end.column > start.column) {
|
|
r.end.column = start.column;
|
|
r.end.row = start.row;
|
|
}
|
|
}
|
|
else {
|
|
r.end.column += colDiff;
|
|
r.end.row += lineDif;
|
|
}
|
|
}
|
|
else if (r.end.row > endRow) {
|
|
r.end.row += lineDif;
|
|
}
|
|
|
|
if (r.start.row < endRow
|
|
&& (
|
|
startRow < r.start.row
|
|
|| startRow == r.start.row && start.column < r.start.column
|
|
)
|
|
) {
|
|
r.start.row = startRow;
|
|
r.start.column = start.column;
|
|
}
|
|
else if (r.start.row == endRow) {
|
|
if (r.start.column <= end.column) {
|
|
if (lineDif || r.start.column > start.column) {
|
|
r.start.column = start.column;
|
|
r.start.row = start.row;
|
|
}
|
|
}
|
|
else {
|
|
r.start.column += colDiff;
|
|
r.start.row += lineDif;
|
|
}
|
|
}
|
|
else if (r.start.row > endRow) {
|
|
r.start.row += lineDif;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (lineDif != 0 && i < n) {
|
|
for (; i < n; i++) {
|
|
var r = ranges[i];
|
|
r.start.row += lineDif;
|
|
r.end.row += lineDif;
|
|
}
|
|
}
|
|
};
|
|
|
|
}).call(RangeList.prototype);
|
|
|
|
exports.RangeList = RangeList;
|
|
});
|
|
|
|
ace.define("ace/edit_session/fold",["require","exports","module","ace/range_list","ace/lib/oop"], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var RangeList = require("../range_list").RangeList;
|
|
var oop = require("../lib/oop");
|
|
var Fold = exports.Fold = function(range, placeholder) {
|
|
this.foldLine = null;
|
|
this.placeholder = placeholder;
|
|
this.range = range;
|
|
this.start = range.start;
|
|
this.end = range.end;
|
|
|
|
this.sameRow = range.start.row == range.end.row;
|
|
this.subFolds = this.ranges = [];
|
|
};
|
|
|
|
oop.inherits(Fold, RangeList);
|
|
|
|
(function() {
|
|
|
|
this.toString = function() {
|
|
return '"' + this.placeholder + '" ' + this.range.toString();
|
|
};
|
|
|
|
this.setFoldLine = function(foldLine) {
|
|
this.foldLine = foldLine;
|
|
this.subFolds.forEach(function(fold) {
|
|
fold.setFoldLine(foldLine);
|
|
});
|
|
};
|
|
|
|
this.clone = function() {
|
|
var range = this.range.clone();
|
|
var fold = new Fold(range, this.placeholder);
|
|
this.subFolds.forEach(function(subFold) {
|
|
fold.subFolds.push(subFold.clone());
|
|
});
|
|
fold.collapseChildren = this.collapseChildren;
|
|
return fold;
|
|
};
|
|
|
|
this.addSubFold = function(fold) {
|
|
if (this.range.isEqual(fold))
|
|
return;
|
|
consumeRange(fold, this.start);
|
|
|
|
var row = fold.start.row, column = fold.start.column;
|
|
for (var i = 0, cmp = -1; i < this.subFolds.length; i++) {
|
|
cmp = this.subFolds[i].range.compare(row, column);
|
|
if (cmp != 1)
|
|
break;
|
|
}
|
|
var afterStart = this.subFolds[i];
|
|
var firstConsumed = 0;
|
|
|
|
if (cmp == 0) {
|
|
if (afterStart.range.containsRange(fold))
|
|
return afterStart.addSubFold(fold);
|
|
else
|
|
firstConsumed = 1;
|
|
}
|
|
var row = fold.range.end.row, column = fold.range.end.column;
|
|
for (var j = i, cmp = -1; j < this.subFolds.length; j++) {
|
|
cmp = this.subFolds[j].range.compare(row, column);
|
|
if (cmp != 1)
|
|
break;
|
|
}
|
|
if (cmp == 0) j++;
|
|
var consumedFolds = this.subFolds.splice(i, j - i, fold);
|
|
var last = cmp == 0 ? consumedFolds.length - 1 : consumedFolds.length;
|
|
for (var k = firstConsumed; k < last; k++) {
|
|
fold.addSubFold(consumedFolds[k]);
|
|
}
|
|
fold.setFoldLine(this.foldLine);
|
|
|
|
return fold;
|
|
};
|
|
|
|
this.restoreRange = function(range) {
|
|
return restoreRange(range, this.start);
|
|
};
|
|
|
|
}).call(Fold.prototype);
|
|
|
|
function consumePoint(point, anchor) {
|
|
point.row -= anchor.row;
|
|
if (point.row == 0)
|
|
point.column -= anchor.column;
|
|
}
|
|
function consumeRange(range, anchor) {
|
|
consumePoint(range.start, anchor);
|
|
consumePoint(range.end, anchor);
|
|
}
|
|
function restorePoint(point, anchor) {
|
|
if (point.row == 0)
|
|
point.column += anchor.column;
|
|
point.row += anchor.row;
|
|
}
|
|
function restoreRange(range, anchor) {
|
|
restorePoint(range.start, anchor);
|
|
restorePoint(range.end, anchor);
|
|
}
|
|
|
|
});
|
|
|
|
ace.define("ace/edit_session/folding",["require","exports","module","ace/range","ace/edit_session/fold_line","ace/edit_session/fold","ace/token_iterator"], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var Range = require("../range").Range;
|
|
var FoldLine = require("./fold_line").FoldLine;
|
|
var Fold = require("./fold").Fold;
|
|
var TokenIterator = require("../token_iterator").TokenIterator;
|
|
|
|
function Folding() {
|
|
this.getFoldAt = function(row, column, side) {
|
|
var foldLine = this.getFoldLine(row);
|
|
if (!foldLine)
|
|
return null;
|
|
|
|
var folds = foldLine.folds;
|
|
for (var i = 0; i < folds.length; i++) {
|
|
var range = folds[i].range;
|
|
if (range.contains(row, column)) {
|
|
if (side == 1 && range.isEnd(row, column) && !range.isEmpty()) {
|
|
continue;
|
|
} else if (side == -1 && range.isStart(row, column) && !range.isEmpty()) {
|
|
continue;
|
|
}
|
|
return folds[i];
|
|
}
|
|
}
|
|
};
|
|
this.getFoldsInRange = function(range) {
|
|
var start = range.start;
|
|
var end = range.end;
|
|
var foldLines = this.$foldData;
|
|
var foundFolds = [];
|
|
|
|
start.column += 1;
|
|
end.column -= 1;
|
|
|
|
for (var i = 0; i < foldLines.length; i++) {
|
|
var cmp = foldLines[i].range.compareRange(range);
|
|
if (cmp == 2) {
|
|
continue;
|
|
}
|
|
else if (cmp == -2) {
|
|
break;
|
|
}
|
|
|
|
var folds = foldLines[i].folds;
|
|
for (var j = 0; j < folds.length; j++) {
|
|
var fold = folds[j];
|
|
cmp = fold.range.compareRange(range);
|
|
if (cmp == -2) {
|
|
break;
|
|
} else if (cmp == 2) {
|
|
continue;
|
|
} else
|
|
if (cmp == 42) {
|
|
break;
|
|
}
|
|
foundFolds.push(fold);
|
|
}
|
|
}
|
|
start.column -= 1;
|
|
end.column += 1;
|
|
|
|
return foundFolds;
|
|
};
|
|
|
|
this.getFoldsInRangeList = function(ranges) {
|
|
if (Array.isArray(ranges)) {
|
|
var folds = [];
|
|
ranges.forEach(function(range) {
|
|
folds = folds.concat(this.getFoldsInRange(range));
|
|
}, this);
|
|
} else {
|
|
var folds = this.getFoldsInRange(ranges);
|
|
}
|
|
return folds;
|
|
};
|
|
this.getAllFolds = function() {
|
|
var folds = [];
|
|
var foldLines = this.$foldData;
|
|
|
|
for (var i = 0; i < foldLines.length; i++)
|
|
for (var j = 0; j < foldLines[i].folds.length; j++)
|
|
folds.push(foldLines[i].folds[j]);
|
|
|
|
return folds;
|
|
};
|
|
this.getFoldStringAt = function(row, column, trim, foldLine) {
|
|
foldLine = foldLine || this.getFoldLine(row);
|
|
if (!foldLine)
|
|
return null;
|
|
|
|
var lastFold = {
|
|
end: { column: 0 }
|
|
};
|
|
var str, fold;
|
|
for (var i = 0; i < foldLine.folds.length; i++) {
|
|
fold = foldLine.folds[i];
|
|
var cmp = fold.range.compareEnd(row, column);
|
|
if (cmp == -1) {
|
|
str = this
|
|
.getLine(fold.start.row)
|
|
.substring(lastFold.end.column, fold.start.column);
|
|
break;
|
|
}
|
|
else if (cmp === 0) {
|
|
return null;
|
|
}
|
|
lastFold = fold;
|
|
}
|
|
if (!str)
|
|
str = this.getLine(fold.start.row).substring(lastFold.end.column);
|
|
|
|
if (trim == -1)
|
|
return str.substring(0, column - lastFold.end.column);
|
|
else if (trim == 1)
|
|
return str.substring(column - lastFold.end.column);
|
|
else
|
|
return str;
|
|
};
|
|
|
|
this.getFoldLine = function(docRow, startFoldLine) {
|
|
var foldData = this.$foldData;
|
|
var i = 0;
|
|
if (startFoldLine)
|
|
i = foldData.indexOf(startFoldLine);
|
|
if (i == -1)
|
|
i = 0;
|
|
for (i; i < foldData.length; i++) {
|
|
var foldLine = foldData[i];
|
|
if (foldLine.start.row <= docRow && foldLine.end.row >= docRow) {
|
|
return foldLine;
|
|
} else if (foldLine.end.row > docRow) {
|
|
return null;
|
|
}
|
|
}
|
|
return null;
|
|
};
|
|
this.getNextFoldLine = function(docRow, startFoldLine) {
|
|
var foldData = this.$foldData;
|
|
var i = 0;
|
|
if (startFoldLine)
|
|
i = foldData.indexOf(startFoldLine);
|
|
if (i == -1)
|
|
i = 0;
|
|
for (i; i < foldData.length; i++) {
|
|
var foldLine = foldData[i];
|
|
if (foldLine.end.row >= docRow) {
|
|
return foldLine;
|
|
}
|
|
}
|
|
return null;
|
|
};
|
|
|
|
this.getFoldedRowCount = function(first, last) {
|
|
var foldData = this.$foldData, rowCount = last-first+1;
|
|
for (var i = 0; i < foldData.length; i++) {
|
|
var foldLine = foldData[i],
|
|
end = foldLine.end.row,
|
|
start = foldLine.start.row;
|
|
if (end >= last) {
|
|
if (start < last) {
|
|
if (start >= first)
|
|
rowCount -= last-start;
|
|
else
|
|
rowCount = 0; // in one fold
|
|
}
|
|
break;
|
|
} else if (end >= first){
|
|
if (start >= first) // fold inside range
|
|
rowCount -= end-start;
|
|
else
|
|
rowCount -= end-first+1;
|
|
}
|
|
}
|
|
return rowCount;
|
|
};
|
|
|
|
this.$addFoldLine = function(foldLine) {
|
|
this.$foldData.push(foldLine);
|
|
this.$foldData.sort(function(a, b) {
|
|
return a.start.row - b.start.row;
|
|
});
|
|
return foldLine;
|
|
};
|
|
this.addFold = function(placeholder, range) {
|
|
var foldData = this.$foldData;
|
|
var added = false;
|
|
var fold;
|
|
|
|
if (placeholder instanceof Fold)
|
|
fold = placeholder;
|
|
else {
|
|
fold = new Fold(range, placeholder);
|
|
fold.collapseChildren = range.collapseChildren;
|
|
}
|
|
this.$clipRangeToDocument(fold.range);
|
|
|
|
var startRow = fold.start.row;
|
|
var startColumn = fold.start.column;
|
|
var endRow = fold.end.row;
|
|
var endColumn = fold.end.column;
|
|
|
|
var startFold = this.getFoldAt(startRow, startColumn, 1);
|
|
var endFold = this.getFoldAt(endRow, endColumn, -1);
|
|
if (startFold && endFold == startFold)
|
|
return startFold.addSubFold(fold);
|
|
|
|
if (startFold && !startFold.range.isStart(startRow, startColumn))
|
|
this.removeFold(startFold);
|
|
|
|
if (endFold && !endFold.range.isEnd(endRow, endColumn))
|
|
this.removeFold(endFold);
|
|
var folds = this.getFoldsInRange(fold.range);
|
|
if (folds.length > 0) {
|
|
this.removeFolds(folds);
|
|
if (!fold.collapseChildren) {
|
|
folds.forEach(function(subFold) {
|
|
fold.addSubFold(subFold);
|
|
});
|
|
}
|
|
}
|
|
|
|
for (var i = 0; i < foldData.length; i++) {
|
|
var foldLine = foldData[i];
|
|
if (endRow == foldLine.start.row) {
|
|
foldLine.addFold(fold);
|
|
added = true;
|
|
break;
|
|
} else if (startRow == foldLine.end.row) {
|
|
foldLine.addFold(fold);
|
|
added = true;
|
|
if (!fold.sameRow) {
|
|
var foldLineNext = foldData[i + 1];
|
|
if (foldLineNext && foldLineNext.start.row == endRow) {
|
|
foldLine.merge(foldLineNext);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
} else if (endRow <= foldLine.start.row) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!added)
|
|
foldLine = this.$addFoldLine(new FoldLine(this.$foldData, fold));
|
|
|
|
if (this.$useWrapMode)
|
|
this.$updateWrapData(foldLine.start.row, foldLine.start.row);
|
|
else
|
|
this.$updateRowLengthCache(foldLine.start.row, foldLine.start.row);
|
|
this.$modified = true;
|
|
this._signal("changeFold", { data: fold, action: "add" });
|
|
|
|
return fold;
|
|
};
|
|
|
|
this.addFolds = function(folds) {
|
|
folds.forEach(function(fold) {
|
|
this.addFold(fold);
|
|
}, this);
|
|
};
|
|
|
|
this.removeFold = function(fold) {
|
|
var foldLine = fold.foldLine;
|
|
var startRow = foldLine.start.row;
|
|
var endRow = foldLine.end.row;
|
|
|
|
var foldLines = this.$foldData;
|
|
var folds = foldLine.folds;
|
|
if (folds.length == 1) {
|
|
foldLines.splice(foldLines.indexOf(foldLine), 1);
|
|
} else
|
|
if (foldLine.range.isEnd(fold.end.row, fold.end.column)) {
|
|
folds.pop();
|
|
foldLine.end.row = folds[folds.length - 1].end.row;
|
|
foldLine.end.column = folds[folds.length - 1].end.column;
|
|
} else
|
|
if (foldLine.range.isStart(fold.start.row, fold.start.column)) {
|
|
folds.shift();
|
|
foldLine.start.row = folds[0].start.row;
|
|
foldLine.start.column = folds[0].start.column;
|
|
} else
|
|
if (fold.sameRow) {
|
|
folds.splice(folds.indexOf(fold), 1);
|
|
} else
|
|
{
|
|
var newFoldLine = foldLine.split(fold.start.row, fold.start.column);
|
|
folds = newFoldLine.folds;
|
|
folds.shift();
|
|
newFoldLine.start.row = folds[0].start.row;
|
|
newFoldLine.start.column = folds[0].start.column;
|
|
}
|
|
|
|
if (!this.$updating) {
|
|
if (this.$useWrapMode)
|
|
this.$updateWrapData(startRow, endRow);
|
|
else
|
|
this.$updateRowLengthCache(startRow, endRow);
|
|
}
|
|
this.$modified = true;
|
|
this._signal("changeFold", { data: fold, action: "remove" });
|
|
};
|
|
|
|
this.removeFolds = function(folds) {
|
|
var cloneFolds = [];
|
|
for (var i = 0; i < folds.length; i++) {
|
|
cloneFolds.push(folds[i]);
|
|
}
|
|
|
|
cloneFolds.forEach(function(fold) {
|
|
this.removeFold(fold);
|
|
}, this);
|
|
this.$modified = true;
|
|
};
|
|
|
|
this.expandFold = function(fold) {
|
|
this.removeFold(fold);
|
|
fold.subFolds.forEach(function(subFold) {
|
|
fold.restoreRange(subFold);
|
|
this.addFold(subFold);
|
|
}, this);
|
|
if (fold.collapseChildren > 0) {
|
|
this.foldAll(fold.start.row+1, fold.end.row, fold.collapseChildren-1);
|
|
}
|
|
fold.subFolds = [];
|
|
};
|
|
|
|
this.expandFolds = function(folds) {
|
|
folds.forEach(function(fold) {
|
|
this.expandFold(fold);
|
|
}, this);
|
|
};
|
|
|
|
this.unfold = function(location, expandInner) {
|
|
var range, folds;
|
|
if (location == null) {
|
|
range = new Range(0, 0, this.getLength(), 0);
|
|
if (expandInner == null) expandInner = true;
|
|
} else if (typeof location == "number")
|
|
range = new Range(location, 0, location, this.getLine(location).length);
|
|
else if ("row" in location)
|
|
range = Range.fromPoints(location, location);
|
|
else
|
|
range = location;
|
|
|
|
folds = this.getFoldsInRangeList(range);
|
|
if (expandInner != false) {
|
|
this.removeFolds(folds);
|
|
} else {
|
|
this.expandFolds(folds);
|
|
}
|
|
if (folds.length)
|
|
return folds;
|
|
};
|
|
this.isRowFolded = function(docRow, startFoldRow) {
|
|
return !!this.getFoldLine(docRow, startFoldRow);
|
|
};
|
|
|
|
this.getRowFoldEnd = function(docRow, startFoldRow) {
|
|
var foldLine = this.getFoldLine(docRow, startFoldRow);
|
|
return foldLine ? foldLine.end.row : docRow;
|
|
};
|
|
|
|
this.getRowFoldStart = function(docRow, startFoldRow) {
|
|
var foldLine = this.getFoldLine(docRow, startFoldRow);
|
|
return foldLine ? foldLine.start.row : docRow;
|
|
};
|
|
|
|
this.getFoldDisplayLine = function(foldLine, endRow, endColumn, startRow, startColumn) {
|
|
if (startRow == null)
|
|
startRow = foldLine.start.row;
|
|
if (startColumn == null)
|
|
startColumn = 0;
|
|
if (endRow == null)
|
|
endRow = foldLine.end.row;
|
|
if (endColumn == null)
|
|
endColumn = this.getLine(endRow).length;
|
|
var doc = this.doc;
|
|
var textLine = "";
|
|
|
|
foldLine.walk(function(placeholder, row, column, lastColumn) {
|
|
if (row < startRow)
|
|
return;
|
|
if (row == startRow) {
|
|
if (column < startColumn)
|
|
return;
|
|
lastColumn = Math.max(startColumn, lastColumn);
|
|
}
|
|
|
|
if (placeholder != null) {
|
|
textLine += placeholder;
|
|
} else {
|
|
textLine += doc.getLine(row).substring(lastColumn, column);
|
|
}
|
|
}, endRow, endColumn);
|
|
return textLine;
|
|
};
|
|
|
|
this.getDisplayLine = function(row, endColumn, startRow, startColumn) {
|
|
var foldLine = this.getFoldLine(row);
|
|
|
|
if (!foldLine) {
|
|
var line;
|
|
line = this.doc.getLine(row);
|
|
return line.substring(startColumn || 0, endColumn || line.length);
|
|
} else {
|
|
return this.getFoldDisplayLine(
|
|
foldLine, row, endColumn, startRow, startColumn);
|
|
}
|
|
};
|
|
|
|
this.$cloneFoldData = function() {
|
|
var fd = [];
|
|
fd = this.$foldData.map(function(foldLine) {
|
|
var folds = foldLine.folds.map(function(fold) {
|
|
return fold.clone();
|
|
});
|
|
return new FoldLine(fd, folds);
|
|
});
|
|
|
|
return fd;
|
|
};
|
|
|
|
this.toggleFold = function(tryToUnfold) {
|
|
var selection = this.selection;
|
|
var range = selection.getRange();
|
|
var fold;
|
|
var bracketPos;
|
|
|
|
if (range.isEmpty()) {
|
|
var cursor = range.start;
|
|
fold = this.getFoldAt(cursor.row, cursor.column);
|
|
|
|
if (fold) {
|
|
this.expandFold(fold);
|
|
return;
|
|
} else if (bracketPos = this.findMatchingBracket(cursor)) {
|
|
if (range.comparePoint(bracketPos) == 1) {
|
|
range.end = bracketPos;
|
|
} else {
|
|
range.start = bracketPos;
|
|
range.start.column++;
|
|
range.end.column--;
|
|
}
|
|
} else if (bracketPos = this.findMatchingBracket({row: cursor.row, column: cursor.column + 1})) {
|
|
if (range.comparePoint(bracketPos) == 1)
|
|
range.end = bracketPos;
|
|
else
|
|
range.start = bracketPos;
|
|
|
|
range.start.column++;
|
|
} else {
|
|
range = this.getCommentFoldRange(cursor.row, cursor.column) || range;
|
|
}
|
|
} else {
|
|
var folds = this.getFoldsInRange(range);
|
|
if (tryToUnfold && folds.length) {
|
|
this.expandFolds(folds);
|
|
return;
|
|
} else if (folds.length == 1 ) {
|
|
fold = folds[0];
|
|
}
|
|
}
|
|
|
|
if (!fold)
|
|
fold = this.getFoldAt(range.start.row, range.start.column);
|
|
|
|
if (fold && fold.range.toString() == range.toString()) {
|
|
this.expandFold(fold);
|
|
return;
|
|
}
|
|
|
|
var placeholder = "...";
|
|
if (!range.isMultiLine()) {
|
|
placeholder = this.getTextRange(range);
|
|
if (placeholder.length < 4)
|
|
return;
|
|
placeholder = placeholder.trim().substring(0, 2) + "..";
|
|
}
|
|
|
|
this.addFold(placeholder, range);
|
|
};
|
|
|
|
this.getCommentFoldRange = function(row, column, dir) {
|
|
var iterator = new TokenIterator(this, row, column);
|
|
var token = iterator.getCurrentToken();
|
|
var type = token && token.type;
|
|
if (token && /^comment|string/.test(type)) {
|
|
type = type.match(/comment|string/)[0];
|
|
if (type == "comment")
|
|
type += "|doc-start";
|
|
var re = new RegExp(type);
|
|
var range = new Range();
|
|
if (dir != 1) {
|
|
do {
|
|
token = iterator.stepBackward();
|
|
} while (token && re.test(token.type));
|
|
iterator.stepForward();
|
|
}
|
|
|
|
range.start.row = iterator.getCurrentTokenRow();
|
|
range.start.column = iterator.getCurrentTokenColumn() + 2;
|
|
|
|
iterator = new TokenIterator(this, row, column);
|
|
|
|
if (dir != -1) {
|
|
var lastRow = -1;
|
|
do {
|
|
token = iterator.stepForward();
|
|
if (lastRow == -1) {
|
|
var state = this.getState(iterator.$row);
|
|
if (!re.test(state))
|
|
lastRow = iterator.$row;
|
|
} else if (iterator.$row > lastRow) {
|
|
break;
|
|
}
|
|
} while (token && re.test(token.type));
|
|
token = iterator.stepBackward();
|
|
} else
|
|
token = iterator.getCurrentToken();
|
|
|
|
range.end.row = iterator.getCurrentTokenRow();
|
|
range.end.column = iterator.getCurrentTokenColumn() + token.value.length - 2;
|
|
return range;
|
|
}
|
|
};
|
|
|
|
this.foldAll = function(startRow, endRow, depth, test) {
|
|
if (depth == undefined)
|
|
depth = 100000; // JSON.stringify doesn't hanle Infinity
|
|
var foldWidgets = this.foldWidgets;
|
|
if (!foldWidgets)
|
|
return; // mode doesn't support folding
|
|
endRow = endRow || this.getLength();
|
|
startRow = startRow || 0;
|
|
for (var row = startRow; row < endRow; row++) {
|
|
if (foldWidgets[row] == null)
|
|
foldWidgets[row] = this.getFoldWidget(row);
|
|
if (foldWidgets[row] != "start")
|
|
continue;
|
|
|
|
if (test && !test(row)) continue;
|
|
|
|
var range = this.getFoldWidgetRange(row);
|
|
if (range && range.isMultiLine()
|
|
&& range.end.row <= endRow
|
|
&& range.start.row >= startRow
|
|
) {
|
|
row = range.end.row;
|
|
range.collapseChildren = depth;
|
|
this.addFold("...", range);
|
|
}
|
|
}
|
|
};
|
|
|
|
this.foldToLevel = function(level) {
|
|
this.foldAll();
|
|
while (level-- > 0)
|
|
this.unfold(null, false);
|
|
};
|
|
|
|
this.foldAllComments = function() {
|
|
var session = this;
|
|
this.foldAll(null, null, null, function(row) {
|
|
var tokens = session.getTokens(row);
|
|
for (var i = 0; i < tokens.length; i++) {
|
|
var token = tokens[i];
|
|
if (token.type == "text" && /^\s+$/.test(token.value))
|
|
continue;
|
|
if (/comment/.test(token.type))
|
|
return true;
|
|
return false;
|
|
}
|
|
});
|
|
};
|
|
this.$foldStyles = {
|
|
"manual": 1,
|
|
"markbegin": 1,
|
|
"markbeginend": 1
|
|
};
|
|
this.$foldStyle = "markbegin";
|
|
this.setFoldStyle = function(style) {
|
|
if (!this.$foldStyles[style])
|
|
throw new Error("invalid fold style: " + style + "[" + Object.keys(this.$foldStyles).join(", ") + "]");
|
|
|
|
if (this.$foldStyle == style)
|
|
return;
|
|
|
|
this.$foldStyle = style;
|
|
|
|
if (style == "manual")
|
|
this.unfold();
|
|
var mode = this.$foldMode;
|
|
this.$setFolding(null);
|
|
this.$setFolding(mode);
|
|
};
|
|
|
|
this.$setFolding = function(foldMode) {
|
|
if (this.$foldMode == foldMode)
|
|
return;
|
|
|
|
this.$foldMode = foldMode;
|
|
|
|
this.off('change', this.$updateFoldWidgets);
|
|
this.off('tokenizerUpdate', this.$tokenizerUpdateFoldWidgets);
|
|
this._signal("changeAnnotation");
|
|
|
|
if (!foldMode || this.$foldStyle == "manual") {
|
|
this.foldWidgets = null;
|
|
return;
|
|
}
|
|
|
|
this.foldWidgets = [];
|
|
this.getFoldWidget = foldMode.getFoldWidget.bind(foldMode, this, this.$foldStyle);
|
|
this.getFoldWidgetRange = foldMode.getFoldWidgetRange.bind(foldMode, this, this.$foldStyle);
|
|
|
|
this.$updateFoldWidgets = this.updateFoldWidgets.bind(this);
|
|
this.$tokenizerUpdateFoldWidgets = this.tokenizerUpdateFoldWidgets.bind(this);
|
|
this.on('change', this.$updateFoldWidgets);
|
|
this.on('tokenizerUpdate', this.$tokenizerUpdateFoldWidgets);
|
|
};
|
|
|
|
this.getParentFoldRangeData = function (row, ignoreCurrent) {
|
|
var fw = this.foldWidgets;
|
|
if (!fw || (ignoreCurrent && fw[row]))
|
|
return {};
|
|
|
|
var i = row - 1, firstRange;
|
|
while (i >= 0) {
|
|
var c = fw[i];
|
|
if (c == null)
|
|
c = fw[i] = this.getFoldWidget(i);
|
|
|
|
if (c == "start") {
|
|
var range = this.getFoldWidgetRange(i);
|
|
if (!firstRange)
|
|
firstRange = range;
|
|
if (range && range.end.row >= row)
|
|
break;
|
|
}
|
|
i--;
|
|
}
|
|
|
|
return {
|
|
range: i !== -1 && range,
|
|
firstRange: firstRange
|
|
};
|
|
};
|
|
|
|
this.onFoldWidgetClick = function(row, e) {
|
|
e = e.domEvent;
|
|
var options = {
|
|
children: e.shiftKey,
|
|
all: e.ctrlKey || e.metaKey,
|
|
siblings: e.altKey
|
|
};
|
|
|
|
var range = this.$toggleFoldWidget(row, options);
|
|
if (!range) {
|
|
var el = (e.target || e.srcElement);
|
|
if (el && /ace_fold-widget/.test(el.className))
|
|
el.className += " ace_invalid";
|
|
}
|
|
};
|
|
|
|
this.$toggleFoldWidget = function(row, options) {
|
|
if (!this.getFoldWidget)
|
|
return;
|
|
var type = this.getFoldWidget(row);
|
|
var line = this.getLine(row);
|
|
|
|
var dir = type === "end" ? -1 : 1;
|
|
var fold = this.getFoldAt(row, dir === -1 ? 0 : line.length, dir);
|
|
|
|
if (fold) {
|
|
if (options.children || options.all)
|
|
this.removeFold(fold);
|
|
else
|
|
this.expandFold(fold);
|
|
return fold;
|
|
}
|
|
|
|
var range = this.getFoldWidgetRange(row, true);
|
|
if (range && !range.isMultiLine()) {
|
|
fold = this.getFoldAt(range.start.row, range.start.column, 1);
|
|
if (fold && range.isEqual(fold.range)) {
|
|
this.removeFold(fold);
|
|
return fold;
|
|
}
|
|
}
|
|
|
|
if (options.siblings) {
|
|
var data = this.getParentFoldRangeData(row);
|
|
if (data.range) {
|
|
var startRow = data.range.start.row + 1;
|
|
var endRow = data.range.end.row;
|
|
}
|
|
this.foldAll(startRow, endRow, options.all ? 10000 : 0);
|
|
} else if (options.children) {
|
|
endRow = range ? range.end.row : this.getLength();
|
|
this.foldAll(row + 1, endRow, options.all ? 10000 : 0);
|
|
} else if (range) {
|
|
if (options.all)
|
|
range.collapseChildren = 10000;
|
|
this.addFold("...", range);
|
|
}
|
|
|
|
return range;
|
|
};
|
|
|
|
|
|
|
|
this.toggleFoldWidget = function(toggleParent) {
|
|
var row = this.selection.getCursor().row;
|
|
row = this.getRowFoldStart(row);
|
|
var range = this.$toggleFoldWidget(row, {});
|
|
|
|
if (range)
|
|
return;
|
|
var data = this.getParentFoldRangeData(row, true);
|
|
range = data.range || data.firstRange;
|
|
|
|
if (range) {
|
|
row = range.start.row;
|
|
var fold = this.getFoldAt(row, this.getLine(row).length, 1);
|
|
|
|
if (fold) {
|
|
this.removeFold(fold);
|
|
} else {
|
|
this.addFold("...", range);
|
|
}
|
|
}
|
|
};
|
|
|
|
this.updateFoldWidgets = function(delta) {
|
|
var firstRow = delta.start.row;
|
|
var len = delta.end.row - firstRow;
|
|
|
|
if (len === 0) {
|
|
this.foldWidgets[firstRow] = null;
|
|
} else if (delta.action == 'remove') {
|
|
this.foldWidgets.splice(firstRow, len + 1, null);
|
|
} else {
|
|
var args = Array(len + 1);
|
|
args.unshift(firstRow, 1);
|
|
this.foldWidgets.splice.apply(this.foldWidgets, args);
|
|
}
|
|
};
|
|
this.tokenizerUpdateFoldWidgets = function(e) {
|
|
var rows = e.data;
|
|
if (rows.first != rows.last) {
|
|
if (this.foldWidgets.length > rows.first)
|
|
this.foldWidgets.splice(rows.first, this.foldWidgets.length);
|
|
}
|
|
};
|
|
}
|
|
|
|
exports.Folding = Folding;
|
|
|
|
});
|
|
|
|
ace.define("ace/edit_session/bracket_match",["require","exports","module","ace/token_iterator","ace/range"], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var TokenIterator = require("../token_iterator").TokenIterator;
|
|
var Range = require("../range").Range;
|
|
|
|
|
|
function BracketMatch() {
|
|
|
|
this.findMatchingBracket = function(position, chr) {
|
|
if (position.column == 0) return null;
|
|
|
|
var charBeforeCursor = chr || this.getLine(position.row).charAt(position.column-1);
|
|
if (charBeforeCursor == "") return null;
|
|
|
|
var match = charBeforeCursor.match(/([\(\[\{])|([\)\]\}])/);
|
|
if (!match)
|
|
return null;
|
|
|
|
if (match[1])
|
|
return this.$findClosingBracket(match[1], position);
|
|
else
|
|
return this.$findOpeningBracket(match[2], position);
|
|
};
|
|
|
|
this.getBracketRange = function(pos) {
|
|
var line = this.getLine(pos.row);
|
|
var before = true, range;
|
|
|
|
var chr = line.charAt(pos.column - 1);
|
|
var match = chr && chr.match(/([\(\[\{])|([\)\]\}])/);
|
|
if (!match) {
|
|
chr = line.charAt(pos.column);
|
|
pos = {row: pos.row, column: pos.column + 1};
|
|
match = chr && chr.match(/([\(\[\{])|([\)\]\}])/);
|
|
before = false;
|
|
}
|
|
if (!match)
|
|
return null;
|
|
|
|
if (match[1]) {
|
|
var bracketPos = this.$findClosingBracket(match[1], pos);
|
|
if (!bracketPos)
|
|
return null;
|
|
range = Range.fromPoints(pos, bracketPos);
|
|
if (!before) {
|
|
range.end.column++;
|
|
range.start.column--;
|
|
}
|
|
range.cursor = range.end;
|
|
} else {
|
|
var bracketPos = this.$findOpeningBracket(match[2], pos);
|
|
if (!bracketPos)
|
|
return null;
|
|
range = Range.fromPoints(bracketPos, pos);
|
|
if (!before) {
|
|
range.start.column++;
|
|
range.end.column--;
|
|
}
|
|
range.cursor = range.start;
|
|
}
|
|
|
|
return range;
|
|
};
|
|
this.getMatchingBracketRanges = function(pos) {
|
|
var line = this.getLine(pos.row);
|
|
|
|
var chr = line.charAt(pos.column - 1);
|
|
var match = chr && chr.match(/([\(\[\{])|([\)\]\}])/);
|
|
if (!match) {
|
|
chr = line.charAt(pos.column);
|
|
pos = {row: pos.row, column: pos.column + 1};
|
|
match = chr && chr.match(/([\(\[\{])|([\)\]\}])/);
|
|
}
|
|
|
|
if (!match)
|
|
return null;
|
|
|
|
var startRange = new Range(pos.row, pos.column - 1, pos.row, pos.column);
|
|
var bracketPos = match[1] ? this.$findClosingBracket(match[1], pos)
|
|
: this.$findOpeningBracket(match[2], pos);
|
|
if (!bracketPos)
|
|
return [startRange];
|
|
var endRange = new Range(bracketPos.row, bracketPos.column, bracketPos.row, bracketPos.column + 1);
|
|
|
|
return [startRange, endRange];
|
|
};
|
|
|
|
this.$brackets = {
|
|
")": "(",
|
|
"(": ")",
|
|
"]": "[",
|
|
"[": "]",
|
|
"{": "}",
|
|
"}": "{",
|
|
"<": ">",
|
|
">": "<"
|
|
};
|
|
|
|
this.$findOpeningBracket = function(bracket, position, typeRe) {
|
|
var openBracket = this.$brackets[bracket];
|
|
var depth = 1;
|
|
|
|
var iterator = new TokenIterator(this, position.row, position.column);
|
|
var token = iterator.getCurrentToken();
|
|
if (!token)
|
|
token = iterator.stepForward();
|
|
if (!token)
|
|
return;
|
|
|
|
if (!typeRe){
|
|
typeRe = new RegExp(
|
|
"(\\.?" +
|
|
token.type.replace(".", "\\.").replace("rparen", ".paren")
|
|
.replace(/\b(?:end)\b/, "(?:start|begin|end)")
|
|
+ ")+"
|
|
);
|
|
}
|
|
var valueIndex = position.column - iterator.getCurrentTokenColumn() - 2;
|
|
var value = token.value;
|
|
|
|
while (true) {
|
|
|
|
while (valueIndex >= 0) {
|
|
var chr = value.charAt(valueIndex);
|
|
if (chr == openBracket) {
|
|
depth -= 1;
|
|
if (depth == 0) {
|
|
return {row: iterator.getCurrentTokenRow(),
|
|
column: valueIndex + iterator.getCurrentTokenColumn()};
|
|
}
|
|
}
|
|
else if (chr == bracket) {
|
|
depth += 1;
|
|
}
|
|
valueIndex -= 1;
|
|
}
|
|
do {
|
|
token = iterator.stepBackward();
|
|
} while (token && !typeRe.test(token.type));
|
|
|
|
if (token == null)
|
|
break;
|
|
|
|
value = token.value;
|
|
valueIndex = value.length - 1;
|
|
}
|
|
|
|
return null;
|
|
};
|
|
|
|
this.$findClosingBracket = function(bracket, position, typeRe) {
|
|
var closingBracket = this.$brackets[bracket];
|
|
var depth = 1;
|
|
|
|
var iterator = new TokenIterator(this, position.row, position.column);
|
|
var token = iterator.getCurrentToken();
|
|
if (!token)
|
|
token = iterator.stepForward();
|
|
if (!token)
|
|
return;
|
|
|
|
if (!typeRe){
|
|
typeRe = new RegExp(
|
|
"(\\.?" +
|
|
token.type.replace(".", "\\.").replace("lparen", ".paren")
|
|
.replace(/\b(?:start|begin)\b/, "(?:start|begin|end)")
|
|
+ ")+"
|
|
);
|
|
}
|
|
var valueIndex = position.column - iterator.getCurrentTokenColumn();
|
|
|
|
while (true) {
|
|
|
|
var value = token.value;
|
|
var valueLength = value.length;
|
|
while (valueIndex < valueLength) {
|
|
var chr = value.charAt(valueIndex);
|
|
if (chr == closingBracket) {
|
|
depth -= 1;
|
|
if (depth == 0) {
|
|
return {row: iterator.getCurrentTokenRow(),
|
|
column: valueIndex + iterator.getCurrentTokenColumn()};
|
|
}
|
|
}
|
|
else if (chr == bracket) {
|
|
depth += 1;
|
|
}
|
|
valueIndex += 1;
|
|
}
|
|
do {
|
|
token = iterator.stepForward();
|
|
} while (token && !typeRe.test(token.type));
|
|
|
|
if (token == null)
|
|
break;
|
|
|
|
valueIndex = 0;
|
|
}
|
|
|
|
return null;
|
|
};
|
|
}
|
|
exports.BracketMatch = BracketMatch;
|
|
|
|
});
|
|
|
|
ace.define("ace/edit_session",["require","exports","module","ace/lib/oop","ace/lib/lang","ace/bidihandler","ace/config","ace/lib/event_emitter","ace/selection","ace/mode/text","ace/range","ace/document","ace/background_tokenizer","ace/search_highlight","ace/edit_session/folding","ace/edit_session/bracket_match"], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var oop = require("./lib/oop");
|
|
var lang = require("./lib/lang");
|
|
var BidiHandler = require("./bidihandler").BidiHandler;
|
|
var config = require("./config");
|
|
var EventEmitter = require("./lib/event_emitter").EventEmitter;
|
|
var Selection = require("./selection").Selection;
|
|
var TextMode = require("./mode/text").Mode;
|
|
var Range = require("./range").Range;
|
|
var Document = require("./document").Document;
|
|
var BackgroundTokenizer = require("./background_tokenizer").BackgroundTokenizer;
|
|
var SearchHighlight = require("./search_highlight").SearchHighlight;
|
|
|
|
var EditSession = function(text, mode) {
|
|
this.$breakpoints = [];
|
|
this.$decorations = [];
|
|
this.$frontMarkers = {};
|
|
this.$backMarkers = {};
|
|
this.$markerId = 1;
|
|
this.$undoSelect = true;
|
|
|
|
this.$foldData = [];
|
|
this.id = "session" + (++EditSession.$uid);
|
|
this.$foldData.toString = function() {
|
|
return this.join("\n");
|
|
};
|
|
this.on("changeFold", this.onChangeFold.bind(this));
|
|
this.$onChange = this.onChange.bind(this);
|
|
|
|
if (typeof text != "object" || !text.getLine)
|
|
text = new Document(text);
|
|
|
|
this.setDocument(text);
|
|
this.selection = new Selection(this);
|
|
this.$bidiHandler = new BidiHandler(this);
|
|
|
|
config.resetOptions(this);
|
|
this.setMode(mode);
|
|
config._signal("session", this);
|
|
};
|
|
|
|
|
|
EditSession.$uid = 0;
|
|
|
|
(function() {
|
|
|
|
oop.implement(this, EventEmitter);
|
|
this.setDocument = function(doc) {
|
|
if (this.doc)
|
|
this.doc.removeListener("change", this.$onChange);
|
|
|
|
this.doc = doc;
|
|
doc.on("change", this.$onChange);
|
|
|
|
if (this.bgTokenizer)
|
|
this.bgTokenizer.setDocument(this.getDocument());
|
|
|
|
this.resetCaches();
|
|
};
|
|
this.getDocument = function() {
|
|
return this.doc;
|
|
};
|
|
this.$resetRowCache = function(docRow) {
|
|
if (!docRow) {
|
|
this.$docRowCache = [];
|
|
this.$screenRowCache = [];
|
|
return;
|
|
}
|
|
var l = this.$docRowCache.length;
|
|
var i = this.$getRowCacheIndex(this.$docRowCache, docRow) + 1;
|
|
if (l > i) {
|
|
this.$docRowCache.splice(i, l);
|
|
this.$screenRowCache.splice(i, l);
|
|
}
|
|
};
|
|
|
|
this.$getRowCacheIndex = function(cacheArray, val) {
|
|
var low = 0;
|
|
var hi = cacheArray.length - 1;
|
|
|
|
while (low <= hi) {
|
|
var mid = (low + hi) >> 1;
|
|
var c = cacheArray[mid];
|
|
|
|
if (val > c)
|
|
low = mid + 1;
|
|
else if (val < c)
|
|
hi = mid - 1;
|
|
else
|
|
return mid;
|
|
}
|
|
|
|
return low -1;
|
|
};
|
|
|
|
this.resetCaches = function() {
|
|
this.$modified = true;
|
|
this.$wrapData = [];
|
|
this.$rowLengthCache = [];
|
|
this.$resetRowCache(0);
|
|
if (this.bgTokenizer)
|
|
this.bgTokenizer.start(0);
|
|
};
|
|
|
|
this.onChangeFold = function(e) {
|
|
var fold = e.data;
|
|
this.$resetRowCache(fold.start.row);
|
|
};
|
|
|
|
this.onChange = function(delta) {
|
|
this.$modified = true;
|
|
this.$bidiHandler.onChange(delta);
|
|
this.$resetRowCache(delta.start.row);
|
|
|
|
var removedFolds = this.$updateInternalDataOnChange(delta);
|
|
if (!this.$fromUndo && this.$undoManager) {
|
|
if (removedFolds && removedFolds.length) {
|
|
this.$undoManager.add({
|
|
action: "removeFolds",
|
|
folds: removedFolds
|
|
}, this.mergeUndoDeltas);
|
|
this.mergeUndoDeltas = true;
|
|
}
|
|
this.$undoManager.add(delta, this.mergeUndoDeltas);
|
|
this.mergeUndoDeltas = true;
|
|
|
|
this.$informUndoManager.schedule();
|
|
}
|
|
|
|
this.bgTokenizer && this.bgTokenizer.$updateOnChange(delta);
|
|
this._signal("change", delta);
|
|
};
|
|
this.setValue = function(text) {
|
|
this.doc.setValue(text);
|
|
this.selection.moveTo(0, 0);
|
|
|
|
this.$resetRowCache(0);
|
|
this.setUndoManager(this.$undoManager);
|
|
this.getUndoManager().reset();
|
|
};
|
|
this.getValue =
|
|
this.toString = function() {
|
|
return this.doc.getValue();
|
|
};
|
|
this.getSelection = function() {
|
|
return this.selection;
|
|
};
|
|
this.getState = function(row) {
|
|
return this.bgTokenizer.getState(row);
|
|
};
|
|
this.getTokens = function(row) {
|
|
return this.bgTokenizer.getTokens(row);
|
|
};
|
|
this.getTokenAt = function(row, column) {
|
|
var tokens = this.bgTokenizer.getTokens(row);
|
|
var token, c = 0;
|
|
if (column == null) {
|
|
var i = tokens.length - 1;
|
|
c = this.getLine(row).length;
|
|
} else {
|
|
for (var i = 0; i < tokens.length; i++) {
|
|
c += tokens[i].value.length;
|
|
if (c >= column)
|
|
break;
|
|
}
|
|
}
|
|
token = tokens[i];
|
|
if (!token)
|
|
return null;
|
|
token.index = i;
|
|
token.start = c - token.value.length;
|
|
return token;
|
|
};
|
|
this.setUndoManager = function(undoManager) {
|
|
this.$undoManager = undoManager;
|
|
|
|
if (this.$informUndoManager)
|
|
this.$informUndoManager.cancel();
|
|
|
|
if (undoManager) {
|
|
var self = this;
|
|
undoManager.addSession(this);
|
|
this.$syncInformUndoManager = function() {
|
|
self.$informUndoManager.cancel();
|
|
self.mergeUndoDeltas = false;
|
|
};
|
|
this.$informUndoManager = lang.delayedCall(this.$syncInformUndoManager);
|
|
} else {
|
|
this.$syncInformUndoManager = function() {};
|
|
}
|
|
};
|
|
this.markUndoGroup = function() {
|
|
if (this.$syncInformUndoManager)
|
|
this.$syncInformUndoManager();
|
|
};
|
|
|
|
this.$defaultUndoManager = {
|
|
undo: function() {},
|
|
redo: function() {},
|
|
hasUndo: function() {},
|
|
hasRedo: function() {},
|
|
reset: function() {},
|
|
add: function() {},
|
|
addSelection: function() {},
|
|
startNewGroup: function() {},
|
|
addSession: function() {}
|
|
};
|
|
this.getUndoManager = function() {
|
|
return this.$undoManager || this.$defaultUndoManager;
|
|
};
|
|
this.getTabString = function() {
|
|
if (this.getUseSoftTabs()) {
|
|
return lang.stringRepeat(" ", this.getTabSize());
|
|
} else {
|
|
return "\t";
|
|
}
|
|
};
|
|
this.setUseSoftTabs = function(val) {
|
|
this.setOption("useSoftTabs", val);
|
|
};
|
|
this.getUseSoftTabs = function() {
|
|
return this.$useSoftTabs && !this.$mode.$indentWithTabs;
|
|
};
|
|
this.setTabSize = function(tabSize) {
|
|
this.setOption("tabSize", tabSize);
|
|
};
|
|
this.getTabSize = function() {
|
|
return this.$tabSize;
|
|
};
|
|
this.isTabStop = function(position) {
|
|
return this.$useSoftTabs && (position.column % this.$tabSize === 0);
|
|
};
|
|
this.setNavigateWithinSoftTabs = function (navigateWithinSoftTabs) {
|
|
this.setOption("navigateWithinSoftTabs", navigateWithinSoftTabs);
|
|
};
|
|
this.getNavigateWithinSoftTabs = function() {
|
|
return this.$navigateWithinSoftTabs;
|
|
};
|
|
|
|
this.$overwrite = false;
|
|
this.setOverwrite = function(overwrite) {
|
|
this.setOption("overwrite", overwrite);
|
|
};
|
|
this.getOverwrite = function() {
|
|
return this.$overwrite;
|
|
};
|
|
this.toggleOverwrite = function() {
|
|
this.setOverwrite(!this.$overwrite);
|
|
};
|
|
this.addGutterDecoration = function(row, className) {
|
|
if (!this.$decorations[row])
|
|
this.$decorations[row] = "";
|
|
this.$decorations[row] += " " + className;
|
|
this._signal("changeBreakpoint", {});
|
|
};
|
|
this.removeGutterDecoration = function(row, className) {
|
|
this.$decorations[row] = (this.$decorations[row] || "").replace(" " + className, "");
|
|
this._signal("changeBreakpoint", {});
|
|
};
|
|
this.getBreakpoints = function() {
|
|
return this.$breakpoints;
|
|
};
|
|
this.setBreakpoints = function(rows) {
|
|
this.$breakpoints = [];
|
|
for (var i=0; i<rows.length; i++) {
|
|
this.$breakpoints[rows[i]] = "ace_breakpoint";
|
|
}
|
|
this._signal("changeBreakpoint", {});
|
|
};
|
|
this.clearBreakpoints = function() {
|
|
this.$breakpoints = [];
|
|
this._signal("changeBreakpoint", {});
|
|
};
|
|
this.setBreakpoint = function(row, className) {
|
|
if (className === undefined)
|
|
className = "ace_breakpoint";
|
|
if (className)
|
|
this.$breakpoints[row] = className;
|
|
else
|
|
delete this.$breakpoints[row];
|
|
this._signal("changeBreakpoint", {});
|
|
};
|
|
this.clearBreakpoint = function(row) {
|
|
delete this.$breakpoints[row];
|
|
this._signal("changeBreakpoint", {});
|
|
};
|
|
this.addMarker = function(range, clazz, type, inFront) {
|
|
var id = this.$markerId++;
|
|
|
|
var marker = {
|
|
range : range,
|
|
type : type || "line",
|
|
renderer: typeof type == "function" ? type : null,
|
|
clazz : clazz,
|
|
inFront: !!inFront,
|
|
id: id
|
|
};
|
|
|
|
if (inFront) {
|
|
this.$frontMarkers[id] = marker;
|
|
this._signal("changeFrontMarker");
|
|
} else {
|
|
this.$backMarkers[id] = marker;
|
|
this._signal("changeBackMarker");
|
|
}
|
|
|
|
return id;
|
|
};
|
|
this.addDynamicMarker = function(marker, inFront) {
|
|
if (!marker.update)
|
|
return;
|
|
var id = this.$markerId++;
|
|
marker.id = id;
|
|
marker.inFront = !!inFront;
|
|
|
|
if (inFront) {
|
|
this.$frontMarkers[id] = marker;
|
|
this._signal("changeFrontMarker");
|
|
} else {
|
|
this.$backMarkers[id] = marker;
|
|
this._signal("changeBackMarker");
|
|
}
|
|
|
|
return marker;
|
|
};
|
|
this.removeMarker = function(markerId) {
|
|
var marker = this.$frontMarkers[markerId] || this.$backMarkers[markerId];
|
|
if (!marker)
|
|
return;
|
|
|
|
var markers = marker.inFront ? this.$frontMarkers : this.$backMarkers;
|
|
delete (markers[markerId]);
|
|
this._signal(marker.inFront ? "changeFrontMarker" : "changeBackMarker");
|
|
};
|
|
this.getMarkers = function(inFront) {
|
|
return inFront ? this.$frontMarkers : this.$backMarkers;
|
|
};
|
|
|
|
this.highlight = function(re) {
|
|
if (!this.$searchHighlight) {
|
|
var highlight = new SearchHighlight(null, "ace_selected-word", "text");
|
|
this.$searchHighlight = this.addDynamicMarker(highlight);
|
|
}
|
|
this.$searchHighlight.setRegexp(re);
|
|
};
|
|
this.highlightLines = function(startRow, endRow, clazz, inFront) {
|
|
if (typeof endRow != "number") {
|
|
clazz = endRow;
|
|
endRow = startRow;
|
|
}
|
|
if (!clazz)
|
|
clazz = "ace_step";
|
|
|
|
var range = new Range(startRow, 0, endRow, Infinity);
|
|
range.id = this.addMarker(range, clazz, "fullLine", inFront);
|
|
return range;
|
|
};
|
|
this.setAnnotations = function(annotations) {
|
|
this.$annotations = annotations;
|
|
this._signal("changeAnnotation", {});
|
|
};
|
|
this.getAnnotations = function() {
|
|
return this.$annotations || [];
|
|
};
|
|
this.clearAnnotations = function() {
|
|
this.setAnnotations([]);
|
|
};
|
|
this.$detectNewLine = function(text) {
|
|
var match = text.match(/^.*?(\r?\n)/m);
|
|
if (match) {
|
|
this.$autoNewLine = match[1];
|
|
} else {
|
|
this.$autoNewLine = "\n";
|
|
}
|
|
};
|
|
this.getWordRange = function(row, column) {
|
|
var line = this.getLine(row);
|
|
|
|
var inToken = false;
|
|
if (column > 0)
|
|
inToken = !!line.charAt(column - 1).match(this.tokenRe);
|
|
|
|
if (!inToken)
|
|
inToken = !!line.charAt(column).match(this.tokenRe);
|
|
|
|
if (inToken)
|
|
var re = this.tokenRe;
|
|
else if (/^\s+$/.test(line.slice(column-1, column+1)))
|
|
var re = /\s/;
|
|
else
|
|
var re = this.nonTokenRe;
|
|
|
|
var start = column;
|
|
if (start > 0) {
|
|
do {
|
|
start--;
|
|
}
|
|
while (start >= 0 && line.charAt(start).match(re));
|
|
start++;
|
|
}
|
|
|
|
var end = column;
|
|
while (end < line.length && line.charAt(end).match(re)) {
|
|
end++;
|
|
}
|
|
|
|
return new Range(row, start, row, end);
|
|
};
|
|
this.getAWordRange = function(row, column) {
|
|
var wordRange = this.getWordRange(row, column);
|
|
var line = this.getLine(wordRange.end.row);
|
|
|
|
while (line.charAt(wordRange.end.column).match(/[ \t]/)) {
|
|
wordRange.end.column += 1;
|
|
}
|
|
return wordRange;
|
|
};
|
|
this.setNewLineMode = function(newLineMode) {
|
|
this.doc.setNewLineMode(newLineMode);
|
|
};
|
|
this.getNewLineMode = function() {
|
|
return this.doc.getNewLineMode();
|
|
};
|
|
this.setUseWorker = function(useWorker) { this.setOption("useWorker", useWorker); };
|
|
this.getUseWorker = function() { return this.$useWorker; };
|
|
this.onReloadTokenizer = function(e) {
|
|
var rows = e.data;
|
|
this.bgTokenizer.start(rows.first);
|
|
this._signal("tokenizerUpdate", e);
|
|
};
|
|
|
|
this.$modes = config.$modes;
|
|
this.$mode = null;
|
|
this.$modeId = null;
|
|
this.setMode = function(mode, cb) {
|
|
if (mode && typeof mode === "object") {
|
|
if (mode.getTokenizer)
|
|
return this.$onChangeMode(mode);
|
|
var options = mode;
|
|
var path = options.path;
|
|
} else {
|
|
path = mode || "ace/mode/text";
|
|
}
|
|
if (!this.$modes["ace/mode/text"])
|
|
this.$modes["ace/mode/text"] = new TextMode();
|
|
|
|
if (this.$modes[path] && !options) {
|
|
this.$onChangeMode(this.$modes[path]);
|
|
cb && cb();
|
|
return;
|
|
}
|
|
this.$modeId = path;
|
|
config.loadModule(["mode", path], function(m) {
|
|
if (this.$modeId !== path)
|
|
return cb && cb();
|
|
if (this.$modes[path] && !options) {
|
|
this.$onChangeMode(this.$modes[path]);
|
|
} else if (m && m.Mode) {
|
|
m = new m.Mode(options);
|
|
if (!options) {
|
|
this.$modes[path] = m;
|
|
m.$id = path;
|
|
}
|
|
this.$onChangeMode(m);
|
|
}
|
|
cb && cb();
|
|
}.bind(this));
|
|
if (!this.$mode)
|
|
this.$onChangeMode(this.$modes["ace/mode/text"], true);
|
|
};
|
|
|
|
this.$onChangeMode = function(mode, $isPlaceholder) {
|
|
if (!$isPlaceholder)
|
|
this.$modeId = mode.$id;
|
|
if (this.$mode === mode)
|
|
return;
|
|
|
|
var oldMode = this.$mode;
|
|
this.$mode = mode;
|
|
|
|
this.$stopWorker();
|
|
|
|
if (this.$useWorker)
|
|
this.$startWorker();
|
|
|
|
var tokenizer = mode.getTokenizer();
|
|
|
|
if(tokenizer.on !== undefined) {
|
|
var onReloadTokenizer = this.onReloadTokenizer.bind(this);
|
|
tokenizer.on("update", onReloadTokenizer);
|
|
}
|
|
|
|
if (!this.bgTokenizer) {
|
|
this.bgTokenizer = new BackgroundTokenizer(tokenizer);
|
|
var _self = this;
|
|
this.bgTokenizer.on("update", function(e) {
|
|
_self._signal("tokenizerUpdate", e);
|
|
});
|
|
} else {
|
|
this.bgTokenizer.setTokenizer(tokenizer);
|
|
}
|
|
|
|
this.bgTokenizer.setDocument(this.getDocument());
|
|
|
|
this.tokenRe = mode.tokenRe;
|
|
this.nonTokenRe = mode.nonTokenRe;
|
|
|
|
|
|
if (!$isPlaceholder) {
|
|
if (mode.attachToSession)
|
|
mode.attachToSession(this);
|
|
this.$options.wrapMethod.set.call(this, this.$wrapMethod);
|
|
this.$setFolding(mode.foldingRules);
|
|
this.bgTokenizer.start(0);
|
|
this._emit("changeMode", {oldMode: oldMode, mode: mode});
|
|
}
|
|
};
|
|
|
|
this.$stopWorker = function() {
|
|
if (this.$worker) {
|
|
this.$worker.terminate();
|
|
this.$worker = null;
|
|
}
|
|
};
|
|
|
|
this.$startWorker = function() {
|
|
try {
|
|
this.$worker = this.$mode.createWorker(this);
|
|
} catch (e) {
|
|
config.warn("Could not load worker", e);
|
|
this.$worker = null;
|
|
}
|
|
};
|
|
this.getMode = function() {
|
|
return this.$mode;
|
|
};
|
|
|
|
this.$scrollTop = 0;
|
|
this.setScrollTop = function(scrollTop) {
|
|
if (this.$scrollTop === scrollTop || isNaN(scrollTop))
|
|
return;
|
|
|
|
this.$scrollTop = scrollTop;
|
|
this._signal("changeScrollTop", scrollTop);
|
|
};
|
|
this.getScrollTop = function() {
|
|
return this.$scrollTop;
|
|
};
|
|
|
|
this.$scrollLeft = 0;
|
|
this.setScrollLeft = function(scrollLeft) {
|
|
if (this.$scrollLeft === scrollLeft || isNaN(scrollLeft))
|
|
return;
|
|
|
|
this.$scrollLeft = scrollLeft;
|
|
this._signal("changeScrollLeft", scrollLeft);
|
|
};
|
|
this.getScrollLeft = function() {
|
|
return this.$scrollLeft;
|
|
};
|
|
this.getScreenWidth = function() {
|
|
this.$computeWidth();
|
|
if (this.lineWidgets)
|
|
return Math.max(this.getLineWidgetMaxWidth(), this.screenWidth);
|
|
return this.screenWidth;
|
|
};
|
|
|
|
this.getLineWidgetMaxWidth = function() {
|
|
if (this.lineWidgetsWidth != null) return this.lineWidgetsWidth;
|
|
var width = 0;
|
|
this.lineWidgets.forEach(function(w) {
|
|
if (w && w.screenWidth > width)
|
|
width = w.screenWidth;
|
|
});
|
|
return this.lineWidgetWidth = width;
|
|
};
|
|
|
|
this.$computeWidth = function(force) {
|
|
if (this.$modified || force) {
|
|
this.$modified = false;
|
|
|
|
if (this.$useWrapMode)
|
|
return this.screenWidth = this.$wrapLimit;
|
|
|
|
var lines = this.doc.getAllLines();
|
|
var cache = this.$rowLengthCache;
|
|
var longestScreenLine = 0;
|
|
var foldIndex = 0;
|
|
var foldLine = this.$foldData[foldIndex];
|
|
var foldStart = foldLine ? foldLine.start.row : Infinity;
|
|
var len = lines.length;
|
|
|
|
for (var i = 0; i < len; i++) {
|
|
if (i > foldStart) {
|
|
i = foldLine.end.row + 1;
|
|
if (i >= len)
|
|
break;
|
|
foldLine = this.$foldData[foldIndex++];
|
|
foldStart = foldLine ? foldLine.start.row : Infinity;
|
|
}
|
|
|
|
if (cache[i] == null)
|
|
cache[i] = this.$getStringScreenWidth(lines[i])[0];
|
|
|
|
if (cache[i] > longestScreenLine)
|
|
longestScreenLine = cache[i];
|
|
}
|
|
this.screenWidth = longestScreenLine;
|
|
}
|
|
};
|
|
this.getLine = function(row) {
|
|
return this.doc.getLine(row);
|
|
};
|
|
this.getLines = function(firstRow, lastRow) {
|
|
return this.doc.getLines(firstRow, lastRow);
|
|
};
|
|
this.getLength = function() {
|
|
return this.doc.getLength();
|
|
};
|
|
this.getTextRange = function(range) {
|
|
return this.doc.getTextRange(range || this.selection.getRange());
|
|
};
|
|
this.insert = function(position, text) {
|
|
return this.doc.insert(position, text);
|
|
};
|
|
this.remove = function(range) {
|
|
return this.doc.remove(range);
|
|
};
|
|
this.removeFullLines = function(firstRow, lastRow){
|
|
return this.doc.removeFullLines(firstRow, lastRow);
|
|
};
|
|
this.undoChanges = function(deltas, dontSelect) {
|
|
if (!deltas.length)
|
|
return;
|
|
|
|
this.$fromUndo = true;
|
|
for (var i = deltas.length - 1; i != -1; i--) {
|
|
var delta = deltas[i];
|
|
if (delta.action == "insert" || delta.action == "remove") {
|
|
this.doc.revertDelta(delta);
|
|
} else if (delta.folds) {
|
|
this.addFolds(delta.folds);
|
|
}
|
|
}
|
|
if (!dontSelect && this.$undoSelect) {
|
|
if (deltas.selectionBefore)
|
|
this.selection.fromJSON(deltas.selectionBefore);
|
|
else
|
|
this.selection.setRange(this.$getUndoSelection(deltas, true));
|
|
}
|
|
this.$fromUndo = false;
|
|
};
|
|
this.redoChanges = function(deltas, dontSelect) {
|
|
if (!deltas.length)
|
|
return;
|
|
|
|
this.$fromUndo = true;
|
|
for (var i = 0; i < deltas.length; i++) {
|
|
var delta = deltas[i];
|
|
if (delta.action == "insert" || delta.action == "remove") {
|
|
this.doc.$safeApplyDelta(delta);
|
|
}
|
|
}
|
|
|
|
if (!dontSelect && this.$undoSelect) {
|
|
if (deltas.selectionAfter)
|
|
this.selection.fromJSON(deltas.selectionAfter);
|
|
else
|
|
this.selection.setRange(this.$getUndoSelection(deltas, false));
|
|
}
|
|
this.$fromUndo = false;
|
|
};
|
|
this.setUndoSelect = function(enable) {
|
|
this.$undoSelect = enable;
|
|
};
|
|
|
|
this.$getUndoSelection = function(deltas, isUndo) {
|
|
function isInsert(delta) {
|
|
return isUndo ? delta.action !== "insert" : delta.action === "insert";
|
|
}
|
|
|
|
var range, point;
|
|
|
|
for (var i = 0; i < deltas.length; i++) {
|
|
var delta = deltas[i];
|
|
if (!delta.start) continue; // skip folds
|
|
if (!range) {
|
|
if (isInsert(delta)) {
|
|
range = Range.fromPoints(delta.start, delta.end);
|
|
} else {
|
|
range = Range.fromPoints(delta.start, delta.start);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (isInsert(delta)) {
|
|
point = delta.start;
|
|
if (range.compare(point.row, point.column) == -1) {
|
|
range.setStart(point);
|
|
}
|
|
point = delta.end;
|
|
if (range.compare(point.row, point.column) == 1) {
|
|
range.setEnd(point);
|
|
}
|
|
} else {
|
|
point = delta.start;
|
|
if (range.compare(point.row, point.column) == -1) {
|
|
range = Range.fromPoints(delta.start, delta.start);
|
|
}
|
|
}
|
|
}
|
|
return range;
|
|
};
|
|
this.replace = function(range, text) {
|
|
return this.doc.replace(range, text);
|
|
};
|
|
this.moveText = function(fromRange, toPosition, copy) {
|
|
var text = this.getTextRange(fromRange);
|
|
var folds = this.getFoldsInRange(fromRange);
|
|
|
|
var toRange = Range.fromPoints(toPosition, toPosition);
|
|
if (!copy) {
|
|
this.remove(fromRange);
|
|
var rowDiff = fromRange.start.row - fromRange.end.row;
|
|
var collDiff = rowDiff ? -fromRange.end.column : fromRange.start.column - fromRange.end.column;
|
|
if (collDiff) {
|
|
if (toRange.start.row == fromRange.end.row && toRange.start.column > fromRange.end.column)
|
|
toRange.start.column += collDiff;
|
|
if (toRange.end.row == fromRange.end.row && toRange.end.column > fromRange.end.column)
|
|
toRange.end.column += collDiff;
|
|
}
|
|
if (rowDiff && toRange.start.row >= fromRange.end.row) {
|
|
toRange.start.row += rowDiff;
|
|
toRange.end.row += rowDiff;
|
|
}
|
|
}
|
|
|
|
toRange.end = this.insert(toRange.start, text);
|
|
if (folds.length) {
|
|
var oldStart = fromRange.start;
|
|
var newStart = toRange.start;
|
|
var rowDiff = newStart.row - oldStart.row;
|
|
var collDiff = newStart.column - oldStart.column;
|
|
this.addFolds(folds.map(function(x) {
|
|
x = x.clone();
|
|
if (x.start.row == oldStart.row)
|
|
x.start.column += collDiff;
|
|
if (x.end.row == oldStart.row)
|
|
x.end.column += collDiff;
|
|
x.start.row += rowDiff;
|
|
x.end.row += rowDiff;
|
|
return x;
|
|
}));
|
|
}
|
|
|
|
return toRange;
|
|
};
|
|
this.indentRows = function(startRow, endRow, indentString) {
|
|
indentString = indentString.replace(/\t/g, this.getTabString());
|
|
for (var row=startRow; row<=endRow; row++)
|
|
this.doc.insertInLine({row: row, column: 0}, indentString);
|
|
};
|
|
this.outdentRows = function (range) {
|
|
var rowRange = range.collapseRows();
|
|
var deleteRange = new Range(0, 0, 0, 0);
|
|
var size = this.getTabSize();
|
|
|
|
for (var i = rowRange.start.row; i <= rowRange.end.row; ++i) {
|
|
var line = this.getLine(i);
|
|
|
|
deleteRange.start.row = i;
|
|
deleteRange.end.row = i;
|
|
for (var j = 0; j < size; ++j)
|
|
if (line.charAt(j) != ' ')
|
|
break;
|
|
if (j < size && line.charAt(j) == '\t') {
|
|
deleteRange.start.column = j;
|
|
deleteRange.end.column = j + 1;
|
|
} else {
|
|
deleteRange.start.column = 0;
|
|
deleteRange.end.column = j;
|
|
}
|
|
this.remove(deleteRange);
|
|
}
|
|
};
|
|
|
|
this.$moveLines = function(firstRow, lastRow, dir) {
|
|
firstRow = this.getRowFoldStart(firstRow);
|
|
lastRow = this.getRowFoldEnd(lastRow);
|
|
if (dir < 0) {
|
|
var row = this.getRowFoldStart(firstRow + dir);
|
|
if (row < 0) return 0;
|
|
var diff = row-firstRow;
|
|
} else if (dir > 0) {
|
|
var row = this.getRowFoldEnd(lastRow + dir);
|
|
if (row > this.doc.getLength()-1) return 0;
|
|
var diff = row-lastRow;
|
|
} else {
|
|
firstRow = this.$clipRowToDocument(firstRow);
|
|
lastRow = this.$clipRowToDocument(lastRow);
|
|
var diff = lastRow - firstRow + 1;
|
|
}
|
|
|
|
var range = new Range(firstRow, 0, lastRow, Number.MAX_VALUE);
|
|
var folds = this.getFoldsInRange(range).map(function(x){
|
|
x = x.clone();
|
|
x.start.row += diff;
|
|
x.end.row += diff;
|
|
return x;
|
|
});
|
|
|
|
var lines = dir == 0
|
|
? this.doc.getLines(firstRow, lastRow)
|
|
: this.doc.removeFullLines(firstRow, lastRow);
|
|
this.doc.insertFullLines(firstRow+diff, lines);
|
|
folds.length && this.addFolds(folds);
|
|
return diff;
|
|
};
|
|
this.moveLinesUp = function(firstRow, lastRow) {
|
|
return this.$moveLines(firstRow, lastRow, -1);
|
|
};
|
|
this.moveLinesDown = function(firstRow, lastRow) {
|
|
return this.$moveLines(firstRow, lastRow, 1);
|
|
};
|
|
this.duplicateLines = function(firstRow, lastRow) {
|
|
return this.$moveLines(firstRow, lastRow, 0);
|
|
};
|
|
|
|
|
|
this.$clipRowToDocument = function(row) {
|
|
return Math.max(0, Math.min(row, this.doc.getLength()-1));
|
|
};
|
|
|
|
this.$clipColumnToRow = function(row, column) {
|
|
if (column < 0)
|
|
return 0;
|
|
return Math.min(this.doc.getLine(row).length, column);
|
|
};
|
|
|
|
|
|
this.$clipPositionToDocument = function(row, column) {
|
|
column = Math.max(0, column);
|
|
|
|
if (row < 0) {
|
|
row = 0;
|
|
column = 0;
|
|
} else {
|
|
var len = this.doc.getLength();
|
|
if (row >= len) {
|
|
row = len - 1;
|
|
column = this.doc.getLine(len-1).length;
|
|
} else {
|
|
column = Math.min(this.doc.getLine(row).length, column);
|
|
}
|
|
}
|
|
|
|
return {
|
|
row: row,
|
|
column: column
|
|
};
|
|
};
|
|
|
|
this.$clipRangeToDocument = function(range) {
|
|
if (range.start.row < 0) {
|
|
range.start.row = 0;
|
|
range.start.column = 0;
|
|
} else {
|
|
range.start.column = this.$clipColumnToRow(
|
|
range.start.row,
|
|
range.start.column
|
|
);
|
|
}
|
|
|
|
var len = this.doc.getLength() - 1;
|
|
if (range.end.row > len) {
|
|
range.end.row = len;
|
|
range.end.column = this.doc.getLine(len).length;
|
|
} else {
|
|
range.end.column = this.$clipColumnToRow(
|
|
range.end.row,
|
|
range.end.column
|
|
);
|
|
}
|
|
return range;
|
|
};
|
|
this.$wrapLimit = 80;
|
|
this.$useWrapMode = false;
|
|
this.$wrapLimitRange = {
|
|
min : null,
|
|
max : null
|
|
};
|
|
this.setUseWrapMode = function(useWrapMode) {
|
|
if (useWrapMode != this.$useWrapMode) {
|
|
this.$useWrapMode = useWrapMode;
|
|
this.$modified = true;
|
|
this.$resetRowCache(0);
|
|
if (useWrapMode) {
|
|
var len = this.getLength();
|
|
this.$wrapData = Array(len);
|
|
this.$updateWrapData(0, len - 1);
|
|
}
|
|
|
|
this._signal("changeWrapMode");
|
|
}
|
|
};
|
|
this.getUseWrapMode = function() {
|
|
return this.$useWrapMode;
|
|
};
|
|
this.setWrapLimitRange = function(min, max) {
|
|
if (this.$wrapLimitRange.min !== min || this.$wrapLimitRange.max !== max) {
|
|
this.$wrapLimitRange = { min: min, max: max };
|
|
this.$modified = true;
|
|
this.$bidiHandler.markAsDirty();
|
|
if (this.$useWrapMode)
|
|
this._signal("changeWrapMode");
|
|
}
|
|
};
|
|
this.adjustWrapLimit = function(desiredLimit, $printMargin) {
|
|
var limits = this.$wrapLimitRange;
|
|
if (limits.max < 0)
|
|
limits = {min: $printMargin, max: $printMargin};
|
|
var wrapLimit = this.$constrainWrapLimit(desiredLimit, limits.min, limits.max);
|
|
if (wrapLimit != this.$wrapLimit && wrapLimit > 1) {
|
|
this.$wrapLimit = wrapLimit;
|
|
this.$modified = true;
|
|
if (this.$useWrapMode) {
|
|
this.$updateWrapData(0, this.getLength() - 1);
|
|
this.$resetRowCache(0);
|
|
this._signal("changeWrapLimit");
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
};
|
|
|
|
this.$constrainWrapLimit = function(wrapLimit, min, max) {
|
|
if (min)
|
|
wrapLimit = Math.max(min, wrapLimit);
|
|
|
|
if (max)
|
|
wrapLimit = Math.min(max, wrapLimit);
|
|
|
|
return wrapLimit;
|
|
};
|
|
this.getWrapLimit = function() {
|
|
return this.$wrapLimit;
|
|
};
|
|
this.setWrapLimit = function (limit) {
|
|
this.setWrapLimitRange(limit, limit);
|
|
};
|
|
this.getWrapLimitRange = function() {
|
|
return {
|
|
min : this.$wrapLimitRange.min,
|
|
max : this.$wrapLimitRange.max
|
|
};
|
|
};
|
|
|
|
this.$updateInternalDataOnChange = function(delta) {
|
|
var useWrapMode = this.$useWrapMode;
|
|
var action = delta.action;
|
|
var start = delta.start;
|
|
var end = delta.end;
|
|
var firstRow = start.row;
|
|
var lastRow = end.row;
|
|
var len = lastRow - firstRow;
|
|
var removedFolds = null;
|
|
|
|
this.$updating = true;
|
|
if (len != 0) {
|
|
if (action === "remove") {
|
|
this[useWrapMode ? "$wrapData" : "$rowLengthCache"].splice(firstRow, len);
|
|
|
|
var foldLines = this.$foldData;
|
|
removedFolds = this.getFoldsInRange(delta);
|
|
this.removeFolds(removedFolds);
|
|
|
|
var foldLine = this.getFoldLine(end.row);
|
|
var idx = 0;
|
|
if (foldLine) {
|
|
foldLine.addRemoveChars(end.row, end.column, start.column - end.column);
|
|
foldLine.shiftRow(-len);
|
|
|
|
var foldLineBefore = this.getFoldLine(firstRow);
|
|
if (foldLineBefore && foldLineBefore !== foldLine) {
|
|
foldLineBefore.merge(foldLine);
|
|
foldLine = foldLineBefore;
|
|
}
|
|
idx = foldLines.indexOf(foldLine) + 1;
|
|
}
|
|
|
|
for (idx; idx < foldLines.length; idx++) {
|
|
var foldLine = foldLines[idx];
|
|
if (foldLine.start.row >= end.row) {
|
|
foldLine.shiftRow(-len);
|
|
}
|
|
}
|
|
|
|
lastRow = firstRow;
|
|
} else {
|
|
var args = Array(len);
|
|
args.unshift(firstRow, 0);
|
|
var arr = useWrapMode ? this.$wrapData : this.$rowLengthCache;
|
|
arr.splice.apply(arr, args);
|
|
var foldLines = this.$foldData;
|
|
var foldLine = this.getFoldLine(firstRow);
|
|
var idx = 0;
|
|
if (foldLine) {
|
|
var cmp = foldLine.range.compareInside(start.row, start.column);
|
|
if (cmp == 0) {
|
|
foldLine = foldLine.split(start.row, start.column);
|
|
if (foldLine) {
|
|
foldLine.shiftRow(len);
|
|
foldLine.addRemoveChars(lastRow, 0, end.column - start.column);
|
|
}
|
|
} else
|
|
if (cmp == -1) {
|
|
foldLine.addRemoveChars(firstRow, 0, end.column - start.column);
|
|
foldLine.shiftRow(len);
|
|
}
|
|
idx = foldLines.indexOf(foldLine) + 1;
|
|
}
|
|
|
|
for (idx; idx < foldLines.length; idx++) {
|
|
var foldLine = foldLines[idx];
|
|
if (foldLine.start.row >= firstRow) {
|
|
foldLine.shiftRow(len);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
len = Math.abs(delta.start.column - delta.end.column);
|
|
if (action === "remove") {
|
|
removedFolds = this.getFoldsInRange(delta);
|
|
this.removeFolds(removedFolds);
|
|
|
|
len = -len;
|
|
}
|
|
var foldLine = this.getFoldLine(firstRow);
|
|
if (foldLine) {
|
|
foldLine.addRemoveChars(firstRow, start.column, len);
|
|
}
|
|
}
|
|
|
|
if (useWrapMode && this.$wrapData.length != this.doc.getLength()) {
|
|
console.error("doc.getLength() and $wrapData.length have to be the same!");
|
|
}
|
|
this.$updating = false;
|
|
|
|
if (useWrapMode)
|
|
this.$updateWrapData(firstRow, lastRow);
|
|
else
|
|
this.$updateRowLengthCache(firstRow, lastRow);
|
|
|
|
return removedFolds;
|
|
};
|
|
|
|
this.$updateRowLengthCache = function(firstRow, lastRow, b) {
|
|
this.$rowLengthCache[firstRow] = null;
|
|
this.$rowLengthCache[lastRow] = null;
|
|
};
|
|
|
|
this.$updateWrapData = function(firstRow, lastRow) {
|
|
var lines = this.doc.getAllLines();
|
|
var tabSize = this.getTabSize();
|
|
var wrapData = this.$wrapData;
|
|
var wrapLimit = this.$wrapLimit;
|
|
var tokens;
|
|
var foldLine;
|
|
|
|
var row = firstRow;
|
|
lastRow = Math.min(lastRow, lines.length - 1);
|
|
while (row <= lastRow) {
|
|
foldLine = this.getFoldLine(row, foldLine);
|
|
if (!foldLine) {
|
|
tokens = this.$getDisplayTokens(lines[row]);
|
|
wrapData[row] = this.$computeWrapSplits(tokens, wrapLimit, tabSize);
|
|
row ++;
|
|
} else {
|
|
tokens = [];
|
|
foldLine.walk(function(placeholder, row, column, lastColumn) {
|
|
var walkTokens;
|
|
if (placeholder != null) {
|
|
walkTokens = this.$getDisplayTokens(
|
|
placeholder, tokens.length);
|
|
walkTokens[0] = PLACEHOLDER_START;
|
|
for (var i = 1; i < walkTokens.length; i++) {
|
|
walkTokens[i] = PLACEHOLDER_BODY;
|
|
}
|
|
} else {
|
|
walkTokens = this.$getDisplayTokens(
|
|
lines[row].substring(lastColumn, column),
|
|
tokens.length);
|
|
}
|
|
tokens = tokens.concat(walkTokens);
|
|
}.bind(this),
|
|
foldLine.end.row,
|
|
lines[foldLine.end.row].length + 1
|
|
);
|
|
|
|
wrapData[foldLine.start.row] = this.$computeWrapSplits(tokens, wrapLimit, tabSize);
|
|
row = foldLine.end.row + 1;
|
|
}
|
|
}
|
|
};
|
|
var CHAR = 1,
|
|
CHAR_EXT = 2,
|
|
PLACEHOLDER_START = 3,
|
|
PLACEHOLDER_BODY = 4,
|
|
PUNCTUATION = 9,
|
|
SPACE = 10,
|
|
TAB = 11,
|
|
TAB_SPACE = 12;
|
|
|
|
|
|
this.$computeWrapSplits = function(tokens, wrapLimit, tabSize) {
|
|
if (tokens.length == 0) {
|
|
return [];
|
|
}
|
|
|
|
var splits = [];
|
|
var displayLength = tokens.length;
|
|
var lastSplit = 0, lastDocSplit = 0;
|
|
|
|
var isCode = this.$wrapAsCode;
|
|
|
|
var indentedSoftWrap = this.$indentedSoftWrap;
|
|
var maxIndent = wrapLimit <= Math.max(2 * tabSize, 8)
|
|
|| indentedSoftWrap === false ? 0 : Math.floor(wrapLimit / 2);
|
|
|
|
function getWrapIndent() {
|
|
var indentation = 0;
|
|
if (maxIndent === 0)
|
|
return indentation;
|
|
if (indentedSoftWrap) {
|
|
for (var i = 0; i < tokens.length; i++) {
|
|
var token = tokens[i];
|
|
if (token == SPACE)
|
|
indentation += 1;
|
|
else if (token == TAB)
|
|
indentation += tabSize;
|
|
else if (token == TAB_SPACE)
|
|
continue;
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
if (isCode && indentedSoftWrap !== false)
|
|
indentation += tabSize;
|
|
return Math.min(indentation, maxIndent);
|
|
}
|
|
function addSplit(screenPos) {
|
|
var len = screenPos - lastSplit;
|
|
for (var i = lastSplit; i < screenPos; i++) {
|
|
var ch = tokens[i];
|
|
if (ch === 12 || ch === 2) len -= 1;
|
|
}
|
|
|
|
if (!splits.length) {
|
|
indent = getWrapIndent();
|
|
splits.indent = indent;
|
|
}
|
|
lastDocSplit += len;
|
|
splits.push(lastDocSplit);
|
|
lastSplit = screenPos;
|
|
}
|
|
var indent = 0;
|
|
while (displayLength - lastSplit > wrapLimit - indent) {
|
|
var split = lastSplit + wrapLimit - indent;
|
|
if (tokens[split - 1] >= SPACE && tokens[split] >= SPACE) {
|
|
addSplit(split);
|
|
continue;
|
|
}
|
|
if (tokens[split] == PLACEHOLDER_START || tokens[split] == PLACEHOLDER_BODY) {
|
|
for (split; split != lastSplit - 1; split--) {
|
|
if (tokens[split] == PLACEHOLDER_START) {
|
|
break;
|
|
}
|
|
}
|
|
if (split > lastSplit) {
|
|
addSplit(split);
|
|
continue;
|
|
}
|
|
split = lastSplit + wrapLimit;
|
|
for (split; split < tokens.length; split++) {
|
|
if (tokens[split] != PLACEHOLDER_BODY) {
|
|
break;
|
|
}
|
|
}
|
|
if (split == tokens.length) {
|
|
break; // Breaks the while-loop.
|
|
}
|
|
addSplit(split);
|
|
continue;
|
|
}
|
|
var minSplit = Math.max(split - (wrapLimit -(wrapLimit>>2)), lastSplit - 1);
|
|
while (split > minSplit && tokens[split] < PLACEHOLDER_START) {
|
|
split --;
|
|
}
|
|
if (isCode) {
|
|
while (split > minSplit && tokens[split] < PLACEHOLDER_START) {
|
|
split --;
|
|
}
|
|
while (split > minSplit && tokens[split] == PUNCTUATION) {
|
|
split --;
|
|
}
|
|
} else {
|
|
while (split > minSplit && tokens[split] < SPACE) {
|
|
split --;
|
|
}
|
|
}
|
|
if (split > minSplit) {
|
|
addSplit(++split);
|
|
continue;
|
|
}
|
|
split = lastSplit + wrapLimit;
|
|
if (tokens[split] == CHAR_EXT)
|
|
split--;
|
|
addSplit(split - indent);
|
|
}
|
|
return splits;
|
|
};
|
|
this.$getDisplayTokens = function(str, offset) {
|
|
var arr = [];
|
|
var tabSize;
|
|
offset = offset || 0;
|
|
|
|
for (var i = 0; i < str.length; i++) {
|
|
var c = str.charCodeAt(i);
|
|
if (c == 9) {
|
|
tabSize = this.getScreenTabSize(arr.length + offset);
|
|
arr.push(TAB);
|
|
for (var n = 1; n < tabSize; n++) {
|
|
arr.push(TAB_SPACE);
|
|
}
|
|
}
|
|
else if (c == 32) {
|
|
arr.push(SPACE);
|
|
} else if((c > 39 && c < 48) || (c > 57 && c < 64)) {
|
|
arr.push(PUNCTUATION);
|
|
}
|
|
else if (c >= 0x1100 && isFullWidth(c)) {
|
|
arr.push(CHAR, CHAR_EXT);
|
|
} else {
|
|
arr.push(CHAR);
|
|
}
|
|
}
|
|
return arr;
|
|
};
|
|
this.$getStringScreenWidth = function(str, maxScreenColumn, screenColumn) {
|
|
if (maxScreenColumn == 0)
|
|
return [0, 0];
|
|
if (maxScreenColumn == null)
|
|
maxScreenColumn = Infinity;
|
|
screenColumn = screenColumn || 0;
|
|
|
|
var c, column;
|
|
for (column = 0; column < str.length; column++) {
|
|
c = str.charCodeAt(column);
|
|
if (c == 9) {
|
|
screenColumn += this.getScreenTabSize(screenColumn);
|
|
}
|
|
else if (c >= 0x1100 && isFullWidth(c)) {
|
|
screenColumn += 2;
|
|
} else {
|
|
screenColumn += 1;
|
|
}
|
|
if (screenColumn > maxScreenColumn) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return [screenColumn, column];
|
|
};
|
|
|
|
this.lineWidgets = null;
|
|
this.getRowLength = function(row) {
|
|
var h = 1;
|
|
if (this.lineWidgets)
|
|
h += this.lineWidgets[row] && this.lineWidgets[row].rowCount || 0;
|
|
|
|
if (!this.$useWrapMode || !this.$wrapData[row])
|
|
return h;
|
|
else
|
|
return this.$wrapData[row].length + h;
|
|
};
|
|
this.getRowLineCount = function(row) {
|
|
if (!this.$useWrapMode || !this.$wrapData[row]) {
|
|
return 1;
|
|
} else {
|
|
return this.$wrapData[row].length + 1;
|
|
}
|
|
};
|
|
|
|
this.getRowWrapIndent = function(screenRow) {
|
|
if (this.$useWrapMode) {
|
|
var pos = this.screenToDocumentPosition(screenRow, Number.MAX_VALUE);
|
|
var splits = this.$wrapData[pos.row];
|
|
return splits.length && splits[0] < pos.column ? splits.indent : 0;
|
|
} else {
|
|
return 0;
|
|
}
|
|
};
|
|
this.getScreenLastRowColumn = function(screenRow) {
|
|
var pos = this.screenToDocumentPosition(screenRow, Number.MAX_VALUE);
|
|
return this.documentToScreenColumn(pos.row, pos.column);
|
|
};
|
|
this.getDocumentLastRowColumn = function(docRow, docColumn) {
|
|
var screenRow = this.documentToScreenRow(docRow, docColumn);
|
|
return this.getScreenLastRowColumn(screenRow);
|
|
};
|
|
this.getDocumentLastRowColumnPosition = function(docRow, docColumn) {
|
|
var screenRow = this.documentToScreenRow(docRow, docColumn);
|
|
return this.screenToDocumentPosition(screenRow, Number.MAX_VALUE / 10);
|
|
};
|
|
this.getRowSplitData = function(row) {
|
|
if (!this.$useWrapMode) {
|
|
return undefined;
|
|
} else {
|
|
return this.$wrapData[row];
|
|
}
|
|
};
|
|
this.getScreenTabSize = function(screenColumn) {
|
|
return this.$tabSize - (screenColumn % this.$tabSize | 0);
|
|
};
|
|
|
|
|
|
this.screenToDocumentRow = function(screenRow, screenColumn) {
|
|
return this.screenToDocumentPosition(screenRow, screenColumn).row;
|
|
};
|
|
|
|
|
|
this.screenToDocumentColumn = function(screenRow, screenColumn) {
|
|
return this.screenToDocumentPosition(screenRow, screenColumn).column;
|
|
};
|
|
this.screenToDocumentPosition = function(screenRow, screenColumn, offsetX) {
|
|
if (screenRow < 0)
|
|
return {row: 0, column: 0};
|
|
|
|
var line;
|
|
var docRow = 0;
|
|
var docColumn = 0;
|
|
var column;
|
|
var row = 0;
|
|
var rowLength = 0;
|
|
|
|
var rowCache = this.$screenRowCache;
|
|
var i = this.$getRowCacheIndex(rowCache, screenRow);
|
|
var l = rowCache.length;
|
|
if (l && i >= 0) {
|
|
var row = rowCache[i];
|
|
var docRow = this.$docRowCache[i];
|
|
var doCache = screenRow > rowCache[l - 1];
|
|
} else {
|
|
var doCache = !l;
|
|
}
|
|
|
|
var maxRow = this.getLength() - 1;
|
|
var foldLine = this.getNextFoldLine(docRow);
|
|
var foldStart = foldLine ? foldLine.start.row : Infinity;
|
|
|
|
while (row <= screenRow) {
|
|
rowLength = this.getRowLength(docRow);
|
|
if (row + rowLength > screenRow || docRow >= maxRow) {
|
|
break;
|
|
} else {
|
|
row += rowLength;
|
|
docRow++;
|
|
if (docRow > foldStart) {
|
|
docRow = foldLine.end.row+1;
|
|
foldLine = this.getNextFoldLine(docRow, foldLine);
|
|
foldStart = foldLine ? foldLine.start.row : Infinity;
|
|
}
|
|
}
|
|
|
|
if (doCache) {
|
|
this.$docRowCache.push(docRow);
|
|
this.$screenRowCache.push(row);
|
|
}
|
|
}
|
|
|
|
if (foldLine && foldLine.start.row <= docRow) {
|
|
line = this.getFoldDisplayLine(foldLine);
|
|
docRow = foldLine.start.row;
|
|
} else if (row + rowLength <= screenRow || docRow > maxRow) {
|
|
return {
|
|
row: maxRow,
|
|
column: this.getLine(maxRow).length
|
|
};
|
|
} else {
|
|
line = this.getLine(docRow);
|
|
foldLine = null;
|
|
}
|
|
var wrapIndent = 0, splitIndex = Math.floor(screenRow - row);
|
|
if (this.$useWrapMode) {
|
|
var splits = this.$wrapData[docRow];
|
|
if (splits) {
|
|
column = splits[splitIndex];
|
|
if(splitIndex > 0 && splits.length) {
|
|
wrapIndent = splits.indent;
|
|
docColumn = splits[splitIndex - 1] || splits[splits.length - 1];
|
|
line = line.substring(docColumn);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (offsetX !== undefined && this.$bidiHandler.isBidiRow(row + splitIndex, docRow, splitIndex))
|
|
screenColumn = this.$bidiHandler.offsetToCol(offsetX);
|
|
|
|
docColumn += this.$getStringScreenWidth(line, screenColumn - wrapIndent)[1];
|
|
if (this.$useWrapMode && docColumn >= column)
|
|
docColumn = column - 1;
|
|
|
|
if (foldLine)
|
|
return foldLine.idxToPosition(docColumn);
|
|
|
|
return {row: docRow, column: docColumn};
|
|
};
|
|
this.documentToScreenPosition = function(docRow, docColumn) {
|
|
if (typeof docColumn === "undefined")
|
|
var pos = this.$clipPositionToDocument(docRow.row, docRow.column);
|
|
else
|
|
pos = this.$clipPositionToDocument(docRow, docColumn);
|
|
|
|
docRow = pos.row;
|
|
docColumn = pos.column;
|
|
|
|
var screenRow = 0;
|
|
var foldStartRow = null;
|
|
var fold = null;
|
|
fold = this.getFoldAt(docRow, docColumn, 1);
|
|
if (fold) {
|
|
docRow = fold.start.row;
|
|
docColumn = fold.start.column;
|
|
}
|
|
|
|
var rowEnd, row = 0;
|
|
|
|
|
|
var rowCache = this.$docRowCache;
|
|
var i = this.$getRowCacheIndex(rowCache, docRow);
|
|
var l = rowCache.length;
|
|
if (l && i >= 0) {
|
|
var row = rowCache[i];
|
|
var screenRow = this.$screenRowCache[i];
|
|
var doCache = docRow > rowCache[l - 1];
|
|
} else {
|
|
var doCache = !l;
|
|
}
|
|
|
|
var foldLine = this.getNextFoldLine(row);
|
|
var foldStart = foldLine ?foldLine.start.row :Infinity;
|
|
|
|
while (row < docRow) {
|
|
if (row >= foldStart) {
|
|
rowEnd = foldLine.end.row + 1;
|
|
if (rowEnd > docRow)
|
|
break;
|
|
foldLine = this.getNextFoldLine(rowEnd, foldLine);
|
|
foldStart = foldLine ?foldLine.start.row :Infinity;
|
|
}
|
|
else {
|
|
rowEnd = row + 1;
|
|
}
|
|
|
|
screenRow += this.getRowLength(row);
|
|
row = rowEnd;
|
|
|
|
if (doCache) {
|
|
this.$docRowCache.push(row);
|
|
this.$screenRowCache.push(screenRow);
|
|
}
|
|
}
|
|
var textLine = "";
|
|
if (foldLine && row >= foldStart) {
|
|
textLine = this.getFoldDisplayLine(foldLine, docRow, docColumn);
|
|
foldStartRow = foldLine.start.row;
|
|
} else {
|
|
textLine = this.getLine(docRow).substring(0, docColumn);
|
|
foldStartRow = docRow;
|
|
}
|
|
var wrapIndent = 0;
|
|
if (this.$useWrapMode) {
|
|
var wrapRow = this.$wrapData[foldStartRow];
|
|
if (wrapRow) {
|
|
var screenRowOffset = 0;
|
|
while (textLine.length >= wrapRow[screenRowOffset]) {
|
|
screenRow ++;
|
|
screenRowOffset++;
|
|
}
|
|
textLine = textLine.substring(
|
|
wrapRow[screenRowOffset - 1] || 0, textLine.length
|
|
);
|
|
wrapIndent = screenRowOffset > 0 ? wrapRow.indent : 0;
|
|
}
|
|
}
|
|
|
|
if (this.lineWidgets && this.lineWidgets[row] && this.lineWidgets[row].rowsAbove)
|
|
screenRow += this.lineWidgets[row].rowsAbove;
|
|
|
|
return {
|
|
row: screenRow,
|
|
column: wrapIndent + this.$getStringScreenWidth(textLine)[0]
|
|
};
|
|
};
|
|
this.documentToScreenColumn = function(row, docColumn) {
|
|
return this.documentToScreenPosition(row, docColumn).column;
|
|
};
|
|
this.documentToScreenRow = function(docRow, docColumn) {
|
|
return this.documentToScreenPosition(docRow, docColumn).row;
|
|
};
|
|
this.getScreenLength = function() {
|
|
var screenRows = 0;
|
|
var fold = null;
|
|
if (!this.$useWrapMode) {
|
|
screenRows = this.getLength();
|
|
var foldData = this.$foldData;
|
|
for (var i = 0; i < foldData.length; i++) {
|
|
fold = foldData[i];
|
|
screenRows -= fold.end.row - fold.start.row;
|
|
}
|
|
} else {
|
|
var lastRow = this.$wrapData.length;
|
|
var row = 0, i = 0;
|
|
var fold = this.$foldData[i++];
|
|
var foldStart = fold ? fold.start.row :Infinity;
|
|
|
|
while (row < lastRow) {
|
|
var splits = this.$wrapData[row];
|
|
screenRows += splits ? splits.length + 1 : 1;
|
|
row ++;
|
|
if (row > foldStart) {
|
|
row = fold.end.row+1;
|
|
fold = this.$foldData[i++];
|
|
foldStart = fold ?fold.start.row :Infinity;
|
|
}
|
|
}
|
|
}
|
|
if (this.lineWidgets)
|
|
screenRows += this.$getWidgetScreenLength();
|
|
|
|
return screenRows;
|
|
};
|
|
this.$setFontMetrics = function(fm) {
|
|
if (!this.$enableVarChar) return;
|
|
this.$getStringScreenWidth = function(str, maxScreenColumn, screenColumn) {
|
|
if (maxScreenColumn === 0)
|
|
return [0, 0];
|
|
if (!maxScreenColumn)
|
|
maxScreenColumn = Infinity;
|
|
screenColumn = screenColumn || 0;
|
|
|
|
var c, column;
|
|
for (column = 0; column < str.length; column++) {
|
|
c = str.charAt(column);
|
|
if (c === "\t") {
|
|
screenColumn += this.getScreenTabSize(screenColumn);
|
|
} else {
|
|
screenColumn += fm.getCharacterWidth(c);
|
|
}
|
|
if (screenColumn > maxScreenColumn) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return [screenColumn, column];
|
|
};
|
|
};
|
|
|
|
this.destroy = function() {
|
|
if (this.bgTokenizer) {
|
|
this.bgTokenizer.setDocument(null);
|
|
this.bgTokenizer = null;
|
|
}
|
|
this.$stopWorker();
|
|
this.removeAllListeners();
|
|
this.selection.detach();
|
|
};
|
|
|
|
this.isFullWidth = isFullWidth;
|
|
function isFullWidth(c) {
|
|
if (c < 0x1100)
|
|
return false;
|
|
return c >= 0x1100 && c <= 0x115F ||
|
|
c >= 0x11A3 && c <= 0x11A7 ||
|
|
c >= 0x11FA && c <= 0x11FF ||
|
|
c >= 0x2329 && c <= 0x232A ||
|
|
c >= 0x2E80 && c <= 0x2E99 ||
|
|
c >= 0x2E9B && c <= 0x2EF3 ||
|
|
c >= 0x2F00 && c <= 0x2FD5 ||
|
|
c >= 0x2FF0 && c <= 0x2FFB ||
|
|
c >= 0x3000 && c <= 0x303E ||
|
|
c >= 0x3041 && c <= 0x3096 ||
|
|
c >= 0x3099 && c <= 0x30FF ||
|
|
c >= 0x3105 && c <= 0x312D ||
|
|
c >= 0x3131 && c <= 0x318E ||
|
|
c >= 0x3190 && c <= 0x31BA ||
|
|
c >= 0x31C0 && c <= 0x31E3 ||
|
|
c >= 0x31F0 && c <= 0x321E ||
|
|
c >= 0x3220 && c <= 0x3247 ||
|
|
c >= 0x3250 && c <= 0x32FE ||
|
|
c >= 0x3300 && c <= 0x4DBF ||
|
|
c >= 0x4E00 && c <= 0xA48C ||
|
|
c >= 0xA490 && c <= 0xA4C6 ||
|
|
c >= 0xA960 && c <= 0xA97C ||
|
|
c >= 0xAC00 && c <= 0xD7A3 ||
|
|
c >= 0xD7B0 && c <= 0xD7C6 ||
|
|
c >= 0xD7CB && c <= 0xD7FB ||
|
|
c >= 0xF900 && c <= 0xFAFF ||
|
|
c >= 0xFE10 && c <= 0xFE19 ||
|
|
c >= 0xFE30 && c <= 0xFE52 ||
|
|
c >= 0xFE54 && c <= 0xFE66 ||
|
|
c >= 0xFE68 && c <= 0xFE6B ||
|
|
c >= 0xFF01 && c <= 0xFF60 ||
|
|
c >= 0xFFE0 && c <= 0xFFE6;
|
|
}
|
|
|
|
}).call(EditSession.prototype);
|
|
|
|
require("./edit_session/folding").Folding.call(EditSession.prototype);
|
|
require("./edit_session/bracket_match").BracketMatch.call(EditSession.prototype);
|
|
|
|
|
|
config.defineOptions(EditSession.prototype, "session", {
|
|
wrap: {
|
|
set: function(value) {
|
|
if (!value || value == "off")
|
|
value = false;
|
|
else if (value == "free")
|
|
value = true;
|
|
else if (value == "printMargin")
|
|
value = -1;
|
|
else if (typeof value == "string")
|
|
value = parseInt(value, 10) || false;
|
|
|
|
if (this.$wrap == value)
|
|
return;
|
|
this.$wrap = value;
|
|
if (!value) {
|
|
this.setUseWrapMode(false);
|
|
} else {
|
|
var col = typeof value == "number" ? value : null;
|
|
this.setWrapLimitRange(col, col);
|
|
this.setUseWrapMode(true);
|
|
}
|
|
},
|
|
get: function() {
|
|
if (this.getUseWrapMode()) {
|
|
if (this.$wrap == -1)
|
|
return "printMargin";
|
|
if (!this.getWrapLimitRange().min)
|
|
return "free";
|
|
return this.$wrap;
|
|
}
|
|
return "off";
|
|
},
|
|
handlesSet: true
|
|
},
|
|
wrapMethod: {
|
|
set: function(val) {
|
|
val = val == "auto"
|
|
? this.$mode.type != "text"
|
|
: val != "text";
|
|
if (val != this.$wrapAsCode) {
|
|
this.$wrapAsCode = val;
|
|
if (this.$useWrapMode) {
|
|
this.$useWrapMode = false;
|
|
this.setUseWrapMode(true);
|
|
}
|
|
}
|
|
},
|
|
initialValue: "auto"
|
|
},
|
|
indentedSoftWrap: {
|
|
set: function() {
|
|
if (this.$useWrapMode) {
|
|
this.$useWrapMode = false;
|
|
this.setUseWrapMode(true);
|
|
}
|
|
},
|
|
initialValue: true
|
|
},
|
|
firstLineNumber: {
|
|
set: function() {this._signal("changeBreakpoint");},
|
|
initialValue: 1
|
|
},
|
|
useWorker: {
|
|
set: function(useWorker) {
|
|
this.$useWorker = useWorker;
|
|
|
|
this.$stopWorker();
|
|
if (useWorker)
|
|
this.$startWorker();
|
|
},
|
|
initialValue: true
|
|
},
|
|
useSoftTabs: {initialValue: true},
|
|
tabSize: {
|
|
set: function(tabSize) {
|
|
tabSize = parseInt(tabSize);
|
|
if (tabSize > 0 && this.$tabSize !== tabSize) {
|
|
this.$modified = true;
|
|
this.$rowLengthCache = [];
|
|
this.$tabSize = tabSize;
|
|
this._signal("changeTabSize");
|
|
}
|
|
},
|
|
initialValue: 4,
|
|
handlesSet: true
|
|
},
|
|
navigateWithinSoftTabs: {initialValue: false},
|
|
foldStyle: {
|
|
set: function(val) {this.setFoldStyle(val);},
|
|
handlesSet: true
|
|
},
|
|
overwrite: {
|
|
set: function(val) {this._signal("changeOverwrite");},
|
|
initialValue: false
|
|
},
|
|
newLineMode: {
|
|
set: function(val) {this.doc.setNewLineMode(val);},
|
|
get: function() {return this.doc.getNewLineMode();},
|
|
handlesSet: true
|
|
},
|
|
mode: {
|
|
set: function(val) { this.setMode(val); },
|
|
get: function() { return this.$modeId; },
|
|
handlesSet: true
|
|
}
|
|
});
|
|
|
|
exports.EditSession = EditSession;
|
|
});
|
|
|
|
ace.define("ace/search",["require","exports","module","ace/lib/lang","ace/lib/oop","ace/range"], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var lang = require("./lib/lang");
|
|
var oop = require("./lib/oop");
|
|
var Range = require("./range").Range;
|
|
|
|
var Search = function() {
|
|
this.$options = {};
|
|
};
|
|
|
|
(function() {
|
|
this.set = function(options) {
|
|
oop.mixin(this.$options, options);
|
|
return this;
|
|
};
|
|
this.getOptions = function() {
|
|
return lang.copyObject(this.$options);
|
|
};
|
|
this.setOptions = function(options) {
|
|
this.$options = options;
|
|
};
|
|
this.find = function(session) {
|
|
var options = this.$options;
|
|
var iterator = this.$matchIterator(session, options);
|
|
if (!iterator)
|
|
return false;
|
|
|
|
var firstRange = null;
|
|
iterator.forEach(function(sr, sc, er, ec) {
|
|
firstRange = new Range(sr, sc, er, ec);
|
|
if (sc == ec && options.start && options.start.start
|
|
&& options.skipCurrent != false && firstRange.isEqual(options.start)
|
|
) {
|
|
firstRange = null;
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
});
|
|
|
|
return firstRange;
|
|
};
|
|
this.findAll = function(session) {
|
|
var options = this.$options;
|
|
if (!options.needle)
|
|
return [];
|
|
this.$assembleRegExp(options);
|
|
|
|
var range = options.range;
|
|
var lines = range
|
|
? session.getLines(range.start.row, range.end.row)
|
|
: session.doc.getAllLines();
|
|
|
|
var ranges = [];
|
|
var re = options.re;
|
|
if (options.$isMultiLine) {
|
|
var len = re.length;
|
|
var maxRow = lines.length - len;
|
|
var prevRange;
|
|
outer: for (var row = re.offset || 0; row <= maxRow; row++) {
|
|
for (var j = 0; j < len; j++)
|
|
if (lines[row + j].search(re[j]) == -1)
|
|
continue outer;
|
|
|
|
var startLine = lines[row];
|
|
var line = lines[row + len - 1];
|
|
var startIndex = startLine.length - startLine.match(re[0])[0].length;
|
|
var endIndex = line.match(re[len - 1])[0].length;
|
|
|
|
if (prevRange && prevRange.end.row === row &&
|
|
prevRange.end.column > startIndex
|
|
) {
|
|
continue;
|
|
}
|
|
ranges.push(prevRange = new Range(
|
|
row, startIndex, row + len - 1, endIndex
|
|
));
|
|
if (len > 2)
|
|
row = row + len - 2;
|
|
}
|
|
} else {
|
|
for (var i = 0; i < lines.length; i++) {
|
|
var matches = lang.getMatchOffsets(lines[i], re);
|
|
for (var j = 0; j < matches.length; j++) {
|
|
var match = matches[j];
|
|
ranges.push(new Range(i, match.offset, i, match.offset + match.length));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (range) {
|
|
var startColumn = range.start.column;
|
|
var endColumn = range.start.column;
|
|
var i = 0, j = ranges.length - 1;
|
|
while (i < j && ranges[i].start.column < startColumn && ranges[i].start.row == range.start.row)
|
|
i++;
|
|
|
|
while (i < j && ranges[j].end.column > endColumn && ranges[j].end.row == range.end.row)
|
|
j--;
|
|
|
|
ranges = ranges.slice(i, j + 1);
|
|
for (i = 0, j = ranges.length; i < j; i++) {
|
|
ranges[i].start.row += range.start.row;
|
|
ranges[i].end.row += range.start.row;
|
|
}
|
|
}
|
|
|
|
return ranges;
|
|
};
|
|
this.replace = function(input, replacement) {
|
|
var options = this.$options;
|
|
|
|
var re = this.$assembleRegExp(options);
|
|
if (options.$isMultiLine)
|
|
return replacement;
|
|
|
|
if (!re)
|
|
return;
|
|
|
|
var match = re.exec(input);
|
|
if (!match || match[0].length != input.length)
|
|
return null;
|
|
|
|
replacement = input.replace(re, replacement);
|
|
if (options.preserveCase) {
|
|
replacement = replacement.split("");
|
|
for (var i = Math.min(input.length, input.length); i--; ) {
|
|
var ch = input[i];
|
|
if (ch && ch.toLowerCase() != ch)
|
|
replacement[i] = replacement[i].toUpperCase();
|
|
else
|
|
replacement[i] = replacement[i].toLowerCase();
|
|
}
|
|
replacement = replacement.join("");
|
|
}
|
|
|
|
return replacement;
|
|
};
|
|
|
|
this.$assembleRegExp = function(options, $disableFakeMultiline) {
|
|
if (options.needle instanceof RegExp)
|
|
return options.re = options.needle;
|
|
|
|
var needle = options.needle;
|
|
|
|
if (!options.needle)
|
|
return options.re = false;
|
|
|
|
if (!options.regExp)
|
|
needle = lang.escapeRegExp(needle);
|
|
|
|
if (options.wholeWord)
|
|
needle = addWordBoundary(needle, options);
|
|
|
|
var modifier = options.caseSensitive ? "gm" : "gmi";
|
|
|
|
options.$isMultiLine = !$disableFakeMultiline && /[\n\r]/.test(needle);
|
|
if (options.$isMultiLine)
|
|
return options.re = this.$assembleMultilineRegExp(needle, modifier);
|
|
|
|
try {
|
|
var re = new RegExp(needle, modifier);
|
|
} catch(e) {
|
|
re = false;
|
|
}
|
|
return options.re = re;
|
|
};
|
|
|
|
this.$assembleMultilineRegExp = function(needle, modifier) {
|
|
var parts = needle.replace(/\r\n|\r|\n/g, "$\n^").split("\n");
|
|
var re = [];
|
|
for (var i = 0; i < parts.length; i++) try {
|
|
re.push(new RegExp(parts[i], modifier));
|
|
} catch(e) {
|
|
return false;
|
|
}
|
|
return re;
|
|
};
|
|
|
|
this.$matchIterator = function(session, options) {
|
|
var re = this.$assembleRegExp(options);
|
|
if (!re)
|
|
return false;
|
|
var backwards = options.backwards == true;
|
|
var skipCurrent = options.skipCurrent != false;
|
|
|
|
var range = options.range;
|
|
var start = options.start;
|
|
if (!start)
|
|
start = range ? range[backwards ? "end" : "start"] : session.selection.getRange();
|
|
|
|
if (start.start)
|
|
start = start[skipCurrent != backwards ? "end" : "start"];
|
|
|
|
var firstRow = range ? range.start.row : 0;
|
|
var lastRow = range ? range.end.row : session.getLength() - 1;
|
|
|
|
if (backwards) {
|
|
var forEach = function(callback) {
|
|
var row = start.row;
|
|
if (forEachInLine(row, start.column, callback))
|
|
return;
|
|
for (row--; row >= firstRow; row--)
|
|
if (forEachInLine(row, Number.MAX_VALUE, callback))
|
|
return;
|
|
if (options.wrap == false)
|
|
return;
|
|
for (row = lastRow, firstRow = start.row; row >= firstRow; row--)
|
|
if (forEachInLine(row, Number.MAX_VALUE, callback))
|
|
return;
|
|
};
|
|
}
|
|
else {
|
|
var forEach = function(callback) {
|
|
var row = start.row;
|
|
if (forEachInLine(row, start.column, callback))
|
|
return;
|
|
for (row = row + 1; row <= lastRow; row++)
|
|
if (forEachInLine(row, 0, callback))
|
|
return;
|
|
if (options.wrap == false)
|
|
return;
|
|
for (row = firstRow, lastRow = start.row; row <= lastRow; row++)
|
|
if (forEachInLine(row, 0, callback))
|
|
return;
|
|
};
|
|
}
|
|
|
|
if (options.$isMultiLine) {
|
|
var len = re.length;
|
|
var forEachInLine = function(row, offset, callback) {
|
|
var startRow = backwards ? row - len + 1 : row;
|
|
if (startRow < 0) return;
|
|
var line = session.getLine(startRow);
|
|
var startIndex = line.search(re[0]);
|
|
if (!backwards && startIndex < offset || startIndex === -1) return;
|
|
for (var i = 1; i < len; i++) {
|
|
line = session.getLine(startRow + i);
|
|
if (line.search(re[i]) == -1)
|
|
return;
|
|
}
|
|
var endIndex = line.match(re[len - 1])[0].length;
|
|
if (backwards && endIndex > offset) return;
|
|
if (callback(startRow, startIndex, startRow + len - 1, endIndex))
|
|
return true;
|
|
};
|
|
}
|
|
else if (backwards) {
|
|
var forEachInLine = function(row, endIndex, callback) {
|
|
var line = session.getLine(row);
|
|
var matches = [];
|
|
var m, last = 0;
|
|
re.lastIndex = 0;
|
|
while((m = re.exec(line))) {
|
|
var length = m[0].length;
|
|
last = m.index;
|
|
if (!length) {
|
|
if (last >= line.length) break;
|
|
re.lastIndex = last += 1;
|
|
}
|
|
if (m.index + length > endIndex)
|
|
break;
|
|
matches.push(m.index, length);
|
|
}
|
|
for (var i = matches.length - 1; i >= 0; i -= 2) {
|
|
var column = matches[i - 1];
|
|
var length = matches[i];
|
|
if (callback(row, column, row, column + length))
|
|
return true;
|
|
}
|
|
};
|
|
}
|
|
else {
|
|
var forEachInLine = function(row, startIndex, callback) {
|
|
var line = session.getLine(row);
|
|
var last;
|
|
var m;
|
|
re.lastIndex = startIndex;
|
|
while((m = re.exec(line))) {
|
|
var length = m[0].length;
|
|
last = m.index;
|
|
if (callback(row, last, row,last + length))
|
|
return true;
|
|
if (!length) {
|
|
re.lastIndex = last += 1;
|
|
if (last >= line.length) return false;
|
|
}
|
|
}
|
|
};
|
|
}
|
|
return {forEach: forEach};
|
|
};
|
|
|
|
}).call(Search.prototype);
|
|
|
|
function addWordBoundary(needle, options) {
|
|
function wordBoundary(c) {
|
|
if (/\w/.test(c) || options.regExp) return "\\b";
|
|
return "";
|
|
}
|
|
return wordBoundary(needle[0]) + needle
|
|
+ wordBoundary(needle[needle.length - 1]);
|
|
}
|
|
|
|
exports.Search = Search;
|
|
});
|
|
|
|
ace.define("ace/keyboard/hash_handler",["require","exports","module","ace/lib/keys","ace/lib/useragent"], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var keyUtil = require("../lib/keys");
|
|
var useragent = require("../lib/useragent");
|
|
var KEY_MODS = keyUtil.KEY_MODS;
|
|
|
|
function HashHandler(config, platform) {
|
|
this.platform = platform || (useragent.isMac ? "mac" : "win");
|
|
this.commands = {};
|
|
this.commandKeyBinding = {};
|
|
this.addCommands(config);
|
|
this.$singleCommand = true;
|
|
}
|
|
|
|
function MultiHashHandler(config, platform) {
|
|
HashHandler.call(this, config, platform);
|
|
this.$singleCommand = false;
|
|
}
|
|
|
|
MultiHashHandler.prototype = HashHandler.prototype;
|
|
|
|
(function() {
|
|
|
|
|
|
this.addCommand = function(command) {
|
|
if (this.commands[command.name])
|
|
this.removeCommand(command);
|
|
|
|
this.commands[command.name] = command;
|
|
|
|
if (command.bindKey)
|
|
this._buildKeyHash(command);
|
|
};
|
|
|
|
this.removeCommand = function(command, keepCommand) {
|
|
var name = command && (typeof command === 'string' ? command : command.name);
|
|
command = this.commands[name];
|
|
if (!keepCommand)
|
|
delete this.commands[name];
|
|
var ckb = this.commandKeyBinding;
|
|
for (var keyId in ckb) {
|
|
var cmdGroup = ckb[keyId];
|
|
if (cmdGroup == command) {
|
|
delete ckb[keyId];
|
|
} else if (Array.isArray(cmdGroup)) {
|
|
var i = cmdGroup.indexOf(command);
|
|
if (i != -1) {
|
|
cmdGroup.splice(i, 1);
|
|
if (cmdGroup.length == 1)
|
|
ckb[keyId] = cmdGroup[0];
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
this.bindKey = function(key, command, position) {
|
|
if (typeof key == "object" && key) {
|
|
if (position == undefined)
|
|
position = key.position;
|
|
key = key[this.platform];
|
|
}
|
|
if (!key)
|
|
return;
|
|
if (typeof command == "function")
|
|
return this.addCommand({exec: command, bindKey: key, name: command.name || key});
|
|
|
|
key.split("|").forEach(function(keyPart) {
|
|
var chain = "";
|
|
if (keyPart.indexOf(" ") != -1) {
|
|
var parts = keyPart.split(/\s+/);
|
|
keyPart = parts.pop();
|
|
parts.forEach(function(keyPart) {
|
|
var binding = this.parseKeys(keyPart);
|
|
var id = KEY_MODS[binding.hashId] + binding.key;
|
|
chain += (chain ? " " : "") + id;
|
|
this._addCommandToBinding(chain, "chainKeys");
|
|
}, this);
|
|
chain += " ";
|
|
}
|
|
var binding = this.parseKeys(keyPart);
|
|
var id = KEY_MODS[binding.hashId] + binding.key;
|
|
this._addCommandToBinding(chain + id, command, position);
|
|
}, this);
|
|
};
|
|
|
|
function getPosition(command) {
|
|
return typeof command == "object" && command.bindKey
|
|
&& command.bindKey.position
|
|
|| (command.isDefault ? -100 : 0);
|
|
}
|
|
this._addCommandToBinding = function(keyId, command, position) {
|
|
var ckb = this.commandKeyBinding, i;
|
|
if (!command) {
|
|
delete ckb[keyId];
|
|
} else if (!ckb[keyId] || this.$singleCommand) {
|
|
ckb[keyId] = command;
|
|
} else {
|
|
if (!Array.isArray(ckb[keyId])) {
|
|
ckb[keyId] = [ckb[keyId]];
|
|
} else if ((i = ckb[keyId].indexOf(command)) != -1) {
|
|
ckb[keyId].splice(i, 1);
|
|
}
|
|
|
|
if (typeof position != "number") {
|
|
position = getPosition(command);
|
|
}
|
|
|
|
var commands = ckb[keyId];
|
|
for (i = 0; i < commands.length; i++) {
|
|
var other = commands[i];
|
|
var otherPos = getPosition(other);
|
|
if (otherPos > position)
|
|
break;
|
|
}
|
|
commands.splice(i, 0, command);
|
|
}
|
|
};
|
|
|
|
this.addCommands = function(commands) {
|
|
commands && Object.keys(commands).forEach(function(name) {
|
|
var command = commands[name];
|
|
if (!command)
|
|
return;
|
|
|
|
if (typeof command === "string")
|
|
return this.bindKey(command, name);
|
|
|
|
if (typeof command === "function")
|
|
command = { exec: command };
|
|
|
|
if (typeof command !== "object")
|
|
return;
|
|
|
|
if (!command.name)
|
|
command.name = name;
|
|
|
|
this.addCommand(command);
|
|
}, this);
|
|
};
|
|
|
|
this.removeCommands = function(commands) {
|
|
Object.keys(commands).forEach(function(name) {
|
|
this.removeCommand(commands[name]);
|
|
}, this);
|
|
};
|
|
|
|
this.bindKeys = function(keyList) {
|
|
Object.keys(keyList).forEach(function(key) {
|
|
this.bindKey(key, keyList[key]);
|
|
}, this);
|
|
};
|
|
|
|
this._buildKeyHash = function(command) {
|
|
this.bindKey(command.bindKey, command);
|
|
};
|
|
this.parseKeys = function(keys) {
|
|
var parts = keys.toLowerCase().split(/[\-\+]([\-\+])?/).filter(function(x){return x;});
|
|
var key = parts.pop();
|
|
|
|
var keyCode = keyUtil[key];
|
|
if (keyUtil.FUNCTION_KEYS[keyCode])
|
|
key = keyUtil.FUNCTION_KEYS[keyCode].toLowerCase();
|
|
else if (!parts.length)
|
|
return {key: key, hashId: -1};
|
|
else if (parts.length == 1 && parts[0] == "shift")
|
|
return {key: key.toUpperCase(), hashId: -1};
|
|
|
|
var hashId = 0;
|
|
for (var i = parts.length; i--;) {
|
|
var modifier = keyUtil.KEY_MODS[parts[i]];
|
|
if (modifier == null) {
|
|
if (typeof console != "undefined")
|
|
console.error("invalid modifier " + parts[i] + " in " + keys);
|
|
return false;
|
|
}
|
|
hashId |= modifier;
|
|
}
|
|
return {key: key, hashId: hashId};
|
|
};
|
|
|
|
this.findKeyCommand = function findKeyCommand(hashId, keyString) {
|
|
var key = KEY_MODS[hashId] + keyString;
|
|
return this.commandKeyBinding[key];
|
|
};
|
|
|
|
this.handleKeyboard = function(data, hashId, keyString, keyCode) {
|
|
if (keyCode < 0) return;
|
|
var key = KEY_MODS[hashId] + keyString;
|
|
var command = this.commandKeyBinding[key];
|
|
if (data.$keyChain) {
|
|
data.$keyChain += " " + key;
|
|
command = this.commandKeyBinding[data.$keyChain] || command;
|
|
}
|
|
|
|
if (command) {
|
|
if (command == "chainKeys" || command[command.length - 1] == "chainKeys") {
|
|
data.$keyChain = data.$keyChain || key;
|
|
return {command: "null"};
|
|
}
|
|
}
|
|
|
|
if (data.$keyChain) {
|
|
if ((!hashId || hashId == 4) && keyString.length == 1)
|
|
data.$keyChain = data.$keyChain.slice(0, -key.length - 1); // wait for input
|
|
else if (hashId == -1 || keyCode > 0)
|
|
data.$keyChain = ""; // reset keyChain
|
|
}
|
|
return {command: command};
|
|
};
|
|
|
|
this.getStatusText = function(editor, data) {
|
|
return data.$keyChain || "";
|
|
};
|
|
|
|
}).call(HashHandler.prototype);
|
|
|
|
exports.HashHandler = HashHandler;
|
|
exports.MultiHashHandler = MultiHashHandler;
|
|
});
|
|
|
|
ace.define("ace/commands/command_manager",["require","exports","module","ace/lib/oop","ace/keyboard/hash_handler","ace/lib/event_emitter"], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var oop = require("../lib/oop");
|
|
var MultiHashHandler = require("../keyboard/hash_handler").MultiHashHandler;
|
|
var EventEmitter = require("../lib/event_emitter").EventEmitter;
|
|
|
|
var CommandManager = function(platform, commands) {
|
|
MultiHashHandler.call(this, commands, platform);
|
|
this.byName = this.commands;
|
|
this.setDefaultHandler("exec", function(e) {
|
|
return e.command.exec(e.editor, e.args || {});
|
|
});
|
|
};
|
|
|
|
oop.inherits(CommandManager, MultiHashHandler);
|
|
|
|
(function() {
|
|
|
|
oop.implement(this, EventEmitter);
|
|
|
|
this.exec = function(command, editor, args) {
|
|
if (Array.isArray(command)) {
|
|
for (var i = command.length; i--; ) {
|
|
if (this.exec(command[i], editor, args)) return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
if (typeof command === "string")
|
|
command = this.commands[command];
|
|
|
|
if (!command)
|
|
return false;
|
|
|
|
if (editor && editor.$readOnly && !command.readOnly)
|
|
return false;
|
|
|
|
if (this.$checkCommandState != false && command.isAvailable && !command.isAvailable(editor))
|
|
return false;
|
|
|
|
var e = {editor: editor, command: command, args: args};
|
|
e.returnValue = this._emit("exec", e);
|
|
this._signal("afterExec", e);
|
|
|
|
return e.returnValue === false ? false : true;
|
|
};
|
|
|
|
this.toggleRecording = function(editor) {
|
|
if (this.$inReplay)
|
|
return;
|
|
|
|
editor && editor._emit("changeStatus");
|
|
if (this.recording) {
|
|
this.macro.pop();
|
|
this.off("exec", this.$addCommandToMacro);
|
|
|
|
if (!this.macro.length)
|
|
this.macro = this.oldMacro;
|
|
|
|
return this.recording = false;
|
|
}
|
|
if (!this.$addCommandToMacro) {
|
|
this.$addCommandToMacro = function(e) {
|
|
this.macro.push([e.command, e.args]);
|
|
}.bind(this);
|
|
}
|
|
|
|
this.oldMacro = this.macro;
|
|
this.macro = [];
|
|
this.on("exec", this.$addCommandToMacro);
|
|
return this.recording = true;
|
|
};
|
|
|
|
this.replay = function(editor) {
|
|
if (this.$inReplay || !this.macro)
|
|
return;
|
|
|
|
if (this.recording)
|
|
return this.toggleRecording(editor);
|
|
|
|
try {
|
|
this.$inReplay = true;
|
|
this.macro.forEach(function(x) {
|
|
if (typeof x == "string")
|
|
this.exec(x, editor);
|
|
else
|
|
this.exec(x[0], editor, x[1]);
|
|
}, this);
|
|
} finally {
|
|
this.$inReplay = false;
|
|
}
|
|
};
|
|
|
|
this.trimMacro = function(m) {
|
|
return m.map(function(x){
|
|
if (typeof x[0] != "string")
|
|
x[0] = x[0].name;
|
|
if (!x[1])
|
|
x = x[0];
|
|
return x;
|
|
});
|
|
};
|
|
|
|
}).call(CommandManager.prototype);
|
|
|
|
exports.CommandManager = CommandManager;
|
|
|
|
});
|
|
|
|
ace.define("ace/commands/default_commands",["require","exports","module","ace/lib/lang","ace/config","ace/range"], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var lang = require("../lib/lang");
|
|
var config = require("../config");
|
|
var Range = require("../range").Range;
|
|
|
|
function bindKey(win, mac) {
|
|
return {win: win, mac: mac};
|
|
}
|
|
exports.commands = [{
|
|
name: "showSettingsMenu",
|
|
bindKey: bindKey("Ctrl-,", "Command-,"),
|
|
exec: function(editor) {
|
|
config.loadModule("ace/ext/settings_menu", function(module) {
|
|
module.init(editor);
|
|
editor.showSettingsMenu();
|
|
});
|
|
},
|
|
readOnly: true
|
|
}, {
|
|
name: "goToNextError",
|
|
bindKey: bindKey("Alt-E", "F4"),
|
|
exec: function(editor) {
|
|
config.loadModule("./ext/error_marker", function(module) {
|
|
module.showErrorMarker(editor, 1);
|
|
});
|
|
},
|
|
scrollIntoView: "animate",
|
|
readOnly: true
|
|
}, {
|
|
name: "goToPreviousError",
|
|
bindKey: bindKey("Alt-Shift-E", "Shift-F4"),
|
|
exec: function(editor) {
|
|
config.loadModule("./ext/error_marker", function(module) {
|
|
module.showErrorMarker(editor, -1);
|
|
});
|
|
},
|
|
scrollIntoView: "animate",
|
|
readOnly: true
|
|
}, {
|
|
name: "selectall",
|
|
description: "Select all",
|
|
bindKey: bindKey("Ctrl-A", "Command-A"),
|
|
exec: function(editor) { editor.selectAll(); },
|
|
readOnly: true
|
|
}, {
|
|
name: "centerselection",
|
|
description: "Center selection",
|
|
bindKey: bindKey(null, "Ctrl-L"),
|
|
exec: function(editor) { editor.centerSelection(); },
|
|
readOnly: true
|
|
}, {
|
|
name: "gotoline",
|
|
description: "Go to line...",
|
|
bindKey: bindKey("Ctrl-L", "Command-L"),
|
|
exec: function(editor, line) {
|
|
if (typeof line === "number" && !isNaN(line))
|
|
editor.gotoLine(line);
|
|
editor.prompt({ $type: "gotoLine" });
|
|
},
|
|
readOnly: true
|
|
}, {
|
|
name: "fold",
|
|
bindKey: bindKey("Alt-L|Ctrl-F1", "Command-Alt-L|Command-F1"),
|
|
exec: function(editor) { editor.session.toggleFold(false); },
|
|
multiSelectAction: "forEach",
|
|
scrollIntoView: "center",
|
|
readOnly: true
|
|
}, {
|
|
name: "unfold",
|
|
bindKey: bindKey("Alt-Shift-L|Ctrl-Shift-F1", "Command-Alt-Shift-L|Command-Shift-F1"),
|
|
exec: function(editor) { editor.session.toggleFold(true); },
|
|
multiSelectAction: "forEach",
|
|
scrollIntoView: "center",
|
|
readOnly: true
|
|
}, {
|
|
name: "toggleFoldWidget",
|
|
bindKey: bindKey("F2", "F2"),
|
|
exec: function(editor) { editor.session.toggleFoldWidget(); },
|
|
multiSelectAction: "forEach",
|
|
scrollIntoView: "center",
|
|
readOnly: true
|
|
}, {
|
|
name: "toggleParentFoldWidget",
|
|
bindKey: bindKey("Alt-F2", "Alt-F2"),
|
|
exec: function(editor) { editor.session.toggleFoldWidget(true); },
|
|
multiSelectAction: "forEach",
|
|
scrollIntoView: "center",
|
|
readOnly: true
|
|
}, {
|
|
name: "foldall",
|
|
description: "Fold all",
|
|
bindKey: bindKey(null, "Ctrl-Command-Option-0"),
|
|
exec: function(editor) { editor.session.foldAll(); },
|
|
scrollIntoView: "center",
|
|
readOnly: true
|
|
}, {
|
|
name: "foldAllComments",
|
|
description: "Fold all comments",
|
|
bindKey: bindKey(null, "Ctrl-Command-Option-0"),
|
|
exec: function(editor) { editor.session.foldAllComments(); },
|
|
scrollIntoView: "center",
|
|
readOnly: true
|
|
}, {
|
|
name: "foldOther",
|
|
description: "Fold other",
|
|
bindKey: bindKey("Alt-0", "Command-Option-0"),
|
|
exec: function(editor) {
|
|
editor.session.foldAll();
|
|
editor.session.unfold(editor.selection.getAllRanges());
|
|
},
|
|
scrollIntoView: "center",
|
|
readOnly: true
|
|
}, {
|
|
name: "unfoldall",
|
|
description: "Unfold all",
|
|
bindKey: bindKey("Alt-Shift-0", "Command-Option-Shift-0"),
|
|
exec: function(editor) { editor.session.unfold(); },
|
|
scrollIntoView: "center",
|
|
readOnly: true
|
|
}, {
|
|
name: "findnext",
|
|
description: "Find next",
|
|
bindKey: bindKey("Ctrl-K", "Command-G"),
|
|
exec: function(editor) { editor.findNext(); },
|
|
multiSelectAction: "forEach",
|
|
scrollIntoView: "center",
|
|
readOnly: true
|
|
}, {
|
|
name: "findprevious",
|
|
description: "Find previous",
|
|
bindKey: bindKey("Ctrl-Shift-K", "Command-Shift-G"),
|
|
exec: function(editor) { editor.findPrevious(); },
|
|
multiSelectAction: "forEach",
|
|
scrollIntoView: "center",
|
|
readOnly: true
|
|
}, {
|
|
name: "selectOrFindNext",
|
|
description: "Select or find next",
|
|
bindKey: bindKey("Alt-K", "Ctrl-G"),
|
|
exec: function(editor) {
|
|
if (editor.selection.isEmpty())
|
|
editor.selection.selectWord();
|
|
else
|
|
editor.findNext();
|
|
},
|
|
readOnly: true
|
|
}, {
|
|
name: "selectOrFindPrevious",
|
|
description: "Select or find previous",
|
|
bindKey: bindKey("Alt-Shift-K", "Ctrl-Shift-G"),
|
|
exec: function(editor) {
|
|
if (editor.selection.isEmpty())
|
|
editor.selection.selectWord();
|
|
else
|
|
editor.findPrevious();
|
|
},
|
|
readOnly: true
|
|
}, {
|
|
name: "find",
|
|
description: "Find",
|
|
bindKey: bindKey("Ctrl-F", "Command-F"),
|
|
exec: function(editor) {
|
|
config.loadModule("ace/ext/searchbox", function(e) {e.Search(editor);});
|
|
},
|
|
readOnly: true
|
|
}, {
|
|
name: "overwrite",
|
|
description: "Overwrite",
|
|
bindKey: "Insert",
|
|
exec: function(editor) { editor.toggleOverwrite(); },
|
|
readOnly: true
|
|
}, {
|
|
name: "selecttostart",
|
|
description: "Select to start",
|
|
bindKey: bindKey("Ctrl-Shift-Home", "Command-Shift-Home|Command-Shift-Up"),
|
|
exec: function(editor) { editor.getSelection().selectFileStart(); },
|
|
multiSelectAction: "forEach",
|
|
readOnly: true,
|
|
scrollIntoView: "animate",
|
|
aceCommandGroup: "fileJump"
|
|
}, {
|
|
name: "gotostart",
|
|
description: "Go to start",
|
|
bindKey: bindKey("Ctrl-Home", "Command-Home|Command-Up"),
|
|
exec: function(editor) { editor.navigateFileStart(); },
|
|
multiSelectAction: "forEach",
|
|
readOnly: true,
|
|
scrollIntoView: "animate",
|
|
aceCommandGroup: "fileJump"
|
|
}, {
|
|
name: "selectup",
|
|
description: "Select up",
|
|
bindKey: bindKey("Shift-Up", "Shift-Up|Ctrl-Shift-P"),
|
|
exec: function(editor) { editor.getSelection().selectUp(); },
|
|
multiSelectAction: "forEach",
|
|
scrollIntoView: "cursor",
|
|
readOnly: true
|
|
}, {
|
|
name: "golineup",
|
|
description: "Go line up",
|
|
bindKey: bindKey("Up", "Up|Ctrl-P"),
|
|
exec: function(editor, args) { editor.navigateUp(args.times); },
|
|
multiSelectAction: "forEach",
|
|
scrollIntoView: "cursor",
|
|
readOnly: true
|
|
}, {
|
|
name: "selecttoend",
|
|
description: "Select to end",
|
|
bindKey: bindKey("Ctrl-Shift-End", "Command-Shift-End|Command-Shift-Down"),
|
|
exec: function(editor) { editor.getSelection().selectFileEnd(); },
|
|
multiSelectAction: "forEach",
|
|
readOnly: true,
|
|
scrollIntoView: "animate",
|
|
aceCommandGroup: "fileJump"
|
|
}, {
|
|
name: "gotoend",
|
|
description: "Go to end",
|
|
bindKey: bindKey("Ctrl-End", "Command-End|Command-Down"),
|
|
exec: function(editor) { editor.navigateFileEnd(); },
|
|
multiSelectAction: "forEach",
|
|
readOnly: true,
|
|
scrollIntoView: "animate",
|
|
aceCommandGroup: "fileJump"
|
|
}, {
|
|
name: "selectdown",
|
|
description: "Select down",
|
|
bindKey: bindKey("Shift-Down", "Shift-Down|Ctrl-Shift-N"),
|
|
exec: function(editor) { editor.getSelection().selectDown(); },
|
|
multiSelectAction: "forEach",
|
|
scrollIntoView: "cursor",
|
|
readOnly: true
|
|
}, {
|
|
name: "golinedown",
|
|
description: "Go line down",
|
|
bindKey: bindKey("Down", "Down|Ctrl-N"),
|
|
exec: function(editor, args) { editor.navigateDown(args.times); },
|
|
multiSelectAction: "forEach",
|
|
scrollIntoView: "cursor",
|
|
readOnly: true
|
|
}, {
|
|
name: "selectwordleft",
|
|
description: "Select word left",
|
|
bindKey: bindKey("Ctrl-Shift-Left", "Option-Shift-Left"),
|
|
exec: function(editor) { editor.getSelection().selectWordLeft(); },
|
|
multiSelectAction: "forEach",
|
|
scrollIntoView: "cursor",
|
|
readOnly: true
|
|
}, {
|
|
name: "gotowordleft",
|
|
description: "Go to word left",
|
|
bindKey: bindKey("Ctrl-Left", "Option-Left"),
|
|
exec: function(editor) { editor.navigateWordLeft(); },
|
|
multiSelectAction: "forEach",
|
|
scrollIntoView: "cursor",
|
|
readOnly: true
|
|
}, {
|
|
name: "selecttolinestart",
|
|
description: "Select to line start",
|
|
bindKey: bindKey("Alt-Shift-Left", "Command-Shift-Left|Ctrl-Shift-A"),
|
|
exec: function(editor) { editor.getSelection().selectLineStart(); },
|
|
multiSelectAction: "forEach",
|
|
scrollIntoView: "cursor",
|
|
readOnly: true
|
|
}, {
|
|
name: "gotolinestart",
|
|
description: "Go to line start",
|
|
bindKey: bindKey("Alt-Left|Home", "Command-Left|Home|Ctrl-A"),
|
|
exec: function(editor) { editor.navigateLineStart(); },
|
|
multiSelectAction: "forEach",
|
|
scrollIntoView: "cursor",
|
|
readOnly: true
|
|
}, {
|
|
name: "selectleft",
|
|
description: "Select left",
|
|
bindKey: bindKey("Shift-Left", "Shift-Left|Ctrl-Shift-B"),
|
|
exec: function(editor) { editor.getSelection().selectLeft(); },
|
|
multiSelectAction: "forEach",
|
|
scrollIntoView: "cursor",
|
|
readOnly: true
|
|
}, {
|
|
name: "gotoleft",
|
|
description: "Go to left",
|
|
bindKey: bindKey("Left", "Left|Ctrl-B"),
|
|
exec: function(editor, args) { editor.navigateLeft(args.times); },
|
|
multiSelectAction: "forEach",
|
|
scrollIntoView: "cursor",
|
|
readOnly: true
|
|
}, {
|
|
name: "selectwordright",
|
|
description: "Select word right",
|
|
bindKey: bindKey("Ctrl-Shift-Right", "Option-Shift-Right"),
|
|
exec: function(editor) { editor.getSelection().selectWordRight(); },
|
|
multiSelectAction: "forEach",
|
|
scrollIntoView: "cursor",
|
|
readOnly: true
|
|
}, {
|
|
name: "gotowordright",
|
|
description: "Go to word right",
|
|
bindKey: bindKey("Ctrl-Right", "Option-Right"),
|
|
exec: function(editor) { editor.navigateWordRight(); },
|
|
multiSelectAction: "forEach",
|
|
scrollIntoView: "cursor",
|
|
readOnly: true
|
|
}, {
|
|
name: "selecttolineend",
|
|
description: "Select to line end",
|
|
bindKey: bindKey("Alt-Shift-Right", "Command-Shift-Right|Shift-End|Ctrl-Shift-E"),
|
|
exec: function(editor) { editor.getSelection().selectLineEnd(); },
|
|
multiSelectAction: "forEach",
|
|
scrollIntoView: "cursor",
|
|
readOnly: true
|
|
}, {
|
|
name: "gotolineend",
|
|
description: "Go to line end",
|
|
bindKey: bindKey("Alt-Right|End", "Command-Right|End|Ctrl-E"),
|
|
exec: function(editor) { editor.navigateLineEnd(); },
|
|
multiSelectAction: "forEach",
|
|
scrollIntoView: "cursor",
|
|
readOnly: true
|
|
}, {
|
|
name: "selectright",
|
|
description: "Select right",
|
|
bindKey: bindKey("Shift-Right", "Shift-Right"),
|
|
exec: function(editor) { editor.getSelection().selectRight(); },
|
|
multiSelectAction: "forEach",
|
|
scrollIntoView: "cursor",
|
|
readOnly: true
|
|
}, {
|
|
name: "gotoright",
|
|
description: "Go to right",
|
|
bindKey: bindKey("Right", "Right|Ctrl-F"),
|
|
exec: function(editor, args) { editor.navigateRight(args.times); },
|
|
multiSelectAction: "forEach",
|
|
scrollIntoView: "cursor",
|
|
readOnly: true
|
|
}, {
|
|
name: "selectpagedown",
|
|
description: "Select page down",
|
|
bindKey: "Shift-PageDown",
|
|
exec: function(editor) { editor.selectPageDown(); },
|
|
readOnly: true
|
|
}, {
|
|
name: "pagedown",
|
|
description: "Page down",
|
|
bindKey: bindKey(null, "Option-PageDown"),
|
|
exec: function(editor) { editor.scrollPageDown(); },
|
|
readOnly: true
|
|
}, {
|
|
name: "gotopagedown",
|
|
description: "Go to page down",
|
|
bindKey: bindKey("PageDown", "PageDown|Ctrl-V"),
|
|
exec: function(editor) { editor.gotoPageDown(); },
|
|
readOnly: true
|
|
}, {
|
|
name: "selectpageup",
|
|
description: "Select page up",
|
|
bindKey: "Shift-PageUp",
|
|
exec: function(editor) { editor.selectPageUp(); },
|
|
readOnly: true
|
|
}, {
|
|
name: "pageup",
|
|
description: "Page up",
|
|
bindKey: bindKey(null, "Option-PageUp"),
|
|
exec: function(editor) { editor.scrollPageUp(); },
|
|
readOnly: true
|
|
}, {
|
|
name: "gotopageup",
|
|
description: "Go to page up",
|
|
bindKey: "PageUp",
|
|
exec: function(editor) { editor.gotoPageUp(); },
|
|
readOnly: true
|
|
}, {
|
|
name: "scrollup",
|
|
description: "Scroll up",
|
|
bindKey: bindKey("Ctrl-Up", null),
|
|
exec: function(e) { e.renderer.scrollBy(0, -2 * e.renderer.layerConfig.lineHeight); },
|
|
readOnly: true
|
|
}, {
|
|
name: "scrolldown",
|
|
description: "Scroll down",
|
|
bindKey: bindKey("Ctrl-Down", null),
|
|
exec: function(e) { e.renderer.scrollBy(0, 2 * e.renderer.layerConfig.lineHeight); },
|
|
readOnly: true
|
|
}, {
|
|
name: "selectlinestart",
|
|
description: "Select line start",
|
|
bindKey: "Shift-Home",
|
|
exec: function(editor) { editor.getSelection().selectLineStart(); },
|
|
multiSelectAction: "forEach",
|
|
scrollIntoView: "cursor",
|
|
readOnly: true
|
|
}, {
|
|
name: "selectlineend",
|
|
description: "Select line end",
|
|
bindKey: "Shift-End",
|
|
exec: function(editor) { editor.getSelection().selectLineEnd(); },
|
|
multiSelectAction: "forEach",
|
|
scrollIntoView: "cursor",
|
|
readOnly: true
|
|
}, {
|
|
name: "togglerecording",
|
|
description: "Toggle recording",
|
|
bindKey: bindKey("Ctrl-Alt-E", "Command-Option-E"),
|
|
exec: function(editor) { editor.commands.toggleRecording(editor); },
|
|
readOnly: true
|
|
}, {
|
|
name: "replaymacro",
|
|
description: "Replay macro",
|
|
bindKey: bindKey("Ctrl-Shift-E", "Command-Shift-E"),
|
|
exec: function(editor) { editor.commands.replay(editor); },
|
|
readOnly: true
|
|
}, {
|
|
name: "jumptomatching",
|
|
description: "Jump to matching",
|
|
bindKey: bindKey("Ctrl-\\|Ctrl-P", "Command-\\"),
|
|
exec: function(editor) { editor.jumpToMatching(); },
|
|
multiSelectAction: "forEach",
|
|
scrollIntoView: "animate",
|
|
readOnly: true
|
|
}, {
|
|
name: "selecttomatching",
|
|
description: "Select to matching",
|
|
bindKey: bindKey("Ctrl-Shift-\\|Ctrl-Shift-P", "Command-Shift-\\"),
|
|
exec: function(editor) { editor.jumpToMatching(true); },
|
|
multiSelectAction: "forEach",
|
|
scrollIntoView: "animate",
|
|
readOnly: true
|
|
}, {
|
|
name: "expandToMatching",
|
|
description: "Expand to matching",
|
|
bindKey: bindKey("Ctrl-Shift-M", "Ctrl-Shift-M"),
|
|
exec: function(editor) { editor.jumpToMatching(true, true); },
|
|
multiSelectAction: "forEach",
|
|
scrollIntoView: "animate",
|
|
readOnly: true
|
|
}, {
|
|
name: "passKeysToBrowser",
|
|
description: "Pass keys to browser",
|
|
bindKey: bindKey(null, null),
|
|
exec: function() {},
|
|
passEvent: true,
|
|
readOnly: true
|
|
}, {
|
|
name: "copy",
|
|
description: "Copy",
|
|
exec: function(editor) {
|
|
},
|
|
readOnly: true
|
|
},
|
|
{
|
|
name: "cut",
|
|
description: "Cut",
|
|
exec: function(editor) {
|
|
var cutLine = editor.$copyWithEmptySelection && editor.selection.isEmpty();
|
|
var range = cutLine ? editor.selection.getLineRange() : editor.selection.getRange();
|
|
editor._emit("cut", range);
|
|
|
|
if (!range.isEmpty())
|
|
editor.session.remove(range);
|
|
editor.clearSelection();
|
|
},
|
|
scrollIntoView: "cursor",
|
|
multiSelectAction: "forEach"
|
|
}, {
|
|
name: "paste",
|
|
description: "Paste",
|
|
exec: function(editor, args) {
|
|
editor.$handlePaste(args);
|
|
},
|
|
scrollIntoView: "cursor"
|
|
}, {
|
|
name: "removeline",
|
|
description: "Remove line",
|
|
bindKey: bindKey("Ctrl-D", "Command-D"),
|
|
exec: function(editor) { editor.removeLines(); },
|
|
scrollIntoView: "cursor",
|
|
multiSelectAction: "forEachLine"
|
|
}, {
|
|
name: "duplicateSelection",
|
|
description: "Duplicate selection",
|
|
bindKey: bindKey("Ctrl-Shift-D", "Command-Shift-D"),
|
|
exec: function(editor) { editor.duplicateSelection(); },
|
|
scrollIntoView: "cursor",
|
|
multiSelectAction: "forEach"
|
|
}, {
|
|
name: "sortlines",
|
|
description: "Sort lines",
|
|
bindKey: bindKey("Ctrl-Alt-S", "Command-Alt-S"),
|
|
exec: function(editor) { editor.sortLines(); },
|
|
scrollIntoView: "selection",
|
|
multiSelectAction: "forEachLine"
|
|
}, {
|
|
name: "togglecomment",
|
|
description: "Toggle comment",
|
|
bindKey: bindKey("Ctrl-/", "Command-/"),
|
|
exec: function(editor) { editor.toggleCommentLines(); },
|
|
multiSelectAction: "forEachLine",
|
|
scrollIntoView: "selectionPart"
|
|
}, {
|
|
name: "toggleBlockComment",
|
|
description: "Toggle block comment",
|
|
bindKey: bindKey("Ctrl-Shift-/", "Command-Shift-/"),
|
|
exec: function(editor) { editor.toggleBlockComment(); },
|
|
multiSelectAction: "forEach",
|
|
scrollIntoView: "selectionPart"
|
|
}, {
|
|
name: "modifyNumberUp",
|
|
description: "Modify number up",
|
|
bindKey: bindKey("Ctrl-Shift-Up", "Alt-Shift-Up"),
|
|
exec: function(editor) { editor.modifyNumber(1); },
|
|
scrollIntoView: "cursor",
|
|
multiSelectAction: "forEach"
|
|
}, {
|
|
name: "modifyNumberDown",
|
|
description: "Modify number down",
|
|
bindKey: bindKey("Ctrl-Shift-Down", "Alt-Shift-Down"),
|
|
exec: function(editor) { editor.modifyNumber(-1); },
|
|
scrollIntoView: "cursor",
|
|
multiSelectAction: "forEach"
|
|
}, {
|
|
name: "replace",
|
|
description: "Replace",
|
|
bindKey: bindKey("Ctrl-H", "Command-Option-F"),
|
|
exec: function(editor) {
|
|
config.loadModule("ace/ext/searchbox", function(e) {e.Search(editor, true);});
|
|
}
|
|
}, {
|
|
name: "undo",
|
|
description: "Undo",
|
|
bindKey: bindKey("Ctrl-Z", "Command-Z"),
|
|
exec: function(editor) { editor.undo(); }
|
|
}, {
|
|
name: "redo",
|
|
description: "Redo",
|
|
bindKey: bindKey("Ctrl-Shift-Z|Ctrl-Y", "Command-Shift-Z|Command-Y"),
|
|
exec: function(editor) { editor.redo(); }
|
|
}, {
|
|
name: "copylinesup",
|
|
description: "Copy lines up",
|
|
bindKey: bindKey("Alt-Shift-Up", "Command-Option-Up"),
|
|
exec: function(editor) { editor.copyLinesUp(); },
|
|
scrollIntoView: "cursor"
|
|
}, {
|
|
name: "movelinesup",
|
|
description: "Move lines up",
|
|
bindKey: bindKey("Alt-Up", "Option-Up"),
|
|
exec: function(editor) { editor.moveLinesUp(); },
|
|
scrollIntoView: "cursor"
|
|
}, {
|
|
name: "copylinesdown",
|
|
description: "Copy lines down",
|
|
bindKey: bindKey("Alt-Shift-Down", "Command-Option-Down"),
|
|
exec: function(editor) { editor.copyLinesDown(); },
|
|
scrollIntoView: "cursor"
|
|
}, {
|
|
name: "movelinesdown",
|
|
description: "Move lines down",
|
|
bindKey: bindKey("Alt-Down", "Option-Down"),
|
|
exec: function(editor) { editor.moveLinesDown(); },
|
|
scrollIntoView: "cursor"
|
|
}, {
|
|
name: "del",
|
|
description: "Delete",
|
|
bindKey: bindKey("Delete", "Delete|Ctrl-D|Shift-Delete"),
|
|
exec: function(editor) { editor.remove("right"); },
|
|
multiSelectAction: "forEach",
|
|
scrollIntoView: "cursor"
|
|
}, {
|
|
name: "backspace",
|
|
description: "Backspace",
|
|
bindKey: bindKey(
|
|
"Shift-Backspace|Backspace",
|
|
"Ctrl-Backspace|Shift-Backspace|Backspace|Ctrl-H"
|
|
),
|
|
exec: function(editor) { editor.remove("left"); },
|
|
multiSelectAction: "forEach",
|
|
scrollIntoView: "cursor"
|
|
}, {
|
|
name: "cut_or_delete",
|
|
description: "Cut or delete",
|
|
bindKey: bindKey("Shift-Delete", null),
|
|
exec: function(editor) {
|
|
if (editor.selection.isEmpty()) {
|
|
editor.remove("left");
|
|
} else {
|
|
return false;
|
|
}
|
|
},
|
|
multiSelectAction: "forEach",
|
|
scrollIntoView: "cursor"
|
|
}, {
|
|
name: "removetolinestart",
|
|
description: "Remove to line start",
|
|
bindKey: bindKey("Alt-Backspace", "Command-Backspace"),
|
|
exec: function(editor) { editor.removeToLineStart(); },
|
|
multiSelectAction: "forEach",
|
|
scrollIntoView: "cursor"
|
|
}, {
|
|
name: "removetolineend",
|
|
description: "Remove to line end",
|
|
bindKey: bindKey("Alt-Delete", "Ctrl-K|Command-Delete"),
|
|
exec: function(editor) { editor.removeToLineEnd(); },
|
|
multiSelectAction: "forEach",
|
|
scrollIntoView: "cursor"
|
|
}, {
|
|
name: "removetolinestarthard",
|
|
description: "Remove to line start hard",
|
|
bindKey: bindKey("Ctrl-Shift-Backspace", null),
|
|
exec: function(editor) {
|
|
var range = editor.selection.getRange();
|
|
range.start.column = 0;
|
|
editor.session.remove(range);
|
|
},
|
|
multiSelectAction: "forEach",
|
|
scrollIntoView: "cursor"
|
|
}, {
|
|
name: "removetolineendhard",
|
|
description: "Remove to line end hard",
|
|
bindKey: bindKey("Ctrl-Shift-Delete", null),
|
|
exec: function(editor) {
|
|
var range = editor.selection.getRange();
|
|
range.end.column = Number.MAX_VALUE;
|
|
editor.session.remove(range);
|
|
},
|
|
multiSelectAction: "forEach",
|
|
scrollIntoView: "cursor"
|
|
}, {
|
|
name: "removewordleft",
|
|
description: "Remove word left",
|
|
bindKey: bindKey("Ctrl-Backspace", "Alt-Backspace|Ctrl-Alt-Backspace"),
|
|
exec: function(editor) { editor.removeWordLeft(); },
|
|
multiSelectAction: "forEach",
|
|
scrollIntoView: "cursor"
|
|
}, {
|
|
name: "removewordright",
|
|
description: "Remove word right",
|
|
bindKey: bindKey("Ctrl-Delete", "Alt-Delete"),
|
|
exec: function(editor) { editor.removeWordRight(); },
|
|
multiSelectAction: "forEach",
|
|
scrollIntoView: "cursor"
|
|
}, {
|
|
name: "outdent",
|
|
description: "Outdent",
|
|
bindKey: bindKey("Shift-Tab", "Shift-Tab"),
|
|
exec: function(editor) { editor.blockOutdent(); },
|
|
multiSelectAction: "forEach",
|
|
scrollIntoView: "selectionPart"
|
|
}, {
|
|
name: "indent",
|
|
description: "Indent",
|
|
bindKey: bindKey("Tab", "Tab"),
|
|
exec: function(editor) { editor.indent(); },
|
|
multiSelectAction: "forEach",
|
|
scrollIntoView: "selectionPart"
|
|
}, {
|
|
name: "blockoutdent",
|
|
description: "Block outdent",
|
|
bindKey: bindKey("Ctrl-[", "Ctrl-["),
|
|
exec: function(editor) { editor.blockOutdent(); },
|
|
multiSelectAction: "forEachLine",
|
|
scrollIntoView: "selectionPart"
|
|
}, {
|
|
name: "blockindent",
|
|
description: "Block indent",
|
|
bindKey: bindKey("Ctrl-]", "Ctrl-]"),
|
|
exec: function(editor) { editor.blockIndent(); },
|
|
multiSelectAction: "forEachLine",
|
|
scrollIntoView: "selectionPart"
|
|
}, {
|
|
name: "insertstring",
|
|
description: "Insert string",
|
|
exec: function(editor, str) { editor.insert(str); },
|
|
multiSelectAction: "forEach",
|
|
scrollIntoView: "cursor"
|
|
}, {
|
|
name: "inserttext",
|
|
description: "Insert text",
|
|
exec: function(editor, args) {
|
|
editor.insert(lang.stringRepeat(args.text || "", args.times || 1));
|
|
},
|
|
multiSelectAction: "forEach",
|
|
scrollIntoView: "cursor"
|
|
}, {
|
|
name: "splitline",
|
|
description: "Split line",
|
|
bindKey: bindKey(null, "Ctrl-O"),
|
|
exec: function(editor) { editor.splitLine(); },
|
|
multiSelectAction: "forEach",
|
|
scrollIntoView: "cursor"
|
|
}, {
|
|
name: "transposeletters",
|
|
description: "Transpose letters",
|
|
bindKey: bindKey("Alt-Shift-X", "Ctrl-T"),
|
|
exec: function(editor) { editor.transposeLetters(); },
|
|
multiSelectAction: function(editor) {editor.transposeSelections(1); },
|
|
scrollIntoView: "cursor"
|
|
}, {
|
|
name: "touppercase",
|
|
description: "To uppercase",
|
|
bindKey: bindKey("Ctrl-U", "Ctrl-U"),
|
|
exec: function(editor) { editor.toUpperCase(); },
|
|
multiSelectAction: "forEach",
|
|
scrollIntoView: "cursor"
|
|
}, {
|
|
name: "tolowercase",
|
|
description: "To lowercase",
|
|
bindKey: bindKey("Ctrl-Shift-U", "Ctrl-Shift-U"),
|
|
exec: function(editor) { editor.toLowerCase(); },
|
|
multiSelectAction: "forEach",
|
|
scrollIntoView: "cursor"
|
|
}, {
|
|
name: "autoindent",
|
|
description: "Auto Indent",
|
|
bindKey: bindKey(null, null),
|
|
exec: function(editor) { editor.autoIndent(); },
|
|
multiSelectAction: "forEachLine",
|
|
scrollIntoView: "animate"
|
|
}, {
|
|
name: "expandtoline",
|
|
description: "Expand to line",
|
|
bindKey: bindKey("Ctrl-Shift-L", "Command-Shift-L"),
|
|
exec: function(editor) {
|
|
var range = editor.selection.getRange();
|
|
|
|
range.start.column = range.end.column = 0;
|
|
range.end.row++;
|
|
editor.selection.setRange(range, false);
|
|
},
|
|
multiSelectAction: "forEach",
|
|
scrollIntoView: "cursor",
|
|
readOnly: true
|
|
}, {
|
|
name: "joinlines",
|
|
description: "Join lines",
|
|
bindKey: bindKey(null, null),
|
|
exec: function(editor) {
|
|
var isBackwards = editor.selection.isBackwards();
|
|
var selectionStart = isBackwards ? editor.selection.getSelectionLead() : editor.selection.getSelectionAnchor();
|
|
var selectionEnd = isBackwards ? editor.selection.getSelectionAnchor() : editor.selection.getSelectionLead();
|
|
var firstLineEndCol = editor.session.doc.getLine(selectionStart.row).length;
|
|
var selectedText = editor.session.doc.getTextRange(editor.selection.getRange());
|
|
var selectedCount = selectedText.replace(/\n\s*/, " ").length;
|
|
var insertLine = editor.session.doc.getLine(selectionStart.row);
|
|
|
|
for (var i = selectionStart.row + 1; i <= selectionEnd.row + 1; i++) {
|
|
var curLine = lang.stringTrimLeft(lang.stringTrimRight(editor.session.doc.getLine(i)));
|
|
if (curLine.length !== 0) {
|
|
curLine = " " + curLine;
|
|
}
|
|
insertLine += curLine;
|
|
}
|
|
|
|
if (selectionEnd.row + 1 < (editor.session.doc.getLength() - 1)) {
|
|
insertLine += editor.session.doc.getNewLineCharacter();
|
|
}
|
|
|
|
editor.clearSelection();
|
|
editor.session.doc.replace(new Range(selectionStart.row, 0, selectionEnd.row + 2, 0), insertLine);
|
|
|
|
if (selectedCount > 0) {
|
|
editor.selection.moveCursorTo(selectionStart.row, selectionStart.column);
|
|
editor.selection.selectTo(selectionStart.row, selectionStart.column + selectedCount);
|
|
} else {
|
|
firstLineEndCol = editor.session.doc.getLine(selectionStart.row).length > firstLineEndCol ? (firstLineEndCol + 1) : firstLineEndCol;
|
|
editor.selection.moveCursorTo(selectionStart.row, firstLineEndCol);
|
|
}
|
|
},
|
|
multiSelectAction: "forEach",
|
|
readOnly: true
|
|
}, {
|
|
name: "invertSelection",
|
|
description: "Invert selection",
|
|
bindKey: bindKey(null, null),
|
|
exec: function(editor) {
|
|
var endRow = editor.session.doc.getLength() - 1;
|
|
var endCol = editor.session.doc.getLine(endRow).length;
|
|
var ranges = editor.selection.rangeList.ranges;
|
|
var newRanges = [];
|
|
if (ranges.length < 1) {
|
|
ranges = [editor.selection.getRange()];
|
|
}
|
|
|
|
for (var i = 0; i < ranges.length; i++) {
|
|
if (i == (ranges.length - 1)) {
|
|
if (!(ranges[i].end.row === endRow && ranges[i].end.column === endCol)) {
|
|
newRanges.push(new Range(ranges[i].end.row, ranges[i].end.column, endRow, endCol));
|
|
}
|
|
}
|
|
|
|
if (i === 0) {
|
|
if (!(ranges[i].start.row === 0 && ranges[i].start.column === 0)) {
|
|
newRanges.push(new Range(0, 0, ranges[i].start.row, ranges[i].start.column));
|
|
}
|
|
} else {
|
|
newRanges.push(new Range(ranges[i-1].end.row, ranges[i-1].end.column, ranges[i].start.row, ranges[i].start.column));
|
|
}
|
|
}
|
|
|
|
editor.exitMultiSelectMode();
|
|
editor.clearSelection();
|
|
|
|
for(var i = 0; i < newRanges.length; i++) {
|
|
editor.selection.addRange(newRanges[i], false);
|
|
}
|
|
},
|
|
readOnly: true,
|
|
scrollIntoView: "none"
|
|
}, {
|
|
name: "addLineAfter",
|
|
exec: function(editor) {
|
|
editor.selection.clearSelection();
|
|
editor.navigateLineEnd();
|
|
editor.insert("\n");
|
|
},
|
|
multiSelectAction: "forEach",
|
|
scrollIntoView: "cursor"
|
|
}, {
|
|
name: "addLineBefore",
|
|
exec: function(editor) {
|
|
editor.selection.clearSelection();
|
|
var cursor = editor.getCursorPosition();
|
|
editor.selection.moveTo(cursor.row - 1, Number.MAX_VALUE);
|
|
editor.insert("\n");
|
|
if (cursor.row === 0) editor.navigateUp();
|
|
},
|
|
multiSelectAction: "forEach",
|
|
scrollIntoView: "cursor"
|
|
}, {
|
|
name: "openCommandPallete",
|
|
description: "Open command pallete",
|
|
bindKey: bindKey("F1", "F1"),
|
|
exec: function(editor) {
|
|
editor.prompt({ $type: "commands" });
|
|
},
|
|
readOnly: true
|
|
}, {
|
|
name: "modeSelect",
|
|
description: "Change language mode...",
|
|
bindKey: bindKey(null, null),
|
|
exec: function(editor) {
|
|
editor.prompt({ $type: "modes" });
|
|
},
|
|
readOnly: true
|
|
}];
|
|
|
|
for (var i = 1; i < 9; i++) {
|
|
exports.commands.push({
|
|
name: "foldToLevel" + i,
|
|
description: "Fold To Level " + i,
|
|
level: i,
|
|
exec: function(editor) { editor.session.foldToLevel(this.level); },
|
|
scrollIntoView: "center",
|
|
readOnly: true
|
|
});
|
|
}
|
|
|
|
});
|
|
|
|
ace.define("ace/editor",["require","exports","module","ace/lib/fixoldbrowsers","ace/lib/oop","ace/lib/dom","ace/lib/lang","ace/lib/useragent","ace/keyboard/textinput","ace/mouse/mouse_handler","ace/mouse/fold_handler","ace/keyboard/keybinding","ace/edit_session","ace/search","ace/range","ace/lib/event_emitter","ace/commands/command_manager","ace/commands/default_commands","ace/config","ace/token_iterator","ace/clipboard"], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
require("./lib/fixoldbrowsers");
|
|
|
|
var oop = require("./lib/oop");
|
|
var dom = require("./lib/dom");
|
|
var lang = require("./lib/lang");
|
|
var useragent = require("./lib/useragent");
|
|
var TextInput = require("./keyboard/textinput").TextInput;
|
|
var MouseHandler = require("./mouse/mouse_handler").MouseHandler;
|
|
var FoldHandler = require("./mouse/fold_handler").FoldHandler;
|
|
var KeyBinding = require("./keyboard/keybinding").KeyBinding;
|
|
var EditSession = require("./edit_session").EditSession;
|
|
var Search = require("./search").Search;
|
|
var Range = require("./range").Range;
|
|
var EventEmitter = require("./lib/event_emitter").EventEmitter;
|
|
var CommandManager = require("./commands/command_manager").CommandManager;
|
|
var defaultCommands = require("./commands/default_commands").commands;
|
|
var config = require("./config");
|
|
var TokenIterator = require("./token_iterator").TokenIterator;
|
|
|
|
var clipboard = require("./clipboard");
|
|
var Editor = function(renderer, session, options) {
|
|
this.$toDestroy = [];
|
|
var container = renderer.getContainerElement();
|
|
this.container = container;
|
|
this.renderer = renderer;
|
|
this.id = "editor" + (++Editor.$uid);
|
|
|
|
this.commands = new CommandManager(useragent.isMac ? "mac" : "win", defaultCommands);
|
|
if (typeof document == "object") {
|
|
this.textInput = new TextInput(renderer.getTextAreaContainer(), this);
|
|
this.renderer.textarea = this.textInput.getElement();
|
|
this.$mouseHandler = new MouseHandler(this);
|
|
new FoldHandler(this);
|
|
}
|
|
|
|
this.keyBinding = new KeyBinding(this);
|
|
|
|
this.$search = new Search().set({
|
|
wrap: true
|
|
});
|
|
|
|
this.$historyTracker = this.$historyTracker.bind(this);
|
|
this.commands.on("exec", this.$historyTracker);
|
|
|
|
this.$initOperationListeners();
|
|
|
|
this._$emitInputEvent = lang.delayedCall(function() {
|
|
this._signal("input", {});
|
|
if (this.session && this.session.bgTokenizer)
|
|
this.session.bgTokenizer.scheduleStart();
|
|
}.bind(this));
|
|
|
|
this.on("change", function(_, _self) {
|
|
_self._$emitInputEvent.schedule(31);
|
|
});
|
|
|
|
this.setSession(session || options && options.session || new EditSession(""));
|
|
config.resetOptions(this);
|
|
if (options)
|
|
this.setOptions(options);
|
|
config._signal("editor", this);
|
|
};
|
|
|
|
Editor.$uid = 0;
|
|
|
|
(function(){
|
|
|
|
oop.implement(this, EventEmitter);
|
|
|
|
this.$initOperationListeners = function() {
|
|
this.commands.on("exec", this.startOperation.bind(this), true);
|
|
this.commands.on("afterExec", this.endOperation.bind(this), true);
|
|
|
|
this.$opResetTimer = lang.delayedCall(this.endOperation.bind(this, true));
|
|
this.on("change", function() {
|
|
if (!this.curOp) {
|
|
this.startOperation();
|
|
this.curOp.selectionBefore = this.$lastSel;
|
|
}
|
|
this.curOp.docChanged = true;
|
|
}.bind(this), true);
|
|
|
|
this.on("changeSelection", function() {
|
|
if (!this.curOp) {
|
|
this.startOperation();
|
|
this.curOp.selectionBefore = this.$lastSel;
|
|
}
|
|
this.curOp.selectionChanged = true;
|
|
}.bind(this), true);
|
|
};
|
|
|
|
this.curOp = null;
|
|
this.prevOp = {};
|
|
this.startOperation = function(commandEvent) {
|
|
if (this.curOp) {
|
|
if (!commandEvent || this.curOp.command)
|
|
return;
|
|
this.prevOp = this.curOp;
|
|
}
|
|
if (!commandEvent) {
|
|
this.previousCommand = null;
|
|
commandEvent = {};
|
|
}
|
|
|
|
this.$opResetTimer.schedule();
|
|
this.curOp = this.session.curOp = {
|
|
command: commandEvent.command || {},
|
|
args: commandEvent.args,
|
|
scrollTop: this.renderer.scrollTop
|
|
};
|
|
this.curOp.selectionBefore = this.selection.toJSON();
|
|
};
|
|
|
|
this.endOperation = function(e) {
|
|
if (this.curOp && this.session) {
|
|
if (e && e.returnValue === false || !this.session)
|
|
return (this.curOp = null);
|
|
if (e == true && this.curOp.command && this.curOp.command.name == "mouse")
|
|
return;
|
|
this._signal("beforeEndOperation");
|
|
if (!this.curOp) return;
|
|
var command = this.curOp.command;
|
|
var scrollIntoView = command && command.scrollIntoView;
|
|
if (scrollIntoView) {
|
|
switch (scrollIntoView) {
|
|
case "center-animate":
|
|
scrollIntoView = "animate";
|
|
case "center":
|
|
this.renderer.scrollCursorIntoView(null, 0.5);
|
|
break;
|
|
case "animate":
|
|
case "cursor":
|
|
this.renderer.scrollCursorIntoView();
|
|
break;
|
|
case "selectionPart":
|
|
var range = this.selection.getRange();
|
|
var config = this.renderer.layerConfig;
|
|
if (range.start.row >= config.lastRow || range.end.row <= config.firstRow) {
|
|
this.renderer.scrollSelectionIntoView(this.selection.anchor, this.selection.lead);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if (scrollIntoView == "animate")
|
|
this.renderer.animateScrolling(this.curOp.scrollTop);
|
|
}
|
|
var sel = this.selection.toJSON();
|
|
this.curOp.selectionAfter = sel;
|
|
this.$lastSel = this.selection.toJSON();
|
|
this.session.getUndoManager().addSelection(sel);
|
|
this.prevOp = this.curOp;
|
|
this.curOp = null;
|
|
}
|
|
};
|
|
this.$mergeableCommands = ["backspace", "del", "insertstring"];
|
|
this.$historyTracker = function(e) {
|
|
if (!this.$mergeUndoDeltas)
|
|
return;
|
|
|
|
var prev = this.prevOp;
|
|
var mergeableCommands = this.$mergeableCommands;
|
|
var shouldMerge = prev.command && (e.command.name == prev.command.name);
|
|
if (e.command.name == "insertstring") {
|
|
var text = e.args;
|
|
if (this.mergeNextCommand === undefined)
|
|
this.mergeNextCommand = true;
|
|
|
|
shouldMerge = shouldMerge
|
|
&& this.mergeNextCommand // previous command allows to coalesce with
|
|
&& (!/\s/.test(text) || /\s/.test(prev.args)); // previous insertion was of same type
|
|
|
|
this.mergeNextCommand = true;
|
|
} else {
|
|
shouldMerge = shouldMerge
|
|
&& mergeableCommands.indexOf(e.command.name) !== -1; // the command is mergeable
|
|
}
|
|
|
|
if (
|
|
this.$mergeUndoDeltas != "always"
|
|
&& Date.now() - this.sequenceStartTime > 2000
|
|
) {
|
|
shouldMerge = false; // the sequence is too long
|
|
}
|
|
|
|
if (shouldMerge)
|
|
this.session.mergeUndoDeltas = true;
|
|
else if (mergeableCommands.indexOf(e.command.name) !== -1)
|
|
this.sequenceStartTime = Date.now();
|
|
};
|
|
this.setKeyboardHandler = function(keyboardHandler, cb) {
|
|
if (keyboardHandler && typeof keyboardHandler === "string" && keyboardHandler != "ace") {
|
|
this.$keybindingId = keyboardHandler;
|
|
var _self = this;
|
|
config.loadModule(["keybinding", keyboardHandler], function(module) {
|
|
if (_self.$keybindingId == keyboardHandler)
|
|
_self.keyBinding.setKeyboardHandler(module && module.handler);
|
|
cb && cb();
|
|
});
|
|
} else {
|
|
this.$keybindingId = null;
|
|
this.keyBinding.setKeyboardHandler(keyboardHandler);
|
|
cb && cb();
|
|
}
|
|
};
|
|
this.getKeyboardHandler = function() {
|
|
return this.keyBinding.getKeyboardHandler();
|
|
};
|
|
this.setSession = function(session) {
|
|
if (this.session == session)
|
|
return;
|
|
if (this.curOp) this.endOperation();
|
|
this.curOp = {};
|
|
|
|
var oldSession = this.session;
|
|
if (oldSession) {
|
|
this.session.off("change", this.$onDocumentChange);
|
|
this.session.off("changeMode", this.$onChangeMode);
|
|
this.session.off("tokenizerUpdate", this.$onTokenizerUpdate);
|
|
this.session.off("changeTabSize", this.$onChangeTabSize);
|
|
this.session.off("changeWrapLimit", this.$onChangeWrapLimit);
|
|
this.session.off("changeWrapMode", this.$onChangeWrapMode);
|
|
this.session.off("changeFold", this.$onChangeFold);
|
|
this.session.off("changeFrontMarker", this.$onChangeFrontMarker);
|
|
this.session.off("changeBackMarker", this.$onChangeBackMarker);
|
|
this.session.off("changeBreakpoint", this.$onChangeBreakpoint);
|
|
this.session.off("changeAnnotation", this.$onChangeAnnotation);
|
|
this.session.off("changeOverwrite", this.$onCursorChange);
|
|
this.session.off("changeScrollTop", this.$onScrollTopChange);
|
|
this.session.off("changeScrollLeft", this.$onScrollLeftChange);
|
|
|
|
var selection = this.session.getSelection();
|
|
selection.off("changeCursor", this.$onCursorChange);
|
|
selection.off("changeSelection", this.$onSelectionChange);
|
|
}
|
|
|
|
this.session = session;
|
|
if (session) {
|
|
this.$onDocumentChange = this.onDocumentChange.bind(this);
|
|
session.on("change", this.$onDocumentChange);
|
|
this.renderer.setSession(session);
|
|
|
|
this.$onChangeMode = this.onChangeMode.bind(this);
|
|
session.on("changeMode", this.$onChangeMode);
|
|
|
|
this.$onTokenizerUpdate = this.onTokenizerUpdate.bind(this);
|
|
session.on("tokenizerUpdate", this.$onTokenizerUpdate);
|
|
|
|
this.$onChangeTabSize = this.renderer.onChangeTabSize.bind(this.renderer);
|
|
session.on("changeTabSize", this.$onChangeTabSize);
|
|
|
|
this.$onChangeWrapLimit = this.onChangeWrapLimit.bind(this);
|
|
session.on("changeWrapLimit", this.$onChangeWrapLimit);
|
|
|
|
this.$onChangeWrapMode = this.onChangeWrapMode.bind(this);
|
|
session.on("changeWrapMode", this.$onChangeWrapMode);
|
|
|
|
this.$onChangeFold = this.onChangeFold.bind(this);
|
|
session.on("changeFold", this.$onChangeFold);
|
|
|
|
this.$onChangeFrontMarker = this.onChangeFrontMarker.bind(this);
|
|
this.session.on("changeFrontMarker", this.$onChangeFrontMarker);
|
|
|
|
this.$onChangeBackMarker = this.onChangeBackMarker.bind(this);
|
|
this.session.on("changeBackMarker", this.$onChangeBackMarker);
|
|
|
|
this.$onChangeBreakpoint = this.onChangeBreakpoint.bind(this);
|
|
this.session.on("changeBreakpoint", this.$onChangeBreakpoint);
|
|
|
|
this.$onChangeAnnotation = this.onChangeAnnotation.bind(this);
|
|
this.session.on("changeAnnotation", this.$onChangeAnnotation);
|
|
|
|
this.$onCursorChange = this.onCursorChange.bind(this);
|
|
this.session.on("changeOverwrite", this.$onCursorChange);
|
|
|
|
this.$onScrollTopChange = this.onScrollTopChange.bind(this);
|
|
this.session.on("changeScrollTop", this.$onScrollTopChange);
|
|
|
|
this.$onScrollLeftChange = this.onScrollLeftChange.bind(this);
|
|
this.session.on("changeScrollLeft", this.$onScrollLeftChange);
|
|
|
|
this.selection = session.getSelection();
|
|
this.selection.on("changeCursor", this.$onCursorChange);
|
|
|
|
this.$onSelectionChange = this.onSelectionChange.bind(this);
|
|
this.selection.on("changeSelection", this.$onSelectionChange);
|
|
|
|
this.onChangeMode();
|
|
|
|
this.onCursorChange();
|
|
|
|
this.onScrollTopChange();
|
|
this.onScrollLeftChange();
|
|
this.onSelectionChange();
|
|
this.onChangeFrontMarker();
|
|
this.onChangeBackMarker();
|
|
this.onChangeBreakpoint();
|
|
this.onChangeAnnotation();
|
|
this.session.getUseWrapMode() && this.renderer.adjustWrapLimit();
|
|
this.renderer.updateFull();
|
|
} else {
|
|
this.selection = null;
|
|
this.renderer.setSession(session);
|
|
}
|
|
|
|
this._signal("changeSession", {
|
|
session: session,
|
|
oldSession: oldSession
|
|
});
|
|
|
|
this.curOp = null;
|
|
|
|
oldSession && oldSession._signal("changeEditor", {oldEditor: this});
|
|
session && session._signal("changeEditor", {editor: this});
|
|
|
|
if (session && session.bgTokenizer)
|
|
session.bgTokenizer.scheduleStart();
|
|
};
|
|
this.getSession = function() {
|
|
return this.session;
|
|
};
|
|
this.setValue = function(val, cursorPos) {
|
|
this.session.doc.setValue(val);
|
|
|
|
if (!cursorPos)
|
|
this.selectAll();
|
|
else if (cursorPos == 1)
|
|
this.navigateFileEnd();
|
|
else if (cursorPos == -1)
|
|
this.navigateFileStart();
|
|
|
|
return val;
|
|
};
|
|
this.getValue = function() {
|
|
return this.session.getValue();
|
|
};
|
|
this.getSelection = function() {
|
|
return this.selection;
|
|
};
|
|
this.resize = function(force) {
|
|
this.renderer.onResize(force);
|
|
};
|
|
this.setTheme = function(theme, cb) {
|
|
this.renderer.setTheme(theme, cb);
|
|
};
|
|
this.getTheme = function() {
|
|
return this.renderer.getTheme();
|
|
};
|
|
this.setStyle = function(style) {
|
|
this.renderer.setStyle(style);
|
|
};
|
|
this.unsetStyle = function(style) {
|
|
this.renderer.unsetStyle(style);
|
|
};
|
|
this.getFontSize = function () {
|
|
return this.getOption("fontSize") ||
|
|
dom.computedStyle(this.container).fontSize;
|
|
};
|
|
this.setFontSize = function(size) {
|
|
this.setOption("fontSize", size);
|
|
};
|
|
|
|
this.$highlightBrackets = function() {
|
|
if (this.$highlightPending) {
|
|
return;
|
|
}
|
|
var self = this;
|
|
this.$highlightPending = true;
|
|
setTimeout(function () {
|
|
self.$highlightPending = false;
|
|
var session = self.session;
|
|
if (!session || !session.bgTokenizer) return;
|
|
if (session.$bracketHighlight) {
|
|
session.$bracketHighlight.markerIds.forEach(function(id) {
|
|
session.removeMarker(id);
|
|
});
|
|
session.$bracketHighlight = null;
|
|
}
|
|
var ranges = session.getMatchingBracketRanges(self.getCursorPosition());
|
|
if (!ranges && session.$mode.getMatching)
|
|
ranges = session.$mode.getMatching(self.session);
|
|
if (!ranges)
|
|
return;
|
|
|
|
var markerType = "ace_bracket";
|
|
if (!Array.isArray(ranges)) {
|
|
ranges = [ranges];
|
|
} else if (ranges.length == 1) {
|
|
markerType = "ace_error_bracket";
|
|
}
|
|
if (ranges.length == 2) {
|
|
if (Range.comparePoints(ranges[0].end, ranges[1].start) == 0)
|
|
ranges = [Range.fromPoints(ranges[0].start, ranges[1].end)];
|
|
else if (Range.comparePoints(ranges[0].start, ranges[1].end) == 0)
|
|
ranges = [Range.fromPoints(ranges[1].start, ranges[0].end)];
|
|
}
|
|
|
|
session.$bracketHighlight = {
|
|
ranges: ranges,
|
|
markerIds: ranges.map(function(range) {
|
|
return session.addMarker(range, markerType, "text");
|
|
})
|
|
};
|
|
}, 50);
|
|
};
|
|
this.$highlightTags = function() {
|
|
if (this.$highlightTagPending)
|
|
return;
|
|
var self = this;
|
|
this.$highlightTagPending = true;
|
|
setTimeout(function() {
|
|
self.$highlightTagPending = false;
|
|
|
|
var session = self.session;
|
|
if (!session || !session.bgTokenizer) return;
|
|
|
|
var pos = self.getCursorPosition();
|
|
var iterator = new TokenIterator(self.session, pos.row, pos.column);
|
|
var token = iterator.getCurrentToken();
|
|
|
|
if (!token || !/\b(?:tag-open|tag-name)/.test(token.type)) {
|
|
session.removeMarker(session.$tagHighlight);
|
|
session.$tagHighlight = null;
|
|
return;
|
|
}
|
|
|
|
if (token.type.indexOf("tag-open") !== -1) {
|
|
token = iterator.stepForward();
|
|
if (!token)
|
|
return;
|
|
}
|
|
|
|
var tag = token.value;
|
|
var currentTag = token.value;
|
|
var depth = 0;
|
|
var prevToken = iterator.stepBackward();
|
|
|
|
if (prevToken.value === '<'){
|
|
do {
|
|
prevToken = token;
|
|
token = iterator.stepForward();
|
|
|
|
if (token) {
|
|
if (token.type.indexOf('tag-name') !== -1) {
|
|
currentTag = token.value;
|
|
if (tag === currentTag) {
|
|
if (prevToken.value === '<') {
|
|
depth++;
|
|
} else if (prevToken.value === '</') {
|
|
depth--;
|
|
}
|
|
}
|
|
} else if (tag === currentTag && token.value === '/>') { // self closing tag
|
|
depth--;
|
|
}
|
|
}
|
|
|
|
} while (token && depth >= 0);
|
|
} else {
|
|
do {
|
|
token = prevToken;
|
|
prevToken = iterator.stepBackward();
|
|
|
|
if (token) {
|
|
if (token.type.indexOf('tag-name') !== -1) {
|
|
if (tag === token.value) {
|
|
if (prevToken.value === '<') {
|
|
depth++;
|
|
} else if (prevToken.value === '</') {
|
|
depth--;
|
|
}
|
|
}
|
|
} else if (token.value === '/>') { // self closing tag
|
|
var stepCount = 0;
|
|
var tmpToken = prevToken;
|
|
while (tmpToken) {
|
|
if (tmpToken.type.indexOf('tag-name') !== -1 && tmpToken.value === tag) {
|
|
depth--;
|
|
break;
|
|
} else if (tmpToken.value === '<') {
|
|
break;
|
|
}
|
|
tmpToken = iterator.stepBackward();
|
|
stepCount++;
|
|
}
|
|
for (var i = 0; i < stepCount; i++) {
|
|
iterator.stepForward();
|
|
}
|
|
}
|
|
}
|
|
} while (prevToken && depth <= 0);
|
|
iterator.stepForward();
|
|
}
|
|
|
|
if (!token) {
|
|
session.removeMarker(session.$tagHighlight);
|
|
session.$tagHighlight = null;
|
|
return;
|
|
}
|
|
|
|
var row = iterator.getCurrentTokenRow();
|
|
var column = iterator.getCurrentTokenColumn();
|
|
var range = new Range(row, column, row, column+token.value.length);
|
|
var sbm = session.$backMarkers[session.$tagHighlight];
|
|
if (session.$tagHighlight && sbm != undefined && range.compareRange(sbm.range) !== 0) {
|
|
session.removeMarker(session.$tagHighlight);
|
|
session.$tagHighlight = null;
|
|
}
|
|
|
|
if (!session.$tagHighlight)
|
|
session.$tagHighlight = session.addMarker(range, "ace_bracket", "text");
|
|
}, 50);
|
|
};
|
|
this.focus = function() {
|
|
var _self = this;
|
|
setTimeout(function() {
|
|
if (!_self.isFocused())
|
|
_self.textInput.focus();
|
|
});
|
|
this.textInput.focus();
|
|
};
|
|
this.isFocused = function() {
|
|
return this.textInput.isFocused();
|
|
};
|
|
this.blur = function() {
|
|
this.textInput.blur();
|
|
};
|
|
this.onFocus = function(e) {
|
|
if (this.$isFocused)
|
|
return;
|
|
this.$isFocused = true;
|
|
this.renderer.showCursor();
|
|
this.renderer.visualizeFocus();
|
|
this._emit("focus", e);
|
|
};
|
|
this.onBlur = function(e) {
|
|
if (!this.$isFocused)
|
|
return;
|
|
this.$isFocused = false;
|
|
this.renderer.hideCursor();
|
|
this.renderer.visualizeBlur();
|
|
this._emit("blur", e);
|
|
};
|
|
|
|
this.$cursorChange = function() {
|
|
this.renderer.updateCursor();
|
|
this.$highlightBrackets();
|
|
this.$highlightTags();
|
|
this.$updateHighlightActiveLine();
|
|
};
|
|
this.onDocumentChange = function(delta) {
|
|
var wrap = this.session.$useWrapMode;
|
|
var lastRow = (delta.start.row == delta.end.row ? delta.end.row : Infinity);
|
|
this.renderer.updateLines(delta.start.row, lastRow, wrap);
|
|
|
|
this._signal("change", delta);
|
|
this.$cursorChange();
|
|
};
|
|
|
|
this.onTokenizerUpdate = function(e) {
|
|
var rows = e.data;
|
|
this.renderer.updateLines(rows.first, rows.last);
|
|
};
|
|
|
|
|
|
this.onScrollTopChange = function() {
|
|
this.renderer.scrollToY(this.session.getScrollTop());
|
|
};
|
|
|
|
this.onScrollLeftChange = function() {
|
|
this.renderer.scrollToX(this.session.getScrollLeft());
|
|
};
|
|
this.onCursorChange = function() {
|
|
this.$cursorChange();
|
|
this._signal("changeSelection");
|
|
};
|
|
|
|
this.$updateHighlightActiveLine = function() {
|
|
var session = this.getSession();
|
|
|
|
var highlight;
|
|
if (this.$highlightActiveLine) {
|
|
if (this.$selectionStyle != "line" || !this.selection.isMultiLine())
|
|
highlight = this.getCursorPosition();
|
|
if (this.renderer.theme && this.renderer.theme.$selectionColorConflict && !this.selection.isEmpty())
|
|
highlight = false;
|
|
if (this.renderer.$maxLines && this.session.getLength() === 1 && !(this.renderer.$minLines > 1))
|
|
highlight = false;
|
|
}
|
|
|
|
if (session.$highlightLineMarker && !highlight) {
|
|
session.removeMarker(session.$highlightLineMarker.id);
|
|
session.$highlightLineMarker = null;
|
|
} else if (!session.$highlightLineMarker && highlight) {
|
|
var range = new Range(highlight.row, highlight.column, highlight.row, Infinity);
|
|
range.id = session.addMarker(range, "ace_active-line", "screenLine");
|
|
session.$highlightLineMarker = range;
|
|
} else if (highlight) {
|
|
session.$highlightLineMarker.start.row = highlight.row;
|
|
session.$highlightLineMarker.end.row = highlight.row;
|
|
session.$highlightLineMarker.start.column = highlight.column;
|
|
session._signal("changeBackMarker");
|
|
}
|
|
};
|
|
|
|
this.onSelectionChange = function(e) {
|
|
var session = this.session;
|
|
|
|
if (session.$selectionMarker) {
|
|
session.removeMarker(session.$selectionMarker);
|
|
}
|
|
session.$selectionMarker = null;
|
|
|
|
if (!this.selection.isEmpty()) {
|
|
var range = this.selection.getRange();
|
|
var style = this.getSelectionStyle();
|
|
session.$selectionMarker = session.addMarker(range, "ace_selection", style);
|
|
} else {
|
|
this.$updateHighlightActiveLine();
|
|
}
|
|
|
|
var re = this.$highlightSelectedWord && this.$getSelectionHighLightRegexp();
|
|
this.session.highlight(re);
|
|
|
|
this._signal("changeSelection");
|
|
};
|
|
|
|
this.$getSelectionHighLightRegexp = function() {
|
|
var session = this.session;
|
|
|
|
var selection = this.getSelectionRange();
|
|
if (selection.isEmpty() || selection.isMultiLine())
|
|
return;
|
|
|
|
var startColumn = selection.start.column;
|
|
var endColumn = selection.end.column;
|
|
var line = session.getLine(selection.start.row);
|
|
|
|
var needle = line.substring(startColumn, endColumn);
|
|
if (needle.length > 5000 || !/[\w\d]/.test(needle))
|
|
return;
|
|
|
|
var re = this.$search.$assembleRegExp({
|
|
wholeWord: true,
|
|
caseSensitive: true,
|
|
needle: needle
|
|
});
|
|
|
|
var wordWithBoundary = line.substring(startColumn - 1, endColumn + 1);
|
|
if (!re.test(wordWithBoundary))
|
|
return;
|
|
|
|
return re;
|
|
};
|
|
|
|
|
|
this.onChangeFrontMarker = function() {
|
|
this.renderer.updateFrontMarkers();
|
|
};
|
|
|
|
this.onChangeBackMarker = function() {
|
|
this.renderer.updateBackMarkers();
|
|
};
|
|
|
|
|
|
this.onChangeBreakpoint = function() {
|
|
this.renderer.updateBreakpoints();
|
|
};
|
|
|
|
this.onChangeAnnotation = function() {
|
|
this.renderer.setAnnotations(this.session.getAnnotations());
|
|
};
|
|
|
|
|
|
this.onChangeMode = function(e) {
|
|
this.renderer.updateText();
|
|
this._emit("changeMode", e);
|
|
};
|
|
|
|
|
|
this.onChangeWrapLimit = function() {
|
|
this.renderer.updateFull();
|
|
};
|
|
|
|
this.onChangeWrapMode = function() {
|
|
this.renderer.onResize(true);
|
|
};
|
|
|
|
|
|
this.onChangeFold = function() {
|
|
this.$updateHighlightActiveLine();
|
|
this.renderer.updateFull();
|
|
};
|
|
this.getSelectedText = function() {
|
|
return this.session.getTextRange(this.getSelectionRange());
|
|
};
|
|
this.getCopyText = function() {
|
|
var text = this.getSelectedText();
|
|
var nl = this.session.doc.getNewLineCharacter();
|
|
var copyLine= false;
|
|
if (!text && this.$copyWithEmptySelection) {
|
|
copyLine = true;
|
|
var ranges = this.selection.getAllRanges();
|
|
for (var i = 0; i < ranges.length; i++) {
|
|
var range = ranges[i];
|
|
if (i && ranges[i - 1].start.row == range.start.row)
|
|
continue;
|
|
text += this.session.getLine(range.start.row) + nl;
|
|
}
|
|
}
|
|
var e = {text: text};
|
|
this._signal("copy", e);
|
|
clipboard.lineMode = copyLine ? e.text : "";
|
|
return e.text;
|
|
};
|
|
this.onCopy = function() {
|
|
this.commands.exec("copy", this);
|
|
};
|
|
this.onCut = function() {
|
|
this.commands.exec("cut", this);
|
|
};
|
|
this.onPaste = function(text, event) {
|
|
var e = {text: text, event: event};
|
|
this.commands.exec("paste", this, e);
|
|
};
|
|
|
|
this.$handlePaste = function(e) {
|
|
if (typeof e == "string")
|
|
e = {text: e};
|
|
this._signal("paste", e);
|
|
var text = e.text;
|
|
|
|
var lineMode = text == clipboard.lineMode;
|
|
var session = this.session;
|
|
if (!this.inMultiSelectMode || this.inVirtualSelectionMode) {
|
|
if (lineMode)
|
|
session.insert({ row: this.selection.lead.row, column: 0 }, text);
|
|
else
|
|
this.insert(text);
|
|
} else if (lineMode) {
|
|
this.selection.rangeList.ranges.forEach(function(range) {
|
|
session.insert({ row: range.start.row, column: 0 }, text);
|
|
});
|
|
} else {
|
|
var lines = text.split(/\r\n|\r|\n/);
|
|
var ranges = this.selection.rangeList.ranges;
|
|
|
|
var isFullLine = lines.length == 2 && (!lines[0] || !lines[1]);
|
|
if (lines.length != ranges.length || isFullLine)
|
|
return this.commands.exec("insertstring", this, text);
|
|
|
|
for (var i = ranges.length; i--;) {
|
|
var range = ranges[i];
|
|
if (!range.isEmpty())
|
|
session.remove(range);
|
|
|
|
session.insert(range.start, lines[i]);
|
|
}
|
|
}
|
|
};
|
|
|
|
this.execCommand = function(command, args) {
|
|
return this.commands.exec(command, this, args);
|
|
};
|
|
this.insert = function(text, pasted) {
|
|
var session = this.session;
|
|
var mode = session.getMode();
|
|
var cursor = this.getCursorPosition();
|
|
|
|
if (this.getBehavioursEnabled() && !pasted) {
|
|
var transform = mode.transformAction(session.getState(cursor.row), 'insertion', this, session, text);
|
|
if (transform) {
|
|
if (text !== transform.text) {
|
|
if (!this.inVirtualSelectionMode) {
|
|
this.session.mergeUndoDeltas = false;
|
|
this.mergeNextCommand = false;
|
|
}
|
|
}
|
|
text = transform.text;
|
|
|
|
}
|
|
}
|
|
|
|
if (text == "\t")
|
|
text = this.session.getTabString();
|
|
if (!this.selection.isEmpty()) {
|
|
var range = this.getSelectionRange();
|
|
cursor = this.session.remove(range);
|
|
this.clearSelection();
|
|
}
|
|
else if (this.session.getOverwrite() && text.indexOf("\n") == -1) {
|
|
var range = new Range.fromPoints(cursor, cursor);
|
|
range.end.column += text.length;
|
|
this.session.remove(range);
|
|
}
|
|
|
|
if (text == "\n" || text == "\r\n") {
|
|
var line = session.getLine(cursor.row);
|
|
if (cursor.column > line.search(/\S|$/)) {
|
|
var d = line.substr(cursor.column).search(/\S|$/);
|
|
session.doc.removeInLine(cursor.row, cursor.column, cursor.column + d);
|
|
}
|
|
}
|
|
this.clearSelection();
|
|
|
|
var start = cursor.column;
|
|
var lineState = session.getState(cursor.row);
|
|
var line = session.getLine(cursor.row);
|
|
var shouldOutdent = mode.checkOutdent(lineState, line, text);
|
|
session.insert(cursor, text);
|
|
|
|
if (transform && transform.selection) {
|
|
if (transform.selection.length == 2) { // Transform relative to the current column
|
|
this.selection.setSelectionRange(
|
|
new Range(cursor.row, start + transform.selection[0],
|
|
cursor.row, start + transform.selection[1]));
|
|
} else { // Transform relative to the current row.
|
|
this.selection.setSelectionRange(
|
|
new Range(cursor.row + transform.selection[0],
|
|
transform.selection[1],
|
|
cursor.row + transform.selection[2],
|
|
transform.selection[3]));
|
|
}
|
|
}
|
|
if (this.$enableAutoIndent) {
|
|
if (session.getDocument().isNewLine(text)) {
|
|
var lineIndent = mode.getNextLineIndent(lineState, line.slice(0, cursor.column), session.getTabString());
|
|
|
|
session.insert({row: cursor.row+1, column: 0}, lineIndent);
|
|
}
|
|
if (shouldOutdent)
|
|
mode.autoOutdent(lineState, session, cursor.row);
|
|
}
|
|
};
|
|
|
|
this.autoIndent = function () {
|
|
var session = this.session;
|
|
var mode = session.getMode();
|
|
|
|
var startRow, endRow;
|
|
if (this.selection.isEmpty()) {
|
|
startRow = 0;
|
|
endRow = session.doc.getLength() - 1;
|
|
} else {
|
|
var selectedRange = this.getSelectionRange();
|
|
|
|
startRow = selectedRange.start.row;
|
|
endRow = selectedRange.end.row;
|
|
}
|
|
|
|
var prevLineState = "";
|
|
var prevLine = "";
|
|
var lineIndent = "";
|
|
var line, currIndent, range;
|
|
var tab = session.getTabString();
|
|
|
|
for (var row = startRow; row <= endRow; row++) {
|
|
if (row > 0) {
|
|
prevLineState = session.getState(row - 1);
|
|
prevLine = session.getLine(row - 1);
|
|
lineIndent = mode.getNextLineIndent(prevLineState, prevLine, tab);
|
|
}
|
|
|
|
line = session.getLine(row);
|
|
currIndent = mode.$getIndent(line);
|
|
if (lineIndent !== currIndent) {
|
|
if (currIndent.length > 0) {
|
|
range = new Range(row, 0, row, currIndent.length);
|
|
session.remove(range);
|
|
}
|
|
if (lineIndent.length > 0) {
|
|
session.insert({row: row, column: 0}, lineIndent);
|
|
}
|
|
}
|
|
|
|
mode.autoOutdent(prevLineState, session, row);
|
|
}
|
|
};
|
|
|
|
|
|
this.onTextInput = function(text, composition) {
|
|
if (!composition)
|
|
return this.keyBinding.onTextInput(text);
|
|
|
|
this.startOperation({command: { name: "insertstring" }});
|
|
var applyComposition = this.applyComposition.bind(this, text, composition);
|
|
if (this.selection.rangeCount)
|
|
this.forEachSelection(applyComposition);
|
|
else
|
|
applyComposition();
|
|
this.endOperation();
|
|
};
|
|
|
|
this.applyComposition = function(text, composition) {
|
|
if (composition.extendLeft || composition.extendRight) {
|
|
var r = this.selection.getRange();
|
|
r.start.column -= composition.extendLeft;
|
|
r.end.column += composition.extendRight;
|
|
if (r.start.column < 0) {
|
|
r.start.row--;
|
|
r.start.column += this.session.getLine(r.start.row).length + 1;
|
|
}
|
|
this.selection.setRange(r);
|
|
if (!text && !r.isEmpty())
|
|
this.remove();
|
|
}
|
|
if (text || !this.selection.isEmpty())
|
|
this.insert(text, true);
|
|
if (composition.restoreStart || composition.restoreEnd) {
|
|
var r = this.selection.getRange();
|
|
r.start.column -= composition.restoreStart;
|
|
r.end.column -= composition.restoreEnd;
|
|
this.selection.setRange(r);
|
|
}
|
|
};
|
|
|
|
this.onCommandKey = function(e, hashId, keyCode) {
|
|
return this.keyBinding.onCommandKey(e, hashId, keyCode);
|
|
};
|
|
this.setOverwrite = function(overwrite) {
|
|
this.session.setOverwrite(overwrite);
|
|
};
|
|
this.getOverwrite = function() {
|
|
return this.session.getOverwrite();
|
|
};
|
|
this.toggleOverwrite = function() {
|
|
this.session.toggleOverwrite();
|
|
};
|
|
this.setScrollSpeed = function(speed) {
|
|
this.setOption("scrollSpeed", speed);
|
|
};
|
|
this.getScrollSpeed = function() {
|
|
return this.getOption("scrollSpeed");
|
|
};
|
|
this.setDragDelay = function(dragDelay) {
|
|
this.setOption("dragDelay", dragDelay);
|
|
};
|
|
this.getDragDelay = function() {
|
|
return this.getOption("dragDelay");
|
|
};
|
|
this.setSelectionStyle = function(val) {
|
|
this.setOption("selectionStyle", val);
|
|
};
|
|
this.getSelectionStyle = function() {
|
|
return this.getOption("selectionStyle");
|
|
};
|
|
this.setHighlightActiveLine = function(shouldHighlight) {
|
|
this.setOption("highlightActiveLine", shouldHighlight);
|
|
};
|
|
this.getHighlightActiveLine = function() {
|
|
return this.getOption("highlightActiveLine");
|
|
};
|
|
this.setHighlightGutterLine = function(shouldHighlight) {
|
|
this.setOption("highlightGutterLine", shouldHighlight);
|
|
};
|
|
|
|
this.getHighlightGutterLine = function() {
|
|
return this.getOption("highlightGutterLine");
|
|
};
|
|
this.setHighlightSelectedWord = function(shouldHighlight) {
|
|
this.setOption("highlightSelectedWord", shouldHighlight);
|
|
};
|
|
this.getHighlightSelectedWord = function() {
|
|
return this.$highlightSelectedWord;
|
|
};
|
|
|
|
this.setAnimatedScroll = function(shouldAnimate){
|
|
this.renderer.setAnimatedScroll(shouldAnimate);
|
|
};
|
|
|
|
this.getAnimatedScroll = function(){
|
|
return this.renderer.getAnimatedScroll();
|
|
};
|
|
this.setShowInvisibles = function(showInvisibles) {
|
|
this.renderer.setShowInvisibles(showInvisibles);
|
|
};
|
|
this.getShowInvisibles = function() {
|
|
return this.renderer.getShowInvisibles();
|
|
};
|
|
|
|
this.setDisplayIndentGuides = function(display) {
|
|
this.renderer.setDisplayIndentGuides(display);
|
|
};
|
|
|
|
this.getDisplayIndentGuides = function() {
|
|
return this.renderer.getDisplayIndentGuides();
|
|
};
|
|
this.setShowPrintMargin = function(showPrintMargin) {
|
|
this.renderer.setShowPrintMargin(showPrintMargin);
|
|
};
|
|
this.getShowPrintMargin = function() {
|
|
return this.renderer.getShowPrintMargin();
|
|
};
|
|
this.setPrintMarginColumn = function(showPrintMargin) {
|
|
this.renderer.setPrintMarginColumn(showPrintMargin);
|
|
};
|
|
this.getPrintMarginColumn = function() {
|
|
return this.renderer.getPrintMarginColumn();
|
|
};
|
|
this.setReadOnly = function(readOnly) {
|
|
this.setOption("readOnly", readOnly);
|
|
};
|
|
this.getReadOnly = function() {
|
|
return this.getOption("readOnly");
|
|
};
|
|
this.setBehavioursEnabled = function (enabled) {
|
|
this.setOption("behavioursEnabled", enabled);
|
|
};
|
|
this.getBehavioursEnabled = function () {
|
|
return this.getOption("behavioursEnabled");
|
|
};
|
|
this.setWrapBehavioursEnabled = function (enabled) {
|
|
this.setOption("wrapBehavioursEnabled", enabled);
|
|
};
|
|
this.getWrapBehavioursEnabled = function () {
|
|
return this.getOption("wrapBehavioursEnabled");
|
|
};
|
|
this.setShowFoldWidgets = function(show) {
|
|
this.setOption("showFoldWidgets", show);
|
|
|
|
};
|
|
this.getShowFoldWidgets = function() {
|
|
return this.getOption("showFoldWidgets");
|
|
};
|
|
|
|
this.setFadeFoldWidgets = function(fade) {
|
|
this.setOption("fadeFoldWidgets", fade);
|
|
};
|
|
|
|
this.getFadeFoldWidgets = function() {
|
|
return this.getOption("fadeFoldWidgets");
|
|
};
|
|
this.remove = function(dir) {
|
|
if (this.selection.isEmpty()){
|
|
if (dir == "left")
|
|
this.selection.selectLeft();
|
|
else
|
|
this.selection.selectRight();
|
|
}
|
|
|
|
var range = this.getSelectionRange();
|
|
if (this.getBehavioursEnabled()) {
|
|
var session = this.session;
|
|
var state = session.getState(range.start.row);
|
|
var new_range = session.getMode().transformAction(state, 'deletion', this, session, range);
|
|
|
|
if (range.end.column === 0) {
|
|
var text = session.getTextRange(range);
|
|
if (text[text.length - 1] == "\n") {
|
|
var line = session.getLine(range.end.row);
|
|
if (/^\s+$/.test(line)) {
|
|
range.end.column = line.length;
|
|
}
|
|
}
|
|
}
|
|
if (new_range)
|
|
range = new_range;
|
|
}
|
|
|
|
this.session.remove(range);
|
|
this.clearSelection();
|
|
};
|
|
this.removeWordRight = function() {
|
|
if (this.selection.isEmpty())
|
|
this.selection.selectWordRight();
|
|
|
|
this.session.remove(this.getSelectionRange());
|
|
this.clearSelection();
|
|
};
|
|
this.removeWordLeft = function() {
|
|
if (this.selection.isEmpty())
|
|
this.selection.selectWordLeft();
|
|
|
|
this.session.remove(this.getSelectionRange());
|
|
this.clearSelection();
|
|
};
|
|
this.removeToLineStart = function() {
|
|
if (this.selection.isEmpty())
|
|
this.selection.selectLineStart();
|
|
if (this.selection.isEmpty())
|
|
this.selection.selectLeft();
|
|
this.session.remove(this.getSelectionRange());
|
|
this.clearSelection();
|
|
};
|
|
this.removeToLineEnd = function() {
|
|
if (this.selection.isEmpty())
|
|
this.selection.selectLineEnd();
|
|
|
|
var range = this.getSelectionRange();
|
|
if (range.start.column == range.end.column && range.start.row == range.end.row) {
|
|
range.end.column = 0;
|
|
range.end.row++;
|
|
}
|
|
|
|
this.session.remove(range);
|
|
this.clearSelection();
|
|
};
|
|
this.splitLine = function() {
|
|
if (!this.selection.isEmpty()) {
|
|
this.session.remove(this.getSelectionRange());
|
|
this.clearSelection();
|
|
}
|
|
|
|
var cursor = this.getCursorPosition();
|
|
this.insert("\n");
|
|
this.moveCursorToPosition(cursor);
|
|
};
|
|
this.transposeLetters = function() {
|
|
if (!this.selection.isEmpty()) {
|
|
return;
|
|
}
|
|
|
|
var cursor = this.getCursorPosition();
|
|
var column = cursor.column;
|
|
if (column === 0)
|
|
return;
|
|
|
|
var line = this.session.getLine(cursor.row);
|
|
var swap, range;
|
|
if (column < line.length) {
|
|
swap = line.charAt(column) + line.charAt(column-1);
|
|
range = new Range(cursor.row, column-1, cursor.row, column+1);
|
|
}
|
|
else {
|
|
swap = line.charAt(column-1) + line.charAt(column-2);
|
|
range = new Range(cursor.row, column-2, cursor.row, column);
|
|
}
|
|
this.session.replace(range, swap);
|
|
this.session.selection.moveToPosition(range.end);
|
|
};
|
|
this.toLowerCase = function() {
|
|
var originalRange = this.getSelectionRange();
|
|
if (this.selection.isEmpty()) {
|
|
this.selection.selectWord();
|
|
}
|
|
|
|
var range = this.getSelectionRange();
|
|
var text = this.session.getTextRange(range);
|
|
this.session.replace(range, text.toLowerCase());
|
|
this.selection.setSelectionRange(originalRange);
|
|
};
|
|
this.toUpperCase = function() {
|
|
var originalRange = this.getSelectionRange();
|
|
if (this.selection.isEmpty()) {
|
|
this.selection.selectWord();
|
|
}
|
|
|
|
var range = this.getSelectionRange();
|
|
var text = this.session.getTextRange(range);
|
|
this.session.replace(range, text.toUpperCase());
|
|
this.selection.setSelectionRange(originalRange);
|
|
};
|
|
this.indent = function() {
|
|
var session = this.session;
|
|
var range = this.getSelectionRange();
|
|
|
|
if (range.start.row < range.end.row) {
|
|
var rows = this.$getSelectedRows();
|
|
session.indentRows(rows.first, rows.last, "\t");
|
|
return;
|
|
} else if (range.start.column < range.end.column) {
|
|
var text = session.getTextRange(range);
|
|
if (!/^\s+$/.test(text)) {
|
|
var rows = this.$getSelectedRows();
|
|
session.indentRows(rows.first, rows.last, "\t");
|
|
return;
|
|
}
|
|
}
|
|
|
|
var line = session.getLine(range.start.row);
|
|
var position = range.start;
|
|
var size = session.getTabSize();
|
|
var column = session.documentToScreenColumn(position.row, position.column);
|
|
|
|
if (this.session.getUseSoftTabs()) {
|
|
var count = (size - column % size);
|
|
var indentString = lang.stringRepeat(" ", count);
|
|
} else {
|
|
var count = column % size;
|
|
while (line[range.start.column - 1] == " " && count) {
|
|
range.start.column--;
|
|
count--;
|
|
}
|
|
this.selection.setSelectionRange(range);
|
|
indentString = "\t";
|
|
}
|
|
return this.insert(indentString);
|
|
};
|
|
this.blockIndent = function() {
|
|
var rows = this.$getSelectedRows();
|
|
this.session.indentRows(rows.first, rows.last, "\t");
|
|
};
|
|
this.blockOutdent = function() {
|
|
var selection = this.session.getSelection();
|
|
this.session.outdentRows(selection.getRange());
|
|
};
|
|
this.sortLines = function() {
|
|
var rows = this.$getSelectedRows();
|
|
var session = this.session;
|
|
|
|
var lines = [];
|
|
for (var i = rows.first; i <= rows.last; i++)
|
|
lines.push(session.getLine(i));
|
|
|
|
lines.sort(function(a, b) {
|
|
if (a.toLowerCase() < b.toLowerCase()) return -1;
|
|
if (a.toLowerCase() > b.toLowerCase()) return 1;
|
|
return 0;
|
|
});
|
|
|
|
var deleteRange = new Range(0, 0, 0, 0);
|
|
for (var i = rows.first; i <= rows.last; i++) {
|
|
var line = session.getLine(i);
|
|
deleteRange.start.row = i;
|
|
deleteRange.end.row = i;
|
|
deleteRange.end.column = line.length;
|
|
session.replace(deleteRange, lines[i-rows.first]);
|
|
}
|
|
};
|
|
this.toggleCommentLines = function() {
|
|
var state = this.session.getState(this.getCursorPosition().row);
|
|
var rows = this.$getSelectedRows();
|
|
this.session.getMode().toggleCommentLines(state, this.session, rows.first, rows.last);
|
|
};
|
|
|
|
this.toggleBlockComment = function() {
|
|
var cursor = this.getCursorPosition();
|
|
var state = this.session.getState(cursor.row);
|
|
var range = this.getSelectionRange();
|
|
this.session.getMode().toggleBlockComment(state, this.session, range, cursor);
|
|
};
|
|
this.getNumberAt = function(row, column) {
|
|
var _numberRx = /[\-]?[0-9]+(?:\.[0-9]+)?/g;
|
|
_numberRx.lastIndex = 0;
|
|
|
|
var s = this.session.getLine(row);
|
|
while (_numberRx.lastIndex < column) {
|
|
var m = _numberRx.exec(s);
|
|
if(m.index <= column && m.index+m[0].length >= column){
|
|
var number = {
|
|
value: m[0],
|
|
start: m.index,
|
|
end: m.index+m[0].length
|
|
};
|
|
return number;
|
|
}
|
|
}
|
|
return null;
|
|
};
|
|
this.modifyNumber = function(amount) {
|
|
var row = this.selection.getCursor().row;
|
|
var column = this.selection.getCursor().column;
|
|
var charRange = new Range(row, column-1, row, column);
|
|
|
|
var c = this.session.getTextRange(charRange);
|
|
if (!isNaN(parseFloat(c)) && isFinite(c)) {
|
|
var nr = this.getNumberAt(row, column);
|
|
if (nr) {
|
|
var fp = nr.value.indexOf(".") >= 0 ? nr.start + nr.value.indexOf(".") + 1 : nr.end;
|
|
var decimals = nr.start + nr.value.length - fp;
|
|
|
|
var t = parseFloat(nr.value);
|
|
t *= Math.pow(10, decimals);
|
|
|
|
|
|
if(fp !== nr.end && column < fp){
|
|
amount *= Math.pow(10, nr.end - column - 1);
|
|
} else {
|
|
amount *= Math.pow(10, nr.end - column);
|
|
}
|
|
|
|
t += amount;
|
|
t /= Math.pow(10, decimals);
|
|
var nnr = t.toFixed(decimals);
|
|
var replaceRange = new Range(row, nr.start, row, nr.end);
|
|
this.session.replace(replaceRange, nnr);
|
|
this.moveCursorTo(row, Math.max(nr.start +1, column + nnr.length - nr.value.length));
|
|
|
|
}
|
|
} else {
|
|
this.toggleWord();
|
|
}
|
|
};
|
|
|
|
this.$toggleWordPairs = [
|
|
["first", "last"],
|
|
["true", "false"],
|
|
["yes", "no"],
|
|
["width", "height"],
|
|
["top", "bottom"],
|
|
["right", "left"],
|
|
["on", "off"],
|
|
["x", "y"],
|
|
["get", "set"],
|
|
["max", "min"],
|
|
["horizontal", "vertical"],
|
|
["show", "hide"],
|
|
["add", "remove"],
|
|
["up", "down"],
|
|
["before", "after"],
|
|
["even", "odd"],
|
|
["in", "out"],
|
|
["inside", "outside"],
|
|
["next", "previous"],
|
|
["increase", "decrease"],
|
|
["attach", "detach"],
|
|
["&&", "||"],
|
|
["==", "!="]
|
|
];
|
|
|
|
this.toggleWord = function () {
|
|
var row = this.selection.getCursor().row;
|
|
var column = this.selection.getCursor().column;
|
|
this.selection.selectWord();
|
|
var currentState = this.getSelectedText();
|
|
var currWordStart = this.selection.getWordRange().start.column;
|
|
var wordParts = currentState.replace(/([a-z]+|[A-Z]+)(?=[A-Z_]|$)/g, '$1 ').split(/\s/);
|
|
var delta = column - currWordStart - 1;
|
|
if (delta < 0) delta = 0;
|
|
var curLength = 0, itLength = 0;
|
|
var that = this;
|
|
if (currentState.match(/[A-Za-z0-9_]+/)) {
|
|
wordParts.forEach(function (item, i) {
|
|
itLength = curLength + item.length;
|
|
if (delta >= curLength && delta <= itLength) {
|
|
currentState = item;
|
|
that.selection.clearSelection();
|
|
that.moveCursorTo(row, curLength + currWordStart);
|
|
that.selection.selectTo(row, itLength + currWordStart);
|
|
}
|
|
curLength = itLength;
|
|
});
|
|
}
|
|
|
|
var wordPairs = this.$toggleWordPairs;
|
|
var reg;
|
|
for (var i = 0; i < wordPairs.length; i++) {
|
|
var item = wordPairs[i];
|
|
for (var j = 0; j <= 1; j++) {
|
|
var negate = +!j;
|
|
var firstCondition = currentState.match(new RegExp('^\\s?_?(' + lang.escapeRegExp(item[j]) + ')\\s?$', 'i'));
|
|
if (firstCondition) {
|
|
var secondCondition = currentState.match(new RegExp('([_]|^|\\s)(' + lang.escapeRegExp(firstCondition[1]) + ')($|\\s)', 'g'));
|
|
if (secondCondition) {
|
|
reg = currentState.replace(new RegExp(lang.escapeRegExp(item[j]), 'i'), function (result) {
|
|
var res = item[negate];
|
|
if (result.toUpperCase() == result) {
|
|
res = res.toUpperCase();
|
|
} else if (result.charAt(0).toUpperCase() == result.charAt(0)) {
|
|
res = res.substr(0, 0) + item[negate].charAt(0).toUpperCase() + res.substr(1);
|
|
}
|
|
return res;
|
|
});
|
|
this.insert(reg);
|
|
reg = "";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
this.removeLines = function() {
|
|
var rows = this.$getSelectedRows();
|
|
this.session.removeFullLines(rows.first, rows.last);
|
|
this.clearSelection();
|
|
};
|
|
|
|
this.duplicateSelection = function() {
|
|
var sel = this.selection;
|
|
var doc = this.session;
|
|
var range = sel.getRange();
|
|
var reverse = sel.isBackwards();
|
|
if (range.isEmpty()) {
|
|
var row = range.start.row;
|
|
doc.duplicateLines(row, row);
|
|
} else {
|
|
var point = reverse ? range.start : range.end;
|
|
var endPoint = doc.insert(point, doc.getTextRange(range), false);
|
|
range.start = point;
|
|
range.end = endPoint;
|
|
|
|
sel.setSelectionRange(range, reverse);
|
|
}
|
|
};
|
|
this.moveLinesDown = function() {
|
|
this.$moveLines(1, false);
|
|
};
|
|
this.moveLinesUp = function() {
|
|
this.$moveLines(-1, false);
|
|
};
|
|
this.moveText = function(range, toPosition, copy) {
|
|
return this.session.moveText(range, toPosition, copy);
|
|
};
|
|
this.copyLinesUp = function() {
|
|
this.$moveLines(-1, true);
|
|
};
|
|
this.copyLinesDown = function() {
|
|
this.$moveLines(1, true);
|
|
};
|
|
this.$moveLines = function(dir, copy) {
|
|
var rows, moved;
|
|
var selection = this.selection;
|
|
if (!selection.inMultiSelectMode || this.inVirtualSelectionMode) {
|
|
var range = selection.toOrientedRange();
|
|
rows = this.$getSelectedRows(range);
|
|
moved = this.session.$moveLines(rows.first, rows.last, copy ? 0 : dir);
|
|
if (copy && dir == -1) moved = 0;
|
|
range.moveBy(moved, 0);
|
|
selection.fromOrientedRange(range);
|
|
} else {
|
|
var ranges = selection.rangeList.ranges;
|
|
selection.rangeList.detach(this.session);
|
|
this.inVirtualSelectionMode = true;
|
|
|
|
var diff = 0;
|
|
var totalDiff = 0;
|
|
var l = ranges.length;
|
|
for (var i = 0; i < l; i++) {
|
|
var rangeIndex = i;
|
|
ranges[i].moveBy(diff, 0);
|
|
rows = this.$getSelectedRows(ranges[i]);
|
|
var first = rows.first;
|
|
var last = rows.last;
|
|
while (++i < l) {
|
|
if (totalDiff) ranges[i].moveBy(totalDiff, 0);
|
|
var subRows = this.$getSelectedRows(ranges[i]);
|
|
if (copy && subRows.first != last)
|
|
break;
|
|
else if (!copy && subRows.first > last + 1)
|
|
break;
|
|
last = subRows.last;
|
|
}
|
|
i--;
|
|
diff = this.session.$moveLines(first, last, copy ? 0 : dir);
|
|
if (copy && dir == -1) rangeIndex = i + 1;
|
|
while (rangeIndex <= i) {
|
|
ranges[rangeIndex].moveBy(diff, 0);
|
|
rangeIndex++;
|
|
}
|
|
if (!copy) diff = 0;
|
|
totalDiff += diff;
|
|
}
|
|
|
|
selection.fromOrientedRange(selection.ranges[0]);
|
|
selection.rangeList.attach(this.session);
|
|
this.inVirtualSelectionMode = false;
|
|
}
|
|
};
|
|
this.$getSelectedRows = function(range) {
|
|
range = (range || this.getSelectionRange()).collapseRows();
|
|
|
|
return {
|
|
first: this.session.getRowFoldStart(range.start.row),
|
|
last: this.session.getRowFoldEnd(range.end.row)
|
|
};
|
|
};
|
|
|
|
this.onCompositionStart = function(compositionState) {
|
|
this.renderer.showComposition(compositionState);
|
|
};
|
|
|
|
this.onCompositionUpdate = function(text) {
|
|
this.renderer.setCompositionText(text);
|
|
};
|
|
|
|
this.onCompositionEnd = function() {
|
|
this.renderer.hideComposition();
|
|
};
|
|
this.getFirstVisibleRow = function() {
|
|
return this.renderer.getFirstVisibleRow();
|
|
};
|
|
this.getLastVisibleRow = function() {
|
|
return this.renderer.getLastVisibleRow();
|
|
};
|
|
this.isRowVisible = function(row) {
|
|
return (row >= this.getFirstVisibleRow() && row <= this.getLastVisibleRow());
|
|
};
|
|
this.isRowFullyVisible = function(row) {
|
|
return (row >= this.renderer.getFirstFullyVisibleRow() && row <= this.renderer.getLastFullyVisibleRow());
|
|
};
|
|
this.$getVisibleRowCount = function() {
|
|
return this.renderer.getScrollBottomRow() - this.renderer.getScrollTopRow() + 1;
|
|
};
|
|
|
|
this.$moveByPage = function(dir, select) {
|
|
var renderer = this.renderer;
|
|
var config = this.renderer.layerConfig;
|
|
var rows = dir * Math.floor(config.height / config.lineHeight);
|
|
|
|
if (select === true) {
|
|
this.selection.$moveSelection(function(){
|
|
this.moveCursorBy(rows, 0);
|
|
});
|
|
} else if (select === false) {
|
|
this.selection.moveCursorBy(rows, 0);
|
|
this.selection.clearSelection();
|
|
}
|
|
|
|
var scrollTop = renderer.scrollTop;
|
|
|
|
renderer.scrollBy(0, rows * config.lineHeight);
|
|
if (select != null)
|
|
renderer.scrollCursorIntoView(null, 0.5);
|
|
|
|
renderer.animateScrolling(scrollTop);
|
|
};
|
|
this.selectPageDown = function() {
|
|
this.$moveByPage(1, true);
|
|
};
|
|
this.selectPageUp = function() {
|
|
this.$moveByPage(-1, true);
|
|
};
|
|
this.gotoPageDown = function() {
|
|
this.$moveByPage(1, false);
|
|
};
|
|
this.gotoPageUp = function() {
|
|
this.$moveByPage(-1, false);
|
|
};
|
|
this.scrollPageDown = function() {
|
|
this.$moveByPage(1);
|
|
};
|
|
this.scrollPageUp = function() {
|
|
this.$moveByPage(-1);
|
|
};
|
|
this.scrollToRow = function(row) {
|
|
this.renderer.scrollToRow(row);
|
|
};
|
|
this.scrollToLine = function(line, center, animate, callback) {
|
|
this.renderer.scrollToLine(line, center, animate, callback);
|
|
};
|
|
this.centerSelection = function() {
|
|
var range = this.getSelectionRange();
|
|
var pos = {
|
|
row: Math.floor(range.start.row + (range.end.row - range.start.row) / 2),
|
|
column: Math.floor(range.start.column + (range.end.column - range.start.column) / 2)
|
|
};
|
|
this.renderer.alignCursor(pos, 0.5);
|
|
};
|
|
this.getCursorPosition = function() {
|
|
return this.selection.getCursor();
|
|
};
|
|
this.getCursorPositionScreen = function() {
|
|
return this.session.documentToScreenPosition(this.getCursorPosition());
|
|
};
|
|
this.getSelectionRange = function() {
|
|
return this.selection.getRange();
|
|
};
|
|
this.selectAll = function() {
|
|
this.selection.selectAll();
|
|
};
|
|
this.clearSelection = function() {
|
|
this.selection.clearSelection();
|
|
};
|
|
this.moveCursorTo = function(row, column) {
|
|
this.selection.moveCursorTo(row, column);
|
|
};
|
|
this.moveCursorToPosition = function(pos) {
|
|
this.selection.moveCursorToPosition(pos);
|
|
};
|
|
this.jumpToMatching = function(select, expand) {
|
|
var cursor = this.getCursorPosition();
|
|
var iterator = new TokenIterator(this.session, cursor.row, cursor.column);
|
|
var prevToken = iterator.getCurrentToken();
|
|
var token = prevToken || iterator.stepForward();
|
|
|
|
if (!token) return;
|
|
var matchType;
|
|
var found = false;
|
|
var depth = {};
|
|
var i = cursor.column - token.start;
|
|
var bracketType;
|
|
var brackets = {
|
|
")": "(",
|
|
"(": "(",
|
|
"]": "[",
|
|
"[": "[",
|
|
"{": "{",
|
|
"}": "{"
|
|
};
|
|
|
|
do {
|
|
if (token.value.match(/[{}()\[\]]/g)) {
|
|
for (; i < token.value.length && !found; i++) {
|
|
if (!brackets[token.value[i]]) {
|
|
continue;
|
|
}
|
|
|
|
bracketType = brackets[token.value[i]] + '.' + token.type.replace("rparen", "lparen");
|
|
|
|
if (isNaN(depth[bracketType])) {
|
|
depth[bracketType] = 0;
|
|
}
|
|
|
|
switch (token.value[i]) {
|
|
case '(':
|
|
case '[':
|
|
case '{':
|
|
depth[bracketType]++;
|
|
break;
|
|
case ')':
|
|
case ']':
|
|
case '}':
|
|
depth[bracketType]--;
|
|
|
|
if (depth[bracketType] === -1) {
|
|
matchType = 'bracket';
|
|
found = true;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else if (token.type.indexOf('tag-name') !== -1) {
|
|
if (isNaN(depth[token.value])) {
|
|
depth[token.value] = 0;
|
|
}
|
|
|
|
if (prevToken.value === '<') {
|
|
depth[token.value]++;
|
|
}
|
|
else if (prevToken.value === '</') {
|
|
depth[token.value]--;
|
|
}
|
|
|
|
if (depth[token.value] === -1) {
|
|
matchType = 'tag';
|
|
found = true;
|
|
}
|
|
}
|
|
|
|
if (!found) {
|
|
prevToken = token;
|
|
token = iterator.stepForward();
|
|
i = 0;
|
|
}
|
|
} while (token && !found);
|
|
if (!matchType)
|
|
return;
|
|
|
|
var range, pos;
|
|
if (matchType === 'bracket') {
|
|
range = this.session.getBracketRange(cursor);
|
|
if (!range) {
|
|
range = new Range(
|
|
iterator.getCurrentTokenRow(),
|
|
iterator.getCurrentTokenColumn() + i - 1,
|
|
iterator.getCurrentTokenRow(),
|
|
iterator.getCurrentTokenColumn() + i - 1
|
|
);
|
|
pos = range.start;
|
|
if (expand || pos.row === cursor.row && Math.abs(pos.column - cursor.column) < 2)
|
|
range = this.session.getBracketRange(pos);
|
|
}
|
|
}
|
|
else if (matchType === 'tag') {
|
|
if (token && token.type.indexOf('tag-name') !== -1)
|
|
var tag = token.value;
|
|
else
|
|
return;
|
|
|
|
range = new Range(
|
|
iterator.getCurrentTokenRow(),
|
|
iterator.getCurrentTokenColumn() - 2,
|
|
iterator.getCurrentTokenRow(),
|
|
iterator.getCurrentTokenColumn() - 2
|
|
);
|
|
if (range.compare(cursor.row, cursor.column) === 0) {
|
|
found = false;
|
|
do {
|
|
token = prevToken;
|
|
prevToken = iterator.stepBackward();
|
|
|
|
if (prevToken) {
|
|
if (prevToken.type.indexOf('tag-close') !== -1) {
|
|
range.setEnd(iterator.getCurrentTokenRow(), iterator.getCurrentTokenColumn() + 1);
|
|
}
|
|
|
|
if (token.value === tag && token.type.indexOf('tag-name') !== -1) {
|
|
if (prevToken.value === '<') {
|
|
depth[tag]++;
|
|
}
|
|
else if (prevToken.value === '</') {
|
|
depth[tag]--;
|
|
}
|
|
|
|
if (depth[tag] === 0)
|
|
found = true;
|
|
}
|
|
}
|
|
} while (prevToken && !found);
|
|
}
|
|
if (token && token.type.indexOf('tag-name')) {
|
|
pos = range.start;
|
|
if (pos.row == cursor.row && Math.abs(pos.column - cursor.column) < 2)
|
|
pos = range.end;
|
|
}
|
|
}
|
|
|
|
pos = range && range.cursor || pos;
|
|
if (pos) {
|
|
if (select) {
|
|
if (range && expand) {
|
|
this.selection.setRange(range);
|
|
} else if (range && range.isEqual(this.getSelectionRange())) {
|
|
this.clearSelection();
|
|
} else {
|
|
this.selection.selectTo(pos.row, pos.column);
|
|
}
|
|
} else {
|
|
this.selection.moveTo(pos.row, pos.column);
|
|
}
|
|
}
|
|
};
|
|
this.gotoLine = function(lineNumber, column, animate) {
|
|
this.selection.clearSelection();
|
|
this.session.unfold({row: lineNumber - 1, column: column || 0});
|
|
this.exitMultiSelectMode && this.exitMultiSelectMode();
|
|
this.moveCursorTo(lineNumber - 1, column || 0);
|
|
|
|
if (!this.isRowFullyVisible(lineNumber - 1))
|
|
this.scrollToLine(lineNumber - 1, true, animate);
|
|
};
|
|
this.navigateTo = function(row, column) {
|
|
this.selection.moveTo(row, column);
|
|
};
|
|
this.navigateUp = function(times) {
|
|
if (this.selection.isMultiLine() && !this.selection.isBackwards()) {
|
|
var selectionStart = this.selection.anchor.getPosition();
|
|
return this.moveCursorToPosition(selectionStart);
|
|
}
|
|
this.selection.clearSelection();
|
|
this.selection.moveCursorBy(-times || -1, 0);
|
|
};
|
|
this.navigateDown = function(times) {
|
|
if (this.selection.isMultiLine() && this.selection.isBackwards()) {
|
|
var selectionEnd = this.selection.anchor.getPosition();
|
|
return this.moveCursorToPosition(selectionEnd);
|
|
}
|
|
this.selection.clearSelection();
|
|
this.selection.moveCursorBy(times || 1, 0);
|
|
};
|
|
this.navigateLeft = function(times) {
|
|
if (!this.selection.isEmpty()) {
|
|
var selectionStart = this.getSelectionRange().start;
|
|
this.moveCursorToPosition(selectionStart);
|
|
}
|
|
else {
|
|
times = times || 1;
|
|
while (times--) {
|
|
this.selection.moveCursorLeft();
|
|
}
|
|
}
|
|
this.clearSelection();
|
|
};
|
|
this.navigateRight = function(times) {
|
|
if (!this.selection.isEmpty()) {
|
|
var selectionEnd = this.getSelectionRange().end;
|
|
this.moveCursorToPosition(selectionEnd);
|
|
}
|
|
else {
|
|
times = times || 1;
|
|
while (times--) {
|
|
this.selection.moveCursorRight();
|
|
}
|
|
}
|
|
this.clearSelection();
|
|
};
|
|
this.navigateLineStart = function() {
|
|
this.selection.moveCursorLineStart();
|
|
this.clearSelection();
|
|
};
|
|
this.navigateLineEnd = function() {
|
|
this.selection.moveCursorLineEnd();
|
|
this.clearSelection();
|
|
};
|
|
this.navigateFileEnd = function() {
|
|
this.selection.moveCursorFileEnd();
|
|
this.clearSelection();
|
|
};
|
|
this.navigateFileStart = function() {
|
|
this.selection.moveCursorFileStart();
|
|
this.clearSelection();
|
|
};
|
|
this.navigateWordRight = function() {
|
|
this.selection.moveCursorWordRight();
|
|
this.clearSelection();
|
|
};
|
|
this.navigateWordLeft = function() {
|
|
this.selection.moveCursorWordLeft();
|
|
this.clearSelection();
|
|
};
|
|
this.replace = function(replacement, options) {
|
|
if (options)
|
|
this.$search.set(options);
|
|
|
|
var range = this.$search.find(this.session);
|
|
var replaced = 0;
|
|
if (!range)
|
|
return replaced;
|
|
|
|
if (this.$tryReplace(range, replacement)) {
|
|
replaced = 1;
|
|
}
|
|
|
|
this.selection.setSelectionRange(range);
|
|
this.renderer.scrollSelectionIntoView(range.start, range.end);
|
|
|
|
return replaced;
|
|
};
|
|
this.replaceAll = function(replacement, options) {
|
|
if (options) {
|
|
this.$search.set(options);
|
|
}
|
|
|
|
var ranges = this.$search.findAll(this.session);
|
|
var replaced = 0;
|
|
if (!ranges.length)
|
|
return replaced;
|
|
|
|
var selection = this.getSelectionRange();
|
|
this.selection.moveTo(0, 0);
|
|
|
|
for (var i = ranges.length - 1; i >= 0; --i) {
|
|
if(this.$tryReplace(ranges[i], replacement)) {
|
|
replaced++;
|
|
}
|
|
}
|
|
|
|
this.selection.setSelectionRange(selection);
|
|
|
|
return replaced;
|
|
};
|
|
|
|
this.$tryReplace = function(range, replacement) {
|
|
var input = this.session.getTextRange(range);
|
|
replacement = this.$search.replace(input, replacement);
|
|
if (replacement !== null) {
|
|
range.end = this.session.replace(range, replacement);
|
|
return range;
|
|
} else {
|
|
return null;
|
|
}
|
|
};
|
|
this.getLastSearchOptions = function() {
|
|
return this.$search.getOptions();
|
|
};
|
|
this.find = function(needle, options, animate) {
|
|
if (!options)
|
|
options = {};
|
|
|
|
if (typeof needle == "string" || needle instanceof RegExp)
|
|
options.needle = needle;
|
|
else if (typeof needle == "object")
|
|
oop.mixin(options, needle);
|
|
|
|
var range = this.selection.getRange();
|
|
if (options.needle == null) {
|
|
needle = this.session.getTextRange(range)
|
|
|| this.$search.$options.needle;
|
|
if (!needle) {
|
|
range = this.session.getWordRange(range.start.row, range.start.column);
|
|
needle = this.session.getTextRange(range);
|
|
}
|
|
this.$search.set({needle: needle});
|
|
}
|
|
|
|
this.$search.set(options);
|
|
if (!options.start)
|
|
this.$search.set({start: range});
|
|
|
|
var newRange = this.$search.find(this.session);
|
|
if (options.preventScroll)
|
|
return newRange;
|
|
if (newRange) {
|
|
this.revealRange(newRange, animate);
|
|
return newRange;
|
|
}
|
|
if (options.backwards)
|
|
range.start = range.end;
|
|
else
|
|
range.end = range.start;
|
|
this.selection.setRange(range);
|
|
};
|
|
this.findNext = function(options, animate) {
|
|
this.find({skipCurrent: true, backwards: false}, options, animate);
|
|
};
|
|
this.findPrevious = function(options, animate) {
|
|
this.find(options, {skipCurrent: true, backwards: true}, animate);
|
|
};
|
|
|
|
this.revealRange = function(range, animate) {
|
|
this.session.unfold(range);
|
|
this.selection.setSelectionRange(range);
|
|
|
|
var scrollTop = this.renderer.scrollTop;
|
|
this.renderer.scrollSelectionIntoView(range.start, range.end, 0.5);
|
|
if (animate !== false)
|
|
this.renderer.animateScrolling(scrollTop);
|
|
};
|
|
this.undo = function() {
|
|
this.session.getUndoManager().undo(this.session);
|
|
this.renderer.scrollCursorIntoView(null, 0.5);
|
|
};
|
|
this.redo = function() {
|
|
this.session.getUndoManager().redo(this.session);
|
|
this.renderer.scrollCursorIntoView(null, 0.5);
|
|
};
|
|
this.destroy = function() {
|
|
if (this.$toDestroy) {
|
|
this.$toDestroy.forEach(function(el) {
|
|
el.destroy();
|
|
});
|
|
this.$toDestroy = null;
|
|
}
|
|
if (this.$mouseHandler)
|
|
this.$mouseHandler.destroy();
|
|
this.renderer.destroy();
|
|
this._signal("destroy", this);
|
|
if (this.session)
|
|
this.session.destroy();
|
|
if (this._$emitInputEvent)
|
|
this._$emitInputEvent.cancel();
|
|
this.removeAllListeners();
|
|
};
|
|
this.setAutoScrollEditorIntoView = function(enable) {
|
|
if (!enable)
|
|
return;
|
|
var rect;
|
|
var self = this;
|
|
var shouldScroll = false;
|
|
if (!this.$scrollAnchor)
|
|
this.$scrollAnchor = document.createElement("div");
|
|
var scrollAnchor = this.$scrollAnchor;
|
|
scrollAnchor.style.cssText = "position:absolute";
|
|
this.container.insertBefore(scrollAnchor, this.container.firstChild);
|
|
var onChangeSelection = this.on("changeSelection", function() {
|
|
shouldScroll = true;
|
|
});
|
|
var onBeforeRender = this.renderer.on("beforeRender", function() {
|
|
if (shouldScroll)
|
|
rect = self.renderer.container.getBoundingClientRect();
|
|
});
|
|
var onAfterRender = this.renderer.on("afterRender", function() {
|
|
if (shouldScroll && rect && (self.isFocused()
|
|
|| self.searchBox && self.searchBox.isFocused())
|
|
) {
|
|
var renderer = self.renderer;
|
|
var pos = renderer.$cursorLayer.$pixelPos;
|
|
var config = renderer.layerConfig;
|
|
var top = pos.top - config.offset;
|
|
if (pos.top >= 0 && top + rect.top < 0) {
|
|
shouldScroll = true;
|
|
} else if (pos.top < config.height &&
|
|
pos.top + rect.top + config.lineHeight > window.innerHeight) {
|
|
shouldScroll = false;
|
|
} else {
|
|
shouldScroll = null;
|
|
}
|
|
if (shouldScroll != null) {
|
|
scrollAnchor.style.top = top + "px";
|
|
scrollAnchor.style.left = pos.left + "px";
|
|
scrollAnchor.style.height = config.lineHeight + "px";
|
|
scrollAnchor.scrollIntoView(shouldScroll);
|
|
}
|
|
shouldScroll = rect = null;
|
|
}
|
|
});
|
|
this.setAutoScrollEditorIntoView = function(enable) {
|
|
if (enable)
|
|
return;
|
|
delete this.setAutoScrollEditorIntoView;
|
|
this.off("changeSelection", onChangeSelection);
|
|
this.renderer.off("afterRender", onAfterRender);
|
|
this.renderer.off("beforeRender", onBeforeRender);
|
|
};
|
|
};
|
|
|
|
|
|
this.$resetCursorStyle = function() {
|
|
var style = this.$cursorStyle || "ace";
|
|
var cursorLayer = this.renderer.$cursorLayer;
|
|
if (!cursorLayer)
|
|
return;
|
|
cursorLayer.setSmoothBlinking(/smooth/.test(style));
|
|
cursorLayer.isBlinking = !this.$readOnly && style != "wide";
|
|
dom.setCssClass(cursorLayer.element, "ace_slim-cursors", /slim/.test(style));
|
|
};
|
|
this.prompt = function(message, options, callback) {
|
|
var editor = this;
|
|
config.loadModule("./ext/prompt", function (module) {
|
|
module.prompt(editor, message, options, callback);
|
|
});
|
|
};
|
|
|
|
}).call(Editor.prototype);
|
|
|
|
|
|
|
|
config.defineOptions(Editor.prototype, "editor", {
|
|
selectionStyle: {
|
|
set: function(style) {
|
|
this.onSelectionChange();
|
|
this._signal("changeSelectionStyle", {data: style});
|
|
},
|
|
initialValue: "line"
|
|
},
|
|
highlightActiveLine: {
|
|
set: function() {this.$updateHighlightActiveLine();},
|
|
initialValue: true
|
|
},
|
|
highlightSelectedWord: {
|
|
set: function(shouldHighlight) {this.$onSelectionChange();},
|
|
initialValue: true
|
|
},
|
|
readOnly: {
|
|
set: function(readOnly) {
|
|
this.textInput.setReadOnly(readOnly);
|
|
this.$resetCursorStyle();
|
|
},
|
|
initialValue: false
|
|
},
|
|
copyWithEmptySelection: {
|
|
set: function(value) {
|
|
this.textInput.setCopyWithEmptySelection(value);
|
|
},
|
|
initialValue: false
|
|
},
|
|
cursorStyle: {
|
|
set: function(val) { this.$resetCursorStyle(); },
|
|
values: ["ace", "slim", "smooth", "wide"],
|
|
initialValue: "ace"
|
|
},
|
|
mergeUndoDeltas: {
|
|
values: [false, true, "always"],
|
|
initialValue: true
|
|
},
|
|
behavioursEnabled: {initialValue: true},
|
|
wrapBehavioursEnabled: {initialValue: true},
|
|
enableAutoIndent: {initialValue: true},
|
|
autoScrollEditorIntoView: {
|
|
set: function(val) {this.setAutoScrollEditorIntoView(val);}
|
|
},
|
|
keyboardHandler: {
|
|
set: function(val) { this.setKeyboardHandler(val); },
|
|
get: function() { return this.$keybindingId; },
|
|
handlesSet: true
|
|
},
|
|
value: {
|
|
set: function(val) { this.session.setValue(val); },
|
|
get: function() { return this.getValue(); },
|
|
handlesSet: true,
|
|
hidden: true
|
|
},
|
|
session: {
|
|
set: function(val) { this.setSession(val); },
|
|
get: function() { return this.session; },
|
|
handlesSet: true,
|
|
hidden: true
|
|
},
|
|
|
|
showLineNumbers: {
|
|
set: function(show) {
|
|
this.renderer.$gutterLayer.setShowLineNumbers(show);
|
|
this.renderer.$loop.schedule(this.renderer.CHANGE_GUTTER);
|
|
if (show && this.$relativeLineNumbers)
|
|
relativeNumberRenderer.attach(this);
|
|
else
|
|
relativeNumberRenderer.detach(this);
|
|
},
|
|
initialValue: true
|
|
},
|
|
relativeLineNumbers: {
|
|
set: function(value) {
|
|
if (this.$showLineNumbers && value)
|
|
relativeNumberRenderer.attach(this);
|
|
else
|
|
relativeNumberRenderer.detach(this);
|
|
}
|
|
},
|
|
placeholder: {
|
|
set: function(message) {
|
|
if (!this.$updatePlaceholder) {
|
|
this.$updatePlaceholder = function() {
|
|
var value = this.session && (this.renderer.$composition || this.getValue());
|
|
if (value && this.renderer.placeholderNode) {
|
|
this.renderer.off("afterRender", this.$updatePlaceholder);
|
|
dom.removeCssClass(this.container, "ace_hasPlaceholder");
|
|
this.renderer.placeholderNode.remove();
|
|
this.renderer.placeholderNode = null;
|
|
} else if (!value && !this.renderer.placeholderNode) {
|
|
this.renderer.on("afterRender", this.$updatePlaceholder);
|
|
dom.addCssClass(this.container, "ace_hasPlaceholder");
|
|
var el = dom.createElement("div");
|
|
el.className = "ace_placeholder";
|
|
el.textContent = this.$placeholder || "";
|
|
this.renderer.placeholderNode = el;
|
|
this.renderer.content.appendChild(this.renderer.placeholderNode);
|
|
} else if (!value && this.renderer.placeholderNode) {
|
|
this.renderer.placeholderNode.textContent = this.$placeholder || "";
|
|
}
|
|
}.bind(this);
|
|
this.on("input", this.$updatePlaceholder);
|
|
}
|
|
this.$updatePlaceholder();
|
|
}
|
|
},
|
|
|
|
hScrollBarAlwaysVisible: "renderer",
|
|
vScrollBarAlwaysVisible: "renderer",
|
|
highlightGutterLine: "renderer",
|
|
animatedScroll: "renderer",
|
|
showInvisibles: "renderer",
|
|
showPrintMargin: "renderer",
|
|
printMarginColumn: "renderer",
|
|
printMargin: "renderer",
|
|
fadeFoldWidgets: "renderer",
|
|
showFoldWidgets: "renderer",
|
|
displayIndentGuides: "renderer",
|
|
showGutter: "renderer",
|
|
fontSize: "renderer",
|
|
fontFamily: "renderer",
|
|
maxLines: "renderer",
|
|
minLines: "renderer",
|
|
scrollPastEnd: "renderer",
|
|
fixedWidthGutter: "renderer",
|
|
theme: "renderer",
|
|
hasCssTransforms: "renderer",
|
|
maxPixelHeight: "renderer",
|
|
useTextareaForIME: "renderer",
|
|
|
|
scrollSpeed: "$mouseHandler",
|
|
dragDelay: "$mouseHandler",
|
|
dragEnabled: "$mouseHandler",
|
|
focusTimeout: "$mouseHandler",
|
|
tooltipFollowsMouse: "$mouseHandler",
|
|
|
|
firstLineNumber: "session",
|
|
overwrite: "session",
|
|
newLineMode: "session",
|
|
useWorker: "session",
|
|
useSoftTabs: "session",
|
|
navigateWithinSoftTabs: "session",
|
|
tabSize: "session",
|
|
wrap: "session",
|
|
indentedSoftWrap: "session",
|
|
foldStyle: "session",
|
|
mode: "session"
|
|
});
|
|
|
|
|
|
var relativeNumberRenderer = {
|
|
getText: function(session, row) {
|
|
return (Math.abs(session.selection.lead.row - row) || (row + 1 + (row < 9 ? "\xb7" : ""))) + "";
|
|
},
|
|
getWidth: function(session, lastLineNumber, config) {
|
|
return Math.max(
|
|
lastLineNumber.toString().length,
|
|
(config.lastRow + 1).toString().length,
|
|
2
|
|
) * config.characterWidth;
|
|
},
|
|
update: function(e, editor) {
|
|
editor.renderer.$loop.schedule(editor.renderer.CHANGE_GUTTER);
|
|
},
|
|
attach: function(editor) {
|
|
editor.renderer.$gutterLayer.$renderer = this;
|
|
editor.on("changeSelection", this.update);
|
|
this.update(null, editor);
|
|
},
|
|
detach: function(editor) {
|
|
if (editor.renderer.$gutterLayer.$renderer == this)
|
|
editor.renderer.$gutterLayer.$renderer = null;
|
|
editor.off("changeSelection", this.update);
|
|
this.update(null, editor);
|
|
}
|
|
};
|
|
|
|
exports.Editor = Editor;
|
|
});
|
|
|
|
ace.define("ace/undomanager",["require","exports","module","ace/range"], function(require, exports, module) {
|
|
"use strict";
|
|
var UndoManager = function() {
|
|
this.$maxRev = 0;
|
|
this.$fromUndo = false;
|
|
this.reset();
|
|
};
|
|
|
|
(function() {
|
|
|
|
this.addSession = function(session) {
|
|
this.$session = session;
|
|
};
|
|
this.add = function(delta, allowMerge, session) {
|
|
if (this.$fromUndo) return;
|
|
if (delta == this.$lastDelta) return;
|
|
if (!this.$keepRedoStack) this.$redoStack.length = 0;
|
|
if (allowMerge === false || !this.lastDeltas) {
|
|
this.lastDeltas = [];
|
|
this.$undoStack.push(this.lastDeltas);
|
|
delta.id = this.$rev = ++this.$maxRev;
|
|
}
|
|
if (delta.action == "remove" || delta.action == "insert")
|
|
this.$lastDelta = delta;
|
|
this.lastDeltas.push(delta);
|
|
};
|
|
|
|
this.addSelection = function(selection, rev) {
|
|
this.selections.push({
|
|
value: selection,
|
|
rev: rev || this.$rev
|
|
});
|
|
};
|
|
|
|
this.startNewGroup = function() {
|
|
this.lastDeltas = null;
|
|
return this.$rev;
|
|
};
|
|
|
|
this.markIgnored = function(from, to) {
|
|
if (to == null) to = this.$rev + 1;
|
|
var stack = this.$undoStack;
|
|
for (var i = stack.length; i--;) {
|
|
var delta = stack[i][0];
|
|
if (delta.id <= from)
|
|
break;
|
|
if (delta.id < to)
|
|
delta.ignore = true;
|
|
}
|
|
this.lastDeltas = null;
|
|
};
|
|
|
|
this.getSelection = function(rev, after) {
|
|
var stack = this.selections;
|
|
for (var i = stack.length; i--;) {
|
|
var selection = stack[i];
|
|
if (selection.rev < rev) {
|
|
if (after)
|
|
selection = stack[i + 1];
|
|
return selection;
|
|
}
|
|
}
|
|
};
|
|
|
|
this.getRevision = function() {
|
|
return this.$rev;
|
|
};
|
|
|
|
this.getDeltas = function(from, to) {
|
|
if (to == null) to = this.$rev + 1;
|
|
var stack = this.$undoStack;
|
|
var end = null, start = 0;
|
|
for (var i = stack.length; i--;) {
|
|
var delta = stack[i][0];
|
|
if (delta.id < to && !end)
|
|
end = i+1;
|
|
if (delta.id <= from) {
|
|
start = i + 1;
|
|
break;
|
|
}
|
|
}
|
|
return stack.slice(start, end);
|
|
};
|
|
|
|
this.getChangedRanges = function(from, to) {
|
|
if (to == null) to = this.$rev + 1;
|
|
|
|
};
|
|
|
|
this.getChangedLines = function(from, to) {
|
|
if (to == null) to = this.$rev + 1;
|
|
|
|
};
|
|
this.undo = function(session, dontSelect) {
|
|
this.lastDeltas = null;
|
|
var stack = this.$undoStack;
|
|
|
|
if (!rearrangeUndoStack(stack, stack.length))
|
|
return;
|
|
|
|
if (!session)
|
|
session = this.$session;
|
|
|
|
if (this.$redoStackBaseRev !== this.$rev && this.$redoStack.length)
|
|
this.$redoStack = [];
|
|
|
|
this.$fromUndo = true;
|
|
|
|
var deltaSet = stack.pop();
|
|
var undoSelectionRange = null;
|
|
if (deltaSet) {
|
|
undoSelectionRange = session.undoChanges(deltaSet, dontSelect);
|
|
this.$redoStack.push(deltaSet);
|
|
this.$syncRev();
|
|
}
|
|
|
|
this.$fromUndo = false;
|
|
|
|
return undoSelectionRange;
|
|
};
|
|
this.redo = function(session, dontSelect) {
|
|
this.lastDeltas = null;
|
|
|
|
if (!session)
|
|
session = this.$session;
|
|
|
|
this.$fromUndo = true;
|
|
if (this.$redoStackBaseRev != this.$rev) {
|
|
var diff = this.getDeltas(this.$redoStackBaseRev, this.$rev + 1);
|
|
rebaseRedoStack(this.$redoStack, diff);
|
|
this.$redoStackBaseRev = this.$rev;
|
|
this.$redoStack.forEach(function(x) {
|
|
x[0].id = ++this.$maxRev;
|
|
}, this);
|
|
}
|
|
var deltaSet = this.$redoStack.pop();
|
|
var redoSelectionRange = null;
|
|
|
|
if (deltaSet) {
|
|
redoSelectionRange = session.redoChanges(deltaSet, dontSelect);
|
|
this.$undoStack.push(deltaSet);
|
|
this.$syncRev();
|
|
}
|
|
this.$fromUndo = false;
|
|
|
|
return redoSelectionRange;
|
|
};
|
|
|
|
this.$syncRev = function() {
|
|
var stack = this.$undoStack;
|
|
var nextDelta = stack[stack.length - 1];
|
|
var id = nextDelta && nextDelta[0].id || 0;
|
|
this.$redoStackBaseRev = id;
|
|
this.$rev = id;
|
|
};
|
|
this.reset = function() {
|
|
this.lastDeltas = null;
|
|
this.$lastDelta = null;
|
|
this.$undoStack = [];
|
|
this.$redoStack = [];
|
|
this.$rev = 0;
|
|
this.mark = 0;
|
|
this.$redoStackBaseRev = this.$rev;
|
|
this.selections = [];
|
|
};
|
|
this.canUndo = function() {
|
|
return this.$undoStack.length > 0;
|
|
};
|
|
this.canRedo = function() {
|
|
return this.$redoStack.length > 0;
|
|
};
|
|
this.bookmark = function(rev) {
|
|
if (rev == undefined)
|
|
rev = this.$rev;
|
|
this.mark = rev;
|
|
};
|
|
this.isAtBookmark = function() {
|
|
return this.$rev === this.mark;
|
|
};
|
|
|
|
this.toJSON = function() {
|
|
|
|
};
|
|
|
|
this.fromJSON = function() {
|
|
|
|
};
|
|
|
|
this.hasUndo = this.canUndo;
|
|
this.hasRedo = this.canRedo;
|
|
this.isClean = this.isAtBookmark;
|
|
this.markClean = this.bookmark;
|
|
|
|
this.$prettyPrint = function(delta) {
|
|
if (delta) return stringifyDelta(delta);
|
|
return stringifyDelta(this.$undoStack) + "\n---\n" + stringifyDelta(this.$redoStack);
|
|
};
|
|
}).call(UndoManager.prototype);
|
|
|
|
function rearrangeUndoStack(stack, pos) {
|
|
for (var i = pos; i--; ) {
|
|
var deltaSet = stack[i];
|
|
if (deltaSet && !deltaSet[0].ignore) {
|
|
while(i < pos - 1) {
|
|
var swapped = swapGroups(stack[i], stack[i + 1]);
|
|
stack[i] = swapped[0];
|
|
stack[i + 1] = swapped[1];
|
|
i++;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
var Range = require("./range").Range;
|
|
var cmp = Range.comparePoints;
|
|
var comparePoints = Range.comparePoints;
|
|
|
|
function $updateMarkers(delta) {
|
|
var isInsert = delta.action == "insert";
|
|
var start = delta.start;
|
|
var end = delta.end;
|
|
var rowShift = (end.row - start.row) * (isInsert ? 1 : -1);
|
|
var colShift = (end.column - start.column) * (isInsert ? 1 : -1);
|
|
if (isInsert) end = start;
|
|
|
|
for (var i in this.marks) {
|
|
var point = this.marks[i];
|
|
var cmp = comparePoints(point, start);
|
|
if (cmp < 0) {
|
|
continue; // delta starts after the range
|
|
}
|
|
if (cmp === 0) {
|
|
if (isInsert) {
|
|
if (point.bias == 1) {
|
|
cmp = 1;
|
|
}
|
|
else {
|
|
point.bias == -1;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
var cmp2 = isInsert ? cmp : comparePoints(point, end);
|
|
if (cmp2 > 0) {
|
|
point.row += rowShift;
|
|
point.column += point.row == end.row ? colShift : 0;
|
|
continue;
|
|
}
|
|
if (!isInsert && cmp2 <= 0) {
|
|
point.row = start.row;
|
|
point.column = start.column;
|
|
if (cmp2 === 0)
|
|
point.bias = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
function clonePos(pos) {
|
|
return {row: pos.row,column: pos.column};
|
|
}
|
|
function cloneDelta(d) {
|
|
return {
|
|
start: clonePos(d.start),
|
|
end: clonePos(d.end),
|
|
action: d.action,
|
|
lines: d.lines.slice()
|
|
};
|
|
}
|
|
function stringifyDelta(d) {
|
|
d = d || this;
|
|
if (Array.isArray(d)) {
|
|
return d.map(stringifyDelta).join("\n");
|
|
}
|
|
var type = "";
|
|
if (d.action) {
|
|
type = d.action == "insert" ? "+" : "-";
|
|
type += "[" + d.lines + "]";
|
|
} else if (d.value) {
|
|
if (Array.isArray(d.value)) {
|
|
type = d.value.map(stringifyRange).join("\n");
|
|
} else {
|
|
type = stringifyRange(d.value);
|
|
}
|
|
}
|
|
if (d.start) {
|
|
type += stringifyRange(d);
|
|
}
|
|
if (d.id || d.rev) {
|
|
type += "\t(" + (d.id || d.rev) + ")";
|
|
}
|
|
return type;
|
|
}
|
|
function stringifyRange(r) {
|
|
return r.start.row + ":" + r.start.column
|
|
+ "=>" + r.end.row + ":" + r.end.column;
|
|
}
|
|
|
|
function swap(d1, d2) {
|
|
var i1 = d1.action == "insert";
|
|
var i2 = d2.action == "insert";
|
|
|
|
if (i1 && i2) {
|
|
if (cmp(d2.start, d1.end) >= 0) {
|
|
shift(d2, d1, -1);
|
|
} else if (cmp(d2.start, d1.start) <= 0) {
|
|
shift(d1, d2, +1);
|
|
} else {
|
|
return null;
|
|
}
|
|
} else if (i1 && !i2) {
|
|
if (cmp(d2.start, d1.end) >= 0) {
|
|
shift(d2, d1, -1);
|
|
} else if (cmp(d2.end, d1.start) <= 0) {
|
|
shift(d1, d2, -1);
|
|
} else {
|
|
return null;
|
|
}
|
|
} else if (!i1 && i2) {
|
|
if (cmp(d2.start, d1.start) >= 0) {
|
|
shift(d2, d1, +1);
|
|
} else if (cmp(d2.start, d1.start) <= 0) {
|
|
shift(d1, d2, +1);
|
|
} else {
|
|
return null;
|
|
}
|
|
} else if (!i1 && !i2) {
|
|
if (cmp(d2.start, d1.start) >= 0) {
|
|
shift(d2, d1, +1);
|
|
} else if (cmp(d2.end, d1.start) <= 0) {
|
|
shift(d1, d2, -1);
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
return [d2, d1];
|
|
}
|
|
function swapGroups(ds1, ds2) {
|
|
for (var i = ds1.length; i--; ) {
|
|
for (var j = 0; j < ds2.length; j++) {
|
|
if (!swap(ds1[i], ds2[j])) {
|
|
while (i < ds1.length) {
|
|
while (j--) {
|
|
swap(ds2[j], ds1[i]);
|
|
}
|
|
j = ds2.length;
|
|
i++;
|
|
}
|
|
return [ds1, ds2];
|
|
}
|
|
}
|
|
}
|
|
ds1.selectionBefore = ds2.selectionBefore =
|
|
ds1.selectionAfter = ds2.selectionAfter = null;
|
|
return [ds2, ds1];
|
|
}
|
|
function xform(d1, c1) {
|
|
var i1 = d1.action == "insert";
|
|
var i2 = c1.action == "insert";
|
|
|
|
if (i1 && i2) {
|
|
if (cmp(d1.start, c1.start) < 0) {
|
|
shift(c1, d1, 1);
|
|
} else {
|
|
shift(d1, c1, 1);
|
|
}
|
|
} else if (i1 && !i2) {
|
|
if (cmp(d1.start, c1.end) >= 0) {
|
|
shift(d1, c1, -1);
|
|
} else if (cmp(d1.start, c1.start) <= 0) {
|
|
shift(c1, d1, +1);
|
|
} else {
|
|
shift(d1, Range.fromPoints(c1.start, d1.start), -1);
|
|
shift(c1, d1, +1);
|
|
}
|
|
} else if (!i1 && i2) {
|
|
if (cmp(c1.start, d1.end) >= 0) {
|
|
shift(c1, d1, -1);
|
|
} else if (cmp(c1.start, d1.start) <= 0) {
|
|
shift(d1, c1, +1);
|
|
} else {
|
|
shift(c1, Range.fromPoints(d1.start, c1.start), -1);
|
|
shift(d1, c1, +1);
|
|
}
|
|
} else if (!i1 && !i2) {
|
|
if (cmp(c1.start, d1.end) >= 0) {
|
|
shift(c1, d1, -1);
|
|
} else if (cmp(c1.end, d1.start) <= 0) {
|
|
shift(d1, c1, -1);
|
|
} else {
|
|
var before, after;
|
|
if (cmp(d1.start, c1.start) < 0) {
|
|
before = d1;
|
|
d1 = splitDelta(d1, c1.start);
|
|
}
|
|
if (cmp(d1.end, c1.end) > 0) {
|
|
after = splitDelta(d1, c1.end);
|
|
}
|
|
|
|
shiftPos(c1.end, d1.start, d1.end, -1);
|
|
if (after && !before) {
|
|
d1.lines = after.lines;
|
|
d1.start = after.start;
|
|
d1.end = after.end;
|
|
after = d1;
|
|
}
|
|
|
|
return [c1, before, after].filter(Boolean);
|
|
}
|
|
}
|
|
return [c1, d1];
|
|
}
|
|
|
|
function shift(d1, d2, dir) {
|
|
shiftPos(d1.start, d2.start, d2.end, dir);
|
|
shiftPos(d1.end, d2.start, d2.end, dir);
|
|
}
|
|
function shiftPos(pos, start, end, dir) {
|
|
if (pos.row == (dir == 1 ? start : end).row) {
|
|
pos.column += dir * (end.column - start.column);
|
|
}
|
|
pos.row += dir * (end.row - start.row);
|
|
}
|
|
function splitDelta(c, pos) {
|
|
var lines = c.lines;
|
|
var end = c.end;
|
|
c.end = clonePos(pos);
|
|
var rowsBefore = c.end.row - c.start.row;
|
|
var otherLines = lines.splice(rowsBefore, lines.length);
|
|
|
|
var col = rowsBefore ? pos.column : pos.column - c.start.column;
|
|
lines.push(otherLines[0].substring(0, col));
|
|
otherLines[0] = otherLines[0].substr(col) ;
|
|
var rest = {
|
|
start: clonePos(pos),
|
|
end: end,
|
|
lines: otherLines,
|
|
action: c.action
|
|
};
|
|
return rest;
|
|
}
|
|
|
|
function moveDeltasByOne(redoStack, d) {
|
|
d = cloneDelta(d);
|
|
for (var j = redoStack.length; j--;) {
|
|
var deltaSet = redoStack[j];
|
|
for (var i = 0; i < deltaSet.length; i++) {
|
|
var x = deltaSet[i];
|
|
var xformed = xform(x, d);
|
|
d = xformed[0];
|
|
if (xformed.length != 2) {
|
|
if (xformed[2]) {
|
|
deltaSet.splice(i + 1, 1, xformed[1], xformed[2]);
|
|
i++;
|
|
} else if (!xformed[1]) {
|
|
deltaSet.splice(i, 1);
|
|
i--;
|
|
}
|
|
}
|
|
}
|
|
if (!deltaSet.length) {
|
|
redoStack.splice(j, 1);
|
|
}
|
|
}
|
|
return redoStack;
|
|
}
|
|
function rebaseRedoStack(redoStack, deltaSets) {
|
|
for (var i = 0; i < deltaSets.length; i++) {
|
|
var deltas = deltaSets[i];
|
|
for (var j = 0; j < deltas.length; j++) {
|
|
moveDeltasByOne(redoStack, deltas[j]);
|
|
}
|
|
}
|
|
}
|
|
|
|
exports.UndoManager = UndoManager;
|
|
|
|
});
|
|
|
|
ace.define("ace/layer/lines",["require","exports","module","ace/lib/dom"], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var dom = require("../lib/dom");
|
|
|
|
var Lines = function(element, canvasHeight) {
|
|
this.element = element;
|
|
this.canvasHeight = canvasHeight || 500000;
|
|
this.element.style.height = (this.canvasHeight * 2) + "px";
|
|
|
|
this.cells = [];
|
|
this.cellCache = [];
|
|
this.$offsetCoefficient = 0;
|
|
};
|
|
|
|
(function() {
|
|
|
|
this.moveContainer = function(config) {
|
|
dom.translate(this.element, 0, -((config.firstRowScreen * config.lineHeight) % this.canvasHeight) - config.offset * this.$offsetCoefficient);
|
|
};
|
|
|
|
this.pageChanged = function(oldConfig, newConfig) {
|
|
return (
|
|
Math.floor((oldConfig.firstRowScreen * oldConfig.lineHeight) / this.canvasHeight) !==
|
|
Math.floor((newConfig.firstRowScreen * newConfig.lineHeight) / this.canvasHeight)
|
|
);
|
|
};
|
|
|
|
this.computeLineTop = function(row, config, session) {
|
|
var screenTop = config.firstRowScreen * config.lineHeight;
|
|
var screenPage = Math.floor(screenTop / this.canvasHeight);
|
|
var lineTop = session.documentToScreenRow(row, 0) * config.lineHeight;
|
|
return lineTop - (screenPage * this.canvasHeight);
|
|
};
|
|
|
|
this.computeLineHeight = function(row, config, session) {
|
|
return config.lineHeight * session.getRowLineCount(row);
|
|
};
|
|
|
|
this.getLength = function() {
|
|
return this.cells.length;
|
|
};
|
|
|
|
this.get = function(index) {
|
|
return this.cells[index];
|
|
};
|
|
|
|
this.shift = function() {
|
|
this.$cacheCell(this.cells.shift());
|
|
};
|
|
|
|
this.pop = function() {
|
|
this.$cacheCell(this.cells.pop());
|
|
};
|
|
|
|
this.push = function(cell) {
|
|
if (Array.isArray(cell)) {
|
|
this.cells.push.apply(this.cells, cell);
|
|
var fragment = dom.createFragment(this.element);
|
|
for (var i=0; i<cell.length; i++) {
|
|
fragment.appendChild(cell[i].element);
|
|
}
|
|
this.element.appendChild(fragment);
|
|
} else {
|
|
this.cells.push(cell);
|
|
this.element.appendChild(cell.element);
|
|
}
|
|
};
|
|
|
|
this.unshift = function(cell) {
|
|
if (Array.isArray(cell)) {
|
|
this.cells.unshift.apply(this.cells, cell);
|
|
var fragment = dom.createFragment(this.element);
|
|
for (var i=0; i<cell.length; i++) {
|
|
fragment.appendChild(cell[i].element);
|
|
}
|
|
if (this.element.firstChild)
|
|
this.element.insertBefore(fragment, this.element.firstChild);
|
|
else
|
|
this.element.appendChild(fragment);
|
|
} else {
|
|
this.cells.unshift(cell);
|
|
this.element.insertAdjacentElement("afterbegin", cell.element);
|
|
}
|
|
};
|
|
|
|
this.last = function() {
|
|
if (this.cells.length)
|
|
return this.cells[this.cells.length-1];
|
|
else
|
|
return null;
|
|
};
|
|
|
|
this.$cacheCell = function(cell) {
|
|
if (!cell)
|
|
return;
|
|
|
|
cell.element.remove();
|
|
this.cellCache.push(cell);
|
|
};
|
|
|
|
this.createCell = function(row, config, session, initElement) {
|
|
var cell = this.cellCache.pop();
|
|
if (!cell) {
|
|
var element = dom.createElement("div");
|
|
if (initElement)
|
|
initElement(element);
|
|
|
|
this.element.appendChild(element);
|
|
|
|
cell = {
|
|
element: element,
|
|
text: "",
|
|
row: row
|
|
};
|
|
}
|
|
cell.row = row;
|
|
|
|
return cell;
|
|
};
|
|
|
|
}).call(Lines.prototype);
|
|
|
|
exports.Lines = Lines;
|
|
|
|
});
|
|
|
|
ace.define("ace/layer/gutter",["require","exports","module","ace/lib/dom","ace/lib/oop","ace/lib/lang","ace/lib/event_emitter","ace/layer/lines"], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var dom = require("../lib/dom");
|
|
var oop = require("../lib/oop");
|
|
var lang = require("../lib/lang");
|
|
var EventEmitter = require("../lib/event_emitter").EventEmitter;
|
|
var Lines = require("./lines").Lines;
|
|
|
|
var Gutter = function(parentEl) {
|
|
this.element = dom.createElement("div");
|
|
this.element.className = "ace_layer ace_gutter-layer";
|
|
parentEl.appendChild(this.element);
|
|
this.setShowFoldWidgets(this.$showFoldWidgets);
|
|
|
|
this.gutterWidth = 0;
|
|
|
|
this.$annotations = [];
|
|
this.$updateAnnotations = this.$updateAnnotations.bind(this);
|
|
|
|
this.$lines = new Lines(this.element);
|
|
this.$lines.$offsetCoefficient = 1;
|
|
};
|
|
|
|
(function() {
|
|
|
|
oop.implement(this, EventEmitter);
|
|
|
|
this.setSession = function(session) {
|
|
if (this.session)
|
|
this.session.off("change", this.$updateAnnotations);
|
|
this.session = session;
|
|
if (session)
|
|
session.on("change", this.$updateAnnotations);
|
|
};
|
|
|
|
this.addGutterDecoration = function(row, className) {
|
|
if (window.console)
|
|
console.warn && console.warn("deprecated use session.addGutterDecoration");
|
|
this.session.addGutterDecoration(row, className);
|
|
};
|
|
|
|
this.removeGutterDecoration = function(row, className) {
|
|
if (window.console)
|
|
console.warn && console.warn("deprecated use session.removeGutterDecoration");
|
|
this.session.removeGutterDecoration(row, className);
|
|
};
|
|
|
|
this.setAnnotations = function(annotations) {
|
|
this.$annotations = [];
|
|
for (var i = 0; i < annotations.length; i++) {
|
|
var annotation = annotations[i];
|
|
var row = annotation.row;
|
|
var rowInfo = this.$annotations[row];
|
|
if (!rowInfo)
|
|
rowInfo = this.$annotations[row] = {text: []};
|
|
|
|
var annoText = annotation.text;
|
|
annoText = annoText ? lang.escapeHTML(annoText) : annotation.html || "";
|
|
|
|
if (rowInfo.text.indexOf(annoText) === -1)
|
|
rowInfo.text.push(annoText);
|
|
|
|
var type = annotation.type;
|
|
if (type == "error")
|
|
rowInfo.className = " ace_error";
|
|
else if (type == "warning" && rowInfo.className != " ace_error")
|
|
rowInfo.className = " ace_warning";
|
|
else if (type == "info" && (!rowInfo.className))
|
|
rowInfo.className = " ace_info";
|
|
}
|
|
};
|
|
|
|
this.$updateAnnotations = function (delta) {
|
|
if (!this.$annotations.length)
|
|
return;
|
|
var firstRow = delta.start.row;
|
|
var len = delta.end.row - firstRow;
|
|
if (len === 0) {
|
|
} else if (delta.action == 'remove') {
|
|
this.$annotations.splice(firstRow, len + 1, null);
|
|
} else {
|
|
var args = new Array(len + 1);
|
|
args.unshift(firstRow, 1);
|
|
this.$annotations.splice.apply(this.$annotations, args);
|
|
}
|
|
};
|
|
|
|
this.update = function(config) {
|
|
this.config = config;
|
|
|
|
var session = this.session;
|
|
var firstRow = config.firstRow;
|
|
var lastRow = Math.min(config.lastRow + config.gutterOffset, // needed to compensate for hor scollbar
|
|
session.getLength() - 1);
|
|
|
|
this.oldLastRow = lastRow;
|
|
this.config = config;
|
|
|
|
this.$lines.moveContainer(config);
|
|
this.$updateCursorRow();
|
|
|
|
var fold = session.getNextFoldLine(firstRow);
|
|
var foldStart = fold ? fold.start.row : Infinity;
|
|
|
|
var cell = null;
|
|
var index = -1;
|
|
var row = firstRow;
|
|
|
|
while (true) {
|
|
if (row > foldStart) {
|
|
row = fold.end.row + 1;
|
|
fold = session.getNextFoldLine(row, fold);
|
|
foldStart = fold ? fold.start.row : Infinity;
|
|
}
|
|
if (row > lastRow) {
|
|
while (this.$lines.getLength() > index + 1)
|
|
this.$lines.pop();
|
|
|
|
break;
|
|
}
|
|
|
|
cell = this.$lines.get(++index);
|
|
if (cell) {
|
|
cell.row = row;
|
|
} else {
|
|
cell = this.$lines.createCell(row, config, this.session, onCreateCell);
|
|
this.$lines.push(cell);
|
|
}
|
|
|
|
this.$renderCell(cell, config, fold, row);
|
|
row++;
|
|
}
|
|
|
|
this._signal("afterRender");
|
|
this.$updateGutterWidth(config);
|
|
};
|
|
|
|
this.$updateGutterWidth = function(config) {
|
|
var session = this.session;
|
|
|
|
var gutterRenderer = session.gutterRenderer || this.$renderer;
|
|
|
|
var firstLineNumber = session.$firstLineNumber;
|
|
var lastLineText = this.$lines.last() ? this.$lines.last().text : "";
|
|
|
|
if (this.$fixedWidth || session.$useWrapMode)
|
|
lastLineText = session.getLength() + firstLineNumber - 1;
|
|
|
|
var gutterWidth = gutterRenderer
|
|
? gutterRenderer.getWidth(session, lastLineText, config)
|
|
: lastLineText.toString().length * config.characterWidth;
|
|
|
|
var padding = this.$padding || this.$computePadding();
|
|
gutterWidth += padding.left + padding.right;
|
|
if (gutterWidth !== this.gutterWidth && !isNaN(gutterWidth)) {
|
|
this.gutterWidth = gutterWidth;
|
|
this.element.parentNode.style.width =
|
|
this.element.style.width = Math.ceil(this.gutterWidth) + "px";
|
|
this._signal("changeGutterWidth", gutterWidth);
|
|
}
|
|
};
|
|
|
|
this.$updateCursorRow = function() {
|
|
if (!this.$highlightGutterLine)
|
|
return;
|
|
|
|
var position = this.session.selection.getCursor();
|
|
if (this.$cursorRow === position.row)
|
|
return;
|
|
|
|
this.$cursorRow = position.row;
|
|
};
|
|
|
|
this.updateLineHighlight = function() {
|
|
if (!this.$highlightGutterLine)
|
|
return;
|
|
var row = this.session.selection.cursor.row;
|
|
this.$cursorRow = row;
|
|
|
|
if (this.$cursorCell && this.$cursorCell.row == row)
|
|
return;
|
|
if (this.$cursorCell)
|
|
this.$cursorCell.element.className = this.$cursorCell.element.className.replace("ace_gutter-active-line ", "");
|
|
var cells = this.$lines.cells;
|
|
this.$cursorCell = null;
|
|
for (var i = 0; i < cells.length; i++) {
|
|
var cell = cells[i];
|
|
if (cell.row >= this.$cursorRow) {
|
|
if (cell.row > this.$cursorRow) {
|
|
var fold = this.session.getFoldLine(this.$cursorRow);
|
|
if (i > 0 && fold && fold.start.row == cells[i - 1].row)
|
|
cell = cells[i - 1];
|
|
else
|
|
break;
|
|
}
|
|
cell.element.className = "ace_gutter-active-line " + cell.element.className;
|
|
this.$cursorCell = cell;
|
|
break;
|
|
}
|
|
}
|
|
};
|
|
|
|
this.scrollLines = function(config) {
|
|
var oldConfig = this.config;
|
|
this.config = config;
|
|
|
|
this.$updateCursorRow();
|
|
if (this.$lines.pageChanged(oldConfig, config))
|
|
return this.update(config);
|
|
|
|
this.$lines.moveContainer(config);
|
|
|
|
var lastRow = Math.min(config.lastRow + config.gutterOffset, // needed to compensate for hor scollbar
|
|
this.session.getLength() - 1);
|
|
var oldLastRow = this.oldLastRow;
|
|
this.oldLastRow = lastRow;
|
|
|
|
if (!oldConfig || oldLastRow < config.firstRow)
|
|
return this.update(config);
|
|
|
|
if (lastRow < oldConfig.firstRow)
|
|
return this.update(config);
|
|
|
|
if (oldConfig.firstRow < config.firstRow)
|
|
for (var row=this.session.getFoldedRowCount(oldConfig.firstRow, config.firstRow - 1); row>0; row--)
|
|
this.$lines.shift();
|
|
|
|
if (oldLastRow > lastRow)
|
|
for (var row=this.session.getFoldedRowCount(lastRow + 1, oldLastRow); row>0; row--)
|
|
this.$lines.pop();
|
|
|
|
if (config.firstRow < oldConfig.firstRow) {
|
|
this.$lines.unshift(this.$renderLines(config, config.firstRow, oldConfig.firstRow - 1));
|
|
}
|
|
|
|
if (lastRow > oldLastRow) {
|
|
this.$lines.push(this.$renderLines(config, oldLastRow + 1, lastRow));
|
|
}
|
|
|
|
this.updateLineHighlight();
|
|
|
|
this._signal("afterRender");
|
|
this.$updateGutterWidth(config);
|
|
};
|
|
|
|
this.$renderLines = function(config, firstRow, lastRow) {
|
|
var fragment = [];
|
|
var row = firstRow;
|
|
var foldLine = this.session.getNextFoldLine(row);
|
|
var foldStart = foldLine ? foldLine.start.row : Infinity;
|
|
|
|
while (true) {
|
|
if (row > foldStart) {
|
|
row = foldLine.end.row+1;
|
|
foldLine = this.session.getNextFoldLine(row, foldLine);
|
|
foldStart = foldLine ? foldLine.start.row : Infinity;
|
|
}
|
|
if (row > lastRow)
|
|
break;
|
|
|
|
var cell = this.$lines.createCell(row, config, this.session, onCreateCell);
|
|
this.$renderCell(cell, config, foldLine, row);
|
|
fragment.push(cell);
|
|
|
|
row++;
|
|
}
|
|
return fragment;
|
|
};
|
|
|
|
this.$renderCell = function(cell, config, fold, row) {
|
|
var element = cell.element;
|
|
|
|
var session = this.session;
|
|
|
|
var textNode = element.childNodes[0];
|
|
var foldWidget = element.childNodes[1];
|
|
|
|
var firstLineNumber = session.$firstLineNumber;
|
|
|
|
var breakpoints = session.$breakpoints;
|
|
var decorations = session.$decorations;
|
|
var gutterRenderer = session.gutterRenderer || this.$renderer;
|
|
var foldWidgets = this.$showFoldWidgets && session.foldWidgets;
|
|
var foldStart = fold ? fold.start.row : Number.MAX_VALUE;
|
|
|
|
var className = "ace_gutter-cell ";
|
|
if (this.$highlightGutterLine) {
|
|
if (row == this.$cursorRow || (fold && row < this.$cursorRow && row >= foldStart && this.$cursorRow <= fold.end.row)) {
|
|
className += "ace_gutter-active-line ";
|
|
if (this.$cursorCell != cell) {
|
|
if (this.$cursorCell)
|
|
this.$cursorCell.element.className = this.$cursorCell.element.className.replace("ace_gutter-active-line ", "");
|
|
this.$cursorCell = cell;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (breakpoints[row])
|
|
className += breakpoints[row];
|
|
if (decorations[row])
|
|
className += decorations[row];
|
|
if (this.$annotations[row])
|
|
className += this.$annotations[row].className;
|
|
if (element.className != className)
|
|
element.className = className;
|
|
|
|
if (foldWidgets) {
|
|
var c = foldWidgets[row];
|
|
if (c == null)
|
|
c = foldWidgets[row] = session.getFoldWidget(row);
|
|
}
|
|
|
|
if (c) {
|
|
var className = "ace_fold-widget ace_" + c;
|
|
if (c == "start" && row == foldStart && row < fold.end.row)
|
|
className += " ace_closed";
|
|
else
|
|
className += " ace_open";
|
|
if (foldWidget.className != className)
|
|
foldWidget.className = className;
|
|
|
|
var foldHeight = config.lineHeight + "px";
|
|
dom.setStyle(foldWidget.style, "height", foldHeight);
|
|
dom.setStyle(foldWidget.style, "display", "inline-block");
|
|
} else {
|
|
if (foldWidget) {
|
|
dom.setStyle(foldWidget.style, "display", "none");
|
|
}
|
|
}
|
|
|
|
var text = (gutterRenderer
|
|
? gutterRenderer.getText(session, row)
|
|
: row + firstLineNumber).toString();
|
|
|
|
if (text !== textNode.data) {
|
|
textNode.data = text;
|
|
}
|
|
|
|
dom.setStyle(cell.element.style, "height", this.$lines.computeLineHeight(row, config, session) + "px");
|
|
dom.setStyle(cell.element.style, "top", this.$lines.computeLineTop(row, config, session) + "px");
|
|
|
|
cell.text = text;
|
|
return cell;
|
|
};
|
|
|
|
this.$fixedWidth = false;
|
|
|
|
this.$highlightGutterLine = true;
|
|
this.$renderer = "";
|
|
this.setHighlightGutterLine = function(highlightGutterLine) {
|
|
this.$highlightGutterLine = highlightGutterLine;
|
|
};
|
|
|
|
this.$showLineNumbers = true;
|
|
this.$renderer = "";
|
|
this.setShowLineNumbers = function(show) {
|
|
this.$renderer = !show && {
|
|
getWidth: function() {return 0;},
|
|
getText: function() {return "";}
|
|
};
|
|
};
|
|
|
|
this.getShowLineNumbers = function() {
|
|
return this.$showLineNumbers;
|
|
};
|
|
|
|
this.$showFoldWidgets = true;
|
|
this.setShowFoldWidgets = function(show) {
|
|
if (show)
|
|
dom.addCssClass(this.element, "ace_folding-enabled");
|
|
else
|
|
dom.removeCssClass(this.element, "ace_folding-enabled");
|
|
|
|
this.$showFoldWidgets = show;
|
|
this.$padding = null;
|
|
};
|
|
|
|
this.getShowFoldWidgets = function() {
|
|
return this.$showFoldWidgets;
|
|
};
|
|
|
|
this.$computePadding = function() {
|
|
if (!this.element.firstChild)
|
|
return {left: 0, right: 0};
|
|
var style = dom.computedStyle(this.element.firstChild);
|
|
this.$padding = {};
|
|
this.$padding.left = (parseInt(style.borderLeftWidth) || 0)
|
|
+ (parseInt(style.paddingLeft) || 0) + 1;
|
|
this.$padding.right = (parseInt(style.borderRightWidth) || 0)
|
|
+ (parseInt(style.paddingRight) || 0);
|
|
return this.$padding;
|
|
};
|
|
|
|
this.getRegion = function(point) {
|
|
var padding = this.$padding || this.$computePadding();
|
|
var rect = this.element.getBoundingClientRect();
|
|
if (point.x < padding.left + rect.left)
|
|
return "markers";
|
|
if (this.$showFoldWidgets && point.x > rect.right - padding.right)
|
|
return "foldWidgets";
|
|
};
|
|
|
|
}).call(Gutter.prototype);
|
|
|
|
function onCreateCell(element) {
|
|
var textNode = document.createTextNode('');
|
|
element.appendChild(textNode);
|
|
|
|
var foldWidget = dom.createElement("span");
|
|
element.appendChild(foldWidget);
|
|
|
|
return element;
|
|
}
|
|
|
|
exports.Gutter = Gutter;
|
|
|
|
});
|
|
|
|
ace.define("ace/layer/marker",["require","exports","module","ace/range","ace/lib/dom"], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var Range = require("../range").Range;
|
|
var dom = require("../lib/dom");
|
|
|
|
var Marker = function(parentEl) {
|
|
this.element = dom.createElement("div");
|
|
this.element.className = "ace_layer ace_marker-layer";
|
|
parentEl.appendChild(this.element);
|
|
};
|
|
|
|
(function() {
|
|
|
|
this.$padding = 0;
|
|
|
|
this.setPadding = function(padding) {
|
|
this.$padding = padding;
|
|
};
|
|
this.setSession = function(session) {
|
|
this.session = session;
|
|
};
|
|
|
|
this.setMarkers = function(markers) {
|
|
this.markers = markers;
|
|
};
|
|
|
|
this.elt = function(className, css) {
|
|
var x = this.i != -1 && this.element.childNodes[this.i];
|
|
if (!x) {
|
|
x = document.createElement("div");
|
|
this.element.appendChild(x);
|
|
this.i = -1;
|
|
} else {
|
|
this.i++;
|
|
}
|
|
x.style.cssText = css;
|
|
x.className = className;
|
|
};
|
|
|
|
this.update = function(config) {
|
|
if (!config) return;
|
|
|
|
this.config = config;
|
|
|
|
this.i = 0;
|
|
var html;
|
|
for (var key in this.markers) {
|
|
var marker = this.markers[key];
|
|
|
|
if (!marker.range) {
|
|
marker.update(html, this, this.session, config);
|
|
continue;
|
|
}
|
|
|
|
var range = marker.range.clipRows(config.firstRow, config.lastRow);
|
|
if (range.isEmpty()) continue;
|
|
|
|
range = range.toScreenRange(this.session);
|
|
if (marker.renderer) {
|
|
var top = this.$getTop(range.start.row, config);
|
|
var left = this.$padding + range.start.column * config.characterWidth;
|
|
marker.renderer(html, range, left, top, config);
|
|
} else if (marker.type == "fullLine") {
|
|
this.drawFullLineMarker(html, range, marker.clazz, config);
|
|
} else if (marker.type == "screenLine") {
|
|
this.drawScreenLineMarker(html, range, marker.clazz, config);
|
|
} else if (range.isMultiLine()) {
|
|
if (marker.type == "text")
|
|
this.drawTextMarker(html, range, marker.clazz, config);
|
|
else
|
|
this.drawMultiLineMarker(html, range, marker.clazz, config);
|
|
} else {
|
|
this.drawSingleLineMarker(html, range, marker.clazz + " ace_start" + " ace_br15", config);
|
|
}
|
|
}
|
|
if (this.i !=-1) {
|
|
while (this.i < this.element.childElementCount)
|
|
this.element.removeChild(this.element.lastChild);
|
|
}
|
|
};
|
|
|
|
this.$getTop = function(row, layerConfig) {
|
|
return (row - layerConfig.firstRowScreen) * layerConfig.lineHeight;
|
|
};
|
|
|
|
function getBorderClass(tl, tr, br, bl) {
|
|
return (tl ? 1 : 0) | (tr ? 2 : 0) | (br ? 4 : 0) | (bl ? 8 : 0);
|
|
}
|
|
this.drawTextMarker = function(stringBuilder, range, clazz, layerConfig, extraStyle) {
|
|
var session = this.session;
|
|
var start = range.start.row;
|
|
var end = range.end.row;
|
|
var row = start;
|
|
var prev = 0;
|
|
var curr = 0;
|
|
var next = session.getScreenLastRowColumn(row);
|
|
var lineRange = new Range(row, range.start.column, row, curr);
|
|
for (; row <= end; row++) {
|
|
lineRange.start.row = lineRange.end.row = row;
|
|
lineRange.start.column = row == start ? range.start.column : session.getRowWrapIndent(row);
|
|
lineRange.end.column = next;
|
|
prev = curr;
|
|
curr = next;
|
|
next = row + 1 < end ? session.getScreenLastRowColumn(row + 1) : row == end ? 0 : range.end.column;
|
|
this.drawSingleLineMarker(stringBuilder, lineRange,
|
|
clazz + (row == start ? " ace_start" : "") + " ace_br"
|
|
+ getBorderClass(row == start || row == start + 1 && range.start.column, prev < curr, curr > next, row == end),
|
|
layerConfig, row == end ? 0 : 1, extraStyle);
|
|
}
|
|
};
|
|
this.drawMultiLineMarker = function(stringBuilder, range, clazz, config, extraStyle) {
|
|
var padding = this.$padding;
|
|
var height = config.lineHeight;
|
|
var top = this.$getTop(range.start.row, config);
|
|
var left = padding + range.start.column * config.characterWidth;
|
|
extraStyle = extraStyle || "";
|
|
|
|
if (this.session.$bidiHandler.isBidiRow(range.start.row)) {
|
|
var range1 = range.clone();
|
|
range1.end.row = range1.start.row;
|
|
range1.end.column = this.session.getLine(range1.start.row).length;
|
|
this.drawBidiSingleLineMarker(stringBuilder, range1, clazz + " ace_br1 ace_start", config, null, extraStyle);
|
|
} else {
|
|
this.elt(
|
|
clazz + " ace_br1 ace_start",
|
|
"height:"+ height+ "px;"+ "right:0;"+ "top:"+top+ "px;left:"+ left+ "px;" + (extraStyle || "")
|
|
);
|
|
}
|
|
if (this.session.$bidiHandler.isBidiRow(range.end.row)) {
|
|
var range1 = range.clone();
|
|
range1.start.row = range1.end.row;
|
|
range1.start.column = 0;
|
|
this.drawBidiSingleLineMarker(stringBuilder, range1, clazz + " ace_br12", config, null, extraStyle);
|
|
} else {
|
|
top = this.$getTop(range.end.row, config);
|
|
var width = range.end.column * config.characterWidth;
|
|
|
|
this.elt(
|
|
clazz + " ace_br12",
|
|
"height:"+ height+ "px;"+
|
|
"width:"+ width+ "px;"+
|
|
"top:"+ top+ "px;"+
|
|
"left:"+ padding+ "px;"+ (extraStyle || "")
|
|
);
|
|
}
|
|
height = (range.end.row - range.start.row - 1) * config.lineHeight;
|
|
if (height <= 0)
|
|
return;
|
|
top = this.$getTop(range.start.row + 1, config);
|
|
|
|
var radiusClass = (range.start.column ? 1 : 0) | (range.end.column ? 0 : 8);
|
|
|
|
this.elt(
|
|
clazz + (radiusClass ? " ace_br" + radiusClass : ""),
|
|
"height:"+ height+ "px;"+
|
|
"right:0;"+
|
|
"top:"+ top+ "px;"+
|
|
"left:"+ padding+ "px;"+ (extraStyle || "")
|
|
);
|
|
};
|
|
this.drawSingleLineMarker = function(stringBuilder, range, clazz, config, extraLength, extraStyle) {
|
|
if (this.session.$bidiHandler.isBidiRow(range.start.row))
|
|
return this.drawBidiSingleLineMarker(stringBuilder, range, clazz, config, extraLength, extraStyle);
|
|
var height = config.lineHeight;
|
|
var width = (range.end.column + (extraLength || 0) - range.start.column) * config.characterWidth;
|
|
|
|
var top = this.$getTop(range.start.row, config);
|
|
var left = this.$padding + range.start.column * config.characterWidth;
|
|
|
|
this.elt(
|
|
clazz,
|
|
"height:"+ height+ "px;"+
|
|
"width:"+ width+ "px;"+
|
|
"top:"+ top+ "px;"+
|
|
"left:"+ left+ "px;"+ (extraStyle || "")
|
|
);
|
|
};
|
|
this.drawBidiSingleLineMarker = function(stringBuilder, range, clazz, config, extraLength, extraStyle) {
|
|
var height = config.lineHeight, top = this.$getTop(range.start.row, config), padding = this.$padding;
|
|
var selections = this.session.$bidiHandler.getSelections(range.start.column, range.end.column);
|
|
|
|
selections.forEach(function(selection) {
|
|
this.elt(
|
|
clazz,
|
|
"height:" + height + "px;" +
|
|
"width:" + selection.width + (extraLength || 0) + "px;" +
|
|
"top:" + top + "px;" +
|
|
"left:" + (padding + selection.left) + "px;" + (extraStyle || "")
|
|
);
|
|
}, this);
|
|
};
|
|
|
|
this.drawFullLineMarker = function(stringBuilder, range, clazz, config, extraStyle) {
|
|
var top = this.$getTop(range.start.row, config);
|
|
var height = config.lineHeight;
|
|
if (range.start.row != range.end.row)
|
|
height += this.$getTop(range.end.row, config) - top;
|
|
|
|
this.elt(
|
|
clazz,
|
|
"height:"+ height+ "px;"+
|
|
"top:"+ top+ "px;"+
|
|
"left:0;right:0;"+ (extraStyle || "")
|
|
);
|
|
};
|
|
|
|
this.drawScreenLineMarker = function(stringBuilder, range, clazz, config, extraStyle) {
|
|
var top = this.$getTop(range.start.row, config);
|
|
var height = config.lineHeight;
|
|
|
|
this.elt(
|
|
clazz,
|
|
"height:"+ height+ "px;"+
|
|
"top:"+ top+ "px;"+
|
|
"left:0;right:0;"+ (extraStyle || "")
|
|
);
|
|
};
|
|
|
|
}).call(Marker.prototype);
|
|
|
|
exports.Marker = Marker;
|
|
|
|
});
|
|
|
|
ace.define("ace/layer/text",["require","exports","module","ace/lib/oop","ace/lib/dom","ace/lib/lang","ace/layer/lines","ace/lib/event_emitter"], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var oop = require("../lib/oop");
|
|
var dom = require("../lib/dom");
|
|
var lang = require("../lib/lang");
|
|
var Lines = require("./lines").Lines;
|
|
var EventEmitter = require("../lib/event_emitter").EventEmitter;
|
|
|
|
var Text = function(parentEl) {
|
|
this.dom = dom;
|
|
this.element = this.dom.createElement("div");
|
|
this.element.className = "ace_layer ace_text-layer";
|
|
parentEl.appendChild(this.element);
|
|
this.$updateEolChar = this.$updateEolChar.bind(this);
|
|
this.$lines = new Lines(this.element);
|
|
};
|
|
|
|
(function() {
|
|
|
|
oop.implement(this, EventEmitter);
|
|
|
|
this.EOF_CHAR = "\xB6";
|
|
this.EOL_CHAR_LF = "\xAC";
|
|
this.EOL_CHAR_CRLF = "\xa4";
|
|
this.EOL_CHAR = this.EOL_CHAR_LF;
|
|
this.TAB_CHAR = "\u2014"; //"\u21E5";
|
|
this.SPACE_CHAR = "\xB7";
|
|
this.$padding = 0;
|
|
this.MAX_LINE_LENGTH = 10000;
|
|
|
|
this.$updateEolChar = function() {
|
|
var doc = this.session.doc;
|
|
var unixMode = doc.getNewLineCharacter() == "\n" && doc.getNewLineMode() != "windows";
|
|
var EOL_CHAR = unixMode ? this.EOL_CHAR_LF : this.EOL_CHAR_CRLF;
|
|
if (this.EOL_CHAR != EOL_CHAR) {
|
|
this.EOL_CHAR = EOL_CHAR;
|
|
return true;
|
|
}
|
|
};
|
|
|
|
this.setPadding = function(padding) {
|
|
this.$padding = padding;
|
|
this.element.style.margin = "0 " + padding + "px";
|
|
};
|
|
|
|
this.getLineHeight = function() {
|
|
return this.$fontMetrics.$characterSize.height || 0;
|
|
};
|
|
|
|
this.getCharacterWidth = function() {
|
|
return this.$fontMetrics.$characterSize.width || 0;
|
|
};
|
|
|
|
this.$setFontMetrics = function(measure) {
|
|
this.$fontMetrics = measure;
|
|
this.$fontMetrics.on("changeCharacterSize", function(e) {
|
|
this._signal("changeCharacterSize", e);
|
|
}.bind(this));
|
|
this.$pollSizeChanges();
|
|
};
|
|
|
|
this.checkForSizeChanges = function() {
|
|
this.$fontMetrics.checkForSizeChanges();
|
|
};
|
|
this.$pollSizeChanges = function() {
|
|
return this.$pollSizeChangesTimer = this.$fontMetrics.$pollSizeChanges();
|
|
};
|
|
this.setSession = function(session) {
|
|
this.session = session;
|
|
if (session)
|
|
this.$computeTabString();
|
|
};
|
|
|
|
this.showInvisibles = false;
|
|
this.showSpaces = false;
|
|
this.showTabs = false;
|
|
this.showEOL = false;
|
|
this.setShowInvisibles = function(showInvisibles) {
|
|
if (this.showInvisibles == showInvisibles)
|
|
return false;
|
|
|
|
this.showInvisibles = showInvisibles;
|
|
if (typeof showInvisibles == "string") {
|
|
this.showSpaces = /tab/i.test(showInvisibles);
|
|
this.showTabs = /space/i.test(showInvisibles);
|
|
this.showEOL = /eol/i.test(showInvisibles);
|
|
} else {
|
|
this.showSpaces = this.showTabs = this.showEOL = showInvisibles;
|
|
}
|
|
this.$computeTabString();
|
|
return true;
|
|
};
|
|
|
|
this.displayIndentGuides = true;
|
|
this.setDisplayIndentGuides = function(display) {
|
|
if (this.displayIndentGuides == display)
|
|
return false;
|
|
|
|
this.displayIndentGuides = display;
|
|
this.$computeTabString();
|
|
return true;
|
|
};
|
|
|
|
this.$tabStrings = [];
|
|
this.onChangeTabSize =
|
|
this.$computeTabString = function() {
|
|
var tabSize = this.session.getTabSize();
|
|
this.tabSize = tabSize;
|
|
var tabStr = this.$tabStrings = [0];
|
|
for (var i = 1; i < tabSize + 1; i++) {
|
|
if (this.showTabs) {
|
|
var span = this.dom.createElement("span");
|
|
span.className = "ace_invisible ace_invisible_tab";
|
|
span.textContent = lang.stringRepeat(this.TAB_CHAR, i);
|
|
tabStr.push(span);
|
|
} else {
|
|
tabStr.push(this.dom.createTextNode(lang.stringRepeat(" ", i), this.element));
|
|
}
|
|
}
|
|
if (this.displayIndentGuides) {
|
|
this.$indentGuideRe = /\s\S| \t|\t |\s$/;
|
|
var className = "ace_indent-guide";
|
|
var spaceClass = this.showSpaces ? " ace_invisible ace_invisible_space" : "";
|
|
var spaceContent = this.showSpaces
|
|
? lang.stringRepeat(this.SPACE_CHAR, this.tabSize)
|
|
: lang.stringRepeat(" ", this.tabSize);
|
|
|
|
var tabClass = this.showTabs ? " ace_invisible ace_invisible_tab" : "";
|
|
var tabContent = this.showTabs
|
|
? lang.stringRepeat(this.TAB_CHAR, this.tabSize)
|
|
: spaceContent;
|
|
|
|
var span = this.dom.createElement("span");
|
|
span.className = className + spaceClass;
|
|
span.textContent = spaceContent;
|
|
this.$tabStrings[" "] = span;
|
|
|
|
var span = this.dom.createElement("span");
|
|
span.className = className + tabClass;
|
|
span.textContent = tabContent;
|
|
this.$tabStrings["\t"] = span;
|
|
}
|
|
};
|
|
|
|
this.updateLines = function(config, firstRow, lastRow) {
|
|
if (this.config.lastRow != config.lastRow ||
|
|
this.config.firstRow != config.firstRow) {
|
|
return this.update(config);
|
|
}
|
|
|
|
this.config = config;
|
|
|
|
var first = Math.max(firstRow, config.firstRow);
|
|
var last = Math.min(lastRow, config.lastRow);
|
|
|
|
var lineElements = this.element.childNodes;
|
|
var lineElementsIdx = 0;
|
|
|
|
for (var row = config.firstRow; row < first; row++) {
|
|
var foldLine = this.session.getFoldLine(row);
|
|
if (foldLine) {
|
|
if (foldLine.containsRow(first)) {
|
|
first = foldLine.start.row;
|
|
break;
|
|
} else {
|
|
row = foldLine.end.row;
|
|
}
|
|
}
|
|
lineElementsIdx ++;
|
|
}
|
|
|
|
var heightChanged = false;
|
|
var row = first;
|
|
var foldLine = this.session.getNextFoldLine(row);
|
|
var foldStart = foldLine ? foldLine.start.row : Infinity;
|
|
|
|
while (true) {
|
|
if (row > foldStart) {
|
|
row = foldLine.end.row+1;
|
|
foldLine = this.session.getNextFoldLine(row, foldLine);
|
|
foldStart = foldLine ? foldLine.start.row :Infinity;
|
|
}
|
|
if (row > last)
|
|
break;
|
|
|
|
var lineElement = lineElements[lineElementsIdx++];
|
|
if (lineElement) {
|
|
this.dom.removeChildren(lineElement);
|
|
this.$renderLine(
|
|
lineElement, row, row == foldStart ? foldLine : false
|
|
);
|
|
|
|
if (heightChanged)
|
|
lineElement.style.top = this.$lines.computeLineTop(row, config, this.session) + "px";
|
|
|
|
var height = (config.lineHeight * this.session.getRowLength(row)) + "px";
|
|
if (lineElement.style.height != height) {
|
|
heightChanged = true;
|
|
lineElement.style.height = height;
|
|
}
|
|
}
|
|
row++;
|
|
}
|
|
if (heightChanged) {
|
|
while (lineElementsIdx < this.$lines.cells.length) {
|
|
var cell = this.$lines.cells[lineElementsIdx++];
|
|
cell.element.style.top = this.$lines.computeLineTop(cell.row, config, this.session) + "px";
|
|
}
|
|
}
|
|
};
|
|
|
|
this.scrollLines = function(config) {
|
|
var oldConfig = this.config;
|
|
this.config = config;
|
|
|
|
if (this.$lines.pageChanged(oldConfig, config))
|
|
return this.update(config);
|
|
|
|
this.$lines.moveContainer(config);
|
|
|
|
var lastRow = config.lastRow;
|
|
var oldLastRow = oldConfig ? oldConfig.lastRow : -1;
|
|
|
|
if (!oldConfig || oldLastRow < config.firstRow)
|
|
return this.update(config);
|
|
|
|
if (lastRow < oldConfig.firstRow)
|
|
return this.update(config);
|
|
|
|
if (!oldConfig || oldConfig.lastRow < config.firstRow)
|
|
return this.update(config);
|
|
|
|
if (config.lastRow < oldConfig.firstRow)
|
|
return this.update(config);
|
|
|
|
if (oldConfig.firstRow < config.firstRow)
|
|
for (var row=this.session.getFoldedRowCount(oldConfig.firstRow, config.firstRow - 1); row>0; row--)
|
|
this.$lines.shift();
|
|
|
|
if (oldConfig.lastRow > config.lastRow)
|
|
for (var row=this.session.getFoldedRowCount(config.lastRow + 1, oldConfig.lastRow); row>0; row--)
|
|
this.$lines.pop();
|
|
|
|
if (config.firstRow < oldConfig.firstRow) {
|
|
this.$lines.unshift(this.$renderLinesFragment(config, config.firstRow, oldConfig.firstRow - 1));
|
|
}
|
|
|
|
if (config.lastRow > oldConfig.lastRow) {
|
|
this.$lines.push(this.$renderLinesFragment(config, oldConfig.lastRow + 1, config.lastRow));
|
|
}
|
|
};
|
|
|
|
this.$renderLinesFragment = function(config, firstRow, lastRow) {
|
|
var fragment = [];
|
|
var row = firstRow;
|
|
var foldLine = this.session.getNextFoldLine(row);
|
|
var foldStart = foldLine ? foldLine.start.row : Infinity;
|
|
|
|
while (true) {
|
|
if (row > foldStart) {
|
|
row = foldLine.end.row+1;
|
|
foldLine = this.session.getNextFoldLine(row, foldLine);
|
|
foldStart = foldLine ? foldLine.start.row : Infinity;
|
|
}
|
|
if (row > lastRow)
|
|
break;
|
|
|
|
var line = this.$lines.createCell(row, config, this.session);
|
|
|
|
var lineEl = line.element;
|
|
this.dom.removeChildren(lineEl);
|
|
dom.setStyle(lineEl.style, "height", this.$lines.computeLineHeight(row, config, this.session) + "px");
|
|
dom.setStyle(lineEl.style, "top", this.$lines.computeLineTop(row, config, this.session) + "px");
|
|
this.$renderLine(lineEl, row, row == foldStart ? foldLine : false);
|
|
|
|
if (this.$useLineGroups()) {
|
|
lineEl.className = "ace_line_group";
|
|
} else {
|
|
lineEl.className = "ace_line";
|
|
}
|
|
fragment.push(line);
|
|
|
|
row++;
|
|
}
|
|
return fragment;
|
|
};
|
|
|
|
this.update = function(config) {
|
|
this.$lines.moveContainer(config);
|
|
|
|
this.config = config;
|
|
|
|
var firstRow = config.firstRow;
|
|
var lastRow = config.lastRow;
|
|
|
|
var lines = this.$lines;
|
|
while (lines.getLength())
|
|
lines.pop();
|
|
|
|
lines.push(this.$renderLinesFragment(config, firstRow, lastRow));
|
|
};
|
|
|
|
this.$textToken = {
|
|
"text": true,
|
|
"rparen": true,
|
|
"lparen": true
|
|
};
|
|
|
|
this.$renderToken = function(parent, screenColumn, token, value) {
|
|
var self = this;
|
|
var re = /(\t)|( +)|([\x00-\x1f\x80-\xa0\xad\u1680\u180E\u2000-\u200f\u2028\u2029\u202F\u205F\uFEFF\uFFF9-\uFFFC]+)|(\u3000)|([\u1100-\u115F\u11A3-\u11A7\u11FA-\u11FF\u2329-\u232A\u2E80-\u2E99\u2E9B-\u2EF3\u2F00-\u2FD5\u2FF0-\u2FFB\u3001-\u303E\u3041-\u3096\u3099-\u30FF\u3105-\u312D\u3131-\u318E\u3190-\u31BA\u31C0-\u31E3\u31F0-\u321E\u3220-\u3247\u3250-\u32FE\u3300-\u4DBF\u4E00-\uA48C\uA490-\uA4C6\uA960-\uA97C\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFAFF\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE66\uFE68-\uFE6B\uFF01-\uFF60\uFFE0-\uFFE6]|[\uD800-\uDBFF][\uDC00-\uDFFF])/g;
|
|
|
|
var valueFragment = this.dom.createFragment(this.element);
|
|
|
|
var m;
|
|
var i = 0;
|
|
while (m = re.exec(value)) {
|
|
var tab = m[1];
|
|
var simpleSpace = m[2];
|
|
var controlCharacter = m[3];
|
|
var cjkSpace = m[4];
|
|
var cjk = m[5];
|
|
|
|
if (!self.showSpaces && simpleSpace)
|
|
continue;
|
|
|
|
var before = i != m.index ? value.slice(i, m.index) : "";
|
|
|
|
i = m.index + m[0].length;
|
|
|
|
if (before) {
|
|
valueFragment.appendChild(this.dom.createTextNode(before, this.element));
|
|
}
|
|
|
|
if (tab) {
|
|
var tabSize = self.session.getScreenTabSize(screenColumn + m.index);
|
|
valueFragment.appendChild(self.$tabStrings[tabSize].cloneNode(true));
|
|
screenColumn += tabSize - 1;
|
|
} else if (simpleSpace) {
|
|
if (self.showSpaces) {
|
|
var span = this.dom.createElement("span");
|
|
span.className = "ace_invisible ace_invisible_space";
|
|
span.textContent = lang.stringRepeat(self.SPACE_CHAR, simpleSpace.length);
|
|
valueFragment.appendChild(span);
|
|
} else {
|
|
valueFragment.appendChild(this.com.createTextNode(simpleSpace, this.element));
|
|
}
|
|
} else if (controlCharacter) {
|
|
var span = this.dom.createElement("span");
|
|
span.className = "ace_invisible ace_invisible_space ace_invalid";
|
|
span.textContent = lang.stringRepeat(self.SPACE_CHAR, controlCharacter.length);
|
|
valueFragment.appendChild(span);
|
|
} else if (cjkSpace) {
|
|
screenColumn += 1;
|
|
|
|
var span = this.dom.createElement("span");
|
|
span.style.width = (self.config.characterWidth * 2) + "px";
|
|
span.className = self.showSpaces ? "ace_cjk ace_invisible ace_invisible_space" : "ace_cjk";
|
|
span.textContent = self.showSpaces ? self.SPACE_CHAR : cjkSpace;
|
|
valueFragment.appendChild(span);
|
|
} else if (cjk) {
|
|
screenColumn += 1;
|
|
var span = this.dom.createElement("span");
|
|
span.style.width = (self.config.characterWidth * 2) + "px";
|
|
span.className = "ace_cjk";
|
|
span.textContent = cjk;
|
|
valueFragment.appendChild(span);
|
|
}
|
|
}
|
|
|
|
valueFragment.appendChild(this.dom.createTextNode(i ? value.slice(i) : value, this.element));
|
|
|
|
if (!this.$textToken[token.type]) {
|
|
var classes = "ace_" + token.type.replace(/\./g, " ace_");
|
|
var span = this.dom.createElement("span");
|
|
if (token.type == "fold")
|
|
span.style.width = (token.value.length * this.config.characterWidth) + "px";
|
|
|
|
span.className = classes;
|
|
span.appendChild(valueFragment);
|
|
|
|
parent.appendChild(span);
|
|
}
|
|
else {
|
|
parent.appendChild(valueFragment);
|
|
}
|
|
|
|
return screenColumn + value.length;
|
|
};
|
|
|
|
this.renderIndentGuide = function(parent, value, max) {
|
|
var cols = value.search(this.$indentGuideRe);
|
|
if (cols <= 0 || cols >= max)
|
|
return value;
|
|
if (value[0] == " ") {
|
|
cols -= cols % this.tabSize;
|
|
var count = cols/this.tabSize;
|
|
for (var i=0; i<count; i++) {
|
|
parent.appendChild(this.$tabStrings[" "].cloneNode(true));
|
|
}
|
|
return value.substr(cols);
|
|
} else if (value[0] == "\t") {
|
|
for (var i=0; i<cols; i++) {
|
|
parent.appendChild(this.$tabStrings["\t"].cloneNode(true));
|
|
}
|
|
return value.substr(cols);
|
|
}
|
|
return value;
|
|
};
|
|
|
|
this.$createLineElement = function(parent) {
|
|
var lineEl = this.dom.createElement("div");
|
|
lineEl.className = "ace_line";
|
|
lineEl.style.height = this.config.lineHeight + "px";
|
|
|
|
return lineEl;
|
|
};
|
|
|
|
this.$renderWrappedLine = function(parent, tokens, splits) {
|
|
var chars = 0;
|
|
var split = 0;
|
|
var splitChars = splits[0];
|
|
var screenColumn = 0;
|
|
|
|
var lineEl = this.$createLineElement();
|
|
parent.appendChild(lineEl);
|
|
|
|
for (var i = 0; i < tokens.length; i++) {
|
|
var token = tokens[i];
|
|
var value = token.value;
|
|
if (i == 0 && this.displayIndentGuides) {
|
|
chars = value.length;
|
|
value = this.renderIndentGuide(lineEl, value, splitChars);
|
|
if (!value)
|
|
continue;
|
|
chars -= value.length;
|
|
}
|
|
|
|
if (chars + value.length < splitChars) {
|
|
screenColumn = this.$renderToken(lineEl, screenColumn, token, value);
|
|
chars += value.length;
|
|
} else {
|
|
while (chars + value.length >= splitChars) {
|
|
screenColumn = this.$renderToken(
|
|
lineEl, screenColumn,
|
|
token, value.substring(0, splitChars - chars)
|
|
);
|
|
value = value.substring(splitChars - chars);
|
|
chars = splitChars;
|
|
|
|
lineEl = this.$createLineElement();
|
|
parent.appendChild(lineEl);
|
|
|
|
lineEl.appendChild(this.dom.createTextNode(lang.stringRepeat("\xa0", splits.indent), this.element));
|
|
|
|
split ++;
|
|
screenColumn = 0;
|
|
splitChars = splits[split] || Number.MAX_VALUE;
|
|
}
|
|
if (value.length != 0) {
|
|
chars += value.length;
|
|
screenColumn = this.$renderToken(
|
|
lineEl, screenColumn, token, value
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (splits[splits.length - 1] > this.MAX_LINE_LENGTH)
|
|
this.$renderOverflowMessage(lineEl, screenColumn, null, "", true);
|
|
};
|
|
|
|
this.$renderSimpleLine = function(parent, tokens) {
|
|
var screenColumn = 0;
|
|
var token = tokens[0];
|
|
var value = token.value;
|
|
if (this.displayIndentGuides)
|
|
value = this.renderIndentGuide(parent, value);
|
|
if (value)
|
|
screenColumn = this.$renderToken(parent, screenColumn, token, value);
|
|
for (var i = 1; i < tokens.length; i++) {
|
|
token = tokens[i];
|
|
value = token.value;
|
|
if (screenColumn + value.length > this.MAX_LINE_LENGTH)
|
|
return this.$renderOverflowMessage(parent, screenColumn, token, value);
|
|
screenColumn = this.$renderToken(parent, screenColumn, token, value);
|
|
}
|
|
};
|
|
|
|
this.$renderOverflowMessage = function(parent, screenColumn, token, value, hide) {
|
|
token && this.$renderToken(parent, screenColumn, token,
|
|
value.slice(0, this.MAX_LINE_LENGTH - screenColumn));
|
|
|
|
var overflowEl = this.dom.createElement("span");
|
|
overflowEl.className = "ace_inline_button ace_keyword ace_toggle_wrap";
|
|
overflowEl.textContent = hide ? "<hide>" : "<click to see more...>";
|
|
|
|
parent.appendChild(overflowEl);
|
|
};
|
|
this.$renderLine = function(parent, row, foldLine) {
|
|
if (!foldLine && foldLine != false)
|
|
foldLine = this.session.getFoldLine(row);
|
|
|
|
if (foldLine)
|
|
var tokens = this.$getFoldLineTokens(row, foldLine);
|
|
else
|
|
var tokens = this.session.getTokens(row);
|
|
|
|
var lastLineEl = parent;
|
|
if (tokens.length) {
|
|
var splits = this.session.getRowSplitData(row);
|
|
if (splits && splits.length) {
|
|
this.$renderWrappedLine(parent, tokens, splits);
|
|
var lastLineEl = parent.lastChild;
|
|
} else {
|
|
var lastLineEl = parent;
|
|
if (this.$useLineGroups()) {
|
|
lastLineEl = this.$createLineElement();
|
|
parent.appendChild(lastLineEl);
|
|
}
|
|
this.$renderSimpleLine(lastLineEl, tokens);
|
|
}
|
|
} else if (this.$useLineGroups()) {
|
|
lastLineEl = this.$createLineElement();
|
|
parent.appendChild(lastLineEl);
|
|
}
|
|
|
|
if (this.showEOL && lastLineEl) {
|
|
if (foldLine)
|
|
row = foldLine.end.row;
|
|
|
|
var invisibleEl = this.dom.createElement("span");
|
|
invisibleEl.className = "ace_invisible ace_invisible_eol";
|
|
invisibleEl.textContent = row == this.session.getLength() - 1 ? this.EOF_CHAR : this.EOL_CHAR;
|
|
|
|
lastLineEl.appendChild(invisibleEl);
|
|
}
|
|
};
|
|
|
|
this.$getFoldLineTokens = function(row, foldLine) {
|
|
var session = this.session;
|
|
var renderTokens = [];
|
|
|
|
function addTokens(tokens, from, to) {
|
|
var idx = 0, col = 0;
|
|
while ((col + tokens[idx].value.length) < from) {
|
|
col += tokens[idx].value.length;
|
|
idx++;
|
|
|
|
if (idx == tokens.length)
|
|
return;
|
|
}
|
|
if (col != from) {
|
|
var value = tokens[idx].value.substring(from - col);
|
|
if (value.length > (to - from))
|
|
value = value.substring(0, to - from);
|
|
|
|
renderTokens.push({
|
|
type: tokens[idx].type,
|
|
value: value
|
|
});
|
|
|
|
col = from + value.length;
|
|
idx += 1;
|
|
}
|
|
|
|
while (col < to && idx < tokens.length) {
|
|
var value = tokens[idx].value;
|
|
if (value.length + col > to) {
|
|
renderTokens.push({
|
|
type: tokens[idx].type,
|
|
value: value.substring(0, to - col)
|
|
});
|
|
} else
|
|
renderTokens.push(tokens[idx]);
|
|
col += value.length;
|
|
idx += 1;
|
|
}
|
|
}
|
|
|
|
var tokens = session.getTokens(row);
|
|
foldLine.walk(function(placeholder, row, column, lastColumn, isNewRow) {
|
|
if (placeholder != null) {
|
|
renderTokens.push({
|
|
type: "fold",
|
|
value: placeholder
|
|
});
|
|
} else {
|
|
if (isNewRow)
|
|
tokens = session.getTokens(row);
|
|
|
|
if (tokens.length)
|
|
addTokens(tokens, lastColumn, column);
|
|
}
|
|
}, foldLine.end.row, this.session.getLine(foldLine.end.row).length);
|
|
|
|
return renderTokens;
|
|
};
|
|
|
|
this.$useLineGroups = function() {
|
|
return this.session.getUseWrapMode();
|
|
};
|
|
|
|
this.destroy = function() {};
|
|
}).call(Text.prototype);
|
|
|
|
exports.Text = Text;
|
|
|
|
});
|
|
|
|
ace.define("ace/layer/cursor",["require","exports","module","ace/lib/dom"], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var dom = require("../lib/dom");
|
|
|
|
var Cursor = function(parentEl) {
|
|
this.element = dom.createElement("div");
|
|
this.element.className = "ace_layer ace_cursor-layer";
|
|
parentEl.appendChild(this.element);
|
|
|
|
this.isVisible = false;
|
|
this.isBlinking = true;
|
|
this.blinkInterval = 1000;
|
|
this.smoothBlinking = false;
|
|
|
|
this.cursors = [];
|
|
this.cursor = this.addCursor();
|
|
dom.addCssClass(this.element, "ace_hidden-cursors");
|
|
this.$updateCursors = this.$updateOpacity.bind(this);
|
|
};
|
|
|
|
(function() {
|
|
|
|
this.$updateOpacity = function(val) {
|
|
var cursors = this.cursors;
|
|
for (var i = cursors.length; i--; )
|
|
dom.setStyle(cursors[i].style, "opacity", val ? "" : "0");
|
|
};
|
|
|
|
this.$startCssAnimation = function() {
|
|
var cursors = this.cursors;
|
|
for (var i = cursors.length; i--; )
|
|
cursors[i].style.animationDuration = this.blinkInterval + "ms";
|
|
|
|
setTimeout(function() {
|
|
dom.addCssClass(this.element, "ace_animate-blinking");
|
|
}.bind(this));
|
|
};
|
|
|
|
this.$stopCssAnimation = function() {
|
|
dom.removeCssClass(this.element, "ace_animate-blinking");
|
|
};
|
|
|
|
this.$padding = 0;
|
|
this.setPadding = function(padding) {
|
|
this.$padding = padding;
|
|
};
|
|
|
|
this.setSession = function(session) {
|
|
this.session = session;
|
|
};
|
|
|
|
this.setBlinking = function(blinking) {
|
|
if (blinking != this.isBlinking) {
|
|
this.isBlinking = blinking;
|
|
this.restartTimer();
|
|
}
|
|
};
|
|
|
|
this.setBlinkInterval = function(blinkInterval) {
|
|
if (blinkInterval != this.blinkInterval) {
|
|
this.blinkInterval = blinkInterval;
|
|
this.restartTimer();
|
|
}
|
|
};
|
|
|
|
this.setSmoothBlinking = function(smoothBlinking) {
|
|
if (smoothBlinking != this.smoothBlinking) {
|
|
this.smoothBlinking = smoothBlinking;
|
|
dom.setCssClass(this.element, "ace_smooth-blinking", smoothBlinking);
|
|
this.$updateCursors(true);
|
|
this.restartTimer();
|
|
}
|
|
};
|
|
|
|
this.addCursor = function() {
|
|
var el = dom.createElement("div");
|
|
el.className = "ace_cursor";
|
|
this.element.appendChild(el);
|
|
this.cursors.push(el);
|
|
return el;
|
|
};
|
|
|
|
this.removeCursor = function() {
|
|
if (this.cursors.length > 1) {
|
|
var el = this.cursors.pop();
|
|
el.parentNode.removeChild(el);
|
|
return el;
|
|
}
|
|
};
|
|
|
|
this.hideCursor = function() {
|
|
this.isVisible = false;
|
|
dom.addCssClass(this.element, "ace_hidden-cursors");
|
|
this.restartTimer();
|
|
};
|
|
|
|
this.showCursor = function() {
|
|
this.isVisible = true;
|
|
dom.removeCssClass(this.element, "ace_hidden-cursors");
|
|
this.restartTimer();
|
|
};
|
|
|
|
this.restartTimer = function() {
|
|
var update = this.$updateCursors;
|
|
clearInterval(this.intervalId);
|
|
clearTimeout(this.timeoutId);
|
|
this.$stopCssAnimation();
|
|
|
|
if (this.smoothBlinking) {
|
|
dom.removeCssClass(this.element, "ace_smooth-blinking");
|
|
}
|
|
|
|
update(true);
|
|
|
|
if (!this.isBlinking || !this.blinkInterval || !this.isVisible) {
|
|
this.$stopCssAnimation();
|
|
return;
|
|
}
|
|
|
|
if (this.smoothBlinking) {
|
|
setTimeout(function(){
|
|
dom.addCssClass(this.element, "ace_smooth-blinking");
|
|
}.bind(this));
|
|
}
|
|
|
|
if (dom.HAS_CSS_ANIMATION) {
|
|
this.$startCssAnimation();
|
|
} else {
|
|
var blink = function(){
|
|
this.timeoutId = setTimeout(function() {
|
|
update(false);
|
|
}, 0.6 * this.blinkInterval);
|
|
}.bind(this);
|
|
|
|
this.intervalId = setInterval(function() {
|
|
update(true);
|
|
blink();
|
|
}, this.blinkInterval);
|
|
blink();
|
|
}
|
|
};
|
|
|
|
this.getPixelPosition = function(position, onScreen) {
|
|
if (!this.config || !this.session)
|
|
return {left : 0, top : 0};
|
|
|
|
if (!position)
|
|
position = this.session.selection.getCursor();
|
|
var pos = this.session.documentToScreenPosition(position);
|
|
var cursorLeft = this.$padding + (this.session.$bidiHandler.isBidiRow(pos.row, position.row)
|
|
? this.session.$bidiHandler.getPosLeft(pos.column)
|
|
: pos.column * this.config.characterWidth);
|
|
|
|
var cursorTop = (pos.row - (onScreen ? this.config.firstRowScreen : 0)) *
|
|
this.config.lineHeight;
|
|
|
|
return {left : cursorLeft, top : cursorTop};
|
|
};
|
|
|
|
this.isCursorInView = function(pixelPos, config) {
|
|
return pixelPos.top >= 0 && pixelPos.top < config.maxHeight;
|
|
};
|
|
|
|
this.update = function(config) {
|
|
this.config = config;
|
|
|
|
var selections = this.session.$selectionMarkers;
|
|
var i = 0, cursorIndex = 0;
|
|
|
|
if (selections === undefined || selections.length === 0){
|
|
selections = [{cursor: null}];
|
|
}
|
|
|
|
for (var i = 0, n = selections.length; i < n; i++) {
|
|
var pixelPos = this.getPixelPosition(selections[i].cursor, true);
|
|
if ((pixelPos.top > config.height + config.offset ||
|
|
pixelPos.top < 0) && i > 1) {
|
|
continue;
|
|
}
|
|
|
|
var element = this.cursors[cursorIndex++] || this.addCursor();
|
|
var style = element.style;
|
|
|
|
if (!this.drawCursor) {
|
|
if (!this.isCursorInView(pixelPos, config)) {
|
|
dom.setStyle(style, "display", "none");
|
|
} else {
|
|
dom.setStyle(style, "display", "block");
|
|
dom.translate(element, pixelPos.left, pixelPos.top);
|
|
dom.setStyle(style, "width", Math.round(config.characterWidth) + "px");
|
|
dom.setStyle(style, "height", config.lineHeight + "px");
|
|
}
|
|
} else {
|
|
this.drawCursor(element, pixelPos, config, selections[i], this.session);
|
|
}
|
|
}
|
|
while (this.cursors.length > cursorIndex)
|
|
this.removeCursor();
|
|
|
|
var overwrite = this.session.getOverwrite();
|
|
this.$setOverwrite(overwrite);
|
|
this.$pixelPos = pixelPos;
|
|
this.restartTimer();
|
|
};
|
|
|
|
this.drawCursor = null;
|
|
|
|
this.$setOverwrite = function(overwrite) {
|
|
if (overwrite != this.overwrite) {
|
|
this.overwrite = overwrite;
|
|
if (overwrite)
|
|
dom.addCssClass(this.element, "ace_overwrite-cursors");
|
|
else
|
|
dom.removeCssClass(this.element, "ace_overwrite-cursors");
|
|
}
|
|
};
|
|
|
|
this.destroy = function() {
|
|
clearInterval(this.intervalId);
|
|
clearTimeout(this.timeoutId);
|
|
};
|
|
|
|
}).call(Cursor.prototype);
|
|
|
|
exports.Cursor = Cursor;
|
|
|
|
});
|
|
|
|
ace.define("ace/scrollbar",["require","exports","module","ace/lib/oop","ace/lib/dom","ace/lib/event","ace/lib/event_emitter"], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var oop = require("./lib/oop");
|
|
var dom = require("./lib/dom");
|
|
var event = require("./lib/event");
|
|
var EventEmitter = require("./lib/event_emitter").EventEmitter;
|
|
var MAX_SCROLL_H = 0x8000;
|
|
var ScrollBar = function(parent) {
|
|
this.element = dom.createElement("div");
|
|
this.element.className = "ace_scrollbar ace_scrollbar" + this.classSuffix;
|
|
|
|
this.inner = dom.createElement("div");
|
|
this.inner.className = "ace_scrollbar-inner";
|
|
this.inner.textContent = "\xa0";
|
|
this.element.appendChild(this.inner);
|
|
|
|
parent.appendChild(this.element);
|
|
|
|
this.setVisible(false);
|
|
this.skipEvent = false;
|
|
|
|
event.addListener(this.element, "scroll", this.onScroll.bind(this));
|
|
event.addListener(this.element, "mousedown", event.preventDefault);
|
|
};
|
|
|
|
(function() {
|
|
oop.implement(this, EventEmitter);
|
|
|
|
this.setVisible = function(isVisible) {
|
|
this.element.style.display = isVisible ? "" : "none";
|
|
this.isVisible = isVisible;
|
|
this.coeff = 1;
|
|
};
|
|
}).call(ScrollBar.prototype);
|
|
var VScrollBar = function(parent, renderer) {
|
|
ScrollBar.call(this, parent);
|
|
this.scrollTop = 0;
|
|
this.scrollHeight = 0;
|
|
renderer.$scrollbarWidth =
|
|
this.width = dom.scrollbarWidth(parent.ownerDocument);
|
|
this.inner.style.width =
|
|
this.element.style.width = (this.width || 15) + 5 + "px";
|
|
this.$minWidth = 0;
|
|
};
|
|
|
|
oop.inherits(VScrollBar, ScrollBar);
|
|
|
|
(function() {
|
|
|
|
this.classSuffix = '-v';
|
|
this.onScroll = function() {
|
|
if (!this.skipEvent) {
|
|
this.scrollTop = this.element.scrollTop;
|
|
if (this.coeff != 1) {
|
|
var h = this.element.clientHeight / this.scrollHeight;
|
|
this.scrollTop = this.scrollTop * (1 - h) / (this.coeff - h);
|
|
}
|
|
this._emit("scroll", {data: this.scrollTop});
|
|
}
|
|
this.skipEvent = false;
|
|
};
|
|
this.getWidth = function() {
|
|
return Math.max(this.isVisible ? this.width : 0, this.$minWidth || 0);
|
|
};
|
|
this.setHeight = function(height) {
|
|
this.element.style.height = height + "px";
|
|
};
|
|
this.setInnerHeight =
|
|
this.setScrollHeight = function(height) {
|
|
this.scrollHeight = height;
|
|
if (height > MAX_SCROLL_H) {
|
|
this.coeff = MAX_SCROLL_H / height;
|
|
height = MAX_SCROLL_H;
|
|
} else if (this.coeff != 1) {
|
|
this.coeff = 1;
|
|
}
|
|
this.inner.style.height = height + "px";
|
|
};
|
|
this.setScrollTop = function(scrollTop) {
|
|
if (this.scrollTop != scrollTop) {
|
|
this.skipEvent = true;
|
|
this.scrollTop = scrollTop;
|
|
this.element.scrollTop = scrollTop * this.coeff;
|
|
}
|
|
};
|
|
|
|
}).call(VScrollBar.prototype);
|
|
var HScrollBar = function(parent, renderer) {
|
|
ScrollBar.call(this, parent);
|
|
this.scrollLeft = 0;
|
|
this.height = renderer.$scrollbarWidth;
|
|
this.inner.style.height =
|
|
this.element.style.height = (this.height || 15) + 5 + "px";
|
|
};
|
|
|
|
oop.inherits(HScrollBar, ScrollBar);
|
|
|
|
(function() {
|
|
|
|
this.classSuffix = '-h';
|
|
this.onScroll = function() {
|
|
if (!this.skipEvent) {
|
|
this.scrollLeft = this.element.scrollLeft;
|
|
this._emit("scroll", {data: this.scrollLeft});
|
|
}
|
|
this.skipEvent = false;
|
|
};
|
|
this.getHeight = function() {
|
|
return this.isVisible ? this.height : 0;
|
|
};
|
|
this.setWidth = function(width) {
|
|
this.element.style.width = width + "px";
|
|
};
|
|
this.setInnerWidth = function(width) {
|
|
this.inner.style.width = width + "px";
|
|
};
|
|
this.setScrollWidth = function(width) {
|
|
this.inner.style.width = width + "px";
|
|
};
|
|
this.setScrollLeft = function(scrollLeft) {
|
|
if (this.scrollLeft != scrollLeft) {
|
|
this.skipEvent = true;
|
|
this.scrollLeft = this.element.scrollLeft = scrollLeft;
|
|
}
|
|
};
|
|
|
|
}).call(HScrollBar.prototype);
|
|
|
|
|
|
exports.ScrollBar = VScrollBar; // backward compatibility
|
|
exports.ScrollBarV = VScrollBar; // backward compatibility
|
|
exports.ScrollBarH = HScrollBar; // backward compatibility
|
|
|
|
exports.VScrollBar = VScrollBar;
|
|
exports.HScrollBar = HScrollBar;
|
|
});
|
|
|
|
ace.define("ace/renderloop",["require","exports","module","ace/lib/event"], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var event = require("./lib/event");
|
|
|
|
|
|
var RenderLoop = function(onRender, win) {
|
|
this.onRender = onRender;
|
|
this.pending = false;
|
|
this.changes = 0;
|
|
this.$recursionLimit = 2;
|
|
this.window = win || window;
|
|
var _self = this;
|
|
this._flush = function(ts) {
|
|
_self.pending = false;
|
|
var changes = _self.changes;
|
|
|
|
if (changes) {
|
|
event.blockIdle(100);
|
|
_self.changes = 0;
|
|
_self.onRender(changes);
|
|
}
|
|
|
|
if (_self.changes) {
|
|
if (_self.$recursionLimit-- < 0) return;
|
|
_self.schedule();
|
|
} else {
|
|
_self.$recursionLimit = 2;
|
|
}
|
|
};
|
|
};
|
|
|
|
(function() {
|
|
|
|
this.schedule = function(change) {
|
|
this.changes = this.changes | change;
|
|
if (this.changes && !this.pending) {
|
|
event.nextFrame(this._flush);
|
|
this.pending = true;
|
|
}
|
|
};
|
|
|
|
this.clear = function(change) {
|
|
var changes = this.changes;
|
|
this.changes = 0;
|
|
return changes;
|
|
};
|
|
|
|
}).call(RenderLoop.prototype);
|
|
|
|
exports.RenderLoop = RenderLoop;
|
|
});
|
|
|
|
ace.define("ace/layer/font_metrics",["require","exports","module","ace/lib/oop","ace/lib/dom","ace/lib/lang","ace/lib/event","ace/lib/useragent","ace/lib/event_emitter"], function(require, exports, module) {
|
|
|
|
var oop = require("../lib/oop");
|
|
var dom = require("../lib/dom");
|
|
var lang = require("../lib/lang");
|
|
var event = require("../lib/event");
|
|
var useragent = require("../lib/useragent");
|
|
var EventEmitter = require("../lib/event_emitter").EventEmitter;
|
|
|
|
var CHAR_COUNT = 256;
|
|
var USE_OBSERVER = typeof ResizeObserver == "function";
|
|
var L = 200;
|
|
|
|
var FontMetrics = exports.FontMetrics = function(parentEl) {
|
|
this.el = dom.createElement("div");
|
|
this.$setMeasureNodeStyles(this.el.style, true);
|
|
|
|
this.$main = dom.createElement("div");
|
|
this.$setMeasureNodeStyles(this.$main.style);
|
|
|
|
this.$measureNode = dom.createElement("div");
|
|
this.$setMeasureNodeStyles(this.$measureNode.style);
|
|
|
|
|
|
this.el.appendChild(this.$main);
|
|
this.el.appendChild(this.$measureNode);
|
|
parentEl.appendChild(this.el);
|
|
|
|
this.$measureNode.textContent = lang.stringRepeat("X", CHAR_COUNT);
|
|
|
|
this.$characterSize = {width: 0, height: 0};
|
|
|
|
|
|
if (USE_OBSERVER)
|
|
this.$addObserver();
|
|
else
|
|
this.checkForSizeChanges();
|
|
};
|
|
|
|
(function() {
|
|
|
|
oop.implement(this, EventEmitter);
|
|
|
|
this.$characterSize = {width: 0, height: 0};
|
|
|
|
this.$setMeasureNodeStyles = function(style, isRoot) {
|
|
style.width = style.height = "auto";
|
|
style.left = style.top = "0px";
|
|
style.visibility = "hidden";
|
|
style.position = "absolute";
|
|
style.whiteSpace = "pre";
|
|
|
|
if (useragent.isIE < 8) {
|
|
style["font-family"] = "inherit";
|
|
} else {
|
|
style.font = "inherit";
|
|
}
|
|
style.overflow = isRoot ? "hidden" : "visible";
|
|
};
|
|
|
|
this.checkForSizeChanges = function(size) {
|
|
if (size === undefined)
|
|
size = this.$measureSizes();
|
|
if (size && (this.$characterSize.width !== size.width || this.$characterSize.height !== size.height)) {
|
|
this.$measureNode.style.fontWeight = "bold";
|
|
var boldSize = this.$measureSizes();
|
|
this.$measureNode.style.fontWeight = "";
|
|
this.$characterSize = size;
|
|
this.charSizes = Object.create(null);
|
|
this.allowBoldFonts = boldSize && boldSize.width === size.width && boldSize.height === size.height;
|
|
this._emit("changeCharacterSize", {data: size});
|
|
}
|
|
};
|
|
|
|
this.$addObserver = function() {
|
|
var self = this;
|
|
this.$observer = new window.ResizeObserver(function(e) {
|
|
self.checkForSizeChanges();
|
|
});
|
|
this.$observer.observe(this.$measureNode);
|
|
};
|
|
|
|
this.$pollSizeChanges = function() {
|
|
if (this.$pollSizeChangesTimer || this.$observer)
|
|
return this.$pollSizeChangesTimer;
|
|
var self = this;
|
|
|
|
return this.$pollSizeChangesTimer = event.onIdle(function cb() {
|
|
self.checkForSizeChanges();
|
|
event.onIdle(cb, 500);
|
|
}, 500);
|
|
};
|
|
|
|
this.setPolling = function(val) {
|
|
if (val) {
|
|
this.$pollSizeChanges();
|
|
} else if (this.$pollSizeChangesTimer) {
|
|
clearInterval(this.$pollSizeChangesTimer);
|
|
this.$pollSizeChangesTimer = 0;
|
|
}
|
|
};
|
|
|
|
this.$measureSizes = function(node) {
|
|
var size = {
|
|
height: (node || this.$measureNode).clientHeight,
|
|
width: (node || this.$measureNode).clientWidth / CHAR_COUNT
|
|
};
|
|
if (size.width === 0 || size.height === 0)
|
|
return null;
|
|
return size;
|
|
};
|
|
|
|
this.$measureCharWidth = function(ch) {
|
|
this.$main.textContent = lang.stringRepeat(ch, CHAR_COUNT);
|
|
var rect = this.$main.getBoundingClientRect();
|
|
return rect.width / CHAR_COUNT;
|
|
};
|
|
|
|
this.getCharacterWidth = function(ch) {
|
|
var w = this.charSizes[ch];
|
|
if (w === undefined) {
|
|
w = this.charSizes[ch] = this.$measureCharWidth(ch) / this.$characterSize.width;
|
|
}
|
|
return w;
|
|
};
|
|
|
|
this.destroy = function() {
|
|
clearInterval(this.$pollSizeChangesTimer);
|
|
if (this.$observer)
|
|
this.$observer.disconnect();
|
|
if (this.el && this.el.parentNode)
|
|
this.el.parentNode.removeChild(this.el);
|
|
};
|
|
|
|
|
|
this.$getZoom = function getZoom(element) {
|
|
if (!element || !element.parentElement) return 1;
|
|
return (window.getComputedStyle(element).zoom || 1) * getZoom(element.parentElement);
|
|
};
|
|
this.$initTransformMeasureNodes = function() {
|
|
var t = function(t, l) {
|
|
return ["div", {
|
|
style: "position: absolute;top:" + t + "px;left:" + l + "px;"
|
|
}];
|
|
};
|
|
this.els = dom.buildDom([t(0, 0), t(L, 0), t(0, L), t(L, L)], this.el);
|
|
};
|
|
this.transformCoordinates = function(clientPos, elPos) {
|
|
if (clientPos) {
|
|
var zoom = this.$getZoom(this.el);
|
|
clientPos = mul(1 / zoom, clientPos);
|
|
}
|
|
function solve(l1, l2, r) {
|
|
var det = l1[1] * l2[0] - l1[0] * l2[1];
|
|
return [
|
|
(-l2[1] * r[0] + l2[0] * r[1]) / det,
|
|
(+l1[1] * r[0] - l1[0] * r[1]) / det
|
|
];
|
|
}
|
|
function sub(a, b) { return [a[0] - b[0], a[1] - b[1]]; }
|
|
function add(a, b) { return [a[0] + b[0], a[1] + b[1]]; }
|
|
function mul(a, b) { return [a * b[0], a * b[1]]; }
|
|
|
|
if (!this.els)
|
|
this.$initTransformMeasureNodes();
|
|
|
|
function p(el) {
|
|
var r = el.getBoundingClientRect();
|
|
return [r.left, r.top];
|
|
}
|
|
|
|
var a = p(this.els[0]);
|
|
var b = p(this.els[1]);
|
|
var c = p(this.els[2]);
|
|
var d = p(this.els[3]);
|
|
|
|
var h = solve(sub(d, b), sub(d, c), sub(add(b, c), add(d, a)));
|
|
|
|
var m1 = mul(1 + h[0], sub(b, a));
|
|
var m2 = mul(1 + h[1], sub(c, a));
|
|
|
|
if (elPos) {
|
|
var x = elPos;
|
|
var k = h[0] * x[0] / L + h[1] * x[1] / L + 1;
|
|
var ut = add(mul(x[0], m1), mul(x[1], m2));
|
|
return add(mul(1 / k / L, ut), a);
|
|
}
|
|
var u = sub(clientPos, a);
|
|
var f = solve(sub(m1, mul(h[0], u)), sub(m2, mul(h[1], u)), u);
|
|
return mul(L, f);
|
|
};
|
|
|
|
}).call(FontMetrics.prototype);
|
|
|
|
});
|
|
|
|
ace.define("ace/virtual_renderer",["require","exports","module","ace/lib/oop","ace/lib/dom","ace/config","ace/layer/gutter","ace/layer/marker","ace/layer/text","ace/layer/cursor","ace/scrollbar","ace/scrollbar","ace/renderloop","ace/layer/font_metrics","ace/lib/event_emitter","ace/lib/useragent"], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var oop = require("./lib/oop");
|
|
var dom = require("./lib/dom");
|
|
var config = require("./config");
|
|
var GutterLayer = require("./layer/gutter").Gutter;
|
|
var MarkerLayer = require("./layer/marker").Marker;
|
|
var TextLayer = require("./layer/text").Text;
|
|
var CursorLayer = require("./layer/cursor").Cursor;
|
|
var HScrollBar = require("./scrollbar").HScrollBar;
|
|
var VScrollBar = require("./scrollbar").VScrollBar;
|
|
var RenderLoop = require("./renderloop").RenderLoop;
|
|
var FontMetrics = require("./layer/font_metrics").FontMetrics;
|
|
var EventEmitter = require("./lib/event_emitter").EventEmitter;
|
|
var editorCss = "\
|
|
.ace_br1 {border-top-left-radius : 3px;}\
|
|
.ace_br2 {border-top-right-radius : 3px;}\
|
|
.ace_br3 {border-top-left-radius : 3px; border-top-right-radius: 3px;}\
|
|
.ace_br4 {border-bottom-right-radius: 3px;}\
|
|
.ace_br5 {border-top-left-radius : 3px; border-bottom-right-radius: 3px;}\
|
|
.ace_br6 {border-top-right-radius : 3px; border-bottom-right-radius: 3px;}\
|
|
.ace_br7 {border-top-left-radius : 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px;}\
|
|
.ace_br8 {border-bottom-left-radius : 3px;}\
|
|
.ace_br9 {border-top-left-radius : 3px; border-bottom-left-radius: 3px;}\
|
|
.ace_br10{border-top-right-radius : 3px; border-bottom-left-radius: 3px;}\
|
|
.ace_br11{border-top-left-radius : 3px; border-top-right-radius: 3px; border-bottom-left-radius: 3px;}\
|
|
.ace_br12{border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;}\
|
|
.ace_br13{border-top-left-radius : 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;}\
|
|
.ace_br14{border-top-right-radius : 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;}\
|
|
.ace_br15{border-top-left-radius : 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;}\
|
|
.ace_editor {\
|
|
position: relative;\
|
|
overflow: hidden;\
|
|
padding: 0;\
|
|
font: 12px/normal 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', monospace;\
|
|
direction: ltr;\
|
|
text-align: left;\
|
|
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);\
|
|
}\
|
|
.ace_scroller {\
|
|
position: absolute;\
|
|
overflow: hidden;\
|
|
top: 0;\
|
|
bottom: 0;\
|
|
background-color: inherit;\
|
|
-ms-user-select: none;\
|
|
-moz-user-select: none;\
|
|
-webkit-user-select: none;\
|
|
user-select: none;\
|
|
cursor: text;\
|
|
}\
|
|
.ace_content {\
|
|
position: absolute;\
|
|
box-sizing: border-box;\
|
|
min-width: 100%;\
|
|
contain: style size layout;\
|
|
font-variant-ligatures: no-common-ligatures;\
|
|
}\
|
|
.ace_dragging .ace_scroller:before{\
|
|
position: absolute;\
|
|
top: 0;\
|
|
left: 0;\
|
|
right: 0;\
|
|
bottom: 0;\
|
|
content: '';\
|
|
background: rgba(250, 250, 250, 0.01);\
|
|
z-index: 1000;\
|
|
}\
|
|
.ace_dragging.ace_dark .ace_scroller:before{\
|
|
background: rgba(0, 0, 0, 0.01);\
|
|
}\
|
|
.ace_selecting, .ace_selecting * {\
|
|
cursor: text !important;\
|
|
}\
|
|
.ace_gutter {\
|
|
position: absolute;\
|
|
overflow : hidden;\
|
|
width: auto;\
|
|
top: 0;\
|
|
bottom: 0;\
|
|
left: 0;\
|
|
cursor: default;\
|
|
z-index: 4;\
|
|
-ms-user-select: none;\
|
|
-moz-user-select: none;\
|
|
-webkit-user-select: none;\
|
|
user-select: none;\
|
|
contain: style size layout;\
|
|
}\
|
|
.ace_gutter-active-line {\
|
|
position: absolute;\
|
|
left: 0;\
|
|
right: 0;\
|
|
}\
|
|
.ace_scroller.ace_scroll-left {\
|
|
box-shadow: 17px 0 16px -16px rgba(0, 0, 0, 0.4) inset;\
|
|
}\
|
|
.ace_gutter-cell {\
|
|
position: absolute;\
|
|
top: 0;\
|
|
left: 0;\
|
|
right: 0;\
|
|
padding-left: 19px;\
|
|
padding-right: 6px;\
|
|
background-repeat: no-repeat;\
|
|
}\
|
|
.ace_gutter-cell.ace_error {\
|
|
background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABOFBMVEX/////////QRswFAb/Ui4wFAYwFAYwFAaWGAfDRymzOSH/PxswFAb/SiUwFAYwFAbUPRvjQiDllog5HhHdRybsTi3/Tyv9Tir+Syj/UC3////XurebMBIwFAb/RSHbPx/gUzfdwL3kzMivKBAwFAbbvbnhPx66NhowFAYwFAaZJg8wFAaxKBDZurf/RB6mMxb/SCMwFAYwFAbxQB3+RB4wFAb/Qhy4Oh+4QifbNRcwFAYwFAYwFAb/QRzdNhgwFAYwFAbav7v/Uy7oaE68MBK5LxLewr/r2NXewLswFAaxJw4wFAbkPRy2PyYwFAaxKhLm1tMwFAazPiQwFAaUGAb/QBrfOx3bvrv/VC/maE4wFAbRPBq6MRO8Qynew8Dp2tjfwb0wFAbx6eju5+by6uns4uH9/f36+vr/GkHjAAAAYnRSTlMAGt+64rnWu/bo8eAA4InH3+DwoN7j4eLi4xP99Nfg4+b+/u9B/eDs1MD1mO7+4PHg2MXa347g7vDizMLN4eG+Pv7i5evs/v79yu7S3/DV7/498Yv24eH+4ufQ3Ozu/v7+y13sRqwAAADLSURBVHjaZc/XDsFgGIBhtDrshlitmk2IrbHFqL2pvXf/+78DPokj7+Fz9qpU/9UXJIlhmPaTaQ6QPaz0mm+5gwkgovcV6GZzd5JtCQwgsxoHOvJO15kleRLAnMgHFIESUEPmawB9ngmelTtipwwfASilxOLyiV5UVUyVAfbG0cCPHig+GBkzAENHS0AstVF6bacZIOzgLmxsHbt2OecNgJC83JERmePUYq8ARGkJx6XtFsdddBQgZE2nPR6CICZhawjA4Fb/chv+399kfR+MMMDGOQAAAABJRU5ErkJggg==\");\
|
|
background-repeat: no-repeat;\
|
|
background-position: 2px center;\
|
|
}\
|
|
.ace_gutter-cell.ace_warning {\
|
|
background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAmVBMVEX///8AAAD///8AAAAAAABPSzb/5sAAAAB/blH/73z/ulkAAAAAAAD85pkAAAAAAAACAgP/vGz/rkDerGbGrV7/pkQICAf////e0IsAAAD/oED/qTvhrnUAAAD/yHD/njcAAADuv2r/nz//oTj/p064oGf/zHAAAAA9Nir/tFIAAAD/tlTiuWf/tkIAAACynXEAAAAAAAAtIRW7zBpBAAAAM3RSTlMAABR1m7RXO8Ln31Z36zT+neXe5OzooRDfn+TZ4p3h2hTf4t3k3ucyrN1K5+Xaks52Sfs9CXgrAAAAjklEQVR42o3PbQ+CIBQFYEwboPhSYgoYunIqqLn6/z8uYdH8Vmdnu9vz4WwXgN/xTPRD2+sgOcZjsge/whXZgUaYYvT8QnuJaUrjrHUQreGczuEafQCO/SJTufTbroWsPgsllVhq3wJEk2jUSzX3CUEDJC84707djRc5MTAQxoLgupWRwW6UB5fS++NV8AbOZgnsC7BpEAAAAABJRU5ErkJggg==\");\
|
|
background-position: 2px center;\
|
|
}\
|
|
.ace_gutter-cell.ace_info {\
|
|
background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAAAAAA6mKC9AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAAJ0Uk5TAAB2k804AAAAPklEQVQY02NgIB68QuO3tiLznjAwpKTgNyDbMegwisCHZUETUZV0ZqOquBpXj2rtnpSJT1AEnnRmL2OgGgAAIKkRQap2htgAAAAASUVORK5CYII=\");\
|
|
background-position: 2px center;\
|
|
}\
|
|
.ace_dark .ace_gutter-cell.ace_info {\
|
|
background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAJFBMVEUAAAChoaGAgIAqKiq+vr6tra1ZWVmUlJSbm5s8PDxubm56enrdgzg3AAAAAXRSTlMAQObYZgAAAClJREFUeNpjYMAPdsMYHegyJZFQBlsUlMFVCWUYKkAZMxZAGdxlDMQBAG+TBP4B6RyJAAAAAElFTkSuQmCC\");\
|
|
}\
|
|
.ace_scrollbar {\
|
|
contain: strict;\
|
|
position: absolute;\
|
|
right: 0;\
|
|
bottom: 0;\
|
|
z-index: 6;\
|
|
}\
|
|
.ace_scrollbar-inner {\
|
|
position: absolute;\
|
|
cursor: text;\
|
|
left: 0;\
|
|
top: 0;\
|
|
}\
|
|
.ace_scrollbar-v{\
|
|
overflow-x: hidden;\
|
|
overflow-y: scroll;\
|
|
top: 0;\
|
|
}\
|
|
.ace_scrollbar-h {\
|
|
overflow-x: scroll;\
|
|
overflow-y: hidden;\
|
|
left: 0;\
|
|
}\
|
|
.ace_print-margin {\
|
|
position: absolute;\
|
|
height: 100%;\
|
|
}\
|
|
.ace_text-input {\
|
|
position: absolute;\
|
|
z-index: 0;\
|
|
width: 0.5em;\
|
|
height: 1em;\
|
|
opacity: 0;\
|
|
background: transparent;\
|
|
-moz-appearance: none;\
|
|
appearance: none;\
|
|
border: none;\
|
|
resize: none;\
|
|
outline: none;\
|
|
overflow: hidden;\
|
|
font: inherit;\
|
|
padding: 0 1px;\
|
|
margin: 0 -1px;\
|
|
contain: strict;\
|
|
-ms-user-select: text;\
|
|
-moz-user-select: text;\
|
|
-webkit-user-select: text;\
|
|
user-select: text;\
|
|
white-space: pre!important;\
|
|
}\
|
|
.ace_text-input.ace_composition {\
|
|
background: transparent;\
|
|
color: inherit;\
|
|
z-index: 1000;\
|
|
opacity: 1;\
|
|
}\
|
|
.ace_composition_placeholder { color: transparent }\
|
|
.ace_composition_marker { \
|
|
border-bottom: 1px solid;\
|
|
position: absolute;\
|
|
border-radius: 0;\
|
|
margin-top: 1px;\
|
|
}\
|
|
[ace_nocontext=true] {\
|
|
transform: none!important;\
|
|
filter: none!important;\
|
|
clip-path: none!important;\
|
|
mask : none!important;\
|
|
contain: none!important;\
|
|
perspective: none!important;\
|
|
mix-blend-mode: initial!important;\
|
|
z-index: auto;\
|
|
}\
|
|
.ace_layer {\
|
|
z-index: 1;\
|
|
position: absolute;\
|
|
overflow: hidden;\
|
|
word-wrap: normal;\
|
|
white-space: pre;\
|
|
height: 100%;\
|
|
width: 100%;\
|
|
box-sizing: border-box;\
|
|
pointer-events: none;\
|
|
}\
|
|
.ace_gutter-layer {\
|
|
position: relative;\
|
|
width: auto;\
|
|
text-align: right;\
|
|
pointer-events: auto;\
|
|
height: 1000000px;\
|
|
contain: style size layout;\
|
|
}\
|
|
.ace_text-layer {\
|
|
font: inherit !important;\
|
|
position: absolute;\
|
|
height: 1000000px;\
|
|
width: 1000000px;\
|
|
contain: style size layout;\
|
|
}\
|
|
.ace_text-layer > .ace_line, .ace_text-layer > .ace_line_group {\
|
|
contain: style size layout;\
|
|
position: absolute;\
|
|
top: 0;\
|
|
left: 0;\
|
|
right: 0;\
|
|
}\
|
|
.ace_hidpi .ace_text-layer,\
|
|
.ace_hidpi .ace_gutter-layer,\
|
|
.ace_hidpi .ace_content,\
|
|
.ace_hidpi .ace_gutter {\
|
|
contain: strict;\
|
|
will-change: transform;\
|
|
}\
|
|
.ace_hidpi .ace_text-layer > .ace_line, \
|
|
.ace_hidpi .ace_text-layer > .ace_line_group {\
|
|
contain: strict;\
|
|
}\
|
|
.ace_cjk {\
|
|
display: inline-block;\
|
|
text-align: center;\
|
|
}\
|
|
.ace_cursor-layer {\
|
|
z-index: 4;\
|
|
}\
|
|
.ace_cursor {\
|
|
z-index: 4;\
|
|
position: absolute;\
|
|
box-sizing: border-box;\
|
|
border-left: 2px solid;\
|
|
transform: translatez(0);\
|
|
}\
|
|
.ace_multiselect .ace_cursor {\
|
|
border-left-width: 1px;\
|
|
}\
|
|
.ace_slim-cursors .ace_cursor {\
|
|
border-left-width: 1px;\
|
|
}\
|
|
.ace_overwrite-cursors .ace_cursor {\
|
|
border-left-width: 0;\
|
|
border-bottom: 1px solid;\
|
|
}\
|
|
.ace_hidden-cursors .ace_cursor {\
|
|
opacity: 0.2;\
|
|
}\
|
|
.ace_hasPlaceholder .ace_hidden-cursors .ace_cursor {\
|
|
opacity: 0;\
|
|
}\
|
|
.ace_smooth-blinking .ace_cursor {\
|
|
transition: opacity 0.18s;\
|
|
}\
|
|
.ace_animate-blinking .ace_cursor {\
|
|
animation-duration: 1000ms;\
|
|
animation-timing-function: step-end;\
|
|
animation-name: blink-ace-animate;\
|
|
animation-iteration-count: infinite;\
|
|
}\
|
|
.ace_animate-blinking.ace_smooth-blinking .ace_cursor {\
|
|
animation-duration: 1000ms;\
|
|
animation-timing-function: ease-in-out;\
|
|
animation-name: blink-ace-animate-smooth;\
|
|
}\
|
|
@keyframes blink-ace-animate {\
|
|
from, to { opacity: 1; }\
|
|
60% { opacity: 0; }\
|
|
}\
|
|
@keyframes blink-ace-animate-smooth {\
|
|
from, to { opacity: 1; }\
|
|
45% { opacity: 1; }\
|
|
60% { opacity: 0; }\
|
|
85% { opacity: 0; }\
|
|
}\
|
|
.ace_marker-layer .ace_step, .ace_marker-layer .ace_stack {\
|
|
position: absolute;\
|
|
z-index: 3;\
|
|
}\
|
|
.ace_marker-layer .ace_selection {\
|
|
position: absolute;\
|
|
z-index: 5;\
|
|
}\
|
|
.ace_marker-layer .ace_bracket {\
|
|
position: absolute;\
|
|
z-index: 6;\
|
|
}\
|
|
.ace_marker-layer .ace_error_bracket {\
|
|
position: absolute;\
|
|
border-bottom: 1px solid #DE5555;\
|
|
border-radius: 0;\
|
|
}\
|
|
.ace_marker-layer .ace_active-line {\
|
|
position: absolute;\
|
|
z-index: 2;\
|
|
}\
|
|
.ace_marker-layer .ace_selected-word {\
|
|
position: absolute;\
|
|
z-index: 4;\
|
|
box-sizing: border-box;\
|
|
}\
|
|
.ace_line .ace_fold {\
|
|
box-sizing: border-box;\
|
|
display: inline-block;\
|
|
height: 11px;\
|
|
margin-top: -2px;\
|
|
vertical-align: middle;\
|
|
background-image:\
|
|
url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAJCAYAAADU6McMAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAJpJREFUeNpi/P//PwOlgAXGYGRklAVSokD8GmjwY1wasKljQpYACtpCFeADcHVQfQyMQAwzwAZI3wJKvCLkfKBaMSClBlR7BOQikCFGQEErIH0VqkabiGCAqwUadAzZJRxQr/0gwiXIal8zQQPnNVTgJ1TdawL0T5gBIP1MUJNhBv2HKoQHHjqNrA4WO4zY0glyNKLT2KIfIMAAQsdgGiXvgnYAAAAASUVORK5CYII=\"),\
|
|
url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAA3CAYAAADNNiA5AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAACJJREFUeNpi+P//fxgTAwPDBxDxD078RSX+YeEyDFMCIMAAI3INmXiwf2YAAAAASUVORK5CYII=\");\
|
|
background-repeat: no-repeat, repeat-x;\
|
|
background-position: center center, top left;\
|
|
color: transparent;\
|
|
border: 1px solid black;\
|
|
border-radius: 2px;\
|
|
cursor: pointer;\
|
|
pointer-events: auto;\
|
|
}\
|
|
.ace_dark .ace_fold {\
|
|
}\
|
|
.ace_fold:hover{\
|
|
background-image:\
|
|
url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAJCAYAAADU6McMAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAJpJREFUeNpi/P//PwOlgAXGYGRklAVSokD8GmjwY1wasKljQpYACtpCFeADcHVQfQyMQAwzwAZI3wJKvCLkfKBaMSClBlR7BOQikCFGQEErIH0VqkabiGCAqwUadAzZJRxQr/0gwiXIal8zQQPnNVTgJ1TdawL0T5gBIP1MUJNhBv2HKoQHHjqNrA4WO4zY0glyNKLT2KIfIMAAQsdgGiXvgnYAAAAASUVORK5CYII=\"),\
|
|
url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAA3CAYAAADNNiA5AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAACBJREFUeNpi+P//fz4TAwPDZxDxD5X4i5fLMEwJgAADAEPVDbjNw87ZAAAAAElFTkSuQmCC\");\
|
|
}\
|
|
.ace_tooltip {\
|
|
background-color: #FFF;\
|
|
background-image: linear-gradient(to bottom, transparent, rgba(0, 0, 0, 0.1));\
|
|
border: 1px solid gray;\
|
|
border-radius: 1px;\
|
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);\
|
|
color: black;\
|
|
max-width: 100%;\
|
|
padding: 3px 4px;\
|
|
position: fixed;\
|
|
z-index: 999999;\
|
|
box-sizing: border-box;\
|
|
cursor: default;\
|
|
white-space: pre;\
|
|
word-wrap: break-word;\
|
|
line-height: normal;\
|
|
font-style: normal;\
|
|
font-weight: normal;\
|
|
letter-spacing: normal;\
|
|
pointer-events: none;\
|
|
}\
|
|
.ace_folding-enabled > .ace_gutter-cell {\
|
|
padding-right: 13px;\
|
|
}\
|
|
.ace_fold-widget {\
|
|
box-sizing: border-box;\
|
|
margin: 0 -12px 0 1px;\
|
|
display: none;\
|
|
width: 11px;\
|
|
vertical-align: top;\
|
|
background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAANElEQVR42mWKsQ0AMAzC8ixLlrzQjzmBiEjp0A6WwBCSPgKAXoLkqSot7nN3yMwR7pZ32NzpKkVoDBUxKAAAAABJRU5ErkJggg==\");\
|
|
background-repeat: no-repeat;\
|
|
background-position: center;\
|
|
border-radius: 3px;\
|
|
border: 1px solid transparent;\
|
|
cursor: pointer;\
|
|
}\
|
|
.ace_folding-enabled .ace_fold-widget {\
|
|
display: inline-block; \
|
|
}\
|
|
.ace_fold-widget.ace_end {\
|
|
background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAANElEQVR42m3HwQkAMAhD0YzsRchFKI7sAikeWkrxwScEB0nh5e7KTPWimZki4tYfVbX+MNl4pyZXejUO1QAAAABJRU5ErkJggg==\");\
|
|
}\
|
|
.ace_fold-widget.ace_closed {\
|
|
background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAGCAYAAAAG5SQMAAAAOUlEQVR42jXKwQkAMAgDwKwqKD4EwQ26sSOkVWjgIIHAzPiCgaqiqnJHZnKICBERHN194O5b9vbLuAVRL+l0YWnZAAAAAElFTkSuQmCCXA==\");\
|
|
}\
|
|
.ace_fold-widget:hover {\
|
|
border: 1px solid rgba(0, 0, 0, 0.3);\
|
|
background-color: rgba(255, 255, 255, 0.2);\
|
|
box-shadow: 0 1px 1px rgba(255, 255, 255, 0.7);\
|
|
}\
|
|
.ace_fold-widget:active {\
|
|
border: 1px solid rgba(0, 0, 0, 0.4);\
|
|
background-color: rgba(0, 0, 0, 0.05);\
|
|
box-shadow: 0 1px 1px rgba(255, 255, 255, 0.8);\
|
|
}\
|
|
.ace_dark .ace_fold-widget {\
|
|
background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHklEQVQIW2P4//8/AzoGEQ7oGCaLLAhWiSwB146BAQCSTPYocqT0AAAAAElFTkSuQmCC\");\
|
|
}\
|
|
.ace_dark .ace_fold-widget.ace_end {\
|
|
background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAH0lEQVQIW2P4//8/AxQ7wNjIAjDMgC4AxjCVKBirIAAF0kz2rlhxpAAAAABJRU5ErkJggg==\");\
|
|
}\
|
|
.ace_dark .ace_fold-widget.ace_closed {\
|
|
background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAHElEQVQIW2P4//+/AxAzgDADlOOAznHAKgPWAwARji8UIDTfQQAAAABJRU5ErkJggg==\");\
|
|
}\
|
|
.ace_dark .ace_fold-widget:hover {\
|
|
box-shadow: 0 1px 1px rgba(255, 255, 255, 0.2);\
|
|
background-color: rgba(255, 255, 255, 0.1);\
|
|
}\
|
|
.ace_dark .ace_fold-widget:active {\
|
|
box-shadow: 0 1px 1px rgba(255, 255, 255, 0.2);\
|
|
}\
|
|
.ace_inline_button {\
|
|
border: 1px solid lightgray;\
|
|
display: inline-block;\
|
|
margin: -1px 8px;\
|
|
padding: 0 5px;\
|
|
pointer-events: auto;\
|
|
cursor: pointer;\
|
|
}\
|
|
.ace_inline_button:hover {\
|
|
border-color: gray;\
|
|
background: rgba(200,200,200,0.2);\
|
|
display: inline-block;\
|
|
pointer-events: auto;\
|
|
}\
|
|
.ace_fold-widget.ace_invalid {\
|
|
background-color: #FFB4B4;\
|
|
border-color: #DE5555;\
|
|
}\
|
|
.ace_fade-fold-widgets .ace_fold-widget {\
|
|
transition: opacity 0.4s ease 0.05s;\
|
|
opacity: 0;\
|
|
}\
|
|
.ace_fade-fold-widgets:hover .ace_fold-widget {\
|
|
transition: opacity 0.05s ease 0.05s;\
|
|
opacity:1;\
|
|
}\
|
|
.ace_underline {\
|
|
text-decoration: underline;\
|
|
}\
|
|
.ace_bold {\
|
|
font-weight: bold;\
|
|
}\
|
|
.ace_nobold .ace_bold {\
|
|
font-weight: normal;\
|
|
}\
|
|
.ace_italic {\
|
|
font-style: italic;\
|
|
}\
|
|
.ace_error-marker {\
|
|
background-color: rgba(255, 0, 0,0.2);\
|
|
position: absolute;\
|
|
z-index: 9;\
|
|
}\
|
|
.ace_highlight-marker {\
|
|
background-color: rgba(255, 255, 0,0.2);\
|
|
position: absolute;\
|
|
z-index: 8;\
|
|
}\
|
|
.ace_mobile-menu {\
|
|
position: absolute;\
|
|
line-height: 1.5;\
|
|
border-radius: 4px;\
|
|
-ms-user-select: none;\
|
|
-moz-user-select: none;\
|
|
-webkit-user-select: none;\
|
|
user-select: none;\
|
|
background: white;\
|
|
box-shadow: 1px 3px 2px grey;\
|
|
border: 1px solid #dcdcdc;\
|
|
color: black;\
|
|
}\
|
|
.ace_dark > .ace_mobile-menu {\
|
|
background: #333;\
|
|
color: #ccc;\
|
|
box-shadow: 1px 3px 2px grey;\
|
|
border: 1px solid #444;\
|
|
}\
|
|
.ace_mobile-button {\
|
|
padding: 2px;\
|
|
cursor: pointer;\
|
|
overflow: hidden;\
|
|
}\
|
|
.ace_mobile-button:hover {\
|
|
background-color: #eee;\
|
|
opacity:1;\
|
|
}\
|
|
.ace_mobile-button:active {\
|
|
background-color: #ddd;\
|
|
}\
|
|
.ace_placeholder {\
|
|
font-family: arial;\
|
|
transform: scale(0.9);\
|
|
transform-origin: left;\
|
|
white-space: pre;\
|
|
opacity: 0.7;\
|
|
margin: 0 10px;\
|
|
}";
|
|
|
|
var useragent = require("./lib/useragent");
|
|
var HIDE_TEXTAREA = useragent.isIE;
|
|
|
|
dom.importCssString(editorCss, "ace_editor.css");
|
|
|
|
var VirtualRenderer = function(container, theme) {
|
|
var _self = this;
|
|
|
|
this.container = container || dom.createElement("div");
|
|
|
|
dom.addCssClass(this.container, "ace_editor");
|
|
if (dom.HI_DPI) dom.addCssClass(this.container, "ace_hidpi");
|
|
|
|
this.setTheme(theme);
|
|
|
|
this.$gutter = dom.createElement("div");
|
|
this.$gutter.className = "ace_gutter";
|
|
this.container.appendChild(this.$gutter);
|
|
this.$gutter.setAttribute("aria-hidden", true);
|
|
|
|
this.scroller = dom.createElement("div");
|
|
this.scroller.className = "ace_scroller";
|
|
|
|
this.container.appendChild(this.scroller);
|
|
|
|
this.content = dom.createElement("div");
|
|
this.content.className = "ace_content";
|
|
this.scroller.appendChild(this.content);
|
|
|
|
this.$gutterLayer = new GutterLayer(this.$gutter);
|
|
this.$gutterLayer.on("changeGutterWidth", this.onGutterResize.bind(this));
|
|
|
|
this.$markerBack = new MarkerLayer(this.content);
|
|
|
|
var textLayer = this.$textLayer = new TextLayer(this.content);
|
|
this.canvas = textLayer.element;
|
|
|
|
this.$markerFront = new MarkerLayer(this.content);
|
|
|
|
this.$cursorLayer = new CursorLayer(this.content);
|
|
this.$horizScroll = false;
|
|
this.$vScroll = false;
|
|
|
|
this.scrollBar =
|
|
this.scrollBarV = new VScrollBar(this.container, this);
|
|
this.scrollBarH = new HScrollBar(this.container, this);
|
|
this.scrollBarV.on("scroll", function(e) {
|
|
if (!_self.$scrollAnimation)
|
|
_self.session.setScrollTop(e.data - _self.scrollMargin.top);
|
|
});
|
|
this.scrollBarH.on("scroll", function(e) {
|
|
if (!_self.$scrollAnimation)
|
|
_self.session.setScrollLeft(e.data - _self.scrollMargin.left);
|
|
});
|
|
|
|
this.scrollTop = 0;
|
|
this.scrollLeft = 0;
|
|
|
|
this.cursorPos = {
|
|
row : 0,
|
|
column : 0
|
|
};
|
|
|
|
this.$fontMetrics = new FontMetrics(this.container);
|
|
this.$textLayer.$setFontMetrics(this.$fontMetrics);
|
|
this.$textLayer.on("changeCharacterSize", function(e) {
|
|
_self.updateCharacterSize();
|
|
_self.onResize(true, _self.gutterWidth, _self.$size.width, _self.$size.height);
|
|
_self._signal("changeCharacterSize", e);
|
|
});
|
|
|
|
this.$size = {
|
|
width: 0,
|
|
height: 0,
|
|
scrollerHeight: 0,
|
|
scrollerWidth: 0,
|
|
$dirty: true
|
|
};
|
|
|
|
this.layerConfig = {
|
|
width : 1,
|
|
padding : 0,
|
|
firstRow : 0,
|
|
firstRowScreen: 0,
|
|
lastRow : 0,
|
|
lineHeight : 0,
|
|
characterWidth : 0,
|
|
minHeight : 1,
|
|
maxHeight : 1,
|
|
offset : 0,
|
|
height : 1,
|
|
gutterOffset: 1
|
|
};
|
|
|
|
this.scrollMargin = {
|
|
left: 0,
|
|
right: 0,
|
|
top: 0,
|
|
bottom: 0,
|
|
v: 0,
|
|
h: 0
|
|
};
|
|
|
|
this.margin = {
|
|
left: 0,
|
|
right: 0,
|
|
top: 0,
|
|
bottom: 0,
|
|
v: 0,
|
|
h: 0
|
|
};
|
|
|
|
this.$keepTextAreaAtCursor = !useragent.isIOS;
|
|
|
|
this.$loop = new RenderLoop(
|
|
this.$renderChanges.bind(this),
|
|
this.container.ownerDocument.defaultView
|
|
);
|
|
this.$loop.schedule(this.CHANGE_FULL);
|
|
|
|
this.updateCharacterSize();
|
|
this.setPadding(4);
|
|
config.resetOptions(this);
|
|
config._signal("renderer", this);
|
|
};
|
|
|
|
(function() {
|
|
|
|
this.CHANGE_CURSOR = 1;
|
|
this.CHANGE_MARKER = 2;
|
|
this.CHANGE_GUTTER = 4;
|
|
this.CHANGE_SCROLL = 8;
|
|
this.CHANGE_LINES = 16;
|
|
this.CHANGE_TEXT = 32;
|
|
this.CHANGE_SIZE = 64;
|
|
this.CHANGE_MARKER_BACK = 128;
|
|
this.CHANGE_MARKER_FRONT = 256;
|
|
this.CHANGE_FULL = 512;
|
|
this.CHANGE_H_SCROLL = 1024;
|
|
|
|
oop.implement(this, EventEmitter);
|
|
|
|
this.updateCharacterSize = function() {
|
|
if (this.$textLayer.allowBoldFonts != this.$allowBoldFonts) {
|
|
this.$allowBoldFonts = this.$textLayer.allowBoldFonts;
|
|
this.setStyle("ace_nobold", !this.$allowBoldFonts);
|
|
}
|
|
|
|
this.layerConfig.characterWidth =
|
|
this.characterWidth = this.$textLayer.getCharacterWidth();
|
|
this.layerConfig.lineHeight =
|
|
this.lineHeight = this.$textLayer.getLineHeight();
|
|
this.$updatePrintMargin();
|
|
dom.setStyle(this.scroller.style, "line-height", this.lineHeight + "px");
|
|
};
|
|
this.setSession = function(session) {
|
|
if (this.session)
|
|
this.session.doc.off("changeNewLineMode", this.onChangeNewLineMode);
|
|
|
|
this.session = session;
|
|
if (session && this.scrollMargin.top && session.getScrollTop() <= 0)
|
|
session.setScrollTop(-this.scrollMargin.top);
|
|
|
|
this.$cursorLayer.setSession(session);
|
|
this.$markerBack.setSession(session);
|
|
this.$markerFront.setSession(session);
|
|
this.$gutterLayer.setSession(session);
|
|
this.$textLayer.setSession(session);
|
|
if (!session)
|
|
return;
|
|
|
|
this.$loop.schedule(this.CHANGE_FULL);
|
|
this.session.$setFontMetrics(this.$fontMetrics);
|
|
this.scrollBarH.scrollLeft = this.scrollBarV.scrollTop = null;
|
|
|
|
this.onChangeNewLineMode = this.onChangeNewLineMode.bind(this);
|
|
this.onChangeNewLineMode();
|
|
this.session.doc.on("changeNewLineMode", this.onChangeNewLineMode);
|
|
};
|
|
this.updateLines = function(firstRow, lastRow, force) {
|
|
if (lastRow === undefined)
|
|
lastRow = Infinity;
|
|
|
|
if (!this.$changedLines) {
|
|
this.$changedLines = {
|
|
firstRow: firstRow,
|
|
lastRow: lastRow
|
|
};
|
|
}
|
|
else {
|
|
if (this.$changedLines.firstRow > firstRow)
|
|
this.$changedLines.firstRow = firstRow;
|
|
|
|
if (this.$changedLines.lastRow < lastRow)
|
|
this.$changedLines.lastRow = lastRow;
|
|
}
|
|
if (this.$changedLines.lastRow < this.layerConfig.firstRow) {
|
|
if (force)
|
|
this.$changedLines.lastRow = this.layerConfig.lastRow;
|
|
else
|
|
return;
|
|
}
|
|
if (this.$changedLines.firstRow > this.layerConfig.lastRow)
|
|
return;
|
|
this.$loop.schedule(this.CHANGE_LINES);
|
|
};
|
|
|
|
this.onChangeNewLineMode = function() {
|
|
this.$loop.schedule(this.CHANGE_TEXT);
|
|
this.$textLayer.$updateEolChar();
|
|
this.session.$bidiHandler.setEolChar(this.$textLayer.EOL_CHAR);
|
|
};
|
|
|
|
this.onChangeTabSize = function() {
|
|
this.$loop.schedule(this.CHANGE_TEXT | this.CHANGE_MARKER);
|
|
this.$textLayer.onChangeTabSize();
|
|
};
|
|
this.updateText = function() {
|
|
this.$loop.schedule(this.CHANGE_TEXT);
|
|
};
|
|
this.updateFull = function(force) {
|
|
if (force)
|
|
this.$renderChanges(this.CHANGE_FULL, true);
|
|
else
|
|
this.$loop.schedule(this.CHANGE_FULL);
|
|
};
|
|
this.updateFontSize = function() {
|
|
this.$textLayer.checkForSizeChanges();
|
|
};
|
|
|
|
this.$changes = 0;
|
|
this.$updateSizeAsync = function() {
|
|
if (this.$loop.pending)
|
|
this.$size.$dirty = true;
|
|
else
|
|
this.onResize();
|
|
};
|
|
this.onResize = function(force, gutterWidth, width, height) {
|
|
if (this.resizing > 2)
|
|
return;
|
|
else if (this.resizing > 0)
|
|
this.resizing++;
|
|
else
|
|
this.resizing = force ? 1 : 0;
|
|
var el = this.container;
|
|
if (!height)
|
|
height = el.clientHeight || el.scrollHeight;
|
|
if (!width)
|
|
width = el.clientWidth || el.scrollWidth;
|
|
var changes = this.$updateCachedSize(force, gutterWidth, width, height);
|
|
|
|
|
|
if (!this.$size.scrollerHeight || (!width && !height))
|
|
return this.resizing = 0;
|
|
|
|
if (force)
|
|
this.$gutterLayer.$padding = null;
|
|
|
|
if (force)
|
|
this.$renderChanges(changes | this.$changes, true);
|
|
else
|
|
this.$loop.schedule(changes | this.$changes);
|
|
|
|
if (this.resizing)
|
|
this.resizing = 0;
|
|
this.scrollBarV.scrollLeft = this.scrollBarV.scrollTop = null;
|
|
};
|
|
|
|
this.$updateCachedSize = function(force, gutterWidth, width, height) {
|
|
height -= (this.$extraHeight || 0);
|
|
var changes = 0;
|
|
var size = this.$size;
|
|
var oldSize = {
|
|
width: size.width,
|
|
height: size.height,
|
|
scrollerHeight: size.scrollerHeight,
|
|
scrollerWidth: size.scrollerWidth
|
|
};
|
|
if (height && (force || size.height != height)) {
|
|
size.height = height;
|
|
changes |= this.CHANGE_SIZE;
|
|
|
|
size.scrollerHeight = size.height;
|
|
if (this.$horizScroll)
|
|
size.scrollerHeight -= this.scrollBarH.getHeight();
|
|
this.scrollBarV.element.style.bottom = this.scrollBarH.getHeight() + "px";
|
|
|
|
changes = changes | this.CHANGE_SCROLL;
|
|
}
|
|
|
|
if (width && (force || size.width != width)) {
|
|
changes |= this.CHANGE_SIZE;
|
|
size.width = width;
|
|
|
|
if (gutterWidth == null)
|
|
gutterWidth = this.$showGutter ? this.$gutter.offsetWidth : 0;
|
|
|
|
this.gutterWidth = gutterWidth;
|
|
|
|
dom.setStyle(this.scrollBarH.element.style, "left", gutterWidth + "px");
|
|
dom.setStyle(this.scroller.style, "left", gutterWidth + this.margin.left + "px");
|
|
size.scrollerWidth = Math.max(0, width - gutterWidth - this.scrollBarV.getWidth() - this.margin.h);
|
|
dom.setStyle(this.$gutter.style, "left", this.margin.left + "px");
|
|
|
|
var right = this.scrollBarV.getWidth() + "px";
|
|
dom.setStyle(this.scrollBarH.element.style, "right", right);
|
|
dom.setStyle(this.scroller.style, "right", right);
|
|
dom.setStyle(this.scroller.style, "bottom", this.scrollBarH.getHeight());
|
|
|
|
if (this.session && this.session.getUseWrapMode() && this.adjustWrapLimit() || force) {
|
|
changes |= this.CHANGE_FULL;
|
|
}
|
|
}
|
|
|
|
size.$dirty = !width || !height;
|
|
|
|
if (changes)
|
|
this._signal("resize", oldSize);
|
|
|
|
return changes;
|
|
};
|
|
|
|
this.onGutterResize = function(width) {
|
|
var gutterWidth = this.$showGutter ? width : 0;
|
|
if (gutterWidth != this.gutterWidth)
|
|
this.$changes |= this.$updateCachedSize(true, gutterWidth, this.$size.width, this.$size.height);
|
|
|
|
if (this.session.getUseWrapMode() && this.adjustWrapLimit()) {
|
|
this.$loop.schedule(this.CHANGE_FULL);
|
|
} else if (this.$size.$dirty) {
|
|
this.$loop.schedule(this.CHANGE_FULL);
|
|
} else {
|
|
this.$computeLayerConfig();
|
|
}
|
|
};
|
|
this.adjustWrapLimit = function() {
|
|
var availableWidth = this.$size.scrollerWidth - this.$padding * 2;
|
|
var limit = Math.floor(availableWidth / this.characterWidth);
|
|
return this.session.adjustWrapLimit(limit, this.$showPrintMargin && this.$printMarginColumn);
|
|
};
|
|
this.setAnimatedScroll = function(shouldAnimate){
|
|
this.setOption("animatedScroll", shouldAnimate);
|
|
};
|
|
this.getAnimatedScroll = function() {
|
|
return this.$animatedScroll;
|
|
};
|
|
this.setShowInvisibles = function(showInvisibles) {
|
|
this.setOption("showInvisibles", showInvisibles);
|
|
this.session.$bidiHandler.setShowInvisibles(showInvisibles);
|
|
};
|
|
this.getShowInvisibles = function() {
|
|
return this.getOption("showInvisibles");
|
|
};
|
|
this.getDisplayIndentGuides = function() {
|
|
return this.getOption("displayIndentGuides");
|
|
};
|
|
|
|
this.setDisplayIndentGuides = function(display) {
|
|
this.setOption("displayIndentGuides", display);
|
|
};
|
|
this.setShowPrintMargin = function(showPrintMargin) {
|
|
this.setOption("showPrintMargin", showPrintMargin);
|
|
};
|
|
this.getShowPrintMargin = function() {
|
|
return this.getOption("showPrintMargin");
|
|
};
|
|
this.setPrintMarginColumn = function(showPrintMargin) {
|
|
this.setOption("printMarginColumn", showPrintMargin);
|
|
};
|
|
this.getPrintMarginColumn = function() {
|
|
return this.getOption("printMarginColumn");
|
|
};
|
|
this.getShowGutter = function(){
|
|
return this.getOption("showGutter");
|
|
};
|
|
this.setShowGutter = function(show){
|
|
return this.setOption("showGutter", show);
|
|
};
|
|
|
|
this.getFadeFoldWidgets = function(){
|
|
return this.getOption("fadeFoldWidgets");
|
|
};
|
|
|
|
this.setFadeFoldWidgets = function(show) {
|
|
this.setOption("fadeFoldWidgets", show);
|
|
};
|
|
|
|
this.setHighlightGutterLine = function(shouldHighlight) {
|
|
this.setOption("highlightGutterLine", shouldHighlight);
|
|
};
|
|
|
|
this.getHighlightGutterLine = function() {
|
|
return this.getOption("highlightGutterLine");
|
|
};
|
|
|
|
this.$updatePrintMargin = function() {
|
|
if (!this.$showPrintMargin && !this.$printMarginEl)
|
|
return;
|
|
|
|
if (!this.$printMarginEl) {
|
|
var containerEl = dom.createElement("div");
|
|
containerEl.className = "ace_layer ace_print-margin-layer";
|
|
this.$printMarginEl = dom.createElement("div");
|
|
this.$printMarginEl.className = "ace_print-margin";
|
|
containerEl.appendChild(this.$printMarginEl);
|
|
this.content.insertBefore(containerEl, this.content.firstChild);
|
|
}
|
|
|
|
var style = this.$printMarginEl.style;
|
|
style.left = Math.round(this.characterWidth * this.$printMarginColumn + this.$padding) + "px";
|
|
style.visibility = this.$showPrintMargin ? "visible" : "hidden";
|
|
|
|
if (this.session && this.session.$wrap == -1)
|
|
this.adjustWrapLimit();
|
|
};
|
|
this.getContainerElement = function() {
|
|
return this.container;
|
|
};
|
|
this.getMouseEventTarget = function() {
|
|
return this.scroller;
|
|
};
|
|
this.getTextAreaContainer = function() {
|
|
return this.container;
|
|
};
|
|
this.$moveTextAreaToCursor = function() {
|
|
if (this.$isMousePressed) return;
|
|
var style = this.textarea.style;
|
|
var composition = this.$composition;
|
|
if (!this.$keepTextAreaAtCursor && !composition) {
|
|
dom.translate(this.textarea, -100, 0);
|
|
return;
|
|
}
|
|
var pixelPos = this.$cursorLayer.$pixelPos;
|
|
if (!pixelPos)
|
|
return;
|
|
if (composition && composition.markerRange)
|
|
pixelPos = this.$cursorLayer.getPixelPosition(composition.markerRange.start, true);
|
|
|
|
var config = this.layerConfig;
|
|
var posTop = pixelPos.top;
|
|
var posLeft = pixelPos.left;
|
|
posTop -= config.offset;
|
|
|
|
var h = composition && composition.useTextareaForIME ? this.lineHeight : HIDE_TEXTAREA ? 0 : 1;
|
|
if (posTop < 0 || posTop > config.height - h) {
|
|
dom.translate(this.textarea, 0, 0);
|
|
return;
|
|
}
|
|
|
|
var w = 1;
|
|
var maxTop = this.$size.height - h;
|
|
if (!composition) {
|
|
posTop += this.lineHeight;
|
|
}
|
|
else {
|
|
if (composition.useTextareaForIME) {
|
|
var val = this.textarea.value;
|
|
w = this.characterWidth * (this.session.$getStringScreenWidth(val)[0]);
|
|
}
|
|
else {
|
|
posTop += this.lineHeight + 2;
|
|
}
|
|
}
|
|
|
|
posLeft -= this.scrollLeft;
|
|
if (posLeft > this.$size.scrollerWidth - w)
|
|
posLeft = this.$size.scrollerWidth - w;
|
|
|
|
posLeft += this.gutterWidth + this.margin.left;
|
|
|
|
dom.setStyle(style, "height", h + "px");
|
|
dom.setStyle(style, "width", w + "px");
|
|
dom.translate(this.textarea, Math.min(posLeft, this.$size.scrollerWidth - w), Math.min(posTop, maxTop));
|
|
};
|
|
this.getFirstVisibleRow = function() {
|
|
return this.layerConfig.firstRow;
|
|
};
|
|
this.getFirstFullyVisibleRow = function() {
|
|
return this.layerConfig.firstRow + (this.layerConfig.offset === 0 ? 0 : 1);
|
|
};
|
|
this.getLastFullyVisibleRow = function() {
|
|
var config = this.layerConfig;
|
|
var lastRow = config.lastRow;
|
|
var top = this.session.documentToScreenRow(lastRow, 0) * config.lineHeight;
|
|
if (top - this.session.getScrollTop() > config.height - config.lineHeight)
|
|
return lastRow - 1;
|
|
return lastRow;
|
|
};
|
|
this.getLastVisibleRow = function() {
|
|
return this.layerConfig.lastRow;
|
|
};
|
|
|
|
this.$padding = null;
|
|
this.setPadding = function(padding) {
|
|
this.$padding = padding;
|
|
this.$textLayer.setPadding(padding);
|
|
this.$cursorLayer.setPadding(padding);
|
|
this.$markerFront.setPadding(padding);
|
|
this.$markerBack.setPadding(padding);
|
|
this.$loop.schedule(this.CHANGE_FULL);
|
|
this.$updatePrintMargin();
|
|
};
|
|
|
|
this.setScrollMargin = function(top, bottom, left, right) {
|
|
var sm = this.scrollMargin;
|
|
sm.top = top|0;
|
|
sm.bottom = bottom|0;
|
|
sm.right = right|0;
|
|
sm.left = left|0;
|
|
sm.v = sm.top + sm.bottom;
|
|
sm.h = sm.left + sm.right;
|
|
if (sm.top && this.scrollTop <= 0 && this.session)
|
|
this.session.setScrollTop(-sm.top);
|
|
this.updateFull();
|
|
};
|
|
|
|
this.setMargin = function(top, bottom, left, right) {
|
|
var sm = this.margin;
|
|
sm.top = top|0;
|
|
sm.bottom = bottom|0;
|
|
sm.right = right|0;
|
|
sm.left = left|0;
|
|
sm.v = sm.top + sm.bottom;
|
|
sm.h = sm.left + sm.right;
|
|
this.$updateCachedSize(true, this.gutterWidth, this.$size.width, this.$size.height);
|
|
this.updateFull();
|
|
};
|
|
this.getHScrollBarAlwaysVisible = function() {
|
|
return this.$hScrollBarAlwaysVisible;
|
|
};
|
|
this.setHScrollBarAlwaysVisible = function(alwaysVisible) {
|
|
this.setOption("hScrollBarAlwaysVisible", alwaysVisible);
|
|
};
|
|
this.getVScrollBarAlwaysVisible = function() {
|
|
return this.$vScrollBarAlwaysVisible;
|
|
};
|
|
this.setVScrollBarAlwaysVisible = function(alwaysVisible) {
|
|
this.setOption("vScrollBarAlwaysVisible", alwaysVisible);
|
|
};
|
|
|
|
this.$updateScrollBarV = function() {
|
|
var scrollHeight = this.layerConfig.maxHeight;
|
|
var scrollerHeight = this.$size.scrollerHeight;
|
|
if (!this.$maxLines && this.$scrollPastEnd) {
|
|
scrollHeight -= (scrollerHeight - this.lineHeight) * this.$scrollPastEnd;
|
|
if (this.scrollTop > scrollHeight - scrollerHeight) {
|
|
scrollHeight = this.scrollTop + scrollerHeight;
|
|
this.scrollBarV.scrollTop = null;
|
|
}
|
|
}
|
|
this.scrollBarV.setScrollHeight(scrollHeight + this.scrollMargin.v);
|
|
this.scrollBarV.setScrollTop(this.scrollTop + this.scrollMargin.top);
|
|
};
|
|
this.$updateScrollBarH = function() {
|
|
this.scrollBarH.setScrollWidth(this.layerConfig.width + 2 * this.$padding + this.scrollMargin.h);
|
|
this.scrollBarH.setScrollLeft(this.scrollLeft + this.scrollMargin.left);
|
|
};
|
|
|
|
this.$frozen = false;
|
|
this.freeze = function() {
|
|
this.$frozen = true;
|
|
};
|
|
|
|
this.unfreeze = function() {
|
|
this.$frozen = false;
|
|
};
|
|
|
|
this.$renderChanges = function(changes, force) {
|
|
if (this.$changes) {
|
|
changes |= this.$changes;
|
|
this.$changes = 0;
|
|
}
|
|
if ((!this.session || !this.container.offsetWidth || this.$frozen) || (!changes && !force)) {
|
|
this.$changes |= changes;
|
|
return;
|
|
}
|
|
if (this.$size.$dirty) {
|
|
this.$changes |= changes;
|
|
return this.onResize(true);
|
|
}
|
|
if (!this.lineHeight) {
|
|
this.$textLayer.checkForSizeChanges();
|
|
}
|
|
|
|
this._signal("beforeRender", changes);
|
|
|
|
if (this.session && this.session.$bidiHandler)
|
|
this.session.$bidiHandler.updateCharacterWidths(this.$fontMetrics);
|
|
|
|
var config = this.layerConfig;
|
|
if (changes & this.CHANGE_FULL ||
|
|
changes & this.CHANGE_SIZE ||
|
|
changes & this.CHANGE_TEXT ||
|
|
changes & this.CHANGE_LINES ||
|
|
changes & this.CHANGE_SCROLL ||
|
|
changes & this.CHANGE_H_SCROLL
|
|
) {
|
|
changes |= this.$computeLayerConfig() | this.$loop.clear();
|
|
if (config.firstRow != this.layerConfig.firstRow && config.firstRowScreen == this.layerConfig.firstRowScreen) {
|
|
var st = this.scrollTop + (config.firstRow - this.layerConfig.firstRow) * this.lineHeight;
|
|
if (st > 0) {
|
|
this.scrollTop = st;
|
|
changes = changes | this.CHANGE_SCROLL;
|
|
changes |= this.$computeLayerConfig() | this.$loop.clear();
|
|
}
|
|
}
|
|
config = this.layerConfig;
|
|
this.$updateScrollBarV();
|
|
if (changes & this.CHANGE_H_SCROLL)
|
|
this.$updateScrollBarH();
|
|
|
|
dom.translate(this.content, -this.scrollLeft, -config.offset);
|
|
|
|
var width = config.width + 2 * this.$padding + "px";
|
|
var height = config.minHeight + "px";
|
|
|
|
dom.setStyle(this.content.style, "width", width);
|
|
dom.setStyle(this.content.style, "height", height);
|
|
}
|
|
if (changes & this.CHANGE_H_SCROLL) {
|
|
dom.translate(this.content, -this.scrollLeft, -config.offset);
|
|
this.scroller.className = this.scrollLeft <= 0 ? "ace_scroller" : "ace_scroller ace_scroll-left";
|
|
}
|
|
if (changes & this.CHANGE_FULL) {
|
|
this.$changedLines = null;
|
|
this.$textLayer.update(config);
|
|
if (this.$showGutter)
|
|
this.$gutterLayer.update(config);
|
|
this.$markerBack.update(config);
|
|
this.$markerFront.update(config);
|
|
this.$cursorLayer.update(config);
|
|
this.$moveTextAreaToCursor();
|
|
this._signal("afterRender", changes);
|
|
return;
|
|
}
|
|
if (changes & this.CHANGE_SCROLL) {
|
|
this.$changedLines = null;
|
|
if (changes & this.CHANGE_TEXT || changes & this.CHANGE_LINES)
|
|
this.$textLayer.update(config);
|
|
else
|
|
this.$textLayer.scrollLines(config);
|
|
|
|
if (this.$showGutter) {
|
|
if (changes & this.CHANGE_GUTTER || changes & this.CHANGE_LINES)
|
|
this.$gutterLayer.update(config);
|
|
else
|
|
this.$gutterLayer.scrollLines(config);
|
|
}
|
|
this.$markerBack.update(config);
|
|
this.$markerFront.update(config);
|
|
this.$cursorLayer.update(config);
|
|
this.$moveTextAreaToCursor();
|
|
this._signal("afterRender", changes);
|
|
return;
|
|
}
|
|
|
|
if (changes & this.CHANGE_TEXT) {
|
|
this.$changedLines = null;
|
|
this.$textLayer.update(config);
|
|
if (this.$showGutter)
|
|
this.$gutterLayer.update(config);
|
|
}
|
|
else if (changes & this.CHANGE_LINES) {
|
|
if (this.$updateLines() || (changes & this.CHANGE_GUTTER) && this.$showGutter)
|
|
this.$gutterLayer.update(config);
|
|
}
|
|
else if (changes & this.CHANGE_TEXT || changes & this.CHANGE_GUTTER) {
|
|
if (this.$showGutter)
|
|
this.$gutterLayer.update(config);
|
|
}
|
|
else if (changes & this.CHANGE_CURSOR) {
|
|
if (this.$highlightGutterLine)
|
|
this.$gutterLayer.updateLineHighlight(config);
|
|
}
|
|
|
|
if (changes & this.CHANGE_CURSOR) {
|
|
this.$cursorLayer.update(config);
|
|
this.$moveTextAreaToCursor();
|
|
}
|
|
|
|
if (changes & (this.CHANGE_MARKER | this.CHANGE_MARKER_FRONT)) {
|
|
this.$markerFront.update(config);
|
|
}
|
|
|
|
if (changes & (this.CHANGE_MARKER | this.CHANGE_MARKER_BACK)) {
|
|
this.$markerBack.update(config);
|
|
}
|
|
|
|
this._signal("afterRender", changes);
|
|
};
|
|
|
|
|
|
this.$autosize = function() {
|
|
var height = this.session.getScreenLength() * this.lineHeight;
|
|
var maxHeight = this.$maxLines * this.lineHeight;
|
|
var desiredHeight = Math.min(maxHeight,
|
|
Math.max((this.$minLines || 1) * this.lineHeight, height)
|
|
) + this.scrollMargin.v + (this.$extraHeight || 0);
|
|
if (this.$horizScroll)
|
|
desiredHeight += this.scrollBarH.getHeight();
|
|
if (this.$maxPixelHeight && desiredHeight > this.$maxPixelHeight)
|
|
desiredHeight = this.$maxPixelHeight;
|
|
|
|
var hideScrollbars = desiredHeight <= 2 * this.lineHeight;
|
|
var vScroll = !hideScrollbars && height > maxHeight;
|
|
|
|
if (desiredHeight != this.desiredHeight ||
|
|
this.$size.height != this.desiredHeight || vScroll != this.$vScroll) {
|
|
if (vScroll != this.$vScroll) {
|
|
this.$vScroll = vScroll;
|
|
this.scrollBarV.setVisible(vScroll);
|
|
}
|
|
|
|
var w = this.container.clientWidth;
|
|
this.container.style.height = desiredHeight + "px";
|
|
this.$updateCachedSize(true, this.$gutterWidth, w, desiredHeight);
|
|
this.desiredHeight = desiredHeight;
|
|
|
|
this._signal("autosize");
|
|
}
|
|
};
|
|
|
|
this.$computeLayerConfig = function() {
|
|
var session = this.session;
|
|
var size = this.$size;
|
|
|
|
var hideScrollbars = size.height <= 2 * this.lineHeight;
|
|
var screenLines = this.session.getScreenLength();
|
|
var maxHeight = screenLines * this.lineHeight;
|
|
|
|
var longestLine = this.$getLongestLine();
|
|
|
|
var horizScroll = !hideScrollbars && (this.$hScrollBarAlwaysVisible ||
|
|
size.scrollerWidth - longestLine - 2 * this.$padding < 0);
|
|
|
|
var hScrollChanged = this.$horizScroll !== horizScroll;
|
|
if (hScrollChanged) {
|
|
this.$horizScroll = horizScroll;
|
|
this.scrollBarH.setVisible(horizScroll);
|
|
}
|
|
var vScrollBefore = this.$vScroll; // autosize can change vscroll value in which case we need to update longestLine
|
|
if (this.$maxLines && this.lineHeight > 1)
|
|
this.$autosize();
|
|
|
|
var minHeight = size.scrollerHeight + this.lineHeight;
|
|
|
|
var scrollPastEnd = !this.$maxLines && this.$scrollPastEnd
|
|
? (size.scrollerHeight - this.lineHeight) * this.$scrollPastEnd
|
|
: 0;
|
|
maxHeight += scrollPastEnd;
|
|
|
|
var sm = this.scrollMargin;
|
|
this.session.setScrollTop(Math.max(-sm.top,
|
|
Math.min(this.scrollTop, maxHeight - size.scrollerHeight + sm.bottom)));
|
|
|
|
this.session.setScrollLeft(Math.max(-sm.left, Math.min(this.scrollLeft,
|
|
longestLine + 2 * this.$padding - size.scrollerWidth + sm.right)));
|
|
|
|
var vScroll = !hideScrollbars && (this.$vScrollBarAlwaysVisible ||
|
|
size.scrollerHeight - maxHeight + scrollPastEnd < 0 || this.scrollTop > sm.top);
|
|
var vScrollChanged = vScrollBefore !== vScroll;
|
|
if (vScrollChanged) {
|
|
this.$vScroll = vScroll;
|
|
this.scrollBarV.setVisible(vScroll);
|
|
}
|
|
|
|
var offset = this.scrollTop % this.lineHeight;
|
|
var lineCount = Math.ceil(minHeight / this.lineHeight) - 1;
|
|
var firstRow = Math.max(0, Math.round((this.scrollTop - offset) / this.lineHeight));
|
|
var lastRow = firstRow + lineCount;
|
|
var firstRowScreen, firstRowHeight;
|
|
var lineHeight = this.lineHeight;
|
|
firstRow = session.screenToDocumentRow(firstRow, 0);
|
|
var foldLine = session.getFoldLine(firstRow);
|
|
if (foldLine) {
|
|
firstRow = foldLine.start.row;
|
|
}
|
|
|
|
firstRowScreen = session.documentToScreenRow(firstRow, 0);
|
|
firstRowHeight = session.getRowLength(firstRow) * lineHeight;
|
|
|
|
lastRow = Math.min(session.screenToDocumentRow(lastRow, 0), session.getLength() - 1);
|
|
minHeight = size.scrollerHeight + session.getRowLength(lastRow) * lineHeight +
|
|
firstRowHeight;
|
|
|
|
offset = this.scrollTop - firstRowScreen * lineHeight;
|
|
|
|
var changes = 0;
|
|
if (this.layerConfig.width != longestLine || hScrollChanged)
|
|
changes = this.CHANGE_H_SCROLL;
|
|
if (hScrollChanged || vScrollChanged) {
|
|
changes |= this.$updateCachedSize(true, this.gutterWidth, size.width, size.height);
|
|
this._signal("scrollbarVisibilityChanged");
|
|
if (vScrollChanged)
|
|
longestLine = this.$getLongestLine();
|
|
}
|
|
|
|
this.layerConfig = {
|
|
width : longestLine,
|
|
padding : this.$padding,
|
|
firstRow : firstRow,
|
|
firstRowScreen: firstRowScreen,
|
|
lastRow : lastRow,
|
|
lineHeight : lineHeight,
|
|
characterWidth : this.characterWidth,
|
|
minHeight : minHeight,
|
|
maxHeight : maxHeight,
|
|
offset : offset,
|
|
gutterOffset : lineHeight ? Math.max(0, Math.ceil((offset + size.height - size.scrollerHeight) / lineHeight)) : 0,
|
|
height : this.$size.scrollerHeight
|
|
};
|
|
|
|
if (this.session.$bidiHandler)
|
|
this.session.$bidiHandler.setContentWidth(longestLine - this.$padding);
|
|
|
|
return changes;
|
|
};
|
|
|
|
this.$updateLines = function() {
|
|
if (!this.$changedLines) return;
|
|
var firstRow = this.$changedLines.firstRow;
|
|
var lastRow = this.$changedLines.lastRow;
|
|
this.$changedLines = null;
|
|
|
|
var layerConfig = this.layerConfig;
|
|
|
|
if (firstRow > layerConfig.lastRow + 1) { return; }
|
|
if (lastRow < layerConfig.firstRow) { return; }
|
|
if (lastRow === Infinity) {
|
|
if (this.$showGutter)
|
|
this.$gutterLayer.update(layerConfig);
|
|
this.$textLayer.update(layerConfig);
|
|
return;
|
|
}
|
|
this.$textLayer.updateLines(layerConfig, firstRow, lastRow);
|
|
return true;
|
|
};
|
|
|
|
this.$getLongestLine = function() {
|
|
var charCount = this.session.getScreenWidth();
|
|
if (this.showInvisibles && !this.session.$useWrapMode)
|
|
charCount += 1;
|
|
|
|
if (this.$textLayer && charCount > this.$textLayer.MAX_LINE_LENGTH)
|
|
charCount = this.$textLayer.MAX_LINE_LENGTH + 30;
|
|
|
|
return Math.max(this.$size.scrollerWidth - 2 * this.$padding, Math.round(charCount * this.characterWidth));
|
|
};
|
|
this.updateFrontMarkers = function() {
|
|
this.$markerFront.setMarkers(this.session.getMarkers(true));
|
|
this.$loop.schedule(this.CHANGE_MARKER_FRONT);
|
|
};
|
|
this.updateBackMarkers = function() {
|
|
this.$markerBack.setMarkers(this.session.getMarkers());
|
|
this.$loop.schedule(this.CHANGE_MARKER_BACK);
|
|
};
|
|
this.addGutterDecoration = function(row, className){
|
|
this.$gutterLayer.addGutterDecoration(row, className);
|
|
};
|
|
this.removeGutterDecoration = function(row, className){
|
|
this.$gutterLayer.removeGutterDecoration(row, className);
|
|
};
|
|
this.updateBreakpoints = function(rows) {
|
|
this.$loop.schedule(this.CHANGE_GUTTER);
|
|
};
|
|
this.setAnnotations = function(annotations) {
|
|
this.$gutterLayer.setAnnotations(annotations);
|
|
this.$loop.schedule(this.CHANGE_GUTTER);
|
|
};
|
|
this.updateCursor = function() {
|
|
this.$loop.schedule(this.CHANGE_CURSOR);
|
|
};
|
|
this.hideCursor = function() {
|
|
this.$cursorLayer.hideCursor();
|
|
};
|
|
this.showCursor = function() {
|
|
this.$cursorLayer.showCursor();
|
|
};
|
|
|
|
this.scrollSelectionIntoView = function(anchor, lead, offset) {
|
|
this.scrollCursorIntoView(anchor, offset);
|
|
this.scrollCursorIntoView(lead, offset);
|
|
};
|
|
this.scrollCursorIntoView = function(cursor, offset, $viewMargin) {
|
|
if (this.$size.scrollerHeight === 0)
|
|
return;
|
|
|
|
var pos = this.$cursorLayer.getPixelPosition(cursor);
|
|
|
|
var left = pos.left;
|
|
var top = pos.top;
|
|
|
|
var topMargin = $viewMargin && $viewMargin.top || 0;
|
|
var bottomMargin = $viewMargin && $viewMargin.bottom || 0;
|
|
|
|
var scrollTop = this.$scrollAnimation ? this.session.getScrollTop() : this.scrollTop;
|
|
|
|
if (scrollTop + topMargin > top) {
|
|
if (offset && scrollTop + topMargin > top + this.lineHeight)
|
|
top -= offset * this.$size.scrollerHeight;
|
|
if (top === 0)
|
|
top = -this.scrollMargin.top;
|
|
this.session.setScrollTop(top);
|
|
} else if (scrollTop + this.$size.scrollerHeight - bottomMargin < top + this.lineHeight) {
|
|
if (offset && scrollTop + this.$size.scrollerHeight - bottomMargin < top - this.lineHeight)
|
|
top += offset * this.$size.scrollerHeight;
|
|
this.session.setScrollTop(top + this.lineHeight + bottomMargin - this.$size.scrollerHeight);
|
|
}
|
|
|
|
var scrollLeft = this.scrollLeft;
|
|
|
|
if (scrollLeft > left) {
|
|
if (left < this.$padding + 2 * this.layerConfig.characterWidth)
|
|
left = -this.scrollMargin.left;
|
|
this.session.setScrollLeft(left);
|
|
} else if (scrollLeft + this.$size.scrollerWidth < left + this.characterWidth) {
|
|
this.session.setScrollLeft(Math.round(left + this.characterWidth - this.$size.scrollerWidth));
|
|
} else if (scrollLeft <= this.$padding && left - scrollLeft < this.characterWidth) {
|
|
this.session.setScrollLeft(0);
|
|
}
|
|
};
|
|
this.getScrollTop = function() {
|
|
return this.session.getScrollTop();
|
|
};
|
|
this.getScrollLeft = function() {
|
|
return this.session.getScrollLeft();
|
|
};
|
|
this.getScrollTopRow = function() {
|
|
return this.scrollTop / this.lineHeight;
|
|
};
|
|
this.getScrollBottomRow = function() {
|
|
return Math.max(0, Math.floor((this.scrollTop + this.$size.scrollerHeight) / this.lineHeight) - 1);
|
|
};
|
|
this.scrollToRow = function(row) {
|
|
this.session.setScrollTop(row * this.lineHeight);
|
|
};
|
|
|
|
this.alignCursor = function(cursor, alignment) {
|
|
if (typeof cursor == "number")
|
|
cursor = {row: cursor, column: 0};
|
|
|
|
var pos = this.$cursorLayer.getPixelPosition(cursor);
|
|
var h = this.$size.scrollerHeight - this.lineHeight;
|
|
var offset = pos.top - h * (alignment || 0);
|
|
|
|
this.session.setScrollTop(offset);
|
|
return offset;
|
|
};
|
|
|
|
this.STEPS = 8;
|
|
this.$calcSteps = function(fromValue, toValue){
|
|
var i = 0;
|
|
var l = this.STEPS;
|
|
var steps = [];
|
|
|
|
var func = function(t, x_min, dx) {
|
|
return dx * (Math.pow(t - 1, 3) + 1) + x_min;
|
|
};
|
|
|
|
for (i = 0; i < l; ++i)
|
|
steps.push(func(i / this.STEPS, fromValue, toValue - fromValue));
|
|
|
|
return steps;
|
|
};
|
|
this.scrollToLine = function(line, center, animate, callback) {
|
|
var pos = this.$cursorLayer.getPixelPosition({row: line, column: 0});
|
|
var offset = pos.top;
|
|
if (center)
|
|
offset -= this.$size.scrollerHeight / 2;
|
|
|
|
var initialScroll = this.scrollTop;
|
|
this.session.setScrollTop(offset);
|
|
if (animate !== false)
|
|
this.animateScrolling(initialScroll, callback);
|
|
};
|
|
|
|
this.animateScrolling = function(fromValue, callback) {
|
|
var toValue = this.scrollTop;
|
|
if (!this.$animatedScroll)
|
|
return;
|
|
var _self = this;
|
|
|
|
if (fromValue == toValue)
|
|
return;
|
|
|
|
if (this.$scrollAnimation) {
|
|
var oldSteps = this.$scrollAnimation.steps;
|
|
if (oldSteps.length) {
|
|
fromValue = oldSteps[0];
|
|
if (fromValue == toValue)
|
|
return;
|
|
}
|
|
}
|
|
|
|
var steps = _self.$calcSteps(fromValue, toValue);
|
|
this.$scrollAnimation = {from: fromValue, to: toValue, steps: steps};
|
|
|
|
clearInterval(this.$timer);
|
|
|
|
_self.session.setScrollTop(steps.shift());
|
|
_self.session.$scrollTop = toValue;
|
|
this.$timer = setInterval(function() {
|
|
if (!_self.session)
|
|
return clearInterval(_self.$timer);
|
|
if (steps.length) {
|
|
_self.session.setScrollTop(steps.shift());
|
|
_self.session.$scrollTop = toValue;
|
|
} else if (toValue != null) {
|
|
_self.session.$scrollTop = -1;
|
|
_self.session.setScrollTop(toValue);
|
|
toValue = null;
|
|
} else {
|
|
_self.$timer = clearInterval(_self.$timer);
|
|
_self.$scrollAnimation = null;
|
|
callback && callback();
|
|
}
|
|
}, 10);
|
|
};
|
|
this.scrollToY = function(scrollTop) {
|
|
if (this.scrollTop !== scrollTop) {
|
|
this.$loop.schedule(this.CHANGE_SCROLL);
|
|
this.scrollTop = scrollTop;
|
|
}
|
|
};
|
|
this.scrollToX = function(scrollLeft) {
|
|
if (this.scrollLeft !== scrollLeft)
|
|
this.scrollLeft = scrollLeft;
|
|
this.$loop.schedule(this.CHANGE_H_SCROLL);
|
|
};
|
|
this.scrollTo = function(x, y) {
|
|
this.session.setScrollTop(y);
|
|
this.session.setScrollLeft(y);
|
|
};
|
|
this.scrollBy = function(deltaX, deltaY) {
|
|
deltaY && this.session.setScrollTop(this.session.getScrollTop() + deltaY);
|
|
deltaX && this.session.setScrollLeft(this.session.getScrollLeft() + deltaX);
|
|
};
|
|
this.isScrollableBy = function(deltaX, deltaY) {
|
|
if (deltaY < 0 && this.session.getScrollTop() >= 1 - this.scrollMargin.top)
|
|
return true;
|
|
if (deltaY > 0 && this.session.getScrollTop() + this.$size.scrollerHeight
|
|
- this.layerConfig.maxHeight < -1 + this.scrollMargin.bottom)
|
|
return true;
|
|
if (deltaX < 0 && this.session.getScrollLeft() >= 1 - this.scrollMargin.left)
|
|
return true;
|
|
if (deltaX > 0 && this.session.getScrollLeft() + this.$size.scrollerWidth
|
|
- this.layerConfig.width < -1 + this.scrollMargin.right)
|
|
return true;
|
|
};
|
|
|
|
this.pixelToScreenCoordinates = function(x, y) {
|
|
var canvasPos;
|
|
if (this.$hasCssTransforms) {
|
|
canvasPos = {top:0, left: 0};
|
|
var p = this.$fontMetrics.transformCoordinates([x, y]);
|
|
x = p[1] - this.gutterWidth - this.margin.left;
|
|
y = p[0];
|
|
} else {
|
|
canvasPos = this.scroller.getBoundingClientRect();
|
|
}
|
|
|
|
var offsetX = x + this.scrollLeft - canvasPos.left - this.$padding;
|
|
var offset = offsetX / this.characterWidth;
|
|
var row = Math.floor((y + this.scrollTop - canvasPos.top) / this.lineHeight);
|
|
var col = this.$blockCursor ? Math.floor(offset) : Math.round(offset);
|
|
|
|
return {row: row, column: col, side: offset - col > 0 ? 1 : -1, offsetX: offsetX};
|
|
};
|
|
|
|
this.screenToTextCoordinates = function(x, y) {
|
|
var canvasPos;
|
|
if (this.$hasCssTransforms) {
|
|
canvasPos = {top:0, left: 0};
|
|
var p = this.$fontMetrics.transformCoordinates([x, y]);
|
|
x = p[1] - this.gutterWidth - this.margin.left;
|
|
y = p[0];
|
|
} else {
|
|
canvasPos = this.scroller.getBoundingClientRect();
|
|
}
|
|
|
|
var offsetX = x + this.scrollLeft - canvasPos.left - this.$padding;
|
|
var offset = offsetX / this.characterWidth;
|
|
var col = this.$blockCursor ? Math.floor(offset) : Math.round(offset);
|
|
|
|
var row = Math.floor((y + this.scrollTop - canvasPos.top) / this.lineHeight);
|
|
|
|
return this.session.screenToDocumentPosition(row, Math.max(col, 0), offsetX);
|
|
};
|
|
this.textToScreenCoordinates = function(row, column) {
|
|
var canvasPos = this.scroller.getBoundingClientRect();
|
|
var pos = this.session.documentToScreenPosition(row, column);
|
|
|
|
var x = this.$padding + (this.session.$bidiHandler.isBidiRow(pos.row, row)
|
|
? this.session.$bidiHandler.getPosLeft(pos.column)
|
|
: Math.round(pos.column * this.characterWidth));
|
|
|
|
var y = pos.row * this.lineHeight;
|
|
|
|
return {
|
|
pageX: canvasPos.left + x - this.scrollLeft,
|
|
pageY: canvasPos.top + y - this.scrollTop
|
|
};
|
|
};
|
|
this.visualizeFocus = function() {
|
|
dom.addCssClass(this.container, "ace_focus");
|
|
};
|
|
this.visualizeBlur = function() {
|
|
dom.removeCssClass(this.container, "ace_focus");
|
|
};
|
|
this.showComposition = function(composition) {
|
|
this.$composition = composition;
|
|
if (!composition.cssText) {
|
|
composition.cssText = this.textarea.style.cssText;
|
|
}
|
|
if (composition.useTextareaForIME == undefined)
|
|
composition.useTextareaForIME = this.$useTextareaForIME;
|
|
|
|
if (this.$useTextareaForIME) {
|
|
dom.addCssClass(this.textarea, "ace_composition");
|
|
this.textarea.style.cssText = "";
|
|
this.$moveTextAreaToCursor();
|
|
this.$cursorLayer.element.style.display = "none";
|
|
}
|
|
else {
|
|
composition.markerId = this.session.addMarker(composition.markerRange, "ace_composition_marker", "text");
|
|
}
|
|
};
|
|
this.setCompositionText = function(text) {
|
|
var cursor = this.session.selection.cursor;
|
|
this.addToken(text, "composition_placeholder", cursor.row, cursor.column);
|
|
this.$moveTextAreaToCursor();
|
|
};
|
|
this.hideComposition = function() {
|
|
if (!this.$composition)
|
|
return;
|
|
|
|
if (this.$composition.markerId)
|
|
this.session.removeMarker(this.$composition.markerId);
|
|
|
|
dom.removeCssClass(this.textarea, "ace_composition");
|
|
this.textarea.style.cssText = this.$composition.cssText;
|
|
var cursor = this.session.selection.cursor;
|
|
this.removeExtraToken(cursor.row, cursor.column);
|
|
this.$composition = null;
|
|
this.$cursorLayer.element.style.display = "";
|
|
};
|
|
|
|
this.addToken = function(text, type, row, column) {
|
|
var session = this.session;
|
|
session.bgTokenizer.lines[row] = null;
|
|
var newToken = {type: type, value: text};
|
|
var tokens = session.getTokens(row);
|
|
if (column == null) {
|
|
tokens.push(newToken);
|
|
} else {
|
|
var l = 0;
|
|
for (var i =0; i < tokens.length; i++) {
|
|
var token = tokens[i];
|
|
l += token.value.length;
|
|
if (column <= l) {
|
|
var diff = token.value.length - (l - column);
|
|
var before = token.value.slice(0, diff);
|
|
var after = token.value.slice(diff);
|
|
|
|
tokens.splice(i, 1, {type: token.type, value: before}, newToken, {type: token.type, value: after});
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
this.updateLines(row, row);
|
|
};
|
|
|
|
this.removeExtraToken = function(row, column) {
|
|
this.updateLines(row, row);
|
|
};
|
|
this.setTheme = function(theme, cb) {
|
|
var _self = this;
|
|
this.$themeId = theme;
|
|
_self._dispatchEvent('themeChange',{theme:theme});
|
|
|
|
if (!theme || typeof theme == "string") {
|
|
var moduleName = theme || this.$options.theme.initialValue;
|
|
config.loadModule(["theme", moduleName], afterLoad);
|
|
} else {
|
|
afterLoad(theme);
|
|
}
|
|
|
|
function afterLoad(module) {
|
|
if (_self.$themeId != theme)
|
|
return cb && cb();
|
|
if (!module || !module.cssClass)
|
|
throw new Error("couldn't load module " + theme + " or it didn't call define");
|
|
if (module.$id)
|
|
_self.$themeId = module.$id;
|
|
dom.importCssString(
|
|
module.cssText,
|
|
module.cssClass,
|
|
_self.container
|
|
);
|
|
|
|
if (_self.theme)
|
|
dom.removeCssClass(_self.container, _self.theme.cssClass);
|
|
|
|
var padding = "padding" in module ? module.padding
|
|
: "padding" in (_self.theme || {}) ? 4 : _self.$padding;
|
|
if (_self.$padding && padding != _self.$padding)
|
|
_self.setPadding(padding);
|
|
_self.$theme = module.cssClass;
|
|
|
|
_self.theme = module;
|
|
dom.addCssClass(_self.container, module.cssClass);
|
|
dom.setCssClass(_self.container, "ace_dark", module.isDark);
|
|
if (_self.$size) {
|
|
_self.$size.width = 0;
|
|
_self.$updateSizeAsync();
|
|
}
|
|
|
|
_self._dispatchEvent('themeLoaded', {theme:module});
|
|
cb && cb();
|
|
}
|
|
};
|
|
this.getTheme = function() {
|
|
return this.$themeId;
|
|
};
|
|
this.setStyle = function(style, include) {
|
|
dom.setCssClass(this.container, style, include !== false);
|
|
};
|
|
this.unsetStyle = function(style) {
|
|
dom.removeCssClass(this.container, style);
|
|
};
|
|
|
|
this.setCursorStyle = function(style) {
|
|
dom.setStyle(this.scroller.style, "cursor", style);
|
|
};
|
|
this.setMouseCursor = function(cursorStyle) {
|
|
dom.setStyle(this.scroller.style, "cursor", cursorStyle);
|
|
};
|
|
|
|
this.attachToShadowRoot = function() {
|
|
dom.importCssString(editorCss, "ace_editor.css", this.container);
|
|
};
|
|
this.destroy = function() {
|
|
this.freeze();
|
|
this.$fontMetrics.destroy();
|
|
this.$cursorLayer.destroy();
|
|
this.removeAllListeners();
|
|
this.container.textContent = "";
|
|
};
|
|
|
|
}).call(VirtualRenderer.prototype);
|
|
|
|
|
|
config.defineOptions(VirtualRenderer.prototype, "renderer", {
|
|
animatedScroll: {initialValue: false},
|
|
showInvisibles: {
|
|
set: function(value) {
|
|
if (this.$textLayer.setShowInvisibles(value))
|
|
this.$loop.schedule(this.CHANGE_TEXT);
|
|
},
|
|
initialValue: false
|
|
},
|
|
showPrintMargin: {
|
|
set: function() { this.$updatePrintMargin(); },
|
|
initialValue: true
|
|
},
|
|
printMarginColumn: {
|
|
set: function() { this.$updatePrintMargin(); },
|
|
initialValue: 80
|
|
},
|
|
printMargin: {
|
|
set: function(val) {
|
|
if (typeof val == "number")
|
|
this.$printMarginColumn = val;
|
|
this.$showPrintMargin = !!val;
|
|
this.$updatePrintMargin();
|
|
},
|
|
get: function() {
|
|
return this.$showPrintMargin && this.$printMarginColumn;
|
|
}
|
|
},
|
|
showGutter: {
|
|
set: function(show){
|
|
this.$gutter.style.display = show ? "block" : "none";
|
|
this.$loop.schedule(this.CHANGE_FULL);
|
|
this.onGutterResize();
|
|
},
|
|
initialValue: true
|
|
},
|
|
fadeFoldWidgets: {
|
|
set: function(show) {
|
|
dom.setCssClass(this.$gutter, "ace_fade-fold-widgets", show);
|
|
},
|
|
initialValue: false
|
|
},
|
|
showFoldWidgets: {
|
|
set: function(show) {
|
|
this.$gutterLayer.setShowFoldWidgets(show);
|
|
this.$loop.schedule(this.CHANGE_GUTTER);
|
|
},
|
|
initialValue: true
|
|
},
|
|
displayIndentGuides: {
|
|
set: function(show) {
|
|
if (this.$textLayer.setDisplayIndentGuides(show))
|
|
this.$loop.schedule(this.CHANGE_TEXT);
|
|
},
|
|
initialValue: true
|
|
},
|
|
highlightGutterLine: {
|
|
set: function(shouldHighlight) {
|
|
this.$gutterLayer.setHighlightGutterLine(shouldHighlight);
|
|
this.$loop.schedule(this.CHANGE_GUTTER);
|
|
},
|
|
initialValue: true
|
|
},
|
|
hScrollBarAlwaysVisible: {
|
|
set: function(val) {
|
|
if (!this.$hScrollBarAlwaysVisible || !this.$horizScroll)
|
|
this.$loop.schedule(this.CHANGE_SCROLL);
|
|
},
|
|
initialValue: false
|
|
},
|
|
vScrollBarAlwaysVisible: {
|
|
set: function(val) {
|
|
if (!this.$vScrollBarAlwaysVisible || !this.$vScroll)
|
|
this.$loop.schedule(this.CHANGE_SCROLL);
|
|
},
|
|
initialValue: false
|
|
},
|
|
fontSize: {
|
|
set: function(size) {
|
|
if (typeof size == "number")
|
|
size = size + "px";
|
|
this.container.style.fontSize = size;
|
|
this.updateFontSize();
|
|
},
|
|
initialValue: 12
|
|
},
|
|
fontFamily: {
|
|
set: function(name) {
|
|
this.container.style.fontFamily = name;
|
|
this.updateFontSize();
|
|
}
|
|
},
|
|
maxLines: {
|
|
set: function(val) {
|
|
this.updateFull();
|
|
}
|
|
},
|
|
minLines: {
|
|
set: function(val) {
|
|
if (!(this.$minLines < 0x1ffffffffffff))
|
|
this.$minLines = 0;
|
|
this.updateFull();
|
|
}
|
|
},
|
|
maxPixelHeight: {
|
|
set: function(val) {
|
|
this.updateFull();
|
|
},
|
|
initialValue: 0
|
|
},
|
|
scrollPastEnd: {
|
|
set: function(val) {
|
|
val = +val || 0;
|
|
if (this.$scrollPastEnd == val)
|
|
return;
|
|
this.$scrollPastEnd = val;
|
|
this.$loop.schedule(this.CHANGE_SCROLL);
|
|
},
|
|
initialValue: 0,
|
|
handlesSet: true
|
|
},
|
|
fixedWidthGutter: {
|
|
set: function(val) {
|
|
this.$gutterLayer.$fixedWidth = !!val;
|
|
this.$loop.schedule(this.CHANGE_GUTTER);
|
|
}
|
|
},
|
|
theme: {
|
|
set: function(val) { this.setTheme(val); },
|
|
get: function() { return this.$themeId || this.theme; },
|
|
initialValue: "./theme/textmate",
|
|
handlesSet: true
|
|
},
|
|
hasCssTransforms: {
|
|
},
|
|
useTextareaForIME: {
|
|
initialValue: !useragent.isMobile && !useragent.isIE
|
|
}
|
|
});
|
|
|
|
exports.VirtualRenderer = VirtualRenderer;
|
|
});
|
|
|
|
ace.define("ace/worker/worker_client",["require","exports","module","ace/lib/oop","ace/lib/net","ace/lib/event_emitter","ace/config"], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var oop = require("../lib/oop");
|
|
var net = require("../lib/net");
|
|
var EventEmitter = require("../lib/event_emitter").EventEmitter;
|
|
var config = require("../config");
|
|
|
|
function $workerBlob(workerUrl) {
|
|
var script = "importScripts('" + net.qualifyURL(workerUrl) + "');";
|
|
try {
|
|
return new Blob([script], {"type": "application/javascript"});
|
|
} catch (e) { // Backwards-compatibility
|
|
var BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder;
|
|
var blobBuilder = new BlobBuilder();
|
|
blobBuilder.append(script);
|
|
return blobBuilder.getBlob("application/javascript");
|
|
}
|
|
}
|
|
|
|
function createWorker(workerUrl) {
|
|
if (typeof Worker == "undefined")
|
|
return { postMessage: function() {}, terminate: function() {} };
|
|
if (config.get("loadWorkerFromBlob")) {
|
|
var blob = $workerBlob(workerUrl);
|
|
var URL = window.URL || window.webkitURL;
|
|
var blobURL = URL.createObjectURL(blob);
|
|
return new Worker(blobURL);
|
|
}
|
|
return new Worker(workerUrl);
|
|
}
|
|
|
|
var WorkerClient = function(worker) {
|
|
if (!worker.postMessage)
|
|
worker = this.$createWorkerFromOldConfig.apply(this, arguments);
|
|
|
|
this.$worker = worker;
|
|
this.$sendDeltaQueue = this.$sendDeltaQueue.bind(this);
|
|
this.changeListener = this.changeListener.bind(this);
|
|
this.onMessage = this.onMessage.bind(this);
|
|
|
|
this.callbackId = 1;
|
|
this.callbacks = {};
|
|
|
|
this.$worker.onmessage = this.onMessage;
|
|
};
|
|
|
|
(function(){
|
|
|
|
oop.implement(this, EventEmitter);
|
|
|
|
this.$createWorkerFromOldConfig = function(topLevelNamespaces, mod, classname, workerUrl, importScripts) {
|
|
if (require.nameToUrl && !require.toUrl)
|
|
require.toUrl = require.nameToUrl;
|
|
|
|
if (config.get("packaged") || !require.toUrl) {
|
|
workerUrl = workerUrl || config.moduleUrl(mod, "worker");
|
|
} else {
|
|
var normalizePath = this.$normalizePath;
|
|
workerUrl = workerUrl || normalizePath(require.toUrl("ace/worker/worker.js", null, "_"));
|
|
|
|
var tlns = {};
|
|
topLevelNamespaces.forEach(function(ns) {
|
|
tlns[ns] = normalizePath(require.toUrl(ns, null, "_").replace(/(\.js)?(\?.*)?$/, ""));
|
|
});
|
|
}
|
|
|
|
this.$worker = createWorker(workerUrl);
|
|
if (importScripts) {
|
|
this.send("importScripts", importScripts);
|
|
}
|
|
this.$worker.postMessage({
|
|
init : true,
|
|
tlns : tlns,
|
|
module : mod,
|
|
classname : classname
|
|
});
|
|
return this.$worker;
|
|
};
|
|
|
|
this.onMessage = function(e) {
|
|
var msg = e.data;
|
|
switch (msg.type) {
|
|
case "event":
|
|
this._signal(msg.name, {data: msg.data});
|
|
break;
|
|
case "call":
|
|
var callback = this.callbacks[msg.id];
|
|
if (callback) {
|
|
callback(msg.data);
|
|
delete this.callbacks[msg.id];
|
|
}
|
|
break;
|
|
case "error":
|
|
this.reportError(msg.data);
|
|
break;
|
|
case "log":
|
|
window.console && console.log && console.log.apply(console, msg.data);
|
|
break;
|
|
}
|
|
};
|
|
|
|
this.reportError = function(err) {
|
|
window.console && console.error && console.error(err);
|
|
};
|
|
|
|
this.$normalizePath = function(path) {
|
|
return net.qualifyURL(path);
|
|
};
|
|
|
|
this.terminate = function() {
|
|
this._signal("terminate", {});
|
|
this.deltaQueue = null;
|
|
this.$worker.terminate();
|
|
this.$worker = null;
|
|
if (this.$doc)
|
|
this.$doc.off("change", this.changeListener);
|
|
this.$doc = null;
|
|
};
|
|
|
|
this.send = function(cmd, args) {
|
|
this.$worker.postMessage({command: cmd, args: args});
|
|
};
|
|
|
|
this.call = function(cmd, args, callback) {
|
|
if (callback) {
|
|
var id = this.callbackId++;
|
|
this.callbacks[id] = callback;
|
|
args.push(id);
|
|
}
|
|
this.send(cmd, args);
|
|
};
|
|
|
|
this.emit = function(event, data) {
|
|
try {
|
|
if (data.data && data.data.err)
|
|
data.data.err = {message: data.data.err.message, stack: data.data.err.stack, code: data.data.err.code};
|
|
this.$worker.postMessage({event: event, data: {data: data.data}});
|
|
}
|
|
catch(ex) {
|
|
console.error(ex.stack);
|
|
}
|
|
};
|
|
|
|
this.attachToDocument = function(doc) {
|
|
if (this.$doc)
|
|
this.terminate();
|
|
|
|
this.$doc = doc;
|
|
this.call("setValue", [doc.getValue()]);
|
|
doc.on("change", this.changeListener);
|
|
};
|
|
|
|
this.changeListener = function(delta) {
|
|
if (!this.deltaQueue) {
|
|
this.deltaQueue = [];
|
|
setTimeout(this.$sendDeltaQueue, 0);
|
|
}
|
|
if (delta.action == "insert")
|
|
this.deltaQueue.push(delta.start, delta.lines);
|
|
else
|
|
this.deltaQueue.push(delta.start, delta.end);
|
|
};
|
|
|
|
this.$sendDeltaQueue = function() {
|
|
var q = this.deltaQueue;
|
|
if (!q) return;
|
|
this.deltaQueue = null;
|
|
if (q.length > 50 && q.length > this.$doc.getLength() >> 1) {
|
|
this.call("setValue", [this.$doc.getValue()]);
|
|
} else
|
|
this.emit("change", {data: q});
|
|
};
|
|
|
|
}).call(WorkerClient.prototype);
|
|
|
|
|
|
var UIWorkerClient = function(topLevelNamespaces, mod, classname) {
|
|
var main = null;
|
|
var emitSync = false;
|
|
var sender = Object.create(EventEmitter);
|
|
|
|
var messageBuffer = [];
|
|
var workerClient = new WorkerClient({
|
|
messageBuffer: messageBuffer,
|
|
terminate: function() {},
|
|
postMessage: function(e) {
|
|
messageBuffer.push(e);
|
|
if (!main) return;
|
|
if (emitSync)
|
|
setTimeout(processNext);
|
|
else
|
|
processNext();
|
|
}
|
|
});
|
|
|
|
workerClient.setEmitSync = function(val) { emitSync = val; };
|
|
|
|
var processNext = function() {
|
|
var msg = messageBuffer.shift();
|
|
if (msg.command)
|
|
main[msg.command].apply(main, msg.args);
|
|
else if (msg.event)
|
|
sender._signal(msg.event, msg.data);
|
|
};
|
|
|
|
sender.postMessage = function(msg) {
|
|
workerClient.onMessage({data: msg});
|
|
};
|
|
sender.callback = function(data, callbackId) {
|
|
this.postMessage({type: "call", id: callbackId, data: data});
|
|
};
|
|
sender.emit = function(name, data) {
|
|
this.postMessage({type: "event", name: name, data: data});
|
|
};
|
|
|
|
config.loadModule(["worker", mod], function(Main) {
|
|
main = new Main[classname](sender);
|
|
while (messageBuffer.length)
|
|
processNext();
|
|
});
|
|
|
|
return workerClient;
|
|
};
|
|
|
|
exports.UIWorkerClient = UIWorkerClient;
|
|
exports.WorkerClient = WorkerClient;
|
|
exports.createWorker = createWorker;
|
|
|
|
|
|
});
|
|
|
|
ace.define("ace/placeholder",["require","exports","module","ace/range","ace/lib/event_emitter","ace/lib/oop"], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var Range = require("./range").Range;
|
|
var EventEmitter = require("./lib/event_emitter").EventEmitter;
|
|
var oop = require("./lib/oop");
|
|
|
|
var PlaceHolder = function(session, length, pos, others, mainClass, othersClass) {
|
|
var _self = this;
|
|
this.length = length;
|
|
this.session = session;
|
|
this.doc = session.getDocument();
|
|
this.mainClass = mainClass;
|
|
this.othersClass = othersClass;
|
|
this.$onUpdate = this.onUpdate.bind(this);
|
|
this.doc.on("change", this.$onUpdate);
|
|
this.$others = others;
|
|
|
|
this.$onCursorChange = function() {
|
|
setTimeout(function() {
|
|
_self.onCursorChange();
|
|
});
|
|
};
|
|
|
|
this.$pos = pos;
|
|
var undoStack = session.getUndoManager().$undoStack || session.getUndoManager().$undostack || {length: -1};
|
|
this.$undoStackDepth = undoStack.length;
|
|
this.setup();
|
|
|
|
session.selection.on("changeCursor", this.$onCursorChange);
|
|
};
|
|
|
|
(function() {
|
|
|
|
oop.implement(this, EventEmitter);
|
|
this.setup = function() {
|
|
var _self = this;
|
|
var doc = this.doc;
|
|
var session = this.session;
|
|
|
|
this.selectionBefore = session.selection.toJSON();
|
|
if (session.selection.inMultiSelectMode)
|
|
session.selection.toSingleRange();
|
|
|
|
this.pos = doc.createAnchor(this.$pos.row, this.$pos.column);
|
|
var pos = this.pos;
|
|
pos.$insertRight = true;
|
|
pos.detach();
|
|
pos.markerId = session.addMarker(new Range(pos.row, pos.column, pos.row, pos.column + this.length), this.mainClass, null, false);
|
|
this.others = [];
|
|
this.$others.forEach(function(other) {
|
|
var anchor = doc.createAnchor(other.row, other.column);
|
|
anchor.$insertRight = true;
|
|
anchor.detach();
|
|
_self.others.push(anchor);
|
|
});
|
|
session.setUndoSelect(false);
|
|
};
|
|
this.showOtherMarkers = function() {
|
|
if (this.othersActive) return;
|
|
var session = this.session;
|
|
var _self = this;
|
|
this.othersActive = true;
|
|
this.others.forEach(function(anchor) {
|
|
anchor.markerId = session.addMarker(new Range(anchor.row, anchor.column, anchor.row, anchor.column+_self.length), _self.othersClass, null, false);
|
|
});
|
|
};
|
|
this.hideOtherMarkers = function() {
|
|
if (!this.othersActive) return;
|
|
this.othersActive = false;
|
|
for (var i = 0; i < this.others.length; i++) {
|
|
this.session.removeMarker(this.others[i].markerId);
|
|
}
|
|
};
|
|
this.onUpdate = function(delta) {
|
|
if (this.$updating)
|
|
return this.updateAnchors(delta);
|
|
|
|
var range = delta;
|
|
if (range.start.row !== range.end.row) return;
|
|
if (range.start.row !== this.pos.row) return;
|
|
this.$updating = true;
|
|
var lengthDiff = delta.action === "insert" ? range.end.column - range.start.column : range.start.column - range.end.column;
|
|
var inMainRange = range.start.column >= this.pos.column && range.start.column <= this.pos.column + this.length + 1;
|
|
var distanceFromStart = range.start.column - this.pos.column;
|
|
|
|
this.updateAnchors(delta);
|
|
|
|
if (inMainRange)
|
|
this.length += lengthDiff;
|
|
|
|
if (inMainRange && !this.session.$fromUndo) {
|
|
if (delta.action === 'insert') {
|
|
for (var i = this.others.length - 1; i >= 0; i--) {
|
|
var otherPos = this.others[i];
|
|
var newPos = {row: otherPos.row, column: otherPos.column + distanceFromStart};
|
|
this.doc.insertMergedLines(newPos, delta.lines);
|
|
}
|
|
} else if (delta.action === 'remove') {
|
|
for (var i = this.others.length - 1; i >= 0; i--) {
|
|
var otherPos = this.others[i];
|
|
var newPos = {row: otherPos.row, column: otherPos.column + distanceFromStart};
|
|
this.doc.remove(new Range(newPos.row, newPos.column, newPos.row, newPos.column - lengthDiff));
|
|
}
|
|
}
|
|
}
|
|
|
|
this.$updating = false;
|
|
this.updateMarkers();
|
|
};
|
|
|
|
this.updateAnchors = function(delta) {
|
|
this.pos.onChange(delta);
|
|
for (var i = this.others.length; i--;)
|
|
this.others[i].onChange(delta);
|
|
this.updateMarkers();
|
|
};
|
|
|
|
this.updateMarkers = function() {
|
|
if (this.$updating)
|
|
return;
|
|
var _self = this;
|
|
var session = this.session;
|
|
var updateMarker = function(pos, className) {
|
|
session.removeMarker(pos.markerId);
|
|
pos.markerId = session.addMarker(new Range(pos.row, pos.column, pos.row, pos.column+_self.length), className, null, false);
|
|
};
|
|
updateMarker(this.pos, this.mainClass);
|
|
for (var i = this.others.length; i--;)
|
|
updateMarker(this.others[i], this.othersClass);
|
|
};
|
|
|
|
this.onCursorChange = function(event) {
|
|
if (this.$updating || !this.session) return;
|
|
var pos = this.session.selection.getCursor();
|
|
if (pos.row === this.pos.row && pos.column >= this.pos.column && pos.column <= this.pos.column + this.length) {
|
|
this.showOtherMarkers();
|
|
this._emit("cursorEnter", event);
|
|
} else {
|
|
this.hideOtherMarkers();
|
|
this._emit("cursorLeave", event);
|
|
}
|
|
};
|
|
this.detach = function() {
|
|
this.session.removeMarker(this.pos && this.pos.markerId);
|
|
this.hideOtherMarkers();
|
|
this.doc.off("change", this.$onUpdate);
|
|
this.session.selection.off("changeCursor", this.$onCursorChange);
|
|
this.session.setUndoSelect(true);
|
|
this.session = null;
|
|
};
|
|
this.cancel = function() {
|
|
if (this.$undoStackDepth === -1)
|
|
return;
|
|
var undoManager = this.session.getUndoManager();
|
|
var undosRequired = (undoManager.$undoStack || undoManager.$undostack).length - this.$undoStackDepth;
|
|
for (var i = 0; i < undosRequired; i++) {
|
|
undoManager.undo(this.session, true);
|
|
}
|
|
if (this.selectionBefore)
|
|
this.session.selection.fromJSON(this.selectionBefore);
|
|
};
|
|
}).call(PlaceHolder.prototype);
|
|
|
|
|
|
exports.PlaceHolder = PlaceHolder;
|
|
});
|
|
|
|
ace.define("ace/mouse/multi_select_handler",["require","exports","module","ace/lib/event","ace/lib/useragent"], function(require, exports, module) {
|
|
|
|
var event = require("../lib/event");
|
|
var useragent = require("../lib/useragent");
|
|
function isSamePoint(p1, p2) {
|
|
return p1.row == p2.row && p1.column == p2.column;
|
|
}
|
|
|
|
function onMouseDown(e) {
|
|
var ev = e.domEvent;
|
|
var alt = ev.altKey;
|
|
var shift = ev.shiftKey;
|
|
var ctrl = ev.ctrlKey;
|
|
var accel = e.getAccelKey();
|
|
var button = e.getButton();
|
|
|
|
if (ctrl && useragent.isMac)
|
|
button = ev.button;
|
|
|
|
if (e.editor.inMultiSelectMode && button == 2) {
|
|
e.editor.textInput.onContextMenu(e.domEvent);
|
|
return;
|
|
}
|
|
|
|
if (!ctrl && !alt && !accel) {
|
|
if (button === 0 && e.editor.inMultiSelectMode)
|
|
e.editor.exitMultiSelectMode();
|
|
return;
|
|
}
|
|
|
|
if (button !== 0)
|
|
return;
|
|
|
|
var editor = e.editor;
|
|
var selection = editor.selection;
|
|
var isMultiSelect = editor.inMultiSelectMode;
|
|
var pos = e.getDocumentPosition();
|
|
var cursor = selection.getCursor();
|
|
var inSelection = e.inSelection() || (selection.isEmpty() && isSamePoint(pos, cursor));
|
|
|
|
var mouseX = e.x, mouseY = e.y;
|
|
var onMouseSelection = function(e) {
|
|
mouseX = e.clientX;
|
|
mouseY = e.clientY;
|
|
};
|
|
|
|
var session = editor.session;
|
|
var screenAnchor = editor.renderer.pixelToScreenCoordinates(mouseX, mouseY);
|
|
var screenCursor = screenAnchor;
|
|
|
|
var selectionMode;
|
|
if (editor.$mouseHandler.$enableJumpToDef) {
|
|
if (ctrl && alt || accel && alt)
|
|
selectionMode = shift ? "block" : "add";
|
|
else if (alt && editor.$blockSelectEnabled)
|
|
selectionMode = "block";
|
|
} else {
|
|
if (accel && !alt) {
|
|
selectionMode = "add";
|
|
if (!isMultiSelect && shift)
|
|
return;
|
|
} else if (alt && editor.$blockSelectEnabled) {
|
|
selectionMode = "block";
|
|
}
|
|
}
|
|
|
|
if (selectionMode && useragent.isMac && ev.ctrlKey) {
|
|
editor.$mouseHandler.cancelContextMenu();
|
|
}
|
|
|
|
if (selectionMode == "add") {
|
|
if (!isMultiSelect && inSelection)
|
|
return; // dragging
|
|
|
|
if (!isMultiSelect) {
|
|
var range = selection.toOrientedRange();
|
|
editor.addSelectionMarker(range);
|
|
}
|
|
|
|
var oldRange = selection.rangeList.rangeAtPoint(pos);
|
|
|
|
editor.inVirtualSelectionMode = true;
|
|
|
|
if (shift) {
|
|
oldRange = null;
|
|
range = selection.ranges[0] || range;
|
|
editor.removeSelectionMarker(range);
|
|
}
|
|
editor.once("mouseup", function() {
|
|
var tmpSel = selection.toOrientedRange();
|
|
|
|
if (oldRange && tmpSel.isEmpty() && isSamePoint(oldRange.cursor, tmpSel.cursor))
|
|
selection.substractPoint(tmpSel.cursor);
|
|
else {
|
|
if (shift) {
|
|
selection.substractPoint(range.cursor);
|
|
} else if (range) {
|
|
editor.removeSelectionMarker(range);
|
|
selection.addRange(range);
|
|
}
|
|
selection.addRange(tmpSel);
|
|
}
|
|
editor.inVirtualSelectionMode = false;
|
|
});
|
|
|
|
} else if (selectionMode == "block") {
|
|
e.stop();
|
|
editor.inVirtualSelectionMode = true;
|
|
var initialRange;
|
|
var rectSel = [];
|
|
var blockSelect = function() {
|
|
var newCursor = editor.renderer.pixelToScreenCoordinates(mouseX, mouseY);
|
|
var cursor = session.screenToDocumentPosition(newCursor.row, newCursor.column, newCursor.offsetX);
|
|
|
|
if (isSamePoint(screenCursor, newCursor) && isSamePoint(cursor, selection.lead))
|
|
return;
|
|
screenCursor = newCursor;
|
|
|
|
editor.selection.moveToPosition(cursor);
|
|
editor.renderer.scrollCursorIntoView();
|
|
|
|
editor.removeSelectionMarkers(rectSel);
|
|
rectSel = selection.rectangularRangeBlock(screenCursor, screenAnchor);
|
|
if (editor.$mouseHandler.$clickSelection && rectSel.length == 1 && rectSel[0].isEmpty())
|
|
rectSel[0] = editor.$mouseHandler.$clickSelection.clone();
|
|
rectSel.forEach(editor.addSelectionMarker, editor);
|
|
editor.updateSelectionMarkers();
|
|
};
|
|
if (isMultiSelect && !accel) {
|
|
selection.toSingleRange();
|
|
} else if (!isMultiSelect && accel) {
|
|
initialRange = selection.toOrientedRange();
|
|
editor.addSelectionMarker(initialRange);
|
|
}
|
|
|
|
if (shift)
|
|
screenAnchor = session.documentToScreenPosition(selection.lead);
|
|
else
|
|
selection.moveToPosition(pos);
|
|
|
|
screenCursor = {row: -1, column: -1};
|
|
|
|
var onMouseSelectionEnd = function(e) {
|
|
blockSelect();
|
|
clearInterval(timerId);
|
|
editor.removeSelectionMarkers(rectSel);
|
|
if (!rectSel.length)
|
|
rectSel = [selection.toOrientedRange()];
|
|
if (initialRange) {
|
|
editor.removeSelectionMarker(initialRange);
|
|
selection.toSingleRange(initialRange);
|
|
}
|
|
for (var i = 0; i < rectSel.length; i++)
|
|
selection.addRange(rectSel[i]);
|
|
editor.inVirtualSelectionMode = false;
|
|
editor.$mouseHandler.$clickSelection = null;
|
|
};
|
|
|
|
var onSelectionInterval = blockSelect;
|
|
|
|
event.capture(editor.container, onMouseSelection, onMouseSelectionEnd);
|
|
var timerId = setInterval(function() {onSelectionInterval();}, 20);
|
|
|
|
return e.preventDefault();
|
|
}
|
|
}
|
|
|
|
|
|
exports.onMouseDown = onMouseDown;
|
|
|
|
});
|
|
|
|
ace.define("ace/commands/multi_select_commands",["require","exports","module","ace/keyboard/hash_handler"], function(require, exports, module) {
|
|
exports.defaultCommands = [{
|
|
name: "addCursorAbove",
|
|
description: "Add cursor above",
|
|
exec: function(editor) { editor.selectMoreLines(-1); },
|
|
bindKey: {win: "Ctrl-Alt-Up", mac: "Ctrl-Alt-Up"},
|
|
scrollIntoView: "cursor",
|
|
readOnly: true
|
|
}, {
|
|
name: "addCursorBelow",
|
|
description: "Add cursor below",
|
|
exec: function(editor) { editor.selectMoreLines(1); },
|
|
bindKey: {win: "Ctrl-Alt-Down", mac: "Ctrl-Alt-Down"},
|
|
scrollIntoView: "cursor",
|
|
readOnly: true
|
|
}, {
|
|
name: "addCursorAboveSkipCurrent",
|
|
description: "Add cursor above (skip current)",
|
|
exec: function(editor) { editor.selectMoreLines(-1, true); },
|
|
bindKey: {win: "Ctrl-Alt-Shift-Up", mac: "Ctrl-Alt-Shift-Up"},
|
|
scrollIntoView: "cursor",
|
|
readOnly: true
|
|
}, {
|
|
name: "addCursorBelowSkipCurrent",
|
|
description: "Add cursor below (skip current)",
|
|
exec: function(editor) { editor.selectMoreLines(1, true); },
|
|
bindKey: {win: "Ctrl-Alt-Shift-Down", mac: "Ctrl-Alt-Shift-Down"},
|
|
scrollIntoView: "cursor",
|
|
readOnly: true
|
|
}, {
|
|
name: "selectMoreBefore",
|
|
description: "Select more before",
|
|
exec: function(editor) { editor.selectMore(-1); },
|
|
bindKey: {win: "Ctrl-Alt-Left", mac: "Ctrl-Alt-Left"},
|
|
scrollIntoView: "cursor",
|
|
readOnly: true
|
|
}, {
|
|
name: "selectMoreAfter",
|
|
description: "Select more after",
|
|
exec: function(editor) { editor.selectMore(1); },
|
|
bindKey: {win: "Ctrl-Alt-Right", mac: "Ctrl-Alt-Right"},
|
|
scrollIntoView: "cursor",
|
|
readOnly: true
|
|
}, {
|
|
name: "selectNextBefore",
|
|
description: "Select next before",
|
|
exec: function(editor) { editor.selectMore(-1, true); },
|
|
bindKey: {win: "Ctrl-Alt-Shift-Left", mac: "Ctrl-Alt-Shift-Left"},
|
|
scrollIntoView: "cursor",
|
|
readOnly: true
|
|
}, {
|
|
name: "selectNextAfter",
|
|
description: "Select next after",
|
|
exec: function(editor) { editor.selectMore(1, true); },
|
|
bindKey: {win: "Ctrl-Alt-Shift-Right", mac: "Ctrl-Alt-Shift-Right"},
|
|
scrollIntoView: "cursor",
|
|
readOnly: true
|
|
}, {
|
|
name: "toggleSplitSelectionIntoLines",
|
|
description: "Split into lines",
|
|
exec: function(editor) {
|
|
if (editor.multiSelect.rangeCount > 1)
|
|
editor.multiSelect.joinSelections();
|
|
else
|
|
editor.multiSelect.splitIntoLines();
|
|
},
|
|
bindKey: {win: "Ctrl-Alt-L", mac: "Ctrl-Alt-L"},
|
|
readOnly: true
|
|
}, {
|
|
name: "splitSelectionIntoLines",
|
|
description: "Split into lines",
|
|
exec: function(editor) { editor.multiSelect.splitIntoLines(); },
|
|
readOnly: true
|
|
}, {
|
|
name: "alignCursors",
|
|
description: "Align cursors",
|
|
exec: function(editor) { editor.alignCursors(); },
|
|
bindKey: {win: "Ctrl-Alt-A", mac: "Ctrl-Alt-A"},
|
|
scrollIntoView: "cursor"
|
|
}, {
|
|
name: "findAll",
|
|
description: "Find all",
|
|
exec: function(editor) { editor.findAll(); },
|
|
bindKey: {win: "Ctrl-Alt-K", mac: "Ctrl-Alt-G"},
|
|
scrollIntoView: "cursor",
|
|
readOnly: true
|
|
}];
|
|
exports.multiSelectCommands = [{
|
|
name: "singleSelection",
|
|
description: "Single selection",
|
|
bindKey: "esc",
|
|
exec: function(editor) { editor.exitMultiSelectMode(); },
|
|
scrollIntoView: "cursor",
|
|
readOnly: true,
|
|
isAvailable: function(editor) {return editor && editor.inMultiSelectMode;}
|
|
}];
|
|
|
|
var HashHandler = require("../keyboard/hash_handler").HashHandler;
|
|
exports.keyboardHandler = new HashHandler(exports.multiSelectCommands);
|
|
|
|
});
|
|
|
|
ace.define("ace/multi_select",["require","exports","module","ace/range_list","ace/range","ace/selection","ace/mouse/multi_select_handler","ace/lib/event","ace/lib/lang","ace/commands/multi_select_commands","ace/search","ace/edit_session","ace/editor","ace/config"], function(require, exports, module) {
|
|
|
|
var RangeList = require("./range_list").RangeList;
|
|
var Range = require("./range").Range;
|
|
var Selection = require("./selection").Selection;
|
|
var onMouseDown = require("./mouse/multi_select_handler").onMouseDown;
|
|
var event = require("./lib/event");
|
|
var lang = require("./lib/lang");
|
|
var commands = require("./commands/multi_select_commands");
|
|
exports.commands = commands.defaultCommands.concat(commands.multiSelectCommands);
|
|
var Search = require("./search").Search;
|
|
var search = new Search();
|
|
|
|
function find(session, needle, dir) {
|
|
search.$options.wrap = true;
|
|
search.$options.needle = needle;
|
|
search.$options.backwards = dir == -1;
|
|
return search.find(session);
|
|
}
|
|
var EditSession = require("./edit_session").EditSession;
|
|
(function() {
|
|
this.getSelectionMarkers = function() {
|
|
return this.$selectionMarkers;
|
|
};
|
|
}).call(EditSession.prototype);
|
|
(function() {
|
|
this.ranges = null;
|
|
this.rangeList = null;
|
|
this.addRange = function(range, $blockChangeEvents) {
|
|
if (!range)
|
|
return;
|
|
|
|
if (!this.inMultiSelectMode && this.rangeCount === 0) {
|
|
var oldRange = this.toOrientedRange();
|
|
this.rangeList.add(oldRange);
|
|
this.rangeList.add(range);
|
|
if (this.rangeList.ranges.length != 2) {
|
|
this.rangeList.removeAll();
|
|
return $blockChangeEvents || this.fromOrientedRange(range);
|
|
}
|
|
this.rangeList.removeAll();
|
|
this.rangeList.add(oldRange);
|
|
this.$onAddRange(oldRange);
|
|
}
|
|
|
|
if (!range.cursor)
|
|
range.cursor = range.end;
|
|
|
|
var removed = this.rangeList.add(range);
|
|
|
|
this.$onAddRange(range);
|
|
|
|
if (removed.length)
|
|
this.$onRemoveRange(removed);
|
|
|
|
if (this.rangeCount > 1 && !this.inMultiSelectMode) {
|
|
this._signal("multiSelect");
|
|
this.inMultiSelectMode = true;
|
|
this.session.$undoSelect = false;
|
|
this.rangeList.attach(this.session);
|
|
}
|
|
|
|
return $blockChangeEvents || this.fromOrientedRange(range);
|
|
};
|
|
this.toSingleRange = function(range) {
|
|
range = range || this.ranges[0];
|
|
var removed = this.rangeList.removeAll();
|
|
if (removed.length)
|
|
this.$onRemoveRange(removed);
|
|
|
|
range && this.fromOrientedRange(range);
|
|
};
|
|
this.substractPoint = function(pos) {
|
|
var removed = this.rangeList.substractPoint(pos);
|
|
if (removed) {
|
|
this.$onRemoveRange(removed);
|
|
return removed[0];
|
|
}
|
|
};
|
|
this.mergeOverlappingRanges = function() {
|
|
var removed = this.rangeList.merge();
|
|
if (removed.length)
|
|
this.$onRemoveRange(removed);
|
|
};
|
|
|
|
this.$onAddRange = function(range) {
|
|
this.rangeCount = this.rangeList.ranges.length;
|
|
this.ranges.unshift(range);
|
|
this._signal("addRange", {range: range});
|
|
};
|
|
|
|
this.$onRemoveRange = function(removed) {
|
|
this.rangeCount = this.rangeList.ranges.length;
|
|
if (this.rangeCount == 1 && this.inMultiSelectMode) {
|
|
var lastRange = this.rangeList.ranges.pop();
|
|
removed.push(lastRange);
|
|
this.rangeCount = 0;
|
|
}
|
|
|
|
for (var i = removed.length; i--; ) {
|
|
var index = this.ranges.indexOf(removed[i]);
|
|
this.ranges.splice(index, 1);
|
|
}
|
|
|
|
this._signal("removeRange", {ranges: removed});
|
|
|
|
if (this.rangeCount === 0 && this.inMultiSelectMode) {
|
|
this.inMultiSelectMode = false;
|
|
this._signal("singleSelect");
|
|
this.session.$undoSelect = true;
|
|
this.rangeList.detach(this.session);
|
|
}
|
|
|
|
lastRange = lastRange || this.ranges[0];
|
|
if (lastRange && !lastRange.isEqual(this.getRange()))
|
|
this.fromOrientedRange(lastRange);
|
|
};
|
|
this.$initRangeList = function() {
|
|
if (this.rangeList)
|
|
return;
|
|
|
|
this.rangeList = new RangeList();
|
|
this.ranges = [];
|
|
this.rangeCount = 0;
|
|
};
|
|
this.getAllRanges = function() {
|
|
return this.rangeCount ? this.rangeList.ranges.concat() : [this.getRange()];
|
|
};
|
|
this.splitIntoLines = function () {
|
|
var ranges = this.ranges.length ? this.ranges : [this.getRange()];
|
|
var newRanges = [];
|
|
for (var i = 0; i < ranges.length; i++) {
|
|
var range = ranges[i];
|
|
var row = range.start.row;
|
|
var endRow = range.end.row;
|
|
if (row === endRow) {
|
|
newRanges.push(range.clone());
|
|
} else {
|
|
newRanges.push(new Range(row, range.start.column, row, this.session.getLine(row).length));
|
|
while (++row < endRow)
|
|
newRanges.push(this.getLineRange(row, true));
|
|
newRanges.push(new Range(endRow, 0, endRow, range.end.column));
|
|
}
|
|
if (i == 0 && !this.isBackwards())
|
|
newRanges = newRanges.reverse();
|
|
}
|
|
this.toSingleRange();
|
|
for (var i = newRanges.length; i--;)
|
|
this.addRange(newRanges[i]);
|
|
};
|
|
|
|
this.joinSelections = function () {
|
|
var ranges = this.rangeList.ranges;
|
|
var lastRange = ranges[ranges.length - 1];
|
|
var range = Range.fromPoints(ranges[0].start, lastRange.end);
|
|
|
|
this.toSingleRange();
|
|
this.setSelectionRange(range, lastRange.cursor == lastRange.start);
|
|
};
|
|
this.toggleBlockSelection = function () {
|
|
if (this.rangeCount > 1) {
|
|
var ranges = this.rangeList.ranges;
|
|
var lastRange = ranges[ranges.length - 1];
|
|
var range = Range.fromPoints(ranges[0].start, lastRange.end);
|
|
|
|
this.toSingleRange();
|
|
this.setSelectionRange(range, lastRange.cursor == lastRange.start);
|
|
} else {
|
|
var cursor = this.session.documentToScreenPosition(this.cursor);
|
|
var anchor = this.session.documentToScreenPosition(this.anchor);
|
|
|
|
var rectSel = this.rectangularRangeBlock(cursor, anchor);
|
|
rectSel.forEach(this.addRange, this);
|
|
}
|
|
};
|
|
this.rectangularRangeBlock = function(screenCursor, screenAnchor, includeEmptyLines) {
|
|
var rectSel = [];
|
|
|
|
var xBackwards = screenCursor.column < screenAnchor.column;
|
|
if (xBackwards) {
|
|
var startColumn = screenCursor.column;
|
|
var endColumn = screenAnchor.column;
|
|
var startOffsetX = screenCursor.offsetX;
|
|
var endOffsetX = screenAnchor.offsetX;
|
|
} else {
|
|
var startColumn = screenAnchor.column;
|
|
var endColumn = screenCursor.column;
|
|
var startOffsetX = screenAnchor.offsetX;
|
|
var endOffsetX = screenCursor.offsetX;
|
|
}
|
|
|
|
var yBackwards = screenCursor.row < screenAnchor.row;
|
|
if (yBackwards) {
|
|
var startRow = screenCursor.row;
|
|
var endRow = screenAnchor.row;
|
|
} else {
|
|
var startRow = screenAnchor.row;
|
|
var endRow = screenCursor.row;
|
|
}
|
|
|
|
if (startColumn < 0)
|
|
startColumn = 0;
|
|
if (startRow < 0)
|
|
startRow = 0;
|
|
|
|
if (startRow == endRow)
|
|
includeEmptyLines = true;
|
|
|
|
var docEnd;
|
|
for (var row = startRow; row <= endRow; row++) {
|
|
var range = Range.fromPoints(
|
|
this.session.screenToDocumentPosition(row, startColumn, startOffsetX),
|
|
this.session.screenToDocumentPosition(row, endColumn, endOffsetX)
|
|
);
|
|
if (range.isEmpty()) {
|
|
if (docEnd && isSamePoint(range.end, docEnd))
|
|
break;
|
|
docEnd = range.end;
|
|
}
|
|
range.cursor = xBackwards ? range.start : range.end;
|
|
rectSel.push(range);
|
|
}
|
|
|
|
if (yBackwards)
|
|
rectSel.reverse();
|
|
|
|
if (!includeEmptyLines) {
|
|
var end = rectSel.length - 1;
|
|
while (rectSel[end].isEmpty() && end > 0)
|
|
end--;
|
|
if (end > 0) {
|
|
var start = 0;
|
|
while (rectSel[start].isEmpty())
|
|
start++;
|
|
}
|
|
for (var i = end; i >= start; i--) {
|
|
if (rectSel[i].isEmpty())
|
|
rectSel.splice(i, 1);
|
|
}
|
|
}
|
|
|
|
return rectSel;
|
|
};
|
|
}).call(Selection.prototype);
|
|
var Editor = require("./editor").Editor;
|
|
(function() {
|
|
this.updateSelectionMarkers = function() {
|
|
this.renderer.updateCursor();
|
|
this.renderer.updateBackMarkers();
|
|
};
|
|
this.addSelectionMarker = function(orientedRange) {
|
|
if (!orientedRange.cursor)
|
|
orientedRange.cursor = orientedRange.end;
|
|
|
|
var style = this.getSelectionStyle();
|
|
orientedRange.marker = this.session.addMarker(orientedRange, "ace_selection", style);
|
|
|
|
this.session.$selectionMarkers.push(orientedRange);
|
|
this.session.selectionMarkerCount = this.session.$selectionMarkers.length;
|
|
return orientedRange;
|
|
};
|
|
this.removeSelectionMarker = function(range) {
|
|
if (!range.marker)
|
|
return;
|
|
this.session.removeMarker(range.marker);
|
|
var index = this.session.$selectionMarkers.indexOf(range);
|
|
if (index != -1)
|
|
this.session.$selectionMarkers.splice(index, 1);
|
|
this.session.selectionMarkerCount = this.session.$selectionMarkers.length;
|
|
};
|
|
|
|
this.removeSelectionMarkers = function(ranges) {
|
|
var markerList = this.session.$selectionMarkers;
|
|
for (var i = ranges.length; i--; ) {
|
|
var range = ranges[i];
|
|
if (!range.marker)
|
|
continue;
|
|
this.session.removeMarker(range.marker);
|
|
var index = markerList.indexOf(range);
|
|
if (index != -1)
|
|
markerList.splice(index, 1);
|
|
}
|
|
this.session.selectionMarkerCount = markerList.length;
|
|
};
|
|
|
|
this.$onAddRange = function(e) {
|
|
this.addSelectionMarker(e.range);
|
|
this.renderer.updateCursor();
|
|
this.renderer.updateBackMarkers();
|
|
};
|
|
|
|
this.$onRemoveRange = function(e) {
|
|
this.removeSelectionMarkers(e.ranges);
|
|
this.renderer.updateCursor();
|
|
this.renderer.updateBackMarkers();
|
|
};
|
|
|
|
this.$onMultiSelect = function(e) {
|
|
if (this.inMultiSelectMode)
|
|
return;
|
|
this.inMultiSelectMode = true;
|
|
|
|
this.setStyle("ace_multiselect");
|
|
this.keyBinding.addKeyboardHandler(commands.keyboardHandler);
|
|
this.commands.setDefaultHandler("exec", this.$onMultiSelectExec);
|
|
|
|
this.renderer.updateCursor();
|
|
this.renderer.updateBackMarkers();
|
|
};
|
|
|
|
this.$onSingleSelect = function(e) {
|
|
if (this.session.multiSelect.inVirtualMode)
|
|
return;
|
|
this.inMultiSelectMode = false;
|
|
|
|
this.unsetStyle("ace_multiselect");
|
|
this.keyBinding.removeKeyboardHandler(commands.keyboardHandler);
|
|
|
|
this.commands.removeDefaultHandler("exec", this.$onMultiSelectExec);
|
|
this.renderer.updateCursor();
|
|
this.renderer.updateBackMarkers();
|
|
this._emit("changeSelection");
|
|
};
|
|
|
|
this.$onMultiSelectExec = function(e) {
|
|
var command = e.command;
|
|
var editor = e.editor;
|
|
if (!editor.multiSelect)
|
|
return;
|
|
if (!command.multiSelectAction) {
|
|
var result = command.exec(editor, e.args || {});
|
|
editor.multiSelect.addRange(editor.multiSelect.toOrientedRange());
|
|
editor.multiSelect.mergeOverlappingRanges();
|
|
} else if (command.multiSelectAction == "forEach") {
|
|
result = editor.forEachSelection(command, e.args);
|
|
} else if (command.multiSelectAction == "forEachLine") {
|
|
result = editor.forEachSelection(command, e.args, true);
|
|
} else if (command.multiSelectAction == "single") {
|
|
editor.exitMultiSelectMode();
|
|
result = command.exec(editor, e.args || {});
|
|
} else {
|
|
result = command.multiSelectAction(editor, e.args || {});
|
|
}
|
|
return result;
|
|
};
|
|
this.forEachSelection = function(cmd, args, options) {
|
|
if (this.inVirtualSelectionMode)
|
|
return;
|
|
var keepOrder = options && options.keepOrder;
|
|
var $byLines = options == true || options && options.$byLines;
|
|
var session = this.session;
|
|
var selection = this.selection;
|
|
var rangeList = selection.rangeList;
|
|
var ranges = (keepOrder ? selection : rangeList).ranges;
|
|
var result;
|
|
|
|
if (!ranges.length)
|
|
return cmd.exec ? cmd.exec(this, args || {}) : cmd(this, args || {});
|
|
|
|
var reg = selection._eventRegistry;
|
|
selection._eventRegistry = {};
|
|
|
|
var tmpSel = new Selection(session);
|
|
this.inVirtualSelectionMode = true;
|
|
for (var i = ranges.length; i--;) {
|
|
if ($byLines) {
|
|
while (i > 0 && ranges[i].start.row == ranges[i - 1].end.row)
|
|
i--;
|
|
}
|
|
tmpSel.fromOrientedRange(ranges[i]);
|
|
tmpSel.index = i;
|
|
this.selection = session.selection = tmpSel;
|
|
var cmdResult = cmd.exec ? cmd.exec(this, args || {}) : cmd(this, args || {});
|
|
if (!result && cmdResult !== undefined)
|
|
result = cmdResult;
|
|
tmpSel.toOrientedRange(ranges[i]);
|
|
}
|
|
tmpSel.detach();
|
|
|
|
this.selection = session.selection = selection;
|
|
this.inVirtualSelectionMode = false;
|
|
selection._eventRegistry = reg;
|
|
selection.mergeOverlappingRanges();
|
|
if (selection.ranges[0])
|
|
selection.fromOrientedRange(selection.ranges[0]);
|
|
|
|
var anim = this.renderer.$scrollAnimation;
|
|
this.onCursorChange();
|
|
this.onSelectionChange();
|
|
if (anim && anim.from == anim.to)
|
|
this.renderer.animateScrolling(anim.from);
|
|
|
|
return result;
|
|
};
|
|
this.exitMultiSelectMode = function() {
|
|
if (!this.inMultiSelectMode || this.inVirtualSelectionMode)
|
|
return;
|
|
this.multiSelect.toSingleRange();
|
|
};
|
|
|
|
this.getSelectedText = function() {
|
|
var text = "";
|
|
if (this.inMultiSelectMode && !this.inVirtualSelectionMode) {
|
|
var ranges = this.multiSelect.rangeList.ranges;
|
|
var buf = [];
|
|
for (var i = 0; i < ranges.length; i++) {
|
|
buf.push(this.session.getTextRange(ranges[i]));
|
|
}
|
|
var nl = this.session.getDocument().getNewLineCharacter();
|
|
text = buf.join(nl);
|
|
if (text.length == (buf.length - 1) * nl.length)
|
|
text = "";
|
|
} else if (!this.selection.isEmpty()) {
|
|
text = this.session.getTextRange(this.getSelectionRange());
|
|
}
|
|
return text;
|
|
};
|
|
|
|
this.$checkMultiselectChange = function(e, anchor) {
|
|
if (this.inMultiSelectMode && !this.inVirtualSelectionMode) {
|
|
var range = this.multiSelect.ranges[0];
|
|
if (this.multiSelect.isEmpty() && anchor == this.multiSelect.anchor)
|
|
return;
|
|
var pos = anchor == this.multiSelect.anchor
|
|
? range.cursor == range.start ? range.end : range.start
|
|
: range.cursor;
|
|
if (pos.row != anchor.row
|
|
|| this.session.$clipPositionToDocument(pos.row, pos.column).column != anchor.column)
|
|
this.multiSelect.toSingleRange(this.multiSelect.toOrientedRange());
|
|
else
|
|
this.multiSelect.mergeOverlappingRanges();
|
|
}
|
|
};
|
|
this.findAll = function(needle, options, additive) {
|
|
options = options || {};
|
|
options.needle = needle || options.needle;
|
|
if (options.needle == undefined) {
|
|
var range = this.selection.isEmpty()
|
|
? this.selection.getWordRange()
|
|
: this.selection.getRange();
|
|
options.needle = this.session.getTextRange(range);
|
|
}
|
|
this.$search.set(options);
|
|
|
|
var ranges = this.$search.findAll(this.session);
|
|
if (!ranges.length)
|
|
return 0;
|
|
|
|
var selection = this.multiSelect;
|
|
|
|
if (!additive)
|
|
selection.toSingleRange(ranges[0]);
|
|
|
|
for (var i = ranges.length; i--; )
|
|
selection.addRange(ranges[i], true);
|
|
if (range && selection.rangeList.rangeAtPoint(range.start))
|
|
selection.addRange(range, true);
|
|
|
|
return ranges.length;
|
|
};
|
|
this.selectMoreLines = function(dir, skip) {
|
|
var range = this.selection.toOrientedRange();
|
|
var isBackwards = range.cursor == range.end;
|
|
|
|
var screenLead = this.session.documentToScreenPosition(range.cursor);
|
|
if (this.selection.$desiredColumn)
|
|
screenLead.column = this.selection.$desiredColumn;
|
|
|
|
var lead = this.session.screenToDocumentPosition(screenLead.row + dir, screenLead.column);
|
|
|
|
if (!range.isEmpty()) {
|
|
var screenAnchor = this.session.documentToScreenPosition(isBackwards ? range.end : range.start);
|
|
var anchor = this.session.screenToDocumentPosition(screenAnchor.row + dir, screenAnchor.column);
|
|
} else {
|
|
var anchor = lead;
|
|
}
|
|
|
|
if (isBackwards) {
|
|
var newRange = Range.fromPoints(lead, anchor);
|
|
newRange.cursor = newRange.start;
|
|
} else {
|
|
var newRange = Range.fromPoints(anchor, lead);
|
|
newRange.cursor = newRange.end;
|
|
}
|
|
|
|
newRange.desiredColumn = screenLead.column;
|
|
if (!this.selection.inMultiSelectMode) {
|
|
this.selection.addRange(range);
|
|
} else {
|
|
if (skip)
|
|
var toRemove = range.cursor;
|
|
}
|
|
|
|
this.selection.addRange(newRange);
|
|
if (toRemove)
|
|
this.selection.substractPoint(toRemove);
|
|
};
|
|
this.transposeSelections = function(dir) {
|
|
var session = this.session;
|
|
var sel = session.multiSelect;
|
|
var all = sel.ranges;
|
|
|
|
for (var i = all.length; i--; ) {
|
|
var range = all[i];
|
|
if (range.isEmpty()) {
|
|
var tmp = session.getWordRange(range.start.row, range.start.column);
|
|
range.start.row = tmp.start.row;
|
|
range.start.column = tmp.start.column;
|
|
range.end.row = tmp.end.row;
|
|
range.end.column = tmp.end.column;
|
|
}
|
|
}
|
|
sel.mergeOverlappingRanges();
|
|
|
|
var words = [];
|
|
for (var i = all.length; i--; ) {
|
|
var range = all[i];
|
|
words.unshift(session.getTextRange(range));
|
|
}
|
|
|
|
if (dir < 0)
|
|
words.unshift(words.pop());
|
|
else
|
|
words.push(words.shift());
|
|
|
|
for (var i = all.length; i--; ) {
|
|
var range = all[i];
|
|
var tmp = range.clone();
|
|
session.replace(range, words[i]);
|
|
range.start.row = tmp.start.row;
|
|
range.start.column = tmp.start.column;
|
|
}
|
|
sel.fromOrientedRange(sel.ranges[0]);
|
|
};
|
|
this.selectMore = function(dir, skip, stopAtFirst) {
|
|
var session = this.session;
|
|
var sel = session.multiSelect;
|
|
|
|
var range = sel.toOrientedRange();
|
|
if (range.isEmpty()) {
|
|
range = session.getWordRange(range.start.row, range.start.column);
|
|
range.cursor = dir == -1 ? range.start : range.end;
|
|
this.multiSelect.addRange(range);
|
|
if (stopAtFirst)
|
|
return;
|
|
}
|
|
var needle = session.getTextRange(range);
|
|
|
|
var newRange = find(session, needle, dir);
|
|
if (newRange) {
|
|
newRange.cursor = dir == -1 ? newRange.start : newRange.end;
|
|
this.session.unfold(newRange);
|
|
this.multiSelect.addRange(newRange);
|
|
this.renderer.scrollCursorIntoView(null, 0.5);
|
|
}
|
|
if (skip)
|
|
this.multiSelect.substractPoint(range.cursor);
|
|
};
|
|
this.alignCursors = function() {
|
|
var session = this.session;
|
|
var sel = session.multiSelect;
|
|
var ranges = sel.ranges;
|
|
var row = -1;
|
|
var sameRowRanges = ranges.filter(function(r) {
|
|
if (r.cursor.row == row)
|
|
return true;
|
|
row = r.cursor.row;
|
|
});
|
|
|
|
if (!ranges.length || sameRowRanges.length == ranges.length - 1) {
|
|
var range = this.selection.getRange();
|
|
var fr = range.start.row, lr = range.end.row;
|
|
var guessRange = fr == lr;
|
|
if (guessRange) {
|
|
var max = this.session.getLength();
|
|
var line;
|
|
do {
|
|
line = this.session.getLine(lr);
|
|
} while (/[=:]/.test(line) && ++lr < max);
|
|
do {
|
|
line = this.session.getLine(fr);
|
|
} while (/[=:]/.test(line) && --fr > 0);
|
|
|
|
if (fr < 0) fr = 0;
|
|
if (lr >= max) lr = max - 1;
|
|
}
|
|
var lines = this.session.removeFullLines(fr, lr);
|
|
lines = this.$reAlignText(lines, guessRange);
|
|
this.session.insert({row: fr, column: 0}, lines.join("\n") + "\n");
|
|
if (!guessRange) {
|
|
range.start.column = 0;
|
|
range.end.column = lines[lines.length - 1].length;
|
|
}
|
|
this.selection.setRange(range);
|
|
} else {
|
|
sameRowRanges.forEach(function(r) {
|
|
sel.substractPoint(r.cursor);
|
|
});
|
|
|
|
var maxCol = 0;
|
|
var minSpace = Infinity;
|
|
var spaceOffsets = ranges.map(function(r) {
|
|
var p = r.cursor;
|
|
var line = session.getLine(p.row);
|
|
var spaceOffset = line.substr(p.column).search(/\S/g);
|
|
if (spaceOffset == -1)
|
|
spaceOffset = 0;
|
|
|
|
if (p.column > maxCol)
|
|
maxCol = p.column;
|
|
if (spaceOffset < minSpace)
|
|
minSpace = spaceOffset;
|
|
return spaceOffset;
|
|
});
|
|
ranges.forEach(function(r, i) {
|
|
var p = r.cursor;
|
|
var l = maxCol - p.column;
|
|
var d = spaceOffsets[i] - minSpace;
|
|
if (l > d)
|
|
session.insert(p, lang.stringRepeat(" ", l - d));
|
|
else
|
|
session.remove(new Range(p.row, p.column, p.row, p.column - l + d));
|
|
|
|
r.start.column = r.end.column = maxCol;
|
|
r.start.row = r.end.row = p.row;
|
|
r.cursor = r.end;
|
|
});
|
|
sel.fromOrientedRange(ranges[0]);
|
|
this.renderer.updateCursor();
|
|
this.renderer.updateBackMarkers();
|
|
}
|
|
};
|
|
|
|
this.$reAlignText = function(lines, forceLeft) {
|
|
var isLeftAligned = true, isRightAligned = true;
|
|
var startW, textW, endW;
|
|
|
|
return lines.map(function(line) {
|
|
var m = line.match(/(\s*)(.*?)(\s*)([=:].*)/);
|
|
if (!m)
|
|
return [line];
|
|
|
|
if (startW == null) {
|
|
startW = m[1].length;
|
|
textW = m[2].length;
|
|
endW = m[3].length;
|
|
return m;
|
|
}
|
|
|
|
if (startW + textW + endW != m[1].length + m[2].length + m[3].length)
|
|
isRightAligned = false;
|
|
if (startW != m[1].length)
|
|
isLeftAligned = false;
|
|
|
|
if (startW > m[1].length)
|
|
startW = m[1].length;
|
|
if (textW < m[2].length)
|
|
textW = m[2].length;
|
|
if (endW > m[3].length)
|
|
endW = m[3].length;
|
|
|
|
return m;
|
|
}).map(forceLeft ? alignLeft :
|
|
isLeftAligned ? isRightAligned ? alignRight : alignLeft : unAlign);
|
|
|
|
function spaces(n) {
|
|
return lang.stringRepeat(" ", n);
|
|
}
|
|
|
|
function alignLeft(m) {
|
|
return !m[2] ? m[0] : spaces(startW) + m[2]
|
|
+ spaces(textW - m[2].length + endW)
|
|
+ m[4].replace(/^([=:])\s+/, "$1 ");
|
|
}
|
|
function alignRight(m) {
|
|
return !m[2] ? m[0] : spaces(startW + textW - m[2].length) + m[2]
|
|
+ spaces(endW)
|
|
+ m[4].replace(/^([=:])\s+/, "$1 ");
|
|
}
|
|
function unAlign(m) {
|
|
return !m[2] ? m[0] : spaces(startW) + m[2]
|
|
+ spaces(endW)
|
|
+ m[4].replace(/^([=:])\s+/, "$1 ");
|
|
}
|
|
};
|
|
}).call(Editor.prototype);
|
|
|
|
|
|
function isSamePoint(p1, p2) {
|
|
return p1.row == p2.row && p1.column == p2.column;
|
|
}
|
|
exports.onSessionChange = function(e) {
|
|
var session = e.session;
|
|
if (session && !session.multiSelect) {
|
|
session.$selectionMarkers = [];
|
|
session.selection.$initRangeList();
|
|
session.multiSelect = session.selection;
|
|
}
|
|
this.multiSelect = session && session.multiSelect;
|
|
|
|
var oldSession = e.oldSession;
|
|
if (oldSession) {
|
|
oldSession.multiSelect.off("addRange", this.$onAddRange);
|
|
oldSession.multiSelect.off("removeRange", this.$onRemoveRange);
|
|
oldSession.multiSelect.off("multiSelect", this.$onMultiSelect);
|
|
oldSession.multiSelect.off("singleSelect", this.$onSingleSelect);
|
|
oldSession.multiSelect.lead.off("change", this.$checkMultiselectChange);
|
|
oldSession.multiSelect.anchor.off("change", this.$checkMultiselectChange);
|
|
}
|
|
|
|
if (session) {
|
|
session.multiSelect.on("addRange", this.$onAddRange);
|
|
session.multiSelect.on("removeRange", this.$onRemoveRange);
|
|
session.multiSelect.on("multiSelect", this.$onMultiSelect);
|
|
session.multiSelect.on("singleSelect", this.$onSingleSelect);
|
|
session.multiSelect.lead.on("change", this.$checkMultiselectChange);
|
|
session.multiSelect.anchor.on("change", this.$checkMultiselectChange);
|
|
}
|
|
|
|
if (session && this.inMultiSelectMode != session.selection.inMultiSelectMode) {
|
|
if (session.selection.inMultiSelectMode)
|
|
this.$onMultiSelect();
|
|
else
|
|
this.$onSingleSelect();
|
|
}
|
|
};
|
|
function MultiSelect(editor) {
|
|
if (editor.$multiselectOnSessionChange)
|
|
return;
|
|
editor.$onAddRange = editor.$onAddRange.bind(editor);
|
|
editor.$onRemoveRange = editor.$onRemoveRange.bind(editor);
|
|
editor.$onMultiSelect = editor.$onMultiSelect.bind(editor);
|
|
editor.$onSingleSelect = editor.$onSingleSelect.bind(editor);
|
|
editor.$multiselectOnSessionChange = exports.onSessionChange.bind(editor);
|
|
editor.$checkMultiselectChange = editor.$checkMultiselectChange.bind(editor);
|
|
|
|
editor.$multiselectOnSessionChange(editor);
|
|
editor.on("changeSession", editor.$multiselectOnSessionChange);
|
|
|
|
editor.on("mousedown", onMouseDown);
|
|
editor.commands.addCommands(commands.defaultCommands);
|
|
|
|
addAltCursorListeners(editor);
|
|
}
|
|
|
|
function addAltCursorListeners(editor){
|
|
if (!editor.textInput) return;
|
|
var el = editor.textInput.getElement();
|
|
var altCursor = false;
|
|
event.addListener(el, "keydown", function(e) {
|
|
var altDown = e.keyCode == 18 && !(e.ctrlKey || e.shiftKey || e.metaKey);
|
|
if (editor.$blockSelectEnabled && altDown) {
|
|
if (!altCursor) {
|
|
editor.renderer.setMouseCursor("crosshair");
|
|
altCursor = true;
|
|
}
|
|
} else if (altCursor) {
|
|
reset();
|
|
}
|
|
}, editor);
|
|
|
|
event.addListener(el, "keyup", reset, editor);
|
|
event.addListener(el, "blur", reset, editor);
|
|
function reset(e) {
|
|
if (altCursor) {
|
|
editor.renderer.setMouseCursor("");
|
|
altCursor = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
exports.MultiSelect = MultiSelect;
|
|
|
|
|
|
require("./config").defineOptions(Editor.prototype, "editor", {
|
|
enableMultiselect: {
|
|
set: function(val) {
|
|
MultiSelect(this);
|
|
if (val) {
|
|
this.on("changeSession", this.$multiselectOnSessionChange);
|
|
this.on("mousedown", onMouseDown);
|
|
} else {
|
|
this.off("changeSession", this.$multiselectOnSessionChange);
|
|
this.off("mousedown", onMouseDown);
|
|
}
|
|
},
|
|
value: true
|
|
},
|
|
enableBlockSelect: {
|
|
set: function(val) {
|
|
this.$blockSelectEnabled = val;
|
|
},
|
|
value: true
|
|
}
|
|
});
|
|
|
|
|
|
|
|
});
|
|
|
|
ace.define("ace/mode/folding/fold_mode",["require","exports","module","ace/range"], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var Range = require("../../range").Range;
|
|
|
|
var FoldMode = exports.FoldMode = function() {};
|
|
|
|
(function() {
|
|
|
|
this.foldingStartMarker = null;
|
|
this.foldingStopMarker = null;
|
|
this.getFoldWidget = function(session, foldStyle, row) {
|
|
var line = session.getLine(row);
|
|
if (this.foldingStartMarker.test(line))
|
|
return "start";
|
|
if (foldStyle == "markbeginend"
|
|
&& this.foldingStopMarker
|
|
&& this.foldingStopMarker.test(line))
|
|
return "end";
|
|
return "";
|
|
};
|
|
|
|
this.getFoldWidgetRange = function(session, foldStyle, row) {
|
|
return null;
|
|
};
|
|
|
|
this.indentationBlock = function(session, row, column) {
|
|
var re = /\S/;
|
|
var line = session.getLine(row);
|
|
var startLevel = line.search(re);
|
|
if (startLevel == -1)
|
|
return;
|
|
|
|
var startColumn = column || line.length;
|
|
var maxRow = session.getLength();
|
|
var startRow = row;
|
|
var endRow = row;
|
|
|
|
while (++row < maxRow) {
|
|
var level = session.getLine(row).search(re);
|
|
|
|
if (level == -1)
|
|
continue;
|
|
|
|
if (level <= startLevel) {
|
|
var token = session.getTokenAt(row, 0);
|
|
if (!token || token.type !== "string")
|
|
break;
|
|
}
|
|
|
|
endRow = row;
|
|
}
|
|
|
|
if (endRow > startRow) {
|
|
var endColumn = session.getLine(endRow).length;
|
|
return new Range(startRow, startColumn, endRow, endColumn);
|
|
}
|
|
};
|
|
|
|
this.openingBracketBlock = function(session, bracket, row, column, typeRe) {
|
|
var start = {row: row, column: column + 1};
|
|
var end = session.$findClosingBracket(bracket, start, typeRe);
|
|
if (!end)
|
|
return;
|
|
|
|
var fw = session.foldWidgets[end.row];
|
|
if (fw == null)
|
|
fw = session.getFoldWidget(end.row);
|
|
|
|
if (fw == "start" && end.row > start.row) {
|
|
end.row --;
|
|
end.column = session.getLine(end.row).length;
|
|
}
|
|
return Range.fromPoints(start, end);
|
|
};
|
|
|
|
this.closingBracketBlock = function(session, bracket, row, column, typeRe) {
|
|
var end = {row: row, column: column};
|
|
var start = session.$findOpeningBracket(bracket, end);
|
|
|
|
if (!start)
|
|
return;
|
|
|
|
start.column++;
|
|
end.column--;
|
|
|
|
return Range.fromPoints(start, end);
|
|
};
|
|
}).call(FoldMode.prototype);
|
|
|
|
});
|
|
|
|
ace.define("ace/theme/textmate",["require","exports","module","ace/lib/dom"], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
exports.isDark = false;
|
|
exports.cssClass = "ace-tm";
|
|
exports.cssText = ".ace-tm .ace_gutter {\
|
|
background: #f0f0f0;\
|
|
color: #333;\
|
|
}\
|
|
.ace-tm .ace_print-margin {\
|
|
width: 1px;\
|
|
background: #e8e8e8;\
|
|
}\
|
|
.ace-tm .ace_fold {\
|
|
background-color: #6B72E6;\
|
|
}\
|
|
.ace-tm {\
|
|
background-color: #FFFFFF;\
|
|
color: black;\
|
|
}\
|
|
.ace-tm .ace_cursor {\
|
|
color: black;\
|
|
}\
|
|
.ace-tm .ace_invisible {\
|
|
color: rgb(191, 191, 191);\
|
|
}\
|
|
.ace-tm .ace_storage,\
|
|
.ace-tm .ace_keyword {\
|
|
color: blue;\
|
|
}\
|
|
.ace-tm .ace_constant {\
|
|
color: rgb(197, 6, 11);\
|
|
}\
|
|
.ace-tm .ace_constant.ace_buildin {\
|
|
color: rgb(88, 72, 246);\
|
|
}\
|
|
.ace-tm .ace_constant.ace_language {\
|
|
color: rgb(88, 92, 246);\
|
|
}\
|
|
.ace-tm .ace_constant.ace_library {\
|
|
color: rgb(6, 150, 14);\
|
|
}\
|
|
.ace-tm .ace_invalid {\
|
|
background-color: rgba(255, 0, 0, 0.1);\
|
|
color: red;\
|
|
}\
|
|
.ace-tm .ace_support.ace_function {\
|
|
color: rgb(60, 76, 114);\
|
|
}\
|
|
.ace-tm .ace_support.ace_constant {\
|
|
color: rgb(6, 150, 14);\
|
|
}\
|
|
.ace-tm .ace_support.ace_type,\
|
|
.ace-tm .ace_support.ace_class {\
|
|
color: rgb(109, 121, 222);\
|
|
}\
|
|
.ace-tm .ace_keyword.ace_operator {\
|
|
color: rgb(104, 118, 135);\
|
|
}\
|
|
.ace-tm .ace_string {\
|
|
color: rgb(3, 106, 7);\
|
|
}\
|
|
.ace-tm .ace_comment {\
|
|
color: rgb(76, 136, 107);\
|
|
}\
|
|
.ace-tm .ace_comment.ace_doc {\
|
|
color: rgb(0, 102, 255);\
|
|
}\
|
|
.ace-tm .ace_comment.ace_doc.ace_tag {\
|
|
color: rgb(128, 159, 191);\
|
|
}\
|
|
.ace-tm .ace_constant.ace_numeric {\
|
|
color: rgb(0, 0, 205);\
|
|
}\
|
|
.ace-tm .ace_variable {\
|
|
color: rgb(49, 132, 149);\
|
|
}\
|
|
.ace-tm .ace_xml-pe {\
|
|
color: rgb(104, 104, 91);\
|
|
}\
|
|
.ace-tm .ace_entity.ace_name.ace_function {\
|
|
color: #0000A2;\
|
|
}\
|
|
.ace-tm .ace_heading {\
|
|
color: rgb(12, 7, 255);\
|
|
}\
|
|
.ace-tm .ace_list {\
|
|
color:rgb(185, 6, 144);\
|
|
}\
|
|
.ace-tm .ace_meta.ace_tag {\
|
|
color:rgb(0, 22, 142);\
|
|
}\
|
|
.ace-tm .ace_string.ace_regex {\
|
|
color: rgb(255, 0, 0)\
|
|
}\
|
|
.ace-tm .ace_marker-layer .ace_selection {\
|
|
background: rgb(181, 213, 255);\
|
|
}\
|
|
.ace-tm.ace_multiselect .ace_selection.ace_start {\
|
|
box-shadow: 0 0 3px 0px white;\
|
|
}\
|
|
.ace-tm .ace_marker-layer .ace_step {\
|
|
background: rgb(252, 255, 0);\
|
|
}\
|
|
.ace-tm .ace_marker-layer .ace_stack {\
|
|
background: rgb(164, 229, 101);\
|
|
}\
|
|
.ace-tm .ace_marker-layer .ace_bracket {\
|
|
margin: -1px 0 0 -1px;\
|
|
border: 1px solid rgb(192, 192, 192);\
|
|
}\
|
|
.ace-tm .ace_marker-layer .ace_active-line {\
|
|
background: rgba(0, 0, 0, 0.07);\
|
|
}\
|
|
.ace-tm .ace_gutter-active-line {\
|
|
background-color : #dcdcdc;\
|
|
}\
|
|
.ace-tm .ace_marker-layer .ace_selected-word {\
|
|
background: rgb(250, 250, 255);\
|
|
border: 1px solid rgb(200, 200, 250);\
|
|
}\
|
|
.ace-tm .ace_indent-guide {\
|
|
background: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAE0lEQVQImWP4////f4bLly//BwAmVgd1/w11/gAAAABJRU5ErkJggg==\") right repeat-y;\
|
|
}\
|
|
";
|
|
exports.$id = "ace/theme/textmate";
|
|
|
|
var dom = require("../lib/dom");
|
|
dom.importCssString(exports.cssText, exports.cssClass);
|
|
});
|
|
|
|
ace.define("ace/line_widgets",["require","exports","module","ace/lib/dom"], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var dom = require("./lib/dom");
|
|
|
|
function LineWidgets(session) {
|
|
this.session = session;
|
|
this.session.widgetManager = this;
|
|
this.session.getRowLength = this.getRowLength;
|
|
this.session.$getWidgetScreenLength = this.$getWidgetScreenLength;
|
|
this.updateOnChange = this.updateOnChange.bind(this);
|
|
this.renderWidgets = this.renderWidgets.bind(this);
|
|
this.measureWidgets = this.measureWidgets.bind(this);
|
|
this.session._changedWidgets = [];
|
|
this.$onChangeEditor = this.$onChangeEditor.bind(this);
|
|
|
|
this.session.on("change", this.updateOnChange);
|
|
this.session.on("changeFold", this.updateOnFold);
|
|
this.session.on("changeEditor", this.$onChangeEditor);
|
|
}
|
|
|
|
(function() {
|
|
this.getRowLength = function(row) {
|
|
var h;
|
|
if (this.lineWidgets)
|
|
h = this.lineWidgets[row] && this.lineWidgets[row].rowCount || 0;
|
|
else
|
|
h = 0;
|
|
if (!this.$useWrapMode || !this.$wrapData[row]) {
|
|
return 1 + h;
|
|
} else {
|
|
return this.$wrapData[row].length + 1 + h;
|
|
}
|
|
};
|
|
|
|
this.$getWidgetScreenLength = function() {
|
|
var screenRows = 0;
|
|
this.lineWidgets.forEach(function(w){
|
|
if (w && w.rowCount && !w.hidden)
|
|
screenRows += w.rowCount;
|
|
});
|
|
return screenRows;
|
|
};
|
|
|
|
this.$onChangeEditor = function(e) {
|
|
this.attach(e.editor);
|
|
};
|
|
|
|
this.attach = function(editor) {
|
|
if (editor && editor.widgetManager && editor.widgetManager != this)
|
|
editor.widgetManager.detach();
|
|
|
|
if (this.editor == editor)
|
|
return;
|
|
|
|
this.detach();
|
|
this.editor = editor;
|
|
|
|
if (editor) {
|
|
editor.widgetManager = this;
|
|
editor.renderer.on("beforeRender", this.measureWidgets);
|
|
editor.renderer.on("afterRender", this.renderWidgets);
|
|
}
|
|
};
|
|
this.detach = function(e) {
|
|
var editor = this.editor;
|
|
if (!editor)
|
|
return;
|
|
|
|
this.editor = null;
|
|
editor.widgetManager = null;
|
|
|
|
editor.renderer.off("beforeRender", this.measureWidgets);
|
|
editor.renderer.off("afterRender", this.renderWidgets);
|
|
var lineWidgets = this.session.lineWidgets;
|
|
lineWidgets && lineWidgets.forEach(function(w) {
|
|
if (w && w.el && w.el.parentNode) {
|
|
w._inDocument = false;
|
|
w.el.parentNode.removeChild(w.el);
|
|
}
|
|
});
|
|
};
|
|
|
|
this.updateOnFold = function(e, session) {
|
|
var lineWidgets = session.lineWidgets;
|
|
if (!lineWidgets || !e.action)
|
|
return;
|
|
var fold = e.data;
|
|
var start = fold.start.row;
|
|
var end = fold.end.row;
|
|
var hide = e.action == "add";
|
|
for (var i = start + 1; i < end; i++) {
|
|
if (lineWidgets[i])
|
|
lineWidgets[i].hidden = hide;
|
|
}
|
|
if (lineWidgets[end]) {
|
|
if (hide) {
|
|
if (!lineWidgets[start])
|
|
lineWidgets[start] = lineWidgets[end];
|
|
else
|
|
lineWidgets[end].hidden = hide;
|
|
} else {
|
|
if (lineWidgets[start] == lineWidgets[end])
|
|
lineWidgets[start] = undefined;
|
|
lineWidgets[end].hidden = hide;
|
|
}
|
|
}
|
|
};
|
|
|
|
this.updateOnChange = function(delta) {
|
|
var lineWidgets = this.session.lineWidgets;
|
|
if (!lineWidgets) return;
|
|
|
|
var startRow = delta.start.row;
|
|
var len = delta.end.row - startRow;
|
|
|
|
if (len === 0) {
|
|
} else if (delta.action == "remove") {
|
|
var removed = lineWidgets.splice(startRow + 1, len);
|
|
if (!lineWidgets[startRow] && removed[removed.length - 1]) {
|
|
lineWidgets[startRow] = removed.pop();
|
|
}
|
|
removed.forEach(function(w) {
|
|
w && this.removeLineWidget(w);
|
|
}, this);
|
|
this.$updateRows();
|
|
} else {
|
|
var args = new Array(len);
|
|
if (lineWidgets[startRow] && lineWidgets[startRow].column != null) {
|
|
if (delta.start.column > lineWidgets[startRow].column)
|
|
startRow++;
|
|
}
|
|
args.unshift(startRow, 0);
|
|
lineWidgets.splice.apply(lineWidgets, args);
|
|
this.$updateRows();
|
|
}
|
|
};
|
|
|
|
this.$updateRows = function() {
|
|
var lineWidgets = this.session.lineWidgets;
|
|
if (!lineWidgets) return;
|
|
var noWidgets = true;
|
|
lineWidgets.forEach(function(w, i) {
|
|
if (w) {
|
|
noWidgets = false;
|
|
w.row = i;
|
|
while (w.$oldWidget) {
|
|
w.$oldWidget.row = i;
|
|
w = w.$oldWidget;
|
|
}
|
|
}
|
|
});
|
|
if (noWidgets)
|
|
this.session.lineWidgets = null;
|
|
};
|
|
|
|
this.$registerLineWidget = function(w) {
|
|
if (!this.session.lineWidgets)
|
|
this.session.lineWidgets = new Array(this.session.getLength());
|
|
|
|
var old = this.session.lineWidgets[w.row];
|
|
if (old) {
|
|
w.$oldWidget = old;
|
|
if (old.el && old.el.parentNode) {
|
|
old.el.parentNode.removeChild(old.el);
|
|
old._inDocument = false;
|
|
}
|
|
}
|
|
|
|
this.session.lineWidgets[w.row] = w;
|
|
return w;
|
|
};
|
|
|
|
this.addLineWidget = function(w) {
|
|
this.$registerLineWidget(w);
|
|
w.session = this.session;
|
|
|
|
if (!this.editor) return w;
|
|
|
|
var renderer = this.editor.renderer;
|
|
if (w.html && !w.el) {
|
|
w.el = dom.createElement("div");
|
|
w.el.innerHTML = w.html;
|
|
}
|
|
if (w.el) {
|
|
dom.addCssClass(w.el, "ace_lineWidgetContainer");
|
|
w.el.style.position = "absolute";
|
|
w.el.style.zIndex = 5;
|
|
renderer.container.appendChild(w.el);
|
|
w._inDocument = true;
|
|
|
|
if (!w.coverGutter) {
|
|
w.el.style.zIndex = 3;
|
|
}
|
|
if (w.pixelHeight == null) {
|
|
w.pixelHeight = w.el.offsetHeight;
|
|
}
|
|
}
|
|
if (w.rowCount == null) {
|
|
w.rowCount = w.pixelHeight / renderer.layerConfig.lineHeight;
|
|
}
|
|
|
|
var fold = this.session.getFoldAt(w.row, 0);
|
|
w.$fold = fold;
|
|
if (fold) {
|
|
var lineWidgets = this.session.lineWidgets;
|
|
if (w.row == fold.end.row && !lineWidgets[fold.start.row])
|
|
lineWidgets[fold.start.row] = w;
|
|
else
|
|
w.hidden = true;
|
|
}
|
|
|
|
this.session._emit("changeFold", {data:{start:{row: w.row}}});
|
|
|
|
this.$updateRows();
|
|
this.renderWidgets(null, renderer);
|
|
this.onWidgetChanged(w);
|
|
return w;
|
|
};
|
|
|
|
this.removeLineWidget = function(w) {
|
|
w._inDocument = false;
|
|
w.session = null;
|
|
if (w.el && w.el.parentNode)
|
|
w.el.parentNode.removeChild(w.el);
|
|
if (w.editor && w.editor.destroy) try {
|
|
w.editor.destroy();
|
|
} catch(e){}
|
|
if (this.session.lineWidgets) {
|
|
var w1 = this.session.lineWidgets[w.row];
|
|
if (w1 == w) {
|
|
this.session.lineWidgets[w.row] = w.$oldWidget;
|
|
if (w.$oldWidget)
|
|
this.onWidgetChanged(w.$oldWidget);
|
|
} else {
|
|
while (w1) {
|
|
if (w1.$oldWidget == w) {
|
|
w1.$oldWidget = w.$oldWidget;
|
|
break;
|
|
}
|
|
w1 = w1.$oldWidget;
|
|
}
|
|
}
|
|
}
|
|
this.session._emit("changeFold", {data:{start:{row: w.row}}});
|
|
this.$updateRows();
|
|
};
|
|
|
|
this.getWidgetsAtRow = function(row) {
|
|
var lineWidgets = this.session.lineWidgets;
|
|
var w = lineWidgets && lineWidgets[row];
|
|
var list = [];
|
|
while (w) {
|
|
list.push(w);
|
|
w = w.$oldWidget;
|
|
}
|
|
return list;
|
|
};
|
|
|
|
this.onWidgetChanged = function(w) {
|
|
this.session._changedWidgets.push(w);
|
|
this.editor && this.editor.renderer.updateFull();
|
|
};
|
|
|
|
this.measureWidgets = function(e, renderer) {
|
|
var changedWidgets = this.session._changedWidgets;
|
|
var config = renderer.layerConfig;
|
|
|
|
if (!changedWidgets || !changedWidgets.length) return;
|
|
var min = Infinity;
|
|
for (var i = 0; i < changedWidgets.length; i++) {
|
|
var w = changedWidgets[i];
|
|
if (!w || !w.el) continue;
|
|
if (w.session != this.session) continue;
|
|
if (!w._inDocument) {
|
|
if (this.session.lineWidgets[w.row] != w)
|
|
continue;
|
|
w._inDocument = true;
|
|
renderer.container.appendChild(w.el);
|
|
}
|
|
|
|
w.h = w.el.offsetHeight;
|
|
|
|
if (!w.fixedWidth) {
|
|
w.w = w.el.offsetWidth;
|
|
w.screenWidth = Math.ceil(w.w / config.characterWidth);
|
|
}
|
|
|
|
var rowCount = w.h / config.lineHeight;
|
|
if (w.coverLine) {
|
|
rowCount -= this.session.getRowLineCount(w.row);
|
|
if (rowCount < 0)
|
|
rowCount = 0;
|
|
}
|
|
if (w.rowCount != rowCount) {
|
|
w.rowCount = rowCount;
|
|
if (w.row < min)
|
|
min = w.row;
|
|
}
|
|
}
|
|
if (min != Infinity) {
|
|
this.session._emit("changeFold", {data:{start:{row: min}}});
|
|
this.session.lineWidgetWidth = null;
|
|
}
|
|
this.session._changedWidgets = [];
|
|
};
|
|
|
|
this.renderWidgets = function(e, renderer) {
|
|
var config = renderer.layerConfig;
|
|
var lineWidgets = this.session.lineWidgets;
|
|
if (!lineWidgets)
|
|
return;
|
|
var first = Math.min(this.firstRow, config.firstRow);
|
|
var last = Math.max(this.lastRow, config.lastRow, lineWidgets.length);
|
|
|
|
while (first > 0 && !lineWidgets[first])
|
|
first--;
|
|
|
|
this.firstRow = config.firstRow;
|
|
this.lastRow = config.lastRow;
|
|
|
|
renderer.$cursorLayer.config = config;
|
|
for (var i = first; i <= last; i++) {
|
|
var w = lineWidgets[i];
|
|
if (!w || !w.el) continue;
|
|
if (w.hidden) {
|
|
w.el.style.top = -100 - (w.pixelHeight || 0) + "px";
|
|
continue;
|
|
}
|
|
if (!w._inDocument) {
|
|
w._inDocument = true;
|
|
renderer.container.appendChild(w.el);
|
|
}
|
|
var top = renderer.$cursorLayer.getPixelPosition({row: i, column:0}, true).top;
|
|
if (!w.coverLine)
|
|
top += config.lineHeight * this.session.getRowLineCount(w.row);
|
|
w.el.style.top = top - config.offset + "px";
|
|
|
|
var left = w.coverGutter ? 0 : renderer.gutterWidth;
|
|
if (!w.fixedWidth)
|
|
left -= renderer.scrollLeft;
|
|
w.el.style.left = left + "px";
|
|
|
|
if (w.fullWidth && w.screenWidth) {
|
|
w.el.style.minWidth = config.width + 2 * config.padding + "px";
|
|
}
|
|
|
|
if (w.fixedWidth) {
|
|
w.el.style.right = renderer.scrollBar.getWidth() + "px";
|
|
} else {
|
|
w.el.style.right = "";
|
|
}
|
|
}
|
|
};
|
|
|
|
}).call(LineWidgets.prototype);
|
|
|
|
|
|
exports.LineWidgets = LineWidgets;
|
|
|
|
});
|
|
|
|
ace.define("ace/ext/error_marker",["require","exports","module","ace/line_widgets","ace/lib/dom","ace/range"], function(require, exports, module) {
|
|
"use strict";
|
|
var LineWidgets = require("../line_widgets").LineWidgets;
|
|
var dom = require("../lib/dom");
|
|
var Range = require("../range").Range;
|
|
|
|
function binarySearch(array, needle, comparator) {
|
|
var first = 0;
|
|
var last = array.length - 1;
|
|
|
|
while (first <= last) {
|
|
var mid = (first + last) >> 1;
|
|
var c = comparator(needle, array[mid]);
|
|
if (c > 0)
|
|
first = mid + 1;
|
|
else if (c < 0)
|
|
last = mid - 1;
|
|
else
|
|
return mid;
|
|
}
|
|
return -(first + 1);
|
|
}
|
|
|
|
function findAnnotations(session, row, dir) {
|
|
var annotations = session.getAnnotations().sort(Range.comparePoints);
|
|
if (!annotations.length)
|
|
return;
|
|
|
|
var i = binarySearch(annotations, {row: row, column: -1}, Range.comparePoints);
|
|
if (i < 0)
|
|
i = -i - 1;
|
|
|
|
if (i >= annotations.length)
|
|
i = dir > 0 ? 0 : annotations.length - 1;
|
|
else if (i === 0 && dir < 0)
|
|
i = annotations.length - 1;
|
|
|
|
var annotation = annotations[i];
|
|
if (!annotation || !dir)
|
|
return;
|
|
|
|
if (annotation.row === row) {
|
|
do {
|
|
annotation = annotations[i += dir];
|
|
} while (annotation && annotation.row === row);
|
|
if (!annotation)
|
|
return annotations.slice();
|
|
}
|
|
|
|
|
|
var matched = [];
|
|
row = annotation.row;
|
|
do {
|
|
matched[dir < 0 ? "unshift" : "push"](annotation);
|
|
annotation = annotations[i += dir];
|
|
} while (annotation && annotation.row == row);
|
|
return matched.length && matched;
|
|
}
|
|
|
|
exports.showErrorMarker = function(editor, dir) {
|
|
var session = editor.session;
|
|
if (!session.widgetManager) {
|
|
session.widgetManager = new LineWidgets(session);
|
|
session.widgetManager.attach(editor);
|
|
}
|
|
|
|
var pos = editor.getCursorPosition();
|
|
var row = pos.row;
|
|
var oldWidget = session.widgetManager.getWidgetsAtRow(row).filter(function(w) {
|
|
return w.type == "errorMarker";
|
|
})[0];
|
|
if (oldWidget) {
|
|
oldWidget.destroy();
|
|
} else {
|
|
row -= dir;
|
|
}
|
|
var annotations = findAnnotations(session, row, dir);
|
|
var gutterAnno;
|
|
if (annotations) {
|
|
var annotation = annotations[0];
|
|
pos.column = (annotation.pos && typeof annotation.column != "number"
|
|
? annotation.pos.sc
|
|
: annotation.column) || 0;
|
|
pos.row = annotation.row;
|
|
gutterAnno = editor.renderer.$gutterLayer.$annotations[pos.row];
|
|
} else if (oldWidget) {
|
|
return;
|
|
} else {
|
|
gutterAnno = {
|
|
text: ["Looks good!"],
|
|
className: "ace_ok"
|
|
};
|
|
}
|
|
editor.session.unfold(pos.row);
|
|
editor.selection.moveToPosition(pos);
|
|
|
|
var w = {
|
|
row: pos.row,
|
|
fixedWidth: true,
|
|
coverGutter: true,
|
|
el: dom.createElement("div"),
|
|
type: "errorMarker"
|
|
};
|
|
var el = w.el.appendChild(dom.createElement("div"));
|
|
var arrow = w.el.appendChild(dom.createElement("div"));
|
|
arrow.className = "error_widget_arrow " + gutterAnno.className;
|
|
|
|
var left = editor.renderer.$cursorLayer
|
|
.getPixelPosition(pos).left;
|
|
arrow.style.left = left + editor.renderer.gutterWidth - 5 + "px";
|
|
|
|
w.el.className = "error_widget_wrapper";
|
|
el.className = "error_widget " + gutterAnno.className;
|
|
el.innerHTML = gutterAnno.text.join("<br>");
|
|
|
|
el.appendChild(dom.createElement("div"));
|
|
|
|
var kb = function(_, hashId, keyString) {
|
|
if (hashId === 0 && (keyString === "esc" || keyString === "return")) {
|
|
w.destroy();
|
|
return {command: "null"};
|
|
}
|
|
};
|
|
|
|
w.destroy = function() {
|
|
if (editor.$mouseHandler.isMousePressed)
|
|
return;
|
|
editor.keyBinding.removeKeyboardHandler(kb);
|
|
session.widgetManager.removeLineWidget(w);
|
|
editor.off("changeSelection", w.destroy);
|
|
editor.off("changeSession", w.destroy);
|
|
editor.off("mouseup", w.destroy);
|
|
editor.off("change", w.destroy);
|
|
};
|
|
|
|
editor.keyBinding.addKeyboardHandler(kb);
|
|
editor.on("changeSelection", w.destroy);
|
|
editor.on("changeSession", w.destroy);
|
|
editor.on("mouseup", w.destroy);
|
|
editor.on("change", w.destroy);
|
|
|
|
editor.session.widgetManager.addLineWidget(w);
|
|
|
|
w.el.onmousedown = editor.focus.bind(editor);
|
|
|
|
editor.renderer.scrollCursorIntoView(null, 0.5, {bottom: w.el.offsetHeight});
|
|
};
|
|
|
|
|
|
dom.importCssString("\
|
|
.error_widget_wrapper {\
|
|
background: inherit;\
|
|
color: inherit;\
|
|
border:none\
|
|
}\
|
|
.error_widget {\
|
|
border-top: solid 2px;\
|
|
border-bottom: solid 2px;\
|
|
margin: 5px 0;\
|
|
padding: 10px 40px;\
|
|
white-space: pre-wrap;\
|
|
}\
|
|
.error_widget.ace_error, .error_widget_arrow.ace_error{\
|
|
border-color: #ff5a5a\
|
|
}\
|
|
.error_widget.ace_warning, .error_widget_arrow.ace_warning{\
|
|
border-color: #F1D817\
|
|
}\
|
|
.error_widget.ace_info, .error_widget_arrow.ace_info{\
|
|
border-color: #5a5a5a\
|
|
}\
|
|
.error_widget.ace_ok, .error_widget_arrow.ace_ok{\
|
|
border-color: #5aaa5a\
|
|
}\
|
|
.error_widget_arrow {\
|
|
position: absolute;\
|
|
border: solid 5px;\
|
|
border-top-color: transparent!important;\
|
|
border-right-color: transparent!important;\
|
|
border-left-color: transparent!important;\
|
|
top: -5px;\
|
|
}\
|
|
", "");
|
|
|
|
});
|
|
|
|
ace.define("ace/ace",["require","exports","module","ace/lib/fixoldbrowsers","ace/lib/dom","ace/lib/event","ace/range","ace/editor","ace/edit_session","ace/undomanager","ace/virtual_renderer","ace/worker/worker_client","ace/keyboard/hash_handler","ace/placeholder","ace/multi_select","ace/mode/folding/fold_mode","ace/theme/textmate","ace/ext/error_marker","ace/config"], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
require("./lib/fixoldbrowsers");
|
|
|
|
var dom = require("./lib/dom");
|
|
var event = require("./lib/event");
|
|
|
|
var Range = require("./range").Range;
|
|
var Editor = require("./editor").Editor;
|
|
var EditSession = require("./edit_session").EditSession;
|
|
var UndoManager = require("./undomanager").UndoManager;
|
|
var Renderer = require("./virtual_renderer").VirtualRenderer;
|
|
require("./worker/worker_client");
|
|
require("./keyboard/hash_handler");
|
|
require("./placeholder");
|
|
require("./multi_select");
|
|
require("./mode/folding/fold_mode");
|
|
require("./theme/textmate");
|
|
require("./ext/error_marker");
|
|
|
|
exports.config = require("./config");
|
|
exports.require = require;
|
|
|
|
if (true)
|
|
exports.define = __webpack_require__.amdD;
|
|
exports.edit = function(el, options) {
|
|
if (typeof el == "string") {
|
|
var _id = el;
|
|
el = document.getElementById(_id);
|
|
if (!el)
|
|
throw new Error("ace.edit can't find div #" + _id);
|
|
}
|
|
|
|
if (el && el.env && el.env.editor instanceof Editor)
|
|
return el.env.editor;
|
|
|
|
var value = "";
|
|
if (el && /input|textarea/i.test(el.tagName)) {
|
|
var oldNode = el;
|
|
value = oldNode.value;
|
|
el = dom.createElement("pre");
|
|
oldNode.parentNode.replaceChild(el, oldNode);
|
|
} else if (el) {
|
|
value = el.textContent;
|
|
el.innerHTML = "";
|
|
}
|
|
|
|
var doc = exports.createEditSession(value);
|
|
|
|
var editor = new Editor(new Renderer(el), doc, options);
|
|
|
|
var env = {
|
|
document: doc,
|
|
editor: editor,
|
|
onResize: editor.resize.bind(editor, null)
|
|
};
|
|
if (oldNode) env.textarea = oldNode;
|
|
event.addListener(window, "resize", env.onResize);
|
|
editor.on("destroy", function() {
|
|
event.removeListener(window, "resize", env.onResize);
|
|
env.editor.container.env = null; // prevent memory leak on old ie
|
|
});
|
|
editor.container.env = editor.env = env;
|
|
return editor;
|
|
};
|
|
exports.createEditSession = function(text, mode) {
|
|
var doc = new EditSession(text, mode);
|
|
doc.setUndoManager(new UndoManager());
|
|
return doc;
|
|
};
|
|
exports.Range = Range;
|
|
exports.Editor = Editor;
|
|
exports.EditSession = EditSession;
|
|
exports.UndoManager = UndoManager;
|
|
exports.VirtualRenderer = Renderer;
|
|
exports.version = exports.config.version;
|
|
}); (function() {
|
|
ace.require(["ace/ace"], function(a) {
|
|
if (a) {
|
|
a.config.init(true);
|
|
a.define = ace.define;
|
|
}
|
|
if (!window.ace)
|
|
window.ace = a;
|
|
for (var key in a) if (a.hasOwnProperty(key))
|
|
window.ace[key] = a[key];
|
|
window.ace["default"] = window.ace;
|
|
if ( true && module) {
|
|
module.exports = window.ace;
|
|
}
|
|
});
|
|
})();
|
|
|
|
|
|
/***/ }),
|
|
|
|
/***/ 3330:
|
|
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
|
|
|
|
/* module decorator */ module = __webpack_require__.nmd(module);
|
|
ace.define("ace/ext/searchbox",["require","exports","module","ace/lib/dom","ace/lib/lang","ace/lib/event","ace/keyboard/hash_handler","ace/lib/keys"], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var dom = require("../lib/dom");
|
|
var lang = require("../lib/lang");
|
|
var event = require("../lib/event");
|
|
var searchboxCss = "\
|
|
.ace_search {\
|
|
background-color: #ddd;\
|
|
color: #666;\
|
|
border: 1px solid #cbcbcb;\
|
|
border-top: 0 none;\
|
|
overflow: hidden;\
|
|
margin: 0;\
|
|
padding: 4px 6px 0 4px;\
|
|
position: absolute;\
|
|
top: 0;\
|
|
z-index: 99;\
|
|
white-space: normal;\
|
|
}\
|
|
.ace_search.left {\
|
|
border-left: 0 none;\
|
|
border-radius: 0px 0px 5px 0px;\
|
|
left: 0;\
|
|
}\
|
|
.ace_search.right {\
|
|
border-radius: 0px 0px 0px 5px;\
|
|
border-right: 0 none;\
|
|
right: 0;\
|
|
}\
|
|
.ace_search_form, .ace_replace_form {\
|
|
margin: 0 20px 4px 0;\
|
|
overflow: hidden;\
|
|
line-height: 1.9;\
|
|
}\
|
|
.ace_replace_form {\
|
|
margin-right: 0;\
|
|
}\
|
|
.ace_search_form.ace_nomatch {\
|
|
outline: 1px solid red;\
|
|
}\
|
|
.ace_search_field {\
|
|
border-radius: 3px 0 0 3px;\
|
|
background-color: white;\
|
|
color: black;\
|
|
border: 1px solid #cbcbcb;\
|
|
border-right: 0 none;\
|
|
outline: 0;\
|
|
padding: 0;\
|
|
font-size: inherit;\
|
|
margin: 0;\
|
|
line-height: inherit;\
|
|
padding: 0 6px;\
|
|
min-width: 17em;\
|
|
vertical-align: top;\
|
|
min-height: 1.8em;\
|
|
box-sizing: content-box;\
|
|
}\
|
|
.ace_searchbtn {\
|
|
border: 1px solid #cbcbcb;\
|
|
line-height: inherit;\
|
|
display: inline-block;\
|
|
padding: 0 6px;\
|
|
background: #fff;\
|
|
border-right: 0 none;\
|
|
border-left: 1px solid #dcdcdc;\
|
|
cursor: pointer;\
|
|
margin: 0;\
|
|
position: relative;\
|
|
color: #666;\
|
|
}\
|
|
.ace_searchbtn:last-child {\
|
|
border-radius: 0 3px 3px 0;\
|
|
border-right: 1px solid #cbcbcb;\
|
|
}\
|
|
.ace_searchbtn:disabled {\
|
|
background: none;\
|
|
cursor: default;\
|
|
}\
|
|
.ace_searchbtn:hover {\
|
|
background-color: #eef1f6;\
|
|
}\
|
|
.ace_searchbtn.prev, .ace_searchbtn.next {\
|
|
padding: 0px 0.7em\
|
|
}\
|
|
.ace_searchbtn.prev:after, .ace_searchbtn.next:after {\
|
|
content: \"\";\
|
|
border: solid 2px #888;\
|
|
width: 0.5em;\
|
|
height: 0.5em;\
|
|
border-width: 2px 0 0 2px;\
|
|
display:inline-block;\
|
|
transform: rotate(-45deg);\
|
|
}\
|
|
.ace_searchbtn.next:after {\
|
|
border-width: 0 2px 2px 0 ;\
|
|
}\
|
|
.ace_searchbtn_close {\
|
|
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAcCAYAAABRVo5BAAAAZ0lEQVR42u2SUQrAMAhDvazn8OjZBilCkYVVxiis8H4CT0VrAJb4WHT3C5xU2a2IQZXJjiQIRMdkEoJ5Q2yMqpfDIo+XY4k6h+YXOyKqTIj5REaxloNAd0xiKmAtsTHqW8sR2W5f7gCu5nWFUpVjZwAAAABJRU5ErkJggg==) no-repeat 50% 0;\
|
|
border-radius: 50%;\
|
|
border: 0 none;\
|
|
color: #656565;\
|
|
cursor: pointer;\
|
|
font: 16px/16px Arial;\
|
|
padding: 0;\
|
|
height: 14px;\
|
|
width: 14px;\
|
|
top: 9px;\
|
|
right: 7px;\
|
|
position: absolute;\
|
|
}\
|
|
.ace_searchbtn_close:hover {\
|
|
background-color: #656565;\
|
|
background-position: 50% 100%;\
|
|
color: white;\
|
|
}\
|
|
.ace_button {\
|
|
margin-left: 2px;\
|
|
cursor: pointer;\
|
|
-webkit-user-select: none;\
|
|
-moz-user-select: none;\
|
|
-o-user-select: none;\
|
|
-ms-user-select: none;\
|
|
user-select: none;\
|
|
overflow: hidden;\
|
|
opacity: 0.7;\
|
|
border: 1px solid rgba(100,100,100,0.23);\
|
|
padding: 1px;\
|
|
box-sizing: border-box!important;\
|
|
color: black;\
|
|
}\
|
|
.ace_button:hover {\
|
|
background-color: #eee;\
|
|
opacity:1;\
|
|
}\
|
|
.ace_button:active {\
|
|
background-color: #ddd;\
|
|
}\
|
|
.ace_button.checked {\
|
|
border-color: #3399ff;\
|
|
opacity:1;\
|
|
}\
|
|
.ace_search_options{\
|
|
margin-bottom: 3px;\
|
|
text-align: right;\
|
|
-webkit-user-select: none;\
|
|
-moz-user-select: none;\
|
|
-o-user-select: none;\
|
|
-ms-user-select: none;\
|
|
user-select: none;\
|
|
clear: both;\
|
|
}\
|
|
.ace_search_counter {\
|
|
float: left;\
|
|
font-family: arial;\
|
|
padding: 0 8px;\
|
|
}";
|
|
var HashHandler = require("../keyboard/hash_handler").HashHandler;
|
|
var keyUtil = require("../lib/keys");
|
|
|
|
var MAX_COUNT = 999;
|
|
|
|
dom.importCssString(searchboxCss, "ace_searchbox");
|
|
|
|
var SearchBox = function(editor, range, showReplaceForm) {
|
|
var div = dom.createElement("div");
|
|
dom.buildDom(["div", {class:"ace_search right"},
|
|
["span", {action: "hide", class: "ace_searchbtn_close"}],
|
|
["div", {class: "ace_search_form"},
|
|
["input", {class: "ace_search_field", placeholder: "Search for", spellcheck: "false"}],
|
|
["span", {action: "findPrev", class: "ace_searchbtn prev"}, "\u200b"],
|
|
["span", {action: "findNext", class: "ace_searchbtn next"}, "\u200b"],
|
|
["span", {action: "findAll", class: "ace_searchbtn", title: "Alt-Enter"}, "All"]
|
|
],
|
|
["div", {class: "ace_replace_form"},
|
|
["input", {class: "ace_search_field", placeholder: "Replace with", spellcheck: "false"}],
|
|
["span", {action: "replaceAndFindNext", class: "ace_searchbtn"}, "Replace"],
|
|
["span", {action: "replaceAll", class: "ace_searchbtn"}, "All"]
|
|
],
|
|
["div", {class: "ace_search_options"},
|
|
["span", {action: "toggleReplace", class: "ace_button", title: "Toggle Replace mode",
|
|
style: "float:left;margin-top:-2px;padding:0 5px;"}, "+"],
|
|
["span", {class: "ace_search_counter"}],
|
|
["span", {action: "toggleRegexpMode", class: "ace_button", title: "RegExp Search"}, ".*"],
|
|
["span", {action: "toggleCaseSensitive", class: "ace_button", title: "CaseSensitive Search"}, "Aa"],
|
|
["span", {action: "toggleWholeWords", class: "ace_button", title: "Whole Word Search"}, "\\b"],
|
|
["span", {action: "searchInSelection", class: "ace_button", title: "Search In Selection"}, "S"]
|
|
]
|
|
], div);
|
|
this.element = div.firstChild;
|
|
|
|
this.setSession = this.setSession.bind(this);
|
|
|
|
this.$init();
|
|
this.setEditor(editor);
|
|
dom.importCssString(searchboxCss, "ace_searchbox", editor.container);
|
|
};
|
|
|
|
(function() {
|
|
this.setEditor = function(editor) {
|
|
editor.searchBox = this;
|
|
editor.renderer.scroller.appendChild(this.element);
|
|
this.editor = editor;
|
|
};
|
|
|
|
this.setSession = function(e) {
|
|
this.searchRange = null;
|
|
this.$syncOptions(true);
|
|
};
|
|
|
|
this.$initElements = function(sb) {
|
|
this.searchBox = sb.querySelector(".ace_search_form");
|
|
this.replaceBox = sb.querySelector(".ace_replace_form");
|
|
this.searchOption = sb.querySelector("[action=searchInSelection]");
|
|
this.replaceOption = sb.querySelector("[action=toggleReplace]");
|
|
this.regExpOption = sb.querySelector("[action=toggleRegexpMode]");
|
|
this.caseSensitiveOption = sb.querySelector("[action=toggleCaseSensitive]");
|
|
this.wholeWordOption = sb.querySelector("[action=toggleWholeWords]");
|
|
this.searchInput = this.searchBox.querySelector(".ace_search_field");
|
|
this.replaceInput = this.replaceBox.querySelector(".ace_search_field");
|
|
this.searchCounter = sb.querySelector(".ace_search_counter");
|
|
};
|
|
|
|
this.$init = function() {
|
|
var sb = this.element;
|
|
|
|
this.$initElements(sb);
|
|
|
|
var _this = this;
|
|
event.addListener(sb, "mousedown", function(e) {
|
|
setTimeout(function(){
|
|
_this.activeInput.focus();
|
|
}, 0);
|
|
event.stopPropagation(e);
|
|
});
|
|
event.addListener(sb, "click", function(e) {
|
|
var t = e.target || e.srcElement;
|
|
var action = t.getAttribute("action");
|
|
if (action && _this[action])
|
|
_this[action]();
|
|
else if (_this.$searchBarKb.commands[action])
|
|
_this.$searchBarKb.commands[action].exec(_this);
|
|
event.stopPropagation(e);
|
|
});
|
|
|
|
event.addCommandKeyListener(sb, function(e, hashId, keyCode) {
|
|
var keyString = keyUtil.keyCodeToString(keyCode);
|
|
var command = _this.$searchBarKb.findKeyCommand(hashId, keyString);
|
|
if (command && command.exec) {
|
|
command.exec(_this);
|
|
event.stopEvent(e);
|
|
}
|
|
});
|
|
|
|
this.$onChange = lang.delayedCall(function() {
|
|
_this.find(false, false);
|
|
});
|
|
|
|
event.addListener(this.searchInput, "input", function() {
|
|
_this.$onChange.schedule(20);
|
|
});
|
|
event.addListener(this.searchInput, "focus", function() {
|
|
_this.activeInput = _this.searchInput;
|
|
_this.searchInput.value && _this.highlight();
|
|
});
|
|
event.addListener(this.replaceInput, "focus", function() {
|
|
_this.activeInput = _this.replaceInput;
|
|
_this.searchInput.value && _this.highlight();
|
|
});
|
|
};
|
|
this.$closeSearchBarKb = new HashHandler([{
|
|
bindKey: "Esc",
|
|
name: "closeSearchBar",
|
|
exec: function(editor) {
|
|
editor.searchBox.hide();
|
|
}
|
|
}]);
|
|
this.$searchBarKb = new HashHandler();
|
|
this.$searchBarKb.bindKeys({
|
|
"Ctrl-f|Command-f": function(sb) {
|
|
var isReplace = sb.isReplace = !sb.isReplace;
|
|
sb.replaceBox.style.display = isReplace ? "" : "none";
|
|
sb.replaceOption.checked = false;
|
|
sb.$syncOptions();
|
|
sb.searchInput.focus();
|
|
},
|
|
"Ctrl-H|Command-Option-F": function(sb) {
|
|
if (sb.editor.getReadOnly())
|
|
return;
|
|
sb.replaceOption.checked = true;
|
|
sb.$syncOptions();
|
|
sb.replaceInput.focus();
|
|
},
|
|
"Ctrl-G|Command-G": function(sb) {
|
|
sb.findNext();
|
|
},
|
|
"Ctrl-Shift-G|Command-Shift-G": function(sb) {
|
|
sb.findPrev();
|
|
},
|
|
"esc": function(sb) {
|
|
setTimeout(function() { sb.hide();});
|
|
},
|
|
"Return": function(sb) {
|
|
if (sb.activeInput == sb.replaceInput)
|
|
sb.replace();
|
|
sb.findNext();
|
|
},
|
|
"Shift-Return": function(sb) {
|
|
if (sb.activeInput == sb.replaceInput)
|
|
sb.replace();
|
|
sb.findPrev();
|
|
},
|
|
"Alt-Return": function(sb) {
|
|
if (sb.activeInput == sb.replaceInput)
|
|
sb.replaceAll();
|
|
sb.findAll();
|
|
},
|
|
"Tab": function(sb) {
|
|
(sb.activeInput == sb.replaceInput ? sb.searchInput : sb.replaceInput).focus();
|
|
}
|
|
});
|
|
|
|
this.$searchBarKb.addCommands([{
|
|
name: "toggleRegexpMode",
|
|
bindKey: {win: "Alt-R|Alt-/", mac: "Ctrl-Alt-R|Ctrl-Alt-/"},
|
|
exec: function(sb) {
|
|
sb.regExpOption.checked = !sb.regExpOption.checked;
|
|
sb.$syncOptions();
|
|
}
|
|
}, {
|
|
name: "toggleCaseSensitive",
|
|
bindKey: {win: "Alt-C|Alt-I", mac: "Ctrl-Alt-R|Ctrl-Alt-I"},
|
|
exec: function(sb) {
|
|
sb.caseSensitiveOption.checked = !sb.caseSensitiveOption.checked;
|
|
sb.$syncOptions();
|
|
}
|
|
}, {
|
|
name: "toggleWholeWords",
|
|
bindKey: {win: "Alt-B|Alt-W", mac: "Ctrl-Alt-B|Ctrl-Alt-W"},
|
|
exec: function(sb) {
|
|
sb.wholeWordOption.checked = !sb.wholeWordOption.checked;
|
|
sb.$syncOptions();
|
|
}
|
|
}, {
|
|
name: "toggleReplace",
|
|
exec: function(sb) {
|
|
sb.replaceOption.checked = !sb.replaceOption.checked;
|
|
sb.$syncOptions();
|
|
}
|
|
}, {
|
|
name: "searchInSelection",
|
|
exec: function(sb) {
|
|
sb.searchOption.checked = !sb.searchRange;
|
|
sb.setSearchRange(sb.searchOption.checked && sb.editor.getSelectionRange());
|
|
sb.$syncOptions();
|
|
}
|
|
}]);
|
|
|
|
this.setSearchRange = function(range) {
|
|
this.searchRange = range;
|
|
if (range) {
|
|
this.searchRangeMarker = this.editor.session.addMarker(range, "ace_active-line");
|
|
} else if (this.searchRangeMarker) {
|
|
this.editor.session.removeMarker(this.searchRangeMarker);
|
|
this.searchRangeMarker = null;
|
|
}
|
|
};
|
|
|
|
this.$syncOptions = function(preventScroll) {
|
|
dom.setCssClass(this.replaceOption, "checked", this.searchRange);
|
|
dom.setCssClass(this.searchOption, "checked", this.searchOption.checked);
|
|
this.replaceOption.textContent = this.replaceOption.checked ? "-" : "+";
|
|
dom.setCssClass(this.regExpOption, "checked", this.regExpOption.checked);
|
|
dom.setCssClass(this.wholeWordOption, "checked", this.wholeWordOption.checked);
|
|
dom.setCssClass(this.caseSensitiveOption, "checked", this.caseSensitiveOption.checked);
|
|
var readOnly = this.editor.getReadOnly();
|
|
this.replaceOption.style.display = readOnly ? "none" : "";
|
|
this.replaceBox.style.display = this.replaceOption.checked && !readOnly ? "" : "none";
|
|
this.find(false, false, preventScroll);
|
|
};
|
|
|
|
this.highlight = function(re) {
|
|
this.editor.session.highlight(re || this.editor.$search.$options.re);
|
|
this.editor.renderer.updateBackMarkers();
|
|
};
|
|
this.find = function(skipCurrent, backwards, preventScroll) {
|
|
var range = this.editor.find(this.searchInput.value, {
|
|
skipCurrent: skipCurrent,
|
|
backwards: backwards,
|
|
wrap: true,
|
|
regExp: this.regExpOption.checked,
|
|
caseSensitive: this.caseSensitiveOption.checked,
|
|
wholeWord: this.wholeWordOption.checked,
|
|
preventScroll: preventScroll,
|
|
range: this.searchRange
|
|
});
|
|
var noMatch = !range && this.searchInput.value;
|
|
dom.setCssClass(this.searchBox, "ace_nomatch", noMatch);
|
|
this.editor._emit("findSearchBox", { match: !noMatch });
|
|
this.highlight();
|
|
this.updateCounter();
|
|
};
|
|
this.updateCounter = function() {
|
|
var editor = this.editor;
|
|
var regex = editor.$search.$options.re;
|
|
var all = 0;
|
|
var before = 0;
|
|
if (regex) {
|
|
var value = this.searchRange
|
|
? editor.session.getTextRange(this.searchRange)
|
|
: editor.getValue();
|
|
|
|
var offset = editor.session.doc.positionToIndex(editor.selection.anchor);
|
|
if (this.searchRange)
|
|
offset -= editor.session.doc.positionToIndex(this.searchRange.start);
|
|
|
|
var last = regex.lastIndex = 0;
|
|
var m;
|
|
while ((m = regex.exec(value))) {
|
|
all++;
|
|
last = m.index;
|
|
if (last <= offset)
|
|
before++;
|
|
if (all > MAX_COUNT)
|
|
break;
|
|
if (!m[0]) {
|
|
regex.lastIndex = last += 1;
|
|
if (last >= value.length)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
this.searchCounter.textContent = before + " of " + (all > MAX_COUNT ? MAX_COUNT + "+" : all);
|
|
};
|
|
this.findNext = function() {
|
|
this.find(true, false);
|
|
};
|
|
this.findPrev = function() {
|
|
this.find(true, true);
|
|
};
|
|
this.findAll = function(){
|
|
var range = this.editor.findAll(this.searchInput.value, {
|
|
regExp: this.regExpOption.checked,
|
|
caseSensitive: this.caseSensitiveOption.checked,
|
|
wholeWord: this.wholeWordOption.checked
|
|
});
|
|
var noMatch = !range && this.searchInput.value;
|
|
dom.setCssClass(this.searchBox, "ace_nomatch", noMatch);
|
|
this.editor._emit("findSearchBox", { match: !noMatch });
|
|
this.highlight();
|
|
this.hide();
|
|
};
|
|
this.replace = function() {
|
|
if (!this.editor.getReadOnly())
|
|
this.editor.replace(this.replaceInput.value);
|
|
};
|
|
this.replaceAndFindNext = function() {
|
|
if (!this.editor.getReadOnly()) {
|
|
this.editor.replace(this.replaceInput.value);
|
|
this.findNext();
|
|
}
|
|
};
|
|
this.replaceAll = function() {
|
|
if (!this.editor.getReadOnly())
|
|
this.editor.replaceAll(this.replaceInput.value);
|
|
};
|
|
|
|
this.hide = function() {
|
|
this.active = false;
|
|
this.setSearchRange(null);
|
|
this.editor.off("changeSession", this.setSession);
|
|
|
|
this.element.style.display = "none";
|
|
this.editor.keyBinding.removeKeyboardHandler(this.$closeSearchBarKb);
|
|
this.editor.focus();
|
|
};
|
|
this.show = function(value, isReplace) {
|
|
this.active = true;
|
|
this.editor.on("changeSession", this.setSession);
|
|
this.element.style.display = "";
|
|
this.replaceOption.checked = isReplace;
|
|
|
|
if (value)
|
|
this.searchInput.value = value;
|
|
|
|
this.searchInput.focus();
|
|
this.searchInput.select();
|
|
|
|
this.editor.keyBinding.addKeyboardHandler(this.$closeSearchBarKb);
|
|
|
|
this.$syncOptions(true);
|
|
};
|
|
|
|
this.isFocused = function() {
|
|
var el = document.activeElement;
|
|
return el == this.searchInput || el == this.replaceInput;
|
|
};
|
|
}).call(SearchBox.prototype);
|
|
|
|
exports.SearchBox = SearchBox;
|
|
|
|
exports.Search = function(editor, isReplace) {
|
|
var sb = editor.searchBox || new SearchBox(editor);
|
|
sb.show(editor.session.getTextRange(), isReplace);
|
|
};
|
|
|
|
}); (function() {
|
|
ace.require(["ace/ext/searchbox"], function(m) {
|
|
if ( true && module) {
|
|
module.exports = m;
|
|
}
|
|
});
|
|
})();
|
|
|
|
|
|
/***/ }),
|
|
|
|
/***/ 4091:
|
|
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
|
|
|
|
/* module decorator */ module = __webpack_require__.nmd(module);
|
|
ace.define("ace/mode/json_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var oop = require("../lib/oop");
|
|
var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules;
|
|
|
|
var JsonHighlightRules = function() {
|
|
this.$rules = {
|
|
"start" : [
|
|
{
|
|
token : "variable", // single line
|
|
regex : '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]\\s*(?=:)'
|
|
}, {
|
|
token : "string", // single line
|
|
regex : '"',
|
|
next : "string"
|
|
}, {
|
|
token : "constant.numeric", // hex
|
|
regex : "0[xX][0-9a-fA-F]+\\b"
|
|
}, {
|
|
token : "constant.numeric", // float
|
|
regex : "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b"
|
|
}, {
|
|
token : "constant.language.boolean",
|
|
regex : "(?:true|false)\\b"
|
|
}, {
|
|
token : "text", // single quoted strings are not allowed
|
|
regex : "['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']"
|
|
}, {
|
|
token : "comment", // comments are not allowed, but who cares?
|
|
regex : "\\/\\/.*$"
|
|
}, {
|
|
token : "comment.start", // comments are not allowed, but who cares?
|
|
regex : "\\/\\*",
|
|
next : "comment"
|
|
}, {
|
|
token : "paren.lparen",
|
|
regex : "[[({]"
|
|
}, {
|
|
token : "paren.rparen",
|
|
regex : "[\\])}]"
|
|
}, {
|
|
token : "text",
|
|
regex : "\\s+"
|
|
}
|
|
],
|
|
"string" : [
|
|
{
|
|
token : "constant.language.escape",
|
|
regex : /\\(?:x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|["\\\/bfnrt])/
|
|
}, {
|
|
token : "string",
|
|
regex : '"|$',
|
|
next : "start"
|
|
}, {
|
|
defaultToken : "string"
|
|
}
|
|
],
|
|
"comment" : [
|
|
{
|
|
token : "comment.end", // comments are not allowed, but who cares?
|
|
regex : "\\*\\/",
|
|
next : "start"
|
|
}, {
|
|
defaultToken: "comment"
|
|
}
|
|
]
|
|
};
|
|
|
|
};
|
|
|
|
oop.inherits(JsonHighlightRules, TextHighlightRules);
|
|
|
|
exports.JsonHighlightRules = JsonHighlightRules;
|
|
});
|
|
|
|
ace.define("ace/mode/matching_brace_outdent",["require","exports","module","ace/range"], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var Range = require("../range").Range;
|
|
|
|
var MatchingBraceOutdent = function() {};
|
|
|
|
(function() {
|
|
|
|
this.checkOutdent = function(line, input) {
|
|
if (! /^\s+$/.test(line))
|
|
return false;
|
|
|
|
return /^\s*\}/.test(input);
|
|
};
|
|
|
|
this.autoOutdent = function(doc, row) {
|
|
var line = doc.getLine(row);
|
|
var match = line.match(/^(\s*\})/);
|
|
|
|
if (!match) return 0;
|
|
|
|
var column = match[1].length;
|
|
var openBracePos = doc.findMatchingBracket({row: row, column: column});
|
|
|
|
if (!openBracePos || openBracePos.row == row) return 0;
|
|
|
|
var indent = this.$getIndent(doc.getLine(openBracePos.row));
|
|
doc.replace(new Range(row, 0, row, column-1), indent);
|
|
};
|
|
|
|
this.$getIndent = function(line) {
|
|
return line.match(/^\s*/)[0];
|
|
};
|
|
|
|
}).call(MatchingBraceOutdent.prototype);
|
|
|
|
exports.MatchingBraceOutdent = MatchingBraceOutdent;
|
|
});
|
|
|
|
ace.define("ace/mode/folding/cstyle",["require","exports","module","ace/lib/oop","ace/range","ace/mode/folding/fold_mode"], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var oop = require("../../lib/oop");
|
|
var Range = require("../../range").Range;
|
|
var BaseFoldMode = require("./fold_mode").FoldMode;
|
|
|
|
var FoldMode = exports.FoldMode = function(commentRegex) {
|
|
if (commentRegex) {
|
|
this.foldingStartMarker = new RegExp(
|
|
this.foldingStartMarker.source.replace(/\|[^|]*?$/, "|" + commentRegex.start)
|
|
);
|
|
this.foldingStopMarker = new RegExp(
|
|
this.foldingStopMarker.source.replace(/\|[^|]*?$/, "|" + commentRegex.end)
|
|
);
|
|
}
|
|
};
|
|
oop.inherits(FoldMode, BaseFoldMode);
|
|
|
|
(function() {
|
|
|
|
this.foldingStartMarker = /([\{\[\(])[^\}\]\)]*$|^\s*(\/\*)/;
|
|
this.foldingStopMarker = /^[^\[\{\(]*([\}\]\)])|^[\s\*]*(\*\/)/;
|
|
this.singleLineBlockCommentRe= /^\s*(\/\*).*\*\/\s*$/;
|
|
this.tripleStarBlockCommentRe = /^\s*(\/\*\*\*).*\*\/\s*$/;
|
|
this.startRegionRe = /^\s*(\/\*|\/\/)#?region\b/;
|
|
this._getFoldWidgetBase = this.getFoldWidget;
|
|
this.getFoldWidget = function(session, foldStyle, row) {
|
|
var line = session.getLine(row);
|
|
|
|
if (this.singleLineBlockCommentRe.test(line)) {
|
|
if (!this.startRegionRe.test(line) && !this.tripleStarBlockCommentRe.test(line))
|
|
return "";
|
|
}
|
|
|
|
var fw = this._getFoldWidgetBase(session, foldStyle, row);
|
|
|
|
if (!fw && this.startRegionRe.test(line))
|
|
return "start"; // lineCommentRegionStart
|
|
|
|
return fw;
|
|
};
|
|
|
|
this.getFoldWidgetRange = function(session, foldStyle, row, forceMultiline) {
|
|
var line = session.getLine(row);
|
|
|
|
if (this.startRegionRe.test(line))
|
|
return this.getCommentRegionBlock(session, line, row);
|
|
|
|
var match = line.match(this.foldingStartMarker);
|
|
if (match) {
|
|
var i = match.index;
|
|
|
|
if (match[1])
|
|
return this.openingBracketBlock(session, match[1], row, i);
|
|
|
|
var range = session.getCommentFoldRange(row, i + match[0].length, 1);
|
|
|
|
if (range && !range.isMultiLine()) {
|
|
if (forceMultiline) {
|
|
range = this.getSectionRange(session, row);
|
|
} else if (foldStyle != "all")
|
|
range = null;
|
|
}
|
|
|
|
return range;
|
|
}
|
|
|
|
if (foldStyle === "markbegin")
|
|
return;
|
|
|
|
var match = line.match(this.foldingStopMarker);
|
|
if (match) {
|
|
var i = match.index + match[0].length;
|
|
|
|
if (match[1])
|
|
return this.closingBracketBlock(session, match[1], row, i);
|
|
|
|
return session.getCommentFoldRange(row, i, -1);
|
|
}
|
|
};
|
|
|
|
this.getSectionRange = function(session, row) {
|
|
var line = session.getLine(row);
|
|
var startIndent = line.search(/\S/);
|
|
var startRow = row;
|
|
var startColumn = line.length;
|
|
row = row + 1;
|
|
var endRow = row;
|
|
var maxRow = session.getLength();
|
|
while (++row < maxRow) {
|
|
line = session.getLine(row);
|
|
var indent = line.search(/\S/);
|
|
if (indent === -1)
|
|
continue;
|
|
if (startIndent > indent)
|
|
break;
|
|
var subRange = this.getFoldWidgetRange(session, "all", row);
|
|
|
|
if (subRange) {
|
|
if (subRange.start.row <= startRow) {
|
|
break;
|
|
} else if (subRange.isMultiLine()) {
|
|
row = subRange.end.row;
|
|
} else if (startIndent == indent) {
|
|
break;
|
|
}
|
|
}
|
|
endRow = row;
|
|
}
|
|
|
|
return new Range(startRow, startColumn, endRow, session.getLine(endRow).length);
|
|
};
|
|
this.getCommentRegionBlock = function(session, line, row) {
|
|
var startColumn = line.search(/\s*$/);
|
|
var maxRow = session.getLength();
|
|
var startRow = row;
|
|
|
|
var re = /^\s*(?:\/\*|\/\/|--)#?(end)?region\b/;
|
|
var depth = 1;
|
|
while (++row < maxRow) {
|
|
line = session.getLine(row);
|
|
var m = re.exec(line);
|
|
if (!m) continue;
|
|
if (m[1]) depth--;
|
|
else depth++;
|
|
|
|
if (!depth) break;
|
|
}
|
|
|
|
var endRow = row;
|
|
if (endRow > startRow) {
|
|
return new Range(startRow, startColumn, endRow, line.length);
|
|
}
|
|
};
|
|
|
|
}).call(FoldMode.prototype);
|
|
|
|
});
|
|
|
|
ace.define("ace/mode/json",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/json_highlight_rules","ace/mode/matching_brace_outdent","ace/mode/behaviour/cstyle","ace/mode/folding/cstyle","ace/worker/worker_client"], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var oop = require("../lib/oop");
|
|
var TextMode = require("./text").Mode;
|
|
var HighlightRules = require("./json_highlight_rules").JsonHighlightRules;
|
|
var MatchingBraceOutdent = require("./matching_brace_outdent").MatchingBraceOutdent;
|
|
var CstyleBehaviour = require("./behaviour/cstyle").CstyleBehaviour;
|
|
var CStyleFoldMode = require("./folding/cstyle").FoldMode;
|
|
var WorkerClient = require("../worker/worker_client").WorkerClient;
|
|
|
|
var Mode = function() {
|
|
this.HighlightRules = HighlightRules;
|
|
this.$outdent = new MatchingBraceOutdent();
|
|
this.$behaviour = new CstyleBehaviour();
|
|
this.foldingRules = new CStyleFoldMode();
|
|
};
|
|
oop.inherits(Mode, TextMode);
|
|
|
|
(function() {
|
|
|
|
this.lineCommentStart = "//";
|
|
this.blockComment = {start: "/*", end: "*/"};
|
|
|
|
this.getNextLineIndent = function(state, line, tab) {
|
|
var indent = this.$getIndent(line);
|
|
|
|
if (state == "start") {
|
|
var match = line.match(/^.*[\{\(\[]\s*$/);
|
|
if (match) {
|
|
indent += tab;
|
|
}
|
|
}
|
|
|
|
return indent;
|
|
};
|
|
|
|
this.checkOutdent = function(state, line, input) {
|
|
return this.$outdent.checkOutdent(line, input);
|
|
};
|
|
|
|
this.autoOutdent = function(state, doc, row) {
|
|
this.$outdent.autoOutdent(doc, row);
|
|
};
|
|
|
|
this.createWorker = function(session) {
|
|
var worker = new WorkerClient(["ace"], "ace/mode/json_worker", "JsonWorker");
|
|
worker.attachToDocument(session.getDocument());
|
|
|
|
worker.on("annotate", function(e) {
|
|
session.setAnnotations(e.data);
|
|
});
|
|
|
|
worker.on("terminate", function() {
|
|
session.clearAnnotations();
|
|
});
|
|
|
|
return worker;
|
|
};
|
|
|
|
|
|
this.$id = "ace/mode/json";
|
|
}).call(Mode.prototype);
|
|
|
|
exports.Mode = Mode;
|
|
}); (function() {
|
|
ace.require(["ace/mode/json"], function(m) {
|
|
if ( true && module) {
|
|
module.exports = m;
|
|
}
|
|
});
|
|
})();
|
|
|
|
|
|
/***/ }),
|
|
|
|
/***/ 8903:
|
|
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
|
|
|
|
"use strict";
|
|
|
|
|
|
var compileSchema = __webpack_require__(5689)
|
|
, resolve = __webpack_require__(3969)
|
|
, Cache = __webpack_require__(5255)
|
|
, SchemaObject = __webpack_require__(4293)
|
|
, stableStringify = __webpack_require__(3508)
|
|
, formats = __webpack_require__(3368)
|
|
, rules = __webpack_require__(742)
|
|
, $dataMetaSchema = __webpack_require__(9394)
|
|
, util = __webpack_require__(3724);
|
|
|
|
module.exports = Ajv;
|
|
|
|
Ajv.prototype.validate = validate;
|
|
Ajv.prototype.compile = compile;
|
|
Ajv.prototype.addSchema = addSchema;
|
|
Ajv.prototype.addMetaSchema = addMetaSchema;
|
|
Ajv.prototype.validateSchema = validateSchema;
|
|
Ajv.prototype.getSchema = getSchema;
|
|
Ajv.prototype.removeSchema = removeSchema;
|
|
Ajv.prototype.addFormat = addFormat;
|
|
Ajv.prototype.errorsText = errorsText;
|
|
|
|
Ajv.prototype._addSchema = _addSchema;
|
|
Ajv.prototype._compile = _compile;
|
|
|
|
Ajv.prototype.compileAsync = __webpack_require__(9677);
|
|
var customKeyword = __webpack_require__(7931);
|
|
Ajv.prototype.addKeyword = customKeyword.add;
|
|
Ajv.prototype.getKeyword = customKeyword.get;
|
|
Ajv.prototype.removeKeyword = customKeyword.remove;
|
|
Ajv.prototype.validateKeyword = customKeyword.validate;
|
|
|
|
var errorClasses = __webpack_require__(5359);
|
|
Ajv.ValidationError = errorClasses.Validation;
|
|
Ajv.MissingRefError = errorClasses.MissingRef;
|
|
Ajv.$dataMetaSchema = $dataMetaSchema;
|
|
|
|
var META_SCHEMA_ID = 'http://json-schema.org/draft-07/schema';
|
|
|
|
var META_IGNORE_OPTIONS = [ 'removeAdditional', 'useDefaults', 'coerceTypes', 'strictDefaults' ];
|
|
var META_SUPPORT_DATA = ['/properties'];
|
|
|
|
/**
|
|
* Creates validator instance.
|
|
* Usage: `Ajv(opts)`
|
|
* @param {Object} opts optional options
|
|
* @return {Object} ajv instance
|
|
*/
|
|
function Ajv(opts) {
|
|
if (!(this instanceof Ajv)) return new Ajv(opts);
|
|
opts = this._opts = util.copy(opts) || {};
|
|
setLogger(this);
|
|
this._schemas = {};
|
|
this._refs = {};
|
|
this._fragments = {};
|
|
this._formats = formats(opts.format);
|
|
|
|
this._cache = opts.cache || new Cache;
|
|
this._loadingSchemas = {};
|
|
this._compilations = [];
|
|
this.RULES = rules();
|
|
this._getId = chooseGetId(opts);
|
|
|
|
opts.loopRequired = opts.loopRequired || Infinity;
|
|
if (opts.errorDataPath == 'property') opts._errorDataPathProperty = true;
|
|
if (opts.serialize === undefined) opts.serialize = stableStringify;
|
|
this._metaOpts = getMetaSchemaOptions(this);
|
|
|
|
if (opts.formats) addInitialFormats(this);
|
|
if (opts.keywords) addInitialKeywords(this);
|
|
addDefaultMetaSchema(this);
|
|
if (typeof opts.meta == 'object') this.addMetaSchema(opts.meta);
|
|
if (opts.nullable) this.addKeyword('nullable', {metaSchema: {type: 'boolean'}});
|
|
addInitialSchemas(this);
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* Validate data using schema
|
|
* Schema will be compiled and cached (using serialized JSON as key. [fast-json-stable-stringify](https://github.com/epoberezkin/fast-json-stable-stringify) is used to serialize.
|
|
* @this Ajv
|
|
* @param {String|Object} schemaKeyRef key, ref or schema object
|
|
* @param {Any} data to be validated
|
|
* @return {Boolean} validation result. Errors from the last validation will be available in `ajv.errors` (and also in compiled schema: `schema.errors`).
|
|
*/
|
|
function validate(schemaKeyRef, data) {
|
|
var v;
|
|
if (typeof schemaKeyRef == 'string') {
|
|
v = this.getSchema(schemaKeyRef);
|
|
if (!v) throw new Error('no schema with key or ref "' + schemaKeyRef + '"');
|
|
} else {
|
|
var schemaObj = this._addSchema(schemaKeyRef);
|
|
v = schemaObj.validate || this._compile(schemaObj);
|
|
}
|
|
|
|
var valid = v(data);
|
|
if (v.$async !== true) this.errors = v.errors;
|
|
return valid;
|
|
}
|
|
|
|
|
|
/**
|
|
* Create validating function for passed schema.
|
|
* @this Ajv
|
|
* @param {Object} schema schema object
|
|
* @param {Boolean} _meta true if schema is a meta-schema. Used internally to compile meta schemas of custom keywords.
|
|
* @return {Function} validating function
|
|
*/
|
|
function compile(schema, _meta) {
|
|
var schemaObj = this._addSchema(schema, undefined, _meta);
|
|
return schemaObj.validate || this._compile(schemaObj);
|
|
}
|
|
|
|
|
|
/**
|
|
* Adds schema to the instance.
|
|
* @this Ajv
|
|
* @param {Object|Array} schema schema or array of schemas. If array is passed, `key` and other parameters will be ignored.
|
|
* @param {String} key Optional schema key. Can be passed to `validate` method instead of schema object or id/ref. One schema per instance can have empty `id` and `key`.
|
|
* @param {Boolean} _skipValidation true to skip schema validation. Used internally, option validateSchema should be used instead.
|
|
* @param {Boolean} _meta true if schema is a meta-schema. Used internally, addMetaSchema should be used instead.
|
|
* @return {Ajv} this for method chaining
|
|
*/
|
|
function addSchema(schema, key, _skipValidation, _meta) {
|
|
if (Array.isArray(schema)){
|
|
for (var i=0; i<schema.length; i++) this.addSchema(schema[i], undefined, _skipValidation, _meta);
|
|
return this;
|
|
}
|
|
var id = this._getId(schema);
|
|
if (id !== undefined && typeof id != 'string')
|
|
throw new Error('schema id must be string');
|
|
key = resolve.normalizeId(key || id);
|
|
checkUnique(this, key);
|
|
this._schemas[key] = this._addSchema(schema, _skipValidation, _meta, true);
|
|
return this;
|
|
}
|
|
|
|
|
|
/**
|
|
* Add schema that will be used to validate other schemas
|
|
* options in META_IGNORE_OPTIONS are alway set to false
|
|
* @this Ajv
|
|
* @param {Object} schema schema object
|
|
* @param {String} key optional schema key
|
|
* @param {Boolean} skipValidation true to skip schema validation, can be used to override validateSchema option for meta-schema
|
|
* @return {Ajv} this for method chaining
|
|
*/
|
|
function addMetaSchema(schema, key, skipValidation) {
|
|
this.addSchema(schema, key, skipValidation, true);
|
|
return this;
|
|
}
|
|
|
|
|
|
/**
|
|
* Validate schema
|
|
* @this Ajv
|
|
* @param {Object} schema schema to validate
|
|
* @param {Boolean} throwOrLogError pass true to throw (or log) an error if invalid
|
|
* @return {Boolean} true if schema is valid
|
|
*/
|
|
function validateSchema(schema, throwOrLogError) {
|
|
var $schema = schema.$schema;
|
|
if ($schema !== undefined && typeof $schema != 'string')
|
|
throw new Error('$schema must be a string');
|
|
$schema = $schema || this._opts.defaultMeta || defaultMeta(this);
|
|
if (!$schema) {
|
|
this.logger.warn('meta-schema not available');
|
|
this.errors = null;
|
|
return true;
|
|
}
|
|
var valid = this.validate($schema, schema);
|
|
if (!valid && throwOrLogError) {
|
|
var message = 'schema is invalid: ' + this.errorsText();
|
|
if (this._opts.validateSchema == 'log') this.logger.error(message);
|
|
else throw new Error(message);
|
|
}
|
|
return valid;
|
|
}
|
|
|
|
|
|
function defaultMeta(self) {
|
|
var meta = self._opts.meta;
|
|
self._opts.defaultMeta = typeof meta == 'object'
|
|
? self._getId(meta) || meta
|
|
: self.getSchema(META_SCHEMA_ID)
|
|
? META_SCHEMA_ID
|
|
: undefined;
|
|
return self._opts.defaultMeta;
|
|
}
|
|
|
|
|
|
/**
|
|
* Get compiled schema from the instance by `key` or `ref`.
|
|
* @this Ajv
|
|
* @param {String} keyRef `key` that was passed to `addSchema` or full schema reference (`schema.id` or resolved id).
|
|
* @return {Function} schema validating function (with property `schema`).
|
|
*/
|
|
function getSchema(keyRef) {
|
|
var schemaObj = _getSchemaObj(this, keyRef);
|
|
switch (typeof schemaObj) {
|
|
case 'object': return schemaObj.validate || this._compile(schemaObj);
|
|
case 'string': return this.getSchema(schemaObj);
|
|
case 'undefined': return _getSchemaFragment(this, keyRef);
|
|
}
|
|
}
|
|
|
|
|
|
function _getSchemaFragment(self, ref) {
|
|
var res = resolve.schema.call(self, { schema: {} }, ref);
|
|
if (res) {
|
|
var schema = res.schema
|
|
, root = res.root
|
|
, baseId = res.baseId;
|
|
var v = compileSchema.call(self, schema, root, undefined, baseId);
|
|
self._fragments[ref] = new SchemaObject({
|
|
ref: ref,
|
|
fragment: true,
|
|
schema: schema,
|
|
root: root,
|
|
baseId: baseId,
|
|
validate: v
|
|
});
|
|
return v;
|
|
}
|
|
}
|
|
|
|
|
|
function _getSchemaObj(self, keyRef) {
|
|
keyRef = resolve.normalizeId(keyRef);
|
|
return self._schemas[keyRef] || self._refs[keyRef] || self._fragments[keyRef];
|
|
}
|
|
|
|
|
|
/**
|
|
* Remove cached schema(s).
|
|
* If no parameter is passed all schemas but meta-schemas are removed.
|
|
* If RegExp is passed all schemas with key/id matching pattern but meta-schemas are removed.
|
|
* Even if schema is referenced by other schemas it still can be removed as other schemas have local references.
|
|
* @this Ajv
|
|
* @param {String|Object|RegExp} schemaKeyRef key, ref, pattern to match key/ref or schema object
|
|
* @return {Ajv} this for method chaining
|
|
*/
|
|
function removeSchema(schemaKeyRef) {
|
|
if (schemaKeyRef instanceof RegExp) {
|
|
_removeAllSchemas(this, this._schemas, schemaKeyRef);
|
|
_removeAllSchemas(this, this._refs, schemaKeyRef);
|
|
return this;
|
|
}
|
|
switch (typeof schemaKeyRef) {
|
|
case 'undefined':
|
|
_removeAllSchemas(this, this._schemas);
|
|
_removeAllSchemas(this, this._refs);
|
|
this._cache.clear();
|
|
return this;
|
|
case 'string':
|
|
var schemaObj = _getSchemaObj(this, schemaKeyRef);
|
|
if (schemaObj) this._cache.del(schemaObj.cacheKey);
|
|
delete this._schemas[schemaKeyRef];
|
|
delete this._refs[schemaKeyRef];
|
|
return this;
|
|
case 'object':
|
|
var serialize = this._opts.serialize;
|
|
var cacheKey = serialize ? serialize(schemaKeyRef) : schemaKeyRef;
|
|
this._cache.del(cacheKey);
|
|
var id = this._getId(schemaKeyRef);
|
|
if (id) {
|
|
id = resolve.normalizeId(id);
|
|
delete this._schemas[id];
|
|
delete this._refs[id];
|
|
}
|
|
}
|
|
return this;
|
|
}
|
|
|
|
|
|
function _removeAllSchemas(self, schemas, regex) {
|
|
for (var keyRef in schemas) {
|
|
var schemaObj = schemas[keyRef];
|
|
if (!schemaObj.meta && (!regex || regex.test(keyRef))) {
|
|
self._cache.del(schemaObj.cacheKey);
|
|
delete schemas[keyRef];
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* @this Ajv */
|
|
function _addSchema(schema, skipValidation, meta, shouldAddSchema) {
|
|
if (typeof schema != 'object' && typeof schema != 'boolean')
|
|
throw new Error('schema should be object or boolean');
|
|
var serialize = this._opts.serialize;
|
|
var cacheKey = serialize ? serialize(schema) : schema;
|
|
var cached = this._cache.get(cacheKey);
|
|
if (cached) return cached;
|
|
|
|
shouldAddSchema = shouldAddSchema || this._opts.addUsedSchema !== false;
|
|
|
|
var id = resolve.normalizeId(this._getId(schema));
|
|
if (id && shouldAddSchema) checkUnique(this, id);
|
|
|
|
var willValidate = this._opts.validateSchema !== false && !skipValidation;
|
|
var recursiveMeta;
|
|
if (willValidate && !(recursiveMeta = id && id == resolve.normalizeId(schema.$schema)))
|
|
this.validateSchema(schema, true);
|
|
|
|
var localRefs = resolve.ids.call(this, schema);
|
|
|
|
var schemaObj = new SchemaObject({
|
|
id: id,
|
|
schema: schema,
|
|
localRefs: localRefs,
|
|
cacheKey: cacheKey,
|
|
meta: meta
|
|
});
|
|
|
|
if (id[0] != '#' && shouldAddSchema) this._refs[id] = schemaObj;
|
|
this._cache.put(cacheKey, schemaObj);
|
|
|
|
if (willValidate && recursiveMeta) this.validateSchema(schema, true);
|
|
|
|
return schemaObj;
|
|
}
|
|
|
|
|
|
/* @this Ajv */
|
|
function _compile(schemaObj, root) {
|
|
if (schemaObj.compiling) {
|
|
schemaObj.validate = callValidate;
|
|
callValidate.schema = schemaObj.schema;
|
|
callValidate.errors = null;
|
|
callValidate.root = root ? root : callValidate;
|
|
if (schemaObj.schema.$async === true)
|
|
callValidate.$async = true;
|
|
return callValidate;
|
|
}
|
|
schemaObj.compiling = true;
|
|
|
|
var currentOpts;
|
|
if (schemaObj.meta) {
|
|
currentOpts = this._opts;
|
|
this._opts = this._metaOpts;
|
|
}
|
|
|
|
var v;
|
|
try { v = compileSchema.call(this, schemaObj.schema, root, schemaObj.localRefs); }
|
|
catch(e) {
|
|
delete schemaObj.validate;
|
|
throw e;
|
|
}
|
|
finally {
|
|
schemaObj.compiling = false;
|
|
if (schemaObj.meta) this._opts = currentOpts;
|
|
}
|
|
|
|
schemaObj.validate = v;
|
|
schemaObj.refs = v.refs;
|
|
schemaObj.refVal = v.refVal;
|
|
schemaObj.root = v.root;
|
|
return v;
|
|
|
|
|
|
/* @this {*} - custom context, see passContext option */
|
|
function callValidate() {
|
|
/* jshint validthis: true */
|
|
var _validate = schemaObj.validate;
|
|
var result = _validate.apply(this, arguments);
|
|
callValidate.errors = _validate.errors;
|
|
return result;
|
|
}
|
|
}
|
|
|
|
|
|
function chooseGetId(opts) {
|
|
switch (opts.schemaId) {
|
|
case 'auto': return _get$IdOrId;
|
|
case 'id': return _getId;
|
|
default: return _get$Id;
|
|
}
|
|
}
|
|
|
|
/* @this Ajv */
|
|
function _getId(schema) {
|
|
if (schema.$id) this.logger.warn('schema $id ignored', schema.$id);
|
|
return schema.id;
|
|
}
|
|
|
|
/* @this Ajv */
|
|
function _get$Id(schema) {
|
|
if (schema.id) this.logger.warn('schema id ignored', schema.id);
|
|
return schema.$id;
|
|
}
|
|
|
|
|
|
function _get$IdOrId(schema) {
|
|
if (schema.$id && schema.id && schema.$id != schema.id)
|
|
throw new Error('schema $id is different from id');
|
|
return schema.$id || schema.id;
|
|
}
|
|
|
|
|
|
/**
|
|
* Convert array of error message objects to string
|
|
* @this Ajv
|
|
* @param {Array<Object>} errors optional array of validation errors, if not passed errors from the instance are used.
|
|
* @param {Object} options optional options with properties `separator` and `dataVar`.
|
|
* @return {String} human readable string with all errors descriptions
|
|
*/
|
|
function errorsText(errors, options) {
|
|
errors = errors || this.errors;
|
|
if (!errors) return 'No errors';
|
|
options = options || {};
|
|
var separator = options.separator === undefined ? ', ' : options.separator;
|
|
var dataVar = options.dataVar === undefined ? 'data' : options.dataVar;
|
|
|
|
var text = '';
|
|
for (var i=0; i<errors.length; i++) {
|
|
var e = errors[i];
|
|
if (e) text += dataVar + e.dataPath + ' ' + e.message + separator;
|
|
}
|
|
return text.slice(0, -separator.length);
|
|
}
|
|
|
|
|
|
/**
|
|
* Add custom format
|
|
* @this Ajv
|
|
* @param {String} name format name
|
|
* @param {String|RegExp|Function} format string is converted to RegExp; function should return boolean (true when valid)
|
|
* @return {Ajv} this for method chaining
|
|
*/
|
|
function addFormat(name, format) {
|
|
if (typeof format == 'string') format = new RegExp(format);
|
|
this._formats[name] = format;
|
|
return this;
|
|
}
|
|
|
|
|
|
function addDefaultMetaSchema(self) {
|
|
var $dataSchema;
|
|
if (self._opts.$data) {
|
|
$dataSchema = __webpack_require__(6835);
|
|
self.addMetaSchema($dataSchema, $dataSchema.$id, true);
|
|
}
|
|
if (self._opts.meta === false) return;
|
|
var metaSchema = __webpack_require__(38);
|
|
if (self._opts.$data) metaSchema = $dataMetaSchema(metaSchema, META_SUPPORT_DATA);
|
|
self.addMetaSchema(metaSchema, META_SCHEMA_ID, true);
|
|
self._refs['http://json-schema.org/schema'] = META_SCHEMA_ID;
|
|
}
|
|
|
|
|
|
function addInitialSchemas(self) {
|
|
var optsSchemas = self._opts.schemas;
|
|
if (!optsSchemas) return;
|
|
if (Array.isArray(optsSchemas)) self.addSchema(optsSchemas);
|
|
else for (var key in optsSchemas) self.addSchema(optsSchemas[key], key);
|
|
}
|
|
|
|
|
|
function addInitialFormats(self) {
|
|
for (var name in self._opts.formats) {
|
|
var format = self._opts.formats[name];
|
|
self.addFormat(name, format);
|
|
}
|
|
}
|
|
|
|
|
|
function addInitialKeywords(self) {
|
|
for (var name in self._opts.keywords) {
|
|
var keyword = self._opts.keywords[name];
|
|
self.addKeyword(name, keyword);
|
|
}
|
|
}
|
|
|
|
|
|
function checkUnique(self, id) {
|
|
if (self._schemas[id] || self._refs[id])
|
|
throw new Error('schema with key or id "' + id + '" already exists');
|
|
}
|
|
|
|
|
|
function getMetaSchemaOptions(self) {
|
|
var metaOpts = util.copy(self._opts);
|
|
for (var i=0; i<META_IGNORE_OPTIONS.length; i++)
|
|
delete metaOpts[META_IGNORE_OPTIONS[i]];
|
|
return metaOpts;
|
|
}
|
|
|
|
|
|
function setLogger(self) {
|
|
var logger = self._opts.logger;
|
|
if (logger === false) {
|
|
self.logger = {log: noop, warn: noop, error: noop};
|
|
} else {
|
|
if (logger === undefined) logger = console;
|
|
if (!(typeof logger == 'object' && logger.log && logger.warn && logger.error))
|
|
throw new Error('logger must implement log, warn and error methods');
|
|
self.logger = logger;
|
|
}
|
|
}
|
|
|
|
|
|
function noop() {}
|
|
|
|
|
|
/***/ }),
|
|
|
|
/***/ 5255:
|
|
/***/ (function(module) {
|
|
|
|
"use strict";
|
|
|
|
|
|
|
|
var Cache = module.exports = function Cache() {
|
|
this._cache = {};
|
|
};
|
|
|
|
|
|
Cache.prototype.put = function Cache_put(key, value) {
|
|
this._cache[key] = value;
|
|
};
|
|
|
|
|
|
Cache.prototype.get = function Cache_get(key) {
|
|
return this._cache[key];
|
|
};
|
|
|
|
|
|
Cache.prototype.del = function Cache_del(key) {
|
|
delete this._cache[key];
|
|
};
|
|
|
|
|
|
Cache.prototype.clear = function Cache_clear() {
|
|
this._cache = {};
|
|
};
|
|
|
|
|
|
/***/ }),
|
|
|
|
/***/ 9677:
|
|
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
|
|
|
|
"use strict";
|
|
|
|
|
|
var MissingRefError = __webpack_require__(5359).MissingRef;
|
|
|
|
module.exports = compileAsync;
|
|
|
|
|
|
/**
|
|
* Creates validating function for passed schema with asynchronous loading of missing schemas.
|
|
* `loadSchema` option should be a function that accepts schema uri and returns promise that resolves with the schema.
|
|
* @this Ajv
|
|
* @param {Object} schema schema object
|
|
* @param {Boolean} meta optional true to compile meta-schema; this parameter can be skipped
|
|
* @param {Function} callback an optional node-style callback, it is called with 2 parameters: error (or null) and validating function.
|
|
* @return {Promise} promise that resolves with a validating function.
|
|
*/
|
|
function compileAsync(schema, meta, callback) {
|
|
/* eslint no-shadow: 0 */
|
|
/* global Promise */
|
|
/* jshint validthis: true */
|
|
var self = this;
|
|
if (typeof this._opts.loadSchema != 'function')
|
|
throw new Error('options.loadSchema should be a function');
|
|
|
|
if (typeof meta == 'function') {
|
|
callback = meta;
|
|
meta = undefined;
|
|
}
|
|
|
|
var p = loadMetaSchemaOf(schema).then(function () {
|
|
var schemaObj = self._addSchema(schema, undefined, meta);
|
|
return schemaObj.validate || _compileAsync(schemaObj);
|
|
});
|
|
|
|
if (callback) {
|
|
p.then(
|
|
function(v) { callback(null, v); },
|
|
callback
|
|
);
|
|
}
|
|
|
|
return p;
|
|
|
|
|
|
function loadMetaSchemaOf(sch) {
|
|
var $schema = sch.$schema;
|
|
return $schema && !self.getSchema($schema)
|
|
? compileAsync.call(self, { $ref: $schema }, true)
|
|
: Promise.resolve();
|
|
}
|
|
|
|
|
|
function _compileAsync(schemaObj) {
|
|
try { return self._compile(schemaObj); }
|
|
catch(e) {
|
|
if (e instanceof MissingRefError) return loadMissingSchema(e);
|
|
throw e;
|
|
}
|
|
|
|
|
|
function loadMissingSchema(e) {
|
|
var ref = e.missingSchema;
|
|
if (added(ref)) throw new Error('Schema ' + ref + ' is loaded but ' + e.missingRef + ' cannot be resolved');
|
|
|
|
var schemaPromise = self._loadingSchemas[ref];
|
|
if (!schemaPromise) {
|
|
schemaPromise = self._loadingSchemas[ref] = self._opts.loadSchema(ref);
|
|
schemaPromise.then(removePromise, removePromise);
|
|
}
|
|
|
|
return schemaPromise.then(function (sch) {
|
|
if (!added(ref)) {
|
|
return loadMetaSchemaOf(sch).then(function () {
|
|
if (!added(ref)) self.addSchema(sch, ref, undefined, meta);
|
|
});
|
|
}
|
|
}).then(function() {
|
|
return _compileAsync(schemaObj);
|
|
});
|
|
|
|
function removePromise() {
|
|
delete self._loadingSchemas[ref];
|
|
}
|
|
|
|
function added(ref) {
|
|
return self._refs[ref] || self._schemas[ref];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***/ }),
|
|
|
|
/***/ 5359:
|
|
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
|
|
|
|
"use strict";
|
|
|
|
|
|
var resolve = __webpack_require__(3969);
|
|
|
|
module.exports = {
|
|
Validation: errorSubclass(ValidationError),
|
|
MissingRef: errorSubclass(MissingRefError)
|
|
};
|
|
|
|
|
|
function ValidationError(errors) {
|
|
this.message = 'validation failed';
|
|
this.errors = errors;
|
|
this.ajv = this.validation = true;
|
|
}
|
|
|
|
|
|
MissingRefError.message = function (baseId, ref) {
|
|
return 'can\'t resolve reference ' + ref + ' from id ' + baseId;
|
|
};
|
|
|
|
|
|
function MissingRefError(baseId, ref, message) {
|
|
this.message = message || MissingRefError.message(baseId, ref);
|
|
this.missingRef = resolve.url(baseId, ref);
|
|
this.missingSchema = resolve.normalizeId(resolve.fullPath(this.missingRef));
|
|
}
|
|
|
|
|
|
function errorSubclass(Subclass) {
|
|
Subclass.prototype = Object.create(Error.prototype);
|
|
Subclass.prototype.constructor = Subclass;
|
|
return Subclass;
|
|
}
|
|
|
|
|
|
/***/ }),
|
|
|
|
/***/ 3368:
|
|
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
|
|
|
|
"use strict";
|
|
|
|
|
|
var util = __webpack_require__(3724);
|
|
|
|
var DATE = /^(\d\d\d\d)-(\d\d)-(\d\d)$/;
|
|
var DAYS = [0,31,28,31,30,31,30,31,31,30,31,30,31];
|
|
var TIME = /^(\d\d):(\d\d):(\d\d)(\.\d+)?(z|[+-]\d\d(?::?\d\d)?)?$/i;
|
|
var HOSTNAME = /^(?=.{1,253}\.?$)[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[-0-9a-z]{0,61}[0-9a-z])?)*\.?$/i;
|
|
var URI = /^(?:[a-z][a-z0-9+\-.]*:)(?:\/?\/(?:(?:[a-z0-9\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|[Vv][0-9a-f]+\.[a-z0-9\-._~!$&'()*+,;=:]+)\]|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)|(?:[a-z0-9\-._~!$&'()*+,;=]|%[0-9a-f]{2})*)(?::\d*)?(?:\/(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*|\/(?:(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?|(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)(?:\?(?:[a-z0-9\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?$/i;
|
|
var URIREF = /^(?:[a-z][a-z0-9+\-.]*:)?(?:\/?\/(?:(?:[a-z0-9\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|[Vv][0-9a-f]+\.[a-z0-9\-._~!$&'()*+,;=:]+)\]|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)|(?:[a-z0-9\-._~!$&'"()*+,;=]|%[0-9a-f]{2})*)(?::\d*)?(?:\/(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})*)*|\/(?:(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})*)*)?|(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})*)*)?(?:\?(?:[a-z0-9\-._~!$&'"()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\-._~!$&'"()*+,;=:@/?]|%[0-9a-f]{2})*)?$/i;
|
|
// uri-template: https://tools.ietf.org/html/rfc6570
|
|
var URITEMPLATE = /^(?:(?:[^\x00-\x20"'<>%\\^`{|}]|%[0-9a-f]{2})|\{[+#./;?&=,!@|]?(?:[a-z0-9_]|%[0-9a-f]{2})+(?::[1-9][0-9]{0,3}|\*)?(?:,(?:[a-z0-9_]|%[0-9a-f]{2})+(?::[1-9][0-9]{0,3}|\*)?)*\})*$/i;
|
|
// For the source: https://gist.github.com/dperini/729294
|
|
// For test cases: https://mathiasbynens.be/demo/url-regex
|
|
// @todo Delete current URL in favour of the commented out URL rule when this issue is fixed https://github.com/eslint/eslint/issues/7983.
|
|
// var URL = /^(?:(?:https?|ftp):\/\/)(?:\S+(?::\S*)?@)?(?:(?!10(?:\.\d{1,3}){3})(?!127(?:\.\d{1,3}){3})(?!169\.254(?:\.\d{1,3}){2})(?!192\.168(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u{00a1}-\u{ffff}0-9]+-)*[a-z\u{00a1}-\u{ffff}0-9]+)(?:\.(?:[a-z\u{00a1}-\u{ffff}0-9]+-)*[a-z\u{00a1}-\u{ffff}0-9]+)*(?:\.(?:[a-z\u{00a1}-\u{ffff}]{2,})))(?::\d{2,5})?(?:\/[^\s]*)?$/iu;
|
|
var URL = /^(?:(?:http[s\u017F]?|ftp):\/\/)(?:(?:[\0-\x08\x0E-\x1F!-\x9F\xA1-\u167F\u1681-\u1FFF\u200B-\u2027\u202A-\u202E\u2030-\u205E\u2060-\u2FFF\u3001-\uD7FF\uE000-\uFEFE\uFF00-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])+(?::(?:[\0-\x08\x0E-\x1F!-\x9F\xA1-\u167F\u1681-\u1FFF\u200B-\u2027\u202A-\u202E\u2030-\u205E\u2060-\u2FFF\u3001-\uD7FF\uE000-\uFEFE\uFF00-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])*)?@)?(?:(?!10(?:\.[0-9]{1,3}){3})(?!127(?:\.[0-9]{1,3}){3})(?!169\.254(?:\.[0-9]{1,3}){2})(?!192\.168(?:\.[0-9]{1,3}){2})(?!172\.(?:1[6-9]|2[0-9]|3[01])(?:\.[0-9]{1,3}){2})(?:[1-9][0-9]?|1[0-9][0-9]|2[01][0-9]|22[0-3])(?:\.(?:1?[0-9]{1,2}|2[0-4][0-9]|25[0-5])){2}(?:\.(?:[1-9][0-9]?|1[0-9][0-9]|2[0-4][0-9]|25[0-4]))|(?:(?:(?:[0-9a-z\xA1-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])+-)*(?:[0-9a-z\xA1-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])+)(?:\.(?:(?:[0-9a-z\xA1-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])+-)*(?:[0-9a-z\xA1-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])+)*(?:\.(?:(?:[a-z\xA1-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]){2,})))(?::[0-9]{2,5})?(?:\/(?:[\0-\x08\x0E-\x1F!-\x9F\xA1-\u167F\u1681-\u1FFF\u200B-\u2027\u202A-\u202E\u2030-\u205E\u2060-\u2FFF\u3001-\uD7FF\uE000-\uFEFE\uFF00-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])*)?$/i;
|
|
var UUID = /^(?:urn:uuid:)?[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12}$/i;
|
|
var JSON_POINTER = /^(?:\/(?:[^~/]|~0|~1)*)*$/;
|
|
var JSON_POINTER_URI_FRAGMENT = /^#(?:\/(?:[a-z0-9_\-.!$&'()*+,;:=@]|%[0-9a-f]{2}|~0|~1)*)*$/i;
|
|
var RELATIVE_JSON_POINTER = /^(?:0|[1-9][0-9]*)(?:#|(?:\/(?:[^~/]|~0|~1)*)*)$/;
|
|
|
|
|
|
module.exports = formats;
|
|
|
|
function formats(mode) {
|
|
mode = mode == 'full' ? 'full' : 'fast';
|
|
return util.copy(formats[mode]);
|
|
}
|
|
|
|
|
|
formats.fast = {
|
|
// date: http://tools.ietf.org/html/rfc3339#section-5.6
|
|
date: /^\d\d\d\d-[0-1]\d-[0-3]\d$/,
|
|
// date-time: http://tools.ietf.org/html/rfc3339#section-5.6
|
|
time: /^(?:[0-2]\d:[0-5]\d:[0-5]\d|23:59:60)(?:\.\d+)?(?:z|[+-]\d\d(?::?\d\d)?)?$/i,
|
|
'date-time': /^\d\d\d\d-[0-1]\d-[0-3]\d[t\s](?:[0-2]\d:[0-5]\d:[0-5]\d|23:59:60)(?:\.\d+)?(?:z|[+-]\d\d(?::?\d\d)?)$/i,
|
|
// uri: https://github.com/mafintosh/is-my-json-valid/blob/master/formats.js
|
|
uri: /^(?:[a-z][a-z0-9+\-.]*:)(?:\/?\/)?[^\s]*$/i,
|
|
'uri-reference': /^(?:(?:[a-z][a-z0-9+\-.]*:)?\/?\/)?(?:[^\\\s#][^\s#]*)?(?:#[^\\\s]*)?$/i,
|
|
'uri-template': URITEMPLATE,
|
|
url: URL,
|
|
// email (sources from jsen validator):
|
|
// http://stackoverflow.com/questions/201323/using-a-regular-expression-to-validate-an-email-address#answer-8829363
|
|
// http://www.w3.org/TR/html5/forms.html#valid-e-mail-address (search for 'willful violation')
|
|
email: /^[a-z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)*$/i,
|
|
hostname: HOSTNAME,
|
|
// optimized https://www.safaribooksonline.com/library/view/regular-expressions-cookbook/9780596802837/ch07s16.html
|
|
ipv4: /^(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)$/,
|
|
// optimized http://stackoverflow.com/questions/53497/regular-expression-that-matches-valid-ipv6-addresses
|
|
ipv6: /^\s*(?:(?:(?:[0-9a-f]{1,4}:){7}(?:[0-9a-f]{1,4}|:))|(?:(?:[0-9a-f]{1,4}:){6}(?::[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(?:(?:[0-9a-f]{1,4}:){5}(?:(?:(?::[0-9a-f]{1,4}){1,2})|:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(?:(?:[0-9a-f]{1,4}:){4}(?:(?:(?::[0-9a-f]{1,4}){1,3})|(?:(?::[0-9a-f]{1,4})?:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){3}(?:(?:(?::[0-9a-f]{1,4}){1,4})|(?:(?::[0-9a-f]{1,4}){0,2}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){2}(?:(?:(?::[0-9a-f]{1,4}){1,5})|(?:(?::[0-9a-f]{1,4}){0,3}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){1}(?:(?:(?::[0-9a-f]{1,4}){1,6})|(?:(?::[0-9a-f]{1,4}){0,4}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?::(?:(?:(?::[0-9a-f]{1,4}){1,7})|(?:(?::[0-9a-f]{1,4}){0,5}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(?:%.+)?\s*$/i,
|
|
regex: regex,
|
|
// uuid: http://tools.ietf.org/html/rfc4122
|
|
uuid: UUID,
|
|
// JSON-pointer: https://tools.ietf.org/html/rfc6901
|
|
// uri fragment: https://tools.ietf.org/html/rfc3986#appendix-A
|
|
'json-pointer': JSON_POINTER,
|
|
'json-pointer-uri-fragment': JSON_POINTER_URI_FRAGMENT,
|
|
// relative JSON-pointer: http://tools.ietf.org/html/draft-luff-relative-json-pointer-00
|
|
'relative-json-pointer': RELATIVE_JSON_POINTER
|
|
};
|
|
|
|
|
|
formats.full = {
|
|
date: date,
|
|
time: time,
|
|
'date-time': date_time,
|
|
uri: uri,
|
|
'uri-reference': URIREF,
|
|
'uri-template': URITEMPLATE,
|
|
url: URL,
|
|
email: /^[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i,
|
|
hostname: HOSTNAME,
|
|
ipv4: /^(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)$/,
|
|
ipv6: /^\s*(?:(?:(?:[0-9a-f]{1,4}:){7}(?:[0-9a-f]{1,4}|:))|(?:(?:[0-9a-f]{1,4}:){6}(?::[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(?:(?:[0-9a-f]{1,4}:){5}(?:(?:(?::[0-9a-f]{1,4}){1,2})|:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(?:(?:[0-9a-f]{1,4}:){4}(?:(?:(?::[0-9a-f]{1,4}){1,3})|(?:(?::[0-9a-f]{1,4})?:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){3}(?:(?:(?::[0-9a-f]{1,4}){1,4})|(?:(?::[0-9a-f]{1,4}){0,2}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){2}(?:(?:(?::[0-9a-f]{1,4}){1,5})|(?:(?::[0-9a-f]{1,4}){0,3}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){1}(?:(?:(?::[0-9a-f]{1,4}){1,6})|(?:(?::[0-9a-f]{1,4}){0,4}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?::(?:(?:(?::[0-9a-f]{1,4}){1,7})|(?:(?::[0-9a-f]{1,4}){0,5}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(?:%.+)?\s*$/i,
|
|
regex: regex,
|
|
uuid: UUID,
|
|
'json-pointer': JSON_POINTER,
|
|
'json-pointer-uri-fragment': JSON_POINTER_URI_FRAGMENT,
|
|
'relative-json-pointer': RELATIVE_JSON_POINTER
|
|
};
|
|
|
|
|
|
function isLeapYear(year) {
|
|
// https://tools.ietf.org/html/rfc3339#appendix-C
|
|
return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
|
|
}
|
|
|
|
|
|
function date(str) {
|
|
// full-date from http://tools.ietf.org/html/rfc3339#section-5.6
|
|
var matches = str.match(DATE);
|
|
if (!matches) return false;
|
|
|
|
var year = +matches[1];
|
|
var month = +matches[2];
|
|
var day = +matches[3];
|
|
|
|
return month >= 1 && month <= 12 && day >= 1 &&
|
|
day <= (month == 2 && isLeapYear(year) ? 29 : DAYS[month]);
|
|
}
|
|
|
|
|
|
function time(str, full) {
|
|
var matches = str.match(TIME);
|
|
if (!matches) return false;
|
|
|
|
var hour = matches[1];
|
|
var minute = matches[2];
|
|
var second = matches[3];
|
|
var timeZone = matches[5];
|
|
return ((hour <= 23 && minute <= 59 && second <= 59) ||
|
|
(hour == 23 && minute == 59 && second == 60)) &&
|
|
(!full || timeZone);
|
|
}
|
|
|
|
|
|
var DATE_TIME_SEPARATOR = /t|\s/i;
|
|
function date_time(str) {
|
|
// http://tools.ietf.org/html/rfc3339#section-5.6
|
|
var dateTime = str.split(DATE_TIME_SEPARATOR);
|
|
return dateTime.length == 2 && date(dateTime[0]) && time(dateTime[1], true);
|
|
}
|
|
|
|
|
|
var NOT_URI_FRAGMENT = /\/|:/;
|
|
function uri(str) {
|
|
// http://jmrware.com/articles/2009/uri_regexp/URI_regex.html + optional protocol + required "."
|
|
return NOT_URI_FRAGMENT.test(str) && URI.test(str);
|
|
}
|
|
|
|
|
|
var Z_ANCHOR = /[^\\]\\Z/;
|
|
function regex(str) {
|
|
if (Z_ANCHOR.test(str)) return false;
|
|
try {
|
|
new RegExp(str);
|
|
return true;
|
|
} catch(e) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
/***/ }),
|
|
|
|
/***/ 5689:
|
|
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
|
|
|
|
"use strict";
|
|
|
|
|
|
var resolve = __webpack_require__(3969)
|
|
, util = __webpack_require__(3724)
|
|
, errorClasses = __webpack_require__(5359)
|
|
, stableStringify = __webpack_require__(3508);
|
|
|
|
var validateGenerator = __webpack_require__(1869);
|
|
|
|
/**
|
|
* Functions below are used inside compiled validations function
|
|
*/
|
|
|
|
var ucs2length = util.ucs2length;
|
|
var equal = __webpack_require__(2303);
|
|
|
|
// this error is thrown by async schemas to return validation errors via exception
|
|
var ValidationError = errorClasses.Validation;
|
|
|
|
module.exports = compile;
|
|
|
|
|
|
/**
|
|
* Compiles schema to validation function
|
|
* @this Ajv
|
|
* @param {Object} schema schema object
|
|
* @param {Object} root object with information about the root schema for this schema
|
|
* @param {Object} localRefs the hash of local references inside the schema (created by resolve.id), used for inline resolution
|
|
* @param {String} baseId base ID for IDs in the schema
|
|
* @return {Function} validation function
|
|
*/
|
|
function compile(schema, root, localRefs, baseId) {
|
|
/* jshint validthis: true, evil: true */
|
|
/* eslint no-shadow: 0 */
|
|
var self = this
|
|
, opts = this._opts
|
|
, refVal = [ undefined ]
|
|
, refs = {}
|
|
, patterns = []
|
|
, patternsHash = {}
|
|
, defaults = []
|
|
, defaultsHash = {}
|
|
, customRules = [];
|
|
|
|
root = root || { schema: schema, refVal: refVal, refs: refs };
|
|
|
|
var c = checkCompiling.call(this, schema, root, baseId);
|
|
var compilation = this._compilations[c.index];
|
|
if (c.compiling) return (compilation.callValidate = callValidate);
|
|
|
|
var formats = this._formats;
|
|
var RULES = this.RULES;
|
|
|
|
try {
|
|
var v = localCompile(schema, root, localRefs, baseId);
|
|
compilation.validate = v;
|
|
var cv = compilation.callValidate;
|
|
if (cv) {
|
|
cv.schema = v.schema;
|
|
cv.errors = null;
|
|
cv.refs = v.refs;
|
|
cv.refVal = v.refVal;
|
|
cv.root = v.root;
|
|
cv.$async = v.$async;
|
|
if (opts.sourceCode) cv.source = v.source;
|
|
}
|
|
return v;
|
|
} finally {
|
|
endCompiling.call(this, schema, root, baseId);
|
|
}
|
|
|
|
/* @this {*} - custom context, see passContext option */
|
|
function callValidate() {
|
|
/* jshint validthis: true */
|
|
var validate = compilation.validate;
|
|
var result = validate.apply(this, arguments);
|
|
callValidate.errors = validate.errors;
|
|
return result;
|
|
}
|
|
|
|
function localCompile(_schema, _root, localRefs, baseId) {
|
|
var isRoot = !_root || (_root && _root.schema == _schema);
|
|
if (_root.schema != root.schema)
|
|
return compile.call(self, _schema, _root, localRefs, baseId);
|
|
|
|
var $async = _schema.$async === true;
|
|
|
|
var sourceCode = validateGenerator({
|
|
isTop: true,
|
|
schema: _schema,
|
|
isRoot: isRoot,
|
|
baseId: baseId,
|
|
root: _root,
|
|
schemaPath: '',
|
|
errSchemaPath: '#',
|
|
errorPath: '""',
|
|
MissingRefError: errorClasses.MissingRef,
|
|
RULES: RULES,
|
|
validate: validateGenerator,
|
|
util: util,
|
|
resolve: resolve,
|
|
resolveRef: resolveRef,
|
|
usePattern: usePattern,
|
|
useDefault: useDefault,
|
|
useCustomRule: useCustomRule,
|
|
opts: opts,
|
|
formats: formats,
|
|
logger: self.logger,
|
|
self: self
|
|
});
|
|
|
|
sourceCode = vars(refVal, refValCode) + vars(patterns, patternCode)
|
|
+ vars(defaults, defaultCode) + vars(customRules, customRuleCode)
|
|
+ sourceCode;
|
|
|
|
if (opts.processCode) sourceCode = opts.processCode(sourceCode, _schema);
|
|
// console.log('\n\n\n *** \n', JSON.stringify(sourceCode));
|
|
var validate;
|
|
try {
|
|
var makeValidate = new Function(
|
|
'self',
|
|
'RULES',
|
|
'formats',
|
|
'root',
|
|
'refVal',
|
|
'defaults',
|
|
'customRules',
|
|
'equal',
|
|
'ucs2length',
|
|
'ValidationError',
|
|
sourceCode
|
|
);
|
|
|
|
validate = makeValidate(
|
|
self,
|
|
RULES,
|
|
formats,
|
|
root,
|
|
refVal,
|
|
defaults,
|
|
customRules,
|
|
equal,
|
|
ucs2length,
|
|
ValidationError
|
|
);
|
|
|
|
refVal[0] = validate;
|
|
} catch(e) {
|
|
self.logger.error('Error compiling schema, function code:', sourceCode);
|
|
throw e;
|
|
}
|
|
|
|
validate.schema = _schema;
|
|
validate.errors = null;
|
|
validate.refs = refs;
|
|
validate.refVal = refVal;
|
|
validate.root = isRoot ? validate : _root;
|
|
if ($async) validate.$async = true;
|
|
if (opts.sourceCode === true) {
|
|
validate.source = {
|
|
code: sourceCode,
|
|
patterns: patterns,
|
|
defaults: defaults
|
|
};
|
|
}
|
|
|
|
return validate;
|
|
}
|
|
|
|
function resolveRef(baseId, ref, isRoot) {
|
|
ref = resolve.url(baseId, ref);
|
|
var refIndex = refs[ref];
|
|
var _refVal, refCode;
|
|
if (refIndex !== undefined) {
|
|
_refVal = refVal[refIndex];
|
|
refCode = 'refVal[' + refIndex + ']';
|
|
return resolvedRef(_refVal, refCode);
|
|
}
|
|
if (!isRoot && root.refs) {
|
|
var rootRefId = root.refs[ref];
|
|
if (rootRefId !== undefined) {
|
|
_refVal = root.refVal[rootRefId];
|
|
refCode = addLocalRef(ref, _refVal);
|
|
return resolvedRef(_refVal, refCode);
|
|
}
|
|
}
|
|
|
|
refCode = addLocalRef(ref);
|
|
var v = resolve.call(self, localCompile, root, ref);
|
|
if (v === undefined) {
|
|
var localSchema = localRefs && localRefs[ref];
|
|
if (localSchema) {
|
|
v = resolve.inlineRef(localSchema, opts.inlineRefs)
|
|
? localSchema
|
|
: compile.call(self, localSchema, root, localRefs, baseId);
|
|
}
|
|
}
|
|
|
|
if (v === undefined) {
|
|
removeLocalRef(ref);
|
|
} else {
|
|
replaceLocalRef(ref, v);
|
|
return resolvedRef(v, refCode);
|
|
}
|
|
}
|
|
|
|
function addLocalRef(ref, v) {
|
|
var refId = refVal.length;
|
|
refVal[refId] = v;
|
|
refs[ref] = refId;
|
|
return 'refVal' + refId;
|
|
}
|
|
|
|
function removeLocalRef(ref) {
|
|
delete refs[ref];
|
|
}
|
|
|
|
function replaceLocalRef(ref, v) {
|
|
var refId = refs[ref];
|
|
refVal[refId] = v;
|
|
}
|
|
|
|
function resolvedRef(refVal, code) {
|
|
return typeof refVal == 'object' || typeof refVal == 'boolean'
|
|
? { code: code, schema: refVal, inline: true }
|
|
: { code: code, $async: refVal && !!refVal.$async };
|
|
}
|
|
|
|
function usePattern(regexStr) {
|
|
var index = patternsHash[regexStr];
|
|
if (index === undefined) {
|
|
index = patternsHash[regexStr] = patterns.length;
|
|
patterns[index] = regexStr;
|
|
}
|
|
return 'pattern' + index;
|
|
}
|
|
|
|
function useDefault(value) {
|
|
switch (typeof value) {
|
|
case 'boolean':
|
|
case 'number':
|
|
return '' + value;
|
|
case 'string':
|
|
return util.toQuotedString(value);
|
|
case 'object':
|
|
if (value === null) return 'null';
|
|
var valueStr = stableStringify(value);
|
|
var index = defaultsHash[valueStr];
|
|
if (index === undefined) {
|
|
index = defaultsHash[valueStr] = defaults.length;
|
|
defaults[index] = value;
|
|
}
|
|
return 'default' + index;
|
|
}
|
|
}
|
|
|
|
function useCustomRule(rule, schema, parentSchema, it) {
|
|
if (self._opts.validateSchema !== false) {
|
|
var deps = rule.definition.dependencies;
|
|
if (deps && !deps.every(function(keyword) {
|
|
return Object.prototype.hasOwnProperty.call(parentSchema, keyword);
|
|
}))
|
|
throw new Error('parent schema must have all required keywords: ' + deps.join(','));
|
|
|
|
var validateSchema = rule.definition.validateSchema;
|
|
if (validateSchema) {
|
|
var valid = validateSchema(schema);
|
|
if (!valid) {
|
|
var message = 'keyword schema is invalid: ' + self.errorsText(validateSchema.errors);
|
|
if (self._opts.validateSchema == 'log') self.logger.error(message);
|
|
else throw new Error(message);
|
|
}
|
|
}
|
|
}
|
|
|
|
var compile = rule.definition.compile
|
|
, inline = rule.definition.inline
|
|
, macro = rule.definition.macro;
|
|
|
|
var validate;
|
|
if (compile) {
|
|
validate = compile.call(self, schema, parentSchema, it);
|
|
} else if (macro) {
|
|
validate = macro.call(self, schema, parentSchema, it);
|
|
if (opts.validateSchema !== false) self.validateSchema(validate, true);
|
|
} else if (inline) {
|
|
validate = inline.call(self, it, rule.keyword, schema, parentSchema);
|
|
} else {
|
|
validate = rule.definition.validate;
|
|
if (!validate) return;
|
|
}
|
|
|
|
if (validate === undefined)
|
|
throw new Error('custom keyword "' + rule.keyword + '"failed to compile');
|
|
|
|
var index = customRules.length;
|
|
customRules[index] = validate;
|
|
|
|
return {
|
|
code: 'customRule' + index,
|
|
validate: validate
|
|
};
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Checks if the schema is currently compiled
|
|
* @this Ajv
|
|
* @param {Object} schema schema to compile
|
|
* @param {Object} root root object
|
|
* @param {String} baseId base schema ID
|
|
* @return {Object} object with properties "index" (compilation index) and "compiling" (boolean)
|
|
*/
|
|
function checkCompiling(schema, root, baseId) {
|
|
/* jshint validthis: true */
|
|
var index = compIndex.call(this, schema, root, baseId);
|
|
if (index >= 0) return { index: index, compiling: true };
|
|
index = this._compilations.length;
|
|
this._compilations[index] = {
|
|
schema: schema,
|
|
root: root,
|
|
baseId: baseId
|
|
};
|
|
return { index: index, compiling: false };
|
|
}
|
|
|
|
|
|
/**
|
|
* Removes the schema from the currently compiled list
|
|
* @this Ajv
|
|
* @param {Object} schema schema to compile
|
|
* @param {Object} root root object
|
|
* @param {String} baseId base schema ID
|
|
*/
|
|
function endCompiling(schema, root, baseId) {
|
|
/* jshint validthis: true */
|
|
var i = compIndex.call(this, schema, root, baseId);
|
|
if (i >= 0) this._compilations.splice(i, 1);
|
|
}
|
|
|
|
|
|
/**
|
|
* Index of schema compilation in the currently compiled list
|
|
* @this Ajv
|
|
* @param {Object} schema schema to compile
|
|
* @param {Object} root root object
|
|
* @param {String} baseId base schema ID
|
|
* @return {Integer} compilation index
|
|
*/
|
|
function compIndex(schema, root, baseId) {
|
|
/* jshint validthis: true */
|
|
for (var i=0; i<this._compilations.length; i++) {
|
|
var c = this._compilations[i];
|
|
if (c.schema == schema && c.root == root && c.baseId == baseId) return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
|
|
function patternCode(i, patterns) {
|
|
return 'var pattern' + i + ' = new RegExp(' + util.toQuotedString(patterns[i]) + ');';
|
|
}
|
|
|
|
|
|
function defaultCode(i) {
|
|
return 'var default' + i + ' = defaults[' + i + '];';
|
|
}
|
|
|
|
|
|
function refValCode(i, refVal) {
|
|
return refVal[i] === undefined ? '' : 'var refVal' + i + ' = refVal[' + i + '];';
|
|
}
|
|
|
|
|
|
function customRuleCode(i) {
|
|
return 'var customRule' + i + ' = customRules[' + i + '];';
|
|
}
|
|
|
|
|
|
function vars(arr, statement) {
|
|
if (!arr.length) return '';
|
|
var code = '';
|
|
for (var i=0; i<arr.length; i++)
|
|
code += statement(i, arr);
|
|
return code;
|
|
}
|
|
|
|
|
|
/***/ }),
|
|
|
|
/***/ 3969:
|
|
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
|
|
|
|
"use strict";
|
|
|
|
|
|
var URI = __webpack_require__(7533)
|
|
, equal = __webpack_require__(2303)
|
|
, util = __webpack_require__(3724)
|
|
, SchemaObject = __webpack_require__(4293)
|
|
, traverse = __webpack_require__(500);
|
|
|
|
module.exports = resolve;
|
|
|
|
resolve.normalizeId = normalizeId;
|
|
resolve.fullPath = getFullPath;
|
|
resolve.url = resolveUrl;
|
|
resolve.ids = resolveIds;
|
|
resolve.inlineRef = inlineRef;
|
|
resolve.schema = resolveSchema;
|
|
|
|
/**
|
|
* [resolve and compile the references ($ref)]
|
|
* @this Ajv
|
|
* @param {Function} compile reference to schema compilation funciton (localCompile)
|
|
* @param {Object} root object with information about the root schema for the current schema
|
|
* @param {String} ref reference to resolve
|
|
* @return {Object|Function} schema object (if the schema can be inlined) or validation function
|
|
*/
|
|
function resolve(compile, root, ref) {
|
|
/* jshint validthis: true */
|
|
var refVal = this._refs[ref];
|
|
if (typeof refVal == 'string') {
|
|
if (this._refs[refVal]) refVal = this._refs[refVal];
|
|
else return resolve.call(this, compile, root, refVal);
|
|
}
|
|
|
|
refVal = refVal || this._schemas[ref];
|
|
if (refVal instanceof SchemaObject) {
|
|
return inlineRef(refVal.schema, this._opts.inlineRefs)
|
|
? refVal.schema
|
|
: refVal.validate || this._compile(refVal);
|
|
}
|
|
|
|
var res = resolveSchema.call(this, root, ref);
|
|
var schema, v, baseId;
|
|
if (res) {
|
|
schema = res.schema;
|
|
root = res.root;
|
|
baseId = res.baseId;
|
|
}
|
|
|
|
if (schema instanceof SchemaObject) {
|
|
v = schema.validate || compile.call(this, schema.schema, root, undefined, baseId);
|
|
} else if (schema !== undefined) {
|
|
v = inlineRef(schema, this._opts.inlineRefs)
|
|
? schema
|
|
: compile.call(this, schema, root, undefined, baseId);
|
|
}
|
|
|
|
return v;
|
|
}
|
|
|
|
|
|
/**
|
|
* Resolve schema, its root and baseId
|
|
* @this Ajv
|
|
* @param {Object} root root object with properties schema, refVal, refs
|
|
* @param {String} ref reference to resolve
|
|
* @return {Object} object with properties schema, root, baseId
|
|
*/
|
|
function resolveSchema(root, ref) {
|
|
/* jshint validthis: true */
|
|
var p = URI.parse(ref)
|
|
, refPath = _getFullPath(p)
|
|
, baseId = getFullPath(this._getId(root.schema));
|
|
if (Object.keys(root.schema).length === 0 || refPath !== baseId) {
|
|
var id = normalizeId(refPath);
|
|
var refVal = this._refs[id];
|
|
if (typeof refVal == 'string') {
|
|
return resolveRecursive.call(this, root, refVal, p);
|
|
} else if (refVal instanceof SchemaObject) {
|
|
if (!refVal.validate) this._compile(refVal);
|
|
root = refVal;
|
|
} else {
|
|
refVal = this._schemas[id];
|
|
if (refVal instanceof SchemaObject) {
|
|
if (!refVal.validate) this._compile(refVal);
|
|
if (id == normalizeId(ref))
|
|
return { schema: refVal, root: root, baseId: baseId };
|
|
root = refVal;
|
|
} else {
|
|
return;
|
|
}
|
|
}
|
|
if (!root.schema) return;
|
|
baseId = getFullPath(this._getId(root.schema));
|
|
}
|
|
return getJsonPointer.call(this, p, baseId, root.schema, root);
|
|
}
|
|
|
|
|
|
/* @this Ajv */
|
|
function resolveRecursive(root, ref, parsedRef) {
|
|
/* jshint validthis: true */
|
|
var res = resolveSchema.call(this, root, ref);
|
|
if (res) {
|
|
var schema = res.schema;
|
|
var baseId = res.baseId;
|
|
root = res.root;
|
|
var id = this._getId(schema);
|
|
if (id) baseId = resolveUrl(baseId, id);
|
|
return getJsonPointer.call(this, parsedRef, baseId, schema, root);
|
|
}
|
|
}
|
|
|
|
|
|
var PREVENT_SCOPE_CHANGE = util.toHash(['properties', 'patternProperties', 'enum', 'dependencies', 'definitions']);
|
|
/* @this Ajv */
|
|
function getJsonPointer(parsedRef, baseId, schema, root) {
|
|
/* jshint validthis: true */
|
|
parsedRef.fragment = parsedRef.fragment || '';
|
|
if (parsedRef.fragment.slice(0,1) != '/') return;
|
|
var parts = parsedRef.fragment.split('/');
|
|
|
|
for (var i = 1; i < parts.length; i++) {
|
|
var part = parts[i];
|
|
if (part) {
|
|
part = util.unescapeFragment(part);
|
|
schema = schema[part];
|
|
if (schema === undefined) break;
|
|
var id;
|
|
if (!PREVENT_SCOPE_CHANGE[part]) {
|
|
id = this._getId(schema);
|
|
if (id) baseId = resolveUrl(baseId, id);
|
|
if (schema.$ref) {
|
|
var $ref = resolveUrl(baseId, schema.$ref);
|
|
var res = resolveSchema.call(this, root, $ref);
|
|
if (res) {
|
|
schema = res.schema;
|
|
root = res.root;
|
|
baseId = res.baseId;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (schema !== undefined && schema !== root.schema)
|
|
return { schema: schema, root: root, baseId: baseId };
|
|
}
|
|
|
|
|
|
var SIMPLE_INLINED = util.toHash([
|
|
'type', 'format', 'pattern',
|
|
'maxLength', 'minLength',
|
|
'maxProperties', 'minProperties',
|
|
'maxItems', 'minItems',
|
|
'maximum', 'minimum',
|
|
'uniqueItems', 'multipleOf',
|
|
'required', 'enum'
|
|
]);
|
|
function inlineRef(schema, limit) {
|
|
if (limit === false) return false;
|
|
if (limit === undefined || limit === true) return checkNoRef(schema);
|
|
else if (limit) return countKeys(schema) <= limit;
|
|
}
|
|
|
|
|
|
function checkNoRef(schema) {
|
|
var item;
|
|
if (Array.isArray(schema)) {
|
|
for (var i=0; i<schema.length; i++) {
|
|
item = schema[i];
|
|
if (typeof item == 'object' && !checkNoRef(item)) return false;
|
|
}
|
|
} else {
|
|
for (var key in schema) {
|
|
if (key == '$ref') return false;
|
|
item = schema[key];
|
|
if (typeof item == 'object' && !checkNoRef(item)) return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
function countKeys(schema) {
|
|
var count = 0, item;
|
|
if (Array.isArray(schema)) {
|
|
for (var i=0; i<schema.length; i++) {
|
|
item = schema[i];
|
|
if (typeof item == 'object') count += countKeys(item);
|
|
if (count == Infinity) return Infinity;
|
|
}
|
|
} else {
|
|
for (var key in schema) {
|
|
if (key == '$ref') return Infinity;
|
|
if (SIMPLE_INLINED[key]) {
|
|
count++;
|
|
} else {
|
|
item = schema[key];
|
|
if (typeof item == 'object') count += countKeys(item) + 1;
|
|
if (count == Infinity) return Infinity;
|
|
}
|
|
}
|
|
}
|
|
return count;
|
|
}
|
|
|
|
|
|
function getFullPath(id, normalize) {
|
|
if (normalize !== false) id = normalizeId(id);
|
|
var p = URI.parse(id);
|
|
return _getFullPath(p);
|
|
}
|
|
|
|
|
|
function _getFullPath(p) {
|
|
return URI.serialize(p).split('#')[0] + '#';
|
|
}
|
|
|
|
|
|
var TRAILING_SLASH_HASH = /#\/?$/;
|
|
function normalizeId(id) {
|
|
return id ? id.replace(TRAILING_SLASH_HASH, '') : '';
|
|
}
|
|
|
|
|
|
function resolveUrl(baseId, id) {
|
|
id = normalizeId(id);
|
|
return URI.resolve(baseId, id);
|
|
}
|
|
|
|
|
|
/* @this Ajv */
|
|
function resolveIds(schema) {
|
|
var schemaId = normalizeId(this._getId(schema));
|
|
var baseIds = {'': schemaId};
|
|
var fullPaths = {'': getFullPath(schemaId, false)};
|
|
var localRefs = {};
|
|
var self = this;
|
|
|
|
traverse(schema, {allKeys: true}, function(sch, jsonPtr, rootSchema, parentJsonPtr, parentKeyword, parentSchema, keyIndex) {
|
|
if (jsonPtr === '') return;
|
|
var id = self._getId(sch);
|
|
var baseId = baseIds[parentJsonPtr];
|
|
var fullPath = fullPaths[parentJsonPtr] + '/' + parentKeyword;
|
|
if (keyIndex !== undefined)
|
|
fullPath += '/' + (typeof keyIndex == 'number' ? keyIndex : util.escapeFragment(keyIndex));
|
|
|
|
if (typeof id == 'string') {
|
|
id = baseId = normalizeId(baseId ? URI.resolve(baseId, id) : id);
|
|
|
|
var refVal = self._refs[id];
|
|
if (typeof refVal == 'string') refVal = self._refs[refVal];
|
|
if (refVal && refVal.schema) {
|
|
if (!equal(sch, refVal.schema))
|
|
throw new Error('id "' + id + '" resolves to more than one schema');
|
|
} else if (id != normalizeId(fullPath)) {
|
|
if (id[0] == '#') {
|
|
if (localRefs[id] && !equal(sch, localRefs[id]))
|
|
throw new Error('id "' + id + '" resolves to more than one schema');
|
|
localRefs[id] = sch;
|
|
} else {
|
|
self._refs[id] = fullPath;
|
|
}
|
|
}
|
|
}
|
|
baseIds[jsonPtr] = baseId;
|
|
fullPaths[jsonPtr] = fullPath;
|
|
});
|
|
|
|
return localRefs;
|
|
}
|
|
|
|
|
|
/***/ }),
|
|
|
|
/***/ 742:
|
|
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
|
|
|
|
"use strict";
|
|
|
|
|
|
var ruleModules = __webpack_require__(9646)
|
|
, toHash = __webpack_require__(3724).toHash;
|
|
|
|
module.exports = function rules() {
|
|
var RULES = [
|
|
{ type: 'number',
|
|
rules: [ { 'maximum': ['exclusiveMaximum'] },
|
|
{ 'minimum': ['exclusiveMinimum'] }, 'multipleOf', 'format'] },
|
|
{ type: 'string',
|
|
rules: [ 'maxLength', 'minLength', 'pattern', 'format' ] },
|
|
{ type: 'array',
|
|
rules: [ 'maxItems', 'minItems', 'items', 'contains', 'uniqueItems' ] },
|
|
{ type: 'object',
|
|
rules: [ 'maxProperties', 'minProperties', 'required', 'dependencies', 'propertyNames',
|
|
{ 'properties': ['additionalProperties', 'patternProperties'] } ] },
|
|
{ rules: [ '$ref', 'const', 'enum', 'not', 'anyOf', 'oneOf', 'allOf', 'if' ] }
|
|
];
|
|
|
|
var ALL = [ 'type', '$comment' ];
|
|
var KEYWORDS = [
|
|
'$schema', '$id', 'id', '$data', '$async', 'title',
|
|
'description', 'default', 'definitions',
|
|
'examples', 'readOnly', 'writeOnly',
|
|
'contentMediaType', 'contentEncoding',
|
|
'additionalItems', 'then', 'else'
|
|
];
|
|
var TYPES = [ 'number', 'integer', 'string', 'array', 'object', 'boolean', 'null' ];
|
|
RULES.all = toHash(ALL);
|
|
RULES.types = toHash(TYPES);
|
|
|
|
RULES.forEach(function (group) {
|
|
group.rules = group.rules.map(function (keyword) {
|
|
var implKeywords;
|
|
if (typeof keyword == 'object') {
|
|
var key = Object.keys(keyword)[0];
|
|
implKeywords = keyword[key];
|
|
keyword = key;
|
|
implKeywords.forEach(function (k) {
|
|
ALL.push(k);
|
|
RULES.all[k] = true;
|
|
});
|
|
}
|
|
ALL.push(keyword);
|
|
var rule = RULES.all[keyword] = {
|
|
keyword: keyword,
|
|
code: ruleModules[keyword],
|
|
implements: implKeywords
|
|
};
|
|
return rule;
|
|
});
|
|
|
|
RULES.all.$comment = {
|
|
keyword: '$comment',
|
|
code: ruleModules.$comment
|
|
};
|
|
|
|
if (group.type) RULES.types[group.type] = group;
|
|
});
|
|
|
|
RULES.keywords = toHash(ALL.concat(KEYWORDS));
|
|
RULES.custom = {};
|
|
|
|
return RULES;
|
|
};
|
|
|
|
|
|
/***/ }),
|
|
|
|
/***/ 4293:
|
|
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
|
|
|
|
"use strict";
|
|
|
|
|
|
var util = __webpack_require__(3724);
|
|
|
|
module.exports = SchemaObject;
|
|
|
|
function SchemaObject(obj) {
|
|
util.copy(obj, this);
|
|
}
|
|
|
|
|
|
/***/ }),
|
|
|
|
/***/ 6887:
|
|
/***/ (function(module) {
|
|
|
|
"use strict";
|
|
|
|
|
|
// https://mathiasbynens.be/notes/javascript-encoding
|
|
// https://github.com/bestiejs/punycode.js - punycode.ucs2.decode
|
|
module.exports = function ucs2length(str) {
|
|
var length = 0
|
|
, len = str.length
|
|
, pos = 0
|
|
, value;
|
|
while (pos < len) {
|
|
length++;
|
|
value = str.charCodeAt(pos++);
|
|
if (value >= 0xD800 && value <= 0xDBFF && pos < len) {
|
|
// high surrogate, and there is a next character
|
|
value = str.charCodeAt(pos);
|
|
if ((value & 0xFC00) == 0xDC00) pos++; // low surrogate
|
|
}
|
|
}
|
|
return length;
|
|
};
|
|
|
|
|
|
/***/ }),
|
|
|
|
/***/ 3724:
|
|
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
|
|
|
|
"use strict";
|
|
|
|
|
|
|
|
module.exports = {
|
|
copy: copy,
|
|
checkDataType: checkDataType,
|
|
checkDataTypes: checkDataTypes,
|
|
coerceToTypes: coerceToTypes,
|
|
toHash: toHash,
|
|
getProperty: getProperty,
|
|
escapeQuotes: escapeQuotes,
|
|
equal: __webpack_require__(2303),
|
|
ucs2length: __webpack_require__(6887),
|
|
varOccurences: varOccurences,
|
|
varReplace: varReplace,
|
|
schemaHasRules: schemaHasRules,
|
|
schemaHasRulesExcept: schemaHasRulesExcept,
|
|
schemaUnknownRules: schemaUnknownRules,
|
|
toQuotedString: toQuotedString,
|
|
getPathExpr: getPathExpr,
|
|
getPath: getPath,
|
|
getData: getData,
|
|
unescapeFragment: unescapeFragment,
|
|
unescapeJsonPointer: unescapeJsonPointer,
|
|
escapeFragment: escapeFragment,
|
|
escapeJsonPointer: escapeJsonPointer
|
|
};
|
|
|
|
|
|
function copy(o, to) {
|
|
to = to || {};
|
|
for (var key in o) to[key] = o[key];
|
|
return to;
|
|
}
|
|
|
|
|
|
function checkDataType(dataType, data, strictNumbers, negate) {
|
|
var EQUAL = negate ? ' !== ' : ' === '
|
|
, AND = negate ? ' || ' : ' && '
|
|
, OK = negate ? '!' : ''
|
|
, NOT = negate ? '' : '!';
|
|
switch (dataType) {
|
|
case 'null': return data + EQUAL + 'null';
|
|
case 'array': return OK + 'Array.isArray(' + data + ')';
|
|
case 'object': return '(' + OK + data + AND +
|
|
'typeof ' + data + EQUAL + '"object"' + AND +
|
|
NOT + 'Array.isArray(' + data + '))';
|
|
case 'integer': return '(typeof ' + data + EQUAL + '"number"' + AND +
|
|
NOT + '(' + data + ' % 1)' +
|
|
AND + data + EQUAL + data +
|
|
(strictNumbers ? (AND + OK + 'isFinite(' + data + ')') : '') + ')';
|
|
case 'number': return '(typeof ' + data + EQUAL + '"' + dataType + '"' +
|
|
(strictNumbers ? (AND + OK + 'isFinite(' + data + ')') : '') + ')';
|
|
default: return 'typeof ' + data + EQUAL + '"' + dataType + '"';
|
|
}
|
|
}
|
|
|
|
|
|
function checkDataTypes(dataTypes, data, strictNumbers) {
|
|
switch (dataTypes.length) {
|
|
case 1: return checkDataType(dataTypes[0], data, strictNumbers, true);
|
|
default:
|
|
var code = '';
|
|
var types = toHash(dataTypes);
|
|
if (types.array && types.object) {
|
|
code = types.null ? '(': '(!' + data + ' || ';
|
|
code += 'typeof ' + data + ' !== "object")';
|
|
delete types.null;
|
|
delete types.array;
|
|
delete types.object;
|
|
}
|
|
if (types.number) delete types.integer;
|
|
for (var t in types)
|
|
code += (code ? ' && ' : '' ) + checkDataType(t, data, strictNumbers, true);
|
|
|
|
return code;
|
|
}
|
|
}
|
|
|
|
|
|
var COERCE_TO_TYPES = toHash([ 'string', 'number', 'integer', 'boolean', 'null' ]);
|
|
function coerceToTypes(optionCoerceTypes, dataTypes) {
|
|
if (Array.isArray(dataTypes)) {
|
|
var types = [];
|
|
for (var i=0; i<dataTypes.length; i++) {
|
|
var t = dataTypes[i];
|
|
if (COERCE_TO_TYPES[t]) types[types.length] = t;
|
|
else if (optionCoerceTypes === 'array' && t === 'array') types[types.length] = t;
|
|
}
|
|
if (types.length) return types;
|
|
} else if (COERCE_TO_TYPES[dataTypes]) {
|
|
return [dataTypes];
|
|
} else if (optionCoerceTypes === 'array' && dataTypes === 'array') {
|
|
return ['array'];
|
|
}
|
|
}
|
|
|
|
|
|
function toHash(arr) {
|
|
var hash = {};
|
|
for (var i=0; i<arr.length; i++) hash[arr[i]] = true;
|
|
return hash;
|
|
}
|
|
|
|
|
|
var IDENTIFIER = /^[a-z$_][a-z$_0-9]*$/i;
|
|
var SINGLE_QUOTE = /'|\\/g;
|
|
function getProperty(key) {
|
|
return typeof key == 'number'
|
|
? '[' + key + ']'
|
|
: IDENTIFIER.test(key)
|
|
? '.' + key
|
|
: "['" + escapeQuotes(key) + "']";
|
|
}
|
|
|
|
|
|
function escapeQuotes(str) {
|
|
return str.replace(SINGLE_QUOTE, '\\$&')
|
|
.replace(/\n/g, '\\n')
|
|
.replace(/\r/g, '\\r')
|
|
.replace(/\f/g, '\\f')
|
|
.replace(/\t/g, '\\t');
|
|
}
|
|
|
|
|
|
function varOccurences(str, dataVar) {
|
|
dataVar += '[^0-9]';
|
|
var matches = str.match(new RegExp(dataVar, 'g'));
|
|
return matches ? matches.length : 0;
|
|
}
|
|
|
|
|
|
function varReplace(str, dataVar, expr) {
|
|
dataVar += '([^0-9])';
|
|
expr = expr.replace(/\$/g, '$$$$');
|
|
return str.replace(new RegExp(dataVar, 'g'), expr + '$1');
|
|
}
|
|
|
|
|
|
function schemaHasRules(schema, rules) {
|
|
if (typeof schema == 'boolean') return !schema;
|
|
for (var key in schema) if (rules[key]) return true;
|
|
}
|
|
|
|
|
|
function schemaHasRulesExcept(schema, rules, exceptKeyword) {
|
|
if (typeof schema == 'boolean') return !schema && exceptKeyword != 'not';
|
|
for (var key in schema) if (key != exceptKeyword && rules[key]) return true;
|
|
}
|
|
|
|
|
|
function schemaUnknownRules(schema, rules) {
|
|
if (typeof schema == 'boolean') return;
|
|
for (var key in schema) if (!rules[key]) return key;
|
|
}
|
|
|
|
|
|
function toQuotedString(str) {
|
|
return '\'' + escapeQuotes(str) + '\'';
|
|
}
|
|
|
|
|
|
function getPathExpr(currentPath, expr, jsonPointers, isNumber) {
|
|
var path = jsonPointers // false by default
|
|
? '\'/\' + ' + expr + (isNumber ? '' : '.replace(/~/g, \'~0\').replace(/\\//g, \'~1\')')
|
|
: (isNumber ? '\'[\' + ' + expr + ' + \']\'' : '\'[\\\'\' + ' + expr + ' + \'\\\']\'');
|
|
return joinPaths(currentPath, path);
|
|
}
|
|
|
|
|
|
function getPath(currentPath, prop, jsonPointers) {
|
|
var path = jsonPointers // false by default
|
|
? toQuotedString('/' + escapeJsonPointer(prop))
|
|
: toQuotedString(getProperty(prop));
|
|
return joinPaths(currentPath, path);
|
|
}
|
|
|
|
|
|
var JSON_POINTER = /^\/(?:[^~]|~0|~1)*$/;
|
|
var RELATIVE_JSON_POINTER = /^([0-9]+)(#|\/(?:[^~]|~0|~1)*)?$/;
|
|
function getData($data, lvl, paths) {
|
|
var up, jsonPointer, data, matches;
|
|
if ($data === '') return 'rootData';
|
|
if ($data[0] == '/') {
|
|
if (!JSON_POINTER.test($data)) throw new Error('Invalid JSON-pointer: ' + $data);
|
|
jsonPointer = $data;
|
|
data = 'rootData';
|
|
} else {
|
|
matches = $data.match(RELATIVE_JSON_POINTER);
|
|
if (!matches) throw new Error('Invalid JSON-pointer: ' + $data);
|
|
up = +matches[1];
|
|
jsonPointer = matches[2];
|
|
if (jsonPointer == '#') {
|
|
if (up >= lvl) throw new Error('Cannot access property/index ' + up + ' levels up, current level is ' + lvl);
|
|
return paths[lvl - up];
|
|
}
|
|
|
|
if (up > lvl) throw new Error('Cannot access data ' + up + ' levels up, current level is ' + lvl);
|
|
data = 'data' + ((lvl - up) || '');
|
|
if (!jsonPointer) return data;
|
|
}
|
|
|
|
var expr = data;
|
|
var segments = jsonPointer.split('/');
|
|
for (var i=0; i<segments.length; i++) {
|
|
var segment = segments[i];
|
|
if (segment) {
|
|
data += getProperty(unescapeJsonPointer(segment));
|
|
expr += ' && ' + data;
|
|
}
|
|
}
|
|
return expr;
|
|
}
|
|
|
|
|
|
function joinPaths (a, b) {
|
|
if (a == '""') return b;
|
|
return (a + ' + ' + b).replace(/([^\\])' \+ '/g, '$1');
|
|
}
|
|
|
|
|
|
function unescapeFragment(str) {
|
|
return unescapeJsonPointer(decodeURIComponent(str));
|
|
}
|
|
|
|
|
|
function escapeFragment(str) {
|
|
return encodeURIComponent(escapeJsonPointer(str));
|
|
}
|
|
|
|
|
|
function escapeJsonPointer(str) {
|
|
return str.replace(/~/g, '~0').replace(/\//g, '~1');
|
|
}
|
|
|
|
|
|
function unescapeJsonPointer(str) {
|
|
return str.replace(/~1/g, '/').replace(/~0/g, '~');
|
|
}
|
|
|
|
|
|
/***/ }),
|
|
|
|
/***/ 9394:
|
|
/***/ (function(module) {
|
|
|
|
"use strict";
|
|
|
|
|
|
var KEYWORDS = [
|
|
'multipleOf',
|
|
'maximum',
|
|
'exclusiveMaximum',
|
|
'minimum',
|
|
'exclusiveMinimum',
|
|
'maxLength',
|
|
'minLength',
|
|
'pattern',
|
|
'additionalItems',
|
|
'maxItems',
|
|
'minItems',
|
|
'uniqueItems',
|
|
'maxProperties',
|
|
'minProperties',
|
|
'required',
|
|
'additionalProperties',
|
|
'enum',
|
|
'format',
|
|
'const'
|
|
];
|
|
|
|
module.exports = function (metaSchema, keywordsJsonPointers) {
|
|
for (var i=0; i<keywordsJsonPointers.length; i++) {
|
|
metaSchema = JSON.parse(JSON.stringify(metaSchema));
|
|
var segments = keywordsJsonPointers[i].split('/');
|
|
var keywords = metaSchema;
|
|
var j;
|
|
for (j=1; j<segments.length; j++)
|
|
keywords = keywords[segments[j]];
|
|
|
|
for (j=0; j<KEYWORDS.length; j++) {
|
|
var key = KEYWORDS[j];
|
|
var schema = keywords[key];
|
|
if (schema) {
|
|
keywords[key] = {
|
|
anyOf: [
|
|
schema,
|
|
{ $ref: 'https://raw.githubusercontent.com/ajv-validator/ajv/master/lib/refs/data.json#' }
|
|
]
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
return metaSchema;
|
|
};
|
|
|
|
|
|
/***/ }),
|
|
|
|
/***/ 5868:
|
|
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
|
|
|
|
"use strict";
|
|
|
|
|
|
var metaSchema = __webpack_require__(38);
|
|
|
|
module.exports = {
|
|
$id: 'https://github.com/ajv-validator/ajv/blob/master/lib/definition_schema.js',
|
|
definitions: {
|
|
simpleTypes: metaSchema.definitions.simpleTypes
|
|
},
|
|
type: 'object',
|
|
dependencies: {
|
|
schema: ['validate'],
|
|
$data: ['validate'],
|
|
statements: ['inline'],
|
|
valid: {not: {required: ['macro']}}
|
|
},
|
|
properties: {
|
|
type: metaSchema.properties.type,
|
|
schema: {type: 'boolean'},
|
|
statements: {type: 'boolean'},
|
|
dependencies: {
|
|
type: 'array',
|
|
items: {type: 'string'}
|
|
},
|
|
metaSchema: {type: 'object'},
|
|
modifying: {type: 'boolean'},
|
|
valid: {type: 'boolean'},
|
|
$data: {type: 'boolean'},
|
|
async: {type: 'boolean'},
|
|
errors: {
|
|
anyOf: [
|
|
{type: 'boolean'},
|
|
{const: 'full'}
|
|
]
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
/***/ }),
|
|
|
|
/***/ 1796:
|
|
/***/ (function(module) {
|
|
|
|
"use strict";
|
|
|
|
module.exports = function generate__limit(it, $keyword, $ruleType) {
|
|
var out = ' ';
|
|
var $lvl = it.level;
|
|
var $dataLvl = it.dataLevel;
|
|
var $schema = it.schema[$keyword];
|
|
var $schemaPath = it.schemaPath + it.util.getProperty($keyword);
|
|
var $errSchemaPath = it.errSchemaPath + '/' + $keyword;
|
|
var $breakOnError = !it.opts.allErrors;
|
|
var $errorKeyword;
|
|
var $data = 'data' + ($dataLvl || '');
|
|
var $isData = it.opts.$data && $schema && $schema.$data,
|
|
$schemaValue;
|
|
if ($isData) {
|
|
out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; ';
|
|
$schemaValue = 'schema' + $lvl;
|
|
} else {
|
|
$schemaValue = $schema;
|
|
}
|
|
var $isMax = $keyword == 'maximum',
|
|
$exclusiveKeyword = $isMax ? 'exclusiveMaximum' : 'exclusiveMinimum',
|
|
$schemaExcl = it.schema[$exclusiveKeyword],
|
|
$isDataExcl = it.opts.$data && $schemaExcl && $schemaExcl.$data,
|
|
$op = $isMax ? '<' : '>',
|
|
$notOp = $isMax ? '>' : '<',
|
|
$errorKeyword = undefined;
|
|
if (!($isData || typeof $schema == 'number' || $schema === undefined)) {
|
|
throw new Error($keyword + ' must be number');
|
|
}
|
|
if (!($isDataExcl || $schemaExcl === undefined || typeof $schemaExcl == 'number' || typeof $schemaExcl == 'boolean')) {
|
|
throw new Error($exclusiveKeyword + ' must be number or boolean');
|
|
}
|
|
if ($isDataExcl) {
|
|
var $schemaValueExcl = it.util.getData($schemaExcl.$data, $dataLvl, it.dataPathArr),
|
|
$exclusive = 'exclusive' + $lvl,
|
|
$exclType = 'exclType' + $lvl,
|
|
$exclIsNumber = 'exclIsNumber' + $lvl,
|
|
$opExpr = 'op' + $lvl,
|
|
$opStr = '\' + ' + $opExpr + ' + \'';
|
|
out += ' var schemaExcl' + ($lvl) + ' = ' + ($schemaValueExcl) + '; ';
|
|
$schemaValueExcl = 'schemaExcl' + $lvl;
|
|
out += ' var ' + ($exclusive) + '; var ' + ($exclType) + ' = typeof ' + ($schemaValueExcl) + '; if (' + ($exclType) + ' != \'boolean\' && ' + ($exclType) + ' != \'undefined\' && ' + ($exclType) + ' != \'number\') { ';
|
|
var $errorKeyword = $exclusiveKeyword;
|
|
var $$outStack = $$outStack || [];
|
|
$$outStack.push(out);
|
|
out = ''; /* istanbul ignore else */
|
|
if (it.createErrors !== false) {
|
|
out += ' { keyword: \'' + ($errorKeyword || '_exclusiveLimit') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: {} ';
|
|
if (it.opts.messages !== false) {
|
|
out += ' , message: \'' + ($exclusiveKeyword) + ' should be boolean\' ';
|
|
}
|
|
if (it.opts.verbose) {
|
|
out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
|
|
}
|
|
out += ' } ';
|
|
} else {
|
|
out += ' {} ';
|
|
}
|
|
var __err = out;
|
|
out = $$outStack.pop();
|
|
if (!it.compositeRule && $breakOnError) {
|
|
/* istanbul ignore if */
|
|
if (it.async) {
|
|
out += ' throw new ValidationError([' + (__err) + ']); ';
|
|
} else {
|
|
out += ' validate.errors = [' + (__err) + ']; return false; ';
|
|
}
|
|
} else {
|
|
out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';
|
|
}
|
|
out += ' } else if ( ';
|
|
if ($isData) {
|
|
out += ' (' + ($schemaValue) + ' !== undefined && typeof ' + ($schemaValue) + ' != \'number\') || ';
|
|
}
|
|
out += ' ' + ($exclType) + ' == \'number\' ? ( (' + ($exclusive) + ' = ' + ($schemaValue) + ' === undefined || ' + ($schemaValueExcl) + ' ' + ($op) + '= ' + ($schemaValue) + ') ? ' + ($data) + ' ' + ($notOp) + '= ' + ($schemaValueExcl) + ' : ' + ($data) + ' ' + ($notOp) + ' ' + ($schemaValue) + ' ) : ( (' + ($exclusive) + ' = ' + ($schemaValueExcl) + ' === true) ? ' + ($data) + ' ' + ($notOp) + '= ' + ($schemaValue) + ' : ' + ($data) + ' ' + ($notOp) + ' ' + ($schemaValue) + ' ) || ' + ($data) + ' !== ' + ($data) + ') { var op' + ($lvl) + ' = ' + ($exclusive) + ' ? \'' + ($op) + '\' : \'' + ($op) + '=\'; ';
|
|
if ($schema === undefined) {
|
|
$errorKeyword = $exclusiveKeyword;
|
|
$errSchemaPath = it.errSchemaPath + '/' + $exclusiveKeyword;
|
|
$schemaValue = $schemaValueExcl;
|
|
$isData = $isDataExcl;
|
|
}
|
|
} else {
|
|
var $exclIsNumber = typeof $schemaExcl == 'number',
|
|
$opStr = $op;
|
|
if ($exclIsNumber && $isData) {
|
|
var $opExpr = '\'' + $opStr + '\'';
|
|
out += ' if ( ';
|
|
if ($isData) {
|
|
out += ' (' + ($schemaValue) + ' !== undefined && typeof ' + ($schemaValue) + ' != \'number\') || ';
|
|
}
|
|
out += ' ( ' + ($schemaValue) + ' === undefined || ' + ($schemaExcl) + ' ' + ($op) + '= ' + ($schemaValue) + ' ? ' + ($data) + ' ' + ($notOp) + '= ' + ($schemaExcl) + ' : ' + ($data) + ' ' + ($notOp) + ' ' + ($schemaValue) + ' ) || ' + ($data) + ' !== ' + ($data) + ') { ';
|
|
} else {
|
|
if ($exclIsNumber && $schema === undefined) {
|
|
$exclusive = true;
|
|
$errorKeyword = $exclusiveKeyword;
|
|
$errSchemaPath = it.errSchemaPath + '/' + $exclusiveKeyword;
|
|
$schemaValue = $schemaExcl;
|
|
$notOp += '=';
|
|
} else {
|
|
if ($exclIsNumber) $schemaValue = Math[$isMax ? 'min' : 'max']($schemaExcl, $schema);
|
|
if ($schemaExcl === ($exclIsNumber ? $schemaValue : true)) {
|
|
$exclusive = true;
|
|
$errorKeyword = $exclusiveKeyword;
|
|
$errSchemaPath = it.errSchemaPath + '/' + $exclusiveKeyword;
|
|
$notOp += '=';
|
|
} else {
|
|
$exclusive = false;
|
|
$opStr += '=';
|
|
}
|
|
}
|
|
var $opExpr = '\'' + $opStr + '\'';
|
|
out += ' if ( ';
|
|
if ($isData) {
|
|
out += ' (' + ($schemaValue) + ' !== undefined && typeof ' + ($schemaValue) + ' != \'number\') || ';
|
|
}
|
|
out += ' ' + ($data) + ' ' + ($notOp) + ' ' + ($schemaValue) + ' || ' + ($data) + ' !== ' + ($data) + ') { ';
|
|
}
|
|
}
|
|
$errorKeyword = $errorKeyword || $keyword;
|
|
var $$outStack = $$outStack || [];
|
|
$$outStack.push(out);
|
|
out = ''; /* istanbul ignore else */
|
|
if (it.createErrors !== false) {
|
|
out += ' { keyword: \'' + ($errorKeyword || '_limit') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { comparison: ' + ($opExpr) + ', limit: ' + ($schemaValue) + ', exclusive: ' + ($exclusive) + ' } ';
|
|
if (it.opts.messages !== false) {
|
|
out += ' , message: \'should be ' + ($opStr) + ' ';
|
|
if ($isData) {
|
|
out += '\' + ' + ($schemaValue);
|
|
} else {
|
|
out += '' + ($schemaValue) + '\'';
|
|
}
|
|
}
|
|
if (it.opts.verbose) {
|
|
out += ' , schema: ';
|
|
if ($isData) {
|
|
out += 'validate.schema' + ($schemaPath);
|
|
} else {
|
|
out += '' + ($schema);
|
|
}
|
|
out += ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
|
|
}
|
|
out += ' } ';
|
|
} else {
|
|
out += ' {} ';
|
|
}
|
|
var __err = out;
|
|
out = $$outStack.pop();
|
|
if (!it.compositeRule && $breakOnError) {
|
|
/* istanbul ignore if */
|
|
if (it.async) {
|
|
out += ' throw new ValidationError([' + (__err) + ']); ';
|
|
} else {
|
|
out += ' validate.errors = [' + (__err) + ']; return false; ';
|
|
}
|
|
} else {
|
|
out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';
|
|
}
|
|
out += ' } ';
|
|
if ($breakOnError) {
|
|
out += ' else { ';
|
|
}
|
|
return out;
|
|
}
|
|
|
|
|
|
/***/ }),
|
|
|
|
/***/ 2407:
|
|
/***/ (function(module) {
|
|
|
|
"use strict";
|
|
|
|
module.exports = function generate__limitItems(it, $keyword, $ruleType) {
|
|
var out = ' ';
|
|
var $lvl = it.level;
|
|
var $dataLvl = it.dataLevel;
|
|
var $schema = it.schema[$keyword];
|
|
var $schemaPath = it.schemaPath + it.util.getProperty($keyword);
|
|
var $errSchemaPath = it.errSchemaPath + '/' + $keyword;
|
|
var $breakOnError = !it.opts.allErrors;
|
|
var $errorKeyword;
|
|
var $data = 'data' + ($dataLvl || '');
|
|
var $isData = it.opts.$data && $schema && $schema.$data,
|
|
$schemaValue;
|
|
if ($isData) {
|
|
out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; ';
|
|
$schemaValue = 'schema' + $lvl;
|
|
} else {
|
|
$schemaValue = $schema;
|
|
}
|
|
if (!($isData || typeof $schema == 'number')) {
|
|
throw new Error($keyword + ' must be number');
|
|
}
|
|
var $op = $keyword == 'maxItems' ? '>' : '<';
|
|
out += 'if ( ';
|
|
if ($isData) {
|
|
out += ' (' + ($schemaValue) + ' !== undefined && typeof ' + ($schemaValue) + ' != \'number\') || ';
|
|
}
|
|
out += ' ' + ($data) + '.length ' + ($op) + ' ' + ($schemaValue) + ') { ';
|
|
var $errorKeyword = $keyword;
|
|
var $$outStack = $$outStack || [];
|
|
$$outStack.push(out);
|
|
out = ''; /* istanbul ignore else */
|
|
if (it.createErrors !== false) {
|
|
out += ' { keyword: \'' + ($errorKeyword || '_limitItems') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { limit: ' + ($schemaValue) + ' } ';
|
|
if (it.opts.messages !== false) {
|
|
out += ' , message: \'should NOT have ';
|
|
if ($keyword == 'maxItems') {
|
|
out += 'more';
|
|
} else {
|
|
out += 'fewer';
|
|
}
|
|
out += ' than ';
|
|
if ($isData) {
|
|
out += '\' + ' + ($schemaValue) + ' + \'';
|
|
} else {
|
|
out += '' + ($schema);
|
|
}
|
|
out += ' items\' ';
|
|
}
|
|
if (it.opts.verbose) {
|
|
out += ' , schema: ';
|
|
if ($isData) {
|
|
out += 'validate.schema' + ($schemaPath);
|
|
} else {
|
|
out += '' + ($schema);
|
|
}
|
|
out += ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
|
|
}
|
|
out += ' } ';
|
|
} else {
|
|
out += ' {} ';
|
|
}
|
|
var __err = out;
|
|
out = $$outStack.pop();
|
|
if (!it.compositeRule && $breakOnError) {
|
|
/* istanbul ignore if */
|
|
if (it.async) {
|
|
out += ' throw new ValidationError([' + (__err) + ']); ';
|
|
} else {
|
|
out += ' validate.errors = [' + (__err) + ']; return false; ';
|
|
}
|
|
} else {
|
|
out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';
|
|
}
|
|
out += '} ';
|
|
if ($breakOnError) {
|
|
out += ' else { ';
|
|
}
|
|
return out;
|
|
}
|
|
|
|
|
|
/***/ }),
|
|
|
|
/***/ 1250:
|
|
/***/ (function(module) {
|
|
|
|
"use strict";
|
|
|
|
module.exports = function generate__limitLength(it, $keyword, $ruleType) {
|
|
var out = ' ';
|
|
var $lvl = it.level;
|
|
var $dataLvl = it.dataLevel;
|
|
var $schema = it.schema[$keyword];
|
|
var $schemaPath = it.schemaPath + it.util.getProperty($keyword);
|
|
var $errSchemaPath = it.errSchemaPath + '/' + $keyword;
|
|
var $breakOnError = !it.opts.allErrors;
|
|
var $errorKeyword;
|
|
var $data = 'data' + ($dataLvl || '');
|
|
var $isData = it.opts.$data && $schema && $schema.$data,
|
|
$schemaValue;
|
|
if ($isData) {
|
|
out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; ';
|
|
$schemaValue = 'schema' + $lvl;
|
|
} else {
|
|
$schemaValue = $schema;
|
|
}
|
|
if (!($isData || typeof $schema == 'number')) {
|
|
throw new Error($keyword + ' must be number');
|
|
}
|
|
var $op = $keyword == 'maxLength' ? '>' : '<';
|
|
out += 'if ( ';
|
|
if ($isData) {
|
|
out += ' (' + ($schemaValue) + ' !== undefined && typeof ' + ($schemaValue) + ' != \'number\') || ';
|
|
}
|
|
if (it.opts.unicode === false) {
|
|
out += ' ' + ($data) + '.length ';
|
|
} else {
|
|
out += ' ucs2length(' + ($data) + ') ';
|
|
}
|
|
out += ' ' + ($op) + ' ' + ($schemaValue) + ') { ';
|
|
var $errorKeyword = $keyword;
|
|
var $$outStack = $$outStack || [];
|
|
$$outStack.push(out);
|
|
out = ''; /* istanbul ignore else */
|
|
if (it.createErrors !== false) {
|
|
out += ' { keyword: \'' + ($errorKeyword || '_limitLength') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { limit: ' + ($schemaValue) + ' } ';
|
|
if (it.opts.messages !== false) {
|
|
out += ' , message: \'should NOT be ';
|
|
if ($keyword == 'maxLength') {
|
|
out += 'longer';
|
|
} else {
|
|
out += 'shorter';
|
|
}
|
|
out += ' than ';
|
|
if ($isData) {
|
|
out += '\' + ' + ($schemaValue) + ' + \'';
|
|
} else {
|
|
out += '' + ($schema);
|
|
}
|
|
out += ' characters\' ';
|
|
}
|
|
if (it.opts.verbose) {
|
|
out += ' , schema: ';
|
|
if ($isData) {
|
|
out += 'validate.schema' + ($schemaPath);
|
|
} else {
|
|
out += '' + ($schema);
|
|
}
|
|
out += ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
|
|
}
|
|
out += ' } ';
|
|
} else {
|
|
out += ' {} ';
|
|
}
|
|
var __err = out;
|
|
out = $$outStack.pop();
|
|
if (!it.compositeRule && $breakOnError) {
|
|
/* istanbul ignore if */
|
|
if (it.async) {
|
|
out += ' throw new ValidationError([' + (__err) + ']); ';
|
|
} else {
|
|
out += ' validate.errors = [' + (__err) + ']; return false; ';
|
|
}
|
|
} else {
|
|
out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';
|
|
}
|
|
out += '} ';
|
|
if ($breakOnError) {
|
|
out += ' else { ';
|
|
}
|
|
return out;
|
|
}
|
|
|
|
|
|
/***/ }),
|
|
|
|
/***/ 2596:
|
|
/***/ (function(module) {
|
|
|
|
"use strict";
|
|
|
|
module.exports = function generate__limitProperties(it, $keyword, $ruleType) {
|
|
var out = ' ';
|
|
var $lvl = it.level;
|
|
var $dataLvl = it.dataLevel;
|
|
var $schema = it.schema[$keyword];
|
|
var $schemaPath = it.schemaPath + it.util.getProperty($keyword);
|
|
var $errSchemaPath = it.errSchemaPath + '/' + $keyword;
|
|
var $breakOnError = !it.opts.allErrors;
|
|
var $errorKeyword;
|
|
var $data = 'data' + ($dataLvl || '');
|
|
var $isData = it.opts.$data && $schema && $schema.$data,
|
|
$schemaValue;
|
|
if ($isData) {
|
|
out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; ';
|
|
$schemaValue = 'schema' + $lvl;
|
|
} else {
|
|
$schemaValue = $schema;
|
|
}
|
|
if (!($isData || typeof $schema == 'number')) {
|
|
throw new Error($keyword + ' must be number');
|
|
}
|
|
var $op = $keyword == 'maxProperties' ? '>' : '<';
|
|
out += 'if ( ';
|
|
if ($isData) {
|
|
out += ' (' + ($schemaValue) + ' !== undefined && typeof ' + ($schemaValue) + ' != \'number\') || ';
|
|
}
|
|
out += ' Object.keys(' + ($data) + ').length ' + ($op) + ' ' + ($schemaValue) + ') { ';
|
|
var $errorKeyword = $keyword;
|
|
var $$outStack = $$outStack || [];
|
|
$$outStack.push(out);
|
|
out = ''; /* istanbul ignore else */
|
|
if (it.createErrors !== false) {
|
|
out += ' { keyword: \'' + ($errorKeyword || '_limitProperties') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { limit: ' + ($schemaValue) + ' } ';
|
|
if (it.opts.messages !== false) {
|
|
out += ' , message: \'should NOT have ';
|
|
if ($keyword == 'maxProperties') {
|
|
out += 'more';
|
|
} else {
|
|
out += 'fewer';
|
|
}
|
|
out += ' than ';
|
|
if ($isData) {
|
|
out += '\' + ' + ($schemaValue) + ' + \'';
|
|
} else {
|
|
out += '' + ($schema);
|
|
}
|
|
out += ' properties\' ';
|
|
}
|
|
if (it.opts.verbose) {
|
|
out += ' , schema: ';
|
|
if ($isData) {
|
|
out += 'validate.schema' + ($schemaPath);
|
|
} else {
|
|
out += '' + ($schema);
|
|
}
|
|
out += ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
|
|
}
|
|
out += ' } ';
|
|
} else {
|
|
out += ' {} ';
|
|
}
|
|
var __err = out;
|
|
out = $$outStack.pop();
|
|
if (!it.compositeRule && $breakOnError) {
|
|
/* istanbul ignore if */
|
|
if (it.async) {
|
|
out += ' throw new ValidationError([' + (__err) + ']); ';
|
|
} else {
|
|
out += ' validate.errors = [' + (__err) + ']; return false; ';
|
|
}
|
|
} else {
|
|
out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';
|
|
}
|
|
out += '} ';
|
|
if ($breakOnError) {
|
|
out += ' else { ';
|
|
}
|
|
return out;
|
|
}
|
|
|
|
|
|
/***/ }),
|
|
|
|
/***/ 9486:
|
|
/***/ (function(module) {
|
|
|
|
"use strict";
|
|
|
|
module.exports = function generate_allOf(it, $keyword, $ruleType) {
|
|
var out = ' ';
|
|
var $schema = it.schema[$keyword];
|
|
var $schemaPath = it.schemaPath + it.util.getProperty($keyword);
|
|
var $errSchemaPath = it.errSchemaPath + '/' + $keyword;
|
|
var $breakOnError = !it.opts.allErrors;
|
|
var $it = it.util.copy(it);
|
|
var $closingBraces = '';
|
|
$it.level++;
|
|
var $nextValid = 'valid' + $it.level;
|
|
var $currentBaseId = $it.baseId,
|
|
$allSchemasEmpty = true;
|
|
var arr1 = $schema;
|
|
if (arr1) {
|
|
var $sch, $i = -1,
|
|
l1 = arr1.length - 1;
|
|
while ($i < l1) {
|
|
$sch = arr1[$i += 1];
|
|
if ((it.opts.strictKeywords ? (typeof $sch == 'object' && Object.keys($sch).length > 0) || $sch === false : it.util.schemaHasRules($sch, it.RULES.all))) {
|
|
$allSchemasEmpty = false;
|
|
$it.schema = $sch;
|
|
$it.schemaPath = $schemaPath + '[' + $i + ']';
|
|
$it.errSchemaPath = $errSchemaPath + '/' + $i;
|
|
out += ' ' + (it.validate($it)) + ' ';
|
|
$it.baseId = $currentBaseId;
|
|
if ($breakOnError) {
|
|
out += ' if (' + ($nextValid) + ') { ';
|
|
$closingBraces += '}';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if ($breakOnError) {
|
|
if ($allSchemasEmpty) {
|
|
out += ' if (true) { ';
|
|
} else {
|
|
out += ' ' + ($closingBraces.slice(0, -1)) + ' ';
|
|
}
|
|
}
|
|
return out;
|
|
}
|
|
|
|
|
|
/***/ }),
|
|
|
|
/***/ 5347:
|
|
/***/ (function(module) {
|
|
|
|
"use strict";
|
|
|
|
module.exports = function generate_anyOf(it, $keyword, $ruleType) {
|
|
var out = ' ';
|
|
var $lvl = it.level;
|
|
var $dataLvl = it.dataLevel;
|
|
var $schema = it.schema[$keyword];
|
|
var $schemaPath = it.schemaPath + it.util.getProperty($keyword);
|
|
var $errSchemaPath = it.errSchemaPath + '/' + $keyword;
|
|
var $breakOnError = !it.opts.allErrors;
|
|
var $data = 'data' + ($dataLvl || '');
|
|
var $valid = 'valid' + $lvl;
|
|
var $errs = 'errs__' + $lvl;
|
|
var $it = it.util.copy(it);
|
|
var $closingBraces = '';
|
|
$it.level++;
|
|
var $nextValid = 'valid' + $it.level;
|
|
var $noEmptySchema = $schema.every(function($sch) {
|
|
return (it.opts.strictKeywords ? (typeof $sch == 'object' && Object.keys($sch).length > 0) || $sch === false : it.util.schemaHasRules($sch, it.RULES.all));
|
|
});
|
|
if ($noEmptySchema) {
|
|
var $currentBaseId = $it.baseId;
|
|
out += ' var ' + ($errs) + ' = errors; var ' + ($valid) + ' = false; ';
|
|
var $wasComposite = it.compositeRule;
|
|
it.compositeRule = $it.compositeRule = true;
|
|
var arr1 = $schema;
|
|
if (arr1) {
|
|
var $sch, $i = -1,
|
|
l1 = arr1.length - 1;
|
|
while ($i < l1) {
|
|
$sch = arr1[$i += 1];
|
|
$it.schema = $sch;
|
|
$it.schemaPath = $schemaPath + '[' + $i + ']';
|
|
$it.errSchemaPath = $errSchemaPath + '/' + $i;
|
|
out += ' ' + (it.validate($it)) + ' ';
|
|
$it.baseId = $currentBaseId;
|
|
out += ' ' + ($valid) + ' = ' + ($valid) + ' || ' + ($nextValid) + '; if (!' + ($valid) + ') { ';
|
|
$closingBraces += '}';
|
|
}
|
|
}
|
|
it.compositeRule = $it.compositeRule = $wasComposite;
|
|
out += ' ' + ($closingBraces) + ' if (!' + ($valid) + ') { var err = '; /* istanbul ignore else */
|
|
if (it.createErrors !== false) {
|
|
out += ' { keyword: \'' + ('anyOf') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: {} ';
|
|
if (it.opts.messages !== false) {
|
|
out += ' , message: \'should match some schema in anyOf\' ';
|
|
}
|
|
if (it.opts.verbose) {
|
|
out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
|
|
}
|
|
out += ' } ';
|
|
} else {
|
|
out += ' {} ';
|
|
}
|
|
out += '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';
|
|
if (!it.compositeRule && $breakOnError) {
|
|
/* istanbul ignore if */
|
|
if (it.async) {
|
|
out += ' throw new ValidationError(vErrors); ';
|
|
} else {
|
|
out += ' validate.errors = vErrors; return false; ';
|
|
}
|
|
}
|
|
out += ' } else { errors = ' + ($errs) + '; if (vErrors !== null) { if (' + ($errs) + ') vErrors.length = ' + ($errs) + '; else vErrors = null; } ';
|
|
if (it.opts.allErrors) {
|
|
out += ' } ';
|
|
}
|
|
} else {
|
|
if ($breakOnError) {
|
|
out += ' if (true) { ';
|
|
}
|
|
}
|
|
return out;
|
|
}
|
|
|
|
|
|
/***/ }),
|
|
|
|
/***/ 923:
|
|
/***/ (function(module) {
|
|
|
|
"use strict";
|
|
|
|
module.exports = function generate_comment(it, $keyword, $ruleType) {
|
|
var out = ' ';
|
|
var $schema = it.schema[$keyword];
|
|
var $errSchemaPath = it.errSchemaPath + '/' + $keyword;
|
|
var $breakOnError = !it.opts.allErrors;
|
|
var $comment = it.util.toQuotedString($schema);
|
|
if (it.opts.$comment === true) {
|
|
out += ' console.log(' + ($comment) + ');';
|
|
} else if (typeof it.opts.$comment == 'function') {
|
|
out += ' self._opts.$comment(' + ($comment) + ', ' + (it.util.toQuotedString($errSchemaPath)) + ', validate.root.schema);';
|
|
}
|
|
return out;
|
|
}
|
|
|
|
|
|
/***/ }),
|
|
|
|
/***/ 2617:
|
|
/***/ (function(module) {
|
|
|
|
"use strict";
|
|
|
|
module.exports = function generate_const(it, $keyword, $ruleType) {
|
|
var out = ' ';
|
|
var $lvl = it.level;
|
|
var $dataLvl = it.dataLevel;
|
|
var $schema = it.schema[$keyword];
|
|
var $schemaPath = it.schemaPath + it.util.getProperty($keyword);
|
|
var $errSchemaPath = it.errSchemaPath + '/' + $keyword;
|
|
var $breakOnError = !it.opts.allErrors;
|
|
var $data = 'data' + ($dataLvl || '');
|
|
var $valid = 'valid' + $lvl;
|
|
var $isData = it.opts.$data && $schema && $schema.$data,
|
|
$schemaValue;
|
|
if ($isData) {
|
|
out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; ';
|
|
$schemaValue = 'schema' + $lvl;
|
|
} else {
|
|
$schemaValue = $schema;
|
|
}
|
|
if (!$isData) {
|
|
out += ' var schema' + ($lvl) + ' = validate.schema' + ($schemaPath) + ';';
|
|
}
|
|
out += 'var ' + ($valid) + ' = equal(' + ($data) + ', schema' + ($lvl) + '); if (!' + ($valid) + ') { ';
|
|
var $$outStack = $$outStack || [];
|
|
$$outStack.push(out);
|
|
out = ''; /* istanbul ignore else */
|
|
if (it.createErrors !== false) {
|
|
out += ' { keyword: \'' + ('const') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { allowedValue: schema' + ($lvl) + ' } ';
|
|
if (it.opts.messages !== false) {
|
|
out += ' , message: \'should be equal to constant\' ';
|
|
}
|
|
if (it.opts.verbose) {
|
|
out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
|
|
}
|
|
out += ' } ';
|
|
} else {
|
|
out += ' {} ';
|
|
}
|
|
var __err = out;
|
|
out = $$outStack.pop();
|
|
if (!it.compositeRule && $breakOnError) {
|
|
/* istanbul ignore if */
|
|
if (it.async) {
|
|
out += ' throw new ValidationError([' + (__err) + ']); ';
|
|
} else {
|
|
out += ' validate.errors = [' + (__err) + ']; return false; ';
|
|
}
|
|
} else {
|
|
out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';
|
|
}
|
|
out += ' }';
|
|
if ($breakOnError) {
|
|
out += ' else { ';
|
|
}
|
|
return out;
|
|
}
|
|
|
|
|
|
/***/ }),
|
|
|
|
/***/ 2119:
|
|
/***/ (function(module) {
|
|
|
|
"use strict";
|
|
|
|
module.exports = function generate_contains(it, $keyword, $ruleType) {
|
|
var out = ' ';
|
|
var $lvl = it.level;
|
|
var $dataLvl = it.dataLevel;
|
|
var $schema = it.schema[$keyword];
|
|
var $schemaPath = it.schemaPath + it.util.getProperty($keyword);
|
|
var $errSchemaPath = it.errSchemaPath + '/' + $keyword;
|
|
var $breakOnError = !it.opts.allErrors;
|
|
var $data = 'data' + ($dataLvl || '');
|
|
var $valid = 'valid' + $lvl;
|
|
var $errs = 'errs__' + $lvl;
|
|
var $it = it.util.copy(it);
|
|
var $closingBraces = '';
|
|
$it.level++;
|
|
var $nextValid = 'valid' + $it.level;
|
|
var $idx = 'i' + $lvl,
|
|
$dataNxt = $it.dataLevel = it.dataLevel + 1,
|
|
$nextData = 'data' + $dataNxt,
|
|
$currentBaseId = it.baseId,
|
|
$nonEmptySchema = (it.opts.strictKeywords ? (typeof $schema == 'object' && Object.keys($schema).length > 0) || $schema === false : it.util.schemaHasRules($schema, it.RULES.all));
|
|
out += 'var ' + ($errs) + ' = errors;var ' + ($valid) + ';';
|
|
if ($nonEmptySchema) {
|
|
var $wasComposite = it.compositeRule;
|
|
it.compositeRule = $it.compositeRule = true;
|
|
$it.schema = $schema;
|
|
$it.schemaPath = $schemaPath;
|
|
$it.errSchemaPath = $errSchemaPath;
|
|
out += ' var ' + ($nextValid) + ' = false; for (var ' + ($idx) + ' = 0; ' + ($idx) + ' < ' + ($data) + '.length; ' + ($idx) + '++) { ';
|
|
$it.errorPath = it.util.getPathExpr(it.errorPath, $idx, it.opts.jsonPointers, true);
|
|
var $passData = $data + '[' + $idx + ']';
|
|
$it.dataPathArr[$dataNxt] = $idx;
|
|
var $code = it.validate($it);
|
|
$it.baseId = $currentBaseId;
|
|
if (it.util.varOccurences($code, $nextData) < 2) {
|
|
out += ' ' + (it.util.varReplace($code, $nextData, $passData)) + ' ';
|
|
} else {
|
|
out += ' var ' + ($nextData) + ' = ' + ($passData) + '; ' + ($code) + ' ';
|
|
}
|
|
out += ' if (' + ($nextValid) + ') break; } ';
|
|
it.compositeRule = $it.compositeRule = $wasComposite;
|
|
out += ' ' + ($closingBraces) + ' if (!' + ($nextValid) + ') {';
|
|
} else {
|
|
out += ' if (' + ($data) + '.length == 0) {';
|
|
}
|
|
var $$outStack = $$outStack || [];
|
|
$$outStack.push(out);
|
|
out = ''; /* istanbul ignore else */
|
|
if (it.createErrors !== false) {
|
|
out += ' { keyword: \'' + ('contains') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: {} ';
|
|
if (it.opts.messages !== false) {
|
|
out += ' , message: \'should contain a valid item\' ';
|
|
}
|
|
if (it.opts.verbose) {
|
|
out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
|
|
}
|
|
out += ' } ';
|
|
} else {
|
|
out += ' {} ';
|
|
}
|
|
var __err = out;
|
|
out = $$outStack.pop();
|
|
if (!it.compositeRule && $breakOnError) {
|
|
/* istanbul ignore if */
|
|
if (it.async) {
|
|
out += ' throw new ValidationError([' + (__err) + ']); ';
|
|
} else {
|
|
out += ' validate.errors = [' + (__err) + ']; return false; ';
|
|
}
|
|
} else {
|
|
out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';
|
|
}
|
|
out += ' } else { ';
|
|
if ($nonEmptySchema) {
|
|
out += ' errors = ' + ($errs) + '; if (vErrors !== null) { if (' + ($errs) + ') vErrors.length = ' + ($errs) + '; else vErrors = null; } ';
|
|
}
|
|
if (it.opts.allErrors) {
|
|
out += ' } ';
|
|
}
|
|
return out;
|
|
}
|
|
|
|
|
|
/***/ }),
|
|
|
|
/***/ 1793:
|
|
/***/ (function(module) {
|
|
|
|
"use strict";
|
|
|
|
module.exports = function generate_custom(it, $keyword, $ruleType) {
|
|
var out = ' ';
|
|
var $lvl = it.level;
|
|
var $dataLvl = it.dataLevel;
|
|
var $schema = it.schema[$keyword];
|
|
var $schemaPath = it.schemaPath + it.util.getProperty($keyword);
|
|
var $errSchemaPath = it.errSchemaPath + '/' + $keyword;
|
|
var $breakOnError = !it.opts.allErrors;
|
|
var $errorKeyword;
|
|
var $data = 'data' + ($dataLvl || '');
|
|
var $valid = 'valid' + $lvl;
|
|
var $errs = 'errs__' + $lvl;
|
|
var $isData = it.opts.$data && $schema && $schema.$data,
|
|
$schemaValue;
|
|
if ($isData) {
|
|
out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; ';
|
|
$schemaValue = 'schema' + $lvl;
|
|
} else {
|
|
$schemaValue = $schema;
|
|
}
|
|
var $rule = this,
|
|
$definition = 'definition' + $lvl,
|
|
$rDef = $rule.definition,
|
|
$closingBraces = '';
|
|
var $compile, $inline, $macro, $ruleValidate, $validateCode;
|
|
if ($isData && $rDef.$data) {
|
|
$validateCode = 'keywordValidate' + $lvl;
|
|
var $validateSchema = $rDef.validateSchema;
|
|
out += ' var ' + ($definition) + ' = RULES.custom[\'' + ($keyword) + '\'].definition; var ' + ($validateCode) + ' = ' + ($definition) + '.validate;';
|
|
} else {
|
|
$ruleValidate = it.useCustomRule($rule, $schema, it.schema, it);
|
|
if (!$ruleValidate) return;
|
|
$schemaValue = 'validate.schema' + $schemaPath;
|
|
$validateCode = $ruleValidate.code;
|
|
$compile = $rDef.compile;
|
|
$inline = $rDef.inline;
|
|
$macro = $rDef.macro;
|
|
}
|
|
var $ruleErrs = $validateCode + '.errors',
|
|
$i = 'i' + $lvl,
|
|
$ruleErr = 'ruleErr' + $lvl,
|
|
$asyncKeyword = $rDef.async;
|
|
if ($asyncKeyword && !it.async) throw new Error('async keyword in sync schema');
|
|
if (!($inline || $macro)) {
|
|
out += '' + ($ruleErrs) + ' = null;';
|
|
}
|
|
out += 'var ' + ($errs) + ' = errors;var ' + ($valid) + ';';
|
|
if ($isData && $rDef.$data) {
|
|
$closingBraces += '}';
|
|
out += ' if (' + ($schemaValue) + ' === undefined) { ' + ($valid) + ' = true; } else { ';
|
|
if ($validateSchema) {
|
|
$closingBraces += '}';
|
|
out += ' ' + ($valid) + ' = ' + ($definition) + '.validateSchema(' + ($schemaValue) + '); if (' + ($valid) + ') { ';
|
|
}
|
|
}
|
|
if ($inline) {
|
|
if ($rDef.statements) {
|
|
out += ' ' + ($ruleValidate.validate) + ' ';
|
|
} else {
|
|
out += ' ' + ($valid) + ' = ' + ($ruleValidate.validate) + '; ';
|
|
}
|
|
} else if ($macro) {
|
|
var $it = it.util.copy(it);
|
|
var $closingBraces = '';
|
|
$it.level++;
|
|
var $nextValid = 'valid' + $it.level;
|
|
$it.schema = $ruleValidate.validate;
|
|
$it.schemaPath = '';
|
|
var $wasComposite = it.compositeRule;
|
|
it.compositeRule = $it.compositeRule = true;
|
|
var $code = it.validate($it).replace(/validate\.schema/g, $validateCode);
|
|
it.compositeRule = $it.compositeRule = $wasComposite;
|
|
out += ' ' + ($code);
|
|
} else {
|
|
var $$outStack = $$outStack || [];
|
|
$$outStack.push(out);
|
|
out = '';
|
|
out += ' ' + ($validateCode) + '.call( ';
|
|
if (it.opts.passContext) {
|
|
out += 'this';
|
|
} else {
|
|
out += 'self';
|
|
}
|
|
if ($compile || $rDef.schema === false) {
|
|
out += ' , ' + ($data) + ' ';
|
|
} else {
|
|
out += ' , ' + ($schemaValue) + ' , ' + ($data) + ' , validate.schema' + (it.schemaPath) + ' ';
|
|
}
|
|
out += ' , (dataPath || \'\')';
|
|
if (it.errorPath != '""') {
|
|
out += ' + ' + (it.errorPath);
|
|
}
|
|
var $parentData = $dataLvl ? 'data' + (($dataLvl - 1) || '') : 'parentData',
|
|
$parentDataProperty = $dataLvl ? it.dataPathArr[$dataLvl] : 'parentDataProperty';
|
|
out += ' , ' + ($parentData) + ' , ' + ($parentDataProperty) + ' , rootData ) ';
|
|
var def_callRuleValidate = out;
|
|
out = $$outStack.pop();
|
|
if ($rDef.errors === false) {
|
|
out += ' ' + ($valid) + ' = ';
|
|
if ($asyncKeyword) {
|
|
out += 'await ';
|
|
}
|
|
out += '' + (def_callRuleValidate) + '; ';
|
|
} else {
|
|
if ($asyncKeyword) {
|
|
$ruleErrs = 'customErrors' + $lvl;
|
|
out += ' var ' + ($ruleErrs) + ' = null; try { ' + ($valid) + ' = await ' + (def_callRuleValidate) + '; } catch (e) { ' + ($valid) + ' = false; if (e instanceof ValidationError) ' + ($ruleErrs) + ' = e.errors; else throw e; } ';
|
|
} else {
|
|
out += ' ' + ($ruleErrs) + ' = null; ' + ($valid) + ' = ' + (def_callRuleValidate) + '; ';
|
|
}
|
|
}
|
|
}
|
|
if ($rDef.modifying) {
|
|
out += ' if (' + ($parentData) + ') ' + ($data) + ' = ' + ($parentData) + '[' + ($parentDataProperty) + '];';
|
|
}
|
|
out += '' + ($closingBraces);
|
|
if ($rDef.valid) {
|
|
if ($breakOnError) {
|
|
out += ' if (true) { ';
|
|
}
|
|
} else {
|
|
out += ' if ( ';
|
|
if ($rDef.valid === undefined) {
|
|
out += ' !';
|
|
if ($macro) {
|
|
out += '' + ($nextValid);
|
|
} else {
|
|
out += '' + ($valid);
|
|
}
|
|
} else {
|
|
out += ' ' + (!$rDef.valid) + ' ';
|
|
}
|
|
out += ') { ';
|
|
$errorKeyword = $rule.keyword;
|
|
var $$outStack = $$outStack || [];
|
|
$$outStack.push(out);
|
|
out = '';
|
|
var $$outStack = $$outStack || [];
|
|
$$outStack.push(out);
|
|
out = ''; /* istanbul ignore else */
|
|
if (it.createErrors !== false) {
|
|
out += ' { keyword: \'' + ($errorKeyword || 'custom') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { keyword: \'' + ($rule.keyword) + '\' } ';
|
|
if (it.opts.messages !== false) {
|
|
out += ' , message: \'should pass "' + ($rule.keyword) + '" keyword validation\' ';
|
|
}
|
|
if (it.opts.verbose) {
|
|
out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
|
|
}
|
|
out += ' } ';
|
|
} else {
|
|
out += ' {} ';
|
|
}
|
|
var __err = out;
|
|
out = $$outStack.pop();
|
|
if (!it.compositeRule && $breakOnError) {
|
|
/* istanbul ignore if */
|
|
if (it.async) {
|
|
out += ' throw new ValidationError([' + (__err) + ']); ';
|
|
} else {
|
|
out += ' validate.errors = [' + (__err) + ']; return false; ';
|
|
}
|
|
} else {
|
|
out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';
|
|
}
|
|
var def_customError = out;
|
|
out = $$outStack.pop();
|
|
if ($inline) {
|
|
if ($rDef.errors) {
|
|
if ($rDef.errors != 'full') {
|
|
out += ' for (var ' + ($i) + '=' + ($errs) + '; ' + ($i) + '<errors; ' + ($i) + '++) { var ' + ($ruleErr) + ' = vErrors[' + ($i) + ']; if (' + ($ruleErr) + '.dataPath === undefined) ' + ($ruleErr) + '.dataPath = (dataPath || \'\') + ' + (it.errorPath) + '; if (' + ($ruleErr) + '.schemaPath === undefined) { ' + ($ruleErr) + '.schemaPath = "' + ($errSchemaPath) + '"; } ';
|
|
if (it.opts.verbose) {
|
|
out += ' ' + ($ruleErr) + '.schema = ' + ($schemaValue) + '; ' + ($ruleErr) + '.data = ' + ($data) + '; ';
|
|
}
|
|
out += ' } ';
|
|
}
|
|
} else {
|
|
if ($rDef.errors === false) {
|
|
out += ' ' + (def_customError) + ' ';
|
|
} else {
|
|
out += ' if (' + ($errs) + ' == errors) { ' + (def_customError) + ' } else { for (var ' + ($i) + '=' + ($errs) + '; ' + ($i) + '<errors; ' + ($i) + '++) { var ' + ($ruleErr) + ' = vErrors[' + ($i) + ']; if (' + ($ruleErr) + '.dataPath === undefined) ' + ($ruleErr) + '.dataPath = (dataPath || \'\') + ' + (it.errorPath) + '; if (' + ($ruleErr) + '.schemaPath === undefined) { ' + ($ruleErr) + '.schemaPath = "' + ($errSchemaPath) + '"; } ';
|
|
if (it.opts.verbose) {
|
|
out += ' ' + ($ruleErr) + '.schema = ' + ($schemaValue) + '; ' + ($ruleErr) + '.data = ' + ($data) + '; ';
|
|
}
|
|
out += ' } } ';
|
|
}
|
|
}
|
|
} else if ($macro) {
|
|
out += ' var err = '; /* istanbul ignore else */
|
|
if (it.createErrors !== false) {
|
|
out += ' { keyword: \'' + ($errorKeyword || 'custom') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { keyword: \'' + ($rule.keyword) + '\' } ';
|
|
if (it.opts.messages !== false) {
|
|
out += ' , message: \'should pass "' + ($rule.keyword) + '" keyword validation\' ';
|
|
}
|
|
if (it.opts.verbose) {
|
|
out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
|
|
}
|
|
out += ' } ';
|
|
} else {
|
|
out += ' {} ';
|
|
}
|
|
out += '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';
|
|
if (!it.compositeRule && $breakOnError) {
|
|
/* istanbul ignore if */
|
|
if (it.async) {
|
|
out += ' throw new ValidationError(vErrors); ';
|
|
} else {
|
|
out += ' validate.errors = vErrors; return false; ';
|
|
}
|
|
}
|
|
} else {
|
|
if ($rDef.errors === false) {
|
|
out += ' ' + (def_customError) + ' ';
|
|
} else {
|
|
out += ' if (Array.isArray(' + ($ruleErrs) + ')) { if (vErrors === null) vErrors = ' + ($ruleErrs) + '; else vErrors = vErrors.concat(' + ($ruleErrs) + '); errors = vErrors.length; for (var ' + ($i) + '=' + ($errs) + '; ' + ($i) + '<errors; ' + ($i) + '++) { var ' + ($ruleErr) + ' = vErrors[' + ($i) + ']; if (' + ($ruleErr) + '.dataPath === undefined) ' + ($ruleErr) + '.dataPath = (dataPath || \'\') + ' + (it.errorPath) + '; ' + ($ruleErr) + '.schemaPath = "' + ($errSchemaPath) + '"; ';
|
|
if (it.opts.verbose) {
|
|
out += ' ' + ($ruleErr) + '.schema = ' + ($schemaValue) + '; ' + ($ruleErr) + '.data = ' + ($data) + '; ';
|
|
}
|
|
out += ' } } else { ' + (def_customError) + ' } ';
|
|
}
|
|
}
|
|
out += ' } ';
|
|
if ($breakOnError) {
|
|
out += ' else { ';
|
|
}
|
|
}
|
|
return out;
|
|
}
|
|
|
|
|
|
/***/ }),
|
|
|
|
/***/ 9115:
|
|
/***/ (function(module) {
|
|
|
|
"use strict";
|
|
|
|
module.exports = function generate_dependencies(it, $keyword, $ruleType) {
|
|
var out = ' ';
|
|
var $lvl = it.level;
|
|
var $dataLvl = it.dataLevel;
|
|
var $schema = it.schema[$keyword];
|
|
var $schemaPath = it.schemaPath + it.util.getProperty($keyword);
|
|
var $errSchemaPath = it.errSchemaPath + '/' + $keyword;
|
|
var $breakOnError = !it.opts.allErrors;
|
|
var $data = 'data' + ($dataLvl || '');
|
|
var $errs = 'errs__' + $lvl;
|
|
var $it = it.util.copy(it);
|
|
var $closingBraces = '';
|
|
$it.level++;
|
|
var $nextValid = 'valid' + $it.level;
|
|
var $schemaDeps = {},
|
|
$propertyDeps = {},
|
|
$ownProperties = it.opts.ownProperties;
|
|
for ($property in $schema) {
|
|
if ($property == '__proto__') continue;
|
|
var $sch = $schema[$property];
|
|
var $deps = Array.isArray($sch) ? $propertyDeps : $schemaDeps;
|
|
$deps[$property] = $sch;
|
|
}
|
|
out += 'var ' + ($errs) + ' = errors;';
|
|
var $currentErrorPath = it.errorPath;
|
|
out += 'var missing' + ($lvl) + ';';
|
|
for (var $property in $propertyDeps) {
|
|
$deps = $propertyDeps[$property];
|
|
if ($deps.length) {
|
|
out += ' if ( ' + ($data) + (it.util.getProperty($property)) + ' !== undefined ';
|
|
if ($ownProperties) {
|
|
out += ' && Object.prototype.hasOwnProperty.call(' + ($data) + ', \'' + (it.util.escapeQuotes($property)) + '\') ';
|
|
}
|
|
if ($breakOnError) {
|
|
out += ' && ( ';
|
|
var arr1 = $deps;
|
|
if (arr1) {
|
|
var $propertyKey, $i = -1,
|
|
l1 = arr1.length - 1;
|
|
while ($i < l1) {
|
|
$propertyKey = arr1[$i += 1];
|
|
if ($i) {
|
|
out += ' || ';
|
|
}
|
|
var $prop = it.util.getProperty($propertyKey),
|
|
$useData = $data + $prop;
|
|
out += ' ( ( ' + ($useData) + ' === undefined ';
|
|
if ($ownProperties) {
|
|
out += ' || ! Object.prototype.hasOwnProperty.call(' + ($data) + ', \'' + (it.util.escapeQuotes($propertyKey)) + '\') ';
|
|
}
|
|
out += ') && (missing' + ($lvl) + ' = ' + (it.util.toQuotedString(it.opts.jsonPointers ? $propertyKey : $prop)) + ') ) ';
|
|
}
|
|
}
|
|
out += ')) { ';
|
|
var $propertyPath = 'missing' + $lvl,
|
|
$missingProperty = '\' + ' + $propertyPath + ' + \'';
|
|
if (it.opts._errorDataPathProperty) {
|
|
it.errorPath = it.opts.jsonPointers ? it.util.getPathExpr($currentErrorPath, $propertyPath, true) : $currentErrorPath + ' + ' + $propertyPath;
|
|
}
|
|
var $$outStack = $$outStack || [];
|
|
$$outStack.push(out);
|
|
out = ''; /* istanbul ignore else */
|
|
if (it.createErrors !== false) {
|
|
out += ' { keyword: \'' + ('dependencies') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { property: \'' + (it.util.escapeQuotes($property)) + '\', missingProperty: \'' + ($missingProperty) + '\', depsCount: ' + ($deps.length) + ', deps: \'' + (it.util.escapeQuotes($deps.length == 1 ? $deps[0] : $deps.join(", "))) + '\' } ';
|
|
if (it.opts.messages !== false) {
|
|
out += ' , message: \'should have ';
|
|
if ($deps.length == 1) {
|
|
out += 'property ' + (it.util.escapeQuotes($deps[0]));
|
|
} else {
|
|
out += 'properties ' + (it.util.escapeQuotes($deps.join(", ")));
|
|
}
|
|
out += ' when property ' + (it.util.escapeQuotes($property)) + ' is present\' ';
|
|
}
|
|
if (it.opts.verbose) {
|
|
out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
|
|
}
|
|
out += ' } ';
|
|
} else {
|
|
out += ' {} ';
|
|
}
|
|
var __err = out;
|
|
out = $$outStack.pop();
|
|
if (!it.compositeRule && $breakOnError) {
|
|
/* istanbul ignore if */
|
|
if (it.async) {
|
|
out += ' throw new ValidationError([' + (__err) + ']); ';
|
|
} else {
|
|
out += ' validate.errors = [' + (__err) + ']; return false; ';
|
|
}
|
|
} else {
|
|
out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';
|
|
}
|
|
} else {
|
|
out += ' ) { ';
|
|
var arr2 = $deps;
|
|
if (arr2) {
|
|
var $propertyKey, i2 = -1,
|
|
l2 = arr2.length - 1;
|
|
while (i2 < l2) {
|
|
$propertyKey = arr2[i2 += 1];
|
|
var $prop = it.util.getProperty($propertyKey),
|
|
$missingProperty = it.util.escapeQuotes($propertyKey),
|
|
$useData = $data + $prop;
|
|
if (it.opts._errorDataPathProperty) {
|
|
it.errorPath = it.util.getPath($currentErrorPath, $propertyKey, it.opts.jsonPointers);
|
|
}
|
|
out += ' if ( ' + ($useData) + ' === undefined ';
|
|
if ($ownProperties) {
|
|
out += ' || ! Object.prototype.hasOwnProperty.call(' + ($data) + ', \'' + (it.util.escapeQuotes($propertyKey)) + '\') ';
|
|
}
|
|
out += ') { var err = '; /* istanbul ignore else */
|
|
if (it.createErrors !== false) {
|
|
out += ' { keyword: \'' + ('dependencies') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { property: \'' + (it.util.escapeQuotes($property)) + '\', missingProperty: \'' + ($missingProperty) + '\', depsCount: ' + ($deps.length) + ', deps: \'' + (it.util.escapeQuotes($deps.length == 1 ? $deps[0] : $deps.join(", "))) + '\' } ';
|
|
if (it.opts.messages !== false) {
|
|
out += ' , message: \'should have ';
|
|
if ($deps.length == 1) {
|
|
out += 'property ' + (it.util.escapeQuotes($deps[0]));
|
|
} else {
|
|
out += 'properties ' + (it.util.escapeQuotes($deps.join(", ")));
|
|
}
|
|
out += ' when property ' + (it.util.escapeQuotes($property)) + ' is present\' ';
|
|
}
|
|
if (it.opts.verbose) {
|
|
out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
|
|
}
|
|
out += ' } ';
|
|
} else {
|
|
out += ' {} ';
|
|
}
|
|
out += '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; } ';
|
|
}
|
|
}
|
|
}
|
|
out += ' } ';
|
|
if ($breakOnError) {
|
|
$closingBraces += '}';
|
|
out += ' else { ';
|
|
}
|
|
}
|
|
}
|
|
it.errorPath = $currentErrorPath;
|
|
var $currentBaseId = $it.baseId;
|
|
for (var $property in $schemaDeps) {
|
|
var $sch = $schemaDeps[$property];
|
|
if ((it.opts.strictKeywords ? (typeof $sch == 'object' && Object.keys($sch).length > 0) || $sch === false : it.util.schemaHasRules($sch, it.RULES.all))) {
|
|
out += ' ' + ($nextValid) + ' = true; if ( ' + ($data) + (it.util.getProperty($property)) + ' !== undefined ';
|
|
if ($ownProperties) {
|
|
out += ' && Object.prototype.hasOwnProperty.call(' + ($data) + ', \'' + (it.util.escapeQuotes($property)) + '\') ';
|
|
}
|
|
out += ') { ';
|
|
$it.schema = $sch;
|
|
$it.schemaPath = $schemaPath + it.util.getProperty($property);
|
|
$it.errSchemaPath = $errSchemaPath + '/' + it.util.escapeFragment($property);
|
|
out += ' ' + (it.validate($it)) + ' ';
|
|
$it.baseId = $currentBaseId;
|
|
out += ' } ';
|
|
if ($breakOnError) {
|
|
out += ' if (' + ($nextValid) + ') { ';
|
|
$closingBraces += '}';
|
|
}
|
|
}
|
|
}
|
|
if ($breakOnError) {
|
|
out += ' ' + ($closingBraces) + ' if (' + ($errs) + ' == errors) {';
|
|
}
|
|
return out;
|
|
}
|
|
|
|
|
|
/***/ }),
|
|
|
|
/***/ 9317:
|
|
/***/ (function(module) {
|
|
|
|
"use strict";
|
|
|
|
module.exports = function generate_enum(it, $keyword, $ruleType) {
|
|
var out = ' ';
|
|
var $lvl = it.level;
|
|
var $dataLvl = it.dataLevel;
|
|
var $schema = it.schema[$keyword];
|
|
var $schemaPath = it.schemaPath + it.util.getProperty($keyword);
|
|
var $errSchemaPath = it.errSchemaPath + '/' + $keyword;
|
|
var $breakOnError = !it.opts.allErrors;
|
|
var $data = 'data' + ($dataLvl || '');
|
|
var $valid = 'valid' + $lvl;
|
|
var $isData = it.opts.$data && $schema && $schema.$data,
|
|
$schemaValue;
|
|
if ($isData) {
|
|
out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; ';
|
|
$schemaValue = 'schema' + $lvl;
|
|
} else {
|
|
$schemaValue = $schema;
|
|
}
|
|
var $i = 'i' + $lvl,
|
|
$vSchema = 'schema' + $lvl;
|
|
if (!$isData) {
|
|
out += ' var ' + ($vSchema) + ' = validate.schema' + ($schemaPath) + ';';
|
|
}
|
|
out += 'var ' + ($valid) + ';';
|
|
if ($isData) {
|
|
out += ' if (schema' + ($lvl) + ' === undefined) ' + ($valid) + ' = true; else if (!Array.isArray(schema' + ($lvl) + ')) ' + ($valid) + ' = false; else {';
|
|
}
|
|
out += '' + ($valid) + ' = false;for (var ' + ($i) + '=0; ' + ($i) + '<' + ($vSchema) + '.length; ' + ($i) + '++) if (equal(' + ($data) + ', ' + ($vSchema) + '[' + ($i) + '])) { ' + ($valid) + ' = true; break; }';
|
|
if ($isData) {
|
|
out += ' } ';
|
|
}
|
|
out += ' if (!' + ($valid) + ') { ';
|
|
var $$outStack = $$outStack || [];
|
|
$$outStack.push(out);
|
|
out = ''; /* istanbul ignore else */
|
|
if (it.createErrors !== false) {
|
|
out += ' { keyword: \'' + ('enum') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { allowedValues: schema' + ($lvl) + ' } ';
|
|
if (it.opts.messages !== false) {
|
|
out += ' , message: \'should be equal to one of the allowed values\' ';
|
|
}
|
|
if (it.opts.verbose) {
|
|
out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
|
|
}
|
|
out += ' } ';
|
|
} else {
|
|
out += ' {} ';
|
|
}
|
|
var __err = out;
|
|
out = $$outStack.pop();
|
|
if (!it.compositeRule && $breakOnError) {
|
|
/* istanbul ignore if */
|
|
if (it.async) {
|
|
out += ' throw new ValidationError([' + (__err) + ']); ';
|
|
} else {
|
|
out += ' validate.errors = [' + (__err) + ']; return false; ';
|
|
}
|
|
} else {
|
|
out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';
|
|
}
|
|
out += ' }';
|
|
if ($breakOnError) {
|
|
out += ' else { ';
|
|
}
|
|
return out;
|
|
}
|
|
|
|
|
|
/***/ }),
|
|
|
|
/***/ 8327:
|
|
/***/ (function(module) {
|
|
|
|
"use strict";
|
|
|
|
module.exports = function generate_format(it, $keyword, $ruleType) {
|
|
var out = ' ';
|
|
var $lvl = it.level;
|
|
var $dataLvl = it.dataLevel;
|
|
var $schema = it.schema[$keyword];
|
|
var $schemaPath = it.schemaPath + it.util.getProperty($keyword);
|
|
var $errSchemaPath = it.errSchemaPath + '/' + $keyword;
|
|
var $breakOnError = !it.opts.allErrors;
|
|
var $data = 'data' + ($dataLvl || '');
|
|
if (it.opts.format === false) {
|
|
if ($breakOnError) {
|
|
out += ' if (true) { ';
|
|
}
|
|
return out;
|
|
}
|
|
var $isData = it.opts.$data && $schema && $schema.$data,
|
|
$schemaValue;
|
|
if ($isData) {
|
|
out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; ';
|
|
$schemaValue = 'schema' + $lvl;
|
|
} else {
|
|
$schemaValue = $schema;
|
|
}
|
|
var $unknownFormats = it.opts.unknownFormats,
|
|
$allowUnknown = Array.isArray($unknownFormats);
|
|
if ($isData) {
|
|
var $format = 'format' + $lvl,
|
|
$isObject = 'isObject' + $lvl,
|
|
$formatType = 'formatType' + $lvl;
|
|
out += ' var ' + ($format) + ' = formats[' + ($schemaValue) + ']; var ' + ($isObject) + ' = typeof ' + ($format) + ' == \'object\' && !(' + ($format) + ' instanceof RegExp) && ' + ($format) + '.validate; var ' + ($formatType) + ' = ' + ($isObject) + ' && ' + ($format) + '.type || \'string\'; if (' + ($isObject) + ') { ';
|
|
if (it.async) {
|
|
out += ' var async' + ($lvl) + ' = ' + ($format) + '.async; ';
|
|
}
|
|
out += ' ' + ($format) + ' = ' + ($format) + '.validate; } if ( ';
|
|
if ($isData) {
|
|
out += ' (' + ($schemaValue) + ' !== undefined && typeof ' + ($schemaValue) + ' != \'string\') || ';
|
|
}
|
|
out += ' (';
|
|
if ($unknownFormats != 'ignore') {
|
|
out += ' (' + ($schemaValue) + ' && !' + ($format) + ' ';
|
|
if ($allowUnknown) {
|
|
out += ' && self._opts.unknownFormats.indexOf(' + ($schemaValue) + ') == -1 ';
|
|
}
|
|
out += ') || ';
|
|
}
|
|
out += ' (' + ($format) + ' && ' + ($formatType) + ' == \'' + ($ruleType) + '\' && !(typeof ' + ($format) + ' == \'function\' ? ';
|
|
if (it.async) {
|
|
out += ' (async' + ($lvl) + ' ? await ' + ($format) + '(' + ($data) + ') : ' + ($format) + '(' + ($data) + ')) ';
|
|
} else {
|
|
out += ' ' + ($format) + '(' + ($data) + ') ';
|
|
}
|
|
out += ' : ' + ($format) + '.test(' + ($data) + '))))) {';
|
|
} else {
|
|
var $format = it.formats[$schema];
|
|
if (!$format) {
|
|
if ($unknownFormats == 'ignore') {
|
|
it.logger.warn('unknown format "' + $schema + '" ignored in schema at path "' + it.errSchemaPath + '"');
|
|
if ($breakOnError) {
|
|
out += ' if (true) { ';
|
|
}
|
|
return out;
|
|
} else if ($allowUnknown && $unknownFormats.indexOf($schema) >= 0) {
|
|
if ($breakOnError) {
|
|
out += ' if (true) { ';
|
|
}
|
|
return out;
|
|
} else {
|
|
throw new Error('unknown format "' + $schema + '" is used in schema at path "' + it.errSchemaPath + '"');
|
|
}
|
|
}
|
|
var $isObject = typeof $format == 'object' && !($format instanceof RegExp) && $format.validate;
|
|
var $formatType = $isObject && $format.type || 'string';
|
|
if ($isObject) {
|
|
var $async = $format.async === true;
|
|
$format = $format.validate;
|
|
}
|
|
if ($formatType != $ruleType) {
|
|
if ($breakOnError) {
|
|
out += ' if (true) { ';
|
|
}
|
|
return out;
|
|
}
|
|
if ($async) {
|
|
if (!it.async) throw new Error('async format in sync schema');
|
|
var $formatRef = 'formats' + it.util.getProperty($schema) + '.validate';
|
|
out += ' if (!(await ' + ($formatRef) + '(' + ($data) + '))) { ';
|
|
} else {
|
|
out += ' if (! ';
|
|
var $formatRef = 'formats' + it.util.getProperty($schema);
|
|
if ($isObject) $formatRef += '.validate';
|
|
if (typeof $format == 'function') {
|
|
out += ' ' + ($formatRef) + '(' + ($data) + ') ';
|
|
} else {
|
|
out += ' ' + ($formatRef) + '.test(' + ($data) + ') ';
|
|
}
|
|
out += ') { ';
|
|
}
|
|
}
|
|
var $$outStack = $$outStack || [];
|
|
$$outStack.push(out);
|
|
out = ''; /* istanbul ignore else */
|
|
if (it.createErrors !== false) {
|
|
out += ' { keyword: \'' + ('format') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { format: ';
|
|
if ($isData) {
|
|
out += '' + ($schemaValue);
|
|
} else {
|
|
out += '' + (it.util.toQuotedString($schema));
|
|
}
|
|
out += ' } ';
|
|
if (it.opts.messages !== false) {
|
|
out += ' , message: \'should match format "';
|
|
if ($isData) {
|
|
out += '\' + ' + ($schemaValue) + ' + \'';
|
|
} else {
|
|
out += '' + (it.util.escapeQuotes($schema));
|
|
}
|
|
out += '"\' ';
|
|
}
|
|
if (it.opts.verbose) {
|
|
out += ' , schema: ';
|
|
if ($isData) {
|
|
out += 'validate.schema' + ($schemaPath);
|
|
} else {
|
|
out += '' + (it.util.toQuotedString($schema));
|
|
}
|
|
out += ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
|
|
}
|
|
out += ' } ';
|
|
} else {
|
|
out += ' {} ';
|
|
}
|
|
var __err = out;
|
|
out = $$outStack.pop();
|
|
if (!it.compositeRule && $breakOnError) {
|
|
/* istanbul ignore if */
|
|
if (it.async) {
|
|
out += ' throw new ValidationError([' + (__err) + ']); ';
|
|
} else {
|
|
out += ' validate.errors = [' + (__err) + ']; return false; ';
|
|
}
|
|
} else {
|
|
out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';
|
|
}
|
|
out += ' } ';
|
|
if ($breakOnError) {
|
|
out += ' else { ';
|
|
}
|
|
return out;
|
|
}
|
|
|
|
|
|
/***/ }),
|
|
|
|
/***/ 5926:
|
|
/***/ (function(module) {
|
|
|
|
"use strict";
|
|
|
|
module.exports = function generate_if(it, $keyword, $ruleType) {
|
|
var out = ' ';
|
|
var $lvl = it.level;
|
|
var $dataLvl = it.dataLevel;
|
|
var $schema = it.schema[$keyword];
|
|
var $schemaPath = it.schemaPath + it.util.getProperty($keyword);
|
|
var $errSchemaPath = it.errSchemaPath + '/' + $keyword;
|
|
var $breakOnError = !it.opts.allErrors;
|
|
var $data = 'data' + ($dataLvl || '');
|
|
var $valid = 'valid' + $lvl;
|
|
var $errs = 'errs__' + $lvl;
|
|
var $it = it.util.copy(it);
|
|
$it.level++;
|
|
var $nextValid = 'valid' + $it.level;
|
|
var $thenSch = it.schema['then'],
|
|
$elseSch = it.schema['else'],
|
|
$thenPresent = $thenSch !== undefined && (it.opts.strictKeywords ? (typeof $thenSch == 'object' && Object.keys($thenSch).length > 0) || $thenSch === false : it.util.schemaHasRules($thenSch, it.RULES.all)),
|
|
$elsePresent = $elseSch !== undefined && (it.opts.strictKeywords ? (typeof $elseSch == 'object' && Object.keys($elseSch).length > 0) || $elseSch === false : it.util.schemaHasRules($elseSch, it.RULES.all)),
|
|
$currentBaseId = $it.baseId;
|
|
if ($thenPresent || $elsePresent) {
|
|
var $ifClause;
|
|
$it.createErrors = false;
|
|
$it.schema = $schema;
|
|
$it.schemaPath = $schemaPath;
|
|
$it.errSchemaPath = $errSchemaPath;
|
|
out += ' var ' + ($errs) + ' = errors; var ' + ($valid) + ' = true; ';
|
|
var $wasComposite = it.compositeRule;
|
|
it.compositeRule = $it.compositeRule = true;
|
|
out += ' ' + (it.validate($it)) + ' ';
|
|
$it.baseId = $currentBaseId;
|
|
$it.createErrors = true;
|
|
out += ' errors = ' + ($errs) + '; if (vErrors !== null) { if (' + ($errs) + ') vErrors.length = ' + ($errs) + '; else vErrors = null; } ';
|
|
it.compositeRule = $it.compositeRule = $wasComposite;
|
|
if ($thenPresent) {
|
|
out += ' if (' + ($nextValid) + ') { ';
|
|
$it.schema = it.schema['then'];
|
|
$it.schemaPath = it.schemaPath + '.then';
|
|
$it.errSchemaPath = it.errSchemaPath + '/then';
|
|
out += ' ' + (it.validate($it)) + ' ';
|
|
$it.baseId = $currentBaseId;
|
|
out += ' ' + ($valid) + ' = ' + ($nextValid) + '; ';
|
|
if ($thenPresent && $elsePresent) {
|
|
$ifClause = 'ifClause' + $lvl;
|
|
out += ' var ' + ($ifClause) + ' = \'then\'; ';
|
|
} else {
|
|
$ifClause = '\'then\'';
|
|
}
|
|
out += ' } ';
|
|
if ($elsePresent) {
|
|
out += ' else { ';
|
|
}
|
|
} else {
|
|
out += ' if (!' + ($nextValid) + ') { ';
|
|
}
|
|
if ($elsePresent) {
|
|
$it.schema = it.schema['else'];
|
|
$it.schemaPath = it.schemaPath + '.else';
|
|
$it.errSchemaPath = it.errSchemaPath + '/else';
|
|
out += ' ' + (it.validate($it)) + ' ';
|
|
$it.baseId = $currentBaseId;
|
|
out += ' ' + ($valid) + ' = ' + ($nextValid) + '; ';
|
|
if ($thenPresent && $elsePresent) {
|
|
$ifClause = 'ifClause' + $lvl;
|
|
out += ' var ' + ($ifClause) + ' = \'else\'; ';
|
|
} else {
|
|
$ifClause = '\'else\'';
|
|
}
|
|
out += ' } ';
|
|
}
|
|
out += ' if (!' + ($valid) + ') { var err = '; /* istanbul ignore else */
|
|
if (it.createErrors !== false) {
|
|
out += ' { keyword: \'' + ('if') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { failingKeyword: ' + ($ifClause) + ' } ';
|
|
if (it.opts.messages !== false) {
|
|
out += ' , message: \'should match "\' + ' + ($ifClause) + ' + \'" schema\' ';
|
|
}
|
|
if (it.opts.verbose) {
|
|
out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
|
|
}
|
|
out += ' } ';
|
|
} else {
|
|
out += ' {} ';
|
|
}
|
|
out += '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';
|
|
if (!it.compositeRule && $breakOnError) {
|
|
/* istanbul ignore if */
|
|
if (it.async) {
|
|
out += ' throw new ValidationError(vErrors); ';
|
|
} else {
|
|
out += ' validate.errors = vErrors; return false; ';
|
|
}
|
|
}
|
|
out += ' } ';
|
|
if ($breakOnError) {
|
|
out += ' else { ';
|
|
}
|
|
} else {
|
|
if ($breakOnError) {
|
|
out += ' if (true) { ';
|
|
}
|
|
}
|
|
return out;
|
|
}
|
|
|
|
|
|
/***/ }),
|
|
|
|
/***/ 9646:
|
|
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
|
|
|
|
"use strict";
|
|
|
|
|
|
//all requires must be explicit because browserify won't work with dynamic requires
|
|
module.exports = {
|
|
'$ref': __webpack_require__(2331),
|
|
allOf: __webpack_require__(9486),
|
|
anyOf: __webpack_require__(5347),
|
|
'$comment': __webpack_require__(923),
|
|
const: __webpack_require__(2617),
|
|
contains: __webpack_require__(2119),
|
|
dependencies: __webpack_require__(9115),
|
|
'enum': __webpack_require__(9317),
|
|
format: __webpack_require__(8327),
|
|
'if': __webpack_require__(5926),
|
|
items: __webpack_require__(392),
|
|
maximum: __webpack_require__(1796),
|
|
minimum: __webpack_require__(1796),
|
|
maxItems: __webpack_require__(2407),
|
|
minItems: __webpack_require__(2407),
|
|
maxLength: __webpack_require__(1250),
|
|
minLength: __webpack_require__(1250),
|
|
maxProperties: __webpack_require__(2596),
|
|
minProperties: __webpack_require__(2596),
|
|
multipleOf: __webpack_require__(6039),
|
|
not: __webpack_require__(7946),
|
|
oneOf: __webpack_require__(9344),
|
|
pattern: __webpack_require__(9737),
|
|
properties: __webpack_require__(2537),
|
|
propertyNames: __webpack_require__(2127),
|
|
required: __webpack_require__(1204),
|
|
uniqueItems: __webpack_require__(1985),
|
|
validate: __webpack_require__(1869)
|
|
};
|
|
|
|
|
|
/***/ }),
|
|
|
|
/***/ 392:
|
|
/***/ (function(module) {
|
|
|
|
"use strict";
|
|
|
|
module.exports = function generate_items(it, $keyword, $ruleType) {
|
|
var out = ' ';
|
|
var $lvl = it.level;
|
|
var $dataLvl = it.dataLevel;
|
|
var $schema = it.schema[$keyword];
|
|
var $schemaPath = it.schemaPath + it.util.getProperty($keyword);
|
|
var $errSchemaPath = it.errSchemaPath + '/' + $keyword;
|
|
var $breakOnError = !it.opts.allErrors;
|
|
var $data = 'data' + ($dataLvl || '');
|
|
var $valid = 'valid' + $lvl;
|
|
var $errs = 'errs__' + $lvl;
|
|
var $it = it.util.copy(it);
|
|
var $closingBraces = '';
|
|
$it.level++;
|
|
var $nextValid = 'valid' + $it.level;
|
|
var $idx = 'i' + $lvl,
|
|
$dataNxt = $it.dataLevel = it.dataLevel + 1,
|
|
$nextData = 'data' + $dataNxt,
|
|
$currentBaseId = it.baseId;
|
|
out += 'var ' + ($errs) + ' = errors;var ' + ($valid) + ';';
|
|
if (Array.isArray($schema)) {
|
|
var $additionalItems = it.schema.additionalItems;
|
|
if ($additionalItems === false) {
|
|
out += ' ' + ($valid) + ' = ' + ($data) + '.length <= ' + ($schema.length) + '; ';
|
|
var $currErrSchemaPath = $errSchemaPath;
|
|
$errSchemaPath = it.errSchemaPath + '/additionalItems';
|
|
out += ' if (!' + ($valid) + ') { ';
|
|
var $$outStack = $$outStack || [];
|
|
$$outStack.push(out);
|
|
out = ''; /* istanbul ignore else */
|
|
if (it.createErrors !== false) {
|
|
out += ' { keyword: \'' + ('additionalItems') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { limit: ' + ($schema.length) + ' } ';
|
|
if (it.opts.messages !== false) {
|
|
out += ' , message: \'should NOT have more than ' + ($schema.length) + ' items\' ';
|
|
}
|
|
if (it.opts.verbose) {
|
|
out += ' , schema: false , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
|
|
}
|
|
out += ' } ';
|
|
} else {
|
|
out += ' {} ';
|
|
}
|
|
var __err = out;
|
|
out = $$outStack.pop();
|
|
if (!it.compositeRule && $breakOnError) {
|
|
/* istanbul ignore if */
|
|
if (it.async) {
|
|
out += ' throw new ValidationError([' + (__err) + ']); ';
|
|
} else {
|
|
out += ' validate.errors = [' + (__err) + ']; return false; ';
|
|
}
|
|
} else {
|
|
out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';
|
|
}
|
|
out += ' } ';
|
|
$errSchemaPath = $currErrSchemaPath;
|
|
if ($breakOnError) {
|
|
$closingBraces += '}';
|
|
out += ' else { ';
|
|
}
|
|
}
|
|
var arr1 = $schema;
|
|
if (arr1) {
|
|
var $sch, $i = -1,
|
|
l1 = arr1.length - 1;
|
|
while ($i < l1) {
|
|
$sch = arr1[$i += 1];
|
|
if ((it.opts.strictKeywords ? (typeof $sch == 'object' && Object.keys($sch).length > 0) || $sch === false : it.util.schemaHasRules($sch, it.RULES.all))) {
|
|
out += ' ' + ($nextValid) + ' = true; if (' + ($data) + '.length > ' + ($i) + ') { ';
|
|
var $passData = $data + '[' + $i + ']';
|
|
$it.schema = $sch;
|
|
$it.schemaPath = $schemaPath + '[' + $i + ']';
|
|
$it.errSchemaPath = $errSchemaPath + '/' + $i;
|
|
$it.errorPath = it.util.getPathExpr(it.errorPath, $i, it.opts.jsonPointers, true);
|
|
$it.dataPathArr[$dataNxt] = $i;
|
|
var $code = it.validate($it);
|
|
$it.baseId = $currentBaseId;
|
|
if (it.util.varOccurences($code, $nextData) < 2) {
|
|
out += ' ' + (it.util.varReplace($code, $nextData, $passData)) + ' ';
|
|
} else {
|
|
out += ' var ' + ($nextData) + ' = ' + ($passData) + '; ' + ($code) + ' ';
|
|
}
|
|
out += ' } ';
|
|
if ($breakOnError) {
|
|
out += ' if (' + ($nextValid) + ') { ';
|
|
$closingBraces += '}';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (typeof $additionalItems == 'object' && (it.opts.strictKeywords ? (typeof $additionalItems == 'object' && Object.keys($additionalItems).length > 0) || $additionalItems === false : it.util.schemaHasRules($additionalItems, it.RULES.all))) {
|
|
$it.schema = $additionalItems;
|
|
$it.schemaPath = it.schemaPath + '.additionalItems';
|
|
$it.errSchemaPath = it.errSchemaPath + '/additionalItems';
|
|
out += ' ' + ($nextValid) + ' = true; if (' + ($data) + '.length > ' + ($schema.length) + ') { for (var ' + ($idx) + ' = ' + ($schema.length) + '; ' + ($idx) + ' < ' + ($data) + '.length; ' + ($idx) + '++) { ';
|
|
$it.errorPath = it.util.getPathExpr(it.errorPath, $idx, it.opts.jsonPointers, true);
|
|
var $passData = $data + '[' + $idx + ']';
|
|
$it.dataPathArr[$dataNxt] = $idx;
|
|
var $code = it.validate($it);
|
|
$it.baseId = $currentBaseId;
|
|
if (it.util.varOccurences($code, $nextData) < 2) {
|
|
out += ' ' + (it.util.varReplace($code, $nextData, $passData)) + ' ';
|
|
} else {
|
|
out += ' var ' + ($nextData) + ' = ' + ($passData) + '; ' + ($code) + ' ';
|
|
}
|
|
if ($breakOnError) {
|
|
out += ' if (!' + ($nextValid) + ') break; ';
|
|
}
|
|
out += ' } } ';
|
|
if ($breakOnError) {
|
|
out += ' if (' + ($nextValid) + ') { ';
|
|
$closingBraces += '}';
|
|
}
|
|
}
|
|
} else if ((it.opts.strictKeywords ? (typeof $schema == 'object' && Object.keys($schema).length > 0) || $schema === false : it.util.schemaHasRules($schema, it.RULES.all))) {
|
|
$it.schema = $schema;
|
|
$it.schemaPath = $schemaPath;
|
|
$it.errSchemaPath = $errSchemaPath;
|
|
out += ' for (var ' + ($idx) + ' = ' + (0) + '; ' + ($idx) + ' < ' + ($data) + '.length; ' + ($idx) + '++) { ';
|
|
$it.errorPath = it.util.getPathExpr(it.errorPath, $idx, it.opts.jsonPointers, true);
|
|
var $passData = $data + '[' + $idx + ']';
|
|
$it.dataPathArr[$dataNxt] = $idx;
|
|
var $code = it.validate($it);
|
|
$it.baseId = $currentBaseId;
|
|
if (it.util.varOccurences($code, $nextData) < 2) {
|
|
out += ' ' + (it.util.varReplace($code, $nextData, $passData)) + ' ';
|
|
} else {
|
|
out += ' var ' + ($nextData) + ' = ' + ($passData) + '; ' + ($code) + ' ';
|
|
}
|
|
if ($breakOnError) {
|
|
out += ' if (!' + ($nextValid) + ') break; ';
|
|
}
|
|
out += ' }';
|
|
}
|
|
if ($breakOnError) {
|
|
out += ' ' + ($closingBraces) + ' if (' + ($errs) + ' == errors) {';
|
|
}
|
|
return out;
|
|
}
|
|
|
|
|
|
/***/ }),
|
|
|
|
/***/ 6039:
|
|
/***/ (function(module) {
|
|
|
|
"use strict";
|
|
|
|
module.exports = function generate_multipleOf(it, $keyword, $ruleType) {
|
|
var out = ' ';
|
|
var $lvl = it.level;
|
|
var $dataLvl = it.dataLevel;
|
|
var $schema = it.schema[$keyword];
|
|
var $schemaPath = it.schemaPath + it.util.getProperty($keyword);
|
|
var $errSchemaPath = it.errSchemaPath + '/' + $keyword;
|
|
var $breakOnError = !it.opts.allErrors;
|
|
var $data = 'data' + ($dataLvl || '');
|
|
var $isData = it.opts.$data && $schema && $schema.$data,
|
|
$schemaValue;
|
|
if ($isData) {
|
|
out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; ';
|
|
$schemaValue = 'schema' + $lvl;
|
|
} else {
|
|
$schemaValue = $schema;
|
|
}
|
|
if (!($isData || typeof $schema == 'number')) {
|
|
throw new Error($keyword + ' must be number');
|
|
}
|
|
out += 'var division' + ($lvl) + ';if (';
|
|
if ($isData) {
|
|
out += ' ' + ($schemaValue) + ' !== undefined && ( typeof ' + ($schemaValue) + ' != \'number\' || ';
|
|
}
|
|
out += ' (division' + ($lvl) + ' = ' + ($data) + ' / ' + ($schemaValue) + ', ';
|
|
if (it.opts.multipleOfPrecision) {
|
|
out += ' Math.abs(Math.round(division' + ($lvl) + ') - division' + ($lvl) + ') > 1e-' + (it.opts.multipleOfPrecision) + ' ';
|
|
} else {
|
|
out += ' division' + ($lvl) + ' !== parseInt(division' + ($lvl) + ') ';
|
|
}
|
|
out += ' ) ';
|
|
if ($isData) {
|
|
out += ' ) ';
|
|
}
|
|
out += ' ) { ';
|
|
var $$outStack = $$outStack || [];
|
|
$$outStack.push(out);
|
|
out = ''; /* istanbul ignore else */
|
|
if (it.createErrors !== false) {
|
|
out += ' { keyword: \'' + ('multipleOf') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { multipleOf: ' + ($schemaValue) + ' } ';
|
|
if (it.opts.messages !== false) {
|
|
out += ' , message: \'should be multiple of ';
|
|
if ($isData) {
|
|
out += '\' + ' + ($schemaValue);
|
|
} else {
|
|
out += '' + ($schemaValue) + '\'';
|
|
}
|
|
}
|
|
if (it.opts.verbose) {
|
|
out += ' , schema: ';
|
|
if ($isData) {
|
|
out += 'validate.schema' + ($schemaPath);
|
|
} else {
|
|
out += '' + ($schema);
|
|
}
|
|
out += ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
|
|
}
|
|
out += ' } ';
|
|
} else {
|
|
out += ' {} ';
|
|
}
|
|
var __err = out;
|
|
out = $$outStack.pop();
|
|
if (!it.compositeRule && $breakOnError) {
|
|
/* istanbul ignore if */
|
|
if (it.async) {
|
|
out += ' throw new ValidationError([' + (__err) + ']); ';
|
|
} else {
|
|
out += ' validate.errors = [' + (__err) + ']; return false; ';
|
|
}
|
|
} else {
|
|
out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';
|
|
}
|
|
out += '} ';
|
|
if ($breakOnError) {
|
|
out += ' else { ';
|
|
}
|
|
return out;
|
|
}
|
|
|
|
|
|
/***/ }),
|
|
|
|
/***/ 7946:
|
|
/***/ (function(module) {
|
|
|
|
"use strict";
|
|
|
|
module.exports = function generate_not(it, $keyword, $ruleType) {
|
|
var out = ' ';
|
|
var $lvl = it.level;
|
|
var $dataLvl = it.dataLevel;
|
|
var $schema = it.schema[$keyword];
|
|
var $schemaPath = it.schemaPath + it.util.getProperty($keyword);
|
|
var $errSchemaPath = it.errSchemaPath + '/' + $keyword;
|
|
var $breakOnError = !it.opts.allErrors;
|
|
var $data = 'data' + ($dataLvl || '');
|
|
var $errs = 'errs__' + $lvl;
|
|
var $it = it.util.copy(it);
|
|
$it.level++;
|
|
var $nextValid = 'valid' + $it.level;
|
|
if ((it.opts.strictKeywords ? (typeof $schema == 'object' && Object.keys($schema).length > 0) || $schema === false : it.util.schemaHasRules($schema, it.RULES.all))) {
|
|
$it.schema = $schema;
|
|
$it.schemaPath = $schemaPath;
|
|
$it.errSchemaPath = $errSchemaPath;
|
|
out += ' var ' + ($errs) + ' = errors; ';
|
|
var $wasComposite = it.compositeRule;
|
|
it.compositeRule = $it.compositeRule = true;
|
|
$it.createErrors = false;
|
|
var $allErrorsOption;
|
|
if ($it.opts.allErrors) {
|
|
$allErrorsOption = $it.opts.allErrors;
|
|
$it.opts.allErrors = false;
|
|
}
|
|
out += ' ' + (it.validate($it)) + ' ';
|
|
$it.createErrors = true;
|
|
if ($allErrorsOption) $it.opts.allErrors = $allErrorsOption;
|
|
it.compositeRule = $it.compositeRule = $wasComposite;
|
|
out += ' if (' + ($nextValid) + ') { ';
|
|
var $$outStack = $$outStack || [];
|
|
$$outStack.push(out);
|
|
out = ''; /* istanbul ignore else */
|
|
if (it.createErrors !== false) {
|
|
out += ' { keyword: \'' + ('not') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: {} ';
|
|
if (it.opts.messages !== false) {
|
|
out += ' , message: \'should NOT be valid\' ';
|
|
}
|
|
if (it.opts.verbose) {
|
|
out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
|
|
}
|
|
out += ' } ';
|
|
} else {
|
|
out += ' {} ';
|
|
}
|
|
var __err = out;
|
|
out = $$outStack.pop();
|
|
if (!it.compositeRule && $breakOnError) {
|
|
/* istanbul ignore if */
|
|
if (it.async) {
|
|
out += ' throw new ValidationError([' + (__err) + ']); ';
|
|
} else {
|
|
out += ' validate.errors = [' + (__err) + ']; return false; ';
|
|
}
|
|
} else {
|
|
out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';
|
|
}
|
|
out += ' } else { errors = ' + ($errs) + '; if (vErrors !== null) { if (' + ($errs) + ') vErrors.length = ' + ($errs) + '; else vErrors = null; } ';
|
|
if (it.opts.allErrors) {
|
|
out += ' } ';
|
|
}
|
|
} else {
|
|
out += ' var err = '; /* istanbul ignore else */
|
|
if (it.createErrors !== false) {
|
|
out += ' { keyword: \'' + ('not') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: {} ';
|
|
if (it.opts.messages !== false) {
|
|
out += ' , message: \'should NOT be valid\' ';
|
|
}
|
|
if (it.opts.verbose) {
|
|
out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
|
|
}
|
|
out += ' } ';
|
|
} else {
|
|
out += ' {} ';
|
|
}
|
|
out += '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';
|
|
if ($breakOnError) {
|
|
out += ' if (false) { ';
|
|
}
|
|
}
|
|
return out;
|
|
}
|
|
|
|
|
|
/***/ }),
|
|
|
|
/***/ 9344:
|
|
/***/ (function(module) {
|
|
|
|
"use strict";
|
|
|
|
module.exports = function generate_oneOf(it, $keyword, $ruleType) {
|
|
var out = ' ';
|
|
var $lvl = it.level;
|
|
var $dataLvl = it.dataLevel;
|
|
var $schema = it.schema[$keyword];
|
|
var $schemaPath = it.schemaPath + it.util.getProperty($keyword);
|
|
var $errSchemaPath = it.errSchemaPath + '/' + $keyword;
|
|
var $breakOnError = !it.opts.allErrors;
|
|
var $data = 'data' + ($dataLvl || '');
|
|
var $valid = 'valid' + $lvl;
|
|
var $errs = 'errs__' + $lvl;
|
|
var $it = it.util.copy(it);
|
|
var $closingBraces = '';
|
|
$it.level++;
|
|
var $nextValid = 'valid' + $it.level;
|
|
var $currentBaseId = $it.baseId,
|
|
$prevValid = 'prevValid' + $lvl,
|
|
$passingSchemas = 'passingSchemas' + $lvl;
|
|
out += 'var ' + ($errs) + ' = errors , ' + ($prevValid) + ' = false , ' + ($valid) + ' = false , ' + ($passingSchemas) + ' = null; ';
|
|
var $wasComposite = it.compositeRule;
|
|
it.compositeRule = $it.compositeRule = true;
|
|
var arr1 = $schema;
|
|
if (arr1) {
|
|
var $sch, $i = -1,
|
|
l1 = arr1.length - 1;
|
|
while ($i < l1) {
|
|
$sch = arr1[$i += 1];
|
|
if ((it.opts.strictKeywords ? (typeof $sch == 'object' && Object.keys($sch).length > 0) || $sch === false : it.util.schemaHasRules($sch, it.RULES.all))) {
|
|
$it.schema = $sch;
|
|
$it.schemaPath = $schemaPath + '[' + $i + ']';
|
|
$it.errSchemaPath = $errSchemaPath + '/' + $i;
|
|
out += ' ' + (it.validate($it)) + ' ';
|
|
$it.baseId = $currentBaseId;
|
|
} else {
|
|
out += ' var ' + ($nextValid) + ' = true; ';
|
|
}
|
|
if ($i) {
|
|
out += ' if (' + ($nextValid) + ' && ' + ($prevValid) + ') { ' + ($valid) + ' = false; ' + ($passingSchemas) + ' = [' + ($passingSchemas) + ', ' + ($i) + ']; } else { ';
|
|
$closingBraces += '}';
|
|
}
|
|
out += ' if (' + ($nextValid) + ') { ' + ($valid) + ' = ' + ($prevValid) + ' = true; ' + ($passingSchemas) + ' = ' + ($i) + '; }';
|
|
}
|
|
}
|
|
it.compositeRule = $it.compositeRule = $wasComposite;
|
|
out += '' + ($closingBraces) + 'if (!' + ($valid) + ') { var err = '; /* istanbul ignore else */
|
|
if (it.createErrors !== false) {
|
|
out += ' { keyword: \'' + ('oneOf') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { passingSchemas: ' + ($passingSchemas) + ' } ';
|
|
if (it.opts.messages !== false) {
|
|
out += ' , message: \'should match exactly one schema in oneOf\' ';
|
|
}
|
|
if (it.opts.verbose) {
|
|
out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
|
|
}
|
|
out += ' } ';
|
|
} else {
|
|
out += ' {} ';
|
|
}
|
|
out += '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';
|
|
if (!it.compositeRule && $breakOnError) {
|
|
/* istanbul ignore if */
|
|
if (it.async) {
|
|
out += ' throw new ValidationError(vErrors); ';
|
|
} else {
|
|
out += ' validate.errors = vErrors; return false; ';
|
|
}
|
|
}
|
|
out += '} else { errors = ' + ($errs) + '; if (vErrors !== null) { if (' + ($errs) + ') vErrors.length = ' + ($errs) + '; else vErrors = null; }';
|
|
if (it.opts.allErrors) {
|
|
out += ' } ';
|
|
}
|
|
return out;
|
|
}
|
|
|
|
|
|
/***/ }),
|
|
|
|
/***/ 9737:
|
|
/***/ (function(module) {
|
|
|
|
"use strict";
|
|
|
|
module.exports = function generate_pattern(it, $keyword, $ruleType) {
|
|
var out = ' ';
|
|
var $lvl = it.level;
|
|
var $dataLvl = it.dataLevel;
|
|
var $schema = it.schema[$keyword];
|
|
var $schemaPath = it.schemaPath + it.util.getProperty($keyword);
|
|
var $errSchemaPath = it.errSchemaPath + '/' + $keyword;
|
|
var $breakOnError = !it.opts.allErrors;
|
|
var $data = 'data' + ($dataLvl || '');
|
|
var $isData = it.opts.$data && $schema && $schema.$data,
|
|
$schemaValue;
|
|
if ($isData) {
|
|
out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; ';
|
|
$schemaValue = 'schema' + $lvl;
|
|
} else {
|
|
$schemaValue = $schema;
|
|
}
|
|
var $regexp = $isData ? '(new RegExp(' + $schemaValue + '))' : it.usePattern($schema);
|
|
out += 'if ( ';
|
|
if ($isData) {
|
|
out += ' (' + ($schemaValue) + ' !== undefined && typeof ' + ($schemaValue) + ' != \'string\') || ';
|
|
}
|
|
out += ' !' + ($regexp) + '.test(' + ($data) + ') ) { ';
|
|
var $$outStack = $$outStack || [];
|
|
$$outStack.push(out);
|
|
out = ''; /* istanbul ignore else */
|
|
if (it.createErrors !== false) {
|
|
out += ' { keyword: \'' + ('pattern') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { pattern: ';
|
|
if ($isData) {
|
|
out += '' + ($schemaValue);
|
|
} else {
|
|
out += '' + (it.util.toQuotedString($schema));
|
|
}
|
|
out += ' } ';
|
|
if (it.opts.messages !== false) {
|
|
out += ' , message: \'should match pattern "';
|
|
if ($isData) {
|
|
out += '\' + ' + ($schemaValue) + ' + \'';
|
|
} else {
|
|
out += '' + (it.util.escapeQuotes($schema));
|
|
}
|
|
out += '"\' ';
|
|
}
|
|
if (it.opts.verbose) {
|
|
out += ' , schema: ';
|
|
if ($isData) {
|
|
out += 'validate.schema' + ($schemaPath);
|
|
} else {
|
|
out += '' + (it.util.toQuotedString($schema));
|
|
}
|
|
out += ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
|
|
}
|
|
out += ' } ';
|
|
} else {
|
|
out += ' {} ';
|
|
}
|
|
var __err = out;
|
|
out = $$outStack.pop();
|
|
if (!it.compositeRule && $breakOnError) {
|
|
/* istanbul ignore if */
|
|
if (it.async) {
|
|
out += ' throw new ValidationError([' + (__err) + ']); ';
|
|
} else {
|
|
out += ' validate.errors = [' + (__err) + ']; return false; ';
|
|
}
|
|
} else {
|
|
out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';
|
|
}
|
|
out += '} ';
|
|
if ($breakOnError) {
|
|
out += ' else { ';
|
|
}
|
|
return out;
|
|
}
|
|
|
|
|
|
/***/ }),
|
|
|
|
/***/ 2537:
|
|
/***/ (function(module) {
|
|
|
|
"use strict";
|
|
|
|
module.exports = function generate_properties(it, $keyword, $ruleType) {
|
|
var out = ' ';
|
|
var $lvl = it.level;
|
|
var $dataLvl = it.dataLevel;
|
|
var $schema = it.schema[$keyword];
|
|
var $schemaPath = it.schemaPath + it.util.getProperty($keyword);
|
|
var $errSchemaPath = it.errSchemaPath + '/' + $keyword;
|
|
var $breakOnError = !it.opts.allErrors;
|
|
var $data = 'data' + ($dataLvl || '');
|
|
var $errs = 'errs__' + $lvl;
|
|
var $it = it.util.copy(it);
|
|
var $closingBraces = '';
|
|
$it.level++;
|
|
var $nextValid = 'valid' + $it.level;
|
|
var $key = 'key' + $lvl,
|
|
$idx = 'idx' + $lvl,
|
|
$dataNxt = $it.dataLevel = it.dataLevel + 1,
|
|
$nextData = 'data' + $dataNxt,
|
|
$dataProperties = 'dataProperties' + $lvl;
|
|
var $schemaKeys = Object.keys($schema || {}).filter(notProto),
|
|
$pProperties = it.schema.patternProperties || {},
|
|
$pPropertyKeys = Object.keys($pProperties).filter(notProto),
|
|
$aProperties = it.schema.additionalProperties,
|
|
$someProperties = $schemaKeys.length || $pPropertyKeys.length,
|
|
$noAdditional = $aProperties === false,
|
|
$additionalIsSchema = typeof $aProperties == 'object' && Object.keys($aProperties).length,
|
|
$removeAdditional = it.opts.removeAdditional,
|
|
$checkAdditional = $noAdditional || $additionalIsSchema || $removeAdditional,
|
|
$ownProperties = it.opts.ownProperties,
|
|
$currentBaseId = it.baseId;
|
|
var $required = it.schema.required;
|
|
if ($required && !(it.opts.$data && $required.$data) && $required.length < it.opts.loopRequired) {
|
|
var $requiredHash = it.util.toHash($required);
|
|
}
|
|
|
|
function notProto(p) {
|
|
return p !== '__proto__';
|
|
}
|
|
out += 'var ' + ($errs) + ' = errors;var ' + ($nextValid) + ' = true;';
|
|
if ($ownProperties) {
|
|
out += ' var ' + ($dataProperties) + ' = undefined;';
|
|
}
|
|
if ($checkAdditional) {
|
|
if ($ownProperties) {
|
|
out += ' ' + ($dataProperties) + ' = ' + ($dataProperties) + ' || Object.keys(' + ($data) + '); for (var ' + ($idx) + '=0; ' + ($idx) + '<' + ($dataProperties) + '.length; ' + ($idx) + '++) { var ' + ($key) + ' = ' + ($dataProperties) + '[' + ($idx) + ']; ';
|
|
} else {
|
|
out += ' for (var ' + ($key) + ' in ' + ($data) + ') { ';
|
|
}
|
|
if ($someProperties) {
|
|
out += ' var isAdditional' + ($lvl) + ' = !(false ';
|
|
if ($schemaKeys.length) {
|
|
if ($schemaKeys.length > 8) {
|
|
out += ' || validate.schema' + ($schemaPath) + '.hasOwnProperty(' + ($key) + ') ';
|
|
} else {
|
|
var arr1 = $schemaKeys;
|
|
if (arr1) {
|
|
var $propertyKey, i1 = -1,
|
|
l1 = arr1.length - 1;
|
|
while (i1 < l1) {
|
|
$propertyKey = arr1[i1 += 1];
|
|
out += ' || ' + ($key) + ' == ' + (it.util.toQuotedString($propertyKey)) + ' ';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if ($pPropertyKeys.length) {
|
|
var arr2 = $pPropertyKeys;
|
|
if (arr2) {
|
|
var $pProperty, $i = -1,
|
|
l2 = arr2.length - 1;
|
|
while ($i < l2) {
|
|
$pProperty = arr2[$i += 1];
|
|
out += ' || ' + (it.usePattern($pProperty)) + '.test(' + ($key) + ') ';
|
|
}
|
|
}
|
|
}
|
|
out += ' ); if (isAdditional' + ($lvl) + ') { ';
|
|
}
|
|
if ($removeAdditional == 'all') {
|
|
out += ' delete ' + ($data) + '[' + ($key) + ']; ';
|
|
} else {
|
|
var $currentErrorPath = it.errorPath;
|
|
var $additionalProperty = '\' + ' + $key + ' + \'';
|
|
if (it.opts._errorDataPathProperty) {
|
|
it.errorPath = it.util.getPathExpr(it.errorPath, $key, it.opts.jsonPointers);
|
|
}
|
|
if ($noAdditional) {
|
|
if ($removeAdditional) {
|
|
out += ' delete ' + ($data) + '[' + ($key) + ']; ';
|
|
} else {
|
|
out += ' ' + ($nextValid) + ' = false; ';
|
|
var $currErrSchemaPath = $errSchemaPath;
|
|
$errSchemaPath = it.errSchemaPath + '/additionalProperties';
|
|
var $$outStack = $$outStack || [];
|
|
$$outStack.push(out);
|
|
out = ''; /* istanbul ignore else */
|
|
if (it.createErrors !== false) {
|
|
out += ' { keyword: \'' + ('additionalProperties') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { additionalProperty: \'' + ($additionalProperty) + '\' } ';
|
|
if (it.opts.messages !== false) {
|
|
out += ' , message: \'';
|
|
if (it.opts._errorDataPathProperty) {
|
|
out += 'is an invalid additional property';
|
|
} else {
|
|
out += 'should NOT have additional properties';
|
|
}
|
|
out += '\' ';
|
|
}
|
|
if (it.opts.verbose) {
|
|
out += ' , schema: false , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
|
|
}
|
|
out += ' } ';
|
|
} else {
|
|
out += ' {} ';
|
|
}
|
|
var __err = out;
|
|
out = $$outStack.pop();
|
|
if (!it.compositeRule && $breakOnError) {
|
|
/* istanbul ignore if */
|
|
if (it.async) {
|
|
out += ' throw new ValidationError([' + (__err) + ']); ';
|
|
} else {
|
|
out += ' validate.errors = [' + (__err) + ']; return false; ';
|
|
}
|
|
} else {
|
|
out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';
|
|
}
|
|
$errSchemaPath = $currErrSchemaPath;
|
|
if ($breakOnError) {
|
|
out += ' break; ';
|
|
}
|
|
}
|
|
} else if ($additionalIsSchema) {
|
|
if ($removeAdditional == 'failing') {
|
|
out += ' var ' + ($errs) + ' = errors; ';
|
|
var $wasComposite = it.compositeRule;
|
|
it.compositeRule = $it.compositeRule = true;
|
|
$it.schema = $aProperties;
|
|
$it.schemaPath = it.schemaPath + '.additionalProperties';
|
|
$it.errSchemaPath = it.errSchemaPath + '/additionalProperties';
|
|
$it.errorPath = it.opts._errorDataPathProperty ? it.errorPath : it.util.getPathExpr(it.errorPath, $key, it.opts.jsonPointers);
|
|
var $passData = $data + '[' + $key + ']';
|
|
$it.dataPathArr[$dataNxt] = $key;
|
|
var $code = it.validate($it);
|
|
$it.baseId = $currentBaseId;
|
|
if (it.util.varOccurences($code, $nextData) < 2) {
|
|
out += ' ' + (it.util.varReplace($code, $nextData, $passData)) + ' ';
|
|
} else {
|
|
out += ' var ' + ($nextData) + ' = ' + ($passData) + '; ' + ($code) + ' ';
|
|
}
|
|
out += ' if (!' + ($nextValid) + ') { errors = ' + ($errs) + '; if (validate.errors !== null) { if (errors) validate.errors.length = errors; else validate.errors = null; } delete ' + ($data) + '[' + ($key) + ']; } ';
|
|
it.compositeRule = $it.compositeRule = $wasComposite;
|
|
} else {
|
|
$it.schema = $aProperties;
|
|
$it.schemaPath = it.schemaPath + '.additionalProperties';
|
|
$it.errSchemaPath = it.errSchemaPath + '/additionalProperties';
|
|
$it.errorPath = it.opts._errorDataPathProperty ? it.errorPath : it.util.getPathExpr(it.errorPath, $key, it.opts.jsonPointers);
|
|
var $passData = $data + '[' + $key + ']';
|
|
$it.dataPathArr[$dataNxt] = $key;
|
|
var $code = it.validate($it);
|
|
$it.baseId = $currentBaseId;
|
|
if (it.util.varOccurences($code, $nextData) < 2) {
|
|
out += ' ' + (it.util.varReplace($code, $nextData, $passData)) + ' ';
|
|
} else {
|
|
out += ' var ' + ($nextData) + ' = ' + ($passData) + '; ' + ($code) + ' ';
|
|
}
|
|
if ($breakOnError) {
|
|
out += ' if (!' + ($nextValid) + ') break; ';
|
|
}
|
|
}
|
|
}
|
|
it.errorPath = $currentErrorPath;
|
|
}
|
|
if ($someProperties) {
|
|
out += ' } ';
|
|
}
|
|
out += ' } ';
|
|
if ($breakOnError) {
|
|
out += ' if (' + ($nextValid) + ') { ';
|
|
$closingBraces += '}';
|
|
}
|
|
}
|
|
var $useDefaults = it.opts.useDefaults && !it.compositeRule;
|
|
if ($schemaKeys.length) {
|
|
var arr3 = $schemaKeys;
|
|
if (arr3) {
|
|
var $propertyKey, i3 = -1,
|
|
l3 = arr3.length - 1;
|
|
while (i3 < l3) {
|
|
$propertyKey = arr3[i3 += 1];
|
|
var $sch = $schema[$propertyKey];
|
|
if ((it.opts.strictKeywords ? (typeof $sch == 'object' && Object.keys($sch).length > 0) || $sch === false : it.util.schemaHasRules($sch, it.RULES.all))) {
|
|
var $prop = it.util.getProperty($propertyKey),
|
|
$passData = $data + $prop,
|
|
$hasDefault = $useDefaults && $sch.default !== undefined;
|
|
$it.schema = $sch;
|
|
$it.schemaPath = $schemaPath + $prop;
|
|
$it.errSchemaPath = $errSchemaPath + '/' + it.util.escapeFragment($propertyKey);
|
|
$it.errorPath = it.util.getPath(it.errorPath, $propertyKey, it.opts.jsonPointers);
|
|
$it.dataPathArr[$dataNxt] = it.util.toQuotedString($propertyKey);
|
|
var $code = it.validate($it);
|
|
$it.baseId = $currentBaseId;
|
|
if (it.util.varOccurences($code, $nextData) < 2) {
|
|
$code = it.util.varReplace($code, $nextData, $passData);
|
|
var $useData = $passData;
|
|
} else {
|
|
var $useData = $nextData;
|
|
out += ' var ' + ($nextData) + ' = ' + ($passData) + '; ';
|
|
}
|
|
if ($hasDefault) {
|
|
out += ' ' + ($code) + ' ';
|
|
} else {
|
|
if ($requiredHash && $requiredHash[$propertyKey]) {
|
|
out += ' if ( ' + ($useData) + ' === undefined ';
|
|
if ($ownProperties) {
|
|
out += ' || ! Object.prototype.hasOwnProperty.call(' + ($data) + ', \'' + (it.util.escapeQuotes($propertyKey)) + '\') ';
|
|
}
|
|
out += ') { ' + ($nextValid) + ' = false; ';
|
|
var $currentErrorPath = it.errorPath,
|
|
$currErrSchemaPath = $errSchemaPath,
|
|
$missingProperty = it.util.escapeQuotes($propertyKey);
|
|
if (it.opts._errorDataPathProperty) {
|
|
it.errorPath = it.util.getPath($currentErrorPath, $propertyKey, it.opts.jsonPointers);
|
|
}
|
|
$errSchemaPath = it.errSchemaPath + '/required';
|
|
var $$outStack = $$outStack || [];
|
|
$$outStack.push(out);
|
|
out = ''; /* istanbul ignore else */
|
|
if (it.createErrors !== false) {
|
|
out += ' { keyword: \'' + ('required') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { missingProperty: \'' + ($missingProperty) + '\' } ';
|
|
if (it.opts.messages !== false) {
|
|
out += ' , message: \'';
|
|
if (it.opts._errorDataPathProperty) {
|
|
out += 'is a required property';
|
|
} else {
|
|
out += 'should have required property \\\'' + ($missingProperty) + '\\\'';
|
|
}
|
|
out += '\' ';
|
|
}
|
|
if (it.opts.verbose) {
|
|
out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
|
|
}
|
|
out += ' } ';
|
|
} else {
|
|
out += ' {} ';
|
|
}
|
|
var __err = out;
|
|
out = $$outStack.pop();
|
|
if (!it.compositeRule && $breakOnError) {
|
|
/* istanbul ignore if */
|
|
if (it.async) {
|
|
out += ' throw new ValidationError([' + (__err) + ']); ';
|
|
} else {
|
|
out += ' validate.errors = [' + (__err) + ']; return false; ';
|
|
}
|
|
} else {
|
|
out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';
|
|
}
|
|
$errSchemaPath = $currErrSchemaPath;
|
|
it.errorPath = $currentErrorPath;
|
|
out += ' } else { ';
|
|
} else {
|
|
if ($breakOnError) {
|
|
out += ' if ( ' + ($useData) + ' === undefined ';
|
|
if ($ownProperties) {
|
|
out += ' || ! Object.prototype.hasOwnProperty.call(' + ($data) + ', \'' + (it.util.escapeQuotes($propertyKey)) + '\') ';
|
|
}
|
|
out += ') { ' + ($nextValid) + ' = true; } else { ';
|
|
} else {
|
|
out += ' if (' + ($useData) + ' !== undefined ';
|
|
if ($ownProperties) {
|
|
out += ' && Object.prototype.hasOwnProperty.call(' + ($data) + ', \'' + (it.util.escapeQuotes($propertyKey)) + '\') ';
|
|
}
|
|
out += ' ) { ';
|
|
}
|
|
}
|
|
out += ' ' + ($code) + ' } ';
|
|
}
|
|
}
|
|
if ($breakOnError) {
|
|
out += ' if (' + ($nextValid) + ') { ';
|
|
$closingBraces += '}';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if ($pPropertyKeys.length) {
|
|
var arr4 = $pPropertyKeys;
|
|
if (arr4) {
|
|
var $pProperty, i4 = -1,
|
|
l4 = arr4.length - 1;
|
|
while (i4 < l4) {
|
|
$pProperty = arr4[i4 += 1];
|
|
var $sch = $pProperties[$pProperty];
|
|
if ((it.opts.strictKeywords ? (typeof $sch == 'object' && Object.keys($sch).length > 0) || $sch === false : it.util.schemaHasRules($sch, it.RULES.all))) {
|
|
$it.schema = $sch;
|
|
$it.schemaPath = it.schemaPath + '.patternProperties' + it.util.getProperty($pProperty);
|
|
$it.errSchemaPath = it.errSchemaPath + '/patternProperties/' + it.util.escapeFragment($pProperty);
|
|
if ($ownProperties) {
|
|
out += ' ' + ($dataProperties) + ' = ' + ($dataProperties) + ' || Object.keys(' + ($data) + '); for (var ' + ($idx) + '=0; ' + ($idx) + '<' + ($dataProperties) + '.length; ' + ($idx) + '++) { var ' + ($key) + ' = ' + ($dataProperties) + '[' + ($idx) + ']; ';
|
|
} else {
|
|
out += ' for (var ' + ($key) + ' in ' + ($data) + ') { ';
|
|
}
|
|
out += ' if (' + (it.usePattern($pProperty)) + '.test(' + ($key) + ')) { ';
|
|
$it.errorPath = it.util.getPathExpr(it.errorPath, $key, it.opts.jsonPointers);
|
|
var $passData = $data + '[' + $key + ']';
|
|
$it.dataPathArr[$dataNxt] = $key;
|
|
var $code = it.validate($it);
|
|
$it.baseId = $currentBaseId;
|
|
if (it.util.varOccurences($code, $nextData) < 2) {
|
|
out += ' ' + (it.util.varReplace($code, $nextData, $passData)) + ' ';
|
|
} else {
|
|
out += ' var ' + ($nextData) + ' = ' + ($passData) + '; ' + ($code) + ' ';
|
|
}
|
|
if ($breakOnError) {
|
|
out += ' if (!' + ($nextValid) + ') break; ';
|
|
}
|
|
out += ' } ';
|
|
if ($breakOnError) {
|
|
out += ' else ' + ($nextValid) + ' = true; ';
|
|
}
|
|
out += ' } ';
|
|
if ($breakOnError) {
|
|
out += ' if (' + ($nextValid) + ') { ';
|
|
$closingBraces += '}';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if ($breakOnError) {
|
|
out += ' ' + ($closingBraces) + ' if (' + ($errs) + ' == errors) {';
|
|
}
|
|
return out;
|
|
}
|
|
|
|
|
|
/***/ }),
|
|
|
|
/***/ 2127:
|
|
/***/ (function(module) {
|
|
|
|
"use strict";
|
|
|
|
module.exports = function generate_propertyNames(it, $keyword, $ruleType) {
|
|
var out = ' ';
|
|
var $lvl = it.level;
|
|
var $dataLvl = it.dataLevel;
|
|
var $schema = it.schema[$keyword];
|
|
var $schemaPath = it.schemaPath + it.util.getProperty($keyword);
|
|
var $errSchemaPath = it.errSchemaPath + '/' + $keyword;
|
|
var $breakOnError = !it.opts.allErrors;
|
|
var $data = 'data' + ($dataLvl || '');
|
|
var $errs = 'errs__' + $lvl;
|
|
var $it = it.util.copy(it);
|
|
var $closingBraces = '';
|
|
$it.level++;
|
|
var $nextValid = 'valid' + $it.level;
|
|
out += 'var ' + ($errs) + ' = errors;';
|
|
if ((it.opts.strictKeywords ? (typeof $schema == 'object' && Object.keys($schema).length > 0) || $schema === false : it.util.schemaHasRules($schema, it.RULES.all))) {
|
|
$it.schema = $schema;
|
|
$it.schemaPath = $schemaPath;
|
|
$it.errSchemaPath = $errSchemaPath;
|
|
var $key = 'key' + $lvl,
|
|
$idx = 'idx' + $lvl,
|
|
$i = 'i' + $lvl,
|
|
$invalidName = '\' + ' + $key + ' + \'',
|
|
$dataNxt = $it.dataLevel = it.dataLevel + 1,
|
|
$nextData = 'data' + $dataNxt,
|
|
$dataProperties = 'dataProperties' + $lvl,
|
|
$ownProperties = it.opts.ownProperties,
|
|
$currentBaseId = it.baseId;
|
|
if ($ownProperties) {
|
|
out += ' var ' + ($dataProperties) + ' = undefined; ';
|
|
}
|
|
if ($ownProperties) {
|
|
out += ' ' + ($dataProperties) + ' = ' + ($dataProperties) + ' || Object.keys(' + ($data) + '); for (var ' + ($idx) + '=0; ' + ($idx) + '<' + ($dataProperties) + '.length; ' + ($idx) + '++) { var ' + ($key) + ' = ' + ($dataProperties) + '[' + ($idx) + ']; ';
|
|
} else {
|
|
out += ' for (var ' + ($key) + ' in ' + ($data) + ') { ';
|
|
}
|
|
out += ' var startErrs' + ($lvl) + ' = errors; ';
|
|
var $passData = $key;
|
|
var $wasComposite = it.compositeRule;
|
|
it.compositeRule = $it.compositeRule = true;
|
|
var $code = it.validate($it);
|
|
$it.baseId = $currentBaseId;
|
|
if (it.util.varOccurences($code, $nextData) < 2) {
|
|
out += ' ' + (it.util.varReplace($code, $nextData, $passData)) + ' ';
|
|
} else {
|
|
out += ' var ' + ($nextData) + ' = ' + ($passData) + '; ' + ($code) + ' ';
|
|
}
|
|
it.compositeRule = $it.compositeRule = $wasComposite;
|
|
out += ' if (!' + ($nextValid) + ') { for (var ' + ($i) + '=startErrs' + ($lvl) + '; ' + ($i) + '<errors; ' + ($i) + '++) { vErrors[' + ($i) + '].propertyName = ' + ($key) + '; } var err = '; /* istanbul ignore else */
|
|
if (it.createErrors !== false) {
|
|
out += ' { keyword: \'' + ('propertyNames') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { propertyName: \'' + ($invalidName) + '\' } ';
|
|
if (it.opts.messages !== false) {
|
|
out += ' , message: \'property name \\\'' + ($invalidName) + '\\\' is invalid\' ';
|
|
}
|
|
if (it.opts.verbose) {
|
|
out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
|
|
}
|
|
out += ' } ';
|
|
} else {
|
|
out += ' {} ';
|
|
}
|
|
out += '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';
|
|
if (!it.compositeRule && $breakOnError) {
|
|
/* istanbul ignore if */
|
|
if (it.async) {
|
|
out += ' throw new ValidationError(vErrors); ';
|
|
} else {
|
|
out += ' validate.errors = vErrors; return false; ';
|
|
}
|
|
}
|
|
if ($breakOnError) {
|
|
out += ' break; ';
|
|
}
|
|
out += ' } }';
|
|
}
|
|
if ($breakOnError) {
|
|
out += ' ' + ($closingBraces) + ' if (' + ($errs) + ' == errors) {';
|
|
}
|
|
return out;
|
|
}
|
|
|
|
|
|
/***/ }),
|
|
|
|
/***/ 2331:
|
|
/***/ (function(module) {
|
|
|
|
"use strict";
|
|
|
|
module.exports = function generate_ref(it, $keyword, $ruleType) {
|
|
var out = ' ';
|
|
var $lvl = it.level;
|
|
var $dataLvl = it.dataLevel;
|
|
var $schema = it.schema[$keyword];
|
|
var $errSchemaPath = it.errSchemaPath + '/' + $keyword;
|
|
var $breakOnError = !it.opts.allErrors;
|
|
var $data = 'data' + ($dataLvl || '');
|
|
var $valid = 'valid' + $lvl;
|
|
var $async, $refCode;
|
|
if ($schema == '#' || $schema == '#/') {
|
|
if (it.isRoot) {
|
|
$async = it.async;
|
|
$refCode = 'validate';
|
|
} else {
|
|
$async = it.root.schema.$async === true;
|
|
$refCode = 'root.refVal[0]';
|
|
}
|
|
} else {
|
|
var $refVal = it.resolveRef(it.baseId, $schema, it.isRoot);
|
|
if ($refVal === undefined) {
|
|
var $message = it.MissingRefError.message(it.baseId, $schema);
|
|
if (it.opts.missingRefs == 'fail') {
|
|
it.logger.error($message);
|
|
var $$outStack = $$outStack || [];
|
|
$$outStack.push(out);
|
|
out = ''; /* istanbul ignore else */
|
|
if (it.createErrors !== false) {
|
|
out += ' { keyword: \'' + ('$ref') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { ref: \'' + (it.util.escapeQuotes($schema)) + '\' } ';
|
|
if (it.opts.messages !== false) {
|
|
out += ' , message: \'can\\\'t resolve reference ' + (it.util.escapeQuotes($schema)) + '\' ';
|
|
}
|
|
if (it.opts.verbose) {
|
|
out += ' , schema: ' + (it.util.toQuotedString($schema)) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
|
|
}
|
|
out += ' } ';
|
|
} else {
|
|
out += ' {} ';
|
|
}
|
|
var __err = out;
|
|
out = $$outStack.pop();
|
|
if (!it.compositeRule && $breakOnError) {
|
|
/* istanbul ignore if */
|
|
if (it.async) {
|
|
out += ' throw new ValidationError([' + (__err) + ']); ';
|
|
} else {
|
|
out += ' validate.errors = [' + (__err) + ']; return false; ';
|
|
}
|
|
} else {
|
|
out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';
|
|
}
|
|
if ($breakOnError) {
|
|
out += ' if (false) { ';
|
|
}
|
|
} else if (it.opts.missingRefs == 'ignore') {
|
|
it.logger.warn($message);
|
|
if ($breakOnError) {
|
|
out += ' if (true) { ';
|
|
}
|
|
} else {
|
|
throw new it.MissingRefError(it.baseId, $schema, $message);
|
|
}
|
|
} else if ($refVal.inline) {
|
|
var $it = it.util.copy(it);
|
|
$it.level++;
|
|
var $nextValid = 'valid' + $it.level;
|
|
$it.schema = $refVal.schema;
|
|
$it.schemaPath = '';
|
|
$it.errSchemaPath = $schema;
|
|
var $code = it.validate($it).replace(/validate\.schema/g, $refVal.code);
|
|
out += ' ' + ($code) + ' ';
|
|
if ($breakOnError) {
|
|
out += ' if (' + ($nextValid) + ') { ';
|
|
}
|
|
} else {
|
|
$async = $refVal.$async === true || (it.async && $refVal.$async !== false);
|
|
$refCode = $refVal.code;
|
|
}
|
|
}
|
|
if ($refCode) {
|
|
var $$outStack = $$outStack || [];
|
|
$$outStack.push(out);
|
|
out = '';
|
|
if (it.opts.passContext) {
|
|
out += ' ' + ($refCode) + '.call(this, ';
|
|
} else {
|
|
out += ' ' + ($refCode) + '( ';
|
|
}
|
|
out += ' ' + ($data) + ', (dataPath || \'\')';
|
|
if (it.errorPath != '""') {
|
|
out += ' + ' + (it.errorPath);
|
|
}
|
|
var $parentData = $dataLvl ? 'data' + (($dataLvl - 1) || '') : 'parentData',
|
|
$parentDataProperty = $dataLvl ? it.dataPathArr[$dataLvl] : 'parentDataProperty';
|
|
out += ' , ' + ($parentData) + ' , ' + ($parentDataProperty) + ', rootData) ';
|
|
var __callValidate = out;
|
|
out = $$outStack.pop();
|
|
if ($async) {
|
|
if (!it.async) throw new Error('async schema referenced by sync schema');
|
|
if ($breakOnError) {
|
|
out += ' var ' + ($valid) + '; ';
|
|
}
|
|
out += ' try { await ' + (__callValidate) + '; ';
|
|
if ($breakOnError) {
|
|
out += ' ' + ($valid) + ' = true; ';
|
|
}
|
|
out += ' } catch (e) { if (!(e instanceof ValidationError)) throw e; if (vErrors === null) vErrors = e.errors; else vErrors = vErrors.concat(e.errors); errors = vErrors.length; ';
|
|
if ($breakOnError) {
|
|
out += ' ' + ($valid) + ' = false; ';
|
|
}
|
|
out += ' } ';
|
|
if ($breakOnError) {
|
|
out += ' if (' + ($valid) + ') { ';
|
|
}
|
|
} else {
|
|
out += ' if (!' + (__callValidate) + ') { if (vErrors === null) vErrors = ' + ($refCode) + '.errors; else vErrors = vErrors.concat(' + ($refCode) + '.errors); errors = vErrors.length; } ';
|
|
if ($breakOnError) {
|
|
out += ' else { ';
|
|
}
|
|
}
|
|
}
|
|
return out;
|
|
}
|
|
|
|
|
|
/***/ }),
|
|
|
|
/***/ 1204:
|
|
/***/ (function(module) {
|
|
|
|
"use strict";
|
|
|
|
module.exports = function generate_required(it, $keyword, $ruleType) {
|
|
var out = ' ';
|
|
var $lvl = it.level;
|
|
var $dataLvl = it.dataLevel;
|
|
var $schema = it.schema[$keyword];
|
|
var $schemaPath = it.schemaPath + it.util.getProperty($keyword);
|
|
var $errSchemaPath = it.errSchemaPath + '/' + $keyword;
|
|
var $breakOnError = !it.opts.allErrors;
|
|
var $data = 'data' + ($dataLvl || '');
|
|
var $valid = 'valid' + $lvl;
|
|
var $isData = it.opts.$data && $schema && $schema.$data,
|
|
$schemaValue;
|
|
if ($isData) {
|
|
out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; ';
|
|
$schemaValue = 'schema' + $lvl;
|
|
} else {
|
|
$schemaValue = $schema;
|
|
}
|
|
var $vSchema = 'schema' + $lvl;
|
|
if (!$isData) {
|
|
if ($schema.length < it.opts.loopRequired && it.schema.properties && Object.keys(it.schema.properties).length) {
|
|
var $required = [];
|
|
var arr1 = $schema;
|
|
if (arr1) {
|
|
var $property, i1 = -1,
|
|
l1 = arr1.length - 1;
|
|
while (i1 < l1) {
|
|
$property = arr1[i1 += 1];
|
|
var $propertySch = it.schema.properties[$property];
|
|
if (!($propertySch && (it.opts.strictKeywords ? (typeof $propertySch == 'object' && Object.keys($propertySch).length > 0) || $propertySch === false : it.util.schemaHasRules($propertySch, it.RULES.all)))) {
|
|
$required[$required.length] = $property;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
var $required = $schema;
|
|
}
|
|
}
|
|
if ($isData || $required.length) {
|
|
var $currentErrorPath = it.errorPath,
|
|
$loopRequired = $isData || $required.length >= it.opts.loopRequired,
|
|
$ownProperties = it.opts.ownProperties;
|
|
if ($breakOnError) {
|
|
out += ' var missing' + ($lvl) + '; ';
|
|
if ($loopRequired) {
|
|
if (!$isData) {
|
|
out += ' var ' + ($vSchema) + ' = validate.schema' + ($schemaPath) + '; ';
|
|
}
|
|
var $i = 'i' + $lvl,
|
|
$propertyPath = 'schema' + $lvl + '[' + $i + ']',
|
|
$missingProperty = '\' + ' + $propertyPath + ' + \'';
|
|
if (it.opts._errorDataPathProperty) {
|
|
it.errorPath = it.util.getPathExpr($currentErrorPath, $propertyPath, it.opts.jsonPointers);
|
|
}
|
|
out += ' var ' + ($valid) + ' = true; ';
|
|
if ($isData) {
|
|
out += ' if (schema' + ($lvl) + ' === undefined) ' + ($valid) + ' = true; else if (!Array.isArray(schema' + ($lvl) + ')) ' + ($valid) + ' = false; else {';
|
|
}
|
|
out += ' for (var ' + ($i) + ' = 0; ' + ($i) + ' < ' + ($vSchema) + '.length; ' + ($i) + '++) { ' + ($valid) + ' = ' + ($data) + '[' + ($vSchema) + '[' + ($i) + ']] !== undefined ';
|
|
if ($ownProperties) {
|
|
out += ' && Object.prototype.hasOwnProperty.call(' + ($data) + ', ' + ($vSchema) + '[' + ($i) + ']) ';
|
|
}
|
|
out += '; if (!' + ($valid) + ') break; } ';
|
|
if ($isData) {
|
|
out += ' } ';
|
|
}
|
|
out += ' if (!' + ($valid) + ') { ';
|
|
var $$outStack = $$outStack || [];
|
|
$$outStack.push(out);
|
|
out = ''; /* istanbul ignore else */
|
|
if (it.createErrors !== false) {
|
|
out += ' { keyword: \'' + ('required') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { missingProperty: \'' + ($missingProperty) + '\' } ';
|
|
if (it.opts.messages !== false) {
|
|
out += ' , message: \'';
|
|
if (it.opts._errorDataPathProperty) {
|
|
out += 'is a required property';
|
|
} else {
|
|
out += 'should have required property \\\'' + ($missingProperty) + '\\\'';
|
|
}
|
|
out += '\' ';
|
|
}
|
|
if (it.opts.verbose) {
|
|
out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
|
|
}
|
|
out += ' } ';
|
|
} else {
|
|
out += ' {} ';
|
|
}
|
|
var __err = out;
|
|
out = $$outStack.pop();
|
|
if (!it.compositeRule && $breakOnError) {
|
|
/* istanbul ignore if */
|
|
if (it.async) {
|
|
out += ' throw new ValidationError([' + (__err) + ']); ';
|
|
} else {
|
|
out += ' validate.errors = [' + (__err) + ']; return false; ';
|
|
}
|
|
} else {
|
|
out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';
|
|
}
|
|
out += ' } else { ';
|
|
} else {
|
|
out += ' if ( ';
|
|
var arr2 = $required;
|
|
if (arr2) {
|
|
var $propertyKey, $i = -1,
|
|
l2 = arr2.length - 1;
|
|
while ($i < l2) {
|
|
$propertyKey = arr2[$i += 1];
|
|
if ($i) {
|
|
out += ' || ';
|
|
}
|
|
var $prop = it.util.getProperty($propertyKey),
|
|
$useData = $data + $prop;
|
|
out += ' ( ( ' + ($useData) + ' === undefined ';
|
|
if ($ownProperties) {
|
|
out += ' || ! Object.prototype.hasOwnProperty.call(' + ($data) + ', \'' + (it.util.escapeQuotes($propertyKey)) + '\') ';
|
|
}
|
|
out += ') && (missing' + ($lvl) + ' = ' + (it.util.toQuotedString(it.opts.jsonPointers ? $propertyKey : $prop)) + ') ) ';
|
|
}
|
|
}
|
|
out += ') { ';
|
|
var $propertyPath = 'missing' + $lvl,
|
|
$missingProperty = '\' + ' + $propertyPath + ' + \'';
|
|
if (it.opts._errorDataPathProperty) {
|
|
it.errorPath = it.opts.jsonPointers ? it.util.getPathExpr($currentErrorPath, $propertyPath, true) : $currentErrorPath + ' + ' + $propertyPath;
|
|
}
|
|
var $$outStack = $$outStack || [];
|
|
$$outStack.push(out);
|
|
out = ''; /* istanbul ignore else */
|
|
if (it.createErrors !== false) {
|
|
out += ' { keyword: \'' + ('required') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { missingProperty: \'' + ($missingProperty) + '\' } ';
|
|
if (it.opts.messages !== false) {
|
|
out += ' , message: \'';
|
|
if (it.opts._errorDataPathProperty) {
|
|
out += 'is a required property';
|
|
} else {
|
|
out += 'should have required property \\\'' + ($missingProperty) + '\\\'';
|
|
}
|
|
out += '\' ';
|
|
}
|
|
if (it.opts.verbose) {
|
|
out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
|
|
}
|
|
out += ' } ';
|
|
} else {
|
|
out += ' {} ';
|
|
}
|
|
var __err = out;
|
|
out = $$outStack.pop();
|
|
if (!it.compositeRule && $breakOnError) {
|
|
/* istanbul ignore if */
|
|
if (it.async) {
|
|
out += ' throw new ValidationError([' + (__err) + ']); ';
|
|
} else {
|
|
out += ' validate.errors = [' + (__err) + ']; return false; ';
|
|
}
|
|
} else {
|
|
out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';
|
|
}
|
|
out += ' } else { ';
|
|
}
|
|
} else {
|
|
if ($loopRequired) {
|
|
if (!$isData) {
|
|
out += ' var ' + ($vSchema) + ' = validate.schema' + ($schemaPath) + '; ';
|
|
}
|
|
var $i = 'i' + $lvl,
|
|
$propertyPath = 'schema' + $lvl + '[' + $i + ']',
|
|
$missingProperty = '\' + ' + $propertyPath + ' + \'';
|
|
if (it.opts._errorDataPathProperty) {
|
|
it.errorPath = it.util.getPathExpr($currentErrorPath, $propertyPath, it.opts.jsonPointers);
|
|
}
|
|
if ($isData) {
|
|
out += ' if (' + ($vSchema) + ' && !Array.isArray(' + ($vSchema) + ')) { var err = '; /* istanbul ignore else */
|
|
if (it.createErrors !== false) {
|
|
out += ' { keyword: \'' + ('required') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { missingProperty: \'' + ($missingProperty) + '\' } ';
|
|
if (it.opts.messages !== false) {
|
|
out += ' , message: \'';
|
|
if (it.opts._errorDataPathProperty) {
|
|
out += 'is a required property';
|
|
} else {
|
|
out += 'should have required property \\\'' + ($missingProperty) + '\\\'';
|
|
}
|
|
out += '\' ';
|
|
}
|
|
if (it.opts.verbose) {
|
|
out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
|
|
}
|
|
out += ' } ';
|
|
} else {
|
|
out += ' {} ';
|
|
}
|
|
out += '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; } else if (' + ($vSchema) + ' !== undefined) { ';
|
|
}
|
|
out += ' for (var ' + ($i) + ' = 0; ' + ($i) + ' < ' + ($vSchema) + '.length; ' + ($i) + '++) { if (' + ($data) + '[' + ($vSchema) + '[' + ($i) + ']] === undefined ';
|
|
if ($ownProperties) {
|
|
out += ' || ! Object.prototype.hasOwnProperty.call(' + ($data) + ', ' + ($vSchema) + '[' + ($i) + ']) ';
|
|
}
|
|
out += ') { var err = '; /* istanbul ignore else */
|
|
if (it.createErrors !== false) {
|
|
out += ' { keyword: \'' + ('required') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { missingProperty: \'' + ($missingProperty) + '\' } ';
|
|
if (it.opts.messages !== false) {
|
|
out += ' , message: \'';
|
|
if (it.opts._errorDataPathProperty) {
|
|
out += 'is a required property';
|
|
} else {
|
|
out += 'should have required property \\\'' + ($missingProperty) + '\\\'';
|
|
}
|
|
out += '\' ';
|
|
}
|
|
if (it.opts.verbose) {
|
|
out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
|
|
}
|
|
out += ' } ';
|
|
} else {
|
|
out += ' {} ';
|
|
}
|
|
out += '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; } } ';
|
|
if ($isData) {
|
|
out += ' } ';
|
|
}
|
|
} else {
|
|
var arr3 = $required;
|
|
if (arr3) {
|
|
var $propertyKey, i3 = -1,
|
|
l3 = arr3.length - 1;
|
|
while (i3 < l3) {
|
|
$propertyKey = arr3[i3 += 1];
|
|
var $prop = it.util.getProperty($propertyKey),
|
|
$missingProperty = it.util.escapeQuotes($propertyKey),
|
|
$useData = $data + $prop;
|
|
if (it.opts._errorDataPathProperty) {
|
|
it.errorPath = it.util.getPath($currentErrorPath, $propertyKey, it.opts.jsonPointers);
|
|
}
|
|
out += ' if ( ' + ($useData) + ' === undefined ';
|
|
if ($ownProperties) {
|
|
out += ' || ! Object.prototype.hasOwnProperty.call(' + ($data) + ', \'' + (it.util.escapeQuotes($propertyKey)) + '\') ';
|
|
}
|
|
out += ') { var err = '; /* istanbul ignore else */
|
|
if (it.createErrors !== false) {
|
|
out += ' { keyword: \'' + ('required') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { missingProperty: \'' + ($missingProperty) + '\' } ';
|
|
if (it.opts.messages !== false) {
|
|
out += ' , message: \'';
|
|
if (it.opts._errorDataPathProperty) {
|
|
out += 'is a required property';
|
|
} else {
|
|
out += 'should have required property \\\'' + ($missingProperty) + '\\\'';
|
|
}
|
|
out += '\' ';
|
|
}
|
|
if (it.opts.verbose) {
|
|
out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
|
|
}
|
|
out += ' } ';
|
|
} else {
|
|
out += ' {} ';
|
|
}
|
|
out += '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; } ';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
it.errorPath = $currentErrorPath;
|
|
} else if ($breakOnError) {
|
|
out += ' if (true) {';
|
|
}
|
|
return out;
|
|
}
|
|
|
|
|
|
/***/ }),
|
|
|
|
/***/ 1985:
|
|
/***/ (function(module) {
|
|
|
|
"use strict";
|
|
|
|
module.exports = function generate_uniqueItems(it, $keyword, $ruleType) {
|
|
var out = ' ';
|
|
var $lvl = it.level;
|
|
var $dataLvl = it.dataLevel;
|
|
var $schema = it.schema[$keyword];
|
|
var $schemaPath = it.schemaPath + it.util.getProperty($keyword);
|
|
var $errSchemaPath = it.errSchemaPath + '/' + $keyword;
|
|
var $breakOnError = !it.opts.allErrors;
|
|
var $data = 'data' + ($dataLvl || '');
|
|
var $valid = 'valid' + $lvl;
|
|
var $isData = it.opts.$data && $schema && $schema.$data,
|
|
$schemaValue;
|
|
if ($isData) {
|
|
out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; ';
|
|
$schemaValue = 'schema' + $lvl;
|
|
} else {
|
|
$schemaValue = $schema;
|
|
}
|
|
if (($schema || $isData) && it.opts.uniqueItems !== false) {
|
|
if ($isData) {
|
|
out += ' var ' + ($valid) + '; if (' + ($schemaValue) + ' === false || ' + ($schemaValue) + ' === undefined) ' + ($valid) + ' = true; else if (typeof ' + ($schemaValue) + ' != \'boolean\') ' + ($valid) + ' = false; else { ';
|
|
}
|
|
out += ' var i = ' + ($data) + '.length , ' + ($valid) + ' = true , j; if (i > 1) { ';
|
|
var $itemType = it.schema.items && it.schema.items.type,
|
|
$typeIsArray = Array.isArray($itemType);
|
|
if (!$itemType || $itemType == 'object' || $itemType == 'array' || ($typeIsArray && ($itemType.indexOf('object') >= 0 || $itemType.indexOf('array') >= 0))) {
|
|
out += ' outer: for (;i--;) { for (j = i; j--;) { if (equal(' + ($data) + '[i], ' + ($data) + '[j])) { ' + ($valid) + ' = false; break outer; } } } ';
|
|
} else {
|
|
out += ' var itemIndices = {}, item; for (;i--;) { var item = ' + ($data) + '[i]; ';
|
|
var $method = 'checkDataType' + ($typeIsArray ? 's' : '');
|
|
out += ' if (' + (it.util[$method]($itemType, 'item', it.opts.strictNumbers, true)) + ') continue; ';
|
|
if ($typeIsArray) {
|
|
out += ' if (typeof item == \'string\') item = \'"\' + item; ';
|
|
}
|
|
out += ' if (typeof itemIndices[item] == \'number\') { ' + ($valid) + ' = false; j = itemIndices[item]; break; } itemIndices[item] = i; } ';
|
|
}
|
|
out += ' } ';
|
|
if ($isData) {
|
|
out += ' } ';
|
|
}
|
|
out += ' if (!' + ($valid) + ') { ';
|
|
var $$outStack = $$outStack || [];
|
|
$$outStack.push(out);
|
|
out = ''; /* istanbul ignore else */
|
|
if (it.createErrors !== false) {
|
|
out += ' { keyword: \'' + ('uniqueItems') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { i: i, j: j } ';
|
|
if (it.opts.messages !== false) {
|
|
out += ' , message: \'should NOT have duplicate items (items ## \' + j + \' and \' + i + \' are identical)\' ';
|
|
}
|
|
if (it.opts.verbose) {
|
|
out += ' , schema: ';
|
|
if ($isData) {
|
|
out += 'validate.schema' + ($schemaPath);
|
|
} else {
|
|
out += '' + ($schema);
|
|
}
|
|
out += ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
|
|
}
|
|
out += ' } ';
|
|
} else {
|
|
out += ' {} ';
|
|
}
|
|
var __err = out;
|
|
out = $$outStack.pop();
|
|
if (!it.compositeRule && $breakOnError) {
|
|
/* istanbul ignore if */
|
|
if (it.async) {
|
|
out += ' throw new ValidationError([' + (__err) + ']); ';
|
|
} else {
|
|
out += ' validate.errors = [' + (__err) + ']; return false; ';
|
|
}
|
|
} else {
|
|
out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';
|
|
}
|
|
out += ' } ';
|
|
if ($breakOnError) {
|
|
out += ' else { ';
|
|
}
|
|
} else {
|
|
if ($breakOnError) {
|
|
out += ' if (true) { ';
|
|
}
|
|
}
|
|
return out;
|
|
}
|
|
|
|
|
|
/***/ }),
|
|
|
|
/***/ 1869:
|
|
/***/ (function(module) {
|
|
|
|
"use strict";
|
|
|
|
module.exports = function generate_validate(it, $keyword, $ruleType) {
|
|
var out = '';
|
|
var $async = it.schema.$async === true,
|
|
$refKeywords = it.util.schemaHasRulesExcept(it.schema, it.RULES.all, '$ref'),
|
|
$id = it.self._getId(it.schema);
|
|
if (it.opts.strictKeywords) {
|
|
var $unknownKwd = it.util.schemaUnknownRules(it.schema, it.RULES.keywords);
|
|
if ($unknownKwd) {
|
|
var $keywordsMsg = 'unknown keyword: ' + $unknownKwd;
|
|
if (it.opts.strictKeywords === 'log') it.logger.warn($keywordsMsg);
|
|
else throw new Error($keywordsMsg);
|
|
}
|
|
}
|
|
if (it.isTop) {
|
|
out += ' var validate = ';
|
|
if ($async) {
|
|
it.async = true;
|
|
out += 'async ';
|
|
}
|
|
out += 'function(data, dataPath, parentData, parentDataProperty, rootData) { \'use strict\'; ';
|
|
if ($id && (it.opts.sourceCode || it.opts.processCode)) {
|
|
out += ' ' + ('/\*# sourceURL=' + $id + ' */') + ' ';
|
|
}
|
|
}
|
|
if (typeof it.schema == 'boolean' || !($refKeywords || it.schema.$ref)) {
|
|
var $keyword = 'false schema';
|
|
var $lvl = it.level;
|
|
var $dataLvl = it.dataLevel;
|
|
var $schema = it.schema[$keyword];
|
|
var $schemaPath = it.schemaPath + it.util.getProperty($keyword);
|
|
var $errSchemaPath = it.errSchemaPath + '/' + $keyword;
|
|
var $breakOnError = !it.opts.allErrors;
|
|
var $errorKeyword;
|
|
var $data = 'data' + ($dataLvl || '');
|
|
var $valid = 'valid' + $lvl;
|
|
if (it.schema === false) {
|
|
if (it.isTop) {
|
|
$breakOnError = true;
|
|
} else {
|
|
out += ' var ' + ($valid) + ' = false; ';
|
|
}
|
|
var $$outStack = $$outStack || [];
|
|
$$outStack.push(out);
|
|
out = ''; /* istanbul ignore else */
|
|
if (it.createErrors !== false) {
|
|
out += ' { keyword: \'' + ($errorKeyword || 'false schema') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: {} ';
|
|
if (it.opts.messages !== false) {
|
|
out += ' , message: \'boolean schema is false\' ';
|
|
}
|
|
if (it.opts.verbose) {
|
|
out += ' , schema: false , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
|
|
}
|
|
out += ' } ';
|
|
} else {
|
|
out += ' {} ';
|
|
}
|
|
var __err = out;
|
|
out = $$outStack.pop();
|
|
if (!it.compositeRule && $breakOnError) {
|
|
/* istanbul ignore if */
|
|
if (it.async) {
|
|
out += ' throw new ValidationError([' + (__err) + ']); ';
|
|
} else {
|
|
out += ' validate.errors = [' + (__err) + ']; return false; ';
|
|
}
|
|
} else {
|
|
out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';
|
|
}
|
|
} else {
|
|
if (it.isTop) {
|
|
if ($async) {
|
|
out += ' return data; ';
|
|
} else {
|
|
out += ' validate.errors = null; return true; ';
|
|
}
|
|
} else {
|
|
out += ' var ' + ($valid) + ' = true; ';
|
|
}
|
|
}
|
|
if (it.isTop) {
|
|
out += ' }; return validate; ';
|
|
}
|
|
return out;
|
|
}
|
|
if (it.isTop) {
|
|
var $top = it.isTop,
|
|
$lvl = it.level = 0,
|
|
$dataLvl = it.dataLevel = 0,
|
|
$data = 'data';
|
|
it.rootId = it.resolve.fullPath(it.self._getId(it.root.schema));
|
|
it.baseId = it.baseId || it.rootId;
|
|
delete it.isTop;
|
|
it.dataPathArr = [""];
|
|
if (it.schema.default !== undefined && it.opts.useDefaults && it.opts.strictDefaults) {
|
|
var $defaultMsg = 'default is ignored in the schema root';
|
|
if (it.opts.strictDefaults === 'log') it.logger.warn($defaultMsg);
|
|
else throw new Error($defaultMsg);
|
|
}
|
|
out += ' var vErrors = null; ';
|
|
out += ' var errors = 0; ';
|
|
out += ' if (rootData === undefined) rootData = data; ';
|
|
} else {
|
|
var $lvl = it.level,
|
|
$dataLvl = it.dataLevel,
|
|
$data = 'data' + ($dataLvl || '');
|
|
if ($id) it.baseId = it.resolve.url(it.baseId, $id);
|
|
if ($async && !it.async) throw new Error('async schema in sync schema');
|
|
out += ' var errs_' + ($lvl) + ' = errors;';
|
|
}
|
|
var $valid = 'valid' + $lvl,
|
|
$breakOnError = !it.opts.allErrors,
|
|
$closingBraces1 = '',
|
|
$closingBraces2 = '';
|
|
var $errorKeyword;
|
|
var $typeSchema = it.schema.type,
|
|
$typeIsArray = Array.isArray($typeSchema);
|
|
if ($typeSchema && it.opts.nullable && it.schema.nullable === true) {
|
|
if ($typeIsArray) {
|
|
if ($typeSchema.indexOf('null') == -1) $typeSchema = $typeSchema.concat('null');
|
|
} else if ($typeSchema != 'null') {
|
|
$typeSchema = [$typeSchema, 'null'];
|
|
$typeIsArray = true;
|
|
}
|
|
}
|
|
if ($typeIsArray && $typeSchema.length == 1) {
|
|
$typeSchema = $typeSchema[0];
|
|
$typeIsArray = false;
|
|
}
|
|
if (it.schema.$ref && $refKeywords) {
|
|
if (it.opts.extendRefs == 'fail') {
|
|
throw new Error('$ref: validation keywords used in schema at path "' + it.errSchemaPath + '" (see option extendRefs)');
|
|
} else if (it.opts.extendRefs !== true) {
|
|
$refKeywords = false;
|
|
it.logger.warn('$ref: keywords ignored in schema at path "' + it.errSchemaPath + '"');
|
|
}
|
|
}
|
|
if (it.schema.$comment && it.opts.$comment) {
|
|
out += ' ' + (it.RULES.all.$comment.code(it, '$comment'));
|
|
}
|
|
if ($typeSchema) {
|
|
if (it.opts.coerceTypes) {
|
|
var $coerceToTypes = it.util.coerceToTypes(it.opts.coerceTypes, $typeSchema);
|
|
}
|
|
var $rulesGroup = it.RULES.types[$typeSchema];
|
|
if ($coerceToTypes || $typeIsArray || $rulesGroup === true || ($rulesGroup && !$shouldUseGroup($rulesGroup))) {
|
|
var $schemaPath = it.schemaPath + '.type',
|
|
$errSchemaPath = it.errSchemaPath + '/type';
|
|
var $schemaPath = it.schemaPath + '.type',
|
|
$errSchemaPath = it.errSchemaPath + '/type',
|
|
$method = $typeIsArray ? 'checkDataTypes' : 'checkDataType';
|
|
out += ' if (' + (it.util[$method]($typeSchema, $data, it.opts.strictNumbers, true)) + ') { ';
|
|
if ($coerceToTypes) {
|
|
var $dataType = 'dataType' + $lvl,
|
|
$coerced = 'coerced' + $lvl;
|
|
out += ' var ' + ($dataType) + ' = typeof ' + ($data) + '; var ' + ($coerced) + ' = undefined; ';
|
|
if (it.opts.coerceTypes == 'array') {
|
|
out += ' if (' + ($dataType) + ' == \'object\' && Array.isArray(' + ($data) + ') && ' + ($data) + '.length == 1) { ' + ($data) + ' = ' + ($data) + '[0]; ' + ($dataType) + ' = typeof ' + ($data) + '; if (' + (it.util.checkDataType(it.schema.type, $data, it.opts.strictNumbers)) + ') ' + ($coerced) + ' = ' + ($data) + '; } ';
|
|
}
|
|
out += ' if (' + ($coerced) + ' !== undefined) ; ';
|
|
var arr1 = $coerceToTypes;
|
|
if (arr1) {
|
|
var $type, $i = -1,
|
|
l1 = arr1.length - 1;
|
|
while ($i < l1) {
|
|
$type = arr1[$i += 1];
|
|
if ($type == 'string') {
|
|
out += ' else if (' + ($dataType) + ' == \'number\' || ' + ($dataType) + ' == \'boolean\') ' + ($coerced) + ' = \'\' + ' + ($data) + '; else if (' + ($data) + ' === null) ' + ($coerced) + ' = \'\'; ';
|
|
} else if ($type == 'number' || $type == 'integer') {
|
|
out += ' else if (' + ($dataType) + ' == \'boolean\' || ' + ($data) + ' === null || (' + ($dataType) + ' == \'string\' && ' + ($data) + ' && ' + ($data) + ' == +' + ($data) + ' ';
|
|
if ($type == 'integer') {
|
|
out += ' && !(' + ($data) + ' % 1)';
|
|
}
|
|
out += ')) ' + ($coerced) + ' = +' + ($data) + '; ';
|
|
} else if ($type == 'boolean') {
|
|
out += ' else if (' + ($data) + ' === \'false\' || ' + ($data) + ' === 0 || ' + ($data) + ' === null) ' + ($coerced) + ' = false; else if (' + ($data) + ' === \'true\' || ' + ($data) + ' === 1) ' + ($coerced) + ' = true; ';
|
|
} else if ($type == 'null') {
|
|
out += ' else if (' + ($data) + ' === \'\' || ' + ($data) + ' === 0 || ' + ($data) + ' === false) ' + ($coerced) + ' = null; ';
|
|
} else if (it.opts.coerceTypes == 'array' && $type == 'array') {
|
|
out += ' else if (' + ($dataType) + ' == \'string\' || ' + ($dataType) + ' == \'number\' || ' + ($dataType) + ' == \'boolean\' || ' + ($data) + ' == null) ' + ($coerced) + ' = [' + ($data) + ']; ';
|
|
}
|
|
}
|
|
}
|
|
out += ' else { ';
|
|
var $$outStack = $$outStack || [];
|
|
$$outStack.push(out);
|
|
out = ''; /* istanbul ignore else */
|
|
if (it.createErrors !== false) {
|
|
out += ' { keyword: \'' + ($errorKeyword || 'type') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { type: \'';
|
|
if ($typeIsArray) {
|
|
out += '' + ($typeSchema.join(","));
|
|
} else {
|
|
out += '' + ($typeSchema);
|
|
}
|
|
out += '\' } ';
|
|
if (it.opts.messages !== false) {
|
|
out += ' , message: \'should be ';
|
|
if ($typeIsArray) {
|
|
out += '' + ($typeSchema.join(","));
|
|
} else {
|
|
out += '' + ($typeSchema);
|
|
}
|
|
out += '\' ';
|
|
}
|
|
if (it.opts.verbose) {
|
|
out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
|
|
}
|
|
out += ' } ';
|
|
} else {
|
|
out += ' {} ';
|
|
}
|
|
var __err = out;
|
|
out = $$outStack.pop();
|
|
if (!it.compositeRule && $breakOnError) {
|
|
/* istanbul ignore if */
|
|
if (it.async) {
|
|
out += ' throw new ValidationError([' + (__err) + ']); ';
|
|
} else {
|
|
out += ' validate.errors = [' + (__err) + ']; return false; ';
|
|
}
|
|
} else {
|
|
out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';
|
|
}
|
|
out += ' } if (' + ($coerced) + ' !== undefined) { ';
|
|
var $parentData = $dataLvl ? 'data' + (($dataLvl - 1) || '') : 'parentData',
|
|
$parentDataProperty = $dataLvl ? it.dataPathArr[$dataLvl] : 'parentDataProperty';
|
|
out += ' ' + ($data) + ' = ' + ($coerced) + '; ';
|
|
if (!$dataLvl) {
|
|
out += 'if (' + ($parentData) + ' !== undefined)';
|
|
}
|
|
out += ' ' + ($parentData) + '[' + ($parentDataProperty) + '] = ' + ($coerced) + '; } ';
|
|
} else {
|
|
var $$outStack = $$outStack || [];
|
|
$$outStack.push(out);
|
|
out = ''; /* istanbul ignore else */
|
|
if (it.createErrors !== false) {
|
|
out += ' { keyword: \'' + ($errorKeyword || 'type') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { type: \'';
|
|
if ($typeIsArray) {
|
|
out += '' + ($typeSchema.join(","));
|
|
} else {
|
|
out += '' + ($typeSchema);
|
|
}
|
|
out += '\' } ';
|
|
if (it.opts.messages !== false) {
|
|
out += ' , message: \'should be ';
|
|
if ($typeIsArray) {
|
|
out += '' + ($typeSchema.join(","));
|
|
} else {
|
|
out += '' + ($typeSchema);
|
|
}
|
|
out += '\' ';
|
|
}
|
|
if (it.opts.verbose) {
|
|
out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
|
|
}
|
|
out += ' } ';
|
|
} else {
|
|
out += ' {} ';
|
|
}
|
|
var __err = out;
|
|
out = $$outStack.pop();
|
|
if (!it.compositeRule && $breakOnError) {
|
|
/* istanbul ignore if */
|
|
if (it.async) {
|
|
out += ' throw new ValidationError([' + (__err) + ']); ';
|
|
} else {
|
|
out += ' validate.errors = [' + (__err) + ']; return false; ';
|
|
}
|
|
} else {
|
|
out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';
|
|
}
|
|
}
|
|
out += ' } ';
|
|
}
|
|
}
|
|
if (it.schema.$ref && !$refKeywords) {
|
|
out += ' ' + (it.RULES.all.$ref.code(it, '$ref')) + ' ';
|
|
if ($breakOnError) {
|
|
out += ' } if (errors === ';
|
|
if ($top) {
|
|
out += '0';
|
|
} else {
|
|
out += 'errs_' + ($lvl);
|
|
}
|
|
out += ') { ';
|
|
$closingBraces2 += '}';
|
|
}
|
|
} else {
|
|
var arr2 = it.RULES;
|
|
if (arr2) {
|
|
var $rulesGroup, i2 = -1,
|
|
l2 = arr2.length - 1;
|
|
while (i2 < l2) {
|
|
$rulesGroup = arr2[i2 += 1];
|
|
if ($shouldUseGroup($rulesGroup)) {
|
|
if ($rulesGroup.type) {
|
|
out += ' if (' + (it.util.checkDataType($rulesGroup.type, $data, it.opts.strictNumbers)) + ') { ';
|
|
}
|
|
if (it.opts.useDefaults) {
|
|
if ($rulesGroup.type == 'object' && it.schema.properties) {
|
|
var $schema = it.schema.properties,
|
|
$schemaKeys = Object.keys($schema);
|
|
var arr3 = $schemaKeys;
|
|
if (arr3) {
|
|
var $propertyKey, i3 = -1,
|
|
l3 = arr3.length - 1;
|
|
while (i3 < l3) {
|
|
$propertyKey = arr3[i3 += 1];
|
|
var $sch = $schema[$propertyKey];
|
|
if ($sch.default !== undefined) {
|
|
var $passData = $data + it.util.getProperty($propertyKey);
|
|
if (it.compositeRule) {
|
|
if (it.opts.strictDefaults) {
|
|
var $defaultMsg = 'default is ignored for: ' + $passData;
|
|
if (it.opts.strictDefaults === 'log') it.logger.warn($defaultMsg);
|
|
else throw new Error($defaultMsg);
|
|
}
|
|
} else {
|
|
out += ' if (' + ($passData) + ' === undefined ';
|
|
if (it.opts.useDefaults == 'empty') {
|
|
out += ' || ' + ($passData) + ' === null || ' + ($passData) + ' === \'\' ';
|
|
}
|
|
out += ' ) ' + ($passData) + ' = ';
|
|
if (it.opts.useDefaults == 'shared') {
|
|
out += ' ' + (it.useDefault($sch.default)) + ' ';
|
|
} else {
|
|
out += ' ' + (JSON.stringify($sch.default)) + ' ';
|
|
}
|
|
out += '; ';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else if ($rulesGroup.type == 'array' && Array.isArray(it.schema.items)) {
|
|
var arr4 = it.schema.items;
|
|
if (arr4) {
|
|
var $sch, $i = -1,
|
|
l4 = arr4.length - 1;
|
|
while ($i < l4) {
|
|
$sch = arr4[$i += 1];
|
|
if ($sch.default !== undefined) {
|
|
var $passData = $data + '[' + $i + ']';
|
|
if (it.compositeRule) {
|
|
if (it.opts.strictDefaults) {
|
|
var $defaultMsg = 'default is ignored for: ' + $passData;
|
|
if (it.opts.strictDefaults === 'log') it.logger.warn($defaultMsg);
|
|
else throw new Error($defaultMsg);
|
|
}
|
|
} else {
|
|
out += ' if (' + ($passData) + ' === undefined ';
|
|
if (it.opts.useDefaults == 'empty') {
|
|
out += ' || ' + ($passData) + ' === null || ' + ($passData) + ' === \'\' ';
|
|
}
|
|
out += ' ) ' + ($passData) + ' = ';
|
|
if (it.opts.useDefaults == 'shared') {
|
|
out += ' ' + (it.useDefault($sch.default)) + ' ';
|
|
} else {
|
|
out += ' ' + (JSON.stringify($sch.default)) + ' ';
|
|
}
|
|
out += '; ';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
var arr5 = $rulesGroup.rules;
|
|
if (arr5) {
|
|
var $rule, i5 = -1,
|
|
l5 = arr5.length - 1;
|
|
while (i5 < l5) {
|
|
$rule = arr5[i5 += 1];
|
|
if ($shouldUseRule($rule)) {
|
|
var $code = $rule.code(it, $rule.keyword, $rulesGroup.type);
|
|
if ($code) {
|
|
out += ' ' + ($code) + ' ';
|
|
if ($breakOnError) {
|
|
$closingBraces1 += '}';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if ($breakOnError) {
|
|
out += ' ' + ($closingBraces1) + ' ';
|
|
$closingBraces1 = '';
|
|
}
|
|
if ($rulesGroup.type) {
|
|
out += ' } ';
|
|
if ($typeSchema && $typeSchema === $rulesGroup.type && !$coerceToTypes) {
|
|
out += ' else { ';
|
|
var $schemaPath = it.schemaPath + '.type',
|
|
$errSchemaPath = it.errSchemaPath + '/type';
|
|
var $$outStack = $$outStack || [];
|
|
$$outStack.push(out);
|
|
out = ''; /* istanbul ignore else */
|
|
if (it.createErrors !== false) {
|
|
out += ' { keyword: \'' + ($errorKeyword || 'type') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { type: \'';
|
|
if ($typeIsArray) {
|
|
out += '' + ($typeSchema.join(","));
|
|
} else {
|
|
out += '' + ($typeSchema);
|
|
}
|
|
out += '\' } ';
|
|
if (it.opts.messages !== false) {
|
|
out += ' , message: \'should be ';
|
|
if ($typeIsArray) {
|
|
out += '' + ($typeSchema.join(","));
|
|
} else {
|
|
out += '' + ($typeSchema);
|
|
}
|
|
out += '\' ';
|
|
}
|
|
if (it.opts.verbose) {
|
|
out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
|
|
}
|
|
out += ' } ';
|
|
} else {
|
|
out += ' {} ';
|
|
}
|
|
var __err = out;
|
|
out = $$outStack.pop();
|
|
if (!it.compositeRule && $breakOnError) {
|
|
/* istanbul ignore if */
|
|
if (it.async) {
|
|
out += ' throw new ValidationError([' + (__err) + ']); ';
|
|
} else {
|
|
out += ' validate.errors = [' + (__err) + ']; return false; ';
|
|
}
|
|
} else {
|
|
out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';
|
|
}
|
|
out += ' } ';
|
|
}
|
|
}
|
|
if ($breakOnError) {
|
|
out += ' if (errors === ';
|
|
if ($top) {
|
|
out += '0';
|
|
} else {
|
|
out += 'errs_' + ($lvl);
|
|
}
|
|
out += ') { ';
|
|
$closingBraces2 += '}';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if ($breakOnError) {
|
|
out += ' ' + ($closingBraces2) + ' ';
|
|
}
|
|
if ($top) {
|
|
if ($async) {
|
|
out += ' if (errors === 0) return data; ';
|
|
out += ' else throw new ValidationError(vErrors); ';
|
|
} else {
|
|
out += ' validate.errors = vErrors; ';
|
|
out += ' return errors === 0; ';
|
|
}
|
|
out += ' }; return validate;';
|
|
} else {
|
|
out += ' var ' + ($valid) + ' = errors === errs_' + ($lvl) + ';';
|
|
}
|
|
|
|
function $shouldUseGroup($rulesGroup) {
|
|
var rules = $rulesGroup.rules;
|
|
for (var i = 0; i < rules.length; i++)
|
|
if ($shouldUseRule(rules[i])) return true;
|
|
}
|
|
|
|
function $shouldUseRule($rule) {
|
|
return it.schema[$rule.keyword] !== undefined || ($rule.implements && $ruleImplementsSomeKeyword($rule));
|
|
}
|
|
|
|
function $ruleImplementsSomeKeyword($rule) {
|
|
var impl = $rule.implements;
|
|
for (var i = 0; i < impl.length; i++)
|
|
if (it.schema[impl[i]] !== undefined) return true;
|
|
}
|
|
return out;
|
|
}
|
|
|
|
|
|
/***/ }),
|
|
|
|
/***/ 7931:
|
|
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
|
|
|
|
"use strict";
|
|
|
|
|
|
var IDENTIFIER = /^[a-z_$][a-z0-9_$-]*$/i;
|
|
var customRuleCode = __webpack_require__(1793);
|
|
var definitionSchema = __webpack_require__(5868);
|
|
|
|
module.exports = {
|
|
add: addKeyword,
|
|
get: getKeyword,
|
|
remove: removeKeyword,
|
|
validate: validateKeyword
|
|
};
|
|
|
|
|
|
/**
|
|
* Define custom keyword
|
|
* @this Ajv
|
|
* @param {String} keyword custom keyword, should be unique (including different from all standard, custom and macro keywords).
|
|
* @param {Object} definition keyword definition object with properties `type` (type(s) which the keyword applies to), `validate` or `compile`.
|
|
* @return {Ajv} this for method chaining
|
|
*/
|
|
function addKeyword(keyword, definition) {
|
|
/* jshint validthis: true */
|
|
/* eslint no-shadow: 0 */
|
|
var RULES = this.RULES;
|
|
if (RULES.keywords[keyword])
|
|
throw new Error('Keyword ' + keyword + ' is already defined');
|
|
|
|
if (!IDENTIFIER.test(keyword))
|
|
throw new Error('Keyword ' + keyword + ' is not a valid identifier');
|
|
|
|
if (definition) {
|
|
this.validateKeyword(definition, true);
|
|
|
|
var dataType = definition.type;
|
|
if (Array.isArray(dataType)) {
|
|
for (var i=0; i<dataType.length; i++)
|
|
_addRule(keyword, dataType[i], definition);
|
|
} else {
|
|
_addRule(keyword, dataType, definition);
|
|
}
|
|
|
|
var metaSchema = definition.metaSchema;
|
|
if (metaSchema) {
|
|
if (definition.$data && this._opts.$data) {
|
|
metaSchema = {
|
|
anyOf: [
|
|
metaSchema,
|
|
{ '$ref': 'https://raw.githubusercontent.com/ajv-validator/ajv/master/lib/refs/data.json#' }
|
|
]
|
|
};
|
|
}
|
|
definition.validateSchema = this.compile(metaSchema, true);
|
|
}
|
|
}
|
|
|
|
RULES.keywords[keyword] = RULES.all[keyword] = true;
|
|
|
|
|
|
function _addRule(keyword, dataType, definition) {
|
|
var ruleGroup;
|
|
for (var i=0; i<RULES.length; i++) {
|
|
var rg = RULES[i];
|
|
if (rg.type == dataType) {
|
|
ruleGroup = rg;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!ruleGroup) {
|
|
ruleGroup = { type: dataType, rules: [] };
|
|
RULES.push(ruleGroup);
|
|
}
|
|
|
|
var rule = {
|
|
keyword: keyword,
|
|
definition: definition,
|
|
custom: true,
|
|
code: customRuleCode,
|
|
implements: definition.implements
|
|
};
|
|
ruleGroup.rules.push(rule);
|
|
RULES.custom[keyword] = rule;
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
|
|
/**
|
|
* Get keyword
|
|
* @this Ajv
|
|
* @param {String} keyword pre-defined or custom keyword.
|
|
* @return {Object|Boolean} custom keyword definition, `true` if it is a predefined keyword, `false` otherwise.
|
|
*/
|
|
function getKeyword(keyword) {
|
|
/* jshint validthis: true */
|
|
var rule = this.RULES.custom[keyword];
|
|
return rule ? rule.definition : this.RULES.keywords[keyword] || false;
|
|
}
|
|
|
|
|
|
/**
|
|
* Remove keyword
|
|
* @this Ajv
|
|
* @param {String} keyword pre-defined or custom keyword.
|
|
* @return {Ajv} this for method chaining
|
|
*/
|
|
function removeKeyword(keyword) {
|
|
/* jshint validthis: true */
|
|
var RULES = this.RULES;
|
|
delete RULES.keywords[keyword];
|
|
delete RULES.all[keyword];
|
|
delete RULES.custom[keyword];
|
|
for (var i=0; i<RULES.length; i++) {
|
|
var rules = RULES[i].rules;
|
|
for (var j=0; j<rules.length; j++) {
|
|
if (rules[j].keyword == keyword) {
|
|
rules.splice(j, 1);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return this;
|
|
}
|
|
|
|
|
|
/**
|
|
* Validate keyword definition
|
|
* @this Ajv
|
|
* @param {Object} definition keyword definition object.
|
|
* @param {Boolean} throwError true to throw exception if definition is invalid
|
|
* @return {boolean} validation result
|
|
*/
|
|
function validateKeyword(definition, throwError) {
|
|
validateKeyword.errors = null;
|
|
var v = this._validateKeyword = this._validateKeyword
|
|
|| this.compile(definitionSchema, true);
|
|
|
|
if (v(definition)) return true;
|
|
validateKeyword.errors = v.errors;
|
|
if (throwError)
|
|
throw new Error('custom keyword definition is invalid: ' + this.errorsText(v.errors));
|
|
else
|
|
return false;
|
|
}
|
|
|
|
|
|
/***/ }),
|
|
|
|
/***/ 2303:
|
|
/***/ (function(module) {
|
|
|
|
"use strict";
|
|
|
|
|
|
// do not edit .js files directly - edit src/index.jst
|
|
|
|
|
|
|
|
module.exports = function equal(a, b) {
|
|
if (a === b) return true;
|
|
|
|
if (a && b && typeof a == 'object' && typeof b == 'object') {
|
|
if (a.constructor !== b.constructor) return false;
|
|
|
|
var length, i, keys;
|
|
if (Array.isArray(a)) {
|
|
length = a.length;
|
|
if (length != b.length) return false;
|
|
for (i = length; i-- !== 0;)
|
|
if (!equal(a[i], b[i])) return false;
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
if (a.constructor === RegExp) return a.source === b.source && a.flags === b.flags;
|
|
if (a.valueOf !== Object.prototype.valueOf) return a.valueOf() === b.valueOf();
|
|
if (a.toString !== Object.prototype.toString) return a.toString() === b.toString();
|
|
|
|
keys = Object.keys(a);
|
|
length = keys.length;
|
|
if (length !== Object.keys(b).length) return false;
|
|
|
|
for (i = length; i-- !== 0;)
|
|
if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false;
|
|
|
|
for (i = length; i-- !== 0;) {
|
|
var key = keys[i];
|
|
|
|
if (!equal(a[key], b[key])) return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// true if both NaN, false otherwise
|
|
return a!==a && b!==b;
|
|
};
|
|
|
|
|
|
/***/ }),
|
|
|
|
/***/ 3508:
|
|
/***/ (function(module) {
|
|
|
|
"use strict";
|
|
|
|
|
|
module.exports = function (data, opts) {
|
|
if (!opts) opts = {};
|
|
if (typeof opts === 'function') opts = { cmp: opts };
|
|
var cycles = (typeof opts.cycles === 'boolean') ? opts.cycles : false;
|
|
|
|
var cmp = opts.cmp && (function (f) {
|
|
return function (node) {
|
|
return function (a, b) {
|
|
var aobj = { key: a, value: node[a] };
|
|
var bobj = { key: b, value: node[b] };
|
|
return f(aobj, bobj);
|
|
};
|
|
};
|
|
})(opts.cmp);
|
|
|
|
var seen = [];
|
|
return (function stringify (node) {
|
|
if (node && node.toJSON && typeof node.toJSON === 'function') {
|
|
node = node.toJSON();
|
|
}
|
|
|
|
if (node === undefined) return;
|
|
if (typeof node == 'number') return isFinite(node) ? '' + node : 'null';
|
|
if (typeof node !== 'object') return JSON.stringify(node);
|
|
|
|
var i, out;
|
|
if (Array.isArray(node)) {
|
|
out = '[';
|
|
for (i = 0; i < node.length; i++) {
|
|
if (i) out += ',';
|
|
out += stringify(node[i]) || 'null';
|
|
}
|
|
return out + ']';
|
|
}
|
|
|
|
if (node === null) return 'null';
|
|
|
|
if (seen.indexOf(node) !== -1) {
|
|
if (cycles) return JSON.stringify('__cycle__');
|
|
throw new TypeError('Converting circular structure to JSON');
|
|
}
|
|
|
|
var seenIndex = seen.push(node) - 1;
|
|
var keys = Object.keys(node).sort(cmp && cmp(node));
|
|
out = '';
|
|
for (i = 0; i < keys.length; i++) {
|
|
var key = keys[i];
|
|
var value = stringify(node[key]);
|
|
|
|
if (!value) continue;
|
|
if (out) out += ',';
|
|
out += JSON.stringify(key) + ':' + value;
|
|
}
|
|
seen.splice(seenIndex, 1);
|
|
return '{' + out + '}';
|
|
})(data);
|
|
};
|
|
|
|
|
|
/***/ }),
|
|
|
|
/***/ 233:
|
|
/***/ (function(module) {
|
|
|
|
/*
|
|
* Natural Sort algorithm for Javascript - Version 0.7 - Released under MIT license
|
|
* Author: Jim Palmer (based on chunking idea from Dave Koelle)
|
|
*/
|
|
/*jshint unused:false */
|
|
module.exports = function naturalSort (a, b) {
|
|
"use strict";
|
|
var re = /(^([+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)?$|^0x[0-9a-f]+$|\d+)/gi,
|
|
sre = /(^[ ]*|[ ]*$)/g,
|
|
dre = /(^([\w ]+,?[\w ]+)?[\w ]+,?[\w ]+\d+:\d+(:\d+)?[\w ]?|^\d{1,4}[\/\-]\d{1,4}[\/\-]\d{1,4}|^\w+, \w+ \d+, \d{4})/,
|
|
hre = /^0x[0-9a-f]+$/i,
|
|
ore = /^0/,
|
|
i = function(s) { return naturalSort.insensitive && ('' + s).toLowerCase() || '' + s; },
|
|
// convert all to strings strip whitespace
|
|
x = i(a).replace(sre, '') || '',
|
|
y = i(b).replace(sre, '') || '',
|
|
// chunk/tokenize
|
|
xN = x.replace(re, '\0$1\0').replace(/\0$/,'').replace(/^\0/,'').split('\0'),
|
|
yN = y.replace(re, '\0$1\0').replace(/\0$/,'').replace(/^\0/,'').split('\0'),
|
|
// numeric, hex or date detection
|
|
xD = parseInt(x.match(hre), 16) || (xN.length !== 1 && x.match(dre) && Date.parse(x)),
|
|
yD = parseInt(y.match(hre), 16) || xD && y.match(dre) && Date.parse(y) || null,
|
|
oFxNcL, oFyNcL;
|
|
// first try and sort Hex codes or Dates
|
|
if (yD) {
|
|
if ( xD < yD ) { return -1; }
|
|
else if ( xD > yD ) { return 1; }
|
|
}
|
|
// natural sorting through split numeric strings and default strings
|
|
for(var cLoc=0, numS=Math.max(xN.length, yN.length); cLoc < numS; cLoc++) {
|
|
// find floats not starting with '0', string or 0 if not defined (Clint Priest)
|
|
oFxNcL = !(xN[cLoc] || '').match(ore) && parseFloat(xN[cLoc]) || xN[cLoc] || 0;
|
|
oFyNcL = !(yN[cLoc] || '').match(ore) && parseFloat(yN[cLoc]) || yN[cLoc] || 0;
|
|
// handle numeric vs string comparison - number < string - (Kyle Adams)
|
|
if (isNaN(oFxNcL) !== isNaN(oFyNcL)) { return (isNaN(oFxNcL)) ? 1 : -1; }
|
|
// rely on string comparison if different types - i.e. '02' < 2 != '02' < '2'
|
|
else if (typeof oFxNcL !== typeof oFyNcL) {
|
|
oFxNcL += '';
|
|
oFyNcL += '';
|
|
}
|
|
if (oFxNcL < oFyNcL) { return -1; }
|
|
if (oFxNcL > oFyNcL) { return 1; }
|
|
}
|
|
return 0;
|
|
};
|
|
|
|
|
|
/***/ }),
|
|
|
|
/***/ 5156:
|
|
/***/ (function(__unused_webpack_module, exports) {
|
|
|
|
(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>"
|
|
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, <signature>]
|
|
// The <signature> 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 ? 0 : exports);
|
|
|
|
|
|
/***/ }),
|
|
|
|
/***/ 500:
|
|
/***/ (function(module) {
|
|
|
|
"use strict";
|
|
|
|
|
|
var traverse = module.exports = function (schema, opts, cb) {
|
|
// Legacy support for v0.3.1 and earlier.
|
|
if (typeof opts == 'function') {
|
|
cb = opts;
|
|
opts = {};
|
|
}
|
|
|
|
cb = opts.cb || cb;
|
|
var pre = (typeof cb == 'function') ? cb : cb.pre || function() {};
|
|
var post = cb.post || function() {};
|
|
|
|
_traverse(opts, pre, post, schema, '', schema);
|
|
};
|
|
|
|
|
|
traverse.keywords = {
|
|
additionalItems: true,
|
|
items: true,
|
|
contains: true,
|
|
additionalProperties: true,
|
|
propertyNames: true,
|
|
not: true
|
|
};
|
|
|
|
traverse.arrayKeywords = {
|
|
items: true,
|
|
allOf: true,
|
|
anyOf: true,
|
|
oneOf: true
|
|
};
|
|
|
|
traverse.propsKeywords = {
|
|
definitions: true,
|
|
properties: true,
|
|
patternProperties: true,
|
|
dependencies: true
|
|
};
|
|
|
|
traverse.skipKeywords = {
|
|
default: true,
|
|
enum: true,
|
|
const: true,
|
|
required: true,
|
|
maximum: true,
|
|
minimum: true,
|
|
exclusiveMaximum: true,
|
|
exclusiveMinimum: true,
|
|
multipleOf: true,
|
|
maxLength: true,
|
|
minLength: true,
|
|
pattern: true,
|
|
format: true,
|
|
maxItems: true,
|
|
minItems: true,
|
|
uniqueItems: true,
|
|
maxProperties: true,
|
|
minProperties: true
|
|
};
|
|
|
|
|
|
function _traverse(opts, pre, post, schema, jsonPtr, rootSchema, parentJsonPtr, parentKeyword, parentSchema, keyIndex) {
|
|
if (schema && typeof schema == 'object' && !Array.isArray(schema)) {
|
|
pre(schema, jsonPtr, rootSchema, parentJsonPtr, parentKeyword, parentSchema, keyIndex);
|
|
for (var key in schema) {
|
|
var sch = schema[key];
|
|
if (Array.isArray(sch)) {
|
|
if (key in traverse.arrayKeywords) {
|
|
for (var i=0; i<sch.length; i++)
|
|
_traverse(opts, pre, post, sch[i], jsonPtr + '/' + key + '/' + i, rootSchema, jsonPtr, key, schema, i);
|
|
}
|
|
} else if (key in traverse.propsKeywords) {
|
|
if (sch && typeof sch == 'object') {
|
|
for (var prop in sch)
|
|
_traverse(opts, pre, post, sch[prop], jsonPtr + '/' + key + '/' + escapeJsonPtr(prop), rootSchema, jsonPtr, key, schema, prop);
|
|
}
|
|
} else if (key in traverse.keywords || (opts.allKeys && !(key in traverse.skipKeywords))) {
|
|
_traverse(opts, pre, post, sch, jsonPtr + '/' + key, rootSchema, jsonPtr, key, schema);
|
|
}
|
|
}
|
|
post(schema, jsonPtr, rootSchema, parentJsonPtr, parentKeyword, parentSchema, keyIndex);
|
|
}
|
|
}
|
|
|
|
|
|
function escapeJsonPtr(str) {
|
|
return str.replace(/~/g, '~0').replace(/\//g, '~1');
|
|
}
|
|
|
|
|
|
/***/ }),
|
|
|
|
/***/ 7026:
|
|
/***/ (function(__unused_webpack_module, exports) {
|
|
|
|
"use strict";
|
|
var __webpack_unused_export__;
|
|
|
|
|
|
var escapedChars = {
|
|
'b': '\b',
|
|
'f': '\f',
|
|
'n': '\n',
|
|
'r': '\r',
|
|
't': '\t',
|
|
'"': '"',
|
|
'/': '/',
|
|
'\\': '\\'
|
|
};
|
|
|
|
var A_CODE = 'a'.charCodeAt();
|
|
|
|
|
|
exports.Q = function (source, _, options) {
|
|
var pointers = {};
|
|
var line = 0;
|
|
var column = 0;
|
|
var pos = 0;
|
|
var bigint = options && options.bigint && typeof BigInt != 'undefined';
|
|
return {
|
|
data: _parse('', true),
|
|
pointers: pointers
|
|
};
|
|
|
|
function _parse(ptr, topLevel) {
|
|
whitespace();
|
|
var data;
|
|
map(ptr, 'value');
|
|
var char = getChar();
|
|
switch (char) {
|
|
case 't': read('rue'); data = true; break;
|
|
case 'f': read('alse'); data = false; break;
|
|
case 'n': read('ull'); data = null; break;
|
|
case '"': data = parseString(); break;
|
|
case '[': data = parseArray(ptr); break;
|
|
case '{': data = parseObject(ptr); break;
|
|
default:
|
|
backChar();
|
|
if ('-0123456789'.indexOf(char) >= 0)
|
|
data = parseNumber();
|
|
else
|
|
unexpectedToken();
|
|
}
|
|
map(ptr, 'valueEnd');
|
|
whitespace();
|
|
if (topLevel && pos < source.length) unexpectedToken();
|
|
return data;
|
|
}
|
|
|
|
function whitespace() {
|
|
loop:
|
|
while (pos < source.length) {
|
|
switch (source[pos]) {
|
|
case ' ': column++; break;
|
|
case '\t': column += 4; break;
|
|
case '\r': column = 0; break;
|
|
case '\n': column = 0; line++; break;
|
|
default: break loop;
|
|
}
|
|
pos++;
|
|
}
|
|
}
|
|
|
|
function parseString() {
|
|
var str = '';
|
|
var char;
|
|
while (true) {
|
|
char = getChar();
|
|
if (char == '"') {
|
|
break;
|
|
} else if (char == '\\') {
|
|
char = getChar();
|
|
if (char in escapedChars)
|
|
str += escapedChars[char];
|
|
else if (char == 'u')
|
|
str += getCharCode();
|
|
else
|
|
wasUnexpectedToken();
|
|
} else {
|
|
str += char;
|
|
}
|
|
}
|
|
return str;
|
|
}
|
|
|
|
function parseNumber() {
|
|
var numStr = '';
|
|
var integer = true;
|
|
if (source[pos] == '-') numStr += getChar();
|
|
|
|
numStr += source[pos] == '0'
|
|
? getChar()
|
|
: getDigits();
|
|
|
|
if (source[pos] == '.') {
|
|
numStr += getChar() + getDigits();
|
|
integer = false;
|
|
}
|
|
|
|
if (source[pos] == 'e' || source[pos] == 'E') {
|
|
numStr += getChar();
|
|
if (source[pos] == '+' || source[pos] == '-') numStr += getChar();
|
|
numStr += getDigits();
|
|
integer = false;
|
|
}
|
|
|
|
var result = +numStr;
|
|
return bigint && integer && (result > Number.MAX_SAFE_INTEGER || result < Number.MIN_SAFE_INTEGER)
|
|
? BigInt(numStr)
|
|
: result;
|
|
}
|
|
|
|
function parseArray(ptr) {
|
|
whitespace();
|
|
var arr = [];
|
|
var i = 0;
|
|
if (getChar() == ']') return arr;
|
|
backChar();
|
|
|
|
while (true) {
|
|
var itemPtr = ptr + '/' + i;
|
|
arr.push(_parse(itemPtr));
|
|
whitespace();
|
|
var char = getChar();
|
|
if (char == ']') break;
|
|
if (char != ',') wasUnexpectedToken();
|
|
whitespace();
|
|
i++;
|
|
}
|
|
return arr;
|
|
}
|
|
|
|
function parseObject(ptr) {
|
|
whitespace();
|
|
var obj = {};
|
|
if (getChar() == '}') return obj;
|
|
backChar();
|
|
|
|
while (true) {
|
|
var loc = getLoc();
|
|
if (getChar() != '"') wasUnexpectedToken();
|
|
var key = parseString();
|
|
var propPtr = ptr + '/' + escapeJsonPointer(key);
|
|
mapLoc(propPtr, 'key', loc);
|
|
map(propPtr, 'keyEnd');
|
|
whitespace();
|
|
if (getChar() != ':') wasUnexpectedToken();
|
|
whitespace();
|
|
obj[key] = _parse(propPtr);
|
|
whitespace();
|
|
var char = getChar();
|
|
if (char == '}') break;
|
|
if (char != ',') wasUnexpectedToken();
|
|
whitespace();
|
|
}
|
|
return obj;
|
|
}
|
|
|
|
function read(str) {
|
|
for (var i=0; i<str.length; i++)
|
|
if (getChar() !== str[i]) wasUnexpectedToken();
|
|
}
|
|
|
|
function getChar() {
|
|
checkUnexpectedEnd();
|
|
var char = source[pos];
|
|
pos++;
|
|
column++; // new line?
|
|
return char;
|
|
}
|
|
|
|
function backChar() {
|
|
pos--;
|
|
column--;
|
|
}
|
|
|
|
function getCharCode() {
|
|
var count = 4;
|
|
var code = 0;
|
|
while (count--) {
|
|
code <<= 4;
|
|
var char = getChar().toLowerCase();
|
|
if (char >= 'a' && char <= 'f')
|
|
code += char.charCodeAt() - A_CODE + 10;
|
|
else if (char >= '0' && char <= '9')
|
|
code += +char;
|
|
else
|
|
wasUnexpectedToken();
|
|
}
|
|
return String.fromCharCode(code);
|
|
}
|
|
|
|
function getDigits() {
|
|
var digits = '';
|
|
while (source[pos] >= '0' && source[pos] <= '9')
|
|
digits += getChar();
|
|
|
|
if (digits.length) return digits;
|
|
checkUnexpectedEnd();
|
|
unexpectedToken();
|
|
}
|
|
|
|
function map(ptr, prop) {
|
|
mapLoc(ptr, prop, getLoc());
|
|
}
|
|
|
|
function mapLoc(ptr, prop, loc) {
|
|
pointers[ptr] = pointers[ptr] || {};
|
|
pointers[ptr][prop] = loc;
|
|
}
|
|
|
|
function getLoc() {
|
|
return {
|
|
line: line,
|
|
column: column,
|
|
pos: pos
|
|
};
|
|
}
|
|
|
|
function unexpectedToken() {
|
|
throw new SyntaxError('Unexpected token ' + source[pos] + ' in JSON at position ' + pos);
|
|
}
|
|
|
|
function wasUnexpectedToken() {
|
|
backChar();
|
|
unexpectedToken();
|
|
}
|
|
|
|
function checkUnexpectedEnd() {
|
|
if (pos >= source.length)
|
|
throw new SyntaxError('Unexpected end of JSON input');
|
|
}
|
|
};
|
|
|
|
|
|
__webpack_unused_export__ = function (data, _, options) {
|
|
if (!validType(data)) return;
|
|
var wsLine = 0;
|
|
var wsPos, wsColumn;
|
|
var whitespace = typeof options == 'object'
|
|
? options.space
|
|
: options;
|
|
switch (typeof whitespace) {
|
|
case 'number':
|
|
var len = whitespace > 10
|
|
? 10
|
|
: whitespace < 0
|
|
? 0
|
|
: Math.floor(whitespace);
|
|
whitespace = len && repeat(len, ' ');
|
|
wsPos = len;
|
|
wsColumn = len;
|
|
break;
|
|
case 'string':
|
|
whitespace = whitespace.slice(0, 10);
|
|
wsPos = 0;
|
|
wsColumn = 0;
|
|
for (var j=0; j<whitespace.length; j++) {
|
|
var char = whitespace[j];
|
|
switch (char) {
|
|
case ' ': wsColumn++; break;
|
|
case '\t': wsColumn += 4; break;
|
|
case '\r': wsColumn = 0; break;
|
|
case '\n': wsColumn = 0; wsLine++; break;
|
|
default: throw new Error('whitespace characters not allowed in JSON');
|
|
}
|
|
wsPos++;
|
|
}
|
|
break;
|
|
default:
|
|
whitespace = undefined;
|
|
}
|
|
|
|
var json = '';
|
|
var pointers = {};
|
|
var line = 0;
|
|
var column = 0;
|
|
var pos = 0;
|
|
var es6 = options && options.es6 && typeof Map == 'function';
|
|
_stringify(data, 0, '');
|
|
return {
|
|
json: json,
|
|
pointers: pointers
|
|
};
|
|
|
|
function _stringify(_data, lvl, ptr) {
|
|
map(ptr, 'value');
|
|
switch (typeof _data) {
|
|
case 'number':
|
|
case 'bigint':
|
|
case 'boolean':
|
|
out('' + _data); break;
|
|
case 'string':
|
|
out(quoted(_data)); break;
|
|
case 'object':
|
|
if (_data === null) {
|
|
out('null');
|
|
} else if (typeof _data.toJSON == 'function') {
|
|
out(quoted(_data.toJSON()));
|
|
} else if (Array.isArray(_data)) {
|
|
stringifyArray();
|
|
} else if (es6) {
|
|
if (_data.constructor.BYTES_PER_ELEMENT)
|
|
stringifyArray();
|
|
else if (_data instanceof Map)
|
|
stringifyMapSet();
|
|
else if (_data instanceof Set)
|
|
stringifyMapSet(true);
|
|
else
|
|
stringifyObject();
|
|
} else {
|
|
stringifyObject();
|
|
}
|
|
}
|
|
map(ptr, 'valueEnd');
|
|
|
|
function stringifyArray() {
|
|
if (_data.length) {
|
|
out('[');
|
|
var itemLvl = lvl + 1;
|
|
for (var i=0; i<_data.length; i++) {
|
|
if (i) out(',');
|
|
indent(itemLvl);
|
|
var item = validType(_data[i]) ? _data[i] : null;
|
|
var itemPtr = ptr + '/' + i;
|
|
_stringify(item, itemLvl, itemPtr);
|
|
}
|
|
indent(lvl);
|
|
out(']');
|
|
} else {
|
|
out('[]');
|
|
}
|
|
}
|
|
|
|
function stringifyObject() {
|
|
var keys = Object.keys(_data);
|
|
if (keys.length) {
|
|
out('{');
|
|
var propLvl = lvl + 1;
|
|
for (var i=0; i<keys.length; i++) {
|
|
var key = keys[i];
|
|
var value = _data[key];
|
|
if (validType(value)) {
|
|
if (i) out(',');
|
|
var propPtr = ptr + '/' + escapeJsonPointer(key);
|
|
indent(propLvl);
|
|
map(propPtr, 'key');
|
|
out(quoted(key));
|
|
map(propPtr, 'keyEnd');
|
|
out(':');
|
|
if (whitespace) out(' ');
|
|
_stringify(value, propLvl, propPtr);
|
|
}
|
|
}
|
|
indent(lvl);
|
|
out('}');
|
|
} else {
|
|
out('{}');
|
|
}
|
|
}
|
|
|
|
function stringifyMapSet(isSet) {
|
|
if (_data.size) {
|
|
out('{');
|
|
var propLvl = lvl + 1;
|
|
var first = true;
|
|
var entries = _data.entries();
|
|
var entry = entries.next();
|
|
while (!entry.done) {
|
|
var item = entry.value;
|
|
var key = item[0];
|
|
var value = isSet ? true : item[1];
|
|
if (validType(value)) {
|
|
if (!first) out(',');
|
|
first = false;
|
|
var propPtr = ptr + '/' + escapeJsonPointer(key);
|
|
indent(propLvl);
|
|
map(propPtr, 'key');
|
|
out(quoted(key));
|
|
map(propPtr, 'keyEnd');
|
|
out(':');
|
|
if (whitespace) out(' ');
|
|
_stringify(value, propLvl, propPtr);
|
|
}
|
|
entry = entries.next();
|
|
}
|
|
indent(lvl);
|
|
out('}');
|
|
} else {
|
|
out('{}');
|
|
}
|
|
}
|
|
}
|
|
|
|
function out(str) {
|
|
column += str.length;
|
|
pos += str.length;
|
|
json += str;
|
|
}
|
|
|
|
function indent(lvl) {
|
|
if (whitespace) {
|
|
json += '\n' + repeat(lvl, whitespace);
|
|
line++;
|
|
column = 0;
|
|
while (lvl--) {
|
|
if (wsLine) {
|
|
line += wsLine;
|
|
column = wsColumn;
|
|
} else {
|
|
column += wsColumn;
|
|
}
|
|
pos += wsPos;
|
|
}
|
|
pos += 1; // \n character
|
|
}
|
|
}
|
|
|
|
function map(ptr, prop) {
|
|
pointers[ptr] = pointers[ptr] || {};
|
|
pointers[ptr][prop] = {
|
|
line: line,
|
|
column: column,
|
|
pos: pos
|
|
};
|
|
}
|
|
|
|
function repeat(n, str) {
|
|
return Array(n + 1).join(str);
|
|
}
|
|
};
|
|
|
|
|
|
var VALID_TYPES = ['number', 'bigint', 'boolean', 'string', 'object'];
|
|
function validType(data) {
|
|
return VALID_TYPES.indexOf(typeof data) >= 0;
|
|
}
|
|
|
|
|
|
var ESC_QUOTE = /"|\\/g;
|
|
var ESC_B = /[\b]/g;
|
|
var ESC_F = /\f/g;
|
|
var ESC_N = /\n/g;
|
|
var ESC_R = /\r/g;
|
|
var ESC_T = /\t/g;
|
|
function quoted(str) {
|
|
str = str.replace(ESC_QUOTE, '\\$&')
|
|
.replace(ESC_F, '\\f')
|
|
.replace(ESC_B, '\\b')
|
|
.replace(ESC_N, '\\n')
|
|
.replace(ESC_R, '\\r')
|
|
.replace(ESC_T, '\\t');
|
|
return '"' + str + '"';
|
|
}
|
|
|
|
|
|
var ESC_0 = /~/g;
|
|
var ESC_1 = /\//g;
|
|
function escapeJsonPointer(str) {
|
|
return str.replace(ESC_0, '~0')
|
|
.replace(ESC_1, '~1');
|
|
}
|
|
|
|
|
|
/***/ }),
|
|
|
|
/***/ 5755:
|
|
/***/ (function(__unused_webpack_module, exports) {
|
|
|
|
"use strict";
|
|
|
|
|
|
Object.defineProperty(exports, "__esModule", ({
|
|
value: true
|
|
}));
|
|
exports.default = JsonRepairError;
|
|
|
|
function JsonRepairError(message, char) {
|
|
if (!(this instanceof JsonRepairError)) {
|
|
throw new SyntaxError('Constructor must be called with the new operator');
|
|
}
|
|
|
|
this.message = message + ' (char ' + char + ')';
|
|
this.char = char;
|
|
this.stack = new Error().stack;
|
|
}
|
|
|
|
JsonRepairError.prototype = new Error();
|
|
JsonRepairError.prototype.constructor = Error;
|
|
|
|
|
|
/***/ }),
|
|
|
|
/***/ 8909:
|
|
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
|
|
|
|
module.exports = __webpack_require__(8107).default
|
|
|
|
|
|
/***/ }),
|
|
|
|
/***/ 8107:
|
|
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
|
|
|
|
"use strict";
|
|
var __webpack_unused_export__;
|
|
|
|
|
|
__webpack_unused_export__ = ({
|
|
value: true
|
|
});
|
|
exports.default = jsonrepair;
|
|
|
|
var _JsonRepairError = _interopRequireDefault(__webpack_require__(5755));
|
|
|
|
var _stringUtils = __webpack_require__(1536);
|
|
|
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
|
|
// token types enumeration
|
|
var DELIMITER = 0;
|
|
var NUMBER = 1;
|
|
var STRING = 2;
|
|
var SYMBOL = 3;
|
|
var WHITESPACE = 4;
|
|
var COMMENT = 5;
|
|
var UNKNOWN = 6;
|
|
/**
|
|
* @typedef {DELIMITER | NUMBER | STRING | SYMBOL | WHITESPACE | COMMENT | UNKNOWN} TokenType
|
|
*/
|
|
// map with all delimiters
|
|
|
|
var DELIMITERS = {
|
|
'': true,
|
|
'{': true,
|
|
'}': true,
|
|
'[': true,
|
|
']': true,
|
|
':': true,
|
|
',': true,
|
|
// for JSONP and MongoDB data type notation
|
|
'(': true,
|
|
')': true,
|
|
';': true,
|
|
// for string concatenation
|
|
'+': true
|
|
}; // map with all escape characters
|
|
|
|
var ESCAPE_CHARACTERS = {
|
|
'"': '"',
|
|
'\\': '\\',
|
|
'/': '/',
|
|
b: '\b',
|
|
f: '\f',
|
|
n: '\n',
|
|
r: '\r',
|
|
t: '\t' // \u is handled by getToken()
|
|
|
|
}; // TODO: can we unify CONTROL_CHARACTERS and ESCAPE_CHARACTERS?
|
|
|
|
var CONTROL_CHARACTERS = {
|
|
'\b': '\\b',
|
|
'\f': '\\f',
|
|
'\n': '\\n',
|
|
'\r': '\\r',
|
|
'\t': '\\t'
|
|
};
|
|
var SYMBOLS = {
|
|
null: 'null',
|
|
true: 'true',
|
|
false: 'false'
|
|
};
|
|
var PYTHON_SYMBOLS = {
|
|
None: 'null',
|
|
True: 'true',
|
|
False: 'false'
|
|
};
|
|
var input = ''; // current json text
|
|
|
|
var output = ''; // generated output
|
|
|
|
var index = 0; // current index in text
|
|
|
|
var c = ''; // current token character in text
|
|
|
|
var token = ''; // current token
|
|
|
|
var tokenType = UNKNOWN; // type of current token
|
|
|
|
/**
|
|
* Repair a string containing an invalid JSON document.
|
|
* For example changes JavaScript notation into JSON notation.
|
|
*
|
|
* Example:
|
|
*
|
|
* jsonrepair('{name: \'John\'}") // '{"name": "John"}'
|
|
*
|
|
* @param {string} text
|
|
* @return {string}
|
|
*/
|
|
|
|
function jsonrepair(text) {
|
|
// initialize
|
|
input = text;
|
|
output = '';
|
|
index = 0;
|
|
c = input.charAt(0);
|
|
token = '';
|
|
tokenType = UNKNOWN; // get first token
|
|
|
|
processNextToken();
|
|
var isRootLevelObject = tokenType === DELIMITER && token === '{'; // parse everything
|
|
|
|
parseObject();
|
|
|
|
if (token === '') {
|
|
// reached the end of the document properly
|
|
return output;
|
|
}
|
|
|
|
if (isRootLevelObject && tokenIsStartOfValue()) {
|
|
// start of a new value after end of the root level object: looks like
|
|
// newline delimited JSON -> turn into a root level array
|
|
while (tokenIsStartOfValue()) {
|
|
output = (0, _stringUtils.insertBeforeLastWhitespace)(output, ','); // parse next newline delimited item
|
|
|
|
parseObject();
|
|
} // wrap the output in an array
|
|
|
|
|
|
return "[\n".concat(output, "\n]");
|
|
}
|
|
|
|
throw new _JsonRepairError.default('Unexpected characters', index - token.length);
|
|
}
|
|
/**
|
|
* Get the next character from the expression.
|
|
* The character is stored into the char c. If the end of the expression is
|
|
* reached, the function puts an empty string in c.
|
|
*/
|
|
|
|
|
|
function next() {
|
|
index++;
|
|
c = input.charAt(index); // Note: not using input[index] because that returns undefined when index is out of range
|
|
}
|
|
/**
|
|
* check whether the current token is the start of a value:
|
|
* object, array, number, string, or symbol
|
|
* @returns {boolean}
|
|
*/
|
|
|
|
|
|
function tokenIsStartOfValue() {
|
|
return tokenType === DELIMITER && (token === '[' || token === '{') || tokenType === STRING || tokenType === NUMBER || tokenType === SYMBOL;
|
|
}
|
|
/**
|
|
* check whether the current token is the start of a key (or possible key):
|
|
* number, string, or symbol
|
|
* @returns {boolean}
|
|
*/
|
|
|
|
|
|
function tokenIsStartOfKey() {
|
|
return tokenType === STRING || tokenType === NUMBER || tokenType === SYMBOL;
|
|
}
|
|
/**
|
|
* Process the previous token, and get next token in the current text
|
|
*/
|
|
|
|
|
|
function processNextToken() {
|
|
output += token;
|
|
tokenType = UNKNOWN;
|
|
token = '';
|
|
getTokenDelimiter();
|
|
|
|
if (tokenType === WHITESPACE) {
|
|
// we leave the whitespace as it is, except replacing special white
|
|
// space character
|
|
token = (0, _stringUtils.normalizeWhitespace)(token);
|
|
processNextToken();
|
|
}
|
|
|
|
if (tokenType === COMMENT) {
|
|
// ignore comments
|
|
tokenType = UNKNOWN;
|
|
token = '';
|
|
processNextToken();
|
|
}
|
|
} // check for delimiters like ':', '{', ']'
|
|
|
|
|
|
function getTokenDelimiter() {
|
|
if (DELIMITERS[c]) {
|
|
tokenType = DELIMITER;
|
|
token = c;
|
|
next();
|
|
return;
|
|
}
|
|
|
|
getTokenNumber();
|
|
} // check for a number like "2.3e+5"
|
|
|
|
|
|
function getTokenNumber() {
|
|
if ((0, _stringUtils.isDigit)(c) || c === '-') {
|
|
tokenType = NUMBER;
|
|
|
|
if (c === '-') {
|
|
token += c;
|
|
next();
|
|
|
|
if (!(0, _stringUtils.isDigit)(c)) {
|
|
throw new _JsonRepairError.default('Invalid number, digit expected', index);
|
|
}
|
|
} else if (c === '0') {
|
|
token += c;
|
|
next();
|
|
} else {// digit 1-9, nothing extra to do
|
|
}
|
|
|
|
while ((0, _stringUtils.isDigit)(c)) {
|
|
token += c;
|
|
next();
|
|
}
|
|
|
|
if (c === '.') {
|
|
token += c;
|
|
next();
|
|
|
|
if (!(0, _stringUtils.isDigit)(c)) {
|
|
throw new _JsonRepairError.default('Invalid number, digit expected', index);
|
|
}
|
|
|
|
while ((0, _stringUtils.isDigit)(c)) {
|
|
token += c;
|
|
next();
|
|
}
|
|
}
|
|
|
|
if (c === 'e' || c === 'E') {
|
|
token += c;
|
|
next();
|
|
|
|
if (c === '+' || c === '-') {
|
|
token += c;
|
|
next();
|
|
}
|
|
|
|
if (!(0, _stringUtils.isDigit)(c)) {
|
|
throw new _JsonRepairError.default('Invalid number, digit expected', index);
|
|
}
|
|
|
|
while ((0, _stringUtils.isDigit)(c)) {
|
|
token += c;
|
|
next();
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
getTokenString();
|
|
} // get a token string like '"hello world"'
|
|
|
|
|
|
function getTokenString() {
|
|
if ((0, _stringUtils.isQuote)(c)) {
|
|
var quote = (0, _stringUtils.normalizeQuote)(c);
|
|
token += '"'; // output valid double quote
|
|
|
|
tokenType = STRING;
|
|
next();
|
|
|
|
while (c !== '' && (0, _stringUtils.normalizeQuote)(c) !== quote) {
|
|
if (c === '\\') {
|
|
// handle escape characters
|
|
next();
|
|
var unescaped = ESCAPE_CHARACTERS[c];
|
|
|
|
if (unescaped !== undefined) {
|
|
token += '\\' + c;
|
|
next();
|
|
} else if (c === 'u') {
|
|
// parse escaped unicode character, like '\\u260E'
|
|
token += "\\u";
|
|
next();
|
|
|
|
for (var u = 0; u < 4; u++) {
|
|
if (!(0, _stringUtils.isHex)(c)) {
|
|
throw new _JsonRepairError.default('Invalid unicode character', index - token.length);
|
|
}
|
|
|
|
token += c;
|
|
next();
|
|
}
|
|
} else if (c === '\'') {
|
|
// escaped single quote character -> remove the escape character
|
|
token += '\'';
|
|
next();
|
|
} else {
|
|
throw new _JsonRepairError.default('Invalid escape character "\\' + c + '"', index);
|
|
}
|
|
} else if (CONTROL_CHARACTERS[c]) {
|
|
// unescaped special character
|
|
// fix by adding an escape character
|
|
token += CONTROL_CHARACTERS[c];
|
|
next();
|
|
} else if (c === '"') {
|
|
// unescaped double quote -> escape it
|
|
token += '\\"';
|
|
next();
|
|
} else {
|
|
// a regular character
|
|
token += c;
|
|
next();
|
|
}
|
|
}
|
|
|
|
if ((0, _stringUtils.normalizeQuote)(c) !== quote) {
|
|
throw new _JsonRepairError.default('End of string expected', index - token.length);
|
|
}
|
|
|
|
token += '"'; // output valid double quote
|
|
|
|
next();
|
|
return;
|
|
}
|
|
|
|
getTokenAlpha();
|
|
} // check for symbols (true, false, null)
|
|
|
|
|
|
function getTokenAlpha() {
|
|
if ((0, _stringUtils.isAlpha)(c)) {
|
|
tokenType = SYMBOL;
|
|
|
|
while ((0, _stringUtils.isAlpha)(c) || (0, _stringUtils.isDigit)(c) || c === '$') {
|
|
token += c;
|
|
next();
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
getTokenWhitespace();
|
|
} // get whitespaces: space, tab, newline, and carriage return
|
|
|
|
|
|
function getTokenWhitespace() {
|
|
if ((0, _stringUtils.isWhitespace)(c) || (0, _stringUtils.isSpecialWhitespace)(c)) {
|
|
tokenType = WHITESPACE;
|
|
|
|
while ((0, _stringUtils.isWhitespace)(c) || (0, _stringUtils.isSpecialWhitespace)(c)) {
|
|
token += c;
|
|
next();
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
getTokenComment();
|
|
}
|
|
|
|
function getTokenComment() {
|
|
// find a block comment '/* ... */'
|
|
if (c === '/' && input[index + 1] === '*') {
|
|
tokenType = COMMENT;
|
|
|
|
while (c !== '' && (c !== '*' || c === '*' && input[index + 1] !== '/')) {
|
|
token += c;
|
|
next();
|
|
}
|
|
|
|
if (c === '*' && input[index + 1] === '/') {
|
|
token += c;
|
|
next();
|
|
token += c;
|
|
next();
|
|
}
|
|
|
|
return;
|
|
} // find a comment '// ...'
|
|
|
|
|
|
if (c === '/' && input[index + 1] === '/') {
|
|
tokenType = COMMENT;
|
|
|
|
while (c !== '' && c !== '\n') {
|
|
token += c;
|
|
next();
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
getTokenUnknown();
|
|
} // something unknown is found, wrong characters -> a syntax error
|
|
|
|
|
|
function getTokenUnknown() {
|
|
tokenType = UNKNOWN;
|
|
|
|
while (c !== '') {
|
|
token += c;
|
|
next();
|
|
}
|
|
|
|
throw new _JsonRepairError.default('Syntax error in part "' + token + '"', index - token.length);
|
|
}
|
|
/**
|
|
* Parse an object like '{"key": "value"}'
|
|
* @return {*}
|
|
*/
|
|
|
|
|
|
function parseObject() {
|
|
if (tokenType === DELIMITER && token === '{') {
|
|
processNextToken(); // TODO: can we make this redundant?
|
|
|
|
if (tokenType === DELIMITER && token === '}') {
|
|
// empty object
|
|
processNextToken();
|
|
return;
|
|
}
|
|
|
|
while (true) {
|
|
// parse key
|
|
if (tokenType === SYMBOL || tokenType === NUMBER) {
|
|
// unquoted key -> add quotes around it, change it into a string
|
|
tokenType = STRING;
|
|
token = "\"".concat(token, "\"");
|
|
}
|
|
|
|
if (tokenType !== STRING) {
|
|
// TODO: handle ambiguous cases like '[{"a":1,{"b":2}]' which could be an array with two objects or one
|
|
throw new _JsonRepairError.default('Object key expected', index - token.length);
|
|
}
|
|
|
|
processNextToken(); // parse colon (key/value separator)
|
|
|
|
if (tokenType === DELIMITER && token === ':') {
|
|
processNextToken();
|
|
} else {
|
|
if (tokenIsStartOfValue()) {
|
|
// we expect a colon here, but got the start of a value
|
|
// -> insert a colon before any inserted whitespaces at the end of output
|
|
output = (0, _stringUtils.insertBeforeLastWhitespace)(output, ':');
|
|
} else {
|
|
throw new _JsonRepairError.default('Colon expected', index - token.length);
|
|
}
|
|
} // parse value
|
|
|
|
|
|
parseObject(); // parse comma (key/value pair separator)
|
|
|
|
if (tokenType === DELIMITER && token === ',') {
|
|
processNextToken();
|
|
|
|
if (tokenType === DELIMITER && token === '}') {
|
|
// we've just passed a trailing comma -> remove the trailing comma
|
|
output = (0, _stringUtils.stripLastOccurrence)(output, ',');
|
|
break;
|
|
}
|
|
} else {
|
|
if (tokenIsStartOfKey()) {
|
|
// we expect a comma here, but got the start of a new key
|
|
// -> insert a comma before any inserted whitespaces at the end of output
|
|
output = (0, _stringUtils.insertBeforeLastWhitespace)(output, ',');
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (tokenType === DELIMITER && token === '}') {
|
|
processNextToken();
|
|
} else {
|
|
// missing end bracket -> insert the missing bracket
|
|
output = (0, _stringUtils.insertBeforeLastWhitespace)(output, '}');
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
parseArray();
|
|
}
|
|
/**
|
|
* Parse an object like '["item1", "item2", ...]'
|
|
*/
|
|
|
|
|
|
function parseArray() {
|
|
if (tokenType === DELIMITER && token === '[') {
|
|
processNextToken();
|
|
|
|
if (tokenType === DELIMITER && token === ']') {
|
|
// empty array
|
|
processNextToken();
|
|
return;
|
|
}
|
|
|
|
while (true) {
|
|
// parse item
|
|
parseObject(); // parse comma (item separator)
|
|
|
|
if (tokenType === DELIMITER && token === ',') {
|
|
processNextToken();
|
|
|
|
if (tokenType === DELIMITER && token === ']') {
|
|
// we've just passed a trailing comma -> remove the trailing comma
|
|
output = (0, _stringUtils.stripLastOccurrence)(output, ',');
|
|
break;
|
|
}
|
|
} else {
|
|
if (tokenIsStartOfValue()) {
|
|
// we expect a comma here, but got the start of a new item
|
|
// -> insert a comma before any inserted whitespaces at the end of output
|
|
output = (0, _stringUtils.insertBeforeLastWhitespace)(output, ',');
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (tokenType === DELIMITER && token === ']') {
|
|
processNextToken();
|
|
} else {
|
|
// missing end bracket -> insert the missing bracket
|
|
output = (0, _stringUtils.insertBeforeLastWhitespace)(output, ']');
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
parseString();
|
|
}
|
|
/**
|
|
* Parse a string enclosed by double quotes "...". Can contain escaped quotes
|
|
*/
|
|
|
|
|
|
function parseString() {
|
|
if (tokenType === STRING) {
|
|
processNextToken();
|
|
|
|
while (tokenType === DELIMITER && token === '+') {
|
|
// string concatenation like "hello" + "world"
|
|
token = ''; // don't output the concatenation
|
|
|
|
processNextToken();
|
|
|
|
if (tokenType === STRING) {
|
|
// concatenate with the previous string
|
|
var endIndex = output.lastIndexOf('"');
|
|
output = output.substring(0, endIndex) + token.substring(1);
|
|
token = '';
|
|
processNextToken();
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
parseNumber();
|
|
}
|
|
/**
|
|
* Parse a number
|
|
*/
|
|
|
|
|
|
function parseNumber() {
|
|
if (tokenType === NUMBER) {
|
|
processNextToken();
|
|
return;
|
|
}
|
|
|
|
parseSymbol();
|
|
}
|
|
/**
|
|
* Parse constants true, false, null
|
|
*/
|
|
|
|
|
|
function parseSymbol() {
|
|
if (tokenType === SYMBOL) {
|
|
// a supported symbol: true, false, null
|
|
if (SYMBOLS[token]) {
|
|
processNextToken();
|
|
return;
|
|
} // for example replace None with null
|
|
|
|
|
|
if (PYTHON_SYMBOLS[token]) {
|
|
token = PYTHON_SYMBOLS[token];
|
|
processNextToken();
|
|
return;
|
|
} // make a copy of the symbol, let's see what comes next
|
|
|
|
|
|
var symbol = token;
|
|
var symbolIndex = output.length;
|
|
token = '';
|
|
processNextToken(); // if (tokenType === DELIMITER && token === '(') {
|
|
|
|
if (tokenType === DELIMITER && token === '(') {
|
|
// a MongoDB function call or JSONP call
|
|
// Can be a MongoDB data type like in {"_id": ObjectId("123")}
|
|
// token = '' // do not output the function name
|
|
// processNextToken()
|
|
// next()
|
|
token = ''; // do not output the ( character
|
|
|
|
processNextToken(); // process the part inside the brackets
|
|
|
|
parseObject(); // skip the closing bracket ")" and ");"
|
|
|
|
if (tokenType === DELIMITER && token === ')') {
|
|
token = ''; // do not output the ) character
|
|
|
|
processNextToken();
|
|
|
|
if (tokenType === DELIMITER && token === ';') {
|
|
token = ''; // do not output the semicolon character
|
|
|
|
processNextToken();
|
|
}
|
|
}
|
|
|
|
return;
|
|
} // unknown symbol => turn into in a string
|
|
// it is possible that by reading the next token we already inserted
|
|
// extra spaces in the output which should be inside the string,
|
|
// hence the symbolIndex
|
|
|
|
|
|
output = (0, _stringUtils.insertAtIndex)(output, "\"".concat(symbol), symbolIndex);
|
|
|
|
while (tokenType === SYMBOL || tokenType === NUMBER) {
|
|
processNextToken();
|
|
}
|
|
|
|
output += '"';
|
|
return;
|
|
}
|
|
|
|
parseEnd();
|
|
}
|
|
/**
|
|
* Evaluated when the expression is not yet ended but expected to end
|
|
*/
|
|
|
|
|
|
function parseEnd() {
|
|
if (token === '') {
|
|
// syntax error or unexpected end of expression
|
|
throw new _JsonRepairError.default('Unexpected end of json string', index - token.length);
|
|
} else {
|
|
throw new _JsonRepairError.default('Value expected', index - token.length);
|
|
}
|
|
}
|
|
|
|
|
|
/***/ }),
|
|
|
|
/***/ 1536:
|
|
/***/ (function(__unused_webpack_module, exports) {
|
|
|
|
"use strict";
|
|
|
|
|
|
Object.defineProperty(exports, "__esModule", ({
|
|
value: true
|
|
}));
|
|
exports.isAlpha = isAlpha;
|
|
exports.isHex = isHex;
|
|
exports.isDigit = isDigit;
|
|
exports.isWhitespace = isWhitespace;
|
|
exports.isSpecialWhitespace = isSpecialWhitespace;
|
|
exports.normalizeWhitespace = normalizeWhitespace;
|
|
exports.isQuote = isQuote;
|
|
exports.normalizeQuote = normalizeQuote;
|
|
exports.stripLastOccurrence = stripLastOccurrence;
|
|
exports.insertBeforeLastWhitespace = insertBeforeLastWhitespace;
|
|
exports.insertAtIndex = insertAtIndex;
|
|
var SINGLE_QUOTES = ['\'', // quote
|
|
"\u2018", // quote left
|
|
"\u2019", // quote right
|
|
"`", // grave accent
|
|
"\xB4" // acute accent
|
|
];
|
|
var DOUBLE_QUOTES = ['"', "\u201C", // double quote left
|
|
"\u201D" // double quote right
|
|
];
|
|
/**
|
|
* Check if the given character contains an alpha character, a-z, A-Z, _
|
|
* @param {string} c
|
|
* @return {boolean}
|
|
*/
|
|
|
|
function isAlpha(c) {
|
|
return /^[a-zA-Z_]$/.test(c);
|
|
}
|
|
/**
|
|
* Check if the given character contains a hexadecimal character 0-9, a-f, A-F
|
|
* @param {string} c
|
|
* @return {boolean}
|
|
*/
|
|
|
|
|
|
function isHex(c) {
|
|
return /^[0-9a-fA-F]$/.test(c);
|
|
}
|
|
/**
|
|
* checks if the given char c is a digit
|
|
* @param {string} c
|
|
* @return {boolean}
|
|
*/
|
|
|
|
|
|
function isDigit(c) {
|
|
return c >= '0' && c <= '9';
|
|
}
|
|
/**
|
|
* Check if the given character is a whitespace character like space, tab, or
|
|
* newline
|
|
* @param {string} c
|
|
* @return {boolean}
|
|
*/
|
|
|
|
|
|
function isWhitespace(c) {
|
|
return c === ' ' || c === '\t' || c === '\n' || c === '\r';
|
|
}
|
|
/**
|
|
* Check if the given character is a special whitespace character, some
|
|
* unicode variant
|
|
* @param {string} c
|
|
* @return {boolean}
|
|
*/
|
|
|
|
|
|
function isSpecialWhitespace(c) {
|
|
return c === "\xA0" || c >= "\u2000" && c <= "\u200A" || c === "\u202F" || c === "\u205F" || c === "\u3000";
|
|
}
|
|
/**
|
|
* Replace speical whitespace characters with regular spaces
|
|
* @param {string} text
|
|
* @returns {string}
|
|
*/
|
|
|
|
|
|
function normalizeWhitespace(text) {
|
|
var normalized = '';
|
|
|
|
for (var i = 0; i < text.length; i++) {
|
|
var char = text[i];
|
|
normalized += isSpecialWhitespace(char) ? ' ' : char;
|
|
}
|
|
|
|
return normalized;
|
|
}
|
|
/**
|
|
* Test whether the given character is a quote or double quote character.
|
|
* Also tests for special variants of quotes.
|
|
* @param {string} c
|
|
* @returns {boolean}
|
|
*/
|
|
|
|
|
|
function isQuote(c) {
|
|
return SINGLE_QUOTES.includes(c) || DOUBLE_QUOTES.includes(c);
|
|
}
|
|
/**
|
|
* Normalize special double or single quote characters to their regular
|
|
* variant ' or "
|
|
* @param {string} c
|
|
* @returns {string}
|
|
*/
|
|
|
|
|
|
function normalizeQuote(c) {
|
|
if (SINGLE_QUOTES.includes(c)) {
|
|
return '\'';
|
|
}
|
|
|
|
if (DOUBLE_QUOTES.includes(c)) {
|
|
return '"';
|
|
}
|
|
|
|
return c;
|
|
}
|
|
/**
|
|
* Strip last occurrence of textToStrip from text
|
|
* @param {string} text
|
|
* @param {string} textToStrip
|
|
* @returns {string}
|
|
*/
|
|
|
|
|
|
function stripLastOccurrence(text, textToStrip) {
|
|
var index = text.lastIndexOf(textToStrip);
|
|
return index !== -1 ? text.substring(0, index) + text.substring(index + 1) : text;
|
|
}
|
|
/**
|
|
* Insert textToInsert into text before the last whitespace in text
|
|
* @param {string} text
|
|
* @param {string} textToInsert
|
|
* @returns {string}
|
|
*/
|
|
|
|
|
|
function insertBeforeLastWhitespace(text, textToInsert) {
|
|
return text.replace(/\s*$/, function (match) {
|
|
return textToInsert + match;
|
|
});
|
|
}
|
|
/**
|
|
* Insert textToInsert at index in text
|
|
* @param {string} text
|
|
* @param {string} textToInsert
|
|
* @param {number} index
|
|
* @returns {string}
|
|
*/
|
|
|
|
|
|
function insertAtIndex(text, textToInsert, index) {
|
|
return text.substring(0, index) + textToInsert + text.substring(index);
|
|
}
|
|
|
|
|
|
/***/ }),
|
|
|
|
/***/ 483:
|
|
/***/ (function(module, exports) {
|
|
|
|
var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/**
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
* SOFTWARE.
|
|
*/
|
|
|
|
(function (root, factory) {
|
|
"use strict";
|
|
|
|
if (true) {
|
|
!(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory),
|
|
__WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ?
|
|
(__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__),
|
|
__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
|
|
}
|
|
else {}
|
|
}(this, function () {
|
|
|
|
/**
|
|
* A self-contained modal library
|
|
*/
|
|
"use strict";
|
|
|
|
/** Returns whether a value is a dom node */
|
|
function isNode(value) {
|
|
if ( typeof Node === "object" ) {
|
|
return value instanceof Node;
|
|
}
|
|
else {
|
|
return value && typeof value === "object" && typeof value.nodeType === "number";
|
|
}
|
|
}
|
|
|
|
/** Returns whether a value is a string */
|
|
function isString(value) {
|
|
return typeof value === "string";
|
|
}
|
|
|
|
/**
|
|
* Generates observable objects that can be watched and triggered
|
|
*/
|
|
function observable() {
|
|
var callbacks = [];
|
|
return {
|
|
watch: callbacks.push.bind(callbacks),
|
|
trigger: function(context, detail) {
|
|
|
|
var unprevented = true;
|
|
var event = {
|
|
detail: detail,
|
|
preventDefault: function preventDefault () {
|
|
unprevented = false;
|
|
}
|
|
};
|
|
|
|
for (var i = 0; i < callbacks.length; i++) {
|
|
callbacks[i](context, event);
|
|
}
|
|
|
|
return unprevented;
|
|
}
|
|
};
|
|
}
|
|
|
|
|
|
/** Whether an element is hidden */
|
|
function isHidden ( elem ) {
|
|
// @see http://stackoverflow.com/questions/19669786
|
|
return window.getComputedStyle(elem).display === 'none';
|
|
}
|
|
|
|
|
|
/**
|
|
* A small interface for creating and managing a dom element
|
|
*/
|
|
function Elem( elem ) {
|
|
this.elem = elem;
|
|
}
|
|
|
|
/** Creates a new div */
|
|
Elem.make = function ( parent, tag ) {
|
|
if ( typeof parent === "string" ) {
|
|
parent = document.querySelector(parent);
|
|
}
|
|
var elem = document.createElement(tag || 'div');
|
|
(parent || document.body).appendChild(elem);
|
|
return new Elem(elem);
|
|
};
|
|
|
|
Elem.prototype = {
|
|
|
|
/** Creates a child of this node */
|
|
child: function (tag) {
|
|
return Elem.make(this.elem, tag);
|
|
},
|
|
|
|
/** Applies a set of styles to an element */
|
|
stylize: function(styles) {
|
|
styles = styles || {};
|
|
|
|
if ( typeof styles.opacity !== "undefined" ) {
|
|
styles.filter = "alpha(opacity=" + (styles.opacity * 100) + ")";
|
|
}
|
|
|
|
for (var prop in styles) {
|
|
if (styles.hasOwnProperty(prop)) {
|
|
this.elem.style[prop] = styles[prop];
|
|
}
|
|
}
|
|
|
|
return this;
|
|
},
|
|
|
|
/** Adds a class name */
|
|
clazz: function (clazz) {
|
|
this.elem.className += " " + clazz;
|
|
return this;
|
|
},
|
|
|
|
/** Sets the HTML */
|
|
html: function (content) {
|
|
if ( isNode(content) ) {
|
|
this.elem.appendChild( content );
|
|
}
|
|
else {
|
|
this.elem.innerHTML = content;
|
|
}
|
|
return this;
|
|
},
|
|
|
|
/** Adds a click handler to this element */
|
|
onClick: function(callback) {
|
|
this.elem.addEventListener('click', callback);
|
|
return this;
|
|
},
|
|
|
|
/** Removes this element from the DOM */
|
|
destroy: function() {
|
|
this.elem.parentNode.removeChild(this.elem);
|
|
},
|
|
|
|
/** Hides this element */
|
|
hide: function() {
|
|
this.elem.style.display = "none";
|
|
},
|
|
|
|
/** Shows this element */
|
|
show: function() {
|
|
this.elem.style.display = "block";
|
|
},
|
|
|
|
/** Sets an attribute on this element */
|
|
attr: function ( name, value ) {
|
|
if (value !== undefined) {
|
|
this.elem.setAttribute(name, value);
|
|
}
|
|
return this;
|
|
},
|
|
|
|
/** Executes a callback on all the ancestors of an element */
|
|
anyAncestor: function ( predicate ) {
|
|
var elem = this.elem;
|
|
while ( elem ) {
|
|
if ( predicate( new Elem(elem) ) ) {
|
|
return true;
|
|
}
|
|
else {
|
|
elem = elem.parentNode;
|
|
}
|
|
}
|
|
return false;
|
|
},
|
|
|
|
/** Whether this element is visible */
|
|
isVisible: function () {
|
|
return !isHidden(this.elem);
|
|
}
|
|
};
|
|
|
|
|
|
/** Generates the grey-out effect */
|
|
function buildOverlay( getOption, close ) {
|
|
return Elem.make( getOption("parent") )
|
|
.clazz("pico-overlay")
|
|
.clazz( getOption("overlayClass", "") )
|
|
.stylize({
|
|
display: "none",
|
|
position: "fixed",
|
|
top: "0px",
|
|
left: "0px",
|
|
height: "100%",
|
|
width: "100%",
|
|
zIndex: 10000
|
|
})
|
|
.stylize(getOption('overlayStyles', {
|
|
opacity: 0.5,
|
|
background: "#000"
|
|
}))
|
|
.onClick(function () {
|
|
if ( getOption('overlayClose', true) ) {
|
|
close();
|
|
}
|
|
});
|
|
}
|
|
|
|
// An auto incrementing ID assigned to each modal
|
|
var autoinc = 1;
|
|
|
|
/** Builds the content of a modal */
|
|
function buildModal( getOption, close ) {
|
|
var width = getOption('width', 'auto');
|
|
if ( typeof width === "number" ) {
|
|
width = "" + width + "px";
|
|
}
|
|
|
|
var id = getOption("modalId", "pico-" + autoinc++);
|
|
|
|
var elem = Elem.make( getOption("parent") )
|
|
.clazz("pico-content")
|
|
.clazz( getOption("modalClass", "") )
|
|
.stylize({
|
|
display: 'none',
|
|
position: 'fixed',
|
|
zIndex: 10001,
|
|
left: "50%",
|
|
top: "38.1966%",
|
|
maxHeight: '90%',
|
|
boxSizing: 'border-box',
|
|
width: width,
|
|
'-ms-transform': 'translate(-50%,-38.1966%)',
|
|
'-moz-transform': 'translate(-50%,-38.1966%)',
|
|
'-webkit-transform': 'translate(-50%,-38.1966%)',
|
|
'-o-transform': 'translate(-50%,-38.1966%)',
|
|
transform: 'translate(-50%,-38.1966%)'
|
|
})
|
|
.stylize(getOption('modalStyles', {
|
|
overflow: 'auto',
|
|
backgroundColor: "white",
|
|
padding: "20px",
|
|
borderRadius: "5px"
|
|
}))
|
|
.html( getOption('content') )
|
|
.attr("id", id)
|
|
.attr("role", "dialog")
|
|
.attr("aria-labelledby", getOption("ariaLabelledBy"))
|
|
.attr("aria-describedby", getOption("ariaDescribedBy", id))
|
|
.onClick(function (event) {
|
|
var isCloseClick = new Elem(event.target).anyAncestor(function (elem) {
|
|
return /\bpico-close\b/.test(elem.elem.className);
|
|
});
|
|
if ( isCloseClick ) {
|
|
close();
|
|
}
|
|
});
|
|
|
|
return elem;
|
|
}
|
|
|
|
/** Builds the close button */
|
|
function buildClose ( elem, getOption ) {
|
|
if ( getOption('closeButton', true) ) {
|
|
return elem.child('button')
|
|
.html( getOption('closeHtml', "×") )
|
|
.clazz("pico-close")
|
|
.clazz( getOption("closeClass", "") )
|
|
.stylize( getOption('closeStyles', {
|
|
borderRadius: "2px",
|
|
border: 0,
|
|
padding: 0,
|
|
cursor: "pointer",
|
|
height: "15px",
|
|
width: "15px",
|
|
position: "absolute",
|
|
top: "5px",
|
|
right: "5px",
|
|
fontSize: "16px",
|
|
textAlign: "center",
|
|
lineHeight: "15px",
|
|
background: "#CCC"
|
|
}) )
|
|
.attr("aria-label", getOption("close-label", "Close"));
|
|
}
|
|
}
|
|
|
|
/** Builds a method that calls a method and returns an element */
|
|
function buildElemAccessor( builder ) {
|
|
return function () {
|
|
return builder().elem;
|
|
};
|
|
}
|
|
|
|
|
|
// An observable that is triggered whenever the escape key is pressed
|
|
var escapeKey = observable();
|
|
|
|
// An observable that is triggered when the user hits the tab key
|
|
var tabKey = observable();
|
|
|
|
/** A global event handler to detect the escape key being pressed */
|
|
document.documentElement.addEventListener('keydown', function onKeyPress (event) {
|
|
var keycode = event.which || event.keyCode;
|
|
|
|
// If this is the escape key
|
|
if ( keycode === 27 ) {
|
|
escapeKey.trigger();
|
|
}
|
|
|
|
// If this is the tab key
|
|
else if ( keycode === 9 ) {
|
|
tabKey.trigger(event);
|
|
}
|
|
});
|
|
|
|
|
|
/** Attaches focus management events */
|
|
function manageFocus ( iface, isEnabled ) {
|
|
|
|
/** Whether an element matches a selector */
|
|
function matches ( elem, selector ) {
|
|
var fn = elem.msMatchesSelector || elem.webkitMatchesSelector || elem.matches;
|
|
return fn.call(elem, selector);
|
|
}
|
|
|
|
/**
|
|
* Returns whether an element is focusable
|
|
* @see http://stackoverflow.com/questions/18261595
|
|
*/
|
|
function canFocus( elem ) {
|
|
if (
|
|
isHidden(elem) ||
|
|
matches(elem, ":disabled") ||
|
|
elem.hasAttribute("contenteditable")
|
|
) {
|
|
return false;
|
|
}
|
|
else {
|
|
return elem.hasAttribute("tabindex") ||
|
|
matches(elem, "input,select,textarea,button,a[href],area[href],iframe");
|
|
}
|
|
}
|
|
|
|
/** Returns the first descendant that can be focused */
|
|
function firstFocusable ( elem ) {
|
|
var items = elem.getElementsByTagName("*");
|
|
for (var i = 0; i < items.length; i++) {
|
|
if ( canFocus(items[i]) ) {
|
|
return items[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Returns the last descendant that can be focused */
|
|
function lastFocusable ( elem ) {
|
|
var items = elem.getElementsByTagName("*");
|
|
for (var i = items.length; i--;) {
|
|
if ( canFocus(items[i]) ) {
|
|
return items[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
// The element focused before the modal opens
|
|
var focused;
|
|
|
|
// Records the currently focused element so state can be returned
|
|
// after the modal closes
|
|
iface.beforeShow(function getActiveFocus() {
|
|
focused = document.activeElement;
|
|
});
|
|
|
|
// Shift focus into the modal
|
|
iface.afterShow(function focusModal() {
|
|
if ( isEnabled() ) {
|
|
var focusable = firstFocusable(iface.modalElem());
|
|
if ( focusable ) {
|
|
focusable.focus();
|
|
}
|
|
}
|
|
});
|
|
|
|
// Restore the previously focused element when the modal closes
|
|
iface.afterClose(function returnFocus() {
|
|
if ( isEnabled() && focused ) {
|
|
focused.focus();
|
|
}
|
|
focused = null;
|
|
});
|
|
|
|
// Capture tab key presses and loop them within the modal
|
|
tabKey.watch(function tabKeyPress (event) {
|
|
if ( isEnabled() && iface.isVisible() ) {
|
|
var first = firstFocusable(iface.modalElem());
|
|
var last = lastFocusable(iface.modalElem());
|
|
|
|
var from = event.shiftKey ? first : last;
|
|
if ( from === document.activeElement ) {
|
|
(event.shiftKey ? last : first).focus();
|
|
event.preventDefault();
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
/** Manages setting the 'overflow: hidden' on the body tag */
|
|
function manageBodyOverflow(iface, isEnabled) {
|
|
var origOverflow;
|
|
var body = new Elem(document.body);
|
|
|
|
iface.beforeShow(function () {
|
|
// Capture the current values so they can be restored
|
|
origOverflow = body.elem.style.overflow;
|
|
|
|
if (isEnabled()) {
|
|
body.stylize({ overflow: "hidden" });
|
|
}
|
|
});
|
|
|
|
iface.afterClose(function () {
|
|
body.stylize({ overflow: origOverflow });
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Displays a modal
|
|
*/
|
|
return function picoModal(options) {
|
|
|
|
if ( isString(options) || isNode(options) ) {
|
|
options = { content: options };
|
|
}
|
|
|
|
var afterCreateEvent = observable();
|
|
var beforeShowEvent = observable();
|
|
var afterShowEvent = observable();
|
|
var beforeCloseEvent = observable();
|
|
var afterCloseEvent = observable();
|
|
|
|
/**
|
|
* Returns a named option if it has been explicitly defined. Otherwise,
|
|
* it returns the given default value
|
|
*/
|
|
function getOption ( opt, defaultValue ) {
|
|
var value = options[opt];
|
|
if ( typeof value === "function" ) {
|
|
value = value( defaultValue );
|
|
}
|
|
return value === undefined ? defaultValue : value;
|
|
}
|
|
|
|
|
|
// The various DOM elements that constitute the modal
|
|
var modalElem = build.bind(window, 'modal');
|
|
var shadowElem = build.bind(window, 'overlay');
|
|
var closeElem = build.bind(window, 'close');
|
|
|
|
// This will eventually contain the modal API returned to the user
|
|
var iface;
|
|
|
|
|
|
/** Hides this modal */
|
|
function forceClose (detail) {
|
|
shadowElem().hide();
|
|
modalElem().hide();
|
|
afterCloseEvent.trigger(iface, detail);
|
|
}
|
|
|
|
/** Gracefully hides this modal */
|
|
function close (detail) {
|
|
if ( beforeCloseEvent.trigger(iface, detail) ) {
|
|
forceClose(detail);
|
|
}
|
|
}
|
|
|
|
/** Wraps a method so it returns the modal interface */
|
|
function returnIface ( callback ) {
|
|
return function () {
|
|
callback.apply(this, arguments);
|
|
return iface;
|
|
};
|
|
}
|
|
|
|
|
|
// The constructed dom nodes
|
|
var built;
|
|
|
|
/** Builds a method that calls a method and returns an element */
|
|
function build (name, detail) {
|
|
if ( !built ) {
|
|
var modal = buildModal(getOption, close);
|
|
built = {
|
|
modal: modal,
|
|
overlay: buildOverlay(getOption, close),
|
|
close: buildClose(modal, getOption)
|
|
};
|
|
afterCreateEvent.trigger(iface, detail);
|
|
}
|
|
return built[name];
|
|
}
|
|
|
|
iface = {
|
|
|
|
/** Returns the wrapping modal element */
|
|
modalElem: buildElemAccessor(modalElem),
|
|
|
|
/** Returns the close button element */
|
|
closeElem: buildElemAccessor(closeElem),
|
|
|
|
/** Returns the overlay element */
|
|
overlayElem: buildElemAccessor(shadowElem),
|
|
|
|
/** Builds the dom without showing the modal */
|
|
buildDom: returnIface(build.bind(null, null)),
|
|
|
|
/** Returns whether this modal is currently being shown */
|
|
isVisible: function () {
|
|
return !!(built && modalElem && modalElem().isVisible());
|
|
},
|
|
|
|
/** Shows this modal */
|
|
show: function (detail) {
|
|
if ( beforeShowEvent.trigger(iface, detail) ) {
|
|
shadowElem().show();
|
|
closeElem();
|
|
modalElem().show();
|
|
afterShowEvent.trigger(iface, detail);
|
|
}
|
|
return this;
|
|
},
|
|
|
|
/** Hides this modal */
|
|
close: returnIface(close),
|
|
|
|
/**
|
|
* Force closes this modal. This will not call beforeClose
|
|
* events and will just immediately hide the modal
|
|
*/
|
|
forceClose: returnIface(forceClose),
|
|
|
|
/** Destroys this modal */
|
|
destroy: function () {
|
|
modalElem().destroy();
|
|
shadowElem().destroy();
|
|
shadowElem = modalElem = closeElem = undefined;
|
|
},
|
|
|
|
/**
|
|
* Updates the options for this modal. This will only let you
|
|
* change options that are re-evaluted regularly, such as
|
|
* `overlayClose`.
|
|
*/
|
|
options: function ( opts ) {
|
|
Object.keys(opts).map(function (key) {
|
|
options[key] = opts[key];
|
|
});
|
|
},
|
|
|
|
/** Executes after the DOM nodes are created */
|
|
afterCreate: returnIface(afterCreateEvent.watch),
|
|
|
|
/** Executes a callback before this modal is closed */
|
|
beforeShow: returnIface(beforeShowEvent.watch),
|
|
|
|
/** Executes a callback after this modal is shown */
|
|
afterShow: returnIface(afterShowEvent.watch),
|
|
|
|
/** Executes a callback before this modal is closed */
|
|
beforeClose: returnIface(beforeCloseEvent.watch),
|
|
|
|
/** Executes a callback after this modal is closed */
|
|
afterClose: returnIface(afterCloseEvent.watch)
|
|
};
|
|
|
|
manageFocus(iface, getOption.bind(null, "focus", true));
|
|
|
|
manageBodyOverflow(iface, getOption.bind(null, "bodyOverflow", true));
|
|
|
|
// If a user presses the 'escape' key, close the modal.
|
|
escapeKey.watch(function escapeKeyPress () {
|
|
if ( getOption("escCloses", true) && iface.isVisible() ) {
|
|
iface.close();
|
|
}
|
|
});
|
|
|
|
return iface;
|
|
};
|
|
|
|
}));
|
|
|
|
|
|
/***/ }),
|
|
|
|
/***/ 7533:
|
|
/***/ (function(__unused_webpack_module, exports) {
|
|
|
|
/** @license URI.js v4.4.0 (c) 2011 Gary Court. License: http://github.com/garycourt/uri-js */
|
|
(function (global, factory) {
|
|
true ? factory(exports) :
|
|
0;
|
|
}(this, (function (exports) { 'use strict';
|
|
|
|
function merge() {
|
|
for (var _len = arguments.length, sets = Array(_len), _key = 0; _key < _len; _key++) {
|
|
sets[_key] = arguments[_key];
|
|
}
|
|
|
|
if (sets.length > 1) {
|
|
sets[0] = sets[0].slice(0, -1);
|
|
var xl = sets.length - 1;
|
|
for (var x = 1; x < xl; ++x) {
|
|
sets[x] = sets[x].slice(1, -1);
|
|
}
|
|
sets[xl] = sets[xl].slice(1);
|
|
return sets.join('');
|
|
} else {
|
|
return sets[0];
|
|
}
|
|
}
|
|
function subexp(str) {
|
|
return "(?:" + str + ")";
|
|
}
|
|
function typeOf(o) {
|
|
return o === undefined ? "undefined" : o === null ? "null" : Object.prototype.toString.call(o).split(" ").pop().split("]").shift().toLowerCase();
|
|
}
|
|
function toUpperCase(str) {
|
|
return str.toUpperCase();
|
|
}
|
|
function toArray(obj) {
|
|
return obj !== undefined && obj !== null ? obj instanceof Array ? obj : typeof obj.length !== "number" || obj.split || obj.setInterval || obj.call ? [obj] : Array.prototype.slice.call(obj) : [];
|
|
}
|
|
function assign(target, source) {
|
|
var obj = target;
|
|
if (source) {
|
|
for (var key in source) {
|
|
obj[key] = source[key];
|
|
}
|
|
}
|
|
return obj;
|
|
}
|
|
|
|
function buildExps(isIRI) {
|
|
var ALPHA$$ = "[A-Za-z]",
|
|
CR$ = "[\\x0D]",
|
|
DIGIT$$ = "[0-9]",
|
|
DQUOTE$$ = "[\\x22]",
|
|
HEXDIG$$ = merge(DIGIT$$, "[A-Fa-f]"),
|
|
//case-insensitive
|
|
LF$$ = "[\\x0A]",
|
|
SP$$ = "[\\x20]",
|
|
PCT_ENCODED$ = subexp(subexp("%[EFef]" + HEXDIG$$ + "%" + HEXDIG$$ + HEXDIG$$ + "%" + HEXDIG$$ + HEXDIG$$) + "|" + subexp("%[89A-Fa-f]" + HEXDIG$$ + "%" + HEXDIG$$ + HEXDIG$$) + "|" + subexp("%" + HEXDIG$$ + HEXDIG$$)),
|
|
//expanded
|
|
GEN_DELIMS$$ = "[\\:\\/\\?\\#\\[\\]\\@]",
|
|
SUB_DELIMS$$ = "[\\!\\$\\&\\'\\(\\)\\*\\+\\,\\;\\=]",
|
|
RESERVED$$ = merge(GEN_DELIMS$$, SUB_DELIMS$$),
|
|
UCSCHAR$$ = isIRI ? "[\\xA0-\\u200D\\u2010-\\u2029\\u202F-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF]" : "[]",
|
|
//subset, excludes bidi control characters
|
|
IPRIVATE$$ = isIRI ? "[\\uE000-\\uF8FF]" : "[]",
|
|
//subset
|
|
UNRESERVED$$ = merge(ALPHA$$, DIGIT$$, "[\\-\\.\\_\\~]", UCSCHAR$$),
|
|
SCHEME$ = subexp(ALPHA$$ + merge(ALPHA$$, DIGIT$$, "[\\+\\-\\.]") + "*"),
|
|
USERINFO$ = subexp(subexp(PCT_ENCODED$ + "|" + merge(UNRESERVED$$, SUB_DELIMS$$, "[\\:]")) + "*"),
|
|
DEC_OCTET$ = subexp(subexp("25[0-5]") + "|" + subexp("2[0-4]" + DIGIT$$) + "|" + subexp("1" + DIGIT$$ + DIGIT$$) + "|" + subexp("[1-9]" + DIGIT$$) + "|" + DIGIT$$),
|
|
DEC_OCTET_RELAXED$ = subexp(subexp("25[0-5]") + "|" + subexp("2[0-4]" + DIGIT$$) + "|" + subexp("1" + DIGIT$$ + DIGIT$$) + "|" + subexp("0?[1-9]" + DIGIT$$) + "|0?0?" + DIGIT$$),
|
|
//relaxed parsing rules
|
|
IPV4ADDRESS$ = subexp(DEC_OCTET_RELAXED$ + "\\." + DEC_OCTET_RELAXED$ + "\\." + DEC_OCTET_RELAXED$ + "\\." + DEC_OCTET_RELAXED$),
|
|
H16$ = subexp(HEXDIG$$ + "{1,4}"),
|
|
LS32$ = subexp(subexp(H16$ + "\\:" + H16$) + "|" + IPV4ADDRESS$),
|
|
IPV6ADDRESS1$ = subexp(subexp(H16$ + "\\:") + "{6}" + LS32$),
|
|
// 6( h16 ":" ) ls32
|
|
IPV6ADDRESS2$ = subexp("\\:\\:" + subexp(H16$ + "\\:") + "{5}" + LS32$),
|
|
// "::" 5( h16 ":" ) ls32
|
|
IPV6ADDRESS3$ = subexp(subexp(H16$) + "?\\:\\:" + subexp(H16$ + "\\:") + "{4}" + LS32$),
|
|
//[ h16 ] "::" 4( h16 ":" ) ls32
|
|
IPV6ADDRESS4$ = subexp(subexp(subexp(H16$ + "\\:") + "{0,1}" + H16$) + "?\\:\\:" + subexp(H16$ + "\\:") + "{3}" + LS32$),
|
|
//[ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32
|
|
IPV6ADDRESS5$ = subexp(subexp(subexp(H16$ + "\\:") + "{0,2}" + H16$) + "?\\:\\:" + subexp(H16$ + "\\:") + "{2}" + LS32$),
|
|
//[ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32
|
|
IPV6ADDRESS6$ = subexp(subexp(subexp(H16$ + "\\:") + "{0,3}" + H16$) + "?\\:\\:" + H16$ + "\\:" + LS32$),
|
|
//[ *3( h16 ":" ) h16 ] "::" h16 ":" ls32
|
|
IPV6ADDRESS7$ = subexp(subexp(subexp(H16$ + "\\:") + "{0,4}" + H16$) + "?\\:\\:" + LS32$),
|
|
//[ *4( h16 ":" ) h16 ] "::" ls32
|
|
IPV6ADDRESS8$ = subexp(subexp(subexp(H16$ + "\\:") + "{0,5}" + H16$) + "?\\:\\:" + H16$),
|
|
//[ *5( h16 ":" ) h16 ] "::" h16
|
|
IPV6ADDRESS9$ = subexp(subexp(subexp(H16$ + "\\:") + "{0,6}" + H16$) + "?\\:\\:"),
|
|
//[ *6( h16 ":" ) h16 ] "::"
|
|
IPV6ADDRESS$ = subexp([IPV6ADDRESS1$, IPV6ADDRESS2$, IPV6ADDRESS3$, IPV6ADDRESS4$, IPV6ADDRESS5$, IPV6ADDRESS6$, IPV6ADDRESS7$, IPV6ADDRESS8$, IPV6ADDRESS9$].join("|")),
|
|
ZONEID$ = subexp(subexp(UNRESERVED$$ + "|" + PCT_ENCODED$) + "+"),
|
|
//RFC 6874
|
|
IPV6ADDRZ$ = subexp(IPV6ADDRESS$ + "\\%25" + ZONEID$),
|
|
//RFC 6874
|
|
IPV6ADDRZ_RELAXED$ = subexp(IPV6ADDRESS$ + subexp("\\%25|\\%(?!" + HEXDIG$$ + "{2})") + ZONEID$),
|
|
//RFC 6874, with relaxed parsing rules
|
|
IPVFUTURE$ = subexp("[vV]" + HEXDIG$$ + "+\\." + merge(UNRESERVED$$, SUB_DELIMS$$, "[\\:]") + "+"),
|
|
IP_LITERAL$ = subexp("\\[" + subexp(IPV6ADDRZ_RELAXED$ + "|" + IPV6ADDRESS$ + "|" + IPVFUTURE$) + "\\]"),
|
|
//RFC 6874
|
|
REG_NAME$ = subexp(subexp(PCT_ENCODED$ + "|" + merge(UNRESERVED$$, SUB_DELIMS$$)) + "*"),
|
|
HOST$ = subexp(IP_LITERAL$ + "|" + IPV4ADDRESS$ + "(?!" + REG_NAME$ + ")" + "|" + REG_NAME$),
|
|
PORT$ = subexp(DIGIT$$ + "*"),
|
|
AUTHORITY$ = subexp(subexp(USERINFO$ + "@") + "?" + HOST$ + subexp("\\:" + PORT$) + "?"),
|
|
PCHAR$ = subexp(PCT_ENCODED$ + "|" + merge(UNRESERVED$$, SUB_DELIMS$$, "[\\:\\@]")),
|
|
SEGMENT$ = subexp(PCHAR$ + "*"),
|
|
SEGMENT_NZ$ = subexp(PCHAR$ + "+"),
|
|
SEGMENT_NZ_NC$ = subexp(subexp(PCT_ENCODED$ + "|" + merge(UNRESERVED$$, SUB_DELIMS$$, "[\\@]")) + "+"),
|
|
PATH_ABEMPTY$ = subexp(subexp("\\/" + SEGMENT$) + "*"),
|
|
PATH_ABSOLUTE$ = subexp("\\/" + subexp(SEGMENT_NZ$ + PATH_ABEMPTY$) + "?"),
|
|
//simplified
|
|
PATH_NOSCHEME$ = subexp(SEGMENT_NZ_NC$ + PATH_ABEMPTY$),
|
|
//simplified
|
|
PATH_ROOTLESS$ = subexp(SEGMENT_NZ$ + PATH_ABEMPTY$),
|
|
//simplified
|
|
PATH_EMPTY$ = "(?!" + PCHAR$ + ")",
|
|
PATH$ = subexp(PATH_ABEMPTY$ + "|" + PATH_ABSOLUTE$ + "|" + PATH_NOSCHEME$ + "|" + PATH_ROOTLESS$ + "|" + PATH_EMPTY$),
|
|
QUERY$ = subexp(subexp(PCHAR$ + "|" + merge("[\\/\\?]", IPRIVATE$$)) + "*"),
|
|
FRAGMENT$ = subexp(subexp(PCHAR$ + "|[\\/\\?]") + "*"),
|
|
HIER_PART$ = subexp(subexp("\\/\\/" + AUTHORITY$ + PATH_ABEMPTY$) + "|" + PATH_ABSOLUTE$ + "|" + PATH_ROOTLESS$ + "|" + PATH_EMPTY$),
|
|
URI$ = subexp(SCHEME$ + "\\:" + HIER_PART$ + subexp("\\?" + QUERY$) + "?" + subexp("\\#" + FRAGMENT$) + "?"),
|
|
RELATIVE_PART$ = subexp(subexp("\\/\\/" + AUTHORITY$ + PATH_ABEMPTY$) + "|" + PATH_ABSOLUTE$ + "|" + PATH_NOSCHEME$ + "|" + PATH_EMPTY$),
|
|
RELATIVE$ = subexp(RELATIVE_PART$ + subexp("\\?" + QUERY$) + "?" + subexp("\\#" + FRAGMENT$) + "?"),
|
|
URI_REFERENCE$ = subexp(URI$ + "|" + RELATIVE$),
|
|
ABSOLUTE_URI$ = subexp(SCHEME$ + "\\:" + HIER_PART$ + subexp("\\?" + QUERY$) + "?"),
|
|
GENERIC_REF$ = "^(" + SCHEME$ + ")\\:" + subexp(subexp("\\/\\/(" + subexp("(" + USERINFO$ + ")@") + "?(" + HOST$ + ")" + subexp("\\:(" + PORT$ + ")") + "?)") + "?(" + PATH_ABEMPTY$ + "|" + PATH_ABSOLUTE$ + "|" + PATH_ROOTLESS$ + "|" + PATH_EMPTY$ + ")") + subexp("\\?(" + QUERY$ + ")") + "?" + subexp("\\#(" + FRAGMENT$ + ")") + "?$",
|
|
RELATIVE_REF$ = "^(){0}" + subexp(subexp("\\/\\/(" + subexp("(" + USERINFO$ + ")@") + "?(" + HOST$ + ")" + subexp("\\:(" + PORT$ + ")") + "?)") + "?(" + PATH_ABEMPTY$ + "|" + PATH_ABSOLUTE$ + "|" + PATH_NOSCHEME$ + "|" + PATH_EMPTY$ + ")") + subexp("\\?(" + QUERY$ + ")") + "?" + subexp("\\#(" + FRAGMENT$ + ")") + "?$",
|
|
ABSOLUTE_REF$ = "^(" + SCHEME$ + ")\\:" + subexp(subexp("\\/\\/(" + subexp("(" + USERINFO$ + ")@") + "?(" + HOST$ + ")" + subexp("\\:(" + PORT$ + ")") + "?)") + "?(" + PATH_ABEMPTY$ + "|" + PATH_ABSOLUTE$ + "|" + PATH_ROOTLESS$ + "|" + PATH_EMPTY$ + ")") + subexp("\\?(" + QUERY$ + ")") + "?$",
|
|
SAMEDOC_REF$ = "^" + subexp("\\#(" + FRAGMENT$ + ")") + "?$",
|
|
AUTHORITY_REF$ = "^" + subexp("(" + USERINFO$ + ")@") + "?(" + HOST$ + ")" + subexp("\\:(" + PORT$ + ")") + "?$";
|
|
return {
|
|
NOT_SCHEME: new RegExp(merge("[^]", ALPHA$$, DIGIT$$, "[\\+\\-\\.]"), "g"),
|
|
NOT_USERINFO: new RegExp(merge("[^\\%\\:]", UNRESERVED$$, SUB_DELIMS$$), "g"),
|
|
NOT_HOST: new RegExp(merge("[^\\%\\[\\]\\:]", UNRESERVED$$, SUB_DELIMS$$), "g"),
|
|
NOT_PATH: new RegExp(merge("[^\\%\\/\\:\\@]", UNRESERVED$$, SUB_DELIMS$$), "g"),
|
|
NOT_PATH_NOSCHEME: new RegExp(merge("[^\\%\\/\\@]", UNRESERVED$$, SUB_DELIMS$$), "g"),
|
|
NOT_QUERY: new RegExp(merge("[^\\%]", UNRESERVED$$, SUB_DELIMS$$, "[\\:\\@\\/\\?]", IPRIVATE$$), "g"),
|
|
NOT_FRAGMENT: new RegExp(merge("[^\\%]", UNRESERVED$$, SUB_DELIMS$$, "[\\:\\@\\/\\?]"), "g"),
|
|
ESCAPE: new RegExp(merge("[^]", UNRESERVED$$, SUB_DELIMS$$), "g"),
|
|
UNRESERVED: new RegExp(UNRESERVED$$, "g"),
|
|
OTHER_CHARS: new RegExp(merge("[^\\%]", UNRESERVED$$, RESERVED$$), "g"),
|
|
PCT_ENCODED: new RegExp(PCT_ENCODED$, "g"),
|
|
IPV4ADDRESS: new RegExp("^(" + IPV4ADDRESS$ + ")$"),
|
|
IPV6ADDRESS: new RegExp("^\\[?(" + IPV6ADDRESS$ + ")" + subexp(subexp("\\%25|\\%(?!" + HEXDIG$$ + "{2})") + "(" + ZONEID$ + ")") + "?\\]?$") //RFC 6874, with relaxed parsing rules
|
|
};
|
|
}
|
|
var URI_PROTOCOL = buildExps(false);
|
|
|
|
var IRI_PROTOCOL = buildExps(true);
|
|
|
|
var slicedToArray = function () {
|
|
function sliceIterator(arr, i) {
|
|
var _arr = [];
|
|
var _n = true;
|
|
var _d = false;
|
|
var _e = undefined;
|
|
|
|
try {
|
|
for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
|
|
_arr.push(_s.value);
|
|
|
|
if (i && _arr.length === i) break;
|
|
}
|
|
} catch (err) {
|
|
_d = true;
|
|
_e = err;
|
|
} finally {
|
|
try {
|
|
if (!_n && _i["return"]) _i["return"]();
|
|
} finally {
|
|
if (_d) throw _e;
|
|
}
|
|
}
|
|
|
|
return _arr;
|
|
}
|
|
|
|
return function (arr, i) {
|
|
if (Array.isArray(arr)) {
|
|
return arr;
|
|
} else if (Symbol.iterator in Object(arr)) {
|
|
return sliceIterator(arr, i);
|
|
} else {
|
|
throw new TypeError("Invalid attempt to destructure non-iterable instance");
|
|
}
|
|
};
|
|
}();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var toConsumableArray = function (arr) {
|
|
if (Array.isArray(arr)) {
|
|
for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];
|
|
|
|
return arr2;
|
|
} else {
|
|
return Array.from(arr);
|
|
}
|
|
};
|
|
|
|
/** Highest positive signed 32-bit float value */
|
|
|
|
var maxInt = 2147483647; // aka. 0x7FFFFFFF or 2^31-1
|
|
|
|
/** Bootstring parameters */
|
|
var base = 36;
|
|
var tMin = 1;
|
|
var tMax = 26;
|
|
var skew = 38;
|
|
var damp = 700;
|
|
var initialBias = 72;
|
|
var initialN = 128; // 0x80
|
|
var delimiter = '-'; // '\x2D'
|
|
|
|
/** Regular expressions */
|
|
var regexPunycode = /^xn--/;
|
|
var regexNonASCII = /[^\0-\x7E]/; // non-ASCII chars
|
|
var regexSeparators = /[\x2E\u3002\uFF0E\uFF61]/g; // RFC 3490 separators
|
|
|
|
/** Error messages */
|
|
var errors = {
|
|
'overflow': 'Overflow: input needs wider integers to process',
|
|
'not-basic': 'Illegal input >= 0x80 (not a basic code point)',
|
|
'invalid-input': 'Invalid input'
|
|
};
|
|
|
|
/** Convenience shortcuts */
|
|
var baseMinusTMin = base - tMin;
|
|
var floor = Math.floor;
|
|
var stringFromCharCode = String.fromCharCode;
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* A generic error utility function.
|
|
* @private
|
|
* @param {String} type The error type.
|
|
* @returns {Error} Throws a `RangeError` with the applicable error message.
|
|
*/
|
|
function error$1(type) {
|
|
throw new RangeError(errors[type]);
|
|
}
|
|
|
|
/**
|
|
* A generic `Array#map` utility function.
|
|
* @private
|
|
* @param {Array} array The array to iterate over.
|
|
* @param {Function} callback The function that gets called for every array
|
|
* item.
|
|
* @returns {Array} A new array of values returned by the callback function.
|
|
*/
|
|
function map(array, fn) {
|
|
var result = [];
|
|
var length = array.length;
|
|
while (length--) {
|
|
result[length] = fn(array[length]);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* A simple `Array#map`-like wrapper to work with domain name strings or email
|
|
* addresses.
|
|
* @private
|
|
* @param {String} domain The domain name or email address.
|
|
* @param {Function} callback The function that gets called for every
|
|
* character.
|
|
* @returns {Array} A new string of characters returned by the callback
|
|
* function.
|
|
*/
|
|
function mapDomain(string, fn) {
|
|
var parts = string.split('@');
|
|
var result = '';
|
|
if (parts.length > 1) {
|
|
// In email addresses, only the domain name should be punycoded. Leave
|
|
// the local part (i.e. everything up to `@`) intact.
|
|
result = parts[0] + '@';
|
|
string = parts[1];
|
|
}
|
|
// Avoid `split(regex)` for IE8 compatibility. See #17.
|
|
string = string.replace(regexSeparators, '\x2E');
|
|
var labels = string.split('.');
|
|
var encoded = map(labels, fn).join('.');
|
|
return result + encoded;
|
|
}
|
|
|
|
/**
|
|
* Creates an array containing the numeric code points of each Unicode
|
|
* character in the string. While JavaScript uses UCS-2 internally,
|
|
* this function will convert a pair of surrogate halves (each of which
|
|
* UCS-2 exposes as separate characters) into a single code point,
|
|
* matching UTF-16.
|
|
* @see `punycode.ucs2.encode`
|
|
* @see <https://mathiasbynens.be/notes/javascript-encoding>
|
|
* @memberOf punycode.ucs2
|
|
* @name decode
|
|
* @param {String} string The Unicode input string (UCS-2).
|
|
* @returns {Array} The new array of code points.
|
|
*/
|
|
function ucs2decode(string) {
|
|
var output = [];
|
|
var counter = 0;
|
|
var length = string.length;
|
|
while (counter < length) {
|
|
var value = string.charCodeAt(counter++);
|
|
if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
|
|
// It's a high surrogate, and there is a next character.
|
|
var extra = string.charCodeAt(counter++);
|
|
if ((extra & 0xFC00) == 0xDC00) {
|
|
// Low surrogate.
|
|
output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
|
|
} else {
|
|
// It's an unmatched surrogate; only append this code unit, in case the
|
|
// next code unit is the high surrogate of a surrogate pair.
|
|
output.push(value);
|
|
counter--;
|
|
}
|
|
} else {
|
|
output.push(value);
|
|
}
|
|
}
|
|
return output;
|
|
}
|
|
|
|
/**
|
|
* Creates a string based on an array of numeric code points.
|
|
* @see `punycode.ucs2.decode`
|
|
* @memberOf punycode.ucs2
|
|
* @name encode
|
|
* @param {Array} codePoints The array of numeric code points.
|
|
* @returns {String} The new Unicode string (UCS-2).
|
|
*/
|
|
var ucs2encode = function ucs2encode(array) {
|
|
return String.fromCodePoint.apply(String, toConsumableArray(array));
|
|
};
|
|
|
|
/**
|
|
* Converts a basic code point into a digit/integer.
|
|
* @see `digitToBasic()`
|
|
* @private
|
|
* @param {Number} codePoint The basic numeric code point value.
|
|
* @returns {Number} The numeric value of a basic code point (for use in
|
|
* representing integers) in the range `0` to `base - 1`, or `base` if
|
|
* the code point does not represent a value.
|
|
*/
|
|
var basicToDigit = function basicToDigit(codePoint) {
|
|
if (codePoint - 0x30 < 0x0A) {
|
|
return codePoint - 0x16;
|
|
}
|
|
if (codePoint - 0x41 < 0x1A) {
|
|
return codePoint - 0x41;
|
|
}
|
|
if (codePoint - 0x61 < 0x1A) {
|
|
return codePoint - 0x61;
|
|
}
|
|
return base;
|
|
};
|
|
|
|
/**
|
|
* Converts a digit/integer into a basic code point.
|
|
* @see `basicToDigit()`
|
|
* @private
|
|
* @param {Number} digit The numeric value of a basic code point.
|
|
* @returns {Number} The basic code point whose value (when used for
|
|
* representing integers) is `digit`, which needs to be in the range
|
|
* `0` to `base - 1`. If `flag` is non-zero, the uppercase form is
|
|
* used; else, the lowercase form is used. The behavior is undefined
|
|
* if `flag` is non-zero and `digit` has no uppercase form.
|
|
*/
|
|
var digitToBasic = function digitToBasic(digit, flag) {
|
|
// 0..25 map to ASCII a..z or A..Z
|
|
// 26..35 map to ASCII 0..9
|
|
return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5);
|
|
};
|
|
|
|
/**
|
|
* Bias adaptation function as per section 3.4 of RFC 3492.
|
|
* https://tools.ietf.org/html/rfc3492#section-3.4
|
|
* @private
|
|
*/
|
|
var adapt = function adapt(delta, numPoints, firstTime) {
|
|
var k = 0;
|
|
delta = firstTime ? floor(delta / damp) : delta >> 1;
|
|
delta += floor(delta / numPoints);
|
|
for (; /* no initialization */delta > baseMinusTMin * tMax >> 1; k += base) {
|
|
delta = floor(delta / baseMinusTMin);
|
|
}
|
|
return floor(k + (baseMinusTMin + 1) * delta / (delta + skew));
|
|
};
|
|
|
|
/**
|
|
* Converts a Punycode string of ASCII-only symbols to a string of Unicode
|
|
* symbols.
|
|
* @memberOf punycode
|
|
* @param {String} input The Punycode string of ASCII-only symbols.
|
|
* @returns {String} The resulting string of Unicode symbols.
|
|
*/
|
|
var decode = function decode(input) {
|
|
// Don't use UCS-2.
|
|
var output = [];
|
|
var inputLength = input.length;
|
|
var i = 0;
|
|
var n = initialN;
|
|
var bias = initialBias;
|
|
|
|
// Handle the basic code points: let `basic` be the number of input code
|
|
// points before the last delimiter, or `0` if there is none, then copy
|
|
// the first basic code points to the output.
|
|
|
|
var basic = input.lastIndexOf(delimiter);
|
|
if (basic < 0) {
|
|
basic = 0;
|
|
}
|
|
|
|
for (var j = 0; j < basic; ++j) {
|
|
// if it's not a basic code point
|
|
if (input.charCodeAt(j) >= 0x80) {
|
|
error$1('not-basic');
|
|
}
|
|
output.push(input.charCodeAt(j));
|
|
}
|
|
|
|
// Main decoding loop: start just after the last delimiter if any basic code
|
|
// points were copied; start at the beginning otherwise.
|
|
|
|
for (var index = basic > 0 ? basic + 1 : 0; index < inputLength;) /* no final expression */{
|
|
|
|
// `index` is the index of the next character to be consumed.
|
|
// Decode a generalized variable-length integer into `delta`,
|
|
// which gets added to `i`. The overflow checking is easier
|
|
// if we increase `i` as we go, then subtract off its starting
|
|
// value at the end to obtain `delta`.
|
|
var oldi = i;
|
|
for (var w = 1, k = base;; /* no condition */k += base) {
|
|
|
|
if (index >= inputLength) {
|
|
error$1('invalid-input');
|
|
}
|
|
|
|
var digit = basicToDigit(input.charCodeAt(index++));
|
|
|
|
if (digit >= base || digit > floor((maxInt - i) / w)) {
|
|
error$1('overflow');
|
|
}
|
|
|
|
i += digit * w;
|
|
var t = k <= bias ? tMin : k >= bias + tMax ? tMax : k - bias;
|
|
|
|
if (digit < t) {
|
|
break;
|
|
}
|
|
|
|
var baseMinusT = base - t;
|
|
if (w > floor(maxInt / baseMinusT)) {
|
|
error$1('overflow');
|
|
}
|
|
|
|
w *= baseMinusT;
|
|
}
|
|
|
|
var out = output.length + 1;
|
|
bias = adapt(i - oldi, out, oldi == 0);
|
|
|
|
// `i` was supposed to wrap around from `out` to `0`,
|
|
// incrementing `n` each time, so we'll fix that now:
|
|
if (floor(i / out) > maxInt - n) {
|
|
error$1('overflow');
|
|
}
|
|
|
|
n += floor(i / out);
|
|
i %= out;
|
|
|
|
// Insert `n` at position `i` of the output.
|
|
output.splice(i++, 0, n);
|
|
}
|
|
|
|
return String.fromCodePoint.apply(String, output);
|
|
};
|
|
|
|
/**
|
|
* Converts a string of Unicode symbols (e.g. a domain name label) to a
|
|
* Punycode string of ASCII-only symbols.
|
|
* @memberOf punycode
|
|
* @param {String} input The string of Unicode symbols.
|
|
* @returns {String} The resulting Punycode string of ASCII-only symbols.
|
|
*/
|
|
var encode = function encode(input) {
|
|
var output = [];
|
|
|
|
// Convert the input in UCS-2 to an array of Unicode code points.
|
|
input = ucs2decode(input);
|
|
|
|
// Cache the length.
|
|
var inputLength = input.length;
|
|
|
|
// Initialize the state.
|
|
var n = initialN;
|
|
var delta = 0;
|
|
var bias = initialBias;
|
|
|
|
// Handle the basic code points.
|
|
var _iteratorNormalCompletion = true;
|
|
var _didIteratorError = false;
|
|
var _iteratorError = undefined;
|
|
|
|
try {
|
|
for (var _iterator = input[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
|
|
var _currentValue2 = _step.value;
|
|
|
|
if (_currentValue2 < 0x80) {
|
|
output.push(stringFromCharCode(_currentValue2));
|
|
}
|
|
}
|
|
} catch (err) {
|
|
_didIteratorError = true;
|
|
_iteratorError = err;
|
|
} finally {
|
|
try {
|
|
if (!_iteratorNormalCompletion && _iterator.return) {
|
|
_iterator.return();
|
|
}
|
|
} finally {
|
|
if (_didIteratorError) {
|
|
throw _iteratorError;
|
|
}
|
|
}
|
|
}
|
|
|
|
var basicLength = output.length;
|
|
var handledCPCount = basicLength;
|
|
|
|
// `handledCPCount` is the number of code points that have been handled;
|
|
// `basicLength` is the number of basic code points.
|
|
|
|
// Finish the basic string with a delimiter unless it's empty.
|
|
if (basicLength) {
|
|
output.push(delimiter);
|
|
}
|
|
|
|
// Main encoding loop:
|
|
while (handledCPCount < inputLength) {
|
|
|
|
// All non-basic code points < n have been handled already. Find the next
|
|
// larger one:
|
|
var m = maxInt;
|
|
var _iteratorNormalCompletion2 = true;
|
|
var _didIteratorError2 = false;
|
|
var _iteratorError2 = undefined;
|
|
|
|
try {
|
|
for (var _iterator2 = input[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
|
|
var currentValue = _step2.value;
|
|
|
|
if (currentValue >= n && currentValue < m) {
|
|
m = currentValue;
|
|
}
|
|
}
|
|
|
|
// Increase `delta` enough to advance the decoder's <n,i> state to <m,0>,
|
|
// but guard against overflow.
|
|
} catch (err) {
|
|
_didIteratorError2 = true;
|
|
_iteratorError2 = err;
|
|
} finally {
|
|
try {
|
|
if (!_iteratorNormalCompletion2 && _iterator2.return) {
|
|
_iterator2.return();
|
|
}
|
|
} finally {
|
|
if (_didIteratorError2) {
|
|
throw _iteratorError2;
|
|
}
|
|
}
|
|
}
|
|
|
|
var handledCPCountPlusOne = handledCPCount + 1;
|
|
if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) {
|
|
error$1('overflow');
|
|
}
|
|
|
|
delta += (m - n) * handledCPCountPlusOne;
|
|
n = m;
|
|
|
|
var _iteratorNormalCompletion3 = true;
|
|
var _didIteratorError3 = false;
|
|
var _iteratorError3 = undefined;
|
|
|
|
try {
|
|
for (var _iterator3 = input[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
|
|
var _currentValue = _step3.value;
|
|
|
|
if (_currentValue < n && ++delta > maxInt) {
|
|
error$1('overflow');
|
|
}
|
|
if (_currentValue == n) {
|
|
// Represent delta as a generalized variable-length integer.
|
|
var q = delta;
|
|
for (var k = base;; /* no condition */k += base) {
|
|
var t = k <= bias ? tMin : k >= bias + tMax ? tMax : k - bias;
|
|
if (q < t) {
|
|
break;
|
|
}
|
|
var qMinusT = q - t;
|
|
var baseMinusT = base - t;
|
|
output.push(stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0)));
|
|
q = floor(qMinusT / baseMinusT);
|
|
}
|
|
|
|
output.push(stringFromCharCode(digitToBasic(q, 0)));
|
|
bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength);
|
|
delta = 0;
|
|
++handledCPCount;
|
|
}
|
|
}
|
|
} catch (err) {
|
|
_didIteratorError3 = true;
|
|
_iteratorError3 = err;
|
|
} finally {
|
|
try {
|
|
if (!_iteratorNormalCompletion3 && _iterator3.return) {
|
|
_iterator3.return();
|
|
}
|
|
} finally {
|
|
if (_didIteratorError3) {
|
|
throw _iteratorError3;
|
|
}
|
|
}
|
|
}
|
|
|
|
++delta;
|
|
++n;
|
|
}
|
|
return output.join('');
|
|
};
|
|
|
|
/**
|
|
* Converts a Punycode string representing a domain name or an email address
|
|
* to Unicode. Only the Punycoded parts of the input will be converted, i.e.
|
|
* it doesn't matter if you call it on a string that has already been
|
|
* converted to Unicode.
|
|
* @memberOf punycode
|
|
* @param {String} input The Punycoded domain name or email address to
|
|
* convert to Unicode.
|
|
* @returns {String} The Unicode representation of the given Punycode
|
|
* string.
|
|
*/
|
|
var toUnicode = function toUnicode(input) {
|
|
return mapDomain(input, function (string) {
|
|
return regexPunycode.test(string) ? decode(string.slice(4).toLowerCase()) : string;
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Converts a Unicode string representing a domain name or an email address to
|
|
* Punycode. Only the non-ASCII parts of the domain name will be converted,
|
|
* i.e. it doesn't matter if you call it with a domain that's already in
|
|
* ASCII.
|
|
* @memberOf punycode
|
|
* @param {String} input The domain name or email address to convert, as a
|
|
* Unicode string.
|
|
* @returns {String} The Punycode representation of the given domain name or
|
|
* email address.
|
|
*/
|
|
var toASCII = function toASCII(input) {
|
|
return mapDomain(input, function (string) {
|
|
return regexNonASCII.test(string) ? 'xn--' + encode(string) : string;
|
|
});
|
|
};
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
/** Define the public API */
|
|
var punycode = {
|
|
/**
|
|
* A string representing the current Punycode.js version number.
|
|
* @memberOf punycode
|
|
* @type String
|
|
*/
|
|
'version': '2.1.0',
|
|
/**
|
|
* An object of methods to convert from JavaScript's internal character
|
|
* representation (UCS-2) to Unicode code points, and back.
|
|
* @see <https://mathiasbynens.be/notes/javascript-encoding>
|
|
* @memberOf punycode
|
|
* @type Object
|
|
*/
|
|
'ucs2': {
|
|
'decode': ucs2decode,
|
|
'encode': ucs2encode
|
|
},
|
|
'decode': decode,
|
|
'encode': encode,
|
|
'toASCII': toASCII,
|
|
'toUnicode': toUnicode
|
|
};
|
|
|
|
/**
|
|
* URI.js
|
|
*
|
|
* @fileoverview An RFC 3986 compliant, scheme extendable URI parsing/validating/resolving library for JavaScript.
|
|
* @author <a href="mailto:gary.court@gmail.com">Gary Court</a>
|
|
* @see http://github.com/garycourt/uri-js
|
|
*/
|
|
/**
|
|
* Copyright 2011 Gary Court. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without modification, are
|
|
* permitted provided that the following conditions are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
|
* conditions and the following disclaimer.
|
|
*
|
|
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
|
* of conditions and the following disclaimer in the documentation and/or other materials
|
|
* provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY GARY COURT ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GARY COURT OR
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
* The views and conclusions contained in the software and documentation are those of the
|
|
* authors and should not be interpreted as representing official policies, either expressed
|
|
* or implied, of Gary Court.
|
|
*/
|
|
var SCHEMES = {};
|
|
function pctEncChar(chr) {
|
|
var c = chr.charCodeAt(0);
|
|
var e = void 0;
|
|
if (c < 16) e = "%0" + c.toString(16).toUpperCase();else if (c < 128) e = "%" + c.toString(16).toUpperCase();else if (c < 2048) e = "%" + (c >> 6 | 192).toString(16).toUpperCase() + "%" + (c & 63 | 128).toString(16).toUpperCase();else e = "%" + (c >> 12 | 224).toString(16).toUpperCase() + "%" + (c >> 6 & 63 | 128).toString(16).toUpperCase() + "%" + (c & 63 | 128).toString(16).toUpperCase();
|
|
return e;
|
|
}
|
|
function pctDecChars(str) {
|
|
var newStr = "";
|
|
var i = 0;
|
|
var il = str.length;
|
|
while (i < il) {
|
|
var c = parseInt(str.substr(i + 1, 2), 16);
|
|
if (c < 128) {
|
|
newStr += String.fromCharCode(c);
|
|
i += 3;
|
|
} else if (c >= 194 && c < 224) {
|
|
if (il - i >= 6) {
|
|
var c2 = parseInt(str.substr(i + 4, 2), 16);
|
|
newStr += String.fromCharCode((c & 31) << 6 | c2 & 63);
|
|
} else {
|
|
newStr += str.substr(i, 6);
|
|
}
|
|
i += 6;
|
|
} else if (c >= 224) {
|
|
if (il - i >= 9) {
|
|
var _c = parseInt(str.substr(i + 4, 2), 16);
|
|
var c3 = parseInt(str.substr(i + 7, 2), 16);
|
|
newStr += String.fromCharCode((c & 15) << 12 | (_c & 63) << 6 | c3 & 63);
|
|
} else {
|
|
newStr += str.substr(i, 9);
|
|
}
|
|
i += 9;
|
|
} else {
|
|
newStr += str.substr(i, 3);
|
|
i += 3;
|
|
}
|
|
}
|
|
return newStr;
|
|
}
|
|
function _normalizeComponentEncoding(components, protocol) {
|
|
function decodeUnreserved(str) {
|
|
var decStr = pctDecChars(str);
|
|
return !decStr.match(protocol.UNRESERVED) ? str : decStr;
|
|
}
|
|
if (components.scheme) components.scheme = String(components.scheme).replace(protocol.PCT_ENCODED, decodeUnreserved).toLowerCase().replace(protocol.NOT_SCHEME, "");
|
|
if (components.userinfo !== undefined) components.userinfo = String(components.userinfo).replace(protocol.PCT_ENCODED, decodeUnreserved).replace(protocol.NOT_USERINFO, pctEncChar).replace(protocol.PCT_ENCODED, toUpperCase);
|
|
if (components.host !== undefined) components.host = String(components.host).replace(protocol.PCT_ENCODED, decodeUnreserved).toLowerCase().replace(protocol.NOT_HOST, pctEncChar).replace(protocol.PCT_ENCODED, toUpperCase);
|
|
if (components.path !== undefined) components.path = String(components.path).replace(protocol.PCT_ENCODED, decodeUnreserved).replace(components.scheme ? protocol.NOT_PATH : protocol.NOT_PATH_NOSCHEME, pctEncChar).replace(protocol.PCT_ENCODED, toUpperCase);
|
|
if (components.query !== undefined) components.query = String(components.query).replace(protocol.PCT_ENCODED, decodeUnreserved).replace(protocol.NOT_QUERY, pctEncChar).replace(protocol.PCT_ENCODED, toUpperCase);
|
|
if (components.fragment !== undefined) components.fragment = String(components.fragment).replace(protocol.PCT_ENCODED, decodeUnreserved).replace(protocol.NOT_FRAGMENT, pctEncChar).replace(protocol.PCT_ENCODED, toUpperCase);
|
|
return components;
|
|
}
|
|
|
|
function _stripLeadingZeros(str) {
|
|
return str.replace(/^0*(.*)/, "$1") || "0";
|
|
}
|
|
function _normalizeIPv4(host, protocol) {
|
|
var matches = host.match(protocol.IPV4ADDRESS) || [];
|
|
|
|
var _matches = slicedToArray(matches, 2),
|
|
address = _matches[1];
|
|
|
|
if (address) {
|
|
return address.split(".").map(_stripLeadingZeros).join(".");
|
|
} else {
|
|
return host;
|
|
}
|
|
}
|
|
function _normalizeIPv6(host, protocol) {
|
|
var matches = host.match(protocol.IPV6ADDRESS) || [];
|
|
|
|
var _matches2 = slicedToArray(matches, 3),
|
|
address = _matches2[1],
|
|
zone = _matches2[2];
|
|
|
|
if (address) {
|
|
var _address$toLowerCase$ = address.toLowerCase().split('::').reverse(),
|
|
_address$toLowerCase$2 = slicedToArray(_address$toLowerCase$, 2),
|
|
last = _address$toLowerCase$2[0],
|
|
first = _address$toLowerCase$2[1];
|
|
|
|
var firstFields = first ? first.split(":").map(_stripLeadingZeros) : [];
|
|
var lastFields = last.split(":").map(_stripLeadingZeros);
|
|
var isLastFieldIPv4Address = protocol.IPV4ADDRESS.test(lastFields[lastFields.length - 1]);
|
|
var fieldCount = isLastFieldIPv4Address ? 7 : 8;
|
|
var lastFieldsStart = lastFields.length - fieldCount;
|
|
var fields = Array(fieldCount);
|
|
for (var x = 0; x < fieldCount; ++x) {
|
|
fields[x] = firstFields[x] || lastFields[lastFieldsStart + x] || '';
|
|
}
|
|
if (isLastFieldIPv4Address) {
|
|
fields[fieldCount - 1] = _normalizeIPv4(fields[fieldCount - 1], protocol);
|
|
}
|
|
var allZeroFields = fields.reduce(function (acc, field, index) {
|
|
if (!field || field === "0") {
|
|
var lastLongest = acc[acc.length - 1];
|
|
if (lastLongest && lastLongest.index + lastLongest.length === index) {
|
|
lastLongest.length++;
|
|
} else {
|
|
acc.push({ index: index, length: 1 });
|
|
}
|
|
}
|
|
return acc;
|
|
}, []);
|
|
var longestZeroFields = allZeroFields.sort(function (a, b) {
|
|
return b.length - a.length;
|
|
})[0];
|
|
var newHost = void 0;
|
|
if (longestZeroFields && longestZeroFields.length > 1) {
|
|
var newFirst = fields.slice(0, longestZeroFields.index);
|
|
var newLast = fields.slice(longestZeroFields.index + longestZeroFields.length);
|
|
newHost = newFirst.join(":") + "::" + newLast.join(":");
|
|
} else {
|
|
newHost = fields.join(":");
|
|
}
|
|
if (zone) {
|
|
newHost += "%" + zone;
|
|
}
|
|
return newHost;
|
|
} else {
|
|
return host;
|
|
}
|
|
}
|
|
var URI_PARSE = /^(?:([^:\/?#]+):)?(?:\/\/((?:([^\/?#@]*)@)?(\[[^\/?#\]]+\]|[^\/?#:]*)(?:\:(\d*))?))?([^?#]*)(?:\?([^#]*))?(?:#((?:.|\n|\r)*))?/i;
|
|
var NO_MATCH_IS_UNDEFINED = "".match(/(){0}/)[1] === undefined;
|
|
function parse(uriString) {
|
|
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
|
|
var components = {};
|
|
var protocol = options.iri !== false ? IRI_PROTOCOL : URI_PROTOCOL;
|
|
if (options.reference === "suffix") uriString = (options.scheme ? options.scheme + ":" : "") + "//" + uriString;
|
|
var matches = uriString.match(URI_PARSE);
|
|
if (matches) {
|
|
if (NO_MATCH_IS_UNDEFINED) {
|
|
//store each component
|
|
components.scheme = matches[1];
|
|
components.userinfo = matches[3];
|
|
components.host = matches[4];
|
|
components.port = parseInt(matches[5], 10);
|
|
components.path = matches[6] || "";
|
|
components.query = matches[7];
|
|
components.fragment = matches[8];
|
|
//fix port number
|
|
if (isNaN(components.port)) {
|
|
components.port = matches[5];
|
|
}
|
|
} else {
|
|
//IE FIX for improper RegExp matching
|
|
//store each component
|
|
components.scheme = matches[1] || undefined;
|
|
components.userinfo = uriString.indexOf("@") !== -1 ? matches[3] : undefined;
|
|
components.host = uriString.indexOf("//") !== -1 ? matches[4] : undefined;
|
|
components.port = parseInt(matches[5], 10);
|
|
components.path = matches[6] || "";
|
|
components.query = uriString.indexOf("?") !== -1 ? matches[7] : undefined;
|
|
components.fragment = uriString.indexOf("#") !== -1 ? matches[8] : undefined;
|
|
//fix port number
|
|
if (isNaN(components.port)) {
|
|
components.port = uriString.match(/\/\/(?:.|\n)*\:(?:\/|\?|\#|$)/) ? matches[4] : undefined;
|
|
}
|
|
}
|
|
if (components.host) {
|
|
//normalize IP hosts
|
|
components.host = _normalizeIPv6(_normalizeIPv4(components.host, protocol), protocol);
|
|
}
|
|
//determine reference type
|
|
if (components.scheme === undefined && components.userinfo === undefined && components.host === undefined && components.port === undefined && !components.path && components.query === undefined) {
|
|
components.reference = "same-document";
|
|
} else if (components.scheme === undefined) {
|
|
components.reference = "relative";
|
|
} else if (components.fragment === undefined) {
|
|
components.reference = "absolute";
|
|
} else {
|
|
components.reference = "uri";
|
|
}
|
|
//check for reference errors
|
|
if (options.reference && options.reference !== "suffix" && options.reference !== components.reference) {
|
|
components.error = components.error || "URI is not a " + options.reference + " reference.";
|
|
}
|
|
//find scheme handler
|
|
var schemeHandler = SCHEMES[(options.scheme || components.scheme || "").toLowerCase()];
|
|
//check if scheme can't handle IRIs
|
|
if (!options.unicodeSupport && (!schemeHandler || !schemeHandler.unicodeSupport)) {
|
|
//if host component is a domain name
|
|
if (components.host && (options.domainHost || schemeHandler && schemeHandler.domainHost)) {
|
|
//convert Unicode IDN -> ASCII IDN
|
|
try {
|
|
components.host = punycode.toASCII(components.host.replace(protocol.PCT_ENCODED, pctDecChars).toLowerCase());
|
|
} catch (e) {
|
|
components.error = components.error || "Host's domain name can not be converted to ASCII via punycode: " + e;
|
|
}
|
|
}
|
|
//convert IRI -> URI
|
|
_normalizeComponentEncoding(components, URI_PROTOCOL);
|
|
} else {
|
|
//normalize encodings
|
|
_normalizeComponentEncoding(components, protocol);
|
|
}
|
|
//perform scheme specific parsing
|
|
if (schemeHandler && schemeHandler.parse) {
|
|
schemeHandler.parse(components, options);
|
|
}
|
|
} else {
|
|
components.error = components.error || "URI can not be parsed.";
|
|
}
|
|
return components;
|
|
}
|
|
|
|
function _recomposeAuthority(components, options) {
|
|
var protocol = options.iri !== false ? IRI_PROTOCOL : URI_PROTOCOL;
|
|
var uriTokens = [];
|
|
if (components.userinfo !== undefined) {
|
|
uriTokens.push(components.userinfo);
|
|
uriTokens.push("@");
|
|
}
|
|
if (components.host !== undefined) {
|
|
//normalize IP hosts, add brackets and escape zone separator for IPv6
|
|
uriTokens.push(_normalizeIPv6(_normalizeIPv4(String(components.host), protocol), protocol).replace(protocol.IPV6ADDRESS, function (_, $1, $2) {
|
|
return "[" + $1 + ($2 ? "%25" + $2 : "") + "]";
|
|
}));
|
|
}
|
|
if (typeof components.port === "number" || typeof components.port === "string") {
|
|
uriTokens.push(":");
|
|
uriTokens.push(String(components.port));
|
|
}
|
|
return uriTokens.length ? uriTokens.join("") : undefined;
|
|
}
|
|
|
|
var RDS1 = /^\.\.?\//;
|
|
var RDS2 = /^\/\.(\/|$)/;
|
|
var RDS3 = /^\/\.\.(\/|$)/;
|
|
var RDS5 = /^\/?(?:.|\n)*?(?=\/|$)/;
|
|
function removeDotSegments(input) {
|
|
var output = [];
|
|
while (input.length) {
|
|
if (input.match(RDS1)) {
|
|
input = input.replace(RDS1, "");
|
|
} else if (input.match(RDS2)) {
|
|
input = input.replace(RDS2, "/");
|
|
} else if (input.match(RDS3)) {
|
|
input = input.replace(RDS3, "/");
|
|
output.pop();
|
|
} else if (input === "." || input === "..") {
|
|
input = "";
|
|
} else {
|
|
var im = input.match(RDS5);
|
|
if (im) {
|
|
var s = im[0];
|
|
input = input.slice(s.length);
|
|
output.push(s);
|
|
} else {
|
|
throw new Error("Unexpected dot segment condition");
|
|
}
|
|
}
|
|
}
|
|
return output.join("");
|
|
}
|
|
|
|
function serialize(components) {
|
|
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
|
|
var protocol = options.iri ? IRI_PROTOCOL : URI_PROTOCOL;
|
|
var uriTokens = [];
|
|
//find scheme handler
|
|
var schemeHandler = SCHEMES[(options.scheme || components.scheme || "").toLowerCase()];
|
|
//perform scheme specific serialization
|
|
if (schemeHandler && schemeHandler.serialize) schemeHandler.serialize(components, options);
|
|
if (components.host) {
|
|
//if host component is an IPv6 address
|
|
if (protocol.IPV6ADDRESS.test(components.host)) {}
|
|
//TODO: normalize IPv6 address as per RFC 5952
|
|
|
|
//if host component is a domain name
|
|
else if (options.domainHost || schemeHandler && schemeHandler.domainHost) {
|
|
//convert IDN via punycode
|
|
try {
|
|
components.host = !options.iri ? punycode.toASCII(components.host.replace(protocol.PCT_ENCODED, pctDecChars).toLowerCase()) : punycode.toUnicode(components.host);
|
|
} catch (e) {
|
|
components.error = components.error || "Host's domain name can not be converted to " + (!options.iri ? "ASCII" : "Unicode") + " via punycode: " + e;
|
|
}
|
|
}
|
|
}
|
|
//normalize encoding
|
|
_normalizeComponentEncoding(components, protocol);
|
|
if (options.reference !== "suffix" && components.scheme) {
|
|
uriTokens.push(components.scheme);
|
|
uriTokens.push(":");
|
|
}
|
|
var authority = _recomposeAuthority(components, options);
|
|
if (authority !== undefined) {
|
|
if (options.reference !== "suffix") {
|
|
uriTokens.push("//");
|
|
}
|
|
uriTokens.push(authority);
|
|
if (components.path && components.path.charAt(0) !== "/") {
|
|
uriTokens.push("/");
|
|
}
|
|
}
|
|
if (components.path !== undefined) {
|
|
var s = components.path;
|
|
if (!options.absolutePath && (!schemeHandler || !schemeHandler.absolutePath)) {
|
|
s = removeDotSegments(s);
|
|
}
|
|
if (authority === undefined) {
|
|
s = s.replace(/^\/\//, "/%2F"); //don't allow the path to start with "//"
|
|
}
|
|
uriTokens.push(s);
|
|
}
|
|
if (components.query !== undefined) {
|
|
uriTokens.push("?");
|
|
uriTokens.push(components.query);
|
|
}
|
|
if (components.fragment !== undefined) {
|
|
uriTokens.push("#");
|
|
uriTokens.push(components.fragment);
|
|
}
|
|
return uriTokens.join(""); //merge tokens into a string
|
|
}
|
|
|
|
function resolveComponents(base, relative) {
|
|
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
var skipNormalization = arguments[3];
|
|
|
|
var target = {};
|
|
if (!skipNormalization) {
|
|
base = parse(serialize(base, options), options); //normalize base components
|
|
relative = parse(serialize(relative, options), options); //normalize relative components
|
|
}
|
|
options = options || {};
|
|
if (!options.tolerant && relative.scheme) {
|
|
target.scheme = relative.scheme;
|
|
//target.authority = relative.authority;
|
|
target.userinfo = relative.userinfo;
|
|
target.host = relative.host;
|
|
target.port = relative.port;
|
|
target.path = removeDotSegments(relative.path || "");
|
|
target.query = relative.query;
|
|
} else {
|
|
if (relative.userinfo !== undefined || relative.host !== undefined || relative.port !== undefined) {
|
|
//target.authority = relative.authority;
|
|
target.userinfo = relative.userinfo;
|
|
target.host = relative.host;
|
|
target.port = relative.port;
|
|
target.path = removeDotSegments(relative.path || "");
|
|
target.query = relative.query;
|
|
} else {
|
|
if (!relative.path) {
|
|
target.path = base.path;
|
|
if (relative.query !== undefined) {
|
|
target.query = relative.query;
|
|
} else {
|
|
target.query = base.query;
|
|
}
|
|
} else {
|
|
if (relative.path.charAt(0) === "/") {
|
|
target.path = removeDotSegments(relative.path);
|
|
} else {
|
|
if ((base.userinfo !== undefined || base.host !== undefined || base.port !== undefined) && !base.path) {
|
|
target.path = "/" + relative.path;
|
|
} else if (!base.path) {
|
|
target.path = relative.path;
|
|
} else {
|
|
target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) + relative.path;
|
|
}
|
|
target.path = removeDotSegments(target.path);
|
|
}
|
|
target.query = relative.query;
|
|
}
|
|
//target.authority = base.authority;
|
|
target.userinfo = base.userinfo;
|
|
target.host = base.host;
|
|
target.port = base.port;
|
|
}
|
|
target.scheme = base.scheme;
|
|
}
|
|
target.fragment = relative.fragment;
|
|
return target;
|
|
}
|
|
|
|
function resolve(baseURI, relativeURI, options) {
|
|
var schemelessOptions = assign({ scheme: 'null' }, options);
|
|
return serialize(resolveComponents(parse(baseURI, schemelessOptions), parse(relativeURI, schemelessOptions), schemelessOptions, true), schemelessOptions);
|
|
}
|
|
|
|
function normalize(uri, options) {
|
|
if (typeof uri === "string") {
|
|
uri = serialize(parse(uri, options), options);
|
|
} else if (typeOf(uri) === "object") {
|
|
uri = parse(serialize(uri, options), options);
|
|
}
|
|
return uri;
|
|
}
|
|
|
|
function equal(uriA, uriB, options) {
|
|
if (typeof uriA === "string") {
|
|
uriA = serialize(parse(uriA, options), options);
|
|
} else if (typeOf(uriA) === "object") {
|
|
uriA = serialize(uriA, options);
|
|
}
|
|
if (typeof uriB === "string") {
|
|
uriB = serialize(parse(uriB, options), options);
|
|
} else if (typeOf(uriB) === "object") {
|
|
uriB = serialize(uriB, options);
|
|
}
|
|
return uriA === uriB;
|
|
}
|
|
|
|
function escapeComponent(str, options) {
|
|
return str && str.toString().replace(!options || !options.iri ? URI_PROTOCOL.ESCAPE : IRI_PROTOCOL.ESCAPE, pctEncChar);
|
|
}
|
|
|
|
function unescapeComponent(str, options) {
|
|
return str && str.toString().replace(!options || !options.iri ? URI_PROTOCOL.PCT_ENCODED : IRI_PROTOCOL.PCT_ENCODED, pctDecChars);
|
|
}
|
|
|
|
var handler = {
|
|
scheme: "http",
|
|
domainHost: true,
|
|
parse: function parse(components, options) {
|
|
//report missing host
|
|
if (!components.host) {
|
|
components.error = components.error || "HTTP URIs must have a host.";
|
|
}
|
|
return components;
|
|
},
|
|
serialize: function serialize(components, options) {
|
|
var secure = String(components.scheme).toLowerCase() === "https";
|
|
//normalize the default port
|
|
if (components.port === (secure ? 443 : 80) || components.port === "") {
|
|
components.port = undefined;
|
|
}
|
|
//normalize the empty path
|
|
if (!components.path) {
|
|
components.path = "/";
|
|
}
|
|
//NOTE: We do not parse query strings for HTTP URIs
|
|
//as WWW Form Url Encoded query strings are part of the HTML4+ spec,
|
|
//and not the HTTP spec.
|
|
return components;
|
|
}
|
|
};
|
|
|
|
var handler$1 = {
|
|
scheme: "https",
|
|
domainHost: handler.domainHost,
|
|
parse: handler.parse,
|
|
serialize: handler.serialize
|
|
};
|
|
|
|
function isSecure(wsComponents) {
|
|
return typeof wsComponents.secure === 'boolean' ? wsComponents.secure : String(wsComponents.scheme).toLowerCase() === "wss";
|
|
}
|
|
//RFC 6455
|
|
var handler$2 = {
|
|
scheme: "ws",
|
|
domainHost: true,
|
|
parse: function parse(components, options) {
|
|
var wsComponents = components;
|
|
//indicate if the secure flag is set
|
|
wsComponents.secure = isSecure(wsComponents);
|
|
//construct resouce name
|
|
wsComponents.resourceName = (wsComponents.path || '/') + (wsComponents.query ? '?' + wsComponents.query : '');
|
|
wsComponents.path = undefined;
|
|
wsComponents.query = undefined;
|
|
return wsComponents;
|
|
},
|
|
serialize: function serialize(wsComponents, options) {
|
|
//normalize the default port
|
|
if (wsComponents.port === (isSecure(wsComponents) ? 443 : 80) || wsComponents.port === "") {
|
|
wsComponents.port = undefined;
|
|
}
|
|
//ensure scheme matches secure flag
|
|
if (typeof wsComponents.secure === 'boolean') {
|
|
wsComponents.scheme = wsComponents.secure ? 'wss' : 'ws';
|
|
wsComponents.secure = undefined;
|
|
}
|
|
//reconstruct path from resource name
|
|
if (wsComponents.resourceName) {
|
|
var _wsComponents$resourc = wsComponents.resourceName.split('?'),
|
|
_wsComponents$resourc2 = slicedToArray(_wsComponents$resourc, 2),
|
|
path = _wsComponents$resourc2[0],
|
|
query = _wsComponents$resourc2[1];
|
|
|
|
wsComponents.path = path && path !== '/' ? path : undefined;
|
|
wsComponents.query = query;
|
|
wsComponents.resourceName = undefined;
|
|
}
|
|
//forbid fragment component
|
|
wsComponents.fragment = undefined;
|
|
return wsComponents;
|
|
}
|
|
};
|
|
|
|
var handler$3 = {
|
|
scheme: "wss",
|
|
domainHost: handler$2.domainHost,
|
|
parse: handler$2.parse,
|
|
serialize: handler$2.serialize
|
|
};
|
|
|
|
var O = {};
|
|
var isIRI = true;
|
|
//RFC 3986
|
|
var UNRESERVED$$ = "[A-Za-z0-9\\-\\.\\_\\~" + (isIRI ? "\\xA0-\\u200D\\u2010-\\u2029\\u202F-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF" : "") + "]";
|
|
var HEXDIG$$ = "[0-9A-Fa-f]"; //case-insensitive
|
|
var PCT_ENCODED$ = subexp(subexp("%[EFef]" + HEXDIG$$ + "%" + HEXDIG$$ + HEXDIG$$ + "%" + HEXDIG$$ + HEXDIG$$) + "|" + subexp("%[89A-Fa-f]" + HEXDIG$$ + "%" + HEXDIG$$ + HEXDIG$$) + "|" + subexp("%" + HEXDIG$$ + HEXDIG$$)); //expanded
|
|
//RFC 5322, except these symbols as per RFC 6068: @ : / ? # [ ] & ; =
|
|
//const ATEXT$$ = "[A-Za-z0-9\\!\\#\\$\\%\\&\\'\\*\\+\\-\\/\\=\\?\\^\\_\\`\\{\\|\\}\\~]";
|
|
//const WSP$$ = "[\\x20\\x09]";
|
|
//const OBS_QTEXT$$ = "[\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F\\x7F]"; //(%d1-8 / %d11-12 / %d14-31 / %d127)
|
|
//const QTEXT$$ = merge("[\\x21\\x23-\\x5B\\x5D-\\x7E]", OBS_QTEXT$$); //%d33 / %d35-91 / %d93-126 / obs-qtext
|
|
//const VCHAR$$ = "[\\x21-\\x7E]";
|
|
//const WSP$$ = "[\\x20\\x09]";
|
|
//const OBS_QP$ = subexp("\\\\" + merge("[\\x00\\x0D\\x0A]", OBS_QTEXT$$)); //%d0 / CR / LF / obs-qtext
|
|
//const FWS$ = subexp(subexp(WSP$$ + "*" + "\\x0D\\x0A") + "?" + WSP$$ + "+");
|
|
//const QUOTED_PAIR$ = subexp(subexp("\\\\" + subexp(VCHAR$$ + "|" + WSP$$)) + "|" + OBS_QP$);
|
|
//const QUOTED_STRING$ = subexp('\\"' + subexp(FWS$ + "?" + QCONTENT$) + "*" + FWS$ + "?" + '\\"');
|
|
var ATEXT$$ = "[A-Za-z0-9\\!\\$\\%\\'\\*\\+\\-\\^\\_\\`\\{\\|\\}\\~]";
|
|
var QTEXT$$ = "[\\!\\$\\%\\'\\(\\)\\*\\+\\,\\-\\.0-9\\<\\>A-Z\\x5E-\\x7E]";
|
|
var VCHAR$$ = merge(QTEXT$$, "[\\\"\\\\]");
|
|
var SOME_DELIMS$$ = "[\\!\\$\\'\\(\\)\\*\\+\\,\\;\\:\\@]";
|
|
var UNRESERVED = new RegExp(UNRESERVED$$, "g");
|
|
var PCT_ENCODED = new RegExp(PCT_ENCODED$, "g");
|
|
var NOT_LOCAL_PART = new RegExp(merge("[^]", ATEXT$$, "[\\.]", '[\\"]', VCHAR$$), "g");
|
|
var NOT_HFNAME = new RegExp(merge("[^]", UNRESERVED$$, SOME_DELIMS$$), "g");
|
|
var NOT_HFVALUE = NOT_HFNAME;
|
|
function decodeUnreserved(str) {
|
|
var decStr = pctDecChars(str);
|
|
return !decStr.match(UNRESERVED) ? str : decStr;
|
|
}
|
|
var handler$4 = {
|
|
scheme: "mailto",
|
|
parse: function parse$$1(components, options) {
|
|
var mailtoComponents = components;
|
|
var to = mailtoComponents.to = mailtoComponents.path ? mailtoComponents.path.split(",") : [];
|
|
mailtoComponents.path = undefined;
|
|
if (mailtoComponents.query) {
|
|
var unknownHeaders = false;
|
|
var headers = {};
|
|
var hfields = mailtoComponents.query.split("&");
|
|
for (var x = 0, xl = hfields.length; x < xl; ++x) {
|
|
var hfield = hfields[x].split("=");
|
|
switch (hfield[0]) {
|
|
case "to":
|
|
var toAddrs = hfield[1].split(",");
|
|
for (var _x = 0, _xl = toAddrs.length; _x < _xl; ++_x) {
|
|
to.push(toAddrs[_x]);
|
|
}
|
|
break;
|
|
case "subject":
|
|
mailtoComponents.subject = unescapeComponent(hfield[1], options);
|
|
break;
|
|
case "body":
|
|
mailtoComponents.body = unescapeComponent(hfield[1], options);
|
|
break;
|
|
default:
|
|
unknownHeaders = true;
|
|
headers[unescapeComponent(hfield[0], options)] = unescapeComponent(hfield[1], options);
|
|
break;
|
|
}
|
|
}
|
|
if (unknownHeaders) mailtoComponents.headers = headers;
|
|
}
|
|
mailtoComponents.query = undefined;
|
|
for (var _x2 = 0, _xl2 = to.length; _x2 < _xl2; ++_x2) {
|
|
var addr = to[_x2].split("@");
|
|
addr[0] = unescapeComponent(addr[0]);
|
|
if (!options.unicodeSupport) {
|
|
//convert Unicode IDN -> ASCII IDN
|
|
try {
|
|
addr[1] = punycode.toASCII(unescapeComponent(addr[1], options).toLowerCase());
|
|
} catch (e) {
|
|
mailtoComponents.error = mailtoComponents.error || "Email address's domain name can not be converted to ASCII via punycode: " + e;
|
|
}
|
|
} else {
|
|
addr[1] = unescapeComponent(addr[1], options).toLowerCase();
|
|
}
|
|
to[_x2] = addr.join("@");
|
|
}
|
|
return mailtoComponents;
|
|
},
|
|
serialize: function serialize$$1(mailtoComponents, options) {
|
|
var components = mailtoComponents;
|
|
var to = toArray(mailtoComponents.to);
|
|
if (to) {
|
|
for (var x = 0, xl = to.length; x < xl; ++x) {
|
|
var toAddr = String(to[x]);
|
|
var atIdx = toAddr.lastIndexOf("@");
|
|
var localPart = toAddr.slice(0, atIdx).replace(PCT_ENCODED, decodeUnreserved).replace(PCT_ENCODED, toUpperCase).replace(NOT_LOCAL_PART, pctEncChar);
|
|
var domain = toAddr.slice(atIdx + 1);
|
|
//convert IDN via punycode
|
|
try {
|
|
domain = !options.iri ? punycode.toASCII(unescapeComponent(domain, options).toLowerCase()) : punycode.toUnicode(domain);
|
|
} catch (e) {
|
|
components.error = components.error || "Email address's domain name can not be converted to " + (!options.iri ? "ASCII" : "Unicode") + " via punycode: " + e;
|
|
}
|
|
to[x] = localPart + "@" + domain;
|
|
}
|
|
components.path = to.join(",");
|
|
}
|
|
var headers = mailtoComponents.headers = mailtoComponents.headers || {};
|
|
if (mailtoComponents.subject) headers["subject"] = mailtoComponents.subject;
|
|
if (mailtoComponents.body) headers["body"] = mailtoComponents.body;
|
|
var fields = [];
|
|
for (var name in headers) {
|
|
if (headers[name] !== O[name]) {
|
|
fields.push(name.replace(PCT_ENCODED, decodeUnreserved).replace(PCT_ENCODED, toUpperCase).replace(NOT_HFNAME, pctEncChar) + "=" + headers[name].replace(PCT_ENCODED, decodeUnreserved).replace(PCT_ENCODED, toUpperCase).replace(NOT_HFVALUE, pctEncChar));
|
|
}
|
|
}
|
|
if (fields.length) {
|
|
components.query = fields.join("&");
|
|
}
|
|
return components;
|
|
}
|
|
};
|
|
|
|
var URN_PARSE = /^([^\:]+)\:(.*)/;
|
|
//RFC 2141
|
|
var handler$5 = {
|
|
scheme: "urn",
|
|
parse: function parse$$1(components, options) {
|
|
var matches = components.path && components.path.match(URN_PARSE);
|
|
var urnComponents = components;
|
|
if (matches) {
|
|
var scheme = options.scheme || urnComponents.scheme || "urn";
|
|
var nid = matches[1].toLowerCase();
|
|
var nss = matches[2];
|
|
var urnScheme = scheme + ":" + (options.nid || nid);
|
|
var schemeHandler = SCHEMES[urnScheme];
|
|
urnComponents.nid = nid;
|
|
urnComponents.nss = nss;
|
|
urnComponents.path = undefined;
|
|
if (schemeHandler) {
|
|
urnComponents = schemeHandler.parse(urnComponents, options);
|
|
}
|
|
} else {
|
|
urnComponents.error = urnComponents.error || "URN can not be parsed.";
|
|
}
|
|
return urnComponents;
|
|
},
|
|
serialize: function serialize$$1(urnComponents, options) {
|
|
var scheme = options.scheme || urnComponents.scheme || "urn";
|
|
var nid = urnComponents.nid;
|
|
var urnScheme = scheme + ":" + (options.nid || nid);
|
|
var schemeHandler = SCHEMES[urnScheme];
|
|
if (schemeHandler) {
|
|
urnComponents = schemeHandler.serialize(urnComponents, options);
|
|
}
|
|
var uriComponents = urnComponents;
|
|
var nss = urnComponents.nss;
|
|
uriComponents.path = (nid || options.nid) + ":" + nss;
|
|
return uriComponents;
|
|
}
|
|
};
|
|
|
|
var UUID = /^[0-9A-Fa-f]{8}(?:\-[0-9A-Fa-f]{4}){3}\-[0-9A-Fa-f]{12}$/;
|
|
//RFC 4122
|
|
var handler$6 = {
|
|
scheme: "urn:uuid",
|
|
parse: function parse(urnComponents, options) {
|
|
var uuidComponents = urnComponents;
|
|
uuidComponents.uuid = uuidComponents.nss;
|
|
uuidComponents.nss = undefined;
|
|
if (!options.tolerant && (!uuidComponents.uuid || !uuidComponents.uuid.match(UUID))) {
|
|
uuidComponents.error = uuidComponents.error || "UUID is not valid.";
|
|
}
|
|
return uuidComponents;
|
|
},
|
|
serialize: function serialize(uuidComponents, options) {
|
|
var urnComponents = uuidComponents;
|
|
//normalize UUID
|
|
urnComponents.nss = (uuidComponents.uuid || "").toLowerCase();
|
|
return urnComponents;
|
|
}
|
|
};
|
|
|
|
SCHEMES[handler.scheme] = handler;
|
|
SCHEMES[handler$1.scheme] = handler$1;
|
|
SCHEMES[handler$2.scheme] = handler$2;
|
|
SCHEMES[handler$3.scheme] = handler$3;
|
|
SCHEMES[handler$4.scheme] = handler$4;
|
|
SCHEMES[handler$5.scheme] = handler$5;
|
|
SCHEMES[handler$6.scheme] = handler$6;
|
|
|
|
exports.SCHEMES = SCHEMES;
|
|
exports.pctEncChar = pctEncChar;
|
|
exports.pctDecChars = pctDecChars;
|
|
exports.parse = parse;
|
|
exports.removeDotSegments = removeDotSegments;
|
|
exports.serialize = serialize;
|
|
exports.resolveComponents = resolveComponents;
|
|
exports.resolve = resolve;
|
|
exports.normalize = normalize;
|
|
exports.equal = equal;
|
|
exports.escapeComponent = escapeComponent;
|
|
exports.unescapeComponent = unescapeComponent;
|
|
|
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
|
})));
|
|
|
|
|
|
/***/ }),
|
|
|
|
/***/ 4049:
|
|
/***/ (function(module) {
|
|
|
|
/*!
|
|
* vanilla-picker v2.11.0
|
|
* https://vanilla-picker.js.org
|
|
*
|
|
* Copyright 2017-2020 Andreas Borgen (https://github.com/Sphinxxxx), Adam Brooks (https://github.com/dissimulate)
|
|
* Released under the ISC license.
|
|
*/
|
|
(function (global, factory) {
|
|
true ? module.exports = factory() :
|
|
0;
|
|
}(this, (function () { 'use strict';
|
|
|
|
var classCallCheck = function (instance, Constructor) {
|
|
if (!(instance instanceof Constructor)) {
|
|
throw new TypeError("Cannot call a class as a function");
|
|
}
|
|
};
|
|
|
|
var createClass = function () {
|
|
function defineProperties(target, props) {
|
|
for (var i = 0; i < props.length; i++) {
|
|
var descriptor = props[i];
|
|
descriptor.enumerable = descriptor.enumerable || false;
|
|
descriptor.configurable = true;
|
|
if ("value" in descriptor) descriptor.writable = true;
|
|
Object.defineProperty(target, descriptor.key, descriptor);
|
|
}
|
|
}
|
|
|
|
return function (Constructor, protoProps, staticProps) {
|
|
if (protoProps) defineProperties(Constructor.prototype, protoProps);
|
|
if (staticProps) defineProperties(Constructor, staticProps);
|
|
return Constructor;
|
|
};
|
|
}();
|
|
|
|
var slicedToArray = function () {
|
|
function sliceIterator(arr, i) {
|
|
var _arr = [];
|
|
var _n = true;
|
|
var _d = false;
|
|
var _e = undefined;
|
|
|
|
try {
|
|
for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
|
|
_arr.push(_s.value);
|
|
|
|
if (i && _arr.length === i) break;
|
|
}
|
|
} catch (err) {
|
|
_d = true;
|
|
_e = err;
|
|
} finally {
|
|
try {
|
|
if (!_n && _i["return"]) _i["return"]();
|
|
} finally {
|
|
if (_d) throw _e;
|
|
}
|
|
}
|
|
|
|
return _arr;
|
|
}
|
|
|
|
return function (arr, i) {
|
|
if (Array.isArray(arr)) {
|
|
return arr;
|
|
} else if (Symbol.iterator in Object(arr)) {
|
|
return sliceIterator(arr, i);
|
|
} else {
|
|
throw new TypeError("Invalid attempt to destructure non-iterable instance");
|
|
}
|
|
};
|
|
}();
|
|
|
|
String.prototype.startsWith = String.prototype.startsWith || function (needle) {
|
|
return this.indexOf(needle) === 0;
|
|
};
|
|
String.prototype.padStart = String.prototype.padStart || function (len, pad) {
|
|
var str = this;while (str.length < len) {
|
|
str = pad + str;
|
|
}return str;
|
|
};
|
|
|
|
var colorNames = { cb: '0f8ff', tqw: 'aebd7', q: '-ffff', qmrn: '7fffd4', zr: '0ffff', bg: '5f5dc', bsq: 'e4c4', bck: '---', nch: 'ebcd', b: '--ff', bvt: '8a2be2', brwn: 'a52a2a', brw: 'deb887', ctb: '5f9ea0', hrt: '7fff-', chcT: 'd2691e', cr: '7f50', rnw: '6495ed', crns: '8dc', crms: 'dc143c', cn: '-ffff', Db: '--8b', Dcn: '-8b8b', Dgnr: 'b8860b', Dgr: 'a9a9a9', Dgrn: '-64-', Dkhk: 'bdb76b', Dmgn: '8b-8b', Dvgr: '556b2f', Drng: '8c-', Drch: '9932cc', Dr: '8b--', Dsmn: 'e9967a', Dsgr: '8fbc8f', DsTb: '483d8b', DsTg: '2f4f4f', Dtrq: '-ced1', Dvt: '94-d3', ppnk: '1493', pskb: '-bfff', mgr: '696969', grb: '1e90ff', rbrc: 'b22222', rwht: 'af0', stg: '228b22', chs: '-ff', gnsb: 'dcdcdc', st: '8f8ff', g: 'd7-', gnr: 'daa520', gr: '808080', grn: '-8-0', grnw: 'adff2f', hnw: '0fff0', htpn: '69b4', nnr: 'cd5c5c', ng: '4b-82', vr: '0', khk: '0e68c', vnr: 'e6e6fa', nrb: '0f5', wngr: '7cfc-', mnch: 'acd', Lb: 'add8e6', Lcr: '08080', Lcn: 'e0ffff', Lgnr: 'afad2', Lgr: 'd3d3d3', Lgrn: '90ee90', Lpnk: 'b6c1', Lsmn: 'a07a', Lsgr: '20b2aa', Lskb: '87cefa', LsTg: '778899', Lstb: 'b0c4de', Lw: 'e0', m: '-ff-', mgrn: '32cd32', nn: 'af0e6', mgnt: '-ff', mrn: '8--0', mqm: '66cdaa', mmb: '--cd', mmrc: 'ba55d3', mmpr: '9370db', msg: '3cb371', mmsT: '7b68ee', '': '-fa9a', mtr: '48d1cc', mmvt: 'c71585', mnLb: '191970', ntc: '5fffa', mstr: 'e4e1', mccs: 'e4b5', vjw: 'dead', nv: '--80', c: 'df5e6', v: '808-0', vrb: '6b8e23', rng: 'a5-', rngr: '45-', rch: 'da70d6', pgnr: 'eee8aa', pgrn: '98fb98', ptrq: 'afeeee', pvtr: 'db7093', ppwh: 'efd5', pchp: 'dab9', pr: 'cd853f', pnk: 'c0cb', pm: 'dda0dd', pwrb: 'b0e0e6', prp: '8-080', cc: '663399', r: '--', sbr: 'bc8f8f', rb: '4169e1', sbrw: '8b4513', smn: 'a8072', nbr: '4a460', sgrn: '2e8b57', ssh: '5ee', snn: 'a0522d', svr: 'c0c0c0', skb: '87ceeb', sTb: '6a5acd', sTgr: '708090', snw: 'afa', n: '-ff7f', stb: '4682b4', tn: 'd2b48c', t: '-8080', thst: 'd8bfd8', tmT: '6347', trqs: '40e0d0', vt: 'ee82ee', whT: '5deb3', wht: '', hts: '5f5f5', w: '-', wgrn: '9acd32' };
|
|
|
|
function printNum(num) {
|
|
var decs = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
|
|
|
|
var str = decs > 0 ? num.toFixed(decs).replace(/0+$/, '').replace(/\.$/, '') : num.toString();
|
|
return str || '0';
|
|
}
|
|
|
|
var Color = function () {
|
|
function Color(r, g, b, a) {
|
|
classCallCheck(this, Color);
|
|
|
|
|
|
var that = this;
|
|
function parseString(input) {
|
|
|
|
if (input.startsWith('hsl')) {
|
|
var _input$match$map = input.match(/([\-\d\.e]+)/g).map(Number),
|
|
_input$match$map2 = slicedToArray(_input$match$map, 4),
|
|
h = _input$match$map2[0],
|
|
s = _input$match$map2[1],
|
|
l = _input$match$map2[2],
|
|
_a = _input$match$map2[3];
|
|
|
|
if (_a === undefined) {
|
|
_a = 1;
|
|
}
|
|
|
|
h /= 360;
|
|
s /= 100;
|
|
l /= 100;
|
|
that.hsla = [h, s, l, _a];
|
|
} else if (input.startsWith('rgb')) {
|
|
var _input$match$map3 = input.match(/([\-\d\.e]+)/g).map(Number),
|
|
_input$match$map4 = slicedToArray(_input$match$map3, 4),
|
|
_r = _input$match$map4[0],
|
|
_g = _input$match$map4[1],
|
|
_b = _input$match$map4[2],
|
|
_a2 = _input$match$map4[3];
|
|
|
|
if (_a2 === undefined) {
|
|
_a2 = 1;
|
|
}
|
|
|
|
that.rgba = [_r, _g, _b, _a2];
|
|
} else {
|
|
if (input.startsWith('#')) {
|
|
that.rgba = Color.hexToRgb(input);
|
|
} else {
|
|
that.rgba = Color.nameToRgb(input) || Color.hexToRgb(input);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (r === undefined) ; else if (Array.isArray(r)) {
|
|
this.rgba = r;
|
|
} else if (b === undefined) {
|
|
var color = r && '' + r;
|
|
if (color) {
|
|
parseString(color.toLowerCase());
|
|
}
|
|
} else {
|
|
this.rgba = [r, g, b, a === undefined ? 1 : a];
|
|
}
|
|
}
|
|
|
|
createClass(Color, [{
|
|
key: 'printRGB',
|
|
value: function printRGB(alpha) {
|
|
var rgb = alpha ? this.rgba : this.rgba.slice(0, 3),
|
|
vals = rgb.map(function (x, i) {
|
|
return printNum(x, i === 3 ? 3 : 0);
|
|
});
|
|
|
|
return alpha ? 'rgba(' + vals + ')' : 'rgb(' + vals + ')';
|
|
}
|
|
}, {
|
|
key: 'printHSL',
|
|
value: function printHSL(alpha) {
|
|
var mults = [360, 100, 100, 1],
|
|
suff = ['', '%', '%', ''];
|
|
|
|
var hsl = alpha ? this.hsla : this.hsla.slice(0, 3),
|
|
vals = hsl.map(function (x, i) {
|
|
return printNum(x * mults[i], i === 3 ? 3 : 1) + suff[i];
|
|
});
|
|
|
|
return alpha ? 'hsla(' + vals + ')' : 'hsl(' + vals + ')';
|
|
}
|
|
}, {
|
|
key: 'printHex',
|
|
value: function printHex(alpha) {
|
|
var hex = this.hex;
|
|
return alpha ? hex : hex.substring(0, 7);
|
|
}
|
|
}, {
|
|
key: 'rgba',
|
|
get: function get$$1() {
|
|
if (this._rgba) {
|
|
return this._rgba;
|
|
}
|
|
if (!this._hsla) {
|
|
throw new Error('No color is set');
|
|
}
|
|
|
|
return this._rgba = Color.hslToRgb(this._hsla);
|
|
},
|
|
set: function set$$1(rgb) {
|
|
if (rgb.length === 3) {
|
|
rgb[3] = 1;
|
|
}
|
|
|
|
this._rgba = rgb;
|
|
this._hsla = null;
|
|
}
|
|
}, {
|
|
key: 'rgbString',
|
|
get: function get$$1() {
|
|
return this.printRGB();
|
|
}
|
|
}, {
|
|
key: 'rgbaString',
|
|
get: function get$$1() {
|
|
return this.printRGB(true);
|
|
}
|
|
}, {
|
|
key: 'hsla',
|
|
get: function get$$1() {
|
|
if (this._hsla) {
|
|
return this._hsla;
|
|
}
|
|
if (!this._rgba) {
|
|
throw new Error('No color is set');
|
|
}
|
|
|
|
return this._hsla = Color.rgbToHsl(this._rgba);
|
|
},
|
|
set: function set$$1(hsl) {
|
|
if (hsl.length === 3) {
|
|
hsl[3] = 1;
|
|
}
|
|
|
|
this._hsla = hsl;
|
|
this._rgba = null;
|
|
}
|
|
}, {
|
|
key: 'hslString',
|
|
get: function get$$1() {
|
|
return this.printHSL();
|
|
}
|
|
}, {
|
|
key: 'hslaString',
|
|
get: function get$$1() {
|
|
return this.printHSL(true);
|
|
}
|
|
}, {
|
|
key: 'hex',
|
|
get: function get$$1() {
|
|
var rgb = this.rgba,
|
|
hex = rgb.map(function (x, i) {
|
|
return i < 3 ? x.toString(16) : Math.round(x * 255).toString(16);
|
|
});
|
|
|
|
return '#' + hex.map(function (x) {
|
|
return x.padStart(2, '0');
|
|
}).join('');
|
|
},
|
|
set: function set$$1(hex) {
|
|
this.rgba = Color.hexToRgb(hex);
|
|
}
|
|
}], [{
|
|
key: 'hexToRgb',
|
|
value: function hexToRgb(input) {
|
|
|
|
var hex = (input.startsWith('#') ? input.slice(1) : input).replace(/^(\w{3})$/, '$1F').replace(/^(\w)(\w)(\w)(\w)$/, '$1$1$2$2$3$3$4$4').replace(/^(\w{6})$/, '$1FF');
|
|
|
|
if (!hex.match(/^([0-9a-fA-F]{8})$/)) {
|
|
throw new Error('Unknown hex color; ' + input);
|
|
}
|
|
|
|
var rgba = hex.match(/^(\w\w)(\w\w)(\w\w)(\w\w)$/).slice(1).map(function (x) {
|
|
return parseInt(x, 16);
|
|
});
|
|
|
|
rgba[3] = rgba[3] / 255;
|
|
return rgba;
|
|
}
|
|
}, {
|
|
key: 'nameToRgb',
|
|
value: function nameToRgb(input) {
|
|
|
|
var hash = input.toLowerCase().replace('at', 'T').replace(/[aeiouyldf]/g, '').replace('ght', 'L').replace('rk', 'D').slice(-5, 4),
|
|
hex = colorNames[hash];
|
|
return hex === undefined ? hex : Color.hexToRgb(hex.replace(/\-/g, '00').padStart(6, 'f'));
|
|
}
|
|
}, {
|
|
key: 'rgbToHsl',
|
|
value: function rgbToHsl(_ref) {
|
|
var _ref2 = slicedToArray(_ref, 4),
|
|
r = _ref2[0],
|
|
g = _ref2[1],
|
|
b = _ref2[2],
|
|
a = _ref2[3];
|
|
|
|
r /= 255;
|
|
g /= 255;
|
|
b /= 255;
|
|
|
|
var max = Math.max(r, g, b),
|
|
min = Math.min(r, g, b);
|
|
var h = void 0,
|
|
s = void 0,
|
|
l = (max + min) / 2;
|
|
|
|
if (max === min) {
|
|
h = s = 0;
|
|
} else {
|
|
var d = max - min;
|
|
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
|
switch (max) {
|
|
case r:
|
|
h = (g - b) / d + (g < b ? 6 : 0);break;
|
|
case g:
|
|
h = (b - r) / d + 2;break;
|
|
case b:
|
|
h = (r - g) / d + 4;break;
|
|
}
|
|
|
|
h /= 6;
|
|
}
|
|
|
|
return [h, s, l, a];
|
|
}
|
|
}, {
|
|
key: 'hslToRgb',
|
|
value: function hslToRgb(_ref3) {
|
|
var _ref4 = slicedToArray(_ref3, 4),
|
|
h = _ref4[0],
|
|
s = _ref4[1],
|
|
l = _ref4[2],
|
|
a = _ref4[3];
|
|
|
|
var r = void 0,
|
|
g = void 0,
|
|
b = void 0;
|
|
|
|
if (s === 0) {
|
|
r = g = b = l;
|
|
} else {
|
|
var hue2rgb = function hue2rgb(p, q, t) {
|
|
if (t < 0) t += 1;
|
|
if (t > 1) t -= 1;
|
|
if (t < 1 / 6) return p + (q - p) * 6 * t;
|
|
if (t < 1 / 2) return q;
|
|
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
|
|
return p;
|
|
};
|
|
|
|
var q = l < 0.5 ? l * (1 + s) : l + s - l * s,
|
|
p = 2 * l - q;
|
|
|
|
r = hue2rgb(p, q, h + 1 / 3);
|
|
g = hue2rgb(p, q, h);
|
|
b = hue2rgb(p, q, h - 1 / 3);
|
|
}
|
|
|
|
var rgba = [r * 255, g * 255, b * 255].map(Math.round);
|
|
rgba[3] = a;
|
|
|
|
return rgba;
|
|
}
|
|
}]);
|
|
return Color;
|
|
}();
|
|
|
|
var EventBucket = function () {
|
|
function EventBucket() {
|
|
classCallCheck(this, EventBucket);
|
|
|
|
this._events = [];
|
|
}
|
|
|
|
createClass(EventBucket, [{
|
|
key: 'add',
|
|
value: function add(target, type, handler) {
|
|
target.addEventListener(type, handler, false);
|
|
this._events.push({
|
|
target: target,
|
|
type: type,
|
|
handler: handler
|
|
});
|
|
}
|
|
}, {
|
|
key: 'remove',
|
|
value: function remove(target, type, handler) {
|
|
this._events = this._events.filter(function (e) {
|
|
var isMatch = true;
|
|
if (target && target !== e.target) {
|
|
isMatch = false;
|
|
}
|
|
if (type && type !== e.type) {
|
|
isMatch = false;
|
|
}
|
|
if (handler && handler !== e.handler) {
|
|
isMatch = false;
|
|
}
|
|
|
|
if (isMatch) {
|
|
EventBucket._doRemove(e.target, e.type, e.handler);
|
|
}
|
|
return !isMatch;
|
|
});
|
|
}
|
|
}, {
|
|
key: 'destroy',
|
|
value: function destroy() {
|
|
this._events.forEach(function (e) {
|
|
return EventBucket._doRemove(e.target, e.type, e.handler);
|
|
});
|
|
this._events = [];
|
|
}
|
|
}], [{
|
|
key: '_doRemove',
|
|
value: function _doRemove(target, type, handler) {
|
|
target.removeEventListener(type, handler, false);
|
|
}
|
|
}]);
|
|
return EventBucket;
|
|
}();
|
|
|
|
function parseHTML(htmlString) {
|
|
|
|
var div = document.createElement('div');
|
|
div.innerHTML = htmlString;
|
|
return div.firstElementChild;
|
|
}
|
|
|
|
function dragTrack(eventBucket, area, callback) {
|
|
var dragging = false;
|
|
|
|
function clamp(val, min, max) {
|
|
return Math.max(min, Math.min(val, max));
|
|
}
|
|
|
|
function onMove(e, info, starting) {
|
|
if (starting) {
|
|
dragging = true;
|
|
}
|
|
if (!dragging) {
|
|
return;
|
|
}
|
|
|
|
e.preventDefault();
|
|
|
|
var bounds = area.getBoundingClientRect(),
|
|
w = bounds.width,
|
|
h = bounds.height,
|
|
x = info.clientX,
|
|
y = info.clientY;
|
|
|
|
var relX = clamp(x - bounds.left, 0, w),
|
|
relY = clamp(y - bounds.top, 0, h);
|
|
|
|
callback(relX / w, relY / h);
|
|
}
|
|
|
|
function onMouse(e, starting) {
|
|
var button = e.buttons === undefined ? e.which : e.buttons;
|
|
if (button === 1) {
|
|
onMove(e, e, starting);
|
|
} else {
|
|
dragging = false;
|
|
}
|
|
}
|
|
|
|
function onTouch(e, starting) {
|
|
if (e.touches.length === 1) {
|
|
onMove(e, e.touches[0], starting);
|
|
} else {
|
|
dragging = false;
|
|
}
|
|
}
|
|
|
|
eventBucket.add(area, 'mousedown', function (e) {
|
|
onMouse(e, true);
|
|
});
|
|
eventBucket.add(area, 'touchstart', function (e) {
|
|
onTouch(e, true);
|
|
});
|
|
eventBucket.add(window, 'mousemove', onMouse);
|
|
eventBucket.add(area, 'touchmove', onTouch);
|
|
eventBucket.add(window, 'mouseup', function (e) {
|
|
dragging = false;
|
|
});
|
|
eventBucket.add(area, 'touchend', function (e) {
|
|
dragging = false;
|
|
});
|
|
eventBucket.add(area, 'touchcancel', function (e) {
|
|
dragging = false;
|
|
});
|
|
}
|
|
|
|
var BG_TRANSP = 'url("data:image/svg+xml,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' width=\'2\' height=\'2\'%3E%3Cpath d=\'M1,0H0V1H2V2H1\' fill=\'lightgrey\'/%3E%3C/svg%3E")';
|
|
var HUES = 360;
|
|
|
|
var EVENT_KEY = 'keydown',
|
|
EVENT_CLICK_OUTSIDE = 'mousedown',
|
|
EVENT_TAB_MOVE = 'focusin';
|
|
|
|
function $(selector, context) {
|
|
return (context || document).querySelector(selector);
|
|
}
|
|
|
|
function stopEvent(e) {
|
|
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
}
|
|
function onKey(bucket, target, keys, handler, stop) {
|
|
bucket.add(target, EVENT_KEY, function (e) {
|
|
if (keys.indexOf(e.key) >= 0) {
|
|
if (stop) {
|
|
stopEvent(e);
|
|
}
|
|
handler(e);
|
|
}
|
|
});
|
|
}
|
|
|
|
var _style = document.createElement('style');
|
|
_style.textContent = '.picker_wrapper.no_alpha .picker_alpha{display:none}.picker_wrapper.no_editor .picker_editor{position:absolute;z-index:-1;opacity:0}.picker_wrapper.no_cancel .picker_cancel{display:none}.layout_default.picker_wrapper{display:-webkit-box;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;flex-flow:row wrap;-webkit-box-pack:justify;justify-content:space-between;-webkit-box-align:stretch;align-items:stretch;font-size:10px;width:25em;padding:.5em}.layout_default.picker_wrapper input,.layout_default.picker_wrapper button{font-size:1rem}.layout_default.picker_wrapper>*{margin:.5em}.layout_default.picker_wrapper::before{content:\'\';display:block;width:100%;height:0;-webkit-box-ordinal-group:2;order:1}.layout_default .picker_slider,.layout_default .picker_selector{padding:1em}.layout_default .picker_hue{width:100%}.layout_default .picker_sl{-webkit-box-flex:1;flex:1 1 auto}.layout_default .picker_sl::before{content:\'\';display:block;padding-bottom:100%}.layout_default .picker_editor{-webkit-box-ordinal-group:2;order:1;width:6.5rem}.layout_default .picker_editor input{width:100%;height:100%}.layout_default .picker_sample{-webkit-box-ordinal-group:2;order:1;-webkit-box-flex:1;flex:1 1 auto}.layout_default .picker_done,.layout_default .picker_cancel{-webkit-box-ordinal-group:2;order:1}.picker_wrapper{box-sizing:border-box;background:#f2f2f2;box-shadow:0 0 0 1px silver;cursor:default;font-family:sans-serif;color:#444;pointer-events:auto}.picker_wrapper:focus{outline:none}.picker_wrapper button,.picker_wrapper input{box-sizing:border-box;border:none;box-shadow:0 0 0 1px silver;outline:none}.picker_wrapper button:focus,.picker_wrapper button:active,.picker_wrapper input:focus,.picker_wrapper input:active{box-shadow:0 0 2px 1px dodgerblue}.picker_wrapper button{padding:.4em .6em;cursor:pointer;background-color:whitesmoke;background-image:-webkit-gradient(linear, left bottom, left top, from(gainsboro), to(transparent));background-image:linear-gradient(0deg, gainsboro, transparent)}.picker_wrapper button:active{background-image:-webkit-gradient(linear, left bottom, left top, from(transparent), to(gainsboro));background-image:linear-gradient(0deg, transparent, gainsboro)}.picker_wrapper button:hover{background-color:white}.picker_selector{position:absolute;z-index:1;display:block;-webkit-transform:translate(-50%, -50%);transform:translate(-50%, -50%);border:2px solid white;border-radius:100%;box-shadow:0 0 3px 1px #67b9ff;background:currentColor;cursor:pointer}.picker_slider .picker_selector{border-radius:2px}.picker_hue{position:relative;background-image:-webkit-gradient(linear, left top, right top, from(red), color-stop(yellow), color-stop(lime), color-stop(cyan), color-stop(blue), color-stop(magenta), to(red));background-image:linear-gradient(90deg, red, yellow, lime, cyan, blue, magenta, red);box-shadow:0 0 0 1px silver}.picker_sl{position:relative;box-shadow:0 0 0 1px silver;background-image:-webkit-gradient(linear, left top, left bottom, from(white), color-stop(50%, rgba(255,255,255,0))),-webkit-gradient(linear, left bottom, left top, from(black), color-stop(50%, rgba(0,0,0,0))),-webkit-gradient(linear, left top, right top, from(gray), to(rgba(128,128,128,0)));background-image:linear-gradient(180deg, white, rgba(255,255,255,0) 50%),linear-gradient(0deg, black, rgba(0,0,0,0) 50%),linear-gradient(90deg, gray, rgba(128,128,128,0))}.picker_alpha,.picker_sample{position:relative;background:url("data:image/svg+xml,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' width=\'2\' height=\'2\'%3E%3Cpath d=\'M1,0H0V1H2V2H1\' fill=\'lightgrey\'/%3E%3C/svg%3E") left top/contain white;box-shadow:0 0 0 1px silver}.picker_alpha .picker_selector,.picker_sample .picker_selector{background:none}.picker_editor input{font-family:monospace;padding:.2em .4em}.picker_sample::before{content:\'\';position:absolute;display:block;width:100%;height:100%;background:currentColor}.picker_arrow{position:absolute;z-index:-1}.picker_wrapper.popup{position:absolute;z-index:2;margin:1.5em}.picker_wrapper.popup,.picker_wrapper.popup .picker_arrow::before,.picker_wrapper.popup .picker_arrow::after{background:#f2f2f2;box-shadow:0 0 10px 1px rgba(0,0,0,0.4)}.picker_wrapper.popup .picker_arrow{width:3em;height:3em;margin:0}.picker_wrapper.popup .picker_arrow::before,.picker_wrapper.popup .picker_arrow::after{content:"";display:block;position:absolute;top:0;left:0;z-index:-99}.picker_wrapper.popup .picker_arrow::before{width:100%;height:100%;-webkit-transform:skew(45deg);transform:skew(45deg);-webkit-transform-origin:0 100%;transform-origin:0 100%}.picker_wrapper.popup .picker_arrow::after{width:150%;height:150%;box-shadow:none}.popup.popup_top{bottom:100%;left:0}.popup.popup_top .picker_arrow{bottom:0;left:0;-webkit-transform:rotate(-90deg);transform:rotate(-90deg)}.popup.popup_bottom{top:100%;left:0}.popup.popup_bottom .picker_arrow{top:0;left:0;-webkit-transform:rotate(90deg) scale(1, -1);transform:rotate(90deg) scale(1, -1)}.popup.popup_left{top:0;right:100%}.popup.popup_left .picker_arrow{top:0;right:0;-webkit-transform:scale(-1, 1);transform:scale(-1, 1)}.popup.popup_right{top:0;left:100%}.popup.popup_right .picker_arrow{top:0;left:0}';
|
|
document.documentElement.firstElementChild.appendChild(_style);
|
|
|
|
var Picker = function () {
|
|
function Picker(options) {
|
|
classCallCheck(this, Picker);
|
|
|
|
|
|
this.settings = {
|
|
|
|
popup: 'right',
|
|
layout: 'default',
|
|
alpha: true,
|
|
editor: true,
|
|
editorFormat: 'hex',
|
|
cancelButton: false,
|
|
defaultColor: '#0cf'
|
|
};
|
|
|
|
this._events = new EventBucket();
|
|
|
|
this.onChange = null;
|
|
|
|
this.onDone = null;
|
|
|
|
this.onOpen = null;
|
|
|
|
this.onClose = null;
|
|
|
|
this.setOptions(options);
|
|
}
|
|
|
|
createClass(Picker, [{
|
|
key: 'setOptions',
|
|
value: function setOptions(options) {
|
|
var _this = this;
|
|
|
|
if (!options) {
|
|
return;
|
|
}
|
|
var settings = this.settings;
|
|
|
|
function transfer(source, target, skipKeys) {
|
|
for (var key in source) {
|
|
if (skipKeys && skipKeys.indexOf(key) >= 0) {
|
|
continue;
|
|
}
|
|
|
|
target[key] = source[key];
|
|
}
|
|
}
|
|
|
|
if (options instanceof HTMLElement) {
|
|
settings.parent = options;
|
|
} else {
|
|
|
|
if (settings.parent && options.parent && settings.parent !== options.parent) {
|
|
this._events.remove(settings.parent);
|
|
this._popupInited = false;
|
|
}
|
|
|
|
transfer(options, settings);
|
|
|
|
if (options.onChange) {
|
|
this.onChange = options.onChange;
|
|
}
|
|
if (options.onDone) {
|
|
this.onDone = options.onDone;
|
|
}
|
|
if (options.onOpen) {
|
|
this.onOpen = options.onOpen;
|
|
}
|
|
if (options.onClose) {
|
|
this.onClose = options.onClose;
|
|
}
|
|
|
|
var col = options.color || options.colour;
|
|
if (col) {
|
|
this._setColor(col);
|
|
}
|
|
}
|
|
|
|
var parent = settings.parent;
|
|
if (parent && settings.popup && !this._popupInited) {
|
|
|
|
var openProxy = function openProxy(e) {
|
|
return _this.openHandler(e);
|
|
};
|
|
|
|
this._events.add(parent, 'click', openProxy);
|
|
|
|
onKey(this._events, parent, [' ', 'Spacebar', 'Enter'], openProxy);
|
|
|
|
this._popupInited = true;
|
|
} else if (options.parent && !settings.popup) {
|
|
this.show();
|
|
}
|
|
}
|
|
}, {
|
|
key: 'openHandler',
|
|
value: function openHandler(e) {
|
|
if (this.show()) {
|
|
|
|
e && e.preventDefault();
|
|
|
|
this.settings.parent.style.pointerEvents = 'none';
|
|
|
|
var toFocus = e && e.type === EVENT_KEY ? this._domEdit : this.domElement;
|
|
setTimeout(function () {
|
|
return toFocus.focus();
|
|
}, 100);
|
|
|
|
if (this.onOpen) {
|
|
this.onOpen(this.colour);
|
|
}
|
|
}
|
|
}
|
|
}, {
|
|
key: 'closeHandler',
|
|
value: function closeHandler(e) {
|
|
var event = e && e.type;
|
|
var doHide = false;
|
|
|
|
if (!e) {
|
|
doHide = true;
|
|
} else if (event === EVENT_CLICK_OUTSIDE || event === EVENT_TAB_MOVE) {
|
|
|
|
var knownTime = (this.__containedEvent || 0) + 100;
|
|
if (e.timeStamp > knownTime) {
|
|
doHide = true;
|
|
}
|
|
} else {
|
|
|
|
stopEvent(e);
|
|
|
|
doHide = true;
|
|
}
|
|
|
|
if (doHide && this.hide()) {
|
|
this.settings.parent.style.pointerEvents = '';
|
|
|
|
if (event !== EVENT_CLICK_OUTSIDE) {
|
|
this.settings.parent.focus();
|
|
}
|
|
|
|
if (this.onClose) {
|
|
this.onClose(this.colour);
|
|
}
|
|
}
|
|
}
|
|
}, {
|
|
key: 'movePopup',
|
|
value: function movePopup(options, open) {
|
|
|
|
this.closeHandler();
|
|
|
|
this.setOptions(options);
|
|
if (open) {
|
|
this.openHandler();
|
|
}
|
|
}
|
|
}, {
|
|
key: 'setColor',
|
|
value: function setColor(color, silent) {
|
|
this._setColor(color, { silent: silent });
|
|
}
|
|
}, {
|
|
key: '_setColor',
|
|
value: function _setColor(color, flags) {
|
|
if (typeof color === 'string') {
|
|
color = color.trim();
|
|
}
|
|
if (!color) {
|
|
return;
|
|
}
|
|
|
|
flags = flags || {};
|
|
var c = void 0;
|
|
try {
|
|
|
|
c = new Color(color);
|
|
} catch (ex) {
|
|
if (flags.failSilently) {
|
|
return;
|
|
}
|
|
throw ex;
|
|
}
|
|
|
|
if (!this.settings.alpha) {
|
|
var hsla = c.hsla;
|
|
hsla[3] = 1;
|
|
c.hsla = hsla;
|
|
}
|
|
this.colour = this.color = c;
|
|
this._setHSLA(null, null, null, null, flags);
|
|
}
|
|
}, {
|
|
key: 'setColour',
|
|
value: function setColour(colour, silent) {
|
|
this.setColor(colour, silent);
|
|
}
|
|
}, {
|
|
key: 'show',
|
|
value: function show() {
|
|
var parent = this.settings.parent;
|
|
if (!parent) {
|
|
return false;
|
|
}
|
|
|
|
if (this.domElement) {
|
|
var toggled = this._toggleDOM(true);
|
|
|
|
this._setPosition();
|
|
|
|
return toggled;
|
|
}
|
|
|
|
var html = this.settings.template || '<div class="picker_wrapper" tabindex="-1"><div class="picker_arrow"></div><div class="picker_hue picker_slider"><div class="picker_selector"></div></div><div class="picker_sl"><div class="picker_selector"></div></div><div class="picker_alpha picker_slider"><div class="picker_selector"></div></div><div class="picker_editor"><input aria-label="Type a color name or hex value"/></div><div class="picker_sample"></div><div class="picker_done"><button>Ok</button></div><div class="picker_cancel"><button>Cancel</button></div></div>';
|
|
var wrapper = parseHTML(html);
|
|
|
|
this.domElement = wrapper;
|
|
this._domH = $('.picker_hue', wrapper);
|
|
this._domSL = $('.picker_sl', wrapper);
|
|
this._domA = $('.picker_alpha', wrapper);
|
|
this._domEdit = $('.picker_editor input', wrapper);
|
|
this._domSample = $('.picker_sample', wrapper);
|
|
this._domOkay = $('.picker_done button', wrapper);
|
|
this._domCancel = $('.picker_cancel button', wrapper);
|
|
|
|
wrapper.classList.add('layout_' + this.settings.layout);
|
|
if (!this.settings.alpha) {
|
|
wrapper.classList.add('no_alpha');
|
|
}
|
|
if (!this.settings.editor) {
|
|
wrapper.classList.add('no_editor');
|
|
}
|
|
if (!this.settings.cancelButton) {
|
|
wrapper.classList.add('no_cancel');
|
|
}
|
|
this._ifPopup(function () {
|
|
return wrapper.classList.add('popup');
|
|
});
|
|
|
|
this._setPosition();
|
|
|
|
if (this.colour) {
|
|
this._updateUI();
|
|
} else {
|
|
this._setColor(this.settings.defaultColor);
|
|
}
|
|
this._bindEvents();
|
|
|
|
return true;
|
|
}
|
|
}, {
|
|
key: 'hide',
|
|
value: function hide() {
|
|
return this._toggleDOM(false);
|
|
}
|
|
}, {
|
|
key: 'destroy',
|
|
value: function destroy() {
|
|
this._events.destroy();
|
|
if (this.domElement) {
|
|
this.settings.parent.removeChild(this.domElement);
|
|
}
|
|
}
|
|
}, {
|
|
key: '_bindEvents',
|
|
value: function _bindEvents() {
|
|
var _this2 = this;
|
|
|
|
var that = this,
|
|
dom = this.domElement,
|
|
events = this._events;
|
|
|
|
function addEvent(target, type, handler) {
|
|
events.add(target, type, handler);
|
|
}
|
|
|
|
addEvent(dom, 'click', function (e) {
|
|
return e.preventDefault();
|
|
});
|
|
|
|
dragTrack(events, this._domH, function (x, y) {
|
|
return that._setHSLA(x);
|
|
});
|
|
|
|
dragTrack(events, this._domSL, function (x, y) {
|
|
return that._setHSLA(null, x, 1 - y);
|
|
});
|
|
|
|
if (this.settings.alpha) {
|
|
dragTrack(events, this._domA, function (x, y) {
|
|
return that._setHSLA(null, null, null, 1 - y);
|
|
});
|
|
}
|
|
|
|
var editInput = this._domEdit;
|
|
{
|
|
addEvent(editInput, 'input', function (e) {
|
|
that._setColor(this.value, { fromEditor: true, failSilently: true });
|
|
});
|
|
|
|
addEvent(editInput, 'focus', function (e) {
|
|
var input = this;
|
|
|
|
if (input.selectionStart === input.selectionEnd) {
|
|
input.select();
|
|
}
|
|
});
|
|
}
|
|
|
|
this._ifPopup(function () {
|
|
|
|
var popupCloseProxy = function popupCloseProxy(e) {
|
|
return _this2.closeHandler(e);
|
|
};
|
|
|
|
addEvent(window, EVENT_CLICK_OUTSIDE, popupCloseProxy);
|
|
addEvent(window, EVENT_TAB_MOVE, popupCloseProxy);
|
|
onKey(events, dom, ['Esc', 'Escape'], popupCloseProxy);
|
|
|
|
var timeKeeper = function timeKeeper(e) {
|
|
_this2.__containedEvent = e.timeStamp;
|
|
};
|
|
addEvent(dom, EVENT_CLICK_OUTSIDE, timeKeeper);
|
|
|
|
addEvent(dom, EVENT_TAB_MOVE, timeKeeper);
|
|
|
|
addEvent(_this2._domCancel, 'click', popupCloseProxy);
|
|
});
|
|
|
|
var onDoneProxy = function onDoneProxy(e) {
|
|
_this2._ifPopup(function () {
|
|
return _this2.closeHandler(e);
|
|
});
|
|
if (_this2.onDone) {
|
|
_this2.onDone(_this2.colour);
|
|
}
|
|
};
|
|
addEvent(this._domOkay, 'click', onDoneProxy);
|
|
onKey(events, dom, ['Enter'], onDoneProxy);
|
|
}
|
|
}, {
|
|
key: '_setPosition',
|
|
value: function _setPosition() {
|
|
var parent = this.settings.parent,
|
|
elm = this.domElement;
|
|
|
|
if (parent !== elm.parentNode) {
|
|
parent.appendChild(elm);
|
|
}
|
|
|
|
this._ifPopup(function (popup) {
|
|
|
|
if (getComputedStyle(parent).position === 'static') {
|
|
parent.style.position = 'relative';
|
|
}
|
|
|
|
var cssClass = popup === true ? 'popup_right' : 'popup_' + popup;
|
|
|
|
['popup_top', 'popup_bottom', 'popup_left', 'popup_right'].forEach(function (c) {
|
|
|
|
if (c === cssClass) {
|
|
elm.classList.add(c);
|
|
} else {
|
|
elm.classList.remove(c);
|
|
}
|
|
});
|
|
|
|
elm.classList.add(cssClass);
|
|
});
|
|
}
|
|
}, {
|
|
key: '_setHSLA',
|
|
value: function _setHSLA(h, s, l, a, flags) {
|
|
flags = flags || {};
|
|
|
|
var col = this.colour,
|
|
hsla = col.hsla;
|
|
|
|
[h, s, l, a].forEach(function (x, i) {
|
|
if (x || x === 0) {
|
|
hsla[i] = x;
|
|
}
|
|
});
|
|
col.hsla = hsla;
|
|
|
|
this._updateUI(flags);
|
|
|
|
if (this.onChange && !flags.silent) {
|
|
this.onChange(col);
|
|
}
|
|
}
|
|
}, {
|
|
key: '_updateUI',
|
|
value: function _updateUI(flags) {
|
|
if (!this.domElement) {
|
|
return;
|
|
}
|
|
flags = flags || {};
|
|
|
|
var col = this.colour,
|
|
hsl = col.hsla,
|
|
cssHue = 'hsl(' + hsl[0] * HUES + ', 100%, 50%)',
|
|
cssHSL = col.hslString,
|
|
cssHSLA = col.hslaString;
|
|
|
|
var uiH = this._domH,
|
|
uiSL = this._domSL,
|
|
uiA = this._domA,
|
|
thumbH = $('.picker_selector', uiH),
|
|
thumbSL = $('.picker_selector', uiSL),
|
|
thumbA = $('.picker_selector', uiA);
|
|
|
|
function posX(parent, child, relX) {
|
|
child.style.left = relX * 100 + '%';
|
|
}
|
|
function posY(parent, child, relY) {
|
|
child.style.top = relY * 100 + '%';
|
|
}
|
|
|
|
posX(uiH, thumbH, hsl[0]);
|
|
|
|
this._domSL.style.backgroundColor = this._domH.style.color = cssHue;
|
|
|
|
posX(uiSL, thumbSL, hsl[1]);
|
|
posY(uiSL, thumbSL, 1 - hsl[2]);
|
|
|
|
uiSL.style.color = cssHSL;
|
|
|
|
posY(uiA, thumbA, 1 - hsl[3]);
|
|
|
|
var opaque = cssHSL,
|
|
transp = opaque.replace('hsl', 'hsla').replace(')', ', 0)'),
|
|
bg = 'linear-gradient(' + [opaque, transp] + ')';
|
|
|
|
this._domA.style.backgroundImage = bg + ', ' + BG_TRANSP;
|
|
|
|
if (!flags.fromEditor) {
|
|
var format = this.settings.editorFormat,
|
|
alpha = this.settings.alpha;
|
|
|
|
var value = void 0;
|
|
switch (format) {
|
|
case 'rgb':
|
|
value = col.printRGB(alpha);break;
|
|
case 'hsl':
|
|
value = col.printHSL(alpha);break;
|
|
default:
|
|
value = col.printHex(alpha);
|
|
}
|
|
this._domEdit.value = value;
|
|
}
|
|
|
|
this._domSample.style.color = cssHSLA;
|
|
}
|
|
}, {
|
|
key: '_ifPopup',
|
|
value: function _ifPopup(actionIf, actionElse) {
|
|
if (this.settings.parent && this.settings.popup) {
|
|
actionIf && actionIf(this.settings.popup);
|
|
} else {
|
|
actionElse && actionElse();
|
|
}
|
|
}
|
|
}, {
|
|
key: '_toggleDOM',
|
|
value: function _toggleDOM(toVisible) {
|
|
var dom = this.domElement;
|
|
if (!dom) {
|
|
return false;
|
|
}
|
|
|
|
var displayStyle = toVisible ? '' : 'none',
|
|
toggle = dom.style.display !== displayStyle;
|
|
|
|
if (toggle) {
|
|
dom.style.display = displayStyle;
|
|
}
|
|
return toggle;
|
|
}
|
|
}], [{
|
|
key: 'StyleElement',
|
|
get: function get$$1() {
|
|
return _style;
|
|
}
|
|
}]);
|
|
return Picker;
|
|
}();
|
|
|
|
return Picker;
|
|
|
|
})));
|
|
|
|
|
|
/***/ })
|
|
|
|
/******/ });
|
|
/************************************************************************/
|
|
/******/ // The module cache
|
|
/******/ var __webpack_module_cache__ = {};
|
|
/******/
|
|
/******/ // The require function
|
|
/******/ function __webpack_require__(moduleId) {
|
|
/******/ // Check if module is in cache
|
|
/******/ if(__webpack_module_cache__[moduleId]) {
|
|
/******/ return __webpack_module_cache__[moduleId].exports;
|
|
/******/ }
|
|
/******/ // Create a new module (and put it into the cache)
|
|
/******/ var module = __webpack_module_cache__[moduleId] = {
|
|
/******/ id: moduleId,
|
|
/******/ loaded: false,
|
|
/******/ exports: {}
|
|
/******/ };
|
|
/******/
|
|
/******/ // Execute the module function
|
|
/******/ __webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);
|
|
/******/
|
|
/******/ // Flag the module as loaded
|
|
/******/ module.loaded = true;
|
|
/******/
|
|
/******/ // Return the exports of the module
|
|
/******/ return module.exports;
|
|
/******/ }
|
|
/******/
|
|
/************************************************************************/
|
|
/******/ /* webpack/runtime/amd define */
|
|
/******/ !function() {
|
|
/******/ __webpack_require__.amdD = function () {
|
|
/******/ throw new Error('define cannot be used indirect');
|
|
/******/ };
|
|
/******/ }();
|
|
/******/
|
|
/******/ /* webpack/runtime/compat get default export */
|
|
/******/ !function() {
|
|
/******/ // getDefaultExport function for compatibility with non-harmony modules
|
|
/******/ __webpack_require__.n = function(module) {
|
|
/******/ var getter = module && module.__esModule ?
|
|
/******/ function() { return module['default']; } :
|
|
/******/ function() { return module; };
|
|
/******/ __webpack_require__.d(getter, { a: getter });
|
|
/******/ return getter;
|
|
/******/ };
|
|
/******/ }();
|
|
/******/
|
|
/******/ /* webpack/runtime/define property getters */
|
|
/******/ !function() {
|
|
/******/ // define getter functions for harmony exports
|
|
/******/ __webpack_require__.d = function(exports, definition) {
|
|
/******/ for(var key in definition) {
|
|
/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
|
|
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
|
|
/******/ }
|
|
/******/ }
|
|
/******/ };
|
|
/******/ }();
|
|
/******/
|
|
/******/ /* webpack/runtime/hasOwnProperty shorthand */
|
|
/******/ !function() {
|
|
/******/ __webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }
|
|
/******/ }();
|
|
/******/
|
|
/******/ /* webpack/runtime/make namespace object */
|
|
/******/ !function() {
|
|
/******/ // 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 });
|
|
/******/ };
|
|
/******/ }();
|
|
/******/
|
|
/******/ /* webpack/runtime/node module decorator */
|
|
/******/ !function() {
|
|
/******/ __webpack_require__.nmd = function(module) {
|
|
/******/ module.paths = [];
|
|
/******/ if (!module.children) module.children = [];
|
|
/******/ return module;
|
|
/******/ };
|
|
/******/ }();
|
|
/******/
|
|
/************************************************************************/
|
|
/******/ // module exports must be returned from runtime so entry inlining is disabled
|
|
/******/ // startup
|
|
/******/ // Load entry module and return exports
|
|
/******/ return __webpack_require__(3161);
|
|
/******/ })()
|
|
;
|
|
});
|