| Current Path : /proc/thread-self/cwd/static/adminhtml/Magento/backend/it_IT/js/bundle/ |
| Current File : //proc/thread-self/cwd/static/adminhtml/Magento/backend/it_IT/js/bundle/bundle9.js |
require.config({"config": {
"jsbuild":{"Magento_PageBuilder/js/content-type/products/mass-converter/carousel-widget-directive.js":"/*eslint-disable */\n/* jscs:disable */\n\nfunction _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\ndefine([\"Magento_PageBuilder/js/mass-converter/widget-directive-abstract\", \"Magento_PageBuilder/js/utils/object\"], function (_widgetDirectiveAbstract, _object) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * @api\n */\n var WidgetDirective = /*#__PURE__*/function (_widgetDirectiveAbstr) {\n \"use strict\";\n\n _inheritsLoose(WidgetDirective, _widgetDirectiveAbstr);\n\n function WidgetDirective() {\n return _widgetDirectiveAbstr.apply(this, arguments) || this;\n }\n\n var _proto = WidgetDirective.prototype;\n\n /**\n * Convert value to internal format\n *\n * @param {object} data\n * @param {object} config\n * @returns {object}\n */\n _proto.fromDom = function fromDom(data, config) {\n var attributes = _widgetDirectiveAbstr.prototype.fromDom.call(this, data, config);\n\n data.carousel_products_count = attributes.products_count;\n data.sort_order = attributes.sort_order;\n data.condition_option = attributes.condition_option || \"condition\";\n data[data.condition_option] = this.decodeWysiwygCharacters(this.decodeHtmlCharacters(attributes.condition_option_value || \"\"));\n data.conditions_encoded = this.decodeWysiwygCharacters(attributes.conditions_encoded || \"\");\n data[data.condition_option + \"_source\"] = data.conditions_encoded;\n return data;\n }\n /**\n * Convert value to knockout format\n *\n * @param {object} data\n * @param {object} config\n * @returns {object}\n */\n ;\n\n _proto.toDom = function toDom(data, config) {\n var attributes = {\n type: \"Magento\\\\CatalogWidget\\\\Block\\\\Product\\\\ProductsList\",\n template: \"Magento_PageBuilder::catalog/product/widget/content/carousel.phtml\",\n anchor_text: \"\",\n id_path: \"\",\n show_pager: 0,\n products_count: data.carousel_products_count,\n condition_option: data.condition_option,\n condition_option_value: \"\",\n type_name: \"Catalog Products Carousel\",\n conditions_encoded: this.encodeWysiwygCharacters(data.conditions_encoded || \"\")\n };\n\n if (data.sort_order) {\n attributes.sort_order = data.sort_order;\n }\n\n if (typeof data[data.condition_option] === \"string\") {\n attributes.condition_option_value = this.encodeWysiwygCharacters(data[data.condition_option]);\n }\n\n if (attributes.conditions_encoded.length === 0) {\n return data;\n }\n\n (0, _object.set)(data, config.html_variable, this.buildDirective(attributes));\n return data;\n }\n /**\n * @param {string} content\n * @returns {string}\n */\n ;\n\n _proto.encodeWysiwygCharacters = function encodeWysiwygCharacters(content) {\n return content.replace(/\\{/g, \"^[\").replace(/\\}/g, \"^]\").replace(/\"/g, \"`\").replace(/\\\\/g, \"|\").replace(/</g, \"<\").replace(/>/g, \">\");\n }\n /**\n * @param {string} content\n * @returns {string}\n */\n ;\n\n _proto.decodeWysiwygCharacters = function decodeWysiwygCharacters(content) {\n return content.replace(/\\^\\[/g, \"{\").replace(/\\^\\]/g, \"}\").replace(/`/g, \"\\\"\").replace(/\\|/g, \"\\\\\").replace(/</g, \"<\").replace(/>/g, \">\");\n }\n /**\n * Decode html special characters\n *\n * @param {string} content\n * @returns {string}\n */\n ;\n\n _proto.decodeHtmlCharacters = function decodeHtmlCharacters(content) {\n if (content) {\n var htmlDocument = new DOMParser().parseFromString(content, \"text/html\");\n return htmlDocument.body ? htmlDocument.body.textContent : content;\n }\n\n return content;\n };\n\n return WidgetDirective;\n }(_widgetDirectiveAbstract);\n\n return WidgetDirective;\n});\n//# sourceMappingURL=carousel-widget-directive.js.map","Magento_PageBuilder/js/content-type/root-container/content-type-collection.js":"/*eslint-disable */\n/* jscs:disable */\n\nfunction _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\ndefine([\"Magento_Ui/js/modal/alert\", \"Magento_PageBuilder/js/content-type-collection\"], function (_alert, _contentTypeCollection) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * @api\n */\n var RootContainer = /*#__PURE__*/function (_contentTypeCollectio) {\n \"use strict\";\n\n _inheritsLoose(RootContainer, _contentTypeCollectio);\n\n function RootContainer() {\n return _contentTypeCollectio.apply(this, arguments) || this;\n }\n\n var _proto = RootContainer.prototype;\n\n /**\n * Remove a child from the observable array\n *\n * @param child\n */\n _proto.removeChild = function removeChild(child) {\n if (this.getChildren().length === 1) {\n (0, _alert)({\n content: $t(\"You are not able to remove the final row from the content.\"),\n title: $t(\"Unable to Remove\")\n });\n return;\n }\n\n _contentTypeCollectio.prototype.removeChild.call(this, child);\n };\n\n return RootContainer;\n }(_contentTypeCollection);\n\n return RootContainer;\n});\n//# sourceMappingURL=content-type-collection.js.map","Magento_PageBuilder/js/content-type/html/preview.js":"/*eslint-disable */\n/* jscs:disable */\n\nfunction _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\ndefine([\"Magento_PageBuilder/js/content-type-menu/hide-show-option\", \"Magento_PageBuilder/js/content-type/preview\"], function (_hideShowOption, _preview) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * @api\n */\n var Preview = /*#__PURE__*/function (_preview2) {\n \"use strict\";\n\n _inheritsLoose(Preview, _preview2);\n\n function Preview() {\n return _preview2.apply(this, arguments) || this;\n }\n\n var _proto = Preview.prototype;\n\n /**\n * Return an array of options\n *\n * @returns {OptionsInterface}\n */\n _proto.retrieveOptions = function retrieveOptions() {\n var options = _preview2.prototype.retrieveOptions.call(this);\n\n options.hideShow = new _hideShowOption({\n preview: this,\n icon: _hideShowOption.showIcon,\n title: _hideShowOption.showText,\n action: this.onOptionVisibilityToggle,\n classes: [\"hide-show-content-type\"],\n sort: 40\n });\n return options;\n };\n\n return Preview;\n }(_preview);\n\n return Preview;\n});\n//# sourceMappingURL=preview.js.map","Magento_PageBuilder/js/content-type/observable-updater/html.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([\"Magento_PageBuilder/js/config\", \"Magento_PageBuilder/js/utils/directives\", \"Magento_PageBuilder/js/utils/editor\", \"Magento_PageBuilder/js/utils/object\"], function (_config, _directives, _editor, _object) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * Generate Knockout compatible bindings for the elements html binding\n *\n * @param elementName\n * @param config\n * @param data\n * @param converterResolver\n * @param converterPool\n */\n function generate(elementName, config, data, converterResolver, converterPool) {\n var value = config.html.var ? (0, _object.get)(data, config.html.var, config.html.placeholder) : config.html.placeholder;\n var converter = converterResolver(config.html);\n\n if (converterPool.get(converter)) {\n value = converterPool.get(converter).toDom(config.html.var, data);\n } // if value is empty, use placeholder\n\n\n if (typeof value === \"string\" && !value.length && config.html.placeholder) {\n value = config.html.placeholder;\n } // Replacing src attribute with data-tmp-src to prevent img requests in iframe during master format rendering\n\n\n if (_config.getMode() !== \"Preview\" && typeof value === \"string\" && value.indexOf(\"{{media url=\") !== -1) {\n value = (0, _directives.replaceWithDataSrc)(value);\n } // Process all desktop styles that left unprocessed after migrating from inline styles.\n\n\n if (typeof value === \"string\") {\n value = (0, _editor.processInlineStyles)(value);\n }\n\n return value;\n }\n\n return generate;\n});\n//# sourceMappingURL=html.js.map","Magento_PageBuilder/js/content-type/observable-updater/css.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([\"Magento_PageBuilder/js/utils/object\"], function (_object) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * Generate Knockout compatible bindings for the elements css binding\n *\n * @param elementName\n * @param config\n * @param data\n * @param converterResolver\n * @param converterPool\n * @param previousData\n */\n function generate(elementName, config, data, converterResolver, converterPool, previousData) {\n var css = (0, _object.get)(data, config.css.var);\n var newClasses = {};\n\n if (css && css.length > 0) {\n css.toString().split(\" \").map(function (value) {\n return newClasses[value] = true;\n });\n }\n\n for (var _i = 0, _Object$keys = Object.keys(previousData); _i < _Object$keys.length; _i++) {\n var className = _Object$keys[_i];\n\n if (!(className in newClasses)) {\n newClasses[className] = false;\n }\n }\n\n return newClasses;\n }\n\n return generate;\n});\n//# sourceMappingURL=css.js.map","Magento_PageBuilder/js/content-type/observable-updater/attributes.js":"/*eslint-disable */\n/* jscs:disable */\n\nfunction _createForOfIteratorHelperLoose(o, allowArrayLike) { var it = typeof Symbol !== \"undefined\" && o[Symbol.iterator] || o[\"@@iterator\"]; if (it) return (it = it.call(o)).next.bind(it); if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === \"number\") { if (it) o = it; var i = 0; return function () { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }; } throw new TypeError(\"Invalid attempt to iterate non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\"); }\n\nfunction _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); }\n\nfunction _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; }\n\ndefine([\"underscore\", \"Magento_PageBuilder/js/config\", \"Magento_PageBuilder/js/utils/object\"], function (_underscore, _config, _object) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * Generate Knockout compatible bindings for the elements attribute binding\n *\n * @param elementName\n * @param config\n * @param data\n * @param converterResolver\n * @param converterPool\n */\n function generate(elementName, config, data, converterResolver, converterPool) {\n var attributeData = {};\n\n var _loop = function _loop() {\n var attributeConfig = _step.value;\n\n if (\"read\" === attributeConfig.persistence_mode) {\n return \"continue\";\n } // @ts-ignore\n\n\n var value = void 0;\n\n if (!!attributeConfig.static) {\n value = attributeConfig.value;\n } else {\n value = (0, _object.get)(data, attributeConfig.var);\n }\n\n var converter = converterResolver(attributeConfig);\n\n if (converterPool.get(converter)) {\n value = converterPool.get(converter).toDom(attributeConfig.var, data);\n } // Replacing src attribute with data-tmp-src to prevent img requests in iframe during master format rendering\n\n\n if (_config.getMode() !== \"Preview\" && attributeConfig.name === \"src\" && _underscore.isString(value) && !value.indexOf(\"{{media url=\")) {\n attributeData[\"data-tmp-\" + attributeConfig.name] = value; // @ts-ignore\n\n Object.defineProperty(attributeData, attributeConfig.name, {\n get: function get() {\n return value;\n }\n });\n } else {\n attributeData[attributeConfig.name] = value;\n }\n };\n\n for (var _iterator = _createForOfIteratorHelperLoose(config.attributes), _step; !(_step = _iterator()).done;) {\n var _ret = _loop();\n\n if (_ret === \"continue\") continue;\n }\n\n attributeData[\"data-element\"] = elementName;\n return attributeData;\n }\n\n return generate;\n});\n//# sourceMappingURL=attributes.js.map","Magento_PageBuilder/js/content-type/observable-updater/style.js":"/*eslint-disable */\n/* jscs:disable */\n\nfunction _createForOfIteratorHelperLoose(o, allowArrayLike) { var it = typeof Symbol !== \"undefined\" && o[Symbol.iterator] || o[\"@@iterator\"]; if (it) return (it = it.call(o)).next.bind(it); if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === \"number\") { if (it) o = it; var i = 0; return function () { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }; } throw new TypeError(\"Invalid attempt to iterate non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\"); }\n\nfunction _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); }\n\nfunction _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; }\n\ndefine([\"underscore\", \"Magento_PageBuilder/js/utils/object\", \"Magento_PageBuilder/js/utils/string\"], function (_underscore, _object, _string) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * Generate Knockout compatible bindings for the elements style binding\n *\n * @param elementName\n * @param config\n * @param data\n * @param converterResolver\n * @param converterPool\n * @param previousData\n */\n function generate(elementName, config, data, converterResolver, converterPool, previousData) {\n var newStyles = {};\n\n if (config.style) {\n for (var _iterator = _createForOfIteratorHelperLoose(config.style), _step; !(_step = _iterator()).done;) {\n var propertyConfig = _step.value;\n\n if (\"read\" === propertyConfig.persistence_mode) {\n continue;\n }\n\n var value = void 0;\n\n if (!!propertyConfig.static) {\n value = propertyConfig.value;\n } else {\n value = (0, _object.get)(data, propertyConfig.var);\n var converter = converterResolver(propertyConfig);\n\n if (converterPool.get(converter)) {\n value = converterPool.get(converter).toDom(propertyConfig.var, data);\n }\n }\n\n if (typeof value === \"object\") {\n _underscore.extend(newStyles, value);\n } else if (value !== undefined) {\n newStyles[(0, _string.fromSnakeToCamelCase)(propertyConfig.name)] = value;\n }\n }\n }\n\n if (previousData) {\n /**\n * If so we need to retrieve the previous styles applied to this element and create a new object\n * which forces all of these styles to be \"false\". Knockout doesn't clean existing styles when\n * applying new styles to an element. This resolves styles sticking around when they should be\n * removed.\n */\n var removeCurrentStyles = Object.keys(previousData).reduce(function (object, styleName) {\n var _Object$assign;\n\n return Object.assign(object, (_Object$assign = {}, _Object$assign[styleName] = \"\", _Object$assign));\n }, {});\n\n if (!_underscore.isEmpty(removeCurrentStyles)) {\n newStyles = _underscore.extend(removeCurrentStyles, newStyles);\n }\n }\n\n return newStyles;\n }\n\n return generate;\n});\n//# sourceMappingURL=style.js.map","Magento_PageBuilder/js/content-type/tabs/preview.js":"/*eslint-disable */\n/* jscs:disable */\n\nfunction _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\ndefine([\"jquery\", \"knockout\", \"mage/translate\", \"Magento_PageBuilder/js/events\", \"tabs\", \"underscore\", \"Magento_PageBuilder/js/config\", \"Magento_PageBuilder/js/content-type-factory\", \"Magento_PageBuilder/js/content-type-menu/hide-show-option\", \"Magento_PageBuilder/js/content-type-menu/option\", \"Magento_PageBuilder/js/utils/delay-until\", \"Magento_PageBuilder/js/utils/promise-deferred\", \"Magento_PageBuilder/js/content-type/preview-collection\"], function (_jquery, _knockout, _translate, _events, _tabs, _underscore, _config, _contentTypeFactory, _hideShowOption, _option, _delayUntil, _promiseDeferred, _previewCollection) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * @api\n */\n var Preview = /*#__PURE__*/function (_previewCollection2) {\n \"use strict\";\n\n _inheritsLoose(Preview, _previewCollection2);\n\n /**\n * @param {ContentTypeCollectionInterface} contentType\n * @param {ContentTypeConfigInterface} config\n * @param {ObservableUpdater} observableUpdater\n */\n function Preview(contentType, config, observableUpdater) {\n var _this;\n\n _this = _previewCollection2.call(this, contentType, config, observableUpdater) || this; // Wait for the tabs instance to mount and the container to be ready\n\n _this.focusedTab = _knockout.observable(null);\n _this.activeTab = _knockout.observable(0);\n _this.onContainerRenderDeferred = (0, _promiseDeferred)();\n _this.mountAfterDeferred = (0, _promiseDeferred)();\n Promise.all([_this.onContainerRenderDeferred.promise, _this.mountAfterDeferred.promise]).then(function (_ref) {\n var element = _ref[0],\n expectedChildren = _ref[1];\n // We always create 1 tab when dropping tabs into the instance\n expectedChildren = expectedChildren || 1; // Wait until all children's DOM elements are present before building the tabs instance\n\n (0, _delayUntil)(function () {\n _this.element = element;\n\n _this.buildTabs();\n }, function () {\n return (0, _jquery)(element).find(\".pagebuilder-tab-item\").length === expectedChildren;\n });\n }); // Resolve our deferred when the tabs item mounts with expect children\n\n _events.on(\"tabs:mountAfter\", function (args) {\n if (args.contentType.id === _this.contentType.id && args.expectChildren !== undefined) {\n _this.mountAfterDeferred.resolve(args.expectChildren);\n }\n });\n\n _events.on(\"tab-item:mountAfter\", function (args) {\n if (_this.element && args.contentType.parentContentType.id === _this.contentType.id) {\n _this.refreshTabs();\n }\n });\n\n _events.on(\"tab-item:renderAfter\", function (args) {\n if (_this.element && args.contentType.parentContentType.id === _this.contentType.id) {\n _underscore.defer(function () {\n _this.refreshTabs();\n });\n }\n }); // Set the active tab to the new position of the sorted tab\n\n\n _events.on(\"tab-item:removeAfter\", function (args) {\n if (args.parentContentType && args.parentContentType.id === _this.contentType.id) {\n _this.refreshTabs(); // We need to wait for the tabs to refresh before executing the focus\n\n\n _underscore.defer(function () {\n var newPosition = args.index > 0 ? args.index - 1 : 0;\n\n _this.setFocusedTab(newPosition, true);\n });\n }\n }); // Refresh tab contents and set the focus to the new position of the sorted tab\n\n\n _events.on(\"childContentType:sortUpdate\", function (args) {\n if (args.instance.id === _this.contentType.id) {\n _this.refreshTabs(args.newPosition, true);\n /**\n * Update the default active tab if its position was affected by the sorting\n */\n\n\n var defaultActiveTab = +_this.activeTab();\n var newDefaultActiveTab = defaultActiveTab;\n\n if (args.originalPosition === defaultActiveTab) {\n newDefaultActiveTab = args.newPosition;\n } else if (args.originalPosition < defaultActiveTab && args.newPosition >= defaultActiveTab) {\n // a tab was moved from the left of the default active tab the right of it, changing its index\n newDefaultActiveTab--;\n } else if (args.originalPosition > defaultActiveTab && args.newPosition <= defaultActiveTab) {\n // a tab was moved from the right of the default active tab the left of it, changing its index\n newDefaultActiveTab++;\n }\n\n _this.updateData(\"default_active\", newDefaultActiveTab.toString());\n }\n }); // Monitor focus tab to start / stop interaction on the stage, debounce to avoid duplicate calls\n\n\n _this.focusedTab.subscribe(_underscore.debounce(function (index) {\n if (index !== null) {\n _events.trigger(\"stage:interactionStart\");\n\n (0, _delayUntil)(function () {\n return (0, _jquery)((0, _jquery)(_this.wrapperElement).find(\".tab-header\")[index]).find(\"[contenteditable]\").focus();\n }, function () {\n return (0, _jquery)((0, _jquery)(_this.wrapperElement).find(\".tab-header\")[index]).find(\"[contenteditable]\").length > 0;\n }, 10);\n } else {\n // We have to force the stop as the event firing is inconsistent for certain operations\n _events.trigger(\"stage:interactionStop\", {\n force: true\n });\n }\n }, 1));\n\n return _this;\n }\n /**\n * Remove focused tab\n */\n\n\n var _proto = Preview.prototype;\n\n _proto.destroy = function destroy() {\n var _this2 = this;\n\n _previewCollection2.prototype.destroy.call(this);\n\n _underscore.defer(function () {\n return _this2.setFocusedTab(null);\n });\n }\n /**\n * Refresh the tabs instance when new content appears\n *\n * @param {number} focusIndex\n * @param {boolean} forceFocus\n * @param {number} activeIndex\n */\n ;\n\n _proto.refreshTabs = function refreshTabs(focusIndex, forceFocus, activeIndex) {\n try {\n (0, _jquery)(this.element).tabs(\"refresh\");\n\n if (focusIndex >= 0) {\n this.setFocusedTab(focusIndex, forceFocus);\n } else if (activeIndex) {\n this.setActiveTab(activeIndex);\n } // update sortability of tabs\n\n\n var sortableElement = (0, _jquery)(this.element).find(\".tabs-navigation\");\n\n if (sortableElement.hasClass(\"ui-sortable\")) {\n if (this.contentType.children().length <= 1) {\n sortableElement.sortable(\"disable\");\n } else {\n sortableElement.sortable(\"enable\");\n }\n }\n } catch (e) {\n this.buildTabs();\n }\n }\n /**\n * Set the active tab, we maintain a reference to it in an observable for when we rebuild the tab instance\n *\n * @param {number} index\n */\n ;\n\n _proto.setActiveTab = function setActiveTab(index) {\n var _this3 = this;\n\n if (index !== null) {\n // Added to prevent mismatched fragment error caused by not yet rendered tab-item\n index = parseInt(index.toString(), 10);\n (0, _delayUntil)(function () {\n (0, _jquery)(_this3.element).tabs(\"option\", \"active\", index);\n\n _this3.activeTab(index);\n\n _events.trigger(\"contentType:redrawAfter\", {\n id: _this3.contentType.id,\n contentType: _this3\n });\n }, function () {\n return (0, _jquery)(_this3.element).find(\".pagebuilder-tab-item\").length >= index + 1;\n });\n }\n }\n /**\n * Set the focused tab\n *\n * @param {number} index\n * @param {boolean} force\n */\n ;\n\n _proto.setFocusedTab = function setFocusedTab(index, force) {\n if (force === void 0) {\n force = false;\n }\n\n this.setActiveTab(index);\n\n if (force) {\n this.focusedTab(null);\n }\n\n this.focusedTab(index);\n }\n /**\n * Return an array of options\n *\n * @returns {OptionsInterface}\n */\n ;\n\n _proto.retrieveOptions = function retrieveOptions() {\n var options = _previewCollection2.prototype.retrieveOptions.call(this);\n\n options.add = new _option({\n preview: this,\n icon: \"<i class='icon-pagebuilder-add'></i>\",\n title: (0, _translate)(\"Add\"),\n action: this.addTab,\n classes: [\"add-child\"],\n sort: 10\n });\n options.hideShow = new _hideShowOption({\n preview: this,\n icon: _hideShowOption.showIcon,\n title: _hideShowOption.showText,\n action: this.onOptionVisibilityToggle,\n classes: [\"hide-show-content-type\"],\n sort: 40\n });\n return options;\n }\n /**\n * Add a tab\n */\n ;\n\n _proto.addTab = function addTab() {\n var _this4 = this;\n\n (0, _contentTypeFactory)(_config.getContentTypeConfig(\"tab-item\"), this.contentType, this.contentType.stageId).then(function (tab) {\n _events.on(\"tab-item:mountAfter\", function (args) {\n if (args.id === tab.id) {\n _this4.setFocusedTab(_this4.contentType.children().length - 1);\n\n _events.off(\"tab-item:\" + tab.id + \":mountAfter\");\n }\n }, \"tab-item:\" + tab.id + \":mountAfter\");\n\n _this4.contentType.addChild(tab, _this4.contentType.children().length); // Update the default tab title when adding a new tab\n\n\n tab.dataStore.set(\"tab_name\", (0, _translate)(\"Tab\") + \" \" + (_this4.contentType.children.indexOf(tab) + 1));\n });\n }\n /**\n * On render init the tabs widget\n *\n * @param {Element} element\n */\n ;\n\n _proto.onContainerRender = function onContainerRender(element) {\n this.element = element;\n this.onContainerRenderDeferred.resolve(element);\n }\n /**\n * Copy over border styles to the tab headers\n *\n * @returns {any}\n */\n ;\n\n _proto.getTabHeaderStyles = function getTabHeaderStyles() {\n var headerStyles = this.data.headers.style();\n return _extends({}, headerStyles, {\n marginBottom: \"-\" + headerStyles.borderWidth,\n marginLeft: \"-\" + headerStyles.borderWidth\n });\n }\n /**\n * Get the sortable options for the tab heading sorting\n *\n * @returns {JQueryUI.SortableOptions}\n */\n ;\n\n _proto.getSortableOptions = function getSortableOptions() {\n var self = this;\n var borderWidth;\n return {\n handle: \".tab-drag-handle\",\n tolerance: \"pointer\",\n cursor: \"grabbing\",\n cursorAt: {\n left: 8,\n top: 25\n },\n\n /**\n * Provide custom helper element\n *\n * @param {Event} event\n * @param {JQueryUI.Sortable} element\n * @returns {Element}\n */\n helper: function helper(event, element) {\n var helper = (0, _jquery)(element).clone().css(\"opacity\", \"0.7\");\n helper[0].querySelector(\".pagebuilder-options\").remove();\n return helper[0];\n },\n\n /**\n * Add a padding to the navigation UL to resolve issues of negative margins when sorting\n *\n * @param {Event} event\n * @param {JQueryUI.SortableUIParams} ui\n */\n start: function start(event, ui) {\n /**\n * Due to the way we use negative margins to overlap the borders we need to apply a padding to the\n * container when we're moving the first item to ensure the tabs remain in the same place.\n */\n if (ui.item.index() === 0) {\n borderWidth = parseInt(ui.item.css(\"borderWidth\"), 10) || 1;\n (0, _jquery)(this).css(\"paddingLeft\", borderWidth);\n }\n\n ui.helper.css(\"width\", \"\");\n\n _events.trigger(\"stage:interactionStart\");\n\n self.disableInteracting = true;\n },\n\n /**\n * Remove the padding once the operation is completed\n *\n * @param {Event} event\n * @param {JQueryUI.SortableUIParams} ui\n */\n stop: function stop(event, ui) {\n (0, _jquery)(this).css(\"paddingLeft\", \"\");\n\n _events.trigger(\"stage:interactionStop\");\n\n self.disableInteracting = false;\n },\n placeholder: {\n /**\n * Provide custom placeholder element\n *\n * @param {JQuery} item\n * @returns {JQuery}\n */\n element: function element(item) {\n var placeholder = item.clone().css({\n display: \"inline-block\",\n opacity: \"0.3\"\n }).removeClass(\"focused\").addClass(\"sortable-placeholder\");\n placeholder[0].querySelector(\".pagebuilder-options\").remove();\n return placeholder[0];\n },\n update: function update() {\n return;\n }\n }\n };\n }\n /**\n * Bind events\n */\n ;\n\n _proto.bindEvents = function bindEvents() {\n var _this5 = this;\n\n _previewCollection2.prototype.bindEvents.call(this); // ContentType being mounted onto container\n\n\n _events.on(\"tabs:dropAfter\", function (args) {\n if (args.id === _this5.contentType.id && _this5.contentType.children().length === 0) {\n _this5.addTab();\n }\n }); // ContentType being removed from container\n\n\n _events.on(\"tab-item:removeAfter\", function (args) {\n if (args.parentContentType && args.parentContentType.id === _this5.contentType.id) {\n // Mark the previous tab as active\n var newIndex = args.index - 1 >= 0 ? args.index - 1 : 0;\n\n _this5.refreshTabs(newIndex, true);\n }\n }); // Capture when a content type is duplicated within the container\n\n\n var duplicatedTab;\n var duplicatedTabIndex;\n\n _events.on(\"tab-item:duplicateAfter\", function (args) {\n if (_this5.contentType.id === args.duplicateContentType.parentContentType.id && args.direct) {\n var tabData = args.duplicateContentType.dataStore.getState();\n args.duplicateContentType.dataStore.set(\"tab_name\", tabData.tab_name.toString() + \" copy\");\n duplicatedTab = args.duplicateContentType;\n duplicatedTabIndex = args.index;\n }\n });\n\n _events.on(\"tab-item:mountAfter\", function (args) {\n if (duplicatedTab && args.id === duplicatedTab.id) {\n _this5.refreshTabs(duplicatedTabIndex, true);\n\n duplicatedTab = duplicatedTabIndex = null;\n }\n\n if (_this5.contentType.id === args.contentType.parentContentType.id) {\n _this5.updateTabNamesInDataStore();\n\n args.contentType.dataStore.subscribe(function () {\n _this5.updateTabNamesInDataStore();\n });\n }\n });\n\n this.contentType.dataStore.subscribe(function (data) {\n _this5.activeTab(data.default_active);\n });\n }\n /**\n * Update data store with active options\n */\n ;\n\n _proto.updateTabNamesInDataStore = function updateTabNamesInDataStore() {\n var activeOptions = [];\n this.contentType.children().forEach(function (tab, index) {\n var tabData = tab.dataStore.getState();\n activeOptions.push({\n label: tabData.tab_name.toString(),\n labeltitle: tabData.tab_name.toString(),\n value: index\n });\n });\n this.contentType.dataStore.set(\"_default_active_options\", activeOptions);\n }\n /**\n * Assign a debounce and delay to the init of tabs to ensure the DOM has updated\n *\n * @type {(() => void) & _.Cancelable}\n */\n ;\n\n _proto.buildTabs = function buildTabs(activeTabIndex) {\n var _this6 = this;\n\n if (activeTabIndex === void 0) {\n activeTabIndex = this.activeTab() || 0;\n }\n\n this.ready = false;\n\n if (this.element && this.element.children.length > 0) {\n var focusedTab = this.focusedTab();\n\n try {\n (0, _jquery)(this.element).tabs(\"destroy\");\n } catch (e) {// We aren't concerned if this fails, tabs throws an Exception when we cannot destroy\n }\n\n (0, _jquery)(this.element).tabs({\n create: function create() {\n _this6.ready = true; // Ensure focus tab is restored after a rebuild cycle\n\n if (focusedTab !== null) {\n _this6.setFocusedTab(focusedTab, true);\n } else {\n _this6.setFocusedTab(null);\n\n if (activeTabIndex) {\n _this6.setActiveTab(activeTabIndex);\n }\n }\n },\n\n /**\n * Trigger redraw event since new content is being displayed\n */\n activate: function activate() {\n _events.trigger(\"contentType:redrawAfter\", {\n element: _this6.element\n });\n }\n });\n }\n };\n\n return Preview;\n }(_previewCollection); // Resolve issue with jQuery UI tabs content typing events on content editable areas\n\n\n var originalTabKeyDown = _jquery.ui.tabs.prototype._tabKeydown;\n\n _jquery.ui.tabs.prototype._tabKeydown = function (event) {\n // If the target is content editable don't handle any events\n if ((0, _jquery)(event.target).attr(\"contenteditable\")) {\n return;\n }\n\n originalTabKeyDown.call(this, event);\n };\n\n return Preview;\n});\n//# sourceMappingURL=preview.js.map","Magento_PageBuilder/js/content-type/tabs/appearance/default/widget.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n 'jquery',\n 'Magento_PageBuilder/js/events',\n 'jquery-ui-modules/tabs'\n], function ($, events) {\n 'use strict';\n\n return function (config, element) {\n var $element = $(element);\n\n // Ignore stage builder preview tabs\n if ($element.is('.pagebuilder-tabs')) {\n return;\n }\n\n // Disambiguate between the mage/tabs component which is loaded randomly depending on requirejs order.\n $.ui.tabs({\n active: $element.data('activeTab') || 0,\n create:\n\n /**\n * Adjust the margin bottom of the navigation to correctly display the active tab\n */\n function () {\n var borderWidth = parseInt($element.find('.tabs-content').css('borderWidth').toString(), 10);\n\n $element.find('.tabs-navigation').css('marginBottom', -borderWidth);\n $element.find('.tabs-navigation li:not(:first-child)').css('marginLeft', -borderWidth);\n },\n activate:\n\n /**\n * Trigger redraw event since new content is being displayed\n */\n function () {\n events.trigger('contentType:redrawAfter', {\n element: element\n });\n }\n }, element);\n };\n});\n","Magento_PageBuilder/js/content-type/tabs/mass-converter/header-alignment.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([\"Magento_PageBuilder/js/utils/object\"], function (_object) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n var HeaderAlignment = /*#__PURE__*/function () {\n \"use strict\";\n\n function HeaderAlignment() {}\n\n var _proto = HeaderAlignment.prototype;\n\n /**\n * Process data after it's read and converted by element converters\n *\n * @param {ConverterDataInterface} data\n * @param {ConverterConfigInterface} config\n * @returns {object}\n */\n _proto.fromDom = function fromDom(data, config) {\n return data;\n }\n /**\n * Add our tab alignment class into the data for the tabs\n *\n * @param {ConverterDataInterface} data\n * @param {ConverterConfigInterface} config\n * @returns {object}\n */\n ;\n\n _proto.toDom = function toDom(data, config) {\n data.css_classes += \" tab-align-\" + (0, _object.get)(data, config.navigation_alignment_variable, \"left\");\n return data;\n };\n\n return HeaderAlignment;\n }();\n\n return HeaderAlignment;\n});\n//# sourceMappingURL=header-alignment.js.map","Magento_PageBuilder/js/content-type/buttons/preview.js":"/*eslint-disable */\n/* jscs:disable */\n\nfunction _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\ndefine([\"jquery\", \"knockout\", \"mage/translate\", \"Magento_PageBuilder/js/events\", \"underscore\", \"Magento_PageBuilder/js/config\", \"Magento_PageBuilder/js/content-type-factory\", \"Magento_PageBuilder/js/content-type-menu/hide-show-option\", \"Magento_PageBuilder/js/content-type-menu/option\", \"Magento_PageBuilder/js/utils/delay-until\", \"Magento_PageBuilder/js/content-type/preview-collection\"], function (_jquery, _knockout, _translate, _events, _underscore, _config, _contentTypeFactory, _hideShowOption, _option, _delayUntil, _previewCollection) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * @api\n */\n var Preview = /*#__PURE__*/function (_previewCollection2) {\n \"use strict\";\n\n _inheritsLoose(Preview, _previewCollection2);\n\n /**\n * @param {ContentTypeCollectionInterface} contentType\n * @param {ContentTypeConfigInterface} config\n * @param {ObservableUpdater} observableUpdater\n */\n function Preview(contentType, config, observableUpdater) {\n var _this;\n\n _this = _previewCollection2.call(this, contentType, config, observableUpdater) || this; // Keeps track of number of button item to disable sortable if there is only 1.\n\n _this.focusedButton = _knockout.observable();\n _this.debouncedResizeHandler = _underscore.debounce(function () {\n _this.resizeChildButtons();\n }, 350);\n\n _this.contentType.children.subscribe(function () {\n var sortableElement = (0, _jquery)(_this.wrapperElement).find(\".buttons-container\");\n\n if (!sortableElement.data(\"ui-sortable\")) {\n return;\n }\n\n if (_this.contentType.children().length <= 1) {\n sortableElement.sortable(\"disable\");\n } else {\n sortableElement.sortable(\"enable\");\n }\n }); // Monitor focus tab to start / stop interaction on the stage, debounce to avoid duplicate calls\n\n\n _this.focusedButton.subscribe(_underscore.debounce(function (index) {\n if (index !== null) {\n _events.trigger(\"stage:interactionStart\");\n\n var focusedButton = _this.contentType.children()[index];\n\n (0, _delayUntil)(function () {\n return (0, _jquery)(focusedButton.preview.wrapperElement).find(\"[contenteditable]\").focus();\n }, function () {\n return typeof focusedButton.preview.wrapperElement !== \"undefined\";\n }, 10);\n } else {\n // We have to force the stop as the event firing is inconsistent for certain operations\n _events.trigger(\"stage:interactionStop\", {\n force: true\n });\n }\n }, 1));\n\n return _this;\n }\n /**\n * Bind events\n */\n\n\n var _proto = Preview.prototype;\n\n _proto.bindEvents = function bindEvents() {\n var _this2 = this;\n\n _previewCollection2.prototype.bindEvents.call(this);\n\n _events.on(\"buttons:dropAfter\", function (args) {\n if (args.id === _this2.contentType.id && _this2.contentType.children().length === 0) {\n _this2.addButton();\n }\n });\n\n _events.on(\"buttons:renderAfter\", function (args) {\n if (args.contentType.id === _this2.contentType.id) {\n _this2.debouncedResizeHandler();\n }\n });\n\n _events.on(\"button-item:renderAfter\", function (args) {\n if (args.contentType.parentContentType.id === _this2.contentType.id) {\n _this2.debouncedResizeHandler();\n }\n });\n\n _events.on(\"stage:updateAfter\", function () {\n _this2.debouncedResizeHandler();\n });\n\n _events.on(\"contentType:redrawAfter\", function () {\n _this2.debouncedResizeHandler();\n }); // Capture when a content type is duplicated within the container\n\n\n var duplicatedButton;\n var duplicatedButtonIndex;\n\n _events.on(\"button-item:duplicateAfter\", function (args) {\n if (_this2.contentType.id === args.duplicateContentType.parentContentType.id && args.direct) {\n duplicatedButton = args.duplicateContentType;\n duplicatedButtonIndex = args.index;\n }\n });\n\n _events.on(\"button-item:mountAfter\", function (args) {\n if (duplicatedButton && args.id === duplicatedButton.id) {\n _this2.focusedButton(duplicatedButtonIndex);\n }\n });\n }\n /**\n * Return an array of options\n *\n * @returns {OptionsInterface}\n */\n ;\n\n _proto.retrieveOptions = function retrieveOptions() {\n var options = _previewCollection2.prototype.retrieveOptions.call(this);\n\n options.add = new _option({\n preview: this,\n icon: \"<i class='icon-pagebuilder-add'></i>\",\n title: (0, _translate)(\"Add Button\"),\n action: this.addButton,\n classes: [\"add-child\"],\n sort: 10\n });\n options.hideShow = new _hideShowOption({\n preview: this,\n icon: _hideShowOption.showIcon,\n title: _hideShowOption.showText,\n action: this.onOptionVisibilityToggle,\n classes: [\"hide-show-content-type\"],\n sort: 40\n });\n return options;\n }\n /**\n * Add button-item to buttons children array\n */\n ;\n\n _proto.addButton = function addButton() {\n var _this3 = this;\n\n var createButtonItemPromise = (0, _contentTypeFactory)(_config.getContentTypeConfig(\"button-item\"), this.contentType, this.contentType.stageId, {});\n createButtonItemPromise.then(function (button) {\n _this3.contentType.addChild(button);\n\n var buttonIndex = _this3.contentType.children().indexOf(button);\n\n _this3.focusedButton(buttonIndex > -1 ? buttonIndex : null);\n\n return button;\n }).catch(function (error) {\n console.error(error);\n });\n }\n /**\n * Get the sortable options for the buttons sorting\n *\n * @param {string} orientation\n * @param {string} tolerance\n * @returns {JQueryUI.Sortable}\n */\n ;\n\n _proto.getSortableOptions = function getSortableOptions(orientation, tolerance) {\n if (orientation === void 0) {\n orientation = \"width\";\n }\n\n if (tolerance === void 0) {\n tolerance = \"intersect\";\n }\n\n return {\n handle: \".button-item-drag-handle\",\n items: \".pagebuilder-content-type-wrapper\",\n cursor: \"grabbing\",\n containment: \"parent\",\n tolerance: tolerance,\n revert: 200,\n disabled: this.contentType.children().length <= 1,\n\n /**\n * Provide custom helper element\n *\n * @param {Event} event\n * @param {JQueryUI.Sortable} element\n * @returns {Element}\n */\n helper: function helper(event, element) {\n var helper = (0, _jquery)(element).clone().css({\n opacity: \"0.7\",\n width: \"auto\"\n });\n helper[0].querySelector(\".pagebuilder-options\").remove();\n return helper[0];\n },\n placeholder: {\n /**\n * Provide custom placeholder element\n *\n * @param {JQuery} item\n * @returns {JQuery}\n */\n element: function element(item) {\n var placeholder = item.clone().css({\n display: \"inline-block\",\n opacity: \"0.3\"\n }).removeClass(\"focused\").addClass(\"sortable-placeholder\");\n placeholder[0].querySelector(\".pagebuilder-options\").remove();\n return placeholder[0];\n },\n update: function update() {\n return;\n }\n },\n\n /**\n * Trigger interaction start on sort\n */\n start: function start() {\n _events.trigger(\"stage:interactionStart\");\n },\n\n /**\n * Stop stage interaction on stop\n */\n stop: function stop() {\n _events.trigger(\"stage:interactionStop\");\n }\n };\n }\n /**\n * Resize width of all child buttons. Dependently make them the same width if configured.\n */\n ;\n\n _proto.resizeChildButtons = function resizeChildButtons() {\n if (this.wrapperElement) {\n var buttonItems = (0, _jquery)(this.wrapperElement).find(\".pagebuilder-button-item > a\");\n var buttonResizeValue = 0;\n\n if (this.contentType.dataStore.get(\"is_same_width\") === \"true\") {\n if (buttonItems.length > 0) {\n var currentLargestButtonWidth = this.findLargestButtonWidth(buttonItems);\n var parentWrapperWidth = (0, _jquery)(this.wrapperElement).find(\".buttons-container\").width();\n\n if (currentLargestButtonWidth === 0) {\n return;\n }\n\n buttonResizeValue = Math.min(currentLargestButtonWidth, parentWrapperWidth);\n }\n }\n\n buttonItems.css(\"min-width\", buttonResizeValue);\n }\n }\n /**\n * Find the largest button width for calculating same size value.\n *\n * @param {JQuery} buttonItems\n * @returns {number}\n */\n ;\n\n _proto.findLargestButtonWidth = function findLargestButtonWidth(buttonItems) {\n var _this4 = this;\n\n return _underscore.max(_underscore.map(buttonItems, function (buttonItem) {\n return _this4.calculateButtonWidth((0, _jquery)(buttonItem));\n }));\n }\n /**\n * Manually calculate button width using content plus box widths (padding, border)\n *\n * @param {JQuery} buttonItem\n * @returns {number}\n */\n ;\n\n _proto.calculateButtonWidth = function calculateButtonWidth(buttonItem) {\n if (buttonItem.is(\":visible\") === false) {\n return 0;\n }\n\n var widthProperties = [\"paddingLeft\", \"paddingRight\", \"borderLeftWidth\", \"borderRightWidth\"];\n var buttonText = buttonItem.find(\"[data-element='link_text']\");\n var textWidth = buttonText.css(\"display\", \"inline-block\").width();\n buttonText.css(\"display\", \"\");\n return widthProperties.reduce(function (accumulatedWidth, widthProperty) {\n return accumulatedWidth + (parseInt(buttonItem.css(widthProperty), 10) || 0);\n }, textWidth);\n };\n\n return Preview;\n }(_previewCollection);\n\n return Preview;\n});\n//# sourceMappingURL=preview.js.map","Magento_PageBuilder/js/content-type/buttons/appearance/inline/widget.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n 'jquery',\n 'Magento_PageBuilder/js/events'\n], function ($, events) {\n 'use strict';\n\n /**\n * Equalize the width of a list of button-item components\n *\n * @param {JQuery} buttonList\n */\n var equalizeButtonWidth = function (buttonList) {\n var buttonMinWidth = 0;\n\n buttonList.css('min-width', buttonMinWidth);\n buttonList.each(function () {\n var buttonWidth = this.offsetWidth;\n\n if (buttonWidth > buttonMinWidth) {\n buttonMinWidth = buttonWidth;\n }\n });\n buttonList.css('min-width', buttonMinWidth);\n };\n\n return function (config, element) {\n var $element = $(element),\n buttonSelector = '[data-element=\"link\"], [data-element=\"empty_link\"]';\n\n if ($element.data('sameWidth')) {\n equalizeButtonWidth($element.find(buttonSelector));\n $(window).on('resize', function () {\n equalizeButtonWidth($element.find(buttonSelector));\n });\n events.on('contentType:redrawAfter', function (eventData) {\n if ($element.closest(eventData.element).length > 0) {\n equalizeButtonWidth($element.find(buttonSelector));\n }\n });\n }\n };\n});\n","Magento_PageBuilder/js/content-type/buttons/converter/style/preview/display/flex.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([], function () {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * @api\n */\n var Display = /*#__PURE__*/function () {\n \"use strict\";\n\n function Display() {}\n\n var _proto = Display.prototype;\n\n /**\n * Ensure the display none property doesn't persist to the preview\n *\n * @param value string\n * @returns {string | object}\n */\n _proto.fromDom = function fromDom(value) {\n return;\n }\n /**\n * Ensure the display none property doesn't persist to the preview\n *\n * @param name string\n * @param data Object\n * @returns {string}\n */\n ;\n\n _proto.toDom = function toDom(name, data) {\n return \"flex\";\n };\n\n return Display;\n }();\n\n return Display;\n});\n//# sourceMappingURL=flex.js.map","Magento_PageBuilder/js/content-type/buttons/converter/style/display/boolean.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([\"underscore\", \"Magento_PageBuilder/js/utils/object\"], function (_underscore, _object) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * @api\n */\n var Boolean = /*#__PURE__*/function () {\n \"use strict\";\n\n function Boolean() {}\n\n var _proto = Boolean.prototype;\n\n /**\n * Convert value to internal format\n *\n * @param value string\n * @returns {string | object}\n */\n _proto.fromDom = function fromDom(value) {\n return !(value === \"none\");\n }\n /**\n * Convert value to knockout format, if buttons are displayed they should be reset to default\n *\n * @param {string} name\n * @param {DataObject} data\n * @returns {string}\n */\n ;\n\n _proto.toDom = function toDom(name, data) {\n var value = (0, _object.get)(data, name);\n\n if (!_underscore.isUndefined(value) && value === false) {\n return \"none\";\n }\n\n return \"\";\n };\n\n return Boolean;\n }();\n\n return Boolean;\n});\n//# sourceMappingURL=boolean.js.map","Magento_PageBuilder/js/content-type/buttons/converter/style/display/flex.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([\"underscore\", \"Magento_PageBuilder/js/utils/object\"], function (_underscore, _object) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * @api\n */\n var Flex = /*#__PURE__*/function () {\n \"use strict\";\n\n function Flex() {}\n\n var _proto = Flex.prototype;\n\n /**\n * Convert value to internal format\n *\n * @param value string\n * @returns {string | object}\n */\n _proto.fromDom = function fromDom(value) {\n return !(value === \"none\");\n }\n /**\n * Convert value to knockout format, if buttons are displayed they should be inline block\n *\n * @param {string} name\n * @param {DataObject} data\n * @returns {string}\n */\n ;\n\n _proto.toDom = function toDom(name, data) {\n var value = (0, _object.get)(data, name);\n\n if (!_underscore.isUndefined(value) && value === false) {\n return \"none\";\n }\n\n return \"flex\";\n };\n\n return Flex;\n }();\n\n return Flex;\n});\n//# sourceMappingURL=flex.js.map","Magento_PageBuilder/js/content-type/video/master.js":"/*eslint-disable */\n/* jscs:disable */\n\nfunction _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\ndefine([\"Magento_PageBuilder/js/content-type/master\"], function (_master) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n var Master = /*#__PURE__*/function (_master2) {\n \"use strict\";\n\n _inheritsLoose(Master, _master2);\n\n function Master() {\n return _master2.apply(this, arguments) || this;\n }\n\n var _proto = Master.prototype;\n\n _proto.isHosted = function isHosted(src) {\n var youtubeRegExp = new RegExp(\"^(?:https?:\\/\\/|\\/\\/)?(?:www\\\\.|m\\\\.)?\" + \"(?:youtu\\\\.be\\/|youtube\\\\.com\\/(?:embed\\/|v\\/|watch\\\\?v=|watch\\\\?.+&v=))([\\\\w-]{11})(?![\\\\w-])\");\n var vimeoRegExp = new RegExp(\"https?:\\/\\/(?:www\\\\.|player\\\\.)?vimeo.com\\/(?:channels\\/\" + \"(?:\\\\w+\\/)?|groups\\/([^\\/]*)\\/videos\\/|album\\/(\\\\d+)\\/video\\/|video\\/|)(\\\\d+)(?:$|\\/|\\\\?)\");\n return vimeoRegExp.test(src) || youtubeRegExp.test(src);\n };\n\n return Master;\n }(_master);\n\n return Master;\n});\n//# sourceMappingURL=master.js.map","Magento_PageBuilder/js/content-type/video/preview.js":"/*eslint-disable */\n/* jscs:disable */\n\nfunction _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\ndefine([\"Magento_PageBuilder/js/content-type-menu/hide-show-option\", \"Magento_PageBuilder/js/content-type/preview\"], function (_hideShowOption, _preview) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * @api\n */\n var Preview = /*#__PURE__*/function (_preview2) {\n \"use strict\";\n\n _inheritsLoose(Preview, _preview2);\n\n function Preview() {\n return _preview2.apply(this, arguments) || this;\n }\n\n var _proto = Preview.prototype;\n\n /**\n * Return an array of options\n *\n * @returns {OptionsInterface}\n */\n _proto.retrieveOptions = function retrieveOptions() {\n var options = _preview2.prototype.retrieveOptions.call(this);\n\n options.hideShow = new _hideShowOption({\n preview: this,\n icon: _hideShowOption.showIcon,\n title: _hideShowOption.showText,\n action: this.onOptionVisibilityToggle,\n classes: [\"hide-show-content-type\"],\n sort: 40\n });\n return options;\n };\n\n _proto.isHosted = function isHosted(src) {\n var youtubeRegExp = new RegExp(\"^(?:https?:\\/\\/|\\/\\/)?(?:www\\\\.|m\\\\.)?\" + \"(?:youtu\\\\.be\\/|youtube\\\\.com\\/(?:embed\\/|v\\/|watch\\\\?v=|watch\\\\?.+&v=))([\\\\w-]{11})(?![\\\\w-])\");\n var vimeoRegExp = new RegExp(\"https?:\\/\\/(?:www\\\\.|player\\\\.)?vimeo.com\\/(?:channels\\/\" + \"(?:\\\\w+\\/)?|groups\\/([^\\/]*)\\/videos\\/|album\\/(\\\\d+)\\/video\\/|video\\/|)(\\\\d+)(?:$|\\/|\\\\?)\");\n return vimeoRegExp.test(src) || youtubeRegExp.test(src);\n }\n /**\n * After render callback\n *\n * @param {HTMLVideoElement} videoElement\n * @param {Preview} self\n */\n ;\n\n _proto.onAfterRender = function onAfterRender(videoElement, self) {\n // Assign muted attribute explicitly due to API issues\n videoElement.muted = self.data.video.attributes().autoplay;\n };\n\n return Preview;\n }(_preview);\n\n return Preview;\n});\n//# sourceMappingURL=preview.js.map","Magento_PageBuilder/js/content-type/video/converter/attribute/src.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([\"Magento_PageBuilder/js/utils/object\"], function (_object) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n var Src = /*#__PURE__*/function () {\n \"use strict\";\n\n function Src() {}\n\n var _proto = Src.prototype;\n\n /**\n * Convert value to internal format\n *\n * @param value string\n * @returns {string | object}\n */\n _proto.fromDom = function fromDom(value) {\n var fileRegExp = new RegExp(\"^(webm:|mp4:|ogv:)\");\n\n if (fileRegExp.test(value)) {\n return value.substr(fileRegExp.exec(value)[0].length);\n }\n\n return value;\n }\n /**\n * Convert value to knockout format\n *\n * @param name string\n * @param data Object\n * @returns {string}\n */\n ;\n\n _proto.toDom = function toDom(name, data) {\n var value = (0, _object.get)(data, name);\n\n if (value === undefined) {\n return \"\";\n }\n\n var youtubeRegExp = new RegExp(\"^(?:https?:\\/\\/|\\/\\/)?(?:www\\\\.|m\\\\.)?\" + \"(?:youtu\\\\.be\\/|youtube\\\\.com\\/(?:embed\\/|v\\/|watch\\\\?v=|watch\\\\?.+&v=))([\\\\w-]{11})(?![\\\\w-])\");\n var vimeoRegExp = new RegExp(\"https?:\\/\\/(?:www\\\\.|player\\\\.)?vimeo.com\\/(?:channels\\/\" + \"(?:\\\\w+\\/)?|groups\\/([^\\/]*)\\/videos\\/|album\\/(\\\\d+)\\/video\\/|video\\/|)(\\\\d+)(?:$|\\/|\\\\?)\");\n var fileRegExp = new RegExp(\"^(?:https:|http:)?\\\\/\\\\/.*[\\\\\\\\\\\\/].+\\\\.(webm|mp4|ogv)(?!\\w)\");\n\n if (youtubeRegExp.test(value)) {\n return \"https://www.youtube.com/embed/\" + youtubeRegExp.exec(value)[1];\n } else if (vimeoRegExp.test(value)) {\n return \"https://player.vimeo.com/video/\" + vimeoRegExp.exec(value)[3] + \"?title=0&byline=0&portrait=0\";\n } else if (fileRegExp.test(value)) {\n var result = fileRegExp.exec(value);\n return result[1] + \":\" + value;\n }\n\n return value;\n };\n\n return Src;\n }();\n\n return Src;\n});\n//# sourceMappingURL=src.js.map","Magento_PageBuilder/js/content-type/video/converter/attribute/autoplay.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([\"Magento_PageBuilder/js/utils/object\"], function (_object) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n var VideoSrc = /*#__PURE__*/function () {\n \"use strict\";\n\n function VideoSrc() {}\n\n var _proto = VideoSrc.prototype;\n\n /**\n * Convert value to internal format\n *\n * @param value string\n * @returns {string | object}\n */\n _proto.fromDom = function fromDom(value) {\n return value === \"true\" ? value : \"false\";\n }\n /**\n * Convert value to knockout format\n *\n * @param name string\n * @param data Object\n * @returns {boolean|string}\n */\n ;\n\n _proto.toDom = function toDom(name, data) {\n var value = (0, _object.get)(data, name);\n return value === \"true\" ? true : null;\n };\n\n return VideoSrc;\n }();\n\n return VideoSrc;\n});\n//# sourceMappingURL=autoplay.js.map","Magento_PageBuilder/js/content-type/video/converter/attribute/videosrc.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([\"Magento_PageBuilder/js/utils/object\"], function (_object) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n var VideoSrc = /*#__PURE__*/function () {\n \"use strict\";\n\n function VideoSrc() {}\n\n /**\n * Parse YouTube parameters from given URL and Autoplay setting from UI\n *\n * @param url string\n * @param data DataObject\n * @returns string\n * @private\n */\n VideoSrc.parseYoutubeGetParams = function parseYoutubeGetParams(url, data) {\n var acceptableYouTubeParams = [\"rel\", \"controls\", \"autoplay\", \"mute\", \"loop\", \"playlist\", \"cc_lang_pref\", \"cc_load_policy\", \"color\", \"disablekb\", \"end\", \"fs\", \"hl\", \"iv_load_policy\", \"modestbranding\", \"start\"];\n var a = document.createElement(\"a\");\n a.href = url;\n var urlGetParams = {};\n a.search.slice(a.search.indexOf(\"?\") + 1).split(\"&\").map(function (hash) {\n var _hash$split = hash.split(\"=\"),\n key = _hash$split[0],\n val = _hash$split[1];\n\n urlGetParams[key] = decodeURIComponent(val);\n });\n var filteredGetParams = {};\n\n for (var _i = 0, _acceptableYouTubePar = acceptableYouTubeParams; _i < _acceptableYouTubePar.length; _i++) {\n var param = _acceptableYouTubePar[_i];\n\n if (urlGetParams.hasOwnProperty(param)) {\n filteredGetParams[param] = urlGetParams[param];\n }\n }\n\n if (data.autoplay === \"true\") {\n filteredGetParams.autoplay = \"1\";\n filteredGetParams.mute = \"1\";\n } else {\n delete filteredGetParams.autoplay;\n delete filteredGetParams.mute;\n }\n\n var processedGetParams = [];\n\n for (var _param in filteredGetParams) {\n if (filteredGetParams.hasOwnProperty(_param)) {\n processedGetParams.push(encodeURI(_param + \"=\" + filteredGetParams[_param]));\n }\n }\n\n return processedGetParams.length > 0 ? \"?\" + processedGetParams.join(\"&\") : \"\";\n }\n /**\n * Convert value to internal format\n *\n * @param value string\n * @returns {string | object}\n */\n ;\n\n var _proto = VideoSrc.prototype;\n\n _proto.fromDom = function fromDom(value) {\n value = value.replace(/\\?autoplay=1&mute=1/g, \"\");\n value = value.replace(/&autoplay=1&mute=1/g, \"\");\n value = value.replace(/\\?title=0&byline=0&portrait=0/g, \"\");\n value = value.replace(/&autoplay=1&autopause=0&muted=1/g, \"\");\n return value;\n }\n /**\n * Convert value to knockout format\n *\n * @param name string\n * @param data Object\n * @returns {string}\n */\n ;\n\n _proto.toDom = function toDom(name, data) {\n var value = (0, _object.get)(data, name);\n\n if (value === undefined) {\n return \"\";\n }\n\n var youtubeRegExp = new RegExp(\"^(?:https?:\\/\\/|\\/\\/)?(?:www\\\\.|m\\\\.)?\" + \"(?:youtu\\\\.be\\/|youtube\\\\.com\\/(?:embed\\/|v\\/|watch\\\\?v=|watch\\\\?.+&v=))([\\\\w-]{11})(?![\\\\w-])\");\n var vimeoRegExp = new RegExp(\"https?:\\/\\/(?:www\\\\.|player\\\\.)?vimeo.com\\/(?:channels\\/\" + \"(?:\\\\w+\\/)?|groups\\/([^\\/]*)\\/videos\\/|album\\/(\\\\d+)\\/video\\/|video\\/|)(\\\\d+)(?:$|\\/|\\\\?)\");\n\n if (youtubeRegExp.test(value)) {\n return \"https://www.youtube.com/embed/\" + youtubeRegExp.exec(value)[1] + VideoSrc.parseYoutubeGetParams(value, data);\n } else if (vimeoRegExp.test(value)) {\n return \"https://player.vimeo.com/video/\" + vimeoRegExp.exec(value)[3] + \"?title=0&byline=0&portrait=0\" + (data.autoplay === \"true\" ? \"&autoplay=1&autopause=0&muted=1\" : \"\");\n }\n\n return value;\n };\n\n return VideoSrc;\n }();\n\n return VideoSrc;\n});\n//# sourceMappingURL=videosrc.js.map","Magento_PageBuilder/js/content-type/column/resize.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([\"Magento_PageBuilder/js/utils/array\"], function (_array) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n var Resize = /*#__PURE__*/function () {\n \"use strict\";\n\n function Resize(columnGroup, columnLine) {\n this.columnGroup = columnGroup;\n this.columnLine = columnLine;\n }\n /**\n * Get the grid size for this columnGroup\n *\n * @returns {number}\n */\n\n\n var _proto = Resize.prototype;\n\n _proto.getGridSize = function getGridSize() {\n return parseInt(this.columnGroup.dataStore.get(\"grid_size\").toString(), 10);\n }\n /**\n * Get the initial grid size for this columnGroup before it was updated\n *\n * @returns {number}\n */\n ;\n\n _proto.getInitialGridSize = function getInitialGridSize() {\n return parseInt(this.columnGroup.dataStore.get(\"initial_grid_size\", 0).toString(), 10);\n }\n /**\n * Get the smallest column width possible\n *\n * @param {number} gridSize\n * @returns {number}\n */\n ;\n\n _proto.getSmallestColumnWidth = function getSmallestColumnWidth(gridSize) {\n gridSize = gridSize || this.getInitialGridSize() || this.getGridSize();\n return this.getAcceptedColumnWidth(parseFloat((100 / gridSize).toString()).toFixed(Math.round(100 / gridSize) !== 100 / gridSize ? 8 : 0));\n }\n /**\n * Get an accepted column width to resolve rounding issues, e.g. turn 49.995% into 50%\n *\n * @param {string} width\n * @param {number} gridSize\n * @returns {number}\n */\n ;\n\n _proto.getAcceptedColumnWidth = function getAcceptedColumnWidth(width, gridSize) {\n gridSize = gridSize || this.getInitialGridSize() || this.getGridSize();\n var newWidth = 0;\n\n for (var i = gridSize; i > 0; i--) {\n var percentage = parseFloat((100 / gridSize * i).toFixed(Math.round(100 / gridSize * i) !== 100 / gridSize * i ? 8 : 0)); // Allow for rounding issues\n\n if (parseFloat(width) > percentage - 0.1 && parseFloat(width) < percentage + 0.1) {\n newWidth = percentage;\n break;\n }\n }\n\n return newWidth;\n }\n /**\n * Return the width of the column\n *\n * @param {ContentTypeCollectionInterface<ColumnPreview>} column\n * @returns {number}\n */\n ;\n\n _proto.getColumnWidth = function getColumnWidth(column) {\n return this.getAcceptedColumnWidth(column.dataStore.get(\"width\").toString());\n }\n /**\n * Get the total width of all columns in the column line\n *\n * @returns {number}\n */\n ;\n\n _proto.getColumnsWidth = function getColumnsWidth() {\n var _this = this;\n\n return this.getAcceptedColumnWidth(this.columnLine.children().map(function (column) {\n return _this.getColumnWidth(column);\n }).reduce(function (widthA, widthB) {\n return widthA + (widthB ? widthB : 0);\n }).toString());\n }\n /**\n * Determine the pixel position of every column that can be created within the group\n *\n * @param {ContentTypeCollectionInterface<ColumnPreview>} column\n * @param {GroupPositionCache} groupPosition\n * @returns {ColumnWidth[]}\n */\n ;\n\n _proto.determineColumnWidths = function determineColumnWidths(column, groupPosition) {\n var gridSize = this.getGridSize();\n var singleColumnWidth = groupPosition.outerWidth / gridSize;\n var adjacentColumn = getAdjacentColumn(column, \"+1\");\n var columnWidths = [];\n var columnLeft = column.preview.element.offset().left - parseInt(column.preview.element.css(\"margin-left\"), 10);\n var adjacentRightPosition = adjacentColumn.preview.element.offset().left + adjacentColumn.preview.element.outerWidth(true); // Determine the maximum size (in pixels) that this column can be dragged to\n\n var columnsToRight = column.parentContentType.children().length - (getColumnIndexInGroup(column) + 1);\n var leftMaxWidthFromChildren = groupPosition.left + groupPosition.outerWidth - columnsToRight * singleColumnWidth + 10;\n var rightMaxWidthFromChildren = groupPosition.left + (column.parentContentType.children().length - columnsToRight) * singleColumnWidth - 10; // Due to rounding we add a threshold of 10\n // Iterate through the amount of columns generating the position for both left & right interactions\n\n for (var i = gridSize; i > 0; i--) {\n var position = Math.round(columnLeft + singleColumnWidth * i);\n\n if (position > Math.round(leftMaxWidthFromChildren)) {\n continue;\n }\n\n columnWidths.push({\n forColumn: \"left\",\n // These positions are for the left column in the pair\n name: i + \"/\" + gridSize,\n position: position,\n width: getRoundedColumnWidth(100 / gridSize * i)\n });\n }\n\n for (var _i = 1; _i < gridSize; _i++) {\n var _position = Math.floor(adjacentRightPosition - _i * singleColumnWidth);\n\n if (_position < Math.floor(rightMaxWidthFromChildren)) {\n continue;\n } // The right interaction is only used when we're crushing a column that isn't adjacent\n\n\n columnWidths.push({\n forColumn: \"right\",\n // These positions are for the left column in the pair\n name: _i + \"/\" + gridSize,\n position: _position,\n width: getRoundedColumnWidth(100 / gridSize * _i)\n });\n }\n\n return columnWidths;\n }\n /**\n * Find a column which can be shrunk for the current resize action\n *\n * @param {ContentTypeCollectionInterface<ColumnPreview>} column\n * @param {\"left\" | \"right\"} direction\n * @returns {ContentTypeCollectionInterface<ColumnPreview>}\n */\n ;\n\n _proto.findShrinkableColumnForResize = function findShrinkableColumnForResize(column, direction) {\n var _this2 = this;\n\n var currentIndex = getColumnIndexInGroup(column);\n var columnItemsArray = column.parentContentType.children();\n var searchArray;\n\n switch (direction) {\n case \"right\":\n searchArray = columnItemsArray.slice(currentIndex + 1);\n break;\n\n case \"left\":\n searchArray = columnItemsArray.slice(0).reverse().slice(columnItemsArray.length - currentIndex);\n break;\n }\n\n return searchArray.find(function (groupColumn) {\n return _this2.getColumnWidth(groupColumn) > _this2.getSmallestColumnWidth();\n });\n }\n /**\n * Find a shrinkable column outwards from the current column\n *\n * @param {ContentTypeCollectionInterface<ColumnPreview>} column\n * @returns {ContentTypeCollectionInterface<ColumnPreview>}\n */\n ;\n\n _proto.findShrinkableColumn = function findShrinkableColumn(column) {\n var _this3 = this;\n\n return (0, _array.outwardSearch)(column.parentContentType.children(), getColumnIndexInGroup(column), function (neighbourColumn) {\n return _this3.getColumnWidth(neighbourColumn) > _this3.getSmallestColumnWidth();\n });\n }\n /**\n * Find a shrinkable column of a greater size outwards from the current column\n *\n * @param {ContentTypeCollectionInterface<ColumnPreview>} column\n * @returns {ContentTypeCollectionInterface<ColumnPreview>}\n */\n ;\n\n _proto.findBiggerShrinkableColumn = function findBiggerShrinkableColumn(column) {\n var _this4 = this;\n\n return (0, _array.outwardSearch)(column.parentContentType.children(), getColumnIndexInGroup(column), function (neighbourColumn) {\n return _this4.getColumnWidth(neighbourColumn) > _this4.getColumnWidth(column);\n });\n }\n /**\n * Calculate the ghost size for the resizing action\n *\n * @param {GroupPositionCache} groupPosition\n * @param {number} currentPos\n * @param {ContentTypeCollectionInterface<ColumnPreview>} column\n * @param {string} modifyColumnInPair\n * @param {MaxGhostWidth} maxGhostWidth\n * @returns {number}\n */\n ;\n\n _proto.calculateGhostWidth = function calculateGhostWidth(groupPosition, currentPos, column, modifyColumnInPair, maxGhostWidth) {\n var ghostWidth = currentPos - groupPosition.left;\n\n switch (modifyColumnInPair) {\n case \"left\":\n var singleColumnWidth = column.preview.element.position().left + groupPosition.outerWidth / this.getGridSize(); // Don't allow the ghost widths be less than the smallest column\n\n if (ghostWidth <= singleColumnWidth) {\n ghostWidth = singleColumnWidth;\n }\n\n if (currentPos >= maxGhostWidth.left) {\n ghostWidth = maxGhostWidth.left - groupPosition.left;\n }\n\n break;\n\n case \"right\":\n if (currentPos <= maxGhostWidth.right) {\n ghostWidth = maxGhostWidth.right - groupPosition.left;\n }\n\n break;\n }\n\n return ghostWidth;\n }\n /**\n * Determine which column in the group should be adjusted for the current resize action\n *\n * @param {number} currentPos\n * @param {ContentTypeCollectionInterface<ColumnPreview>} column\n * @param {ResizeHistory} history\n * @returns {[ContentTypeCollectionInterface<ColumnPreview>, string, string]}\n */\n ;\n\n _proto.determineAdjustedColumn = function determineAdjustedColumn(currentPos, column, history) {\n var modifyColumnInPair = \"left\";\n var usedHistory;\n var resizeColumnLeft = column.preview.element.offset().left - parseInt(column.preview.element.css(\"margin-left\"), 10);\n var resizeColumnWidth = column.preview.element.outerWidth(true);\n var resizeHandlePosition = resizeColumnLeft + resizeColumnWidth;\n var adjustedColumn;\n\n if (currentPos >= resizeHandlePosition) {\n // Get the history for the opposite direction of resizing\n if (history.left.length > 0) {\n usedHistory = \"left\";\n adjustedColumn = history.left.reverse()[0].adjustedColumn;\n modifyColumnInPair = history.left.reverse()[0].modifyColumnInPair;\n } else {\n // If we're increasing the width of our column we need to locate a column that can shrink to the\n // right\n adjustedColumn = this.findShrinkableColumnForResize(column, \"right\");\n }\n } else {\n if (this.getColumnWidth(column) <= this.getSmallestColumnWidth()) {\n adjustedColumn = this.findShrinkableColumnForResize(column, \"left\");\n\n if (adjustedColumn) {\n modifyColumnInPair = \"right\";\n }\n } else if (history.right.length > 0) {\n usedHistory = \"right\";\n adjustedColumn = history.right.reverse()[0].adjustedColumn;\n modifyColumnInPair = history.right.reverse()[0].modifyColumnInPair;\n } else {\n // If we're shrinking our column we can just increase the adjacent column\n adjustedColumn = getAdjacentColumn(column, \"+1\");\n }\n }\n\n return [adjustedColumn, modifyColumnInPair, usedHistory];\n }\n /**\n * Resize a column to a specific width\n *\n * @param {ContentTypeCollectionInterface<Preview>} column\n * @param {number} width\n * @param {ContentTypeCollectionInterface<Preview>} shrinkableColumn\n */\n ;\n\n _proto.resizeColumn = function resizeColumn(column, width, shrinkableColumn) {\n var current = this.getColumnWidth(column);\n var difference = (parseFloat(width.toString()) - current).toFixed(8); // Don't run the update if we've already modified the column\n\n if (current === parseFloat(width.toString()) || parseFloat(width.toString()) < this.getSmallestColumnWidth()) {\n return;\n } // Also shrink the closest shrinkable column\n\n\n var allowedToShrink = true;\n\n if (difference && shrinkableColumn) {\n var currentShrinkable = this.getColumnWidth(shrinkableColumn);\n var shrinkableSize = this.getAcceptedColumnWidth((currentShrinkable + -difference).toString()); // Ensure the column we're crushing is not becoming the same size, and it's not less than the smallest width\n\n if (currentShrinkable === parseFloat(shrinkableSize.toString()) || parseFloat(shrinkableSize.toString()) < this.getSmallestColumnWidth()) {\n allowedToShrink = false;\n } else {\n // Ensure we're not creating more columns width than the grid can support\n if (this.gridSupportsResize(column, width, shrinkableColumn, shrinkableSize)) {\n updateColumnWidth(shrinkableColumn, shrinkableSize);\n } else {\n allowedToShrink = false;\n }\n }\n }\n\n if (allowedToShrink) {\n updateColumnWidth(column, width);\n }\n }\n /**\n * Determine if the grid supports the new proposed grid size\n *\n * @param {ContentTypeCollectionInterface<Preview>} column\n * @param {number} newWidth\n * @param {ContentTypeCollectionInterface<Preview>} shrinkableColumn\n * @param {number} shrinkableColumnNewWidth\n * @returns {boolean}\n */\n ;\n\n _proto.gridSupportsResize = function gridSupportsResize(column, newWidth, shrinkableColumn, shrinkableColumnNewWidth) {\n var _this5 = this;\n\n // Determine the total width of all other columns in the grid, excluding the ones we plan to resize\n var otherColumnsWidth = column.parentContentType.getChildren()().filter(function (gridColumn) {\n return gridColumn !== column && shrinkableColumn && gridColumn !== shrinkableColumn;\n }).map(function (otherColumn) {\n return _this5.getColumnWidth(otherColumn);\n }).reduce(function (a, b) {\n return a + b;\n }, 0); // Determine if the new total grid size will be 100%, with 1 for margin of error with rounding\n\n return comparator(otherColumnsWidth + newWidth + (shrinkableColumnNewWidth ? shrinkableColumnNewWidth : 0), 100, 0.1);\n };\n\n return Resize;\n }();\n /**\n * Retrieve the index of the column within it's group\n * @deprecated use getColumnIndexInLine\n * @param {ContentTypeCollectionInterface<ColumnPreview>} column\n * @returns {number}\n */\n\n\n function getColumnIndexInGroup(column) {\n return column.parentContentType.children().indexOf(column);\n }\n /**\n * Retrieve the index of the column within it's column line\n *\n * @param {ContentTypeCollectionInterface<ColumnPreview>} column\n * @returns {number}\n */\n\n\n function getColumnIndexInLine(column) {\n return column.parentContentType.children().indexOf(column);\n }\n /**\n * Retrieve the adjacent column based on a direction of +1 or -1\n *\n * @param {ContentTypeCollectionInterface<Preview>} column\n * @param {\"+1\" | \"-1\"} direction\n * @returns {ContentTypeCollectionInterface<Preview>}\n */\n\n\n function getAdjacentColumn(column, direction) {\n var currentIndex = getColumnIndexInGroup(column);\n\n if (typeof column.parentContentType.children()[currentIndex + parseInt(direction, 10)] !== \"undefined\") {\n return column.parentContentType.children()[currentIndex + parseInt(direction, 10)];\n }\n\n return null;\n }\n /**\n * Determine the max ghost width based on the calculated columns\n *\n * @param {ColumnWidth[]} columnWidths\n * @returns {MaxGhostWidth}\n */\n\n\n function determineMaxGhostWidth(columnWidths) {\n var leftColumns = columnWidths.filter(function (width) {\n return width.forColumn === \"left\";\n });\n var rightColumns = columnWidths.filter(function (width) {\n return width.forColumn === \"right\";\n });\n return {\n left: leftColumns[0].position,\n right: rightColumns[rightColumns.length - 1].position\n };\n }\n /**\n * Return the column width to 8 decimal places if it's not a whole number\n *\n * @param {number} width\n * @returns {string}\n */\n\n\n function getRoundedColumnWidth(width) {\n return Number(width.toFixed(Math.round(width) !== width ? 8 : 0));\n }\n /**\n * Compare if two numbers are within a certain threshold of each other\n *\n * comparator(10,11,2) => true\n * comparator(1.1,1.11,0.5) => true\n *\n * @param {number} num1\n * @param {number} num2\n * @param {number} threshold\n * @returns {boolean}\n */\n\n\n function comparator(num1, num2, threshold) {\n return num1 > num2 - threshold / 2 && num1 < num2 + threshold / 2;\n }\n /**\n * Update the width of a column\n *\n * @param {ContentTypeCollectionInterface<ColumnPreview>} column\n * @param {number} width\n */\n\n\n function updateColumnWidth(column, width) {\n column.dataStore.set(\"width\", parseFloat(width.toString()) + \"%\");\n }\n\n return Object.assign(Resize, {\n getColumnIndexInGroup: getColumnIndexInGroup,\n getColumnIndexInLine: getColumnIndexInLine,\n getAdjacentColumn: getAdjacentColumn,\n determineMaxGhostWidth: determineMaxGhostWidth,\n getRoundedColumnWidth: getRoundedColumnWidth,\n comparator: comparator,\n updateColumnWidth: updateColumnWidth\n });\n});\n//# sourceMappingURL=resize.js.map","Magento_PageBuilder/js/content-type/column/preview.js":"/*eslint-disable */\n/* jscs:disable */\n\nfunction _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\n\nfunction _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\ndefine([\"jquery\", \"knockout\", \"mage/translate\", \"Magento_PageBuilder/js/events\", \"Magento_Ui/js/modal/alert\", \"Magento_PageBuilder/js/config\", \"Magento_PageBuilder/js/content-type-factory\", \"Magento_PageBuilder/js/content-type-menu/option\", \"Magento_PageBuilder/js/content-type/column-group/grid-size\", \"Magento_PageBuilder/js/content-type/column-line/preview\", \"Magento_PageBuilder/js/content-type/preview-collection\", \"Magento_PageBuilder/js/content-type/column/resize\"], function (_jquery, _knockout, _translate, _events, _alert, _config, _contentTypeFactory, _option, _gridSize, _preview, _previewCollection, _resize) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * @api\n */\n var Preview = /*#__PURE__*/function (_previewCollection2) {\n \"use strict\";\n\n _inheritsLoose(Preview, _previewCollection2);\n\n /**\n * Fields that should not be considered when evaluating whether an object has been configured.\n *\n * @see {Preview.isConfigured}\n * @type {[string]}\n */\n\n /**\n * @param {ContentTypeInterface} contentType\n * @param {ContentTypeConfigInterface} config\n * @param {ObservableUpdater} observableUpdater\n */\n function Preview(contentType, config, observableUpdater) {\n var _this;\n\n _this = _previewCollection2.call(this, contentType, config, observableUpdater) || this; // Update the width label for the column\n\n _this.resizing = _knockout.observable(false);\n _this.fieldsToIgnoreOnRemove = [\"width\"];\n\n _this.contentType.dataStore.subscribe(_this.updateColumnWidthClass.bind(_assertThisInitialized(_this)), \"width\");\n\n _this.contentType.dataStore.subscribe(_this.updateDisplayLabel.bind(_assertThisInitialized(_this)), \"width\");\n\n _this.contentType.dataStore.subscribe(_this.triggerChildren.bind(_assertThisInitialized(_this)), \"width\");\n\n _this.contentType.parentContentType.dataStore.subscribe(_this.updateDisplayLabel.bind(_assertThisInitialized(_this)), \"grid_size\"); // Update the column number for the column\n\n\n _this.contentType.parentContentType.children.subscribe(_this.updateDisplayLabel.bind(_assertThisInitialized(_this)));\n\n return _this;\n }\n /**\n * Get background image url base on the viewport.\n *\n * @returns {string}\n */\n\n\n var _proto = Preview.prototype;\n\n _proto.getBackgroundImage = function getBackgroundImage() {\n var mobileImage = this.contentType.dataStore.get(\"mobile_image\");\n var desktopImage = this.contentType.dataStore.get(\"background_image\");\n var backgroundImage = this.viewport() === \"mobile\" && mobileImage.length ? mobileImage : desktopImage;\n return backgroundImage.length ? \"url(\\\"\" + backgroundImage[0].url + \"\\\")\" : \"none\";\n }\n /**\n * Bind events\n */\n ;\n\n _proto.bindEvents = function bindEvents() {\n var _this2 = this;\n\n _previewCollection2.prototype.bindEvents.call(this);\n\n _events.on(\"column:moveAfter\", function (args) {\n if (args.contentType.id === _this2.contentType.id) {\n _this2.updateDisplayLabel();\n }\n\n _this2.resetRemoveOnLastColumn(args.targetParent);\n\n _this2.resetRemoveOnLastColumn(args.sourceParent);\n });\n\n _events.on(\"column:initializeAfter\", function (args) {\n _this2.resetRemoveOnLastColumn(args.columnLine);\n });\n\n _events.on(\"column:dropAfter\", function (args) {\n _this2.resetRemoveOnLastColumn(_this2.contentType.parentContentType);\n });\n\n _events.on(\"column:duplicateAfter\", function (args) {\n _this2.resetRemoveOnLastColumn(args.duplicateContentType.parentContentType);\n });\n\n _events.on(\"column:removeAfter\", function (args) {\n if (args.contentType.id === _this2.contentType.id) {\n _this2.resetRemoveOnLastColumn(args.parentContentType);\n }\n });\n }\n /**\n * Make a reference to the element in the column\n *\n * @param element\n */\n ;\n\n _proto.initColumn = function initColumn(element) {\n this.element = (0, _jquery)(element);\n this.updateColumnWidthClass();\n\n _events.trigger(\"column:initializeAfter\", {\n column: this.contentType,\n element: (0, _jquery)(element),\n columnLine: this.contentType.parentContentType,\n columnGroup: this.contentType.parentContentType.parentContentType\n });\n\n this.updateDisplayLabel();\n }\n /**\n * Return an array of options\n *\n * @returns {OptionsInterface}\n */\n ;\n\n _proto.retrieveOptions = function retrieveOptions() {\n var options = _previewCollection2.prototype.retrieveOptions.call(this);\n\n options.move = new _option({\n preview: this,\n icon: \"<i class='icon-admin-pagebuilder-handle'></i>\",\n title: (0, _translate)(\"Move\"),\n classes: [\"move-column\"],\n sort: 10\n });\n return options;\n }\n /**\n * Init the resize handle for the resizing functionality\n *\n * @param handle\n */\n ;\n\n _proto.bindResizeHandle = function bindResizeHandle(handle) {\n _events.trigger(\"column:resizeHandleBindAfter\", {\n column: this.contentType,\n handle: (0, _jquery)(handle),\n columnLine: this.contentType.parentContentType\n });\n }\n /**\n * Wrap the current column in a group if it not in a column-group\n *\n * @returns {Promise<ContentTypeCollectionInterface>}\n */\n ;\n\n _proto.createColumnGroup = function createColumnGroup() {\n var _this3 = this;\n\n if (this.contentType.parentContentType.config.name !== \"column-group\") {\n var index = this.contentType.parentContentType.children().indexOf(this.contentType); // Remove child instantly to stop content jumping around\n\n this.contentType.parentContentType.removeChild(this.contentType); // Create a new instance of column group to wrap our columns with\n\n var defaultGridSize = (0, _gridSize.getDefaultGridSize)();\n return (0, _contentTypeFactory)(_config.getContentTypeConfig(\"column-group\"), this.contentType.parentContentType, this.contentType.stageId, {\n grid_size: defaultGridSize\n }).then(function (columnGroup) {\n var col1Width = (Math.ceil(defaultGridSize / 2) * 100 / defaultGridSize).toFixed(Math.round(100 / defaultGridSize) !== 100 / defaultGridSize ? 8 : 0);\n return Promise.all([(0, _contentTypeFactory)(_this3.contentType.config, columnGroup, columnGroup.stageId, {\n width: col1Width + \"%\"\n }), (0, _contentTypeFactory)(_this3.contentType.config, columnGroup, columnGroup.stageId, {\n width: 100 - parseFloat(col1Width) + \"%\"\n })]).then(function (columns) {\n columnGroup.addChild(columns[0], 0);\n columnGroup.addChild(columns[1], 1);\n\n _this3.contentType.parentContentType.addChild(columnGroup, index);\n\n _this3.fireMountEvent(columnGroup, columns[0], columns[1]);\n\n return columnGroup;\n });\n });\n }\n }\n /**\n * Duplicate a child of the current instance\n *\n * @param {ContentTypeCollectionInterface<Preview>} contentType\n * @param {boolean} autoAppend\n * @returns {Promise<ContentTypeCollectionInterface> | void}\n */\n ;\n\n _proto.clone = function clone(contentType, autoAppend) {\n if (autoAppend === void 0) {\n autoAppend = true;\n }\n\n var resizeUtils = this.contentType.parentContentType.preview.getResizeUtils(); // Are we duplicating from a container content type?\n\n if (contentType.config.name !== \"column\" || this.contentType.parentContentType.children().length === 0 || this.contentType.parentContentType.children().length > 0 && resizeUtils.getColumnsWidth() < 100) {\n return _previewCollection2.prototype.clone.call(this, contentType, autoAppend);\n }\n\n var biggestShrinkableColumn = resizeUtils.findBiggerShrinkableColumn(contentType);\n\n if (biggestShrinkableColumn) {\n var shrinkableClone = _previewCollection2.prototype.clone.call(this, contentType, autoAppend);\n\n if (shrinkableClone) {\n var newShrinkableColumnWidth = resizeUtils.getColumnWidth(biggestShrinkableColumn) - resizeUtils.getColumnWidth(contentType);\n var duplicateColumnWidth = resizeUtils.getColumnWidth(contentType);\n shrinkableClone.then(function (duplicateContentType) {\n (0, _resize.updateColumnWidth)(biggestShrinkableColumn, resizeUtils.getAcceptedColumnWidth(newShrinkableColumnWidth.toString()));\n (0, _resize.updateColumnWidth)(duplicateContentType, duplicateColumnWidth);\n return duplicateContentType;\n });\n }\n\n return;\n } // Attempt to split the current column into parts\n\n\n var splitTimes = Math.round(resizeUtils.getColumnWidth(contentType) / resizeUtils.getSmallestColumnWidth());\n\n if (splitTimes > 1) {\n var splitClone = _previewCollection2.prototype.clone.call(this, contentType, autoAppend);\n\n if (splitClone) {\n splitClone.then(function (duplicateContentType) {\n /**\n * Distribute the width across the original & duplicated columns, if the we have an odd number of\n * split times apply it to the original.\n */\n var originalWidth = (Math.floor(splitTimes / 2) + splitTimes % 2) * resizeUtils.getSmallestColumnWidth();\n var duplicateWidth = Math.floor(splitTimes / 2) * resizeUtils.getSmallestColumnWidth();\n (0, _resize.updateColumnWidth)(contentType, resizeUtils.getAcceptedColumnWidth(originalWidth.toString()));\n (0, _resize.updateColumnWidth)(duplicateContentType, resizeUtils.getAcceptedColumnWidth(duplicateWidth.toString()));\n return duplicateContentType;\n });\n }\n } else {\n // Conduct an outward search on the children to locate a suitable shrinkable column\n var shrinkableColumn = resizeUtils.findShrinkableColumn(contentType);\n\n if (shrinkableColumn) {\n var _shrinkableClone = _previewCollection2.prototype.clone.call(this, contentType, autoAppend);\n\n if (_shrinkableClone) {\n _shrinkableClone.then(function (duplicateContentType) {\n (0, _resize.updateColumnWidth)(shrinkableColumn, resizeUtils.getAcceptedColumnWidth((resizeUtils.getColumnWidth(shrinkableColumn) - resizeUtils.getSmallestColumnWidth()).toString()));\n (0, _resize.updateColumnWidth)(duplicateContentType, resizeUtils.getSmallestColumnWidth());\n return duplicateContentType;\n });\n }\n } else {\n // If we aren't able to duplicate inform the user why\n (0, _alert)({\n content: (0, _translate)(\"There is no free space within the column group to perform this action.\"),\n title: (0, _translate)(\"Unable to duplicate column\")\n });\n }\n }\n }\n /**\n * Update the display label for the column\n */\n ;\n\n _proto.updateDisplayLabel = function updateDisplayLabel() {\n if (this.contentType.parentContentType.preview instanceof _preview) {\n var newWidth = parseFloat(this.contentType.dataStore.get(\"width\").toString());\n var grandParent = this.contentType.parentContentType.parentContentType;\n var columnGroupPreview = grandParent.preview;\n var gridSize = columnGroupPreview.gridSize();\n var newLabel = Math.round(newWidth / (100 / gridSize)) + \"/\" + gridSize;\n var columnIndex = this.contentType.parentContentType.children().indexOf(this.contentType);\n var columnNumber = columnIndex !== -1 ? columnIndex + 1 + \" \" : \"\";\n this.displayLabel((0, _translate)(\"Column\") + \" \" + columnNumber + \"(\" + newLabel + \")\");\n }\n }\n /**\n * Reset remove option on all columns within a column-group depending on the number of remaining child columns\n * @param parentContentType\n */\n ;\n\n _proto.resetRemoveOnLastColumn = function resetRemoveOnLastColumn(parentContentType) {\n if (!parentContentType) {\n // can happen if the column is moved within the same column group\n return;\n }\n\n if (parentContentType.config.name !== \"column-line\") {\n // for legacy content in preview mode before stage is initialized, the parent may not be a column line\n return;\n }\n\n var siblings = parentContentType.children();\n var siblingColumnLines = parentContentType.parentContentType.children();\n var totalColumnCount = 0;\n siblingColumnLines.forEach(function (columnLine) {\n var columns = columnLine.children();\n columns.forEach(function (column) {\n totalColumnCount++;\n });\n });\n var isRemoveDisabled = totalColumnCount <= 1;\n siblingColumnLines.forEach(function (columnLine) {\n var columns = columnLine.children();\n columns.forEach(function (column) {\n var removeOption = column.preview.getOptions().getOption(\"remove\");\n removeOption.isDisabled(isRemoveDisabled);\n });\n });\n }\n /**\n * Syncs the column-width-* class on the children-wrapper with the current width to the nearest tenth rounded up\n */\n ;\n\n _proto.updateColumnWidthClass = function updateColumnWidthClass() {\n // Only update once instantiated\n if (!this.element) {\n return;\n }\n\n var currentClass = this.element.attr(\"class\").match(/(?:^|\\s)(column-width-\\d{1,3})(?:$|\\s)/);\n\n if (currentClass !== null) {\n this.element.removeClass(currentClass[1]);\n }\n\n var roundedWidth = Math.ceil(parseFloat(this.contentType.dataStore.get(\"width\").toString()) / 10) * 10;\n this.element.addClass(\"column-width-\" + roundedWidth);\n }\n /**\n * Return selected element styles\n *\n * @param element\n * @param styleProperties\n */\n ;\n\n _proto.getStyle = function getStyle(element, styleProperties) {\n var stylesObject = element.style();\n return styleProperties.reduce(function (obj, key) {\n var _extends2;\n\n return _extends({}, obj, (_extends2 = {}, _extends2[key] = stylesObject[key], _extends2));\n }, {});\n }\n /**\n * Return element styles without selected\n *\n * @param element\n * @param styleProperties\n */\n ;\n\n _proto.getStyleWithout = function getStyleWithout(element, styleProperties) {\n var stylesObject = element.style();\n return Object.keys(stylesObject).filter(function (key) {\n return !styleProperties.includes(key);\n }).reduce(function (obj, key) {\n var _extends3;\n\n return _extends({}, obj, (_extends3 = {}, _extends3[key] = stylesObject[key], _extends3));\n }, {});\n }\n /**\n * Fire the mount event for content types\n *\n * @param {ContentTypeInterface[]} contentTypes\n */\n ;\n\n _proto.fireMountEvent = function fireMountEvent() {\n for (var _len = arguments.length, contentTypes = new Array(_len), _key = 0; _key < _len; _key++) {\n contentTypes[_key] = arguments[_key];\n }\n\n contentTypes.forEach(function (contentType) {\n _events.trigger(\"contentType:mountAfter\", {\n id: contentType.id,\n contentType: contentType\n });\n\n _events.trigger(contentType.config.name + \":mountAfter\", {\n id: contentType.id,\n contentType: contentType\n });\n });\n }\n /**\n * Delegate trigger call on children elements.\n */\n ;\n\n _proto.triggerChildren = function triggerChildren() {\n if (this.contentType.parentContentType.preview instanceof _preview) {\n var newWidth = parseFloat(this.contentType.dataStore.get(\"width\").toString());\n this.delegate(\"trigger\", \"columnWidthChangeAfter\", {\n width: newWidth\n });\n }\n };\n\n return Preview;\n }(_previewCollection);\n\n return Preview;\n});\n//# sourceMappingURL=preview.js.map","Magento_PageBuilder/js/content-type/column/converter/style/margins.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([\"underscore\", \"Magento_PageBuilder/js/utils/object\"], function (_underscore, _object) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n var Margins = /*#__PURE__*/function () {\n \"use strict\";\n\n function Margins() {}\n\n var _proto = Margins.prototype;\n\n /**\n * Convert value to internal format\n *\n * @param value string\n * @returns {string | object}\n */\n _proto.fromDom = function fromDom(value) {\n if (undefined !== value.margin) {\n return {\n margin: {\n top: value.margin.top.replace(\"px\", \"\"),\n left: value.margin.left.replace(\"px\", \"\"),\n right: value.margin.right.replace(\"px\", \"\"),\n bottom: value.margin.bottom.replace(\"px\", \"\")\n }\n };\n }\n\n return {};\n }\n /**\n * Convert value to knockout format\n *\n * @param {string} name\n * @param {DataObject} data\n * @returns {string | object}\n */\n ;\n\n _proto.toDom = function toDom(name, data) {\n var result = {};\n var value = (0, _object.get)(data, name);\n\n if (value && _underscore.isString(value)) {\n value = JSON.parse(value);\n }\n\n if (value && undefined !== value.margin) {\n result.marginLeft = value.margin.left ? value.margin.left + \"px\" : \"\";\n result.marginTop = value.margin.top ? value.margin.top + \"px\" : \"\";\n result.marginRight = (value.margin.right && parseInt(value.margin.right, 10) !== 0 ? value.margin.right : 1) + \"px\";\n result.marginBottom = value.margin.bottom ? value.margin.bottom + \"px\" : \"\";\n }\n\n return result;\n };\n\n return Margins;\n }();\n\n return Margins;\n});\n//# sourceMappingURL=margins.js.map","Magento_PageBuilder/js/content-type/slider/preview.js":"/*eslint-disable */\n/* jscs:disable */\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\n\nfunction _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\ndefine([\"jquery\", \"knockout\", \"mage/translate\", \"Magento_PageBuilder/js/events\", \"slick\", \"underscore\", \"Magento_PageBuilder/js/binding/focus\", \"Magento_PageBuilder/js/config\", \"Magento_PageBuilder/js/content-type-factory\", \"Magento_PageBuilder/js/content-type-menu/hide-show-option\", \"Magento_PageBuilder/js/content-type-menu/option\", \"Magento_PageBuilder/js/utils/delay-until\", \"Magento_PageBuilder/js/utils/promise-deferred\", \"Magento_PageBuilder/js/content-type/preview-collection\"], function (_jquery, _knockout, _translate, _events, _slick, _underscore, _focus, _config, _contentTypeFactory, _hideShowOption, _option, _delayUntil, _promiseDeferred, _previewCollection) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * @api\n */\n var Preview = /*#__PURE__*/function (_previewCollection2) {\n \"use strict\";\n\n _inheritsLoose(Preview, _previewCollection2);\n\n /**\n * Define keys which when changed should not trigger the slider to be rebuilt\n *\n * @type {string[]}\n */\n\n /**\n * @param {ContentTypeCollectionInterface} contentType\n * @param {ContentTypeConfigInterface} config\n * @param {ObservableUpdater} observableUpdater\n */\n function Preview(contentType, config, observableUpdater) {\n var _this;\n\n _this = _previewCollection2.call(this, contentType, config, observableUpdater) || this; // Wait for the tabs instance to mount and the container to be ready\n\n _this.focusedSlide = _knockout.observable();\n _this.activeSlide = _knockout.observable(0);\n _this.events = {\n columnWidthChangeAfter: \"onColumnResize\"\n };\n _this.ready = false;\n _this.mountAfterDeferred = (0, _promiseDeferred)();\n _this.afterChildrenRenderDeferred = (0, _promiseDeferred)();\n _this.buildSlickDebounce = _underscore.debounce(_this.buildSlick.bind(_assertThisInitialized(_this)), 10);\n _this.ignoredKeysForBuild = [\"display\", \"margins_and_padding\", \"border\", \"border_color\", \"border_radius\", \"border_width\", \"css_classes\", \"name\", \"text_align\"];\n Promise.all([_this.afterChildrenRenderDeferred.promise, _this.mountAfterDeferred.promise]).then(function (_ref) {\n var element = _ref[0],\n expectedChildren = _ref[1];\n // We always create 1 tab when dropping tabs into the instance\n expectedChildren = expectedChildren || 1; // Wait until all children's DOM elements are present before building the tabs instance\n\n (0, _delayUntil)(function () {\n _this.element = element;\n _this.childSubscribe = _this.contentType.children.subscribe(_this.buildSlickDebounce);\n _this.previousData = _this.contentType.dataStore.getState();\n\n _this.contentType.dataStore.subscribe(function (data) {\n if (_this.hasDataChanged(_this.previousData, data)) {\n _this.buildSlickDebounce();\n }\n\n _this.previousData = data;\n });\n\n _this.buildSlick(); // Redraw slide after content type gets redrawn\n\n\n _events.on(\"contentType:redrawAfter\", function (args) {\n var $element = (0, _jquery)(_this.element);\n\n if (args.element && _this.element && $element.closest(args.element).length) {\n $element.slick(\"setPosition\");\n }\n }); // Set the stage to interacting when a slide is focused\n\n\n _this.focusedSlideSubscriber = _this.focusedSlide.subscribe(function (value) {\n if (value !== null) {\n _events.trigger(\"stage:interactionStart\");\n } else {\n _events.trigger(\"stage:interactionStop\");\n }\n });\n\n _events.on(\"stage:\" + _this.contentType.stageId + \":fullScreenModeChangeAfter\", _this.onColumnResize.bind(_assertThisInitialized(_this), [true]));\n\n _events.on(\"stage:\" + _this.contentType.stageId + \":viewportChangeAfter\", function () {\n if (_this.element) {\n (0, _jquery)(_this.element).slick(\"setPosition\");\n\n _this.checkWidth();\n }\n });\n }, function () {\n return (0, _jquery)(element).find(\".pagebuilder-slide\").length === expectedChildren;\n });\n });\n return _this;\n }\n /**\n * Return an array of options\n *\n * @returns {OptionsInterface}\n */\n\n\n var _proto = Preview.prototype;\n\n _proto.retrieveOptions = function retrieveOptions() {\n var options = _previewCollection2.prototype.retrieveOptions.call(this);\n\n options.add = new _option({\n preview: this,\n icon: \"<i class='icon-pagebuilder-add'></i>\",\n title: (0, _translate)(\"Add\"),\n action: this.addSlide,\n classes: [\"add-child\"],\n sort: 10\n });\n options.hideShow = new _hideShowOption({\n preview: this,\n icon: _hideShowOption.showIcon,\n title: _hideShowOption.showText,\n action: this.onOptionVisibilityToggle,\n classes: [\"hide-show-content-type\"],\n sort: 40\n });\n return options;\n }\n /**\n * Set an active slide for navigation dot\n *\n * @param slideIndex\n */\n ;\n\n _proto.setActiveSlide = function setActiveSlide(slideIndex) {\n this.activeSlide(slideIndex);\n }\n /**\n * Set the focused slide\n *\n * @param {number} slideIndex\n * @param {boolean} force\n */\n ;\n\n _proto.setFocusedSlide = function setFocusedSlide(slideIndex, force) {\n if (force === void 0) {\n force = false;\n }\n\n if (force) {\n this.focusedSlide(null);\n }\n\n this.focusedSlide(slideIndex);\n }\n /**\n * Unset focused slide on focusout event.\n *\n * @param {PreviewCollection} data\n * @param {JQueryEventObject} event\n */\n ;\n\n _proto.onFocusOut = function onFocusOut(data, event) {\n var relatedTarget = event.relatedTarget;\n\n if (!relatedTarget && document.activeElement && !(document.activeElement instanceof HTMLBodyElement)) {\n relatedTarget = document.activeElement;\n }\n\n if (!relatedTarget) {\n this.setFocusedSlide(null);\n return;\n }\n\n var $relatedTarget = (0, _jquery)(relatedTarget);\n var isRelatedTargetDescendantOfNavigation = $relatedTarget.closest(this.navigationElement).length;\n var isFocusedOnAnotherSlideInThisSlider = $relatedTarget.hasClass(\"navigation-dot-anchor\") && isRelatedTargetDescendantOfNavigation;\n\n if (isFocusedOnAnotherSlideInThisSlider) {\n _events.trigger(\"stage:interactionStop\");\n } else if (!isRelatedTargetDescendantOfNavigation) {\n this.setFocusedSlide(null);\n }\n }\n /**\n * Set reference to navigation element in template\n *\n * @param {HTMLElement} navigationElement\n */\n ;\n\n _proto.afterNavigationRender = function afterNavigationRender(navigationElement) {\n this.navigationElement = navigationElement;\n }\n /**\n * Navigate to a slide\n *\n * @param {number} slideIndex\n * @param {boolean} dontAnimate\n * @param {boolean} force\n */\n ;\n\n _proto.navigateToSlide = function navigateToSlide(slideIndex, dontAnimate, force) {\n if (dontAnimate === void 0) {\n dontAnimate = false;\n }\n\n if (force === void 0) {\n force = false;\n }\n\n if ((0, _jquery)(this.element).hasClass(\"slick-initialized\")) {\n (0, _jquery)(this.element).slick(\"slickGoTo\", slideIndex, dontAnimate);\n this.setActiveSlide(slideIndex);\n this.setFocusedSlide(slideIndex, force);\n }\n }\n /**\n * After child render record element\n *\n * @param {HTMLElement} element\n */\n ;\n\n _proto.afterChildrenRender = function afterChildrenRender(element) {\n this.element = element; // if slider has been re-rendered previously on this element, re-build\n\n if (this.ready) {\n this.buildSlick();\n }\n\n _previewCollection2.prototype.afterChildrenRender.call(this, element);\n\n this.afterChildrenRenderDeferred.resolve(element);\n }\n /**\n * On sort start force the container height, also focus to that slide\n *\n * @param {Event} event\n * @param {JQueryUI.SortableUIParams} params\n */\n ;\n\n _proto.onSortStart = function onSortStart(event, params) {\n this.forceContainerHeight();\n\n if (this.activeSlide() !== params.item.index() || this.focusedSlide() !== params.item.index()) {\n this.navigateToSlide(params.item.index(), false, true); // As we've completed a navigation request we need to ensure we don't remove the forced height\n\n this.contentTypeHeightReset = true;\n }\n }\n /**\n * On sort stop ensure the focused slide and the active slide are in sync, as the focus can be lost in this\n * operation\n */\n ;\n\n _proto.onSortStop = function onSortStop(event, params) {\n var _this2 = this;\n\n if (this.activeSlide() !== this.focusedSlide()) {\n this.setFocusedSlide(this.activeSlide(), true);\n }\n\n if (params.item.index() !== -1) {\n _underscore.defer(this.focusElement.bind(this, event, params.item.index()));\n }\n\n _underscore.defer(function () {\n (0, _jquery)(_this2.element).css({\n height: \"\",\n overflow: \"\"\n });\n });\n }\n /**\n * Add a slide into the slider\n */\n ;\n\n _proto.addSlide = function addSlide() {\n var _this3 = this;\n\n (0, _contentTypeFactory)(_config.getConfig(\"content_types\").slide, this.contentType, this.contentType.stageId).then(function (slide) {\n _events.on(\"slide:mountAfter\", function (args) {\n if (args.id === slide.id) {\n _underscore.defer(function () {\n // Wait until slick is initialized before trying to navigate\n (0, _delayUntil)(function () {\n return _this3.navigateToSlide(_this3.contentType.children().length - 1);\n }, function () {\n return (0, _jquery)(_this3.element).hasClass(\"slick-initialized\");\n }, 10);\n });\n\n _events.off(\"slide:\" + slide.id + \":mountAfter\");\n }\n }, \"slide:\" + slide.id + \":mountAfter\");\n\n _this3.contentType.addChild(slide, _this3.contentType.children().length);\n });\n }\n /**\n * Slider can not receive drops by default\n *\n * @returns {boolean}\n */\n ;\n\n _proto.isContainer = function isContainer() {\n return false;\n }\n /**\n * Slider navigation click handler.\n *\n * @param {number} index\n * @param {Preview} context\n * @param {Event} event\n */\n ;\n\n _proto.onControlClick = function onControlClick(index, context, event) {\n (0, _jquery)(event.target).focus();\n this.navigateToSlide(index);\n this.setFocusedSlide(index);\n }\n /**\n * @inheritdoc\n */\n ;\n\n _proto.destroy = function destroy() {\n _previewCollection2.prototype.destroy.call(this);\n\n if (this.focusedSlideSubscriber) {\n this.focusedSlideSubscriber.dispose();\n }\n }\n /**\n * Bind events\n */\n ;\n\n _proto.bindEvents = function bindEvents() {\n var _this4 = this;\n\n _previewCollection2.prototype.bindEvents.call(this);\n\n _events.on(\"slider:mountAfter\", function (args) {\n if (args.id === _this4.contentType.id) {\n if (args.expectChildren !== undefined) {\n _this4.mountAfterDeferred.resolve(args.expectChildren);\n }\n }\n }); // Set the active slide to the new position of the sorted slide\n\n\n _events.on(\"childContentType:sortUpdate\", function (args) {\n if (args.instance.id === _this4.contentType.id) {\n (0, _jquery)(args.ui.item).remove(); // Remove the item as the container's children is controlled by knockout\n\n _this4.setActiveSlide(args.newPosition);\n\n _underscore.defer(_this4.focusElement.bind(_this4, args.event, args.newPosition));\n }\n }); // When a slide content type is removed\n // we need to force update the content of the slider due to KO rendering issues\n\n\n var newItemIndex;\n\n _events.on(\"slide:removeAfter\", function (args) {\n if (args.parentContentType && args.parentContentType.id === _this4.contentType.id) {\n // Mark the previous slide as active\n newItemIndex = args.index - 1 >= 0 ? args.index - 1 : 0;\n\n _this4.forceContainerHeight();\n\n var data = _this4.contentType.children().slice(0);\n\n _this4.contentType.children([]);\n\n _this4.contentType.children(data);\n\n _underscore.defer(function () {\n _this4.buildSlick();\n });\n }\n });\n\n _events.on(\"slide:renderAfter\", function (args) {\n var itemIndex = args.contentType.parentContentType.getChildren()().indexOf(args.contentType);\n\n if (args.contentType.parentContentType.id === _this4.contentType.id && newItemIndex !== null && newItemIndex === itemIndex) {\n _underscore.defer(function () {\n if (newItemIndex !== null) {\n newItemIndex = null;\n\n _this4.navigateToSlide(itemIndex, true, true);\n\n _underscore.defer(function () {\n _this4.focusedSlide(null);\n\n _this4.focusedSlide(itemIndex);\n });\n }\n });\n }\n }); // On a slide content types creation we need to lock the height of the slider to ensure a smooth transition\n\n\n _events.on(\"slide:createAfter\", function (args) {\n if (_this4.element && _this4.ready && args.contentType.parentContentType.id === _this4.contentType.id) {\n _this4.forceContainerHeight();\n\n _underscore.defer(function () {\n (0, _jquery)(_this4.element).css({\n height: \"\",\n overflow: \"\"\n });\n });\n }\n }); // ContentType being mounted onto container\n\n\n _events.on(\"slider:dropAfter\", function (args) {\n if (args.id === _this4.contentType.id && _this4.contentType.children().length === 0) {\n _this4.addSlide();\n }\n }); // Capture when a content type is duplicated within the container\n\n\n var duplicatedSlide;\n var duplicatedSlideIndex;\n\n _events.on(\"slide:duplicateAfter\", function (args) {\n if (args.duplicateContentType.parentContentType.id === _this4.contentType.id && args.direct) {\n duplicatedSlide = args.duplicateContentType;\n duplicatedSlideIndex = args.index;\n }\n });\n\n _events.on(\"slide:mountAfter\", function (args) {\n if (duplicatedSlide && args.id === duplicatedSlide.id) {\n _underscore.defer(function () {\n // Mark the new duplicate slide as active\n _this4.navigateToSlide(duplicatedSlideIndex, true, true);\n\n duplicatedSlide = duplicatedSlideIndex = null;\n });\n }\n });\n }\n /**\n * Determine if the data has changed, whilst ignoring certain keys which don't require a rebuild\n *\n * @param {DataObject} previousData\n * @param {DataObject} newData\n * @returns {boolean}\n */\n ;\n\n _proto.hasDataChanged = function hasDataChanged(previousData, newData) {\n previousData = _underscore.omit(previousData, this.ignoredKeysForBuild);\n newData = _underscore.omit(newData, this.ignoredKeysForBuild);\n return !_underscore.isEqual(previousData, newData);\n }\n /**\n * Build our instance of slick\n */\n ;\n\n _proto.buildSlick = function buildSlick() {\n var _this5 = this;\n\n if (this.element && this.element.children.length > 0) {\n try {\n (0, _jquery)(this.element).slick(\"unslick\");\n } catch (e) {// We aren't concerned if this fails, slick throws an Exception when we cannot unslick\n } // Dispose current subscription in order to prevent infinite loop\n\n\n if (this.childSubscribe) {\n this.childSubscribe.dispose();\n } // Force an update on all children, ko tries to intelligently re-render but fails\n\n\n var data = this.contentType.children().slice(0);\n this.contentType.children([]);\n (0, _jquery)(this.element).empty();\n this.contentType.children(data); // Re-subscribe original event\n\n this.childSubscribe = this.contentType.children.subscribe(this.buildSlickDebounce); // Bind our init event for slick\n\n (0, _jquery)(this.element).on(\"init\", function () {\n _this5.ready = true;\n }); // Build slick\n\n (0, _jquery)(this.element).slick(Object.assign({\n initialSlide: this.activeSlide() || 0\n }, this.buildSlickConfig())); // Update our KO pointer to the active slide on change\n\n (0, _jquery)(this.element).on(\"beforeChange\", function (event, slick, currentSlide, nextSlide) {\n (0, _jquery)(_this5.element).css(\"pointer-events\", \"none\");\n\n _this5.setActiveSlide(nextSlide);\n }).on(\"afterChange\", function () {\n if (!_this5.contentTypeHeightReset) {\n (0, _jquery)(_this5.element).css({\n height: \"\",\n overflow: \"\"\n });\n _this5.contentTypeHeightReset = null;\n }\n\n (0, _jquery)(_this5.element).css(\"pointer-events\", \"\");\n });\n }\n }\n /**\n * Take dropped element on focus.\n *\n * @param {JQueryEventObject} event\n * @param {number} index\n */\n ;\n\n _proto.focusElement = function focusElement(event, index) {\n var handleClassName = (0, _jquery)(event.target).data(\"ui-sortable\").options.handle;\n (0, _jquery)((0, _jquery)(event.target).find(handleClassName)[index]).focus();\n }\n /**\n * To ensure smooth animations we need to lock the container height\n */\n ;\n\n _proto.forceContainerHeight = function forceContainerHeight() {\n (0, _jquery)(this.element).css({\n height: (0, _jquery)(this.element).outerHeight(),\n overflow: \"hidden\"\n });\n }\n /**\n * Build the slick config object\n *\n * @returns {{autoplay: boolean; autoplaySpeed: (any | number);\n * fade: boolean; infinite: boolean; arrows: boolean; dots: boolean}}\n */\n ;\n\n _proto.buildSlickConfig = function buildSlickConfig() {\n var data = this.contentType.dataStore.getState();\n return {\n arrows: data.show_arrows === \"true\",\n autoplay: data.autoplay === \"true\",\n autoplaySpeed: data.autoplay_speed,\n dots: false,\n // We have our own dots implemented\n fade: data.fade === \"true\",\n infinite: data.is_infinite === \"true\",\n waitForAnimate: false,\n swipe: false\n };\n }\n /**\n * Fit slider in column container\n *\n * @param params\n */\n ;\n\n _proto.onColumnResize = function onColumnResize(params) {\n var _this6 = this;\n\n setTimeout(function () {\n if (_this6.element) {\n (0, _jquery)(_this6.element).slick(\"setPosition\");\n\n _this6.checkWidth();\n }\n }, 450);\n }\n /**\n * Check width and add class that marks element as small\n */\n ;\n\n _proto.checkWidth = function checkWidth() {\n if (this.element.offsetWidth < 410) {\n this.element.classList.add(\"slider-small-width\");\n } else {\n this.element.classList.remove(\"slider-small-width\");\n }\n };\n\n return Preview;\n }(_previewCollection);\n\n return Preview;\n});\n//# sourceMappingURL=preview.js.map","Magento_PageBuilder/js/content-type/slider/appearance/default/widget.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'jquery',\n 'Magento_PageBuilder/js/events',\n 'slick'\n], function ($, events) {\n 'use strict';\n\n return function (config, sliderElement) {\n var $element = $(sliderElement);\n\n /**\n * Prevent each slick slider from being initialized more than once which could throw an error.\n */\n if ($element.hasClass('slick-initialized')) {\n $element.slick('unslick');\n }\n\n $element.slick({\n autoplay: $element.data('autoplay'),\n autoplaySpeed: $element.data('autoplay-speed') || 0,\n fade: $element.data('fade'),\n infinite: $element.data('infinite-loop'),\n arrows: $element.data('show-arrows'),\n dots: $element.data('show-dots')\n });\n\n // Redraw slide after content type gets redrawn\n events.on('contentType:redrawAfter', function (args) {\n if ($element.closest(args.element).length) {\n $element.slick('setPosition');\n }\n });\n // eslint-disable-next-line jquery-no-bind-unbind\n events.on('stage:viewportChangeAfter', $element.slick.bind($element, 'setPosition'));\n };\n});\n","Magento_PageBuilder/js/master-format/render.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([\"jquery\", \"Magento_PageBuilder/js/config\", \"Magento_PageBuilder/js/master-format/render/serialize\"], function (_jquery, _config, _serialize) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n var MasterFormatRenderer = /*#__PURE__*/function () {\n \"use strict\";\n\n /**\n * @param stageId\n */\n function MasterFormatRenderer(stageId) {\n this.ready = false;\n this.readyDeferred = _jquery.Deferred();\n this.stageId = stageId;\n }\n /**\n * Render the root container into a string utilising our sandboxed iframe\n *\n * @param {ContentTypeCollection} rootContainer\n * @returns {Promise<string>}\n */\n\n\n var _proto = MasterFormatRenderer.prototype;\n\n _proto.applyBindings = function applyBindings(rootContainer) {\n var _this = this;\n\n return new Promise(function (resolve, reject) {\n if (!_this.getRenderFrame()) {\n // If the stage exists we should also have a frame\n if (document.getElementById(_this.stageId)) {\n return reject(\"No render frame present for Page Builder instance.\");\n } // Otherwise the instance of Page Builder has been removed from the DOM and this is an old instance.\n\n\n return reject();\n }\n\n if (_this.ready) {\n _this.channel.port1.postMessage({\n type: \"render\",\n message: {\n stageId: _this.stageId,\n tree: (0, _serialize.getSerializedTree)(rootContainer)\n }\n });\n\n _this.channel.port1.onmessage = function (event) {\n if (event.isTrusted) {\n if (event.data.type === \"render\") {\n resolve(event.data.message);\n }\n\n if (event.data.type === \"template\") {\n _this.loadTemplate(event.data.message);\n }\n } else {\n reject(\"Render event was not trusted.\");\n }\n };\n } else {\n _this.readyDeferred.then(function () {\n _this.applyBindings(rootContainer).then(function (rendered) {\n resolve(rendered);\n }).catch(function (error) {\n reject(error);\n });\n });\n }\n });\n }\n /**\n * Create a channel to communicate with our sandboxed iframe. Firstly add a listener to the current window and then\n * set the src of the iframe. Listening for a specific message event with a predefined term and then hand over the\n * MessageChannel port to allow communication between the main window and iframe.\n */\n ;\n\n _proto.setupChannel = function setupChannel() {\n var _this2 = this;\n\n this.channel = new MessageChannel();\n var frame = this.getRenderFrame();\n window.addEventListener(\"message\", function (event) {\n if (!_this2.ready && event.data.name === \"PB_RENDER_READY\" && _this2.stageId === event.data.stageId) {\n frame.contentWindow.postMessage(\"PB_RENDER_PORT\", \"*\", [_this2.channel.port2]);\n _this2.ready = true;\n\n _this2.readyDeferred.resolve();\n }\n });\n frame.src = _config.getConfig(\"render_url\") + \"?stageId=\" + this.stageId;\n }\n /**\n * Use the text! RequireJS plugin to load a template and send it back to the child render iframe\n *\n * @param name\n */\n ;\n\n _proto.loadTemplate = function loadTemplate(name) {\n var _this3 = this;\n\n require([\"text!\" + name], function (template) {\n _this3.channel.port1.postMessage({\n type: \"template\",\n message: {\n name: name,\n template: template\n }\n });\n });\n }\n /**\n * Retrieve the render frame\n *\n * @returns {HTMLIFrameElement}\n */\n ;\n\n _proto.getRenderFrame = function getRenderFrame() {\n return document.getElementById(\"render_frame_\" + this.stageId);\n };\n\n return MasterFormatRenderer;\n }();\n\n return MasterFormatRenderer;\n});\n//# sourceMappingURL=render.js.map","Magento_PageBuilder/js/master-format/filter-html.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([\"jquery\"], function (_jquery) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * Filter the HTML output to only include necessary attributes & nodes\n *\n * @param {JQuery} element\n * @returns {JQuery}\n */\n function filterHtml(element) {\n var isWhiteSpaceOrComment = function isWhiteSpaceOrComment() {\n return this.nodeType === Node.COMMENT_NODE || this.nodeType === Node.TEXT_NODE && this.data.match(/^\\s+$/);\n };\n\n element.find(\"[data-bind]\").each(function (index, value) {\n (0, _jquery)(value).removeAttr(\"data-bind\");\n });\n element.contents().filter(isWhiteSpaceOrComment).remove();\n element.find(\"*\").filter(function (index, descendentEl) {\n // filter out elements that are iframes or have .bypass-html-filter ancestor\n var isIframe = descendentEl.tagName === \"IFRAME\";\n var isBeingBypassedByThisFilter = !!(0, _jquery)(descendentEl).closest(\".bypass-html-filter\").length;\n return !isIframe && !isBeingBypassedByThisFilter;\n }).each(function (index, descendentEl) {\n (0, _jquery)(descendentEl).contents().filter(isWhiteSpaceOrComment).remove();\n });\n element.find(\"[data-wrapper]\").each(function (index, value) {\n (0, _jquery)(value).parent().append((0, _jquery)(value).children());\n (0, _jquery)(value).remove();\n });\n element.find(\".bypass-html-filter\").each(function (index, value) {\n (0, _jquery)(value).removeClass(\"bypass-html-filter\").filter('[class=\"\"]').removeAttr(\"class\");\n });\n return element;\n }\n\n return filterHtml;\n});\n//# sourceMappingURL=filter-html.js.map","Magento_PageBuilder/js/master-format/validator.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([\"Magento_PageBuilder/js/config\"], function (_config) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * Validate if content has page builder format by checking for any data-content-type attributes\n *\n * @param {string} content\n * @returns {boolean}\n */\n function validate(content) {\n var stageDocument = new DOMParser().parseFromString(content, \"text/html\");\n return !!stageDocument.querySelector(\"[\" + _config.getConfig(\"dataContentTypeAttributeName\") + \"]\");\n }\n\n return validate;\n});\n//# sourceMappingURL=validator.js.map","Magento_PageBuilder/js/master-format/read-interface.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([], function () {\n \"use strict\";\n});\n//# sourceMappingURL=read-interface.js.map","Magento_PageBuilder/js/master-format/render/frame.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([\"csso\", \"jquery\", \"knockout\", \"Magento_Ui/js/lib/knockout/template/engine\", \"mageUtils\", \"underscore\", \"Magento_PageBuilder/js/binding/master-style\", \"Magento_PageBuilder/js/config\", \"Magento_PageBuilder/js/content-type-factory\", \"Magento_PageBuilder/js/content-type/style-registry\", \"Magento_PageBuilder/js/utils/directives\", \"Magento_PageBuilder/js/master-format/filter-html\"], function (_csso, _jquery, _knockout, _engine, _mageUtils, _underscore, _masterStyle, _config, _contentTypeFactory, _styleRegistry, _directives, _filterHtml) {\n function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== \"function\") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }\n\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n var port = null;\n\n var portDeferred = _jquery.Deferred();\n\n var deferredTemplates = {};\n var lastRenderId;\n /**\n * Debounce the render call, so we don't render until the final request\n */\n\n var debounceRender = _underscore.debounce(function (message, renderId) {\n render(message, renderId).then(function (output) {\n // Only post the most recent render back to the parent\n if (lastRenderId === renderId) {\n port.postMessage({\n type: \"render\",\n message: output\n });\n }\n });\n }, 50);\n /**\n * Listen for requests from the parent window for a render\n */\n\n\n function listen(config) {\n var stageId = window.location.href.split(\"?\")[1].split(\"=\")[1];\n\n _config.setConfig(config);\n\n _config.setMode(\"Master\"); // Override assign with extend to prevent deep object overriding.\n\n\n Object.assign = _mageUtils.extend;\n /**\n * Create a listener within our iframe so we can observe messages from the parent, once we receive a port on the\n * MessageChannel we utilise that for all communication.\n */\n\n window.addEventListener(\"message\", function (event) {\n if (event.ports && event.ports.length) {\n port = event.ports[0];\n portDeferred.resolve(port);\n\n port.onmessage = function (messageEvent) {\n if (messageEvent.data.type === \"render\") {\n var renderId = _mageUtils.uniqueid();\n\n lastRenderId = renderId;\n debounceRender(messageEvent.data.message, renderId);\n }\n\n if (messageEvent.data.type === \"template\") {\n var message = messageEvent.data.message;\n\n if (message.name in deferredTemplates) {\n deferredTemplates[message.name].resolve(message.template);\n delete deferredTemplates[message.name];\n }\n }\n };\n }\n }, false); // Inform the parent iframe that we're ready to receive the port\n\n window.parent.postMessage({\n name: \"PB_RENDER_READY\",\n stageId: stageId\n }, \"*\");\n }\n /**\n * Use our MessageChannel to load a template from the parent window, this is required as the iframe isn't allowed to\n * make same origin XHR requests.\n *\n * @param name\n */\n\n\n function loadTemplate(name) {\n return new Promise(function (resolve) {\n if (!(name in deferredTemplates)) {\n deferredTemplates[name] = _jquery.Deferred();\n }\n\n deferredTemplates[name].then(function (template) {\n resolve(template);\n });\n\n if (port) {\n port.postMessage({\n type: \"template\",\n message: name\n });\n } else {\n portDeferred.then(function (messagePort) {\n messagePort.postMessage({\n type: \"template\",\n message: name\n });\n });\n }\n });\n }\n /**\n * Assert if the render has finished\n */\n\n\n var assertRenderFinished = _underscore.debounce(function (element, expectedCount, callback) {\n if (element.querySelectorAll(\"[data-content-type]\").length === expectedCount) {\n callback();\n }\n }, 50);\n /**\n * Iterate over the root container and count all content types\n *\n * @param rootContainer\n * @param count\n */\n\n\n function countContentTypes(rootContainer, count) {\n count = count || 0;\n rootContainer.getChildren()().forEach(function (child) {\n ++count;\n\n if (typeof child.getChildren !== \"undefined\" && child.getChildren()().length > 0) {\n count = countContentTypes(child, count);\n }\n });\n return count;\n }\n /**\n * Perform a render of the provided data\n *\n * @param message\n * @param renderId\n */\n\n\n function render(message, renderId) {\n var styleRegistries = {};\n\n _underscore.each(_config.getConfig(\"viewports\"), function (viewport, name) {\n styleRegistries[name] = new _styleRegistry(name + renderId);\n });\n\n return new Promise(function (resolve, reject) {\n createRenderTree(message.stageId, message.tree).then(function (rootContainer) {\n var element = document.createElement(\"div\");\n /**\n * Setup an event on the element to observe changes and count the expected amount of content types are\n * present within the content.\n */\n\n var renderFinished = _jquery.Deferred();\n\n var observer = new MutationObserver(function () {\n assertRenderFinished(element, countContentTypes(rootContainer), renderFinished.resolve);\n });\n observer.observe(element, {\n attributes: true,\n childList: true,\n subtree: true\n }); // Combine this event with our engine waitForRenderFinish to ensure rendering is completed\n\n _jquery.when(_engine.waitForFinishRender(), renderFinished).then(function () {\n observer.disconnect();\n\n _knockout.cleanNode(element);\n\n var styles = generateMasterCssForViewports(styleRegistries);\n\n if (styles) {\n (0, _jquery)(element).append((0, _jquery)(\"<style/>\").html(styles));\n }\n\n _underscore.each(styleRegistries, function (value, name) {\n return (0, _styleRegistry.deleteStyleRegistry)(name + renderId);\n });\n\n var filtered = (0, _filterHtml)((0, _jquery)(element));\n var output = (0, _directives.replaceWithSrc)((0, _directives)(filtered.html()));\n resolve(output);\n });\n\n _knockout.applyBindingsToNode(element, {\n template: {\n data: rootContainer.content,\n name: rootContainer.content.template\n }\n }, {\n id: renderId\n });\n }).catch(function (error) {\n reject(error);\n });\n });\n }\n /**\n * Rebuild the content type tree using their original data and configuration\n *\n * @param stageId\n * @param tree\n * @param parent\n */\n\n\n function createRenderTree(stageId, tree, parent) {\n if (parent === void 0) {\n parent = null;\n }\n\n return new Promise(function (resolve, reject) {\n (0, _contentTypeFactory)(_config.getContentTypeConfig(tree.name), parent, stageId, tree.data, parent !== null ? tree.children.length : 0, tree.viewportsData).then(function (contentType) {\n // Ensure we retain the original tree ID's\n contentType.id = tree.id;\n\n if (tree.children.length > 0) {\n var childPromises = [];\n tree.children.forEach(function (child) {\n childPromises.push(createRenderTree(stageId, child, contentType));\n });\n Promise.all(childPromises).then(function (children) {\n children.forEach(function (child) {\n contentType.addChild(child);\n });\n resolve(contentType);\n });\n } else {\n resolve(contentType);\n }\n }).catch(function (error) {\n reject(error);\n });\n });\n }\n /**\n * Generate the master format CSS\n *\n * @param registry\n */\n\n\n function generateMasterCss(registry) {\n var scopes = Object.keys(registry.getAllStyles()).map(function (selector) {\n return [selector];\n });\n return _csso.minify((0, _styleRegistry.generateCss)(registry.getAllStyles()), {\n usage: {\n scopes: scopes\n }\n }).css;\n }\n\n function generateMasterCssForViewports(registries) {\n var result = \"\";\n\n _underscore.each(registries, function (registry, name) {\n var css = generateMasterCss(registry);\n\n var media = _config.getConfig(\"viewports\")[name].media;\n\n if (media && css) {\n result += \"@media \" + media + \" { \" + css + \" }\";\n } else {\n result += css;\n }\n });\n\n return result;\n }\n\n return Object.assign(listen, {\n loadTemplate: loadTemplate\n });\n});\n//# sourceMappingURL=frame.js.map","Magento_PageBuilder/js/master-format/render/events.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([], function () {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * The frame does not need to create or observe events, however the app will naturally attempt to. So let's stop that!\n */\n var _default = {\n on: function on() {\n return this;\n },\n off: function off() {\n return this;\n },\n trigger: function trigger() {\n return this;\n }\n };\n return _default;\n});\n//# sourceMappingURL=events.js.map","Magento_PageBuilder/js/master-format/render/serialize.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([\"Magento_PageBuilder/js/config\", \"Magento_PageBuilder/js/content-type-collection\"], function (_config, _contentTypeCollection) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * Serialize the tree as a simplified object for rendering\n *\n * @param contentType\n */\n function buildTree(contentType) {\n var data = getData(contentType);\n var viewportsData = getViewportsData(contentType);\n var tree = {\n name: contentType.config.name,\n id: contentType.id,\n data: data,\n children: [],\n viewportsData: viewportsData\n };\n\n if (contentType instanceof _contentTypeCollection && contentType.getChildren()().length > 0) {\n contentType.getChildren()().forEach(function (child) {\n tree.children.push(buildTree(child));\n });\n }\n\n return tree;\n }\n /**\n * Get a serialized version of the tree\n *\n * @param contentType\n */\n\n\n function getSerializedTree(contentType) {\n return buildTree(contentType);\n }\n /**\n * Retrieve the master data from the content types instance\n *\n * @param contentType\n */\n\n\n function getData(contentType) {\n /**\n * Flip flop to JSON and back again to ensure all data is serializable. Magento by default adds functions into\n * some basic types which cannot be serialized when calling PostMessage.\n */\n return JSON.parse(JSON.stringify(contentType.dataStores[_config.getConfig(\"defaultViewport\")].getState())) || {};\n }\n /**\n * Retrieve the master data from the content types instance\n *\n * @param contentType\n */\n\n\n function getViewportsData(contentType) {\n /**\n * Flip flop to JSON and back again to ensure all data is serializable. Magento by default adds functions into\n * some basic types which cannot be serialized when calling PostMessage.\n */\n var result = {};\n Object.keys(contentType.dataStores).forEach(function (name) {\n result[name] = JSON.parse(JSON.stringify(contentType.dataStores[name].getState())) || {};\n });\n return result;\n }\n\n return {\n buildTree: buildTree,\n getSerializedTree: getSerializedTree\n };\n});\n//# sourceMappingURL=serialize.js.map","Magento_PageBuilder/js/master-format/render/requirejs/text.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([\"mage/requirejs/text\", \"Magento_PageBuilder/js/master-format/render/frame\"], function (_text, _frame) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * Within our render frame we override the RequireJS text! plugin, this is originally implemented within\n * lib/web/mage/requirejs/text.js. The override uses the MessageChannel to communicate with the parent frame to\n * retrieve any requested HTML knockout template. We do this due to the sandbox restrictions on the iframe disallow\n * XHR requests to the same origin domain.\n */\n\n /**\n * Load a template\n *\n * @param name\n * @param req\n * @param onLoad\n */\n function load(name, req, onLoad) {\n (0, _frame.loadTemplate)(name).then(function (template) {\n onLoad(template);\n }).catch(function (error) {\n onLoad.error(error);\n });\n }\n /**\n * Retrieve a template\n *\n * @param url\n * @param callback\n * @param fail\n * @param headers\n */\n\n\n function get(url, callback, fail, headers) {\n _text.get.apply(_text, arguments);\n }\n\n return {\n load: load,\n get: get\n };\n});\n//# sourceMappingURL=text.js.map","Magento_PageBuilder/js/master-format/read/configurable.js":"/*eslint-disable */\n/* jscs:disable */\n\nfunction _createForOfIteratorHelperLoose(o, allowArrayLike) { var it = typeof Symbol !== \"undefined\" && o[Symbol.iterator] || o[\"@@iterator\"]; if (it) return (it = it.call(o)).next.bind(it); if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === \"number\") { if (it) o = it; var i = 0; return function () { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }; } throw new TypeError(\"Invalid attempt to iterate non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\"); }\n\nfunction _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); }\n\nfunction _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; }\n\ndefine([\"jquery\", \"mageUtils\", \"underscore\", \"Magento_PageBuilder/js/config\", \"Magento_PageBuilder/js/content-type/appearance-config\", \"Magento_PageBuilder/js/converter/converter-pool-factory\", \"Magento_PageBuilder/js/mass-converter/converter-pool-factory\", \"Magento_PageBuilder/js/property/property-reader-pool-factory\"], function (_jquery, _mageUtils, _underscore, _config, _appearanceConfig, _converterPoolFactory, _converterPoolFactory2, _propertyReaderPoolFactory) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * @api\n */\n var Configurable = /*#__PURE__*/function () {\n \"use strict\";\n\n function Configurable() {}\n\n var _proto = Configurable.prototype;\n\n /**\n * Read data from the dom based on configuration\n *\n * @param element HTMLElement\n * @returns {Promise<any>}\n */\n _proto.read = function read(element) {\n var _this = this;\n\n var role = element.getAttribute(_config.getConfig(\"dataContentTypeAttributeName\"));\n var config = (0, _appearanceConfig)(role, element.getAttribute(\"data-appearance\"));\n var componentsPromise = [(0, _propertyReaderPoolFactory)(role), (0, _converterPoolFactory)(role), (0, _converterPoolFactory2)(role)];\n return new Promise(function (resolve) {\n Promise.all(componentsPromise).then(function (loadedComponents) {\n var propertyReaderPool = loadedComponents[0],\n converterPool = loadedComponents[1],\n massConverterPool = loadedComponents[2];\n\n var viewports = _config.getConfig(\"viewports\");\n\n var data = {};\n\n _underscore.each(viewports, function (viewport, name) {\n return data[name] = {};\n });\n\n var _loop = function _loop() {\n var elementName = _Object$keys[_i];\n var elementConfig = config.elements[elementName];\n\n var currentElement = _this.findElementByName(element, elementName); // If we cannot locate the current element skip trying to read any attributes from it\n\n\n if (currentElement === null || currentElement === undefined) {\n return \"continue\";\n }\n\n _underscore.each(viewports, function (viewportObj, viewport) {\n currentElement.setAttribute(\"style\", currentElement.getAttribute(\"data-\" + viewport + \"-style\"));\n\n if (elementConfig.style.length) {\n data[viewport] = _this.readStyle(elementConfig.style, currentElement, data[viewport], propertyReaderPool, converterPool);\n }\n\n if (elementConfig.attributes.length) {\n data[viewport] = _this.readAttributes(elementConfig.attributes, currentElement, data[viewport], propertyReaderPool, converterPool);\n }\n\n if (undefined !== elementConfig.html.var) {\n data[viewport] = _this.readHtml(elementConfig, currentElement, data[viewport], converterPool);\n }\n\n if (undefined !== elementConfig.tag.var) {\n data[viewport] = _this.readHtmlTag(elementConfig, currentElement, data[viewport]);\n }\n\n if (undefined !== elementConfig.css.var) {\n data[viewport] = _this.readCss(elementConfig, currentElement, data[viewport]);\n }\n });\n };\n\n for (var _i = 0, _Object$keys = Object.keys(config.elements); _i < _Object$keys.length; _i++) {\n var _ret = _loop();\n\n if (_ret === \"continue\") continue;\n }\n\n _underscore.each(viewports, function (viewportObj, viewport) {\n data[viewport] = _this.convertData(config, data[viewport], massConverterPool);\n });\n\n resolve(data);\n }).catch(function (error) {\n console.error(error);\n });\n });\n }\n /**\n * Find the element for the current content type by it's name, avoiding searching in other content types by\n * removing any other element which contains it's own data-content-type.\n *\n * @param {HTMLElement} element\n * @param {string} name\n * @returns {HTMLElement}\n */\n ;\n\n _proto.findElementByName = function findElementByName(element, name) {\n // Create a clone of the element to avoid modifying the source\n var currentElement = (0, _jquery)(element).clone();\n\n if (currentElement.attr(\"data-element\") === name) {\n return currentElement[0];\n } // Attempt to find the element in the children of the data-content-type\n\n\n var searchInChildren = currentElement.find(\"[data-element=\\\"\" + name + \"\\\"]\"); // Ensure the element is within the current content type\n\n if (searchInChildren.length > 0 && searchInChildren.closest(\"[data-content-type]\")[0] === currentElement[0]) {\n return searchInChildren[0];\n }\n\n return null;\n }\n /**\n * Read attributes for element\n *\n * @param {DataMappingAttributesInterface[]} config\n * @param {HTMLElement} element\n * @param {object} data\n * @param {typeof PropertyReaderPool} propertyReaderPool\n * @param {typeof ConverterPool} converterPool\n * @returns {any}\n */\n ;\n\n _proto.readAttributes = function readAttributes(config, element, data, propertyReaderPool, converterPool) {\n var result = {};\n\n for (var _iterator = _createForOfIteratorHelperLoose(config), _step; !(_step = _iterator()).done;) {\n var attributeConfig = _step.value;\n\n if (\"write\" === attributeConfig.persistence_mode) {\n continue;\n }\n\n var value = !!attributeConfig.static ? attributeConfig.value : propertyReaderPool.get(attributeConfig.reader).read(element, attributeConfig.name);\n\n if (converterPool.get(attributeConfig.converter)) {\n value = converterPool.get(attributeConfig.converter).fromDom(value);\n }\n\n if (_jquery.type(result[attributeConfig.var]) === \"object\") {\n var _mageUtils$extend;\n\n value = _mageUtils.extend((_mageUtils$extend = {}, _mageUtils$extend[attributeConfig.name] = value, _mageUtils$extend), result[attributeConfig.var]);\n }\n\n result[attributeConfig.var] = value;\n }\n\n return _underscore.extend(data, result);\n }\n /**\n * Read style properties for element\n *\n * @param {DataMappingStyleInterface[]} config\n * @param {HTMLElement} element\n * @param {object} data\n * @param {typeof PropertyReaderPool} propertyReaderPool\n * @param {typeof ConverterPool} converterPool\n * @returns {{[p: string]: string}}\n */\n ;\n\n _proto.readStyle = function readStyle(config, element, data, propertyReaderPool, converterPool) {\n var result = _underscore.extend({}, data);\n\n for (var _iterator2 = _createForOfIteratorHelperLoose(config), _step2; !(_step2 = _iterator2()).done;) {\n var propertyConfig = _step2.value;\n\n if (\"write\" === propertyConfig.persistence_mode) {\n continue;\n }\n\n var value = !!propertyConfig.static ? propertyConfig.value : propertyReaderPool.get(propertyConfig.reader).read(element, propertyConfig.name);\n\n if (converterPool.get(propertyConfig.converter)) {\n value = converterPool.get(propertyConfig.converter).fromDom(value);\n }\n\n if (_jquery.type(result[propertyConfig.var]) === \"object\") {\n value = _mageUtils.extend(result[propertyConfig.var], value);\n }\n\n result[propertyConfig.var] = value;\n }\n\n return result;\n }\n /**\n * Read element's tag\n *\n * @param {object} config\n * @param {HTMLElement} element\n * @param {object} data\n * @returns {object}\n */\n ;\n\n _proto.readHtmlTag = function readHtmlTag(config, element, data) {\n var result = {};\n result[config.tag.var] = element.nodeName.toLowerCase();\n return _underscore.extend(data, result);\n }\n /**\n * Read element's css\n *\n * @param {ContentTypeConfigAppearanceElementInterface} config\n * @param {HTMLElement} element\n * @param {object} data\n * @returns {any}\n */\n ;\n\n _proto.readCss = function readCss(config, element, data) {\n var result = {};\n var css = element.getAttribute(\"class\") !== null ? element.getAttribute(\"class\") : \"\";\n\n if (config.css !== undefined && config.css.filter !== undefined && config.css.filter.length) {\n for (var _iterator3 = _createForOfIteratorHelperLoose(config.css.filter), _step3; !(_step3 = _iterator3()).done;) {\n var filterClass = _step3.value;\n css = css.replace(filterClass, \"\");\n }\n }\n\n result[config.css.var] = css.replace(/\\s{2,}/g, \" \").trim();\n return _underscore.extend(data, result);\n }\n /**\n * Read element's content\n *\n * @param {ContentTypeConfigAppearanceElementInterface} config\n * @param {HTMLElement} element\n * @param {object} data\n * @param {typeof ConverterPool} converterPool\n * @returns {any}\n */\n ;\n\n _proto.readHtml = function readHtml(config, element, data, converterPool) {\n var result = {};\n var value = element.innerHTML;\n\n if (converterPool.get(config.html.converter)) {\n value = converterPool.get(config.html.converter).fromDom(value);\n }\n\n result[config.html.var] = value;\n return _underscore.extend(data, result);\n }\n /**\n * Convert data after it's read for all elements\n *\n * @param config\n * @param {object} data\n * @param {typeof MassConverterPool} massConverterPool\n * @returns {object}\n */\n ;\n\n _proto.convertData = function convertData(config, data, massConverterPool) {\n for (var _iterator4 = _createForOfIteratorHelperLoose(config.converters), _step4; !(_step4 = _iterator4()).done;) {\n var converterConfig = _step4.value;\n\n if (massConverterPool.get(converterConfig.component)) {\n data = massConverterPool.get(converterConfig.component).fromDom(data, converterConfig.config);\n }\n }\n\n return data;\n };\n\n return Configurable;\n }();\n\n return Configurable;\n});\n//# sourceMappingURL=configurable.js.map","Magento_PageBuilder/js/system/config/google-maps-api-key-validator.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine(['jquery'], function ($) {\n 'use strict';\n\n /**\n * Initialize click and input events to handle validation\n *\n * @param {Object} config\n * @param {HTMLElement} el\n */\n var GoogleMapsApiKeyValidator = function (config, el) {\n var sourceElement = $('#' + config.sourceField),\n initialValue = sourceElement.val(),\n resultElement = $('#' + config.elementId + ' > .result');\n\n if (initialValue) {\n $(el).attr('disabled', false);\n }\n\n $(el).on('click', function () {\n var resultText = config.invalidLabel,\n resultIcon = 'icon-admin-pagebuilder-error',\n resultHtml;\n\n $.ajax({\n url: config.validateUrl,\n showLoader: true,\n data: {\n googleMapsApiKey: sourceElement.val()\n }\n }).done(function (data) {\n if (data.success) {\n resultText = config.validLabel;\n resultIcon = 'icon-admin-pagebuilder-success';\n }\n\n resultHtml = '<i class=\"' + resultIcon + '\"></i> ' + resultText;\n resultElement.html(resultHtml);\n });\n });\n\n sourceElement.on('keyup', function (event) {\n var elementValue = event.currentTarget.value,\n buttonText = config.buttonLabel;\n\n $(el).attr('disabled', !elementValue);\n resultElement.html(buttonText);\n });\n };\n\n return GoogleMapsApiKeyValidator;\n});\n","Magento_PageBuilder/js/system/config/enable-field.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'jquery',\n 'mage/translate',\n 'Magento_Ui/js/modal/confirm',\n 'domReady!'\n], function ($, $t, confirm) {\n 'use strict';\n\n return function (config, enableSelectEl) {\n\n var $enableSelectEl = $(enableSelectEl),\n isEnabledInDatabase = !!parseInt($enableSelectEl.val(), 10);\n\n $enableSelectEl.on('change', function () {\n var userIsDisabling = !parseInt($enableSelectEl.val(), 10);\n\n if (!isEnabledInDatabase || !userIsDisabling) {\n return;\n }\n\n confirm({\n title: $t(config.modalTitleText),\n content: $t(config.modalContentBody),\n buttons: [{\n text: $t('Cancel'),\n class: 'action-secondary action-dismiss action-pagebuilder-cancel',\n\n /**\n * Close modal and trigger 'cancel' action on click\n */\n click: function (event) {\n this.closeModal(event);\n }\n }, {\n text: $t('Turn Off'),\n class: 'action-primary action-accept',\n\n /**\n * Close modal and trigger 'confirm' action on click\n */\n click: function (event) {\n this.closeModal(event, true);\n }\n }],\n actions: {\n\n /**\n * Revert back to original Enabled setting\n */\n cancel: function () {\n $enableSelectEl.val(Number(true));\n }\n }\n });\n });\n };\n});\n","Magento_PageBuilder/js/system/config/validator-rules-mixin.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'jquery'\n], function ($) {\n 'use strict';\n\n return function (target) {\n $.validator.addMethod(\n 'validate-google-map-style',\n function (value) {\n if ($.mage.isEmptyNoTrim(value)) {\n return true;\n }\n\n try {\n JSON.parse(value);\n } catch (e) {\n return false;\n }\n\n return true;\n },\n $.mage.__('Google Maps Style JSON is invalid. Please paste the valid JSON style.')\n );\n\n $.validator.addMethod(\n 'validate-greater-than-one',\n function (value) {\n return !(value <= 1);\n },\n $.mage.__('Please enter a number 2 or greater in this field.')\n );\n\n $.validator.addMethod(\n 'validate-default-grid-size',\n function (value) {\n return !(parseInt(value, 10) >\n parseInt($('[name=\"groups[pagebuilder][fields][column_grid_max][value]\"]').val(), 10)\n );\n },\n $.mage.__('Default grid size must be less than the maximum grid size.')\n );\n\n return target;\n };\n});\n","Magento_PageBuilder/js/system/config/switch-attribute-type.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'jquery',\n 'mage/translate',\n 'Magento_Ui/js/modal/confirm',\n 'domReady!'\n], function ($, $t, confirm) {\n 'use strict';\n\n return function (config, attributeDropDownEl) {\n\n var $attributeDropDownEl = $(attributeDropDownEl),\n previousOption = '';\n\n $attributeDropDownEl.on('focus', function () {\n // Store the current value on focus and on change\n previousOption = this.value;\n });\n\n $attributeDropDownEl.on('change', function () {\n\n if (attributeDropDownEl.options.length > 3 ||\n this.value === 'pagebuilder' ||\n previousOption !== 'pagebuilder'\n ) {\n return;\n }\n\n confirm({\n title: $t(config.modalTitleText),\n content: $t(config.modalContentBody),\n buttons: [{\n text: $t('Cancel'),\n class: 'action-secondary action-dismiss action-pagebuilder-cancel',\n\n /**\n * Close modal and trigger 'cancel' action on click\n */\n click: function (event) {\n this.closeModal(event);\n }\n }, {\n text: $t('Change Input Type'),\n class: 'action-primary action-accept',\n\n /**\n * Close modal and trigger 'confirm' action on click\n */\n click: function (event) {\n this.closeModal(event, true);\n }\n }],\n actions: {\n\n /**\n * Revert back to 'pagebuilder' setting\n */\n cancel: function () {\n $attributeDropDownEl.val('pagebuilder');\n $attributeDropDownEl.trigger('change');\n }\n }\n });\n });\n };\n});\n","Magento_PageBuilder/js/mass-converter/widget-directive-abstract.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([\"underscore\", \"Magento_PageBuilder/js/utils/object\"], function (_underscore, _object) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n var WidgetDirectiveAbstract = /*#__PURE__*/function () {\n \"use strict\";\n\n function WidgetDirectiveAbstract() {}\n\n var _proto = WidgetDirectiveAbstract.prototype;\n\n /**\n * Convert value to internal format\n *\n * @param {ConverterDataInterface} data\n * @param {ConverterConfigInterface} config\n * @returns {WidgetDirectiveAttributes}\n */\n _proto.fromDom = function fromDom(data, config) {\n var _this = this;\n\n var attributes = {};\n (0, _object.get)(data, config.html_variable).replace(/\\{\\{widget([\\S\\s]*?)\\}\\}/i, function (match, attributeString) {\n attributes = _this.parseAttributesString(attributeString);\n }.bind(this));\n return attributes;\n }\n /**\n * Convert value to knockout format\n *\n * @param {ConverterDataInterface} data\n * @param {ConverterConfigInterface} config\n * @returns {object}\n */\n ;\n\n _proto.toDom = function toDom(data, config) {\n (0, _object.set)(data, config.html_variable, this.buildDirective(data));\n return data;\n }\n /**\n * Build the directive string using the supplies attributes\n *\n * @param {object} attributes\n * @returns {string}\n */\n ;\n\n _proto.buildDirective = function buildDirective(attributes) {\n return \"{{widget \" + this.createAttributesString(attributes) + \"}}\";\n }\n /**\n * @param {string} attributes\n * @return {Object}\n */\n ;\n\n _proto.parseAttributesString = function parseAttributesString(attributes) {\n var result = {};\n attributes.replace(/(\\w+)(?:\\s*=\\s*(?:(?:\"((?:\\\\.|[^\"])*)\")|(?:'((?:\\\\.|[^'])*)')|([^>\\s]+)))?/g, function (match, key, value) {\n result[key] = value.replace(/"e;/g, \"\\\"\");\n return \"\";\n });\n return result;\n }\n /**\n * @param {Object} attributes\n * @return {string}\n */\n ;\n\n _proto.createAttributesString = function createAttributesString(attributes) {\n var result = \"\";\n\n _underscore.each(attributes, function (value, name) {\n result += name + \"=\\\"\" + String(value).replace(/\"/g, \""e;\") + \"\\\" \";\n });\n\n return result.substr(0, result.length - 1);\n };\n\n return WidgetDirectiveAbstract;\n }();\n\n return WidgetDirectiveAbstract;\n});\n//# sourceMappingURL=widget-directive-abstract.js.map","Magento_PageBuilder/js/mass-converter/converter-interface.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([], function () {\n \"use strict\";\n});\n//# sourceMappingURL=converter-interface.js.map","Magento_PageBuilder/js/mass-converter/converter-pool.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([], function () {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n var DataConverterPool = /*#__PURE__*/function () {\n \"use strict\";\n\n function DataConverterPool() {\n this.converters = {};\n }\n\n var _proto = DataConverterPool.prototype;\n\n /**\n * Retrieve a data converter instance from the pool\n *\n * @param {string} name\n * @returns {ConverterInterface}\n */\n _proto.get = function get(name) {\n return this.converters[name] !== undefined ? this.converters[name] : null;\n }\n /**\n * Register a new data converter into the pool\n *\n * @param {string} name\n * @param {ConverterInterface} converter\n */\n ;\n\n _proto.register = function register(name, converter) {\n this.converters[name] = converter;\n };\n\n return DataConverterPool;\n }();\n\n var _default = new DataConverterPool();\n\n return _default;\n});\n//# sourceMappingURL=converter-pool.js.map","Magento_PageBuilder/js/mass-converter/background-images.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([\"underscore\", \"Magento_PageBuilder/js/utils/image\", \"Magento_PageBuilder/js/utils/object\"], function (_underscore, _image, _object) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n var BackgroundImages = /*#__PURE__*/function () {\n \"use strict\";\n\n function BackgroundImages() {}\n\n var _proto = BackgroundImages.prototype;\n\n /**\n * Process data after it's read and converted by element converters\n *\n * @param {ConverterDataInterface} data\n * @param {ConverterConfigInterface} config\n * @returns {object}\n */\n _proto.fromDom = function fromDom(data, config) {\n var directive = (0, _object.get)(data, config.attribute_name);\n\n if (directive) {\n var images = JSON.parse(directive.replace(/\\\\(.)/mg, \"$1\")) || {};\n\n if (!_underscore.isUndefined(images.desktop_image)) {\n (0, _object.set)(data, config.desktop_image_variable, (0, _image.decodeUrl)(images.desktop_image));\n }\n\n if (!_underscore.isUndefined(images.mobile_image)) {\n (0, _object.set)(data, config.mobile_image_variable, (0, _image.decodeUrl)(images.mobile_image));\n }\n\n delete data[config.attribute_name];\n }\n\n return data;\n }\n /**\n * Process data before it's converted by element converters\n *\n * @param {ConverterDataInterface} data\n * @param {ConverterConfigInterface} config\n * @returns {object}\n */\n ;\n\n _proto.toDom = function toDom(data, config) {\n var desktopImage = (0, _object.get)(data, config.desktop_image_variable);\n var mobileImage = (0, _object.get)(data, config.mobile_image_variable);\n var directiveData = {};\n\n if (!_underscore.isUndefined(desktopImage) && desktopImage && !_underscore.isUndefined(desktopImage[0])) {\n directiveData.desktop_image = (0, _image.urlToDirective)(desktopImage[0].url);\n }\n\n if (!_underscore.isUndefined(mobileImage) && mobileImage && !_underscore.isUndefined(mobileImage[0])) {\n directiveData.mobile_image = (0, _image.urlToDirective)(mobileImage[0].url);\n } // Add the directive data, ensuring we escape double quotes\n\n\n (0, _object.set)(data, config.attribute_name, JSON.stringify(directiveData).replace(/[\\\\\"']/g, \"\\\\$&\").replace(/\\u0000/g, \"\\\\0\"));\n return data;\n };\n\n return BackgroundImages;\n }();\n\n return BackgroundImages;\n});\n//# sourceMappingURL=background-images.js.map","Magento_PageBuilder/js/mass-converter/converter-pool-factory.js":"/*eslint-disable */\n/* jscs:disable */\n\nfunction _createForOfIteratorHelperLoose(o, allowArrayLike) { var it = typeof Symbol !== \"undefined\" && o[Symbol.iterator] || o[\"@@iterator\"]; if (it) return (it = it.call(o)).next.bind(it); if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === \"number\") { if (it) o = it; var i = 0; return function () { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }; } throw new TypeError(\"Invalid attempt to iterate non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\"); }\n\nfunction _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); }\n\nfunction _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; }\n\ndefine([\"Magento_PageBuilder/js/config\", \"Magento_PageBuilder/js/utils/loader\", \"Magento_PageBuilder/js/mass-converter/converter-pool\"], function (_config, _loader, _converterPool) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * Create a new instance of converter pool\n */\n function create(contentType) {\n var config = _config.getContentTypeConfig(contentType);\n\n var converters = [];\n var appearanceName;\n\n for (var _i = 0, _Object$keys = Object.keys(config.appearances); _i < _Object$keys.length; _i++) {\n appearanceName = _Object$keys[_i];\n var appearance = config.appearances[appearanceName];\n\n if (undefined !== appearance && undefined !== appearance.converters) {\n for (var _iterator = _createForOfIteratorHelperLoose(appearance.converters), _step; !(_step = _iterator()).done;) {\n var converterConfig = _step.value;\n\n if (!!converterConfig.component && !_converterPool.get(converterConfig.component)) {\n converters.push(converterConfig.component);\n }\n }\n }\n }\n\n return new Promise(function (resolve) {\n (0, _loader)(converters, function () {\n for (var _len = arguments.length, loadedConverters = new Array(_len), _key = 0; _key < _len; _key++) {\n loadedConverters[_key] = arguments[_key];\n }\n\n for (var i = 0; i < converters.length; i++) {\n _converterPool.register(converters[i], new loadedConverters[i]());\n }\n\n resolve(_converterPool);\n });\n });\n }\n\n return create;\n});\n//# sourceMappingURL=converter-pool-factory.js.map","Magento_PageBuilder/js/mass-converter/empty-mobile-image.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([\"Magento_PageBuilder/js/utils/object\"], function (_object) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n var EmptyMobileImage = /*#__PURE__*/function () {\n \"use strict\";\n\n function EmptyMobileImage() {}\n\n var _proto = EmptyMobileImage.prototype;\n\n /**\n * Process data after it's read and converted by element converters\n *\n * @param {ConverterDataInterface} data\n * @param {object} config\n * @returns {object}\n */\n _proto.fromDom = function fromDom(data, config) {\n var desktopImage = (0, _object.get)(data, config.desktop_image_variable);\n var mobileImage = (0, _object.get)(data, config.mobile_image_variable);\n\n if (mobileImage && desktopImage && mobileImage[0] !== undefined && desktopImage[0] !== undefined && mobileImage[0].url === desktopImage[0].url) {\n delete data[config.mobile_image_variable];\n }\n\n return data;\n }\n /**\n * Process data before it's converted by element converters\n *\n * @param {ConverterDataInterface} data\n * @param {object} config\n * @returns {object}\n */\n ;\n\n _proto.toDom = function toDom(data, config) {\n var mobileImage = (0, _object.get)(data, config.mobile_image_variable);\n\n if (mobileImage === undefined || mobileImage[0] === undefined) {\n (0, _object.set)(data, config.mobile_image_variable, (0, _object.get)(data, config.desktop_image_variable));\n }\n\n return data;\n };\n\n return EmptyMobileImage;\n }();\n\n return EmptyMobileImage;\n});\n//# sourceMappingURL=empty-mobile-image.js.map","Magento_PageBuilder/js/mass-converter/background-type.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([\"Magento_PageBuilder/js/utils/object\"], function (_object) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n var BackgroundType = /*#__PURE__*/function () {\n \"use strict\";\n\n function BackgroundType() {}\n\n var _proto = BackgroundType.prototype;\n\n /**\n * Process data after it's read and converted by element converters\n *\n * @param {ConverterDataInterface} data\n * @param {ConverterConfigInterface} config\n * @returns {object}\n */\n _proto.fromDom = function fromDom(data, config) {\n return data;\n }\n /**\n * Process data before it's converted by element converters\n *\n * @param {ConverterDataInterface} data\n * @param {ConverterConfigInterface} config\n * @returns {object}\n */\n ;\n\n _proto.toDom = function toDom(data, config) {\n var backgroundType = (0, _object.get)(data, config.attribute_name);\n\n if (backgroundType === \"video\") {\n (0, _object.set)(data, config.desktop_image_variable, []);\n (0, _object.set)(data, config.mobile_image_variable, []);\n } else if (backgroundType === \"image\") {\n (0, _object.set)(data, config.video_source_variable, null);\n (0, _object.set)(data, config.video_fallback_image_variable, []);\n (0, _object.set)(data, config.video_overlay_color_variable, \"\");\n }\n\n return data;\n };\n\n return BackgroundType;\n }();\n\n return BackgroundType;\n});\n//# sourceMappingURL=background-type.js.map","Magento_PageBuilder/js/content-type-menu/title-option.js":"/*eslint-disable */\n/* jscs:disable */\n\nfunction _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\ndefine([\"Magento_PageBuilder/js/content-type-menu/option\"], function (_option) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n var TitleOption = /*#__PURE__*/function (_option2) {\n \"use strict\";\n\n _inheritsLoose(TitleOption, _option2);\n\n /**\n * @param {OptionConfigInterface} options\n */\n function TitleOption(options) {\n var _this;\n\n _this = _option2.call(this, options) || this; // Modify the icon when changes are made to display in the data store\n\n _this.preview.displayLabel.subscribe(function (label) {\n _this.title(label);\n });\n\n return _this;\n }\n\n return TitleOption;\n }(_option);\n\n return TitleOption;\n});\n//# sourceMappingURL=title-option.js.map","Magento_PageBuilder/js/content-type-menu/edit.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([\"Magento_PageBuilder/js/events\", \"mageUtils\", \"underscore\", \"Magento_PageBuilder/js/config\"], function (_events, _mageUtils, _underscore, _config) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n var Edit = /*#__PURE__*/function () {\n \"use strict\";\n\n /**\n * @param {ContentTypeInterface} instance\n * @param {DataStore} dataStore\n */\n function Edit(instance, dataStore) {\n var _this = this;\n\n this.instance = instance;\n this.dataStore = dataStore;\n\n _events.on(\"form:\" + this.instance.id + \":saveAfter\", function (data) {\n var viewport = _config.getConfig(\"viewport\");\n\n var defaultViewport = _config.getConfig(\"defaultViewport\"); // set value to dataStore from default viewport if it is empty\n\n\n if (defaultViewport !== viewport) {\n _underscore.each(_this.instance.getViewportFields(viewport, data), function (value, key) {\n var isEmpty = !_underscore.find(_mageUtils.compare(data[key], _this.instance.dataStores[defaultViewport].get(key)).changes, function (change) {\n return !_underscore.isEmpty(change.oldValue);\n });\n\n if (isEmpty) {\n _this.instance.dataStores[viewport].set(key, data[key]);\n\n data[key] = _this.instance.dataStores[defaultViewport].get(key);\n }\n });\n }\n\n _this.dataStore.setState(_this.filterData(data));\n });\n }\n /**\n * Open the modal\n */\n\n\n var _proto = Edit.prototype;\n\n _proto.open = function open() {\n var _this2 = this;\n\n var contentTypeData = this.dataStore.getState();\n\n var viewport = _config.getConfig(\"viewport\");\n\n var defaultViewport = _config.getConfig(\"defaultViewport\"); // set empty value if it the same in default viewport\n\n\n if (defaultViewport !== viewport) {\n _underscore.each(this.instance.getViewportFields(viewport, contentTypeData), function (value, key) {\n if (_mageUtils.compare(contentTypeData[key], _this2.instance.dataStores.desktop.get(key)).equal) {\n contentTypeData[key] = undefined;\n }\n });\n }\n\n _events.trigger(\"contentType:editBefore\", {\n contentType: this.instance\n });\n\n _events.trigger(\"form:renderAfter\", {\n data: contentTypeData,\n appearances: this.instance.config.appearances,\n defaultNamespace: this.getDefaultNamespaceForm(),\n id: this.instance.id,\n namespace: this.getFormNamespace(contentTypeData),\n title: this.instance.config.label\n });\n }\n /**\n * Flip flop to JSON and back again to ensure all data received from the form is serializable. Magento by default\n * adds functions into some basic types which cannot be serialized when calling PostMessage.\n *\n * @param {DataObject} data\n * @returns {DataObject}\n */\n ;\n\n _proto.filterData = function filterData(data) {\n return JSON.parse(JSON.stringify(data));\n }\n /**\n * Determine the form namespace based on the currently set appearance\n *\n * @param {DataObject} contentTypeData\n * @returns {string}\n */\n ;\n\n _proto.getFormNamespace = function getFormNamespace(contentTypeData) {\n var viewport = this.instance.preview.viewport();\n var currentAppearance = this.dataStore.get(\"appearance\");\n var appearance = this.instance.config.appearances[currentAppearance];\n var breakpoints = appearance.breakpoints;\n var formNamespace = this.getDefaultNamespaceForm(); // Use the default form unless a custom one is defined\n\n if (breakpoints && breakpoints[viewport] && breakpoints[viewport].form) {\n formNamespace = breakpoints[viewport].form;\n } else if (!_underscore.isUndefined(appearance.form)) {\n formNamespace = appearance.form;\n }\n\n return formNamespace;\n }\n /**\n * Determine the form default namespace based on the currently set appearance and breakpoint\n *\n * @returns {string}\n */\n ;\n\n _proto.getDefaultNamespaceForm = function getDefaultNamespaceForm() {\n var viewport = this.instance.preview.viewport();\n var breakpoints = this.instance.config.breakpoints;\n var formNamespace = this.instance.config.form;\n\n if (breakpoints && breakpoints[viewport] && breakpoints[viewport].form) {\n formNamespace = breakpoints[viewport].form;\n }\n\n return formNamespace;\n };\n\n return Edit;\n }();\n\n return Edit;\n});\n//# sourceMappingURL=edit.js.map","Magento_PageBuilder/js/content-type-menu/hide-show-option.js":"/*eslint-disable */\n/* jscs:disable */\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\n\nfunction _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\ndefine([\"mage/translate\", \"Magento_PageBuilder/js/content-type-menu/option\"], function (_translate, _option) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n var HideShowOption = /*#__PURE__*/function (_option2) {\n \"use strict\";\n\n _inheritsLoose(HideShowOption, _option2);\n\n /**\n * @param {OptionConfigInterface} options\n */\n function HideShowOption(options) {\n var _this;\n\n _this = _option2.call(this, options) || this; // Modify the icon when changes are made to display in the data store\n\n _this.preview.contentType.dataStore.subscribe(_this.onDisplayChange.bind(_assertThisInitialized(_this)), \"display\");\n\n return _this;\n }\n /**\n * On display change update the title and icon\n *\n * @param {DataObject} state\n */\n\n\n var _proto = HideShowOption.prototype;\n\n _proto.onDisplayChange = function onDisplayChange(state) {\n var display = !!state.display;\n\n if (display) {\n this.icon(HideShowOption.hideIcon);\n this.title(HideShowOption.hideText);\n } else {\n this.icon(HideShowOption.showIcon);\n this.title(HideShowOption.showText);\n }\n };\n\n return HideShowOption;\n }(_option);\n\n HideShowOption.showText = (0, _translate)(\"Show\");\n HideShowOption.showIcon = \"<i class='icon-pagebuilder-show'></i>\";\n HideShowOption.hideText = (0, _translate)(\"Hide\");\n HideShowOption.hideIcon = \"<i class='icon-pagebuilder-hide'></i>\";\n return HideShowOption;\n});\n//# sourceMappingURL=hide-show-option.js.map","Magento_PageBuilder/js/content-type-menu/option.js":"/*eslint-disable */\n/* jscs:disable */\n\nfunction _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); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\ndefine([\"knockout\"], function (_knockout) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n var Option = /*#__PURE__*/function () {\n \"use strict\";\n\n /**\n * @param {OptionConfigInterface} config\n */\n function Option(config) {\n var _this = this;\n\n this.icon = _knockout.observable(\"\");\n this.title = _knockout.observable(\"\");\n this.classes = _knockout.observable({});\n this.isDisabled = _knockout.observable(false);\n this.config = config;\n this.preview = config.preview;\n this.icon(config.icon);\n this.title(config.title);\n this.code = config.code;\n this.sort = config.sort || 0;\n this.customTemplate = config.template; // Generate an array of classes for KO to consume\n\n var koClasses = {};\n\n if (config.classes && config.classes.length > 0) {\n config.classes.forEach(function (cssClass) {\n koClasses[cssClass] = true;\n });\n } // Always add a disabled class which tracks whether this option is disabled\n\n\n koClasses.disabled = this.isDisabled;\n this.classes(koClasses); // If no action is supplied pass an empty function, this is called within the context of the preview\n\n var action = config.action ? config.action : function () {\n return;\n };\n\n this.action = function () {\n if (!_this.isDisabled()) {\n for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {\n args[_key] = arguments[_key];\n }\n\n action.apply(_this.preview, args);\n }\n };\n }\n\n _createClass(Option, [{\n key: \"template\",\n get: function get() {\n return this.customTemplate || null;\n }\n }]);\n\n return Option;\n }();\n\n return Option;\n});\n//# sourceMappingURL=option.js.map","Magento_PageBuilder/js/content-type-menu/conditional-remove-option.js":"/*eslint-disable */\n/* jscs:disable */\n\nfunction _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\ndefine([\"Magento_PageBuilder/js/content-type-menu/option\"], function (_option) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n var ConditionalRemoveOption = /*#__PURE__*/function (_option2) {\n \"use strict\";\n\n _inheritsLoose(ConditionalRemoveOption, _option2);\n\n /**\n * @param {OptionConfigInterface} config\n */\n function ConditionalRemoveOption(config) {\n var _this;\n\n _this = _option2.call(this, config) || this;\n var parentContentType = _this.preview.contentType.parentContentType;\n\n if (parentContentType.children().length < 2) {\n _this.isDisabled(true);\n }\n\n parentContentType.children.subscribe(function (children) {\n _this.isDisabled(children.length < 2);\n });\n return _this;\n }\n\n return ConditionalRemoveOption;\n }(_option);\n\n return ConditionalRemoveOption;\n});\n//# sourceMappingURL=conditional-remove-option.js.map","Magento_PageBuilder/js/converter/converter-interface.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([], function () {\n \"use strict\";\n});\n//# sourceMappingURL=converter-interface.js.map","Magento_PageBuilder/js/converter/converter-pool.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([], function () {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n var ConverterPool = /*#__PURE__*/function () {\n \"use strict\";\n\n function ConverterPool() {\n this.converters = {};\n }\n\n var _proto = ConverterPool.prototype;\n\n /**\n * Retrieve a converter from the pool\n *\n * @param {string} name\n * @returns {ConverterInterface}\n */\n _proto.get = function get(name) {\n return this.converters[name] !== undefined ? this.converters[name] : null;\n }\n /**\n * Register a new converter into the pool\n *\n * @param {string} name\n * @param {ConverterInterface} converter\n */\n ;\n\n _proto.register = function register(name, converter) {\n this.converters[name] = converter;\n };\n\n return ConverterPool;\n }();\n\n var _default = new ConverterPool();\n\n return _default;\n});\n//# sourceMappingURL=converter-pool.js.map","Magento_PageBuilder/js/converter/converter-pool-factory.js":"/*eslint-disable */\n/* jscs:disable */\n\nfunction _createForOfIteratorHelperLoose(o, allowArrayLike) { var it = typeof Symbol !== \"undefined\" && o[Symbol.iterator] || o[\"@@iterator\"]; if (it) return (it = it.call(o)).next.bind(it); if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === \"number\") { if (it) o = it; var i = 0; return function () { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }; } throw new TypeError(\"Invalid attempt to iterate non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\"); }\n\nfunction _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); }\n\nfunction _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; }\n\ndefine([\"Magento_PageBuilder/js/config\", \"Magento_PageBuilder/js/utils/loader\", \"Magento_PageBuilder/js/converter/converter-pool\"], function (_config, _loader, _converterPool) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * Create a new instance of converter pool\n */\n function create(contentType) {\n var config = _config.getContentTypeConfig(contentType);\n\n var converters = [];\n var appearanceName;\n\n for (var _i = 0, _Object$keys = Object.keys(config.appearances); _i < _Object$keys.length; _i++) {\n appearanceName = _Object$keys[_i];\n var appearance = config.appearances[appearanceName];\n\n if (appearance !== undefined && appearance.elements !== undefined) {\n var elementName = void 0;\n\n for (var _i2 = 0, _Object$keys2 = Object.keys(appearance.elements); _i2 < _Object$keys2.length; _i2++) {\n elementName = _Object$keys2[_i2];\n\n if (appearance.elements[elementName].style !== undefined) {\n for (var _iterator = _createForOfIteratorHelperLoose(appearance.elements[elementName].style), _step; !(_step = _iterator()).done;) {\n var propertyConfig = _step.value;\n\n if (!!propertyConfig.converter && converters.indexOf(propertyConfig.converter) === -1 && !_converterPool.get(propertyConfig.converter)) {\n converters.push(propertyConfig.converter);\n }\n\n if (!!propertyConfig.preview_converter && converters.indexOf(propertyConfig.preview_converter) === -1 && !_converterPool.get(propertyConfig.preview_converter)) {\n converters.push(propertyConfig.preview_converter);\n }\n }\n }\n\n if (appearance.elements[elementName].attributes !== undefined) {\n for (var _iterator2 = _createForOfIteratorHelperLoose(appearance.elements[elementName].attributes), _step2; !(_step2 = _iterator2()).done;) {\n var attributeConfig = _step2.value;\n\n if (!!attributeConfig.converter && converters.indexOf(attributeConfig.converter) === -1 && !_converterPool.get(attributeConfig.converter)) {\n converters.push(attributeConfig.converter);\n }\n\n if (!!attributeConfig.preview_converter && converters.indexOf(attributeConfig.preview_converter) === -1 && !_converterPool.get(attributeConfig.preview_converter)) {\n converters.push(attributeConfig.preview_converter);\n }\n }\n }\n\n if (appearance.elements[elementName].html !== undefined) {\n var htmlConfig = appearance.elements[elementName].html;\n\n if (!!htmlConfig.converter && converters.indexOf(htmlConfig.converter) === -1 && !_converterPool.get(htmlConfig.converter)) {\n converters.push(htmlConfig.converter);\n }\n\n if (!!htmlConfig.preview_converter && converters.indexOf(htmlConfig.preview_converter) === -1 && !_converterPool.get(htmlConfig.preview_converter)) {\n converters.push(htmlConfig.preview_converter);\n }\n }\n }\n }\n }\n\n return new Promise(function (resolve) {\n (0, _loader)(converters, function () {\n for (var _len = arguments.length, loadedConverters = new Array(_len), _key = 0; _key < _len; _key++) {\n loadedConverters[_key] = arguments[_key];\n }\n\n for (var i = 0; i < converters.length; i++) {\n _converterPool.register(converters[i], new loadedConverters[i]());\n }\n\n resolve(_converterPool);\n });\n });\n }\n\n return create;\n});\n//# sourceMappingURL=converter-pool-factory.js.map","Magento_PageBuilder/js/converter/style/border-style.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([\"Magento_PageBuilder/js/utils/object\"], function (_object) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * @api\n */\n var BorderStyleDefault = /*#__PURE__*/function () {\n \"use strict\";\n\n function BorderStyleDefault() {}\n\n var _proto = BorderStyleDefault.prototype;\n\n /**\n * Convert value to internal format\n *\n * @param value string\n * @returns {string | object}\n */\n _proto.fromDom = function fromDom(value) {\n if (!value) {\n return \"_default\";\n }\n\n return value;\n }\n /**\n * Convert value to knockout format\n *\n * @param {string} name\n * @param {DataObject} data\n * @returns {string}\n */\n ;\n\n _proto.toDom = function toDom(name, data) {\n var value = (0, _object.get)(data, name);\n\n if (value && value !== \"_default\") {\n return value;\n }\n };\n\n return BorderStyleDefault;\n }();\n\n return BorderStyleDefault;\n});\n//# sourceMappingURL=border-style.js.map","Magento_PageBuilder/js/converter/style/width.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([], function () {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * Subtract margin from width to ensure adjacent elements do not\n * move or resize when positive or negative margins are present\n *\n * @api\n */\n var Width = /*#__PURE__*/function () {\n \"use strict\";\n\n function Width() {}\n\n var _proto = Width.prototype;\n\n /**\n * Convert value to internal format\n *\n * @param value string\n * @returns {string | object}\n */\n _proto.fromDom = function fromDom(value) {\n if (value.indexOf(\"calc\") !== -1) {\n return value.split(\"%\")[0].split(\"(\")[1] + \"%\";\n }\n\n return value;\n }\n /**\n * Convert value to knockout format\n *\n * @param name string\n * @param data Object\n * @returns {string | object}\n */\n ;\n\n _proto.toDom = function toDom(name, data) {\n if (data[name] && data[name] !== \"\") {\n var marginsAndPadding = data.margins_and_padding || {};\n var margins = marginsAndPadding.margin || \"\";\n var marginLeft = margins.left ? parseInt(margins.left, 10) : 0;\n var marginRight = margins.right ? parseInt(margins.right, 10) : 0;\n\n if (marginLeft === 0 && marginRight === 0) {\n return data[name].toString();\n }\n\n return \"calc(\" + data[name].toString() + \" - \" + (marginLeft + marginRight) + \"px)\";\n }\n };\n\n return Width;\n }();\n\n return Width;\n});\n//# sourceMappingURL=width.js.map","Magento_PageBuilder/js/converter/style/display.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([\"underscore\", \"Magento_PageBuilder/js/utils/object\"], function (_underscore, _object) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * @api\n */\n var Display = /*#__PURE__*/function () {\n \"use strict\";\n\n function Display() {}\n\n var _proto = Display.prototype;\n\n /**\n * Convert value to internal format\n *\n * @param value string\n * @returns {string | object}\n */\n _proto.fromDom = function fromDom(value) {\n return !(value === \"none\");\n }\n /**\n * Convert value to knockout format, we only provide a none property if we intend for the content type to be hidden,\n * otherwise we let the original display property handle the display of the content type.\n *\n * @param {string} name\n * @param {DataObject} data\n * @returns {string}\n */\n ;\n\n _proto.toDom = function toDom(name, data) {\n var value = (0, _object.get)(data, name);\n\n if (!_underscore.isUndefined(value) && value === false) {\n return \"none\";\n }\n\n return;\n };\n\n return Display;\n }();\n\n return Display;\n});\n//# sourceMappingURL=display.js.map","Magento_PageBuilder/js/converter/style/background-image.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([], function () {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * @api\n */\n var BackgroundImage = /*#__PURE__*/function () {\n \"use strict\";\n\n function BackgroundImage() {}\n\n var _proto = BackgroundImage.prototype;\n\n /**\n * Convert value to internal format\n *\n * @param value string\n * @returns {string | object}\n */\n _proto.fromDom = function fromDom(value) {\n return null;\n }\n /**\n * Convert value to knockout format\n *\n * @param name string\n * @param data Object\n * @returns {string}\n */\n ;\n\n _proto.toDom = function toDom(name, data) {\n return null;\n };\n\n return BackgroundImage;\n }();\n\n return BackgroundImage;\n});\n//# sourceMappingURL=background-image.js.map","Magento_PageBuilder/js/converter/style/remove-px.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([\"Magento_PageBuilder/js/utils/object\"], function (_object) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * @api\n */\n var RemovePx = /*#__PURE__*/function () {\n \"use strict\";\n\n function RemovePx() {}\n\n var _proto = RemovePx.prototype;\n\n /**\n * Convert value to internal format\n *\n * @param value string\n * @returns {string | object}\n */\n _proto.fromDom = function fromDom(value) {\n return value.replace(\"px\", \"\");\n }\n /**\n * Convert value to knockout format\n *\n * @param name string\n * @param data Object\n * @returns {string | object}\n */\n ;\n\n _proto.toDom = function toDom(name, data) {\n var value = (0, _object.get)(data, name);\n\n if (value) {\n return value + \"px\";\n }\n };\n\n return RemovePx;\n }();\n\n return RemovePx;\n});\n//# sourceMappingURL=remove-px.js.map","Magento_PageBuilder/js/converter/style/overlay-border-radius.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([], function () {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * Takes difference of border width from border radius to conform snugly to edges of wrapper border\n *\n * @api\n */\n var OverlayBorderRadius = /*#__PURE__*/function () {\n \"use strict\";\n\n function OverlayBorderRadius() {}\n\n var _proto = OverlayBorderRadius.prototype;\n\n /**\n * Convert value to internal format\n *\n * @param value string\n * @returns {string}\n */\n _proto.fromDom = function fromDom(value) {\n return value;\n }\n /**\n * Convert value to knockout format\n *\n * @param {string} name\n * @param {DataObject} data\n * @returns {string}\n */\n ;\n\n _proto.toDom = function toDom(name, data) {\n var borderRadius = data.border_radius ? parseInt(data.border_radius, 10) : 0;\n var borderWidth = data.border_width ? parseInt(data.border_width, 10) : 0;\n\n if (borderRadius <= borderWidth) {\n return \"0\";\n }\n\n return borderRadius - borderWidth + \"px\";\n };\n\n return OverlayBorderRadius;\n }();\n\n return OverlayBorderRadius;\n});\n//# sourceMappingURL=overlay-border-radius.js.map","Magento_PageBuilder/js/converter/style/color.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([\"Magento_PageBuilder/js/utils/object\"], function (_object) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * @api\n */\n var Color = /*#__PURE__*/function () {\n \"use strict\";\n\n function Color() {}\n\n var _proto = Color.prototype;\n\n /**\n * Convert value to internal format\n *\n * @param value string\n * @returns {string | object}\n */\n _proto.fromDom = function fromDom(value) {\n if (value === \"default\" || value === \"initial\" || value === \"\") {\n value = \"\";\n } else {\n var regexp = /(\\d{0,3}),\\s(\\d{0,3}),\\s(\\d{0,3})/;\n var matches = regexp.exec(value);\n\n if (matches) {\n value = \"#\" + this.fromIntToHex(parseInt(matches[1], 10)) + this.fromIntToHex(parseInt(matches[2], 10)) + this.fromIntToHex(parseInt(matches[3], 10));\n }\n }\n\n return value;\n }\n /**\n * Convert value to knockout format\n *\n * @param name string\n * @param data Object\n * @returns {string | object}\n */\n ;\n\n _proto.toDom = function toDom(name, data) {\n return (0, _object.get)(data, name, \"\");\n }\n /**\n * Convert from int to hex\n *\n * @param {number} value\n * @returns {string}\n */\n ;\n\n _proto.fromIntToHex = function fromIntToHex(value) {\n var hex = value.toString(16);\n return hex.length === 1 ? \"0\" + hex : hex;\n };\n\n return Color;\n }();\n\n return Color;\n});\n//# sourceMappingURL=color.js.map","Magento_PageBuilder/js/converter/style/margins.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([\"underscore\", \"Magento_PageBuilder/js/utils/object\"], function (_underscore, _object) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * @api\n */\n var Margins = /*#__PURE__*/function () {\n \"use strict\";\n\n function Margins() {}\n\n var _proto = Margins.prototype;\n\n /**\n * Convert value to internal format\n *\n * @param value string\n * @returns {string | object}\n */\n _proto.fromDom = function fromDom(value) {\n if (undefined !== value.margin) {\n return {\n margin: {\n top: value.margin.top.replace(\"px\", \"\"),\n left: value.margin.left.replace(\"px\", \"\"),\n right: value.margin.right.replace(\"px\", \"\"),\n bottom: value.margin.bottom.replace(\"px\", \"\")\n }\n };\n }\n\n return {};\n }\n /**\n * Convert value to knockout format\n *\n * @param {string} name\n * @param {DataObject} data\n * @returns {string | object}\n */\n ;\n\n _proto.toDom = function toDom(name, data) {\n var result = {};\n var value = (0, _object.get)(data, name);\n\n if (value && _underscore.isString(value)) {\n value = JSON.parse(value);\n }\n\n if (value && undefined !== value.margin) {\n result.marginLeft = value.margin.left ? value.margin.left + \"px\" : \"\";\n result.marginTop = value.margin.top ? value.margin.top + \"px\" : \"\";\n result.marginRight = value.margin.right ? value.margin.right + \"px\" : \"\";\n result.marginBottom = value.margin.bottom ? value.margin.bottom + \"px\" : \"\";\n }\n\n return result;\n };\n\n return Margins;\n }();\n\n return Margins;\n});\n//# sourceMappingURL=margins.js.map","Magento_PageBuilder/js/converter/style/video-overlay-color.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([\"Magento_PageBuilder/js/utils/object\"], function (_object) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n var VideoOverlayColor = /*#__PURE__*/function () {\n \"use strict\";\n\n function VideoOverlayColor() {}\n\n var _proto = VideoOverlayColor.prototype;\n\n /**\n * Convert value to internal format\n *\n * @param value string\n * @returns {string | object}\n */\n _proto.fromDom = function fromDom(value) {\n return value;\n }\n /**\n * Convert value to knockout format\n *\n * @param name string\n * @param data Object\n * @returns {string | object}\n */\n ;\n\n _proto.toDom = function toDom(name, data) {\n var value = (0, _object.get)(data, name);\n\n if (value !== \"\" && value !== undefined) {\n return value;\n }\n\n return \"transparent\";\n };\n\n return VideoOverlayColor;\n }();\n\n return VideoOverlayColor;\n});\n//# sourceMappingURL=video-overlay-color.js.map","Magento_PageBuilder/js/converter/style/min-height.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([\"Magento_PageBuilder/js/utils/object\"], function (_object) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * @api\n */\n var MinHeight = /*#__PURE__*/function () {\n \"use strict\";\n\n function MinHeight() {}\n\n var _proto = MinHeight.prototype;\n\n /**\n * Convert value to internal format\n *\n * @param value string\n * @returns {string | object}\n */\n _proto.fromDom = function fromDom(value) {\n return value.indexOf(\"calc\") !== -1 ? value.substring(5, value.length - 1) : value;\n }\n /**\n * Convert value to knockout format\n *\n * @param name string\n * @param data Object\n * @returns {string | object}\n */\n ;\n\n _proto.toDom = function toDom(name, data) {\n var value = (0, _object.get)(data, name);\n return value.split(/\\+|\\-|\\*|\\//).length > 1 ? \"calc(\" + (0, _object.get)(data, name) + \")\" : value;\n };\n\n return MinHeight;\n }();\n\n return MinHeight;\n});\n//# sourceMappingURL=min-height.js.map","Magento_PageBuilder/js/converter/style/border-width.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([\"Magento_PageBuilder/js/utils/object\"], function (_object) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * @api\n */\n var BorderWidth = /*#__PURE__*/function () {\n \"use strict\";\n\n function BorderWidth() {}\n\n var _proto = BorderWidth.prototype;\n\n /**\n * Convert value to internal format\n *\n * @param value string\n * @returns {string | object}\n */\n _proto.fromDom = function fromDom(value) {\n return value === \"initial\" ? \"\" : value.replace(\"px\", \"\");\n }\n /**\n * Convert value to knockout format\n *\n * @param {string} name\n * @param {DataObject} data\n * @returns {string | object}\n */\n ;\n\n _proto.toDom = function toDom(name, data) {\n var value = (0, _object.get)(data, name);\n\n if (value) {\n return value + \"px\";\n }\n };\n\n return BorderWidth;\n }();\n\n return BorderWidth;\n});\n//# sourceMappingURL=border-width.js.map","Magento_PageBuilder/js/converter/style/paddings.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([\"underscore\", \"Magento_PageBuilder/js/utils/object\"], function (_underscore, _object) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * @api\n */\n var Paddings = /*#__PURE__*/function () {\n \"use strict\";\n\n function Paddings() {}\n\n var _proto = Paddings.prototype;\n\n /**\n * Convert value to internal format\n *\n * @param value string\n * @returns {string | object}\n */\n _proto.fromDom = function fromDom(value) {\n if (undefined !== value.padding) {\n return {\n padding: {\n top: value.padding.top.replace(\"px\", \"\"),\n left: value.padding.left.replace(\"px\", \"\"),\n right: value.padding.right.replace(\"px\", \"\"),\n bottom: value.padding.bottom.replace(\"px\", \"\")\n }\n };\n }\n\n return {};\n }\n /**\n * Convert value to knockout format\n *\n * @param {string} name\n * @param {DataObject} data\n * @returns {string | object}\n */\n ;\n\n _proto.toDom = function toDom(name, data) {\n var result = {};\n var value = (0, _object.get)(data, name);\n\n if (value && _underscore.isString(value)) {\n value = JSON.parse(value);\n }\n\n if (value && undefined !== value.padding) {\n result.paddingLeft = value.padding.left ? value.padding.left + \"px\" : \"\";\n result.paddingTop = value.padding.top ? value.padding.top + \"px\" : \"\";\n result.paddingRight = value.padding.right ? value.padding.right + \"px\" : \"\";\n result.paddingBottom = value.padding.bottom ? value.padding.bottom + \"px\" : \"\";\n }\n\n return result;\n };\n\n return Paddings;\n }();\n\n return Paddings;\n});\n//# sourceMappingURL=paddings.js.map","Magento_PageBuilder/js/converter/style/preview/display.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([], function () {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * @api\n */\n var Display = /*#__PURE__*/function () {\n \"use strict\";\n\n function Display() {}\n\n var _proto = Display.prototype;\n\n /**\n * Ensure the display none property doesn't persist to the preview\n *\n * @param value string\n * @returns {string | object}\n */\n _proto.fromDom = function fromDom(value) {\n return;\n }\n /**\n * Ensure the display none property doesn't persist to the preview\n *\n * @param name string\n * @param data Object\n * @returns {string}\n */\n ;\n\n _proto.toDom = function toDom(name, data) {\n return;\n };\n\n return Display;\n }();\n\n return Display;\n});\n//# sourceMappingURL=display.js.map","Magento_PageBuilder/js/converter/style/preview/background-image.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([\"Magento_PageBuilder/js/utils/object\"], function (_object) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * @api\n */\n var BackgroundImage = /*#__PURE__*/function () {\n \"use strict\";\n\n function BackgroundImage() {}\n\n var _proto = BackgroundImage.prototype;\n\n /**\n * Convert value to internal format\n *\n * @param value string\n * @returns {string | object}\n */\n _proto.fromDom = function fromDom(value) {\n return value;\n }\n /**\n * Convert value to knockout format\n *\n * @param name string\n * @param data Object\n * @returns {string}\n */\n ;\n\n _proto.toDom = function toDom(name, data) {\n var value = (0, _object.get)(data, name);\n\n if (value && typeof value[0] === \"object\") {\n return \"url(\" + value[0].url + \")\";\n }\n\n return \"\";\n };\n\n return BackgroundImage;\n }();\n\n return BackgroundImage;\n});\n//# sourceMappingURL=background-image.js.map","Magento_PageBuilder/js/converter/html/decode.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([\"Magento_PageBuilder/js/utils/directives\", \"Magento_PageBuilder/js/utils/object\"], function (_directives, _object) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * @api\n */\n var Decode = /*#__PURE__*/function () {\n \"use strict\";\n\n function Decode() {}\n\n var _proto = Decode.prototype;\n\n /**\n * Convert value to internal format\n *\n * @param {string} value\n * @returns {string | object}\n */\n _proto.fromDom = function fromDom(value) {\n // Convert the encoded string back to HTML without executing\n var html = new DOMParser().parseFromString(value, \"text/html\");\n return html.body.textContent;\n }\n /**\n * Convert value to knockout format\n *\n * @param {string} name\n * @param {Object} data\n * @returns {string}\n */\n ;\n\n _proto.toDom = function toDom(name, data) {\n return (0, _directives.removeQuotesInMediaDirectives)((0, _object.get)(data, name));\n };\n\n return Decode;\n }();\n\n return Decode;\n});\n//# sourceMappingURL=decode.js.map","Magento_PageBuilder/js/converter/html/tag-escaper.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([\"underscore\", \"Magento_PageBuilder/js/utils/object\"], function (_underscore, _object) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n var TagEscaper = /*#__PURE__*/function () {\n \"use strict\";\n\n function TagEscaper() {}\n\n var _proto = TagEscaper.prototype;\n\n /**\n * Convert value to internal format\n *\n * @param {string} value\n * @returns {string | object}\n */\n _proto.fromDom = function fromDom(value) {\n var result = (0, _underscore.unescape)(value); // Have to do a manual replace since underscore un-escape does not un-escape \n\n return result.replace(/ /g, String.fromCharCode(160));\n }\n /**\n * Convert value to knockout format\n *\n * @param {string} name\n * @param {Object} data\n * @returns {string}\n */\n ;\n\n _proto.toDom = function toDom(name, data) {\n return (0, _underscore.escape)((0, _object.get)(data, name));\n };\n\n return TagEscaper;\n }();\n\n return TagEscaper;\n});\n//# sourceMappingURL=tag-escaper.js.map","Magento_PageBuilder/js/converter/html/directive.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([\"Magento_PageBuilder/js/utils/directives\", \"Magento_PageBuilder/js/utils/editor\", \"Magento_PageBuilder/js/utils/object\"], function (_directives, _editor, _object) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * @api\n */\n var Directives = /*#__PURE__*/function () {\n \"use strict\";\n\n function Directives() {}\n\n var _proto = Directives.prototype;\n\n /**\n * Convert value to internal format\n *\n * @param {string} value\n * @returns {string | object}\n */\n _proto.fromDom = function fromDom(value) {\n return value;\n }\n /**\n * Convert value to knockout format\n *\n * @param {string} name\n * @param {Object} data\n * @returns {string}\n */\n ;\n\n _proto.toDom = function toDom(name, data) {\n return (0, _editor.encodeContent)((0, _directives.convertMediaDirectivesToUrls)((0, _directives.removeQuotesInMediaDirectives)((0, _object.get)(data, name))));\n };\n\n return Directives;\n }();\n\n return Directives;\n});\n//# sourceMappingURL=directive.js.map","Magento_PageBuilder/js/converter/attribute/link-type.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([\"Magento_PageBuilder/js/utils/object\"], function (_object) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * @api\n */\n var CreateValueForLinkType = /*#__PURE__*/function () {\n \"use strict\";\n\n function CreateValueForLinkType() {}\n\n var _proto = CreateValueForLinkType.prototype;\n\n /**\n * Convert value to internal format\n *\n * @param value string\n * @returns {string | object}\n */\n _proto.fromDom = function fromDom(value) {\n return value;\n }\n /**\n * Convert value to knockout format\n *\n * @param name string\n * @param data Object\n * @returns {string}\n */\n ;\n\n _proto.toDom = function toDom(name, data) {\n var value = (0, _object.get)(data, name);\n return value && value.type ? value.type : \"default\";\n };\n\n return CreateValueForLinkType;\n }();\n\n return CreateValueForLinkType;\n});\n//# sourceMappingURL=link-type.js.map","Magento_PageBuilder/js/converter/attribute/src.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([\"Magento_PageBuilder/js/config\", \"Magento_PageBuilder/js/utils/image\", \"Magento_PageBuilder/js/utils/object\", \"Magento_PageBuilder/js/utils/url\"], function (_config, _image, _object, _url) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * @api\n */\n var Src = /*#__PURE__*/function () {\n \"use strict\";\n\n function Src() {}\n\n var _proto = Src.prototype;\n\n /**\n * Convert value to internal format\n *\n * @param value string\n * @returns {string | object}\n */\n _proto.fromDom = function fromDom(value) {\n if (!value) {\n return \"\";\n }\n\n return (0, _image.decodeUrl)(value);\n }\n /**\n * Convert value to knockout format\n *\n * @param {string} name\n * @param {DataObject} data\n * @returns {string}\n */\n ;\n\n _proto.toDom = function toDom(name, data) {\n var value = (0, _object.get)(data, name);\n\n if (value[0] === undefined || value[0].url === undefined) {\n return \"\";\n }\n\n var imageUrl = value[0].url;\n var mediaUrl = (0, _url.convertUrlToPathIfOtherUrlIsOnlyAPath)(_config.getConfig(\"media_url\"), imageUrl);\n var mediaPath = imageUrl.split(mediaUrl);\n return \"{{media url=\" + mediaPath[1] + \"}}\";\n };\n\n return Src;\n }();\n\n return Src;\n});\n//# sourceMappingURL=src.js.map","Magento_PageBuilder/js/converter/attribute/video-overlay-color.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([], function () {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n var OverlayColor = /*#__PURE__*/function () {\n \"use strict\";\n\n function OverlayColor() {}\n\n var _proto = OverlayColor.prototype;\n\n /**\n * Convert value to internal format\n *\n * @param value string\n * @returns {string | object}\n */\n _proto.fromDom = function fromDom(value) {\n return value === \"transparent\" ? \"\" : value;\n }\n /**\n * Convert value to knockout format\n *\n * @param {string} name\n * @param {DataObject} data\n * @returns {string | object}\n */\n ;\n\n _proto.toDom = function toDom(name, data) {\n if (data.video_overlay_color) {\n return data.video_overlay_color.toString();\n }\n\n return \"\";\n };\n\n return OverlayColor;\n }();\n\n return OverlayColor;\n});\n//# sourceMappingURL=video-overlay-color.js.map","Magento_PageBuilder/js/converter/attribute/link-href.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([\"underscore\", \"Magento_PageBuilder/js/utils/object\"], function (_underscore, _object) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * @api\n */\n var CreateValueForHref = /*#__PURE__*/function () {\n \"use strict\";\n\n function CreateValueForHref() {\n this.widgetParamsByLinkType = {\n category: {\n type: \"Magento\\\\Catalog\\\\Block\\\\Category\\\\Widget\\\\Link\",\n id_path: \"category/:href\",\n template: \"Magento_PageBuilder::widget/link_href.phtml\",\n type_name: \"Catalog Category Link\"\n },\n product: {\n type: \"Magento\\\\Catalog\\\\Block\\\\Product\\\\Widget\\\\Link\",\n id_path: \"product/:href\",\n template: \"Magento_PageBuilder::widget/link_href.phtml\",\n type_name: \"Catalog Product Link\"\n },\n page: {\n type: \"Magento\\\\Cms\\\\Block\\\\Widget\\\\Page\\\\Link\",\n page_id: \":href\",\n template: \"Magento_PageBuilder::widget/link_href.phtml\",\n type_name: \"CMS Page Link\"\n }\n };\n }\n\n var _proto = CreateValueForHref.prototype;\n\n /**\n * Convert value to internal format\n *\n * @param value string\n * @returns {string | object}\n */\n _proto.fromDom = function fromDom(value) {\n return value;\n }\n /**\n * Convert value to knockout format\n *\n * @param name string\n * @param data Object\n * @returns {string}\n */\n ;\n\n _proto.toDom = function toDom(name, data) {\n var link = (0, _object.get)(data, name);\n var href = \"\";\n\n if (!link) {\n return href;\n }\n\n var linkType = link.type;\n var isHrefId = !isNaN(parseInt(link[linkType], 10));\n\n if (isHrefId && link) {\n href = this.convertToWidget(link[linkType], linkType);\n } else if (typeof link[linkType] === \"string\") {\n href = link[linkType];\n }\n\n return href;\n }\n /**\n * @param {string} href\n * @param {string} linkType\n * @returns {string}\n */\n ;\n\n _proto.convertToWidget = function convertToWidget(href, linkType) {\n if (!href || !this.widgetParamsByLinkType[linkType]) {\n return href;\n }\n\n var attributesString = _underscore.map(this.widgetParamsByLinkType[linkType], function (val, key) {\n return key + \"='\" + val.replace(\":href\", href) + \"'\";\n }).join(\" \");\n\n return \"{{widget \" + attributesString + \" }}\";\n };\n\n return CreateValueForHref;\n }();\n\n return CreateValueForHref;\n});\n//# sourceMappingURL=link-href.js.map","Magento_PageBuilder/js/converter/attribute/link-target.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([\"Magento_PageBuilder/js/utils/object\"], function (_object) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * @api\n */\n var CreateValueForTarget = /*#__PURE__*/function () {\n \"use strict\";\n\n function CreateValueForTarget() {}\n\n var _proto = CreateValueForTarget.prototype;\n\n /**\n * Convert value to internal format\n *\n * @param value string\n * @returns {string | object}\n */\n _proto.fromDom = function fromDom(value) {\n return value;\n }\n /**\n * Convert value to knockout format\n *\n * @param name string\n * @param data Object\n * @returns {string}\n */\n ;\n\n _proto.toDom = function toDom(name, data) {\n var value = (0, _object.get)(data, name);\n\n if (!value) {\n return \"\";\n }\n\n return value.setting ? \"_blank\" : \"\";\n };\n\n return CreateValueForTarget;\n }();\n\n return CreateValueForTarget;\n});\n//# sourceMappingURL=link-target.js.map","Magento_PageBuilder/js/converter/attribute/preview/store-id.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([\"jquery\"], function (_jquery) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * @api\n */\n var StoreId = /*#__PURE__*/function () {\n \"use strict\";\n\n function StoreId() {}\n\n var _proto = StoreId.prototype;\n\n /**\n * Convert value to internal format\n *\n * @param value string\n * @returns {string | object}\n */\n _proto.fromDom = function fromDom(value) {\n return value;\n }\n /**\n * Convert value to knockout format\n *\n * @param name string\n * @param data Object\n * @returns {string}\n */\n ;\n\n _proto.toDom = function toDom(name, data) {\n if (typeof data[name] !== \"string\") {\n return \"\";\n }\n\n var storeId = (0, _jquery)('[data-role=\"store-view-id\"]').val() || \"0\";\n return data[name].replace(/}}$/, \" store_id=\\\"\" + storeId + \"\\\"}}\");\n };\n\n return StoreId;\n }();\n\n return StoreId;\n});\n//# sourceMappingURL=store-id.js.map","Magento_PageBuilder/js/converter/attribute/preview/src.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([\"Magento_PageBuilder/js/utils/object\"], function (_object) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * @api\n */\n var Src = /*#__PURE__*/function () {\n \"use strict\";\n\n function Src() {}\n\n var _proto = Src.prototype;\n\n /**\n * Convert value to internal format\n *\n * @param value string\n * @returns {string | object}\n */\n _proto.fromDom = function fromDom(value) {\n return value;\n }\n /**\n * Convert value to knockout format\n *\n * @param name string\n * @param data Object\n * @returns {string}\n */\n ;\n\n _proto.toDom = function toDom(name, data) {\n var value = (0, _object.get)(data, name);\n\n if (value && typeof value[0] === \"object\") {\n return value[0].url;\n }\n\n return \"\";\n };\n\n return Src;\n }();\n\n return Src;\n});\n//# sourceMappingURL=src.js.map","Magento_PageBuilder/js/panel/menu.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([\"knockout\"], function (_knockout) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n var Menu = /*#__PURE__*/function () {\n \"use strict\";\n\n /**\n * Menu constructor\n *\n * @param id\n * @param menu\n * @param contentTypes\n * @param stageId\n */\n function Menu(id, menu, contentTypes, stageId) {\n if (contentTypes === void 0) {\n contentTypes = [];\n }\n\n this.hidden = _knockout.observable(false);\n this.id = _knockout.observable();\n this.code = _knockout.observable(\"\");\n this.label = _knockout.observable(\"\");\n this.icon = _knockout.observable(\"\");\n this.sort = _knockout.observable();\n this.contentTypes = _knockout.observableArray([]);\n this.active = _knockout.observable(false);\n this.id(id);\n this.code(menu.code);\n this.label(menu.label);\n this.icon(menu.icon);\n this.sort(menu.sort);\n this.contentTypes(contentTypes);\n this.stageId = stageId;\n }\n /**\n * Toggle the menu\n */\n\n\n var _proto = Menu.prototype;\n\n _proto.toggle = function toggle() {\n this.active(!this.active());\n };\n\n return Menu;\n }();\n\n return {\n Menu: Menu\n };\n});\n//# sourceMappingURL=menu.js.map","Magento_PageBuilder/js/panel/menu/content-type.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([\"knockout\", \"Magento_PageBuilder/js/drag-drop/matrix\"], function (_knockout, _matrix) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n var ContentType = /*#__PURE__*/function () {\n \"use strict\";\n\n /**\n * @param {string} identifier\n * @param {ContentTypeConfigInterface} config\n * @param {string} stageId\n */\n function ContentType(identifier, config, stageId) {\n this.droppable = true;\n this.icon = _knockout.observable(\"\");\n this.identifier = _knockout.observable(\"\");\n this.label = _knockout.observable(\"\");\n this.config = config;\n this.identifier(identifier);\n this.label(config.label);\n this.icon(config.icon);\n this.stageId = stageId;\n }\n /**\n * Retrieve the config object\n *\n * @returns {ContentTypeConfigInterface}\n */\n\n\n var _proto = ContentType.prototype;\n\n _proto.getConfig = function getConfig() {\n return this.config;\n }\n /**\n * Only connect to container sortable instances that the current content type is accepted into\n *\n * @returns {string}\n */\n ;\n\n _proto.getDraggableOptions = function getDraggableOptions() {\n return {\n connectToSortable: (0, _matrix.getAllowedContainersClasses)(this.config.name, this.stageId)\n };\n };\n\n return ContentType;\n }();\n\n return {\n ContentType: ContentType\n };\n});\n//# sourceMappingURL=content-type.js.map","Magento_PageBuilder/js/utils/string.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([], function () {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * Convert from snake case to camel case\n *\n * @param {string} currentString\n * @returns {string}\n * @api\n */\n function fromSnakeToCamelCase(currentString) {\n var parts = currentString.split(/[_-]/);\n var newString = \"\";\n\n for (var i = 1; i < parts.length; i++) {\n newString += parts[i].charAt(0).toUpperCase() + parts[i].slice(1);\n }\n\n return parts[0] + newString;\n }\n /**\n * Convert a camel case string to snake case\n *\n * @param currentString\n */\n\n\n function fromCamelCaseToDash(currentString) {\n return currentString.replace(/[A-Z]/g, function (m) {\n return \"-\" + m.toLowerCase();\n });\n }\n\n return {\n fromSnakeToCamelCase: fromSnakeToCamelCase,\n fromCamelCaseToDash: fromCamelCaseToDash\n };\n});\n//# sourceMappingURL=string.js.map","Magento_PageBuilder/js/utils/directives.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([\"Magento_PageBuilder/js/config\"], function (_config) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * MIME type to use in place of the image\n *\n * @type {string}\n */\n var mimeType = \"text/magento-directive\";\n /**\n * Determine if a URL is a directive of our type\n *\n * @param {string} url\n * @returns {boolean}\n * @api\n */\n\n function isDirectiveDataUrl(url) {\n return url.indexOf(\"data:\" + mimeType) === 0;\n }\n /**\n * Convert a directive into our data URI\n *\n * @param {string} directive\n * @returns {string}\n * @api\n */\n\n\n function toDataUrl(directive) {\n return \"data:\" + mimeType + \",\" + encodeURIComponent(directive);\n }\n /**\n * Convert a URI to it's directive equivalent\n *\n * @param {string} url\n * @returns {string}\n * @api\n */\n\n\n function fromDataUrl(url) {\n if (!isDirectiveDataUrl(url)) {\n throw Error(url + \" is not a magento directive data url\");\n }\n\n return decodeURIComponent(url.split(mimeType + \",\")[1]);\n }\n /**\n * Decode all data URIs present in a string\n *\n * @param {string} str\n * @returns {string}\n * @api\n */\n\n\n function decodeAllDataUrlsInString(str) {\n return str.replace(new RegExp(\"url\\\\s*\\\\(\\\\s*(?:"|\\'|\\\")?(data:\" + mimeType + \",.+?)(?:"|\\'|\\\")?\\\\s*\\\\)\", \"g\"), function (match, url) {\n return \"url(\\'\" + fromDataUrl(url) + \"\\')\";\n });\n }\n /**\n * Retrieve the image URL with directive\n *\n * @param {Array} image\n * @returns {string}\n * @api\n */\n\n\n function getImageUrl(image) {\n var imageUrl = image[0].url;\n var mediaPath = imageUrl.split(_config.getConfig(\"media_url\"));\n return \"{{media url=\" + mediaPath[1] + \"}}\";\n }\n /**\n * Remove quotes in media directives, {{media url=\"wysiwyg/image.png\"}} convert to {{media url=wysiwyg/image.png}}\n *\n * @param {string} html\n * @returns {string}\n * @api\n */\n\n\n function removeQuotesInMediaDirectives(html) {\n if (!html) {\n return \"\";\n }\n\n var mediaDirectiveRegExp = /\\{\\{\\s*media\\s+url\\s*=\\s*(.*?)\\s*\\}\\}/g;\n var urlRegExp = /\\{\\{\\s*media\\s+url\\s*=\\s*(.*)\\s*\\}\\}/;\n var mediaDirectiveMatches = html.match(mediaDirectiveRegExp);\n\n if (mediaDirectiveMatches) {\n mediaDirectiveMatches.forEach(function (mediaDirective) {\n var urlMatches = mediaDirective.match(urlRegExp);\n\n if (urlMatches && urlMatches[1] !== undefined) {\n var directiveWithOutQuotes = \"{{media url=\" + urlMatches[1].replace(/(\"|"|\\s)/g, \"\") + \"}}\";\n html = html.replace(mediaDirective, directiveWithOutQuotes);\n }\n });\n }\n\n return html;\n }\n /**\n * Replace media directives with actual media URLs\n *\n * @param {string} html\n * @returns {string}\n * @api\n */\n\n\n function convertMediaDirectivesToUrls(html) {\n if (!html) {\n return \"\";\n }\n\n var mediaDirectiveRegExp = /\\{\\{\\s*media\\s+url\\s*=\\s*\"?[^\"\\s\\}]+\"?\\s*\\}\\}/g;\n var mediaDirectiveMatches = html.match(mediaDirectiveRegExp);\n\n if (mediaDirectiveMatches) {\n mediaDirectiveMatches.forEach(function (mediaDirective) {\n var urlRegExp = /\\{\\{\\s*media\\s+url\\s*=\\s*(?:\"|")?(.+)(?=}})\\s*\\}\\}/;\n var urlMatches = mediaDirective.match(urlRegExp);\n\n if (urlMatches && typeof urlMatches[1] !== \"undefined\") {\n html = html.replace(mediaDirective, _config.getConfig(\"media_url\") + urlMatches[1].replace(/\"$/, \"\").replace(/"$/, \"\"));\n }\n });\n }\n\n return html;\n }\n /**\n * Replace data-src attribute with src.\n *\n * @param {string} html\n * @returns {string}\n */\n\n\n function replaceWithSrc(html) {\n return html.replace(new RegExp(\"data-tmp-src=\\\"\\{\\{\", \"g\"), \"src=\\\"{{\");\n }\n /**\n * Replace src attribute with data-tmp-src.\n *\n * @param {string} html\n * @returns {string}\n */\n\n\n function replaceWithDataSrc(html) {\n return html.replace(new RegExp(\"src=\\\"\\{\\{\", \"g\"), \"data-tmp-src=\\\"{{\");\n }\n\n return Object.assign(decodeAllDataUrlsInString, {\n toDataUrl: toDataUrl,\n fromDataUrl: fromDataUrl,\n getImageUrl: getImageUrl,\n removeQuotesInMediaDirectives: removeQuotesInMediaDirectives,\n convertMediaDirectivesToUrls: convertMediaDirectivesToUrls,\n replaceWithSrc: replaceWithSrc,\n replaceWithDataSrc: replaceWithDataSrc\n });\n});\n//# sourceMappingURL=directives.js.map","Magento_PageBuilder/js/utils/promise-deferred.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([], function () {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * Returns a deferred promise\n *\n * @returns {DeferredInterface}\n * @api\n */\n function deferred() {\n var resolve;\n var reject;\n var promise = new Promise(function (promiseResolve, promiseReject) {\n resolve = promiseResolve;\n reject = promiseReject;\n });\n return {\n resolve: resolve,\n reject: reject,\n promise: promise\n };\n }\n\n return deferred;\n});\n//# sourceMappingURL=promise-deferred.js.map","Magento_PageBuilder/js/utils/map.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * googleMaps dependency is added within googlemaps.phtml through shim based on API key being set\n *\n * @api\n */\ndefine([\n 'underscore',\n 'module',\n 'Magento_PageBuilder/js/events'\n], function (_, module, events) {\n 'use strict';\n\n var google = window.google || {},\n\n /**\n * Generates a google map usable latitude and longitude object\n *\n * @param {Object} position\n * @return {google.maps.LatLng}\n */\n getGoogleLatitudeLongitude = function (position) {\n return new google.maps.LatLng(position.latitude, position.longitude);\n },\n gmAuthFailure = false;\n\n // jscs:disable requireCamelCaseOrUpperCaseIdentifiers\n /**\n * Google's error listener for map loader failures\n */\n window.gm_authFailure = function () {\n events.trigger('googleMaps:authFailure');\n gmAuthFailure = true;\n };\n // jscs:enable requireCamelCaseOrUpperCaseIdentifiers\n\n return function (element, markers, additionalOptions) {\n var options,\n style;\n\n // If we've previously had an API key error, throw the error even again\n if (gmAuthFailure) {\n events.trigger('googleMaps:authFailure');\n\n return;\n }\n\n // If Google Maps isn't loaded don't try init the map, it won't work\n if (typeof google.maps === 'undefined') {\n return;\n }\n\n /**\n * Just in case of a bad JSON that bypassed validation\n */\n try {\n style = module.config().style ? JSON.parse(module.config().style) : [];\n }\n catch (error) {\n style = [];\n }\n options = _.extend({\n zoom: 8,\n center: getGoogleLatitudeLongitude({\n latitude: 30.2672,\n longitude: -97.7431\n }),\n scrollwheel: false,\n disableDoubleClickZoom: false,\n disableDefaultUI: false,\n mapTypeControl: true,\n mapTypeControlOptions: {\n style: google.maps.MapTypeControlStyle.DEFAULT\n },\n styles: style\n }, additionalOptions);\n\n /* Create the map */\n this.map = new google.maps.Map(element, options);\n this.markers = [];\n\n /**\n * Callback function on map config update\n * @param {Array} newMarkers\n * @param {Object} updateOptions\n */\n this.onUpdate = function (newMarkers, updateOptions) {\n this.map.setOptions(updateOptions);\n this.setMarkers(newMarkers);\n };\n\n /**\n * Sets the markers to selected map\n * @param {Object} newMarkers\n */\n this.setMarkers = function (newMarkers) {\n var activeInfoWindow,\n latitudeLongitudeBounds = new google.maps.LatLngBounds();\n\n this.markers.forEach(function (marker) {\n marker.setMap(null);\n }, this);\n\n this.markers = [];\n this.bounds = [];\n\n /**\n * Creates and set listener for markers\n */\n if (newMarkers && newMarkers.length) {\n newMarkers.forEach(function (newMarker) {\n var location = _.escape(newMarker['location_name']) || '',\n comment = newMarker.comment ?\n '<p>' + _.escape(newMarker.comment).replace(/(?:\\r\\n|\\r|\\n)/g, '<br/>') + '</p>'\n : '',\n phone = newMarker.phone ? '<p>Phone: ' + _.escape(newMarker.phone) + '</p>' : '',\n address = newMarker.address ? _.escape(newMarker.address) + '<br/>' : '',\n city = _.escape(newMarker.city) || '',\n country = newMarker.country ? _.escape(newMarker.country) : '',\n state = newMarker.state ? _.escape(newMarker.state) + ' ' : '',\n zipCode = newMarker.zipcode ? _.escape(newMarker.zipcode) : '',\n cityComma = city !== '' && (zipCode !== '' || state !== '') ? ', ' : '',\n lineBreak = city !== '' || zipCode !== '' ? '<br/>' : '',\n contentString =\n '<div>' +\n '<h3><b>' + location + '</b></h3>' +\n comment +\n phone +\n '<p><span>' + address +\n city + cityComma + state + zipCode + lineBreak +\n country + '</span></p>' +\n '</div>',\n infowindow = new google.maps.InfoWindow({\n content: contentString,\n maxWidth: 350\n }),\n newCreatedMarker = new google.maps.Marker({\n map: this.map,\n position: getGoogleLatitudeLongitude(newMarker.position),\n title: location\n });\n\n if (location) {\n newCreatedMarker.addListener('click', function () {\n if (activeInfoWindow) {\n activeInfoWindow.close();\n }\n\n infowindow.open(this.map, newCreatedMarker);\n activeInfoWindow = infowindow;\n }, this);\n }\n\n this.markers.push(newCreatedMarker);\n this.bounds.push(getGoogleLatitudeLongitude(newMarker.position));\n }, this);\n }\n\n /**\n * This sets the bounds of the map for multiple locations\n */\n if (this.bounds.length > 1) {\n this.bounds.forEach(function (bound) {\n latitudeLongitudeBounds.extend(bound);\n });\n this.map.fitBounds(latitudeLongitudeBounds);\n }\n\n /**\n * Zoom to 8 if there is only a single location\n */\n if (this.bounds.length === 1) {\n this.map.setCenter(this.bounds[0]);\n this.map.setZoom(8);\n }\n };\n\n this.setMarkers(markers);\n };\n});\n","Magento_PageBuilder/js/utils/editor.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([\"jquery\", \"mage/adminhtml/tools\", \"mage/translate\", \"mageUtils\", \"Magento_PageBuilder/js/config\"], function (_jquery, _tools, _translate, _mageUtils, _config) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * Is the inline WYSIWYG supported?\n */\n function isWysiwygSupported() {\n return _config.getConfig(\"can_use_inline_editing_on_stage\");\n }\n /**\n * Encode content for TinyMCE\n *\n * @param content\n */\n\n\n function encodeContent(content) {\n if (isWysiwygSupported()) {\n return convertVariablesToHtmlPreview(convertWidgetsToHtmlPreview(unescapeDoubleQuoteWithinWidgetDirective(removeInvalidPlaceholders(content))));\n }\n\n return content;\n }\n /**\n * Prior to parsing the content remove any invalid placeholders within the content\n *\n * @param content\n */\n\n\n function removeInvalidPlaceholders(content) {\n if (content.indexOf(\"magento-placeholder\") !== -1) {\n var html = new DOMParser().parseFromString(content, \"text/html\");\n var placeholders = html.querySelectorAll(\"span.magento-placeholder\");\n\n if (placeholders.length > 0) {\n [].slice.call(placeholders).forEach(function (placeholder) {\n // If the invalid placeholder contains a directive, let's insert it back where it belongs\n if (placeholder.innerText.indexOf(\"{{\") !== -1) {\n placeholder.parentNode.insertBefore(document.createTextNode(placeholder.innerText), placeholder);\n }\n\n placeholder.remove();\n });\n }\n\n return html.body.innerHTML;\n }\n\n return content;\n }\n /**\n * Convert all variables to their HTML preview counterparts\n *\n * Re-implements logic from lib/web/mage/adminhtml/wysiwyg/tiny_mce/plugins/magentovariable/editor_plugin.js to parse\n * and replace the variables within the content.\n *\n * @param content\n */\n\n\n function convertVariablesToHtmlPreview(content) {\n var config = _config.getConfig(\"tinymce\").variables;\n\n var magentoVariables = JSON.parse(config.placeholders);\n return content.replace(/{\\{\\s?(?:customVar code=|config path=\\\")([^\\}\\\"]+)[\\\"]?\\s?\\}\\}/ig, function (match, path) {\n var id = btoa(path).replace(/\\+/g, \":\").replace(/\\//g, \"_\").replace(/=/g, \"-\");\n var placeholder = (0, _jquery)(\"<span />\").addClass(\"magento-variable\").addClass(\"magento-placeholder\").addClass(\"mceNonEditable\").prop(\"id\", id).prop(\"contentEditable\", \"false\");\n\n if (magentoVariables[path].variable_type === \"custom\") {\n placeholder.addClass(\"magento-custom-var\");\n }\n\n var variableType = magentoVariables[path].variable_type;\n\n if (magentoVariables[path] && (variableType === \"default\" || variableType === \"custom\")) {\n placeholder.text(magentoVariables[path].variable_name);\n } else {\n // If we're unable to find the placeholder we need to attach an error class\n placeholder.addClass(\"magento-placeholder-error\");\n placeholder.text(variableType === \"custom\" ? path : (0, _translate)(\"Not Found\"));\n }\n\n return placeholder[0].outerHTML;\n });\n }\n /**\n * Convert widgets within content to their HTML counterparts\n *\n * @param content\n */\n\n\n function convertWidgetsToHtmlPreview(content) {\n var config = _config.getConfig(\"tinymce\").widgets;\n\n return content.replace(/\\{\\{widget([\\S\\s]*?)\\}\\}/ig, function (match, widgetBody) {\n var attributes = parseAttributesString(widgetBody);\n var imageSrc;\n\n if (attributes.type) {\n var placeholder = (0, _jquery)(\"<span />\").addClass(\"magento-placeholder\").addClass(\"magento-widget\").addClass(\"mceNonEditable\").prop(\"id\", _mageUtils.uniqueid()).prop(\"contentEditable\", \"false\");\n attributes.type = attributes.type.replace(/\\\\\\\\/g, \"\\\\\");\n imageSrc = config.placeholders[attributes.type];\n\n if (!imageSrc) {\n imageSrc = config.error_image_url;\n placeholder.addClass(\"magento-placeholder-error\");\n }\n\n var image = (0, _jquery)(\"<img />\").prop(\"id\", window.Base64.idEncode(match)).prop(\"src\", imageSrc);\n placeholder.append(image);\n var widgetType = \"\";\n\n if (config.types[attributes.type]) {\n widgetType += config.types[attributes.type];\n }\n\n placeholder.append((0, _jquery)(document.createTextNode(widgetType)));\n return placeholder[0].outerHTML;\n }\n });\n }\n /**\n * Parse attributes into a string\n *\n * @param attributes\n */\n\n\n function parseAttributesString(attributes) {\n var result = {};\n attributes.replace(/(\\w+)(?:\\s*=\\s*(?:(?:\"((?:\\\\.|[^\"])*)\")|(?:'((?:\\\\.|[^'])*)')|([^>\\s]+)))?/g, function (match, key, value) {\n result[key] = value ? value.replace(/"e;/g, \"\\\"\") : value;\n return \"\";\n });\n return result;\n }\n /**\n * Lock all image sizes before initializing TinyMCE to avoid content jumps\n *\n * @param element\n */\n\n\n function lockImageSize(element) {\n [].slice.call(element.querySelectorAll(\"img\")).forEach(function (image) {\n if (image.style.width.length === 0) {\n image.style.width = /^\\d+$/.test(image.getAttribute(\"width\")) ? image.getAttribute(\"width\") + \"px\" : image.getAttribute(\"width\");\n image.setAttribute(\"data-width-locked\", \"true\");\n }\n\n if (image.style.height.length === 0) {\n image.style.height = /^\\d+$/.test(image.getAttribute(\"height\")) ? image.getAttribute(\"height\") + \"px\" : image.getAttribute(\"height\");\n image.setAttribute(\"data-height-locked\", \"true\");\n }\n });\n }\n /**\n * Reverse forced image size after TinyMCE is finished initializing\n *\n * @param element\n */\n\n\n function unlockImageSize(element) {\n [].slice.call(element.querySelectorAll(\"img\")).forEach(function (image) {\n if (image.getAttribute(\"data-width-locked\")) {\n image.style.width = null;\n image.removeAttribute(\"data-width-locked\");\n }\n\n if (image.getAttribute(\"data-height-locked\")) {\n image.style.height = null;\n image.removeAttribute(\"data-height-locked\");\n }\n });\n }\n /**\n * Create a bookmark within the content to be restored later\n */\n\n\n function createBookmark(event) {\n var wrapperElement = (0, _jquery)(event.target).parents(\".inline-wysiwyg\");\n /**\n * Create an element bookmark\n *\n * @param element\n */\n\n var createElementBookmark = function createElementBookmark(element) {\n return {\n name: element.nodeName,\n index: findNodeIndex(wrapperElement[0], element.nodeName, element)\n };\n }; // Handle direct clicks onto an IMG\n\n\n if (event.target.nodeName === \"IMG\") {\n return createElementBookmark(event.target);\n }\n\n if (window.getSelection) {\n var selection = window.getSelection();\n\n var id = _mageUtils.uniqueid();\n\n if (selection.getRangeAt && selection.rangeCount) {\n var range = normalizeTableCellSelection(selection.getRangeAt(0).cloneRange()); // Determine if the current node is an image or span that we want to select instead of text\n\n var currentNode = range.startContainer;\n\n if (currentNode.nodeType === Node.ELEMENT_NODE && (currentNode.nodeName === \"IMG\" || currentNode.nodeName === \"SPAN\" && currentNode.classList.contains(\"magento-placeholder\"))) {\n return createElementBookmark(currentNode);\n } // Also check if the direct parent is either of these\n\n\n var parentNode = range.startContainer.parentNode;\n\n if (parentNode.nodeName === \"IMG\" || parentNode.nodeName === \"SPAN\" && parentNode.classList.contains(\"magento-placeholder\")) {\n return createElementBookmark(parentNode);\n }\n\n if (!range.collapsed) {\n range.collapse(false);\n var endBookmarkNode = createBookmarkSpan(id + \"_end\");\n range.insertNode(endBookmarkNode);\n }\n\n var range2 = normalizeTableCellSelection(selection.getRangeAt(0));\n range2.collapse(true);\n var startBookmarkNode = createBookmarkSpan(id + \"_start\");\n range2.insertNode(startBookmarkNode);\n return {\n id: id\n };\n }\n }\n\n return null;\n }\n /**\n * Move the cursor to our new bookmark\n *\n * @param bookmark\n */\n\n\n function moveToBookmark(bookmark) {\n window.tinymce.activeEditor.selection.moveToBookmark(bookmark);\n }\n /**\n * Retrieve active editor from TinyMCE\n */\n\n\n function getActiveEditor() {\n return window.tinymce.activeEditor;\n }\n /**\n * Create a bookmark span for the selection\n *\n * @param id\n */\n\n\n function createBookmarkSpan(id) {\n var bookmark = document.createElement(\"span\");\n bookmark.setAttribute(\"data-mce-type\", \"bookmark\");\n bookmark.id = id;\n bookmark.style.overflow = \"hidden\";\n bookmark.style.lineHeight = \"0px\";\n return bookmark;\n }\n /**\n * Find the index of an element within a wrapper\n *\n * @param wrapperElement\n * @param name\n * @param element\n */\n\n\n function findNodeIndex(wrapperElement, name, element) {\n var selector = name.toLowerCase() + ':not([data-mce-bogus=\"all\"])'; // If there is no ID on the element add a unique ID so we can efficiently find it\n\n if (!element.id) {\n element.id = _mageUtils.uniqueid();\n }\n\n return (0, _jquery)(wrapperElement).find(selector).toArray().findIndex(function (node) {\n return node.id === element.id;\n });\n }\n /**\n * Get a node by index within a wrapper\n *\n * @param wrapperElement\n * @param name\n * @param index\n */\n\n\n function getNodeByIndex(wrapperElement, name, index) {\n var selector = name.toLowerCase() + ':not([data-mce-bogus=\"all\"])';\n return (0, _jquery)(wrapperElement).find(selector).get(index);\n }\n /**\n * Create a double click event that works in all browsers\n */\n\n\n function createDoubleClickEvent() {\n try {\n return new MouseEvent(\"dblclick\", {\n view: window,\n bubbles: true,\n cancelable: true\n });\n } catch (e) {\n var dblClickEvent = document.createEvent(\"MouseEvent\");\n dblClickEvent.initMouseEvent(\"dblclick\", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);\n return dblClickEvent;\n }\n }\n /**\n * Replace all desktop styles that left unprocessed back to style element to prevent data corruption.\n */\n\n\n function processInlineStyles(html) {\n var name = _config.getConfig(\"defaultViewport\");\n\n var searchPattern = new RegExp(\"data-\" + name + \"-style=\", \"g\");\n return html.replace(searchPattern, \"style=\");\n }\n /**\n * Move the end point of a range to handle tables\n *\n * @param range\n * @param start\n */\n\n\n function moveEndPoint(range, start) {\n var container;\n var offset;\n var childNodes;\n\n if (start) {\n container = range.startContainer;\n offset = range.startOffset;\n } else {\n container = range.endContainer;\n offset = range.endOffset;\n }\n\n if (container.nodeType === Node.ELEMENT_NODE && container.nodeName === \"TR\") {\n childNodes = container.childNodes;\n container = childNodes[Math.min(start ? offset : offset - 1, childNodes.length - 1)];\n\n if (container) {\n offset = start ? 0 : container.childNodes.length;\n\n if (start) {\n range.setStart(container, offset);\n } else {\n range.setEnd(container, offset);\n }\n }\n }\n }\n /**\n * Normalize the table sell selection within a range to better handle selections being inside of tables\n *\n * @param range\n */\n\n\n function normalizeTableCellSelection(range) {\n moveEndPoint(range, true);\n moveEndPoint(range, false);\n return range;\n }\n /**\n * Convert HTML encoded double quote to double quote with backslash within widget directives\n *\n * @param {string} content\n * @returns {string}\n */\n\n\n function escapeDoubleQuoteWithinWidgetDirective(content) {\n return content.replace(/\\{\\{widget[\\S\\s]*?\\}\\}/ig, function (match) {\n return match.replace(/"/g, \"\\\\\\\"\");\n });\n }\n /**\n * Convert double quote with backslash to HTML encoded double quote within widget directives\n *\n * @param {string} content\n * @returns {string}\n */\n\n\n function unescapeDoubleQuoteWithinWidgetDirective(content) {\n return content.replace(/\\{\\{widget[\\S\\s]*?\\}\\}/ig, function (match) {\n return match.replace(/\\\\+\"/g, \""\");\n });\n }\n /**\n * Convert double quote to single quote within magento variable directives\n *\n * @param {string} content\n * @returns {string}\n */\n\n\n function replaceDoubleQuoteWithSingleQuoteWithinVariableDirective(content) {\n // Find html elements which attributes contain magento variables directives\n return content.replace(/<([a-z0-9\\-\\_]+)([^>]+?[a-z0-9\\-\\_]+=\"[^\"]*?\\{\\{.+?\\}\\}.*?\".*?)>/gi, function (match1, tag, attributes) {\n // Replace double quote with single quote within magento variable directive\n var sanitizedAttributes = attributes.replace(/\\{\\{[^\\{\\}]+\\}\\}/gi, function (match2) {\n return match2.replace(/\"/g, \"'\");\n });\n return \"<\" + tag + sanitizedAttributes + \">\";\n });\n }\n /**\n * Remove Page Builder reserved html tag attributes from the content\n *\n * @param {string} content\n * @returns {string}\n */\n\n\n function removeReservedHtmlAttributes(content) {\n var attributes = _config.getConfig(\"stage_config\").reserved_html_attributes || {};\n\n for (var _i = 0, _Object$keys = Object.keys(attributes); _i < _Object$keys.length; _i++) {\n var attribute = _Object$keys[_i];\n content = removeHtmlTagAttribute(content, attribute);\n }\n\n return content;\n }\n /**\n * Remove attribute from html tags\n *\n * @param {string} content\n * @param {string} name\n * @returns {string}\n */\n\n\n function removeHtmlTagAttribute(content, name) {\n if (typeof content === \"string\" && content.indexOf(name + \"=\") !== -1) {\n var html = new DOMParser().parseFromString(content, \"text/html\");\n html.querySelectorAll(\"[\" + name + \"]\").forEach(function (child) {\n child.removeAttribute(name);\n });\n content = html.body.innerHTML;\n }\n\n return content;\n }\n\n return {\n isWysiwygSupported: isWysiwygSupported,\n encodeContent: encodeContent,\n parseAttributesString: parseAttributesString,\n lockImageSize: lockImageSize,\n unlockImageSize: unlockImageSize,\n createBookmark: createBookmark,\n moveToBookmark: moveToBookmark,\n getActiveEditor: getActiveEditor,\n findNodeIndex: findNodeIndex,\n getNodeByIndex: getNodeByIndex,\n createDoubleClickEvent: createDoubleClickEvent,\n processInlineStyles: processInlineStyles,\n escapeDoubleQuoteWithinWidgetDirective: escapeDoubleQuoteWithinWidgetDirective,\n unescapeDoubleQuoteWithinWidgetDirective: unescapeDoubleQuoteWithinWidgetDirective,\n replaceDoubleQuoteWithSingleQuoteWithinVariableDirective: replaceDoubleQuoteWithSingleQuoteWithinVariableDirective,\n removeReservedHtmlAttributes: removeReservedHtmlAttributes\n };\n});\n//# sourceMappingURL=editor.js.map","Magento_PageBuilder/js/utils/url.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([], function () {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * Check for whether url string contains only a path\n *\n * @param {String} url\n * @returns {Boolean}\n */\n function isPathOnly(url) {\n return url.indexOf(\"/\") === 0;\n }\n /**\n * Get the path from a URL\n *\n * @param {String} url\n * @returns {String}\n */\n\n\n function getPathFromUrl(url) {\n var a = document.createElement(\"a\");\n a.href = url;\n return a.pathname;\n }\n /**\n * Convert url to path if other url is only a path\n *\n * @param {string} url\n * @param {string} otherUrl\n * @returns {string}\n * @api\n */\n\n\n function convertUrlToPathIfOtherUrlIsOnlyAPath(url, otherUrl) {\n return isPathOnly(otherUrl) ? getPathFromUrl(url) : url;\n }\n\n return {\n convertUrlToPathIfOtherUrlIsOnlyAPath: convertUrlToPathIfOtherUrlIsOnlyAPath\n };\n});\n//# sourceMappingURL=url.js.map","Magento_PageBuilder/js/utils/pagebuilder-header-height.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([\"jquery\"], function (_jquery) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * Checks if PageBuilder has header and returns it's height\n *\n * @param {string} stageId\n * @param {string} stageWrapper\n * @param {string} pageBuilderHeader\n * @returns {number}\n */\n function pageBuilderHeaderHeight(stageId, stageWrapper, pageBuilderHeader) {\n if (stageWrapper === void 0) {\n stageWrapper = \".pagebuilder-stage-wrapper\";\n }\n\n if (pageBuilderHeader === void 0) {\n pageBuilderHeader = \".pagebuilder-header\";\n }\n\n var $stageWrapper = (0, _jquery)(\"#\" + stageId).closest(stageWrapper);\n var $pageBuilderHeader = $stageWrapper.find(pageBuilderHeader);\n return !!$pageBuilderHeader.length ? $pageBuilderHeader.height() : 0;\n }\n\n return pageBuilderHeaderHeight;\n});\n//# sourceMappingURL=pagebuilder-header-height.js.map","Magento_PageBuilder/js/utils/check-stage-full-screen.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([\"jquery\"], function (_jquery) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * Check if stage full screen mode is active\n *\n * @param {string} stageId\n * @returns {boolean}\n */\n function checkStageFullScreen(stageId) {\n var $stage = (0, _jquery)(\"#\" + stageId);\n var $fullScreenStageWrapper = $stage.closest(\".stage-full-screen\");\n return !!$fullScreenStageWrapper.length;\n }\n\n return checkStageFullScreen;\n});\n//# sourceMappingURL=check-stage-full-screen.js.map","Magento_PageBuilder/js/utils/object.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([\"object-path\"], function (_objectPath) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * Retrieve a value from an object via a path\n *\n * @param {object} object\n * @param {string} path\n * @param {TResult} defaultValue\n * @returns {TResult}\n */\n function get(object, path, defaultValue) {\n return _objectPath.get(object, path, defaultValue);\n }\n /**\n * Set a value within an object via a path\n *\n * @param {object} object\n * @param {string} path\n * @param {TResult} value\n * @returns {TResult | undefined}\n */\n\n\n function set(object, path, value) {\n return _objectPath.set(object, path, value);\n }\n\n return {\n get: get,\n set: set\n };\n});\n//# sourceMappingURL=object.js.map","Magento_PageBuilder/js/utils/delay-until.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([], function () {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * Delay until a condition is met\n *\n * @param {() => void} callback\n * @param {() => boolean} condition\n * @param {number} interval\n */\n function delayUntil(callback, condition, interval) {\n if (interval === void 0) {\n interval = 50;\n }\n\n var delayInterval = setInterval(function () {\n if (condition()) {\n clearInterval(delayInterval);\n callback();\n }\n }, interval);\n }\n\n return delayUntil;\n});\n//# sourceMappingURL=delay-until.js.map","Magento_PageBuilder/js/utils/breakpoints.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'underscore'\n], function (_) {\n 'use strict';\n\n return {\n /**\n * Build media query.\n *\n * @param {Object} conditions\n * @returns {String}\n */\n buildMedia: function (conditions) {\n var result = _.map(_.pairs(conditions), function (condition) {\n return '(' + condition.join(': ') + ')';\n });\n\n return result.join(' and ');\n }\n };\n});\n","Magento_PageBuilder/js/utils/array.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([], function () {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * Move an array item within the current array\n *\n * @param array\n * @param fromIndex\n * @param toIndex\n * @returns {Array<any>}\n */\n function moveArrayItem(array, fromIndex, toIndex) {\n array.splice(toIndex, 0, array.splice(fromIndex, 1)[0]);\n return array;\n }\n /**\n * Move an array item from one array into another\n *\n * @param item\n * @param array\n * @param toIndex\n * @returns {Array<any>}\n */\n\n\n function moveArrayItemIntoArray(item, array, toIndex) {\n array.splice(toIndex, 0, item);\n return array;\n }\n /**\n * Remove an array item\n *\n * @param array\n * @param item\n * @returns {Array<any>}\n */\n\n\n function removeArrayItem(array, item) {\n var index = array.indexOf(item);\n\n if (index > -1) {\n array.splice(index, 1);\n }\n\n return array;\n }\n /**\n * Search outwards from an array item until a callback matches\n *\n * @author https://github.com/thejameskyle/outward-search\n *\n * @param {any[]} items\n * @param {number} start\n * @param {(item: any, index: number) => boolean} callback\n * @returns {any}\n * @api\n */\n\n\n function outwardSearch(items, start, callback) {\n if (!items.length) {\n return null;\n }\n\n if (start < 0 || start > items.length - 1) {\n throw new TypeError(\"starting index must be within bounds of array\");\n }\n\n var max = items.length - 1;\n var low = start;\n var high = start + 1;\n\n while (true) {\n var hitMin = low < 0;\n var hitMax = high > max;\n\n if (hitMin && hitMax) {\n break;\n }\n\n if (!hitMin) {\n var _item = items[low];\n var result = callback(_item, low);\n\n if (!!result) {\n return _item;\n }\n\n low--;\n }\n\n if (!hitMax) {\n var _item2 = items[high];\n\n var _result = callback(_item2, high);\n\n if (!!_result) {\n return _item2;\n }\n\n high++;\n }\n }\n\n return null;\n }\n\n return {\n moveArrayItem: moveArrayItem,\n moveArrayItemIntoArray: moveArrayItemIntoArray,\n removeArrayItem: removeArrayItem,\n outwardSearch: outwardSearch\n };\n});\n//# sourceMappingURL=array.js.map","Magento_PageBuilder/js/utils/text.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([], function () {\n \"use strict\";\n});\n//# sourceMappingURL=text.js.map","Magento_PageBuilder/js/utils/create-stylesheet.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([], function () {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * Create a stylesheet DOM object from a style block declaration\n *\n * @param {StyleBlocks} blocks\n * @returns {HTMLStyleElement}\n * @api\n */\n function createStyleSheet(blocks) {\n var style = document.createElement(\"style\");\n var text = Object.keys(blocks).map(function (selector) {\n return selector + (\" {\\n\" + processDeclarationBlock(blocks[selector]) + \"\\n}\");\n }).join(\"\\n\");\n style.setAttribute(\"type\", \"text/css\");\n style.appendChild(document.createTextNode(text));\n return style;\n }\n /**\n * Process a declaration block from the rule set\n *\n * @param {StyleBlock} block\n * @returns {string}\n */\n\n\n function processDeclarationBlock(block) {\n return Object.keys(block).map(function (property) {\n return processDeclaration(property, block[property]);\n }).join(\"\\n\");\n }\n /**\n * Process a declaration, creating the property: value syntax\n *\n * @param {string} property\n * @param {string | number} value\n * @returns {string}\n */\n\n\n function processDeclaration(property, value) {\n return hyphenate(property) + (\": \" + value + \";\");\n }\n /**\n * Hyphenate style property, from textAlign to text-align\n *\n * @param {string} property\n * @returns {string}\n */\n\n\n function hyphenate(property) {\n return property.replace(/[A-Z]/g, function (match) {\n return \"-\" + match.toLowerCase();\n });\n }\n\n return {\n createStyleSheet: createStyleSheet\n };\n});\n//# sourceMappingURL=create-stylesheet.js.map","Magento_PageBuilder/js/utils/image.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([\"Magento_PageBuilder/js/config\", \"Magento_PageBuilder/js/utils/directives\", \"Magento_PageBuilder/js/utils/url\"], function (_config, _directives, _url) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * Decode image background URL to object\n *\n * @param value\n * @returns {Object}\n * @api\n */\n function decodeUrl(value) {\n var result = \"\";\n value = decodeURIComponent(value.replace(window.location.href, \"\"));\n var regexp = /{{.*\\s*url=\"?(.*\\.([a-z|A-Z]*))\"?\\s*}}/;\n\n if (regexp.test(value)) {\n var _regexp$exec = regexp.exec(value),\n url = _regexp$exec[1],\n type = _regexp$exec[2];\n\n var image = {\n name: url.split(\"/\").pop(),\n size: 0,\n type: \"image/\" + type,\n url: _config.getConfig(\"media_url\") + url\n };\n result = [image];\n }\n\n return result;\n }\n /**\n * Convert a URL to an image directive\n *\n * @param {string} imageUrl\n * @returns {string}\n */\n\n\n function urlToDirective(imageUrl) {\n var mediaUrl = (0, _url.convertUrlToPathIfOtherUrlIsOnlyAPath)(_config.getConfig(\"media_url\"), imageUrl);\n var mediaPath = imageUrl.split(mediaUrl);\n return \"{{media url=\" + mediaPath[1] + \"}}\";\n }\n /**\n * Convert an image URL to a background image data uri\n *\n * @param {string} imageUrl\n * @returns {string}\n */\n\n\n function imageToBackgroundImageDataUrl(imageUrl) {\n return \"url(\\'\" + (0, _directives.toDataUrl)(urlToDirective(imageUrl)) + \"\\')\";\n }\n\n return {\n decodeUrl: decodeUrl,\n urlToDirective: urlToDirective,\n imageToBackgroundImageDataUrl: imageToBackgroundImageDataUrl\n };\n});\n//# sourceMappingURL=image.js.map","Magento_PageBuilder/js/utils/position-sticky.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([], function () {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * Determine if the current browser supports position sticky\n *\n * @returns {boolean}\n */\n function supportsPositionSticky() {\n if (!window.getComputedStyle) {\n return false;\n }\n\n var testNode = document.createElement(\"div\");\n return [\"\", \"-webkit-\", \"-moz-\", \"-ms-\"].some(function (prefix) {\n try {\n testNode.style.position = prefix + \"sticky\";\n } catch (e) {// Fail silently\n }\n\n return testNode.style.position !== \"\";\n });\n }\n\n return {\n supportsPositionSticky: supportsPositionSticky\n };\n});\n//# sourceMappingURL=position-sticky.js.map","Magento_PageBuilder/js/utils/nesting-link-dialog.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([\"jquery\", \"mage/translate\", \"Magento_PageBuilder/js/modal/dismissible-confirm\"], function (_jquery, _translate, _dismissibleConfirm) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * Validate inline editor for having nested link\n * Creates a dialog and removes inline editor link if present\n *\n * @param {DataStore} dataStore\n * @param {WysiwygInterface} wysiwyg\n * @param {string} inlineMessageField\n * @param {string} linkUrlField\n */\n function nestingLinkDialog(dataStore, wysiwyg, inlineMessageField, linkUrlField) {\n var dataStoreContent = dataStore.getState();\n var inlineMessage = dataStoreContent[inlineMessageField];\n var linkUrl = dataStoreContent[linkUrlField];\n var aLinkRegex = /(<a[\\s]+[^>]+).+(?=<\\/a>)<\\/a>/igm;\n\n if (wysiwyg && inlineMessage.match(aLinkRegex) && linkUrl && [\"page\", \"product\", \"category\", \"default\"].indexOf(linkUrl.type) !== -1 && linkUrl[linkUrl.type] && linkUrl[linkUrl.type].length !== 0) {\n var inlineEditor = (0, _jquery)(\"#\" + wysiwyg.elementId);\n inlineEditor.trigger(\"blur\");\n (0, _dismissibleConfirm)({\n actions: {\n always: function always() {\n var anchorLessDataStoreMessage = inlineMessage.replace(aLinkRegex, \"\");\n var anchorLessInlineMessage = inlineEditor.html().replace(aLinkRegex, \"\");\n dataStore.set(inlineMessageField, anchorLessDataStoreMessage);\n inlineEditor.html(anchorLessInlineMessage);\n }\n },\n content: (0, _translate)(\"We are unable to support links within the content field whilst having a link set on the content type. Please remove the content type link if you'd like to set a link within the content. We will automatically remove the links within the content field.\"),\n // tslint:disable-line:max-line-length\n title: (0, _translate)(\"Nested links are not allowed\"),\n haveCancelButton: false\n });\n }\n }\n\n return nestingLinkDialog;\n});\n//# sourceMappingURL=nesting-link-dialog.js.map","Magento_PageBuilder/js/utils/nesting-widget-dialog.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([\"jquery\", \"mage/translate\", \"Magento_PageBuilder/js/modal/dismissible-confirm\"], function (_jquery, _translate, _dismissibleConfirm) {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n /**\n * Validate inline editor for having nested widget\n * Creates a dialog and removes inline editor widget if present\n *\n * @param {DataStore} dataStore\n * @param {WysiwygInterface} wysiwyg\n * @param {string} inlineMessageField\n * @param {string} linkUrlField\n */\n function nestingWidgetDialog(dataStore, wysiwyg, inlineMessageField, linkUrlField) {\n var dataStoreContent = dataStore.getState();\n var inlineMessage = dataStoreContent[inlineMessageField];\n var linkUrl = dataStoreContent[linkUrlField];\n var widgetRegex = /\\{\\{widget([\\S\\s]*?)\\}\\}/ig;\n var widgetPlaceholderRegex = /<span.*(class=)(\\\"|\\').*((magento-placeholder).*(magento-widget)|(magento-widget).*(magento-placeholder)).*<\\/span>/igm;\n\n if (wysiwyg && inlineMessage.match(widgetRegex) && linkUrl && [\"page\", \"product\", \"category\", \"default\"].indexOf(linkUrl.type) !== -1 && linkUrl[linkUrl.type] && linkUrl[linkUrl.type].length !== 0) {\n var inlineEditor = (0, _jquery)(\"#\" + wysiwyg.elementId);\n inlineEditor.trigger(\"blur\");\n (0, _dismissibleConfirm)({\n actions: {\n always: function always() {\n var widgetLessDataStoreMessage = inlineMessage.replace(widgetRegex, \"\");\n var widgetLessInlineMessage = inlineEditor.html().replace(widgetPlaceholderRegex, \"\");\n dataStore.set(inlineMessageField, widgetLessDataStoreMessage);\n inlineEditor.html(widgetLessInlineMessage);\n }\n },\n content: (0, _translate)(\"We are unable to support widget within the content field whilst having a link set on the content type. Please remove the content type link if you'd like to set a widget within the content. We will automatically remove the widget within the content field.\"),\n // tslint:disable-line:max-line-length\n title: (0, _translate)(\"Nested widgets are not allowed\"),\n haveCancelButton: false\n });\n }\n }\n\n return nestingWidgetDialog;\n});\n//# sourceMappingURL=nesting-widget-dialog.js.map","Magento_PageBuilder/js/utils/loader.js":"/*eslint-disable */\n/* jscs:disable */\ndefine([], function () {\n /**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n function load(dependencies, factory, onError) {\n require(dependencies, factory, onError);\n }\n\n return load;\n});\n//# sourceMappingURL=loader.js.map","Magento_PageBuilder/js/modal/dismissible-confirm.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * Extend the confirmation prompt to allow for an additional checkbox to be displayed. The checkbox enables the user to\n * dismiss subsequent prompts of the same type based on their dismissKey.\n *\n * Once a type is dismissed a cookie is set and all future instances of that prompt are bypassed. This cookie is\n * cleared once the user logs out and back in via an observer.\n */\ndefine([\n 'jquery',\n 'underscore',\n 'text!Magento_PageBuilder/template/modal/dismissible-modal-content.html',\n 'mage/translate',\n 'Magento_Ui/js/modal/prompt',\n 'mage/cookies'\n], function ($, _, promptContentTmpl, $t) {\n 'use strict';\n\n /**\n * Create buttons array for modal options\n *\n * @param {Boolean} haveCancelButton\n * @return {Object}\n */\n function buttonsConfig(haveCancelButton) {\n var cancelButton = {\n text: $.mage.__('Cancel'),\n class: 'action-secondary action-dismiss',\n\n /**\n * Click handler.\n */\n click: function () {\n this.closeModal(false);\n }\n },\n confirmButton = {\n text: $.mage.__('OK'),\n class: 'action-primary action-accept',\n\n /**\n * Click handler.\n */\n click: function () {\n this.closeModal(true);\n }\n },\n buttons = [];\n\n if (haveCancelButton !== false) {\n buttons.push(cancelButton);\n }\n buttons.push(confirmButton);\n\n return buttons;\n }\n\n $.widget('mage.dismissibleConfirm', $.mage.prompt, {\n options: {\n promptContentTmpl: promptContentTmpl,\n dismissible: false, // Can the modal be dismissed?\n dismissKey: 'default', // The key we'll check to see if the modal has already been dismissed\n dismissMessage: $t('Do not show this again'), // Message to display next to the dismiss checkbox\n dismissCheckbox: '[name=\"modal-dnsa\"]' // Selector to retrieve dismiss checkbox\n },\n\n /**\n * Open the modal window, if the modal has been dismissed, then run the confirm & always actions and don't\n * don't open the modal\n *\n * @returns {*}\n */\n openModal: function () {\n if ($.mage.cookies.get(this.options.dismissKey) === 'true') {\n this.options.actions.confirm();\n\n return this.options.actions.always(); // Always runs after confirm in confirm.js\n }\n\n return this._super();\n },\n\n /**\n * Close modal window.\n *\n * @param {Boolean} result\n */\n closeModal: function (result) {\n this._super(result);\n\n if (result && this._isDismissed()) {\n $.mage.cookies.set(this.options.dismissKey, 'true', {});\n }\n },\n\n /**\n * Is the dismissed checkbox checked?\n *\n * @private\n */\n _isDismissed: function () {\n return this.modal.find(this.options.dismissCheckbox).is(':checked');\n }\n });\n\n return function (config) {\n config.buttons = buttonsConfig(config.haveCancelButton);\n delete config.haveCancelButton;\n\n return $('<div></div>').html(config.content).dismissibleConfirm(config);\n };\n});\n","Magento_PageBuilder/js/modal/modal.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'Magento_Ui/js/modal/modal-component',\n 'Magento_PageBuilder/js/events'\n], function (ModalComponent, events) {\n 'use strict';\n\n return ModalComponent.extend({\n defaults: {\n titlePrefix: '${ $.options.title }',\n modules: {\n insertForm: '${ $.insertFormProvider }'\n }\n },\n\n /** @inheritdoc */\n initialize: function () {\n this._super();\n\n events.on('form:renderAfter', function (params) {\n this.openModal();\n this.setTitle(this.titlePrefix + ' ' + params.title);\n this.startListen(params.id);\n }.bind(this));\n\n return this;\n },\n\n /**\n * Listen for from save.\n *\n * @param {String} id\n */\n startListen: function (id) {\n events.on('form:' + id + ':saveAfter', function () {\n this.closeModal();\n }.bind(this));\n\n },\n\n /**\n * Trigger modalClosed event on external provider\n *\n * @returns {any}\n */\n closeModal: function () {\n this.insertForm() &&\n this.insertForm().externalSource() &&\n this.insertForm().externalSource().trigger('data.modalClosed');\n\n return this._super();\n }\n });\n});\n","Magento_PageBuilder/js/modal/confirm-alert.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'jquery',\n 'jquery-ui-modules/widget',\n 'Magento_Ui/js/modal/alert',\n 'jquery/z-index'\n], function ($) {\n 'use strict';\n\n $.widget('mage.confirmAlert', $.mage.alert, {\n /**\n * Fix issue with zIndex when removing the alert from the screen\n * @private\n */\n _unsetActive: function () {\n this._super();\n\n if (this.overlay) {\n this.overlay.zIndex('');\n }\n }\n });\n\n return function (config) {\n return $('<div></div>').html(config.content).confirmAlert(config);\n };\n});\n","Magento_PageBuilder/js/modal/template-manager-modal.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'jquery',\n 'Magento_Ui/js/modal/modal-component',\n 'Magento_PageBuilder/js/events',\n 'underscore',\n 'Magento_PageBuilder/js/stage-builder'\n], function ($, ModalComponent, events, _, stageBuilder) {\n 'use strict';\n\n return ModalComponent.extend({\n defaults: {\n stage: null,\n modules: {\n messageContainer: '${ $.messageContainerProvider }',\n listing: '${ $.listingProvider }'\n }\n },\n\n /** @inheritdoc */\n initialize: function () {\n this._super();\n _.bindAll(this, 'closeModal');\n\n events.on('stage:templateManager:open', function (params) {\n this.openModal();\n this.stage = params.stage;\n }.bind(this));\n\n return this;\n },\n\n /**\n * Apply selected template\n *\n * @param {String} template\n */\n applySelected: function (template) {\n if (template) {\n // Destroy the old content in the stage\n this.stage.pageBuilder.destroy();\n $('body').trigger('processStart');\n\n stageBuilder(this.stage, template).then(function () {\n $('body').trigger('processStop');\n this.closeModal();\n }.bind(this));\n }\n }\n });\n});\n","Magento_PageBuilder/js/modal/template-manager-save.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n 'jquery',\n 'underscore',\n 'mage/translate',\n 'Magento_Ui/js/modal/prompt'\n], function ($, _, $t) {\n 'use strict';\n\n $.widget('mage.templateManagerSave', $.mage.prompt, {\n options: {\n createdForField: '[data-role=\"createdForField\"]',\n previewImage: '[data-role=\"preview-image\"]',\n previewImageSpinner: '[data-role=\"preview-image-spinner\"]',\n saveButton: '[data-role=\"action\"].action-save',\n form: 'form',\n buttons: [{\n text: $.mage.__('Cancel'),\n class: 'action-secondary action-dismiss',\n\n /**\n * Click handler.\n */\n click: function () {\n this.closeModal();\n }\n }, {\n text: $.mage.__('Save'),\n class: 'action-primary action-save',\n\n /**\n * Click handler.\n */\n click: function () {\n this.submit();\n }\n }]\n },\n\n /**\n * Create widget\n *\n * @private\n */\n _create: function () {\n this._super();\n\n this.modal.find(this.options.saveButton).prop('disabled', 'disabled');\n // Ensure if the form is submitted through hitting enter we handle it correctly\n this.modal.find(this.options.form).on('submit', function (event) {\n event.preventDefault();\n this.submit();\n }.bind(this));\n },\n\n /**\n * Validate prompt contains a template name\n *\n * @returns {Boolean}\n */\n validate: function () {\n return this.modal.find(this.options.promptField) &&\n !_.isEmpty(this.modal.find(this.options.promptField).val());\n },\n\n /**\n * Save the values within the prompt\n */\n submit: function () {\n var name,\n createdFor;\n\n if (this.options.validation && !this.validate()) {\n return false;\n }\n\n $('body').trigger('processStart');\n\n name = this.modal.find(this.options.promptField).val();\n createdFor = this.modal.find(this.options.createdForField).val();\n\n this.options.actions.confirm.call(this, name, createdFor).then(function () {\n this.closeModal(true);\n $('body').trigger('processStop');\n }.bind(this)).catch(function () {\n $('body').trigger('processStop');\n });\n },\n\n /**\n * Set the preview image\n *\n * @param {String} image\n */\n setPreviewImage: function (image) {\n var previewImage = this.modal.find(this.options.previewImage),\n previewImageSpinner = this.modal.find(this.options.previewImageSpinner);\n\n // Update the preview image within the modal\n previewImageSpinner.hide();\n previewImage.append(\n $('<img />').prop('src', image).prop('alt', $t('Template Preview'))\n ).show();\n\n // Enable the button so the user can save\n this.modal.find(this.options.saveButton).prop('disabled', false);\n },\n\n /**\n * Close modal window\n */\n closeModal: function (saved) {\n if (!saved) {\n this.options.actions.cancel.call(this, saved);\n }\n\n this.options.actions.always();\n this.element.on('promptclosed', _.bind(this._remove, this));\n\n return this._super();\n }\n });\n\n return function (config) {\n return $('<div class=\"prompt-message\"></div>').html(config.content).templateManagerSave(config);\n };\n});\n","Magento_AdminAnalytics/js/release-notification/modal/component-mixin.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine(['jquery', 'analyticsPopupConfig'], function ($, analyticsPopupConfig) {\n 'use strict';\n\n var deferred = $.Deferred(),\n\n mixin = {\n /**\n * Initializes content only if its visible\n */\n initializeContent: function () {\n var initializeContent = this._super.bind(this);\n\n if (!analyticsPopupConfig.analyticsVisible) {\n initializeContent();\n } else {\n deferred.then(function () {\n initializeContent();\n });\n }\n },\n\n /**\n * Initializes release notification content after admin analytics\n */\n initializeContentAfterAnalytics: function () {\n deferred.resolve();\n }\n };\n\n return function (target) {\n return target.extend(mixin);\n };\n});\n\n","Magento_AdminAnalytics/js/modal/component.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'underscore',\n 'jquery',\n 'Magento_Ui/js/modal/modal-component',\n 'uiRegistry',\n 'analyticsPopupConfig'\n],\n function (_, $, Modal, registry, analyticsPopupConfig) {\n 'use strict';\n\n return Modal.extend(\n {\n defaults: {\n imports: {\n enableLogAction: '${ $.provider }:data.enableLogAction',\n disableLogAction: '${ $.provider }:data.disableLogAction'\n },\n options: {},\n notificationWindow: null\n },\n\n /**\n * Initializes modal on opened function\n */\n initModal: function () {\n this.options.opened = this.onOpened.bind(this);\n this._super();\n },\n\n /**\n * Configure ESC and TAB so user can't leave modal\n * without selecting an option\n *\n * @returns {Object} Chainable.\n */\n initModalEvents: function () {\n this._super();\n //Don't allow ESC key to close modal\n this.options.keyEventHandlers.escapeKey = this.handleEscKey.bind(this);\n //Restrict tab action to the modal\n this.options.keyEventHandlers.tabKey = this.handleTabKey.bind(this);\n\n return this;\n },\n\n /**\n * Once the modal is opened it hides the X\n */\n onOpened: function () {\n $('.modal-header button.action-close').attr('disabled', true).hide();\n\n this.focusableElements = $(this.rootSelector).find('a[href], button:enabled');\n this.firstFocusableElement = this.focusableElements[0];\n this.lastFocusableElement = this.focusableElements[this.focusableElements.length - 1];\n this.firstFocusableElement.focus();\n },\n\n /**\n * Changes admin usage setting to yes\n */\n enableAdminUsage: function () {\n var data = {\n 'form_key': window.FORM_KEY\n };\n\n $.ajax(\n {\n type: 'POST',\n url: this.enableLogAction,\n data: data,\n showLoader: true\n }\n ).done(\n function (xhr) {\n if (xhr.error) {\n self.onError(xhr);\n }\n }\n ).fail(this.onError);\n this.openReleasePopup();\n this.closeModal();\n },\n\n /**\n * Changes admin usage setting to no\n */\n disableAdminUsage: function () {\n var data = {\n 'form_key': window.FORM_KEY\n };\n\n $.ajax(\n {\n type: 'POST',\n url: this.disableLogAction,\n data: data,\n showLoader: true\n }\n ).done(\n function (xhr) {\n if (xhr.error) {\n self.onError(xhr);\n }\n }\n ).fail(this.onError);\n this.openReleasePopup();\n this.closeModal();\n },\n\n /**\n * Allows admin usage popup to be shown first and then new release notification\n */\n openReleasePopup: function () {\n var notificationModalSelector = 'release_notification.release_notification.notification_modal_1';\n\n if (analyticsPopupConfig.releaseVisible) {\n registry.get(notificationModalSelector).initializeContentAfterAnalytics();\n }\n },\n\n /**\n * Handle Tab and Shift+Tab key event\n *\n * Keep the tab actions restricted to the popup modal\n * so the user must select an option to dismiss the modal\n */\n handleTabKey: function (event) {\n var modal = this,\n KEY_TAB = 9;\n\n /**\n * Handle Shift+Tab to tab backwards\n */\n function handleBackwardTab() {\n if (document.activeElement === modal.firstFocusableElement ||\n document.activeElement === $(modal.rootSelector)[0]\n ) {\n event.preventDefault();\n modal.lastFocusableElement.focus();\n }\n }\n\n /**\n * Handle Tab forward\n */\n function handleForwardTab() {\n if (document.activeElement === modal.lastFocusableElement) {\n event.preventDefault();\n modal.firstFocusableElement.focus();\n }\n }\n\n switch (event.keyCode) {\n case KEY_TAB:\n if (modal.focusableElements.length === 1) {\n event.preventDefault();\n break;\n }\n\n if (event.shiftKey) {\n handleBackwardTab();\n break;\n }\n handleForwardTab();\n break;\n default:\n break;\n }\n },\n\n /**\n * Handle Esc key\n *\n * Esc key should not close modal\n */\n handleEscKey: function (event) {\n event.preventDefault();\n }\n }\n );\n }\n);\n","Magento_Downloadable/downloadable-type-handler.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n 'jquery',\n 'Magento_Catalog/js/product/weight-handler',\n 'Magento_Catalog/catalog/type-events'\n], function ($, weight, productType) {\n 'use strict';\n\n return {\n $checkbox: $('[data-action=change-type-product-downloadable]'),\n $items: $('#product_info_tabs_downloadable_items'),\n $tab: null,\n isDownloadable: false,\n\n /**\n * Show\n */\n show: function () {\n this.$checkbox.prop('checked', true);\n this.$items.show();\n },\n\n /**\n * Hide\n */\n hide: function () {\n this.$checkbox.prop('checked', false);\n this.$items.hide();\n },\n\n /**\n * Constructor component\n * @param {Object} data - this backend data\n */\n 'Magento_Downloadable/downloadable-type-handler': function (data) {\n this.$tab = $('[data-tab=' + data.tabId + ']');\n this.isDownloadable = data.isDownloadable;\n this.bindAll();\n this._initType();\n },\n\n /**\n * Bind all\n */\n bindAll: function () {\n this.$checkbox.on('change', function (event) {\n $(document).trigger('setTypeProduct', $(event.target).prop('checked') ?\n 'downloadable' :\n productType.type.init === 'downloadable' ? 'virtual' : productType.type.init\n );\n });\n\n $(document).on('changeTypeProduct', this._initType.bind(this));\n },\n\n /**\n * Init type\n * @private\n */\n _initType: function () {\n if (productType.type.current === 'downloadable') {\n weight.change(false);\n weight.$weightSwitcher().one('change', function () {\n $(document).trigger(\n 'setTypeProduct',\n productType.type.init === 'downloadable' ? 'virtual' : productType.type.init\n );\n });\n this.show();\n } else {\n this.hide();\n }\n }\n };\n});\n","Magento_Downloadable/js/components/use-price-default-handler.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n 'Magento_Ui/js/form/element/single-checkbox'\n], function (Element) {\n 'use strict';\n\n return Element.extend({\n defaults: {\n linksPurchasedSeparately: '0',\n listens: {\n linksPurchasedSeparately: 'changeVisibleStatus'\n }\n },\n\n /**\n * Change visibility of checkbox\n */\n changeVisibleStatus: function () {\n if (this.linksPurchasedSeparately === '1') {\n this.visible(true);\n } else {\n this.visible(false);\n }\n }\n });\n});\n","Magento_Downloadable/js/components/file-uploader.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n 'Magento_Ui/js/form/element/file-uploader'\n], function (Element) {\n 'use strict';\n\n return Element.extend({\n defaults: {\n fileInputName: ''\n },\n\n /**\n * Adds provided file to the files list.\n *\n * @param {Object} file\n * @returns {FileUploder} Chainable.\n */\n addFile: function (file) {\n var processedFile = this.processFile(file),\n tmpFile = [],\n resultFile = {\n 'file': processedFile.file,\n 'name': processedFile.name,\n 'size': processedFile.size,\n 'status': processedFile.status ? processedFile.status : 'new'\n };\n\n tmpFile[0] = resultFile;\n\n this.isMultipleFiles ?\n this.value.push(tmpFile) :\n this.value(tmpFile);\n\n return this;\n }\n });\n});\n","Magento_Downloadable/js/components/price-handler.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n 'Magento_Ui/js/form/element/abstract'\n], function (Element) {\n 'use strict';\n\n return Element.extend({\n defaults: {\n linksPurchasedSeparately: '0',\n useDefaultPrice: false,\n listens: {\n linksPurchasedSeparately: 'changeDisabledStatus',\n useDefaultPrice: 'changeDisabledStatus'\n }\n },\n\n /**\n * Invokes initialize method of parent class,\n * contains initialization logic\n */\n initialize: function () {\n this._super();\n this.changeDisabledStatus();\n\n return this;\n },\n\n /**\n * Disable/enable price field\n */\n changeDisabledStatus: function () {\n if (this.linksPurchasedSeparately === '1') {\n if (this.useDefaultPrice) {\n this.disabled(true);\n } else {\n this.disabled(false);\n }\n } else {\n this.disabled(true);\n }\n }\n });\n});\n","Magento_Downloadable/js/components/upload-type-handler.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n 'Magento_Ui/js/form/element/select',\n 'uiRegistry'\n], function (Select, registry) {\n 'use strict';\n\n return Select.extend({\n defaults: {\n listens: {\n value: 'changeTypeUpload'\n },\n typeUrl: 'file',\n typeFile: 'link_url',\n filterPlaceholder: 'ns = ${ $.ns }, parentScope = ${ $.parentScope }'\n },\n\n /**\n * Initialize component.\n * @returns {Element}\n */\n initialize: function () {\n return this\n ._super()\n .changeTypeUpload(this.initialValue);\n },\n\n /**\n * Callback that fires when 'value' property is updated.\n *\n * @param {String} currentValue\n * @returns {*}\n */\n onUpdate: function (currentValue) {\n this.changeTypeUpload(currentValue);\n\n return this._super();\n },\n\n /**\n * Change visibility for typeUrl/typeFile based on current value.\n *\n * @param {String} currentValue\n */\n changeTypeUpload: function (currentValue) {\n var componentFile = this.filterPlaceholder + ', index=' + this.typeFile,\n componentUrl = this.filterPlaceholder + ', index=' + this.typeUrl;\n\n switch (currentValue) {\n\n case 'file':\n this.changeVisible(componentFile, true);\n this.changeVisible(componentUrl, false);\n break;\n\n case 'url':\n this.changeVisible(componentFile, false);\n this.changeVisible(componentUrl, true);\n break;\n }\n },\n\n /**\n * Change visible\n *\n * @param {String} filter\n * @param {Boolean} visible\n */\n changeVisible: function (filter, visible) {\n registry.async(filter)(\n function (currentComponent) {\n currentComponent.visible(visible);\n }\n );\n }\n });\n});\n","Magento_Downloadable/js/components/is-downloadable-handler.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n 'Magento_Ui/js/form/element/single-checkbox'\n], function (Element) {\n 'use strict';\n\n return Element.extend({\n defaults: {\n listens: {\n disabled: 'changeVisibility'\n },\n modules: {\n samplesFieldset: '${ $.samplesFieldset }',\n linksFieldset: '${ $.linksFieldset}'\n }\n },\n\n /**\n * Change visibility for samplesFieldset & linksFieldset based on current statuses of checkbox.\n */\n changeVisibility: function () {\n if (this.samplesFieldset() && this.linksFieldset()) {\n if (this.checked() && !this.disabled()) {\n this.samplesFieldset().visible(true);\n this.linksFieldset().visible(true);\n } else {\n this.samplesFieldset().visible(false);\n this.linksFieldset().visible(false);\n }\n }\n },\n\n /**\n * Handle checked state changes for checkbox / radio button.\n *\n * @param {Boolean} newChecked\n */\n onCheckedChanged: function (newChecked) {\n this.changeVisibility();\n this._super(newChecked);\n }\n });\n});\n","Magento_User/js/roles-tree.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n 'jquery',\n 'jquery/ui',\n 'jquery/jstree/jquery.jstree'\n], function ($) {\n 'use strict';\n\n $.widget('mage.rolesTree', {\n options: {\n treeInitData: {},\n editFormSelector: '',\n resourceFieldName: 'resource[]',\n checkboxVisible: true\n },\n\n /** @inheritdoc */\n _create: function () {\n this.element.jstree({\n plugins: ['checkbox'],\n checkbox: {\n // jscs:disable requireCamelCaseOrUpperCaseIdentifiers\n three_state: false,\n // jscs:enable requireCamelCaseOrUpperCaseIdentifiers\n visible: this.options.checkboxVisible,\n cascade: 'undetermined'\n },\n core: {\n data: this.options.treeInitData,\n themes: {\n dots: false\n }\n }\n });\n this._bind();\n },\n\n /**\n * @private\n */\n _destroy: function () {\n this.element.jstree('destroy');\n },\n\n /**\n * @private\n */\n _bind: function () {\n this.element.on('select_node.jstree', $.proxy(this._selectChildNodes, this));\n this.element.on('deselect_node.jstree', $.proxy(this._deselectChildNodes, this));\n this.element.on('changed.jstree', $.proxy(this._changedNode, this));\n },\n\n /**\n * @param {Event} event\n * @param {Object} selected\n * @private\n */\n _selectChildNodes: function (event, selected) {\n // jscs:disable requireCamelCaseOrUpperCaseIdentifiers\n selected.instance.open_node(selected.node);\n selected.node.children.each(function (id) {\n var selector = '[id=\"' + id + '\"]';\n\n selected.instance.select_node(\n selected.instance.get_node($(selector), false)\n );\n });\n // jscs:enable requireCamelCaseOrUpperCaseIdentifiers\n },\n\n /**\n * @param {Event} event\n * @param {Object} selected\n * @private\n */\n _deselectChildNodes: function (event, selected) {\n selected.node.children.each(function (id) {\n var selector = '[id=\"' + id + '\"]';\n\n // jscs:disable requireCamelCaseOrUpperCaseIdentifiers\n selected.instance.deselect_node(\n selected.instance.get_node($(selector), false)\n );\n // jscs:enable requireCamelCaseOrUpperCaseIdentifiers\n });\n },\n\n /**\n * Add selected resources to form to be send later\n *\n * @param {Event} event\n * @param {Object} selected\n * @private\n */\n _changedNode: function (event, selected) {\n var form = $(this.options.editFormSelector),\n fieldName = this.options.resourceFieldName,\n items = selected.selected.concat($(this.element).jstree('get_undetermined'));\n\n if (this.options.editFormSelector === '') {\n return;\n }\n form.find('input[name=\"' + this.options.resourceFieldName + '\"]').remove();\n items.each(function (id) {\n $('<input>', {\n type: 'hidden',\n name: fieldName,\n value: id\n }).appendTo(form);\n });\n }\n });\n\n return $.mage.rolesTree;\n});\n","Magento_User/js/delete-user-account.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n 'jquery'\n], function ($) {\n 'use strict';\n\n var postData;\n\n return function (params, elem) {\n\n elem.on('click', function () {\n\n postData = {\n 'data': {\n 'user_id': params.objId,\n 'current_password': $('[name=\"current_password\"]').val()\n }\n };\n\n if ($.validator.validateElement($('[name=\"current_password\"]'))) {\n window.deleteConfirm(params.message, params.url, postData);\n }\n });\n };\n});\n","Magento_PageBuilderAdminAnalytics/js/page-builder/events-mixin.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine(['underscore', 'Magento_PageBuilderAdminAnalytics/js/page-builder/event-builder'],\n function (_, EventBuilder) {\n 'use strict';\n\n return function (target) {\n var originalTarget = target.trigger,\n isAdminAnalyticsEnabled,\n event,\n hasPageBuilderBeenUsed = false,\n delayedPush;\n\n /**\n * Invokes custom code to track information regarding Page Builder usage\n *\n * @param {String} name\n * @param {Array} args\n */\n\n target.trigger = function (name, args) {\n originalTarget.apply(originalTarget, [name, args]);\n isAdminAnalyticsEnabled =\n !_.isUndefined(window.digitalData) &&\n !_.isUndefined(window._satellite);\n\n if (!hasPageBuilderBeenUsed && name.indexOf('stage:fullScreenModeChangeAfter') !== -1 &&\n args.fullScreen && isAdminAnalyticsEnabled\n ) {\n hasPageBuilderBeenUsed = true;\n window.digitalData.page.url = window.location.href;\n window.digitalData.page.attributes = {\n editedWithPageBuilder: 'true'\n };\n window._satellite.track('page');\n }\n\n event = EventBuilder.build(name, args);\n\n if (isAdminAnalyticsEnabled && !_.isUndefined(window.digitalData.event) && !_.isUndefined(event)) {\n delayedPush = setInterval(function (object) {\n if (_.isArray(window.digitalData.event)) {\n window.digitalData.event.push(object);\n window._satellite.track('event');\n clearInterval(delayedPush);\n }\n }, 500, event);\n }\n };\n\n return target;\n };\n });\n","Magento_PageBuilderAdminAnalytics/js/page-builder/event-builder.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine(['underscore'], function (_) {\n 'use strict';\n\n return {\n\n /**\n * Sets up event attributes and action depending on name and args\n *\n * @param {String} name\n * @param {Array} args\n */\n\n build: function (name, args) {\n var action = '',\n eventAttributes = {},\n event;\n\n if (_.isUndefined(args)) {\n return;\n }\n\n switch (name) {\n case 'contentType:duplicateAfter':\n action = 'duplicate';\n break;\n\n case 'contentType:removeAfter':\n action = 'remove';\n break;\n\n case 'contentType:createAfter':\n action = 'create';\n break;\n\n case 'contentType:editBefore':\n action = 'edit';\n break;\n\n case 'contentType:visibilityAfter':\n action = args.visibility ? 'show' : 'hide';\n break;\n\n default:\n break;\n }\n\n if (!_.isUndefined(args.contentType)) {\n eventAttributes = args.contentType.config;\n } else if (!_.isUndefined(args.originalContentType)) {\n eventAttributes = args.originalContentType.config;\n }\n\n if (action !== '' && !_.isEmpty(eventAttributes)) {\n event = {\n element: eventAttributes.label,\n type: eventAttributes.name,\n action: action,\n widget: {\n name: eventAttributes.form,\n type: eventAttributes['menu_section']\n },\n feature: 'page-builder-tracker'\n };\n }\n\n return event;\n }\n };\n});\n","Magento_Review/js/rating.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n 'jquery',\n 'jquery/ui'\n], function ($) {\n 'use strict';\n\n $.widget('marketing.ratingControl', {\n options: {\n colorFilled: '#333',\n colorUnfilled: '#CCCCCC',\n colorHover: '#f30'\n },\n\n /** @inheritdoc */\n _create: function () {\n this._labels = this.element.find('label');\n this._bind();\n },\n\n /**\n * @private\n */\n _bind: function () {\n this._labels.on({\n click: $.proxy(function (e) {\n $(e.currentTarget).prev().prop('checked', true);\n this._updateRating();\n }, this),\n\n hover: $.proxy(function (e) {\n this._updateHover($(e.currentTarget), this.options.colorHover);\n }, this),\n\n mouseleave: $.proxy(function (e) {\n this._updateHover($(e.currentTarget), this.options.colorUnfilled);\n }, this)\n });\n\n this._updateRating();\n },\n\n /**\n * @param {jQuery} elem\n * @param {String} color\n * @private\n */\n _updateHover: function (elem, color) {\n elem.nextAll('label').addBack().filter(function () {\n return !$(this).data('checked');\n }).css('color', color);\n },\n\n /**\n * @private\n */\n _updateRating: function () {\n var checkedInputs = this.element.find('input[type=\"radio\"]:checked');\n\n checkedInputs.nextAll('label').addBack().css('color', this.options.colorFilled).data('checked', true);\n checkedInputs.prevAll('label').css('color', this.options.colorUnfilled).data('checked', false);\n },\n\n /**\n * Remove rating when form reset\n */\n removeRating: function () {\n var checkedInputs = this.element.find('input[type=\"radio\"]');\n\n checkedInputs.nextAll('label').css('color', this.options.colorUnfilled).data('checked', false);\n }\n });\n\n});\n","Amasty_ImportCore/js/controls.js":"define([\n 'Magento_Ui/js/form/element/abstract',\n 'jquery',\n 'underscore'\n], function (Abstract, $, _) {\n 'use strict';\n\n return Abstract.extend({\n defaults: {\n messages: [],\n status: '',\n proceed: 0,\n total: 0,\n isImport: false,\n listens: {\n '${ $.parentName }:responseData': 'statusCheck'\n },\n modules: {\n formComponent: '${ $.parentName }',\n }\n },\n initObservable: function () {\n this._super().observe([\n 'messages',\n 'isImport',\n 'status',\n 'total',\n 'proceed'\n ]);\n\n return this;\n },\n resetData: function () {\n this.status(null);\n this.proceed(0);\n this.total(0);\n this.messages([]);\n },\n checkData: function () {\n this.resetData();\n this.visible(false);\n this.source.data.processIdentity = this.uuidv4();\n this.formComponent().save();\n if (!this.source.get('params.invalid')) {\n $('.amimport-check-data').prop('disabled', true);\n this.changeFormElementsState(true, this.formComponent().elems());\n }\n },\n cancel: function () {\n $.get(this.cancelUrl, {'processIdentity': this.source.data.processIdentity }, function () {\n $('.amimport-check-data').prop('disabled', false);\n this.changeFormElementsState(false, this.formComponent().elems());\n }.bind(this));\n },\n cancelClick: function () {\n this.visible(false);\n this.cancel();\n },\n processImport: function () {\n _.each(this.formComponent().elems(), function (elem) {\n if (elem.name !== this.name) {\n elem.visible(false);\n }\n }.bind(this));\n this.isImport(true);\n this.resetData();\n $.get(this.importUrl, {'processIdentity': this.source.data.processIdentity }, function (data) {\n this.statusCheck(data);\n }.bind(this));\n },\n statusCheck: function (data) {\n this.visible(true);\n if (!_.isUndefined(data) && !_.isUndefined(data.type)\n && !_.isUndefined(data.message) && data.type === 'error'\n ) {\n this.isImport(false);\n this.messages([{type: 50, message: data.message}]);\n this.cancel();\n return;\n }\n\n this.getStatus().done(function (data) {\n this.status(data.status);\n this.total(data.total);\n this.proceed(data.proceed);\n\n if (data.messages !== undefined) {\n this.messages(data.messages)\n } else {\n this.messages([]);\n }\n\n if (data.status === 'running' || data.status === 'starting') {\n setTimeout(this.statusCheck.bind(this), 1000);\n } else {\n if (this.status() === 'failed') {\n this.cancel();\n }\n }\n }.bind(this));\n },\n getStatus: function () {\n var result = $.Deferred();\n $.get(this.statusUrl, {'processIdentity': this.source.data.processIdentity }, function (data) {\n result.resolve(data);\n });\n\n return result;\n },\n changeFormElementsState: function (disable, elems) {\n _.each(elems, function (elem) {\n if (_.isFunction(elem.visible) && elem.visible() && _.isFunction(elem.disabled)) {\n elem.disabled(disable);\n }\n if (_.isFunction(elem.elems)) {\n if (!_.isFunction(elem.disabled) && elem.disabled === false) {\n this.changeFormElementsState(disable, elem.elems());\n }\n }\n }.bind(this));\n },\n uuidv4: function () {\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(\n /[xy]/g,\n function (c) {\n var r = Math.random() * 16 | 0, v = c === 'x' ? r : (r & 0x3 | 0x8);\n return v.toString(16);\n }\n );\n }\n });\n});\n","Amasty_ImportCore/js/form.js":"define([\n 'Magento_Ui/js/form/form',\n 'jquery',\n 'underscore',\n 'uiRegistry',\n 'Magento_Ui/js/modal/confirm',\n 'mage/translate',\n], function (Form, $, _, registry, confirm, $t) {\n 'use strict';\n\n return Form.extend({\n defaults: {\n downloadSampleFileConfig: {\n confirmMsg: $t('All possible fields will be included in the sample file without configured mapping. Do you really want to proceed?'),\n mapFieldsPath: 'data.fields.fields',\n scrollToFieldsConfigElm: '',\n openFieldsConfigTab: ''\n },\n listens: {\n 'responseData': 'processResponse'\n },\n modules: {\n run: 'index = run'\n }\n },\n _origSaveUrl: false,\n\n initialize: function () {\n this._super();\n\n this._origSaveUrl = this.source.client.urls.save;\n\n return this;\n },\n\n save: function (redirect, data) {\n this._setSaveUrl();\n\n this._super(redirect, data);\n },\n\n processResponse: function () {\n var responseData = this.responseData();\n\n if (!_.isUndefined(responseData.download) && responseData.download) {\n this._downloadFile(responseData.filename, responseData.content);\n }\n },\n\n downloadSampleFile: function (params) {\n let self = this,\n fieldsConfigInstance;\n\n this.validate();\n if (!this.source.get('params.invalid')) {\n if (this._isMappedFields()) {\n self._changeUrlAndSubmit(params.url);\n } else {\n confirm({\n content: self.downloadSampleFileConfig.confirmMsg,\n actions: {\n confirm: function () {\n self._changeUrlAndSubmit(params.url);\n }\n },\n buttons: [\n {\n text: $t('Yes'),\n class: 'action-secondary action-dismiss',\n click: function (event) {\n this.closeModal(event, true);\n }\n }, {\n text: $t('Configure Mapping First'),\n class: 'action-primary action-accept',\n click: function (event) {\n this.closeModal(event);\n if (self.downloadSampleFileConfig.openFieldsConfigTab) {\n fieldsConfigInstance = registry.get(\n self.downloadSampleFileConfig.openFieldsConfigTab\n );\n\n if (fieldsConfigInstance) {\n fieldsConfigInstance.activate();\n }\n }\n\n if (self.downloadSampleFileConfig.scrollToFieldsConfigElm) {\n fieldsConfigInstance = $(self.downloadSampleFileConfig.scrollToFieldsConfigElm);\n\n $([document.documentElement, document.body]).animate({\n scrollTop: fieldsConfigInstance.offset().top - 77\n }, 2000);\n }\n }\n }\n ]\n });\n }\n } else {\n this.focusInvalid();\n }\n },\n\n _isMappedFields: function () {\n let result = false,\n entities;\n\n entities = Object.values(this.source.get(this.downloadSampleFileConfig.mapFieldsPath))[0];\n\n entities['parent'] = {'fields': entities.fields};\n _.each(entities, function (subEntity) {\n if (_.isObject(subEntity) && 'fields' in subEntity\n && _.isObject(subEntity.fields) && Object.keys(subEntity.fields).length\n ) {\n result = true;\n }\n }.bind(this));\n\n return result;\n },\n\n _setSaveUrl: function () {\n this.source.client.urls.save = this._origSaveUrl;\n },\n\n _changeUrlAndSubmit: function (url) {\n this.source.client.urls.save = url;\n this.submit();\n },\n\n _downloadFile: function (filename, content) {\n let a = document.createElement('a');\n\n document.body.appendChild(a);\n a.style = 'display: none';\n a.download = filename;\n a.href = content;\n a.click();\n window.URL.revokeObjectURL(content);\n }\n });\n});\n","Amasty_ImportCore/js/type-selector.js":"define([\n 'Magento_Ui/js/form/element/select',\n 'underscore'\n], function (Select, _) {\n 'use strict';\n\n return Select.extend({\n defaults: {\n prefix: null,\n listens: {\n value: 'checkElements',\n '${ $.parentName }:elems': 'checkElements'\n },\n modules: {\n fieldsetsContainer: '${ $.parentName }'\n }\n },\n checkElements: function () {\n _.each(this.fieldsetsContainer().elems(), function (elem) {\n if (elem.componentType === 'fieldset') {\n var elementIsVisible = (this.prefix + this.value()) === elem.index;\n\n elem.visible(elementIsVisible);\n this.disableElements(elem, !elementIsVisible);\n }\n }.bind(this));\n },\n disableElements: function (element, disable) {\n if (_.isFunction(element.disabled)) {\n element.disabled(disable);\n } else {\n element.disabled = disable;\n }\n\n if (!_.isUndefined(element.elems) && _.isFunction(element.elems)) {\n _.each(element.elems(), function (elem) {\n this.disableElements(elem, disable);\n }.bind(this));\n }\n }\n });\n});\n","Amasty_ImportCore/js/file-uploader.js":"define([\n 'Magento_Ui/js/form/element/file-uploader',\n], function (FileUploader) {\n\n return FileUploader.extend({\n initialize: function () {\n this._super();\n this.inputName = 'file';\n this.maxFileSize = 2000000;\n\n return this;\n },\n\n onFilesChoosed: function (e, data) {\n if (this.allowedExtensions === undefined || this.allowedExtensions === false) {\n this.allowedExtensions = ' '; // Invalidate file type\n }\n\n this._super(e, data);\n }\n });\n});\n","Amasty_ImportCore/js/entity-select.js":"define([\n 'Magento_Ui/js/form/element/ui-select'\n], function (Select) {\n 'use strict';\n\n return Select.extend({\n defaults: {\n switchEntityUrl: '',\n entityUrl: '',\n indexUrl: ''\n },\n\n onUpdate: function () {\n this._super();\n\n if (this.value() !== '' && this.value() !== undefined) {\n location.href = this.entityUrl.replace('__entity_code__', this.value());\n } else {\n location.href = this.indexUrl;\n }\n },\n\n toggleOptionSelected: function (data) {\n if (data.hasOwnProperty(this.separator)) {\n this.openChildLevel(data);\n return;\n }\n\n return this._super();\n },\n\n _getFilteredArray: function (list, value) {\n var i = 0,\n array = [],\n curOption;\n\n for (i; i < list.length; i++) {\n curOption = list[i].label.toLowerCase();\n\n if ((curOption.indexOf(value) > -1) && (list[i].path !== '')) {\n array.push(list[i]); /*eslint max-depth: [2, 4]*/\n }\n }\n\n return array;\n }\n });\n});\n","Amasty_ImportCore/js/condition-value.js":"define([\n 'uiCollection',\n 'underscore',\n 'uiLayout',\n 'mageUtils'\n], function (Collection, _, layout, utils) {\n return Collection.extend({\n defaults: {\n visible: true,\n disabled: false,\n imports: {\n 'fieldValue' : '${ $.parentName}.field:value'\n },\n listens: {\n fieldValue: 'processField'\n },\n modules: {\n recordComponent: '${ $.parentName }'\n }\n },\n initObservable: function () {\n this._super().observe(['visible', 'fieldValue', 'disabled']);\n\n return this;\n },\n processField: function () {\n if (!_.isUndefined(this.elems()[0])) {\n var dataScope = this.elems()[0].dataScope;\n this.elems()[0].destroy();\n this.source.set(dataScope, null);\n }\n var fieldData = this.recordComponent().parentComponent().filterConfig[this.fieldValue()] || {};\n var componentData = fieldData.config,\n name = this.name + '.value';\n this.elems([]);\n componentData = utils.extend(componentData, {\n 'parentName': this.name,\n 'provider': this.provider,\n 'dataScope': this.dataScope + '.value',\n 'parentScope': this.dataScope,\n 'source': this.source,\n 'disabled': this.disabled,\n 'name': name\n });\n layout([componentData]);\n this.insertChild(name);\n }\n });\n});\n","Amasty_ImportCore/js/condition-select.js":"define([\n \"Magento_Ui/js/form/element/select\",\n \"mageUtils\"\n], function (Select, utils) {\n\n return Select.extend({\n defaults: {\n imports: {\n 'fieldValue' : '${ $.parentName}.field:value'\n },\n listens: {\n fieldValue: 'updateConditions'\n },\n modules: {\n recordComponent: '${ $.parentName }'\n }\n },\n initObservable: function () {\n this._super().observe(['fieldValue']);\n\n return this;\n },\n getInitialValue: function () {\n var values = [this.value(), this.default],\n value;\n\n values.some(function (v) {\n if (v !== null && v !== undefined) {\n value = v;\n\n return true;\n }\n\n return false;\n });\n\n return utils.isEmpty(value) ? '' : value;\n },\n updateConditions: function () {\n var fieldData = this.recordComponent().parentComponent().filterConfig[this.fieldValue()] || {};\n if (!_.isUndefined(fieldData.conditions)) {\n this.options(fieldData.conditions);\n } else {\n this.options([]);\n }\n }\n });\n})\n","Amasty_ImportCore/js/provider.js":"define([\n 'jquery',\n 'Magento_Ui/js/form/provider'\n], function ($, Provider) {\n 'use strict';\n\n return Provider.extend({\n defaults: {\n pageMessageSelector: '#messages'\n },\n\n save: function (options) {\n var data = this.get('data');\n\n $(this.pageMessageSelector).html('');\n this.client.save({ encodedData: JSON.stringify(data) }, options);\n\n return this;\n }\n });\n});\n","Amasty_ImportCore/js/form/components/fieldset.js":"define([\n 'Magento_Ui/js/form/components/fieldset'\n], function (FieldSet) {\n return FieldSet.extend({\n validate: function () {\n return {\n valid: true\n };\n }\n });\n});\n","Amasty_ImportCore/js/form/components/button.js":"define([\n 'Magento_Ui/js/form/components/button'\n], function (Button) {\n return Button.extend({\n validate: function () {\n return {\n valid: true\n };\n },\n _setButtonClasses: function () {\n this._super();\n this.buttonClasses['action-basic'] = false;\n }\n });\n});\n","Amasty_ImportCore/js/form/element/behavior-select.js":"define([\n 'Magento_Ui/js/form/element/select',\n '../../storage/typical-fields'\n], function (Select, typicalFields) {\n 'use strict';\n\n return Select.extend({\n defaults: {\n entityCode: '',\n fieldsUrl: '',\n autofill: '',\n fieldsProvider: '',\n listens: {\n autofill: 'checkAutofill'\n },\n modules: {\n dataProvider: '${ $.provider }',\n fields: '${ $.fieldsProvider }'\n }\n },\n\n initObservable: function () {\n this._super().observe(['autofill']);\n\n return this;\n },\n\n checkAutofill: function (value) {\n if (value) {\n this.updateTypicalFields();\n }\n },\n\n updateTypicalFields: function () {\n var behaviorCode = this.value(),\n params = {},\n options = {};\n\n if (behaviorCode !== undefined && this.autofill()) {\n params.entity_code = this.entityCode;\n params.behavior_code = behaviorCode;\n options.dataProvider = this.dataProvider();\n options.fieldsUrl = this.fieldsUrl;\n options.dataScope = this.fields().dataScope;\n\n typicalFields.update(params, options);\n }\n },\n\n onUpdate: function () {\n this._super();\n\n if (this.value()) {\n this.updateTypicalFields();\n }\n }\n });\n});\n","Amasty_ImportCore/js/form/element/input-date.js":"define([\n 'Magento_Ui/js/form/element/date',\n 'underscore'\n], function (Input, _) {\n return Input.extend({\n defaults: {\n template: 'Amasty_ImportCore/form/element/input-date',\n dateElementTmpl: 'ui/form/element/date',\n inputElementTmpl: 'ui/form/element/input',\n inputConditions: [],\n dateNotice: '',\n inputNotice: '',\n notice: '',\n imports: {\n 'parentCondition': '${ $.provider }:${ $.parentScope }.condition'\n },\n isDate: null,\n listens: {\n 'parentCondition': 'conditionChanged'\n }\n },\n _initialized: false,\n\n initObservable: function () {\n this._super().observe(['isDate', 'parentCondition', 'notice']);\n\n return this;\n },\n conditionChanged: function () {\n if (_.contains(this.inputConditions, this.parentCondition())) {\n this.notice(this.dateNotice);\n this.isDate(false);\n } else {\n this.notice(this.inputNotice);\n this.isDate(true);\n }\n\n if (!this._initialized) {\n this._initialized = true;\n if (this.isDate()) {\n this.onValueChange(this.value());\n }\n } else {\n this.value('');\n this.onValueChange('');\n }\n },\n\n onValueChange: function () {\n if (this.isDate()) {\n this._super();\n }\n }\n });\n});\n","Amasty_ImportCore/js/form/element/input-textarea.js":"define([\n 'Magento_Ui/js/form/element/abstract',\n 'underscore'\n], function (Input, _) {\n return Input.extend({\n defaults: {\n cols: 10,\n rows: 4,\n textareaElementTmpl: 'ui/form/element/textarea',\n inputElementTmpl: 'ui/form/element/input',\n textareaNotice: '',\n inputNotice: '',\n notice: '',\n imports: {\n 'parentCondition': '${ $.provider }:${ $.parentScope }.condition'\n },\n isTextarea: false,\n listens: {\n 'parentCondition': 'conditionChanged'\n }\n },\n initObservable: function () {\n this._super().observe(['isTextarea', 'parentCondition', 'notice']);\n\n return this;\n },\n conditionChanged: function () {\n if (_.contains(['in', 'nin'], this.parentCondition())) {\n this.notice(this.textareaNotice);\n this.isTextarea(true);\n } else {\n this.notice(this.inputNotice);\n this.isTextarea(false);\n }\n }\n });\n});\n","Amasty_ImportCore/js/form/element/codemirror.js":"define([\n 'Magento_Ui/js/form/element/textarea',\n 'jquery',\n 'Amasty_ImportCore/js/lib/codemirror',\n 'Amasty_ImportCore/js/lib/codemirror/xml'\n], function (Textarea, $, CodeMirror) {\n 'use strict';\n\n return Textarea.extend({\n defaults: {\n codeMirrorConfig: {\n lineNumbers: true\n }\n },\n editor:null,\n\n initialize: function () {\n var config;\n\n this._super();\n $.async('#' + this.uid, function (elem) {\n config = $.extend();\n this.editor = CodeMirror.fromTextArea(elem, this.codeMirrorConfig);\n this.editor.on('change', function () {\n this.value(this.editor.getValue());\n }.bind(this));\n }.bind(this));\n\n return this;\n },\n setCodeMirrorValue: function (value) {\n this.value(value);\n this.editor.setValue(value);\n }\n });\n});\n","Amasty_ImportCore/js/dynamic-rows/dynamic-rows.js":"define([\n 'Magento_Ui/js/dynamic-rows/dynamic-rows'\n], function (DynamicRows) {\n 'use strict';\n\n return DynamicRows.extend({\n defaults: {\n parentComponent: null,\n listens: {\n relatedData: 'checkRelatedData'\n },\n templates: {\n record: {\n parent: '${ $.$data.collection.name }',\n name: '${ $.$data.index }',\n dataScope: 'filters.${ $.name }',\n nodeTemplate: '${ $.parent }.${ $.$data.collection.recordTemplate }'\n },\n },\n links: {\n recordData: '${ $.provider }:${ $.dataScope }.filters'\n },\n },\n\n checkRelatedData: function () {\n if (this.parentComponent && this.relatedData.length) {\n this.parentComponent.opened(true);\n }\n },\n\n initContainer: function (parent) {\n this._super();\n\n this.parentComponent = parent;\n\n if (this.relatedData.length) {\n this.parentComponent.opened(true);\n }\n\n return this;\n }\n });\n});\n","Amasty_ImportCore/js/storage/typical-fields.js":"define([\n 'jquery',\n 'underscore',\n 'mageUtils'\n], function ($, _, utils) {\n 'use strict';\n\n return {\n cachedData: {},\n currentData: null,\n params: {},\n options: {},\n\n update: function (params, options) {\n this.addParams(params);\n\n if (options) {\n this.options = options;\n }\n\n if (!_.has(this.params, 'entity_code') || !Object.keys(this.options).length) {\n return;\n }\n\n var deferred = $.Deferred(),\n currentKey = this.getCurrentKey();\n\n this.set(deferred);\n\n if (this.cachedData[currentKey]) {\n return deferred.resolve(this.cachedData[currentKey]);\n }\n\n this.get(deferred, this.params.fieldsUrl);\n },\n\n addParams: function (params) {\n _.each(params, function (value, key) {\n this.params[key] = value;\n }, this);\n },\n\n get: function (deferred) {\n var formData = new FormData();\n\n formData.append('form_key', $('[name=\"form_key\"]').val());\n _.each(this.params, function (value, key) {\n formData.append(key, value);\n });\n\n $.ajax({\n showLoader: true,\n url: this.options.fieldsUrl,\n processData: false,\n contentType: false,\n data: formData,\n type: 'POST',\n dataType: 'json'\n }).done(function (response) {\n if (!response.error) {\n deferred.resolve(response);\n }\n });\n },\n\n getCurrentKey: function () {\n var currentKey = '';\n\n _.each(this.params, function (value) {\n currentKey += (value || '') + '_';\n });\n\n return currentKey;\n },\n\n set: function (deferred) {\n var currentKey = this.getCurrentKey(),\n dataProvider = this.options.dataProvider,\n dataScope = this.options.dataScope;\n\n $.when(deferred).done(function (response) {\n if (this.currentData) {\n this.prepareToRemoveEmptyFields(response, this.currentData);\n }\n\n this.cachedData[currentKey] = $.extend(true, {}, response);\n var repairedObject = {};\n\n this.currentData = this.cachedData[currentKey];\n this.repairObject(dataScope, repairedObject, response);\n dataProvider.isBehaviorChanged = true;\n this.setBehaviorData(dataProvider, dataProvider, repairedObject, dataProvider);\n }.bind(this));\n },\n\n /**\n * Set data to provider data.\n *\n * @param {Object} context\n * @param {Object} oldData\n * @param {Object} newData\n * @param {Provider} current\n * @param {String} parentPath\n */\n setBehaviorData: function (context, oldData, newData, current, parentPath) {\n _.each(newData, function (val, key) {\n if (oldData === undefined || _.isArray(val)) {\n context.set(utils.fullPath(parentPath, key), val);\n } else if (_.isObject(val)) {\n this.setBehaviorData(context, oldData[key], val, current[key], utils.fullPath(parentPath, key));\n } else if (val != oldData[key] && oldData[key] == current[key]) { // eslint-disable-line eqeqeq\n context.set(utils.fullPath(parentPath, key), val);\n }\n }, this);\n },\n\n repairObject: function (dataScope, repairedObject, data) {\n var scopeArray = dataScope.split('.'),\n key = scopeArray.shift();\n\n repairedObject[key] = {};\n\n if (scopeArray.length) {\n return this.repairObject(scopeArray.join('.'), repairedObject[key], data);\n }\n\n repairedObject[key] = data;\n },\n\n prepareToRemoveEmptyFields: function (newData, oldData) {\n var key;\n\n for (key in oldData) {\n if (_.isObject(newData[key]) && !_.isArray(newData[key])) {\n this.prepareToRemoveEmptyFields(newData[key], oldData[key]);\n } else if (!newData[key]) {\n newData[key] = {};\n this.createEmptyValue(newData[key]);\n }\n }\n },\n\n createEmptyValue: function (data) {\n data.enabled = 0;\n data.fields = [];\n }\n };\n});\n","Amasty_ImportCore/js/fields/modifier.js":"define([\n 'uiCollection',\n 'underscore',\n 'uiLayout',\n 'mageUtils'\n], function (Collection, _, layout, utils) {\n 'use strict';\n\n return Collection.extend({\n defaults: {\n template: 'Amasty_ImportCore/fields/modifier',\n links: {\n select_value: '${ $.provider }:${ $.dataScope }.select_value',\n eavEntityType: '${ $.provider }:${ $.dataScope }.eavEntityType',\n optionSource: '${ $.provider }:${ $.dataScope }.optionSource'\n },\n listens: {\n select_value: 'getModifierTypeSelected',\n selectedOption: 'createModifierField'\n },\n selectedType: null,\n selectedOption: {},\n options: [],\n selectedActions: [],\n modifierValue: {}\n },\n\n initialize: function () {\n this._super();\n\n this.renderFields();\n\n return this;\n },\n\n initObservable: function () {\n this._super().observe([\n 'eavEntityType',\n 'select_value',\n 'code',\n 'selectedType',\n 'selectedOption',\n 'optionSource'\n ]);\n\n return this;\n },\n\n renderFields: function () {\n var name = this.name + '.value',\n value = this.modifierValue || {},\n componentData = utils.extend(value, {\n 'parentName': this.name,\n 'provider': this.provider,\n 'dataScope': this.dataScope + '.value',\n 'prefer': 'toggle',\n 'parentScope': this.dataScope,\n 'source': this.source,\n 'options': this.options,\n 'name': name,\n 'component': this.childComponent,\n 'template': this.childTemplate\n });\n\n layout([componentData]);\n this.insertChild(name);\n },\n\n getModifierTypeSelected: function (value) {\n var option;\n\n this.options.forEach(function (optgroup) {\n option = this.findValue(optgroup, value);\n\n if (option) {\n this.selectedType(optgroup.type);\n this.selectedOption(option);\n }\n }.bind(this));\n },\n\n createModifierField: function (option) {\n _.each(this.elems(), function (element) {\n element.destroy();\n }, this);\n\n this.childTemplate = this.modifierConfig[option.value].childTemplate || null;\n this.childComponent = this.modifierConfig[option.value].childComponent || null;\n this.eavEntityType(this.selectedOption().eavEntityType);\n this.optionSource(this.selectedOption().optionSource);\n\n if (this.childComponent && this.childTemplate) {\n this.renderFields();\n }\n },\n\n findValue: function (optgroup, value) {\n return optgroup.value.find(function (item) {\n return item.value === value;\n });\n },\n\n remove: function () {\n this.source.remove(this.dataScope);\n this.destroy();\n },\n\n setDefaultValue: function () {\n this.select_value(this.selectValue);\n }\n });\n});\n","Amasty_ImportCore/js/fields/select-fields.js":"define([\n 'uiElement',\n 'underscore',\n 'ko'\n], function (Element, _, ko) {\n 'use strict';\n\n return Element.extend({\n defaults: {\n selected: [],\n fields: [],\n searchFields: [],\n allSelectedState: false,\n isSearchActive: false,\n checkedFields: [],\n newCheckedField: [],\n fieldsToRemove: [],\n copySelected: [],\n elemIndex: 0,\n uniqFor: '',\n listens: {\n selected: 'allSelectedStateCheck',\n checkedFields: 'updateSelected'\n },\n modules: {\n parentComponent: '${ $.parentName }'\n },\n searchValue: ''\n },\n\n initialize: function () {\n this._super();\n\n this.uniqFor = 'a' + Math.round(Math.random() * 100000);\n this.prepareData();\n\n return this;\n },\n\n initObservable: function () {\n this._super().observe([\n 'allSelectedState',\n 'checkedFields',\n 'searchFields',\n 'searchValue',\n 'isSearchActive',\n 'selected',\n 'newCheckedField',\n 'fieldsToRemove'\n ]);\n\n return this;\n },\n\n prepareData: function () {\n _.each(this.checkedFields(), function (field) {\n this.selected.push(field.code);\n });\n },\n\n isAllSelected: function () {\n if (this.searchFields().length) {\n return this.isAllSearchSelected(this.searchFields());\n }\n\n return _.size(this.selected()) === _.size(this.fields);\n },\n\n isAllSearchSelected: function (fields) {\n return fields.every(function (field) {\n return _.contains(this.selected(), field.code);\n }.bind(this));\n },\n\n updateSelected: function () {\n this.selected(_.pluck(this.checkedFields(), 'code'));\n },\n\n checkClick: function () {\n if (!this.isAllSelected()) {\n var fields = this.searchFields().length ? this.searchFields() : this.fields;\n\n fields.forEach(function (field) {\n this.selected.remove(field.code);\n this.selected.push(field.code);\n }.bind(this));\n\n this.copySelected = ko.toJS(this.selected).slice();\n this.allSelectedState(true);\n\n return true;\n }\n\n if (this.isSearchActive()) {\n this.searchFields().forEach(function (field) {\n this.selected.remove(field.code);\n }.bind(this));\n\n return true;\n }\n\n this.selected.removeAll();\n\n return true;\n },\n\n allSelectedStateCheck: function () {\n this.allSelectedState(this.isAllSelected());\n },\n\n getLabel: function (label, code) {\n return label ? label + ' (' + code + ')' : code;\n },\n\n addField: function (parent, field) {\n if (!this.isFieldSelected(field.code)) {\n this.selected.push(field.code);\n this.newCheckedField([field]);\n }\n\n this.parentComponent().closeModal();\n },\n\n isFieldSelected: function (code) {\n return _.some(this.checkedFields(), function (field) {\n return !!field && field.code === code;\n });\n },\n\n addSelectedFields: function () {\n var currentFieldsCodes = _.pluck(ko.toJS(this.checkedFields), 'code'),\n selectedFieldsCodes = this.selected(),\n toRemove = _.difference(currentFieldsCodes, selectedFieldsCodes),\n toAdd = _.difference(selectedFieldsCodes, currentFieldsCodes);\n\n if (!_.isEmpty(toRemove)) {\n this.fieldsToRemove(toRemove);\n }\n\n if (!_.isEmpty(toAdd)) {\n _.each(this.fields, function (field) {\n if (_.contains(toAdd, field.code)) {\n this.newCheckedField([field]);\n }\n }.bind(this));\n }\n },\n\n changeSearch: function () {\n if (this.searchValue().length === 0) {\n this.clearSearch();\n }\n\n if (this.searchValue().length < 3) {\n return true;\n }\n\n this.search();\n },\n\n clearSearch: function () {\n const copySelected = this.selected().slice();\n\n this.isSearchActive(false);\n this.searchValue('');\n this.searchFields([]);\n this.selected(copySelected);\n },\n\n searchClick: function () {\n this.search();\n },\n\n search: function () {\n const copySelected = this.selected().slice();\n\n this.isSearchActive(true);\n this.searchFields(this.searchFilter(this.searchValue().trim()));\n this.allSelectedStateCheck();\n this.selected(copySelected);\n },\n\n searchFilter: function (value) {\n return this.fields.filter(function (field) {\n return field.code.indexOf(value) !== -1;\n });\n }\n });\n});\n","Amasty_ImportCore/js/fields/field.js":"define([\n 'jquery',\n 'uiCollection',\n 'uiLayout',\n 'mageUtils',\n 'underscore'\n], function ($, Collection, layout, utils, _) {\n 'use strict';\n\n return Collection.extend({\n defaults: {\n template: 'Amasty_ImportCore/fields/field',\n links: {\n input_value: '${ $.provider }:${ $.dataScope }.input_value',\n file_field: '${ $.provider }:${ $.dataScope }.file_field',\n output_value: '${ $.provider }:${ $.dataScope }.output_value',\n file_field: '${ $.provider }:${ $.dataScope }.file_field',\n code: '${ $.provider }:${ $.dataScope }.code',\n sortOrder: '${ $.provider }:${ $.dataScope }.sortOrder',\n options: '${ $.provider }:${ $.dataScope }.options'\n },\n imports: {\n modifierConfig: '${ $.parentName }:modifierConfig'\n },\n modules: {\n parent: '${ $.parentName }',\n dataProvider: '${ $.provider }'\n },\n modifierIndex: 0,\n selected_actions: []\n },\n\n initialize: function () {\n this._super();\n\n this.renderDefaultModifies();\n\n return this;\n },\n\n initObservable: function () {\n this._super().observe([\n 'input_value',\n 'file_field',\n 'output_value',\n 'file_field',\n 'code',\n 'sortOrder'\n ]);\n\n return this;\n },\n\n remove: function () {\n if (this.parent().isSorted) {\n this.parent().reRenderAndRemove(this.code());\n } else {\n this.source.remove(this.dataScope);\n this.destroy();\n this.parent().checkFieldsState();\n }\n },\n\n renderDefaultModifies: function () {\n _.each(this.modifier, function (modifier) {\n if (modifier) {\n this.addModifier(this.name, modifier.select_value, modifier.value);\n }\n }, this);\n },\n\n addModifier: function (name, value, modifierValue) {\n var fieldData = this.modifierConfig[value] || {},\n item = utils.extend(fieldData, {\n 'name': name + '.modifier.' + this.modifierIndex,\n 'component': 'Amasty_ImportCore/js/fields/modifier',\n 'provider': this.provider,\n 'selectValue': value || '',\n 'options': this.options,\n 'modifierValue': modifierValue || {},\n 'modifierConfig': this.modifierConfig,\n 'dataScope': this.dataScope + '.modifier.' + this.modifierIndex\n });\n\n layout([item]);\n this.insertChild(item.name);\n this.modifierIndex += 1;\n }\n });\n});\n","Amasty_ImportCore/js/fields/checked-fields.js":"define([\n 'uiCollection',\n 'jquery',\n 'ko',\n 'underscore',\n 'uiLayout',\n 'mageUtils'\n], function (Collection, $, ko, _, layout, utils) {\n 'use strict';\n\n return Collection.extend({\n defaults: {\n checkedFields: [],\n selected: [],\n fieldsContainerSelect: '[data-amimportcore-js=\"fields\"]',\n fieldsSelect: '[data-amimportcore-js=\"field\"]',\n positions: [],\n selectFieldsPath: null,\n isShowFields: false,\n elemIndex: 0,\n isShowDeleteBtn: false,\n listens: {\n newCheckedField: 'addCheckedFields',\n fieldsToRemove: 'removeFields',\n elems: 'toggleBtnDelete'\n },\n exports: {\n checkedFields: '${ $.selectFieldsPath }:checkedFields',\n newCheckedField: '${ $.selectFieldsPath }:newCheckedField',\n isShowDeleteBtn: '${ $.deleteBtnPath }:visible'\n },\n imports: {\n fields: '${ $.selectFieldsPath }:fields',\n selected: '${ $.selectFieldsPath }:selected',\n newCheckedField: '${ $.selectFieldsPath }:newCheckedField',\n fieldsToRemove: '${ $.selectFieldsPath }:fieldsToRemove',\n checkedFields: '${ $.provider }:${ $.dataScope }'\n },\n modules: {\n selectFields: '${ $.selectFieldsPath }',\n deleteBtn: '${ $.deleteBtnPath }'\n }\n },\n\n initObservable: function () {\n this._super().observe([\n 'checkedFields',\n 'selected',\n 'newCheckedField',\n 'fieldsToRemove',\n 'isShowFields',\n 'isShowDeleteBtn'\n ]);\n\n return this;\n },\n\n toggleBtnDelete: function () {\n this.isShowDeleteBtn(!!this.elems().length);\n },\n\n removeFields: function () {\n if (this.fieldsToRemove().length) {\n this.elems.each(function (elem) {\n if (_.contains(this.fieldsToRemove(), elem.code())) {\n elem.remove();\n }\n }.bind(this));\n\n this.fieldsToRemove([]);\n }\n },\n\n removeAllItems: function () {\n this.elems.each(function (elem) {\n elem.source.remove(elem.dataScope);\n elem.destroy();\n });\n\n this.isShowFields(false);\n },\n\n renderDefaultFields: function () {\n if (this.isDefaultRendered) {\n return;\n }\n\n _.each(this.checkedFields(), function (item) {\n this.initFields(item);\n }.bind(this));\n\n this.isDefaultRendered = true;\n },\n\n getNameField: function () {\n return this.name + '.field-' + this.elemIndex;\n },\n\n initFields: function (item) {\n item = this.createField(item, this.elemIndex, this.dataScope, this.getNameField());\n layout([item]);\n this.insertChild(item.name);\n this.elemIndex += 1;\n },\n\n createField: function (data, index, dataScope, name) {\n return utils.extend(data, {\n 'name': name,\n 'component': 'Amasty_ImportCore/js/fields/field',\n 'provider': this.provider,\n 'dataScope': dataScope + '.' + index\n });\n },\n\n addCheckedFields: function () {\n if (this.newCheckedField().length) {\n this.newCheckedField().forEach(function (item) {\n this.initFields(item);\n }.bind(this));\n\n this.isShowFields(true);\n this.newCheckedField([]);\n }\n },\n\n getCheckedLength: function () {\n return Object.keys(this.checkedFields()).length;\n },\n\n checkFieldsState: function () {\n if (!this.getCheckedLength()) {\n this.isShowFields(false);\n }\n }\n });\n});\n","Amasty_ImportCore/js/fields/modifier-field.js":"define([\n 'uiCollection'\n], function (Collection) {\n 'use strict';\n\n return Collection.extend({\n defaults: {\n links: {\n input_value: '${ $.provider }:${ $.dataScope }.input_value',\n from_input_value: '${ $.provider }:${ $.dataScope }.from_input_value',\n to_input_value: '${ $.provider }:${ $.dataScope }.to_input_value'\n }\n },\n\n initObservable: function () {\n this._super().observe([\n 'input_value',\n 'from_input_value',\n 'to_input_value'\n ]);\n\n return this;\n }\n });\n});\n","Amasty_ImportCore/js/lib/codemirror.js":"// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: https://codemirror.net/LICENSE\n\n// This is CodeMirror (https://codemirror.net), a code editor\n// implemented in JavaScript on top of the browser's DOM.\n//\n// You can find some technical background for some of the code below\n// at http://marijnhaverbeke.nl/blog/#cm-internals .\n\n(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :\n typeof define === 'function' && define.amd ? define(factory) :\n (global = global || self, global.CodeMirror = factory());\n}(this, (function () { 'use strict';\n\n // Kludges for bugs and behavior differences that can't be feature\n // detected are enabled based on userAgent etc sniffing.\n var userAgent = navigator.userAgent;\n var platform = navigator.platform;\n\n var gecko = /gecko\\/\\d/i.test(userAgent);\n var ie_upto10 = /MSIE \\d/.test(userAgent);\n var ie_11up = /Trident\\/(?:[7-9]|\\d{2,})\\..*rv:(\\d+)/.exec(userAgent);\n var edge = /Edge\\/(\\d+)/.exec(userAgent);\n var ie = ie_upto10 || ie_11up || edge;\n var ie_version = ie && (ie_upto10 ? document.documentMode || 6 : +(edge || ie_11up)[1]);\n var webkit = !edge && /WebKit\\//.test(userAgent);\n var qtwebkit = webkit && /Qt\\/\\d+\\.\\d+/.test(userAgent);\n var chrome = !edge && /Chrome\\//.test(userAgent);\n var presto = /Opera\\//.test(userAgent);\n var safari = /Apple Computer/.test(navigator.vendor);\n var mac_geMountainLion = /Mac OS X 1\\d\\D([8-9]|\\d\\d)\\D/.test(userAgent);\n var phantom = /PhantomJS/.test(userAgent);\n\n var ios = !edge && /AppleWebKit/.test(userAgent) && /Mobile\\/\\w+/.test(userAgent);\n var android = /Android/.test(userAgent);\n // This is woefully incomplete. Suggestions for alternative methods welcome.\n var mobile = ios || android || /webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(userAgent);\n var mac = ios || /Mac/.test(platform);\n var chromeOS = /\\bCrOS\\b/.test(userAgent);\n var windows = /win/i.test(platform);\n\n var presto_version = presto && userAgent.match(/Version\\/(\\d*\\.\\d*)/);\n if (presto_version) { presto_version = Number(presto_version[1]); }\n if (presto_version && presto_version >= 15) { presto = false; webkit = true; }\n // Some browsers use the wrong event properties to signal cmd/ctrl on OS X\n var flipCtrlCmd = mac && (qtwebkit || presto && (presto_version == null || presto_version < 12.11));\n var captureRightClick = gecko || (ie && ie_version >= 9);\n\n function classTest(cls) { return new RegExp(\"(^|\\\\s)\" + cls + \"(?:$|\\\\s)\\\\s*\") }\n\n var rmClass = function(node, cls) {\n var current = node.className;\n var match = classTest(cls).exec(current);\n if (match) {\n var after = current.slice(match.index + match[0].length);\n node.className = current.slice(0, match.index) + (after ? match[1] + after : \"\");\n }\n };\n\n function removeChildren(e) {\n for (var count = e.childNodes.length; count > 0; --count)\n { e.removeChild(e.firstChild); }\n return e\n }\n\n function removeChildrenAndAdd(parent, e) {\n return removeChildren(parent).appendChild(e)\n }\n\n function elt(tag, content, className, style) {\n var e = document.createElement(tag);\n if (className) { e.className = className; }\n if (style) { e.style.cssText = style; }\n if (typeof content == \"string\") { e.appendChild(document.createTextNode(content)); }\n else if (content) { for (var i = 0; i < content.length; ++i) { e.appendChild(content[i]); } }\n return e\n }\n // wrapper for elt, which removes the elt from the accessibility tree\n function eltP(tag, content, className, style) {\n var e = elt(tag, content, className, style);\n e.setAttribute(\"role\", \"presentation\");\n return e\n }\n\n var range;\n if (document.createRange) { range = function(node, start, end, endNode) {\n var r = document.createRange();\n r.setEnd(endNode || node, end);\n r.setStart(node, start);\n return r\n }; }\n else { range = function(node, start, end) {\n var r = document.body.createTextRange();\n try { r.moveToElementText(node.parentNode); }\n catch(e) { return r }\n r.collapse(true);\n r.moveEnd(\"character\", end);\n r.moveStart(\"character\", start);\n return r\n }; }\n\n function contains(parent, child) {\n if (child.nodeType == 3) // Android browser always returns false when child is a textnode\n { child = child.parentNode; }\n if (parent.contains)\n { return parent.contains(child) }\n do {\n if (child.nodeType == 11) { child = child.host; }\n if (child == parent) { return true }\n } while (child = child.parentNode)\n }\n\n function activeElt() {\n // IE and Edge may throw an \"Unspecified Error\" when accessing document.activeElement.\n // IE < 10 will throw when accessed while the page is loading or in an iframe.\n // IE > 9 and Edge will throw when accessed in an iframe if document.body is unavailable.\n var activeElement;\n try {\n activeElement = document.activeElement;\n } catch(e) {\n activeElement = document.body || null;\n }\n while (activeElement && activeElement.shadowRoot && activeElement.shadowRoot.activeElement)\n { activeElement = activeElement.shadowRoot.activeElement; }\n return activeElement\n }\n\n function addClass(node, cls) {\n var current = node.className;\n if (!classTest(cls).test(current)) { node.className += (current ? \" \" : \"\") + cls; }\n }\n function joinClasses(a, b) {\n var as = a.split(\" \");\n for (var i = 0; i < as.length; i++)\n { if (as[i] && !classTest(as[i]).test(b)) { b += \" \" + as[i]; } }\n return b\n }\n\n var selectInput = function(node) { node.select(); };\n if (ios) // Mobile Safari apparently has a bug where select() is broken.\n { selectInput = function(node) { node.selectionStart = 0; node.selectionEnd = node.value.length; }; }\n else if (ie) // Suppress mysterious IE10 errors\n { selectInput = function(node) { try { node.select(); } catch(_e) {} }; }\n\n function bind(f) {\n var args = Array.prototype.slice.call(arguments, 1);\n return function(){return f.apply(null, args)}\n }\n\n function copyObj(obj, target, overwrite) {\n if (!target) { target = {}; }\n for (var prop in obj)\n { if (obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop)))\n { target[prop] = obj[prop]; } }\n return target\n }\n\n // Counts the column offset in a string, taking tabs into account.\n // Used mostly to find indentation.\n function countColumn(string, end, tabSize, startIndex, startValue) {\n if (end == null) {\n end = string.search(/[^\\s\\u00a0]/);\n if (end == -1) { end = string.length; }\n }\n for (var i = startIndex || 0, n = startValue || 0;;) {\n var nextTab = string.indexOf(\"\\t\", i);\n if (nextTab < 0 || nextTab >= end)\n { return n + (end - i) }\n n += nextTab - i;\n n += tabSize - (n % tabSize);\n i = nextTab + 1;\n }\n }\n\n var Delayed = function() {\n this.id = null;\n this.f = null;\n this.time = 0;\n this.handler = bind(this.onTimeout, this);\n };\n Delayed.prototype.onTimeout = function (self) {\n self.id = 0;\n if (self.time <= +new Date) {\n self.f();\n } else {\n setTimeout(self.handler, self.time - +new Date);\n }\n };\n Delayed.prototype.set = function (ms, f) {\n this.f = f;\n var time = +new Date + ms;\n if (!this.id || time < this.time) {\n clearTimeout(this.id);\n this.id = setTimeout(this.handler, ms);\n this.time = time;\n }\n };\n\n function indexOf(array, elt) {\n for (var i = 0; i < array.length; ++i)\n { if (array[i] == elt) { return i } }\n return -1\n }\n\n // Number of pixels added to scroller and sizer to hide scrollbar\n var scrollerGap = 50;\n\n // Returned or thrown by various protocols to signal 'I'm not\n // handling this'.\n var Pass = {toString: function(){return \"CodeMirror.Pass\"}};\n\n // Reused option objects for setSelection & friends\n var sel_dontScroll = {scroll: false}, sel_mouse = {origin: \"*mouse\"}, sel_move = {origin: \"+move\"};\n\n // The inverse of countColumn -- find the offset that corresponds to\n // a particular column.\n function findColumn(string, goal, tabSize) {\n for (var pos = 0, col = 0;;) {\n var nextTab = string.indexOf(\"\\t\", pos);\n if (nextTab == -1) { nextTab = string.length; }\n var skipped = nextTab - pos;\n if (nextTab == string.length || col + skipped >= goal)\n { return pos + Math.min(skipped, goal - col) }\n col += nextTab - pos;\n col += tabSize - (col % tabSize);\n pos = nextTab + 1;\n if (col >= goal) { return pos }\n }\n }\n\n var spaceStrs = [\"\"];\n function spaceStr(n) {\n while (spaceStrs.length <= n)\n { spaceStrs.push(lst(spaceStrs) + \" \"); }\n return spaceStrs[n]\n }\n\n function lst(arr) { return arr[arr.length-1] }\n\n function map(array, f) {\n var out = [];\n for (var i = 0; i < array.length; i++) { out[i] = f(array[i], i); }\n return out\n }\n\n function insertSorted(array, value, score) {\n var pos = 0, priority = score(value);\n while (pos < array.length && score(array[pos]) <= priority) { pos++; }\n array.splice(pos, 0, value);\n }\n\n function nothing() {}\n\n function createObj(base, props) {\n var inst;\n if (Object.create) {\n inst = Object.create(base);\n } else {\n nothing.prototype = base;\n inst = new nothing();\n }\n if (props) { copyObj(props, inst); }\n return inst\n }\n\n var nonASCIISingleCaseWordChar = /[\\u00df\\u0587\\u0590-\\u05f4\\u0600-\\u06ff\\u3040-\\u309f\\u30a0-\\u30ff\\u3400-\\u4db5\\u4e00-\\u9fcc\\uac00-\\ud7af]/;\n function isWordCharBasic(ch) {\n return /\\w/.test(ch) || ch > \"\\x80\" &&\n (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch))\n }\n function isWordChar(ch, helper) {\n if (!helper) { return isWordCharBasic(ch) }\n if (helper.source.indexOf(\"\\\\w\") > -1 && isWordCharBasic(ch)) { return true }\n return helper.test(ch)\n }\n\n function isEmpty(obj) {\n for (var n in obj) { if (obj.hasOwnProperty(n) && obj[n]) { return false } }\n return true\n }\n\n // Extending unicode characters. A series of a non-extending char +\n // any number of extending chars is treated as a single unit as far\n // as editing and measuring is concerned. This is not fully correct,\n // since some scripts/fonts/browsers also treat other configurations\n // of code points as a group.\n var extendingChars = /[\\u0300-\\u036f\\u0483-\\u0489\\u0591-\\u05bd\\u05bf\\u05c1\\u05c2\\u05c4\\u05c5\\u05c7\\u0610-\\u061a\\u064b-\\u065e\\u0670\\u06d6-\\u06dc\\u06de-\\u06e4\\u06e7\\u06e8\\u06ea-\\u06ed\\u0711\\u0730-\\u074a\\u07a6-\\u07b0\\u07eb-\\u07f3\\u0816-\\u0819\\u081b-\\u0823\\u0825-\\u0827\\u0829-\\u082d\\u0900-\\u0902\\u093c\\u0941-\\u0948\\u094d\\u0951-\\u0955\\u0962\\u0963\\u0981\\u09bc\\u09be\\u09c1-\\u09c4\\u09cd\\u09d7\\u09e2\\u09e3\\u0a01\\u0a02\\u0a3c\\u0a41\\u0a42\\u0a47\\u0a48\\u0a4b-\\u0a4d\\u0a51\\u0a70\\u0a71\\u0a75\\u0a81\\u0a82\\u0abc\\u0ac1-\\u0ac5\\u0ac7\\u0ac8\\u0acd\\u0ae2\\u0ae3\\u0b01\\u0b3c\\u0b3e\\u0b3f\\u0b41-\\u0b44\\u0b4d\\u0b56\\u0b57\\u0b62\\u0b63\\u0b82\\u0bbe\\u0bc0\\u0bcd\\u0bd7\\u0c3e-\\u0c40\\u0c46-\\u0c48\\u0c4a-\\u0c4d\\u0c55\\u0c56\\u0c62\\u0c63\\u0cbc\\u0cbf\\u0cc2\\u0cc6\\u0ccc\\u0ccd\\u0cd5\\u0cd6\\u0ce2\\u0ce3\\u0d3e\\u0d41-\\u0d44\\u0d4d\\u0d57\\u0d62\\u0d63\\u0dca\\u0dcf\\u0dd2-\\u0dd4\\u0dd6\\u0ddf\\u0e31\\u0e34-\\u0e3a\\u0e47-\\u0e4e\\u0eb1\\u0eb4-\\u0eb9\\u0ebb\\u0ebc\\u0ec8-\\u0ecd\\u0f18\\u0f19\\u0f35\\u0f37\\u0f39\\u0f71-\\u0f7e\\u0f80-\\u0f84\\u0f86\\u0f87\\u0f90-\\u0f97\\u0f99-\\u0fbc\\u0fc6\\u102d-\\u1030\\u1032-\\u1037\\u1039\\u103a\\u103d\\u103e\\u1058\\u1059\\u105e-\\u1060\\u1071-\\u1074\\u1082\\u1085\\u1086\\u108d\\u109d\\u135f\\u1712-\\u1714\\u1732-\\u1734\\u1752\\u1753\\u1772\\u1773\\u17b7-\\u17bd\\u17c6\\u17c9-\\u17d3\\u17dd\\u180b-\\u180d\\u18a9\\u1920-\\u1922\\u1927\\u1928\\u1932\\u1939-\\u193b\\u1a17\\u1a18\\u1a56\\u1a58-\\u1a5e\\u1a60\\u1a62\\u1a65-\\u1a6c\\u1a73-\\u1a7c\\u1a7f\\u1b00-\\u1b03\\u1b34\\u1b36-\\u1b3a\\u1b3c\\u1b42\\u1b6b-\\u1b73\\u1b80\\u1b81\\u1ba2-\\u1ba5\\u1ba8\\u1ba9\\u1c2c-\\u1c33\\u1c36\\u1c37\\u1cd0-\\u1cd2\\u1cd4-\\u1ce0\\u1ce2-\\u1ce8\\u1ced\\u1dc0-\\u1de6\\u1dfd-\\u1dff\\u200c\\u200d\\u20d0-\\u20f0\\u2cef-\\u2cf1\\u2de0-\\u2dff\\u302a-\\u302f\\u3099\\u309a\\ua66f-\\ua672\\ua67c\\ua67d\\ua6f0\\ua6f1\\ua802\\ua806\\ua80b\\ua825\\ua826\\ua8c4\\ua8e0-\\ua8f1\\ua926-\\ua92d\\ua947-\\ua951\\ua980-\\ua982\\ua9b3\\ua9b6-\\ua9b9\\ua9bc\\uaa29-\\uaa2e\\uaa31\\uaa32\\uaa35\\uaa36\\uaa43\\uaa4c\\uaab0\\uaab2-\\uaab4\\uaab7\\uaab8\\uaabe\\uaabf\\uaac1\\uabe5\\uabe8\\uabed\\udc00-\\udfff\\ufb1e\\ufe00-\\ufe0f\\ufe20-\\ufe26\\uff9e\\uff9f]/;\n function isExtendingChar(ch) { return ch.charCodeAt(0) >= 768 && extendingChars.test(ch) }\n\n // Returns a number from the range [`0`; `str.length`] unless `pos` is outside that range.\n function skipExtendingChars(str, pos, dir) {\n while ((dir < 0 ? pos > 0 : pos < str.length) && isExtendingChar(str.charAt(pos))) { pos += dir; }\n return pos\n }\n\n // Returns the value from the range [`from`; `to`] that satisfies\n // `pred` and is closest to `from`. Assumes that at least `to`\n // satisfies `pred`. Supports `from` being greater than `to`.\n function findFirst(pred, from, to) {\n // At any point we are certain `to` satisfies `pred`, don't know\n // whether `from` does.\n var dir = from > to ? -1 : 1;\n for (;;) {\n if (from == to) { return from }\n var midF = (from + to) / 2, mid = dir < 0 ? Math.ceil(midF) : Math.floor(midF);\n if (mid == from) { return pred(mid) ? from : to }\n if (pred(mid)) { to = mid; }\n else { from = mid + dir; }\n }\n }\n\n // BIDI HELPERS\n\n function iterateBidiSections(order, from, to, f) {\n if (!order) { return f(from, to, \"ltr\", 0) }\n var found = false;\n for (var i = 0; i < order.length; ++i) {\n var part = order[i];\n if (part.from < to && part.to > from || from == to && part.to == from) {\n f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? \"rtl\" : \"ltr\", i);\n found = true;\n }\n }\n if (!found) { f(from, to, \"ltr\"); }\n }\n\n var bidiOther = null;\n function getBidiPartAt(order, ch, sticky) {\n var found;\n bidiOther = null;\n for (var i = 0; i < order.length; ++i) {\n var cur = order[i];\n if (cur.from < ch && cur.to > ch) { return i }\n if (cur.to == ch) {\n if (cur.from != cur.to && sticky == \"before\") { found = i; }\n else { bidiOther = i; }\n }\n if (cur.from == ch) {\n if (cur.from != cur.to && sticky != \"before\") { found = i; }\n else { bidiOther = i; }\n }\n }\n return found != null ? found : bidiOther\n }\n\n // Bidirectional ordering algorithm\n // See http://unicode.org/reports/tr9/tr9-13.html for the algorithm\n // that this (partially) implements.\n\n // One-char codes used for character types:\n // L (L): Left-to-Right\n // R (R): Right-to-Left\n // r (AL): Right-to-Left Arabic\n // 1 (EN): European Number\n // + (ES): European Number Separator\n // % (ET): European Number Terminator\n // n (AN): Arabic Number\n // , (CS): Common Number Separator\n // m (NSM): Non-Spacing Mark\n // b (BN): Boundary Neutral\n // s (B): Paragraph Separator\n // t (S): Segment Separator\n // w (WS): Whitespace\n // N (ON): Other Neutrals\n\n // Returns null if characters are ordered as they appear\n // (left-to-right), or an array of sections ({from, to, level}\n // objects) in the order in which they occur visually.\n var bidiOrdering = (function() {\n // Character types for codepoints 0 to 0xff\n var lowTypes = \"bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN\";\n // Character types for codepoints 0x600 to 0x6f9\n var arabicTypes = \"nnnnnnNNr%%r,rNNmmmmmmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmmmnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmnNmmmmmmrrmmNmmmmrr1111111111\";\n function charType(code) {\n if (code <= 0xf7) { return lowTypes.charAt(code) }\n else if (0x590 <= code && code <= 0x5f4) { return \"R\" }\n else if (0x600 <= code && code <= 0x6f9) { return arabicTypes.charAt(code - 0x600) }\n else if (0x6ee <= code && code <= 0x8ac) { return \"r\" }\n else if (0x2000 <= code && code <= 0x200b) { return \"w\" }\n else if (code == 0x200c) { return \"b\" }\n else { return \"L\" }\n }\n\n var bidiRE = /[\\u0590-\\u05f4\\u0600-\\u06ff\\u0700-\\u08ac]/;\n var isNeutral = /[stwN]/, isStrong = /[LRr]/, countsAsLeft = /[Lb1n]/, countsAsNum = /[1n]/;\n\n function BidiSpan(level, from, to) {\n this.level = level;\n this.from = from; this.to = to;\n }\n\n return function(str, direction) {\n var outerType = direction == \"ltr\" ? \"L\" : \"R\";\n\n if (str.length == 0 || direction == \"ltr\" && !bidiRE.test(str)) { return false }\n var len = str.length, types = [];\n for (var i = 0; i < len; ++i)\n { types.push(charType(str.charCodeAt(i))); }\n\n // W1. Examine each non-spacing mark (NSM) in the level run, and\n // change the type of the NSM to the type of the previous\n // character. If the NSM is at the start of the level run, it will\n // get the type of sor.\n for (var i$1 = 0, prev = outerType; i$1 < len; ++i$1) {\n var type = types[i$1];\n if (type == \"m\") { types[i$1] = prev; }\n else { prev = type; }\n }\n\n // W2. Search backwards from each instance of a European number\n // until the first strong type (R, L, AL, or sor) is found. If an\n // AL is found, change the type of the European number to Arabic\n // number.\n // W3. Change all ALs to R.\n for (var i$2 = 0, cur = outerType; i$2 < len; ++i$2) {\n var type$1 = types[i$2];\n if (type$1 == \"1\" && cur == \"r\") { types[i$2] = \"n\"; }\n else if (isStrong.test(type$1)) { cur = type$1; if (type$1 == \"r\") { types[i$2] = \"R\"; } }\n }\n\n // W4. A single European separator between two European numbers\n // changes to a European number. A single common separator between\n // two numbers of the same type changes to that type.\n for (var i$3 = 1, prev$1 = types[0]; i$3 < len - 1; ++i$3) {\n var type$2 = types[i$3];\n if (type$2 == \"+\" && prev$1 == \"1\" && types[i$3+1] == \"1\") { types[i$3] = \"1\"; }\n else if (type$2 == \",\" && prev$1 == types[i$3+1] &&\n (prev$1 == \"1\" || prev$1 == \"n\")) { types[i$3] = prev$1; }\n prev$1 = type$2;\n }\n\n // W5. A sequence of European terminators adjacent to European\n // numbers changes to all European numbers.\n // W6. Otherwise, separators and terminators change to Other\n // Neutral.\n for (var i$4 = 0; i$4 < len; ++i$4) {\n var type$3 = types[i$4];\n if (type$3 == \",\") { types[i$4] = \"N\"; }\n else if (type$3 == \"%\") {\n var end = (void 0);\n for (end = i$4 + 1; end < len && types[end] == \"%\"; ++end) {}\n var replace = (i$4 && types[i$4-1] == \"!\") || (end < len && types[end] == \"1\") ? \"1\" : \"N\";\n for (var j = i$4; j < end; ++j) { types[j] = replace; }\n i$4 = end - 1;\n }\n }\n\n // W7. Search backwards from each instance of a European number\n // until the first strong type (R, L, or sor) is found. If an L is\n // found, then change the type of the European number to L.\n for (var i$5 = 0, cur$1 = outerType; i$5 < len; ++i$5) {\n var type$4 = types[i$5];\n if (cur$1 == \"L\" && type$4 == \"1\") { types[i$5] = \"L\"; }\n else if (isStrong.test(type$4)) { cur$1 = type$4; }\n }\n\n // N1. A sequence of neutrals takes the direction of the\n // surrounding strong text if the text on both sides has the same\n // direction. European and Arabic numbers act as if they were R in\n // terms of their influence on neutrals. Start-of-level-run (sor)\n // and end-of-level-run (eor) are used at level run boundaries.\n // N2. Any remaining neutrals take the embedding direction.\n for (var i$6 = 0; i$6 < len; ++i$6) {\n if (isNeutral.test(types[i$6])) {\n var end$1 = (void 0);\n for (end$1 = i$6 + 1; end$1 < len && isNeutral.test(types[end$1]); ++end$1) {}\n var before = (i$6 ? types[i$6-1] : outerType) == \"L\";\n var after = (end$1 < len ? types[end$1] : outerType) == \"L\";\n var replace$1 = before == after ? (before ? \"L\" : \"R\") : outerType;\n for (var j$1 = i$6; j$1 < end$1; ++j$1) { types[j$1] = replace$1; }\n i$6 = end$1 - 1;\n }\n }\n\n // Here we depart from the documented algorithm, in order to avoid\n // building up an actual levels array. Since there are only three\n // levels (0, 1, 2) in an implementation that doesn't take\n // explicit embedding into account, we can build up the order on\n // the fly, without following the level-based algorithm.\n var order = [], m;\n for (var i$7 = 0; i$7 < len;) {\n if (countsAsLeft.test(types[i$7])) {\n var start = i$7;\n for (++i$7; i$7 < len && countsAsLeft.test(types[i$7]); ++i$7) {}\n order.push(new BidiSpan(0, start, i$7));\n } else {\n var pos = i$7, at = order.length, isRTL = direction == \"rtl\" ? 1 : 0;\n for (++i$7; i$7 < len && types[i$7] != \"L\"; ++i$7) {}\n for (var j$2 = pos; j$2 < i$7;) {\n if (countsAsNum.test(types[j$2])) {\n if (pos < j$2) { order.splice(at, 0, new BidiSpan(1, pos, j$2)); at += isRTL; }\n var nstart = j$2;\n for (++j$2; j$2 < i$7 && countsAsNum.test(types[j$2]); ++j$2) {}\n order.splice(at, 0, new BidiSpan(2, nstart, j$2));\n at += isRTL;\n pos = j$2;\n } else { ++j$2; }\n }\n if (pos < i$7) { order.splice(at, 0, new BidiSpan(1, pos, i$7)); }\n }\n }\n if (direction == \"ltr\") {\n if (order[0].level == 1 && (m = str.match(/^\\s+/))) {\n order[0].from = m[0].length;\n order.unshift(new BidiSpan(0, 0, m[0].length));\n }\n if (lst(order).level == 1 && (m = str.match(/\\s+$/))) {\n lst(order).to -= m[0].length;\n order.push(new BidiSpan(0, len - m[0].length, len));\n }\n }\n\n return direction == \"rtl\" ? order.reverse() : order\n }\n })();\n\n // Get the bidi ordering for the given line (and cache it). Returns\n // false for lines that are fully left-to-right, and an array of\n // BidiSpan objects otherwise.\n function getOrder(line, direction) {\n var order = line.order;\n if (order == null) { order = line.order = bidiOrdering(line.text, direction); }\n return order\n }\n\n // EVENT HANDLING\n\n // Lightweight event framework. on/off also work on DOM nodes,\n // registering native DOM handlers.\n\n var noHandlers = [];\n\n var on = function(emitter, type, f) {\n if (emitter.addEventListener) {\n emitter.addEventListener(type, f, false);\n } else if (emitter.attachEvent) {\n emitter.attachEvent(\"on\" + type, f);\n } else {\n var map = emitter._handlers || (emitter._handlers = {});\n map[type] = (map[type] || noHandlers).concat(f);\n }\n };\n\n function getHandlers(emitter, type) {\n return emitter._handlers && emitter._handlers[type] || noHandlers\n }\n\n function off(emitter, type, f) {\n if (emitter.removeEventListener) {\n emitter.removeEventListener(type, f, false);\n } else if (emitter.detachEvent) {\n emitter.detachEvent(\"on\" + type, f);\n } else {\n var map = emitter._handlers, arr = map && map[type];\n if (arr) {\n var index = indexOf(arr, f);\n if (index > -1)\n { map[type] = arr.slice(0, index).concat(arr.slice(index + 1)); }\n }\n }\n }\n\n function signal(emitter, type /*, values...*/) {\n var handlers = getHandlers(emitter, type);\n if (!handlers.length) { return }\n var args = Array.prototype.slice.call(arguments, 2);\n for (var i = 0; i < handlers.length; ++i) { handlers[i].apply(null, args); }\n }\n\n // The DOM events that CodeMirror handles can be overridden by\n // registering a (non-DOM) handler on the editor for the event name,\n // and preventDefault-ing the event in that handler.\n function signalDOMEvent(cm, e, override) {\n if (typeof e == \"string\")\n { e = {type: e, preventDefault: function() { this.defaultPrevented = true; }}; }\n signal(cm, override || e.type, cm, e);\n return e_defaultPrevented(e) || e.codemirrorIgnore\n }\n\n function signalCursorActivity(cm) {\n var arr = cm._handlers && cm._handlers.cursorActivity;\n if (!arr) { return }\n var set = cm.curOp.cursorActivityHandlers || (cm.curOp.cursorActivityHandlers = []);\n for (var i = 0; i < arr.length; ++i) { if (indexOf(set, arr[i]) == -1)\n { set.push(arr[i]); } }\n }\n\n function hasHandler(emitter, type) {\n return getHandlers(emitter, type).length > 0\n }\n\n // Add on and off methods to a constructor's prototype, to make\n // registering events on such objects more convenient.\n function eventMixin(ctor) {\n ctor.prototype.on = function(type, f) {on(this, type, f);};\n ctor.prototype.off = function(type, f) {off(this, type, f);};\n }\n\n // Due to the fact that we still support jurassic IE versions, some\n // compatibility wrappers are needed.\n\n function e_preventDefault(e) {\n if (e.preventDefault) { e.preventDefault(); }\n else { e.returnValue = false; }\n }\n function e_stopPropagation(e) {\n if (e.stopPropagation) { e.stopPropagation(); }\n else { e.cancelBubble = true; }\n }\n function e_defaultPrevented(e) {\n return e.defaultPrevented != null ? e.defaultPrevented : e.returnValue == false\n }\n function e_stop(e) {e_preventDefault(e); e_stopPropagation(e);}\n\n function e_target(e) {return e.target || e.srcElement}\n function e_button(e) {\n var b = e.which;\n if (b == null) {\n if (e.button & 1) { b = 1; }\n else if (e.button & 2) { b = 3; }\n else if (e.button & 4) { b = 2; }\n }\n if (mac && e.ctrlKey && b == 1) { b = 3; }\n return b\n }\n\n // Detect drag-and-drop\n var dragAndDrop = function() {\n // There is *some* kind of drag-and-drop support in IE6-8, but I\n // couldn't get it to work yet.\n if (ie && ie_version < 9) { return false }\n var div = elt('div');\n return \"draggable\" in div || \"dragDrop\" in div\n }();\n\n var zwspSupported;\n function zeroWidthElement(measure) {\n if (zwspSupported == null) {\n var test = elt(\"span\", \"\\u200b\");\n removeChildrenAndAdd(measure, elt(\"span\", [test, document.createTextNode(\"x\")]));\n if (measure.firstChild.offsetHeight != 0)\n { zwspSupported = test.offsetWidth <= 1 && test.offsetHeight > 2 && !(ie && ie_version < 8); }\n }\n var node = zwspSupported ? elt(\"span\", \"\\u200b\") :\n elt(\"span\", \"\\u00a0\", null, \"display: inline-block; width: 1px; margin-right: -1px\");\n node.setAttribute(\"cm-text\", \"\");\n return node\n }\n\n // Feature-detect IE's crummy client rect reporting for bidi text\n var badBidiRects;\n function hasBadBidiRects(measure) {\n if (badBidiRects != null) { return badBidiRects }\n var txt = removeChildrenAndAdd(measure, document.createTextNode(\"A\\u062eA\"));\n var r0 = range(txt, 0, 1).getBoundingClientRect();\n var r1 = range(txt, 1, 2).getBoundingClientRect();\n removeChildren(measure);\n if (!r0 || r0.left == r0.right) { return false } // Safari returns null in some cases (#2780)\n return badBidiRects = (r1.right - r0.right < 3)\n }\n\n // See if \"\".split is the broken IE version, if so, provide an\n // alternative way to split lines.\n var splitLinesAuto = \"\\n\\nb\".split(/\\n/).length != 3 ? function (string) {\n var pos = 0, result = [], l = string.length;\n while (pos <= l) {\n var nl = string.indexOf(\"\\n\", pos);\n if (nl == -1) { nl = string.length; }\n var line = string.slice(pos, string.charAt(nl - 1) == \"\\r\" ? nl - 1 : nl);\n var rt = line.indexOf(\"\\r\");\n if (rt != -1) {\n result.push(line.slice(0, rt));\n pos += rt + 1;\n } else {\n result.push(line);\n pos = nl + 1;\n }\n }\n return result\n } : function (string) { return string.split(/\\r\\n?|\\n/); };\n\n var hasSelection = window.getSelection ? function (te) {\n try { return te.selectionStart != te.selectionEnd }\n catch(e) { return false }\n } : function (te) {\n var range;\n try {range = te.ownerDocument.selection.createRange();}\n catch(e) {}\n if (!range || range.parentElement() != te) { return false }\n return range.compareEndPoints(\"StartToEnd\", range) != 0\n };\n\n var hasCopyEvent = (function () {\n var e = elt(\"div\");\n if (\"oncopy\" in e) { return true }\n e.setAttribute(\"oncopy\", \"return;\");\n return typeof e.oncopy == \"function\"\n })();\n\n var badZoomedRects = null;\n function hasBadZoomedRects(measure) {\n if (badZoomedRects != null) { return badZoomedRects }\n var node = removeChildrenAndAdd(measure, elt(\"span\", \"x\"));\n var normal = node.getBoundingClientRect();\n var fromRange = range(node, 0, 1).getBoundingClientRect();\n return badZoomedRects = Math.abs(normal.left - fromRange.left) > 1\n }\n\n // Known modes, by name and by MIME\n var modes = {}, mimeModes = {};\n\n // Extra arguments are stored as the mode's dependencies, which is\n // used by (legacy) mechanisms like loadmode.js to automatically\n // load a mode. (Preferred mechanism is the require/define calls.)\n function defineMode(name, mode) {\n if (arguments.length > 2)\n { mode.dependencies = Array.prototype.slice.call(arguments, 2); }\n modes[name] = mode;\n }\n\n function defineMIME(mime, spec) {\n mimeModes[mime] = spec;\n }\n\n // Given a MIME type, a {name, ...options} config object, or a name\n // string, return a mode config object.\n function resolveMode(spec) {\n if (typeof spec == \"string\" && mimeModes.hasOwnProperty(spec)) {\n spec = mimeModes[spec];\n } else if (spec && typeof spec.name == \"string\" && mimeModes.hasOwnProperty(spec.name)) {\n var found = mimeModes[spec.name];\n if (typeof found == \"string\") { found = {name: found}; }\n spec = createObj(found, spec);\n spec.name = found.name;\n } else if (typeof spec == \"string\" && /^[\\w\\-]+\\/[\\w\\-]+\\+xml$/.test(spec)) {\n return resolveMode(\"application/xml\")\n } else if (typeof spec == \"string\" && /^[\\w\\-]+\\/[\\w\\-]+\\+json$/.test(spec)) {\n return resolveMode(\"application/json\")\n }\n if (typeof spec == \"string\") { return {name: spec} }\n else { return spec || {name: \"null\"} }\n }\n\n // Given a mode spec (anything that resolveMode accepts), find and\n // initialize an actual mode object.\n function getMode(options, spec) {\n spec = resolveMode(spec);\n var mfactory = modes[spec.name];\n if (!mfactory) { return getMode(options, \"text/plain\") }\n var modeObj = mfactory(options, spec);\n if (modeExtensions.hasOwnProperty(spec.name)) {\n var exts = modeExtensions[spec.name];\n for (var prop in exts) {\n if (!exts.hasOwnProperty(prop)) { continue }\n if (modeObj.hasOwnProperty(prop)) { modeObj[\"_\" + prop] = modeObj[prop]; }\n modeObj[prop] = exts[prop];\n }\n }\n modeObj.name = spec.name;\n if (spec.helperType) { modeObj.helperType = spec.helperType; }\n if (spec.modeProps) { for (var prop$1 in spec.modeProps)\n { modeObj[prop$1] = spec.modeProps[prop$1]; } }\n\n return modeObj\n }\n\n // This can be used to attach properties to mode objects from\n // outside the actual mode definition.\n var modeExtensions = {};\n function extendMode(mode, properties) {\n var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {});\n copyObj(properties, exts);\n }\n\n function copyState(mode, state) {\n if (state === true) { return state }\n if (mode.copyState) { return mode.copyState(state) }\n var nstate = {};\n for (var n in state) {\n var val = state[n];\n if (val instanceof Array) { val = val.concat([]); }\n nstate[n] = val;\n }\n return nstate\n }\n\n // Given a mode and a state (for that mode), find the inner mode and\n // state at the position that the state refers to.\n function innerMode(mode, state) {\n var info;\n while (mode.innerMode) {\n info = mode.innerMode(state);\n if (!info || info.mode == mode) { break }\n state = info.state;\n mode = info.mode;\n }\n return info || {mode: mode, state: state}\n }\n\n function startState(mode, a1, a2) {\n return mode.startState ? mode.startState(a1, a2) : true\n }\n\n // STRING STREAM\n\n // Fed to the mode parsers, provides helper functions to make\n // parsers more succinct.\n\n var StringStream = function(string, tabSize, lineOracle) {\n this.pos = this.start = 0;\n this.string = string;\n this.tabSize = tabSize || 8;\n this.lastColumnPos = this.lastColumnValue = 0;\n this.lineStart = 0;\n this.lineOracle = lineOracle;\n };\n\n StringStream.prototype.eol = function () {return this.pos >= this.string.length};\n StringStream.prototype.sol = function () {return this.pos == this.lineStart};\n StringStream.prototype.peek = function () {return this.string.charAt(this.pos) || undefined};\n StringStream.prototype.next = function () {\n if (this.pos < this.string.length)\n { return this.string.charAt(this.pos++) }\n };\n StringStream.prototype.eat = function (match) {\n var ch = this.string.charAt(this.pos);\n var ok;\n if (typeof match == \"string\") { ok = ch == match; }\n else { ok = ch && (match.test ? match.test(ch) : match(ch)); }\n if (ok) {++this.pos; return ch}\n };\n StringStream.prototype.eatWhile = function (match) {\n var start = this.pos;\n while (this.eat(match)){}\n return this.pos > start\n };\n StringStream.prototype.eatSpace = function () {\n var start = this.pos;\n while (/[\\s\\u00a0]/.test(this.string.charAt(this.pos))) { ++this.pos; }\n return this.pos > start\n };\n StringStream.prototype.skipToEnd = function () {this.pos = this.string.length;};\n StringStream.prototype.skipTo = function (ch) {\n var found = this.string.indexOf(ch, this.pos);\n if (found > -1) {this.pos = found; return true}\n };\n StringStream.prototype.backUp = function (n) {this.pos -= n;};\n StringStream.prototype.column = function () {\n if (this.lastColumnPos < this.start) {\n this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue);\n this.lastColumnPos = this.start;\n }\n return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0)\n };\n StringStream.prototype.indentation = function () {\n return countColumn(this.string, null, this.tabSize) -\n (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0)\n };\n StringStream.prototype.match = function (pattern, consume, caseInsensitive) {\n if (typeof pattern == \"string\") {\n var cased = function (str) { return caseInsensitive ? str.toLowerCase() : str; };\n var substr = this.string.substr(this.pos, pattern.length);\n if (cased(substr) == cased(pattern)) {\n if (consume !== false) { this.pos += pattern.length; }\n return true\n }\n } else {\n var match = this.string.slice(this.pos).match(pattern);\n if (match && match.index > 0) { return null }\n if (match && consume !== false) { this.pos += match[0].length; }\n return match\n }\n };\n StringStream.prototype.current = function (){return this.string.slice(this.start, this.pos)};\n StringStream.prototype.hideFirstChars = function (n, inner) {\n this.lineStart += n;\n try { return inner() }\n finally { this.lineStart -= n; }\n };\n StringStream.prototype.lookAhead = function (n) {\n var oracle = this.lineOracle;\n return oracle && oracle.lookAhead(n)\n };\n StringStream.prototype.baseToken = function () {\n var oracle = this.lineOracle;\n return oracle && oracle.baseToken(this.pos)\n };\n\n // Find the line object corresponding to the given line number.\n function getLine(doc, n) {\n n -= doc.first;\n if (n < 0 || n >= doc.size) { throw new Error(\"There is no line \" + (n + doc.first) + \" in the document.\") }\n var chunk = doc;\n while (!chunk.lines) {\n for (var i = 0;; ++i) {\n var child = chunk.children[i], sz = child.chunkSize();\n if (n < sz) { chunk = child; break }\n n -= sz;\n }\n }\n return chunk.lines[n]\n }\n\n // Get the part of a document between two positions, as an array of\n // strings.\n function getBetween(doc, start, end) {\n var out = [], n = start.line;\n doc.iter(start.line, end.line + 1, function (line) {\n var text = line.text;\n if (n == end.line) { text = text.slice(0, end.ch); }\n if (n == start.line) { text = text.slice(start.ch); }\n out.push(text);\n ++n;\n });\n return out\n }\n // Get the lines between from and to, as array of strings.\n function getLines(doc, from, to) {\n var out = [];\n doc.iter(from, to, function (line) { out.push(line.text); }); // iter aborts when callback returns truthy value\n return out\n }\n\n // Update the height of a line, propagating the height change\n // upwards to parent nodes.\n function updateLineHeight(line, height) {\n var diff = height - line.height;\n if (diff) { for (var n = line; n; n = n.parent) { n.height += diff; } }\n }\n\n // Given a line object, find its line number by walking up through\n // its parent links.\n function lineNo(line) {\n if (line.parent == null) { return null }\n var cur = line.parent, no = indexOf(cur.lines, line);\n for (var chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) {\n for (var i = 0;; ++i) {\n if (chunk.children[i] == cur) { break }\n no += chunk.children[i].chunkSize();\n }\n }\n return no + cur.first\n }\n\n // Find the line at the given vertical position, using the height\n // information in the document tree.\n function lineAtHeight(chunk, h) {\n var n = chunk.first;\n outer: do {\n for (var i$1 = 0; i$1 < chunk.children.length; ++i$1) {\n var child = chunk.children[i$1], ch = child.height;\n if (h < ch) { chunk = child; continue outer }\n h -= ch;\n n += child.chunkSize();\n }\n return n\n } while (!chunk.lines)\n var i = 0;\n for (; i < chunk.lines.length; ++i) {\n var line = chunk.lines[i], lh = line.height;\n if (h < lh) { break }\n h -= lh;\n }\n return n + i\n }\n\n function isLine(doc, l) {return l >= doc.first && l < doc.first + doc.size}\n\n function lineNumberFor(options, i) {\n return String(options.lineNumberFormatter(i + options.firstLineNumber))\n }\n\n // A Pos instance represents a position within the text.\n function Pos(line, ch, sticky) {\n if ( sticky === void 0 ) sticky = null;\n\n if (!(this instanceof Pos)) { return new Pos(line, ch, sticky) }\n this.line = line;\n this.ch = ch;\n this.sticky = sticky;\n }\n\n // Compare two positions, return 0 if they are the same, a negative\n // number when a is less, and a positive number otherwise.\n function cmp(a, b) { return a.line - b.line || a.ch - b.ch }\n\n function equalCursorPos(a, b) { return a.sticky == b.sticky && cmp(a, b) == 0 }\n\n function copyPos(x) {return Pos(x.line, x.ch)}\n function maxPos(a, b) { return cmp(a, b) < 0 ? b : a }\n function minPos(a, b) { return cmp(a, b) < 0 ? a : b }\n\n // Most of the external API clips given positions to make sure they\n // actually exist within the document.\n function clipLine(doc, n) {return Math.max(doc.first, Math.min(n, doc.first + doc.size - 1))}\n function clipPos(doc, pos) {\n if (pos.line < doc.first) { return Pos(doc.first, 0) }\n var last = doc.first + doc.size - 1;\n if (pos.line > last) { return Pos(last, getLine(doc, last).text.length) }\n return clipToLen(pos, getLine(doc, pos.line).text.length)\n }\n function clipToLen(pos, linelen) {\n var ch = pos.ch;\n if (ch == null || ch > linelen) { return Pos(pos.line, linelen) }\n else if (ch < 0) { return Pos(pos.line, 0) }\n else { return pos }\n }\n function clipPosArray(doc, array) {\n var out = [];\n for (var i = 0; i < array.length; i++) { out[i] = clipPos(doc, array[i]); }\n return out\n }\n\n var SavedContext = function(state, lookAhead) {\n this.state = state;\n this.lookAhead = lookAhead;\n };\n\n var Context = function(doc, state, line, lookAhead) {\n this.state = state;\n this.doc = doc;\n this.line = line;\n this.maxLookAhead = lookAhead || 0;\n this.baseTokens = null;\n this.baseTokenPos = 1;\n };\n\n Context.prototype.lookAhead = function (n) {\n var line = this.doc.getLine(this.line + n);\n if (line != null && n > this.maxLookAhead) { this.maxLookAhead = n; }\n return line\n };\n\n Context.prototype.baseToken = function (n) {\n if (!this.baseTokens) { return null }\n while (this.baseTokens[this.baseTokenPos] <= n)\n { this.baseTokenPos += 2; }\n var type = this.baseTokens[this.baseTokenPos + 1];\n return {type: type && type.replace(/( |^)overlay .*/, \"\"),\n size: this.baseTokens[this.baseTokenPos] - n}\n };\n\n Context.prototype.nextLine = function () {\n this.line++;\n if (this.maxLookAhead > 0) { this.maxLookAhead--; }\n };\n\n Context.fromSaved = function (doc, saved, line) {\n if (saved instanceof SavedContext)\n { return new Context(doc, copyState(doc.mode, saved.state), line, saved.lookAhead) }\n else\n { return new Context(doc, copyState(doc.mode, saved), line) }\n };\n\n Context.prototype.save = function (copy) {\n var state = copy !== false ? copyState(this.doc.mode, this.state) : this.state;\n return this.maxLookAhead > 0 ? new SavedContext(state, this.maxLookAhead) : state\n };\n\n\n // Compute a style array (an array starting with a mode generation\n // -- for invalidation -- followed by pairs of end positions and\n // style strings), which is used to highlight the tokens on the\n // line.\n function highlightLine(cm, line, context, forceToEnd) {\n // A styles array always starts with a number identifying the\n // mode/overlays that it is based on (for easy invalidation).\n var st = [cm.state.modeGen], lineClasses = {};\n // Compute the base array of styles\n runMode(cm, line.text, cm.doc.mode, context, function (end, style) { return st.push(end, style); },\n lineClasses, forceToEnd);\n var state = context.state;\n\n // Run overlays, adjust style array.\n var loop = function ( o ) {\n context.baseTokens = st;\n var overlay = cm.state.overlays[o], i = 1, at = 0;\n context.state = true;\n runMode(cm, line.text, overlay.mode, context, function (end, style) {\n var start = i;\n // Ensure there's a token end at the current position, and that i points at it\n while (at < end) {\n var i_end = st[i];\n if (i_end > end)\n { st.splice(i, 1, end, st[i+1], i_end); }\n i += 2;\n at = Math.min(end, i_end);\n }\n if (!style) { return }\n if (overlay.opaque) {\n st.splice(start, i - start, end, \"overlay \" + style);\n i = start + 2;\n } else {\n for (; start < i; start += 2) {\n var cur = st[start+1];\n st[start+1] = (cur ? cur + \" \" : \"\") + \"overlay \" + style;\n }\n }\n }, lineClasses);\n context.state = state;\n context.baseTokens = null;\n context.baseTokenPos = 1;\n };\n\n for (var o = 0; o < cm.state.overlays.length; ++o) loop( o );\n\n return {styles: st, classes: lineClasses.bgClass || lineClasses.textClass ? lineClasses : null}\n }\n\n function getLineStyles(cm, line, updateFrontier) {\n if (!line.styles || line.styles[0] != cm.state.modeGen) {\n var context = getContextBefore(cm, lineNo(line));\n var resetState = line.text.length > cm.options.maxHighlightLength && copyState(cm.doc.mode, context.state);\n var result = highlightLine(cm, line, context);\n if (resetState) { context.state = resetState; }\n line.stateAfter = context.save(!resetState);\n line.styles = result.styles;\n if (result.classes) { line.styleClasses = result.classes; }\n else if (line.styleClasses) { line.styleClasses = null; }\n if (updateFrontier === cm.doc.highlightFrontier)\n { cm.doc.modeFrontier = Math.max(cm.doc.modeFrontier, ++cm.doc.highlightFrontier); }\n }\n return line.styles\n }\n\n function getContextBefore(cm, n, precise) {\n var doc = cm.doc, display = cm.display;\n if (!doc.mode.startState) { return new Context(doc, true, n) }\n var start = findStartLine(cm, n, precise);\n var saved = start > doc.first && getLine(doc, start - 1).stateAfter;\n var context = saved ? Context.fromSaved(doc, saved, start) : new Context(doc, startState(doc.mode), start);\n\n doc.iter(start, n, function (line) {\n processLine(cm, line.text, context);\n var pos = context.line;\n line.stateAfter = pos == n - 1 || pos % 5 == 0 || pos >= display.viewFrom && pos < display.viewTo ? context.save() : null;\n context.nextLine();\n });\n if (precise) { doc.modeFrontier = context.line; }\n return context\n }\n\n // Lightweight form of highlight -- proceed over this line and\n // update state, but don't save a style array. Used for lines that\n // aren't currently visible.\n function processLine(cm, text, context, startAt) {\n var mode = cm.doc.mode;\n var stream = new StringStream(text, cm.options.tabSize, context);\n stream.start = stream.pos = startAt || 0;\n if (text == \"\") { callBlankLine(mode, context.state); }\n while (!stream.eol()) {\n readToken(mode, stream, context.state);\n stream.start = stream.pos;\n }\n }\n\n function callBlankLine(mode, state) {\n if (mode.blankLine) { return mode.blankLine(state) }\n if (!mode.innerMode) { return }\n var inner = innerMode(mode, state);\n if (inner.mode.blankLine) { return inner.mode.blankLine(inner.state) }\n }\n\n function readToken(mode, stream, state, inner) {\n for (var i = 0; i < 10; i++) {\n if (inner) { inner[0] = innerMode(mode, state).mode; }\n var style = mode.token(stream, state);\n if (stream.pos > stream.start) { return style }\n }\n throw new Error(\"Mode \" + mode.name + \" failed to advance stream.\")\n }\n\n var Token = function(stream, type, state) {\n this.start = stream.start; this.end = stream.pos;\n this.string = stream.current();\n this.type = type || null;\n this.state = state;\n };\n\n // Utility for getTokenAt and getLineTokens\n function takeToken(cm, pos, precise, asArray) {\n var doc = cm.doc, mode = doc.mode, style;\n pos = clipPos(doc, pos);\n var line = getLine(doc, pos.line), context = getContextBefore(cm, pos.line, precise);\n var stream = new StringStream(line.text, cm.options.tabSize, context), tokens;\n if (asArray) { tokens = []; }\n while ((asArray || stream.pos < pos.ch) && !stream.eol()) {\n stream.start = stream.pos;\n style = readToken(mode, stream, context.state);\n if (asArray) { tokens.push(new Token(stream, style, copyState(doc.mode, context.state))); }\n }\n return asArray ? tokens : new Token(stream, style, context.state)\n }\n\n function extractLineClasses(type, output) {\n if (type) { for (;;) {\n var lineClass = type.match(/(?:^|\\s+)line-(background-)?(\\S+)/);\n if (!lineClass) { break }\n type = type.slice(0, lineClass.index) + type.slice(lineClass.index + lineClass[0].length);\n var prop = lineClass[1] ? \"bgClass\" : \"textClass\";\n if (output[prop] == null)\n { output[prop] = lineClass[2]; }\n else if (!(new RegExp(\"(?:^|\\\\s)\" + lineClass[2] + \"(?:$|\\\\s)\")).test(output[prop]))\n { output[prop] += \" \" + lineClass[2]; }\n } }\n return type\n }\n\n // Run the given mode's parser over a line, calling f for each token.\n function runMode(cm, text, mode, context, f, lineClasses, forceToEnd) {\n var flattenSpans = mode.flattenSpans;\n if (flattenSpans == null) { flattenSpans = cm.options.flattenSpans; }\n var curStart = 0, curStyle = null;\n var stream = new StringStream(text, cm.options.tabSize, context), style;\n var inner = cm.options.addModeClass && [null];\n if (text == \"\") { extractLineClasses(callBlankLine(mode, context.state), lineClasses); }\n while (!stream.eol()) {\n if (stream.pos > cm.options.maxHighlightLength) {\n flattenSpans = false;\n if (forceToEnd) { processLine(cm, text, context, stream.pos); }\n stream.pos = text.length;\n style = null;\n } else {\n style = extractLineClasses(readToken(mode, stream, context.state, inner), lineClasses);\n }\n if (inner) {\n var mName = inner[0].name;\n if (mName) { style = \"m-\" + (style ? mName + \" \" + style : mName); }\n }\n if (!flattenSpans || curStyle != style) {\n while (curStart < stream.start) {\n curStart = Math.min(stream.start, curStart + 5000);\n f(curStart, curStyle);\n }\n curStyle = style;\n }\n stream.start = stream.pos;\n }\n while (curStart < stream.pos) {\n // Webkit seems to refuse to render text nodes longer than 57444\n // characters, and returns inaccurate measurements in nodes\n // starting around 5000 chars.\n var pos = Math.min(stream.pos, curStart + 5000);\n f(pos, curStyle);\n curStart = pos;\n }\n }\n\n // Finds the line to start with when starting a parse. Tries to\n // find a line with a stateAfter, so that it can start with a\n // valid state. If that fails, it returns the line with the\n // smallest indentation, which tends to need the least context to\n // parse correctly.\n function findStartLine(cm, n, precise) {\n var minindent, minline, doc = cm.doc;\n var lim = precise ? -1 : n - (cm.doc.mode.innerMode ? 1000 : 100);\n for (var search = n; search > lim; --search) {\n if (search <= doc.first) { return doc.first }\n var line = getLine(doc, search - 1), after = line.stateAfter;\n if (after && (!precise || search + (after instanceof SavedContext ? after.lookAhead : 0) <= doc.modeFrontier))\n { return search }\n var indented = countColumn(line.text, null, cm.options.tabSize);\n if (minline == null || minindent > indented) {\n minline = search - 1;\n minindent = indented;\n }\n }\n return minline\n }\n\n function retreatFrontier(doc, n) {\n doc.modeFrontier = Math.min(doc.modeFrontier, n);\n if (doc.highlightFrontier < n - 10) { return }\n var start = doc.first;\n for (var line = n - 1; line > start; line--) {\n var saved = getLine(doc, line).stateAfter;\n // change is on 3\n // state on line 1 looked ahead 2 -- so saw 3\n // test 1 + 2 < 3 should cover this\n if (saved && (!(saved instanceof SavedContext) || line + saved.lookAhead < n)) {\n start = line + 1;\n break\n }\n }\n doc.highlightFrontier = Math.min(doc.highlightFrontier, start);\n }\n\n // Optimize some code when these features are not used.\n var sawReadOnlySpans = false, sawCollapsedSpans = false;\n\n function seeReadOnlySpans() {\n sawReadOnlySpans = true;\n }\n\n function seeCollapsedSpans() {\n sawCollapsedSpans = true;\n }\n\n // TEXTMARKER SPANS\n\n function MarkedSpan(marker, from, to) {\n this.marker = marker;\n this.from = from; this.to = to;\n }\n\n // Search an array of spans for a span matching the given marker.\n function getMarkedSpanFor(spans, marker) {\n if (spans) { for (var i = 0; i < spans.length; ++i) {\n var span = spans[i];\n if (span.marker == marker) { return span }\n } }\n }\n // Remove a span from an array, returning undefined if no spans are\n // left (we don't store arrays for lines without spans).\n function removeMarkedSpan(spans, span) {\n var r;\n for (var i = 0; i < spans.length; ++i)\n { if (spans[i] != span) { (r || (r = [])).push(spans[i]); } }\n return r\n }\n // Add a span to a line.\n function addMarkedSpan(line, span) {\n line.markedSpans = line.markedSpans ? line.markedSpans.concat([span]) : [span];\n span.marker.attachLine(line);\n }\n\n // Used for the algorithm that adjusts markers for a change in the\n // document. These functions cut an array of spans at a given\n // character position, returning an array of remaining chunks (or\n // undefined if nothing remains).\n function markedSpansBefore(old, startCh, isInsert) {\n var nw;\n if (old) { for (var i = 0; i < old.length; ++i) {\n var span = old[i], marker = span.marker;\n var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= startCh : span.from < startCh);\n if (startsBefore || span.from == startCh && marker.type == \"bookmark\" && (!isInsert || !span.marker.insertLeft)) {\n var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= startCh : span.to > startCh)\n ;(nw || (nw = [])).push(new MarkedSpan(marker, span.from, endsAfter ? null : span.to));\n }\n } }\n return nw\n }\n function markedSpansAfter(old, endCh, isInsert) {\n var nw;\n if (old) { for (var i = 0; i < old.length; ++i) {\n var span = old[i], marker = span.marker;\n var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh);\n if (endsAfter || span.from == endCh && marker.type == \"bookmark\" && (!isInsert || span.marker.insertLeft)) {\n var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh)\n ;(nw || (nw = [])).push(new MarkedSpan(marker, startsBefore ? null : span.from - endCh,\n span.to == null ? null : span.to - endCh));\n }\n } }\n return nw\n }\n\n // Given a change object, compute the new set of marker spans that\n // cover the line in which the change took place. Removes spans\n // entirely within the change, reconnects spans belonging to the\n // same marker that appear on both sides of the change, and cuts off\n // spans partially within the change. Returns an array of span\n // arrays with one element for each line in (after) the change.\n function stretchSpansOverChange(doc, change) {\n if (change.full) { return null }\n var oldFirst = isLine(doc, change.from.line) && getLine(doc, change.from.line).markedSpans;\n var oldLast = isLine(doc, change.to.line) && getLine(doc, change.to.line).markedSpans;\n if (!oldFirst && !oldLast) { return null }\n\n var startCh = change.from.ch, endCh = change.to.ch, isInsert = cmp(change.from, change.to) == 0;\n // Get the spans that 'stick out' on both sides\n var first = markedSpansBefore(oldFirst, startCh, isInsert);\n var last = markedSpansAfter(oldLast, endCh, isInsert);\n\n // Next, merge those two ends\n var sameLine = change.text.length == 1, offset = lst(change.text).length + (sameLine ? startCh : 0);\n if (first) {\n // Fix up .to properties of first\n for (var i = 0; i < first.length; ++i) {\n var span = first[i];\n if (span.to == null) {\n var found = getMarkedSpanFor(last, span.marker);\n if (!found) { span.to = startCh; }\n else if (sameLine) { span.to = found.to == null ? null : found.to + offset; }\n }\n }\n }\n if (last) {\n // Fix up .from in last (or move them into first in case of sameLine)\n for (var i$1 = 0; i$1 < last.length; ++i$1) {\n var span$1 = last[i$1];\n if (span$1.to != null) { span$1.to += offset; }\n if (span$1.from == null) {\n var found$1 = getMarkedSpanFor(first, span$1.marker);\n if (!found$1) {\n span$1.from = offset;\n if (sameLine) { (first || (first = [])).push(span$1); }\n }\n } else {\n span$1.from += offset;\n if (sameLine) { (first || (first = [])).push(span$1); }\n }\n }\n }\n // Make sure we didn't create any zero-length spans\n if (first) { first = clearEmptySpans(first); }\n if (last && last != first) { last = clearEmptySpans(last); }\n\n var newMarkers = [first];\n if (!sameLine) {\n // Fill gap with whole-line-spans\n var gap = change.text.length - 2, gapMarkers;\n if (gap > 0 && first)\n { for (var i$2 = 0; i$2 < first.length; ++i$2)\n { if (first[i$2].to == null)\n { (gapMarkers || (gapMarkers = [])).push(new MarkedSpan(first[i$2].marker, null, null)); } } }\n for (var i$3 = 0; i$3 < gap; ++i$3)\n { newMarkers.push(gapMarkers); }\n newMarkers.push(last);\n }\n return newMarkers\n }\n\n // Remove spans that are empty and don't have a clearWhenEmpty\n // option of false.\n function clearEmptySpans(spans) {\n for (var i = 0; i < spans.length; ++i) {\n var span = spans[i];\n if (span.from != null && span.from == span.to && span.marker.clearWhenEmpty !== false)\n { spans.splice(i--, 1); }\n }\n if (!spans.length) { return null }\n return spans\n }\n\n // Used to 'clip' out readOnly ranges when making a change.\n function removeReadOnlyRanges(doc, from, to) {\n var markers = null;\n doc.iter(from.line, to.line + 1, function (line) {\n if (line.markedSpans) { for (var i = 0; i < line.markedSpans.length; ++i) {\n var mark = line.markedSpans[i].marker;\n if (mark.readOnly && (!markers || indexOf(markers, mark) == -1))\n { (markers || (markers = [])).push(mark); }\n } }\n });\n if (!markers) { return null }\n var parts = [{from: from, to: to}];\n for (var i = 0; i < markers.length; ++i) {\n var mk = markers[i], m = mk.find(0);\n for (var j = 0; j < parts.length; ++j) {\n var p = parts[j];\n if (cmp(p.to, m.from) < 0 || cmp(p.from, m.to) > 0) { continue }\n var newParts = [j, 1], dfrom = cmp(p.from, m.from), dto = cmp(p.to, m.to);\n if (dfrom < 0 || !mk.inclusiveLeft && !dfrom)\n { newParts.push({from: p.from, to: m.from}); }\n if (dto > 0 || !mk.inclusiveRight && !dto)\n { newParts.push({from: m.to, to: p.to}); }\n parts.splice.apply(parts, newParts);\n j += newParts.length - 3;\n }\n }\n return parts\n }\n\n // Connect or disconnect spans from a line.\n function detachMarkedSpans(line) {\n var spans = line.markedSpans;\n if (!spans) { return }\n for (var i = 0; i < spans.length; ++i)\n { spans[i].marker.detachLine(line); }\n line.markedSpans = null;\n }\n function attachMarkedSpans(line, spans) {\n if (!spans) { return }\n for (var i = 0; i < spans.length; ++i)\n { spans[i].marker.attachLine(line); }\n line.markedSpans = spans;\n }\n\n // Helpers used when computing which overlapping collapsed span\n // counts as the larger one.\n function extraLeft(marker) { return marker.inclusiveLeft ? -1 : 0 }\n function extraRight(marker) { return marker.inclusiveRight ? 1 : 0 }\n\n // Returns a number indicating which of two overlapping collapsed\n // spans is larger (and thus includes the other). Falls back to\n // comparing ids when the spans cover exactly the same range.\n function compareCollapsedMarkers(a, b) {\n var lenDiff = a.lines.length - b.lines.length;\n if (lenDiff != 0) { return lenDiff }\n var aPos = a.find(), bPos = b.find();\n var fromCmp = cmp(aPos.from, bPos.from) || extraLeft(a) - extraLeft(b);\n if (fromCmp) { return -fromCmp }\n var toCmp = cmp(aPos.to, bPos.to) || extraRight(a) - extraRight(b);\n if (toCmp) { return toCmp }\n return b.id - a.id\n }\n\n // Find out whether a line ends or starts in a collapsed span. If\n // so, return the marker for that span.\n function collapsedSpanAtSide(line, start) {\n var sps = sawCollapsedSpans && line.markedSpans, found;\n if (sps) { for (var sp = (void 0), i = 0; i < sps.length; ++i) {\n sp = sps[i];\n if (sp.marker.collapsed && (start ? sp.from : sp.to) == null &&\n (!found || compareCollapsedMarkers(found, sp.marker) < 0))\n { found = sp.marker; }\n } }\n return found\n }\n function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, true) }\n function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, false) }\n\n function collapsedSpanAround(line, ch) {\n var sps = sawCollapsedSpans && line.markedSpans, found;\n if (sps) { for (var i = 0; i < sps.length; ++i) {\n var sp = sps[i];\n if (sp.marker.collapsed && (sp.from == null || sp.from < ch) && (sp.to == null || sp.to > ch) &&\n (!found || compareCollapsedMarkers(found, sp.marker) < 0)) { found = sp.marker; }\n } }\n return found\n }\n\n // Test whether there exists a collapsed span that partially\n // overlaps (covers the start or end, but not both) of a new span.\n // Such overlap is not allowed.\n function conflictingCollapsedRange(doc, lineNo, from, to, marker) {\n var line = getLine(doc, lineNo);\n var sps = sawCollapsedSpans && line.markedSpans;\n if (sps) { for (var i = 0; i < sps.length; ++i) {\n var sp = sps[i];\n if (!sp.marker.collapsed) { continue }\n var found = sp.marker.find(0);\n var fromCmp = cmp(found.from, from) || extraLeft(sp.marker) - extraLeft(marker);\n var toCmp = cmp(found.to, to) || extraRight(sp.marker) - extraRight(marker);\n if (fromCmp >= 0 && toCmp <= 0 || fromCmp <= 0 && toCmp >= 0) { continue }\n if (fromCmp <= 0 && (sp.marker.inclusiveRight && marker.inclusiveLeft ? cmp(found.to, from) >= 0 : cmp(found.to, from) > 0) ||\n fromCmp >= 0 && (sp.marker.inclusiveRight && marker.inclusiveLeft ? cmp(found.from, to) <= 0 : cmp(found.from, to) < 0))\n { return true }\n } }\n }\n\n // A visual line is a line as drawn on the screen. Folding, for\n // example, can cause multiple logical lines to appear on the same\n // visual line. This finds the start of the visual line that the\n // given line is part of (usually that is the line itself).\n function visualLine(line) {\n var merged;\n while (merged = collapsedSpanAtStart(line))\n { line = merged.find(-1, true).line; }\n return line\n }\n\n function visualLineEnd(line) {\n var merged;\n while (merged = collapsedSpanAtEnd(line))\n { line = merged.find(1, true).line; }\n return line\n }\n\n // Returns an array of logical lines that continue the visual line\n // started by the argument, or undefined if there are no such lines.\n function visualLineContinued(line) {\n var merged, lines;\n while (merged = collapsedSpanAtEnd(line)) {\n line = merged.find(1, true).line\n ;(lines || (lines = [])).push(line);\n }\n return lines\n }\n\n // Get the line number of the start of the visual line that the\n // given line number is part of.\n function visualLineNo(doc, lineN) {\n var line = getLine(doc, lineN), vis = visualLine(line);\n if (line == vis) { return lineN }\n return lineNo(vis)\n }\n\n // Get the line number of the start of the next visual line after\n // the given line.\n function visualLineEndNo(doc, lineN) {\n if (lineN > doc.lastLine()) { return lineN }\n var line = getLine(doc, lineN), merged;\n if (!lineIsHidden(doc, line)) { return lineN }\n while (merged = collapsedSpanAtEnd(line))\n { line = merged.find(1, true).line; }\n return lineNo(line) + 1\n }\n\n // Compute whether a line is hidden. Lines count as hidden when they\n // are part of a visual line that starts with another line, or when\n // they are entirely covered by collapsed, non-widget span.\n function lineIsHidden(doc, line) {\n var sps = sawCollapsedSpans && line.markedSpans;\n if (sps) { for (var sp = (void 0), i = 0; i < sps.length; ++i) {\n sp = sps[i];\n if (!sp.marker.collapsed) { continue }\n if (sp.from == null) { return true }\n if (sp.marker.widgetNode) { continue }\n if (sp.from == 0 && sp.marker.inclusiveLeft && lineIsHiddenInner(doc, line, sp))\n { return true }\n } }\n }\n function lineIsHiddenInner(doc, line, span) {\n if (span.to == null) {\n var end = span.marker.find(1, true);\n return lineIsHiddenInner(doc, end.line, getMarkedSpanFor(end.line.markedSpans, span.marker))\n }\n if (span.marker.inclusiveRight && span.to == line.text.length)\n { return true }\n for (var sp = (void 0), i = 0; i < line.markedSpans.length; ++i) {\n sp = line.markedSpans[i];\n if (sp.marker.collapsed && !sp.marker.widgetNode && sp.from == span.to &&\n (sp.to == null || sp.to != span.from) &&\n (sp.marker.inclusiveLeft || span.marker.inclusiveRight) &&\n lineIsHiddenInner(doc, line, sp)) { return true }\n }\n }\n\n // Find the height above the given line.\n function heightAtLine(lineObj) {\n lineObj = visualLine(lineObj);\n\n var h = 0, chunk = lineObj.parent;\n for (var i = 0; i < chunk.lines.length; ++i) {\n var line = chunk.lines[i];\n if (line == lineObj) { break }\n else { h += line.height; }\n }\n for (var p = chunk.parent; p; chunk = p, p = chunk.parent) {\n for (var i$1 = 0; i$1 < p.children.length; ++i$1) {\n var cur = p.children[i$1];\n if (cur == chunk) { break }\n else { h += cur.height; }\n }\n }\n return h\n }\n\n // Compute the character length of a line, taking into account\n // collapsed ranges (see markText) that might hide parts, and join\n // other lines onto it.\n function lineLength(line) {\n if (line.height == 0) { return 0 }\n var len = line.text.length, merged, cur = line;\n while (merged = collapsedSpanAtStart(cur)) {\n var found = merged.find(0, true);\n cur = found.from.line;\n len += found.from.ch - found.to.ch;\n }\n cur = line;\n while (merged = collapsedSpanAtEnd(cur)) {\n var found$1 = merged.find(0, true);\n len -= cur.text.length - found$1.from.ch;\n cur = found$1.to.line;\n len += cur.text.length - found$1.to.ch;\n }\n return len\n }\n\n // Find the longest line in the document.\n function findMaxLine(cm) {\n var d = cm.display, doc = cm.doc;\n d.maxLine = getLine(doc, doc.first);\n d.maxLineLength = lineLength(d.maxLine);\n d.maxLineChanged = true;\n doc.iter(function (line) {\n var len = lineLength(line);\n if (len > d.maxLineLength) {\n d.maxLineLength = len;\n d.maxLine = line;\n }\n });\n }\n\n // LINE DATA STRUCTURE\n\n // Line objects. These hold state related to a line, including\n // highlighting info (the styles array).\n var Line = function(text, markedSpans, estimateHeight) {\n this.text = text;\n attachMarkedSpans(this, markedSpans);\n this.height = estimateHeight ? estimateHeight(this) : 1;\n };\n\n Line.prototype.lineNo = function () { return lineNo(this) };\n eventMixin(Line);\n\n // Change the content (text, markers) of a line. Automatically\n // invalidates cached information and tries to re-estimate the\n // line's height.\n function updateLine(line, text, markedSpans, estimateHeight) {\n line.text = text;\n if (line.stateAfter) { line.stateAfter = null; }\n if (line.styles) { line.styles = null; }\n if (line.order != null) { line.order = null; }\n detachMarkedSpans(line);\n attachMarkedSpans(line, markedSpans);\n var estHeight = estimateHeight ? estimateHeight(line) : 1;\n if (estHeight != line.height) { updateLineHeight(line, estHeight); }\n }\n\n // Detach a line from the document tree and its markers.\n function cleanUpLine(line) {\n line.parent = null;\n detachMarkedSpans(line);\n }\n\n // Convert a style as returned by a mode (either null, or a string\n // containing one or more styles) to a CSS style. This is cached,\n // and also looks for line-wide styles.\n var styleToClassCache = {}, styleToClassCacheWithMode = {};\n function interpretTokenStyle(style, options) {\n if (!style || /^\\s*$/.test(style)) { return null }\n var cache = options.addModeClass ? styleToClassCacheWithMode : styleToClassCache;\n return cache[style] ||\n (cache[style] = style.replace(/\\S+/g, \"cm-$&\"))\n }\n\n // Render the DOM representation of the text of a line. Also builds\n // up a 'line map', which points at the DOM nodes that represent\n // specific stretches of text, and is used by the measuring code.\n // The returned object contains the DOM node, this map, and\n // information about line-wide styles that were set by the mode.\n function buildLineContent(cm, lineView) {\n // The padding-right forces the element to have a 'border', which\n // is needed on Webkit to be able to get line-level bounding\n // rectangles for it (in measureChar).\n var content = eltP(\"span\", null, null, webkit ? \"padding-right: .1px\" : null);\n var builder = {pre: eltP(\"pre\", [content], \"CodeMirror-line\"), content: content,\n col: 0, pos: 0, cm: cm,\n trailingSpace: false,\n splitSpaces: cm.getOption(\"lineWrapping\")};\n lineView.measure = {};\n\n // Iterate over the logical lines that make up this visual line.\n for (var i = 0; i <= (lineView.rest ? lineView.rest.length : 0); i++) {\n var line = i ? lineView.rest[i - 1] : lineView.line, order = (void 0);\n builder.pos = 0;\n builder.addToken = buildToken;\n // Optionally wire in some hacks into the token-rendering\n // algorithm, to deal with browser quirks.\n if (hasBadBidiRects(cm.display.measure) && (order = getOrder(line, cm.doc.direction)))\n { builder.addToken = buildTokenBadBidi(builder.addToken, order); }\n builder.map = [];\n var allowFrontierUpdate = lineView != cm.display.externalMeasured && lineNo(line);\n insertLineContent(line, builder, getLineStyles(cm, line, allowFrontierUpdate));\n if (line.styleClasses) {\n if (line.styleClasses.bgClass)\n { builder.bgClass = joinClasses(line.styleClasses.bgClass, builder.bgClass || \"\"); }\n if (line.styleClasses.textClass)\n { builder.textClass = joinClasses(line.styleClasses.textClass, builder.textClass || \"\"); }\n }\n\n // Ensure at least a single node is present, for measuring.\n if (builder.map.length == 0)\n { builder.map.push(0, 0, builder.content.appendChild(zeroWidthElement(cm.display.measure))); }\n\n // Store the map and a cache object for the current logical line\n if (i == 0) {\n lineView.measure.map = builder.map;\n lineView.measure.cache = {};\n } else {\n (lineView.measure.maps || (lineView.measure.maps = [])).push(builder.map)\n ;(lineView.measure.caches || (lineView.measure.caches = [])).push({});\n }\n }\n\n // See issue #2901\n if (webkit) {\n var last = builder.content.lastChild;\n if (/\\bcm-tab\\b/.test(last.className) || (last.querySelector && last.querySelector(\".cm-tab\")))\n { builder.content.className = \"cm-tab-wrap-hack\"; }\n }\n\n signal(cm, \"renderLine\", cm, lineView.line, builder.pre);\n if (builder.pre.className)\n { builder.textClass = joinClasses(builder.pre.className, builder.textClass || \"\"); }\n\n return builder\n }\n\n function defaultSpecialCharPlaceholder(ch) {\n var token = elt(\"span\", \"\\u2022\", \"cm-invalidchar\");\n token.title = \"\\\\u\" + ch.charCodeAt(0).toString(16);\n token.setAttribute(\"aria-label\", token.title);\n return token\n }\n\n // Build up the DOM representation for a single token, and add it to\n // the line map. Takes care to render special characters separately.\n function buildToken(builder, text, style, startStyle, endStyle, css, attributes) {\n if (!text) { return }\n var displayText = builder.splitSpaces ? splitSpaces(text, builder.trailingSpace) : text;\n var special = builder.cm.state.specialChars, mustWrap = false;\n var content;\n if (!special.test(text)) {\n builder.col += text.length;\n content = document.createTextNode(displayText);\n builder.map.push(builder.pos, builder.pos + text.length, content);\n if (ie && ie_version < 9) { mustWrap = true; }\n builder.pos += text.length;\n } else {\n content = document.createDocumentFragment();\n var pos = 0;\n while (true) {\n special.lastIndex = pos;\n var m = special.exec(text);\n var skipped = m ? m.index - pos : text.length - pos;\n if (skipped) {\n var txt = document.createTextNode(displayText.slice(pos, pos + skipped));\n if (ie && ie_version < 9) { content.appendChild(elt(\"span\", [txt])); }\n else { content.appendChild(txt); }\n builder.map.push(builder.pos, builder.pos + skipped, txt);\n builder.col += skipped;\n builder.pos += skipped;\n }\n if (!m) { break }\n pos += skipped + 1;\n var txt$1 = (void 0);\n if (m[0] == \"\\t\") {\n var tabSize = builder.cm.options.tabSize, tabWidth = tabSize - builder.col % tabSize;\n txt$1 = content.appendChild(elt(\"span\", spaceStr(tabWidth), \"cm-tab\"));\n txt$1.setAttribute(\"role\", \"presentation\");\n txt$1.setAttribute(\"cm-text\", \"\\t\");\n builder.col += tabWidth;\n } else if (m[0] == \"\\r\" || m[0] == \"\\n\") {\n txt$1 = content.appendChild(elt(\"span\", m[0] == \"\\r\" ? \"\\u240d\" : \"\\u2424\", \"cm-invalidchar\"));\n txt$1.setAttribute(\"cm-text\", m[0]);\n builder.col += 1;\n } else {\n txt$1 = builder.cm.options.specialCharPlaceholder(m[0]);\n txt$1.setAttribute(\"cm-text\", m[0]);\n if (ie && ie_version < 9) { content.appendChild(elt(\"span\", [txt$1])); }\n else { content.appendChild(txt$1); }\n builder.col += 1;\n }\n builder.map.push(builder.pos, builder.pos + 1, txt$1);\n builder.pos++;\n }\n }\n builder.trailingSpace = displayText.charCodeAt(text.length - 1) == 32;\n if (style || startStyle || endStyle || mustWrap || css || attributes) {\n var fullStyle = style || \"\";\n if (startStyle) { fullStyle += startStyle; }\n if (endStyle) { fullStyle += endStyle; }\n var token = elt(\"span\", [content], fullStyle, css);\n if (attributes) {\n for (var attr in attributes) { if (attributes.hasOwnProperty(attr) && attr != \"style\" && attr != \"class\")\n { token.setAttribute(attr, attributes[attr]); } }\n }\n return builder.content.appendChild(token)\n }\n builder.content.appendChild(content);\n }\n\n // Change some spaces to NBSP to prevent the browser from collapsing\n // trailing spaces at the end of a line when rendering text (issue #1362).\n function splitSpaces(text, trailingBefore) {\n if (text.length > 1 && !/ /.test(text)) { return text }\n var spaceBefore = trailingBefore, result = \"\";\n for (var i = 0; i < text.length; i++) {\n var ch = text.charAt(i);\n if (ch == \" \" && spaceBefore && (i == text.length - 1 || text.charCodeAt(i + 1) == 32))\n { ch = \"\\u00a0\"; }\n result += ch;\n spaceBefore = ch == \" \";\n }\n return result\n }\n\n // Work around nonsense dimensions being reported for stretches of\n // right-to-left text.\n function buildTokenBadBidi(inner, order) {\n return function (builder, text, style, startStyle, endStyle, css, attributes) {\n style = style ? style + \" cm-force-border\" : \"cm-force-border\";\n var start = builder.pos, end = start + text.length;\n for (;;) {\n // Find the part that overlaps with the start of this text\n var part = (void 0);\n for (var i = 0; i < order.length; i++) {\n part = order[i];\n if (part.to > start && part.from <= start) { break }\n }\n if (part.to >= end) { return inner(builder, text, style, startStyle, endStyle, css, attributes) }\n inner(builder, text.slice(0, part.to - start), style, startStyle, null, css, attributes);\n startStyle = null;\n text = text.slice(part.to - start);\n start = part.to;\n }\n }\n }\n\n function buildCollapsedSpan(builder, size, marker, ignoreWidget) {\n var widget = !ignoreWidget && marker.widgetNode;\n if (widget) { builder.map.push(builder.pos, builder.pos + size, widget); }\n if (!ignoreWidget && builder.cm.display.input.needsContentAttribute) {\n if (!widget)\n { widget = builder.content.appendChild(document.createElement(\"span\")); }\n widget.setAttribute(\"cm-marker\", marker.id);\n }\n if (widget) {\n builder.cm.display.input.setUneditable(widget);\n builder.content.appendChild(widget);\n }\n builder.pos += size;\n builder.trailingSpace = false;\n }\n\n // Outputs a number of spans to make up a line, taking highlighting\n // and marked text into account.\n function insertLineContent(line, builder, styles) {\n var spans = line.markedSpans, allText = line.text, at = 0;\n if (!spans) {\n for (var i$1 = 1; i$1 < styles.length; i$1+=2)\n { builder.addToken(builder, allText.slice(at, at = styles[i$1]), interpretTokenStyle(styles[i$1+1], builder.cm.options)); }\n return\n }\n\n var len = allText.length, pos = 0, i = 1, text = \"\", style, css;\n var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, collapsed, attributes;\n for (;;) {\n if (nextChange == pos) { // Update current marker set\n spanStyle = spanEndStyle = spanStartStyle = css = \"\";\n attributes = null;\n collapsed = null; nextChange = Infinity;\n var foundBookmarks = [], endStyles = (void 0);\n for (var j = 0; j < spans.length; ++j) {\n var sp = spans[j], m = sp.marker;\n if (m.type == \"bookmark\" && sp.from == pos && m.widgetNode) {\n foundBookmarks.push(m);\n } else if (sp.from <= pos && (sp.to == null || sp.to > pos || m.collapsed && sp.to == pos && sp.from == pos)) {\n if (sp.to != null && sp.to != pos && nextChange > sp.to) {\n nextChange = sp.to;\n spanEndStyle = \"\";\n }\n if (m.className) { spanStyle += \" \" + m.className; }\n if (m.css) { css = (css ? css + \";\" : \"\") + m.css; }\n if (m.startStyle && sp.from == pos) { spanStartStyle += \" \" + m.startStyle; }\n if (m.endStyle && sp.to == nextChange) { (endStyles || (endStyles = [])).push(m.endStyle, sp.to); }\n // support for the old title property\n // https://github.com/codemirror/CodeMirror/pull/5673\n if (m.title) { (attributes || (attributes = {})).title = m.title; }\n if (m.attributes) {\n for (var attr in m.attributes)\n { (attributes || (attributes = {}))[attr] = m.attributes[attr]; }\n }\n if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0))\n { collapsed = sp; }\n } else if (sp.from > pos && nextChange > sp.from) {\n nextChange = sp.from;\n }\n }\n if (endStyles) { for (var j$1 = 0; j$1 < endStyles.length; j$1 += 2)\n { if (endStyles[j$1 + 1] == nextChange) { spanEndStyle += \" \" + endStyles[j$1]; } } }\n\n if (!collapsed || collapsed.from == pos) { for (var j$2 = 0; j$2 < foundBookmarks.length; ++j$2)\n { buildCollapsedSpan(builder, 0, foundBookmarks[j$2]); } }\n if (collapsed && (collapsed.from || 0) == pos) {\n buildCollapsedSpan(builder, (collapsed.to == null ? len + 1 : collapsed.to) - pos,\n collapsed.marker, collapsed.from == null);\n if (collapsed.to == null) { return }\n if (collapsed.to == pos) { collapsed = false; }\n }\n }\n if (pos >= len) { break }\n\n var upto = Math.min(len, nextChange);\n while (true) {\n if (text) {\n var end = pos + text.length;\n if (!collapsed) {\n var tokenText = end > upto ? text.slice(0, upto - pos) : text;\n builder.addToken(builder, tokenText, style ? style + spanStyle : spanStyle,\n spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : \"\", css, attributes);\n }\n if (end >= upto) {text = text.slice(upto - pos); pos = upto; break}\n pos = end;\n spanStartStyle = \"\";\n }\n text = allText.slice(at, at = styles[i++]);\n style = interpretTokenStyle(styles[i++], builder.cm.options);\n }\n }\n }\n\n\n // These objects are used to represent the visible (currently drawn)\n // part of the document. A LineView may correspond to multiple\n // logical lines, if those are connected by collapsed ranges.\n function LineView(doc, line, lineN) {\n // The starting line\n this.line = line;\n // Continuing lines, if any\n this.rest = visualLineContinued(line);\n // Number of logical lines in this visual line\n this.size = this.rest ? lineNo(lst(this.rest)) - lineN + 1 : 1;\n this.node = this.text = null;\n this.hidden = lineIsHidden(doc, line);\n }\n\n // Create a range of LineView objects for the given lines.\n function buildViewArray(cm, from, to) {\n var array = [], nextPos;\n for (var pos = from; pos < to; pos = nextPos) {\n var view = new LineView(cm.doc, getLine(cm.doc, pos), pos);\n nextPos = pos + view.size;\n array.push(view);\n }\n return array\n }\n\n var operationGroup = null;\n\n function pushOperation(op) {\n if (operationGroup) {\n operationGroup.ops.push(op);\n } else {\n op.ownsGroup = operationGroup = {\n ops: [op],\n delayedCallbacks: []\n };\n }\n }\n\n function fireCallbacksForOps(group) {\n // Calls delayed callbacks and cursorActivity handlers until no\n // new ones appear\n var callbacks = group.delayedCallbacks, i = 0;\n do {\n for (; i < callbacks.length; i++)\n { callbacks[i].call(null); }\n for (var j = 0; j < group.ops.length; j++) {\n var op = group.ops[j];\n if (op.cursorActivityHandlers)\n { while (op.cursorActivityCalled < op.cursorActivityHandlers.length)\n { op.cursorActivityHandlers[op.cursorActivityCalled++].call(null, op.cm); } }\n }\n } while (i < callbacks.length)\n }\n\n function finishOperation(op, endCb) {\n var group = op.ownsGroup;\n if (!group) { return }\n\n try { fireCallbacksForOps(group); }\n finally {\n operationGroup = null;\n endCb(group);\n }\n }\n\n var orphanDelayedCallbacks = null;\n\n // Often, we want to signal events at a point where we are in the\n // middle of some work, but don't want the handler to start calling\n // other methods on the editor, which might be in an inconsistent\n // state or simply not expect any other events to happen.\n // signalLater looks whether there are any handlers, and schedules\n // them to be executed when the last operation ends, or, if no\n // operation is active, when a timeout fires.\n function signalLater(emitter, type /*, values...*/) {\n var arr = getHandlers(emitter, type);\n if (!arr.length) { return }\n var args = Array.prototype.slice.call(arguments, 2), list;\n if (operationGroup) {\n list = operationGroup.delayedCallbacks;\n } else if (orphanDelayedCallbacks) {\n list = orphanDelayedCallbacks;\n } else {\n list = orphanDelayedCallbacks = [];\n setTimeout(fireOrphanDelayed, 0);\n }\n var loop = function ( i ) {\n list.push(function () { return arr[i].apply(null, args); });\n };\n\n for (var i = 0; i < arr.length; ++i)\n loop( i );\n }\n\n function fireOrphanDelayed() {\n var delayed = orphanDelayedCallbacks;\n orphanDelayedCallbacks = null;\n for (var i = 0; i < delayed.length; ++i) { delayed[i](); }\n }\n\n // When an aspect of a line changes, a string is added to\n // lineView.changes. This updates the relevant part of the line's\n // DOM structure.\n function updateLineForChanges(cm, lineView, lineN, dims) {\n for (var j = 0; j < lineView.changes.length; j++) {\n var type = lineView.changes[j];\n if (type == \"text\") { updateLineText(cm, lineView); }\n else if (type == \"gutter\") { updateLineGutter(cm, lineView, lineN, dims); }\n else if (type == \"class\") { updateLineClasses(cm, lineView); }\n else if (type == \"widget\") { updateLineWidgets(cm, lineView, dims); }\n }\n lineView.changes = null;\n }\n\n // Lines with gutter elements, widgets or a background class need to\n // be wrapped, and have the extra elements added to the wrapper div\n function ensureLineWrapped(lineView) {\n if (lineView.node == lineView.text) {\n lineView.node = elt(\"div\", null, null, \"position: relative\");\n if (lineView.text.parentNode)\n { lineView.text.parentNode.replaceChild(lineView.node, lineView.text); }\n lineView.node.appendChild(lineView.text);\n if (ie && ie_version < 8) { lineView.node.style.zIndex = 2; }\n }\n return lineView.node\n }\n\n function updateLineBackground(cm, lineView) {\n var cls = lineView.bgClass ? lineView.bgClass + \" \" + (lineView.line.bgClass || \"\") : lineView.line.bgClass;\n if (cls) { cls += \" CodeMirror-linebackground\"; }\n if (lineView.background) {\n if (cls) { lineView.background.className = cls; }\n else { lineView.background.parentNode.removeChild(lineView.background); lineView.background = null; }\n } else if (cls) {\n var wrap = ensureLineWrapped(lineView);\n lineView.background = wrap.insertBefore(elt(\"div\", null, cls), wrap.firstChild);\n cm.display.input.setUneditable(lineView.background);\n }\n }\n\n // Wrapper around buildLineContent which will reuse the structure\n // in display.externalMeasured when possible.\n function getLineContent(cm, lineView) {\n var ext = cm.display.externalMeasured;\n if (ext && ext.line == lineView.line) {\n cm.display.externalMeasured = null;\n lineView.measure = ext.measure;\n return ext.built\n }\n return buildLineContent(cm, lineView)\n }\n\n // Redraw the line's text. Interacts with the background and text\n // classes because the mode may output tokens that influence these\n // classes.\n function updateLineText(cm, lineView) {\n var cls = lineView.text.className;\n var built = getLineContent(cm, lineView);\n if (lineView.text == lineView.node) { lineView.node = built.pre; }\n lineView.text.parentNode.replaceChild(built.pre, lineView.text);\n lineView.text = built.pre;\n if (built.bgClass != lineView.bgClass || built.textClass != lineView.textClass) {\n lineView.bgClass = built.bgClass;\n lineView.textClass = built.textClass;\n updateLineClasses(cm, lineView);\n } else if (cls) {\n lineView.text.className = cls;\n }\n }\n\n function updateLineClasses(cm, lineView) {\n updateLineBackground(cm, lineView);\n if (lineView.line.wrapClass)\n { ensureLineWrapped(lineView).className = lineView.line.wrapClass; }\n else if (lineView.node != lineView.text)\n { lineView.node.className = \"\"; }\n var textClass = lineView.textClass ? lineView.textClass + \" \" + (lineView.line.textClass || \"\") : lineView.line.textClass;\n lineView.text.className = textClass || \"\";\n }\n\n function updateLineGutter(cm, lineView, lineN, dims) {\n if (lineView.gutter) {\n lineView.node.removeChild(lineView.gutter);\n lineView.gutter = null;\n }\n if (lineView.gutterBackground) {\n lineView.node.removeChild(lineView.gutterBackground);\n lineView.gutterBackground = null;\n }\n if (lineView.line.gutterClass) {\n var wrap = ensureLineWrapped(lineView);\n lineView.gutterBackground = elt(\"div\", null, \"CodeMirror-gutter-background \" + lineView.line.gutterClass,\n (\"left: \" + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + \"px; width: \" + (dims.gutterTotalWidth) + \"px\"));\n cm.display.input.setUneditable(lineView.gutterBackground);\n wrap.insertBefore(lineView.gutterBackground, lineView.text);\n }\n var markers = lineView.line.gutterMarkers;\n if (cm.options.lineNumbers || markers) {\n var wrap$1 = ensureLineWrapped(lineView);\n var gutterWrap = lineView.gutter = elt(\"div\", null, \"CodeMirror-gutter-wrapper\", (\"left: \" + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + \"px\"));\n cm.display.input.setUneditable(gutterWrap);\n wrap$1.insertBefore(gutterWrap, lineView.text);\n if (lineView.line.gutterClass)\n { gutterWrap.className += \" \" + lineView.line.gutterClass; }\n if (cm.options.lineNumbers && (!markers || !markers[\"CodeMirror-linenumbers\"]))\n { lineView.lineNumber = gutterWrap.appendChild(\n elt(\"div\", lineNumberFor(cm.options, lineN),\n \"CodeMirror-linenumber CodeMirror-gutter-elt\",\n (\"left: \" + (dims.gutterLeft[\"CodeMirror-linenumbers\"]) + \"px; width: \" + (cm.display.lineNumInnerWidth) + \"px\"))); }\n if (markers) { for (var k = 0; k < cm.display.gutterSpecs.length; ++k) {\n var id = cm.display.gutterSpecs[k].className, found = markers.hasOwnProperty(id) && markers[id];\n if (found)\n { gutterWrap.appendChild(elt(\"div\", [found], \"CodeMirror-gutter-elt\",\n (\"left: \" + (dims.gutterLeft[id]) + \"px; width: \" + (dims.gutterWidth[id]) + \"px\"))); }\n } }\n }\n }\n\n function updateLineWidgets(cm, lineView, dims) {\n if (lineView.alignable) { lineView.alignable = null; }\n var isWidget = classTest(\"CodeMirror-linewidget\");\n for (var node = lineView.node.firstChild, next = (void 0); node; node = next) {\n next = node.nextSibling;\n if (isWidget.test(node.className)) { lineView.node.removeChild(node); }\n }\n insertLineWidgets(cm, lineView, dims);\n }\n\n // Build a line's DOM representation from scratch\n function buildLineElement(cm, lineView, lineN, dims) {\n var built = getLineContent(cm, lineView);\n lineView.text = lineView.node = built.pre;\n if (built.bgClass) { lineView.bgClass = built.bgClass; }\n if (built.textClass) { lineView.textClass = built.textClass; }\n\n updateLineClasses(cm, lineView);\n updateLineGutter(cm, lineView, lineN, dims);\n insertLineWidgets(cm, lineView, dims);\n return lineView.node\n }\n\n // A lineView may contain multiple logical lines (when merged by\n // collapsed spans). The widgets for all of them need to be drawn.\n function insertLineWidgets(cm, lineView, dims) {\n insertLineWidgetsFor(cm, lineView.line, lineView, dims, true);\n if (lineView.rest) { for (var i = 0; i < lineView.rest.length; i++)\n { insertLineWidgetsFor(cm, lineView.rest[i], lineView, dims, false); } }\n }\n\n function insertLineWidgetsFor(cm, line, lineView, dims, allowAbove) {\n if (!line.widgets) { return }\n var wrap = ensureLineWrapped(lineView);\n for (var i = 0, ws = line.widgets; i < ws.length; ++i) {\n var widget = ws[i], node = elt(\"div\", [widget.node], \"CodeMirror-linewidget\" + (widget.className ? \" \" + widget.className : \"\"));\n if (!widget.handleMouseEvents) { node.setAttribute(\"cm-ignore-events\", \"true\"); }\n positionLineWidget(widget, node, lineView, dims);\n cm.display.input.setUneditable(node);\n if (allowAbove && widget.above)\n { wrap.insertBefore(node, lineView.gutter || lineView.text); }\n else\n { wrap.appendChild(node); }\n signalLater(widget, \"redraw\");\n }\n }\n\n function positionLineWidget(widget, node, lineView, dims) {\n if (widget.noHScroll) {\n (lineView.alignable || (lineView.alignable = [])).push(node);\n var width = dims.wrapperWidth;\n node.style.left = dims.fixedPos + \"px\";\n if (!widget.coverGutter) {\n width -= dims.gutterTotalWidth;\n node.style.paddingLeft = dims.gutterTotalWidth + \"px\";\n }\n node.style.width = width + \"px\";\n }\n if (widget.coverGutter) {\n node.style.zIndex = 5;\n node.style.position = \"relative\";\n if (!widget.noHScroll) { node.style.marginLeft = -dims.gutterTotalWidth + \"px\"; }\n }\n }\n\n function widgetHeight(widget) {\n if (widget.height != null) { return widget.height }\n var cm = widget.doc.cm;\n if (!cm) { return 0 }\n if (!contains(document.body, widget.node)) {\n var parentStyle = \"position: relative;\";\n if (widget.coverGutter)\n { parentStyle += \"margin-left: -\" + cm.display.gutters.offsetWidth + \"px;\"; }\n if (widget.noHScroll)\n { parentStyle += \"width: \" + cm.display.wrapper.clientWidth + \"px;\"; }\n removeChildrenAndAdd(cm.display.measure, elt(\"div\", [widget.node], null, parentStyle));\n }\n return widget.height = widget.node.parentNode.offsetHeight\n }\n\n // Return true when the given mouse event happened in a widget\n function eventInWidget(display, e) {\n for (var n = e_target(e); n != display.wrapper; n = n.parentNode) {\n if (!n || (n.nodeType == 1 && n.getAttribute(\"cm-ignore-events\") == \"true\") ||\n (n.parentNode == display.sizer && n != display.mover))\n { return true }\n }\n }\n\n // POSITION MEASUREMENT\n\n function paddingTop(display) {return display.lineSpace.offsetTop}\n function paddingVert(display) {return display.mover.offsetHeight - display.lineSpace.offsetHeight}\n function paddingH(display) {\n if (display.cachedPaddingH) { return display.cachedPaddingH }\n var e = removeChildrenAndAdd(display.measure, elt(\"pre\", \"x\", \"CodeMirror-line-like\"));\n var style = window.getComputedStyle ? window.getComputedStyle(e) : e.currentStyle;\n var data = {left: parseInt(style.paddingLeft), right: parseInt(style.paddingRight)};\n if (!isNaN(data.left) && !isNaN(data.right)) { display.cachedPaddingH = data; }\n return data\n }\n\n function scrollGap(cm) { return scrollerGap - cm.display.nativeBarWidth }\n function displayWidth(cm) {\n return cm.display.scroller.clientWidth - scrollGap(cm) - cm.display.barWidth\n }\n function displayHeight(cm) {\n return cm.display.scroller.clientHeight - scrollGap(cm) - cm.display.barHeight\n }\n\n // Ensure the lineView.wrapping.heights array is populated. This is\n // an array of bottom offsets for the lines that make up a drawn\n // line. When lineWrapping is on, there might be more than one\n // height.\n function ensureLineHeights(cm, lineView, rect) {\n var wrapping = cm.options.lineWrapping;\n var curWidth = wrapping && displayWidth(cm);\n if (!lineView.measure.heights || wrapping && lineView.measure.width != curWidth) {\n var heights = lineView.measure.heights = [];\n if (wrapping) {\n lineView.measure.width = curWidth;\n var rects = lineView.text.firstChild.getClientRects();\n for (var i = 0; i < rects.length - 1; i++) {\n var cur = rects[i], next = rects[i + 1];\n if (Math.abs(cur.bottom - next.bottom) > 2)\n { heights.push((cur.bottom + next.top) / 2 - rect.top); }\n }\n }\n heights.push(rect.bottom - rect.top);\n }\n }\n\n // Find a line map (mapping character offsets to text nodes) and a\n // measurement cache for the given line number. (A line view might\n // contain multiple lines when collapsed ranges are present.)\n function mapFromLineView(lineView, line, lineN) {\n if (lineView.line == line)\n { return {map: lineView.measure.map, cache: lineView.measure.cache} }\n for (var i = 0; i < lineView.rest.length; i++)\n { if (lineView.rest[i] == line)\n { return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i]} } }\n for (var i$1 = 0; i$1 < lineView.rest.length; i$1++)\n { if (lineNo(lineView.rest[i$1]) > lineN)\n { return {map: lineView.measure.maps[i$1], cache: lineView.measure.caches[i$1], before: true} } }\n }\n\n // Render a line into the hidden node display.externalMeasured. Used\n // when measurement is needed for a line that's not in the viewport.\n function updateExternalMeasurement(cm, line) {\n line = visualLine(line);\n var lineN = lineNo(line);\n var view = cm.display.externalMeasured = new LineView(cm.doc, line, lineN);\n view.lineN = lineN;\n var built = view.built = buildLineContent(cm, view);\n view.text = built.pre;\n removeChildrenAndAdd(cm.display.lineMeasure, built.pre);\n return view\n }\n\n // Get a {top, bottom, left, right} box (in line-local coordinates)\n // for a given character.\n function measureChar(cm, line, ch, bias) {\n return measureCharPrepared(cm, prepareMeasureForLine(cm, line), ch, bias)\n }\n\n // Find a line view that corresponds to the given line number.\n function findViewForLine(cm, lineN) {\n if (lineN >= cm.display.viewFrom && lineN < cm.display.viewTo)\n { return cm.display.view[findViewIndex(cm, lineN)] }\n var ext = cm.display.externalMeasured;\n if (ext && lineN >= ext.lineN && lineN < ext.lineN + ext.size)\n { return ext }\n }\n\n // Measurement can be split in two steps, the set-up work that\n // applies to the whole line, and the measurement of the actual\n // character. Functions like coordsChar, that need to do a lot of\n // measurements in a row, can thus ensure that the set-up work is\n // only done once.\n function prepareMeasureForLine(cm, line) {\n var lineN = lineNo(line);\n var view = findViewForLine(cm, lineN);\n if (view && !view.text) {\n view = null;\n } else if (view && view.changes) {\n updateLineForChanges(cm, view, lineN, getDimensions(cm));\n cm.curOp.forceUpdate = true;\n }\n if (!view)\n { view = updateExternalMeasurement(cm, line); }\n\n var info = mapFromLineView(view, line, lineN);\n return {\n line: line, view: view, rect: null,\n map: info.map, cache: info.cache, before: info.before,\n hasHeights: false\n }\n }\n\n // Given a prepared measurement object, measures the position of an\n // actual character (or fetches it from the cache).\n function measureCharPrepared(cm, prepared, ch, bias, varHeight) {\n if (prepared.before) { ch = -1; }\n var key = ch + (bias || \"\"), found;\n if (prepared.cache.hasOwnProperty(key)) {\n found = prepared.cache[key];\n } else {\n if (!prepared.rect)\n { prepared.rect = prepared.view.text.getBoundingClientRect(); }\n if (!prepared.hasHeights) {\n ensureLineHeights(cm, prepared.view, prepared.rect);\n prepared.hasHeights = true;\n }\n found = measureCharInner(cm, prepared, ch, bias);\n if (!found.bogus) { prepared.cache[key] = found; }\n }\n return {left: found.left, right: found.right,\n top: varHeight ? found.rtop : found.top,\n bottom: varHeight ? found.rbottom : found.bottom}\n }\n\n var nullRect = {left: 0, right: 0, top: 0, bottom: 0};\n\n function nodeAndOffsetInLineMap(map, ch, bias) {\n var node, start, end, collapse, mStart, mEnd;\n // First, search the line map for the text node corresponding to,\n // or closest to, the target character.\n for (var i = 0; i < map.length; i += 3) {\n mStart = map[i];\n mEnd = map[i + 1];\n if (ch < mStart) {\n start = 0; end = 1;\n collapse = \"left\";\n } else if (ch < mEnd) {\n start = ch - mStart;\n end = start + 1;\n } else if (i == map.length - 3 || ch == mEnd && map[i + 3] > ch) {\n end = mEnd - mStart;\n start = end - 1;\n if (ch >= mEnd) { collapse = \"right\"; }\n }\n if (start != null) {\n node = map[i + 2];\n if (mStart == mEnd && bias == (node.insertLeft ? \"left\" : \"right\"))\n { collapse = bias; }\n if (bias == \"left\" && start == 0)\n { while (i && map[i - 2] == map[i - 3] && map[i - 1].insertLeft) {\n node = map[(i -= 3) + 2];\n collapse = \"left\";\n } }\n if (bias == \"right\" && start == mEnd - mStart)\n { while (i < map.length - 3 && map[i + 3] == map[i + 4] && !map[i + 5].insertLeft) {\n node = map[(i += 3) + 2];\n collapse = \"right\";\n } }\n break\n }\n }\n return {node: node, start: start, end: end, collapse: collapse, coverStart: mStart, coverEnd: mEnd}\n }\n\n function getUsefulRect(rects, bias) {\n var rect = nullRect;\n if (bias == \"left\") { for (var i = 0; i < rects.length; i++) {\n if ((rect = rects[i]).left != rect.right) { break }\n } } else { for (var i$1 = rects.length - 1; i$1 >= 0; i$1--) {\n if ((rect = rects[i$1]).left != rect.right) { break }\n } }\n return rect\n }\n\n function measureCharInner(cm, prepared, ch, bias) {\n var place = nodeAndOffsetInLineMap(prepared.map, ch, bias);\n var node = place.node, start = place.start, end = place.end, collapse = place.collapse;\n\n var rect;\n if (node.nodeType == 3) { // If it is a text node, use a range to retrieve the coordinates.\n for (var i$1 = 0; i$1 < 4; i$1++) { // Retry a maximum of 4 times when nonsense rectangles are returned\n while (start && isExtendingChar(prepared.line.text.charAt(place.coverStart + start))) { --start; }\n while (place.coverStart + end < place.coverEnd && isExtendingChar(prepared.line.text.charAt(place.coverStart + end))) { ++end; }\n if (ie && ie_version < 9 && start == 0 && end == place.coverEnd - place.coverStart)\n { rect = node.parentNode.getBoundingClientRect(); }\n else\n { rect = getUsefulRect(range(node, start, end).getClientRects(), bias); }\n if (rect.left || rect.right || start == 0) { break }\n end = start;\n start = start - 1;\n collapse = \"right\";\n }\n if (ie && ie_version < 11) { rect = maybeUpdateRectForZooming(cm.display.measure, rect); }\n } else { // If it is a widget, simply get the box for the whole widget.\n if (start > 0) { collapse = bias = \"right\"; }\n var rects;\n if (cm.options.lineWrapping && (rects = node.getClientRects()).length > 1)\n { rect = rects[bias == \"right\" ? rects.length - 1 : 0]; }\n else\n { rect = node.getBoundingClientRect(); }\n }\n if (ie && ie_version < 9 && !start && (!rect || !rect.left && !rect.right)) {\n var rSpan = node.parentNode.getClientRects()[0];\n if (rSpan)\n { rect = {left: rSpan.left, right: rSpan.left + charWidth(cm.display), top: rSpan.top, bottom: rSpan.bottom}; }\n else\n { rect = nullRect; }\n }\n\n var rtop = rect.top - prepared.rect.top, rbot = rect.bottom - prepared.rect.top;\n var mid = (rtop + rbot) / 2;\n var heights = prepared.view.measure.heights;\n var i = 0;\n for (; i < heights.length - 1; i++)\n { if (mid < heights[i]) { break } }\n var top = i ? heights[i - 1] : 0, bot = heights[i];\n var result = {left: (collapse == \"right\" ? rect.right : rect.left) - prepared.rect.left,\n right: (collapse == \"left\" ? rect.left : rect.right) - prepared.rect.left,\n top: top, bottom: bot};\n if (!rect.left && !rect.right) { result.bogus = true; }\n if (!cm.options.singleCursorHeightPerLine) { result.rtop = rtop; result.rbottom = rbot; }\n\n return result\n }\n\n // Work around problem with bounding client rects on ranges being\n // returned incorrectly when zoomed on IE10 and below.\n function maybeUpdateRectForZooming(measure, rect) {\n if (!window.screen || screen.logicalXDPI == null ||\n screen.logicalXDPI == screen.deviceXDPI || !hasBadZoomedRects(measure))\n { return rect }\n var scaleX = screen.logicalXDPI / screen.deviceXDPI;\n var scaleY = screen.logicalYDPI / screen.deviceYDPI;\n return {left: rect.left * scaleX, right: rect.right * scaleX,\n top: rect.top * scaleY, bottom: rect.bottom * scaleY}\n }\n\n function clearLineMeasurementCacheFor(lineView) {\n if (lineView.measure) {\n lineView.measure.cache = {};\n lineView.measure.heights = null;\n if (lineView.rest) { for (var i = 0; i < lineView.rest.length; i++)\n { lineView.measure.caches[i] = {}; } }\n }\n }\n\n function clearLineMeasurementCache(cm) {\n cm.display.externalMeasure = null;\n removeChildren(cm.display.lineMeasure);\n for (var i = 0; i < cm.display.view.length; i++)\n { clearLineMeasurementCacheFor(cm.display.view[i]); }\n }\n\n function clearCaches(cm) {\n clearLineMeasurementCache(cm);\n cm.display.cachedCharWidth = cm.display.cachedTextHeight = cm.display.cachedPaddingH = null;\n if (!cm.options.lineWrapping) { cm.display.maxLineChanged = true; }\n cm.display.lineNumChars = null;\n }\n\n function pageScrollX() {\n // Work around https://bugs.chromium.org/p/chromium/issues/detail?id=489206\n // which causes page_Offset and bounding client rects to use\n // different reference viewports and invalidate our calculations.\n if (chrome && android) { return -(document.body.getBoundingClientRect().left - parseInt(getComputedStyle(document.body).marginLeft)) }\n return window.pageXOffset || (document.documentElement || document.body).scrollLeft\n }\n function pageScrollY() {\n if (chrome && android) { return -(document.body.getBoundingClientRect().top - parseInt(getComputedStyle(document.body).marginTop)) }\n return window.pageYOffset || (document.documentElement || document.body).scrollTop\n }\n\n function widgetTopHeight(lineObj) {\n var height = 0;\n if (lineObj.widgets) { for (var i = 0; i < lineObj.widgets.length; ++i) { if (lineObj.widgets[i].above)\n { height += widgetHeight(lineObj.widgets[i]); } } }\n return height\n }\n\n // Converts a {top, bottom, left, right} box from line-local\n // coordinates into another coordinate system. Context may be one of\n // \"line\", \"div\" (display.lineDiv), \"local\"./null (editor), \"window\",\n // or \"page\".\n function intoCoordSystem(cm, lineObj, rect, context, includeWidgets) {\n if (!includeWidgets) {\n var height = widgetTopHeight(lineObj);\n rect.top += height; rect.bottom += height;\n }\n if (context == \"line\") { return rect }\n if (!context) { context = \"local\"; }\n var yOff = heightAtLine(lineObj);\n if (context == \"local\") { yOff += paddingTop(cm.display); }\n else { yOff -= cm.display.viewOffset; }\n if (context == \"page\" || context == \"window\") {\n var lOff = cm.display.lineSpace.getBoundingClientRect();\n yOff += lOff.top + (context == \"window\" ? 0 : pageScrollY());\n var xOff = lOff.left + (context == \"window\" ? 0 : pageScrollX());\n rect.left += xOff; rect.right += xOff;\n }\n rect.top += yOff; rect.bottom += yOff;\n return rect\n }\n\n // Coverts a box from \"div\" coords to another coordinate system.\n // Context may be \"window\", \"page\", \"div\", or \"local\"./null.\n function fromCoordSystem(cm, coords, context) {\n if (context == \"div\") { return coords }\n var left = coords.left, top = coords.top;\n // First move into \"page\" coordinate system\n if (context == \"page\") {\n left -= pageScrollX();\n top -= pageScrollY();\n } else if (context == \"local\" || !context) {\n var localBox = cm.display.sizer.getBoundingClientRect();\n left += localBox.left;\n top += localBox.top;\n }\n\n var lineSpaceBox = cm.display.lineSpace.getBoundingClientRect();\n return {left: left - lineSpaceBox.left, top: top - lineSpaceBox.top}\n }\n\n function charCoords(cm, pos, context, lineObj, bias) {\n if (!lineObj) { lineObj = getLine(cm.doc, pos.line); }\n return intoCoordSystem(cm, lineObj, measureChar(cm, lineObj, pos.ch, bias), context)\n }\n\n // Returns a box for a given cursor position, which may have an\n // 'other' property containing the position of the secondary cursor\n // on a bidi boundary.\n // A cursor Pos(line, char, \"before\") is on the same visual line as `char - 1`\n // and after `char - 1` in writing order of `char - 1`\n // A cursor Pos(line, char, \"after\") is on the same visual line as `char`\n // and before `char` in writing order of `char`\n // Examples (upper-case letters are RTL, lower-case are LTR):\n // Pos(0, 1, ...)\n // before after\n // ab a|b a|b\n // aB a|B aB|\n // Ab |Ab A|b\n // AB B|A B|A\n // Every position after the last character on a line is considered to stick\n // to the last character on the line.\n function cursorCoords(cm, pos, context, lineObj, preparedMeasure, varHeight) {\n lineObj = lineObj || getLine(cm.doc, pos.line);\n if (!preparedMeasure) { preparedMeasure = prepareMeasureForLine(cm, lineObj); }\n function get(ch, right) {\n var m = measureCharPrepared(cm, preparedMeasure, ch, right ? \"right\" : \"left\", varHeight);\n if (right) { m.left = m.right; } else { m.right = m.left; }\n return intoCoordSystem(cm, lineObj, m, context)\n }\n var order = getOrder(lineObj, cm.doc.direction), ch = pos.ch, sticky = pos.sticky;\n if (ch >= lineObj.text.length) {\n ch = lineObj.text.length;\n sticky = \"before\";\n } else if (ch <= 0) {\n ch = 0;\n sticky = \"after\";\n }\n if (!order) { return get(sticky == \"before\" ? ch - 1 : ch, sticky == \"before\") }\n\n function getBidi(ch, partPos, invert) {\n var part = order[partPos], right = part.level == 1;\n return get(invert ? ch - 1 : ch, right != invert)\n }\n var partPos = getBidiPartAt(order, ch, sticky);\n var other = bidiOther;\n var val = getBidi(ch, partPos, sticky == \"before\");\n if (other != null) { val.other = getBidi(ch, other, sticky != \"before\"); }\n return val\n }\n\n // Used to cheaply estimate the coordinates for a position. Used for\n // intermediate scroll updates.\n function estimateCoords(cm, pos) {\n var left = 0;\n pos = clipPos(cm.doc, pos);\n if (!cm.options.lineWrapping) { left = charWidth(cm.display) * pos.ch; }\n var lineObj = getLine(cm.doc, pos.line);\n var top = heightAtLine(lineObj) + paddingTop(cm.display);\n return {left: left, right: left, top: top, bottom: top + lineObj.height}\n }\n\n // Positions returned by coordsChar contain some extra information.\n // xRel is the relative x position of the input coordinates compared\n // to the found position (so xRel > 0 means the coordinates are to\n // the right of the character position, for example). When outside\n // is true, that means the coordinates lie outside the line's\n // vertical range.\n function PosWithInfo(line, ch, sticky, outside, xRel) {\n var pos = Pos(line, ch, sticky);\n pos.xRel = xRel;\n if (outside) { pos.outside = outside; }\n return pos\n }\n\n // Compute the character position closest to the given coordinates.\n // Input must be lineSpace-local (\"div\" coordinate system).\n function coordsChar(cm, x, y) {\n var doc = cm.doc;\n y += cm.display.viewOffset;\n if (y < 0) { return PosWithInfo(doc.first, 0, null, -1, -1) }\n var lineN = lineAtHeight(doc, y), last = doc.first + doc.size - 1;\n if (lineN > last)\n { return PosWithInfo(doc.first + doc.size - 1, getLine(doc, last).text.length, null, 1, 1) }\n if (x < 0) { x = 0; }\n\n var lineObj = getLine(doc, lineN);\n for (;;) {\n var found = coordsCharInner(cm, lineObj, lineN, x, y);\n var collapsed = collapsedSpanAround(lineObj, found.ch + (found.xRel > 0 || found.outside > 0 ? 1 : 0));\n if (!collapsed) { return found }\n var rangeEnd = collapsed.find(1);\n if (rangeEnd.line == lineN) { return rangeEnd }\n lineObj = getLine(doc, lineN = rangeEnd.line);\n }\n }\n\n function wrappedLineExtent(cm, lineObj, preparedMeasure, y) {\n y -= widgetTopHeight(lineObj);\n var end = lineObj.text.length;\n var begin = findFirst(function (ch) { return measureCharPrepared(cm, preparedMeasure, ch - 1).bottom <= y; }, end, 0);\n end = findFirst(function (ch) { return measureCharPrepared(cm, preparedMeasure, ch).top > y; }, begin, end);\n return {begin: begin, end: end}\n }\n\n function wrappedLineExtentChar(cm, lineObj, preparedMeasure, target) {\n if (!preparedMeasure) { preparedMeasure = prepareMeasureForLine(cm, lineObj); }\n var targetTop = intoCoordSystem(cm, lineObj, measureCharPrepared(cm, preparedMeasure, target), \"line\").top;\n return wrappedLineExtent(cm, lineObj, preparedMeasure, targetTop)\n }\n\n // Returns true if the given side of a box is after the given\n // coordinates, in top-to-bottom, left-to-right order.\n function boxIsAfter(box, x, y, left) {\n return box.bottom <= y ? false : box.top > y ? true : (left ? box.left : box.right) > x\n }\n\n function coordsCharInner(cm, lineObj, lineNo, x, y) {\n // Move y into line-local coordinate space\n y -= heightAtLine(lineObj);\n var preparedMeasure = prepareMeasureForLine(cm, lineObj);\n // When directly calling `measureCharPrepared`, we have to adjust\n // for the widgets at this line.\n var widgetHeight = widgetTopHeight(lineObj);\n var begin = 0, end = lineObj.text.length, ltr = true;\n\n var order = getOrder(lineObj, cm.doc.direction);\n // If the line isn't plain left-to-right text, first figure out\n // which bidi section the coordinates fall into.\n if (order) {\n var part = (cm.options.lineWrapping ? coordsBidiPartWrapped : coordsBidiPart)\n (cm, lineObj, lineNo, preparedMeasure, order, x, y);\n ltr = part.level != 1;\n // The awkward -1 offsets are needed because findFirst (called\n // on these below) will treat its first bound as inclusive,\n // second as exclusive, but we want to actually address the\n // characters in the part's range\n begin = ltr ? part.from : part.to - 1;\n end = ltr ? part.to : part.from - 1;\n }\n\n // A binary search to find the first character whose bounding box\n // starts after the coordinates. If we run across any whose box wrap\n // the coordinates, store that.\n var chAround = null, boxAround = null;\n var ch = findFirst(function (ch) {\n var box = measureCharPrepared(cm, preparedMeasure, ch);\n box.top += widgetHeight; box.bottom += widgetHeight;\n if (!boxIsAfter(box, x, y, false)) { return false }\n if (box.top <= y && box.left <= x) {\n chAround = ch;\n boxAround = box;\n }\n return true\n }, begin, end);\n\n var baseX, sticky, outside = false;\n // If a box around the coordinates was found, use that\n if (boxAround) {\n // Distinguish coordinates nearer to the left or right side of the box\n var atLeft = x - boxAround.left < boxAround.right - x, atStart = atLeft == ltr;\n ch = chAround + (atStart ? 0 : 1);\n sticky = atStart ? \"after\" : \"before\";\n baseX = atLeft ? boxAround.left : boxAround.right;\n } else {\n // (Adjust for extended bound, if necessary.)\n if (!ltr && (ch == end || ch == begin)) { ch++; }\n // To determine which side to associate with, get the box to the\n // left of the character and compare it's vertical position to the\n // coordinates\n sticky = ch == 0 ? \"after\" : ch == lineObj.text.length ? \"before\" :\n (measureCharPrepared(cm, preparedMeasure, ch - (ltr ? 1 : 0)).bottom + widgetHeight <= y) == ltr ?\n \"after\" : \"before\";\n // Now get accurate coordinates for this place, in order to get a\n // base X position\n var coords = cursorCoords(cm, Pos(lineNo, ch, sticky), \"line\", lineObj, preparedMeasure);\n baseX = coords.left;\n outside = y < coords.top ? -1 : y >= coords.bottom ? 1 : 0;\n }\n\n ch = skipExtendingChars(lineObj.text, ch, 1);\n return PosWithInfo(lineNo, ch, sticky, outside, x - baseX)\n }\n\n function coordsBidiPart(cm, lineObj, lineNo, preparedMeasure, order, x, y) {\n // Bidi parts are sorted left-to-right, and in a non-line-wrapping\n // situation, we can take this ordering to correspond to the visual\n // ordering. This finds the first part whose end is after the given\n // coordinates.\n var index = findFirst(function (i) {\n var part = order[i], ltr = part.level != 1;\n return boxIsAfter(cursorCoords(cm, Pos(lineNo, ltr ? part.to : part.from, ltr ? \"before\" : \"after\"),\n \"line\", lineObj, preparedMeasure), x, y, true)\n }, 0, order.length - 1);\n var part = order[index];\n // If this isn't the first part, the part's start is also after\n // the coordinates, and the coordinates aren't on the same line as\n // that start, move one part back.\n if (index > 0) {\n var ltr = part.level != 1;\n var start = cursorCoords(cm, Pos(lineNo, ltr ? part.from : part.to, ltr ? \"after\" : \"before\"),\n \"line\", lineObj, preparedMeasure);\n if (boxIsAfter(start, x, y, true) && start.top > y)\n { part = order[index - 1]; }\n }\n return part\n }\n\n function coordsBidiPartWrapped(cm, lineObj, _lineNo, preparedMeasure, order, x, y) {\n // In a wrapped line, rtl text on wrapping boundaries can do things\n // that don't correspond to the ordering in our `order` array at\n // all, so a binary search doesn't work, and we want to return a\n // part that only spans one line so that the binary search in\n // coordsCharInner is safe. As such, we first find the extent of the\n // wrapped line, and then do a flat search in which we discard any\n // spans that aren't on the line.\n var ref = wrappedLineExtent(cm, lineObj, preparedMeasure, y);\n var begin = ref.begin;\n var end = ref.end;\n if (/\\s/.test(lineObj.text.charAt(end - 1))) { end--; }\n var part = null, closestDist = null;\n for (var i = 0; i < order.length; i++) {\n var p = order[i];\n if (p.from >= end || p.to <= begin) { continue }\n var ltr = p.level != 1;\n var endX = measureCharPrepared(cm, preparedMeasure, ltr ? Math.min(end, p.to) - 1 : Math.max(begin, p.from)).right;\n // Weigh against spans ending before this, so that they are only\n // picked if nothing ends after\n var dist = endX < x ? x - endX + 1e9 : endX - x;\n if (!part || closestDist > dist) {\n part = p;\n closestDist = dist;\n }\n }\n if (!part) { part = order[order.length - 1]; }\n // Clip the part to the wrapped line.\n if (part.from < begin) { part = {from: begin, to: part.to, level: part.level}; }\n if (part.to > end) { part = {from: part.from, to: end, level: part.level}; }\n return part\n }\n\n var measureText;\n // Compute the default text height.\n function textHeight(display) {\n if (display.cachedTextHeight != null) { return display.cachedTextHeight }\n if (measureText == null) {\n measureText = elt(\"pre\", null, \"CodeMirror-line-like\");\n // Measure a bunch of lines, for browsers that compute\n // fractional heights.\n for (var i = 0; i < 49; ++i) {\n measureText.appendChild(document.createTextNode(\"x\"));\n measureText.appendChild(elt(\"br\"));\n }\n measureText.appendChild(document.createTextNode(\"x\"));\n }\n removeChildrenAndAdd(display.measure, measureText);\n var height = measureText.offsetHeight / 50;\n if (height > 3) { display.cachedTextHeight = height; }\n removeChildren(display.measure);\n return height || 1\n }\n\n // Compute the default character width.\n function charWidth(display) {\n if (display.cachedCharWidth != null) { return display.cachedCharWidth }\n var anchor = elt(\"span\", \"xxxxxxxxxx\");\n var pre = elt(\"pre\", [anchor], \"CodeMirror-line-like\");\n removeChildrenAndAdd(display.measure, pre);\n var rect = anchor.getBoundingClientRect(), width = (rect.right - rect.left) / 10;\n if (width > 2) { display.cachedCharWidth = width; }\n return width || 10\n }\n\n // Do a bulk-read of the DOM positions and sizes needed to draw the\n // view, so that we don't interleave reading and writing to the DOM.\n function getDimensions(cm) {\n var d = cm.display, left = {}, width = {};\n var gutterLeft = d.gutters.clientLeft;\n for (var n = d.gutters.firstChild, i = 0; n; n = n.nextSibling, ++i) {\n var id = cm.display.gutterSpecs[i].className;\n left[id] = n.offsetLeft + n.clientLeft + gutterLeft;\n width[id] = n.clientWidth;\n }\n return {fixedPos: compensateForHScroll(d),\n gutterTotalWidth: d.gutters.offsetWidth,\n gutterLeft: left,\n gutterWidth: width,\n wrapperWidth: d.wrapper.clientWidth}\n }\n\n // Computes display.scroller.scrollLeft + display.gutters.offsetWidth,\n // but using getBoundingClientRect to get a sub-pixel-accurate\n // result.\n function compensateForHScroll(display) {\n return display.scroller.getBoundingClientRect().left - display.sizer.getBoundingClientRect().left\n }\n\n // Returns a function that estimates the height of a line, to use as\n // first approximation until the line becomes visible (and is thus\n // properly measurable).\n function estimateHeight(cm) {\n var th = textHeight(cm.display), wrapping = cm.options.lineWrapping;\n var perLine = wrapping && Math.max(5, cm.display.scroller.clientWidth / charWidth(cm.display) - 3);\n return function (line) {\n if (lineIsHidden(cm.doc, line)) { return 0 }\n\n var widgetsHeight = 0;\n if (line.widgets) { for (var i = 0; i < line.widgets.length; i++) {\n if (line.widgets[i].height) { widgetsHeight += line.widgets[i].height; }\n } }\n\n if (wrapping)\n { return widgetsHeight + (Math.ceil(line.text.length / perLine) || 1) * th }\n else\n { return widgetsHeight + th }\n }\n }\n\n function estimateLineHeights(cm) {\n var doc = cm.doc, est = estimateHeight(cm);\n doc.iter(function (line) {\n var estHeight = est(line);\n if (estHeight != line.height) { updateLineHeight(line, estHeight); }\n });\n }\n\n // Given a mouse event, find the corresponding position. If liberal\n // is false, it checks whether a gutter or scrollbar was clicked,\n // and returns null if it was. forRect is used by rectangular\n // selections, and tries to estimate a character position even for\n // coordinates beyond the right of the text.\n function posFromMouse(cm, e, liberal, forRect) {\n var display = cm.display;\n if (!liberal && e_target(e).getAttribute(\"cm-not-content\") == \"true\") { return null }\n\n var x, y, space = display.lineSpace.getBoundingClientRect();\n // Fails unpredictably on IE[67] when mouse is dragged around quickly.\n try { x = e.clientX - space.left; y = e.clientY - space.top; }\n catch (e$1) { return null }\n var coords = coordsChar(cm, x, y), line;\n if (forRect && coords.xRel > 0 && (line = getLine(cm.doc, coords.line).text).length == coords.ch) {\n var colDiff = countColumn(line, line.length, cm.options.tabSize) - line.length;\n coords = Pos(coords.line, Math.max(0, Math.round((x - paddingH(cm.display).left) / charWidth(cm.display)) - colDiff));\n }\n return coords\n }\n\n // Find the view element corresponding to a given line. Return null\n // when the line isn't visible.\n function findViewIndex(cm, n) {\n if (n >= cm.display.viewTo) { return null }\n n -= cm.display.viewFrom;\n if (n < 0) { return null }\n var view = cm.display.view;\n for (var i = 0; i < view.length; i++) {\n n -= view[i].size;\n if (n < 0) { return i }\n }\n }\n\n // Updates the display.view data structure for a given change to the\n // document. From and to are in pre-change coordinates. Lendiff is\n // the amount of lines added or subtracted by the change. This is\n // used for changes that span multiple lines, or change the way\n // lines are divided into visual lines. regLineChange (below)\n // registers single-line changes.\n function regChange(cm, from, to, lendiff) {\n if (from == null) { from = cm.doc.first; }\n if (to == null) { to = cm.doc.first + cm.doc.size; }\n if (!lendiff) { lendiff = 0; }\n\n var display = cm.display;\n if (lendiff && to < display.viewTo &&\n (display.updateLineNumbers == null || display.updateLineNumbers > from))\n { display.updateLineNumbers = from; }\n\n cm.curOp.viewChanged = true;\n\n if (from >= display.viewTo) { // Change after\n if (sawCollapsedSpans && visualLineNo(cm.doc, from) < display.viewTo)\n { resetView(cm); }\n } else if (to <= display.viewFrom) { // Change before\n if (sawCollapsedSpans && visualLineEndNo(cm.doc, to + lendiff) > display.viewFrom) {\n resetView(cm);\n } else {\n display.viewFrom += lendiff;\n display.viewTo += lendiff;\n }\n } else if (from <= display.viewFrom && to >= display.viewTo) { // Full overlap\n resetView(cm);\n } else if (from <= display.viewFrom) { // Top overlap\n var cut = viewCuttingPoint(cm, to, to + lendiff, 1);\n if (cut) {\n display.view = display.view.slice(cut.index);\n display.viewFrom = cut.lineN;\n display.viewTo += lendiff;\n } else {\n resetView(cm);\n }\n } else if (to >= display.viewTo) { // Bottom overlap\n var cut$1 = viewCuttingPoint(cm, from, from, -1);\n if (cut$1) {\n display.view = display.view.slice(0, cut$1.index);\n display.viewTo = cut$1.lineN;\n } else {\n resetView(cm);\n }\n } else { // Gap in the middle\n var cutTop = viewCuttingPoint(cm, from, from, -1);\n var cutBot = viewCuttingPoint(cm, to, to + lendiff, 1);\n if (cutTop && cutBot) {\n display.view = display.view.slice(0, cutTop.index)\n .concat(buildViewArray(cm, cutTop.lineN, cutBot.lineN))\n .concat(display.view.slice(cutBot.index));\n display.viewTo += lendiff;\n } else {\n resetView(cm);\n }\n }\n\n var ext = display.externalMeasured;\n if (ext) {\n if (to < ext.lineN)\n { ext.lineN += lendiff; }\n else if (from < ext.lineN + ext.size)\n { display.externalMeasured = null; }\n }\n }\n\n // Register a change to a single line. Type must be one of \"text\",\n // \"gutter\", \"class\", \"widget\"\n function regLineChange(cm, line, type) {\n cm.curOp.viewChanged = true;\n var display = cm.display, ext = cm.display.externalMeasured;\n if (ext && line >= ext.lineN && line < ext.lineN + ext.size)\n { display.externalMeasured = null; }\n\n if (line < display.viewFrom || line >= display.viewTo) { return }\n var lineView = display.view[findViewIndex(cm, line)];\n if (lineView.node == null) { return }\n var arr = lineView.changes || (lineView.changes = []);\n if (indexOf(arr, type) == -1) { arr.push(type); }\n }\n\n // Clear the view.\n function resetView(cm) {\n cm.display.viewFrom = cm.display.viewTo = cm.doc.first;\n cm.display.view = [];\n cm.display.viewOffset = 0;\n }\n\n function viewCuttingPoint(cm, oldN, newN, dir) {\n var index = findViewIndex(cm, oldN), diff, view = cm.display.view;\n if (!sawCollapsedSpans || newN == cm.doc.first + cm.doc.size)\n { return {index: index, lineN: newN} }\n var n = cm.display.viewFrom;\n for (var i = 0; i < index; i++)\n { n += view[i].size; }\n if (n != oldN) {\n if (dir > 0) {\n if (index == view.length - 1) { return null }\n diff = (n + view[index].size) - oldN;\n index++;\n } else {\n diff = n - oldN;\n }\n oldN += diff; newN += diff;\n }\n while (visualLineNo(cm.doc, newN) != newN) {\n if (index == (dir < 0 ? 0 : view.length - 1)) { return null }\n newN += dir * view[index - (dir < 0 ? 1 : 0)].size;\n index += dir;\n }\n return {index: index, lineN: newN}\n }\n\n // Force the view to cover a given range, adding empty view element\n // or clipping off existing ones as needed.\n function adjustView(cm, from, to) {\n var display = cm.display, view = display.view;\n if (view.length == 0 || from >= display.viewTo || to <= display.viewFrom) {\n display.view = buildViewArray(cm, from, to);\n display.viewFrom = from;\n } else {\n if (display.viewFrom > from)\n { display.view = buildViewArray(cm, from, display.viewFrom).concat(display.view); }\n else if (display.viewFrom < from)\n { display.view = display.view.slice(findViewIndex(cm, from)); }\n display.viewFrom = from;\n if (display.viewTo < to)\n { display.view = display.view.concat(buildViewArray(cm, display.viewTo, to)); }\n else if (display.viewTo > to)\n { display.view = display.view.slice(0, findViewIndex(cm, to)); }\n }\n display.viewTo = to;\n }\n\n // Count the number of lines in the view whose DOM representation is\n // out of date (or nonexistent).\n function countDirtyView(cm) {\n var view = cm.display.view, dirty = 0;\n for (var i = 0; i < view.length; i++) {\n var lineView = view[i];\n if (!lineView.hidden && (!lineView.node || lineView.changes)) { ++dirty; }\n }\n return dirty\n }\n\n function updateSelection(cm) {\n cm.display.input.showSelection(cm.display.input.prepareSelection());\n }\n\n function prepareSelection(cm, primary) {\n if ( primary === void 0 ) primary = true;\n\n var doc = cm.doc, result = {};\n var curFragment = result.cursors = document.createDocumentFragment();\n var selFragment = result.selection = document.createDocumentFragment();\n\n for (var i = 0; i < doc.sel.ranges.length; i++) {\n if (!primary && i == doc.sel.primIndex) { continue }\n var range = doc.sel.ranges[i];\n if (range.from().line >= cm.display.viewTo || range.to().line < cm.display.viewFrom) { continue }\n var collapsed = range.empty();\n if (collapsed || cm.options.showCursorWhenSelecting)\n { drawSelectionCursor(cm, range.head, curFragment); }\n if (!collapsed)\n { drawSelectionRange(cm, range, selFragment); }\n }\n return result\n }\n\n // Draws a cursor for the given range\n function drawSelectionCursor(cm, head, output) {\n var pos = cursorCoords(cm, head, \"div\", null, null, !cm.options.singleCursorHeightPerLine);\n\n var cursor = output.appendChild(elt(\"div\", \"\\u00a0\", \"CodeMirror-cursor\"));\n cursor.style.left = pos.left + \"px\";\n cursor.style.top = pos.top + \"px\";\n cursor.style.height = Math.max(0, pos.bottom - pos.top) * cm.options.cursorHeight + \"px\";\n\n if (pos.other) {\n // Secondary cursor, shown when on a 'jump' in bi-directional text\n var otherCursor = output.appendChild(elt(\"div\", \"\\u00a0\", \"CodeMirror-cursor CodeMirror-secondarycursor\"));\n otherCursor.style.display = \"\";\n otherCursor.style.left = pos.other.left + \"px\";\n otherCursor.style.top = pos.other.top + \"px\";\n otherCursor.style.height = (pos.other.bottom - pos.other.top) * .85 + \"px\";\n }\n }\n\n function cmpCoords(a, b) { return a.top - b.top || a.left - b.left }\n\n // Draws the given range as a highlighted selection\n function drawSelectionRange(cm, range, output) {\n var display = cm.display, doc = cm.doc;\n var fragment = document.createDocumentFragment();\n var padding = paddingH(cm.display), leftSide = padding.left;\n var rightSide = Math.max(display.sizerWidth, displayWidth(cm) - display.sizer.offsetLeft) - padding.right;\n var docLTR = doc.direction == \"ltr\";\n\n function add(left, top, width, bottom) {\n if (top < 0) { top = 0; }\n top = Math.round(top);\n bottom = Math.round(bottom);\n fragment.appendChild(elt(\"div\", null, \"CodeMirror-selected\", (\"position: absolute; left: \" + left + \"px;\\n top: \" + top + \"px; width: \" + (width == null ? rightSide - left : width) + \"px;\\n height: \" + (bottom - top) + \"px\")));\n }\n\n function drawForLine(line, fromArg, toArg) {\n var lineObj = getLine(doc, line);\n var lineLen = lineObj.text.length;\n var start, end;\n function coords(ch, bias) {\n return charCoords(cm, Pos(line, ch), \"div\", lineObj, bias)\n }\n\n function wrapX(pos, dir, side) {\n var extent = wrappedLineExtentChar(cm, lineObj, null, pos);\n var prop = (dir == \"ltr\") == (side == \"after\") ? \"left\" : \"right\";\n var ch = side == \"after\" ? extent.begin : extent.end - (/\\s/.test(lineObj.text.charAt(extent.end - 1)) ? 2 : 1);\n return coords(ch, prop)[prop]\n }\n\n var order = getOrder(lineObj, doc.direction);\n iterateBidiSections(order, fromArg || 0, toArg == null ? lineLen : toArg, function (from, to, dir, i) {\n var ltr = dir == \"ltr\";\n var fromPos = coords(from, ltr ? \"left\" : \"right\");\n var toPos = coords(to - 1, ltr ? \"right\" : \"left\");\n\n var openStart = fromArg == null && from == 0, openEnd = toArg == null && to == lineLen;\n var first = i == 0, last = !order || i == order.length - 1;\n if (toPos.top - fromPos.top <= 3) { // Single line\n var openLeft = (docLTR ? openStart : openEnd) && first;\n var openRight = (docLTR ? openEnd : openStart) && last;\n var left = openLeft ? leftSide : (ltr ? fromPos : toPos).left;\n var right = openRight ? rightSide : (ltr ? toPos : fromPos).right;\n add(left, fromPos.top, right - left, fromPos.bottom);\n } else { // Multiple lines\n var topLeft, topRight, botLeft, botRight;\n if (ltr) {\n topLeft = docLTR && openStart && first ? leftSide : fromPos.left;\n topRight = docLTR ? rightSide : wrapX(from, dir, \"before\");\n botLeft = docLTR ? leftSide : wrapX(to, dir, \"after\");\n botRight = docLTR && openEnd && last ? rightSide : toPos.right;\n } else {\n topLeft = !docLTR ? leftSide : wrapX(from, dir, \"before\");\n topRight = !docLTR && openStart && first ? rightSide : fromPos.right;\n botLeft = !docLTR && openEnd && last ? leftSide : toPos.left;\n botRight = !docLTR ? rightSide : wrapX(to, dir, \"after\");\n }\n add(topLeft, fromPos.top, topRight - topLeft, fromPos.bottom);\n if (fromPos.bottom < toPos.top) { add(leftSide, fromPos.bottom, null, toPos.top); }\n add(botLeft, toPos.top, botRight - botLeft, toPos.bottom);\n }\n\n if (!start || cmpCoords(fromPos, start) < 0) { start = fromPos; }\n if (cmpCoords(toPos, start) < 0) { start = toPos; }\n if (!end || cmpCoords(fromPos, end) < 0) { end = fromPos; }\n if (cmpCoords(toPos, end) < 0) { end = toPos; }\n });\n return {start: start, end: end}\n }\n\n var sFrom = range.from(), sTo = range.to();\n if (sFrom.line == sTo.line) {\n drawForLine(sFrom.line, sFrom.ch, sTo.ch);\n } else {\n var fromLine = getLine(doc, sFrom.line), toLine = getLine(doc, sTo.line);\n var singleVLine = visualLine(fromLine) == visualLine(toLine);\n var leftEnd = drawForLine(sFrom.line, sFrom.ch, singleVLine ? fromLine.text.length + 1 : null).end;\n var rightStart = drawForLine(sTo.line, singleVLine ? 0 : null, sTo.ch).start;\n if (singleVLine) {\n if (leftEnd.top < rightStart.top - 2) {\n add(leftEnd.right, leftEnd.top, null, leftEnd.bottom);\n add(leftSide, rightStart.top, rightStart.left, rightStart.bottom);\n } else {\n add(leftEnd.right, leftEnd.top, rightStart.left - leftEnd.right, leftEnd.bottom);\n }\n }\n if (leftEnd.bottom < rightStart.top)\n { add(leftSide, leftEnd.bottom, null, rightStart.top); }\n }\n\n output.appendChild(fragment);\n }\n\n // Cursor-blinking\n function restartBlink(cm) {\n if (!cm.state.focused) { return }\n var display = cm.display;\n clearInterval(display.blinker);\n var on = true;\n display.cursorDiv.style.visibility = \"\";\n if (cm.options.cursorBlinkRate > 0)\n { display.blinker = setInterval(function () {\n if (!cm.hasFocus()) { onBlur(cm); }\n display.cursorDiv.style.visibility = (on = !on) ? \"\" : \"hidden\";\n }, cm.options.cursorBlinkRate); }\n else if (cm.options.cursorBlinkRate < 0)\n { display.cursorDiv.style.visibility = \"hidden\"; }\n }\n\n function ensureFocus(cm) {\n if (!cm.state.focused) { cm.display.input.focus(); onFocus(cm); }\n }\n\n function delayBlurEvent(cm) {\n cm.state.delayingBlurEvent = true;\n setTimeout(function () { if (cm.state.delayingBlurEvent) {\n cm.state.delayingBlurEvent = false;\n onBlur(cm);\n } }, 100);\n }\n\n function onFocus(cm, e) {\n if (cm.state.delayingBlurEvent) { cm.state.delayingBlurEvent = false; }\n\n if (cm.options.readOnly == \"nocursor\") { return }\n if (!cm.state.focused) {\n signal(cm, \"focus\", cm, e);\n cm.state.focused = true;\n addClass(cm.display.wrapper, \"CodeMirror-focused\");\n // This test prevents this from firing when a context\n // menu is closed (since the input reset would kill the\n // select-all detection hack)\n if (!cm.curOp && cm.display.selForContextMenu != cm.doc.sel) {\n cm.display.input.reset();\n if (webkit) { setTimeout(function () { return cm.display.input.reset(true); }, 20); } // Issue #1730\n }\n cm.display.input.receivedFocus();\n }\n restartBlink(cm);\n }\n function onBlur(cm, e) {\n if (cm.state.delayingBlurEvent) { return }\n\n if (cm.state.focused) {\n signal(cm, \"blur\", cm, e);\n cm.state.focused = false;\n rmClass(cm.display.wrapper, \"CodeMirror-focused\");\n }\n clearInterval(cm.display.blinker);\n setTimeout(function () { if (!cm.state.focused) { cm.display.shift = false; } }, 150);\n }\n\n // Read the actual heights of the rendered lines, and update their\n // stored heights to match.\n function updateHeightsInViewport(cm) {\n var display = cm.display;\n var prevBottom = display.lineDiv.offsetTop;\n for (var i = 0; i < display.view.length; i++) {\n var cur = display.view[i], wrapping = cm.options.lineWrapping;\n var height = (void 0), width = 0;\n if (cur.hidden) { continue }\n if (ie && ie_version < 8) {\n var bot = cur.node.offsetTop + cur.node.offsetHeight;\n height = bot - prevBottom;\n prevBottom = bot;\n } else {\n var box = cur.node.getBoundingClientRect();\n height = box.bottom - box.top;\n // Check that lines don't extend past the right of the current\n // editor width\n if (!wrapping && cur.text.firstChild)\n { width = cur.text.firstChild.getBoundingClientRect().right - box.left - 1; }\n }\n var diff = cur.line.height - height;\n if (diff > .005 || diff < -.005) {\n updateLineHeight(cur.line, height);\n updateWidgetHeight(cur.line);\n if (cur.rest) { for (var j = 0; j < cur.rest.length; j++)\n { updateWidgetHeight(cur.rest[j]); } }\n }\n if (width > cm.display.sizerWidth) {\n var chWidth = Math.ceil(width / charWidth(cm.display));\n if (chWidth > cm.display.maxLineLength) {\n cm.display.maxLineLength = chWidth;\n cm.display.maxLine = cur.line;\n cm.display.maxLineChanged = true;\n }\n }\n }\n }\n\n // Read and store the height of line widgets associated with the\n // given line.\n function updateWidgetHeight(line) {\n if (line.widgets) { for (var i = 0; i < line.widgets.length; ++i) {\n var w = line.widgets[i], parent = w.node.parentNode;\n if (parent) { w.height = parent.offsetHeight; }\n } }\n }\n\n // Compute the lines that are visible in a given viewport (defaults\n // the the current scroll position). viewport may contain top,\n // height, and ensure (see op.scrollToPos) properties.\n function visibleLines(display, doc, viewport) {\n var top = viewport && viewport.top != null ? Math.max(0, viewport.top) : display.scroller.scrollTop;\n top = Math.floor(top - paddingTop(display));\n var bottom = viewport && viewport.bottom != null ? viewport.bottom : top + display.wrapper.clientHeight;\n\n var from = lineAtHeight(doc, top), to = lineAtHeight(doc, bottom);\n // Ensure is a {from: {line, ch}, to: {line, ch}} object, and\n // forces those lines into the viewport (if possible).\n if (viewport && viewport.ensure) {\n var ensureFrom = viewport.ensure.from.line, ensureTo = viewport.ensure.to.line;\n if (ensureFrom < from) {\n from = ensureFrom;\n to = lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + display.wrapper.clientHeight);\n } else if (Math.min(ensureTo, doc.lastLine()) >= to) {\n from = lineAtHeight(doc, heightAtLine(getLine(doc, ensureTo)) - display.wrapper.clientHeight);\n to = ensureTo;\n }\n }\n return {from: from, to: Math.max(to, from + 1)}\n }\n\n // SCROLLING THINGS INTO VIEW\n\n // If an editor sits on the top or bottom of the window, partially\n // scrolled out of view, this ensures that the cursor is visible.\n function maybeScrollWindow(cm, rect) {\n if (signalDOMEvent(cm, \"scrollCursorIntoView\")) { return }\n\n var display = cm.display, box = display.sizer.getBoundingClientRect(), doScroll = null;\n if (rect.top + box.top < 0) { doScroll = true; }\n else if (rect.bottom + box.top > (window.innerHeight || document.documentElement.clientHeight)) { doScroll = false; }\n if (doScroll != null && !phantom) {\n var scrollNode = elt(\"div\", \"\\u200b\", null, (\"position: absolute;\\n top: \" + (rect.top - display.viewOffset - paddingTop(cm.display)) + \"px;\\n height: \" + (rect.bottom - rect.top + scrollGap(cm) + display.barHeight) + \"px;\\n left: \" + (rect.left) + \"px; width: \" + (Math.max(2, rect.right - rect.left)) + \"px;\"));\n cm.display.lineSpace.appendChild(scrollNode);\n scrollNode.scrollIntoView(doScroll);\n cm.display.lineSpace.removeChild(scrollNode);\n }\n }\n\n // Scroll a given position into view (immediately), verifying that\n // it actually became visible (as line heights are accurately\n // measured, the position of something may 'drift' during drawing).\n function scrollPosIntoView(cm, pos, end, margin) {\n if (margin == null) { margin = 0; }\n var rect;\n if (!cm.options.lineWrapping && pos == end) {\n // Set pos and end to the cursor positions around the character pos sticks to\n // If pos.sticky == \"before\", that is around pos.ch - 1, otherwise around pos.ch\n // If pos == Pos(_, 0, \"before\"), pos and end are unchanged\n pos = pos.ch ? Pos(pos.line, pos.sticky == \"before\" ? pos.ch - 1 : pos.ch, \"after\") : pos;\n end = pos.sticky == \"before\" ? Pos(pos.line, pos.ch + 1, \"before\") : pos;\n }\n for (var limit = 0; limit < 5; limit++) {\n var changed = false;\n var coords = cursorCoords(cm, pos);\n var endCoords = !end || end == pos ? coords : cursorCoords(cm, end);\n rect = {left: Math.min(coords.left, endCoords.left),\n top: Math.min(coords.top, endCoords.top) - margin,\n right: Math.max(coords.left, endCoords.left),\n bottom: Math.max(coords.bottom, endCoords.bottom) + margin};\n var scrollPos = calculateScrollPos(cm, rect);\n var startTop = cm.doc.scrollTop, startLeft = cm.doc.scrollLeft;\n if (scrollPos.scrollTop != null) {\n updateScrollTop(cm, scrollPos.scrollTop);\n if (Math.abs(cm.doc.scrollTop - startTop) > 1) { changed = true; }\n }\n if (scrollPos.scrollLeft != null) {\n setScrollLeft(cm, scrollPos.scrollLeft);\n if (Math.abs(cm.doc.scrollLeft - startLeft) > 1) { changed = true; }\n }\n if (!changed) { break }\n }\n return rect\n }\n\n // Scroll a given set of coordinates into view (immediately).\n function scrollIntoView(cm, rect) {\n var scrollPos = calculateScrollPos(cm, rect);\n if (scrollPos.scrollTop != null) { updateScrollTop(cm, scrollPos.scrollTop); }\n if (scrollPos.scrollLeft != null) { setScrollLeft(cm, scrollPos.scrollLeft); }\n }\n\n // Calculate a new scroll position needed to scroll the given\n // rectangle into view. Returns an object with scrollTop and\n // scrollLeft properties. When these are undefined, the\n // vertical/horizontal position does not need to be adjusted.\n function calculateScrollPos(cm, rect) {\n var display = cm.display, snapMargin = textHeight(cm.display);\n if (rect.top < 0) { rect.top = 0; }\n var screentop = cm.curOp && cm.curOp.scrollTop != null ? cm.curOp.scrollTop : display.scroller.scrollTop;\n var screen = displayHeight(cm), result = {};\n if (rect.bottom - rect.top > screen) { rect.bottom = rect.top + screen; }\n var docBottom = cm.doc.height + paddingVert(display);\n var atTop = rect.top < snapMargin, atBottom = rect.bottom > docBottom - snapMargin;\n if (rect.top < screentop) {\n result.scrollTop = atTop ? 0 : rect.top;\n } else if (rect.bottom > screentop + screen) {\n var newTop = Math.min(rect.top, (atBottom ? docBottom : rect.bottom) - screen);\n if (newTop != screentop) { result.scrollTop = newTop; }\n }\n\n var gutterSpace = cm.options.fixedGutter ? 0 : display.gutters.offsetWidth;\n var screenleft = cm.curOp && cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft - gutterSpace;\n var screenw = displayWidth(cm) - display.gutters.offsetWidth;\n var tooWide = rect.right - rect.left > screenw;\n if (tooWide) { rect.right = rect.left + screenw; }\n if (rect.left < 10)\n { result.scrollLeft = 0; }\n else if (rect.left < screenleft)\n { result.scrollLeft = Math.max(0, rect.left + gutterSpace - (tooWide ? 0 : 10)); }\n else if (rect.right > screenw + screenleft - 3)\n { result.scrollLeft = rect.right + (tooWide ? 0 : 10) - screenw; }\n return result\n }\n\n // Store a relative adjustment to the scroll position in the current\n // operation (to be applied when the operation finishes).\n function addToScrollTop(cm, top) {\n if (top == null) { return }\n resolveScrollToPos(cm);\n cm.curOp.scrollTop = (cm.curOp.scrollTop == null ? cm.doc.scrollTop : cm.curOp.scrollTop) + top;\n }\n\n // Make sure that at the end of the operation the current cursor is\n // shown.\n function ensureCursorVisible(cm) {\n resolveScrollToPos(cm);\n var cur = cm.getCursor();\n cm.curOp.scrollToPos = {from: cur, to: cur, margin: cm.options.cursorScrollMargin};\n }\n\n function scrollToCoords(cm, x, y) {\n if (x != null || y != null) { resolveScrollToPos(cm); }\n if (x != null) { cm.curOp.scrollLeft = x; }\n if (y != null) { cm.curOp.scrollTop = y; }\n }\n\n function scrollToRange(cm, range) {\n resolveScrollToPos(cm);\n cm.curOp.scrollToPos = range;\n }\n\n // When an operation has its scrollToPos property set, and another\n // scroll action is applied before the end of the operation, this\n // 'simulates' scrolling that position into view in a cheap way, so\n // that the effect of intermediate scroll commands is not ignored.\n function resolveScrollToPos(cm) {\n var range = cm.curOp.scrollToPos;\n if (range) {\n cm.curOp.scrollToPos = null;\n var from = estimateCoords(cm, range.from), to = estimateCoords(cm, range.to);\n scrollToCoordsRange(cm, from, to, range.margin);\n }\n }\n\n function scrollToCoordsRange(cm, from, to, margin) {\n var sPos = calculateScrollPos(cm, {\n left: Math.min(from.left, to.left),\n top: Math.min(from.top, to.top) - margin,\n right: Math.max(from.right, to.right),\n bottom: Math.max(from.bottom, to.bottom) + margin\n });\n scrollToCoords(cm, sPos.scrollLeft, sPos.scrollTop);\n }\n\n // Sync the scrollable area and scrollbars, ensure the viewport\n // covers the visible area.\n function updateScrollTop(cm, val) {\n if (Math.abs(cm.doc.scrollTop - val) < 2) { return }\n if (!gecko) { updateDisplaySimple(cm, {top: val}); }\n setScrollTop(cm, val, true);\n if (gecko) { updateDisplaySimple(cm); }\n startWorker(cm, 100);\n }\n\n function setScrollTop(cm, val, forceScroll) {\n val = Math.max(0, Math.min(cm.display.scroller.scrollHeight - cm.display.scroller.clientHeight, val));\n if (cm.display.scroller.scrollTop == val && !forceScroll) { return }\n cm.doc.scrollTop = val;\n cm.display.scrollbars.setScrollTop(val);\n if (cm.display.scroller.scrollTop != val) { cm.display.scroller.scrollTop = val; }\n }\n\n // Sync scroller and scrollbar, ensure the gutter elements are\n // aligned.\n function setScrollLeft(cm, val, isScroller, forceScroll) {\n val = Math.max(0, Math.min(val, cm.display.scroller.scrollWidth - cm.display.scroller.clientWidth));\n if ((isScroller ? val == cm.doc.scrollLeft : Math.abs(cm.doc.scrollLeft - val) < 2) && !forceScroll) { return }\n cm.doc.scrollLeft = val;\n alignHorizontally(cm);\n if (cm.display.scroller.scrollLeft != val) { cm.display.scroller.scrollLeft = val; }\n cm.display.scrollbars.setScrollLeft(val);\n }\n\n // SCROLLBARS\n\n // Prepare DOM reads needed to update the scrollbars. Done in one\n // shot to minimize update/measure roundtrips.\n function measureForScrollbars(cm) {\n var d = cm.display, gutterW = d.gutters.offsetWidth;\n var docH = Math.round(cm.doc.height + paddingVert(cm.display));\n return {\n clientHeight: d.scroller.clientHeight,\n viewHeight: d.wrapper.clientHeight,\n scrollWidth: d.scroller.scrollWidth, clientWidth: d.scroller.clientWidth,\n viewWidth: d.wrapper.clientWidth,\n barLeft: cm.options.fixedGutter ? gutterW : 0,\n docHeight: docH,\n scrollHeight: docH + scrollGap(cm) + d.barHeight,\n nativeBarWidth: d.nativeBarWidth,\n gutterWidth: gutterW\n }\n }\n\n var NativeScrollbars = function(place, scroll, cm) {\n this.cm = cm;\n var vert = this.vert = elt(\"div\", [elt(\"div\", null, null, \"min-width: 1px\")], \"CodeMirror-vscrollbar\");\n var horiz = this.horiz = elt(\"div\", [elt(\"div\", null, null, \"height: 100%; min-height: 1px\")], \"CodeMirror-hscrollbar\");\n vert.tabIndex = horiz.tabIndex = -1;\n place(vert); place(horiz);\n\n on(vert, \"scroll\", function () {\n if (vert.clientHeight) { scroll(vert.scrollTop, \"vertical\"); }\n });\n on(horiz, \"scroll\", function () {\n if (horiz.clientWidth) { scroll(horiz.scrollLeft, \"horizontal\"); }\n });\n\n this.checkedZeroWidth = false;\n // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).\n if (ie && ie_version < 8) { this.horiz.style.minHeight = this.vert.style.minWidth = \"18px\"; }\n };\n\n NativeScrollbars.prototype.update = function (measure) {\n var needsH = measure.scrollWidth > measure.clientWidth + 1;\n var needsV = measure.scrollHeight > measure.clientHeight + 1;\n var sWidth = measure.nativeBarWidth;\n\n if (needsV) {\n this.vert.style.display = \"block\";\n this.vert.style.bottom = needsH ? sWidth + \"px\" : \"0\";\n var totalHeight = measure.viewHeight - (needsH ? sWidth : 0);\n // A bug in IE8 can cause this value to be negative, so guard it.\n this.vert.firstChild.style.height =\n Math.max(0, measure.scrollHeight - measure.clientHeight + totalHeight) + \"px\";\n } else {\n this.vert.style.display = \"\";\n this.vert.firstChild.style.height = \"0\";\n }\n\n if (needsH) {\n this.horiz.style.display = \"block\";\n this.horiz.style.right = needsV ? sWidth + \"px\" : \"0\";\n this.horiz.style.left = measure.barLeft + \"px\";\n var totalWidth = measure.viewWidth - measure.barLeft - (needsV ? sWidth : 0);\n this.horiz.firstChild.style.width =\n Math.max(0, measure.scrollWidth - measure.clientWidth + totalWidth) + \"px\";\n } else {\n this.horiz.style.display = \"\";\n this.horiz.firstChild.style.width = \"0\";\n }\n\n if (!this.checkedZeroWidth && measure.clientHeight > 0) {\n if (sWidth == 0) { this.zeroWidthHack(); }\n this.checkedZeroWidth = true;\n }\n\n return {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0}\n };\n\n NativeScrollbars.prototype.setScrollLeft = function (pos) {\n if (this.horiz.scrollLeft != pos) { this.horiz.scrollLeft = pos; }\n if (this.disableHoriz) { this.enableZeroWidthBar(this.horiz, this.disableHoriz, \"horiz\"); }\n };\n\n NativeScrollbars.prototype.setScrollTop = function (pos) {\n if (this.vert.scrollTop != pos) { this.vert.scrollTop = pos; }\n if (this.disableVert) { this.enableZeroWidthBar(this.vert, this.disableVert, \"vert\"); }\n };\n\n NativeScrollbars.prototype.zeroWidthHack = function () {\n var w = mac && !mac_geMountainLion ? \"12px\" : \"18px\";\n this.horiz.style.height = this.vert.style.width = w;\n this.horiz.style.pointerEvents = this.vert.style.pointerEvents = \"none\";\n this.disableHoriz = new Delayed;\n this.disableVert = new Delayed;\n };\n\n NativeScrollbars.prototype.enableZeroWidthBar = function (bar, delay, type) {\n bar.style.pointerEvents = \"auto\";\n function maybeDisable() {\n // To find out whether the scrollbar is still visible, we\n // check whether the element under the pixel in the bottom\n // right corner of the scrollbar box is the scrollbar box\n // itself (when the bar is still visible) or its filler child\n // (when the bar is hidden). If it is still visible, we keep\n // it enabled, if it's hidden, we disable pointer events.\n var box = bar.getBoundingClientRect();\n var elt = type == \"vert\" ? document.elementFromPoint(box.right - 1, (box.top + box.bottom) / 2)\n : document.elementFromPoint((box.right + box.left) / 2, box.bottom - 1);\n if (elt != bar) { bar.style.pointerEvents = \"none\"; }\n else { delay.set(1000, maybeDisable); }\n }\n delay.set(1000, maybeDisable);\n };\n\n NativeScrollbars.prototype.clear = function () {\n var parent = this.horiz.parentNode;\n parent.removeChild(this.horiz);\n parent.removeChild(this.vert);\n };\n\n var NullScrollbars = function () {};\n\n NullScrollbars.prototype.update = function () { return {bottom: 0, right: 0} };\n NullScrollbars.prototype.setScrollLeft = function () {};\n NullScrollbars.prototype.setScrollTop = function () {};\n NullScrollbars.prototype.clear = function () {};\n\n function updateScrollbars(cm, measure) {\n if (!measure) { measure = measureForScrollbars(cm); }\n var startWidth = cm.display.barWidth, startHeight = cm.display.barHeight;\n updateScrollbarsInner(cm, measure);\n for (var i = 0; i < 4 && startWidth != cm.display.barWidth || startHeight != cm.display.barHeight; i++) {\n if (startWidth != cm.display.barWidth && cm.options.lineWrapping)\n { updateHeightsInViewport(cm); }\n updateScrollbarsInner(cm, measureForScrollbars(cm));\n startWidth = cm.display.barWidth; startHeight = cm.display.barHeight;\n }\n }\n\n // Re-synchronize the fake scrollbars with the actual size of the\n // content.\n function updateScrollbarsInner(cm, measure) {\n var d = cm.display;\n var sizes = d.scrollbars.update(measure);\n\n d.sizer.style.paddingRight = (d.barWidth = sizes.right) + \"px\";\n d.sizer.style.paddingBottom = (d.barHeight = sizes.bottom) + \"px\";\n d.heightForcer.style.borderBottom = sizes.bottom + \"px solid transparent\";\n\n if (sizes.right && sizes.bottom) {\n d.scrollbarFiller.style.display = \"block\";\n d.scrollbarFiller.style.height = sizes.bottom + \"px\";\n d.scrollbarFiller.style.width = sizes.right + \"px\";\n } else { d.scrollbarFiller.style.display = \"\"; }\n if (sizes.bottom && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutter) {\n d.gutterFiller.style.display = \"block\";\n d.gutterFiller.style.height = sizes.bottom + \"px\";\n d.gutterFiller.style.width = measure.gutterWidth + \"px\";\n } else { d.gutterFiller.style.display = \"\"; }\n }\n\n var scrollbarModel = {\"native\": NativeScrollbars, \"null\": NullScrollbars};\n\n function initScrollbars(cm) {\n if (cm.display.scrollbars) {\n cm.display.scrollbars.clear();\n if (cm.display.scrollbars.addClass)\n { rmClass(cm.display.wrapper, cm.display.scrollbars.addClass); }\n }\n\n cm.display.scrollbars = new scrollbarModel[cm.options.scrollbarStyle](function (node) {\n cm.display.wrapper.insertBefore(node, cm.display.scrollbarFiller);\n // Prevent clicks in the scrollbars from killing focus\n on(node, \"mousedown\", function () {\n if (cm.state.focused) { setTimeout(function () { return cm.display.input.focus(); }, 0); }\n });\n node.setAttribute(\"cm-not-content\", \"true\");\n }, function (pos, axis) {\n if (axis == \"horizontal\") { setScrollLeft(cm, pos); }\n else { updateScrollTop(cm, pos); }\n }, cm);\n if (cm.display.scrollbars.addClass)\n { addClass(cm.display.wrapper, cm.display.scrollbars.addClass); }\n }\n\n // Operations are used to wrap a series of changes to the editor\n // state in such a way that each change won't have to update the\n // cursor and display (which would be awkward, slow, and\n // error-prone). Instead, display updates are batched and then all\n // combined and executed at once.\n\n var nextOpId = 0;\n // Start a new operation.\n function startOperation(cm) {\n cm.curOp = {\n cm: cm,\n viewChanged: false, // Flag that indicates that lines might need to be redrawn\n startHeight: cm.doc.height, // Used to detect need to update scrollbar\n forceUpdate: false, // Used to force a redraw\n updateInput: 0, // Whether to reset the input textarea\n typing: false, // Whether this reset should be careful to leave existing text (for compositing)\n changeObjs: null, // Accumulated changes, for firing change events\n cursorActivityHandlers: null, // Set of handlers to fire cursorActivity on\n cursorActivityCalled: 0, // Tracks which cursorActivity handlers have been called already\n selectionChanged: false, // Whether the selection needs to be redrawn\n updateMaxLine: false, // Set when the widest line needs to be determined anew\n scrollLeft: null, scrollTop: null, // Intermediate scroll position, not pushed to DOM yet\n scrollToPos: null, // Used to scroll to a specific position\n focus: false,\n id: ++nextOpId // Unique ID\n };\n pushOperation(cm.curOp);\n }\n\n // Finish an operation, updating the display and signalling delayed events\n function endOperation(cm) {\n var op = cm.curOp;\n if (op) { finishOperation(op, function (group) {\n for (var i = 0; i < group.ops.length; i++)\n { group.ops[i].cm.curOp = null; }\n endOperations(group);\n }); }\n }\n\n // The DOM updates done when an operation finishes are batched so\n // that the minimum number of relayouts are required.\n function endOperations(group) {\n var ops = group.ops;\n for (var i = 0; i < ops.length; i++) // Read DOM\n { endOperation_R1(ops[i]); }\n for (var i$1 = 0; i$1 < ops.length; i$1++) // Write DOM (maybe)\n { endOperation_W1(ops[i$1]); }\n for (var i$2 = 0; i$2 < ops.length; i$2++) // Read DOM\n { endOperation_R2(ops[i$2]); }\n for (var i$3 = 0; i$3 < ops.length; i$3++) // Write DOM (maybe)\n { endOperation_W2(ops[i$3]); }\n for (var i$4 = 0; i$4 < ops.length; i$4++) // Read DOM\n { endOperation_finish(ops[i$4]); }\n }\n\n function endOperation_R1(op) {\n var cm = op.cm, display = cm.display;\n maybeClipScrollbars(cm);\n if (op.updateMaxLine) { findMaxLine(cm); }\n\n op.mustUpdate = op.viewChanged || op.forceUpdate || op.scrollTop != null ||\n op.scrollToPos && (op.scrollToPos.from.line < display.viewFrom ||\n op.scrollToPos.to.line >= display.viewTo) ||\n display.maxLineChanged && cm.options.lineWrapping;\n op.update = op.mustUpdate &&\n new DisplayUpdate(cm, op.mustUpdate && {top: op.scrollTop, ensure: op.scrollToPos}, op.forceUpdate);\n }\n\n function endOperation_W1(op) {\n op.updatedDisplay = op.mustUpdate && updateDisplayIfNeeded(op.cm, op.update);\n }\n\n function endOperation_R2(op) {\n var cm = op.cm, display = cm.display;\n if (op.updatedDisplay) { updateHeightsInViewport(cm); }\n\n op.barMeasure = measureForScrollbars(cm);\n\n // If the max line changed since it was last measured, measure it,\n // and ensure the document's width matches it.\n // updateDisplay_W2 will use these properties to do the actual resizing\n if (display.maxLineChanged && !cm.options.lineWrapping) {\n op.adjustWidthTo = measureChar(cm, display.maxLine, display.maxLine.text.length).left + 3;\n cm.display.sizerWidth = op.adjustWidthTo;\n op.barMeasure.scrollWidth =\n Math.max(display.scroller.clientWidth, display.sizer.offsetLeft + op.adjustWidthTo + scrollGap(cm) + cm.display.barWidth);\n op.maxScrollLeft = Math.max(0, display.sizer.offsetLeft + op.adjustWidthTo - displayWidth(cm));\n }\n\n if (op.updatedDisplay || op.selectionChanged)\n { op.preparedSelection = display.input.prepareSelection(); }\n }\n\n function endOperation_W2(op) {\n var cm = op.cm;\n\n if (op.adjustWidthTo != null) {\n cm.display.sizer.style.minWidth = op.adjustWidthTo + \"px\";\n if (op.maxScrollLeft < cm.doc.scrollLeft)\n { setScrollLeft(cm, Math.min(cm.display.scroller.scrollLeft, op.maxScrollLeft), true); }\n cm.display.maxLineChanged = false;\n }\n\n var takeFocus = op.focus && op.focus == activeElt();\n if (op.preparedSelection)\n { cm.display.input.showSelection(op.preparedSelection, takeFocus); }\n if (op.updatedDisplay || op.startHeight != cm.doc.height)\n { updateScrollbars(cm, op.barMeasure); }\n if (op.updatedDisplay)\n { setDocumentHeight(cm, op.barMeasure); }\n\n if (op.selectionChanged) { restartBlink(cm); }\n\n if (cm.state.focused && op.updateInput)\n { cm.display.input.reset(op.typing); }\n if (takeFocus) { ensureFocus(op.cm); }\n }\n\n function endOperation_finish(op) {\n var cm = op.cm, display = cm.display, doc = cm.doc;\n\n if (op.updatedDisplay) { postUpdateDisplay(cm, op.update); }\n\n // Abort mouse wheel delta measurement, when scrolling explicitly\n if (display.wheelStartX != null && (op.scrollTop != null || op.scrollLeft != null || op.scrollToPos))\n { display.wheelStartX = display.wheelStartY = null; }\n\n // Propagate the scroll position to the actual DOM scroller\n if (op.scrollTop != null) { setScrollTop(cm, op.scrollTop, op.forceScroll); }\n\n if (op.scrollLeft != null) { setScrollLeft(cm, op.scrollLeft, true, true); }\n // If we need to scroll a specific position into view, do so.\n if (op.scrollToPos) {\n var rect = scrollPosIntoView(cm, clipPos(doc, op.scrollToPos.from),\n clipPos(doc, op.scrollToPos.to), op.scrollToPos.margin);\n maybeScrollWindow(cm, rect);\n }\n\n // Fire events for markers that are hidden/unidden by editing or\n // undoing\n var hidden = op.maybeHiddenMarkers, unhidden = op.maybeUnhiddenMarkers;\n if (hidden) { for (var i = 0; i < hidden.length; ++i)\n { if (!hidden[i].lines.length) { signal(hidden[i], \"hide\"); } } }\n if (unhidden) { for (var i$1 = 0; i$1 < unhidden.length; ++i$1)\n { if (unhidden[i$1].lines.length) { signal(unhidden[i$1], \"unhide\"); } } }\n\n if (display.wrapper.offsetHeight)\n { doc.scrollTop = cm.display.scroller.scrollTop; }\n\n // Fire change events, and delayed event handlers\n if (op.changeObjs)\n { signal(cm, \"changes\", cm, op.changeObjs); }\n if (op.update)\n { op.update.finish(); }\n }\n\n // Run the given function in an operation\n function runInOp(cm, f) {\n if (cm.curOp) { return f() }\n startOperation(cm);\n try { return f() }\n finally { endOperation(cm); }\n }\n // Wraps a function in an operation. Returns the wrapped function.\n function operation(cm, f) {\n return function() {\n if (cm.curOp) { return f.apply(cm, arguments) }\n startOperation(cm);\n try { return f.apply(cm, arguments) }\n finally { endOperation(cm); }\n }\n }\n // Used to add methods to editor and doc instances, wrapping them in\n // operations.\n function methodOp(f) {\n return function() {\n if (this.curOp) { return f.apply(this, arguments) }\n startOperation(this);\n try { return f.apply(this, arguments) }\n finally { endOperation(this); }\n }\n }\n function docMethodOp(f) {\n return function() {\n var cm = this.cm;\n if (!cm || cm.curOp) { return f.apply(this, arguments) }\n startOperation(cm);\n try { return f.apply(this, arguments) }\n finally { endOperation(cm); }\n }\n }\n\n // HIGHLIGHT WORKER\n\n function startWorker(cm, time) {\n if (cm.doc.highlightFrontier < cm.display.viewTo)\n { cm.state.highlight.set(time, bind(highlightWorker, cm)); }\n }\n\n function highlightWorker(cm) {\n var doc = cm.doc;\n if (doc.highlightFrontier >= cm.display.viewTo) { return }\n var end = +new Date + cm.options.workTime;\n var context = getContextBefore(cm, doc.highlightFrontier);\n var changedLines = [];\n\n doc.iter(context.line, Math.min(doc.first + doc.size, cm.display.viewTo + 500), function (line) {\n if (context.line >= cm.display.viewFrom) { // Visible\n var oldStyles = line.styles;\n var resetState = line.text.length > cm.options.maxHighlightLength ? copyState(doc.mode, context.state) : null;\n var highlighted = highlightLine(cm, line, context, true);\n if (resetState) { context.state = resetState; }\n line.styles = highlighted.styles;\n var oldCls = line.styleClasses, newCls = highlighted.classes;\n if (newCls) { line.styleClasses = newCls; }\n else if (oldCls) { line.styleClasses = null; }\n var ischange = !oldStyles || oldStyles.length != line.styles.length ||\n oldCls != newCls && (!oldCls || !newCls || oldCls.bgClass != newCls.bgClass || oldCls.textClass != newCls.textClass);\n for (var i = 0; !ischange && i < oldStyles.length; ++i) { ischange = oldStyles[i] != line.styles[i]; }\n if (ischange) { changedLines.push(context.line); }\n line.stateAfter = context.save();\n context.nextLine();\n } else {\n if (line.text.length <= cm.options.maxHighlightLength)\n { processLine(cm, line.text, context); }\n line.stateAfter = context.line % 5 == 0 ? context.save() : null;\n context.nextLine();\n }\n if (+new Date > end) {\n startWorker(cm, cm.options.workDelay);\n return true\n }\n });\n doc.highlightFrontier = context.line;\n doc.modeFrontier = Math.max(doc.modeFrontier, context.line);\n if (changedLines.length) { runInOp(cm, function () {\n for (var i = 0; i < changedLines.length; i++)\n { regLineChange(cm, changedLines[i], \"text\"); }\n }); }\n }\n\n // DISPLAY DRAWING\n\n var DisplayUpdate = function(cm, viewport, force) {\n var display = cm.display;\n\n this.viewport = viewport;\n // Store some values that we'll need later (but don't want to force a relayout for)\n this.visible = visibleLines(display, cm.doc, viewport);\n this.editorIsHidden = !display.wrapper.offsetWidth;\n this.wrapperHeight = display.wrapper.clientHeight;\n this.wrapperWidth = display.wrapper.clientWidth;\n this.oldDisplayWidth = displayWidth(cm);\n this.force = force;\n this.dims = getDimensions(cm);\n this.events = [];\n };\n\n DisplayUpdate.prototype.signal = function (emitter, type) {\n if (hasHandler(emitter, type))\n { this.events.push(arguments); }\n };\n DisplayUpdate.prototype.finish = function () {\n for (var i = 0; i < this.events.length; i++)\n { signal.apply(null, this.events[i]); }\n };\n\n function maybeClipScrollbars(cm) {\n var display = cm.display;\n if (!display.scrollbarsClipped && display.scroller.offsetWidth) {\n display.nativeBarWidth = display.scroller.offsetWidth - display.scroller.clientWidth;\n display.heightForcer.style.height = scrollGap(cm) + \"px\";\n display.sizer.style.marginBottom = -display.nativeBarWidth + \"px\";\n display.sizer.style.borderRightWidth = scrollGap(cm) + \"px\";\n display.scrollbarsClipped = true;\n }\n }\n\n function selectionSnapshot(cm) {\n if (cm.hasFocus()) { return null }\n var active = activeElt();\n if (!active || !contains(cm.display.lineDiv, active)) { return null }\n var result = {activeElt: active};\n if (window.getSelection) {\n var sel = window.getSelection();\n if (sel.anchorNode && sel.extend && contains(cm.display.lineDiv, sel.anchorNode)) {\n result.anchorNode = sel.anchorNode;\n result.anchorOffset = sel.anchorOffset;\n result.focusNode = sel.focusNode;\n result.focusOffset = sel.focusOffset;\n }\n }\n return result\n }\n\n function restoreSelection(snapshot) {\n if (!snapshot || !snapshot.activeElt || snapshot.activeElt == activeElt()) { return }\n snapshot.activeElt.focus();\n if (!/^(INPUT|TEXTAREA)$/.test(snapshot.activeElt.nodeName) &&\n snapshot.anchorNode && contains(document.body, snapshot.anchorNode) && contains(document.body, snapshot.focusNode)) {\n var sel = window.getSelection(), range = document.createRange();\n range.setEnd(snapshot.anchorNode, snapshot.anchorOffset);\n range.collapse(false);\n sel.removeAllRanges();\n sel.addRange(range);\n sel.extend(snapshot.focusNode, snapshot.focusOffset);\n }\n }\n\n // Does the actual updating of the line display. Bails out\n // (returning false) when there is nothing to be done and forced is\n // false.\n function updateDisplayIfNeeded(cm, update) {\n var display = cm.display, doc = cm.doc;\n\n if (update.editorIsHidden) {\n resetView(cm);\n return false\n }\n\n // Bail out if the visible area is already rendered and nothing changed.\n if (!update.force &&\n update.visible.from >= display.viewFrom && update.visible.to <= display.viewTo &&\n (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo) &&\n display.renderedView == display.view && countDirtyView(cm) == 0)\n { return false }\n\n if (maybeUpdateLineNumberWidth(cm)) {\n resetView(cm);\n update.dims = getDimensions(cm);\n }\n\n // Compute a suitable new viewport (from & to)\n var end = doc.first + doc.size;\n var from = Math.max(update.visible.from - cm.options.viewportMargin, doc.first);\n var to = Math.min(end, update.visible.to + cm.options.viewportMargin);\n if (display.viewFrom < from && from - display.viewFrom < 20) { from = Math.max(doc.first, display.viewFrom); }\n if (display.viewTo > to && display.viewTo - to < 20) { to = Math.min(end, display.viewTo); }\n if (sawCollapsedSpans) {\n from = visualLineNo(cm.doc, from);\n to = visualLineEndNo(cm.doc, to);\n }\n\n var different = from != display.viewFrom || to != display.viewTo ||\n display.lastWrapHeight != update.wrapperHeight || display.lastWrapWidth != update.wrapperWidth;\n adjustView(cm, from, to);\n\n display.viewOffset = heightAtLine(getLine(cm.doc, display.viewFrom));\n // Position the mover div to align with the current scroll position\n cm.display.mover.style.top = display.viewOffset + \"px\";\n\n var toUpdate = countDirtyView(cm);\n if (!different && toUpdate == 0 && !update.force && display.renderedView == display.view &&\n (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo))\n { return false }\n\n // For big changes, we hide the enclosing element during the\n // update, since that speeds up the operations on most browsers.\n var selSnapshot = selectionSnapshot(cm);\n if (toUpdate > 4) { display.lineDiv.style.display = \"none\"; }\n patchDisplay(cm, display.updateLineNumbers, update.dims);\n if (toUpdate > 4) { display.lineDiv.style.display = \"\"; }\n display.renderedView = display.view;\n // There might have been a widget with a focused element that got\n // hidden or updated, if so re-focus it.\n restoreSelection(selSnapshot);\n\n // Prevent selection and cursors from interfering with the scroll\n // width and height.\n removeChildren(display.cursorDiv);\n removeChildren(display.selectionDiv);\n display.gutters.style.height = display.sizer.style.minHeight = 0;\n\n if (different) {\n display.lastWrapHeight = update.wrapperHeight;\n display.lastWrapWidth = update.wrapperWidth;\n startWorker(cm, 400);\n }\n\n display.updateLineNumbers = null;\n\n return true\n }\n\n function postUpdateDisplay(cm, update) {\n var viewport = update.viewport;\n\n for (var first = true;; first = false) {\n if (!first || !cm.options.lineWrapping || update.oldDisplayWidth == displayWidth(cm)) {\n // Clip forced viewport to actual scrollable area.\n if (viewport && viewport.top != null)\n { viewport = {top: Math.min(cm.doc.height + paddingVert(cm.display) - displayHeight(cm), viewport.top)}; }\n // Updated line heights might result in the drawn area not\n // actually covering the viewport. Keep looping until it does.\n update.visible = visibleLines(cm.display, cm.doc, viewport);\n if (update.visible.from >= cm.display.viewFrom && update.visible.to <= cm.display.viewTo)\n { break }\n } else if (first) {\n update.visible = visibleLines(cm.display, cm.doc, viewport);\n }\n if (!updateDisplayIfNeeded(cm, update)) { break }\n updateHeightsInViewport(cm);\n var barMeasure = measureForScrollbars(cm);\n updateSelection(cm);\n updateScrollbars(cm, barMeasure);\n setDocumentHeight(cm, barMeasure);\n update.force = false;\n }\n\n update.signal(cm, \"update\", cm);\n if (cm.display.viewFrom != cm.display.reportedViewFrom || cm.display.viewTo != cm.display.reportedViewTo) {\n update.signal(cm, \"viewportChange\", cm, cm.display.viewFrom, cm.display.viewTo);\n cm.display.reportedViewFrom = cm.display.viewFrom; cm.display.reportedViewTo = cm.display.viewTo;\n }\n }\n\n function updateDisplaySimple(cm, viewport) {\n var update = new DisplayUpdate(cm, viewport);\n if (updateDisplayIfNeeded(cm, update)) {\n updateHeightsInViewport(cm);\n postUpdateDisplay(cm, update);\n var barMeasure = measureForScrollbars(cm);\n updateSelection(cm);\n updateScrollbars(cm, barMeasure);\n setDocumentHeight(cm, barMeasure);\n update.finish();\n }\n }\n\n // Sync the actual display DOM structure with display.view, removing\n // nodes for lines that are no longer in view, and creating the ones\n // that are not there yet, and updating the ones that are out of\n // date.\n function patchDisplay(cm, updateNumbersFrom, dims) {\n var display = cm.display, lineNumbers = cm.options.lineNumbers;\n var container = display.lineDiv, cur = container.firstChild;\n\n function rm(node) {\n var next = node.nextSibling;\n // Works around a throw-scroll bug in OS X Webkit\n if (webkit && mac && cm.display.currentWheelTarget == node)\n { node.style.display = \"none\"; }\n else\n { node.parentNode.removeChild(node); }\n return next\n }\n\n var view = display.view, lineN = display.viewFrom;\n // Loop over the elements in the view, syncing cur (the DOM nodes\n // in display.lineDiv) with the view as we go.\n for (var i = 0; i < view.length; i++) {\n var lineView = view[i];\n if (lineView.hidden) ; else if (!lineView.node || lineView.node.parentNode != container) { // Not drawn yet\n var node = buildLineElement(cm, lineView, lineN, dims);\n container.insertBefore(node, cur);\n } else { // Already drawn\n while (cur != lineView.node) { cur = rm(cur); }\n var updateNumber = lineNumbers && updateNumbersFrom != null &&\n updateNumbersFrom <= lineN && lineView.lineNumber;\n if (lineView.changes) {\n if (indexOf(lineView.changes, \"gutter\") > -1) { updateNumber = false; }\n updateLineForChanges(cm, lineView, lineN, dims);\n }\n if (updateNumber) {\n removeChildren(lineView.lineNumber);\n lineView.lineNumber.appendChild(document.createTextNode(lineNumberFor(cm.options, lineN)));\n }\n cur = lineView.node.nextSibling;\n }\n lineN += lineView.size;\n }\n while (cur) { cur = rm(cur); }\n }\n\n function updateGutterSpace(display) {\n var width = display.gutters.offsetWidth;\n display.sizer.style.marginLeft = width + \"px\";\n }\n\n function setDocumentHeight(cm, measure) {\n cm.display.sizer.style.minHeight = measure.docHeight + \"px\";\n cm.display.heightForcer.style.top = measure.docHeight + \"px\";\n cm.display.gutters.style.height = (measure.docHeight + cm.display.barHeight + scrollGap(cm)) + \"px\";\n }\n\n // Re-align line numbers and gutter marks to compensate for\n // horizontal scrolling.\n function alignHorizontally(cm) {\n var display = cm.display, view = display.view;\n if (!display.alignWidgets && (!display.gutters.firstChild || !cm.options.fixedGutter)) { return }\n var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.doc.scrollLeft;\n var gutterW = display.gutters.offsetWidth, left = comp + \"px\";\n for (var i = 0; i < view.length; i++) { if (!view[i].hidden) {\n if (cm.options.fixedGutter) {\n if (view[i].gutter)\n { view[i].gutter.style.left = left; }\n if (view[i].gutterBackground)\n { view[i].gutterBackground.style.left = left; }\n }\n var align = view[i].alignable;\n if (align) { for (var j = 0; j < align.length; j++)\n { align[j].style.left = left; } }\n } }\n if (cm.options.fixedGutter)\n { display.gutters.style.left = (comp + gutterW) + \"px\"; }\n }\n\n // Used to ensure that the line number gutter is still the right\n // size for the current document size. Returns true when an update\n // is needed.\n function maybeUpdateLineNumberWidth(cm) {\n if (!cm.options.lineNumbers) { return false }\n var doc = cm.doc, last = lineNumberFor(cm.options, doc.first + doc.size - 1), display = cm.display;\n if (last.length != display.lineNumChars) {\n var test = display.measure.appendChild(elt(\"div\", [elt(\"div\", last)],\n \"CodeMirror-linenumber CodeMirror-gutter-elt\"));\n var innerW = test.firstChild.offsetWidth, padding = test.offsetWidth - innerW;\n display.lineGutter.style.width = \"\";\n display.lineNumInnerWidth = Math.max(innerW, display.lineGutter.offsetWidth - padding) + 1;\n display.lineNumWidth = display.lineNumInnerWidth + padding;\n display.lineNumChars = display.lineNumInnerWidth ? last.length : -1;\n display.lineGutter.style.width = display.lineNumWidth + \"px\";\n updateGutterSpace(cm.display);\n return true\n }\n return false\n }\n\n function getGutters(gutters, lineNumbers) {\n var result = [], sawLineNumbers = false;\n for (var i = 0; i < gutters.length; i++) {\n var name = gutters[i], style = null;\n if (typeof name != \"string\") { style = name.style; name = name.className; }\n if (name == \"CodeMirror-linenumbers\") {\n if (!lineNumbers) { continue }\n else { sawLineNumbers = true; }\n }\n result.push({className: name, style: style});\n }\n if (lineNumbers && !sawLineNumbers) { result.push({className: \"CodeMirror-linenumbers\", style: null}); }\n return result\n }\n\n // Rebuild the gutter elements, ensure the margin to the left of the\n // code matches their width.\n function renderGutters(display) {\n var gutters = display.gutters, specs = display.gutterSpecs;\n removeChildren(gutters);\n display.lineGutter = null;\n for (var i = 0; i < specs.length; ++i) {\n var ref = specs[i];\n var className = ref.className;\n var style = ref.style;\n var gElt = gutters.appendChild(elt(\"div\", null, \"CodeMirror-gutter \" + className));\n if (style) { gElt.style.cssText = style; }\n if (className == \"CodeMirror-linenumbers\") {\n display.lineGutter = gElt;\n gElt.style.width = (display.lineNumWidth || 1) + \"px\";\n }\n }\n gutters.style.display = specs.length ? \"\" : \"none\";\n updateGutterSpace(display);\n }\n\n function updateGutters(cm) {\n renderGutters(cm.display);\n regChange(cm);\n alignHorizontally(cm);\n }\n\n // The display handles the DOM integration, both for input reading\n // and content drawing. It holds references to DOM nodes and\n // display-related state.\n\n function Display(place, doc, input, options) {\n var d = this;\n this.input = input;\n\n // Covers bottom-right square when both scrollbars are present.\n d.scrollbarFiller = elt(\"div\", null, \"CodeMirror-scrollbar-filler\");\n d.scrollbarFiller.setAttribute(\"cm-not-content\", \"true\");\n // Covers bottom of gutter when coverGutterNextToScrollbar is on\n // and h scrollbar is present.\n d.gutterFiller = elt(\"div\", null, \"CodeMirror-gutter-filler\");\n d.gutterFiller.setAttribute(\"cm-not-content\", \"true\");\n // Will contain the actual code, positioned to cover the viewport.\n d.lineDiv = eltP(\"div\", null, \"CodeMirror-code\");\n // Elements are added to these to represent selection and cursors.\n d.selectionDiv = elt(\"div\", null, null, \"position: relative; z-index: 1\");\n d.cursorDiv = elt(\"div\", null, \"CodeMirror-cursors\");\n // A visibility: hidden element used to find the size of things.\n d.measure = elt(\"div\", null, \"CodeMirror-measure\");\n // When lines outside of the viewport are measured, they are drawn in this.\n d.lineMeasure = elt(\"div\", null, \"CodeMirror-measure\");\n // Wraps everything that needs to exist inside the vertically-padded coordinate system\n d.lineSpace = eltP(\"div\", [d.measure, d.lineMeasure, d.selectionDiv, d.cursorDiv, d.lineDiv],\n null, \"position: relative; outline: none\");\n var lines = eltP(\"div\", [d.lineSpace], \"CodeMirror-lines\");\n // Moved around its parent to cover visible view.\n d.mover = elt(\"div\", [lines], null, \"position: relative\");\n // Set to the height of the document, allowing scrolling.\n d.sizer = elt(\"div\", [d.mover], \"CodeMirror-sizer\");\n d.sizerWidth = null;\n // Behavior of elts with overflow: auto and padding is\n // inconsistent across browsers. This is used to ensure the\n // scrollable area is big enough.\n d.heightForcer = elt(\"div\", null, null, \"position: absolute; height: \" + scrollerGap + \"px; width: 1px;\");\n // Will contain the gutters, if any.\n d.gutters = elt(\"div\", null, \"CodeMirror-gutters\");\n d.lineGutter = null;\n // Actual scrollable element.\n d.scroller = elt(\"div\", [d.sizer, d.heightForcer, d.gutters], \"CodeMirror-scroll\");\n d.scroller.setAttribute(\"tabIndex\", \"-1\");\n // The element in which the editor lives.\n d.wrapper = elt(\"div\", [d.scrollbarFiller, d.gutterFiller, d.scroller], \"CodeMirror\");\n\n // Work around IE7 z-index bug (not perfect, hence IE7 not really being supported)\n if (ie && ie_version < 8) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0; }\n if (!webkit && !(gecko && mobile)) { d.scroller.draggable = true; }\n\n if (place) {\n if (place.appendChild) { place.appendChild(d.wrapper); }\n else { place(d.wrapper); }\n }\n\n // Current rendered range (may be bigger than the view window).\n d.viewFrom = d.viewTo = doc.first;\n d.reportedViewFrom = d.reportedViewTo = doc.first;\n // Information about the rendered lines.\n d.view = [];\n d.renderedView = null;\n // Holds info about a single rendered line when it was rendered\n // for measurement, while not in view.\n d.externalMeasured = null;\n // Empty space (in pixels) above the view\n d.viewOffset = 0;\n d.lastWrapHeight = d.lastWrapWidth = 0;\n d.updateLineNumbers = null;\n\n d.nativeBarWidth = d.barHeight = d.barWidth = 0;\n d.scrollbarsClipped = false;\n\n // Used to only resize the line number gutter when necessary (when\n // the amount of lines crosses a boundary that makes its width change)\n d.lineNumWidth = d.lineNumInnerWidth = d.lineNumChars = null;\n // Set to true when a non-horizontal-scrolling line widget is\n // added. As an optimization, line widget aligning is skipped when\n // this is false.\n d.alignWidgets = false;\n\n d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null;\n\n // Tracks the maximum line length so that the horizontal scrollbar\n // can be kept static when scrolling.\n d.maxLine = null;\n d.maxLineLength = 0;\n d.maxLineChanged = false;\n\n // Used for measuring wheel scrolling granularity\n d.wheelDX = d.wheelDY = d.wheelStartX = d.wheelStartY = null;\n\n // True when shift is held down.\n d.shift = false;\n\n // Used to track whether anything happened since the context menu\n // was opened.\n d.selForContextMenu = null;\n\n d.activeTouch = null;\n\n d.gutterSpecs = getGutters(options.gutters, options.lineNumbers);\n renderGutters(d);\n\n input.init(d);\n }\n\n // Since the delta values reported on mouse wheel events are\n // unstandardized between browsers and even browser versions, and\n // generally horribly unpredictable, this code starts by measuring\n // the scroll effect that the first few mouse wheel events have,\n // and, from that, detects the way it can convert deltas to pixel\n // offsets afterwards.\n //\n // The reason we want to know the amount a wheel event will scroll\n // is that it gives us a chance to update the display before the\n // actual scrolling happens, reducing flickering.\n\n var wheelSamples = 0, wheelPixelsPerUnit = null;\n // Fill in a browser-detected starting value on browsers where we\n // know one. These don't have to be accurate -- the result of them\n // being wrong would just be a slight flicker on the first wheel\n // scroll (if it is large enough).\n if (ie) { wheelPixelsPerUnit = -.53; }\n else if (gecko) { wheelPixelsPerUnit = 15; }\n else if (chrome) { wheelPixelsPerUnit = -.7; }\n else if (safari) { wheelPixelsPerUnit = -1/3; }\n\n function wheelEventDelta(e) {\n var dx = e.wheelDeltaX, dy = e.wheelDeltaY;\n if (dx == null && e.detail && e.axis == e.HORIZONTAL_AXIS) { dx = e.detail; }\n if (dy == null && e.detail && e.axis == e.VERTICAL_AXIS) { dy = e.detail; }\n else if (dy == null) { dy = e.wheelDelta; }\n return {x: dx, y: dy}\n }\n function wheelEventPixels(e) {\n var delta = wheelEventDelta(e);\n delta.x *= wheelPixelsPerUnit;\n delta.y *= wheelPixelsPerUnit;\n return delta\n }\n\n function onScrollWheel(cm, e) {\n var delta = wheelEventDelta(e), dx = delta.x, dy = delta.y;\n\n var display = cm.display, scroll = display.scroller;\n // Quit if there's nothing to scroll here\n var canScrollX = scroll.scrollWidth > scroll.clientWidth;\n var canScrollY = scroll.scrollHeight > scroll.clientHeight;\n if (!(dx && canScrollX || dy && canScrollY)) { return }\n\n // Webkit browsers on OS X abort momentum scrolls when the target\n // of the scroll event is removed from the scrollable element.\n // This hack (see related code in patchDisplay) makes sure the\n // element is kept around.\n if (dy && mac && webkit) {\n outer: for (var cur = e.target, view = display.view; cur != scroll; cur = cur.parentNode) {\n for (var i = 0; i < view.length; i++) {\n if (view[i].node == cur) {\n cm.display.currentWheelTarget = cur;\n break outer\n }\n }\n }\n }\n\n // On some browsers, horizontal scrolling will cause redraws to\n // happen before the gutter has been realigned, causing it to\n // wriggle around in a most unseemly way. When we have an\n // estimated pixels/delta value, we just handle horizontal\n // scrolling entirely here. It'll be slightly off from native, but\n // better than glitching out.\n if (dx && !gecko && !presto && wheelPixelsPerUnit != null) {\n if (dy && canScrollY)\n { updateScrollTop(cm, Math.max(0, scroll.scrollTop + dy * wheelPixelsPerUnit)); }\n setScrollLeft(cm, Math.max(0, scroll.scrollLeft + dx * wheelPixelsPerUnit));\n // Only prevent default scrolling if vertical scrolling is\n // actually possible. Otherwise, it causes vertical scroll\n // jitter on OSX trackpads when deltaX is small and deltaY\n // is large (issue #3579)\n if (!dy || (dy && canScrollY))\n { e_preventDefault(e); }\n display.wheelStartX = null; // Abort measurement, if in progress\n return\n }\n\n // 'Project' the visible viewport to cover the area that is being\n // scrolled into view (if we know enough to estimate it).\n if (dy && wheelPixelsPerUnit != null) {\n var pixels = dy * wheelPixelsPerUnit;\n var top = cm.doc.scrollTop, bot = top + display.wrapper.clientHeight;\n if (pixels < 0) { top = Math.max(0, top + pixels - 50); }\n else { bot = Math.min(cm.doc.height, bot + pixels + 50); }\n updateDisplaySimple(cm, {top: top, bottom: bot});\n }\n\n if (wheelSamples < 20) {\n if (display.wheelStartX == null) {\n display.wheelStartX = scroll.scrollLeft; display.wheelStartY = scroll.scrollTop;\n display.wheelDX = dx; display.wheelDY = dy;\n setTimeout(function () {\n if (display.wheelStartX == null) { return }\n var movedX = scroll.scrollLeft - display.wheelStartX;\n var movedY = scroll.scrollTop - display.wheelStartY;\n var sample = (movedY && display.wheelDY && movedY / display.wheelDY) ||\n (movedX && display.wheelDX && movedX / display.wheelDX);\n display.wheelStartX = display.wheelStartY = null;\n if (!sample) { return }\n wheelPixelsPerUnit = (wheelPixelsPerUnit * wheelSamples + sample) / (wheelSamples + 1);\n ++wheelSamples;\n }, 200);\n } else {\n display.wheelDX += dx; display.wheelDY += dy;\n }\n }\n }\n\n // Selection objects are immutable. A new one is created every time\n // the selection changes. A selection is one or more non-overlapping\n // (and non-touching) ranges, sorted, and an integer that indicates\n // which one is the primary selection (the one that's scrolled into\n // view, that getCursor returns, etc).\n var Selection = function(ranges, primIndex) {\n this.ranges = ranges;\n this.primIndex = primIndex;\n };\n\n Selection.prototype.primary = function () { return this.ranges[this.primIndex] };\n\n Selection.prototype.equals = function (other) {\n if (other == this) { return true }\n if (other.primIndex != this.primIndex || other.ranges.length != this.ranges.length) { return false }\n for (var i = 0; i < this.ranges.length; i++) {\n var here = this.ranges[i], there = other.ranges[i];\n if (!equalCursorPos(here.anchor, there.anchor) || !equalCursorPos(here.head, there.head)) { return false }\n }\n return true\n };\n\n Selection.prototype.deepCopy = function () {\n var out = [];\n for (var i = 0; i < this.ranges.length; i++)\n { out[i] = new Range(copyPos(this.ranges[i].anchor), copyPos(this.ranges[i].head)); }\n return new Selection(out, this.primIndex)\n };\n\n Selection.prototype.somethingSelected = function () {\n for (var i = 0; i < this.ranges.length; i++)\n { if (!this.ranges[i].empty()) { return true } }\n return false\n };\n\n Selection.prototype.contains = function (pos, end) {\n if (!end) { end = pos; }\n for (var i = 0; i < this.ranges.length; i++) {\n var range = this.ranges[i];\n if (cmp(end, range.from()) >= 0 && cmp(pos, range.to()) <= 0)\n { return i }\n }\n return -1\n };\n\n var Range = function(anchor, head) {\n this.anchor = anchor; this.head = head;\n };\n\n Range.prototype.from = function () { return minPos(this.anchor, this.head) };\n Range.prototype.to = function () { return maxPos(this.anchor, this.head) };\n Range.prototype.empty = function () { return this.head.line == this.anchor.line && this.head.ch == this.anchor.ch };\n\n // Take an unsorted, potentially overlapping set of ranges, and\n // build a selection out of it. 'Consumes' ranges array (modifying\n // it).\n function normalizeSelection(cm, ranges, primIndex) {\n var mayTouch = cm && cm.options.selectionsMayTouch;\n var prim = ranges[primIndex];\n ranges.sort(function (a, b) { return cmp(a.from(), b.from()); });\n primIndex = indexOf(ranges, prim);\n for (var i = 1; i < ranges.length; i++) {\n var cur = ranges[i], prev = ranges[i - 1];\n var diff = cmp(prev.to(), cur.from());\n if (mayTouch && !cur.empty() ? diff > 0 : diff >= 0) {\n var from = minPos(prev.from(), cur.from()), to = maxPos(prev.to(), cur.to());\n var inv = prev.empty() ? cur.from() == cur.head : prev.from() == prev.head;\n if (i <= primIndex) { --primIndex; }\n ranges.splice(--i, 2, new Range(inv ? to : from, inv ? from : to));\n }\n }\n return new Selection(ranges, primIndex)\n }\n\n function simpleSelection(anchor, head) {\n return new Selection([new Range(anchor, head || anchor)], 0)\n }\n\n // Compute the position of the end of a change (its 'to' property\n // refers to the pre-change end).\n function changeEnd(change) {\n if (!change.text) { return change.to }\n return Pos(change.from.line + change.text.length - 1,\n lst(change.text).length + (change.text.length == 1 ? change.from.ch : 0))\n }\n\n // Adjust a position to refer to the post-change position of the\n // same text, or the end of the change if the change covers it.\n function adjustForChange(pos, change) {\n if (cmp(pos, change.from) < 0) { return pos }\n if (cmp(pos, change.to) <= 0) { return changeEnd(change) }\n\n var line = pos.line + change.text.length - (change.to.line - change.from.line) - 1, ch = pos.ch;\n if (pos.line == change.to.line) { ch += changeEnd(change).ch - change.to.ch; }\n return Pos(line, ch)\n }\n\n function computeSelAfterChange(doc, change) {\n var out = [];\n for (var i = 0; i < doc.sel.ranges.length; i++) {\n var range = doc.sel.ranges[i];\n out.push(new Range(adjustForChange(range.anchor, change),\n adjustForChange(range.head, change)));\n }\n return normalizeSelection(doc.cm, out, doc.sel.primIndex)\n }\n\n function offsetPos(pos, old, nw) {\n if (pos.line == old.line)\n { return Pos(nw.line, pos.ch - old.ch + nw.ch) }\n else\n { return Pos(nw.line + (pos.line - old.line), pos.ch) }\n }\n\n // Used by replaceSelections to allow moving the selection to the\n // start or around the replaced test. Hint may be \"start\" or \"around\".\n function computeReplacedSel(doc, changes, hint) {\n var out = [];\n var oldPrev = Pos(doc.first, 0), newPrev = oldPrev;\n for (var i = 0; i < changes.length; i++) {\n var change = changes[i];\n var from = offsetPos(change.from, oldPrev, newPrev);\n var to = offsetPos(changeEnd(change), oldPrev, newPrev);\n oldPrev = change.to;\n newPrev = to;\n if (hint == \"around\") {\n var range = doc.sel.ranges[i], inv = cmp(range.head, range.anchor) < 0;\n out[i] = new Range(inv ? to : from, inv ? from : to);\n } else {\n out[i] = new Range(from, from);\n }\n }\n return new Selection(out, doc.sel.primIndex)\n }\n\n // Used to get the editor into a consistent state again when options change.\n\n function loadMode(cm) {\n cm.doc.mode = getMode(cm.options, cm.doc.modeOption);\n resetModeState(cm);\n }\n\n function resetModeState(cm) {\n cm.doc.iter(function (line) {\n if (line.stateAfter) { line.stateAfter = null; }\n if (line.styles) { line.styles = null; }\n });\n cm.doc.modeFrontier = cm.doc.highlightFrontier = cm.doc.first;\n startWorker(cm, 100);\n cm.state.modeGen++;\n if (cm.curOp) { regChange(cm); }\n }\n\n // DOCUMENT DATA STRUCTURE\n\n // By default, updates that start and end at the beginning of a line\n // are treated specially, in order to make the association of line\n // widgets and marker elements with the text behave more intuitive.\n function isWholeLineUpdate(doc, change) {\n return change.from.ch == 0 && change.to.ch == 0 && lst(change.text) == \"\" &&\n (!doc.cm || doc.cm.options.wholeLineUpdateBefore)\n }\n\n // Perform a change on the document data structure.\n function updateDoc(doc, change, markedSpans, estimateHeight) {\n function spansFor(n) {return markedSpans ? markedSpans[n] : null}\n function update(line, text, spans) {\n updateLine(line, text, spans, estimateHeight);\n signalLater(line, \"change\", line, change);\n }\n function linesFor(start, end) {\n var result = [];\n for (var i = start; i < end; ++i)\n { result.push(new Line(text[i], spansFor(i), estimateHeight)); }\n return result\n }\n\n var from = change.from, to = change.to, text = change.text;\n var firstLine = getLine(doc, from.line), lastLine = getLine(doc, to.line);\n var lastText = lst(text), lastSpans = spansFor(text.length - 1), nlines = to.line - from.line;\n\n // Adjust the line structure\n if (change.full) {\n doc.insert(0, linesFor(0, text.length));\n doc.remove(text.length, doc.size - text.length);\n } else if (isWholeLineUpdate(doc, change)) {\n // This is a whole-line replace. Treated specially to make\n // sure line objects move the way they are supposed to.\n var added = linesFor(0, text.length - 1);\n update(lastLine, lastLine.text, lastSpans);\n if (nlines) { doc.remove(from.line, nlines); }\n if (added.length) { doc.insert(from.line, added); }\n } else if (firstLine == lastLine) {\n if (text.length == 1) {\n update(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), lastSpans);\n } else {\n var added$1 = linesFor(1, text.length - 1);\n added$1.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight));\n update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0));\n doc.insert(from.line + 1, added$1);\n }\n } else if (text.length == 1) {\n update(firstLine, firstLine.text.slice(0, from.ch) + text[0] + lastLine.text.slice(to.ch), spansFor(0));\n doc.remove(from.line + 1, nlines);\n } else {\n update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0));\n update(lastLine, lastText + lastLine.text.slice(to.ch), lastSpans);\n var added$2 = linesFor(1, text.length - 1);\n if (nlines > 1) { doc.remove(from.line + 1, nlines - 1); }\n doc.insert(from.line + 1, added$2);\n }\n\n signalLater(doc, \"change\", doc, change);\n }\n\n // Call f for all linked documents.\n function linkedDocs(doc, f, sharedHistOnly) {\n function propagate(doc, skip, sharedHist) {\n if (doc.linked) { for (var i = 0; i < doc.linked.length; ++i) {\n var rel = doc.linked[i];\n if (rel.doc == skip) { continue }\n var shared = sharedHist && rel.sharedHist;\n if (sharedHistOnly && !shared) { continue }\n f(rel.doc, shared);\n propagate(rel.doc, doc, shared);\n } }\n }\n propagate(doc, null, true);\n }\n\n // Attach a document to an editor.\n function attachDoc(cm, doc) {\n if (doc.cm) { throw new Error(\"This document is already in use.\") }\n cm.doc = doc;\n doc.cm = cm;\n estimateLineHeights(cm);\n loadMode(cm);\n setDirectionClass(cm);\n if (!cm.options.lineWrapping) { findMaxLine(cm); }\n cm.options.mode = doc.modeOption;\n regChange(cm);\n }\n\n function setDirectionClass(cm) {\n (cm.doc.direction == \"rtl\" ? addClass : rmClass)(cm.display.lineDiv, \"CodeMirror-rtl\");\n }\n\n function directionChanged(cm) {\n runInOp(cm, function () {\n setDirectionClass(cm);\n regChange(cm);\n });\n }\n\n function History(startGen) {\n // Arrays of change events and selections. Doing something adds an\n // event to done and clears undo. Undoing moves events from done\n // to undone, redoing moves them in the other direction.\n this.done = []; this.undone = [];\n this.undoDepth = Infinity;\n // Used to track when changes can be merged into a single undo\n // event\n this.lastModTime = this.lastSelTime = 0;\n this.lastOp = this.lastSelOp = null;\n this.lastOrigin = this.lastSelOrigin = null;\n // Used by the isClean() method\n this.generation = this.maxGeneration = startGen || 1;\n }\n\n // Create a history change event from an updateDoc-style change\n // object.\n function historyChangeFromChange(doc, change) {\n var histChange = {from: copyPos(change.from), to: changeEnd(change), text: getBetween(doc, change.from, change.to)};\n attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1);\n linkedDocs(doc, function (doc) { return attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1); }, true);\n return histChange\n }\n\n // Pop all selection events off the end of a history array. Stop at\n // a change event.\n function clearSelectionEvents(array) {\n while (array.length) {\n var last = lst(array);\n if (last.ranges) { array.pop(); }\n else { break }\n }\n }\n\n // Find the top change event in the history. Pop off selection\n // events that are in the way.\n function lastChangeEvent(hist, force) {\n if (force) {\n clearSelectionEvents(hist.done);\n return lst(hist.done)\n } else if (hist.done.length && !lst(hist.done).ranges) {\n return lst(hist.done)\n } else if (hist.done.length > 1 && !hist.done[hist.done.length - 2].ranges) {\n hist.done.pop();\n return lst(hist.done)\n }\n }\n\n // Register a change in the history. Merges changes that are within\n // a single operation, or are close together with an origin that\n // allows merging (starting with \"+\") into a single event.\n function addChangeToHistory(doc, change, selAfter, opId) {\n var hist = doc.history;\n hist.undone.length = 0;\n var time = +new Date, cur;\n var last;\n\n if ((hist.lastOp == opId ||\n hist.lastOrigin == change.origin && change.origin &&\n ((change.origin.charAt(0) == \"+\" && hist.lastModTime > time - (doc.cm ? doc.cm.options.historyEventDelay : 500)) ||\n change.origin.charAt(0) == \"*\")) &&\n (cur = lastChangeEvent(hist, hist.lastOp == opId))) {\n // Merge this change into the last event\n last = lst(cur.changes);\n if (cmp(change.from, change.to) == 0 && cmp(change.from, last.to) == 0) {\n // Optimized case for simple insertion -- don't want to add\n // new changesets for every character typed\n last.to = changeEnd(change);\n } else {\n // Add new sub-event\n cur.changes.push(historyChangeFromChange(doc, change));\n }\n } else {\n // Can not be merged, start a new event.\n var before = lst(hist.done);\n if (!before || !before.ranges)\n { pushSelectionToHistory(doc.sel, hist.done); }\n cur = {changes: [historyChangeFromChange(doc, change)],\n generation: hist.generation};\n hist.done.push(cur);\n while (hist.done.length > hist.undoDepth) {\n hist.done.shift();\n if (!hist.done[0].ranges) { hist.done.shift(); }\n }\n }\n hist.done.push(selAfter);\n hist.generation = ++hist.maxGeneration;\n hist.lastModTime = hist.lastSelTime = time;\n hist.lastOp = hist.lastSelOp = opId;\n hist.lastOrigin = hist.lastSelOrigin = change.origin;\n\n if (!last) { signal(doc, \"historyAdded\"); }\n }\n\n function selectionEventCanBeMerged(doc, origin, prev, sel) {\n var ch = origin.charAt(0);\n return ch == \"*\" ||\n ch == \"+\" &&\n prev.ranges.length == sel.ranges.length &&\n prev.somethingSelected() == sel.somethingSelected() &&\n new Date - doc.history.lastSelTime <= (doc.cm ? doc.cm.options.historyEventDelay : 500)\n }\n\n // Called whenever the selection changes, sets the new selection as\n // the pending selection in the history, and pushes the old pending\n // selection into the 'done' array when it was significantly\n // different (in number of selected ranges, emptiness, or time).\n function addSelectionToHistory(doc, sel, opId, options) {\n var hist = doc.history, origin = options && options.origin;\n\n // A new event is started when the previous origin does not match\n // the current, or the origins don't allow matching. Origins\n // starting with * are always merged, those starting with + are\n // merged when similar and close together in time.\n if (opId == hist.lastSelOp ||\n (origin && hist.lastSelOrigin == origin &&\n (hist.lastModTime == hist.lastSelTime && hist.lastOrigin == origin ||\n selectionEventCanBeMerged(doc, origin, lst(hist.done), sel))))\n { hist.done[hist.done.length - 1] = sel; }\n else\n { pushSelectionToHistory(sel, hist.done); }\n\n hist.lastSelTime = +new Date;\n hist.lastSelOrigin = origin;\n hist.lastSelOp = opId;\n if (options && options.clearRedo !== false)\n { clearSelectionEvents(hist.undone); }\n }\n\n function pushSelectionToHistory(sel, dest) {\n var top = lst(dest);\n if (!(top && top.ranges && top.equals(sel)))\n { dest.push(sel); }\n }\n\n // Used to store marked span information in the history.\n function attachLocalSpans(doc, change, from, to) {\n var existing = change[\"spans_\" + doc.id], n = 0;\n doc.iter(Math.max(doc.first, from), Math.min(doc.first + doc.size, to), function (line) {\n if (line.markedSpans)\n { (existing || (existing = change[\"spans_\" + doc.id] = {}))[n] = line.markedSpans; }\n ++n;\n });\n }\n\n // When un/re-doing restores text containing marked spans, those\n // that have been explicitly cleared should not be restored.\n function removeClearedSpans(spans) {\n if (!spans) { return null }\n var out;\n for (var i = 0; i < spans.length; ++i) {\n if (spans[i].marker.explicitlyCleared) { if (!out) { out = spans.slice(0, i); } }\n else if (out) { out.push(spans[i]); }\n }\n return !out ? spans : out.length ? out : null\n }\n\n // Retrieve and filter the old marked spans stored in a change event.\n function getOldSpans(doc, change) {\n var found = change[\"spans_\" + doc.id];\n if (!found) { return null }\n var nw = [];\n for (var i = 0; i < change.text.length; ++i)\n { nw.push(removeClearedSpans(found[i])); }\n return nw\n }\n\n // Used for un/re-doing changes from the history. Combines the\n // result of computing the existing spans with the set of spans that\n // existed in the history (so that deleting around a span and then\n // undoing brings back the span).\n function mergeOldSpans(doc, change) {\n var old = getOldSpans(doc, change);\n var stretched = stretchSpansOverChange(doc, change);\n if (!old) { return stretched }\n if (!stretched) { return old }\n\n for (var i = 0; i < old.length; ++i) {\n var oldCur = old[i], stretchCur = stretched[i];\n if (oldCur && stretchCur) {\n spans: for (var j = 0; j < stretchCur.length; ++j) {\n var span = stretchCur[j];\n for (var k = 0; k < oldCur.length; ++k)\n { if (oldCur[k].marker == span.marker) { continue spans } }\n oldCur.push(span);\n }\n } else if (stretchCur) {\n old[i] = stretchCur;\n }\n }\n return old\n }\n\n // Used both to provide a JSON-safe object in .getHistory, and, when\n // detaching a document, to split the history in two\n function copyHistoryArray(events, newGroup, instantiateSel) {\n var copy = [];\n for (var i = 0; i < events.length; ++i) {\n var event = events[i];\n if (event.ranges) {\n copy.push(instantiateSel ? Selection.prototype.deepCopy.call(event) : event);\n continue\n }\n var changes = event.changes, newChanges = [];\n copy.push({changes: newChanges});\n for (var j = 0; j < changes.length; ++j) {\n var change = changes[j], m = (void 0);\n newChanges.push({from: change.from, to: change.to, text: change.text});\n if (newGroup) { for (var prop in change) { if (m = prop.match(/^spans_(\\d+)$/)) {\n if (indexOf(newGroup, Number(m[1])) > -1) {\n lst(newChanges)[prop] = change[prop];\n delete change[prop];\n }\n } } }\n }\n }\n return copy\n }\n\n // The 'scroll' parameter given to many of these indicated whether\n // the new cursor position should be scrolled into view after\n // modifying the selection.\n\n // If shift is held or the extend flag is set, extends a range to\n // include a given position (and optionally a second position).\n // Otherwise, simply returns the range between the given positions.\n // Used for cursor motion and such.\n function extendRange(range, head, other, extend) {\n if (extend) {\n var anchor = range.anchor;\n if (other) {\n var posBefore = cmp(head, anchor) < 0;\n if (posBefore != (cmp(other, anchor) < 0)) {\n anchor = head;\n head = other;\n } else if (posBefore != (cmp(head, other) < 0)) {\n head = other;\n }\n }\n return new Range(anchor, head)\n } else {\n return new Range(other || head, head)\n }\n }\n\n // Extend the primary selection range, discard the rest.\n function extendSelection(doc, head, other, options, extend) {\n if (extend == null) { extend = doc.cm && (doc.cm.display.shift || doc.extend); }\n setSelection(doc, new Selection([extendRange(doc.sel.primary(), head, other, extend)], 0), options);\n }\n\n // Extend all selections (pos is an array of selections with length\n // equal the number of selections)\n function extendSelections(doc, heads, options) {\n var out = [];\n var extend = doc.cm && (doc.cm.display.shift || doc.extend);\n for (var i = 0; i < doc.sel.ranges.length; i++)\n { out[i] = extendRange(doc.sel.ranges[i], heads[i], null, extend); }\n var newSel = normalizeSelection(doc.cm, out, doc.sel.primIndex);\n setSelection(doc, newSel, options);\n }\n\n // Updates a single range in the selection.\n function replaceOneSelection(doc, i, range, options) {\n var ranges = doc.sel.ranges.slice(0);\n ranges[i] = range;\n setSelection(doc, normalizeSelection(doc.cm, ranges, doc.sel.primIndex), options);\n }\n\n // Reset the selection to a single range.\n function setSimpleSelection(doc, anchor, head, options) {\n setSelection(doc, simpleSelection(anchor, head), options);\n }\n\n // Give beforeSelectionChange handlers a change to influence a\n // selection update.\n function filterSelectionChange(doc, sel, options) {\n var obj = {\n ranges: sel.ranges,\n update: function(ranges) {\n this.ranges = [];\n for (var i = 0; i < ranges.length; i++)\n { this.ranges[i] = new Range(clipPos(doc, ranges[i].anchor),\n clipPos(doc, ranges[i].head)); }\n },\n origin: options && options.origin\n };\n signal(doc, \"beforeSelectionChange\", doc, obj);\n if (doc.cm) { signal(doc.cm, \"beforeSelectionChange\", doc.cm, obj); }\n if (obj.ranges != sel.ranges) { return normalizeSelection(doc.cm, obj.ranges, obj.ranges.length - 1) }\n else { return sel }\n }\n\n function setSelectionReplaceHistory(doc, sel, options) {\n var done = doc.history.done, last = lst(done);\n if (last && last.ranges) {\n done[done.length - 1] = sel;\n setSelectionNoUndo(doc, sel, options);\n } else {\n setSelection(doc, sel, options);\n }\n }\n\n // Set a new selection.\n function setSelection(doc, sel, options) {\n setSelectionNoUndo(doc, sel, options);\n addSelectionToHistory(doc, doc.sel, doc.cm ? doc.cm.curOp.id : NaN, options);\n }\n\n function setSelectionNoUndo(doc, sel, options) {\n if (hasHandler(doc, \"beforeSelectionChange\") || doc.cm && hasHandler(doc.cm, \"beforeSelectionChange\"))\n { sel = filterSelectionChange(doc, sel, options); }\n\n var bias = options && options.bias ||\n (cmp(sel.primary().head, doc.sel.primary().head) < 0 ? -1 : 1);\n setSelectionInner(doc, skipAtomicInSelection(doc, sel, bias, true));\n\n if (!(options && options.scroll === false) && doc.cm)\n { ensureCursorVisible(doc.cm); }\n }\n\n function setSelectionInner(doc, sel) {\n if (sel.equals(doc.sel)) { return }\n\n doc.sel = sel;\n\n if (doc.cm) {\n doc.cm.curOp.updateInput = 1;\n doc.cm.curOp.selectionChanged = true;\n signalCursorActivity(doc.cm);\n }\n signalLater(doc, \"cursorActivity\", doc);\n }\n\n // Verify that the selection does not partially select any atomic\n // marked ranges.\n function reCheckSelection(doc) {\n setSelectionInner(doc, skipAtomicInSelection(doc, doc.sel, null, false));\n }\n\n // Return a selection that does not partially select any atomic\n // ranges.\n function skipAtomicInSelection(doc, sel, bias, mayClear) {\n var out;\n for (var i = 0; i < sel.ranges.length; i++) {\n var range = sel.ranges[i];\n var old = sel.ranges.length == doc.sel.ranges.length && doc.sel.ranges[i];\n var newAnchor = skipAtomic(doc, range.anchor, old && old.anchor, bias, mayClear);\n var newHead = skipAtomic(doc, range.head, old && old.head, bias, mayClear);\n if (out || newAnchor != range.anchor || newHead != range.head) {\n if (!out) { out = sel.ranges.slice(0, i); }\n out[i] = new Range(newAnchor, newHead);\n }\n }\n return out ? normalizeSelection(doc.cm, out, sel.primIndex) : sel\n }\n\n function skipAtomicInner(doc, pos, oldPos, dir, mayClear) {\n var line = getLine(doc, pos.line);\n if (line.markedSpans) { for (var i = 0; i < line.markedSpans.length; ++i) {\n var sp = line.markedSpans[i], m = sp.marker;\n\n // Determine if we should prevent the cursor being placed to the left/right of an atomic marker\n // Historically this was determined using the inclusiveLeft/Right option, but the new way to control it\n // is with selectLeft/Right\n var preventCursorLeft = (\"selectLeft\" in m) ? !m.selectLeft : m.inclusiveLeft;\n var preventCursorRight = (\"selectRight\" in m) ? !m.selectRight : m.inclusiveRight;\n\n if ((sp.from == null || (preventCursorLeft ? sp.from <= pos.ch : sp.from < pos.ch)) &&\n (sp.to == null || (preventCursorRight ? sp.to >= pos.ch : sp.to > pos.ch))) {\n if (mayClear) {\n signal(m, \"beforeCursorEnter\");\n if (m.explicitlyCleared) {\n if (!line.markedSpans) { break }\n else {--i; continue}\n }\n }\n if (!m.atomic) { continue }\n\n if (oldPos) {\n var near = m.find(dir < 0 ? 1 : -1), diff = (void 0);\n if (dir < 0 ? preventCursorRight : preventCursorLeft)\n { near = movePos(doc, near, -dir, near && near.line == pos.line ? line : null); }\n if (near && near.line == pos.line && (diff = cmp(near, oldPos)) && (dir < 0 ? diff < 0 : diff > 0))\n { return skipAtomicInner(doc, near, pos, dir, mayClear) }\n }\n\n var far = m.find(dir < 0 ? -1 : 1);\n if (dir < 0 ? preventCursorLeft : preventCursorRight)\n { far = movePos(doc, far, dir, far.line == pos.line ? line : null); }\n return far ? skipAtomicInner(doc, far, pos, dir, mayClear) : null\n }\n } }\n return pos\n }\n\n // Ensure a given position is not inside an atomic range.\n function skipAtomic(doc, pos, oldPos, bias, mayClear) {\n var dir = bias || 1;\n var found = skipAtomicInner(doc, pos, oldPos, dir, mayClear) ||\n (!mayClear && skipAtomicInner(doc, pos, oldPos, dir, true)) ||\n skipAtomicInner(doc, pos, oldPos, -dir, mayClear) ||\n (!mayClear && skipAtomicInner(doc, pos, oldPos, -dir, true));\n if (!found) {\n doc.cantEdit = true;\n return Pos(doc.first, 0)\n }\n return found\n }\n\n function movePos(doc, pos, dir, line) {\n if (dir < 0 && pos.ch == 0) {\n if (pos.line > doc.first) { return clipPos(doc, Pos(pos.line - 1)) }\n else { return null }\n } else if (dir > 0 && pos.ch == (line || getLine(doc, pos.line)).text.length) {\n if (pos.line < doc.first + doc.size - 1) { return Pos(pos.line + 1, 0) }\n else { return null }\n } else {\n return new Pos(pos.line, pos.ch + dir)\n }\n }\n\n function selectAll(cm) {\n cm.setSelection(Pos(cm.firstLine(), 0), Pos(cm.lastLine()), sel_dontScroll);\n }\n\n // UPDATING\n\n // Allow \"beforeChange\" event handlers to influence a change\n function filterChange(doc, change, update) {\n var obj = {\n canceled: false,\n from: change.from,\n to: change.to,\n text: change.text,\n origin: change.origin,\n cancel: function () { return obj.canceled = true; }\n };\n if (update) { obj.update = function (from, to, text, origin) {\n if (from) { obj.from = clipPos(doc, from); }\n if (to) { obj.to = clipPos(doc, to); }\n if (text) { obj.text = text; }\n if (origin !== undefined) { obj.origin = origin; }\n }; }\n signal(doc, \"beforeChange\", doc, obj);\n if (doc.cm) { signal(doc.cm, \"beforeChange\", doc.cm, obj); }\n\n if (obj.canceled) {\n if (doc.cm) { doc.cm.curOp.updateInput = 2; }\n return null\n }\n return {from: obj.from, to: obj.to, text: obj.text, origin: obj.origin}\n }\n\n // Apply a change to a document, and add it to the document's\n // history, and propagating it to all linked documents.\n function makeChange(doc, change, ignoreReadOnly) {\n if (doc.cm) {\n if (!doc.cm.curOp) { return operation(doc.cm, makeChange)(doc, change, ignoreReadOnly) }\n if (doc.cm.state.suppressEdits) { return }\n }\n\n if (hasHandler(doc, \"beforeChange\") || doc.cm && hasHandler(doc.cm, \"beforeChange\")) {\n change = filterChange(doc, change, true);\n if (!change) { return }\n }\n\n // Possibly split or suppress the update based on the presence\n // of read-only spans in its range.\n var split = sawReadOnlySpans && !ignoreReadOnly && removeReadOnlyRanges(doc, change.from, change.to);\n if (split) {\n for (var i = split.length - 1; i >= 0; --i)\n { makeChangeInner(doc, {from: split[i].from, to: split[i].to, text: i ? [\"\"] : change.text, origin: change.origin}); }\n } else {\n makeChangeInner(doc, change);\n }\n }\n\n function makeChangeInner(doc, change) {\n if (change.text.length == 1 && change.text[0] == \"\" && cmp(change.from, change.to) == 0) { return }\n var selAfter = computeSelAfterChange(doc, change);\n addChangeToHistory(doc, change, selAfter, doc.cm ? doc.cm.curOp.id : NaN);\n\n makeChangeSingleDoc(doc, change, selAfter, stretchSpansOverChange(doc, change));\n var rebased = [];\n\n linkedDocs(doc, function (doc, sharedHist) {\n if (!sharedHist && indexOf(rebased, doc.history) == -1) {\n rebaseHist(doc.history, change);\n rebased.push(doc.history);\n }\n makeChangeSingleDoc(doc, change, null, stretchSpansOverChange(doc, change));\n });\n }\n\n // Revert a change stored in a document's history.\n function makeChangeFromHistory(doc, type, allowSelectionOnly) {\n var suppress = doc.cm && doc.cm.state.suppressEdits;\n if (suppress && !allowSelectionOnly) { return }\n\n var hist = doc.history, event, selAfter = doc.sel;\n var source = type == \"undo\" ? hist.done : hist.undone, dest = type == \"undo\" ? hist.undone : hist.done;\n\n // Verify that there is a useable event (so that ctrl-z won't\n // needlessly clear selection events)\n var i = 0;\n for (; i < source.length; i++) {\n event = source[i];\n if (allowSelectionOnly ? event.ranges && !event.equals(doc.sel) : !event.ranges)\n { break }\n }\n if (i == source.length) { return }\n hist.lastOrigin = hist.lastSelOrigin = null;\n\n for (;;) {\n event = source.pop();\n if (event.ranges) {\n pushSelectionToHistory(event, dest);\n if (allowSelectionOnly && !event.equals(doc.sel)) {\n setSelection(doc, event, {clearRedo: false});\n return\n }\n selAfter = event;\n } else if (suppress) {\n source.push(event);\n return\n } else { break }\n }\n\n // Build up a reverse change object to add to the opposite history\n // stack (redo when undoing, and vice versa).\n var antiChanges = [];\n pushSelectionToHistory(selAfter, dest);\n dest.push({changes: antiChanges, generation: hist.generation});\n hist.generation = event.generation || ++hist.maxGeneration;\n\n var filter = hasHandler(doc, \"beforeChange\") || doc.cm && hasHandler(doc.cm, \"beforeChange\");\n\n var loop = function ( i ) {\n var change = event.changes[i];\n change.origin = type;\n if (filter && !filterChange(doc, change, false)) {\n source.length = 0;\n return {}\n }\n\n antiChanges.push(historyChangeFromChange(doc, change));\n\n var after = i ? computeSelAfterChange(doc, change) : lst(source);\n makeChangeSingleDoc(doc, change, after, mergeOldSpans(doc, change));\n if (!i && doc.cm) { doc.cm.scrollIntoView({from: change.from, to: changeEnd(change)}); }\n var rebased = [];\n\n // Propagate to the linked documents\n linkedDocs(doc, function (doc, sharedHist) {\n if (!sharedHist && indexOf(rebased, doc.history) == -1) {\n rebaseHist(doc.history, change);\n rebased.push(doc.history);\n }\n makeChangeSingleDoc(doc, change, null, mergeOldSpans(doc, change));\n });\n };\n\n for (var i$1 = event.changes.length - 1; i$1 >= 0; --i$1) {\n var returned = loop( i$1 );\n\n if ( returned ) return returned.v;\n }\n }\n\n // Sub-views need their line numbers shifted when text is added\n // above or below them in the parent document.\n function shiftDoc(doc, distance) {\n if (distance == 0) { return }\n doc.first += distance;\n doc.sel = new Selection(map(doc.sel.ranges, function (range) { return new Range(\n Pos(range.anchor.line + distance, range.anchor.ch),\n Pos(range.head.line + distance, range.head.ch)\n ); }), doc.sel.primIndex);\n if (doc.cm) {\n regChange(doc.cm, doc.first, doc.first - distance, distance);\n for (var d = doc.cm.display, l = d.viewFrom; l < d.viewTo; l++)\n { regLineChange(doc.cm, l, \"gutter\"); }\n }\n }\n\n // More lower-level change function, handling only a single document\n // (not linked ones).\n function makeChangeSingleDoc(doc, change, selAfter, spans) {\n if (doc.cm && !doc.cm.curOp)\n { return operation(doc.cm, makeChangeSingleDoc)(doc, change, selAfter, spans) }\n\n if (change.to.line < doc.first) {\n shiftDoc(doc, change.text.length - 1 - (change.to.line - change.from.line));\n return\n }\n if (change.from.line > doc.lastLine()) { return }\n\n // Clip the change to the size of this doc\n if (change.from.line < doc.first) {\n var shift = change.text.length - 1 - (doc.first - change.from.line);\n shiftDoc(doc, shift);\n change = {from: Pos(doc.first, 0), to: Pos(change.to.line + shift, change.to.ch),\n text: [lst(change.text)], origin: change.origin};\n }\n var last = doc.lastLine();\n if (change.to.line > last) {\n change = {from: change.from, to: Pos(last, getLine(doc, last).text.length),\n text: [change.text[0]], origin: change.origin};\n }\n\n change.removed = getBetween(doc, change.from, change.to);\n\n if (!selAfter) { selAfter = computeSelAfterChange(doc, change); }\n if (doc.cm) { makeChangeSingleDocInEditor(doc.cm, change, spans); }\n else { updateDoc(doc, change, spans); }\n setSelectionNoUndo(doc, selAfter, sel_dontScroll);\n\n if (doc.cantEdit && skipAtomic(doc, Pos(doc.firstLine(), 0)))\n { doc.cantEdit = false; }\n }\n\n // Handle the interaction of a change to a document with the editor\n // that this document is part of.\n function makeChangeSingleDocInEditor(cm, change, spans) {\n var doc = cm.doc, display = cm.display, from = change.from, to = change.to;\n\n var recomputeMaxLength = false, checkWidthStart = from.line;\n if (!cm.options.lineWrapping) {\n checkWidthStart = lineNo(visualLine(getLine(doc, from.line)));\n doc.iter(checkWidthStart, to.line + 1, function (line) {\n if (line == display.maxLine) {\n recomputeMaxLength = true;\n return true\n }\n });\n }\n\n if (doc.sel.contains(change.from, change.to) > -1)\n { signalCursorActivity(cm); }\n\n updateDoc(doc, change, spans, estimateHeight(cm));\n\n if (!cm.options.lineWrapping) {\n doc.iter(checkWidthStart, from.line + change.text.length, function (line) {\n var len = lineLength(line);\n if (len > display.maxLineLength) {\n display.maxLine = line;\n display.maxLineLength = len;\n display.maxLineChanged = true;\n recomputeMaxLength = false;\n }\n });\n if (recomputeMaxLength) { cm.curOp.updateMaxLine = true; }\n }\n\n retreatFrontier(doc, from.line);\n startWorker(cm, 400);\n\n var lendiff = change.text.length - (to.line - from.line) - 1;\n // Remember that these lines changed, for updating the display\n if (change.full)\n { regChange(cm); }\n else if (from.line == to.line && change.text.length == 1 && !isWholeLineUpdate(cm.doc, change))\n { regLineChange(cm, from.line, \"text\"); }\n else\n { regChange(cm, from.line, to.line + 1, lendiff); }\n\n var changesHandler = hasHandler(cm, \"changes\"), changeHandler = hasHandler(cm, \"change\");\n if (changeHandler || changesHandler) {\n var obj = {\n from: from, to: to,\n text: change.text,\n removed: change.removed,\n origin: change.origin\n };\n if (changeHandler) { signalLater(cm, \"change\", cm, obj); }\n if (changesHandler) { (cm.curOp.changeObjs || (cm.curOp.changeObjs = [])).push(obj); }\n }\n cm.display.selForContextMenu = null;\n }\n\n function replaceRange(doc, code, from, to, origin) {\n var assign;\n\n if (!to) { to = from; }\n if (cmp(to, from) < 0) { (assign = [to, from], from = assign[0], to = assign[1]); }\n if (typeof code == \"string\") { code = doc.splitLines(code); }\n makeChange(doc, {from: from, to: to, text: code, origin: origin});\n }\n\n // Rebasing/resetting history to deal with externally-sourced changes\n\n function rebaseHistSelSingle(pos, from, to, diff) {\n if (to < pos.line) {\n pos.line += diff;\n } else if (from < pos.line) {\n pos.line = from;\n pos.ch = 0;\n }\n }\n\n // Tries to rebase an array of history events given a change in the\n // document. If the change touches the same lines as the event, the\n // event, and everything 'behind' it, is discarded. If the change is\n // before the event, the event's positions are updated. Uses a\n // copy-on-write scheme for the positions, to avoid having to\n // reallocate them all on every rebase, but also avoid problems with\n // shared position objects being unsafely updated.\n function rebaseHistArray(array, from, to, diff) {\n for (var i = 0; i < array.length; ++i) {\n var sub = array[i], ok = true;\n if (sub.ranges) {\n if (!sub.copied) { sub = array[i] = sub.deepCopy(); sub.copied = true; }\n for (var j = 0; j < sub.ranges.length; j++) {\n rebaseHistSelSingle(sub.ranges[j].anchor, from, to, diff);\n rebaseHistSelSingle(sub.ranges[j].head, from, to, diff);\n }\n continue\n }\n for (var j$1 = 0; j$1 < sub.changes.length; ++j$1) {\n var cur = sub.changes[j$1];\n if (to < cur.from.line) {\n cur.from = Pos(cur.from.line + diff, cur.from.ch);\n cur.to = Pos(cur.to.line + diff, cur.to.ch);\n } else if (from <= cur.to.line) {\n ok = false;\n break\n }\n }\n if (!ok) {\n array.splice(0, i + 1);\n i = 0;\n }\n }\n }\n\n function rebaseHist(hist, change) {\n var from = change.from.line, to = change.to.line, diff = change.text.length - (to - from) - 1;\n rebaseHistArray(hist.done, from, to, diff);\n rebaseHistArray(hist.undone, from, to, diff);\n }\n\n // Utility for applying a change to a line by handle or number,\n // returning the number and optionally registering the line as\n // changed.\n function changeLine(doc, handle, changeType, op) {\n var no = handle, line = handle;\n if (typeof handle == \"number\") { line = getLine(doc, clipLine(doc, handle)); }\n else { no = lineNo(handle); }\n if (no == null) { return null }\n if (op(line, no) && doc.cm) { regLineChange(doc.cm, no, changeType); }\n return line\n }\n\n // The document is represented as a BTree consisting of leaves, with\n // chunk of lines in them, and branches, with up to ten leaves or\n // other branch nodes below them. The top node is always a branch\n // node, and is the document object itself (meaning it has\n // additional methods and properties).\n //\n // All nodes have parent links. The tree is used both to go from\n // line numbers to line objects, and to go from objects to numbers.\n // It also indexes by height, and is used to convert between height\n // and line object, and to find the total height of the document.\n //\n // See also http://marijnhaverbeke.nl/blog/codemirror-line-tree.html\n\n function LeafChunk(lines) {\n this.lines = lines;\n this.parent = null;\n var height = 0;\n for (var i = 0; i < lines.length; ++i) {\n lines[i].parent = this;\n height += lines[i].height;\n }\n this.height = height;\n }\n\n LeafChunk.prototype = {\n chunkSize: function() { return this.lines.length },\n\n // Remove the n lines at offset 'at'.\n removeInner: function(at, n) {\n for (var i = at, e = at + n; i < e; ++i) {\n var line = this.lines[i];\n this.height -= line.height;\n cleanUpLine(line);\n signalLater(line, \"delete\");\n }\n this.lines.splice(at, n);\n },\n\n // Helper used to collapse a small branch into a single leaf.\n collapse: function(lines) {\n lines.push.apply(lines, this.lines);\n },\n\n // Insert the given array of lines at offset 'at', count them as\n // having the given height.\n insertInner: function(at, lines, height) {\n this.height += height;\n this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at));\n for (var i = 0; i < lines.length; ++i) { lines[i].parent = this; }\n },\n\n // Used to iterate over a part of the tree.\n iterN: function(at, n, op) {\n for (var e = at + n; at < e; ++at)\n { if (op(this.lines[at])) { return true } }\n }\n };\n\n function BranchChunk(children) {\n this.children = children;\n var size = 0, height = 0;\n for (var i = 0; i < children.length; ++i) {\n var ch = children[i];\n size += ch.chunkSize(); height += ch.height;\n ch.parent = this;\n }\n this.size = size;\n this.height = height;\n this.parent = null;\n }\n\n BranchChunk.prototype = {\n chunkSize: function() { return this.size },\n\n removeInner: function(at, n) {\n this.size -= n;\n for (var i = 0; i < this.children.length; ++i) {\n var child = this.children[i], sz = child.chunkSize();\n if (at < sz) {\n var rm = Math.min(n, sz - at), oldHeight = child.height;\n child.removeInner(at, rm);\n this.height -= oldHeight - child.height;\n if (sz == rm) { this.children.splice(i--, 1); child.parent = null; }\n if ((n -= rm) == 0) { break }\n at = 0;\n } else { at -= sz; }\n }\n // If the result is smaller than 25 lines, ensure that it is a\n // single leaf node.\n if (this.size - n < 25 &&\n (this.children.length > 1 || !(this.children[0] instanceof LeafChunk))) {\n var lines = [];\n this.collapse(lines);\n this.children = [new LeafChunk(lines)];\n this.children[0].parent = this;\n }\n },\n\n collapse: function(lines) {\n for (var i = 0; i < this.children.length; ++i) { this.children[i].collapse(lines); }\n },\n\n insertInner: function(at, lines, height) {\n this.size += lines.length;\n this.height += height;\n for (var i = 0; i < this.children.length; ++i) {\n var child = this.children[i], sz = child.chunkSize();\n if (at <= sz) {\n child.insertInner(at, lines, height);\n if (child.lines && child.lines.length > 50) {\n // To avoid memory thrashing when child.lines is huge (e.g. first view of a large file), it's never spliced.\n // Instead, small slices are taken. They're taken in order because sequential memory accesses are fastest.\n var remaining = child.lines.length % 25 + 25;\n for (var pos = remaining; pos < child.lines.length;) {\n var leaf = new LeafChunk(child.lines.slice(pos, pos += 25));\n child.height -= leaf.height;\n this.children.splice(++i, 0, leaf);\n leaf.parent = this;\n }\n child.lines = child.lines.slice(0, remaining);\n this.maybeSpill();\n }\n break\n }\n at -= sz;\n }\n },\n\n // When a node has grown, check whether it should be split.\n maybeSpill: function() {\n if (this.children.length <= 10) { return }\n var me = this;\n do {\n var spilled = me.children.splice(me.children.length - 5, 5);\n var sibling = new BranchChunk(spilled);\n if (!me.parent) { // Become the parent node\n var copy = new BranchChunk(me.children);\n copy.parent = me;\n me.children = [copy, sibling];\n me = copy;\n } else {\n me.size -= sibling.size;\n me.height -= sibling.height;\n var myIndex = indexOf(me.parent.children, me);\n me.parent.children.splice(myIndex + 1, 0, sibling);\n }\n sibling.parent = me.parent;\n } while (me.children.length > 10)\n me.parent.maybeSpill();\n },\n\n iterN: function(at, n, op) {\n for (var i = 0; i < this.children.length; ++i) {\n var child = this.children[i], sz = child.chunkSize();\n if (at < sz) {\n var used = Math.min(n, sz - at);\n if (child.iterN(at, used, op)) { return true }\n if ((n -= used) == 0) { break }\n at = 0;\n } else { at -= sz; }\n }\n }\n };\n\n // Line widgets are block elements displayed above or below a line.\n\n var LineWidget = function(doc, node, options) {\n if (options) { for (var opt in options) { if (options.hasOwnProperty(opt))\n { this[opt] = options[opt]; } } }\n this.doc = doc;\n this.node = node;\n };\n\n LineWidget.prototype.clear = function () {\n var cm = this.doc.cm, ws = this.line.widgets, line = this.line, no = lineNo(line);\n if (no == null || !ws) { return }\n for (var i = 0; i < ws.length; ++i) { if (ws[i] == this) { ws.splice(i--, 1); } }\n if (!ws.length) { line.widgets = null; }\n var height = widgetHeight(this);\n updateLineHeight(line, Math.max(0, line.height - height));\n if (cm) {\n runInOp(cm, function () {\n adjustScrollWhenAboveVisible(cm, line, -height);\n regLineChange(cm, no, \"widget\");\n });\n signalLater(cm, \"lineWidgetCleared\", cm, this, no);\n }\n };\n\n LineWidget.prototype.changed = function () {\n var this$1 = this;\n\n var oldH = this.height, cm = this.doc.cm, line = this.line;\n this.height = null;\n var diff = widgetHeight(this) - oldH;\n if (!diff) { return }\n if (!lineIsHidden(this.doc, line)) { updateLineHeight(line, line.height + diff); }\n if (cm) {\n runInOp(cm, function () {\n cm.curOp.forceUpdate = true;\n adjustScrollWhenAboveVisible(cm, line, diff);\n signalLater(cm, \"lineWidgetChanged\", cm, this$1, lineNo(line));\n });\n }\n };\n eventMixin(LineWidget);\n\n function adjustScrollWhenAboveVisible(cm, line, diff) {\n if (heightAtLine(line) < ((cm.curOp && cm.curOp.scrollTop) || cm.doc.scrollTop))\n { addToScrollTop(cm, diff); }\n }\n\n function addLineWidget(doc, handle, node, options) {\n var widget = new LineWidget(doc, node, options);\n var cm = doc.cm;\n if (cm && widget.noHScroll) { cm.display.alignWidgets = true; }\n changeLine(doc, handle, \"widget\", function (line) {\n var widgets = line.widgets || (line.widgets = []);\n if (widget.insertAt == null) { widgets.push(widget); }\n else { widgets.splice(Math.min(widgets.length - 1, Math.max(0, widget.insertAt)), 0, widget); }\n widget.line = line;\n if (cm && !lineIsHidden(doc, line)) {\n var aboveVisible = heightAtLine(line) < doc.scrollTop;\n updateLineHeight(line, line.height + widgetHeight(widget));\n if (aboveVisible) { addToScrollTop(cm, widget.height); }\n cm.curOp.forceUpdate = true;\n }\n return true\n });\n if (cm) { signalLater(cm, \"lineWidgetAdded\", cm, widget, typeof handle == \"number\" ? handle : lineNo(handle)); }\n return widget\n }\n\n // TEXTMARKERS\n\n // Created with markText and setBookmark methods. A TextMarker is a\n // handle that can be used to clear or find a marked position in the\n // document. Line objects hold arrays (markedSpans) containing\n // {from, to, marker} object pointing to such marker objects, and\n // indicating that such a marker is present on that line. Multiple\n // lines may point to the same marker when it spans across lines.\n // The spans will have null for their from/to properties when the\n // marker continues beyond the start/end of the line. Markers have\n // links back to the lines they currently touch.\n\n // Collapsed markers have unique ids, in order to be able to order\n // them, which is needed for uniquely determining an outer marker\n // when they overlap (they may nest, but not partially overlap).\n var nextMarkerId = 0;\n\n var TextMarker = function(doc, type) {\n this.lines = [];\n this.type = type;\n this.doc = doc;\n this.id = ++nextMarkerId;\n };\n\n // Clear the marker.\n TextMarker.prototype.clear = function () {\n if (this.explicitlyCleared) { return }\n var cm = this.doc.cm, withOp = cm && !cm.curOp;\n if (withOp) { startOperation(cm); }\n if (hasHandler(this, \"clear\")) {\n var found = this.find();\n if (found) { signalLater(this, \"clear\", found.from, found.to); }\n }\n var min = null, max = null;\n for (var i = 0; i < this.lines.length; ++i) {\n var line = this.lines[i];\n var span = getMarkedSpanFor(line.markedSpans, this);\n if (cm && !this.collapsed) { regLineChange(cm, lineNo(line), \"text\"); }\n else if (cm) {\n if (span.to != null) { max = lineNo(line); }\n if (span.from != null) { min = lineNo(line); }\n }\n line.markedSpans = removeMarkedSpan(line.markedSpans, span);\n if (span.from == null && this.collapsed && !lineIsHidden(this.doc, line) && cm)\n { updateLineHeight(line, textHeight(cm.display)); }\n }\n if (cm && this.collapsed && !cm.options.lineWrapping) { for (var i$1 = 0; i$1 < this.lines.length; ++i$1) {\n var visual = visualLine(this.lines[i$1]), len = lineLength(visual);\n if (len > cm.display.maxLineLength) {\n cm.display.maxLine = visual;\n cm.display.maxLineLength = len;\n cm.display.maxLineChanged = true;\n }\n } }\n\n if (min != null && cm && this.collapsed) { regChange(cm, min, max + 1); }\n this.lines.length = 0;\n this.explicitlyCleared = true;\n if (this.atomic && this.doc.cantEdit) {\n this.doc.cantEdit = false;\n if (cm) { reCheckSelection(cm.doc); }\n }\n if (cm) { signalLater(cm, \"markerCleared\", cm, this, min, max); }\n if (withOp) { endOperation(cm); }\n if (this.parent) { this.parent.clear(); }\n };\n\n // Find the position of the marker in the document. Returns a {from,\n // to} object by default. Side can be passed to get a specific side\n // -- 0 (both), -1 (left), or 1 (right). When lineObj is true, the\n // Pos objects returned contain a line object, rather than a line\n // number (used to prevent looking up the same line twice).\n TextMarker.prototype.find = function (side, lineObj) {\n if (side == null && this.type == \"bookmark\") { side = 1; }\n var from, to;\n for (var i = 0; i < this.lines.length; ++i) {\n var line = this.lines[i];\n var span = getMarkedSpanFor(line.markedSpans, this);\n if (span.from != null) {\n from = Pos(lineObj ? line : lineNo(line), span.from);\n if (side == -1) { return from }\n }\n if (span.to != null) {\n to = Pos(lineObj ? line : lineNo(line), span.to);\n if (side == 1) { return to }\n }\n }\n return from && {from: from, to: to}\n };\n\n // Signals that the marker's widget changed, and surrounding layout\n // should be recomputed.\n TextMarker.prototype.changed = function () {\n var this$1 = this;\n\n var pos = this.find(-1, true), widget = this, cm = this.doc.cm;\n if (!pos || !cm) { return }\n runInOp(cm, function () {\n var line = pos.line, lineN = lineNo(pos.line);\n var view = findViewForLine(cm, lineN);\n if (view) {\n clearLineMeasurementCacheFor(view);\n cm.curOp.selectionChanged = cm.curOp.forceUpdate = true;\n }\n cm.curOp.updateMaxLine = true;\n if (!lineIsHidden(widget.doc, line) && widget.height != null) {\n var oldHeight = widget.height;\n widget.height = null;\n var dHeight = widgetHeight(widget) - oldHeight;\n if (dHeight)\n { updateLineHeight(line, line.height + dHeight); }\n }\n signalLater(cm, \"markerChanged\", cm, this$1);\n });\n };\n\n TextMarker.prototype.attachLine = function (line) {\n if (!this.lines.length && this.doc.cm) {\n var op = this.doc.cm.curOp;\n if (!op.maybeHiddenMarkers || indexOf(op.maybeHiddenMarkers, this) == -1)\n { (op.maybeUnhiddenMarkers || (op.maybeUnhiddenMarkers = [])).push(this); }\n }\n this.lines.push(line);\n };\n\n TextMarker.prototype.detachLine = function (line) {\n this.lines.splice(indexOf(this.lines, line), 1);\n if (!this.lines.length && this.doc.cm) {\n var op = this.doc.cm.curOp\n ;(op.maybeHiddenMarkers || (op.maybeHiddenMarkers = [])).push(this);\n }\n };\n eventMixin(TextMarker);\n\n // Create a marker, wire it up to the right lines, and\n function markText(doc, from, to, options, type) {\n // Shared markers (across linked documents) are handled separately\n // (markTextShared will call out to this again, once per\n // document).\n if (options && options.shared) { return markTextShared(doc, from, to, options, type) }\n // Ensure we are in an operation.\n if (doc.cm && !doc.cm.curOp) { return operation(doc.cm, markText)(doc, from, to, options, type) }\n\n var marker = new TextMarker(doc, type), diff = cmp(from, to);\n if (options) { copyObj(options, marker, false); }\n // Don't connect empty markers unless clearWhenEmpty is false\n if (diff > 0 || diff == 0 && marker.clearWhenEmpty !== false)\n { return marker }\n if (marker.replacedWith) {\n // Showing up as a widget implies collapsed (widget replaces text)\n marker.collapsed = true;\n marker.widgetNode = eltP(\"span\", [marker.replacedWith], \"CodeMirror-widget\");\n if (!options.handleMouseEvents) { marker.widgetNode.setAttribute(\"cm-ignore-events\", \"true\"); }\n if (options.insertLeft) { marker.widgetNode.insertLeft = true; }\n }\n if (marker.collapsed) {\n if (conflictingCollapsedRange(doc, from.line, from, to, marker) ||\n from.line != to.line && conflictingCollapsedRange(doc, to.line, from, to, marker))\n { throw new Error(\"Inserting collapsed marker partially overlapping an existing one\") }\n seeCollapsedSpans();\n }\n\n if (marker.addToHistory)\n { addChangeToHistory(doc, {from: from, to: to, origin: \"markText\"}, doc.sel, NaN); }\n\n var curLine = from.line, cm = doc.cm, updateMaxLine;\n doc.iter(curLine, to.line + 1, function (line) {\n if (cm && marker.collapsed && !cm.options.lineWrapping && visualLine(line) == cm.display.maxLine)\n { updateMaxLine = true; }\n if (marker.collapsed && curLine != from.line) { updateLineHeight(line, 0); }\n addMarkedSpan(line, new MarkedSpan(marker,\n curLine == from.line ? from.ch : null,\n curLine == to.line ? to.ch : null));\n ++curLine;\n });\n // lineIsHidden depends on the presence of the spans, so needs a second pass\n if (marker.collapsed) { doc.iter(from.line, to.line + 1, function (line) {\n if (lineIsHidden(doc, line)) { updateLineHeight(line, 0); }\n }); }\n\n if (marker.clearOnEnter) { on(marker, \"beforeCursorEnter\", function () { return marker.clear(); }); }\n\n if (marker.readOnly) {\n seeReadOnlySpans();\n if (doc.history.done.length || doc.history.undone.length)\n { doc.clearHistory(); }\n }\n if (marker.collapsed) {\n marker.id = ++nextMarkerId;\n marker.atomic = true;\n }\n if (cm) {\n // Sync editor state\n if (updateMaxLine) { cm.curOp.updateMaxLine = true; }\n if (marker.collapsed)\n { regChange(cm, from.line, to.line + 1); }\n else if (marker.className || marker.startStyle || marker.endStyle || marker.css ||\n marker.attributes || marker.title)\n { for (var i = from.line; i <= to.line; i++) { regLineChange(cm, i, \"text\"); } }\n if (marker.atomic) { reCheckSelection(cm.doc); }\n signalLater(cm, \"markerAdded\", cm, marker);\n }\n return marker\n }\n\n // SHARED TEXTMARKERS\n\n // A shared marker spans multiple linked documents. It is\n // implemented as a meta-marker-object controlling multiple normal\n // markers.\n var SharedTextMarker = function(markers, primary) {\n this.markers = markers;\n this.primary = primary;\n for (var i = 0; i < markers.length; ++i)\n { markers[i].parent = this; }\n };\n\n SharedTextMarker.prototype.clear = function () {\n if (this.explicitlyCleared) { return }\n this.explicitlyCleared = true;\n for (var i = 0; i < this.markers.length; ++i)\n { this.markers[i].clear(); }\n signalLater(this, \"clear\");\n };\n\n SharedTextMarker.prototype.find = function (side, lineObj) {\n return this.primary.find(side, lineObj)\n };\n eventMixin(SharedTextMarker);\n\n function markTextShared(doc, from, to, options, type) {\n options = copyObj(options);\n options.shared = false;\n var markers = [markText(doc, from, to, options, type)], primary = markers[0];\n var widget = options.widgetNode;\n linkedDocs(doc, function (doc) {\n if (widget) { options.widgetNode = widget.cloneNode(true); }\n markers.push(markText(doc, clipPos(doc, from), clipPos(doc, to), options, type));\n for (var i = 0; i < doc.linked.length; ++i)\n { if (doc.linked[i].isParent) { return } }\n primary = lst(markers);\n });\n return new SharedTextMarker(markers, primary)\n }\n\n function findSharedMarkers(doc) {\n return doc.findMarks(Pos(doc.first, 0), doc.clipPos(Pos(doc.lastLine())), function (m) { return m.parent; })\n }\n\n function copySharedMarkers(doc, markers) {\n for (var i = 0; i < markers.length; i++) {\n var marker = markers[i], pos = marker.find();\n var mFrom = doc.clipPos(pos.from), mTo = doc.clipPos(pos.to);\n if (cmp(mFrom, mTo)) {\n var subMark = markText(doc, mFrom, mTo, marker.primary, marker.primary.type);\n marker.markers.push(subMark);\n subMark.parent = marker;\n }\n }\n }\n\n function detachSharedMarkers(markers) {\n var loop = function ( i ) {\n var marker = markers[i], linked = [marker.primary.doc];\n linkedDocs(marker.primary.doc, function (d) { return linked.push(d); });\n for (var j = 0; j < marker.markers.length; j++) {\n var subMarker = marker.markers[j];\n if (indexOf(linked, subMarker.doc) == -1) {\n subMarker.parent = null;\n marker.markers.splice(j--, 1);\n }\n }\n };\n\n for (var i = 0; i < markers.length; i++) loop( i );\n }\n\n var nextDocId = 0;\n var Doc = function(text, mode, firstLine, lineSep, direction) {\n if (!(this instanceof Doc)) { return new Doc(text, mode, firstLine, lineSep, direction) }\n if (firstLine == null) { firstLine = 0; }\n\n BranchChunk.call(this, [new LeafChunk([new Line(\"\", null)])]);\n this.first = firstLine;\n this.scrollTop = this.scrollLeft = 0;\n this.cantEdit = false;\n this.cleanGeneration = 1;\n this.modeFrontier = this.highlightFrontier = firstLine;\n var start = Pos(firstLine, 0);\n this.sel = simpleSelection(start);\n this.history = new History(null);\n this.id = ++nextDocId;\n this.modeOption = mode;\n this.lineSep = lineSep;\n this.direction = (direction == \"rtl\") ? \"rtl\" : \"ltr\";\n this.extend = false;\n\n if (typeof text == \"string\") { text = this.splitLines(text); }\n updateDoc(this, {from: start, to: start, text: text});\n setSelection(this, simpleSelection(start), sel_dontScroll);\n };\n\n Doc.prototype = createObj(BranchChunk.prototype, {\n constructor: Doc,\n // Iterate over the document. Supports two forms -- with only one\n // argument, it calls that for each line in the document. With\n // three, it iterates over the range given by the first two (with\n // the second being non-inclusive).\n iter: function(from, to, op) {\n if (op) { this.iterN(from - this.first, to - from, op); }\n else { this.iterN(this.first, this.first + this.size, from); }\n },\n\n // Non-public interface for adding and removing lines.\n insert: function(at, lines) {\n var height = 0;\n for (var i = 0; i < lines.length; ++i) { height += lines[i].height; }\n this.insertInner(at - this.first, lines, height);\n },\n remove: function(at, n) { this.removeInner(at - this.first, n); },\n\n // From here, the methods are part of the public interface. Most\n // are also available from CodeMirror (editor) instances.\n\n getValue: function(lineSep) {\n var lines = getLines(this, this.first, this.first + this.size);\n if (lineSep === false) { return lines }\n return lines.join(lineSep || this.lineSeparator())\n },\n setValue: docMethodOp(function(code) {\n var top = Pos(this.first, 0), last = this.first + this.size - 1;\n makeChange(this, {from: top, to: Pos(last, getLine(this, last).text.length),\n text: this.splitLines(code), origin: \"setValue\", full: true}, true);\n if (this.cm) { scrollToCoords(this.cm, 0, 0); }\n setSelection(this, simpleSelection(top), sel_dontScroll);\n }),\n replaceRange: function(code, from, to, origin) {\n from = clipPos(this, from);\n to = to ? clipPos(this, to) : from;\n replaceRange(this, code, from, to, origin);\n },\n getRange: function(from, to, lineSep) {\n var lines = getBetween(this, clipPos(this, from), clipPos(this, to));\n if (lineSep === false) { return lines }\n return lines.join(lineSep || this.lineSeparator())\n },\n\n getLine: function(line) {var l = this.getLineHandle(line); return l && l.text},\n\n getLineHandle: function(line) {if (isLine(this, line)) { return getLine(this, line) }},\n getLineNumber: function(line) {return lineNo(line)},\n\n getLineHandleVisualStart: function(line) {\n if (typeof line == \"number\") { line = getLine(this, line); }\n return visualLine(line)\n },\n\n lineCount: function() {return this.size},\n firstLine: function() {return this.first},\n lastLine: function() {return this.first + this.size - 1},\n\n clipPos: function(pos) {return clipPos(this, pos)},\n\n getCursor: function(start) {\n var range = this.sel.primary(), pos;\n if (start == null || start == \"head\") { pos = range.head; }\n else if (start == \"anchor\") { pos = range.anchor; }\n else if (start == \"end\" || start == \"to\" || start === false) { pos = range.to(); }\n else { pos = range.from(); }\n return pos\n },\n listSelections: function() { return this.sel.ranges },\n somethingSelected: function() {return this.sel.somethingSelected()},\n\n setCursor: docMethodOp(function(line, ch, options) {\n setSimpleSelection(this, clipPos(this, typeof line == \"number\" ? Pos(line, ch || 0) : line), null, options);\n }),\n setSelection: docMethodOp(function(anchor, head, options) {\n setSimpleSelection(this, clipPos(this, anchor), clipPos(this, head || anchor), options);\n }),\n extendSelection: docMethodOp(function(head, other, options) {\n extendSelection(this, clipPos(this, head), other && clipPos(this, other), options);\n }),\n extendSelections: docMethodOp(function(heads, options) {\n extendSelections(this, clipPosArray(this, heads), options);\n }),\n extendSelectionsBy: docMethodOp(function(f, options) {\n var heads = map(this.sel.ranges, f);\n extendSelections(this, clipPosArray(this, heads), options);\n }),\n setSelections: docMethodOp(function(ranges, primary, options) {\n if (!ranges.length) { return }\n var out = [];\n for (var i = 0; i < ranges.length; i++)\n { out[i] = new Range(clipPos(this, ranges[i].anchor),\n clipPos(this, ranges[i].head)); }\n if (primary == null) { primary = Math.min(ranges.length - 1, this.sel.primIndex); }\n setSelection(this, normalizeSelection(this.cm, out, primary), options);\n }),\n addSelection: docMethodOp(function(anchor, head, options) {\n var ranges = this.sel.ranges.slice(0);\n ranges.push(new Range(clipPos(this, anchor), clipPos(this, head || anchor)));\n setSelection(this, normalizeSelection(this.cm, ranges, ranges.length - 1), options);\n }),\n\n getSelection: function(lineSep) {\n var ranges = this.sel.ranges, lines;\n for (var i = 0; i < ranges.length; i++) {\n var sel = getBetween(this, ranges[i].from(), ranges[i].to());\n lines = lines ? lines.concat(sel) : sel;\n }\n if (lineSep === false) { return lines }\n else { return lines.join(lineSep || this.lineSeparator()) }\n },\n getSelections: function(lineSep) {\n var parts = [], ranges = this.sel.ranges;\n for (var i = 0; i < ranges.length; i++) {\n var sel = getBetween(this, ranges[i].from(), ranges[i].to());\n if (lineSep !== false) { sel = sel.join(lineSep || this.lineSeparator()); }\n parts[i] = sel;\n }\n return parts\n },\n replaceSelection: function(code, collapse, origin) {\n var dup = [];\n for (var i = 0; i < this.sel.ranges.length; i++)\n { dup[i] = code; }\n this.replaceSelections(dup, collapse, origin || \"+input\");\n },\n replaceSelections: docMethodOp(function(code, collapse, origin) {\n var changes = [], sel = this.sel;\n for (var i = 0; i < sel.ranges.length; i++) {\n var range = sel.ranges[i];\n changes[i] = {from: range.from(), to: range.to(), text: this.splitLines(code[i]), origin: origin};\n }\n var newSel = collapse && collapse != \"end\" && computeReplacedSel(this, changes, collapse);\n for (var i$1 = changes.length - 1; i$1 >= 0; i$1--)\n { makeChange(this, changes[i$1]); }\n if (newSel) { setSelectionReplaceHistory(this, newSel); }\n else if (this.cm) { ensureCursorVisible(this.cm); }\n }),\n undo: docMethodOp(function() {makeChangeFromHistory(this, \"undo\");}),\n redo: docMethodOp(function() {makeChangeFromHistory(this, \"redo\");}),\n undoSelection: docMethodOp(function() {makeChangeFromHistory(this, \"undo\", true);}),\n redoSelection: docMethodOp(function() {makeChangeFromHistory(this, \"redo\", true);}),\n\n setExtending: function(val) {this.extend = val;},\n getExtending: function() {return this.extend},\n\n historySize: function() {\n var hist = this.history, done = 0, undone = 0;\n for (var i = 0; i < hist.done.length; i++) { if (!hist.done[i].ranges) { ++done; } }\n for (var i$1 = 0; i$1 < hist.undone.length; i$1++) { if (!hist.undone[i$1].ranges) { ++undone; } }\n return {undo: done, redo: undone}\n },\n clearHistory: function() {\n var this$1 = this;\n\n this.history = new History(this.history.maxGeneration);\n linkedDocs(this, function (doc) { return doc.history = this$1.history; }, true);\n },\n\n markClean: function() {\n this.cleanGeneration = this.changeGeneration(true);\n },\n changeGeneration: function(forceSplit) {\n if (forceSplit)\n { this.history.lastOp = this.history.lastSelOp = this.history.lastOrigin = null; }\n return this.history.generation\n },\n isClean: function (gen) {\n return this.history.generation == (gen || this.cleanGeneration)\n },\n\n getHistory: function() {\n return {done: copyHistoryArray(this.history.done),\n undone: copyHistoryArray(this.history.undone)}\n },\n setHistory: function(histData) {\n var hist = this.history = new History(this.history.maxGeneration);\n hist.done = copyHistoryArray(histData.done.slice(0), null, true);\n hist.undone = copyHistoryArray(histData.undone.slice(0), null, true);\n },\n\n setGutterMarker: docMethodOp(function(line, gutterID, value) {\n return changeLine(this, line, \"gutter\", function (line) {\n var markers = line.gutterMarkers || (line.gutterMarkers = {});\n markers[gutterID] = value;\n if (!value && isEmpty(markers)) { line.gutterMarkers = null; }\n return true\n })\n }),\n\n clearGutter: docMethodOp(function(gutterID) {\n var this$1 = this;\n\n this.iter(function (line) {\n if (line.gutterMarkers && line.gutterMarkers[gutterID]) {\n changeLine(this$1, line, \"gutter\", function () {\n line.gutterMarkers[gutterID] = null;\n if (isEmpty(line.gutterMarkers)) { line.gutterMarkers = null; }\n return true\n });\n }\n });\n }),\n\n lineInfo: function(line) {\n var n;\n if (typeof line == \"number\") {\n if (!isLine(this, line)) { return null }\n n = line;\n line = getLine(this, line);\n if (!line) { return null }\n } else {\n n = lineNo(line);\n if (n == null) { return null }\n }\n return {line: n, handle: line, text: line.text, gutterMarkers: line.gutterMarkers,\n textClass: line.textClass, bgClass: line.bgClass, wrapClass: line.wrapClass,\n widgets: line.widgets}\n },\n\n addLineClass: docMethodOp(function(handle, where, cls) {\n return changeLine(this, handle, where == \"gutter\" ? \"gutter\" : \"class\", function (line) {\n var prop = where == \"text\" ? \"textClass\"\n : where == \"background\" ? \"bgClass\"\n : where == \"gutter\" ? \"gutterClass\" : \"wrapClass\";\n if (!line[prop]) { line[prop] = cls; }\n else if (classTest(cls).test(line[prop])) { return false }\n else { line[prop] += \" \" + cls; }\n return true\n })\n }),\n removeLineClass: docMethodOp(function(handle, where, cls) {\n return changeLine(this, handle, where == \"gutter\" ? \"gutter\" : \"class\", function (line) {\n var prop = where == \"text\" ? \"textClass\"\n : where == \"background\" ? \"bgClass\"\n : where == \"gutter\" ? \"gutterClass\" : \"wrapClass\";\n var cur = line[prop];\n if (!cur) { return false }\n else if (cls == null) { line[prop] = null; }\n else {\n var found = cur.match(classTest(cls));\n if (!found) { return false }\n var end = found.index + found[0].length;\n line[prop] = cur.slice(0, found.index) + (!found.index || end == cur.length ? \"\" : \" \") + cur.slice(end) || null;\n }\n return true\n })\n }),\n\n addLineWidget: docMethodOp(function(handle, node, options) {\n return addLineWidget(this, handle, node, options)\n }),\n removeLineWidget: function(widget) { widget.clear(); },\n\n markText: function(from, to, options) {\n return markText(this, clipPos(this, from), clipPos(this, to), options, options && options.type || \"range\")\n },\n setBookmark: function(pos, options) {\n var realOpts = {replacedWith: options && (options.nodeType == null ? options.widget : options),\n insertLeft: options && options.insertLeft,\n clearWhenEmpty: false, shared: options && options.shared,\n handleMouseEvents: options && options.handleMouseEvents};\n pos = clipPos(this, pos);\n return markText(this, pos, pos, realOpts, \"bookmark\")\n },\n findMarksAt: function(pos) {\n pos = clipPos(this, pos);\n var markers = [], spans = getLine(this, pos.line).markedSpans;\n if (spans) { for (var i = 0; i < spans.length; ++i) {\n var span = spans[i];\n if ((span.from == null || span.from <= pos.ch) &&\n (span.to == null || span.to >= pos.ch))\n { markers.push(span.marker.parent || span.marker); }\n } }\n return markers\n },\n findMarks: function(from, to, filter) {\n from = clipPos(this, from); to = clipPos(this, to);\n var found = [], lineNo = from.line;\n this.iter(from.line, to.line + 1, function (line) {\n var spans = line.markedSpans;\n if (spans) { for (var i = 0; i < spans.length; i++) {\n var span = spans[i];\n if (!(span.to != null && lineNo == from.line && from.ch >= span.to ||\n span.from == null && lineNo != from.line ||\n span.from != null && lineNo == to.line && span.from >= to.ch) &&\n (!filter || filter(span.marker)))\n { found.push(span.marker.parent || span.marker); }\n } }\n ++lineNo;\n });\n return found\n },\n getAllMarks: function() {\n var markers = [];\n this.iter(function (line) {\n var sps = line.markedSpans;\n if (sps) { for (var i = 0; i < sps.length; ++i)\n { if (sps[i].from != null) { markers.push(sps[i].marker); } } }\n });\n return markers\n },\n\n posFromIndex: function(off) {\n var ch, lineNo = this.first, sepSize = this.lineSeparator().length;\n this.iter(function (line) {\n var sz = line.text.length + sepSize;\n if (sz > off) { ch = off; return true }\n off -= sz;\n ++lineNo;\n });\n return clipPos(this, Pos(lineNo, ch))\n },\n indexFromPos: function (coords) {\n coords = clipPos(this, coords);\n var index = coords.ch;\n if (coords.line < this.first || coords.ch < 0) { return 0 }\n var sepSize = this.lineSeparator().length;\n this.iter(this.first, coords.line, function (line) { // iter aborts when callback returns a truthy value\n index += line.text.length + sepSize;\n });\n return index\n },\n\n copy: function(copyHistory) {\n var doc = new Doc(getLines(this, this.first, this.first + this.size),\n this.modeOption, this.first, this.lineSep, this.direction);\n doc.scrollTop = this.scrollTop; doc.scrollLeft = this.scrollLeft;\n doc.sel = this.sel;\n doc.extend = false;\n if (copyHistory) {\n doc.history.undoDepth = this.history.undoDepth;\n doc.setHistory(this.getHistory());\n }\n return doc\n },\n\n linkedDoc: function(options) {\n if (!options) { options = {}; }\n var from = this.first, to = this.first + this.size;\n if (options.from != null && options.from > from) { from = options.from; }\n if (options.to != null && options.to < to) { to = options.to; }\n var copy = new Doc(getLines(this, from, to), options.mode || this.modeOption, from, this.lineSep, this.direction);\n if (options.sharedHist) { copy.history = this.history\n ; }(this.linked || (this.linked = [])).push({doc: copy, sharedHist: options.sharedHist});\n copy.linked = [{doc: this, isParent: true, sharedHist: options.sharedHist}];\n copySharedMarkers(copy, findSharedMarkers(this));\n return copy\n },\n unlinkDoc: function(other) {\n if (other instanceof CodeMirror) { other = other.doc; }\n if (this.linked) { for (var i = 0; i < this.linked.length; ++i) {\n var link = this.linked[i];\n if (link.doc != other) { continue }\n this.linked.splice(i, 1);\n other.unlinkDoc(this);\n detachSharedMarkers(findSharedMarkers(this));\n break\n } }\n // If the histories were shared, split them again\n if (other.history == this.history) {\n var splitIds = [other.id];\n linkedDocs(other, function (doc) { return splitIds.push(doc.id); }, true);\n other.history = new History(null);\n other.history.done = copyHistoryArray(this.history.done, splitIds);\n other.history.undone = copyHistoryArray(this.history.undone, splitIds);\n }\n },\n iterLinkedDocs: function(f) {linkedDocs(this, f);},\n\n getMode: function() {return this.mode},\n getEditor: function() {return this.cm},\n\n splitLines: function(str) {\n if (this.lineSep) { return str.split(this.lineSep) }\n return splitLinesAuto(str)\n },\n lineSeparator: function() { return this.lineSep || \"\\n\" },\n\n setDirection: docMethodOp(function (dir) {\n if (dir != \"rtl\") { dir = \"ltr\"; }\n if (dir == this.direction) { return }\n this.direction = dir;\n this.iter(function (line) { return line.order = null; });\n if (this.cm) { directionChanged(this.cm); }\n })\n });\n\n // Public alias.\n Doc.prototype.eachLine = Doc.prototype.iter;\n\n // Kludge to work around strange IE behavior where it'll sometimes\n // re-fire a series of drag-related events right after the drop (#1551)\n var lastDrop = 0;\n\n function onDrop(e) {\n var cm = this;\n clearDragCursor(cm);\n if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e))\n { return }\n e_preventDefault(e);\n if (ie) { lastDrop = +new Date; }\n var pos = posFromMouse(cm, e, true), files = e.dataTransfer.files;\n if (!pos || cm.isReadOnly()) { return }\n // Might be a file drop, in which case we simply extract the text\n // and insert it.\n if (files && files.length && window.FileReader && window.File) {\n var n = files.length, text = Array(n), read = 0;\n var markAsReadAndPasteIfAllFilesAreRead = function () {\n if (++read == n) {\n operation(cm, function () {\n pos = clipPos(cm.doc, pos);\n var change = {from: pos, to: pos,\n text: cm.doc.splitLines(\n text.filter(function (t) { return t != null; }).join(cm.doc.lineSeparator())),\n origin: \"paste\"};\n makeChange(cm.doc, change);\n setSelectionReplaceHistory(cm.doc, simpleSelection(clipPos(cm.doc, pos), clipPos(cm.doc, changeEnd(change))));\n })();\n }\n };\n var readTextFromFile = function (file, i) {\n if (cm.options.allowDropFileTypes &&\n indexOf(cm.options.allowDropFileTypes, file.type) == -1) {\n markAsReadAndPasteIfAllFilesAreRead();\n return\n }\n var reader = new FileReader;\n reader.onerror = function () { return markAsReadAndPasteIfAllFilesAreRead(); };\n reader.onload = function () {\n var content = reader.result;\n if (/[\\x00-\\x08\\x0e-\\x1f]{2}/.test(content)) {\n markAsReadAndPasteIfAllFilesAreRead();\n return\n }\n text[i] = content;\n markAsReadAndPasteIfAllFilesAreRead();\n };\n reader.readAsText(file);\n };\n for (var i = 0; i < files.length; i++) { readTextFromFile(files[i], i); }\n } else { // Normal drop\n // Don't do a replace if the drop happened inside of the selected text.\n if (cm.state.draggingText && cm.doc.sel.contains(pos) > -1) {\n cm.state.draggingText(e);\n // Ensure the editor is re-focused\n setTimeout(function () { return cm.display.input.focus(); }, 20);\n return\n }\n try {\n var text$1 = e.dataTransfer.getData(\"Text\");\n if (text$1) {\n var selected;\n if (cm.state.draggingText && !cm.state.draggingText.copy)\n { selected = cm.listSelections(); }\n setSelectionNoUndo(cm.doc, simpleSelection(pos, pos));\n if (selected) { for (var i$1 = 0; i$1 < selected.length; ++i$1)\n { replaceRange(cm.doc, \"\", selected[i$1].anchor, selected[i$1].head, \"drag\"); } }\n cm.replaceSelection(text$1, \"around\", \"paste\");\n cm.display.input.focus();\n }\n }\n catch(e$1){}\n }\n }\n\n function onDragStart(cm, e) {\n if (ie && (!cm.state.draggingText || +new Date - lastDrop < 100)) { e_stop(e); return }\n if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) { return }\n\n e.dataTransfer.setData(\"Text\", cm.getSelection());\n e.dataTransfer.effectAllowed = \"copyMove\";\n\n // Use dummy image instead of default browsers image.\n // Recent Safari (~6.0.2) have a tendency to segfault when this happens, so we don't do it there.\n if (e.dataTransfer.setDragImage && !safari) {\n var img = elt(\"img\", null, null, \"position: fixed; left: 0; top: 0;\");\n img.src = \"data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\";\n if (presto) {\n img.width = img.height = 1;\n cm.display.wrapper.appendChild(img);\n // Force a relayout, or Opera won't use our image for some obscure reason\n img._top = img.offsetTop;\n }\n e.dataTransfer.setDragImage(img, 0, 0);\n if (presto) { img.parentNode.removeChild(img); }\n }\n }\n\n function onDragOver(cm, e) {\n var pos = posFromMouse(cm, e);\n if (!pos) { return }\n var frag = document.createDocumentFragment();\n drawSelectionCursor(cm, pos, frag);\n if (!cm.display.dragCursor) {\n cm.display.dragCursor = elt(\"div\", null, \"CodeMirror-cursors CodeMirror-dragcursors\");\n cm.display.lineSpace.insertBefore(cm.display.dragCursor, cm.display.cursorDiv);\n }\n removeChildrenAndAdd(cm.display.dragCursor, frag);\n }\n\n function clearDragCursor(cm) {\n if (cm.display.dragCursor) {\n cm.display.lineSpace.removeChild(cm.display.dragCursor);\n cm.display.dragCursor = null;\n }\n }\n\n // These must be handled carefully, because naively registering a\n // handler for each editor will cause the editors to never be\n // garbage collected.\n\n function forEachCodeMirror(f) {\n if (!document.getElementsByClassName) { return }\n var byClass = document.getElementsByClassName(\"CodeMirror\"), editors = [];\n for (var i = 0; i < byClass.length; i++) {\n var cm = byClass[i].CodeMirror;\n if (cm) { editors.push(cm); }\n }\n if (editors.length) { editors[0].operation(function () {\n for (var i = 0; i < editors.length; i++) { f(editors[i]); }\n }); }\n }\n\n var globalsRegistered = false;\n function ensureGlobalHandlers() {\n if (globalsRegistered) { return }\n registerGlobalHandlers();\n globalsRegistered = true;\n }\n function registerGlobalHandlers() {\n // When the window resizes, we need to refresh active editors.\n var resizeTimer;\n on(window, \"resize\", function () {\n if (resizeTimer == null) { resizeTimer = setTimeout(function () {\n resizeTimer = null;\n forEachCodeMirror(onResize);\n }, 100); }\n });\n // When the window loses focus, we want to show the editor as blurred\n on(window, \"blur\", function () { return forEachCodeMirror(onBlur); });\n }\n // Called when the window resizes\n function onResize(cm) {\n var d = cm.display;\n // Might be a text scaling operation, clear size caches.\n d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null;\n d.scrollbarsClipped = false;\n cm.setSize();\n }\n\n var keyNames = {\n 3: \"Pause\", 8: \"Backspace\", 9: \"Tab\", 13: \"Enter\", 16: \"Shift\", 17: \"Ctrl\", 18: \"Alt\",\n 19: \"Pause\", 20: \"CapsLock\", 27: \"Esc\", 32: \"Space\", 33: \"PageUp\", 34: \"PageDown\", 35: \"End\",\n 36: \"Home\", 37: \"Left\", 38: \"Up\", 39: \"Right\", 40: \"Down\", 44: \"PrintScrn\", 45: \"Insert\",\n 46: \"Delete\", 59: \";\", 61: \"=\", 91: \"Mod\", 92: \"Mod\", 93: \"Mod\",\n 106: \"*\", 107: \"=\", 109: \"-\", 110: \".\", 111: \"/\", 145: \"ScrollLock\",\n 173: \"-\", 186: \";\", 187: \"=\", 188: \",\", 189: \"-\", 190: \".\", 191: \"/\", 192: \"`\", 219: \"[\", 220: \"\\\\\",\n 221: \"]\", 222: \"'\", 224: \"Mod\", 63232: \"Up\", 63233: \"Down\", 63234: \"Left\", 63235: \"Right\", 63272: \"Delete\",\n 63273: \"Home\", 63275: \"End\", 63276: \"PageUp\", 63277: \"PageDown\", 63302: \"Insert\"\n };\n\n // Number keys\n for (var i = 0; i < 10; i++) { keyNames[i + 48] = keyNames[i + 96] = String(i); }\n // Alphabetic keys\n for (var i$1 = 65; i$1 <= 90; i$1++) { keyNames[i$1] = String.fromCharCode(i$1); }\n // Function keys\n for (var i$2 = 1; i$2 <= 12; i$2++) { keyNames[i$2 + 111] = keyNames[i$2 + 63235] = \"F\" + i$2; }\n\n var keyMap = {};\n\n keyMap.basic = {\n \"Left\": \"goCharLeft\", \"Right\": \"goCharRight\", \"Up\": \"goLineUp\", \"Down\": \"goLineDown\",\n \"End\": \"goLineEnd\", \"Home\": \"goLineStartSmart\", \"PageUp\": \"goPageUp\", \"PageDown\": \"goPageDown\",\n \"Delete\": \"delCharAfter\", \"Backspace\": \"delCharBefore\", \"Shift-Backspace\": \"delCharBefore\",\n \"Tab\": \"defaultTab\", \"Shift-Tab\": \"indentAuto\",\n \"Enter\": \"newlineAndIndent\", \"Insert\": \"toggleOverwrite\",\n \"Esc\": \"singleSelection\"\n };\n // Note that the save and find-related commands aren't defined by\n // default. User code or addons can define them. Unknown commands\n // are simply ignored.\n keyMap.pcDefault = {\n \"Ctrl-A\": \"selectAll\", \"Ctrl-D\": \"deleteLine\", \"Ctrl-Z\": \"undo\", \"Shift-Ctrl-Z\": \"redo\", \"Ctrl-Y\": \"redo\",\n \"Ctrl-Home\": \"goDocStart\", \"Ctrl-End\": \"goDocEnd\", \"Ctrl-Up\": \"goLineUp\", \"Ctrl-Down\": \"goLineDown\",\n \"Ctrl-Left\": \"goGroupLeft\", \"Ctrl-Right\": \"goGroupRight\", \"Alt-Left\": \"goLineStart\", \"Alt-Right\": \"goLineEnd\",\n \"Ctrl-Backspace\": \"delGroupBefore\", \"Ctrl-Delete\": \"delGroupAfter\", \"Ctrl-S\": \"save\", \"Ctrl-F\": \"find\",\n \"Ctrl-G\": \"findNext\", \"Shift-Ctrl-G\": \"findPrev\", \"Shift-Ctrl-F\": \"replace\", \"Shift-Ctrl-R\": \"replaceAll\",\n \"Ctrl-[\": \"indentLess\", \"Ctrl-]\": \"indentMore\",\n \"Ctrl-U\": \"undoSelection\", \"Shift-Ctrl-U\": \"redoSelection\", \"Alt-U\": \"redoSelection\",\n \"fallthrough\": \"basic\"\n };\n // Very basic readline/emacs-style bindings, which are standard on Mac.\n keyMap.emacsy = {\n \"Ctrl-F\": \"goCharRight\", \"Ctrl-B\": \"goCharLeft\", \"Ctrl-P\": \"goLineUp\", \"Ctrl-N\": \"goLineDown\",\n \"Alt-F\": \"goWordRight\", \"Alt-B\": \"goWordLeft\", \"Ctrl-A\": \"goLineStart\", \"Ctrl-E\": \"goLineEnd\",\n \"Ctrl-V\": \"goPageDown\", \"Shift-Ctrl-V\": \"goPageUp\", \"Ctrl-D\": \"delCharAfter\", \"Ctrl-H\": \"delCharBefore\",\n \"Alt-D\": \"delWordAfter\", \"Alt-Backspace\": \"delWordBefore\", \"Ctrl-K\": \"killLine\", \"Ctrl-T\": \"transposeChars\",\n \"Ctrl-O\": \"openLine\"\n };\n keyMap.macDefault = {\n \"Cmd-A\": \"selectAll\", \"Cmd-D\": \"deleteLine\", \"Cmd-Z\": \"undo\", \"Shift-Cmd-Z\": \"redo\", \"Cmd-Y\": \"redo\",\n \"Cmd-Home\": \"goDocStart\", \"Cmd-Up\": \"goDocStart\", \"Cmd-End\": \"goDocEnd\", \"Cmd-Down\": \"goDocEnd\", \"Alt-Left\": \"goGroupLeft\",\n \"Alt-Right\": \"goGroupRight\", \"Cmd-Left\": \"goLineLeft\", \"Cmd-Right\": \"goLineRight\", \"Alt-Backspace\": \"delGroupBefore\",\n \"Ctrl-Alt-Backspace\": \"delGroupAfter\", \"Alt-Delete\": \"delGroupAfter\", \"Cmd-S\": \"save\", \"Cmd-F\": \"find\",\n \"Cmd-G\": \"findNext\", \"Shift-Cmd-G\": \"findPrev\", \"Cmd-Alt-F\": \"replace\", \"Shift-Cmd-Alt-F\": \"replaceAll\",\n \"Cmd-[\": \"indentLess\", \"Cmd-]\": \"indentMore\", \"Cmd-Backspace\": \"delWrappedLineLeft\", \"Cmd-Delete\": \"delWrappedLineRight\",\n \"Cmd-U\": \"undoSelection\", \"Shift-Cmd-U\": \"redoSelection\", \"Ctrl-Up\": \"goDocStart\", \"Ctrl-Down\": \"goDocEnd\",\n \"fallthrough\": [\"basic\", \"emacsy\"]\n };\n keyMap[\"default\"] = mac ? keyMap.macDefault : keyMap.pcDefault;\n\n // KEYMAP DISPATCH\n\n function normalizeKeyName(name) {\n var parts = name.split(/-(?!$)/);\n name = parts[parts.length - 1];\n var alt, ctrl, shift, cmd;\n for (var i = 0; i < parts.length - 1; i++) {\n var mod = parts[i];\n if (/^(cmd|meta|m)$/i.test(mod)) { cmd = true; }\n else if (/^a(lt)?$/i.test(mod)) { alt = true; }\n else if (/^(c|ctrl|control)$/i.test(mod)) { ctrl = true; }\n else if (/^s(hift)?$/i.test(mod)) { shift = true; }\n else { throw new Error(\"Unrecognized modifier name: \" + mod) }\n }\n if (alt) { name = \"Alt-\" + name; }\n if (ctrl) { name = \"Ctrl-\" + name; }\n if (cmd) { name = \"Cmd-\" + name; }\n if (shift) { name = \"Shift-\" + name; }\n return name\n }\n\n // This is a kludge to keep keymaps mostly working as raw objects\n // (backwards compatibility) while at the same time support features\n // like normalization and multi-stroke key bindings. It compiles a\n // new normalized keymap, and then updates the old object to reflect\n // this.\n function normalizeKeyMap(keymap) {\n var copy = {};\n for (var keyname in keymap) { if (keymap.hasOwnProperty(keyname)) {\n var value = keymap[keyname];\n if (/^(name|fallthrough|(de|at)tach)$/.test(keyname)) { continue }\n if (value == \"...\") { delete keymap[keyname]; continue }\n\n var keys = map(keyname.split(\" \"), normalizeKeyName);\n for (var i = 0; i < keys.length; i++) {\n var val = (void 0), name = (void 0);\n if (i == keys.length - 1) {\n name = keys.join(\" \");\n val = value;\n } else {\n name = keys.slice(0, i + 1).join(\" \");\n val = \"...\";\n }\n var prev = copy[name];\n if (!prev) { copy[name] = val; }\n else if (prev != val) { throw new Error(\"Inconsistent bindings for \" + name) }\n }\n delete keymap[keyname];\n } }\n for (var prop in copy) { keymap[prop] = copy[prop]; }\n return keymap\n }\n\n function lookupKey(key, map, handle, context) {\n map = getKeyMap(map);\n var found = map.call ? map.call(key, context) : map[key];\n if (found === false) { return \"nothing\" }\n if (found === \"...\") { return \"multi\" }\n if (found != null && handle(found)) { return \"handled\" }\n\n if (map.fallthrough) {\n if (Object.prototype.toString.call(map.fallthrough) != \"[object Array]\")\n { return lookupKey(key, map.fallthrough, handle, context) }\n for (var i = 0; i < map.fallthrough.length; i++) {\n var result = lookupKey(key, map.fallthrough[i], handle, context);\n if (result) { return result }\n }\n }\n }\n\n // Modifier key presses don't count as 'real' key presses for the\n // purpose of keymap fallthrough.\n function isModifierKey(value) {\n var name = typeof value == \"string\" ? value : keyNames[value.keyCode];\n return name == \"Ctrl\" || name == \"Alt\" || name == \"Shift\" || name == \"Mod\"\n }\n\n function addModifierNames(name, event, noShift) {\n var base = name;\n if (event.altKey && base != \"Alt\") { name = \"Alt-\" + name; }\n if ((flipCtrlCmd ? event.metaKey : event.ctrlKey) && base != \"Ctrl\") { name = \"Ctrl-\" + name; }\n if ((flipCtrlCmd ? event.ctrlKey : event.metaKey) && base != \"Mod\") { name = \"Cmd-\" + name; }\n if (!noShift && event.shiftKey && base != \"Shift\") { name = \"Shift-\" + name; }\n return name\n }\n\n // Look up the name of a key as indicated by an event object.\n function keyName(event, noShift) {\n if (presto && event.keyCode == 34 && event[\"char\"]) { return false }\n var name = keyNames[event.keyCode];\n if (name == null || event.altGraphKey) { return false }\n // Ctrl-ScrollLock has keyCode 3, same as Ctrl-Pause,\n // so we'll use event.code when available (Chrome 48+, FF 38+, Safari 10.1+)\n if (event.keyCode == 3 && event.code) { name = event.code; }\n return addModifierNames(name, event, noShift)\n }\n\n function getKeyMap(val) {\n return typeof val == \"string\" ? keyMap[val] : val\n }\n\n // Helper for deleting text near the selection(s), used to implement\n // backspace, delete, and similar functionality.\n function deleteNearSelection(cm, compute) {\n var ranges = cm.doc.sel.ranges, kill = [];\n // Build up a set of ranges to kill first, merging overlapping\n // ranges.\n for (var i = 0; i < ranges.length; i++) {\n var toKill = compute(ranges[i]);\n while (kill.length && cmp(toKill.from, lst(kill).to) <= 0) {\n var replaced = kill.pop();\n if (cmp(replaced.from, toKill.from) < 0) {\n toKill.from = replaced.from;\n break\n }\n }\n kill.push(toKill);\n }\n // Next, remove those actual ranges.\n runInOp(cm, function () {\n for (var i = kill.length - 1; i >= 0; i--)\n { replaceRange(cm.doc, \"\", kill[i].from, kill[i].to, \"+delete\"); }\n ensureCursorVisible(cm);\n });\n }\n\n function moveCharLogically(line, ch, dir) {\n var target = skipExtendingChars(line.text, ch + dir, dir);\n return target < 0 || target > line.text.length ? null : target\n }\n\n function moveLogically(line, start, dir) {\n var ch = moveCharLogically(line, start.ch, dir);\n return ch == null ? null : new Pos(start.line, ch, dir < 0 ? \"after\" : \"before\")\n }\n\n function endOfLine(visually, cm, lineObj, lineNo, dir) {\n if (visually) {\n if (cm.doc.direction == \"rtl\") { dir = -dir; }\n var order = getOrder(lineObj, cm.doc.direction);\n if (order) {\n var part = dir < 0 ? lst(order) : order[0];\n var moveInStorageOrder = (dir < 0) == (part.level == 1);\n var sticky = moveInStorageOrder ? \"after\" : \"before\";\n var ch;\n // With a wrapped rtl chunk (possibly spanning multiple bidi parts),\n // it could be that the last bidi part is not on the last visual line,\n // since visual lines contain content order-consecutive chunks.\n // Thus, in rtl, we are looking for the first (content-order) character\n // in the rtl chunk that is on the last line (that is, the same line\n // as the last (content-order) character).\n if (part.level > 0 || cm.doc.direction == \"rtl\") {\n var prep = prepareMeasureForLine(cm, lineObj);\n ch = dir < 0 ? lineObj.text.length - 1 : 0;\n var targetTop = measureCharPrepared(cm, prep, ch).top;\n ch = findFirst(function (ch) { return measureCharPrepared(cm, prep, ch).top == targetTop; }, (dir < 0) == (part.level == 1) ? part.from : part.to - 1, ch);\n if (sticky == \"before\") { ch = moveCharLogically(lineObj, ch, 1); }\n } else { ch = dir < 0 ? part.to : part.from; }\n return new Pos(lineNo, ch, sticky)\n }\n }\n return new Pos(lineNo, dir < 0 ? lineObj.text.length : 0, dir < 0 ? \"before\" : \"after\")\n }\n\n function moveVisually(cm, line, start, dir) {\n var bidi = getOrder(line, cm.doc.direction);\n if (!bidi) { return moveLogically(line, start, dir) }\n if (start.ch >= line.text.length) {\n start.ch = line.text.length;\n start.sticky = \"before\";\n } else if (start.ch <= 0) {\n start.ch = 0;\n start.sticky = \"after\";\n }\n var partPos = getBidiPartAt(bidi, start.ch, start.sticky), part = bidi[partPos];\n if (cm.doc.direction == \"ltr\" && part.level % 2 == 0 && (dir > 0 ? part.to > start.ch : part.from < start.ch)) {\n // Case 1: We move within an ltr part in an ltr editor. Even with wrapped lines,\n // nothing interesting happens.\n return moveLogically(line, start, dir)\n }\n\n var mv = function (pos, dir) { return moveCharLogically(line, pos instanceof Pos ? pos.ch : pos, dir); };\n var prep;\n var getWrappedLineExtent = function (ch) {\n if (!cm.options.lineWrapping) { return {begin: 0, end: line.text.length} }\n prep = prep || prepareMeasureForLine(cm, line);\n return wrappedLineExtentChar(cm, line, prep, ch)\n };\n var wrappedLineExtent = getWrappedLineExtent(start.sticky == \"before\" ? mv(start, -1) : start.ch);\n\n if (cm.doc.direction == \"rtl\" || part.level == 1) {\n var moveInStorageOrder = (part.level == 1) == (dir < 0);\n var ch = mv(start, moveInStorageOrder ? 1 : -1);\n if (ch != null && (!moveInStorageOrder ? ch >= part.from && ch >= wrappedLineExtent.begin : ch <= part.to && ch <= wrappedLineExtent.end)) {\n // Case 2: We move within an rtl part or in an rtl editor on the same visual line\n var sticky = moveInStorageOrder ? \"before\" : \"after\";\n return new Pos(start.line, ch, sticky)\n }\n }\n\n // Case 3: Could not move within this bidi part in this visual line, so leave\n // the current bidi part\n\n var searchInVisualLine = function (partPos, dir, wrappedLineExtent) {\n var getRes = function (ch, moveInStorageOrder) { return moveInStorageOrder\n ? new Pos(start.line, mv(ch, 1), \"before\")\n : new Pos(start.line, ch, \"after\"); };\n\n for (; partPos >= 0 && partPos < bidi.length; partPos += dir) {\n var part = bidi[partPos];\n var moveInStorageOrder = (dir > 0) == (part.level != 1);\n var ch = moveInStorageOrder ? wrappedLineExtent.begin : mv(wrappedLineExtent.end, -1);\n if (part.from <= ch && ch < part.to) { return getRes(ch, moveInStorageOrder) }\n ch = moveInStorageOrder ? part.from : mv(part.to, -1);\n if (wrappedLineExtent.begin <= ch && ch < wrappedLineExtent.end) { return getRes(ch, moveInStorageOrder) }\n }\n };\n\n // Case 3a: Look for other bidi parts on the same visual line\n var res = searchInVisualLine(partPos + dir, dir, wrappedLineExtent);\n if (res) { return res }\n\n // Case 3b: Look for other bidi parts on the next visual line\n var nextCh = dir > 0 ? wrappedLineExtent.end : mv(wrappedLineExtent.begin, -1);\n if (nextCh != null && !(dir > 0 && nextCh == line.text.length)) {\n res = searchInVisualLine(dir > 0 ? 0 : bidi.length - 1, dir, getWrappedLineExtent(nextCh));\n if (res) { return res }\n }\n\n // Case 4: Nowhere to move\n return null\n }\n\n // Commands are parameter-less actions that can be performed on an\n // editor, mostly used for keybindings.\n var commands = {\n selectAll: selectAll,\n singleSelection: function (cm) { return cm.setSelection(cm.getCursor(\"anchor\"), cm.getCursor(\"head\"), sel_dontScroll); },\n killLine: function (cm) { return deleteNearSelection(cm, function (range) {\n if (range.empty()) {\n var len = getLine(cm.doc, range.head.line).text.length;\n if (range.head.ch == len && range.head.line < cm.lastLine())\n { return {from: range.head, to: Pos(range.head.line + 1, 0)} }\n else\n { return {from: range.head, to: Pos(range.head.line, len)} }\n } else {\n return {from: range.from(), to: range.to()}\n }\n }); },\n deleteLine: function (cm) { return deleteNearSelection(cm, function (range) { return ({\n from: Pos(range.from().line, 0),\n to: clipPos(cm.doc, Pos(range.to().line + 1, 0))\n }); }); },\n delLineLeft: function (cm) { return deleteNearSelection(cm, function (range) { return ({\n from: Pos(range.from().line, 0), to: range.from()\n }); }); },\n delWrappedLineLeft: function (cm) { return deleteNearSelection(cm, function (range) {\n var top = cm.charCoords(range.head, \"div\").top + 5;\n var leftPos = cm.coordsChar({left: 0, top: top}, \"div\");\n return {from: leftPos, to: range.from()}\n }); },\n delWrappedLineRight: function (cm) { return deleteNearSelection(cm, function (range) {\n var top = cm.charCoords(range.head, \"div\").top + 5;\n var rightPos = cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, \"div\");\n return {from: range.from(), to: rightPos }\n }); },\n undo: function (cm) { return cm.undo(); },\n redo: function (cm) { return cm.redo(); },\n undoSelection: function (cm) { return cm.undoSelection(); },\n redoSelection: function (cm) { return cm.redoSelection(); },\n goDocStart: function (cm) { return cm.extendSelection(Pos(cm.firstLine(), 0)); },\n goDocEnd: function (cm) { return cm.extendSelection(Pos(cm.lastLine())); },\n goLineStart: function (cm) { return cm.extendSelectionsBy(function (range) { return lineStart(cm, range.head.line); },\n {origin: \"+move\", bias: 1}\n ); },\n goLineStartSmart: function (cm) { return cm.extendSelectionsBy(function (range) { return lineStartSmart(cm, range.head); },\n {origin: \"+move\", bias: 1}\n ); },\n goLineEnd: function (cm) { return cm.extendSelectionsBy(function (range) { return lineEnd(cm, range.head.line); },\n {origin: \"+move\", bias: -1}\n ); },\n goLineRight: function (cm) { return cm.extendSelectionsBy(function (range) {\n var top = cm.cursorCoords(range.head, \"div\").top + 5;\n return cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, \"div\")\n }, sel_move); },\n goLineLeft: function (cm) { return cm.extendSelectionsBy(function (range) {\n var top = cm.cursorCoords(range.head, \"div\").top + 5;\n return cm.coordsChar({left: 0, top: top}, \"div\")\n }, sel_move); },\n goLineLeftSmart: function (cm) { return cm.extendSelectionsBy(function (range) {\n var top = cm.cursorCoords(range.head, \"div\").top + 5;\n var pos = cm.coordsChar({left: 0, top: top}, \"div\");\n if (pos.ch < cm.getLine(pos.line).search(/\\S/)) { return lineStartSmart(cm, range.head) }\n return pos\n }, sel_move); },\n goLineUp: function (cm) { return cm.moveV(-1, \"line\"); },\n goLineDown: function (cm) { return cm.moveV(1, \"line\"); },\n goPageUp: function (cm) { return cm.moveV(-1, \"page\"); },\n goPageDown: function (cm) { return cm.moveV(1, \"page\"); },\n goCharLeft: function (cm) { return cm.moveH(-1, \"char\"); },\n goCharRight: function (cm) { return cm.moveH(1, \"char\"); },\n goColumnLeft: function (cm) { return cm.moveH(-1, \"column\"); },\n goColumnRight: function (cm) { return cm.moveH(1, \"column\"); },\n goWordLeft: function (cm) { return cm.moveH(-1, \"word\"); },\n goGroupRight: function (cm) { return cm.moveH(1, \"group\"); },\n goGroupLeft: function (cm) { return cm.moveH(-1, \"group\"); },\n goWordRight: function (cm) { return cm.moveH(1, \"word\"); },\n delCharBefore: function (cm) { return cm.deleteH(-1, \"codepoint\"); },\n delCharAfter: function (cm) { return cm.deleteH(1, \"char\"); },\n delWordBefore: function (cm) { return cm.deleteH(-1, \"word\"); },\n delWordAfter: function (cm) { return cm.deleteH(1, \"word\"); },\n delGroupBefore: function (cm) { return cm.deleteH(-1, \"group\"); },\n delGroupAfter: function (cm) { return cm.deleteH(1, \"group\"); },\n indentAuto: function (cm) { return cm.indentSelection(\"smart\"); },\n indentMore: function (cm) { return cm.indentSelection(\"add\"); },\n indentLess: function (cm) { return cm.indentSelection(\"subtract\"); },\n insertTab: function (cm) { return cm.replaceSelection(\"\\t\"); },\n insertSoftTab: function (cm) {\n var spaces = [], ranges = cm.listSelections(), tabSize = cm.options.tabSize;\n for (var i = 0; i < ranges.length; i++) {\n var pos = ranges[i].from();\n var col = countColumn(cm.getLine(pos.line), pos.ch, tabSize);\n spaces.push(spaceStr(tabSize - col % tabSize));\n }\n cm.replaceSelections(spaces);\n },\n defaultTab: function (cm) {\n if (cm.somethingSelected()) { cm.indentSelection(\"add\"); }\n else { cm.execCommand(\"insertTab\"); }\n },\n // Swap the two chars left and right of each selection's head.\n // Move cursor behind the two swapped characters afterwards.\n //\n // Doesn't consider line feeds a character.\n // Doesn't scan more than one line above to find a character.\n // Doesn't do anything on an empty line.\n // Doesn't do anything with non-empty selections.\n transposeChars: function (cm) { return runInOp(cm, function () {\n var ranges = cm.listSelections(), newSel = [];\n for (var i = 0; i < ranges.length; i++) {\n if (!ranges[i].empty()) { continue }\n var cur = ranges[i].head, line = getLine(cm.doc, cur.line).text;\n if (line) {\n if (cur.ch == line.length) { cur = new Pos(cur.line, cur.ch - 1); }\n if (cur.ch > 0) {\n cur = new Pos(cur.line, cur.ch + 1);\n cm.replaceRange(line.charAt(cur.ch - 1) + line.charAt(cur.ch - 2),\n Pos(cur.line, cur.ch - 2), cur, \"+transpose\");\n } else if (cur.line > cm.doc.first) {\n var prev = getLine(cm.doc, cur.line - 1).text;\n if (prev) {\n cur = new Pos(cur.line, 1);\n cm.replaceRange(line.charAt(0) + cm.doc.lineSeparator() +\n prev.charAt(prev.length - 1),\n Pos(cur.line - 1, prev.length - 1), cur, \"+transpose\");\n }\n }\n }\n newSel.push(new Range(cur, cur));\n }\n cm.setSelections(newSel);\n }); },\n newlineAndIndent: function (cm) { return runInOp(cm, function () {\n var sels = cm.listSelections();\n for (var i = sels.length - 1; i >= 0; i--)\n { cm.replaceRange(cm.doc.lineSeparator(), sels[i].anchor, sels[i].head, \"+input\"); }\n sels = cm.listSelections();\n for (var i$1 = 0; i$1 < sels.length; i$1++)\n { cm.indentLine(sels[i$1].from().line, null, true); }\n ensureCursorVisible(cm);\n }); },\n openLine: function (cm) { return cm.replaceSelection(\"\\n\", \"start\"); },\n toggleOverwrite: function (cm) { return cm.toggleOverwrite(); }\n };\n\n\n function lineStart(cm, lineN) {\n var line = getLine(cm.doc, lineN);\n var visual = visualLine(line);\n if (visual != line) { lineN = lineNo(visual); }\n return endOfLine(true, cm, visual, lineN, 1)\n }\n function lineEnd(cm, lineN) {\n var line = getLine(cm.doc, lineN);\n var visual = visualLineEnd(line);\n if (visual != line) { lineN = lineNo(visual); }\n return endOfLine(true, cm, line, lineN, -1)\n }\n function lineStartSmart(cm, pos) {\n var start = lineStart(cm, pos.line);\n var line = getLine(cm.doc, start.line);\n var order = getOrder(line, cm.doc.direction);\n if (!order || order[0].level == 0) {\n var firstNonWS = Math.max(start.ch, line.text.search(/\\S/));\n var inWS = pos.line == start.line && pos.ch <= firstNonWS && pos.ch;\n return Pos(start.line, inWS ? 0 : firstNonWS, start.sticky)\n }\n return start\n }\n\n // Run a handler that was bound to a key.\n function doHandleBinding(cm, bound, dropShift) {\n if (typeof bound == \"string\") {\n bound = commands[bound];\n if (!bound) { return false }\n }\n // Ensure previous input has been read, so that the handler sees a\n // consistent view of the document\n cm.display.input.ensurePolled();\n var prevShift = cm.display.shift, done = false;\n try {\n if (cm.isReadOnly()) { cm.state.suppressEdits = true; }\n if (dropShift) { cm.display.shift = false; }\n done = bound(cm) != Pass;\n } finally {\n cm.display.shift = prevShift;\n cm.state.suppressEdits = false;\n }\n return done\n }\n\n function lookupKeyForEditor(cm, name, handle) {\n for (var i = 0; i < cm.state.keyMaps.length; i++) {\n var result = lookupKey(name, cm.state.keyMaps[i], handle, cm);\n if (result) { return result }\n }\n return (cm.options.extraKeys && lookupKey(name, cm.options.extraKeys, handle, cm))\n || lookupKey(name, cm.options.keyMap, handle, cm)\n }\n\n // Note that, despite the name, this function is also used to check\n // for bound mouse clicks.\n\n var stopSeq = new Delayed;\n\n function dispatchKey(cm, name, e, handle) {\n var seq = cm.state.keySeq;\n if (seq) {\n if (isModifierKey(name)) { return \"handled\" }\n if (/\\'$/.test(name))\n { cm.state.keySeq = null; }\n else\n { stopSeq.set(50, function () {\n if (cm.state.keySeq == seq) {\n cm.state.keySeq = null;\n cm.display.input.reset();\n }\n }); }\n if (dispatchKeyInner(cm, seq + \" \" + name, e, handle)) { return true }\n }\n return dispatchKeyInner(cm, name, e, handle)\n }\n\n function dispatchKeyInner(cm, name, e, handle) {\n var result = lookupKeyForEditor(cm, name, handle);\n\n if (result == \"multi\")\n { cm.state.keySeq = name; }\n if (result == \"handled\")\n { signalLater(cm, \"keyHandled\", cm, name, e); }\n\n if (result == \"handled\" || result == \"multi\") {\n e_preventDefault(e);\n restartBlink(cm);\n }\n\n return !!result\n }\n\n // Handle a key from the keydown event.\n function handleKeyBinding(cm, e) {\n var name = keyName(e, true);\n if (!name) { return false }\n\n if (e.shiftKey && !cm.state.keySeq) {\n // First try to resolve full name (including 'Shift-'). Failing\n // that, see if there is a cursor-motion command (starting with\n // 'go') bound to the keyname without 'Shift-'.\n return dispatchKey(cm, \"Shift-\" + name, e, function (b) { return doHandleBinding(cm, b, true); })\n || dispatchKey(cm, name, e, function (b) {\n if (typeof b == \"string\" ? /^go[A-Z]/.test(b) : b.motion)\n { return doHandleBinding(cm, b) }\n })\n } else {\n return dispatchKey(cm, name, e, function (b) { return doHandleBinding(cm, b); })\n }\n }\n\n // Handle a key from the keypress event\n function handleCharBinding(cm, e, ch) {\n return dispatchKey(cm, \"'\" + ch + \"'\", e, function (b) { return doHandleBinding(cm, b, true); })\n }\n\n var lastStoppedKey = null;\n function onKeyDown(e) {\n var cm = this;\n if (e.target && e.target != cm.display.input.getField()) { return }\n cm.curOp.focus = activeElt();\n if (signalDOMEvent(cm, e)) { return }\n // IE does strange things with escape.\n if (ie && ie_version < 11 && e.keyCode == 27) { e.returnValue = false; }\n var code = e.keyCode;\n cm.display.shift = code == 16 || e.shiftKey;\n var handled = handleKeyBinding(cm, e);\n if (presto) {\n lastStoppedKey = handled ? code : null;\n // Opera has no cut event... we try to at least catch the key combo\n if (!handled && code == 88 && !hasCopyEvent && (mac ? e.metaKey : e.ctrlKey))\n { cm.replaceSelection(\"\", null, \"cut\"); }\n }\n if (gecko && !mac && !handled && code == 46 && e.shiftKey && !e.ctrlKey && document.execCommand)\n { document.execCommand(\"cut\"); }\n\n // Turn mouse into crosshair when Alt is held on Mac.\n if (code == 18 && !/\\bCodeMirror-crosshair\\b/.test(cm.display.lineDiv.className))\n { showCrossHair(cm); }\n }\n\n function showCrossHair(cm) {\n var lineDiv = cm.display.lineDiv;\n addClass(lineDiv, \"CodeMirror-crosshair\");\n\n function up(e) {\n if (e.keyCode == 18 || !e.altKey) {\n rmClass(lineDiv, \"CodeMirror-crosshair\");\n off(document, \"keyup\", up);\n off(document, \"mouseover\", up);\n }\n }\n on(document, \"keyup\", up);\n on(document, \"mouseover\", up);\n }\n\n function onKeyUp(e) {\n if (e.keyCode == 16) { this.doc.sel.shift = false; }\n signalDOMEvent(this, e);\n }\n\n function onKeyPress(e) {\n var cm = this;\n if (e.target && e.target != cm.display.input.getField()) { return }\n if (eventInWidget(cm.display, e) || signalDOMEvent(cm, e) || e.ctrlKey && !e.altKey || mac && e.metaKey) { return }\n var keyCode = e.keyCode, charCode = e.charCode;\n if (presto && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return}\n if ((presto && (!e.which || e.which < 10)) && handleKeyBinding(cm, e)) { return }\n var ch = String.fromCharCode(charCode == null ? keyCode : charCode);\n // Some browsers fire keypress events for backspace\n if (ch == \"\\x08\") { return }\n if (handleCharBinding(cm, e, ch)) { return }\n cm.display.input.onKeyPress(e);\n }\n\n var DOUBLECLICK_DELAY = 400;\n\n var PastClick = function(time, pos, button) {\n this.time = time;\n this.pos = pos;\n this.button = button;\n };\n\n PastClick.prototype.compare = function (time, pos, button) {\n return this.time + DOUBLECLICK_DELAY > time &&\n cmp(pos, this.pos) == 0 && button == this.button\n };\n\n var lastClick, lastDoubleClick;\n function clickRepeat(pos, button) {\n var now = +new Date;\n if (lastDoubleClick && lastDoubleClick.compare(now, pos, button)) {\n lastClick = lastDoubleClick = null;\n return \"triple\"\n } else if (lastClick && lastClick.compare(now, pos, button)) {\n lastDoubleClick = new PastClick(now, pos, button);\n lastClick = null;\n return \"double\"\n } else {\n lastClick = new PastClick(now, pos, button);\n lastDoubleClick = null;\n return \"single\"\n }\n }\n\n // A mouse down can be a single click, double click, triple click,\n // start of selection drag, start of text drag, new cursor\n // (ctrl-click), rectangle drag (alt-drag), or xwin\n // middle-click-paste. Or it might be a click on something we should\n // not interfere with, such as a scrollbar or widget.\n function onMouseDown(e) {\n var cm = this, display = cm.display;\n if (signalDOMEvent(cm, e) || display.activeTouch && display.input.supportsTouch()) { return }\n display.input.ensurePolled();\n display.shift = e.shiftKey;\n\n if (eventInWidget(display, e)) {\n if (!webkit) {\n // Briefly turn off draggability, to allow widgets to do\n // normal dragging things.\n display.scroller.draggable = false;\n setTimeout(function () { return display.scroller.draggable = true; }, 100);\n }\n return\n }\n if (clickInGutter(cm, e)) { return }\n var pos = posFromMouse(cm, e), button = e_button(e), repeat = pos ? clickRepeat(pos, button) : \"single\";\n window.focus();\n\n // #3261: make sure, that we're not starting a second selection\n if (button == 1 && cm.state.selectingText)\n { cm.state.selectingText(e); }\n\n if (pos && handleMappedButton(cm, button, pos, repeat, e)) { return }\n\n if (button == 1) {\n if (pos) { leftButtonDown(cm, pos, repeat, e); }\n else if (e_target(e) == display.scroller) { e_preventDefault(e); }\n } else if (button == 2) {\n if (pos) { extendSelection(cm.doc, pos); }\n setTimeout(function () { return display.input.focus(); }, 20);\n } else if (button == 3) {\n if (captureRightClick) { cm.display.input.onContextMenu(e); }\n else { delayBlurEvent(cm); }\n }\n }\n\n function handleMappedButton(cm, button, pos, repeat, event) {\n var name = \"Click\";\n if (repeat == \"double\") { name = \"Double\" + name; }\n else if (repeat == \"triple\") { name = \"Triple\" + name; }\n name = (button == 1 ? \"Left\" : button == 2 ? \"Middle\" : \"Right\") + name;\n\n return dispatchKey(cm, addModifierNames(name, event), event, function (bound) {\n if (typeof bound == \"string\") { bound = commands[bound]; }\n if (!bound) { return false }\n var done = false;\n try {\n if (cm.isReadOnly()) { cm.state.suppressEdits = true; }\n done = bound(cm, pos) != Pass;\n } finally {\n cm.state.suppressEdits = false;\n }\n return done\n })\n }\n\n function configureMouse(cm, repeat, event) {\n var option = cm.getOption(\"configureMouse\");\n var value = option ? option(cm, repeat, event) : {};\n if (value.unit == null) {\n var rect = chromeOS ? event.shiftKey && event.metaKey : event.altKey;\n value.unit = rect ? \"rectangle\" : repeat == \"single\" ? \"char\" : repeat == \"double\" ? \"word\" : \"line\";\n }\n if (value.extend == null || cm.doc.extend) { value.extend = cm.doc.extend || event.shiftKey; }\n if (value.addNew == null) { value.addNew = mac ? event.metaKey : event.ctrlKey; }\n if (value.moveOnDrag == null) { value.moveOnDrag = !(mac ? event.altKey : event.ctrlKey); }\n return value\n }\n\n function leftButtonDown(cm, pos, repeat, event) {\n if (ie) { setTimeout(bind(ensureFocus, cm), 0); }\n else { cm.curOp.focus = activeElt(); }\n\n var behavior = configureMouse(cm, repeat, event);\n\n var sel = cm.doc.sel, contained;\n if (cm.options.dragDrop && dragAndDrop && !cm.isReadOnly() &&\n repeat == \"single\" && (contained = sel.contains(pos)) > -1 &&\n (cmp((contained = sel.ranges[contained]).from(), pos) < 0 || pos.xRel > 0) &&\n (cmp(contained.to(), pos) > 0 || pos.xRel < 0))\n { leftButtonStartDrag(cm, event, pos, behavior); }\n else\n { leftButtonSelect(cm, event, pos, behavior); }\n }\n\n // Start a text drag. When it ends, see if any dragging actually\n // happen, and treat as a click if it didn't.\n function leftButtonStartDrag(cm, event, pos, behavior) {\n var display = cm.display, moved = false;\n var dragEnd = operation(cm, function (e) {\n if (webkit) { display.scroller.draggable = false; }\n cm.state.draggingText = false;\n off(display.wrapper.ownerDocument, \"mouseup\", dragEnd);\n off(display.wrapper.ownerDocument, \"mousemove\", mouseMove);\n off(display.scroller, \"dragstart\", dragStart);\n off(display.scroller, \"drop\", dragEnd);\n if (!moved) {\n e_preventDefault(e);\n if (!behavior.addNew)\n { extendSelection(cm.doc, pos, null, null, behavior.extend); }\n // Work around unexplainable focus problem in IE9 (#2127) and Chrome (#3081)\n if ((webkit && !safari) || ie && ie_version == 9)\n { setTimeout(function () {display.wrapper.ownerDocument.body.focus({preventScroll: true}); display.input.focus();}, 20); }\n else\n { display.input.focus(); }\n }\n });\n var mouseMove = function(e2) {\n moved = moved || Math.abs(event.clientX - e2.clientX) + Math.abs(event.clientY - e2.clientY) >= 10;\n };\n var dragStart = function () { return moved = true; };\n // Let the drag handler handle this.\n if (webkit) { display.scroller.draggable = true; }\n cm.state.draggingText = dragEnd;\n dragEnd.copy = !behavior.moveOnDrag;\n // IE's approach to draggable\n if (display.scroller.dragDrop) { display.scroller.dragDrop(); }\n on(display.wrapper.ownerDocument, \"mouseup\", dragEnd);\n on(display.wrapper.ownerDocument, \"mousemove\", mouseMove);\n on(display.scroller, \"dragstart\", dragStart);\n on(display.scroller, \"drop\", dragEnd);\n\n delayBlurEvent(cm);\n setTimeout(function () { return display.input.focus(); }, 20);\n }\n\n function rangeForUnit(cm, pos, unit) {\n if (unit == \"char\") { return new Range(pos, pos) }\n if (unit == \"word\") { return cm.findWordAt(pos) }\n if (unit == \"line\") { return new Range(Pos(pos.line, 0), clipPos(cm.doc, Pos(pos.line + 1, 0))) }\n var result = unit(cm, pos);\n return new Range(result.from, result.to)\n }\n\n // Normal selection, as opposed to text dragging.\n function leftButtonSelect(cm, event, start, behavior) {\n var display = cm.display, doc = cm.doc;\n e_preventDefault(event);\n\n var ourRange, ourIndex, startSel = doc.sel, ranges = startSel.ranges;\n if (behavior.addNew && !behavior.extend) {\n ourIndex = doc.sel.contains(start);\n if (ourIndex > -1)\n { ourRange = ranges[ourIndex]; }\n else\n { ourRange = new Range(start, start); }\n } else {\n ourRange = doc.sel.primary();\n ourIndex = doc.sel.primIndex;\n }\n\n if (behavior.unit == \"rectangle\") {\n if (!behavior.addNew) { ourRange = new Range(start, start); }\n start = posFromMouse(cm, event, true, true);\n ourIndex = -1;\n } else {\n var range = rangeForUnit(cm, start, behavior.unit);\n if (behavior.extend)\n { ourRange = extendRange(ourRange, range.anchor, range.head, behavior.extend); }\n else\n { ourRange = range; }\n }\n\n if (!behavior.addNew) {\n ourIndex = 0;\n setSelection(doc, new Selection([ourRange], 0), sel_mouse);\n startSel = doc.sel;\n } else if (ourIndex == -1) {\n ourIndex = ranges.length;\n setSelection(doc, normalizeSelection(cm, ranges.concat([ourRange]), ourIndex),\n {scroll: false, origin: \"*mouse\"});\n } else if (ranges.length > 1 && ranges[ourIndex].empty() && behavior.unit == \"char\" && !behavior.extend) {\n setSelection(doc, normalizeSelection(cm, ranges.slice(0, ourIndex).concat(ranges.slice(ourIndex + 1)), 0),\n {scroll: false, origin: \"*mouse\"});\n startSel = doc.sel;\n } else {\n replaceOneSelection(doc, ourIndex, ourRange, sel_mouse);\n }\n\n var lastPos = start;\n function extendTo(pos) {\n if (cmp(lastPos, pos) == 0) { return }\n lastPos = pos;\n\n if (behavior.unit == \"rectangle\") {\n var ranges = [], tabSize = cm.options.tabSize;\n var startCol = countColumn(getLine(doc, start.line).text, start.ch, tabSize);\n var posCol = countColumn(getLine(doc, pos.line).text, pos.ch, tabSize);\n var left = Math.min(startCol, posCol), right = Math.max(startCol, posCol);\n for (var line = Math.min(start.line, pos.line), end = Math.min(cm.lastLine(), Math.max(start.line, pos.line));\n line <= end; line++) {\n var text = getLine(doc, line).text, leftPos = findColumn(text, left, tabSize);\n if (left == right)\n { ranges.push(new Range(Pos(line, leftPos), Pos(line, leftPos))); }\n else if (text.length > leftPos)\n { ranges.push(new Range(Pos(line, leftPos), Pos(line, findColumn(text, right, tabSize)))); }\n }\n if (!ranges.length) { ranges.push(new Range(start, start)); }\n setSelection(doc, normalizeSelection(cm, startSel.ranges.slice(0, ourIndex).concat(ranges), ourIndex),\n {origin: \"*mouse\", scroll: false});\n cm.scrollIntoView(pos);\n } else {\n var oldRange = ourRange;\n var range = rangeForUnit(cm, pos, behavior.unit);\n var anchor = oldRange.anchor, head;\n if (cmp(range.anchor, anchor) > 0) {\n head = range.head;\n anchor = minPos(oldRange.from(), range.anchor);\n } else {\n head = range.anchor;\n anchor = maxPos(oldRange.to(), range.head);\n }\n var ranges$1 = startSel.ranges.slice(0);\n ranges$1[ourIndex] = bidiSimplify(cm, new Range(clipPos(doc, anchor), head));\n setSelection(doc, normalizeSelection(cm, ranges$1, ourIndex), sel_mouse);\n }\n }\n\n var editorSize = display.wrapper.getBoundingClientRect();\n // Used to ensure timeout re-tries don't fire when another extend\n // happened in the meantime (clearTimeout isn't reliable -- at\n // least on Chrome, the timeouts still happen even when cleared,\n // if the clear happens after their scheduled firing time).\n var counter = 0;\n\n function extend(e) {\n var curCount = ++counter;\n var cur = posFromMouse(cm, e, true, behavior.unit == \"rectangle\");\n if (!cur) { return }\n if (cmp(cur, lastPos) != 0) {\n cm.curOp.focus = activeElt();\n extendTo(cur);\n var visible = visibleLines(display, doc);\n if (cur.line >= visible.to || cur.line < visible.from)\n { setTimeout(operation(cm, function () {if (counter == curCount) { extend(e); }}), 150); }\n } else {\n var outside = e.clientY < editorSize.top ? -20 : e.clientY > editorSize.bottom ? 20 : 0;\n if (outside) { setTimeout(operation(cm, function () {\n if (counter != curCount) { return }\n display.scroller.scrollTop += outside;\n extend(e);\n }), 50); }\n }\n }\n\n function done(e) {\n cm.state.selectingText = false;\n counter = Infinity;\n // If e is null or undefined we interpret this as someone trying\n // to explicitly cancel the selection rather than the user\n // letting go of the mouse button.\n if (e) {\n e_preventDefault(e);\n display.input.focus();\n }\n off(display.wrapper.ownerDocument, \"mousemove\", move);\n off(display.wrapper.ownerDocument, \"mouseup\", up);\n doc.history.lastSelOrigin = null;\n }\n\n var move = operation(cm, function (e) {\n if (e.buttons === 0 || !e_button(e)) { done(e); }\n else { extend(e); }\n });\n var up = operation(cm, done);\n cm.state.selectingText = up;\n on(display.wrapper.ownerDocument, \"mousemove\", move);\n on(display.wrapper.ownerDocument, \"mouseup\", up);\n }\n\n // Used when mouse-selecting to adjust the anchor to the proper side\n // of a bidi jump depending on the visual position of the head.\n function bidiSimplify(cm, range) {\n var anchor = range.anchor;\n var head = range.head;\n var anchorLine = getLine(cm.doc, anchor.line);\n if (cmp(anchor, head) == 0 && anchor.sticky == head.sticky) { return range }\n var order = getOrder(anchorLine);\n if (!order) { return range }\n var index = getBidiPartAt(order, anchor.ch, anchor.sticky), part = order[index];\n if (part.from != anchor.ch && part.to != anchor.ch) { return range }\n var boundary = index + ((part.from == anchor.ch) == (part.level != 1) ? 0 : 1);\n if (boundary == 0 || boundary == order.length) { return range }\n\n // Compute the relative visual position of the head compared to the\n // anchor (<0 is to the left, >0 to the right)\n var leftSide;\n if (head.line != anchor.line) {\n leftSide = (head.line - anchor.line) * (cm.doc.direction == \"ltr\" ? 1 : -1) > 0;\n } else {\n var headIndex = getBidiPartAt(order, head.ch, head.sticky);\n var dir = headIndex - index || (head.ch - anchor.ch) * (part.level == 1 ? -1 : 1);\n if (headIndex == boundary - 1 || headIndex == boundary)\n { leftSide = dir < 0; }\n else\n { leftSide = dir > 0; }\n }\n\n var usePart = order[boundary + (leftSide ? -1 : 0)];\n var from = leftSide == (usePart.level == 1);\n var ch = from ? usePart.from : usePart.to, sticky = from ? \"after\" : \"before\";\n return anchor.ch == ch && anchor.sticky == sticky ? range : new Range(new Pos(anchor.line, ch, sticky), head)\n }\n\n\n // Determines whether an event happened in the gutter, and fires the\n // handlers for the corresponding event.\n function gutterEvent(cm, e, type, prevent) {\n var mX, mY;\n if (e.touches) {\n mX = e.touches[0].clientX;\n mY = e.touches[0].clientY;\n } else {\n try { mX = e.clientX; mY = e.clientY; }\n catch(e$1) { return false }\n }\n if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) { return false }\n if (prevent) { e_preventDefault(e); }\n\n var display = cm.display;\n var lineBox = display.lineDiv.getBoundingClientRect();\n\n if (mY > lineBox.bottom || !hasHandler(cm, type)) { return e_defaultPrevented(e) }\n mY -= lineBox.top - display.viewOffset;\n\n for (var i = 0; i < cm.display.gutterSpecs.length; ++i) {\n var g = display.gutters.childNodes[i];\n if (g && g.getBoundingClientRect().right >= mX) {\n var line = lineAtHeight(cm.doc, mY);\n var gutter = cm.display.gutterSpecs[i];\n signal(cm, type, cm, line, gutter.className, e);\n return e_defaultPrevented(e)\n }\n }\n }\n\n function clickInGutter(cm, e) {\n return gutterEvent(cm, e, \"gutterClick\", true)\n }\n\n // CONTEXT MENU HANDLING\n\n // To make the context menu work, we need to briefly unhide the\n // textarea (making it as unobtrusive as possible) to let the\n // right-click take effect on it.\n function onContextMenu(cm, e) {\n if (eventInWidget(cm.display, e) || contextMenuInGutter(cm, e)) { return }\n if (signalDOMEvent(cm, e, \"contextmenu\")) { return }\n if (!captureRightClick) { cm.display.input.onContextMenu(e); }\n }\n\n function contextMenuInGutter(cm, e) {\n if (!hasHandler(cm, \"gutterContextMenu\")) { return false }\n return gutterEvent(cm, e, \"gutterContextMenu\", false)\n }\n\n function themeChanged(cm) {\n cm.display.wrapper.className = cm.display.wrapper.className.replace(/\\s*cm-s-\\S+/g, \"\") +\n cm.options.theme.replace(/(^|\\s)\\s*/g, \" cm-s-\");\n clearCaches(cm);\n }\n\n var Init = {toString: function(){return \"CodeMirror.Init\"}};\n\n var defaults = {};\n var optionHandlers = {};\n\n function defineOptions(CodeMirror) {\n var optionHandlers = CodeMirror.optionHandlers;\n\n function option(name, deflt, handle, notOnInit) {\n CodeMirror.defaults[name] = deflt;\n if (handle) { optionHandlers[name] =\n notOnInit ? function (cm, val, old) {if (old != Init) { handle(cm, val, old); }} : handle; }\n }\n\n CodeMirror.defineOption = option;\n\n // Passed to option handlers when there is no old value.\n CodeMirror.Init = Init;\n\n // These two are, on init, called from the constructor because they\n // have to be initialized before the editor can start at all.\n option(\"value\", \"\", function (cm, val) { return cm.setValue(val); }, true);\n option(\"mode\", null, function (cm, val) {\n cm.doc.modeOption = val;\n loadMode(cm);\n }, true);\n\n option(\"indentUnit\", 2, loadMode, true);\n option(\"indentWithTabs\", false);\n option(\"smartIndent\", true);\n option(\"tabSize\", 4, function (cm) {\n resetModeState(cm);\n clearCaches(cm);\n regChange(cm);\n }, true);\n\n option(\"lineSeparator\", null, function (cm, val) {\n cm.doc.lineSep = val;\n if (!val) { return }\n var newBreaks = [], lineNo = cm.doc.first;\n cm.doc.iter(function (line) {\n for (var pos = 0;;) {\n var found = line.text.indexOf(val, pos);\n if (found == -1) { break }\n pos = found + val.length;\n newBreaks.push(Pos(lineNo, found));\n }\n lineNo++;\n });\n for (var i = newBreaks.length - 1; i >= 0; i--)\n { replaceRange(cm.doc, val, newBreaks[i], Pos(newBreaks[i].line, newBreaks[i].ch + val.length)); }\n });\n option(\"specialChars\", /[\\u0000-\\u001f\\u007f-\\u009f\\u00ad\\u061c\\u200b-\\u200c\\u200e\\u200f\\u2028\\u2029\\ufeff\\ufff9-\\ufffc]/g, function (cm, val, old) {\n cm.state.specialChars = new RegExp(val.source + (val.test(\"\\t\") ? \"\" : \"|\\t\"), \"g\");\n if (old != Init) { cm.refresh(); }\n });\n option(\"specialCharPlaceholder\", defaultSpecialCharPlaceholder, function (cm) { return cm.refresh(); }, true);\n option(\"electricChars\", true);\n option(\"inputStyle\", mobile ? \"contenteditable\" : \"textarea\", function () {\n throw new Error(\"inputStyle can not (yet) be changed in a running editor\") // FIXME\n }, true);\n option(\"spellcheck\", false, function (cm, val) { return cm.getInputField().spellcheck = val; }, true);\n option(\"autocorrect\", false, function (cm, val) { return cm.getInputField().autocorrect = val; }, true);\n option(\"autocapitalize\", false, function (cm, val) { return cm.getInputField().autocapitalize = val; }, true);\n option(\"rtlMoveVisually\", !windows);\n option(\"wholeLineUpdateBefore\", true);\n\n option(\"theme\", \"default\", function (cm) {\n themeChanged(cm);\n updateGutters(cm);\n }, true);\n option(\"keyMap\", \"default\", function (cm, val, old) {\n var next = getKeyMap(val);\n var prev = old != Init && getKeyMap(old);\n if (prev && prev.detach) { prev.detach(cm, next); }\n if (next.attach) { next.attach(cm, prev || null); }\n });\n option(\"extraKeys\", null);\n option(\"configureMouse\", null);\n\n option(\"lineWrapping\", false, wrappingChanged, true);\n option(\"gutters\", [], function (cm, val) {\n cm.display.gutterSpecs = getGutters(val, cm.options.lineNumbers);\n updateGutters(cm);\n }, true);\n option(\"fixedGutter\", true, function (cm, val) {\n cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + \"px\" : \"0\";\n cm.refresh();\n }, true);\n option(\"coverGutterNextToScrollbar\", false, function (cm) { return updateScrollbars(cm); }, true);\n option(\"scrollbarStyle\", \"native\", function (cm) {\n initScrollbars(cm);\n updateScrollbars(cm);\n cm.display.scrollbars.setScrollTop(cm.doc.scrollTop);\n cm.display.scrollbars.setScrollLeft(cm.doc.scrollLeft);\n }, true);\n option(\"lineNumbers\", false, function (cm, val) {\n cm.display.gutterSpecs = getGutters(cm.options.gutters, val);\n updateGutters(cm);\n }, true);\n option(\"firstLineNumber\", 1, updateGutters, true);\n option(\"lineNumberFormatter\", function (integer) { return integer; }, updateGutters, true);\n option(\"showCursorWhenSelecting\", false, updateSelection, true);\n\n option(\"resetSelectionOnContextMenu\", true);\n option(\"lineWiseCopyCut\", true);\n option(\"pasteLinesPerSelection\", true);\n option(\"selectionsMayTouch\", false);\n\n option(\"readOnly\", false, function (cm, val) {\n if (val == \"nocursor\") {\n onBlur(cm);\n cm.display.input.blur();\n }\n cm.display.input.readOnlyChanged(val);\n });\n\n option(\"screenReaderLabel\", null, function (cm, val) {\n val = (val === '') ? null : val;\n cm.display.input.screenReaderLabelChanged(val);\n });\n\n option(\"disableInput\", false, function (cm, val) {if (!val) { cm.display.input.reset(); }}, true);\n option(\"dragDrop\", true, dragDropChanged);\n option(\"allowDropFileTypes\", null);\n\n option(\"cursorBlinkRate\", 530);\n option(\"cursorScrollMargin\", 0);\n option(\"cursorHeight\", 1, updateSelection, true);\n option(\"singleCursorHeightPerLine\", true, updateSelection, true);\n option(\"workTime\", 100);\n option(\"workDelay\", 100);\n option(\"flattenSpans\", true, resetModeState, true);\n option(\"addModeClass\", false, resetModeState, true);\n option(\"pollInterval\", 100);\n option(\"undoDepth\", 200, function (cm, val) { return cm.doc.history.undoDepth = val; });\n option(\"historyEventDelay\", 1250);\n option(\"viewportMargin\", 10, function (cm) { return cm.refresh(); }, true);\n option(\"maxHighlightLength\", 10000, resetModeState, true);\n option(\"moveInputWithCursor\", true, function (cm, val) {\n if (!val) { cm.display.input.resetPosition(); }\n });\n\n option(\"tabindex\", null, function (cm, val) { return cm.display.input.getField().tabIndex = val || \"\"; });\n option(\"autofocus\", null);\n option(\"direction\", \"ltr\", function (cm, val) { return cm.doc.setDirection(val); }, true);\n option(\"phrases\", null);\n }\n\n function dragDropChanged(cm, value, old) {\n var wasOn = old && old != Init;\n if (!value != !wasOn) {\n var funcs = cm.display.dragFunctions;\n var toggle = value ? on : off;\n toggle(cm.display.scroller, \"dragstart\", funcs.start);\n toggle(cm.display.scroller, \"dragenter\", funcs.enter);\n toggle(cm.display.scroller, \"dragover\", funcs.over);\n toggle(cm.display.scroller, \"dragleave\", funcs.leave);\n toggle(cm.display.scroller, \"drop\", funcs.drop);\n }\n }\n\n function wrappingChanged(cm) {\n if (cm.options.lineWrapping) {\n addClass(cm.display.wrapper, \"CodeMirror-wrap\");\n cm.display.sizer.style.minWidth = \"\";\n cm.display.sizerWidth = null;\n } else {\n rmClass(cm.display.wrapper, \"CodeMirror-wrap\");\n findMaxLine(cm);\n }\n estimateLineHeights(cm);\n regChange(cm);\n clearCaches(cm);\n setTimeout(function () { return updateScrollbars(cm); }, 100);\n }\n\n // A CodeMirror instance represents an editor. This is the object\n // that user code is usually dealing with.\n\n function CodeMirror(place, options) {\n var this$1 = this;\n\n if (!(this instanceof CodeMirror)) { return new CodeMirror(place, options) }\n\n this.options = options = options ? copyObj(options) : {};\n // Determine effective options based on given values and defaults.\n copyObj(defaults, options, false);\n\n var doc = options.value;\n if (typeof doc == \"string\") { doc = new Doc(doc, options.mode, null, options.lineSeparator, options.direction); }\n else if (options.mode) { doc.modeOption = options.mode; }\n this.doc = doc;\n\n var input = new CodeMirror.inputStyles[options.inputStyle](this);\n var display = this.display = new Display(place, doc, input, options);\n display.wrapper.CodeMirror = this;\n themeChanged(this);\n if (options.lineWrapping)\n { this.display.wrapper.className += \" CodeMirror-wrap\"; }\n initScrollbars(this);\n\n this.state = {\n keyMaps: [], // stores maps added by addKeyMap\n overlays: [], // highlighting overlays, as added by addOverlay\n modeGen: 0, // bumped when mode/overlay changes, used to invalidate highlighting info\n overwrite: false,\n delayingBlurEvent: false,\n focused: false,\n suppressEdits: false, // used to disable editing during key handlers when in readOnly mode\n pasteIncoming: -1, cutIncoming: -1, // help recognize paste/cut edits in input.poll\n selectingText: false,\n draggingText: false,\n highlight: new Delayed(), // stores highlight worker timeout\n keySeq: null, // Unfinished key sequence\n specialChars: null\n };\n\n if (options.autofocus && !mobile) { display.input.focus(); }\n\n // Override magic textarea content restore that IE sometimes does\n // on our hidden textarea on reload\n if (ie && ie_version < 11) { setTimeout(function () { return this$1.display.input.reset(true); }, 20); }\n\n registerEventHandlers(this);\n ensureGlobalHandlers();\n\n startOperation(this);\n this.curOp.forceUpdate = true;\n attachDoc(this, doc);\n\n if ((options.autofocus && !mobile) || this.hasFocus())\n { setTimeout(function () {\n if (this$1.hasFocus() && !this$1.state.focused) { onFocus(this$1); }\n }, 20); }\n else\n { onBlur(this); }\n\n for (var opt in optionHandlers) { if (optionHandlers.hasOwnProperty(opt))\n { optionHandlers[opt](this, options[opt], Init); } }\n maybeUpdateLineNumberWidth(this);\n if (options.finishInit) { options.finishInit(this); }\n for (var i = 0; i < initHooks.length; ++i) { initHooks[i](this); }\n endOperation(this);\n // Suppress optimizelegibility in Webkit, since it breaks text\n // measuring on line wrapping boundaries.\n if (webkit && options.lineWrapping &&\n getComputedStyle(display.lineDiv).textRendering == \"optimizelegibility\")\n { display.lineDiv.style.textRendering = \"auto\"; }\n }\n\n // The default configuration options.\n CodeMirror.defaults = defaults;\n // Functions to run when options are changed.\n CodeMirror.optionHandlers = optionHandlers;\n\n // Attach the necessary event handlers when initializing the editor\n function registerEventHandlers(cm) {\n var d = cm.display;\n on(d.scroller, \"mousedown\", operation(cm, onMouseDown));\n // Older IE's will not fire a second mousedown for a double click\n if (ie && ie_version < 11)\n { on(d.scroller, \"dblclick\", operation(cm, function (e) {\n if (signalDOMEvent(cm, e)) { return }\n var pos = posFromMouse(cm, e);\n if (!pos || clickInGutter(cm, e) || eventInWidget(cm.display, e)) { return }\n e_preventDefault(e);\n var word = cm.findWordAt(pos);\n extendSelection(cm.doc, word.anchor, word.head);\n })); }\n else\n { on(d.scroller, \"dblclick\", function (e) { return signalDOMEvent(cm, e) || e_preventDefault(e); }); }\n // Some browsers fire contextmenu *after* opening the menu, at\n // which point we can't mess with it anymore. Context menu is\n // handled in onMouseDown for these browsers.\n on(d.scroller, \"contextmenu\", function (e) { return onContextMenu(cm, e); });\n on(d.input.getField(), \"contextmenu\", function (e) {\n if (!d.scroller.contains(e.target)) { onContextMenu(cm, e); }\n });\n\n // Used to suppress mouse event handling when a touch happens\n var touchFinished, prevTouch = {end: 0};\n function finishTouch() {\n if (d.activeTouch) {\n touchFinished = setTimeout(function () { return d.activeTouch = null; }, 1000);\n prevTouch = d.activeTouch;\n prevTouch.end = +new Date;\n }\n }\n function isMouseLikeTouchEvent(e) {\n if (e.touches.length != 1) { return false }\n var touch = e.touches[0];\n return touch.radiusX <= 1 && touch.radiusY <= 1\n }\n function farAway(touch, other) {\n if (other.left == null) { return true }\n var dx = other.left - touch.left, dy = other.top - touch.top;\n return dx * dx + dy * dy > 20 * 20\n }\n on(d.scroller, \"touchstart\", function (e) {\n if (!signalDOMEvent(cm, e) && !isMouseLikeTouchEvent(e) && !clickInGutter(cm, e)) {\n d.input.ensurePolled();\n clearTimeout(touchFinished);\n var now = +new Date;\n d.activeTouch = {start: now, moved: false,\n prev: now - prevTouch.end <= 300 ? prevTouch : null};\n if (e.touches.length == 1) {\n d.activeTouch.left = e.touches[0].pageX;\n d.activeTouch.top = e.touches[0].pageY;\n }\n }\n });\n on(d.scroller, \"touchmove\", function () {\n if (d.activeTouch) { d.activeTouch.moved = true; }\n });\n on(d.scroller, \"touchend\", function (e) {\n var touch = d.activeTouch;\n if (touch && !eventInWidget(d, e) && touch.left != null &&\n !touch.moved && new Date - touch.start < 300) {\n var pos = cm.coordsChar(d.activeTouch, \"page\"), range;\n if (!touch.prev || farAway(touch, touch.prev)) // Single tap\n { range = new Range(pos, pos); }\n else if (!touch.prev.prev || farAway(touch, touch.prev.prev)) // Double tap\n { range = cm.findWordAt(pos); }\n else // Triple tap\n { range = new Range(Pos(pos.line, 0), clipPos(cm.doc, Pos(pos.line + 1, 0))); }\n cm.setSelection(range.anchor, range.head);\n cm.focus();\n e_preventDefault(e);\n }\n finishTouch();\n });\n on(d.scroller, \"touchcancel\", finishTouch);\n\n // Sync scrolling between fake scrollbars and real scrollable\n // area, ensure viewport is updated when scrolling.\n on(d.scroller, \"scroll\", function () {\n if (d.scroller.clientHeight) {\n updateScrollTop(cm, d.scroller.scrollTop);\n setScrollLeft(cm, d.scroller.scrollLeft, true);\n signal(cm, \"scroll\", cm);\n }\n });\n\n // Listen to wheel events in order to try and update the viewport on time.\n on(d.scroller, \"mousewheel\", function (e) { return onScrollWheel(cm, e); });\n on(d.scroller, \"DOMMouseScroll\", function (e) { return onScrollWheel(cm, e); });\n\n // Prevent wrapper from ever scrolling\n on(d.wrapper, \"scroll\", function () { return d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; });\n\n d.dragFunctions = {\n enter: function (e) {if (!signalDOMEvent(cm, e)) { e_stop(e); }},\n over: function (e) {if (!signalDOMEvent(cm, e)) { onDragOver(cm, e); e_stop(e); }},\n start: function (e) { return onDragStart(cm, e); },\n drop: operation(cm, onDrop),\n leave: function (e) {if (!signalDOMEvent(cm, e)) { clearDragCursor(cm); }}\n };\n\n var inp = d.input.getField();\n on(inp, \"keyup\", function (e) { return onKeyUp.call(cm, e); });\n on(inp, \"keydown\", operation(cm, onKeyDown));\n on(inp, \"keypress\", operation(cm, onKeyPress));\n on(inp, \"focus\", function (e) { return onFocus(cm, e); });\n on(inp, \"blur\", function (e) { return onBlur(cm, e); });\n }\n\n var initHooks = [];\n CodeMirror.defineInitHook = function (f) { return initHooks.push(f); };\n\n // Indent the given line. The how parameter can be \"smart\",\n // \"add\"/null, \"subtract\", or \"prev\". When aggressive is false\n // (typically set to true for forced single-line indents), empty\n // lines are not indented, and places where the mode returns Pass\n // are left alone.\n function indentLine(cm, n, how, aggressive) {\n var doc = cm.doc, state;\n if (how == null) { how = \"add\"; }\n if (how == \"smart\") {\n // Fall back to \"prev\" when the mode doesn't have an indentation\n // method.\n if (!doc.mode.indent) { how = \"prev\"; }\n else { state = getContextBefore(cm, n).state; }\n }\n\n var tabSize = cm.options.tabSize;\n var line = getLine(doc, n), curSpace = countColumn(line.text, null, tabSize);\n if (line.stateAfter) { line.stateAfter = null; }\n var curSpaceString = line.text.match(/^\\s*/)[0], indentation;\n if (!aggressive && !/\\S/.test(line.text)) {\n indentation = 0;\n how = \"not\";\n } else if (how == \"smart\") {\n indentation = doc.mode.indent(state, line.text.slice(curSpaceString.length), line.text);\n if (indentation == Pass || indentation > 150) {\n if (!aggressive) { return }\n how = \"prev\";\n }\n }\n if (how == \"prev\") {\n if (n > doc.first) { indentation = countColumn(getLine(doc, n-1).text, null, tabSize); }\n else { indentation = 0; }\n } else if (how == \"add\") {\n indentation = curSpace + cm.options.indentUnit;\n } else if (how == \"subtract\") {\n indentation = curSpace - cm.options.indentUnit;\n } else if (typeof how == \"number\") {\n indentation = curSpace + how;\n }\n indentation = Math.max(0, indentation);\n\n var indentString = \"\", pos = 0;\n if (cm.options.indentWithTabs)\n { for (var i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += \"\\t\";} }\n if (pos < indentation) { indentString += spaceStr(indentation - pos); }\n\n if (indentString != curSpaceString) {\n replaceRange(doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), \"+input\");\n line.stateAfter = null;\n return true\n } else {\n // Ensure that, if the cursor was in the whitespace at the start\n // of the line, it is moved to the end of that space.\n for (var i$1 = 0; i$1 < doc.sel.ranges.length; i$1++) {\n var range = doc.sel.ranges[i$1];\n if (range.head.line == n && range.head.ch < curSpaceString.length) {\n var pos$1 = Pos(n, curSpaceString.length);\n replaceOneSelection(doc, i$1, new Range(pos$1, pos$1));\n break\n }\n }\n }\n }\n\n // This will be set to a {lineWise: bool, text: [string]} object, so\n // that, when pasting, we know what kind of selections the copied\n // text was made out of.\n var lastCopied = null;\n\n function setLastCopied(newLastCopied) {\n lastCopied = newLastCopied;\n }\n\n function applyTextInput(cm, inserted, deleted, sel, origin) {\n var doc = cm.doc;\n cm.display.shift = false;\n if (!sel) { sel = doc.sel; }\n\n var recent = +new Date - 200;\n var paste = origin == \"paste\" || cm.state.pasteIncoming > recent;\n var textLines = splitLinesAuto(inserted), multiPaste = null;\n // When pasting N lines into N selections, insert one line per selection\n if (paste && sel.ranges.length > 1) {\n if (lastCopied && lastCopied.text.join(\"\\n\") == inserted) {\n if (sel.ranges.length % lastCopied.text.length == 0) {\n multiPaste = [];\n for (var i = 0; i < lastCopied.text.length; i++)\n { multiPaste.push(doc.splitLines(lastCopied.text[i])); }\n }\n } else if (textLines.length == sel.ranges.length && cm.options.pasteLinesPerSelection) {\n multiPaste = map(textLines, function (l) { return [l]; });\n }\n }\n\n var updateInput = cm.curOp.updateInput;\n // Normal behavior is to insert the new text into every selection\n for (var i$1 = sel.ranges.length - 1; i$1 >= 0; i$1--) {\n var range = sel.ranges[i$1];\n var from = range.from(), to = range.to();\n if (range.empty()) {\n if (deleted && deleted > 0) // Handle deletion\n { from = Pos(from.line, from.ch - deleted); }\n else if (cm.state.overwrite && !paste) // Handle overwrite\n { to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + lst(textLines).length)); }\n else if (paste && lastCopied && lastCopied.lineWise && lastCopied.text.join(\"\\n\") == textLines.join(\"\\n\"))\n { from = to = Pos(from.line, 0); }\n }\n var changeEvent = {from: from, to: to, text: multiPaste ? multiPaste[i$1 % multiPaste.length] : textLines,\n origin: origin || (paste ? \"paste\" : cm.state.cutIncoming > recent ? \"cut\" : \"+input\")};\n makeChange(cm.doc, changeEvent);\n signalLater(cm, \"inputRead\", cm, changeEvent);\n }\n if (inserted && !paste)\n { triggerElectric(cm, inserted); }\n\n ensureCursorVisible(cm);\n if (cm.curOp.updateInput < 2) { cm.curOp.updateInput = updateInput; }\n cm.curOp.typing = true;\n cm.state.pasteIncoming = cm.state.cutIncoming = -1;\n }\n\n function handlePaste(e, cm) {\n var pasted = e.clipboardData && e.clipboardData.getData(\"Text\");\n if (pasted) {\n e.preventDefault();\n if (!cm.isReadOnly() && !cm.options.disableInput)\n { runInOp(cm, function () { return applyTextInput(cm, pasted, 0, null, \"paste\"); }); }\n return true\n }\n }\n\n function triggerElectric(cm, inserted) {\n // When an 'electric' character is inserted, immediately trigger a reindent\n if (!cm.options.electricChars || !cm.options.smartIndent) { return }\n var sel = cm.doc.sel;\n\n for (var i = sel.ranges.length - 1; i >= 0; i--) {\n var range = sel.ranges[i];\n if (range.head.ch > 100 || (i && sel.ranges[i - 1].head.line == range.head.line)) { continue }\n var mode = cm.getModeAt(range.head);\n var indented = false;\n if (mode.electricChars) {\n for (var j = 0; j < mode.electricChars.length; j++)\n { if (inserted.indexOf(mode.electricChars.charAt(j)) > -1) {\n indented = indentLine(cm, range.head.line, \"smart\");\n break\n } }\n } else if (mode.electricInput) {\n if (mode.electricInput.test(getLine(cm.doc, range.head.line).text.slice(0, range.head.ch)))\n { indented = indentLine(cm, range.head.line, \"smart\"); }\n }\n if (indented) { signalLater(cm, \"electricInput\", cm, range.head.line); }\n }\n }\n\n function copyableRanges(cm) {\n var text = [], ranges = [];\n for (var i = 0; i < cm.doc.sel.ranges.length; i++) {\n var line = cm.doc.sel.ranges[i].head.line;\n var lineRange = {anchor: Pos(line, 0), head: Pos(line + 1, 0)};\n ranges.push(lineRange);\n text.push(cm.getRange(lineRange.anchor, lineRange.head));\n }\n return {text: text, ranges: ranges}\n }\n\n function disableBrowserMagic(field, spellcheck, autocorrect, autocapitalize) {\n field.setAttribute(\"autocorrect\", autocorrect ? \"\" : \"off\");\n field.setAttribute(\"autocapitalize\", autocapitalize ? \"\" : \"off\");\n field.setAttribute(\"spellcheck\", !!spellcheck);\n }\n\n function hiddenTextarea() {\n var te = elt(\"textarea\", null, null, \"position: absolute; bottom: -1em; padding: 0; width: 1px; height: 1em; outline: none\");\n var div = elt(\"div\", [te], null, \"overflow: hidden; position: relative; width: 3px; height: 0px;\");\n // The textarea is kept positioned near the cursor to prevent the\n // fact that it'll be scrolled into view on input from scrolling\n // our fake cursor out of view. On webkit, when wrap=off, paste is\n // very slow. So make the area wide instead.\n if (webkit) { te.style.width = \"1000px\"; }\n else { te.setAttribute(\"wrap\", \"off\"); }\n // If border: 0; -- iOS fails to open keyboard (issue #1287)\n if (ios) { te.style.border = \"1px solid black\"; }\n disableBrowserMagic(te);\n return div\n }\n\n // The publicly visible API. Note that methodOp(f) means\n // 'wrap f in an operation, performed on its `this` parameter'.\n\n // This is not the complete set of editor methods. Most of the\n // methods defined on the Doc type are also injected into\n // CodeMirror.prototype, for backwards compatibility and\n // convenience.\n\n function addEditorMethods(CodeMirror) {\n var optionHandlers = CodeMirror.optionHandlers;\n\n var helpers = CodeMirror.helpers = {};\n\n CodeMirror.prototype = {\n constructor: CodeMirror,\n focus: function(){window.focus(); this.display.input.focus();},\n\n setOption: function(option, value) {\n var options = this.options, old = options[option];\n if (options[option] == value && option != \"mode\") { return }\n options[option] = value;\n if (optionHandlers.hasOwnProperty(option))\n { operation(this, optionHandlers[option])(this, value, old); }\n signal(this, \"optionChange\", this, option);\n },\n\n getOption: function(option) {return this.options[option]},\n getDoc: function() {return this.doc},\n\n addKeyMap: function(map, bottom) {\n this.state.keyMaps[bottom ? \"push\" : \"unshift\"](getKeyMap(map));\n },\n removeKeyMap: function(map) {\n var maps = this.state.keyMaps;\n for (var i = 0; i < maps.length; ++i)\n { if (maps[i] == map || maps[i].name == map) {\n maps.splice(i, 1);\n return true\n } }\n },\n\n addOverlay: methodOp(function(spec, options) {\n var mode = spec.token ? spec : CodeMirror.getMode(this.options, spec);\n if (mode.startState) { throw new Error(\"Overlays may not be stateful.\") }\n insertSorted(this.state.overlays,\n {mode: mode, modeSpec: spec, opaque: options && options.opaque,\n priority: (options && options.priority) || 0},\n function (overlay) { return overlay.priority; });\n this.state.modeGen++;\n regChange(this);\n }),\n removeOverlay: methodOp(function(spec) {\n var overlays = this.state.overlays;\n for (var i = 0; i < overlays.length; ++i) {\n var cur = overlays[i].modeSpec;\n if (cur == spec || typeof spec == \"string\" && cur.name == spec) {\n overlays.splice(i, 1);\n this.state.modeGen++;\n regChange(this);\n return\n }\n }\n }),\n\n indentLine: methodOp(function(n, dir, aggressive) {\n if (typeof dir != \"string\" && typeof dir != \"number\") {\n if (dir == null) { dir = this.options.smartIndent ? \"smart\" : \"prev\"; }\n else { dir = dir ? \"add\" : \"subtract\"; }\n }\n if (isLine(this.doc, n)) { indentLine(this, n, dir, aggressive); }\n }),\n indentSelection: methodOp(function(how) {\n var ranges = this.doc.sel.ranges, end = -1;\n for (var i = 0; i < ranges.length; i++) {\n var range = ranges[i];\n if (!range.empty()) {\n var from = range.from(), to = range.to();\n var start = Math.max(end, from.line);\n end = Math.min(this.lastLine(), to.line - (to.ch ? 0 : 1)) + 1;\n for (var j = start; j < end; ++j)\n { indentLine(this, j, how); }\n var newRanges = this.doc.sel.ranges;\n if (from.ch == 0 && ranges.length == newRanges.length && newRanges[i].from().ch > 0)\n { replaceOneSelection(this.doc, i, new Range(from, newRanges[i].to()), sel_dontScroll); }\n } else if (range.head.line > end) {\n indentLine(this, range.head.line, how, true);\n end = range.head.line;\n if (i == this.doc.sel.primIndex) { ensureCursorVisible(this); }\n }\n }\n }),\n\n // Fetch the parser token for a given character. Useful for hacks\n // that want to inspect the mode state (say, for completion).\n getTokenAt: function(pos, precise) {\n return takeToken(this, pos, precise)\n },\n\n getLineTokens: function(line, precise) {\n return takeToken(this, Pos(line), precise, true)\n },\n\n getTokenTypeAt: function(pos) {\n pos = clipPos(this.doc, pos);\n var styles = getLineStyles(this, getLine(this.doc, pos.line));\n var before = 0, after = (styles.length - 1) / 2, ch = pos.ch;\n var type;\n if (ch == 0) { type = styles[2]; }\n else { for (;;) {\n var mid = (before + after) >> 1;\n if ((mid ? styles[mid * 2 - 1] : 0) >= ch) { after = mid; }\n else if (styles[mid * 2 + 1] < ch) { before = mid + 1; }\n else { type = styles[mid * 2 + 2]; break }\n } }\n var cut = type ? type.indexOf(\"overlay \") : -1;\n return cut < 0 ? type : cut == 0 ? null : type.slice(0, cut - 1)\n },\n\n getModeAt: function(pos) {\n var mode = this.doc.mode;\n if (!mode.innerMode) { return mode }\n return CodeMirror.innerMode(mode, this.getTokenAt(pos).state).mode\n },\n\n getHelper: function(pos, type) {\n return this.getHelpers(pos, type)[0]\n },\n\n getHelpers: function(pos, type) {\n var found = [];\n if (!helpers.hasOwnProperty(type)) { return found }\n var help = helpers[type], mode = this.getModeAt(pos);\n if (typeof mode[type] == \"string\") {\n if (help[mode[type]]) { found.push(help[mode[type]]); }\n } else if (mode[type]) {\n for (var i = 0; i < mode[type].length; i++) {\n var val = help[mode[type][i]];\n if (val) { found.push(val); }\n }\n } else if (mode.helperType && help[mode.helperType]) {\n found.push(help[mode.helperType]);\n } else if (help[mode.name]) {\n found.push(help[mode.name]);\n }\n for (var i$1 = 0; i$1 < help._global.length; i$1++) {\n var cur = help._global[i$1];\n if (cur.pred(mode, this) && indexOf(found, cur.val) == -1)\n { found.push(cur.val); }\n }\n return found\n },\n\n getStateAfter: function(line, precise) {\n var doc = this.doc;\n line = clipLine(doc, line == null ? doc.first + doc.size - 1: line);\n return getContextBefore(this, line + 1, precise).state\n },\n\n cursorCoords: function(start, mode) {\n var pos, range = this.doc.sel.primary();\n if (start == null) { pos = range.head; }\n else if (typeof start == \"object\") { pos = clipPos(this.doc, start); }\n else { pos = start ? range.from() : range.to(); }\n return cursorCoords(this, pos, mode || \"page\")\n },\n\n charCoords: function(pos, mode) {\n return charCoords(this, clipPos(this.doc, pos), mode || \"page\")\n },\n\n coordsChar: function(coords, mode) {\n coords = fromCoordSystem(this, coords, mode || \"page\");\n return coordsChar(this, coords.left, coords.top)\n },\n\n lineAtHeight: function(height, mode) {\n height = fromCoordSystem(this, {top: height, left: 0}, mode || \"page\").top;\n return lineAtHeight(this.doc, height + this.display.viewOffset)\n },\n heightAtLine: function(line, mode, includeWidgets) {\n var end = false, lineObj;\n if (typeof line == \"number\") {\n var last = this.doc.first + this.doc.size - 1;\n if (line < this.doc.first) { line = this.doc.first; }\n else if (line > last) { line = last; end = true; }\n lineObj = getLine(this.doc, line);\n } else {\n lineObj = line;\n }\n return intoCoordSystem(this, lineObj, {top: 0, left: 0}, mode || \"page\", includeWidgets || end).top +\n (end ? this.doc.height - heightAtLine(lineObj) : 0)\n },\n\n defaultTextHeight: function() { return textHeight(this.display) },\n defaultCharWidth: function() { return charWidth(this.display) },\n\n getViewport: function() { return {from: this.display.viewFrom, to: this.display.viewTo}},\n\n addWidget: function(pos, node, scroll, vert, horiz) {\n var display = this.display;\n pos = cursorCoords(this, clipPos(this.doc, pos));\n var top = pos.bottom, left = pos.left;\n node.style.position = \"absolute\";\n node.setAttribute(\"cm-ignore-events\", \"true\");\n this.display.input.setUneditable(node);\n display.sizer.appendChild(node);\n if (vert == \"over\") {\n top = pos.top;\n } else if (vert == \"above\" || vert == \"near\") {\n var vspace = Math.max(display.wrapper.clientHeight, this.doc.height),\n hspace = Math.max(display.sizer.clientWidth, display.lineSpace.clientWidth);\n // Default to positioning above (if specified and possible); otherwise default to positioning below\n if ((vert == 'above' || pos.bottom + node.offsetHeight > vspace) && pos.top > node.offsetHeight)\n { top = pos.top - node.offsetHeight; }\n else if (pos.bottom + node.offsetHeight <= vspace)\n { top = pos.bottom; }\n if (left + node.offsetWidth > hspace)\n { left = hspace - node.offsetWidth; }\n }\n node.style.top = top + \"px\";\n node.style.left = node.style.right = \"\";\n if (horiz == \"right\") {\n left = display.sizer.clientWidth - node.offsetWidth;\n node.style.right = \"0px\";\n } else {\n if (horiz == \"left\") { left = 0; }\n else if (horiz == \"middle\") { left = (display.sizer.clientWidth - node.offsetWidth) / 2; }\n node.style.left = left + \"px\";\n }\n if (scroll)\n { scrollIntoView(this, {left: left, top: top, right: left + node.offsetWidth, bottom: top + node.offsetHeight}); }\n },\n\n triggerOnKeyDown: methodOp(onKeyDown),\n triggerOnKeyPress: methodOp(onKeyPress),\n triggerOnKeyUp: onKeyUp,\n triggerOnMouseDown: methodOp(onMouseDown),\n\n execCommand: function(cmd) {\n if (commands.hasOwnProperty(cmd))\n { return commands[cmd].call(null, this) }\n },\n\n triggerElectric: methodOp(function(text) { triggerElectric(this, text); }),\n\n findPosH: function(from, amount, unit, visually) {\n var dir = 1;\n if (amount < 0) { dir = -1; amount = -amount; }\n var cur = clipPos(this.doc, from);\n for (var i = 0; i < amount; ++i) {\n cur = findPosH(this.doc, cur, dir, unit, visually);\n if (cur.hitSide) { break }\n }\n return cur\n },\n\n moveH: methodOp(function(dir, unit) {\n var this$1 = this;\n\n this.extendSelectionsBy(function (range) {\n if (this$1.display.shift || this$1.doc.extend || range.empty())\n { return findPosH(this$1.doc, range.head, dir, unit, this$1.options.rtlMoveVisually) }\n else\n { return dir < 0 ? range.from() : range.to() }\n }, sel_move);\n }),\n\n deleteH: methodOp(function(dir, unit) {\n var sel = this.doc.sel, doc = this.doc;\n if (sel.somethingSelected())\n { doc.replaceSelection(\"\", null, \"+delete\"); }\n else\n { deleteNearSelection(this, function (range) {\n var other = findPosH(doc, range.head, dir, unit, false);\n return dir < 0 ? {from: other, to: range.head} : {from: range.head, to: other}\n }); }\n }),\n\n findPosV: function(from, amount, unit, goalColumn) {\n var dir = 1, x = goalColumn;\n if (amount < 0) { dir = -1; amount = -amount; }\n var cur = clipPos(this.doc, from);\n for (var i = 0; i < amount; ++i) {\n var coords = cursorCoords(this, cur, \"div\");\n if (x == null) { x = coords.left; }\n else { coords.left = x; }\n cur = findPosV(this, coords, dir, unit);\n if (cur.hitSide) { break }\n }\n return cur\n },\n\n moveV: methodOp(function(dir, unit) {\n var this$1 = this;\n\n var doc = this.doc, goals = [];\n var collapse = !this.display.shift && !doc.extend && doc.sel.somethingSelected();\n doc.extendSelectionsBy(function (range) {\n if (collapse)\n { return dir < 0 ? range.from() : range.to() }\n var headPos = cursorCoords(this$1, range.head, \"div\");\n if (range.goalColumn != null) { headPos.left = range.goalColumn; }\n goals.push(headPos.left);\n var pos = findPosV(this$1, headPos, dir, unit);\n if (unit == \"page\" && range == doc.sel.primary())\n { addToScrollTop(this$1, charCoords(this$1, pos, \"div\").top - headPos.top); }\n return pos\n }, sel_move);\n if (goals.length) { for (var i = 0; i < doc.sel.ranges.length; i++)\n { doc.sel.ranges[i].goalColumn = goals[i]; } }\n }),\n\n // Find the word at the given position (as returned by coordsChar).\n findWordAt: function(pos) {\n var doc = this.doc, line = getLine(doc, pos.line).text;\n var start = pos.ch, end = pos.ch;\n if (line) {\n var helper = this.getHelper(pos, \"wordChars\");\n if ((pos.sticky == \"before\" || end == line.length) && start) { --start; } else { ++end; }\n var startChar = line.charAt(start);\n var check = isWordChar(startChar, helper)\n ? function (ch) { return isWordChar(ch, helper); }\n : /\\s/.test(startChar) ? function (ch) { return /\\s/.test(ch); }\n : function (ch) { return (!/\\s/.test(ch) && !isWordChar(ch)); };\n while (start > 0 && check(line.charAt(start - 1))) { --start; }\n while (end < line.length && check(line.charAt(end))) { ++end; }\n }\n return new Range(Pos(pos.line, start), Pos(pos.line, end))\n },\n\n toggleOverwrite: function(value) {\n if (value != null && value == this.state.overwrite) { return }\n if (this.state.overwrite = !this.state.overwrite)\n { addClass(this.display.cursorDiv, \"CodeMirror-overwrite\"); }\n else\n { rmClass(this.display.cursorDiv, \"CodeMirror-overwrite\"); }\n\n signal(this, \"overwriteToggle\", this, this.state.overwrite);\n },\n hasFocus: function() { return this.display.input.getField() == activeElt() },\n isReadOnly: function() { return !!(this.options.readOnly || this.doc.cantEdit) },\n\n scrollTo: methodOp(function (x, y) { scrollToCoords(this, x, y); }),\n getScrollInfo: function() {\n var scroller = this.display.scroller;\n return {left: scroller.scrollLeft, top: scroller.scrollTop,\n height: scroller.scrollHeight - scrollGap(this) - this.display.barHeight,\n width: scroller.scrollWidth - scrollGap(this) - this.display.barWidth,\n clientHeight: displayHeight(this), clientWidth: displayWidth(this)}\n },\n\n scrollIntoView: methodOp(function(range, margin) {\n if (range == null) {\n range = {from: this.doc.sel.primary().head, to: null};\n if (margin == null) { margin = this.options.cursorScrollMargin; }\n } else if (typeof range == \"number\") {\n range = {from: Pos(range, 0), to: null};\n } else if (range.from == null) {\n range = {from: range, to: null};\n }\n if (!range.to) { range.to = range.from; }\n range.margin = margin || 0;\n\n if (range.from.line != null) {\n scrollToRange(this, range);\n } else {\n scrollToCoordsRange(this, range.from, range.to, range.margin);\n }\n }),\n\n setSize: methodOp(function(width, height) {\n var this$1 = this;\n\n var interpret = function (val) { return typeof val == \"number\" || /^\\d+$/.test(String(val)) ? val + \"px\" : val; };\n if (width != null) { this.display.wrapper.style.width = interpret(width); }\n if (height != null) { this.display.wrapper.style.height = interpret(height); }\n if (this.options.lineWrapping) { clearLineMeasurementCache(this); }\n var lineNo = this.display.viewFrom;\n this.doc.iter(lineNo, this.display.viewTo, function (line) {\n if (line.widgets) { for (var i = 0; i < line.widgets.length; i++)\n { if (line.widgets[i].noHScroll) { regLineChange(this$1, lineNo, \"widget\"); break } } }\n ++lineNo;\n });\n this.curOp.forceUpdate = true;\n signal(this, \"refresh\", this);\n }),\n\n operation: function(f){return runInOp(this, f)},\n startOperation: function(){return startOperation(this)},\n endOperation: function(){return endOperation(this)},\n\n refresh: methodOp(function() {\n var oldHeight = this.display.cachedTextHeight;\n regChange(this);\n this.curOp.forceUpdate = true;\n clearCaches(this);\n scrollToCoords(this, this.doc.scrollLeft, this.doc.scrollTop);\n updateGutterSpace(this.display);\n if (oldHeight == null || Math.abs(oldHeight - textHeight(this.display)) > .5 || this.options.lineWrapping)\n { estimateLineHeights(this); }\n signal(this, \"refresh\", this);\n }),\n\n swapDoc: methodOp(function(doc) {\n var old = this.doc;\n old.cm = null;\n // Cancel the current text selection if any (#5821)\n if (this.state.selectingText) { this.state.selectingText(); }\n attachDoc(this, doc);\n clearCaches(this);\n this.display.input.reset();\n scrollToCoords(this, doc.scrollLeft, doc.scrollTop);\n this.curOp.forceScroll = true;\n signalLater(this, \"swapDoc\", this, old);\n return old\n }),\n\n phrase: function(phraseText) {\n var phrases = this.options.phrases;\n return phrases && Object.prototype.hasOwnProperty.call(phrases, phraseText) ? phrases[phraseText] : phraseText\n },\n\n getInputField: function(){return this.display.input.getField()},\n getWrapperElement: function(){return this.display.wrapper},\n getScrollerElement: function(){return this.display.scroller},\n getGutterElement: function(){return this.display.gutters}\n };\n eventMixin(CodeMirror);\n\n CodeMirror.registerHelper = function(type, name, value) {\n if (!helpers.hasOwnProperty(type)) { helpers[type] = CodeMirror[type] = {_global: []}; }\n helpers[type][name] = value;\n };\n CodeMirror.registerGlobalHelper = function(type, name, predicate, value) {\n CodeMirror.registerHelper(type, name, value);\n helpers[type]._global.push({pred: predicate, val: value});\n };\n }\n\n // Used for horizontal relative motion. Dir is -1 or 1 (left or\n // right), unit can be \"codepoint\", \"char\", \"column\" (like char, but\n // doesn't cross line boundaries), \"word\" (across next word), or\n // \"group\" (to the start of next group of word or\n // non-word-non-whitespace chars). The visually param controls\n // whether, in right-to-left text, direction 1 means to move towards\n // the next index in the string, or towards the character to the right\n // of the current position. The resulting position will have a\n // hitSide=true property if it reached the end of the document.\n function findPosH(doc, pos, dir, unit, visually) {\n var oldPos = pos;\n var origDir = dir;\n var lineObj = getLine(doc, pos.line);\n var lineDir = visually && doc.direction == \"rtl\" ? -dir : dir;\n function findNextLine() {\n var l = pos.line + lineDir;\n if (l < doc.first || l >= doc.first + doc.size) { return false }\n pos = new Pos(l, pos.ch, pos.sticky);\n return lineObj = getLine(doc, l)\n }\n function moveOnce(boundToLine) {\n var next;\n if (unit == \"codepoint\") {\n var ch = lineObj.text.charCodeAt(pos.ch + (unit > 0 ? 0 : -1));\n if (isNaN(ch)) { next = null; }\n else { next = new Pos(pos.line, Math.max(0, Math.min(lineObj.text.length, pos.ch + dir * (ch >= 0xD800 && ch < 0xDC00 ? 2 : 1))),\n -dir); }\n } else if (visually) {\n next = moveVisually(doc.cm, lineObj, pos, dir);\n } else {\n next = moveLogically(lineObj, pos, dir);\n }\n if (next == null) {\n if (!boundToLine && findNextLine())\n { pos = endOfLine(visually, doc.cm, lineObj, pos.line, lineDir); }\n else\n { return false }\n } else {\n pos = next;\n }\n return true\n }\n\n if (unit == \"char\" || unit == \"codepoint\") {\n moveOnce();\n } else if (unit == \"column\") {\n moveOnce(true);\n } else if (unit == \"word\" || unit == \"group\") {\n var sawType = null, group = unit == \"group\";\n var helper = doc.cm && doc.cm.getHelper(pos, \"wordChars\");\n for (var first = true;; first = false) {\n if (dir < 0 && !moveOnce(!first)) { break }\n var cur = lineObj.text.charAt(pos.ch) || \"\\n\";\n var type = isWordChar(cur, helper) ? \"w\"\n : group && cur == \"\\n\" ? \"n\"\n : !group || /\\s/.test(cur) ? null\n : \"p\";\n if (group && !first && !type) { type = \"s\"; }\n if (sawType && sawType != type) {\n if (dir < 0) {dir = 1; moveOnce(); pos.sticky = \"after\";}\n break\n }\n\n if (type) { sawType = type; }\n if (dir > 0 && !moveOnce(!first)) { break }\n }\n }\n var result = skipAtomic(doc, pos, oldPos, origDir, true);\n if (equalCursorPos(oldPos, result)) { result.hitSide = true; }\n return result\n }\n\n // For relative vertical movement. Dir may be -1 or 1. Unit can be\n // \"page\" or \"line\". The resulting position will have a hitSide=true\n // property if it reached the end of the document.\n function findPosV(cm, pos, dir, unit) {\n var doc = cm.doc, x = pos.left, y;\n if (unit == \"page\") {\n var pageSize = Math.min(cm.display.wrapper.clientHeight, window.innerHeight || document.documentElement.clientHeight);\n var moveAmount = Math.max(pageSize - .5 * textHeight(cm.display), 3);\n y = (dir > 0 ? pos.bottom : pos.top) + dir * moveAmount;\n\n } else if (unit == \"line\") {\n y = dir > 0 ? pos.bottom + 3 : pos.top - 3;\n }\n var target;\n for (;;) {\n target = coordsChar(cm, x, y);\n if (!target.outside) { break }\n if (dir < 0 ? y <= 0 : y >= doc.height) { target.hitSide = true; break }\n y += dir * 5;\n }\n return target\n }\n\n // CONTENTEDITABLE INPUT STYLE\n\n var ContentEditableInput = function(cm) {\n this.cm = cm;\n this.lastAnchorNode = this.lastAnchorOffset = this.lastFocusNode = this.lastFocusOffset = null;\n this.polling = new Delayed();\n this.composing = null;\n this.gracePeriod = false;\n this.readDOMTimeout = null;\n };\n\n ContentEditableInput.prototype.init = function (display) {\n var this$1 = this;\n\n var input = this, cm = input.cm;\n var div = input.div = display.lineDiv;\n disableBrowserMagic(div, cm.options.spellcheck, cm.options.autocorrect, cm.options.autocapitalize);\n\n function belongsToInput(e) {\n for (var t = e.target; t; t = t.parentNode) {\n if (t == div) { return true }\n if (/\\bCodeMirror-(?:line)?widget\\b/.test(t.className)) { break }\n }\n return false\n }\n\n on(div, \"paste\", function (e) {\n if (!belongsToInput(e) || signalDOMEvent(cm, e) || handlePaste(e, cm)) { return }\n // IE doesn't fire input events, so we schedule a read for the pasted content in this way\n if (ie_version <= 11) { setTimeout(operation(cm, function () { return this$1.updateFromDOM(); }), 20); }\n });\n\n on(div, \"compositionstart\", function (e) {\n this$1.composing = {data: e.data, done: false};\n });\n on(div, \"compositionupdate\", function (e) {\n if (!this$1.composing) { this$1.composing = {data: e.data, done: false}; }\n });\n on(div, \"compositionend\", function (e) {\n if (this$1.composing) {\n if (e.data != this$1.composing.data) { this$1.readFromDOMSoon(); }\n this$1.composing.done = true;\n }\n });\n\n on(div, \"touchstart\", function () { return input.forceCompositionEnd(); });\n\n on(div, \"input\", function () {\n if (!this$1.composing) { this$1.readFromDOMSoon(); }\n });\n\n function onCopyCut(e) {\n if (!belongsToInput(e) || signalDOMEvent(cm, e)) { return }\n if (cm.somethingSelected()) {\n setLastCopied({lineWise: false, text: cm.getSelections()});\n if (e.type == \"cut\") { cm.replaceSelection(\"\", null, \"cut\"); }\n } else if (!cm.options.lineWiseCopyCut) {\n return\n } else {\n var ranges = copyableRanges(cm);\n setLastCopied({lineWise: true, text: ranges.text});\n if (e.type == \"cut\") {\n cm.operation(function () {\n cm.setSelections(ranges.ranges, 0, sel_dontScroll);\n cm.replaceSelection(\"\", null, \"cut\");\n });\n }\n }\n if (e.clipboardData) {\n e.clipboardData.clearData();\n var content = lastCopied.text.join(\"\\n\");\n // iOS exposes the clipboard API, but seems to discard content inserted into it\n e.clipboardData.setData(\"Text\", content);\n if (e.clipboardData.getData(\"Text\") == content) {\n e.preventDefault();\n return\n }\n }\n // Old-fashioned briefly-focus-a-textarea hack\n var kludge = hiddenTextarea(), te = kludge.firstChild;\n cm.display.lineSpace.insertBefore(kludge, cm.display.lineSpace.firstChild);\n te.value = lastCopied.text.join(\"\\n\");\n var hadFocus = document.activeElement;\n selectInput(te);\n setTimeout(function () {\n cm.display.lineSpace.removeChild(kludge);\n hadFocus.focus();\n if (hadFocus == div) { input.showPrimarySelection(); }\n }, 50);\n }\n on(div, \"copy\", onCopyCut);\n on(div, \"cut\", onCopyCut);\n };\n\n ContentEditableInput.prototype.screenReaderLabelChanged = function (label) {\n // Label for screenreaders, accessibility\n if(label) {\n this.div.setAttribute('aria-label', label);\n } else {\n this.div.removeAttribute('aria-label');\n }\n };\n\n ContentEditableInput.prototype.prepareSelection = function () {\n var result = prepareSelection(this.cm, false);\n result.focus = document.activeElement == this.div;\n return result\n };\n\n ContentEditableInput.prototype.showSelection = function (info, takeFocus) {\n if (!info || !this.cm.display.view.length) { return }\n if (info.focus || takeFocus) { this.showPrimarySelection(); }\n this.showMultipleSelections(info);\n };\n\n ContentEditableInput.prototype.getSelection = function () {\n return this.cm.display.wrapper.ownerDocument.getSelection()\n };\n\n ContentEditableInput.prototype.showPrimarySelection = function () {\n var sel = this.getSelection(), cm = this.cm, prim = cm.doc.sel.primary();\n var from = prim.from(), to = prim.to();\n\n if (cm.display.viewTo == cm.display.viewFrom || from.line >= cm.display.viewTo || to.line < cm.display.viewFrom) {\n sel.removeAllRanges();\n return\n }\n\n var curAnchor = domToPos(cm, sel.anchorNode, sel.anchorOffset);\n var curFocus = domToPos(cm, sel.focusNode, sel.focusOffset);\n if (curAnchor && !curAnchor.bad && curFocus && !curFocus.bad &&\n cmp(minPos(curAnchor, curFocus), from) == 0 &&\n cmp(maxPos(curAnchor, curFocus), to) == 0)\n { return }\n\n var view = cm.display.view;\n var start = (from.line >= cm.display.viewFrom && posToDOM(cm, from)) ||\n {node: view[0].measure.map[2], offset: 0};\n var end = to.line < cm.display.viewTo && posToDOM(cm, to);\n if (!end) {\n var measure = view[view.length - 1].measure;\n var map = measure.maps ? measure.maps[measure.maps.length - 1] : measure.map;\n end = {node: map[map.length - 1], offset: map[map.length - 2] - map[map.length - 3]};\n }\n\n if (!start || !end) {\n sel.removeAllRanges();\n return\n }\n\n var old = sel.rangeCount && sel.getRangeAt(0), rng;\n try { rng = range(start.node, start.offset, end.offset, end.node); }\n catch(e) {} // Our model of the DOM might be outdated, in which case the range we try to set can be impossible\n if (rng) {\n if (!gecko && cm.state.focused) {\n sel.collapse(start.node, start.offset);\n if (!rng.collapsed) {\n sel.removeAllRanges();\n sel.addRange(rng);\n }\n } else {\n sel.removeAllRanges();\n sel.addRange(rng);\n }\n if (old && sel.anchorNode == null) { sel.addRange(old); }\n else if (gecko) { this.startGracePeriod(); }\n }\n this.rememberSelection();\n };\n\n ContentEditableInput.prototype.startGracePeriod = function () {\n var this$1 = this;\n\n clearTimeout(this.gracePeriod);\n this.gracePeriod = setTimeout(function () {\n this$1.gracePeriod = false;\n if (this$1.selectionChanged())\n { this$1.cm.operation(function () { return this$1.cm.curOp.selectionChanged = true; }); }\n }, 20);\n };\n\n ContentEditableInput.prototype.showMultipleSelections = function (info) {\n removeChildrenAndAdd(this.cm.display.cursorDiv, info.cursors);\n removeChildrenAndAdd(this.cm.display.selectionDiv, info.selection);\n };\n\n ContentEditableInput.prototype.rememberSelection = function () {\n var sel = this.getSelection();\n this.lastAnchorNode = sel.anchorNode; this.lastAnchorOffset = sel.anchorOffset;\n this.lastFocusNode = sel.focusNode; this.lastFocusOffset = sel.focusOffset;\n };\n\n ContentEditableInput.prototype.selectionInEditor = function () {\n var sel = this.getSelection();\n if (!sel.rangeCount) { return false }\n var node = sel.getRangeAt(0).commonAncestorContainer;\n return contains(this.div, node)\n };\n\n ContentEditableInput.prototype.focus = function () {\n if (this.cm.options.readOnly != \"nocursor\") {\n if (!this.selectionInEditor() || document.activeElement != this.div)\n { this.showSelection(this.prepareSelection(), true); }\n this.div.focus();\n }\n };\n ContentEditableInput.prototype.blur = function () { this.div.blur(); };\n ContentEditableInput.prototype.getField = function () { return this.div };\n\n ContentEditableInput.prototype.supportsTouch = function () { return true };\n\n ContentEditableInput.prototype.receivedFocus = function () {\n var input = this;\n if (this.selectionInEditor())\n { this.pollSelection(); }\n else\n { runInOp(this.cm, function () { return input.cm.curOp.selectionChanged = true; }); }\n\n function poll() {\n if (input.cm.state.focused) {\n input.pollSelection();\n input.polling.set(input.cm.options.pollInterval, poll);\n }\n }\n this.polling.set(this.cm.options.pollInterval, poll);\n };\n\n ContentEditableInput.prototype.selectionChanged = function () {\n var sel = this.getSelection();\n return sel.anchorNode != this.lastAnchorNode || sel.anchorOffset != this.lastAnchorOffset ||\n sel.focusNode != this.lastFocusNode || sel.focusOffset != this.lastFocusOffset\n };\n\n ContentEditableInput.prototype.pollSelection = function () {\n if (this.readDOMTimeout != null || this.gracePeriod || !this.selectionChanged()) { return }\n var sel = this.getSelection(), cm = this.cm;\n // On Android Chrome (version 56, at least), backspacing into an\n // uneditable block element will put the cursor in that element,\n // and then, because it's not editable, hide the virtual keyboard.\n // Because Android doesn't allow us to actually detect backspace\n // presses in a sane way, this code checks for when that happens\n // and simulates a backspace press in this case.\n if (android && chrome && this.cm.display.gutterSpecs.length && isInGutter(sel.anchorNode)) {\n this.cm.triggerOnKeyDown({type: \"keydown\", keyCode: 8, preventDefault: Math.abs});\n this.blur();\n this.focus();\n return\n }\n if (this.composing) { return }\n this.rememberSelection();\n var anchor = domToPos(cm, sel.anchorNode, sel.anchorOffset);\n var head = domToPos(cm, sel.focusNode, sel.focusOffset);\n if (anchor && head) { runInOp(cm, function () {\n setSelection(cm.doc, simpleSelection(anchor, head), sel_dontScroll);\n if (anchor.bad || head.bad) { cm.curOp.selectionChanged = true; }\n }); }\n };\n\n ContentEditableInput.prototype.pollContent = function () {\n if (this.readDOMTimeout != null) {\n clearTimeout(this.readDOMTimeout);\n this.readDOMTimeout = null;\n }\n\n var cm = this.cm, display = cm.display, sel = cm.doc.sel.primary();\n var from = sel.from(), to = sel.to();\n if (from.ch == 0 && from.line > cm.firstLine())\n { from = Pos(from.line - 1, getLine(cm.doc, from.line - 1).length); }\n if (to.ch == getLine(cm.doc, to.line).text.length && to.line < cm.lastLine())\n { to = Pos(to.line + 1, 0); }\n if (from.line < display.viewFrom || to.line > display.viewTo - 1) { return false }\n\n var fromIndex, fromLine, fromNode;\n if (from.line == display.viewFrom || (fromIndex = findViewIndex(cm, from.line)) == 0) {\n fromLine = lineNo(display.view[0].line);\n fromNode = display.view[0].node;\n } else {\n fromLine = lineNo(display.view[fromIndex].line);\n fromNode = display.view[fromIndex - 1].node.nextSibling;\n }\n var toIndex = findViewIndex(cm, to.line);\n var toLine, toNode;\n if (toIndex == display.view.length - 1) {\n toLine = display.viewTo - 1;\n toNode = display.lineDiv.lastChild;\n } else {\n toLine = lineNo(display.view[toIndex + 1].line) - 1;\n toNode = display.view[toIndex + 1].node.previousSibling;\n }\n\n if (!fromNode) { return false }\n var newText = cm.doc.splitLines(domTextBetween(cm, fromNode, toNode, fromLine, toLine));\n var oldText = getBetween(cm.doc, Pos(fromLine, 0), Pos(toLine, getLine(cm.doc, toLine).text.length));\n while (newText.length > 1 && oldText.length > 1) {\n if (lst(newText) == lst(oldText)) { newText.pop(); oldText.pop(); toLine--; }\n else if (newText[0] == oldText[0]) { newText.shift(); oldText.shift(); fromLine++; }\n else { break }\n }\n\n var cutFront = 0, cutEnd = 0;\n var newTop = newText[0], oldTop = oldText[0], maxCutFront = Math.min(newTop.length, oldTop.length);\n while (cutFront < maxCutFront && newTop.charCodeAt(cutFront) == oldTop.charCodeAt(cutFront))\n { ++cutFront; }\n var newBot = lst(newText), oldBot = lst(oldText);\n var maxCutEnd = Math.min(newBot.length - (newText.length == 1 ? cutFront : 0),\n oldBot.length - (oldText.length == 1 ? cutFront : 0));\n while (cutEnd < maxCutEnd &&\n newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1))\n { ++cutEnd; }\n // Try to move start of change to start of selection if ambiguous\n if (newText.length == 1 && oldText.length == 1 && fromLine == from.line) {\n while (cutFront && cutFront > from.ch &&\n newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1)) {\n cutFront--;\n cutEnd++;\n }\n }\n\n newText[newText.length - 1] = newBot.slice(0, newBot.length - cutEnd).replace(/^\\u200b+/, \"\");\n newText[0] = newText[0].slice(cutFront).replace(/\\u200b+$/, \"\");\n\n var chFrom = Pos(fromLine, cutFront);\n var chTo = Pos(toLine, oldText.length ? lst(oldText).length - cutEnd : 0);\n if (newText.length > 1 || newText[0] || cmp(chFrom, chTo)) {\n replaceRange(cm.doc, newText, chFrom, chTo, \"+input\");\n return true\n }\n };\n\n ContentEditableInput.prototype.ensurePolled = function () {\n this.forceCompositionEnd();\n };\n ContentEditableInput.prototype.reset = function () {\n this.forceCompositionEnd();\n };\n ContentEditableInput.prototype.forceCompositionEnd = function () {\n if (!this.composing) { return }\n clearTimeout(this.readDOMTimeout);\n this.composing = null;\n this.updateFromDOM();\n this.div.blur();\n this.div.focus();\n };\n ContentEditableInput.prototype.readFromDOMSoon = function () {\n var this$1 = this;\n\n if (this.readDOMTimeout != null) { return }\n this.readDOMTimeout = setTimeout(function () {\n this$1.readDOMTimeout = null;\n if (this$1.composing) {\n if (this$1.composing.done) { this$1.composing = null; }\n else { return }\n }\n this$1.updateFromDOM();\n }, 80);\n };\n\n ContentEditableInput.prototype.updateFromDOM = function () {\n var this$1 = this;\n\n if (this.cm.isReadOnly() || !this.pollContent())\n { runInOp(this.cm, function () { return regChange(this$1.cm); }); }\n };\n\n ContentEditableInput.prototype.setUneditable = function (node) {\n node.contentEditable = \"false\";\n };\n\n ContentEditableInput.prototype.onKeyPress = function (e) {\n if (e.charCode == 0 || this.composing) { return }\n e.preventDefault();\n if (!this.cm.isReadOnly())\n { operation(this.cm, applyTextInput)(this.cm, String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode), 0); }\n };\n\n ContentEditableInput.prototype.readOnlyChanged = function (val) {\n this.div.contentEditable = String(val != \"nocursor\");\n };\n\n ContentEditableInput.prototype.onContextMenu = function () {};\n ContentEditableInput.prototype.resetPosition = function () {};\n\n ContentEditableInput.prototype.needsContentAttribute = true;\n\n function posToDOM(cm, pos) {\n var view = findViewForLine(cm, pos.line);\n if (!view || view.hidden) { return null }\n var line = getLine(cm.doc, pos.line);\n var info = mapFromLineView(view, line, pos.line);\n\n var order = getOrder(line, cm.doc.direction), side = \"left\";\n if (order) {\n var partPos = getBidiPartAt(order, pos.ch);\n side = partPos % 2 ? \"right\" : \"left\";\n }\n var result = nodeAndOffsetInLineMap(info.map, pos.ch, side);\n result.offset = result.collapse == \"right\" ? result.end : result.start;\n return result\n }\n\n function isInGutter(node) {\n for (var scan = node; scan; scan = scan.parentNode)\n { if (/CodeMirror-gutter-wrapper/.test(scan.className)) { return true } }\n return false\n }\n\n function badPos(pos, bad) { if (bad) { pos.bad = true; } return pos }\n\n function domTextBetween(cm, from, to, fromLine, toLine) {\n var text = \"\", closing = false, lineSep = cm.doc.lineSeparator(), extraLinebreak = false;\n function recognizeMarker(id) { return function (marker) { return marker.id == id; } }\n function close() {\n if (closing) {\n text += lineSep;\n if (extraLinebreak) { text += lineSep; }\n closing = extraLinebreak = false;\n }\n }\n function addText(str) {\n if (str) {\n close();\n text += str;\n }\n }\n function walk(node) {\n if (node.nodeType == 1) {\n var cmText = node.getAttribute(\"cm-text\");\n if (cmText) {\n addText(cmText);\n return\n }\n var markerID = node.getAttribute(\"cm-marker\"), range;\n if (markerID) {\n var found = cm.findMarks(Pos(fromLine, 0), Pos(toLine + 1, 0), recognizeMarker(+markerID));\n if (found.length && (range = found[0].find(0)))\n { addText(getBetween(cm.doc, range.from, range.to).join(lineSep)); }\n return\n }\n if (node.getAttribute(\"contenteditable\") == \"false\") { return }\n var isBlock = /^(pre|div|p|li|table|br)$/i.test(node.nodeName);\n if (!/^br$/i.test(node.nodeName) && node.textContent.length == 0) { return }\n\n if (isBlock) { close(); }\n for (var i = 0; i < node.childNodes.length; i++)\n { walk(node.childNodes[i]); }\n\n if (/^(pre|p)$/i.test(node.nodeName)) { extraLinebreak = true; }\n if (isBlock) { closing = true; }\n } else if (node.nodeType == 3) {\n addText(node.nodeValue.replace(/\\u200b/g, \"\").replace(/\\u00a0/g, \" \"));\n }\n }\n for (;;) {\n walk(from);\n if (from == to) { break }\n from = from.nextSibling;\n extraLinebreak = false;\n }\n return text\n }\n\n function domToPos(cm, node, offset) {\n var lineNode;\n if (node == cm.display.lineDiv) {\n lineNode = cm.display.lineDiv.childNodes[offset];\n if (!lineNode) { return badPos(cm.clipPos(Pos(cm.display.viewTo - 1)), true) }\n node = null; offset = 0;\n } else {\n for (lineNode = node;; lineNode = lineNode.parentNode) {\n if (!lineNode || lineNode == cm.display.lineDiv) { return null }\n if (lineNode.parentNode && lineNode.parentNode == cm.display.lineDiv) { break }\n }\n }\n for (var i = 0; i < cm.display.view.length; i++) {\n var lineView = cm.display.view[i];\n if (lineView.node == lineNode)\n { return locateNodeInLineView(lineView, node, offset) }\n }\n }\n\n function locateNodeInLineView(lineView, node, offset) {\n var wrapper = lineView.text.firstChild, bad = false;\n if (!node || !contains(wrapper, node)) { return badPos(Pos(lineNo(lineView.line), 0), true) }\n if (node == wrapper) {\n bad = true;\n node = wrapper.childNodes[offset];\n offset = 0;\n if (!node) {\n var line = lineView.rest ? lst(lineView.rest) : lineView.line;\n return badPos(Pos(lineNo(line), line.text.length), bad)\n }\n }\n\n var textNode = node.nodeType == 3 ? node : null, topNode = node;\n if (!textNode && node.childNodes.length == 1 && node.firstChild.nodeType == 3) {\n textNode = node.firstChild;\n if (offset) { offset = textNode.nodeValue.length; }\n }\n while (topNode.parentNode != wrapper) { topNode = topNode.parentNode; }\n var measure = lineView.measure, maps = measure.maps;\n\n function find(textNode, topNode, offset) {\n for (var i = -1; i < (maps ? maps.length : 0); i++) {\n var map = i < 0 ? measure.map : maps[i];\n for (var j = 0; j < map.length; j += 3) {\n var curNode = map[j + 2];\n if (curNode == textNode || curNode == topNode) {\n var line = lineNo(i < 0 ? lineView.line : lineView.rest[i]);\n var ch = map[j] + offset;\n if (offset < 0 || curNode != textNode) { ch = map[j + (offset ? 1 : 0)]; }\n return Pos(line, ch)\n }\n }\n }\n }\n var found = find(textNode, topNode, offset);\n if (found) { return badPos(found, bad) }\n\n // FIXME this is all really shaky. might handle the few cases it needs to handle, but likely to cause problems\n for (var after = topNode.nextSibling, dist = textNode ? textNode.nodeValue.length - offset : 0; after; after = after.nextSibling) {\n found = find(after, after.firstChild, 0);\n if (found)\n { return badPos(Pos(found.line, found.ch - dist), bad) }\n else\n { dist += after.textContent.length; }\n }\n for (var before = topNode.previousSibling, dist$1 = offset; before; before = before.previousSibling) {\n found = find(before, before.firstChild, -1);\n if (found)\n { return badPos(Pos(found.line, found.ch + dist$1), bad) }\n else\n { dist$1 += before.textContent.length; }\n }\n }\n\n // TEXTAREA INPUT STYLE\n\n var TextareaInput = function(cm) {\n this.cm = cm;\n // See input.poll and input.reset\n this.prevInput = \"\";\n\n // Flag that indicates whether we expect input to appear real soon\n // now (after some event like 'keypress' or 'input') and are\n // polling intensively.\n this.pollingFast = false;\n // Self-resetting timeout for the poller\n this.polling = new Delayed();\n // Used to work around IE issue with selection being forgotten when focus moves away from textarea\n this.hasSelection = false;\n this.composing = null;\n };\n\n TextareaInput.prototype.init = function (display) {\n var this$1 = this;\n\n var input = this, cm = this.cm;\n this.createField(display);\n var te = this.textarea;\n\n display.wrapper.insertBefore(this.wrapper, display.wrapper.firstChild);\n\n // Needed to hide big blue blinking cursor on Mobile Safari (doesn't seem to work in iOS 8 anymore)\n if (ios) { te.style.width = \"0px\"; }\n\n on(te, \"input\", function () {\n if (ie && ie_version >= 9 && this$1.hasSelection) { this$1.hasSelection = null; }\n input.poll();\n });\n\n on(te, \"paste\", function (e) {\n if (signalDOMEvent(cm, e) || handlePaste(e, cm)) { return }\n\n cm.state.pasteIncoming = +new Date;\n input.fastPoll();\n });\n\n function prepareCopyCut(e) {\n if (signalDOMEvent(cm, e)) { return }\n if (cm.somethingSelected()) {\n setLastCopied({lineWise: false, text: cm.getSelections()});\n } else if (!cm.options.lineWiseCopyCut) {\n return\n } else {\n var ranges = copyableRanges(cm);\n setLastCopied({lineWise: true, text: ranges.text});\n if (e.type == \"cut\") {\n cm.setSelections(ranges.ranges, null, sel_dontScroll);\n } else {\n input.prevInput = \"\";\n te.value = ranges.text.join(\"\\n\");\n selectInput(te);\n }\n }\n if (e.type == \"cut\") { cm.state.cutIncoming = +new Date; }\n }\n on(te, \"cut\", prepareCopyCut);\n on(te, \"copy\", prepareCopyCut);\n\n on(display.scroller, \"paste\", function (e) {\n if (eventInWidget(display, e) || signalDOMEvent(cm, e)) { return }\n if (!te.dispatchEvent) {\n cm.state.pasteIncoming = +new Date;\n input.focus();\n return\n }\n\n // Pass the `paste` event to the textarea so it's handled by its event listener.\n var event = new Event(\"paste\");\n event.clipboardData = e.clipboardData;\n te.dispatchEvent(event);\n });\n\n // Prevent normal selection in the editor (we handle our own)\n on(display.lineSpace, \"selectstart\", function (e) {\n if (!eventInWidget(display, e)) { e_preventDefault(e); }\n });\n\n on(te, \"compositionstart\", function () {\n var start = cm.getCursor(\"from\");\n if (input.composing) { input.composing.range.clear(); }\n input.composing = {\n start: start,\n range: cm.markText(start, cm.getCursor(\"to\"), {className: \"CodeMirror-composing\"})\n };\n });\n on(te, \"compositionend\", function () {\n if (input.composing) {\n input.poll();\n input.composing.range.clear();\n input.composing = null;\n }\n });\n };\n\n TextareaInput.prototype.createField = function (_display) {\n // Wraps and hides input textarea\n this.wrapper = hiddenTextarea();\n // The semihidden textarea that is focused when the editor is\n // focused, and receives input.\n this.textarea = this.wrapper.firstChild;\n };\n\n TextareaInput.prototype.screenReaderLabelChanged = function (label) {\n // Label for screenreaders, accessibility\n if(label) {\n this.textarea.setAttribute('aria-label', label);\n } else {\n this.textarea.removeAttribute('aria-label');\n }\n };\n\n TextareaInput.prototype.prepareSelection = function () {\n // Redraw the selection and/or cursor\n var cm = this.cm, display = cm.display, doc = cm.doc;\n var result = prepareSelection(cm);\n\n // Move the hidden textarea near the cursor to prevent scrolling artifacts\n if (cm.options.moveInputWithCursor) {\n var headPos = cursorCoords(cm, doc.sel.primary().head, \"div\");\n var wrapOff = display.wrapper.getBoundingClientRect(), lineOff = display.lineDiv.getBoundingClientRect();\n result.teTop = Math.max(0, Math.min(display.wrapper.clientHeight - 10,\n headPos.top + lineOff.top - wrapOff.top));\n result.teLeft = Math.max(0, Math.min(display.wrapper.clientWidth - 10,\n headPos.left + lineOff.left - wrapOff.left));\n }\n\n return result\n };\n\n TextareaInput.prototype.showSelection = function (drawn) {\n var cm = this.cm, display = cm.display;\n removeChildrenAndAdd(display.cursorDiv, drawn.cursors);\n removeChildrenAndAdd(display.selectionDiv, drawn.selection);\n if (drawn.teTop != null) {\n this.wrapper.style.top = drawn.teTop + \"px\";\n this.wrapper.style.left = drawn.teLeft + \"px\";\n }\n };\n\n // Reset the input to correspond to the selection (or to be empty,\n // when not typing and nothing is selected)\n TextareaInput.prototype.reset = function (typing) {\n if (this.contextMenuPending || this.composing) { return }\n var cm = this.cm;\n if (cm.somethingSelected()) {\n this.prevInput = \"\";\n var content = cm.getSelection();\n this.textarea.value = content;\n if (cm.state.focused) { selectInput(this.textarea); }\n if (ie && ie_version >= 9) { this.hasSelection = content; }\n } else if (!typing) {\n this.prevInput = this.textarea.value = \"\";\n if (ie && ie_version >= 9) { this.hasSelection = null; }\n }\n };\n\n TextareaInput.prototype.getField = function () { return this.textarea };\n\n TextareaInput.prototype.supportsTouch = function () { return false };\n\n TextareaInput.prototype.focus = function () {\n if (this.cm.options.readOnly != \"nocursor\" && (!mobile || activeElt() != this.textarea)) {\n try { this.textarea.focus(); }\n catch (e) {} // IE8 will throw if the textarea is display: none or not in DOM\n }\n };\n\n TextareaInput.prototype.blur = function () { this.textarea.blur(); };\n\n TextareaInput.prototype.resetPosition = function () {\n this.wrapper.style.top = this.wrapper.style.left = 0;\n };\n\n TextareaInput.prototype.receivedFocus = function () { this.slowPoll(); };\n\n // Poll for input changes, using the normal rate of polling. This\n // runs as long as the editor is focused.\n TextareaInput.prototype.slowPoll = function () {\n var this$1 = this;\n\n if (this.pollingFast) { return }\n this.polling.set(this.cm.options.pollInterval, function () {\n this$1.poll();\n if (this$1.cm.state.focused) { this$1.slowPoll(); }\n });\n };\n\n // When an event has just come in that is likely to add or change\n // something in the input textarea, we poll faster, to ensure that\n // the change appears on the screen quickly.\n TextareaInput.prototype.fastPoll = function () {\n var missed = false, input = this;\n input.pollingFast = true;\n function p() {\n var changed = input.poll();\n if (!changed && !missed) {missed = true; input.polling.set(60, p);}\n else {input.pollingFast = false; input.slowPoll();}\n }\n input.polling.set(20, p);\n };\n\n // Read input from the textarea, and update the document to match.\n // When something is selected, it is present in the textarea, and\n // selected (unless it is huge, in which case a placeholder is\n // used). When nothing is selected, the cursor sits after previously\n // seen text (can be empty), which is stored in prevInput (we must\n // not reset the textarea when typing, because that breaks IME).\n TextareaInput.prototype.poll = function () {\n var this$1 = this;\n\n var cm = this.cm, input = this.textarea, prevInput = this.prevInput;\n // Since this is called a *lot*, try to bail out as cheaply as\n // possible when it is clear that nothing happened. hasSelection\n // will be the case when there is a lot of text in the textarea,\n // in which case reading its value would be expensive.\n if (this.contextMenuPending || !cm.state.focused ||\n (hasSelection(input) && !prevInput && !this.composing) ||\n cm.isReadOnly() || cm.options.disableInput || cm.state.keySeq)\n { return false }\n\n var text = input.value;\n // If nothing changed, bail.\n if (text == prevInput && !cm.somethingSelected()) { return false }\n // Work around nonsensical selection resetting in IE9/10, and\n // inexplicable appearance of private area unicode characters on\n // some key combos in Mac (#2689).\n if (ie && ie_version >= 9 && this.hasSelection === text ||\n mac && /[\\uf700-\\uf7ff]/.test(text)) {\n cm.display.input.reset();\n return false\n }\n\n if (cm.doc.sel == cm.display.selForContextMenu) {\n var first = text.charCodeAt(0);\n if (first == 0x200b && !prevInput) { prevInput = \"\\u200b\"; }\n if (first == 0x21da) { this.reset(); return this.cm.execCommand(\"undo\") }\n }\n // Find the part of the input that is actually new\n var same = 0, l = Math.min(prevInput.length, text.length);\n while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same)) { ++same; }\n\n runInOp(cm, function () {\n applyTextInput(cm, text.slice(same), prevInput.length - same,\n null, this$1.composing ? \"*compose\" : null);\n\n // Don't leave long text in the textarea, since it makes further polling slow\n if (text.length > 1000 || text.indexOf(\"\\n\") > -1) { input.value = this$1.prevInput = \"\"; }\n else { this$1.prevInput = text; }\n\n if (this$1.composing) {\n this$1.composing.range.clear();\n this$1.composing.range = cm.markText(this$1.composing.start, cm.getCursor(\"to\"),\n {className: \"CodeMirror-composing\"});\n }\n });\n return true\n };\n\n TextareaInput.prototype.ensurePolled = function () {\n if (this.pollingFast && this.poll()) { this.pollingFast = false; }\n };\n\n TextareaInput.prototype.onKeyPress = function () {\n if (ie && ie_version >= 9) { this.hasSelection = null; }\n this.fastPoll();\n };\n\n TextareaInput.prototype.onContextMenu = function (e) {\n var input = this, cm = input.cm, display = cm.display, te = input.textarea;\n if (input.contextMenuPending) { input.contextMenuPending(); }\n var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop;\n if (!pos || presto) { return } // Opera is difficult.\n\n // Reset the current text selection only if the click is done outside of the selection\n // and 'resetSelectionOnContextMenu' option is true.\n var reset = cm.options.resetSelectionOnContextMenu;\n if (reset && cm.doc.sel.contains(pos) == -1)\n { operation(cm, setSelection)(cm.doc, simpleSelection(pos), sel_dontScroll); }\n\n var oldCSS = te.style.cssText, oldWrapperCSS = input.wrapper.style.cssText;\n var wrapperBox = input.wrapper.offsetParent.getBoundingClientRect();\n input.wrapper.style.cssText = \"position: static\";\n te.style.cssText = \"position: absolute; width: 30px; height: 30px;\\n top: \" + (e.clientY - wrapperBox.top - 5) + \"px; left: \" + (e.clientX - wrapperBox.left - 5) + \"px;\\n z-index: 1000; background: \" + (ie ? \"rgba(255, 255, 255, .05)\" : \"transparent\") + \";\\n outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);\";\n var oldScrollY;\n if (webkit) { oldScrollY = window.scrollY; } // Work around Chrome issue (#2712)\n display.input.focus();\n if (webkit) { window.scrollTo(null, oldScrollY); }\n display.input.reset();\n // Adds \"Select all\" to context menu in FF\n if (!cm.somethingSelected()) { te.value = input.prevInput = \" \"; }\n input.contextMenuPending = rehide;\n display.selForContextMenu = cm.doc.sel;\n clearTimeout(display.detectingSelectAll);\n\n // Select-all will be greyed out if there's nothing to select, so\n // this adds a zero-width space so that we can later check whether\n // it got selected.\n function prepareSelectAllHack() {\n if (te.selectionStart != null) {\n var selected = cm.somethingSelected();\n var extval = \"\\u200b\" + (selected ? te.value : \"\");\n te.value = \"\\u21da\"; // Used to catch context-menu undo\n te.value = extval;\n input.prevInput = selected ? \"\" : \"\\u200b\";\n te.selectionStart = 1; te.selectionEnd = extval.length;\n // Re-set this, in case some other handler touched the\n // selection in the meantime.\n display.selForContextMenu = cm.doc.sel;\n }\n }\n function rehide() {\n if (input.contextMenuPending != rehide) { return }\n input.contextMenuPending = false;\n input.wrapper.style.cssText = oldWrapperCSS;\n te.style.cssText = oldCSS;\n if (ie && ie_version < 9) { display.scrollbars.setScrollTop(display.scroller.scrollTop = scrollPos); }\n\n // Try to detect the user choosing select-all\n if (te.selectionStart != null) {\n if (!ie || (ie && ie_version < 9)) { prepareSelectAllHack(); }\n var i = 0, poll = function () {\n if (display.selForContextMenu == cm.doc.sel && te.selectionStart == 0 &&\n te.selectionEnd > 0 && input.prevInput == \"\\u200b\") {\n operation(cm, selectAll)(cm);\n } else if (i++ < 10) {\n display.detectingSelectAll = setTimeout(poll, 500);\n } else {\n display.selForContextMenu = null;\n display.input.reset();\n }\n };\n display.detectingSelectAll = setTimeout(poll, 200);\n }\n }\n\n if (ie && ie_version >= 9) { prepareSelectAllHack(); }\n if (captureRightClick) {\n e_stop(e);\n var mouseup = function () {\n off(window, \"mouseup\", mouseup);\n setTimeout(rehide, 20);\n };\n on(window, \"mouseup\", mouseup);\n } else {\n setTimeout(rehide, 50);\n }\n };\n\n TextareaInput.prototype.readOnlyChanged = function (val) {\n if (!val) { this.reset(); }\n this.textarea.disabled = val == \"nocursor\";\n this.textarea.readOnly = !!val;\n };\n\n TextareaInput.prototype.setUneditable = function () {};\n\n TextareaInput.prototype.needsContentAttribute = false;\n\n function fromTextArea(textarea, options) {\n options = options ? copyObj(options) : {};\n options.value = textarea.value;\n if (!options.tabindex && textarea.tabIndex)\n { options.tabindex = textarea.tabIndex; }\n if (!options.placeholder && textarea.placeholder)\n { options.placeholder = textarea.placeholder; }\n // Set autofocus to true if this textarea is focused, or if it has\n // autofocus and no other element is focused.\n if (options.autofocus == null) {\n var hasFocus = activeElt();\n options.autofocus = hasFocus == textarea ||\n textarea.getAttribute(\"autofocus\") != null && hasFocus == document.body;\n }\n\n function save() {textarea.value = cm.getValue();}\n\n var realSubmit;\n if (textarea.form) {\n on(textarea.form, \"submit\", save);\n // Deplorable hack to make the submit method do the right thing.\n if (!options.leaveSubmitMethodAlone) {\n var form = textarea.form;\n realSubmit = form.submit;\n try {\n var wrappedSubmit = form.submit = function () {\n save();\n form.submit = realSubmit;\n form.submit();\n form.submit = wrappedSubmit;\n };\n } catch(e) {}\n }\n }\n\n options.finishInit = function (cm) {\n cm.save = save;\n cm.getTextArea = function () { return textarea; };\n cm.toTextArea = function () {\n cm.toTextArea = isNaN; // Prevent this from being ran twice\n save();\n textarea.parentNode.removeChild(cm.getWrapperElement());\n textarea.style.display = \"\";\n if (textarea.form) {\n off(textarea.form, \"submit\", save);\n if (!options.leaveSubmitMethodAlone && typeof textarea.form.submit == \"function\")\n { textarea.form.submit = realSubmit; }\n }\n };\n };\n\n textarea.style.display = \"none\";\n var cm = CodeMirror(function (node) { return textarea.parentNode.insertBefore(node, textarea.nextSibling); },\n options);\n return cm\n }\n\n function addLegacyProps(CodeMirror) {\n CodeMirror.off = off;\n CodeMirror.on = on;\n CodeMirror.wheelEventPixels = wheelEventPixels;\n CodeMirror.Doc = Doc;\n CodeMirror.splitLines = splitLinesAuto;\n CodeMirror.countColumn = countColumn;\n CodeMirror.findColumn = findColumn;\n CodeMirror.isWordChar = isWordCharBasic;\n CodeMirror.Pass = Pass;\n CodeMirror.signal = signal;\n CodeMirror.Line = Line;\n CodeMirror.changeEnd = changeEnd;\n CodeMirror.scrollbarModel = scrollbarModel;\n CodeMirror.Pos = Pos;\n CodeMirror.cmpPos = cmp;\n CodeMirror.modes = modes;\n CodeMirror.mimeModes = mimeModes;\n CodeMirror.resolveMode = resolveMode;\n CodeMirror.getMode = getMode;\n CodeMirror.modeExtensions = modeExtensions;\n CodeMirror.extendMode = extendMode;\n CodeMirror.copyState = copyState;\n CodeMirror.startState = startState;\n CodeMirror.innerMode = innerMode;\n CodeMirror.commands = commands;\n CodeMirror.keyMap = keyMap;\n CodeMirror.keyName = keyName;\n CodeMirror.isModifierKey = isModifierKey;\n CodeMirror.lookupKey = lookupKey;\n CodeMirror.normalizeKeyMap = normalizeKeyMap;\n CodeMirror.StringStream = StringStream;\n CodeMirror.SharedTextMarker = SharedTextMarker;\n CodeMirror.TextMarker = TextMarker;\n CodeMirror.LineWidget = LineWidget;\n CodeMirror.e_preventDefault = e_preventDefault;\n CodeMirror.e_stopPropagation = e_stopPropagation;\n CodeMirror.e_stop = e_stop;\n CodeMirror.addClass = addClass;\n CodeMirror.contains = contains;\n CodeMirror.rmClass = rmClass;\n CodeMirror.keyNames = keyNames;\n }\n\n // EDITOR CONSTRUCTOR\n\n defineOptions(CodeMirror);\n\n addEditorMethods(CodeMirror);\n\n // Set up methods on CodeMirror's prototype to redirect to the editor's document.\n var dontDelegate = \"iter insert remove copy getEditor constructor\".split(\" \");\n for (var prop in Doc.prototype) { if (Doc.prototype.hasOwnProperty(prop) && indexOf(dontDelegate, prop) < 0)\n { CodeMirror.prototype[prop] = (function(method) {\n return function() {return method.apply(this.doc, arguments)}\n })(Doc.prototype[prop]); } }\n\n eventMixin(Doc);\n CodeMirror.inputStyles = {\"textarea\": TextareaInput, \"contenteditable\": ContentEditableInput};\n\n // Extra arguments are stored as the mode's dependencies, which is\n // used by (legacy) mechanisms like loadmode.js to automatically\n // load a mode. (Preferred mechanism is the require/define calls.)\n CodeMirror.defineMode = function(name/*, mode, \u2026*/) {\n if (!CodeMirror.defaults.mode && name != \"null\") { CodeMirror.defaults.mode = name; }\n defineMode.apply(this, arguments);\n };\n\n CodeMirror.defineMIME = defineMIME;\n\n // Minimal default mode.\n CodeMirror.defineMode(\"null\", function () { return ({token: function (stream) { return stream.skipToEnd(); }}); });\n CodeMirror.defineMIME(\"text/plain\", \"null\");\n\n // EXTENSIONS\n\n CodeMirror.defineExtension = function (name, func) {\n CodeMirror.prototype[name] = func;\n };\n CodeMirror.defineDocExtension = function (name, func) {\n Doc.prototype[name] = func;\n };\n\n CodeMirror.fromTextArea = fromTextArea;\n\n addLegacyProps(CodeMirror);\n\n CodeMirror.version = \"5.58.1\";\n\n return CodeMirror;\n\n})));\n","Amasty_ImportCore/js/lib/codemirror/xml.js":"// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: https://codemirror.net/LICENSE\n\n(function(mod) {\n if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n mod(require(\"../../lib/codemirror\"));\n else if (typeof define == \"function\" && define.amd) // AMD\n define([\"../../lib/codemirror\"], mod);\n else // Plain browser env\n mod(CodeMirror);\n})(function(CodeMirror) {\n \"use strict\";\n\n var htmlConfig = {\n autoSelfClosers: {'area': true, 'base': true, 'br': true, 'col': true, 'command': true,\n 'embed': true, 'frame': true, 'hr': true, 'img': true, 'input': true,\n 'keygen': true, 'link': true, 'meta': true, 'param': true, 'source': true,\n 'track': true, 'wbr': true, 'menuitem': true},\n implicitlyClosed: {'dd': true, 'li': true, 'optgroup': true, 'option': true, 'p': true,\n 'rp': true, 'rt': true, 'tbody': true, 'td': true, 'tfoot': true,\n 'th': true, 'tr': true},\n contextGrabbers: {\n 'dd': {'dd': true, 'dt': true},\n 'dt': {'dd': true, 'dt': true},\n 'li': {'li': true},\n 'option': {'option': true, 'optgroup': true},\n 'optgroup': {'optgroup': true},\n 'p': {'address': true, 'article': true, 'aside': true, 'blockquote': true, 'dir': true,\n 'div': true, 'dl': true, 'fieldset': true, 'footer': true, 'form': true,\n 'h1': true, 'h2': true, 'h3': true, 'h4': true, 'h5': true, 'h6': true,\n 'header': true, 'hgroup': true, 'hr': true, 'menu': true, 'nav': true, 'ol': true,\n 'p': true, 'pre': true, 'section': true, 'table': true, 'ul': true},\n 'rp': {'rp': true, 'rt': true},\n 'rt': {'rp': true, 'rt': true},\n 'tbody': {'tbody': true, 'tfoot': true},\n 'td': {'td': true, 'th': true},\n 'tfoot': {'tbody': true},\n 'th': {'td': true, 'th': true},\n 'thead': {'tbody': true, 'tfoot': true},\n 'tr': {'tr': true}\n },\n doNotIndent: {\"pre\": true},\n allowUnquoted: true,\n allowMissing: true,\n caseFold: true\n }\n\n var xmlConfig = {\n autoSelfClosers: {},\n implicitlyClosed: {},\n contextGrabbers: {},\n doNotIndent: {},\n allowUnquoted: false,\n allowMissing: false,\n allowMissingTagName: false,\n caseFold: false\n }\n\n CodeMirror.defineMode(\"xml\", function(editorConf, config_) {\n var indentUnit = editorConf.indentUnit\n var config = {}\n var defaults = config_.htmlMode ? htmlConfig : xmlConfig\n for (var prop in defaults) config[prop] = defaults[prop]\n for (var prop in config_) config[prop] = config_[prop]\n\n // Return variables for tokenizers\n var type, setStyle;\n\n function inText(stream, state) {\n function chain(parser) {\n state.tokenize = parser;\n return parser(stream, state);\n }\n\n var ch = stream.next();\n if (ch == \"<\") {\n if (stream.eat(\"!\")) {\n if (stream.eat(\"[\")) {\n if (stream.match(\"CDATA[\")) return chain(inBlock(\"atom\", \"]]>\"));\n else return null;\n } else if (stream.match(\"--\")) {\n return chain(inBlock(\"comment\", \"-->\"));\n } else if (stream.match(\"DOCTYPE\", true, true)) {\n stream.eatWhile(/[\\w\\._\\-]/);\n return chain(doctype(1));\n } else {\n return null;\n }\n } else if (stream.eat(\"?\")) {\n stream.eatWhile(/[\\w\\._\\-]/);\n state.tokenize = inBlock(\"meta\", \"?>\");\n return \"meta\";\n } else {\n type = stream.eat(\"/\") ? \"closeTag\" : \"openTag\";\n state.tokenize = inTag;\n return \"tag bracket\";\n }\n } else if (ch == \"&\") {\n var ok;\n if (stream.eat(\"#\")) {\n if (stream.eat(\"x\")) {\n ok = stream.eatWhile(/[a-fA-F\\d]/) && stream.eat(\";\");\n } else {\n ok = stream.eatWhile(/[\\d]/) && stream.eat(\";\");\n }\n } else {\n ok = stream.eatWhile(/[\\w\\.\\-:]/) && stream.eat(\";\");\n }\n return ok ? \"atom\" : \"error\";\n } else {\n stream.eatWhile(/[^&<]/);\n return null;\n }\n }\n inText.isInText = true;\n\n function inTag(stream, state) {\n var ch = stream.next();\n if (ch == \">\" || (ch == \"/\" && stream.eat(\">\"))) {\n state.tokenize = inText;\n type = ch == \">\" ? \"endTag\" : \"selfcloseTag\";\n return \"tag bracket\";\n } else if (ch == \"=\") {\n type = \"equals\";\n return null;\n } else if (ch == \"<\") {\n state.tokenize = inText;\n state.state = baseState;\n state.tagName = state.tagStart = null;\n var next = state.tokenize(stream, state);\n return next ? next + \" tag error\" : \"tag error\";\n } else if (/[\\'\\\"]/.test(ch)) {\n state.tokenize = inAttribute(ch);\n state.stringStartCol = stream.column();\n return state.tokenize(stream, state);\n } else {\n stream.match(/^[^\\s\\u00a0=<>\\\"\\']*[^\\s\\u00a0=<>\\\"\\'\\/]/);\n return \"word\";\n }\n }\n\n function inAttribute(quote) {\n var closure = function(stream, state) {\n while (!stream.eol()) {\n if (stream.next() == quote) {\n state.tokenize = inTag;\n break;\n }\n }\n return \"string\";\n };\n closure.isInAttribute = true;\n return closure;\n }\n\n function inBlock(style, terminator) {\n return function(stream, state) {\n while (!stream.eol()) {\n if (stream.match(terminator)) {\n state.tokenize = inText;\n break;\n }\n stream.next();\n }\n return style;\n }\n }\n\n function doctype(depth) {\n return function(stream, state) {\n var ch;\n while ((ch = stream.next()) != null) {\n if (ch == \"<\") {\n state.tokenize = doctype(depth + 1);\n return state.tokenize(stream, state);\n } else if (ch == \">\") {\n if (depth == 1) {\n state.tokenize = inText;\n break;\n } else {\n state.tokenize = doctype(depth - 1);\n return state.tokenize(stream, state);\n }\n }\n }\n return \"meta\";\n };\n }\n\n function lower(tagName) {\n return tagName && tagName.toLowerCase();\n }\n\n function Context(state, tagName, startOfLine) {\n this.prev = state.context;\n this.tagName = tagName || \"\";\n this.indent = state.indented;\n this.startOfLine = startOfLine;\n if (config.doNotIndent.hasOwnProperty(tagName) || (state.context && state.context.noIndent))\n this.noIndent = true;\n }\n function popContext(state) {\n if (state.context) state.context = state.context.prev;\n }\n function maybePopContext(state, nextTagName) {\n var parentTagName;\n while (true) {\n if (!state.context) {\n return;\n }\n parentTagName = state.context.tagName;\n if (!config.contextGrabbers.hasOwnProperty(lower(parentTagName)) ||\n !config.contextGrabbers[lower(parentTagName)].hasOwnProperty(lower(nextTagName))) {\n return;\n }\n popContext(state);\n }\n }\n\n function baseState(type, stream, state) {\n if (type == \"openTag\") {\n state.tagStart = stream.column();\n return tagNameState;\n } else if (type == \"closeTag\") {\n return closeTagNameState;\n } else {\n return baseState;\n }\n }\n function tagNameState(type, stream, state) {\n if (type == \"word\") {\n state.tagName = stream.current();\n setStyle = \"tag\";\n return attrState;\n } else if (config.allowMissingTagName && type == \"endTag\") {\n setStyle = \"tag bracket\";\n return attrState(type, stream, state);\n } else {\n setStyle = \"error\";\n return tagNameState;\n }\n }\n function closeTagNameState(type, stream, state) {\n if (type == \"word\") {\n var tagName = stream.current();\n if (state.context && state.context.tagName != tagName &&\n config.implicitlyClosed.hasOwnProperty(lower(state.context.tagName)))\n popContext(state);\n if ((state.context && state.context.tagName == tagName) || config.matchClosing === false) {\n setStyle = \"tag\";\n return closeState;\n } else {\n setStyle = \"tag error\";\n return closeStateErr;\n }\n } else if (config.allowMissingTagName && type == \"endTag\") {\n setStyle = \"tag bracket\";\n return closeState(type, stream, state);\n } else {\n setStyle = \"error\";\n return closeStateErr;\n }\n }\n\n function closeState(type, _stream, state) {\n if (type != \"endTag\") {\n setStyle = \"error\";\n return closeState;\n }\n popContext(state);\n return baseState;\n }\n function closeStateErr(type, stream, state) {\n setStyle = \"error\";\n return closeState(type, stream, state);\n }\n\n function attrState(type, _stream, state) {\n if (type == \"word\") {\n setStyle = \"attribute\";\n return attrEqState;\n } else if (type == \"endTag\" || type == \"selfcloseTag\") {\n var tagName = state.tagName, tagStart = state.tagStart;\n state.tagName = state.tagStart = null;\n if (type == \"selfcloseTag\" ||\n config.autoSelfClosers.hasOwnProperty(lower(tagName))) {\n maybePopContext(state, tagName);\n } else {\n maybePopContext(state, tagName);\n state.context = new Context(state, tagName, tagStart == state.indented);\n }\n return baseState;\n }\n setStyle = \"error\";\n return attrState;\n }\n function attrEqState(type, stream, state) {\n if (type == \"equals\") return attrValueState;\n if (!config.allowMissing) setStyle = \"error\";\n return attrState(type, stream, state);\n }\n function attrValueState(type, stream, state) {\n if (type == \"string\") return attrContinuedState;\n if (type == \"word\" && config.allowUnquoted) {setStyle = \"string\"; return attrState;}\n setStyle = \"error\";\n return attrState(type, stream, state);\n }\n function attrContinuedState(type, stream, state) {\n if (type == \"string\") return attrContinuedState;\n return attrState(type, stream, state);\n }\n\n return {\n startState: function(baseIndent) {\n var state = {tokenize: inText,\n state: baseState,\n indented: baseIndent || 0,\n tagName: null, tagStart: null,\n context: null}\n if (baseIndent != null) state.baseIndent = baseIndent\n return state\n },\n\n token: function(stream, state) {\n if (!state.tagName && stream.sol())\n state.indented = stream.indentation();\n\n if (stream.eatSpace()) return null;\n type = null;\n var style = state.tokenize(stream, state);\n if ((style || type) && style != \"comment\") {\n setStyle = null;\n state.state = state.state(type || style, stream, state);\n if (setStyle)\n style = setStyle == \"error\" ? style + \" error\" : setStyle;\n }\n return style;\n },\n\n indent: function(state, textAfter, fullLine) {\n var context = state.context;\n // Indent multi-line strings (e.g. css).\n if (state.tokenize.isInAttribute) {\n if (state.tagStart == state.indented)\n return state.stringStartCol + 1;\n else\n return state.indented + indentUnit;\n }\n if (context && context.noIndent) return CodeMirror.Pass;\n if (state.tokenize != inTag && state.tokenize != inText)\n return fullLine ? fullLine.match(/^(\\s*)/)[0].length : 0;\n // Indent the starts of attribute names.\n if (state.tagName) {\n if (config.multilineTagIndentPastTag !== false)\n return state.tagStart + state.tagName.length + 2;\n else\n return state.tagStart + indentUnit * (config.multilineTagIndentFactor || 1);\n }\n if (config.alignCDATA && /<!\\[CDATA\\[/.test(textAfter)) return 0;\n var tagAfter = textAfter && /^<(\\/)?([\\w_:\\.-]*)/.exec(textAfter);\n if (tagAfter && tagAfter[1]) { // Closing tag spotted\n while (context) {\n if (context.tagName == tagAfter[2]) {\n context = context.prev;\n break;\n } else if (config.implicitlyClosed.hasOwnProperty(lower(context.tagName))) {\n context = context.prev;\n } else {\n break;\n }\n }\n } else if (tagAfter) { // Opening tag spotted\n while (context) {\n var grabbers = config.contextGrabbers[lower(context.tagName)];\n if (grabbers && grabbers.hasOwnProperty(lower(tagAfter[2])))\n context = context.prev;\n else\n break;\n }\n }\n while (context && context.prev && !context.startOfLine)\n context = context.prev;\n if (context) return context.indent + indentUnit;\n else return state.baseIndent || 0;\n },\n\n electricInput: /<\\/[\\s\\w:]+>$/,\n blockCommentStart: \"<!--\",\n blockCommentEnd: \"-->\",\n\n configuration: config.htmlMode ? \"html\" : \"xml\",\n helperType: config.htmlMode ? \"html\" : \"xml\",\n\n skipAttribute: function(state) {\n if (state.state == attrValueState)\n state.state = attrState\n },\n\n xmlCurrentTag: function(state) {\n return state.tagName ? {name: state.tagName, close: state.type == \"closeTag\"} : null\n },\n\n xmlCurrentContext: function(state) {\n var context = []\n for (var cx = state.context; cx; cx = cx.prev)\n context.push(cx.tagName)\n return context.reverse()\n }\n };\n });\n\n CodeMirror.defineMIME(\"text/xml\", \"xml\");\n CodeMirror.defineMIME(\"application/xml\", \"xml\");\n if (!CodeMirror.mimeModes.hasOwnProperty(\"text/html\"))\n CodeMirror.defineMIME(\"text/html\", {name: \"xml\", htmlMode: true});\n\n});","Magento_AdminAdobeIms/postcss.config.js":"module.exports = {\n plugins: [\n require('postcss-import'),\n require('postcss-varfallback'),\n require('postcss-dropunusedvars'),\n require('cssnano')\n ]\n};\n","Magento_AdminAdobeIms/js/loadicons.js":"/*\nCopyright 2018 Adobe. All rights reserved.\nThis file is licensed to you under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License. You may obtain a copy\nof the License at http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software distributed under\nthe License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\nOF ANY KIND, either express or implied. See the License for the specific language\ngoverning permissions and limitations under the License.\n*/\n\n// UMD pattern via umdjs\n(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n // AMD\n define([], factory);\n }\n else if (typeof module === 'object' && module.exports) {\n // CommonJS-like\n module.exports = factory();\n }\n else {\n // Browser\n root.loadIcons = factory();\n }\n}(typeof self !== 'undefined' ? self : this, function() {\n function handleError(string) {\n string = 'loadIcons: '+string;\n var error = new Error(string);\n\n console.error(error.toString());\n\n if (typeof callback === 'function') {\n callback(error);\n }\n }\n\n function injectSVG(svgURL, callback) {\n var error;\n // 200 for web servers, 0 for CEP panels\n if (this.status !== 200 && this.status !== 0) {\n handleError('Failed to fetch icons, server returned ' + this.status);\n return;\n }\n\n // Parse the SVG\n var parser = new DOMParser();\n try {\n var doc = parser.parseFromString(this.responseText, 'image/svg+xml');\n var svg = doc.firstChild;\n }\n catch (err) {\n handleError('Error parsing SVG: ' + err);\n return;\n }\n\n // Make sure a real SVG was returned\n if (svg && svg.tagName === 'svg') {\n // Hide the element\n svg.style.display = 'none';\n\n svg.setAttribute('data-url', svgURL);\n\n // Insert it into the head\n document.head.insertBefore(svg, null);\n\n // Pass the SVG to the callback\n if (typeof callback === 'function') {\n callback(null, svg);\n }\n }\n else {\n handleError('Parsed SVG document contained something other than an SVG');\n }\n }\n\n function loadIcons(svgURL, callback) {\n // Request the SVG sprite\n var req = new XMLHttpRequest();\n req.open('GET', svgURL, true);\n req.addEventListener('load', injectSVG.bind(req, svgURL, callback));\n req.addEventListener('error', function(event) {\n handleError('Request failed');\n });\n req.send();\n }\n\n return loadIcons;\n}));\n","Magento_AdminAdobeIms/js/admin_adobe_ims_load_icons.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n 'jquery',\n 'underscore',\n 'Magento_AdminAdobeIms/js/loadicons'\n], function ($, _, loadicons) {\n 'use strict';\n\n var icons = {},\n\n loadIcons = {\n /**\n * loadicons initialization\n */\n init: function () {\n loadicons(icons.spectrumCssIcons);\n loadicons(icons.spectrumIcons);\n },\n\n /**\n * @param {Object} iconUrls\n * @constructor\n */\n 'Magento_AdminAdobeIms/js/admin_adobe_ims_load_icons': function (iconUrls) {\n icons = iconUrls;\n loadIcons.init();\n }\n };\n\n return loadIcons;\n});\n","Magento_AdminAdobeIms/js/adobe-ims-reauth.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n 'uiComponent',\n 'jquery',\n 'Magento_AdobeIms/js/action/authorization'\n], function (Component, $, login) {\n 'use strict';\n\n return Component.extend({\n defaults: {\n loginConfig: {\n url: 'https://ims-na1-stg.adobelogin.com/ims/authorize',\n callbackParsingParams: {\n regexpPattern: /auth\\[code=(success|error);message=(.+)\\]/,\n codeIndex: 1,\n messageIndex: 2,\n nameIndex: 3,\n successCode: 'success',\n errorCode: 'error'\n },\n popupWindowParams: {\n width: 500,\n height: 600,\n top: 100,\n left: 300\n },\n popupWindowTimeout: 60000\n }\n },\n\n /**\n * @override\n */\n initialize: function () {\n this._super();\n this.login();\n },\n\n /**\n * Open popup for Adobe reauth\n *\n * @return {window.Promise}\n */\n login: function () {\n var deferred = $.Deferred(),\n loginConfig = this.loginConfig;\n\n $('input.ims_verification').on('click', function () {\n login(loginConfig)\n .then(function (response) {\n if (response.isAuthorized === true) {\n $('input.ims_verified').val(true);\n }\n deferred.resolve(response);\n })\n .fail(function (error) {\n deferred.reject(error);\n });\n });\n\n return deferred.promise();\n }\n });\n});\n","mage/multiselect.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'underscore',\n 'jquery',\n 'text!mage/multiselect.html',\n 'Magento_Ui/js/modal/alert',\n 'jquery-ui-modules/widget',\n 'jquery/editableMultiselect/js/jquery.multiselect'\n], function (_, $, searchTemplate, alert) {\n 'use strict';\n\n $.widget('mage.multiselect2', {\n options: {\n mselectContainer: 'section.mselect-list',\n mselectItemsWrapperClass: 'mselect-items-wrapper',\n mselectCheckedClass: 'mselect-checked',\n containerClass: 'paginated',\n searchInputClass: 'admin__action-multiselect-search',\n selectedItemsCountClass: 'admin__action-multiselect-items-selected',\n currentPage: 1,\n lastAppendValue: 0,\n updateDelay: 1000,\n optionsLoaded: false\n },\n\n /** @inheritdoc */\n _create: function () {\n $.fn.multiselect.call(this.element, this.options);\n },\n\n /** @inheritdoc */\n _init: function () {\n this.domElement = this.element.get(0);\n\n this.$container = $(this.options.mselectContainer);\n this.$wrapper = this.$container.find('.' + this.options.mselectItemsWrapperClass);\n this.$item = this.$wrapper.find('div').first();\n this.selectedValues = [];\n this.values = {};\n\n this.$container.addClass(this.options.containerClass).prepend(searchTemplate);\n this.$input = this.$container.find('.' + this.options.searchInputClass);\n this.$selectedCounter = this.$container.find('.' + this.options.selectedItemsCountClass);\n this.filter = '';\n\n if (this.domElement.options.length) {\n this._setLastAppendOption(this.domElement.options[this.domElement.options.length - 1].value);\n }\n\n this._initElement();\n this._events();\n },\n\n /**\n * Leave only saved/selected options in select element.\n *\n * @private\n */\n _initElement: function () {\n this.element.empty();\n _.each(this.options.selectedValues, function (value) {\n this._createSelectedOption({\n value: value,\n label: value\n });\n }, this);\n },\n\n /**\n * Attach required events.\n *\n * @private\n */\n _events: function () {\n var onKeyUp = _.debounce(this.onKeyUp, this.options.updateDelay);\n\n _.bindAll(this, 'onScroll', 'onCheck', 'onOptionsChange');\n\n this.$wrapper.on('scroll', this.onScroll);\n this.$wrapper.on('change.mselectCheck', '[type=checkbox]', this.onCheck);\n this.$input.on('keyup', _.bind(onKeyUp, this));\n this.element.on('change.hiddenSelect', this.onOptionsChange);\n },\n\n /**\n * Behaves multiselect scroll.\n */\n onScroll: function () {\n var height = this.$wrapper.height(),\n scrollHeight = this.$wrapper.prop('scrollHeight'),\n scrollTop = Math.ceil(this.$wrapper.prop('scrollTop'));\n\n if (!this.options.optionsLoaded && scrollHeight - height <= scrollTop) {\n this.loadOptions();\n }\n },\n\n /**\n * Behaves keyup event on input search\n */\n onKeyUp: function () {\n if (this.getSearchCriteria() === this.filter) {\n return false;\n }\n\n this.setFilter();\n this.clearMultiselectOptions();\n this.setCurrentPage(0);\n this.loadOptions();\n },\n\n /**\n * Callback for select change event\n */\n onOptionsChange: function () {\n this.selectedValues = _.map(this.domElement.options, function (option) {\n this.values[option.value] = true;\n\n return option.value;\n }, this);\n\n this._updateSelectedCounter();\n },\n\n /**\n * Overrides native check behaviour.\n *\n * @param {Event} event\n */\n onCheck: function (event) {\n var checkbox = event.target,\n option = {\n value: checkbox.value,\n label: $(checkbox).parent('label').text()\n };\n\n checkbox.checked ? this._createSelectedOption(option) : this._removeSelectedOption(option);\n event.stopPropagation();\n },\n\n /**\n * Show error message.\n *\n * @param {String} message\n */\n onError: function (message) {\n alert({\n content: message\n });\n },\n\n /**\n * Updates current filter state.\n */\n setFilter: function () {\n this.filter = this.getSearchCriteria() || '';\n },\n\n /**\n * Reads search input value.\n *\n * @return {String}\n */\n getSearchCriteria: function () {\n return this.$input.val().trim();\n },\n\n /**\n * Load options data.\n */\n loadOptions: function () {\n var nextPage = this.getCurrentPage() + 1;\n\n this.$wrapper.trigger('processStart');\n this.$input.prop('disabled', true);\n\n $.get(this.options.nextPageUrl, {\n p: nextPage,\n s: this.filter\n })\n .done(function (response) {\n if (response.success) {\n this.appendOptions(response.result);\n this.setCurrentPage(nextPage);\n } else {\n this.onError(response.errorMessage);\n }\n }.bind(this))\n .always(function () {\n this.$wrapper.trigger('processStop');\n this.$input.prop('disabled', false);\n\n if (this.filter) {\n this.$input.focus();\n }\n }.bind(this));\n },\n\n /**\n * Append loaded options\n *\n * @param {Array} options\n */\n appendOptions: function (options) {\n var divOptions = [];\n\n if (!options.length) {\n return false;\n }\n\n if (this.isOptionsLoaded(options)) {\n return;\n }\n\n options.forEach(function (option) {\n if (!this.values[option.value]) {\n this.values[option.value] = true;\n option.selected = this._isOptionSelected(option);\n divOptions.push(this._createMultiSelectOption(option));\n this._setLastAppendOption(option.value);\n }\n }, this);\n\n this.$wrapper.append(divOptions);\n },\n\n /**\n * Clear multiselect options\n */\n clearMultiselectOptions: function () {\n this._setLastAppendOption(0);\n this.values = {};\n this.$wrapper.empty();\n },\n\n /**\n * Checks if all options are already loaded\n *\n * @return {Boolean}\n */\n isOptionsLoaded: function (options) {\n this.options.optionsLoaded = this.options.lastAppendValue === options[options.length - 1].value;\n\n return this.options.optionsLoaded;\n },\n\n /**\n * Setter for current page.\n *\n * @param {Number} page\n */\n setCurrentPage: function (page) {\n this.options.currentPage = page;\n },\n\n /**\n * Getter for current page.\n *\n * @return {Number}\n */\n getCurrentPage: function () {\n return this.options.currentPage;\n },\n\n /**\n * Creates new selected option for select element\n *\n * @param {Object} option - option object\n * @param {String} option.value - option value\n * @param {String} option.label - option label\n * @private\n */\n _createSelectedOption: function (option) {\n var selectOption = new Option(option.label, option.value, false, true);\n\n this.element.append(selectOption);\n this.selectedValues.push(option.value);\n this._updateSelectedCounter();\n\n return selectOption;\n },\n\n /**\n * Remove passed option from select element\n *\n * @param {Object} option - option object\n * @param {String} option.value - option value\n * @param {String} option.label - option label\n * @return {Object} option\n * @private\n */\n _removeSelectedOption: function (option) {\n var unselectedOption = _.findWhere(this.domElement.options, {\n value: option.value\n });\n\n if (!_.isUndefined(unselectedOption)) {\n this.domElement.remove(unselectedOption.index);\n this.selectedValues.splice(_.indexOf(this.selectedValues, option.value), 1);\n this._updateSelectedCounter();\n }\n\n return unselectedOption;\n },\n\n /**\n * Creates new DIV option for multiselect widget\n *\n * @param {Object} option - option object\n * @param {String} option.value - option value\n * @param {String} option.label - option label\n * @param {Boolean} option.selected - is option selected\n * @private\n */\n _createMultiSelectOption: function (option) {\n var item = this.$item.clone(),\n checkbox = item.find('input'),\n isSelected = !!option.selected;\n\n checkbox.val(option.value)\n .prop('checked', isSelected)\n .toggleClass(this.options.mselectCheckedClass, isSelected);\n\n item.find('label > span').text(option.label);\n\n return item;\n },\n\n /**\n * Checks if passed option should be selected\n *\n * @param {Object} option - option object\n * @param {String} option.value - option value\n * @param {String} option.label - option label\n * @param {Boolean} option.selected - is option selected\n * @return {Boolean}\n * @private\n */\n _isOptionSelected: function (option) {\n return !!~this.selectedValues.indexOf(option.value);\n },\n\n /**\n * Saves last added option value.\n *\n * @param {Number} value\n * @private\n */\n _setLastAppendOption: function (value) {\n this.options.lastAppendValue = value;\n },\n\n /**\n * Updates counter of selected items.\n *\n * @private\n */\n _updateSelectedCounter: function () {\n this.$selectedCounter.text(this.selectedValues.length);\n }\n });\n\n return $.mage.multiselect2;\n});\n","mage/tabs.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'jquery',\n 'jquery-ui-modules/widget',\n 'jquery/ui-modules/widgets/tabs',\n 'mage/mage',\n 'mage/collapsible'\n], function ($) {\n 'use strict';\n\n $.widget('mage.tabs', {\n options: {\n active: 0,\n disabled: [],\n openOnFocus: true,\n collapsible: false,\n collapsibleElement: '[data-role=collapsible]',\n header: '[data-role=title]',\n content: '[data-role=content]',\n trigger: '[data-role=trigger]',\n closedState: null,\n openedState: null,\n disabledState: null,\n ajaxUrlElement: '[data-ajax=true]',\n ajaxContent: false,\n loadingClass: null,\n saveState: false,\n animate: false,\n icons: {\n activeHeader: null,\n header: null\n }\n },\n\n /**\n * @private\n */\n _create: function () {\n if (typeof this.options.disabled === 'string') {\n this.options.disabled = this.options.disabled.split(' ').map(function (item) {\n return parseInt(item, 10);\n });\n }\n this._processPanels();\n this._handleDeepLinking();\n this._processTabIndex();\n this._closeOthers();\n this._bind();\n },\n\n /**\n * @private\n */\n _destroy: function () {\n $.each(this.collapsibles, function () {\n $(this).collapsible('destroy');\n });\n },\n\n /**\n * If deep linking is used, all sections must be closed but the one that contains the anchor.\n * @private\n */\n _handleDeepLinking: function () {\n var self = this,\n anchor = window.location.hash,\n isValid = $.mage.isValidSelector(anchor),\n anchorId = anchor.replace('#', '');\n\n if (anchor && isValid) {\n $.each(self.contents, function (i) {\n if ($(this).attr('id') === anchorId || $(this).find('#' + anchorId).length) {\n self.collapsibles.not(self.collapsibles.eq(i)).collapsible('forceDeactivate');\n\n return false;\n }\n });\n }\n },\n\n /**\n * When the widget gets instantiated, the first tab that is not disabled receive focusable property\n * All tabs receive tabIndex 0\n * @private\n */\n _processTabIndex: function () {\n var self = this;\n\n self.triggers.attr('tabIndex', 0);\n $.each(this.collapsibles, function (i) {\n self.triggers.attr('tabIndex', 0);\n self.triggers.eq(i).attr('tabIndex', 0);\n });\n },\n\n /**\n * Prepare the elements for instantiating the collapsible widget\n * @private\n */\n _processPanels: function () {\n var isNotNested = this._isNotNested.bind(this);\n\n this.contents = this.element\n .find(this.options.content)\n .filter(isNotNested);\n\n this.collapsibles = this.element\n .find(this.options.collapsibleElement)\n .filter(isNotNested);\n\n this.collapsibles\n .attr('role', 'presentation')\n .parent()\n .attr('role', 'tablist');\n\n this.headers = this.element\n .find(this.options.header)\n .filter(isNotNested);\n\n if (this.headers.length === 0) {\n this.headers = this.collapsibles;\n }\n this.triggers = this.element\n .find(this.options.trigger)\n .filter(isNotNested);\n\n if (this.triggers.length === 0) {\n this.triggers = this.headers;\n }\n this._callCollapsible();\n },\n\n /**\n * Checks if element is not in nested container to keep the correct scope of collapsible\n * @param {Number} index\n * @param {HTMLElement} element\n * @private\n * @return {Boolean}\n */\n _isNotNested: function (index, element) {\n var parentContent = $(element).parents(this.options.content);\n\n return !parentContent.length || !this.element.find(parentContent).length;\n },\n\n /**\n * Setting the disabled and active tabs and calling instantiation of collapsible\n * @private\n */\n _callCollapsible: function () {\n var self = this,\n disabled = false,\n active = false;\n\n $.each(this.collapsibles, function (i) {\n disabled = active = false;\n\n if ($.inArray(i, self.options.disabled) !== -1) {\n disabled = true;\n }\n\n if (i === self.options.active) {\n active = true;\n }\n self._instantiateCollapsible(this, i, active, disabled);\n });\n },\n\n /**\n * Instantiate collapsible.\n *\n * @param {HTMLElement} element\n * @param {Number} index\n * @param {*} active\n * @param {*} disabled\n * @private\n */\n _instantiateCollapsible: function (element, index, active, disabled) {\n $(element).collapsible(\n $.extend({}, this.options, {\n active: active,\n disabled: disabled,\n header: this.headers.eq(index),\n content: this.contents.eq(index),\n trigger: this.triggers.eq(index)\n })\n );\n },\n\n /**\n * Adding callback to close others tabs when one gets opened\n * @private\n */\n _closeOthers: function () {\n var self = this;\n\n $.each(this.collapsibles, function () {\n $(this).on('beforeOpen', function () {\n self.collapsibles.not(this).collapsible('forceDeactivate');\n });\n });\n },\n\n /**\n * @param {*} index\n */\n activate: function (index) {\n this._toggleActivate('activate', index);\n },\n\n /**\n * @param {*} index\n */\n deactivate: function (index) {\n this._toggleActivate('deactivate', index);\n },\n\n /**\n * @param {*} action\n * @param {*} index\n * @private\n */\n _toggleActivate: function (action, index) {\n this.collapsibles.eq(index).collapsible(action);\n },\n\n /**\n * @param {*} index\n */\n disable: function (index) {\n this._toggleEnable('disable', index);\n },\n\n /**\n * @param {*} index\n */\n enable: function (index) {\n this._toggleEnable('enable', index);\n },\n\n /**\n * @param {*} action\n * @param {*} index\n * @private\n */\n _toggleEnable: function (action, index) {\n var self = this;\n\n if (Array.isArray(index)) {\n $.each(index, function () {\n self.collapsibles.eq(this).collapsible(action);\n });\n } else if (index === undefined) {\n this.collapsibles.collapsible(action);\n } else {\n this.collapsibles.eq(index).collapsible(action);\n }\n },\n\n /**\n * @param {jQuery.Event} event\n * @private\n */\n _keydown: function (event) {\n var self = this,\n keyCode, toFocus, toFocusIndex, enabledTriggers, length, currentIndex, nextToFocus;\n\n if (event.altKey || event.ctrlKey) {\n return;\n }\n keyCode = $.ui.keyCode;\n toFocus = false;\n enabledTriggers = [];\n\n $.each(this.triggers, function () {\n if (!self.collapsibles.eq(self.triggers.index($(this))).collapsible('option', 'disabled')) {\n enabledTriggers.push(this);\n }\n });\n length = $(enabledTriggers).length;\n currentIndex = $(enabledTriggers).index(event.target);\n\n /**\n * @param {String} direction\n * @return {*}\n */\n nextToFocus = function (direction) {\n if (length > 0) {\n if (direction === 'right') {\n toFocusIndex = (currentIndex + 1) % length;\n } else {\n toFocusIndex = (currentIndex + length - 1) % length;\n }\n\n return enabledTriggers[toFocusIndex];\n }\n\n return event.target;\n };\n\n switch (event.keyCode) {\n case keyCode.RIGHT:\n case keyCode.DOWN:\n toFocus = nextToFocus('right');\n break;\n\n case keyCode.LEFT:\n case keyCode.UP:\n toFocus = nextToFocus('left');\n break;\n\n case keyCode.HOME:\n toFocus = enabledTriggers[0];\n break;\n\n case keyCode.END:\n toFocus = enabledTriggers[length - 1];\n break;\n }\n\n if (toFocus) {\n toFocusIndex = this.triggers.index(toFocus);\n $(event.target).attr('tabIndex', -1);\n $(toFocus).attr('tabIndex', 0);\n toFocus.focus();\n\n if (this.options.openOnFocus) {\n this.activate(toFocusIndex);\n }\n event.preventDefault();\n }\n },\n\n /**\n * @private\n */\n _bind: function () {\n var events = {\n keydown: '_keydown'\n };\n\n this._off(this.triggers);\n this._on(this.triggers, events);\n }\n });\n\n return $.mage.tabs;\n});\n","mage/validation.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'jquery',\n 'moment',\n 'mageUtils',\n 'jquery-ui-modules/widget',\n 'jquery/validate',\n 'mage/translate'\n], function ($, moment, utils) {\n 'use strict';\n\n var creditCartTypes, rules, showLabel, originValidateDelegate;\n\n $.extend(true, $, {\n // @TODO: Move methods 'isEmpty', 'isEmptyNoTrim', 'parseNumber', 'stripHtml' in file with utility functions\n mage: {\n /**\n * Check if string is empty with trim\n * @param {String} value\n */\n isEmpty: function (value) {\n return value === '' || value === undefined ||\n value == null || value.length === 0 || /^\\s+$/.test(value);\n },\n\n /**\n * Check if string is empty no trim\n * @param {String} value\n */\n isEmptyNoTrim: function (value) {\n return value === '' || value == null || value.length === 0;\n },\n\n /**\n * Checks if {value} is between numbers {from} and {to}\n * @param {String} value\n * @param {String} from\n * @param {String} to\n * @returns {Boolean}\n */\n isBetween: function (value, from, to) {\n return ($.mage.isEmpty(from) || value >= $.mage.parseNumber(from)) &&\n ($.mage.isEmpty(to) || value <= $.mage.parseNumber(to));\n },\n\n /**\n * Parse price string\n * @param {String} value\n */\n parseNumber: function (value) {\n var isDot, isComa;\n\n if (typeof value !== 'string') {\n return parseFloat(value);\n }\n isDot = value.indexOf('.');\n isComa = value.indexOf(',');\n\n if (isDot !== -1 && isComa !== -1) {\n if (isComa > isDot) {\n value = value.replace('.', '').replace(',', '.');\n } else {\n value = value.replace(',', '');\n }\n } else if (isComa !== -1) {\n value = value.replace(',', '.');\n }\n\n return parseFloat(value);\n },\n\n /**\n * Removes HTML tags and space characters, numbers and punctuation.\n *\n * @param {String} value - Value being stripped.\n * @return {String}\n */\n stripHtml: function (value) {\n return value.replace(/<.[^<>]*?>/g, ' ').replace(/ | /gi, ' ')\n .replace(/[0-9.(),;:!?%#$'\"_+=\\/-]*/g, '');\n }\n }\n });\n\n /**\n * @param {String} name\n * @param {*} method\n * @param {*} message\n * @param {*} dontSkip\n */\n $.validator.addMethod = function (name, method, message, dontSkip) {\n $.validator.methods[name] = method;\n $.validator.messages[name] = message !== undefined ? message : $.validator.messages[name];\n\n if (method.length < 3 || dontSkip) {\n $.validator.addClassRules(name, $.validator.normalizeRule(name));\n }\n };\n\n /**\n * Javascript object with credit card types\n * 0 - regexp for card number\n * 1 - regexp for cvn\n * 2 - check or not credit card number trough Luhn algorithm by\n */\n creditCartTypes = {\n 'SO': [\n new RegExp('^(6334[5-9]([0-9]{11}|[0-9]{13,14}))|(6767([0-9]{12}|[0-9]{14,15}))$'),\n new RegExp('^([0-9]{3}|[0-9]{4})?$'),\n true\n ],\n 'SM': [\n new RegExp('(^(5[0678])[0-9]{11,18}$)|(^(6[^05])[0-9]{11,18}$)|' +\n '(^(601)[^1][0-9]{9,16}$)|(^(6011)[0-9]{9,11}$)|(^(6011)[0-9]{13,16}$)|' +\n '(^(65)[0-9]{11,13}$)|(^(65)[0-9]{15,18}$)|(^(49030)[2-9]([0-9]{10}$|[0-9]{12,13}$))|' +\n '(^(49033)[5-9]([0-9]{10}$|[0-9]{12,13}$))|(^(49110)[1-2]([0-9]{10}$|[0-9]{12,13}$))|' +\n '(^(49117)[4-9]([0-9]{10}$|[0-9]{12,13}$))|(^(49118)[0-2]([0-9]{10}$|[0-9]{12,13}$))|' +\n '(^(4936)([0-9]{12}$|[0-9]{14,15}$))'), new RegExp('^([0-9]{3}|[0-9]{4})?$'),\n true\n ],\n 'VI': [new RegExp('^4[0-9]{12}([0-9]{3})?$'), new RegExp('^[0-9]{3}$'), true],\n 'MC': [\n new RegExp('^(?:5[1-5][0-9]{2}|222[1-9]|22[3-9][0-9]|2[3-6][0-9]{2}|27[01][0-9]|2720)[0-9]{12}$'),\n new RegExp('^[0-9]{3}$'),\n true\n ],\n 'AE': [new RegExp('^3[47][0-9]{13}$'), new RegExp('^[0-9]{4}$'), true],\n 'DI': [new RegExp('^(6011(0|[2-4]|74|7[7-9]|8[6-9]|9)|6(4[4-9]|5))\\\\d*$'), new RegExp('^[0-9]{3}$'), true],\n 'JCB': [new RegExp('^35(2[8-9]|[3-8])\\\\d*$'), new RegExp('^[0-9]{3}$'), true],\n 'DN': [new RegExp('^(3(0[0-5]|095|6|[8-9]))\\\\d*$'), new RegExp('^[0-9]{3}$'), true],\n 'UN': [\n new RegExp('^(622(1(2[6-9]|[3-9])|[3-8]|9([[0-1]|2[0-5]))|62[4-6]|628([2-8]))\\\\d*?$'),\n new RegExp('^[0-9]{3}$'),\n true\n ],\n 'MI': [new RegExp('^(5(0|[6-9])|63|67(?!59|6770|6774))\\\\d*$'), new RegExp('^[0-9]{3}$'), true],\n 'MD': [new RegExp('^6759(?!24|38|40|6[3-9]|70|76)|676770|676774\\\\d*$'), new RegExp('^[0-9]{3}$'), true]\n };\n\n /**\n * validate credit card number using mod10\n * @param {String} s\n * @return {Boolean}\n */\n function validateCreditCard(s) {\n // remove non-numerics\n var v = '0123456789',\n w = '',\n i, j, k, m, c, a, x;\n\n for (i = 0; i < s.length; i++) {\n x = s.charAt(i);\n\n if (v.indexOf(x, 0) !== -1) {\n w += x;\n }\n }\n // validate number\n j = w.length / 2;\n k = Math.floor(j);\n m = Math.ceil(j) - k;\n c = 0;\n\n for (i = 0; i < k; i++) {\n a = w.charAt(i * 2 + m) * 2;\n c += a > 9 ? Math.floor(a / 10 + a % 10) : a;\n }\n\n for (i = 0; i < k + m; i++) {\n c += w.charAt(i * 2 + 1 - m) * 1;\n }\n\n return c % 10 === 0;\n }\n\n /**\n * validate all table required inputs at once, using single hidden input\n * @param {String} value\n * @param {HTMLElement} element\n *\n * @return {Boolean}\n */\n function tableSingleValidation(value, element) {\n var empty = $(element).closest('table')\n .find('input.required-option:visible')\n .filter(function (i, el) {\n if ($(el).is('disabled')) {\n return $.mage.isEmpty(el.value);\n }\n })\n .length;\n\n return empty === 0;\n }\n\n /**\n *\n * @param {float} qty\n * @param {float} qtyIncrements\n * @returns {float}\n */\n function resolveModulo(qty, qtyIncrements) {\n var divideEpsilon = 10000,\n epsilon,\n remainder;\n\n while (qtyIncrements < 1) {\n qty *= 10;\n qtyIncrements *= 10;\n }\n\n epsilon = qtyIncrements / divideEpsilon;\n remainder = qty % qtyIncrements;\n\n if (Math.abs(remainder - qtyIncrements) < epsilon ||\n Math.abs(remainder) < epsilon) {\n remainder = 0;\n }\n\n return remainder;\n }\n\n /**\n * Collection of validation rules including rules from additional-methods.js\n * @type {Object}\n */\n rules = {\n 'max-words': [\n function (value, element, params) {\n return this.optional(element) || $.mage.stripHtml(value).match(/\\b\\w+\\b/g).length <= params;\n },\n $.mage.__('Please enter {0} words or less.')\n ],\n 'min-words': [\n function (value, element, params) {\n return this.optional(element) || $.mage.stripHtml(value).match(/\\b\\w+\\b/g).length >= params;\n },\n $.mage.__('Please enter at least {0} words.')\n ],\n 'range-words': [\n function (value, element, params) {\n return this.optional(element) ||\n $.mage.stripHtml(value).match(/\\b\\w+\\b/g).length >= params[0] &&\n value.match(/bw+b/g).length < params[1];\n },\n $.mage.__('Please enter between {0} and {1} words.')\n ],\n 'letters-with-basic-punc': [\n function (value, element) {\n return this.optional(element) || /^[a-z\\-.,()'\\\"\\s]+$/i.test(value);\n },\n $.mage.__('Letters or punctuation only please')\n ],\n 'alphanumeric': [\n function (value, element) {\n return this.optional(element) || /^\\w+$/i.test(value);\n },\n $.mage.__('Letters, numbers, spaces or underscores only please')\n ],\n 'letters-only': [\n function (value, element) {\n return this.optional(element) || /^[a-z]+$/i.test(value);\n },\n $.mage.__('Letters only please')\n ],\n 'no-whitespace': [\n function (value, element) {\n return this.optional(element) || /^\\S+$/i.test(value);\n },\n $.mage.__('No white space please')\n ],\n 'no-marginal-whitespace': [\n function (value, element) {\n return this.optional(element) || !/^\\s+|\\s+$/i.test(value);\n },\n $.mage.__('No marginal white space please')\n ],\n 'zip-range': [\n function (value, element) {\n return this.optional(element) || /^90[2-5]-\\d{2}-\\d{4}$/.test(value);\n },\n $.mage.__('Your ZIP-code must be in the range 902xx-xxxx to 905-xx-xxxx')\n ],\n 'integer': [\n function (value, element) {\n return this.optional(element) || /^-?\\d+$/.test(value);\n },\n $.mage.__('A positive or negative non-decimal number please')\n ],\n 'vinUS': [\n function (v) {\n var i, n, d, f, cd, cdv, LL, VL, FL, rs;\n\n /* eslint-disable max-depth */\n if (v.length !== 17) {\n return false;\n }\n\n LL = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L',\n 'M', 'N', 'P', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];\n VL = [1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 7, 9, 2, 3, 4, 5, 6, 7, 8, 9];\n FL = [8, 7, 6, 5, 4, 3, 2, 10, 0, 9, 8, 7, 6, 5, 4, 3, 2];\n rs = 0;\n\n for (i = 0; i < 17; i++) {\n f = FL[i];\n d = v.slice(i, i + 1);\n\n if (i === 8) {\n cdv = d;\n }\n\n if (!isNaN(d)) {\n d *= f;\n } else {\n for (n = 0; n < LL.length; n++) {\n if (d.toUpperCase() === LL[n]) {\n d = VL[n];\n d *= f;\n\n if (isNaN(cdv) && n === 8) {\n cdv = LL[n];\n }\n break;\n }\n }\n }\n rs += d;\n }\n\n /* eslint-enable max-depth */\n cd = rs % 11;\n\n if (cd === 10) {\n cd = 'X';\n }\n\n if (cd === cdv) {\n return true;\n }\n\n return false;\n },\n $.mage.__('The specified vehicle identification number (VIN) is invalid.')\n ],\n 'dateITA': [\n function (value, element) {\n var check = false,\n re = /^\\d{1,2}\\/\\d{1,2}\\/\\d{4}$/,\n adata, gg, mm, aaaa, xdata;\n\n if (re.test(value)) {\n adata = value.split('/');\n gg = parseInt(adata[0], 10);\n mm = parseInt(adata[1], 10);\n aaaa = parseInt(adata[2], 10);\n xdata = new Date(aaaa, mm - 1, gg);\n\n if (xdata.getFullYear() === aaaa &&\n xdata.getMonth() === mm - 1 &&\n xdata.getDate() === gg\n ) {\n check = true;\n } else {\n check = false;\n }\n } else {\n check = false;\n }\n\n return this.optional(element) || check;\n },\n $.mage.__('Please enter a correct date')\n ],\n 'dateNL': [\n function (value, element) {\n return this.optional(element) || /^\\d\\d?[\\.\\/-]\\d\\d?[\\.\\/-]\\d\\d\\d?\\d?$/.test(value);\n },\n 'Vul hier een geldige datum in.'\n ],\n 'time': [\n function (value, element) {\n return this.optional(element) || /^([01]\\d|2[0-3])(:[0-5]\\d){0,2}$/.test(value);\n },\n $.mage.__('Please enter a valid time, between 00:00 and 23:59')\n ],\n 'time12h': [\n function (value, element) {\n return this.optional(element) || /^((0?[1-9]|1[012])(:[0-5]\\d){0,2}(\\s[AP]M))$/i.test(value);\n },\n $.mage.__('Please enter a valid time, between 00:00 am and 12:00 pm')\n ],\n 'phoneUS': [\n function (phoneNumber, element) {\n phoneNumber = phoneNumber.replace(/\\s+/g, '');\n\n return this.optional(element) || phoneNumber.length > 9 &&\n phoneNumber.match(/^(1-?)?(\\([2-9]\\d{2}\\)|[2-9]\\d{2})-?[2-9]\\d{2}-?\\d{4}$/);\n },\n $.mage.__('Please specify a valid phone number')\n ],\n 'phoneUK': [\n function (phoneNumber, element) {\n return this.optional(element) || phoneNumber.length > 9 &&\n phoneNumber.match(/^(\\(?(0|\\+44)[1-9]{1}\\d{1,4}?\\)?\\s?\\d{3,4}\\s?\\d{3,4})$/);\n },\n $.mage.__('Please specify a valid phone number')\n ],\n 'mobileUK': [\n function (phoneNumber, element) {\n return this.optional(element) || phoneNumber.length > 9 &&\n phoneNumber.match(/^((0|\\+44)7\\d{3}\\s?\\d{6})$/);\n },\n $.mage.__('Please specify a valid mobile number')\n ],\n 'stripped-min-length': [\n function (value, element, param) {\n return value.length >= param;\n },\n $.mage.__('Please enter at least {0} characters')\n ],\n\n /* detect chars that would require more than 3 bytes */\n 'validate-no-utf8mb4-characters': [\n function (value) {\n var validator = this,\n message = $.mage.__('Please remove invalid characters: {0}.'),\n matches = value.match(/(?:[\\uD800-\\uDBFF][\\uDC00-\\uDFFF])/g),\n result = matches === null;\n\n if (!result) {\n validator.charErrorMessage = message.replace('{0}', matches.join());\n }\n\n return result;\n }, function () {\n return this.charErrorMessage;\n }\n ],\n\n /* eslint-disable max-len */\n 'email2': [\n function (value, element) {\n return this.optional(element) ||\n /^((([a-z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+(\\.([a-z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+)*)|((\\x22)((((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(([\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]|\\x21|[\\x23-\\x5b]|[\\x5d-\\x7e]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(\\\\([\\x01-\\x09\\x0b\\x0c\\x0d-\\x7f]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF]))))*(((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(\\x22)))@((([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])*([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])))\\.)*(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])*([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])))\\.?$/i.test(value);\n },\n $.validator.messages.email\n ],\n 'url2': [\n function (value, element) {\n return this.optional(element) || /^(https?|ftp):\\/\\/(((([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(%[\\da-f]{2})|[!\\$&'\\(\\)\\*\\+,;=]|:)*@)?(((\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5]))|((([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])*([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])))\\.)*(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])*([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])))\\.?)(:\\d*)?)(\\/((([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(%[\\da-f]{2})|[!\\$&'\\(\\)\\*\\+,;=]|:|@)+(\\/(([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(%[\\da-f]{2})|[!\\$&'\\(\\)\\*\\+,;=]|:|@)*)*)?)?(\\?((([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(%[\\da-f]{2})|[!\\$&'\\(\\)\\*\\+,;=]|:|@)|[\\uE000-\\uF8FF]|\\/|\\?)*)?(\\#((([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(%[\\da-f]{2})|[!\\$&'\\(\\)\\*\\+,;=]|:|@)|\\/|\\?)*)?$/i.test(value);\n },\n $.validator.messages.url\n ],\n\n /* eslint-enable max-len */\n 'credit-card-types': [\n function (value, element, param) {\n var validTypes;\n\n if (/[^0-9-]+/.test(value)) {\n return false;\n }\n value = value.replace(/\\D/g, '');\n\n validTypes = 0x0000;\n\n if (param.mastercard) {\n validTypes |= 0x0001;\n }\n\n if (param.visa) {\n validTypes |= 0x0002;\n }\n\n if (param.amex) {\n validTypes |= 0x0004;\n }\n\n if (param.dinersclub) {\n validTypes |= 0x0008;\n }\n\n if (param.enroute) {\n validTypes |= 0x0010;\n }\n\n if (param.discover) {\n validTypes |= 0x0020;\n }\n\n if (param.jcb) {\n validTypes |= 0x0040;\n }\n\n if (param.unknown) {\n validTypes |= 0x0080;\n }\n\n if (param.all) {\n validTypes = 0x0001 | 0x0002 | 0x0004 | 0x0008 | 0x0010 | 0x0020 | 0x0040 | 0x0080;\n }\n\n if (validTypes & 0x0001 && /^(51|52|53|54|55)/.test(value)) { //mastercard\n return value.length === 16;\n }\n\n if (validTypes & 0x0002 && /^(4)/.test(value)) { //visa\n return value.length === 16;\n }\n\n if (validTypes & 0x0004 && /^(34|37)/.test(value)) { //amex\n return value.length === 15;\n }\n\n if (validTypes & 0x0008 && /^(300|301|302|303|304|305|36|38)/.test(value)) { //dinersclub\n return value.length === 14;\n }\n\n if (validTypes & 0x0010 && /^(2014|2149)/.test(value)) { //enroute\n return value.length === 15;\n }\n\n if (validTypes & 0x0020 && /^(6011)/.test(value)) { //discover\n return value.length === 16;\n }\n\n if (validTypes & 0x0040 && /^(3)/.test(value)) { //jcb\n return value.length === 16;\n }\n\n if (validTypes & 0x0040 && /^(2131|1800)/.test(value)) { //jcb\n return value.length === 15;\n }\n\n if (validTypes & 0x0080) { //unknown\n return true;\n }\n\n return false;\n },\n $.mage.__('Please enter a valid credit card number.')\n ],\n\n /* eslint-disable max-len */\n 'ipv4': [\n function (value, element) {\n return this.optional(element) ||\n /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/i.test(value);\n },\n $.mage.__('Please enter a valid IP v4 address.')\n ],\n 'ipv6': [\n function (value, element) {\n return this.optional(element) || /^((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((\\b((25[0-5])|(1\\d{2})|(2[0-4]\\d)|(\\d{1,2}))\\b)\\.){3}(\\b((25[0-5])|(1\\d{2})|(2[0-4]\\d)|(\\d{1,2}))\\b))|(([0-9A-Fa-f]{1,4}:){0,5}:((\\b((25[0-5])|(1\\d{2})|(2[0-4]\\d)|(\\d{1,2}))\\b)\\.){3}(\\b((25[0-5])|(1\\d{2})|(2[0-4]\\d)|(\\d{1,2}))\\b))|(::([0-9A-Fa-f]{1,4}:){0,5}((\\b((25[0-5])|(1\\d{2})|(2[0-4]\\d)|(\\d{1,2}))\\b)\\.){3}(\\b((25[0-5])|(1\\d{2})|(2[0-4]\\d)|(\\d{1,2}))\\b))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))$/i.test(value);\n },\n $.mage.__('Please enter a valid IP v6 address.')\n ],\n\n /* eslint-enable max-len */\n 'pattern': [\n function (value, element, param) {\n return this.optional(element) || new RegExp(param).test(value);\n },\n $.mage.__('Invalid format.')\n ],\n 'allow-container-className': [\n function (element) {\n if (element.type === 'radio' || element.type === 'checkbox') {\n return $(element).hasClass('change-container-classname');\n }\n },\n ''\n ],\n 'validate-no-html-tags': [\n function (value) {\n return !/<(\\/)?\\w+/.test(value);\n },\n $.mage.__('HTML tags are not allowed.')\n ],\n 'validate-select': [\n function (value) {\n return value !== 'none' && value != null && value.length !== 0;\n },\n $.mage.__('Please select an option.')\n ],\n 'validate-no-empty': [\n function (value) {\n return !$.mage.isEmpty(value);\n },\n $.mage.__('Empty Value.')\n ],\n 'validate-alphanum-with-spaces': [\n function (v) {\n return $.mage.isEmptyNoTrim(v) || /^[a-zA-Z0-9 ]+$/.test(v);\n },\n $.mage.__('Please use only letters (a-z or A-Z), numbers (0-9) or spaces only in this field.')\n ],\n 'validate-data': [\n function (v) {\n return $.mage.isEmptyNoTrim(v) || /^[A-Za-z]+[A-Za-z0-9_]+$/.test(v);\n },\n $.mage.__('Please use only letters (a-z or A-Z), numbers (0-9) or underscore (_) in this field, and the first character should be a letter.') //eslint-disable-line max-len\n ],\n 'validate-street': [\n function (v) {\n return $.mage.isEmptyNoTrim(v) || /^[ \\w]{3,}([A-Za-z]\\.)?([ \\w]*\\#\\d+)?(\\r\\n| )[ \\w]{3,}/.test(v);\n },\n $.mage.__('Please use only letters (a-z or A-Z), numbers (0-9), spaces and \"#\" in this field.')\n ],\n 'validate-phoneStrict': [\n function (v) {\n return $.mage.isEmptyNoTrim(v) || /^(\\()?\\d{3}(\\))?(-|\\s)?\\d{3}(-|\\s)\\d{4}$/.test(v);\n },\n $.mage.__('Please enter a valid phone number. For example (123) 456-7890 or 123-456-7890.')\n ],\n 'validate-phoneLax': [\n function (v) {\n return $.mage.isEmptyNoTrim(v) ||\n /^((\\d[\\-. ]?)?((\\(\\d{3}\\))|\\d{3}))?[\\-. ]?\\d{3}[\\-. ]?\\d{4}$/.test(v);\n },\n $.mage.__('Please enter a valid phone number. For example (123) 456-7890 or 123-456-7890.')\n ],\n 'validate-fax': [\n function (v) {\n return $.mage.isEmptyNoTrim(v) || /^(\\()?\\d{3}(\\))?(-|\\s)?\\d{3}(-|\\s)\\d{4}$/.test(v);\n },\n $.mage.__('Please enter a valid fax number (Ex: 123-456-7890).')\n ],\n 'validate-email': [\n function (v) {\n return $.mage.isEmptyNoTrim(v) || /^([a-z0-9,!\\#\\$%&'\\*\\+\\/=\\?\\^_`\\{\\|\\}~-]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+(\\.([a-z0-9,!\\#\\$%&'\\*\\+\\/=\\?\\^_`\\{\\|\\}~-]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+)*@([a-z0-9-]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+(\\.([a-z0-9-]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+)*\\.(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF]){2,})$/i.test(v); //eslint-disable-line max-len\n },\n $.mage.__('Please enter a valid email address (Ex: johndoe@domain.com).')\n ],\n //replace jquery.validation.js email validation rule\n 'email' : [\n function (v) {\n return $.mage.isEmptyNoTrim(v) || /^([a-z0-9,!\\#\\$%&'\\*\\+\\/=\\?\\^_`\\{\\|\\}~-]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+(\\.([a-z0-9,!\\#\\$%&'\\*\\+\\/=\\?\\^_`\\{\\|\\}~-]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+)*@([a-z0-9-]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+(\\.([a-z0-9-]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+)*\\.(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF]){2,})$/i.test(v); //eslint-disable-line max-len\n },\n $.mage.__('Please enter a valid email address.')\n ],\n 'validate-emailSender': [\n function (v) {\n return $.mage.isEmptyNoTrim(v) || /^(?!.*:)[\\S ]+$/.test(v);\n },\n $.mage.__('Please use only visible characters and spaces. The colon character is not allowed.')\n ],\n 'validate-password': [\n function (v) {\n var pass;\n\n if (v == null) {\n return false;\n }\n //strip leading and trailing spaces\n pass = v.trim();\n\n if (!pass.length) {\n return true;\n }\n\n return !(pass.length > 0 && pass.length < 6);\n },\n $.mage.__('Please enter 6 or more characters. Leading and trailing spaces will be ignored.')\n ],\n 'validate-admin-password': [\n function (v) {\n var pass;\n\n if (v == null) {\n return false;\n }\n pass = v.trim();\n // strip leading and trailing spaces\n if (pass.length === 0) {\n return true;\n }\n\n if (!/[a-z]/i.test(v) || !/[0-9]/.test(v)) {\n return false;\n }\n\n if (pass.length < 7) {\n return false;\n }\n\n return true;\n },\n $.mage.__('Please enter 7 or more characters, using both numeric and alphabetic.')\n ],\n 'validate-customer-password': [\n function (v, elm) {\n var validator = this,\n counter = 0,\n passwordMinLength = $(elm).data('password-min-length'),\n passwordMinCharacterSets = $(elm).data('password-min-character-sets'),\n pass = v.trim(),\n result = pass.length >= passwordMinLength;\n\n if (result === false) {\n validator.passwordErrorMessage = $.mage.__('Minimum length of this field must be equal or greater than %1 symbols. Leading and trailing spaces will be ignored.').replace('%1', passwordMinLength); //eslint-disable-line max-len\n\n return result;\n }\n\n if (pass.match(/\\d+/)) {\n counter++;\n }\n\n if (pass.match(/[a-z]+/)) {\n counter++;\n }\n\n if (pass.match(/[A-Z]+/)) {\n counter++;\n }\n\n if (pass.match(/[^a-zA-Z0-9]+/)) {\n counter++;\n }\n\n if (counter < passwordMinCharacterSets) {\n result = false;\n validator.passwordErrorMessage = $.mage.__('Minimum of different classes of characters in password is %1. Classes of characters: Lower Case, Upper Case, Digits, Special Characters.').replace('%1', passwordMinCharacterSets); //eslint-disable-line max-len\n }\n\n return result;\n }, function () {\n return this.passwordErrorMessage;\n }\n ],\n 'validate-url': [\n function (v) {\n if ($.mage.isEmptyNoTrim(v)) {\n return true;\n }\n v = (v || '').replace(/^\\s+/, '').replace(/\\s+$/, '');\n\n return (/^(http|https|ftp):\\/\\/(([A-Z0-9]([A-Z0-9_-]*[A-Z0-9]|))(\\.[A-Z0-9]([A-Z0-9_-]*[A-Z0-9]|))*)(:(\\d+))?(\\/[A-Z0-9~](([A-Z0-9_~-]|\\.)*[A-Z0-9~]|))*\\/?(.*)?$/i).test(v); //eslint-disable-line max-len\n\n },\n $.mage.__('Please enter a valid URL. Protocol is required (http://, https:// or ftp://).')\n ],\n 'validate-clean-url': [\n function (v) {\n return $.mage.isEmptyNoTrim(v) || /^(http|https|ftp):\\/\\/(([A-Z0-9][A-Z0-9_-]*)(\\.[A-Z0-9][A-Z0-9_-]*)+.(com|org|net|dk|at|us|tv|info|uk|co.uk|biz|se)$)(:(\\d+))?\\/?/i.test(v) || /^(www)((\\.[A-Z0-9][A-Z0-9_-]*)+.(com|org|net|dk|at|us|tv|info|uk|co.uk|biz|se)$)(:(\\d+))?\\/?/i.test(v); //eslint-disable-line max-len\n\n },\n $.mage.__('Please enter a valid URL. For example http://www.example.com or www.example.com.')\n ],\n 'validate-xml-identifier': [\n function (v) {\n return $.mage.isEmptyNoTrim(v) || /^[A-Z][A-Z0-9_\\/-]*$/i.test(v);\n\n },\n $.mage.__('Please enter a valid XML-identifier (Ex: something_1, block5, id-4).')\n ],\n 'validate-ssn': [\n function (v) {\n return $.mage.isEmptyNoTrim(v) || /^\\d{3}-?\\d{2}-?\\d{4}$/.test(v);\n\n },\n $.mage.__('Please enter a valid social security number (Ex: 123-45-6789).')\n ],\n 'validate-zip-us': [\n function (v) {\n return $.mage.isEmptyNoTrim(v) || /(^\\d{5}$)|(^\\d{5}-\\d{4}$)/.test(v);\n\n },\n $.mage.__('Please enter a valid zip code (Ex: 90602 or 90602-1234).')\n ],\n 'validate-date-au': [\n function (v) {\n var regex, d;\n\n if ($.mage.isEmptyNoTrim(v)) {\n return true;\n }\n regex = /^(\\d{2})\\/(\\d{2})\\/(\\d{4})$/;\n\n if ($.mage.isEmpty(v) || !regex.test(v)) {\n return false;\n }\n d = new Date(v.replace(regex, '$2/$1/$3'));\n\n return parseInt(RegExp.$2, 10) === 1 + d.getMonth() &&\n parseInt(RegExp.$1, 10) === d.getDate() &&\n parseInt(RegExp.$3, 10) === d.getFullYear();\n\n },\n $.mage.__('Please use this date format: dd/mm/yyyy. For example 17/03/2006 for the 17th of March, 2006.')\n ],\n 'validate-currency-dollar': [\n function (v) {\n return $.mage.isEmptyNoTrim(v) || /^\\$?\\-?([1-9]{1}[0-9]{0,2}(\\,[0-9]{3})*(\\.[0-9]{0,2})?|[1-9]{1}\\d*(\\.[0-9]{0,2})?|0(\\.[0-9]{0,2})?|(\\.[0-9]{1,2})?)$/.test(v); //eslint-disable-line max-len\n\n },\n $.mage.__('Please enter a valid $ amount. For example $100.00.')\n ],\n 'validate-not-negative-number': [\n function (v) {\n if ($.mage.isEmptyNoTrim(v)) {\n return true;\n }\n v = $.mage.parseNumber(v);\n\n return !isNaN(v) && v >= 0;\n\n },\n $.mage.__('Please enter a number 0 or greater in this field.')\n ],\n // validate-not-negative-number should be replaced in all places with this one and then removed\n 'validate-zero-or-greater': [\n function (v) {\n if ($.mage.isEmptyNoTrim(v)) {\n return true;\n }\n v = $.mage.parseNumber(v);\n\n return !isNaN(v) && v >= 0;\n\n },\n $.mage.__('Please enter a number 0 or greater in this field.')\n ],\n 'validate-greater-than-zero': [\n function (v) {\n if ($.mage.isEmptyNoTrim(v)) {\n return true;\n }\n v = $.mage.parseNumber(v);\n\n return !isNaN(v) && v > 0;\n },\n $.mage.__('Please enter a number greater than 0 in this field.')\n ],\n 'validate-css-length': [\n function (v) {\n if (v !== '') {\n return (/^[0-9]*\\.*[0-9]+(px|pc|pt|ex|em|mm|cm|in|%)?$/).test(v);\n }\n\n return true;\n },\n $.mage.__('Please input a valid CSS-length (Ex: 100px, 77pt, 20em, .5ex or 50%).')\n ],\n // Additional methods\n 'validate-number': [\n function (v) {\n return $.mage.isEmptyNoTrim(v) || !isNaN($.mage.parseNumber(v)) && /^\\s*-?\\d*(\\.\\d*)?\\s*$/.test(v);\n },\n $.mage.__('Please enter a valid number in this field.')\n ],\n 'required-number': [\n function (v) {\n return !!v.length;\n },\n $.mage.__('Please enter a valid number in this field.')\n ],\n 'validate-number-range': [\n function (v, elm, param) {\n var numValue, dataAttrRange, classNameRange, result, range, m, classes, ii;\n\n if ($.mage.isEmptyNoTrim(v)) {\n return true;\n }\n\n numValue = $.mage.parseNumber(v);\n\n if (isNaN(numValue)) {\n return false;\n }\n\n dataAttrRange = /^(-?[\\d.,]+)?-(-?[\\d.,]+)?$/;\n classNameRange = /^number-range-(-?[\\d.,]+)?-(-?[\\d.,]+)?$/;\n result = true;\n range = param;\n\n if (typeof range === 'string') {\n m = dataAttrRange.exec(range);\n\n if (m) {\n result = result && $.mage.isBetween(numValue, m[1], m[2]);\n } else {\n result = false;\n }\n } else if (elm && elm.className) {\n classes = elm.className.split(' ');\n ii = classes.length;\n\n while (ii--) {\n range = classes[ii];\n m = classNameRange.exec(range);\n\n if (m) { //eslint-disable-line max-depth\n result = result && $.mage.isBetween(numValue, m[1], m[2]);\n break;\n }\n }\n }\n\n return result;\n },\n $.mage.__('The value is not within the specified range.'),\n true\n ],\n 'validate-digits': [\n function (v) {\n return $.mage.isEmptyNoTrim(v) || !/[^\\d]/.test(v);\n },\n $.mage.__('Please enter a valid number in this field.')\n ],\n 'validate-forbidden-extensions': [\n function (v, elem) {\n var forbiddenExtensions = $(elem).attr('data-validation-params'),\n forbiddenExtensionsArray = forbiddenExtensions.split(','),\n extensionsArray = v.split(','),\n result = true;\n\n this.validateExtensionsMessage = $.mage.__('Forbidden extensions has been used. Avoid usage of ') +\n forbiddenExtensions;\n\n $.each(extensionsArray, function (key, extension) {\n if (forbiddenExtensionsArray.indexOf(extension) !== -1) {\n result = false;\n }\n });\n\n return result;\n }, function () {\n return this.validateExtensionsMessage;\n }\n ],\n 'validate-digits-range': [\n function (v, elm, param) {\n var numValue, dataAttrRange, classNameRange, result, range, m, classes, ii;\n\n if ($.mage.isEmptyNoTrim(v)) {\n return true;\n }\n\n numValue = $.mage.parseNumber(v);\n\n if (isNaN(numValue)) {\n return false;\n }\n\n dataAttrRange = /^(-?\\d+)?-(-?\\d+)?$/;\n classNameRange = /^digits-range-(-?\\d+)?-(-?\\d+)?$/;\n result = true;\n range = param;\n\n if (typeof range === 'string') {\n m = dataAttrRange.exec(range);\n\n if (m) {\n result = result && $.mage.isBetween(numValue, m[1], m[2]);\n } else {\n result = false;\n }\n } else if (elm && elm.className) {\n classes = elm.className.split(' ');\n ii = classes.length;\n\n while (ii--) {\n range = classes[ii];\n m = classNameRange.exec(range);\n\n if (m) { //eslint-disable-line max-depth\n result = result && $.mage.isBetween(numValue, m[1], m[2]);\n break;\n }\n }\n }\n\n return result;\n },\n $.mage.__('The value is not within the specified range.'),\n true\n ],\n 'validate-range': [\n function (v, elm) {\n var minValue, maxValue, ranges, reRange, result, values,\n i, name, validRange, minValidRange, maxValidRange;\n\n if ($.mage.isEmptyNoTrim(v)) {\n return true;\n } else if ($.validator.methods['validate-digits'] && $.validator.methods['validate-digits'](v)) {\n minValue = maxValue = $.mage.parseNumber(v);\n } else {\n ranges = /^(-?\\d+)?-(-?\\d+)?$/.exec(v);\n\n if (ranges) {\n minValue = $.mage.parseNumber(ranges[1]);\n maxValue = $.mage.parseNumber(ranges[2]);\n\n if (minValue > maxValue) { //eslint-disable-line max-depth\n return false;\n }\n } else {\n return false;\n }\n }\n reRange = /^range-(-?\\d+)?-(-?\\d+)?$/;\n result = true;\n values = $(elm).prop('class').split(' ');\n\n for (i = values.length - 1; i >= 0; i--) {\n name = values[i];\n validRange = reRange.exec(name);\n\n if (validRange) {\n minValidRange = $.mage.parseNumber(validRange[1]);\n maxValidRange = $.mage.parseNumber(validRange[2]);\n result = result &&\n (isNaN(minValidRange) || minValue >= minValidRange) &&\n (isNaN(maxValidRange) || maxValue <= maxValidRange);\n }\n }\n\n return result;\n },\n $.mage.__('The value is not within the specified range.')\n ],\n 'validate-alpha': [\n function (v) {\n return $.mage.isEmptyNoTrim(v) || /^[a-zA-Z]+$/.test(v);\n },\n $.mage.__('Please use letters only (a-z or A-Z) in this field.')\n ],\n 'validate-code': [\n function (v) {\n return $.mage.isEmptyNoTrim(v) || /^[a-zA-Z]+[a-zA-Z0-9_]+$/.test(v);\n },\n $.mage.__('Please use only letters (a-z or A-Z), numbers (0-9) or underscore (_) in this field, and the first character should be a letter.') //eslint-disable-line max-len\n ],\n 'validate-alphanum': [\n function (v) {\n return $.mage.isEmptyNoTrim(v) || /^[a-zA-Z0-9]+$/.test(v);\n },\n $.mage.__('Please use only letters (a-z or A-Z) or numbers (0-9) in this field. No spaces or other characters are allowed.') //eslint-disable-line max-len\n ],\n 'validate-not-number-first': [\n function (value) {\n return $.mage.isEmptyNoTrim(value) || /^[^0-9-\\.].*$/.test(value.trim());\n },\n $.mage.__('First character must be letter.')\n ],\n 'validate-date': [\n function (value, params, additionalParams) {\n var test = moment(value, utils.convertToMomentFormat(additionalParams.dateFormat));\n\n return $.mage.isEmptyNoTrim(value) || test.isValid();\n },\n $.mage.__('Please enter a valid date.')\n\n ],\n 'validate-date-range': [\n function (v, elm) {\n var m = /\\bdate-range-(\\w+)-(\\w+)\\b/.exec(elm.className),\n currentYear, normalizedTime, dependentElements;\n\n if (!m || m[2] === 'to' || $.mage.isEmptyNoTrim(v)) {\n return true;\n }\n\n currentYear = new Date().getFullYear() + '';\n\n /**\n * @param {String} vd\n * @return {Number}\n */\n normalizedTime = function (vd) {\n vd = vd.split(/[.\\/]/);\n\n if (vd[2] && vd[2].length < 4) {\n vd[2] = currentYear.substr(0, vd[2].length) + vd[2];\n }\n\n return new Date(vd.join('/')).getTime();\n };\n\n dependentElements = $(elm.form).find('.validate-date-range.date-range-' + m[1] + '-to');\n\n return !dependentElements.length || $.mage.isEmptyNoTrim(dependentElements[0].value) ||\n normalizedTime(v) <= normalizedTime(dependentElements[0].value);\n },\n $.mage.__('Make sure the To Date is later than or the same as the From Date.')\n ],\n 'validate-cpassword': [\n function () {\n var conf = $('#confirmation').length > 0 ? $('#confirmation') : $($('.validate-cpassword')[0]),\n pass = false,\n passwordElements, i, passwordElement;\n\n if ($('#password')) {\n pass = $('#password');\n }\n passwordElements = $('.validate-password');\n\n for (i = 0; i < passwordElements.length; i++) {\n passwordElement = $(passwordElements[i]);\n\n if (passwordElement.closest('form').attr('id') === conf.closest('form').attr('id')) {\n pass = passwordElement;\n }\n }\n\n if ($('.validate-admin-password').length) {\n pass = $($('.validate-admin-password')[0]);\n }\n\n return pass.val() === conf.val();\n },\n $.mage.__('Please make sure your passwords match.')\n ],\n 'validate-identifier': [\n function (v) {\n return $.mage.isEmptyNoTrim(v) || /^[a-z0-9][a-z0-9_\\/-]+(\\.[a-z0-9_-]+)?$/.test(v);\n },\n $.mage.__('Please enter a valid URL Key (Ex: \"example-page\", \"example-page.html\" or \"anotherlevel/example-page\").') //eslint-disable-line max-len\n ],\n 'validate-zip-international': [\n\n /*function(v) {\n // @TODO: Cleanup\n return Validation.get('IsEmpty').test(v) ||\n /(^[A-z0-9]{2,10}([\\s]{0,1}|[\\-]{0,1})[A-z0-9]{2,10}$)/.test(v);\n }*/\n function () {\n return true;\n },\n $.mage.__('Please enter a valid zip code.')\n ],\n 'validate-one-required': [\n function (v, elm) {\n var p = $(elm).parent(),\n options = p.find('input');\n\n return options.map(function (el) {\n return $(el).val();\n }).length > 0;\n },\n $.mage.__('Please select one of the options above.')\n ],\n 'validate-state': [\n function (v) {\n return v !== 0;\n },\n $.mage.__('Please select State/Province.')\n ],\n 'required-file': [\n function (v, elm) {\n var result = !$.mage.isEmptyNoTrim(v),\n ovId;\n\n if (!result) {\n ovId = $('#' + $(elm).attr('id') + '_value');\n\n if (ovId.length > 0) {\n result = !$.mage.isEmptyNoTrim(ovId.val());\n }\n }\n\n return result;\n },\n $.mage.__('Please select a file.')\n ],\n 'validate-ajax-error': [\n function (v, element) {\n element = $(element);\n element.on('change.ajaxError', function () {\n element.removeClass('validate-ajax-error');\n element.off('change.ajaxError');\n });\n\n return !element.hasClass('validate-ajax-error');\n },\n ''\n ],\n 'validate-optional-datetime': [\n function (v, elm, param) {\n var dateTimeParts = $('.datetime-picker[id^=\"options_' + param + '\"]'),\n hasWithValue = false,\n hasWithNoValue = false,\n pattern = /day_part$/i,\n i;\n\n for (i = 0; i < dateTimeParts.length; i++) {\n if (!pattern.test($(dateTimeParts[i]).attr('id'))) {\n if ($(dateTimeParts[i]).val() === 's') { //eslint-disable-line max-depth\n hasWithValue = true;\n } else {\n hasWithNoValue = true;\n }\n }\n }\n\n return hasWithValue ^ hasWithNoValue;\n },\n $.mage.__('The field isn\\'t complete.')\n ],\n 'validate-required-datetime': [\n function (v, elm, param) {\n var dateTimeParts = $('.datetime-picker[id^=\"options_' + param + '\"]'),\n i;\n\n for (i = 0; i < dateTimeParts.length; i++) {\n if (dateTimeParts[i].value === '') {\n return false;\n }\n }\n\n return true;\n },\n $.mage.__('This is a required field.')\n ],\n 'validate-one-required-by-name': [\n function (v, elm, selector) {\n var name = elm.name.replace(/([\\\\\"])/g, '\\\\$1'),\n container = this.currentForm;\n\n selector = selector === true ? 'input[name=\"' + name + '\"]:checked' : selector;\n\n return !!container.querySelectorAll(selector).length;\n },\n $.mage.__('Please select one of the options.')\n ],\n 'less-than-equals-to': [\n function (value, element, params) {\n if ($.isNumeric($(params).val()) && $.isNumeric(value)) {\n this.lteToVal = $(params).val();\n\n return parseFloat(value) <= parseFloat($(params).val());\n }\n\n return true;\n },\n function () {\n var message = $.mage.__('Please enter a value less than or equal to %s.');\n\n return message.replace('%s', this.lteToVal);\n }\n ],\n 'greater-than-equals-to': [\n function (value, element, params) {\n if ($.isNumeric($(params).val()) && $.isNumeric(value)) {\n this.gteToVal = $(params).val();\n\n return parseFloat(value) >= parseFloat($(params).val());\n }\n\n return true;\n },\n function () {\n var message = $.mage.__('Please enter a value greater than or equal to %s.');\n\n return message.replace('%s', this.gteToVal);\n }\n ],\n 'validate-emails': [\n function (value) {\n var validRegexp, emails, i;\n\n if ($.mage.isEmpty(value)) {\n return true;\n }\n validRegexp = /^([a-z0-9,!\\#\\$%&'\\*\\+\\/=\\?\\^_`\\{\\|\\}~-]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+(\\.([a-z0-9,!\\#\\$%&'\\*\\+\\/=\\?\\^_`\\{\\|\\}~-]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+)*@([a-z0-9-]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+(\\.([a-z0-9-]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+)*\\.(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF]){2,})$/i; //eslint-disable-line max-len\n emails = value.split(/[\\s\\n\\,]+/g);\n\n for (i = 0; i < emails.length; i++) {\n if (!validRegexp.test(emails[i].trim())) {\n return false;\n }\n }\n\n return true;\n },\n $.mage.__('Please enter valid email addresses, separated by commas. For example, johndoe@domain.com, johnsmith@domain.com.') //eslint-disable-line max-len\n ],\n\n 'validate-cc-type-select': [\n\n /**\n * Validate credit card type matches credit card number\n * @param {*} value - select credit card type\n * @param {*} element - element contains the select box for credit card types\n * @param {*} params - selector for credit card number\n * @return {Boolean}\n */\n function (value, element, params) {\n if (value && params && creditCartTypes[value]) {\n return creditCartTypes[value][0].test($(params).val().replace(/\\s+/g, ''));\n }\n\n return false;\n },\n $.mage.__('Card type does not match credit card number.')\n ],\n 'validate-cc-number': [\n\n /**\n * Validate credit card number based on mod 10.\n *\n * @param {*} value - credit card number\n * @return {Boolean}\n */\n function (value) {\n if (value) {\n return validateCreditCard(value);\n }\n\n return false;\n },\n $.mage.__('Please enter a valid credit card number.')\n ],\n 'validate-cc-type': [\n\n /**\n * Validate credit card number is for the correct credit card type.\n *\n * @param {String} value - credit card number\n * @param {*} element - element contains credit card number\n * @param {*} params - selector for credit card type\n * @return {Boolean}\n */\n function (value, element, params) {\n var ccType;\n\n if (value && params) {\n ccType = $(params).val();\n value = value.replace(/\\s/g, '').replace(/\\-/g, '');\n\n if (creditCartTypes[ccType] && creditCartTypes[ccType][0]) {\n return creditCartTypes[ccType][0].test(value);\n } else if (creditCartTypes[ccType] && !creditCartTypes[ccType][0]) {\n return true;\n }\n }\n\n return false;\n },\n $.mage.__('Credit card number does not match credit card type.')\n ],\n 'validate-cc-exp': [\n\n /**\n * Validate credit card expiration date, make sure it's within the year and not before current month.\n *\n * @param {*} value - month\n * @param {*} element - element contains month\n * @param {*} params - year selector\n * @return {Boolean}\n */\n function (value, element, params) {\n var isValid = false,\n month, year, currentTime, currentMonth, currentYear;\n\n if (value && params) {\n month = value;\n year = $(params).val();\n currentTime = new Date();\n currentMonth = currentTime.getMonth() + 1;\n currentYear = currentTime.getFullYear();\n\n isValid = !year || year > currentYear || year == currentYear && month >= currentMonth; //eslint-disable-line\n }\n\n return isValid;\n },\n $.mage.__('Incorrect credit card expiration date.')\n ],\n 'validate-cc-cvn': [\n\n /**\n * Validate credit card cvn based on credit card type.\n *\n * @param {*} value - credit card cvn\n * @param {*} element - element contains credit card cvn\n * @param {*} params - credit card type selector\n * @return {*}\n */\n function (value, element, params) {\n var ccType;\n\n if (value && params) {\n ccType = $(params).val();\n\n if (creditCartTypes[ccType] && creditCartTypes[ccType][0]) {\n return creditCartTypes[ccType][1].test(value);\n }\n }\n\n return false;\n },\n $.mage.__('Please enter a valid credit card verification number.')\n ],\n 'validate-cc-ukss': [\n\n /**\n * Validate Switch/Solo/Maestro issue number and start date is filled.\n *\n * @param {*} value - input field value\n * @return {*}\n */\n function (value) {\n return value;\n },\n $.mage.__('Please enter issue number or start date for switch/solo card type.')\n ],\n 'validate-length': [\n function (v, elm) {\n var reMax = new RegExp(/^maximum-length-[0-9]+$/),\n reMin = new RegExp(/^minimum-length-[0-9]+$/),\n validator = this,\n result = true,\n length = 0;\n\n $.each(elm.className.split(' '), function (index, name) {\n if (name.match(reMax) && result) {\n length = name.split('-')[2];\n result = v.length <= length;\n validator.validateMessage =\n $.mage.__('Please enter less or equal than %1 symbols.').replace('%1', length);\n }\n\n if (name.match(reMin) && result && !$.mage.isEmpty(v)) {\n length = name.split('-')[2];\n result = v.length >= length;\n validator.validateMessage =\n $.mage.__('Please enter more or equal than %1 symbols.').replace('%1', length);\n }\n });\n\n return result;\n }, function () {\n return this.validateMessage;\n }\n ],\n 'required-entry': [\n function (value) {\n return !$.mage.isEmpty(value);\n }, $.mage.__('This is a required field.')\n ],\n 'not-negative-amount': [\n function (v) {\n if (v.length) {\n return (/^\\s*\\d+([,.]\\d+)*\\s*%?\\s*$/).test(v);\n }\n\n return true;\n },\n $.mage.__('Please enter positive number in this field.')\n ],\n 'validate-per-page-value-list': [\n function (v) {\n var isValid = true,\n values = v.split(','),\n i;\n\n if ($.mage.isEmpty(v)) {\n return isValid;\n }\n\n for (i = 0; i < values.length; i++) {\n if (!/^[0-9]+$/.test(values[i])) {\n isValid = false;\n }\n }\n\n return isValid;\n },\n $.mage.__('Please enter a valid value, ex: 10,20,30')\n ],\n 'validate-per-page-value': [\n function (v, elm) {\n var values;\n\n if ($.mage.isEmpty(v)) {\n return false;\n }\n values = $('#' + elm.id + '_values').val().split(',');\n\n return values.indexOf(v) !== -1;\n },\n $.mage.__('Please enter a valid value from list')\n ],\n 'validate-new-password': [\n function (v) {\n if ($.validator.methods['validate-password'] && !$.validator.methods['validate-password'](v)) {\n return false;\n }\n\n if ($.mage.isEmpty(v) && v !== '') {\n return false;\n }\n\n return true;\n },\n $.mage.__('Please enter 6 or more characters. Leading and trailing spaces will be ignored.')\n ],\n 'required-if-not-specified': [\n function (value, element, params) {\n var valid = false,\n alternate = $(params),\n alternateValue;\n\n if (alternate.length > 0) {\n valid = this.check(alternate);\n // if valid, it may be blank, so check for that\n if (valid) {\n alternateValue = alternate.val();\n\n if (typeof alternateValue == 'undefined' || alternateValue.length === 0) { //eslint-disable-line\n valid = false;\n }\n }\n }\n\n if (!valid) {\n valid = !this.optional(element);\n }\n\n return valid;\n },\n $.mage.__('This is a required field.')\n ],\n 'required-if-all-sku-empty-and-file-not-loaded': [\n function (value, element, params) {\n var valid = false,\n alternate = $(params.specifiedId),\n alternateValue;\n\n if (alternate.length > 0) {\n valid = this.check(alternate);\n // if valid, it may be blank, so check for that\n if (valid) {\n alternateValue = alternate.val();\n\n if (typeof alternateValue == 'undefined' || alternateValue.length === 0) { //eslint-disable-line\n valid = false;\n }\n }\n }\n\n if (!valid) {\n valid = !this.optional(element);\n }\n\n $('input[' + params.dataSku + '=true]').each(function () {\n if ($(this).val() !== '') {\n valid = true;\n }\n });\n\n return valid;\n },\n $.mage.__('Please enter valid SKU key.')\n ],\n 'required-if-specified': [\n function (value, element, params) {\n var valid = true,\n dependent = $(params),\n dependentValue;\n\n if (dependent.length > 0) {\n valid = this.check(dependent);\n // if valid, it may be blank, so check for that\n if (valid) {\n dependentValue = dependent.val();\n valid = typeof dependentValue != 'undefined' && dependentValue.length > 0;\n }\n }\n\n if (valid) {\n valid = !this.optional(element);\n } else {\n valid = true; // dependent was not valid, so don't even check\n }\n\n return valid;\n },\n $.mage.__('This is a required field.')\n ],\n 'required-number-if-specified': [\n function (value, element, params) {\n var valid = true,\n dependent = $(params),\n depeValue;\n\n if (dependent.length) {\n valid = this.check(dependent);\n\n if (valid) {\n depeValue = dependent[0].value;\n valid = !!(depeValue && depeValue.length);\n }\n }\n\n return valid ? !!value.length : true;\n },\n $.mage.__('Please enter a valid number.')\n ],\n 'datetime-validation': [\n function (value, element) {\n var isValid = true;\n\n if ($(element).val().length === 0) {\n isValid = false;\n $(element).addClass('mage-error');\n }\n\n return isValid;\n },\n $.mage.__('This is required field')\n ],\n 'required-text-swatch-entry': [\n tableSingleValidation,\n $.mage.__('Admin is a required field in each row.')\n ],\n 'required-visual-swatch-entry': [\n tableSingleValidation,\n $.mage.__('Admin is a required field in each row.')\n ],\n 'required-dropdown-attribute-entry': [\n tableSingleValidation,\n $.mage.__('Admin is a required field in each row.')\n ],\n 'validate-item-quantity': [\n function (value, element, params) {\n var validator = this,\n result = false,\n // obtain values for validation\n qty = $.mage.parseNumber(value),\n isMinAllowedValid = typeof params.minAllowed === 'undefined' ||\n qty >= $.mage.parseNumber(params.minAllowed),\n isMaxAllowedValid = typeof params.maxAllowed === 'undefined' ||\n qty <= $.mage.parseNumber(params.maxAllowed),\n isQtyIncrementsValid = typeof params.qtyIncrements === 'undefined' ||\n resolveModulo(qty, $.mage.parseNumber(params.qtyIncrements)) === 0.0;\n\n result = qty > 0;\n\n if (result === false) {\n validator.itemQtyErrorMessage = $.mage.__('Please enter a quantity greater than 0.');//eslint-disable-line max-len\n\n return result;\n }\n\n result = isMinAllowedValid;\n\n if (result === false) {\n validator.itemQtyErrorMessage = $.mage.__('The fewest you may purchase is %1.').replace('%1', params.minAllowed);//eslint-disable-line max-len\n\n return result;\n }\n\n result = isMaxAllowedValid;\n\n if (result === false) {\n validator.itemQtyErrorMessage = $.mage.__('The maximum you may purchase is %1.').replace('%1', params.maxAllowed);//eslint-disable-line max-len\n\n return result;\n }\n\n result = isQtyIncrementsValid;\n\n if (result === false) {\n validator.itemQtyErrorMessage = $.mage.__('You can buy this product only in quantities of %1 at a time.').replace('%1', params.qtyIncrements);//eslint-disable-line max-len\n\n return result;\n }\n\n return result;\n }, function () {\n return this.itemQtyErrorMessage;\n }\n ],\n 'password-not-equal-to-user-name': [\n function (value, element, params) {\n if (typeof params === 'string') {\n return value.toLowerCase() !== params.toLowerCase();\n }\n\n return true;\n },\n $.mage.__('The password can\\'t be the same as the email address. Create a new password and try again.')\n ]\n };\n\n $.each(rules, function (i, rule) {\n rule.unshift(i);\n $.validator.addMethod.apply($.validator, rule);\n });\n $.validator.addClassRules({\n 'required-option': {\n required: true\n },\n 'required-options-count': {\n required: true\n },\n 'validate-both-passwords': {\n 'validate-cpassword': true\n }\n });\n $.validator.messages = $.extend($.validator.messages, {\n required: $.mage.__('This is a required field.'),\n remote: $.mage.__('Please fix this field.'),\n email: $.mage.__('Please enter a valid email address.'),\n url: $.mage.__('Please enter a valid URL.'),\n date: $.mage.__('Please enter a valid date.'),\n dateISO: $.mage.__('Please enter a valid date (ISO).'),\n number: $.mage.__('Please enter a valid number.'),\n digits: $.mage.__('Please enter only digits.'),\n creditcard: $.mage.__('Please enter a valid credit card number.'),\n equalTo: $.mage.__('Please enter the same value again.'),\n maxlength: $.validator.format($.mage.__('Please enter no more than {0} characters.')),\n minlength: $.validator.format($.mage.__('Please enter at least {0} characters.')),\n rangelength: $.validator.format($.mage.__('Please enter a value between {0} and {1} characters long.')),\n range: $.validator.format($.mage.__('Please enter a value between {0} and {1}.')),\n max: $.validator.format($.mage.__('Please enter a value less than or equal to {0}.')),\n min: $.validator.format($.mage.__('Please enter a value greater than or equal to {0}.'))\n });\n\n if ($.metadata) {\n // Setting the type as html5 to enable data-validate attribute\n $.metadata.setType('html5');\n }\n\n showLabel = $.validator.prototype.showLabel;\n $.extend(true, $.validator.prototype, {\n /**\n * @param {*} element\n * @param {*} message\n */\n showLabel: function (element, message) {\n var label, elem;\n\n showLabel.call(this, element, message);\n\n // ARIA (adding aria-invalid & aria-describedby)\n label = this.errorsFor(element);\n elem = $(element);\n\n if (!label.attr('id')) {\n label.attr('id', this.idOrName(element) + '-error');\n }\n elem.attr('aria-invalid', 'true')\n .attr('aria-describedby', label.attr('id'));\n }\n });\n\n /**\n * Validate form field without instantiating validate plug-in.\n *\n * @param {Element|String} element - DOM element or selector\n * @return {Boolean} validation result\n */\n $.validator.validateElement = function (element) {\n var form, validator, valid, classes;\n\n element = $(element);\n form = element.get(0).form;\n validator = form ? $(form).data('validator') : null;\n\n if (validator) {\n return validator.element(element.get(0));\n }\n valid = true;\n classes = element.prop('class').split(' ');\n $.each(classes, $.proxy(function (i, className) {\n if (this.methods[className] && !this.methods[className](element.val(), element.get(0))) {\n valid = false;\n\n return valid;\n }\n }, this));\n\n return valid;\n };\n\n originValidateDelegate = $.fn.validateDelegate;\n\n /**\n * @return {*}\n */\n $.fn.validateDelegate = function () {\n if (!this[0].form) {\n return this;\n }\n\n return originValidateDelegate.apply(this, arguments);\n };\n\n /**\n * Validate single element.\n *\n * @param {Element} element\n * @param {Object} config\n * @returns {*}\n */\n $.validator.validateSingleElement = function (element, config) {\n var errors = {},\n valid = true,\n validateConfig = {\n errorElement: 'label',\n ignore: '.ignore-validate',\n hideError: false\n },\n form, validator, classes, elementValue;\n\n $.extend(validateConfig, config);\n element = $(element).not(validateConfig.ignore);\n\n if (!element.length) {\n return true;\n }\n\n form = element.get(0).form;\n validator = form ? $(form).data('validator') : null;\n\n if (validator) {\n return validator.element(element.get(0));\n }\n\n classes = element.prop('class').split(' ');\n validator = element.parent().data('validator') ||\n $.mage.validation(validateConfig, element.parent()).validate;\n\n element.removeClass(validator.settings.errorClass);\n validator.toHide = validator.toShow;\n validator.hideErrors();\n validator.toShow = validator.toHide = $([]);\n\n $.each(classes, $.proxy(function (i, className) {\n elementValue = element.val();\n\n if (element.is(':checkbox') || element.is(':radio')) {\n elementValue = element.is(':checked') || null;\n }\n\n if (this.methods[className] && !this.methods[className](elementValue, element.get(0))) {\n valid = false;\n errors[element.get(0).name] = this.messages[className];\n validator.invalid[element.get(0).name] = true;\n\n if (!validateConfig.hideError) {\n validator.showErrors(errors);\n }\n\n return valid;\n }\n }, this));\n\n return valid;\n };\n\n $.widget('mage.validation', {\n options: {\n meta: 'validate',\n onfocusout: false,\n onkeyup: false,\n onclick: false,\n ignoreTitle: true,\n errorClass: 'mage-error',\n errorElement: 'div',\n\n /**\n * @param {*} error\n * @param {*} element\n */\n errorPlacement: function (error, element) {\n var errorPlacement = element,\n fieldWrapper;\n\n // logic for date-picker error placement\n if (element.hasClass('_has-datepicker')) {\n errorPlacement = element.siblings('button');\n }\n // logic for field wrapper\n fieldWrapper = element.closest('.addon');\n\n if (fieldWrapper.length) {\n errorPlacement = fieldWrapper.after(error);\n }\n //logic for checkboxes/radio\n if (element.is(':checkbox') || element.is(':radio')) {\n errorPlacement = element.parents('.control').children().last();\n\n //fallback if group does not have .control parent\n if (!errorPlacement.length) {\n errorPlacement = element.siblings('label').last();\n }\n }\n //logic for control with tooltip\n if (element.siblings('.tooltip').length) {\n errorPlacement = element.siblings('.tooltip');\n }\n //logic for select with tooltip in after element\n if (element.next().find('.tooltip').length) {\n errorPlacement = element.next();\n }\n errorPlacement.after(error);\n }\n },\n\n /**\n * Check if form pass validation rules without submit.\n *\n * @return boolean\n */\n isValid: function () {\n return this.element.valid();\n },\n\n /**\n * Remove validation error messages\n */\n clearError: function () {\n if (arguments.length) {\n $.each(arguments, $.proxy(function (index, item) {\n this.validate.prepareElement(item);\n this.validate.hideErrors();\n }, this));\n } else {\n this.validate.resetForm();\n }\n },\n\n /**\n * Validation creation.\n *\n * @protected\n */\n _create: function () {\n this.validate = this.element.validate(this.options);\n\n // ARIA (adding aria-required attribute)\n this.element\n .find('.field.required')\n .find('.control')\n .find('input, select, textarea')\n .attr('aria-required', 'true');\n this.element\n .find('.field.additional')\n .find('.control')\n .find('input, select, textarea')\n .removeAttr('aria-required');\n this._listenFormValidate();\n },\n\n /**\n * Validation listening.\n *\n * @protected\n */\n _listenFormValidate: function () {\n $('form').on('invalid-form.validate', this.listenFormValidateHandler);\n },\n\n /**\n * Handle form validation. Focus on first invalid form field.\n *\n * @param {jQuery.Event} event\n * @param {Object} validation\n */\n listenFormValidateHandler: function (event, validation) {\n var firstActive = $(validation.errorList[0].element || []),\n lastActive = $(validation.findLastActive() ||\n validation.errorList.length && validation.errorList[0].element || []),\n windowHeight = $(window).height(),\n parent, successList;\n\n if (lastActive.is(':hidden')) {\n parent = lastActive.parent();\n $('html, body').animate({\n scrollTop: parent.offset().top - windowHeight / 2\n });\n }\n\n // ARIA (removing aria attributes if success)\n successList = validation.successList;\n\n if (successList.length) {\n $.each(successList, function () {\n $(this)\n .removeAttr('aria-describedby')\n .removeAttr('aria-invalid');\n });\n }\n\n if (firstActive.length) {\n $('html, body').stop().animate({\n scrollTop: firstActive.parent().offset().top - windowHeight / 2\n });\n firstActive.trigger('focus');\n }\n }\n });\n\n return $.mage.validation;\n});\n","mage/polyfill.js":"(function (root, doc) {\n 'use strict';\n\n var Storage;\n\n try {\n if (!root.localStorage || !root.sessionStorage) {\n throw new Error();\n }\n\n localStorage.setItem('storage_test', 1);\n localStorage.removeItem('storage_test');\n } catch (e) {\n /**\n * Returns a storage object to shim local or sessionStorage\n * @param {String} type - either 'local' or 'session'\n */\n Storage = function (type) {\n var data;\n\n /**\n * Creates a cookie\n * @param {String} name\n * @param {String} value\n * @param {Integer} days\n */\n function createCookie(name, value, days) {\n var date, expires;\n\n if (days) {\n date = new Date();\n date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000);\n expires = '; expires=' + date.toGMTString();\n } else {\n expires = '';\n }\n doc.cookie = name + '=' + value + expires + '; path=/';\n }\n\n /**\n * Reads value of a cookie\n * @param {String} name\n */\n function readCookie(name) {\n var nameEQ = name + '=',\n ca = doc.cookie.split(';'),\n i = 0,\n c;\n\n for (i = 0; i < ca.length; i++) {\n c = ca[i];\n\n while (c.charAt(0) === ' ') {\n c = c.substring(1, c.length);\n }\n\n if (c.indexOf(nameEQ) === 0) {\n return c.substring(nameEQ.length, c.length);\n }\n }\n\n return null;\n }\n\n /**\n * Returns cookie name based upon the storage type.\n * If this is session storage, the function returns a unique cookie per tab\n */\n function getCookieName() {\n\n if (type !== 'session') {\n return 'localstorage';\n }\n\n if (!root.name) {\n root.name = new Date().getTime();\n }\n\n return 'sessionStorage' + root.name;\n }\n\n /**\n * Sets storage cookie to a data object\n * @param {Object} dataObject\n */\n function setData(dataObject) {\n data = encodeURIComponent(JSON.stringify(dataObject));\n createCookie(getCookieName(), data, 365);\n }\n\n /**\n * Clears value of cookie data\n */\n function clearData() {\n createCookie(getCookieName(), '', 365);\n }\n\n /**\n * @returns value of cookie data\n */\n function getData() {\n var dataResponse = readCookie(getCookieName());\n\n return dataResponse ? JSON.parse(decodeURIComponent(dataResponse)) : {};\n }\n\n data = getData();\n\n return {\n length: 0,\n\n /**\n * Clears data from storage\n */\n clear: function () {\n data = {};\n this.length = 0;\n clearData();\n },\n\n /**\n * Gets an item from storage\n * @param {String} key\n */\n getItem: function (key) {\n return data[key] === undefined ? null : data[key];\n },\n\n /**\n * Gets an item by index from storage\n * @param {Integer} i\n */\n key: function (i) {\n var ctr = 0,\n k;\n\n for (k in data) {\n\n if (data.hasOwnProperty(k)) {\n\n // eslint-disable-next-line max-depth\n if (ctr.toString() === i.toString()) {\n return k;\n }\n ctr++;\n }\n }\n\n return null;\n },\n\n /**\n * Removes an item from storage\n * @param {String} key\n */\n removeItem: function (key) {\n delete data[key];\n this.length--;\n setData(data);\n },\n\n /**\n * Sets an item from storage\n * @param {String} key\n * @param {String} value\n */\n setItem: function (key, value) {\n data[key] = value.toString();\n this.length++;\n setData(data);\n }\n };\n };\n\n root.localStorage.prototype = root.localStorage = new Storage('local');\n root.sessionStorage.prototype = root.sessionStorage = new Storage('session');\n }\n})(window, document);\n","mage/mage.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'jquery',\n 'mage/apply/main'\n], function ($, mage) {\n 'use strict';\n\n /**\n * Main namespace for Magento extensions\n * @type {Object}\n */\n $.mage = $.mage || {};\n\n /**\n * Plugin mage, initialize components on elements\n * @param {String} name - Components' path.\n * @param {Object} config - Components' config.\n * @returns {JQuery} Chainable.\n */\n $.fn.mage = function (name, config) {\n config = config || {};\n\n this.each(function (index, el) {\n mage.applyFor(el, config, name);\n });\n\n return this;\n };\n\n $.extend($.mage, {\n /**\n * Handle all components declared via data attribute\n * @return {Object} $.mage\n */\n init: function () {\n mage.apply();\n\n return this;\n },\n\n /**\n * Method handling redirects and page refresh\n * @param {String} url - redirect URL\n * @param {(undefined|String)} type - 'assign', 'reload', 'replace'\n * @param {(undefined|Number)} timeout - timeout in milliseconds before processing the redirect or reload\n * @param {(undefined|Boolean)} forced - true|false used for 'reload' only\n */\n redirect: function (url, type, timeout, forced) {\n var _redirect;\n\n forced = !!forced;\n timeout = timeout || 0;\n type = type || 'assign';\n\n /**\n * @private\n */\n _redirect = function () {\n window.location[type](type === 'reload' ? forced : url);\n };\n\n timeout ? setTimeout(_redirect, timeout) : _redirect();\n },\n\n /**\n * Checks if provided string is a valid selector.\n * @param {String} selector - Selector to check.\n * @returns {Boolean}\n */\n isValidSelector: function (selector) {\n try {\n document.querySelector(selector);\n\n return true;\n } catch (e) {\n return false;\n }\n }\n });\n\n /**\n * Init components inside of dynamically updated elements\n */\n $(document).on('contentUpdated', 'body', function () {\n if (mage) {\n mage.apply();\n }\n });\n\n return $.mage;\n});\n","mage/edit-trigger.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @deprecated since version 2.2.0\n */\ndefine([\n 'jquery',\n 'mage/template',\n 'jquery-ui-modules/widget'\n], function ($, mageTemplate) {\n 'use strict';\n\n var editTriggerPrototype;\n\n $.widget('mage.editTrigger', {\n options: {\n img: '',\n alt: '[TR]',\n template: '#translate-inline-icon',\n zIndex: 2000,\n editSelector: '[data-translate]',\n delay: 2000,\n offsetTop: -3,\n singleElement: true\n },\n\n /**\n * editTriger creation\n * @protected\n */\n _create: function () {\n this.tmpl = mageTemplate(this.options.template);\n this._initTrigger();\n this._bind();\n },\n\n /**\n * @return {Object}\n * @private\n */\n _getCss: function () {\n return {\n position: 'absolute',\n cursor: 'pointer',\n display: 'none',\n 'z-index': this.options.zIndex\n };\n },\n\n /**\n * @param {*} appendTo\n * @return {*|jQuery}\n * @private\n */\n _createTrigger: function (appendTo) {\n var tmpl = this.tmpl({\n data: this.options\n });\n\n return $(tmpl)\n .css(this._getCss())\n .data('role', 'edit-trigger-element')\n .appendTo(appendTo);\n },\n\n /**\n * @private\n */\n _initTrigger: function () {\n this.trigger = this._createTrigger($('body'));\n },\n\n /**\n * Bind on mousemove event\n * @protected\n */\n _bind: function () {\n this.trigger.on('click.' + this.widgetName, $.proxy(this._onClick, this));\n this.element.on('mousemove.' + this.widgetName, $.proxy(this._onMouseMove, this));\n },\n\n /**\n * Show editTriger\n */\n show: function () {\n if (this.trigger.is(':hidden')) {\n this.trigger.show();\n }\n },\n\n /**\n * Hide editTriger\n */\n hide: function () {\n this.currentTarget = null;\n\n if (this.trigger && this.trigger.is(':visible')) {\n this.trigger.hide();\n }\n },\n\n /**\n * Set editTriger position\n * @protected\n */\n _setPosition: function (el) {\n var offset = el.offset();\n\n this.trigger.css({\n top: offset.top + el.outerHeight() + this.options.offsetTop,\n left: offset.left\n });\n },\n\n /**\n * Show/hide trigger on mouse move.\n *\n * @param {jQuery.Event} e\n * @protected\n */\n _onMouseMove: function (e) {\n var target = $(e.target),\n inner = target.find(this.options.editSelector);\n\n if ($(e.target).is('button') && inner.length) {\n target = inner;\n } else if (!target.is(this.trigger) && !target.is(this.options.editSelector)) {\n target = target.parents(this.options.editSelector).first();\n }\n\n if (target.length) {\n if (!target.is(this.trigger)) {\n this._setPosition(target);\n this.currentTarget = target;\n }\n this.show();\n } else {\n this.hide();\n }\n },\n\n /**\n * Trigger event \"edit\" on element for translate.\n *\n * @param {jQuery.Event} e\n * @protected\n */\n _onClick: function (e) {\n e.preventDefault();\n e.stopImmediatePropagation();\n $(this.currentTarget).trigger('edit.' + this.widgetName);\n this.hide(true);\n },\n\n /**\n * Destroy editTriger\n */\n destroy: function () {\n this.trigger.remove();\n this.element.off('.' + this.widgetName);\n\n return $.Widget.prototype.destroy.call(this);\n }\n });\n\n /**\n * Extention for widget editTrigger - hide trigger with delay\n */\n editTriggerPrototype = $.mage.editTrigger.prototype;\n\n $.widget('mage.editTrigger', $.extend({}, editTriggerPrototype, {\n /**\n * Added clear timeout on trigger show\n */\n show: function () {\n editTriggerPrototype.show.apply(this, arguments);\n\n if (this.options.delay) {\n this._clearTimer();\n }\n },\n\n /**\n * Added setTimeout on trigger hide\n */\n hide: function (immediate) {\n if (!immediate && this.options.delay) {\n if (!this.timer) {\n this.timer = setTimeout($.proxy(function () {\n editTriggerPrototype.hide.apply(this, arguments);\n this._clearTimer();\n }, this), this.options.delay);\n }\n } else {\n editTriggerPrototype.hide.apply(this, arguments);\n }\n },\n\n /**\n * Clear timer\n * @protected\n */\n _clearTimer: function () {\n if (this.timer) {\n clearTimeout(this.timer);\n this.timer = null;\n }\n }\n }));\n\n return $.mage.editTrigger;\n});\n","mage/bootstrap.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'jquery',\n 'mage/apply/main',\n 'Magento_Ui/js/lib/knockout/bootstrap'\n], function ($, mage) {\n 'use strict';\n\n $.ajaxSetup({\n cache: false\n });\n\n /**\n * Init all components defined via data-mage-init attribute.\n * Execute in a separate task to prevent main thread blocking.\n */\n setTimeout(mage.apply);\n});\n","mage/url.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* eslint-disable strict */\ndefine([], function () {\n var baseUrl = '';\n\n return {\n /**\n * @param {String} url\n */\n setBaseUrl: function (url) {\n baseUrl = url;\n },\n\n /**\n * @param {String} path\n * @return {*}\n */\n build: function (path) {\n if (path.indexOf(baseUrl) !== -1) {\n return path;\n }\n\n return baseUrl + path;\n }\n };\n});\n","mage/calendar.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/*eslint max-depth: 0*/\ndefine([\n 'jquery',\n 'jquery-ui-modules/widget',\n 'jquery-ui-modules/datepicker',\n 'jquery-ui-modules/timepicker'\n], function ($) {\n 'use strict';\n\n var calendarBasePrototype,\n datepickerPrototype = $.datepicker.constructor.prototype;\n\n $.datepicker.markerClassName = '_has-datepicker';\n\n /**\n * Extend JQuery date picker prototype with store local time methods\n */\n $.extend(datepickerPrototype, {\n /**\n * Get date/time according to store settings.\n * We use serverTimezoneOffset (in seconds) instead of serverTimezoneSeconds\n * in order to have ability to know actual store time even if page hadn't been reloaded\n * @returns {Date}\n */\n _getTimezoneDate: function (options) {\n // local time in ms\n var ms = Date.now();\n\n options = options || $.calendarConfig || {};\n\n // Adjust milliseconds according to store timezone offset,\n // mind the GMT zero offset\n if (typeof options.serverTimezoneOffset !== 'undefined') {\n // Make UTC time and add store timezone offset in seconds\n ms += new Date().getTimezoneOffset() * 60 * 1000 + options.serverTimezoneOffset * 1000;\n } else if (typeof options.serverTimezoneSeconds !== 'undefined') {\n //Set milliseconds according to client local timezone offset\n ms = (options.serverTimezoneSeconds + new Date().getTimezoneOffset() * 60) * 1000;\n }\n\n return new Date(ms);\n },\n\n /**\n * Set date/time according to store settings.\n * @param {String|Object} target - the target input field or division or span\n */\n _setTimezoneDateDatepicker: function (target) {\n this._setDateDatepicker(target, this._getTimezoneDate());\n }\n });\n\n /**\n * Widget calendar\n */\n $.widget('mage.calendar', {\n options: {\n autoComplete: true\n },\n\n /**\n * Merge global options with options passed to widget invoke\n * @protected\n */\n _create: function () {\n this._enableAMPM();\n this.options = $.extend(\n {},\n $.calendarConfig ? $.calendarConfig : {},\n this.options.showsTime ? {\n showTime: true,\n showHour: true,\n showMinute: true\n } : {},\n this.options\n );\n this._initPicker(this.element);\n this._overwriteGenerateHtml();\n },\n\n /**\n * Get picker name\n * @protected\n */\n _picker: function () {\n return this.options.showsTime ? 'datetimepicker' : 'datepicker';\n },\n\n /**\n * Fix for Timepicker - Set ampm option for Timepicker if timeformat contains string 'tt'\n * @protected\n */\n _enableAMPM: function () {\n if (this.options.timeFormat && this.options.timeFormat.indexOf('tt') >= 0) {\n this.options.ampm = true;\n }\n },\n\n /**\n * Wrapper for overwrite jQuery UI datepicker function.\n */\n _overwriteGenerateHtml: function () {\n /**\n * Overwrite jQuery UI datepicker function.\n * Reason: magento date could be set before calendar show\n * but local date will be styled as current in original _generateHTML\n *\n * @param {Object} inst - instance datepicker.\n * @return {String} html template\n */\n $.datepicker.constructor.prototype._generateHTML = function (inst) {\n var today = this._getTimezoneDate(),\n isRTL = this._get(inst, 'isRTL'),\n showButtonPanel = this._get(inst, 'showButtonPanel'),\n hideIfNoPrevNext = this._get(inst, 'hideIfNoPrevNext'),\n navigationAsDateFormat = this._get(inst, 'navigationAsDateFormat'),\n numMonths = this._getNumberOfMonths(inst),\n showCurrentAtPos = this._get(inst, 'showCurrentAtPos'),\n stepMonths = this._get(inst, 'stepMonths'),\n isMultiMonth = parseInt(numMonths[0], 10) !== 1 || parseInt(numMonths[1], 10) !== 1,\n currentDate = this._daylightSavingAdjust(!inst.currentDay ? new Date(9999, 9, 9) :\n new Date(inst.currentYear, inst.currentMonth, inst.currentDay)),\n minDate = this._getMinMaxDate(inst, 'min'),\n maxDate = this._getMinMaxDate(inst, 'max'),\n drawMonth = inst.drawMonth - showCurrentAtPos,\n drawYear = inst.drawYear,\n maxDraw,\n prevText = this._get(inst, 'prevText'),\n prev,\n nextText = this._get(inst, 'nextText'),\n next,\n currentText = this._get(inst, 'currentText'),\n gotoDate,\n controls,\n buttonPanel,\n firstDay,\n showWeek = this._get(inst, 'showWeek'),\n dayNames = this._get(inst, 'dayNames'),\n dayNamesMin = this._get(inst, 'dayNamesMin'),\n monthNames = this._get(inst, 'monthNames'),\n monthNamesShort = this._get(inst, 'monthNamesShort'),\n beforeShowDay = this._get(inst, 'beforeShowDay'),\n showOtherMonths = this._get(inst, 'showOtherMonths'),\n selectOtherMonths = this._get(inst, 'selectOtherMonths'),\n defaultDate = this._getDefaultDate(inst),\n html = '',\n row = 0,\n col = 0,\n selectedDate,\n cornerClass = ' ui-corner-all',\n group = '',\n calender = '',\n dow = 0,\n thead,\n day,\n daysInMonth,\n leadDays,\n curRows,\n numRows,\n printDate,\n dRow = 0,\n tbody,\n daySettings,\n otherMonth,\n unselectable;\n\n if (drawMonth < 0) {\n drawMonth += 12;\n drawYear--;\n }\n\n if (maxDate) {\n maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(),\n maxDate.getMonth() - numMonths[0] * numMonths[1] + 1, maxDate.getDate()));\n maxDraw = minDate && maxDraw < minDate ? minDate : maxDraw;\n\n while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) {\n drawMonth--;\n\n if (drawMonth < 0) {\n drawMonth = 11;\n drawYear--;\n\n }\n }\n }\n inst.drawMonth = drawMonth;\n inst.drawYear = drawYear;\n prevText = !navigationAsDateFormat ? prevText : this.formatDate(prevText,\n this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)),\n this._getFormatConfig(inst));\n prev = this._canAdjustMonth(inst, -1, drawYear, drawMonth) ?\n '<a class=\"ui-datepicker-prev ui-corner-all\" data-handler=\"prev\" data-event=\"click\"' +\n ' title=\"' + prevText + '\">' +\n '<span class=\"ui-icon ui-icon-circle-triangle-' + (isRTL ? 'e' : 'w') + '\">' +\n '' + prevText + '</span></a>'\n : hideIfNoPrevNext ? ''\n : '<a class=\"ui-datepicker-prev ui-corner-all ui-state-disabled\" title=\"' +\n '' + prevText + '\"><span class=\"ui-icon ui-icon-circle-triangle-' +\n '' + (isRTL ? 'e' : 'w') + '\">' + prevText + '</span></a>';\n nextText = !navigationAsDateFormat ?\n nextText\n : this.formatDate(nextText,\n this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)),\n this._getFormatConfig(inst));\n next = this._canAdjustMonth(inst, +1, drawYear, drawMonth) ?\n '<a class=\"ui-datepicker-next ui-corner-all\" data-handler=\"next\" data-event=\"click\"' +\n 'title=\"' + nextText + '\"><span class=\"ui-icon ui-icon-circle-triangle-' +\n '' + (isRTL ? 'w' : 'e') + '\">' + nextText + '</span></a>'\n : hideIfNoPrevNext ? ''\n : '<a class=\"ui-datepicker-next ui-corner-all ui-state-disabled\" title=\"' + nextText + '\">' +\n '<span class=\"ui-icon ui-icon-circle-triangle-' + (isRTL ? 'w' : 'e') + '\">' + nextText +\n '</span></a>';\n gotoDate = this._get(inst, 'gotoCurrent') && inst.currentDay ? currentDate : today;\n currentText = !navigationAsDateFormat ? currentText :\n this.formatDate(currentText, gotoDate, this._getFormatConfig(inst));\n controls = !inst.inline ?\n '<button type=\"button\" class=\"ui-datepicker-close ui-state-default ui-priority-primary ' +\n 'ui-corner-all\" data-handler=\"hide\" data-event=\"click\">' +\n this._get(inst, 'closeText') + '</button>'\n : '';\n buttonPanel = showButtonPanel ?\n '<div class=\"ui-datepicker-buttonpane ui-widget-content\">' + (isRTL ? controls : '') +\n (this._isInRange(inst, gotoDate) ? '<button type=\"button\" class=\"ui-datepicker-current ' +\n 'ui-state-default ui-priority-secondary ui-corner-all\" data-handler=\"today\" data-event=\"click\"' +\n '>' + currentText + '</button>' : '') + (isRTL ? '' : controls) + '</div>' : '';\n firstDay = parseInt(this._get(inst, 'firstDay'), 10);\n firstDay = isNaN(firstDay) ? 0 : firstDay;\n\n for (row = 0; row < numMonths[0]; row++) {\n this.maxRows = 4;\n\n for (col = 0; col < numMonths[1]; col++) {\n selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay));\n\n calender = '';\n\n if (isMultiMonth) {\n calender += '<div class=\"ui-datepicker-group';\n\n if (numMonths[1] > 1) {\n switch (col) {\n case 0: calender += ' ui-datepicker-group-first';\n cornerClass = ' ui-corner-' + (isRTL ? 'right' : 'left');\n break;\n\n case numMonths[1] - 1: calender += ' ui-datepicker-group-last';\n cornerClass = ' ui-corner-' + (isRTL ? 'left' : 'right');\n break;\n\n default: calender += ' ui-datepicker-group-middle'; cornerClass = '';\n }\n }\n calender += '\">';\n }\n calender += '<div class=\"ui-datepicker-header ' +\n 'ui-widget-header ui-helper-clearfix' + cornerClass + '\">' +\n (/all|left/.test(cornerClass) && parseInt(row, 10) === 0 ? isRTL ? next : prev : '') +\n (/all|right/.test(cornerClass) && parseInt(row, 10) === 0 ? isRTL ? prev : next : '') +\n this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate,\n row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers\n '</div><table class=\"ui-datepicker-calendar\"><thead>' +\n '<tr>';\n thead = showWeek ?\n '<th class=\"ui-datepicker-week-col\">' + this._get(inst, 'weekHeader') + '</th>' : '';\n\n for (dow = 0; dow < 7; dow++) { // days of the week\n day = (dow + firstDay) % 7;\n thead += '<th' + ((dow + firstDay + 6) % 7 >= 5 ?\n ' class=\"ui-datepicker-week-end\"' : '') + '>' +\n '<span title=\"' + dayNames[day] + '\">' + dayNamesMin[day] + '</span></th>';\n }\n calender += thead + '</tr></thead><tbody>';\n daysInMonth = this._getDaysInMonth(drawYear, drawMonth);\n\n if (drawYear === inst.selectedYear && drawMonth === inst.selectedMonth) {\n inst.selectedDay = Math.min(inst.selectedDay, daysInMonth);\n }\n leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7;\n curRows = Math.ceil((leadDays + daysInMonth) / 7); // calculate the number of rows to generate\n numRows = isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows;\n this.maxRows = numRows;\n printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays));\n\n for (dRow = 0; dRow < numRows; dRow++) { // create date picker rows\n calender += '<tr>';\n tbody = !showWeek ? '' : '<td class=\"ui-datepicker-week-col\">' +\n this._get(inst, 'calculateWeek')(printDate) + '</td>';\n\n for (dow = 0; dow < 7; dow++) { // create date picker days\n daySettings = beforeShowDay ?\n beforeShowDay.apply(inst.input ? inst.input[0] : null, [printDate]) : [true, ''];\n otherMonth = printDate.getMonth() !== drawMonth;\n unselectable = otherMonth && !selectOtherMonths || !daySettings[0] ||\n minDate && printDate < minDate || maxDate && printDate > maxDate;\n tbody += '<td class=\"' +\n ((dow + firstDay + 6) % 7 >= 5 ? ' ui-datepicker-week-end' : '') + // highlight weekends\n (otherMonth ? ' ui-datepicker-other-month' : '') + // highlight days from other months\n (printDate.getTime() === selectedDate.getTime() &&\n drawMonth === inst.selectedMonth && inst._keyEvent || // user pressed key\n defaultDate.getTime() === printDate.getTime() &&\n defaultDate.getTime() === selectedDate.getTime() ?\n // or defaultDate is current printedDate and defaultDate is selectedDate\n ' ' + this._dayOverClass : '') + // highlight selected day\n (unselectable ? ' ' + this._unselectableClass + ' ui-state-disabled' : '') +\n (otherMonth && !showOtherMonths ? '' : ' ' + daySettings[1] + // highlight custom dates\n (printDate.getTime() === currentDate.getTime() ? ' ' + this._currentClass : '') +\n (printDate.getDate() === today.getDate() && printDate.getMonth() === today.getMonth() &&\n printDate.getYear() === today.getYear() ? ' ui-datepicker-today' : '')) + '\"' +\n ((!otherMonth || showOtherMonths) && daySettings[2] ?\n ' title=\"' + daySettings[2] + '\"' : '') + // cell title\n (unselectable ? '' : ' data-handler=\"selectDay\" data-event=\"click\" data-month=\"' +\n '' + printDate.getMonth() + '\" data-year=\"' + printDate.getFullYear() + '\"') + '>' +\n (otherMonth && !showOtherMonths ? ' ' : // display for other months\n unselectable ? '<span class=\"ui-state-default\">' + printDate.getDate() + '</span>'\n : '<a class=\"ui-state-default' +\n (printDate.getTime() === today.getTime() ? ' ' : '') +\n (printDate.getTime() === currentDate.getTime() ? ' ui-state-active' : '') +\n (otherMonth ? ' ui-priority-secondary' : '') +\n '\" data-date=\"' + printDate.getDate() + '\" href=\"#\">' +\n printDate.getDate() + '</a>') + '</td>';\n printDate.setDate(printDate.getDate() + 1);\n printDate = this._daylightSavingAdjust(printDate);\n }\n calender += tbody + '</tr>';\n }\n drawMonth++;\n\n if (drawMonth > 11) {\n drawMonth = 0;\n drawYear++;\n }\n calender += '</tbody></table>' + (isMultiMonth ? '</div>' +\n (numMonths[0] > 0 && col === numMonths[1] - 1 ? '<div class=\"ui-datepicker-row-break\"></div>'\n : '') : '');\n group += calender;\n }\n html += group;\n }\n html += buttonPanel + ($.ui.ie6 && !inst.inline ?\n '<iframe src=\"javascript:false;\" class=\"ui-datepicker-cover\" frameborder=\"0\"></iframe>' : '');\n inst._keyEvent = false;\n\n return html;\n };\n },\n\n /**\n * Set current date if the date is not set\n * @protected\n * @param {Object} element\n */\n _setCurrentDate: function (element) {\n if (!element.val()) {\n element[this._picker()]('setTimezoneDate').val('');\n }\n },\n\n /**\n * Init Datetimepicker\n * @protected\n * @param {Object} element\n */\n _initPicker: function (element) {\n var picker = element[this._picker()](this.options),\n pickerButtonText = picker.next('.ui-datepicker-trigger')\n .find('img')\n .attr('title');\n\n picker.next('.ui-datepicker-trigger')\n .addClass('v-middle')\n .text('') // Remove jQuery UI datepicker generated image\n .append('<span>' + pickerButtonText + '</span>');\n\n $(element).attr('autocomplete', this.options.autoComplete ? 'on' : 'off');\n\n this._setCurrentDate(element);\n },\n\n /**\n * destroy instance of datetimepicker\n */\n _destroy: function () {\n this.element[this._picker()]('destroy');\n this._super();\n },\n\n /**\n * Method is kept for backward compatibility and unit-tests acceptance\n * see \\mage\\calendar\\calendar-test.js\n * @return {Object} date\n */\n getTimezoneDate: function () {\n return datepickerPrototype._getTimezoneDate.call(this, this.options);\n }\n });\n\n calendarBasePrototype = $.mage.calendar.prototype;\n\n /**\n * Extension for Calendar - date and time format convert functionality\n * @var {Object}\n */\n $.widget('mage.calendar', $.extend({}, calendarBasePrototype,\n /** @lends {$.mage.calendar.prototype} */ {\n /**\n * key - backend format, value - jquery format\n * @type {Object}\n * @private\n */\n dateTimeFormat: {\n date: {\n 'EEEE': 'DD',\n 'EEE': 'D',\n 'EE': 'D',\n 'E': 'D',\n 'D': 'o',\n 'MMMM': 'MM',\n 'MMM': 'M',\n 'MM': 'mm',\n 'M': 'mm',\n 'yyyy': 'yy',\n 'y': 'yy',\n 'Y': 'yy',\n 'yy': 'yy' // Always long year format on frontend\n },\n time: {\n 'a': 'TT'\n }\n },\n\n /**\n * Add Date and Time converting to _create method\n * @protected\n */\n _create: function () {\n if (this.options.dateFormat) {\n this.options.dateFormat = this._convertFormat(this.options.dateFormat, 'date');\n }\n\n if (this.options.timeFormat) {\n this.options.timeFormat = this._convertFormat(this.options.timeFormat, 'time');\n }\n calendarBasePrototype._create.apply(this, arguments);\n },\n\n /**\n * Converting date or time format\n * @protected\n * @param {String} format\n * @param {String} type\n * @return {String}\n */\n _convertFormat: function (format, type) {\n var symbols = format.match(/([a-z]+)/ig),\n separators = format.match(/([^a-z]+)/ig),\n self = this,\n convertedFormat = '';\n\n if (symbols) {\n $.each(symbols, function (key, val) {\n convertedFormat +=\n (self.dateTimeFormat[type][val] || val) +\n (separators[key] || '');\n });\n }\n\n return convertedFormat;\n }\n })\n );\n\n /**\n * Widget dateRange\n * @extends $.mage.calendar\n */\n $.widget('mage.dateRange', $.mage.calendar, {\n\n /**\n * creates two instances of datetimepicker for date range selection\n * @protected\n */\n _initPicker: function () {\n var from,\n to;\n\n if (this.options.from && this.options.to) {\n from = this.element.find('#' + this.options.from.id);\n to = this.element.find('#' + this.options.to.id);\n this.options.onSelect = $.proxy(function (selectedDate) {\n to[this._picker()]('option', 'minDate', selectedDate);\n }, this);\n $.mage.calendar.prototype._initPicker.call(this, from);\n from.on('change', $.proxy(function () {\n to[this._picker()]('option', 'minDate', from[this._picker()]('getDate'));\n }, this));\n this.options.onSelect = $.proxy(function (selectedDate) {\n from[this._picker()]('option', 'maxDate', selectedDate);\n }, this);\n $.mage.calendar.prototype._initPicker.call(this, to);\n to.on('change', $.proxy(function () {\n from[this._picker()]('option', 'maxDate', to[this._picker()]('getDate'));\n }, this));\n }\n },\n\n /**\n * destroy two instances of datetimepicker\n */\n _destroy: function () {\n if (this.options.from) {\n this.element.find('#' + this.options.from.id)[this._picker()]('destroy');\n }\n\n if (this.options.to) {\n this.element.find('#' + this.options.to.id)[this._picker()]('destroy');\n }\n this._super();\n }\n });\n\n // Overrides the \"today\" button functionality to select today's date when clicked.\n $.datepicker._gotoTodayOriginal = $.datepicker._gotoToday;\n\n /**\n * overwrite jQuery UI _showDatepicker function for proper HTML generation conditions.\n *\n */\n $.datepicker._showDatepickerOriginal = $.datepicker._showDatepicker;\n\n /**\n * Triggers original method showDataPicker for rendering calendar\n * @param {HTMLObject} input\n * @private\n */\n $.datepicker._showDatepicker = function (input) {\n if (!input.disabled) {\n $.datepicker._showDatepickerOriginal.call(this, input);\n }\n };\n\n /**\n * _gotoToday\n * @param {Object} el\n */\n $.datepicker._gotoToday = function (el) {\n //Set date/time according to timezone offset\n $(el).datepicker('setTimezoneDate')\n // To ensure that user can re-select date field without clicking outside it first.\n .trigger('blur').trigger('change');\n };\n\n return {\n dateRange: $.mage.dateRange,\n calendar: $.mage.calendar\n };\n});\n","mage/translate.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'jquery',\n 'mage/mage',\n 'mageTranslationDictionary',\n 'underscore'\n], function ($, mage, dictionary, _) {\n 'use strict';\n\n $.extend(true, $, {\n mage: {\n translate: (function () {\n /**\n * Key-value translations storage\n * @type {Object}\n * @private\n */\n var _data = dictionary;\n\n return {\n /**\n * Add new translation (two string parameters) or several translations (object)\n */\n add: function () {\n if (arguments.length > 1) {\n _data[arguments[0]] = arguments[1];\n } else if (typeof arguments[0] === 'object') {\n $.extend(_data, arguments[0]);\n }\n },\n\n /**\n * Make a translation with parsing (to handle case when _data represents tuple)\n * @param {String} text\n * @return {String}\n */\n translate: function (text) {\n return typeof _data[text] !== 'undefined' ? _data[text] : text;\n }\n };\n }())\n }\n });\n $.mage.__ = $.proxy($.mage.translate.translate, $.mage.translate);\n\n // Provide i18n wrapper to be used in underscore templates for translation\n _.extend(_, {\n /**\n * Make a translation using $.mage.__\n *\n * @param {String} text\n * @return {String}\n */\n i18n: function (text) {\n return $.mage.__(text);\n }\n });\n\n return $.mage.__;\n});\n","mage/accordion.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'jquery',\n 'mage/tabs'\n], function ($, tabs) {\n 'use strict';\n\n $.widget('mage.accordion', tabs, {\n options: {\n active: [0],\n multipleCollapsible: false,\n openOnFocus: false\n },\n\n /**\n * @private\n */\n _callCollapsible: function () {\n var self = this,\n disabled = false,\n active = false;\n\n if (typeof this.options.active === 'string') {\n this.options.active = this.options.active.split(' ').map(function (item) {\n return parseInt(item, 10);\n });\n }\n\n $.each(this.collapsibles, function (i) {\n disabled = active = false;\n\n if ($.inArray(i, self.options.disabled) !== -1) {\n disabled = true;\n }\n\n if ($.inArray(i, self.options.active) !== -1) {\n active = true;\n }\n self._instantiateCollapsible(this, i, active, disabled);\n });\n },\n\n /**\n * Overwrites default functionality to provide the option to activate/deactivate multiple sections simultaneous\n * @param {*} action\n * @param {*} index\n * @private\n */\n _toggleActivate: function (action, index) {\n var self = this;\n\n if (Array.isArray(index && this.options.multipleCollapsible)) {\n $.each(index, function () {\n self.collapsibles.eq(this).collapsible(action);\n });\n } else if (index === undefined && this.options.multipleCollapsible) {\n this.collapsibles.collapsible(action);\n } else {\n this._super(action, index);\n }\n },\n\n /**\n * If the Accordion allows multiple section to be active at the same time, if deep linking is used\n * sections that don't contain the id from anchor shouldn't be closed, otherwise the accordion uses the\n * tabs behavior\n * @private\n */\n _handleDeepLinking: function () {\n if (!this.options.multipleCollapsible) {\n this._super();\n }\n },\n\n /**\n * Prevent default behavior that closes the other sections when one gets activated if the Accordion allows\n * multiple sections simultaneous\n * @private\n */\n _closeOthers: function () {\n var self = this;\n\n if (!this.options.multipleCollapsible) {\n $.each(this.collapsibles, function () {\n $(this).on('beforeOpen', function () {\n self.collapsibles.not(this).collapsible('deactivate');\n });\n });\n }\n $.each(this.collapsibles, function () {\n $(this).on('beforeOpen', function () {\n var section = $(this);\n\n section.addClass('allow').prevAll().addClass('allow');\n section.nextAll().removeClass('allow');\n });\n });\n }\n });\n\n return $.mage.accordion;\n});\n","mage/touch-slider.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'jquery',\n 'underscore',\n 'jquery-ui-modules/slider'\n], function ($, _) {\n 'use strict';\n\n /**\n * Adds support for touch events for regular jQuery UI slider.\n */\n $.widget('mage.touchSlider', $.ui.slider, {\n\n /**\n * Creates instance of widget.\n *\n * @override\n */\n _create: function () {\n _.bindAll(\n this,\n '_mouseDown',\n '_mouseMove',\n '_onTouchEnd'\n );\n\n return this._superApply(arguments);\n },\n\n /**\n * Initializes mouse events on element.\n * @override\n */\n _mouseInit: function () {\n var result = this._superApply(arguments);\n\n this.element\n .off('mousedown.' + this.widgetName)\n .on('touchstart.' + this.widgetName, this._mouseDown);\n\n return result;\n },\n\n /**\n * Elements' 'mousedown' event handler polyfill.\n * @override\n */\n _mouseDown: function (event) {\n var prevDelegate = this._mouseMoveDelegate,\n result;\n\n event = this._touchToMouse(event);\n result = this._super(event);\n\n if (prevDelegate === this._mouseMoveDelegate) {\n return result;\n }\n\n $(document)\n .off('mousemove.' + this.widgetName)\n .off('mouseup.' + this.widgetName);\n\n $(document)\n .on('touchmove.' + this.widgetName, this._mouseMove)\n .on('touchend.' + this.widgetName, this._onTouchEnd)\n .on('tochleave.' + this.widgetName, this._onTouchEnd);\n\n return result;\n },\n\n /**\n * Documents' 'mousemove' event handler polyfill.\n *\n * @override\n * @param {Event} event - Touch event object.\n */\n _mouseMove: function (event) {\n event = this._touchToMouse(event);\n\n return this._super(event);\n },\n\n /**\n * Documents' 'touchend' event handler.\n */\n _onTouchEnd: function (event) {\n $(document).trigger('mouseup');\n\n return this._mouseUp(event);\n },\n\n /**\n * Removes previously assigned touch handlers.\n *\n * @override\n */\n _mouseUp: function () {\n this._removeTouchHandlers();\n\n return this._superApply(arguments);\n },\n\n /**\n * Removes previously assigned touch handlers.\n *\n * @override\n */\n _mouseDestroy: function () {\n this._removeTouchHandlers();\n\n return this._superApply(arguments);\n },\n\n /**\n * Removes touch events from document object.\n */\n _removeTouchHandlers: function () {\n $(document)\n .off('touchmove.' + this.widgetName)\n .off('touchend.' + this.widgetName)\n .off('touchleave.' + this.widgetName);\n },\n\n /**\n * Adds properties to the touch event to mimic mouse event.\n *\n * @param {Event} event - Touch event object.\n * @returns {Event}\n */\n _touchToMouse: function (event) {\n var orig = event.originalEvent,\n touch = orig.touches[0];\n\n return _.extend(event, {\n which: 1,\n pageX: touch.pageX,\n pageY: touch.pageY,\n clientX: touch.clientX,\n clientY: touch.clientY,\n screenX: touch.screenX,\n screenY: touch.screenY\n });\n }\n });\n\n return $.mage.touchSlider;\n});\n","mage/smart-keyboard-handler.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n 'jquery'\n], function ($) {\n 'use strict';\n\n /**\n * @return {Object}\n * @constructor\n */\n function KeyboardHandler() {\n var body = $('body'),\n focusState = false,\n tabFocusClass = '_keyfocus',\n productsGrid = '[data-container=\"product-grid\"]',\n catalogProductsGrid = $(productsGrid),\n CODE_TAB = 9;\n\n /**\n * Handle logic, when onTabKeyPress fired at first.\n * Then it changes state.\n */\n function onFocusInHandler() {\n focusState = true;\n body.addClass(tabFocusClass)\n .off('focusin.keyboardHandler', onFocusInHandler);\n }\n\n /**\n * Handle logic to remove state after onTabKeyPress to normal.\n */\n function onClickHandler() {\n focusState = false;\n body.removeClass(tabFocusClass)\n .off('click', onClickHandler);\n }\n\n /**\n * Tab key onKeypress handler. Apply main logic:\n * - call differ actions onTabKeyPress and onClick\n */\n function smartKeyboardFocus() {\n $(document).on('keydown keypress', function (event) {\n if (event.which === CODE_TAB && !focusState) {\n body\n .on('focusin.keyboardHandler', onFocusInHandler)\n .on('click', onClickHandler);\n }\n });\n\n // ARIA support for catalog grid products\n if (catalogProductsGrid.length) {\n body.on('focusin.gridProducts', productsGrid, function () {\n if (body.hasClass(tabFocusClass)) {\n $(this).addClass('active');\n }\n });\n body.on('focusout.gridProducts', productsGrid, function () {\n $(this).removeClass('active');\n });\n }\n }\n\n /**\n * Attach smart focus on specific element.\n * @param {jQuery} element\n */\n function handleFocus(element) {\n element.on('focusin.emulateTabFocus', function () {\n focusState = true;\n body.addClass(tabFocusClass);\n element.off();\n });\n\n element.on('focusout.emulateTabFocus', function () {\n focusState = false;\n body.removeClass(tabFocusClass);\n element.off();\n });\n }\n\n return {\n apply: smartKeyboardFocus,\n focus: handleFocus\n };\n }\n\n return new KeyboardHandler;\n});\n","mage/template.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'underscore'\n], function (_) {\n 'use strict';\n\n /**\n * Checks if provided string is a valid DOM selector.\n *\n * @param {String} selector - Selector to be checked.\n * @returns {Boolean}\n */\n function isSelector(selector) {\n try {\n document.querySelector(selector);\n\n return true;\n } catch (e) {\n return false;\n }\n }\n\n /**\n * Unescapes characters used in underscore templates.\n *\n * @param {String} str - String to be processed.\n * @returns {String}\n */\n function unescape(str) {\n return str.replace(/<%|%3C%/g, '<%').replace(/%>|%%3E/g, '%>');\n }\n\n /**\n * If 'tmpl' is a valid selector, returns target node's innerHTML if found.\n * Else, returns empty string and emits console warning.\n * If 'tmpl' is not a selector, returns 'tmpl' as is.\n *\n * @param {String} tmpl\n * @returns {String}\n */\n function getTmplString(tmpl) {\n if (isSelector(tmpl)) {\n tmpl = document.querySelector(tmpl);\n\n if (tmpl) {\n tmpl = tmpl.innerHTML.trim();\n } else {\n console.warn('No template was found by selector: ' + tmpl);\n\n tmpl = '';\n }\n }\n\n return unescape(tmpl);\n }\n\n /**\n * Compiles or renders template provided either\n * by selector or by the template string.\n *\n * @param {String} tmpl - Template string or selector.\n * @param {(Object|Array|Function)} [data] - Data object with which to render template.\n * @returns {String|Function}\n */\n return function (tmpl, data) {\n var render;\n\n tmpl = getTmplString(tmpl);\n render = _.template(tmpl);\n\n return !_.isUndefined(data) ?\n render(data) :\n render;\n };\n});\n","mage/popup-window.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'jquery',\n 'jquery-ui-modules/widget'\n], function ($) {\n 'use strict';\n\n $.widget('mage.popupWindow', {\n options: {\n centerBrowser: 0, // center window over browser window? {1 (YES) or 0 (NO)}. overrides top and left\n centerScreen: 0, // center window over entire screen? {1 (YES) or 0 (NO)}. overrides top and left\n height: 500, // sets the height in pixels of the window.\n left: 0, // left position when the window appears.\n location: 0, // determines whether the address bar is displayed {1 (YES) or 0 (NO)}.\n menubar: 0, // determines whether the menu bar is displayed {1 (YES) or 0 (NO)}.\n resizable: 0, // whether the window can be resized {1 (YES) or 0 (NO)}.\n scrollbars: 0, // determines whether scrollbars appear on the window {1 (YES) or 0 (NO)}.\n status: 0, // whether a status line appears at the bottom of the window {1 (YES) or 0 (NO)}.\n width: 500, // sets the width in pixels of the window.\n windowName: null, // name of window set from the name attribute of the element that invokes the click\n windowURL: null, // url used for the popup\n top: 0, // top position when the window appears.\n toolbar: 0 // determines whether a toolbar is displayed {1 (YES) or 0 (NO)}.\n },\n\n /**\n * @private\n */\n _create: function () {\n this.element.on('click', $.proxy(this._openPopupWindow, this));\n },\n\n /**\n * @param {jQuery.Event} event\n * @private\n */\n _openPopupWindow: function (event) {\n var element = $(event.target),\n settings = this.options,\n windowFeatures =\n 'height=' + settings.height +\n ',width=' + settings.width +\n ',toolbar=' + settings.toolbar +\n ',scrollbars=' + settings.scrollbars +\n ',status=' + settings.status +\n ',resizable=' + settings.resizable +\n ',location=' + settings.location +\n ',menuBar=' + settings.menubar,\n centeredX,\n centeredY;\n\n settings.windowName = settings.windowName || element.attr('name');\n settings.windowURL = settings.windowURL || element.attr('href');\n\n if (settings.centerBrowser) {\n centeredY = window.screenY + (window.outerHeight / 2 - settings.height / 2);\n centeredX = window.screenX + (window.outerWidth / 2 - settings.width / 2);\n windowFeatures += ',left=' + centeredX + ',top=' + centeredY;\n } else if (settings.centerScreen) {\n centeredY = (screen.height - settings.height) / 2;\n centeredX = (screen.width - settings.width) / 2;\n windowFeatures += ',left=' + centeredX + ',top=' + centeredY;\n } else {\n windowFeatures += ',left=' + settings.left + ',top=' + settings.top;\n }\n\n window.open(settings.windowURL, settings.windowName, windowFeatures).focus();\n event.preventDefault();\n }\n });\n\n return $.mage.popupWindow;\n});\n","mage/storage.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine(['jquery', 'mage/url'], function ($, urlBuilder) {\n 'use strict';\n\n return {\n /**\n * Perform asynchronous GET request to server.\n * @param {String} url\n * @param {Boolean} global\n * @param {String} contentType\n * @param {Object} headers\n * @returns {Deferred}\n */\n get: function (url, global, contentType, headers) {\n headers = headers || {};\n global = global === undefined ? true : global;\n contentType = contentType || 'application/json';\n\n return $.ajax({\n url: urlBuilder.build(url),\n type: 'GET',\n global: global,\n contentType: contentType,\n headers: headers\n });\n },\n\n /**\n * Perform asynchronous POST request to server.\n * @param {String} url\n * @param {String} data\n * @param {Boolean} global\n * @param {String} contentType\n * @param {Object} headers\n * @param {Boolean} async\n * @returns {Deferred}\n */\n post: function (url, data, global, contentType, headers, async) {\n headers = headers || {};\n global = global === undefined ? true : global;\n contentType = contentType || 'application/json';\n async = async === undefined ? true : async;\n\n return $.ajax({\n url: urlBuilder.build(url),\n type: 'POST',\n data: data,\n global: global,\n contentType: contentType,\n headers: headers,\n async: async\n });\n },\n\n /**\n * Perform asynchronous PUT request to server.\n * @param {String} url\n * @param {String} data\n * @param {Boolean} global\n * @param {String} contentType\n * @param {Object} headers\n * @returns {Deferred}\n */\n put: function (url, data, global, contentType, headers) {\n var ajaxSettings = {};\n\n headers = headers || {};\n global = global === undefined ? true : global;\n contentType = contentType || 'application/json';\n ajaxSettings.url = urlBuilder.build(url);\n ajaxSettings.type = 'PUT';\n ajaxSettings.data = data;\n ajaxSettings.global = global;\n ajaxSettings.contentType = contentType;\n ajaxSettings.headers = headers;\n\n return $.ajax(ajaxSettings);\n },\n\n /**\n * Perform asynchronous DELETE request to server.\n * @param {String} url\n * @param {Boolean} global\n * @param {String} contentType\n * @param {Object} headers\n * @returns {Deferred}\n */\n delete: function (url, global, contentType, headers) {\n headers = headers || {};\n global = global === undefined ? true : global;\n contentType = contentType || 'application/json';\n\n return $.ajax({\n url: urlBuilder.build(url),\n type: 'DELETE',\n global: global,\n contentType: contentType,\n headers: headers\n });\n }\n };\n});\n","mage/translate-inline.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'jquery',\n 'mage/template',\n 'mage/utils/misc',\n 'mage/translate',\n 'jquery-ui-modules/dialog'\n], function ($, mageTemplate, miscUtils) {\n 'use strict';\n\n $.widget('mage.translateInline', $.ui.dialog, {\n options: {\n translateForm: {\n template: '#translate-form-template',\n data: {\n id: 'translate-inline-form',\n message: 'Please refresh the page to see your changes after submitting this form. ' +\n 'Note: browser cache refresh may be required'\n }\n },\n autoOpen: false,\n translateArea: null,\n modal: true,\n dialogClass: 'popup-window window-translate-inline',\n width: '75%',\n title: $.mage.__('Translate'),\n height: 470,\n position: {\n my: 'left top',\n at: 'center top',\n of: 'body'\n },\n buttons: [{\n text: $.mage.__('Submit'),\n 'class': 'action-primary',\n\n /**\n * Click\n */\n click: function () {\n $(this).translateInline('submit');\n }\n },\n {\n text: $.mage.__('Close'),\n 'class': 'action-close',\n\n /**\n * Click.\n */\n click: function () {\n $(this).translateInline('close');\n }\n }],\n\n /**\n * Open.\n */\n open: function () {\n var $uiDialog = $(this).closest('.ui-dialog'),\n topMargin = $uiDialog.children('.ui-dialog-titlebar').outerHeight() + 45;\n\n $uiDialog\n .addClass('ui-dialog-active')\n .css('margin-top', topMargin);\n },\n\n /**\n * Close.\n */\n close: function () {\n $(this).closest('.ui-dialog').removeClass('ui-dialog-active');\n }\n },\n\n /**\n * Translate Inline creation\n * @protected\n */\n _create: function () {\n var $translateArea = $(this.options.translateArea);\n\n if (!$translateArea.length) {\n $translateArea = $('body');\n }\n $translateArea.on('edit.editTrigger', $.proxy(this._onEdit, this));\n\n this.tmpl = mageTemplate(this.options.translateForm.template);\n\n this._super();\n },\n\n /**\n * @param {*} templateData\n * @return {*|jQuery|HTMLElement}\n * @private\n */\n _prepareContent: function (templateData) {\n var data = $.extend({\n items: templateData,\n escape: miscUtils.escape\n }, this.options.translateForm.data);\n\n this.data = data;\n\n return $(this.tmpl({\n data: data\n }));\n },\n\n /**\n * Render translation form and open dialog\n * @param {Object} e - object\n * @protected\n */\n _onEdit: function (e) {\n this.target = e.target;\n this.element.html(this._prepareContent($(e.target).data('translate')));\n this.open(e);\n },\n\n /**\n * Submit.\n */\n submit: function () {\n if (this.formIsSubmitted) {\n return;\n }\n this._formSubmit();\n },\n\n /**\n * Send ajax request on form submit\n * @protected\n */\n _formSubmit: function () {\n var parameters = $.param({\n area: this.options.area\n }) + '&' + $('#' + this.options.translateForm.data.id).serialize();\n\n this.formIsSubmitted = true;\n\n $.ajax({\n url: this.options.ajaxUrl,\n type: 'POST',\n data: parameters,\n loaderContext: this.element,\n showLoader: true\n }).always($.proxy(this._formSubmitComplete, this));\n },\n\n /**\n * @param {Object} response\n * @private\n */\n _formSubmitComplete: function (response) {\n var responseJSON = response.responseJSON || response;\n\n this.close();\n this.formIsSubmitted = false;\n $.mage.translate.add(responseJSON);\n this._updatePlaceholder(responseJSON[this.data.items[0].original]);\n },\n\n /**\n * @param {*} newValue\n * @private\n */\n _updatePlaceholder: function (newValue) {\n var $target = $(this.target),\n translateObject = $target.data('translate')[0];\n\n translateObject.shown = newValue;\n translateObject.translated = newValue;\n $.mage.translate.add(this.data.items[0].original, newValue);\n\n $target.html(newValue);\n },\n\n /**\n * Destroy translateInline\n */\n destroy: function () {\n this.element.off('.editTrigger');\n this._super();\n }\n });\n\n return $.mage.translateInline;\n});\n","mage/trim-input.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'jquery',\n 'jquery-ui-modules/widget'\n], function ($) {\n 'use strict';\n\n $.widget('mage.trimInput', {\n options: {\n cache: {}\n },\n\n /**\n * Widget initialization\n * @private\n */\n _create: function () {\n this.options.cache.input = $(this.element);\n this._bind();\n },\n\n /**\n * Event binding, will monitor change, keyup and paste events.\n * @private\n */\n _bind: function () {\n if (this.options.cache.input.length) {\n this._on(this.options.cache.input, {\n 'change': this._trimInput,\n 'keyup': this._trimInput,\n 'paste': this._trimInput\n });\n }\n },\n\n /**\n * Trim value\n * @private\n */\n _trimInput: function () {\n // Safari caret position workaround: storing carter position\n var caretStart, caretEnd, input;\n\n caretStart = this.options.cache.input.get(0).selectionStart;\n caretEnd = this.options.cache.input.get(0).selectionEnd;\n\n input = this._getInputValue().trim();\n\n this.options.cache.input.val(input);\n\n // Safari caret position workaround: setting caret position to previously stored values\n if (caretStart !== null && caretEnd !== null) {\n this.options.cache.input.get(0).setSelectionRange(caretStart, caretEnd);\n }\n },\n\n /**\n * Get input value\n * @returns {*}\n * @private\n */\n _getInputValue: function () {\n return this.options.cache.input.val();\n }\n });\n\n return $.mage.trimInput;\n});\n","mage/collapsible.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'jquery',\n 'jquery-ui-modules/widget',\n 'jquery-ui-modules/core',\n 'jquery/jquery-storageapi',\n 'mage/mage'\n], function ($) {\n 'use strict';\n\n var hideProps = {},\n showProps = {};\n\n hideProps.height = 'hide';\n showProps.height = 'show';\n\n $.widget('mage.collapsible', {\n options: {\n active: false,\n disabled: false,\n collapsible: true,\n header: '[data-role=title]',\n content: '[data-role=content]',\n trigger: '[data-role=trigger]',\n closedState: null,\n openedState: null,\n disabledState: null,\n ajaxUrlElement: '[data-ajax=true]',\n ajaxContent: false,\n loadingClass: null,\n saveState: false,\n animate: false,\n icons: {\n activeHeader: null,\n header: null\n },\n collateral: {\n element: null,\n openedState: null\n }\n },\n\n /**\n * @private\n */\n _create: function () {\n this.storage = $.localStorage;\n this.icons = false;\n\n if (typeof this.options.icons === 'string') {\n this.options.icons = JSON.parse(this.options.icons);\n }\n\n this._processPanels();\n this._processState();\n this._refresh();\n\n if (this.options.icons.header && this.options.icons.activeHeader) {\n this._createIcons();\n this.icons = true;\n }\n\n this.element.on('dimensionsChanged', function (e) {\n if (e.target && e.target.classList.contains('active')) {\n this._scrollToTopIfNotVisible();\n }\n }.bind(this));\n\n this._bind('click');\n this._trigger('created');\n },\n\n /**\n * @private\n */\n _refresh: function () {\n this.trigger.attr('tabIndex', 0);\n\n if (this.options.active && !this.options.disabled) {\n if (this.options.openedState) {\n this.element.addClass(this.options.openedState);\n }\n\n if (this.options.collateral.element && this.options.collateral.openedState) {\n $(this.options.collateral.element).addClass(this.options.collateral.openedState);\n }\n\n if (this.options.ajaxContent) {\n this._loadContent();\n }\n // ARIA (updates aria attributes)\n this.header.attr({\n 'aria-selected': false\n });\n } else if (this.options.disabled) {\n this.disable();\n } else {\n this.content.hide();\n\n if (this.options.closedState) {\n this.element.addClass(this.options.closedState);\n }\n }\n },\n\n /**\n * Processing the state:\n * If deep linking is used and the anchor is the id of the content or the content contains this id,\n * and the collapsible element is a nested one having collapsible parents, in order to see the content,\n * all the parents must be expanded.\n * @private\n */\n _processState: function () {\n var anchor = window.location.hash,\n isValid = $.mage.isValidSelector(anchor),\n urlPath = window.location.pathname.replace(/\\./g, ''),\n state;\n\n this.stateKey = encodeURIComponent(urlPath + this.element.attr('id'));\n\n if (isValid &&\n ($(this.content.find(anchor)).length > 0 || this.content.attr('id') === anchor.replace('#', ''))\n ) {\n this.element.parents('[data-collapsible=true]').collapsible('forceActivate');\n\n if (!this.options.disabled) {\n this.options.active = true;\n\n if (this.options.saveState) { //eslint-disable-line max-depth\n this.storage.set(this.stateKey, true);\n }\n }\n } else if (this.options.saveState && !this.options.disabled) {\n state = this.storage.get(this.stateKey);\n\n if (typeof state === 'undefined' || state === null) {\n this.storage.set(this.stateKey, this.options.active);\n } else if (state === true) {\n this.options.active = true;\n } else if (state === false) {\n this.options.active = false;\n }\n }\n },\n\n /**\n * @private\n */\n _createIcons: function () {\n var icons = this.options.icons;\n\n if (icons) {\n $('<span>')\n .addClass(icons.header)\n .attr('data-role', 'icons')\n .prependTo(this.header);\n\n if (this.options.active && !this.options.disabled) {\n this.header.children('[data-role=icons]')\n .removeClass(icons.header)\n .addClass(icons.activeHeader);\n }\n }\n },\n\n /**\n * @private\n */\n _destroyIcons: function () {\n this.header\n .children('[data-role=icons]')\n .remove();\n },\n\n /**\n * @private\n */\n _destroy: function () {\n var options = this.options;\n\n this.element.removeAttr('data-collapsible');\n\n this.trigger.removeAttr('tabIndex');\n\n if (options.openedState) {\n this.element.removeClass(options.openedState);\n }\n\n if (this.options.collateral.element && this.options.collateral.openedState) {\n $(this.options.collateral.element).removeClass(this.options.collateral.openedState);\n }\n\n if (options.closedState) {\n this.element.removeClass(options.closedState);\n }\n\n if (options.disabledState) {\n this.element.removeClass(options.disabledState);\n }\n\n if (this.icons) {\n this._destroyIcons();\n }\n },\n\n /**\n * @private\n */\n _processPanels: function () {\n var headers, triggers;\n\n this.element.attr('data-collapsible', 'true');\n\n if (typeof this.options.header === 'object') {\n this.header = this.options.header;\n } else {\n headers = this.element.find(this.options.header);\n\n if (headers.length > 0) {\n this.header = headers.eq(0);\n } else {\n this.header = this.element;\n }\n }\n\n if (typeof this.options.content === 'object') {\n this.content = this.options.content;\n } else {\n this.content = this.header.next(this.options.content).eq(0);\n }\n\n // ARIA (init aria attributes)\n if (this.header.attr('id')) {\n this.content.attr('aria-labelledby', this.header.attr('id'));\n }\n\n if (this.content.attr('id')) {\n this.header.attr('aria-controls', this.content.attr('id'));\n }\n\n this.header\n .attr({\n 'role': 'tab',\n 'aria-selected': this.options.active,\n 'aria-expanded': this.options.active\n });\n\n // For collapsible widget only (not tabs or accordion)\n if (this.header.parent().attr('role') !== 'presentation') {\n this.header\n .parent()\n .attr('role', 'tablist');\n }\n\n this.content.attr({\n 'role': 'tabpanel',\n 'aria-hidden': !this.options.active\n });\n\n if (typeof this.options.trigger === 'object') {\n this.trigger = this.options.trigger;\n } else {\n triggers = this.header.find(this.options.trigger);\n\n if (triggers.length > 0) {\n this.trigger = triggers.eq(0);\n } else {\n this.trigger = this.header;\n }\n }\n },\n\n /**\n * @param {jQuery.Event} event\n * @private\n */\n _keydown: function (event) {\n var keyCode;\n\n if (event.altKey || event.ctrlKey) {\n return;\n }\n\n keyCode = $.ui.keyCode;\n\n switch (event.keyCode) {\n case keyCode.SPACE:\n case keyCode.ENTER:\n this._eventHandler(event);\n break;\n }\n\n },\n\n /**\n * @param {jQuery.Event} event\n * @private\n */\n _bind: function (event) {\n var self = this;\n\n this.events = {\n keydown: '_keydown'\n };\n\n if (event) {\n $.each(event.split(' '), function (index, eventName) {\n self.events[eventName] = '_eventHandler';\n });\n }\n this._off(this.trigger);\n\n if (!this.options.disabled) {\n this._on(this.trigger, this.events);\n }\n },\n\n /**\n * Disable.\n */\n disable: function () {\n this.options.disabled = true;\n this._off(this.trigger);\n this.forceDeactivate();\n\n if (this.options.disabledState) {\n this.element.addClass(this.options.disabledState);\n }\n this.trigger.attr('tabIndex', -1);\n },\n\n /**\n * Enable.\n */\n enable: function () {\n this.options.disabled = false;\n this._on(this.trigger, this.events);\n this.forceActivate();\n\n if (this.options.disabledState) {\n this.element.removeClass(this.options.disabledState);\n }\n this.trigger.attr('tabIndex', 0);\n },\n\n /**\n * @param {jQuery.Event} event\n * @private\n */\n _eventHandler: function (event) {\n\n if (this.options.active && this.options.collapsible) {\n this.deactivate();\n } else {\n this.activate();\n\n }\n event.preventDefault();\n\n },\n\n /**\n * @param {*} prop\n * @private\n */\n _animate: function (prop) {\n var duration,\n easing,\n animate = this.options.animate;\n\n if (typeof animate === 'number') {\n duration = animate;\n }\n\n if (typeof animate === 'string') {\n animate = JSON.parse(animate);\n }\n duration = duration || animate.duration;\n easing = animate.easing;\n this.content.animate(prop, duration, easing);\n },\n\n /**\n * Deactivate.\n */\n deactivate: function () {\n if (this.options.animate) {\n this._animate(hideProps);\n } else {\n this.content.hide();\n }\n this._close();\n },\n\n /**\n * Force deactivate.\n */\n forceDeactivate: function () {\n this.content.hide();\n this._close();\n\n },\n\n /**\n * @private\n */\n _close: function () {\n this.options.active = false;\n\n if (this.options.saveState) {\n this.storage.set(this.stateKey, false);\n }\n\n if (this.options.openedState) {\n this.element.removeClass(this.options.openedState);\n }\n\n if (this.options.collateral.element && this.options.collateral.openedState) {\n $(this.options.collateral.element).removeClass(this.options.collateral.openedState);\n }\n\n if (this.options.closedState) {\n this.element.addClass(this.options.closedState);\n }\n\n if (this.icons) {\n this.header.children('[data-role=icons]')\n .removeClass(this.options.icons.activeHeader)\n .addClass(this.options.icons.header);\n }\n\n // ARIA (updates aria attributes)\n this.header.attr({\n 'aria-selected': 'false',\n 'aria-expanded': 'false'\n });\n this.content.attr({\n 'aria-hidden': 'true'\n });\n\n this.element.trigger('dimensionsChanged', {\n opened: false\n });\n },\n\n /**\n * Activate.\n *\n * @return void;\n */\n activate: function () {\n if (this.options.disabled) {\n return;\n }\n\n if (this.options.animate) {\n this._animate(showProps);\n } else {\n this.content.show();\n }\n this._open();\n },\n\n /**\n * Force activate.\n */\n forceActivate: function () {\n if (!this.options.disabled) {\n this.content.show();\n this._open();\n }\n },\n\n /**\n * @private\n */\n _open: function () {\n this.element.trigger('beforeOpen');\n this.options.active = true;\n\n if (this.options.ajaxContent) {\n this._loadContent();\n }\n\n if (this.options.saveState) {\n this.storage.set(this.stateKey, true);\n }\n\n if (this.options.openedState) {\n this.element.addClass(this.options.openedState);\n }\n\n if (this.options.collateral.element && this.options.collateral.openedState) {\n $(this.options.collateral.element).addClass(this.options.collateral.openedState);\n }\n\n if (this.options.closedState) {\n this.element.removeClass(this.options.closedState);\n }\n\n if (this.icons) {\n this.header.children('[data-role=icons]')\n .removeClass(this.options.icons.header)\n .addClass(this.options.icons.activeHeader);\n }\n\n // ARIA (updates aria attributes)\n this.header.attr({\n 'aria-selected': 'true',\n 'aria-expanded': 'true'\n });\n this.content.attr({\n 'aria-hidden': 'false'\n });\n\n this.element.trigger('dimensionsChanged', {\n opened: true\n });\n },\n\n /**\n * @private\n */\n _loadContent: function () {\n var url = this.element.find(this.options.ajaxUrlElement).attr('href'),\n that = this;\n\n if (url) {\n that.xhr = $.get({\n url: url,\n dataType: 'html'\n }, function () {\n });\n }\n\n if (that.xhr && that.xhr.statusText !== 'canceled') {\n if (that.options.loadingClass) {\n that.element.addClass(that.options.loadingClass);\n }\n that.content.attr('aria-busy', 'true');\n that.xhr.done(function (response) {\n setTimeout(function () {\n that.content.html(response);\n }, 1);\n });\n that.xhr.always(function (jqXHR, status) {\n setTimeout(function () {\n if (status === 'abort') {\n that.content.stop(false, true);\n }\n\n if (that.options.loadingClass) {\n that.element.removeClass(that.options.loadingClass);\n }\n that.content.removeAttr('aria-busy');\n\n if (jqXHR === that.xhr) {\n delete that.xhr;\n }\n }, 1);\n });\n }\n },\n\n /**\n * @private\n */\n _scrollToTopIfNotVisible: function () {\n if (this._isElementOutOfViewport()) {\n this.header[0].scrollIntoView();\n }\n },\n\n /**\n * @private\n * @return {Boolean}\n */\n _isElementOutOfViewport: function () {\n var headerRect = this.header[0].getBoundingClientRect(),\n contentRect = this.content.get().length ? this.content[0].getBoundingClientRect() : false,\n headerOut,\n contentOut;\n\n headerOut = headerRect.bottom - headerRect.height < 0 ||\n headerRect.right - headerRect.width < 0 ||\n headerRect.left + headerRect.width > window.innerWidth ||\n headerRect.top + headerRect.height > window.innerHeight;\n\n contentOut = contentRect ? contentRect.bottom - contentRect.height < 0 ||\n contentRect.right - contentRect.width < 0 ||\n contentRect.left + contentRect.width > window.innerWidth ||\n contentRect.top + contentRect.height > window.innerHeight : false;\n\n return headerOut ? headerOut : contentOut;\n }\n });\n\n return $.mage.collapsible;\n});\n","mage/requirejs/resolver.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n 'underscore',\n 'domReady!'\n], function (_) {\n 'use strict';\n\n var context = require.s.contexts._,\n execCb = context.execCb,\n registry = context.registry,\n callbacks = [],\n retries = 10,\n updateDelay = 1,\n ready,\n update;\n\n /**\n * Checks if provided callback already exists in the callbacks list.\n *\n * @param {Object} callback - Callback object to be checked.\n * @returns {Boolean}\n */\n function isSubscribed(callback) {\n return !!_.findWhere(callbacks, callback);\n }\n\n /**\n * Checks if provided module is rejected during load.\n *\n * @param {Object} module - Module to be checked.\n * @return {Boolean}\n */\n function isRejected(module) {\n return registry[module.id] && (registry[module.id].inited || registry[module.id].error);\n }\n\n /**\n * Checks if provided module had path fallback triggered.\n *\n * @param {Object} module - Module to be checked.\n * @return {Boolean}\n */\n function isPathFallback(module) {\n return registry[module.id] && registry[module.id].events.error;\n }\n\n /**\n * Checks if provided module has unresolved dependencies.\n *\n * @param {Object} module - Module to be checked.\n * @returns {Boolean}\n */\n function isPending(module) {\n if (!module.depCount) {\n return false;\n }\n\n return module.depCount >\n _.filter(module.depMaps, isRejected).length + _.filter(module.depMaps, isPathFallback).length;\n }\n\n /**\n * Checks if requirejs's registry object contains pending modules.\n *\n * @returns {Boolean}\n */\n function hasPending() {\n return _.some(registry, isPending);\n }\n\n /**\n * Checks if 'resolver' module is in ready\n * state and that there are no pending modules.\n *\n * @returns {Boolean}\n */\n function isReady() {\n return ready && !hasPending();\n }\n\n /**\n * Invokes provided callback handler.\n *\n * @param {Object} callback\n */\n function invoke(callback) {\n callback.handler.call(callback.ctx);\n }\n\n /**\n * Sets 'resolver' module to a ready state\n * and invokes pending callbacks.\n */\n function resolve() {\n ready = true;\n\n callbacks.splice(0).forEach(invoke);\n }\n\n /**\n * Drops 'ready' flag and runs the update process.\n */\n function tick() {\n ready = false;\n\n update(retries);\n }\n\n /**\n * Adds callback which will be invoked\n * when all of the pending modules are initiated.\n *\n * @param {Function} handler - 'Ready' event handler function.\n * @param {Object} [ctx] - Optional context with which handler\n * will be invoked.\n */\n function subscribe(handler, ctx) {\n var callback = {\n handler: handler,\n ctx: ctx\n };\n\n if (!isSubscribed(callback)) {\n callbacks.push(callback);\n\n if (isReady()) {\n _.defer(tick);\n }\n }\n }\n\n /**\n * Checks for all modules to be initiated\n * and invokes pending callbacks if it's so.\n *\n * @param {Number} [retry] - Number of retries\n * that will be used to repeat the 'update' function\n * invokation in case if there are no pending requests.\n */\n update = _.debounce(function (retry) {\n if (!hasPending()) {\n retry ? update(--retry) : resolve();\n }\n }, updateDelay);\n\n /**\n * Overrides requirejs's original 'execCb' method\n * in order to track pending modules.\n *\n * @returns {*} Result of original method call.\n */\n context.execCb = function () {\n var exported = execCb.apply(context, arguments);\n\n tick();\n\n return exported;\n };\n\n return subscribe;\n});\n","mage/requirejs/text.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/* inspired by http://github.com/requirejs/text */\n/*global XDomainRequest */\n\ndefine(['module'], function (module) {\n 'use strict';\n\n var xmlRegExp = /^\\s*<\\?xml(\\s)+version=[\\'\\\"](\\d)*.(\\d)*[\\'\\\"](\\s)*\\?>/im,\n bodyRegExp = /<body[^>]*>\\s*([\\s\\S]+)\\s*<\\/body>/im,\n stripReg = /!strip$/i,\n defaultConfig = module.config && module.config() || {};\n\n /**\n * Strips <?xml ...?> declarations so that external SVG and XML documents can be\n * added to a document without worry.\n * Also, if the string is an HTML document, only the part inside the body tag is returned.\n *\n * @param {String} external\n * @returns {String}\n */\n function stripContent(external) {\n var matches;\n\n if (!external) {\n return '';\n }\n\n matches = external.match(bodyRegExp);\n external = matches ?\n matches[1] :\n external.replace(xmlRegExp, '');\n\n return external;\n }\n\n /**\n * Checks that url match current location\n *\n * @param {String} url\n * @returns {Boolean}\n */\n function sameDomain(url) {\n var uProtocol, uHostName, uPort,\n xdRegExp = /^([\\w:]+)?\\/\\/([^\\/\\\\]+)/i,\n location = window.location,\n match = xdRegExp.exec(url);\n\n if (!match) {\n return true;\n }\n uProtocol = match[1];\n uHostName = match[2];\n\n uHostName = uHostName.split(':');\n uPort = uHostName[1] || '';\n uHostName = uHostName[0];\n\n return (!uProtocol || uProtocol === location.protocol) &&\n (!uHostName || uHostName.toLowerCase() === location.hostname.toLowerCase()) &&\n (!uPort && !uHostName || uPort === location.port);\n }\n\n /**\n * @returns {XMLHttpRequest|XDomainRequest|null}\n */\n function createRequest(url) {\n var xhr = new XMLHttpRequest();\n\n if (!sameDomain(url) && typeof XDomainRequest !== 'undefined') {\n xhr = new XDomainRequest();\n }\n\n return xhr;\n }\n\n /**\n * XHR requester. Returns value to callback.\n *\n * @param {String} url\n * @param {Function} callback\n * @param {Function} fail\n * @param {Object} headers\n */\n function getContent(url, callback, fail, headers) {\n var xhr = createRequest(url),\n header;\n\n xhr.open('GET', url);\n\n /*eslint-disable max-depth */\n if ('setRequestHeader' in xhr && headers) {\n for (header in headers) {\n if (headers.hasOwnProperty(header)) {\n xhr.setRequestHeader(header.toLowerCase(), headers[header]);\n }\n }\n }\n\n /**\n * @inheritdoc\n */\n xhr.onreadystatechange = function () {\n var status, err;\n\n //Do not explicitly handle errors, those should be\n //visible via console output in the browser.\n if (xhr.readyState === 4) {\n status = xhr.status || 0;\n\n if (status > 399 && status < 600) {\n //An http 4xx or 5xx error. Signal an error.\n err = new Error(url + ' HTTP status: ' + status);\n err.xhr = xhr;\n\n if (fail) {\n fail(err);\n }\n } else {\n callback(xhr.responseText);\n\n if (defaultConfig.onXhrComplete) {\n defaultConfig.onXhrComplete(xhr, url);\n }\n }\n }\n };\n\n /*eslint-enable max-depth */\n\n if (defaultConfig.onXhr) {\n defaultConfig.onXhr(xhr, url);\n }\n\n xhr.send();\n }\n\n /**\n * Main method used by RequireJs.\n *\n * @param {String} name - has format: some.module.filext!strip\n * @param {Function} req\n * @param {Function|undefined} onLoad\n */\n function loadContent(name, req, onLoad) {\n\n var toStrip = stripReg.test(name),\n url = req.toUrl(name.replace(stripReg, '')),\n headers = defaultConfig.headers;\n\n getContent(url, function (content) {\n content = toStrip ? stripContent(content) : content;\n onLoad(content);\n }, onLoad.error, headers);\n }\n\n return {\n load: loadContent,\n get: getContent\n };\n});\n","mage/requirejs/baseUrlResolver.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * Sample configuration:\n *\n require.config({\n \"config\": {\n \"baseUrlInterceptor\": {\n \"Magento_Ui/js/lib/knockout/bindings/collapsible.js\": \"../../../../frontend/Magento/luma/en_US/\"\n }\n }\n });\n */\n\n/* global jsSuffixRegExp */\n/* eslint-disable max-depth */\ndefine('baseUrlInterceptor', [\n 'module'\n], function (module) {\n 'use strict';\n\n /**\n * RequireJS Context object\n */\n var ctx = require.s.contexts._,\n\n /**\n * Original function\n *\n * @type {Function}\n */\n origNameToUrl = ctx.nameToUrl,\n\n /**\n * Original function\n *\n * @type {Function}\n */\n newContextConstr = require.s.newContext;\n\n /**\n * Remove dots from URL\n *\n * @param {Array} ary\n */\n function trimDots(ary) {\n var i, part, length = ary.length;\n\n for (i = 0; i < length; i++) {\n part = ary[i];\n\n if (part === '.') {\n ary.splice(i, 1);\n i -= 1;\n } else if (part === '..') {\n if (i === 1 && (ary[2] === '..' || ary[0] === '..')) {\n //End of the line. Keep at least one non-dot\n //path segment at the front so it can be mapped\n //correctly to disk. Otherwise, there is likely\n //no path mapping for a path starting with '..'.\n //This can still fail, but catches the most reasonable\n //uses of ..\n break;\n } else if (i > 0) {\n ary.splice(i - 1, 2);\n i -= 2;\n }\n }\n }\n }\n\n /**\n * Normalize URL string (remove '/../')\n *\n * @param {String} name\n * @param {String} baseName\n * @param {Object} applyMap\n * @param {Object} localContext\n * @returns {*}\n */\n function normalize(name, baseName, applyMap, localContext) {\n var lastIndex,\n baseParts = baseName && baseName.split('/'),\n normalizedBaseParts = baseParts;\n\n //Adjust any relative paths.\n if (name && name.charAt(0) === '.') {\n //If have a base name, try to normalize against it,\n //otherwise, assume it is a top-level require that will\n //be relative to baseUrl in the end.\n if (baseName) {\n //Convert baseName to array, and lop off the last part,\n //so that . matches that 'directory' and not name of the baseName's\n //module. For instance, baseName of 'one/two/three', maps to\n //'one/two/three.js', but we want the directory, 'one/two' for\n //this normalization.\n normalizedBaseParts = baseParts.slice(0, baseParts.length - 1);\n name = name.split('/');\n lastIndex = name.length - 1;\n\n // If wanting node ID compatibility, strip .js from end\n // of IDs. Have to do this here, and not in nameToUrl\n // because node allows either .js or non .js to map\n // to same file.\n if (localContext.nodeIdCompat && jsSuffixRegExp.test(name[lastIndex])) {\n name[lastIndex] = name[lastIndex].replace(jsSuffixRegExp, '');\n }\n\n name = normalizedBaseParts.concat(name);\n trimDots(name);\n name = name.join('/');\n } else if (name.indexOf('./') === 0) {\n // No baseName, so this is ID is resolved relative\n // to baseUrl, pull off the leading dot.\n name = name.substring(2);\n }\n }\n\n return name;\n }\n\n /**\n * Get full url.\n *\n * @param {Object} context\n * @param {String} url\n * @return {String}\n */\n function getUrl(context, url) {\n var baseUrl = context.config.baseUrl,\n newConfig = context.config,\n modulePath = url.replace(baseUrl, ''),\n newBaseUrl,\n rewrite = module.config()[modulePath];\n\n if (!rewrite) {\n return url;\n }\n\n newBaseUrl = normalize(rewrite, baseUrl, undefined, newConfig);\n\n return newBaseUrl + modulePath;\n }\n\n /**\n * Replace original function.\n *\n * @returns {*}\n */\n ctx.nameToUrl = function () {\n return getUrl(ctx, origNameToUrl.apply(ctx, arguments));\n };\n\n /**\n * Replace original function.\n *\n * @return {*}\n */\n require.s.newContext = function () {\n var newCtx = newContextConstr.apply(require.s, arguments),\n newOrigNameToUrl = newCtx.nameToUrl;\n\n /**\n * New implementation of native function.\n *\n * @returns {String}\n */\n newCtx.nameToUrl = function () {\n return getUrl(newCtx, newOrigNameToUrl.apply(newCtx, arguments));\n };\n\n return newCtx;\n };\n});\n\nrequire(['baseUrlInterceptor'], function () {\n 'use strict';\n\n});\n","mage/msie/file-reader.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n 'jquery'\n], function ($) {\n 'use strict';\n\n /**\n * Init \"readAsBinaryString\" function for FileReader class.\n * It need for IE11\n * @param {Blob} fileData\n */\n var readAsBinaryStringIEFunc = function (fileData) {\n var binary = '',\n self = this,\n reader = new FileReader();\n\n /**\n * Read file as binary string\n */\n reader.onload = function () {\n var bytes, length, index;\n\n /* eslint-disable no-undef */\n bytes = new Uint8Array(reader.result);\n /* eslint-enable */\n length = bytes.length;\n\n for (index = 0; index < length; index++) {\n binary += String.fromCharCode(bytes[index]);\n }\n //self.result - readonly so assign binary\n self.content = binary;\n $(self).trigger('onload');\n };\n reader.readAsArrayBuffer(fileData);\n };\n\n if (typeof FileReader.prototype.readAsBinaryString === 'undefined') {\n FileReader.prototype.readAsBinaryString = readAsBinaryStringIEFunc;\n }\n});\n","mage/apply/main.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'underscore',\n 'jquery',\n './scripts'\n], function (_, $, processScripts) {\n 'use strict';\n\n var dataAttr = 'data-mage-init',\n nodeSelector = '[' + dataAttr + ']';\n\n /**\n * Initializes components assigned to a specified element via data-* attribute.\n *\n * @param {HTMLElement} el - Element to initialize components with.\n * @param {Object|String} config - Initial components' config.\n * @param {String} component - Components' path.\n */\n function init(el, config, component) {\n require([component], function (fn) {\n var $el;\n\n if (typeof fn === 'object') {\n fn = fn[component].bind(fn);\n }\n\n if (_.isFunction(fn)) {\n fn = fn.bind(null, config, el);\n } else {\n $el = $(el);\n\n if ($el[component]) {\n // eslint-disable-next-line jquery-no-bind-unbind\n fn = $el[component].bind($el, config);\n }\n }\n // Init module in separate task to prevent blocking main thread.\n setTimeout(fn);\n }, function (error) {\n if ('console' in window && typeof window.console.error === 'function') {\n console.error(error);\n }\n\n return true;\n });\n }\n\n /**\n * Parses elements 'data-mage-init' attribute as a valid JSON data.\n * Note: data-mage-init attribute will be removed.\n *\n * @param {HTMLElement} el - Element whose attribute should be parsed.\n * @returns {Object}\n */\n function getData(el) {\n var data = el.getAttribute(dataAttr);\n\n el.removeAttribute(dataAttr);\n\n return {\n el: el,\n data: JSON.parse(data)\n };\n }\n\n return {\n /**\n * Initializes components assigned to HTML elements via [data-mage-init].\n *\n * @example Sample 'data-mage-init' declaration.\n * data-mage-init='{\"path/to/component\": {\"foo\": \"bar\"}}'\n */\n apply: function (context) {\n var virtuals = processScripts(!context ? document : context),\n nodes = document.querySelectorAll(nodeSelector);\n\n _.toArray(nodes)\n .map(getData)\n .concat(virtuals)\n .forEach(function (itemContainer) {\n var element = itemContainer.el;\n\n _.each(itemContainer.data, function (obj, key) {\n if (obj.mixins) {\n require(obj.mixins, function () { //eslint-disable-line max-nested-callbacks\n var i, len;\n\n for (i = 0, len = arguments.length; i < len; i++) {\n $.extend(\n true,\n itemContainer.data[key],\n arguments[i](itemContainer.data[key], element)\n );\n }\n\n delete obj.mixins;\n init.call(null, element, obj, key);\n });\n } else {\n init.call(null, element, obj, key);\n }\n\n }\n );\n\n });\n },\n applyFor: init\n };\n});\n","mage/apply/scripts.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'underscore',\n 'jquery'\n], function (_, $) {\n 'use strict';\n\n var scriptSelector = 'script[type=\"text/x-magento-init\"]',\n dataAttr = 'data-mage-init',\n virtuals = [];\n\n /**\n * Adds components to the virtual list.\n *\n * @param {Object} components\n */\n function addVirtual(components) {\n virtuals.push({\n el: false,\n data: components\n });\n }\n\n /**\n * Merges provided data with a current data\n * of a elements' \"data-mage-init\" attribute.\n *\n * @param {Object} components - Object with components and theirs configuration.\n * @param {HTMLElement} elem - Element whose data should be modified.\n */\n function setData(components, elem) {\n var data = elem.getAttribute(dataAttr);\n\n data = data ? JSON.parse(data) : {};\n _.each(components, function (obj, key) {\n if (_.has(obj, 'mixins')) {\n data[key] = data[key] || {};\n data[key].mixins = data[key].mixins || [];\n data[key].mixins = data[key].mixins.concat(obj.mixins);\n delete obj.mixins;\n }\n });\n\n data = $.extend(true, data, components);\n data = JSON.stringify(data);\n elem.setAttribute(dataAttr, data);\n }\n\n /**\n * Search for the elements by privded selector and extends theirs data.\n *\n * @param {Object} components - Object with components and theirs configuration.\n * @param {String} selector - Selector for the elements.\n */\n function processElems(components, selector) {\n var elems,\n iterator;\n\n if (selector === '*') {\n addVirtual(components);\n\n return;\n }\n\n elems = document.querySelectorAll(selector);\n iterator = setData.bind(null, components);\n\n _.toArray(elems).forEach(iterator);\n }\n\n /**\n * Parses content of a provided script node.\n * Note: node will be removed from DOM.\n *\n * @param {HTMLScriptElement} node - Node to be processed.\n * @returns {Object}\n */\n function getNodeData(node) {\n var data = node.textContent;\n\n node.parentNode.removeChild(node);\n\n return JSON.parse(data);\n }\n\n /**\n * Parses 'script' tags with a custom type attribute and moves it's data\n * to a 'data-mage-init' attribute of an element found by provided selector.\n * Note: All found script nodes will be removed from DOM.\n *\n * @returns {Array} An array of components not assigned to the specific element.\n *\n * @example Sample declaration.\n * <script type=\"text/x-magento-init\">\n * {\n * \"body\": {\n * \"path/to/component\": {\"foo\": \"bar\"}\n * }\n * }\n * </script>\n *\n * @example Providing data without selector.\n * {\n * \"*\": {\n * \"path/to/component\": {\"bar\": \"baz\"}\n * }\n * }\n */\n return function () {\n var nodes = document.querySelectorAll(scriptSelector);\n\n _.toArray(nodes)\n .map(getNodeData)\n .forEach(function (item) {\n _.each(item, processElems);\n });\n\n return virtuals.splice(0, virtuals.length);\n };\n});\n","mage/validation/url.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([], function () {\n 'use strict';\n\n return {\n\n /**\n * Redirects to the url if it is considered safe\n *\n * @param {String} path - url to be redirected to\n */\n redirect: function (path) {\n path = this.sanitize(path);\n\n if (this.validate(path)) {\n window.location.href = path;\n }\n },\n\n /**\n * Validates url\n *\n * @param {Object} path - url to be validated\n * @returns {Boolean}\n */\n validate: function (path) {\n var hostname = window.location.hostname;\n\n if (path.indexOf(hostname) === -1 ||\n path.indexOf('javascript:') !== -1 ||\n path.indexOf('vbscript:') !== -1) {\n return false;\n }\n\n return true;\n },\n\n /**\n * Sanitize url, replacing disallowed chars\n *\n * @param {String} path - url to be normalized\n * @returns {String}\n */\n sanitize: function (path) {\n return path.replace('[^-A-Za-z0-9+&@#/%?=~_|!:,.;\\(\\)]', '');\n }\n };\n});\n","mage/utils/wrapper.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * Utility methods used to wrap and extend functions.\n *\n * @example Usage of a 'wrap' method with arguments delegation.\n * var multiply = function (a, b) {\n * return a * b;\n * };\n *\n * multiply = module.wrap(multiply, function (orig) {\n * return 'Result is: ' + orig();\n * });\n *\n * multiply(2, 2);\n * => 'Result is: 4'\n *\n * @example Usage of 'wrapSuper' method.\n * var multiply = function (a, b) {\n * return a * b;\n * };\n *\n * var obj = {\n * multiply: module.wrapSuper(multiply, function () {\n * return 'Result is: ' + this._super();\n * });\n * };\n *\n * obj.multiply(2, 2);\n * => 'Result is: 4'\n */\ndefine([\n 'underscore'\n], function (_) {\n 'use strict';\n\n /**\n * Checks if string has a '_super' substring.\n */\n var superReg = /\\b_super\\b/;\n\n return {\n\n /**\n * Wraps target function with a specified wrapper, which will receive\n * reference to the original function as a first argument.\n *\n * @param {Function} target - Function to be wrapped.\n * @param {Function} wrapper - Wrapper function.\n * @returns {Function} Wrapper function.\n */\n wrap: function (target, wrapper) {\n if (!_.isFunction(target) || !_.isFunction(wrapper)) {\n return wrapper;\n }\n\n return function () {\n var args = _.toArray(arguments),\n ctx = this,\n _super;\n\n /**\n * Function that will be passed to the wrapper.\n * If no arguments will be passed to it, then the original\n * function will be called with an arguments of a wrapper function.\n */\n _super = function () {\n var superArgs = arguments.length ? arguments : args.slice(1);\n\n return target.apply(ctx, superArgs);\n };\n\n args.unshift(_super);\n\n return wrapper.apply(ctx, args);\n };\n },\n\n /**\n * Wraps the incoming function to implement support of the '_super' method.\n *\n * @param {Function} target - Function to be wrapped.\n * @param {Function} wrapper - Wrapper function.\n * @returns {Function} Wrapped function.\n */\n wrapSuper: function (target, wrapper) {\n if (!this.hasSuper(wrapper) || !_.isFunction(target)) {\n return wrapper;\n }\n\n return function () {\n var _super = this._super,\n args = arguments,\n result;\n\n /**\n * Temporary define '_super' method which\n * contains call to the original function.\n */\n this._super = function () {\n var superArgs = arguments.length ? arguments : args;\n\n return target.apply(this, superArgs);\n };\n\n result = wrapper.apply(this, args);\n\n this._super = _super;\n\n return result;\n };\n },\n\n /**\n * Checks wether the incoming method contains calls of the '_super' method.\n *\n * @param {Function} fn - Function to be checked.\n * @returns {Boolean}\n */\n hasSuper: function (fn) {\n return _.isFunction(fn) && superReg.test(fn);\n },\n\n /**\n * Extends target object with provided extenders.\n * If property in target and extender objects is a function,\n * then it will be wrapped using 'wrap' method.\n *\n * @param {Object} target - Object to be extended.\n * @param {...Object} extenders - Multiple extenders objects.\n * @returns {Object} Modified target object.\n */\n extend: function (target) {\n var extenders = _.toArray(arguments).slice(1),\n iterator = this._extend.bind(this, target);\n\n extenders.forEach(iterator);\n\n return target;\n },\n\n /**\n * Same as the 'extend' method, but operates only on one extender object.\n *\n * @private\n * @param {Object} target\n * @param {Object} extender\n */\n _extend: function (target, extender) {\n _.each(extender, function (value, key) {\n target[key] = this.wrap(target[key], extender[key]);\n }, this);\n }\n };\n});\n","mage/utils/misc.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'underscore',\n 'jquery',\n 'mage/utils/objects'\n], function (_, $, utils) {\n 'use strict';\n\n var defaultAttributes,\n ajaxSettings,\n map;\n\n defaultAttributes = {\n method: 'post',\n enctype: 'multipart/form-data'\n };\n\n ajaxSettings = {\n default: {\n method: 'POST',\n cache: false,\n processData: false,\n contentType: false\n },\n simple: {\n method: 'POST',\n dataType: 'json'\n }\n };\n\n map = {\n 'D': 'DDD',\n 'dd': 'DD',\n 'd': 'D',\n 'EEEE': 'dddd',\n 'EEE': 'ddd',\n 'e': 'd',\n 'yyyy': 'YYYY',\n 'yy': 'YY',\n 'y': 'YYYY',\n 'a': 'A'\n };\n\n return {\n\n /**\n * Generates a unique identifier.\n *\n * @param {Number} [size=7] - Length of a resulting identifier.\n * @returns {String}\n */\n uniqueid: function (size) {\n var code = Math.random() * 25 + 65 | 0,\n idstr = String.fromCharCode(code);\n\n size = size || 7;\n\n while (idstr.length < size) {\n code = Math.floor(Math.random() * 42 + 48);\n\n if (code < 58 || code > 64) {\n idstr += String.fromCharCode(code);\n }\n }\n\n return idstr;\n },\n\n /**\n * Limits function call.\n *\n * @param {Object} owner\n * @param {String} target\n * @param {Number} limit\n */\n limit: function (owner, target, limit) {\n var fn = owner[target];\n\n owner[target] = _.debounce(fn.bind(owner), limit);\n },\n\n /**\n * Converts mage date format to a moment.js format.\n *\n * @param {String} mageFormat\n * @returns {String}\n */\n normalizeDate: function (mageFormat) {\n var result = mageFormat;\n\n _.each(map, function (moment, mage) {\n result = result.replace(\n new RegExp(mage + '(?=([^\\u0027]*\\u0027[^\\u0027]*\\u0027)*[^\\u0027]*$)'),\n moment\n );\n });\n result = result.replace(/'(.*?)'/g, '[$1]');\n return result;\n },\n\n /**\n * Puts provided value in range of min and max parameters.\n *\n * @param {Number} value - Value to be located.\n * @param {Number} min - Min value.\n * @param {Number} max - Max value.\n * @returns {Number}\n */\n inRange: function (value, min, max) {\n return Math.min(Math.max(min, value), max);\n },\n\n /**\n * Serializes and sends data via POST request.\n *\n * @param {Object} options - Options object that consists of\n * a 'url' and 'data' properties.\n * @param {Object} attrs - Attributes that will be added to virtual form.\n */\n submit: function (options, attrs) {\n var form = document.createElement('form'),\n data = utils.serialize(options.data),\n attributes = _.extend({}, defaultAttributes, attrs || {});\n\n if (!attributes.action) {\n attributes.action = options.url;\n }\n\n data['form_key'] = window.FORM_KEY;\n\n _.each(attributes, function (value, name) {\n form.setAttribute(name, value);\n });\n\n data = _.map(\n data,\n function (value, name) {\n return '<input type=\"hidden\" ' +\n 'name=\"' + _.escape(name) + '\" ' +\n 'value=\"' + _.escape(value) + '\"' +\n ' />';\n }\n ).join('');\n\n form.insertAdjacentHTML('afterbegin', data);\n document.body.appendChild(form);\n\n form.submit();\n },\n\n /**\n * Serializes and sends data via AJAX POST request.\n *\n * @param {Object} options - Options object that consists of\n * a 'url' and 'data' properties.\n * @param {Object} config\n */\n ajaxSubmit: function (options, config) {\n var t = new Date().getTime(),\n settings;\n\n options.data['form_key'] = window.FORM_KEY;\n options.data = this.prepareFormData(options.data, config.ajaxSaveType);\n settings = _.extend({}, ajaxSettings[config.ajaxSaveType], options || {});\n\n if (!config.ignoreProcessEvents) {\n $('body').trigger('processStart');\n }\n\n return $.ajax(settings)\n .done(function (data) {\n if (config.response) {\n data.t = t;\n config.response.data(data);\n config.response.status(undefined);\n config.response.status(!data.error);\n }\n })\n .fail(function () {\n if (config.response) {\n config.response.status(undefined);\n config.response.status(false);\n config.response.data({\n error: true,\n messages: 'Something went wrong.',\n t: t\n });\n }\n })\n .always(function () {\n if (!config.ignoreProcessEvents) {\n $('body').trigger('processStop');\n }\n });\n },\n\n /**\n * Creates FormData object and append this data.\n *\n * @param {Object} data\n * @param {String} type\n * @returns {FormData}\n */\n prepareFormData: function (data, type) {\n var formData;\n\n if (type === 'default') {\n formData = new FormData();\n _.each(utils.serialize(data), function (val, name) {\n formData.append(name, val);\n });\n } else if (type === 'simple') {\n formData = utils.serialize(data);\n }\n\n return formData;\n },\n\n /**\n * Filters data object. Finds properties with suffix\n * and sets their values to properties with the same name without suffix.\n *\n * @param {Object} data - The data object that should be filtered\n * @param {String} suffix - The string by which data object should be filtered\n * @param {String} separator - The string that is separator between property and suffix\n *\n * @returns {Object} Filtered data object\n */\n filterFormData: function (data, suffix, separator) {\n data = data || {};\n suffix = suffix || 'prepared-for-send';\n separator = separator || '-';\n\n _.each(data, function (value, key) {\n if (_.isObject(value) && !Array.isArray(value)) {\n this.filterFormData(value, suffix, separator);\n } else if (_.isString(key) && ~key.indexOf(suffix)) {\n data[key.split(separator)[0]] = value;\n delete data[key];\n }\n }, this);\n\n return data;\n },\n\n /**\n * Replaces special characters with their corresponding HTML entities.\n *\n * @param {String} string - Text to escape.\n * @returns {String} Escaped text.\n */\n escape: function (string) {\n return string ? $('<p></p>').text(string).html().replace(/\"/g, '"') : string;\n },\n\n /**\n * Replaces symbol codes with their unescaped counterparts.\n *\n * @param {String} data\n *\n * @returns {String}\n */\n unescape: function (data) {\n var unescaped = _.unescape(data),\n mapCharacters = {\n ''': '\\''\n };\n\n _.each(mapCharacters, function (value, key) {\n unescaped = unescaped.replace(key, value);\n });\n\n return unescaped;\n },\n\n /**\n * Converts PHP IntlFormatter format to moment format.\n *\n * @param {String} format - PHP format\n * @returns {String} - moment compatible formatting\n */\n convertToMomentFormat: function (format) {\n var newFormat;\n\n newFormat = format.replace(/yyyy|yy|y/, 'YYYY'); // replace the year\n newFormat = newFormat.replace(/dd|d/g, 'DD'); // replace the date\n\n return newFormat;\n },\n\n /**\n * Get Url Parameters.\n *\n * @param {String} url - Url string\n * @returns {Object}\n */\n getUrlParameters: function (url) {\n var params = {},\n queries = url.split('?'),\n temp,\n i,\n l;\n\n if (!queries[1]) {\n return params;\n }\n\n queries = queries[1].split('&');\n\n for (i = 0, l = queries.length; i < l; i++) {\n temp = queries[i].split('=');\n\n if (temp[1]) {\n params[temp[0]] = decodeURIComponent(temp[1].replace(/\\+/g, '%20'));\n } else {\n params[temp[0]] = '';\n }\n }\n\n return params;\n }\n };\n});\n","mage/utils/main.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine(function (require) {\n 'use strict';\n\n var utils = {},\n _ = require('underscore'),\n root = typeof self == 'object' && self.self === self && self ||\n typeof global == 'object' && global.global === global && global ||\n Function('return this')() || {};\n\n root._ = _;\n\n return _.extend(\n utils,\n require('./arrays'),\n require('./compare'),\n require('./misc'),\n require('./objects'),\n require('./strings'),\n require('./template')\n );\n});\n","mage/utils/template.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* eslint-disable no-shadow */\n\ndefine([\n 'jquery',\n 'underscore',\n 'mage/utils/objects',\n 'mage/utils/strings'\n], function ($, _, utils, stringUtils) {\n 'use strict';\n\n var tmplSettings = _.templateSettings,\n interpolate = /\\$\\{([\\s\\S]+?)\\}/g,\n opener = '${',\n template,\n hasStringTmpls;\n\n /**\n * Identifies whether ES6 templates are supported.\n */\n hasStringTmpls = (function () {\n var testString = 'var foo = \"bar\"; return `${ foo }` === foo';\n\n try {\n return Function(testString)();\n } catch (e) {\n return false;\n }\n })();\n\n /**\n * Objects can specify how to use templating for their properties - getting that configuration.\n *\n * To disable rendering for all properties of your object add __disableTmpl: true.\n * To disable for specific property add __disableTmpl: {propertyName: true}.\n * To limit recursion for a specific property add __disableTmpl: {propertyName: numberOfCycles}.\n *\n * @param {String} tmpl\n * @param {Object | undefined} target\n * @returns {Boolean|Object}\n */\n function isTmplIgnored(tmpl, target) {\n var parsedTmpl;\n\n try {\n parsedTmpl = JSON.parse(tmpl);\n\n if (typeof parsedTmpl === 'object') {\n return tmpl.includes('__disableTmpl');\n }\n } catch (e) {\n }\n\n if (typeof target !== 'undefined') {\n if (typeof target === 'object' && target.hasOwnProperty('__disableTmpl')) {\n return target.__disableTmpl;\n }\n }\n\n return false;\n\n }\n\n if (hasStringTmpls) {\n\n /*eslint-disable no-unused-vars, no-eval*/\n /**\n * Evaluates template string using ES6 templates.\n *\n * @param {String} tmpl - Template string.\n * @param {Object} $ - Data object used in a template.\n * @returns {String} Compiled template.\n */\n template = function (tmpl, $) {\n return eval('`' + tmpl + '`');\n };\n\n /*eslint-enable no-unused-vars, no-eval*/\n } else {\n\n /**\n * Fallback function used when ES6 templates are not supported.\n * Uses underscore templates renderer.\n *\n * @param {String} tmpl - Template string.\n * @param {Object} data - Data object used in a template.\n * @returns {String} Compiled template.\n */\n template = function (tmpl, data) {\n var cached = tmplSettings.interpolate;\n\n tmplSettings.interpolate = interpolate;\n\n tmpl = _.template(tmpl, {\n variable: '$'\n })(data);\n\n tmplSettings.interpolate = cached;\n\n return tmpl;\n };\n }\n\n /**\n * Checks if provided value contains template syntax.\n *\n * @param {*} value - Value to be checked.\n * @returns {Boolean}\n */\n function isTemplate(value) {\n return typeof value === 'string' &&\n value.indexOf(opener) !== -1 &&\n // the below pattern almost always indicates an accident which should not cause template evaluation\n // refuse to evaluate\n value.indexOf('${{') === -1;\n }\n\n /**\n * Iteratively processes provided string\n * until no templates syntax will be found.\n *\n * @param {String} tmpl - Template string.\n * @param {Object} data - Data object used in a template.\n * @param {Boolean} [castString=false] - Flag that indicates whether template\n * should be casted after evaluation to a value of another type or\n * that it should be leaved as a string.\n * @param {Number|undefined} maxCycles - Maximum number of rendering cycles, can be 0.\n * @returns {*} Compiled template.\n */\n function render(tmpl, data, castString, maxCycles) {\n var last = tmpl,\n cycles = 0;\n\n while (~tmpl.indexOf(opener) && (typeof maxCycles === 'undefined' || cycles < maxCycles)) {\n if (!isTmplIgnored(tmpl)) {\n tmpl = template(tmpl, data);\n }\n\n if (tmpl === last) {\n break;\n }\n\n last = tmpl;\n cycles++;\n }\n\n return castString ?\n stringUtils.castString(tmpl) :\n tmpl;\n }\n\n return {\n\n /**\n * Applies provided data to the template.\n *\n * @param {Object|String} tmpl\n * @param {Object} [data] - Data object to match with template.\n * @param {Boolean} [castString=false] - Flag that indicates whether template\n * should be casted after evaluation to a value of another type or\n * that it should be leaved as a string.\n * @returns {*}\n *\n * @example Template defined as a string.\n * var source = { foo: 'Random Stuff', bar: 'Some' };\n *\n * utils.template('${ $.bar } ${ $.foo }', source);\n * => 'Some Random Stuff';\n *\n * @example Template defined as an object.\n * var tmpl = {\n * key: {'${ $.$data.bar }': '${ $.$data.foo }'},\n * foo: 'bar',\n * x1: 2, x2: 5,\n * delta: '${ $.x2 - $.x1 }',\n * baz: 'Upper ${ $.foo.toUpperCase() }'\n * };\n *\n * utils.template(tmpl, source);\n * => {\n * key: {'Some': 'Random Stuff'},\n * foo: 'bar',\n * x1: 2, x2: 5,\n * delta: 3,\n * baz: 'Upper BAR'\n * };\n */\n template: function (tmpl, data, castString, dontClone) {\n if (typeof tmpl === 'string') {\n return render(tmpl, data, castString);\n }\n\n if (!dontClone) {\n tmpl = utils.copy(tmpl);\n }\n\n tmpl.$data = data || {};\n\n /**\n * Template iterator function.\n */\n _.each(tmpl, function iterate(value, key, list) {\n var disabled,\n maxCycles;\n\n if (key === '$data') {\n return;\n }\n\n if (isTemplate(key)) {\n delete list[key];\n\n key = render(key, tmpl);\n list[key] = value;\n }\n\n if (isTemplate(value)) {\n //Getting template disabling settings, can be true for all disabled and separate settings\n //for each property.\n disabled = isTmplIgnored(value, list);\n\n if (typeof disabled === 'object' && disabled.hasOwnProperty(key) && disabled[key] !== false) {\n //Checking if specific settings for a property provided.\n maxCycles = disabled[key];\n }\n\n if (disabled === true || maxCycles === true) {\n //Rendering for all properties is disabled.\n maxCycles = 0;\n }\n\n list[key] = render(value, tmpl, castString, maxCycles);\n } else if ($.isPlainObject(value) || Array.isArray(value)) {\n _.each(value, iterate);\n }\n });\n\n delete tmpl.$data;\n\n return tmpl;\n }\n };\n});\n","mage/utils/compare.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n 'underscore',\n 'mage/utils/objects'\n], function (_, utils) {\n 'use strict';\n\n var result = [];\n\n /**\n * Checks if all of the provided arrays contains equal values.\n *\n * @param {(Boolean|Array)} [keepOrder=false]\n * @param {Array} target\n * @returns {Boolean}\n */\n function equalArrays(keepOrder, target) {\n var args = _.toArray(arguments),\n arrays;\n\n if (!Array.isArray(keepOrder)) {\n arrays = args.slice(2);\n } else {\n target = keepOrder;\n keepOrder = false;\n arrays = args.slice(1);\n }\n\n if (!arrays.length) {\n return true;\n }\n\n return arrays.every(function (array) {\n if (array === target) {\n return true;\n } else if (array.length !== target.length) {\n return false;\n } else if (!keepOrder) {\n return !_.difference(target, array).length;\n }\n\n return array.every(function (value, index) {\n return target[index] === value;\n });\n });\n }\n\n /**\n * Checks if two values are different.\n *\n * @param {*} a - First value.\n * @param {*} b - Second value.\n * @returns {Boolean}\n */\n function isDifferent(a, b) {\n var oldIsPrimitive = utils.isPrimitive(a);\n\n if (Array.isArray(a) && Array.isArray(b)) {\n return !equalArrays(true, a, b);\n }\n\n return oldIsPrimitive ? a !== b : true;\n }\n\n /**\n * @param {String} prefix\n * @param {String} part\n */\n function getPath(prefix, part) {\n return prefix ? prefix + '.' + part : part;\n }\n\n /**\n * Checks if object has own specified property.\n *\n * @param {*} obj - Value to be checked.\n * @param {String} key - Key of the property.\n * @returns {Boolean}\n */\n function hasOwn(obj, key) {\n return Object.prototype.hasOwnProperty.call(obj, key);\n }\n\n /**\n * @param {Array} changes\n */\n function getContainers(changes) {\n var containers = {},\n indexed = _.indexBy(changes, 'path');\n\n _.each(indexed, function (change, name) {\n var path;\n\n name.split('.').forEach(function (part) {\n path = getPath(path, part);\n\n if (path in indexed) {\n return;\n }\n\n (containers[path] = containers[path] || []).push(change);\n });\n });\n\n return containers;\n }\n\n /**\n * @param {String} path\n * @param {String} name\n * @param {String} type\n * @param {String} newValue\n * @param {String} oldValue\n */\n function addChange(path, name, type, newValue, oldValue) {\n var data;\n\n data = {\n path: path,\n name: name,\n type: type\n };\n\n if (type !== 'remove') {\n data.value = newValue;\n data.oldValue = oldValue;\n } else {\n data.oldValue = newValue;\n }\n\n result.push(data);\n }\n\n /**\n * @param {String} ns\n * @param {String} name\n * @param {String} type\n * @param {String} iterator\n * @param {String} placeholder\n */\n function setAll(ns, name, type, iterator, placeholder) {\n var key;\n\n if (arguments.length > 4) {\n type === 'add' ?\n addChange(ns, name, 'update', iterator, placeholder) :\n addChange(ns, name, 'update', placeholder, iterator);\n } else {\n addChange(ns, name, type, iterator);\n }\n\n if (!utils.isObject(iterator)) {\n return;\n }\n\n for (key in iterator) {\n if (hasOwn(iterator, key)) {\n setAll(getPath(ns, key), key, type, iterator[key]);\n }\n }\n }\n\n /*eslint-disable max-depth*/\n /**\n * @param {Object} old\n * @param {Object} current\n * @param {String} ns\n * @param {String} name\n */\n function compare(old, current, ns, name) {\n var key,\n oldIsObj = utils.isObject(old),\n newIsObj = utils.isObject(current);\n\n if (oldIsObj && newIsObj) {\n for (key in old) {\n if (hasOwn(old, key) && !hasOwn(current, key)) {\n setAll(getPath(ns, key), key, 'remove', old[key]);\n }\n }\n\n for (key in current) {\n if (hasOwn(current, key)) {\n hasOwn(old, key) ?\n compare(old[key], current[key], getPath(ns, key), key) :\n setAll(getPath(ns, key), key, 'add', current[key]);\n }\n }\n } else if (oldIsObj) {\n setAll(ns, name, 'remove', old, current);\n } else if (newIsObj) {\n setAll(ns, name, 'add', current, old);\n } else if (isDifferent(old, current)) {\n addChange(ns, name, 'update', current, old);\n }\n }\n\n /*eslint-enable max-depth*/\n\n return {\n\n /**\n *\n * @returns {Object}\n */\n compare: function () {\n var changes;\n\n compare.apply(null, arguments);\n\n changes = result.splice(0);\n\n return {\n containers: getContainers(changes),\n changes: changes,\n equal: !changes.length\n };\n },\n\n equalArrays: equalArrays\n };\n});\n","mage/utils/objects.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n 'ko',\n 'jquery',\n 'underscore',\n 'mage/utils/strings'\n], function (ko, $, _, stringUtils) {\n 'use strict';\n\n var primitives = [\n 'undefined',\n 'boolean',\n 'number',\n 'string'\n ];\n\n /**\n * Sets nested property of a specified object.\n * @private\n *\n * @param {Object} parent - Object to look inside for the properties.\n * @param {Array} path - Splitted path the property.\n * @param {*} value - Value of the last property in 'path' array.\n * returns {*} New value for the property.\n */\n function setNested(parent, path, value) {\n var last = path.pop(),\n len = path.length,\n pi = 0,\n part = path[pi];\n\n for (; pi < len; part = path[++pi]) {\n if (!_.isObject(parent[part])) {\n parent[part] = {};\n }\n\n parent = parent[part];\n }\n\n if (typeof parent[last] === 'function') {\n parent[last](value);\n } else {\n parent[last] = value;\n }\n\n return value;\n }\n\n /**\n * Retrieves value of a nested property.\n * @private\n *\n * @param {Object} parent - Object to look inside for the properties.\n * @param {Array} path - Splitted path the property.\n * @returns {*} Value of the property.\n */\n function getNested(parent, path) {\n var exists = true,\n len = path.length,\n pi = 0;\n\n for (; pi < len && exists; pi++) {\n parent = parent[path[pi]];\n\n if (typeof parent === 'undefined') {\n exists = false;\n }\n }\n\n if (exists) {\n if (ko.isObservable(parent)) {\n parent = parent();\n }\n\n return parent;\n }\n }\n\n /**\n * Removes property from a specified object.\n * @private\n *\n * @param {Object} parent - Object from which to remove property.\n * @param {Array} path - Splitted path to the property.\n */\n function removeNested(parent, path) {\n var field = path.pop();\n\n parent = getNested(parent, path);\n\n if (_.isObject(parent)) {\n delete parent[field];\n }\n }\n\n return {\n\n /**\n * Retrieves or defines objects' property by a composite path.\n *\n * @param {Object} data - Container for the properties specified in path.\n * @param {String} path - Objects' properties divided by dots.\n * @param {*} [value] - New value for the last property.\n * @returns {*} Returns value of the last property in chain.\n *\n * @example\n * utils.nested({}, 'one.two', 3);\n * => { one: {two: 3} }\n */\n nested: function (data, path, value) {\n var action = arguments.length > 2 ? setNested : getNested;\n\n path = path ? path.split('.') : [];\n\n return action(data, path, value);\n },\n\n /**\n * Removes nested property from an object.\n *\n * @param {Object} data - Data source.\n * @param {String} path - Path to the property e.g. 'one.two.three'\n */\n nestedRemove: function (data, path) {\n path = path.split('.');\n\n removeNested(data, path);\n },\n\n /**\n * Flattens objects' nested properties.\n *\n * @param {Object} data - Object to flatten.\n * @param {String} [separator='.'] - Objects' keys separator.\n * @returns {Object} Flattened object.\n *\n * @example Example with a default separator.\n * utils.flatten({one: { two: { three: 'value'} }});\n * => { 'one.two.three': 'value' };\n *\n * @example Example with a custom separator.\n * utils.flatten({one: { two: { three: 'value'} }}, '=>');\n * => {'one=>two=>three': 'value'};\n */\n flatten: function (data, separator, parent, result) {\n separator = separator || '.';\n result = result || {};\n\n if (!data) {\n return result;\n }\n\n // UnderscoreJS each breaks when an object has a length property so we use Object.keys\n _.each(Object.keys(data), function (name) {\n var node = data[name];\n\n if ({}.toString.call(node) === '[object Function]') {\n return;\n }\n\n if (parent) {\n name = parent + separator + name;\n }\n\n typeof node === 'object' ?\n this.flatten(node, separator, name, result) :\n result[name] = node;\n\n }, this);\n\n return result;\n },\n\n /**\n * Opposite operation of the 'flatten' method.\n *\n * @param {Object} data - Previously flattened object.\n * @param {String} [separator='.'] - Keys separator.\n * @returns {Object} Object with nested properties.\n *\n * @example Example using custom separator.\n * utils.unflatten({'one=>two': 'value'}, '=>');\n * => {\n * one: { two: 'value' }\n * };\n */\n unflatten: function (data, separator) {\n var result = {};\n\n separator = separator || '.';\n\n _.each(data, function (value, nodes) {\n nodes = nodes.split(separator);\n\n setNested(result, nodes, value);\n });\n\n return result;\n },\n\n /**\n * Same operation as 'flatten' method,\n * but returns objects' keys wrapped in '[]'.\n *\n * @param {Object} data - Object that should be serialized.\n * @returns {Object} Serialized data.\n *\n * @example\n * utils.serialize({one: { two: { three: 'value'} }});\n * => { 'one[two][three]': 'value' }\n */\n serialize: function (data) {\n var result = {};\n\n data = this.flatten(data);\n\n _.each(data, function (value, keys) {\n keys = stringUtils.serializeName(keys);\n value = _.isUndefined(value) ? '' : value;\n\n result[keys] = value;\n }, this);\n\n return result;\n },\n\n /**\n * Performs deep extend of specified objects.\n *\n * @returns {Object|Array} Extended object.\n */\n extend: function () {\n var args = _.toArray(arguments);\n\n args.unshift(true);\n\n return $.extend.apply($, args);\n },\n\n /**\n * Performs a deep clone of a specified object.\n *\n * @param {(Object|Array)} data - Data that should be copied.\n * @returns {Object|Array} Cloned object.\n */\n copy: function (data) {\n var result = data,\n isArray = Array.isArray(data),\n placeholder;\n\n if (this.isObject(data) || isArray) {\n placeholder = isArray ? [] : {};\n result = this.extend(placeholder, data);\n }\n\n return result;\n },\n\n /**\n * Performs a deep clone of a specified object.\n * Doesn't save links to original object.\n *\n * @param {*} original - Object to clone\n * @returns {*}\n */\n hardCopy: function (original) {\n if (original === null || typeof original !== 'object') {\n return original;\n }\n\n return JSON.parse(JSON.stringify(original));\n },\n\n /**\n * Removes specified nested properties from the target object.\n *\n * @param {Object} target - Object whose properties should be removed.\n * @param {(...String|Array|Object)} list - List that specifies properties to be removed.\n * @returns {Object} Modified object.\n *\n * @example Basic usage\n * var obj = {a: {b: 2}, c: 'a'};\n *\n * omit(obj, 'a.b');\n * => {'a.b': 2};\n * obj => {a: {}, c: 'a'};\n *\n * @example Various syntaxes that would return same result\n * omit(obj, ['a.b', 'c']);\n * omit(obj, 'a.b', 'c');\n * omit(obj, {'a.b': true, 'c': true});\n */\n omit: function (target, list) {\n var removed = {},\n ignored = list;\n\n if (this.isObject(list)) {\n ignored = [];\n\n _.each(list, function (value, key) {\n if (value) {\n ignored.push(key);\n }\n });\n } else if (_.isString(list)) {\n ignored = _.toArray(arguments).slice(1);\n }\n\n _.each(ignored, function (path) {\n var value = this.nested(target, path);\n\n if (!_.isUndefined(value)) {\n removed[path] = value;\n\n this.nestedRemove(target, path);\n }\n }, this);\n\n return removed;\n },\n\n /**\n * Checks if provided value is a plain object.\n *\n * @param {*} value - Value to be checked.\n * @returns {Boolean}\n */\n isObject: function (value) {\n var objProto = Object.prototype;\n\n return typeof value == 'object' ?\n objProto.toString.call(value) === '[object Object]' :\n false;\n },\n\n /**\n *\n * @param {*} value\n * @returns {Boolean}\n */\n isPrimitive: function (value) {\n return value === null || ~primitives.indexOf(typeof value);\n },\n\n /**\n * Iterates over obj props/array elems recursively, applying action to each one\n *\n * @param {Object|Array} data - Data to be iterated.\n * @param {Function} action - Callback to be called with each item as an argument.\n * @param {Number} [maxDepth=7] - Max recursion depth.\n */\n forEachRecursive: function (data, action, maxDepth) {\n maxDepth = typeof maxDepth === 'number' && !isNaN(maxDepth) ? maxDepth - 1 : 7;\n\n if (!_.isFunction(action) || _.isFunction(data) || maxDepth < 0) {\n return;\n }\n\n if (!_.isObject(data)) {\n action(data);\n\n return;\n }\n\n _.each(data, function (value) {\n this.forEachRecursive(value, action, maxDepth);\n }, this);\n\n action(data);\n },\n\n /**\n * Maps obj props/array elems recursively\n *\n * @param {Object|Array} data - Data to be iterated.\n * @param {Function} action - Callback to transform each item.\n * @param {Number} [maxDepth=7] - Max recursion depth.\n *\n * @returns {Object|Array}\n */\n mapRecursive: function (data, action, maxDepth) {\n var newData;\n\n maxDepth = typeof maxDepth === 'number' && !isNaN(maxDepth) ? maxDepth - 1 : 7;\n\n if (!_.isFunction(action) || _.isFunction(data) || maxDepth < 0) {\n return data;\n }\n\n if (!_.isObject(data)) {\n return action(data);\n }\n\n if (_.isArray(data)) {\n newData = _.map(data, function (item) {\n return this.mapRecursive(item, action, maxDepth);\n }, this);\n\n return action(newData);\n }\n\n newData = _.mapObject(data, function (val, key) {\n if (data.hasOwnProperty(key)) {\n return this.mapRecursive(val, action, maxDepth);\n }\n\n return val;\n }, this);\n\n return action(newData);\n },\n\n /**\n * Removes empty(in common sence) obj props/array elems\n *\n * @param {*} data - Data to be cleaned.\n * @returns {*}\n */\n removeEmptyValues: function (data) {\n if (!_.isObject(data)) {\n return data;\n }\n\n if (_.isArray(data)) {\n return data.filter(function (item) {\n return !this.isEmptyObj(item);\n }, this);\n }\n\n return _.omit(data, this.isEmptyObj.bind(this));\n },\n\n /**\n * Checks that argument of any type is empty in common sence:\n * empty string, string with spaces only, object without own props, empty array, null or undefined\n *\n * @param {*} val - Value to be checked.\n * @returns {Boolean}\n */\n isEmptyObj: function (val) {\n\n return _.isObject(val) && _.isEmpty(val) ||\n this.isEmpty(val) ||\n val && val.trim && this.isEmpty(val.trim());\n }\n };\n});\n\n","mage/utils/arrays.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'underscore',\n './strings'\n], function (_, utils) {\n 'use strict';\n\n /**\n * Defines index of an item in a specified container.\n *\n * @param {*} item - Item whose index should be defined.\n * @param {Array} container - Container upon which to perform search.\n * @returns {Number}\n */\n function getIndex(item, container) {\n var index = container.indexOf(item);\n\n if (~index) {\n return index;\n }\n\n return _.findIndex(container, function (value) {\n return value && value.name === item;\n });\n }\n\n return {\n /**\n * Facade method to remove/add value from/to array\n * without creating a new instance.\n *\n * @param {Array} arr - Array to be modified.\n * @param {*} value - Value to add/remove.\n * @param {Boolean} add - Flag that specfies operation.\n * @returns {Utils} Chainable.\n */\n toggle: function (arr, value, add) {\n return add ?\n this.add(arr, value) :\n this.remove(arr, value);\n },\n\n /**\n * Removes the incoming value from array in case\n * without creating a new instance of it.\n *\n * @param {Array} arr - Array to be modified.\n * @param {*} value - Value to be removed.\n * @returns {Utils} Chainable.\n */\n remove: function (arr, value) {\n var index = arr.indexOf(value);\n\n if (~index) {\n arr.splice(index, 1);\n }\n\n return this;\n },\n\n /**\n * Adds the incoming value to array if\n * it's not alredy present in there.\n *\n * @param {Array} arr - Array to be modifed.\n * @param {...*} arguments - Values to be added.\n * @returns {Utils} Chainable.\n */\n add: function (arr) {\n var values = _.toArray(arguments).slice(1);\n\n values.forEach(function (value) {\n if (!~arr.indexOf(value)) {\n arr.push(value);\n }\n });\n\n return this;\n },\n\n /**\n * Inserts specified item into container at a specified position.\n *\n * @param {*} item - Item to be inserted into container.\n * @param {Array} container - Container of items.\n * @param {*} [position=-1] - Position at which item should be inserted.\n * Position can represent:\n * - specific index in container\n * - item which might already be present in container\n * - structure with one of these properties: after, before\n * @returns {Boolean|*}\n * - true if element has changed its' position\n * - false if nothing has changed\n * - inserted value if it wasn't present in container\n */\n insert: function (item, container, position) {\n var currentIndex = getIndex(item, container),\n newIndex,\n target;\n\n if (typeof position === 'undefined') {\n position = -1;\n } else if (typeof position === 'string') {\n position = isNaN(+position) ? position : +position;\n }\n\n newIndex = position;\n\n if (~currentIndex) {\n target = container.splice(currentIndex, 1)[0];\n\n if (typeof item === 'string') {\n item = target;\n }\n }\n\n if (typeof position !== 'number') {\n target = position.after || position.before || position;\n\n newIndex = getIndex(target, container);\n\n if (~newIndex && (position.after || newIndex >= currentIndex)) {\n newIndex++;\n }\n }\n\n if (newIndex < 0) {\n newIndex += container.length + 1;\n }\n\n container[newIndex] ?\n container.splice(newIndex, 0, item) :\n container[newIndex] = item;\n\n return !~currentIndex ? item : currentIndex !== newIndex;\n },\n\n /**\n * @param {Array} elems\n * @param {Number} offset\n * @return {Number|*}\n */\n formatOffset: function (elems, offset) {\n if (utils.isEmpty(offset)) {\n offset = -1;\n }\n\n offset = +offset;\n\n if (offset < 0) {\n offset += elems.length + 1;\n }\n\n return offset;\n }\n };\n});\n","mage/utils/strings.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n 'underscore'\n], function (_) {\n 'use strict';\n\n var jsonRe = /^(?:\\{[\\w\\W]*\\}|\\[[\\w\\W]*\\])$/;\n\n return {\n\n /**\n * Attempts to convert string to one of the primitive values,\n * or to parse it as a valid json object.\n *\n * @param {String} str - String to be processed.\n * @returns {*}\n */\n castString: function (str) {\n try {\n str = str === 'true' ? true :\n str === 'false' ? false :\n str === 'null' ? null :\n +str + '' === str ? +str :\n jsonRe.test(str) ? JSON.parse(str) :\n str;\n } catch (e) {\n }\n\n return str;\n },\n\n /**\n * Splits string by separator if it's possible,\n * otherwise returns the incoming value.\n *\n * @param {(String|Array|*)} str - String to split.\n * @param {String} [separator=' '] - Seperator based on which to split the string.\n * @returns {Array|*} Splitted string or the incoming value.\n */\n stringToArray: function (str, separator) {\n separator = separator || ' ';\n\n return typeof str === 'string' ?\n str.split(separator) :\n str;\n },\n\n /**\n * Converts the incoming string which consists\n * of a specified delimiters into a format commonly used in form elements.\n *\n * @param {String} name - The incoming string.\n * @param {String} [separator='.']\n * @returns {String} Serialized string.\n *\n * @example\n * utils.serializeName('one.two.three');\n * => 'one[two][three]';\n */\n serializeName: function (name, separator) {\n var result;\n\n separator = separator || '.';\n name = name.split(separator);\n\n result = name.shift();\n\n name.forEach(function (part) {\n result += '[' + part + ']';\n });\n\n return result;\n },\n\n /**\n * Checks wether the incoming value is not empty,\n * e.g. not 'null' or 'undefined'\n *\n * @param {*} value - Value to check.\n * @returns {Boolean}\n */\n isEmpty: function (value) {\n return value === '' || _.isUndefined(value) || _.isNull(value);\n },\n\n /**\n * Adds 'prefix' to the 'part' value if it was provided.\n *\n * @param {String} prefix\n * @param {String} part\n * @returns {String}\n */\n fullPath: function (prefix, part) {\n return prefix ? prefix + '.' + part : part;\n },\n\n /**\n * Splits incoming string and returns its' part specified by offset.\n *\n * @param {String} parts\n * @param {Number} [offset]\n * @param {String} [delimiter=.]\n * @returns {String}\n */\n getPart: function (parts, offset, delimiter) {\n delimiter = delimiter || '.';\n parts = parts.split(delimiter);\n offset = this.formatOffset(parts, offset);\n\n parts.splice(offset, 1);\n\n return parts.join(delimiter) || '';\n },\n\n /**\n * Converts nameThroughCamelCase to name-through-minus\n *\n * @param {String} string\n * @returns {String}\n */\n camelCaseToMinus: function camelCaseToMinus(string) {\n return ('' + string)\n .split('')\n .map(function (symbol, index) {\n return index ?\n symbol.toUpperCase() === symbol ?\n '-' + symbol.toLowerCase() :\n symbol :\n symbol.toLowerCase();\n })\n .join('');\n },\n\n /**\n * Converts name-through-minus to nameThroughCamelCase\n *\n * @param {String} string\n * @returns {String}\n */\n minusToCamelCase: function minusToCamelCase(string) {\n return ('' + string)\n .split('-')\n .map(function (part, index) {\n return index ? part.charAt(0).toUpperCase() + part.slice(1) : part;\n })\n .join('');\n }\n };\n});\n","Magento_Backend/js/translate.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* eslint-disable strict */\ndefine([\n 'jquery',\n 'mage/mage'\n], function ($) {\n $.extend(true, $, {\n mage: {\n translate: (function () {\n /**\n * Key-value translations storage\n * @type {Object}\n * @private\n */\n var _data = {};\n\n /**\n * Add new translation (two string parameters) or several translations (object)\n */\n this.add = function () {\n if (arguments.length > 1) {\n _data[arguments[0]] = arguments[1];\n } else if (typeof arguments[0] === 'object') {\n $.extend(_data, arguments[0]);\n }\n };\n\n /**\n * Make a translation with parsing (to handle case when _data represents tuple)\n * @param {String} text\n * @return {String}\n */\n this.translate = function (text) {\n return typeof _data[text] === 'string' ? _data[text] : text;\n };\n\n return this;\n }())\n }\n });\n $.mage.__ = $.proxy($.mage.translate.translate, $.mage.translate);\n\n return $.mage.__;\n});\n","Magento_Backend/js/media-uploader.js":"/**\n *\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* eslint-disable no-undef */\n\n/**\n * @api\n */\n\n/*global byteConvert*/\ndefine([\n 'jquery',\n 'mage/template',\n 'Magento_Ui/js/modal/alert',\n 'Magento_Ui/js/form/element/file-uploader',\n 'mage/translate',\n 'jquery/uppy-core'\n], function ($, mageTemplate, alert, FileUploader) {\n 'use strict';\n\n let fileUploader = new FileUploader({\n dataScope: '',\n isMultipleFiles: true\n });\n\n fileUploader.initUploader();\n\n $.widget('mage.mediaUploader', {\n\n /**\n *\n * @private\n */\n _create: function () {\n let self = this,\n arrayFromObj = Array.from,\n progressTmpl = mageTemplate('[data-template=\"uploader\"]'),\n uploaderElement = '#fileUploader',\n targetElement = this.element.find('.fileinput-button.form-buttons')[0],\n uploadUrl = $(uploaderElement).attr('data-url'),\n fileId = null,\n allowedExt = ['jpeg', 'jpg', 'png', 'gif'],\n allowedResize = false,\n options = {\n proudlyDisplayPoweredByUppy: false,\n target: targetElement,\n hideUploadButton: true,\n hideRetryButton: true,\n hideCancelButton: true,\n inline: true,\n debug:true,\n showRemoveButtonAfterComplete: true,\n showProgressDetails: false,\n showSelectedFiles: false,\n hideProgressAfterFinish: true\n };\n\n $(document).on('click', uploaderElement ,function () {\n $(uploaderElement).closest('.fileinput-button.form-buttons')\n .find('.uppy-Dashboard-browse').trigger('click');\n });\n\n const uppy = new Uppy.Uppy({\n autoProceed: true,\n\n onBeforeFileAdded: (currentFile) => {\n let fileSize,\n tmpl;\n\n fileSize = typeof currentFile.size == 'undefined' ?\n $.mage.__('We could not detect a size.') :\n byteConvert(currentFile.size);\n\n // check if file is allowed to upload and resize\n allowedResize = $.inArray(currentFile.extension, allowedExt) !== -1;\n\n if (!allowedResize) {\n fileUploader.aggregateError(currentFile.name,\n $.mage.__('Disallowed file type.'));\n fileUploader.onLoadingStop();\n return false;\n }\n\n fileId = Math.random().toString(33).substr(2, 18);\n\n tmpl = progressTmpl({\n data: {\n name: currentFile.name,\n size: fileSize,\n id: fileId\n }\n });\n\n // code to allow duplicate files from same folder\n const modifiedFile = {\n ...currentFile,\n id: currentFile.id + '-' + fileId,\n tempFileId: fileId\n };\n\n $(tmpl).appendTo(self.element);\n return modifiedFile;\n },\n\n meta: {\n 'form_key': window.FORM_KEY,\n isAjax : true\n }\n });\n\n // initialize Uppy upload\n uppy.use(Uppy.Dashboard, options);\n\n // Resize Image as per configuration\n if (this.options.isResizeEnabled) {\n uppy.use(Uppy.Compressor, {\n maxWidth: this.options.maxWidth,\n maxHeight: this.options.maxHeight,\n quality: 0.92,\n beforeDraw() {\n if (!allowedResize) {\n this.abort();\n }\n }\n });\n }\n\n // drop area for file upload\n uppy.use(Uppy.DropTarget, {\n target: targetElement,\n onDragOver: () => {\n // override Array.from method of legacy-build.min.js file\n Array.from = null;\n },\n onDragLeave: () => {\n Array.from = arrayFromObj;\n }\n });\n\n // upload files on server\n uppy.use(Uppy.XHRUpload, {\n endpoint: uploadUrl,\n fieldName: 'image'\n });\n\n uppy.on('upload-success', (file, response) => {\n if (response.body && !response.body.error) {\n self.element.trigger('addItem', response.body);\n } else {\n fileUploader.aggregateError(file.name, response.body.error);\n }\n\n self.element.find('#' + file.tempFileId).remove();\n });\n\n uppy.on('upload-progress', (file, progress) => {\n let progressWidth = parseInt(progress.bytesUploaded / progress.bytesTotal * 100, 10),\n progressSelector = '#' + file.tempFileId + ' .progressbar-container .progressbar';\n\n self.element.find(progressSelector).css('width', progressWidth + '%');\n });\n\n uppy.on('upload-error', (error, file) => {\n let progressSelector = '#' + file.tempFileId;\n\n self.element.find(progressSelector).removeClass('upload-progress').addClass('upload-failure')\n .delay(2000)\n .hide('highlight')\n .remove();\n });\n\n uppy.on('complete', () => {\n fileUploader.uploaderConfig.stop();\n $(window).trigger('reload.MediaGallery');\n Array.from = arrayFromObj;\n });\n\n }\n });\n\n return $.mage.mediaUploader;\n});\n","Magento_Backend/js/delete-with-confirm.js":"/**\n *\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n 'jquery',\n 'Magento_Backend/js/validate-store'\n], function ($, validateStore) {\n 'use strict';\n\n $.widget('mage.deleteWithConfirm', validateStore, {});\n\n return $.mage.deleteWithConfirm;\n});\n","Magento_Backend/js/save-with-confirm.js":"/**\n *\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n 'jquery',\n 'Magento_Backend/js/validate-store'\n], function ($, validateStore) {\n 'use strict';\n\n $.widget('mage.saveWithConfirm', validateStore, {\n\n /**\n * Check is it need to show confirmation popup\n *\n * @returns {Boolean}\n */\n _needConfirm: function () {\n\n var storeData = this.settings.storeData,\n\n /* edit store view*/\n storeViewEdit = $('[name=\"store[store_id]\"]').length,\n groupId = $('[name=\"store[group_id]\"]').val(),\n isNewStoreView = !$('[name=\"store[store_id]\"]').val(),\n\n /* edit store */\n storeEdit = $('[name=\"group[group_id]\"]').length,\n storeId = $('[name=\"group[group_id]\"]').val(),\n rootCategoryId = $('[name=\"group[root_category_id]\"]').val(),\n defaultStoreView = $('[name=\"group[default_store_id]\"]').val(),\n\n /* edit website */\n websiteEdit = $('[name=\"website[website_id]\"]').length,\n defaultStore = $('[name=\"website[default_group_id]\"]').val(),\n\n /* conditions */\n storeViewUpdated = storeViewEdit && (isNewStoreView || storeData['group_id'] !== groupId),\n storeUpdated = storeEdit && storeId &&\n (rootCategoryId !== null && storeData['root_category_id'] !== rootCategoryId ||\n defaultStoreView !== null && storeData['default_store_id'] !== defaultStoreView),\n websiteUpdated = websiteEdit && defaultStore !== null && storeData['default_group_id'] !== defaultStore;\n\n return storeViewUpdated || storeUpdated || websiteUpdated;\n }\n });\n\n return $.mage.saveWithConfirm;\n});\n","Magento_Backend/js/validate-store.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n 'jquery',\n 'jquery/ui',\n 'mage/dataPost',\n 'mage/backend/validation',\n 'Magento_Ui/js/modal/confirm'\n], function ($, jqueryUi, dataPost, validation, modalConfirm) {\n 'use strict';\n\n $.widget('mage.storeValidation', {\n\n /**\n * Validation creation\n * @protected\n */\n _create: function () {\n var form = this.element[0],\n validator = $.data(form, 'validator');\n\n if (validator && validator.settings) {\n validator.settings.submitHandler = this._saveHandler;\n validator.settings.confirmCallback = this._needConfirm;\n $.extend(validator.settings, this.options);\n $.data(form, 'validator', validator);\n }\n },\n\n /**\n * Check is it need to show confirmation popup\n *\n * @returns {Boolean}\n */\n _needConfirm: function () {\n return true;\n },\n\n /**\n * Save form with confirmation if needed\n *\n * @param {Object} form\n * @private\n */\n _saveHandler: function (form) {\n var formData = {},\n requestData = {},\n options = $.data(form, 'validator').settings;\n\n if ($(form).validation('isValid')) {\n $.each($(form).serializeArray(), function () {\n formData[this.name] = this.value || '';\n });\n requestData = {\n action: $(form).attr('action'),\n data: formData\n };\n\n if (options.confirmCallback.call(this)) {\n modalConfirm({\n title: $.mage.__('Warning message'),\n content: $.mage.__('This operation can take a long time'),\n actions: {\n /**\n * 'Confirm' action handler.\n */\n confirm: function () {\n $('body').trigger('processStart');\n dataPost().postData(requestData);\n }\n }\n });\n } else {\n dataPost().postData(requestData);\n }\n }\n }\n });\n\n return $.mage.storeValidation;\n});\n","Magento_Backend/js/store-switcher.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'jquery'\n], function ($) {\n 'use strict';\n\n /**\n * @param {Object} storeSwitchConfig\n */\n return function (storeSwitchConfig) {\n var scopeSwitcherHandler;\n\n (function () {\n var storesList = $('[data-role=stores-list]');\n\n storesList.on('click', '[data-value]', function (event) {\n var val = $(event.target).data('value'),\n role = $(event.target).data('role'),\n switcher = $('[data-role=' + role + ']');\n\n event.preventDefault();\n\n if (!switcher.val() || val !== switcher.val()) {\n\n /* Set the value & trigger event */\n switcher.val(val).trigger('change');\n }\n });\n })($);\n\n /**\n * Switch store scope\n *\n * @param {Object} obj\n * @return void\n */\n function switchScope(obj) {\n var switcher = $(obj),\n scopeId = switcher.val(),\n scopeParams = '',\n switcherParams = {};\n\n if (scopeId) {\n scopeParams = switcher.data('param') + '/' + scopeId + '/';\n }\n\n if (obj.switchParams) {\n scopeParams += obj.switchParams;\n }\n\n /**\n * Reload function for switcher\n */\n function reload() {\n var url;\n\n if (!storeSwitchConfig.isUsingIframe) {\n\n if (storeSwitchConfig.switchUrl && storeSwitchConfig.switchUrl.length > 0) {\n url = storeSwitchConfig.switchUrl + scopeParams;\n\n /* eslint-disable no-undef */\n setLocation(url);\n }\n\n } else {\n $('#preview_selected_store').val(scopeId);\n $('#preview_form').trigger('submit');\n\n $('.store-switcher .dropdown-menu li a').each(function () {\n var $this = $(this);\n\n if ($this.data('role') === 'store-view-id' && $this.data('value') === scopeId) {\n $('#store-change-button').html($this.text());\n }\n });\n\n $('#store-change-button').trigger('click');\n }\n }\n\n if (typeof scopeSwitcherHandler !== 'undefined') {\n switcherParams = {\n scopeId: scopeId,\n scopeParams: scopeParams,\n useConfirm: storeSwitchConfig.useConfirm\n };\n\n scopeSwitcherHandler(switcherParams);\n } else if (storeSwitchConfig.useConfirm) {\n require([\n 'Magento_Ui/js/modal/confirm',\n 'mage/translate'\n ], function (confirm, $t) {\n confirm({\n content: $t('Please confirm scope switching. All data that hasn\\'t been saved will be lost.'),\n actions: {\n\n /**\n * Confirm action\n */\n confirm: function () {\n reload();\n },\n\n /**\n * Cancel action\n */\n cancel: function () {\n obj.value = storeSwitchConfig.storeId ? storeSwitchConfig.storeId : '';\n }\n }\n });\n });\n } else {\n reload();\n }\n }\n\n window.scopeSwitcherHandler = scopeSwitcherHandler;\n window.switchScope = switchScope;\n };\n});\n","Magento_Backend/js/dashboard/chart.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/*global FORM_KEY*/\ndefine([\n 'jquery',\n 'chartJs',\n 'jquery-ui-modules/widget',\n 'chartjs/chartjs-adapter-moment',\n 'chartjs/es6-shim.min',\n 'moment'\n], function ($, Chart) {\n 'use strict';\n\n $.widget('mage.dashboardChart', {\n options: {\n updateUrl: '',\n responsive: true,\n maintainAspectRatio: false,\n periodSelect: null,\n periodUnits: [],\n precision: 0,\n type: ''\n },\n chart: null,\n\n /**\n * @private\n */\n _create: function () {\n this.createChart();\n\n if (this.options.periodSelect) {\n $(document).on('change', this.options.periodSelect, this.refreshChartData.bind(this));\n\n this.period = $(this.options.periodSelect).val();\n }\n },\n\n /**\n * @public\n */\n createChart: function () {\n this.chart = new Chart(this.element, this.getChartSettings());\n this.refreshChartData();\n },\n\n /**\n * @public\n */\n refreshChartData: function () {\n var data = {\n 'form_key': FORM_KEY\n };\n\n if (this.options.periodSelect) {\n this.period = data.period = $(this.options.periodSelect).val();\n }\n\n $.ajax({\n url: this.options.updateUrl,\n showLoader: true,\n data: data,\n dataType: 'json',\n type: 'POST',\n success: this.updateChart.bind(this)\n });\n },\n\n /**\n * @public\n * @param {Object} response\n */\n updateChart: function (response) {\n $(this.element).toggle(response.data.length > 0);\n $(this.element).next('.dashboard-diagram-nodata').toggle(response.data.length === 0);\n\n this.chart.options.scales.xAxis.time.unit = this.options.periodUnits[this.period] ?\n this.options.periodUnits[this.period] : 'hour';\n this.chart.data.datasets[0].data = response.data;\n this.chart.data.datasets[0].label = response.label;\n this.chart.update();\n },\n\n /**\n * @returns {Object} chart object configuration\n */\n getChartSettings: function () {\n return {\n type: 'bar',\n data: {\n datasets: [{\n yAxisID: 'yAxis',\n xAxisID: 'xAxis',\n data: [],\n backgroundColor: '#f1d4b3',\n borderColor: '#eb5202',\n borderWidth: 1\n }]\n },\n options: {\n legend: {\n onClick: this.handleChartLegendClick,\n position: 'bottom'\n },\n scales: {\n xAxis: {\n offset: true,\n type: 'time',\n ticks: {\n source: 'data'\n }\n },\n yAxis: {\n ticks: {\n beginAtZero: true,\n precision: this.options.precision\n }\n }\n }\n }\n };\n },\n\n /**\n * @public\n */\n handleChartLegendClick: function () {\n // don't hide dataset on clicking into legend item\n }\n });\n\n return $.mage.dashboardChart;\n});\n","Magento_Backend/js/dashboard/totals.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/*global FORM_KEY*/\ndefine([\n 'jquery',\n 'jquery-ui-modules/widget'\n], function ($) {\n 'use strict';\n\n $.widget('mage.dashboardTotals', {\n options: {\n updateUrl: '',\n periodSelect: null\n },\n elementId: null,\n\n /**\n * @private\n */\n _create: function () {\n this.elementId = $(this.element).attr('id');\n\n if (this.options.periodSelect) {\n $(document).on('change', this.options.periodSelect, $.proxy(function () {\n this.refreshTotals();\n }, this));\n }\n },\n\n /**\n * @public\n */\n refreshTotals: function () {\n var periodParam = '';\n\n if (this.options.periodSelect && $(this.options.periodSelect).val()) {\n periodParam = 'period/' + $(this.options.periodSelect).val() + '/';\n }\n\n $.ajax({\n url: this.options.updateUrl + periodParam,\n showLoader: true,\n data: {\n 'form_key': FORM_KEY\n },\n dataType: 'html',\n type: 'POST',\n success: $.proxy(function (response) {\n $('#' + this.elementId).replaceWith(response);\n }, this)\n });\n }\n });\n\n return $.mage.dashboardTotals;\n});\n","Magento_Backend/js/bootstrap/editor.js":"/**\n *\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\nrequire([\n 'Magento_Variable/variables',\n 'mage/adminhtml/browser'\n]);\n"}
}});