require.config({"config": { "jsbuild":{"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*/\n(function (factory) {\n 'use strict';\n\n if (typeof define === 'function' && define.amd) {\n define([\n 'jquery',\n 'jquery/ui',\n 'jquery/jquery-ui-timepicker-addon'\n ], factory);\n } else {\n factory(window.jQuery);\n }\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 '\" href=\"#\">' + 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 .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\n/* eslint-disable strict */\n(function (factory) {\n if (typeof define === 'function' && define.amd) {\n define([\n 'jquery',\n 'mage/mage'\n ], factory);\n } else {\n factory(jQuery);\n }\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 _data[text] ? _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","mage/ie-class-fixer.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* eslint-disable strict */\n(function () {\n var userAgent = navigator.userAgent, // user agent identifier\n html = document.documentElement, // html tag\n gap = ''; // gap between classes\n\n if (html.className) { // check if neighbour class exist in html tag\n gap = ' ';\n } // end if\n\n if (userAgent.match(/Trident.*rv[ :]*11\\./)) { // Special case for IE11\n html.className += gap + 'ie11';\n } // end if\n\n})();\n","mage/template.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n(function (root, factory) {\n 'use strict';\n\n if (typeof define === 'function' && define.amd) {\n define([\n 'underscore'\n ], factory);\n } else {\n root.mageTemplate = factory(root._);\n }\n}(this, 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/polyfill.js":"try {\n if (!window.localStorage || !window.sessionStorage) {\n throw new Error();\n }\n\n localStorage.setItem('storage_test', 1);\n localStorage.removeItem('storage_test');\n} catch (e) {\n (function () {\n 'use strict';\n\n /**\n * Returns a storage object to shim local or sessionStorage\n * @param {String} type - either 'local' or 'session'\n */\n var 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 document.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 = document.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 (!window.name) {\n window.name = new Date().getTime();\n }\n\n return 'sessionStorage' + window.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 window.localStorage.prototype = window.localStorage = new Storage('local');\n window.sessionStorage.prototype = window.sessionStorage = new Storage('session');\n })();\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 */\n(function (root, factory) {\n 'use strict';\n\n if (typeof define === 'function' && define.amd) {\n define([\n 'jquery',\n 'mage/template',\n 'jquery/ui'\n ], factory);\n } else {\n factory(root.jQuery, root.mageTemplate);\n }\n}(this, 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/dropdown_old.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 var ESC_KEY_CODE = '27';\n\n $(document)\n .on('click.dropdown', function (event) {\n if (!$(event.target).is('[data-toggle=dropdown].active, ' +\n '[data-toggle=dropdown].active *, ' +\n '[data-toggle=dropdown].active + .dropdown-menu, ' +\n '[data-toggle=dropdown].active + .dropdown-menu *,' +\n '[data-toggle=dropdown].active + [data-target=\"dropdown\"],' +\n '[data-toggle=dropdown].active + [data-target=\"dropdown\"] *')\n ) {\n $('[data-toggle=dropdown].active').trigger('close.dropdown');\n }\n })\n .on('keyup.dropdown', function (event) {\n if (event.keyCode == ESC_KEY_CODE) { //eslint-disable-line eqeqeq\n $('[data-toggle=dropdown].active').trigger('close.dropdown');\n }\n });\n\n /**\n * @param {Object} options\n */\n $.fn.dropdown = function (options) {\n options = $.extend({\n parent: null,\n btnArrow: '.arrow',\n activeClass: 'active'\n }, options);\n\n return this.each(function () {\n var elem = $(this);\n\n elem.off('open.dropdown, close.dropdown, click.dropdown');\n elem.on('open.dropdown', function () {\n elem\n .addClass(options.activeClass)\n .parent()\n .addClass(options.activeClass);\n elem.find(options.btnArrow).text('\\u25b2'); // arrow up\n });\n\n elem.on('close.dropdown', function () {\n elem\n .removeClass(options.activeClass)\n .parent()\n .removeClass(options.activeClass);\n elem.find(options.btnArrow).text('\\u25bc'); // arrow down\n });\n\n elem.on('click.dropdown', function () {\n var isActive = elem.hasClass('active');\n\n $('[data-toggle=dropdown].active').trigger('close.dropdown');\n elem.trigger(isActive ? 'close.dropdown' : 'open.dropdown');\n\n return false;\n });\n });\n };\n\n return function (data, el) {\n $(el).dropdown(data);\n };\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',\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) {\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 this.contents = this.element.find(this.options.content);\n\n this.collapsibles = this.element.find(this.options.collapsibleElement);\n\n this.collapsibles\n .attr('role', 'presentation')\n .parent()\n .attr('role', 'tablist');\n\n this.headers = this.element.find(this.options.header);\n\n if (this.headers.length === 0) {\n this.headers = this.collapsibles;\n }\n this.triggers = this.element.find(this.options.trigger);\n\n if (this.triggers.length === 0) {\n this.triggers = this.headers;\n }\n this._callCollapsible();\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 ($.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/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/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\n if (typeof fn === 'object') {\n fn = fn[component].bind(fn);\n }\n\n if (_.isFunction(fn)) {\n fn(config, el);\n } else if ($(el)[component]) {\n $(el)[component](config);\n }\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/app/config.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 */\n/* eslint-disable strict */\ndefine([], function () {\n return {\n /**\n * Get base url.\n */\n getBaseUrl: function () {\n return this.values.baseUrl;\n },\n\n /**\n * Get form key.\n */\n getFormKey: function () {\n return this.values.formKey;\n }\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/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 XMLHttpRequest, 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/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 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 > _.filter(module.depMaps, isRejected).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/adminhtml/accordion.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* global varienAccordion, varienLoader, Cookie */\n/* eslint-disable strict */\ndefine([\n 'prototype'\n], function () {\n window.varienAccordion = new Class.create(); //eslint-disable-line\n varienAccordion.prototype = {\n /**\n * @param {*} containerId\n * @param {*} activeOnlyOne\n */\n initialize: function (containerId, activeOnlyOne) {\n var links, i;\n\n this.containerId = containerId;\n this.activeOnlyOne = activeOnlyOne || false;\n this.container = $(this.containerId);\n this.items = $$('#' + this.containerId + ' dt');\n this.loader = new varienLoader(true); //jscs:ignore requireCapitalizedConstructors\n\n links = $$('#' + this.containerId + ' dt a');\n\n for (i in links) {\n if (links[i].href) {\n Event.observe(links[i], 'click', this.clickItem.bind(this));\n this.items[i].dd = this.items[i].next('dd');\n this.items[i].link = links[i];\n }\n }\n\n this.initFromCookie();\n },\n\n /**\n * Init from cookie.\n */\n initFromCookie: function () {\n var activeItemId, visibility;\n\n if (this.activeOnlyOne &&\n (activeItemId = Cookie.read(this.cookiePrefix() + 'active-item')) !== null) {\n this.hideAllItems();\n this.showItem(this.getItemById(activeItemId));\n } else if (!this.activeOnlyOne) {\n this.items.each(function (item) {\n if ((visibility = Cookie.read(this.cookiePrefix() + item.id)) !== null) {\n if (visibility == 0) { //eslint-disable-line eqeqeq\n this.hideItem(item);\n } else {\n this.showItem(item);\n }\n }\n }.bind(this));\n }\n },\n\n /**\n * @return {String}\n */\n cookiePrefix: function () {\n return 'accordion-' + this.containerId + '-';\n },\n\n /**\n * @param {*} itemId\n * @return {*}\n */\n getItemById: function (itemId) {\n var result = null;\n\n this.items.each(function (item) {\n if (item.id == itemId) { //eslint-disable-line\n result = item;\n throw $break;\n }\n });\n\n return result;\n },\n\n /**\n * @param {*} event\n */\n clickItem: function (event) {\n var item = Event.findElement(event, 'dt');\n\n if (this.activeOnlyOne) {\n this.hideAllItems();\n this.showItem(item);\n Cookie.write(this.cookiePrefix() + 'active-item', item.id, 30 * 24 * 60 * 60);\n } else {\n if (this.isItemVisible(item)) { //eslint-disable-line no-lonely-if\n this.hideItem(item);\n Cookie.write(this.cookiePrefix() + item.id, 0, 30 * 24 * 60 * 60);\n } else {\n this.showItem(item);\n Cookie.write(this.cookiePrefix() + item.id, 1, 30 * 24 * 60 * 60);\n }\n }\n Event.stop(event);\n },\n\n /**\n * @param {Object} item\n */\n showItem: function (item) {\n if (item && item.link) {\n if (item.link.href) {\n this.loadContent(item);\n }\n\n Element.addClassName(item, 'open');\n Element.addClassName(item.dd, 'open');\n }\n },\n\n /**\n * @param {Object} item\n */\n hideItem: function (item) {\n Element.removeClassName(item, 'open');\n Element.removeClassName(item.dd, 'open');\n },\n\n /**\n * @param {*} item\n * @return {*}\n */\n isItemVisible: function (item) {\n return Element.hasClassName(item, 'open');\n },\n\n /**\n * @param {*} item\n */\n loadContent: function (item) {\n if (item.link.href.indexOf('#') == item.link.href.length - 1) { //eslint-disable-line eqeqeq\n return;\n }\n\n if (Element.hasClassName(item.link, 'ajax')) {\n this.loadingItem = item;\n this.loader.load(item.link.href, {\n updaterId: this.loadingItem.dd.id\n }, this.setItemContent.bind(this));\n\n return;\n }\n location.href = item.link.href;\n },\n\n /**\n * @param {Object} content\n */\n setItemContent: function (content) {\n if (content.isJSON) {\n return;\n }\n this.loadingItem.dd.innerHTML = content;\n },\n\n /**\n * Hide all items\n */\n hideAllItems: function () {\n var i;\n\n for (i in this.items) {\n if (this.items[i].id) {\n Element.removeClassName(this.items[i], 'open');\n Element.removeClassName(this.items[i].dd, 'open');\n }\n }\n }\n };\n});\n","mage/adminhtml/grid.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n// also depends on a mage/adminhtml/tools.js for Base64 encoding\n/* global varienGrid, setLocation, varienGlobalEvents, FORM_KEY,\n BASE_URL, Base64, varienGridMassaction, varienStringArray, serializerController\n*/\n/* eslint-disable strict */\ndefine([\n 'jquery',\n 'mage/template',\n 'Magento_Ui/js/modal/alert',\n 'Magento_Ui/js/modal/confirm',\n 'mage/mage',\n 'prototype',\n 'mage/adminhtml/form',\n 'mage/adminhtml/events'\n], function (jQuery, mageTemplate, alert, confirm) {\n /**\n * @param {*} grid\n * @param {*} event\n */\n function openGridRow(grid, event) {\n var element = Event.findElement(event, 'tr');\n\n if (['a', 'input', 'select', 'option'].indexOf(Event.element(event).tagName.toLowerCase()) !== -1) {\n return;\n }\n\n if (element.title) {\n setLocation(element.title);\n }\n }\n window.openGridRow = openGridRow;\n\n window.varienGrid = new Class.create();\n\n varienGrid.prototype = {\n /**\n * @param {String} containerId\n * @param {String} url\n * @param {*} pageVar\n * @param {*} sortVar\n * @param {*} dirVar\n * @param {*} filterVar\n */\n initialize: function (containerId, url, pageVar, sortVar, dirVar, filterVar) {\n this.containerId = containerId;\n jQuery('#' + containerId).data('gridObject', this);\n this.url = url;\n this.pageVar = pageVar || false;\n this.sortVar = sortVar || false;\n this.dirVar = dirVar || false;\n this.filterVar = filterVar || false;\n this.tableSufix = '_table';\n this.useAjax = false;\n this.rowClickCallback = false;\n this.checkboxCheckCallback = false;\n this.preInitCallback = false;\n this.initCallback = false;\n this.initRowCallback = false;\n this.doFilterCallback = false;\n this.sortableUpdateCallback = false;\n\n this.reloadParams = false;\n\n this.trOnMouseOver = this.rowMouseOver.bindAsEventListener(this);\n this.trOnMouseOut = this.rowMouseOut.bindAsEventListener(this);\n this.trOnClick = this.rowMouseClick.bindAsEventListener(this);\n this.trOnDblClick = this.rowMouseDblClick.bindAsEventListener(this);\n this.trOnKeyPress = this.keyPress.bindAsEventListener(this);\n\n this.thLinkOnClick = this.doSort.bindAsEventListener(this);\n this.initGrid();\n },\n\n /**\n * Init grid.\n */\n initGrid: function () {\n var row, columns, col;\n\n if (this.preInitCallback) {\n this.preInitCallback(this);\n }\n\n if ($(this.containerId + this.tableSufix)) {\n this.rows = $$('#' + this.containerId + this.tableSufix + ' tbody tr');\n\n for (row = 0; row < this.rows.length; row++) {\n if (row % 2 == 0) { //eslint-disable-line eqeqeq, max-depth\n Element.addClassName(this.rows[row], 'even');\n }\n\n Event.observe(this.rows[row], 'mouseover', this.trOnMouseOver);\n Event.observe(this.rows[row], 'mouseout', this.trOnMouseOut);\n Event.observe(this.rows[row], 'click', this.trOnClick);\n Event.observe(this.rows[row], 'dblclick', this.trOnDblClick);\n }\n }\n\n if (this.sortVar && this.dirVar) {\n columns = $$('#' + this.containerId + this.tableSufix + ' thead [data-sort]');\n\n for (col = 0; col < columns.length; col++) {\n Event.observe(columns[col], 'click', this.thLinkOnClick);\n }\n }\n this.bindFilterFields();\n this.bindFieldsChange();\n\n if (this.initCallback) {\n try {\n this.initCallback(this);\n }\n catch (e) {\n if (window.console) { //eslint-disable-line max-depth\n console.log(e);\n }\n }\n }\n jQuery('#' + this.containerId).trigger('gridinit', this);\n },\n\n /**\n * Init grid ajax.\n */\n initGridAjax: function () {\n this.initGrid();\n this.initGridRows();\n },\n\n /**\n * Init grid rows.\n */\n initGridRows: function () {\n var row;\n\n if (this.initRowCallback) {\n for (row = 0; row < this.rows.length; row++) {\n try { //eslint-disable-line max-depth\n this.initRowCallback(this, this.rows[row]);\n } catch (e) {\n if (window.console) { //eslint-disable-line max-depth\n console.log(e);\n }\n }\n }\n }\n },\n\n /**\n * @param {*} event\n */\n rowMouseOver: function (event) {\n var element = Event.findElement(event, 'tr');\n\n if (!element.title) {\n return;\n }\n\n Element.addClassName(element, 'on-mouse');\n\n if (!Element.hasClassName('_clickable') && (this.rowClickCallback !== openGridRow || element.title)) {\n if (element.title) {\n Element.addClassName(element, '_clickable');\n }\n }\n },\n\n /**\n * @param {*} event\n */\n rowMouseOut: function (event) {\n var element = Event.findElement(event, 'tr');\n\n Element.removeClassName(element, 'on-mouse');\n },\n\n /**\n * @param {*} event\n */\n rowMouseClick: function (event) {\n if (this.rowClickCallback) {\n try {\n this.rowClickCallback(this, event);\n }\n catch (e) {\n }\n }\n varienGlobalEvents.fireEvent('gridRowClick', event);\n },\n\n /**\n * @param {*} event\n */\n rowMouseDblClick: function (event) {\n varienGlobalEvents.fireEvent('gridRowDblClick', event);\n },\n\n /**\n * Key press.\n */\n keyPress: function () {},\n\n /**\n * @param {*} event\n * @return {Boolean}\n */\n doSort: function (event) {\n var element = Event.findElement(event, 'th');\n\n if (element.readAttribute('data-sort') && element.readAttribute('data-direction')) {\n this.addVarToUrl(this.sortVar, element.readAttribute('data-sort'));\n this.addVarToUrl(this.dirVar, element.readAttribute('data-direction'));\n this.reload(this.url);\n }\n Event.stop(event);\n\n return false;\n },\n\n /**\n * @param {Object} element\n */\n loadByElement: function (element) {\n if (element && element.name) {\n this.reload(this.addVarToUrl(element.name, element.value));\n }\n },\n\n /**\n * @param {*} data\n * @param {*} textStatus\n * @param {*} transport\n * @private\n */\n _onAjaxSeccess: function (data, textStatus, transport) {\n var responseText, response, divId;\n\n /* eslint-disable max-depth */\n try {\n responseText = transport.responseText;\n\n if (transport.responseText.isJSON()) {\n response = transport.responseText.evalJSON();\n\n if (response.error) {\n alert({\n content: response.message\n });\n }\n\n if (response.ajaxExpired && response.ajaxRedirect) {\n setLocation(response.ajaxRedirect);\n }\n } else {\n\n /*eslint-disable max-len*/\n /**\n * For IE <= 7.\n * If there are two elements, and first has name, that equals id of second.\n * In this case, IE will choose one that is above\n *\n * @see https://prototype.lighthouseapp.com/projects/8886/tickets/994-id-selector-finds-elements-by-name-attribute-in-ie7\n */\n\n /*eslint-enable max-len*/\n divId = $(this.containerId);\n\n if (divId.id == this.containerId) { //eslint-disable-line eqeqeq\n divId.update(responseText);\n } else {\n $$('div[id=\"' + this.containerId + '\"]')[0].update(responseText);\n }\n }\n } catch (e) {\n divId = $(this.containerId);\n\n if (divId.id == this.containerId) { //eslint-disable-line eqeqeq\n divId.update(responseText);\n } else {\n $$('div[id=\"' + this.containerId + '\"]')[0].update(responseText);\n }\n }\n\n /* eslint-enable max-depth */\n jQuery('#' + this.containerId).trigger('contentUpdated');\n },\n\n /**\n * @param {*} url\n * @param {Function} onSuccessCallback\n * @return {*}\n */\n reload: function (url, onSuccessCallback) {\n var ajaxSettings, ajaxRequest;\n\n this.reloadParams = this.reloadParams || {};\n this.reloadParams['form_key'] = FORM_KEY;\n url = url || this.url;\n\n if (this.useAjax) {\n ajaxSettings = {\n url: url + (url.match(new RegExp('\\\\?')) ? '&ajax=true' : '?ajax=true'),\n showLoader: true,\n method: 'post',\n context: jQuery('#' + this.containerId),\n data: this.reloadParams,\n error: this._processFailure.bind(this),\n complete: this.initGridAjax.bind(this),\n dataType: 'html',\n\n /**\n * Success callback.\n */\n success: function (data, textStatus, transport) {\n this._onAjaxSeccess(data, textStatus, transport);\n\n if (onSuccessCallback && typeof onSuccessCallback === 'function') {\n // execute the callback, passing parameters as necessary\n onSuccessCallback();\n }\n }.bind(this)\n };\n jQuery('#' + this.containerId).trigger('gridajaxsettings', ajaxSettings);\n ajaxRequest = jQuery.ajax(ajaxSettings);\n jQuery('#' + this.containerId).trigger('gridajax', ajaxRequest);\n\n return ajaxRequest;\n }\n\n if (this.reloadParams) {\n $H(this.reloadParams).each(function (pair) {\n url = this.addVarToUrl(pair.key, pair.value);\n }.bind(this));\n }\n location.href = url;\n },\n\n /**\n * @private\n */\n _processFailure: function () {\n location.href = BASE_URL;\n },\n\n /**\n * @param {*} url\n * @param {*} varName\n * @param {*} varValue\n * @return {String|*}\n * @private\n */\n _addVarToUrl: function (url, varName, varValue) {\n var re = new RegExp('\\/(' + varName + '\\/.*?\\/)'),\n parts = url.split(new RegExp('\\\\?'));\n\n url = parts[0].replace(re, '/');\n url += varName + '/' + varValue + '/';\n\n if (parts.size() > 1) {\n url += '?' + parts[1];\n }\n\n return url;\n },\n\n /**\n * @param {*} varName\n * @param {*} varValue\n * @return {*|String}\n */\n addVarToUrl: function (varName, varValue) {\n this.url = this._addVarToUrl(this.url, varName, varValue);\n\n return this.url;\n },\n\n /**\n * Do export.\n */\n doExport: function () {\n var exportUrl;\n\n if ($(this.containerId + '_export')) {\n exportUrl = $(this.containerId + '_export').value;\n\n if (this.massaction && this.massaction.checkedString) {\n exportUrl = this._addVarToUrl(\n exportUrl,\n this.massaction.formFieldNameInternal,\n this.massaction.checkedString\n );\n }\n location.href = exportUrl;\n }\n },\n\n /**\n * Bind filter fields.\n */\n bindFilterFields: function () {\n var filters = $$(\n '#' + this.containerId + ' [data-role=\"filter-form\"] input',\n '#' + this.containerId + ' [data-role=\"filter-form\"] select'\n ),\n i;\n\n for (i = 0; i < filters.length; i++) {\n Event.observe(filters[i], 'keypress', this.filterKeyPress.bind(this));\n }\n },\n\n /**\n * Bind field change.\n */\n bindFieldsChange: function () {\n var dataElements, i;\n\n if (!$(this.containerId)) {\n return;\n }\n //var dataElements = $(this.containerId+this.tableSufix).down('.data tbody').select('input', 'select');\n dataElements = $(this.containerId + this.tableSufix).down('tbody').select('input', 'select');\n\n for (i = 0; i < dataElements.length; i++) {\n Event.observe(dataElements[i], 'change', dataElements[i].setHasChanges.bind(dataElements[i]));\n }\n },\n\n /**\n * Bind sortable.\n */\n bindSortable: function () {\n if (jQuery('#' + this.containerId).find('.draggable-handle').length) {\n jQuery('#' + this.containerId).find('tbody').sortable({\n axis: 'y',\n handle: '.draggable-handle',\n\n /**\n * @param {*} event\n * @param {*} ui\n * @return {*}\n */\n helper: function (event, ui) {\n ui.children().each(function () {\n jQuery(this).width(jQuery(this).width());\n });\n\n return ui;\n },\n update: this.sortableUpdateCallback ? this.sortableUpdateCallback : function () {},\n tolerance: 'pointer'\n });\n }\n },\n\n /**\n * @param {Object} event\n */\n filterKeyPress: function (event) {\n if (event.keyCode == Event.KEY_RETURN) { //eslint-disable-line eqeqeq\n this.doFilter();\n }\n },\n\n /**\n * @param {Function} callback\n */\n doFilter: function (callback) {\n var filters = $$(\n '#' + this.containerId + ' [data-role=\"filter-form\"] input',\n '#' + this.containerId + ' [data-role=\"filter-form\"] select'\n ),\n elements = [],\n i;\n\n for (i in filters) {\n if (filters[i].value && filters[i].value.length) {\n elements.push(filters[i]);\n }\n }\n\n if (!this.doFilterCallback || this.doFilterCallback && this.doFilterCallback()) {\n this.reload(\n this.addVarToUrl(this.filterVar, Base64.encode(Form.serializeElements(elements))),\n callback\n );\n }\n },\n\n /**\n * @param {Function} callback\n */\n resetFilter: function (callback) {\n this.reload(this.addVarToUrl(this.filterVar, ''), callback);\n },\n\n /**\n * @param {Object} element\n */\n checkCheckboxes: function (element) {\n var elements = Element.select($(this.containerId), 'input[name=\"' + element.name + '\"]'),\n i;\n\n for (i = 0; i < elements.length; i++) {\n this.setCheckboxChecked(elements[i], element.checked);\n }\n\n /*eslint-enable no-undef*/\n },\n\n /**\n *\n * @param {HTMLElement} element\n * @param {*} checked\n */\n setCheckboxChecked: function (element, checked) {\n element.checked = checked;\n jQuery(element).trigger('change');\n element.setHasChanges({});\n\n if (this.checkboxCheckCallback) {\n this.checkboxCheckCallback(this, element, checked);\n }\n },\n\n /**\n * @param {Object} event\n */\n inputPage: function (event) {\n var element = Event.element(event),\n keyCode = event.keyCode || event.which;\n\n if (keyCode == Event.KEY_RETURN) { //eslint-disable-line eqeqeq\n this.setPage(element.value);\n }\n\n /*if(keyCode>47 && keyCode<58){\n\n }\n else{\n Event.stop(event);\n }*/\n },\n\n /**\n * @param {*} pageNumber\n */\n setPage: function (pageNumber) {\n this.reload(this.addVarToUrl(this.pageVar, pageNumber));\n }\n };\n\n window.varienGridMassaction = Class.create();\n varienGridMassaction.prototype = {\n /* Predefined vars */\n checkedValues: $H({}),\n checkedString: '',\n oldCallbacks: {},\n errorText: '',\n items: {},\n gridIds: [],\n useSelectAll: false,\n currentItem: false,\n lastChecked: {\n left: false,\n top: false,\n checkbox: false\n },\n fieldTemplate: mageTemplate('<input type=\"hidden\" name=\"<%- name %>\" value=\"<%- value %>\" />'),\n\n /**\n * @param {*} containerId\n * @param {*} grid\n * @param {*} checkedValues\n * @param {*} formFieldNameInternal\n * @param {*} formFieldName\n */\n initialize: function (containerId, grid, checkedValues, formFieldNameInternal, formFieldName) {\n this.setOldCallback('row_click', grid.rowClickCallback);\n this.setOldCallback('init', grid.initCallback);\n this.setOldCallback('init_row', grid.initRowCallback);\n this.setOldCallback('pre_init', grid.preInitCallback);\n\n this.useAjax = false;\n this.grid = grid;\n this.grid.massaction = this;\n this.containerId = containerId;\n this.initMassactionElements();\n\n this.checkedString = checkedValues;\n this.formFieldName = formFieldName;\n this.formFieldNameInternal = formFieldNameInternal;\n\n this.grid.initCallback = this.onGridInit.bind(this);\n this.grid.preInitCallback = this.onGridPreInit.bind(this);\n this.grid.initRowCallback = this.onGridRowInit.bind(this);\n this.grid.rowClickCallback = this.onGridRowClick.bind(this);\n this.initCheckboxes();\n this.checkCheckboxes();\n },\n\n /**\n * @param {*} flag\n */\n setUseAjax: function (flag) {\n this.useAjax = flag;\n },\n\n /**\n * @param {*} flag\n */\n setUseSelectAll: function (flag) {\n this.useSelectAll = flag;\n },\n\n /**\n * Init massaction elements.\n */\n initMassactionElements: function () {\n this.container = $(this.containerId);\n this.multiselect = $(this.containerId + '-mass-select');\n this.count = $(this.containerId + '-count');\n this.formHiddens = $(this.containerId + '-form-hiddens');\n this.formAdditional = $(this.containerId + '-form-additional');\n this.select = $(this.containerId + '-select');\n this.form = this.prepareForm();\n jQuery(this.form).mage('validation');\n this.select.observe('change', this.onSelectChange.bindAsEventListener(this));\n this.lastChecked = {\n left: false,\n top: false,\n checkbox: false\n };\n this.select.addClassName(this.select.value ? '_selected' : '');\n this.initMassSelect();\n },\n\n /**\n * @return {jQuery|*|HTMLElement}\n */\n prepareForm: function () {\n var form = $(this.containerId + '-form'),\n formPlace = null,\n formElement = this.formHiddens || this.formAdditional;\n\n if (!formElement) {\n formElement = this.container.getElementsByTagName('button')[0];\n formElement && formElement.parentNode;\n }\n\n if (!form && formElement) {\n /* fix problem with rendering form in FF through innerHTML property */\n form = document.createElement('form');\n form.setAttribute('method', 'post');\n form.setAttribute('action', '');\n form.id = this.containerId + '-form';\n formPlace = formElement.parentNode;\n formPlace.parentNode.appendChild(form);\n form.appendChild(formPlace);\n }\n\n return form;\n },\n\n /**\n * @param {Array} gridIds\n */\n setGridIds: function (gridIds) {\n this.gridIds = gridIds;\n this.updateCount();\n },\n\n /**\n * @return {Array}\n */\n getGridIds: function () {\n return this.gridIds;\n },\n\n /**\n * @param {*} items\n */\n setItems: function (items) {\n this.items = items;\n this.updateCount();\n },\n\n /**\n * @return {Object}\n */\n getItems: function () {\n return this.items;\n },\n\n /**\n * @param {*} itemId\n * @return {*}\n */\n getItem: function (itemId) {\n if (this.items[itemId]) {\n return this.items[itemId];\n }\n\n return false;\n },\n\n /**\n * @param {String} callbackName\n * @return {Function}\n */\n getOldCallback: function (callbackName) {\n return this.oldCallbacks[callbackName] ? this.oldCallbacks[callbackName] : Prototype.emptyFunction;\n },\n\n /**\n * @param {String} callbackName\n * @param {Function} callback\n */\n setOldCallback: function (callbackName, callback) {\n this.oldCallbacks[callbackName] = callback;\n },\n\n /**\n * @param {*} grid\n */\n onGridPreInit: function (grid) {\n this.initMassactionElements();\n this.getOldCallback('pre_init')(grid);\n },\n\n /**\n * @param {*} grid\n */\n onGridInit: function (grid) {\n this.initCheckboxes();\n this.checkCheckboxes();\n this.updateCount();\n this.getOldCallback('init')(grid);\n },\n\n /**\n * @param {*} grid\n * @param {*} row\n */\n onGridRowInit: function (grid, row) {\n this.getOldCallback('init_row')(grid, row);\n },\n\n /**\n * @param {Object} evt\n */\n isDisabled: function (evt) {\n var target = jQuery(evt.target),\n tr,\n checkbox;\n\n tr = target.is('tr') ? target : target.closest('tr');\n checkbox = tr.find('input[type=\"checkbox\"]');\n\n return checkbox.is(':disabled');\n },\n\n /**\n * @param {*} grid\n * @param {*} evt\n * @return {*}\n */\n onGridRowClick: function (grid, evt) {\n var tdElement = Event.findElement(evt, 'td'),\n trElement = Event.findElement(evt, 'tr'),\n checkbox, isInput, checked;\n\n if (this.isDisabled(evt)) {\n return false;\n }\n\n if (!$(tdElement).down('input')) {\n if ($(tdElement).down('a') || $(tdElement).down('select')) {\n return; //eslint-disable-line\n }\n\n if (trElement.title && trElement.title.strip() != '#') { //eslint-disable-line eqeqeq\n this.getOldCallback('row_click')(grid, evt);\n } else {\n checkbox = Element.select(trElement, 'input');\n isInput = Event.element(evt).tagName == 'input'; //eslint-disable-line eqeqeq\n checked = isInput ? checkbox[0].checked : !checkbox[0].checked;\n\n if (checked) { //eslint-disable-line max-depth\n this.checkedString = varienStringArray.add(checkbox[0].value, this.checkedString);\n } else {\n this.checkedString = varienStringArray.remove(checkbox[0].value, this.checkedString);\n }\n this.grid.setCheckboxChecked(checkbox[0], checked);\n this.updateCount();\n }\n\n return; //eslint-disable-line\n }\n\n if (Event.element(evt).isMassactionCheckbox) {\n this.setCheckbox(Event.element(evt));\n } else if (checkbox = this.findCheckbox(evt)) { //eslint-disable-line no-cond-assign\n checkbox.checked = !checkbox.checked;\n jQuery(checkbox).trigger('change');\n this.setCheckbox(checkbox);\n }\n },\n\n /**\n * @param {Object} evt\n */\n onSelectChange: function (evt) {\n var item = this.getSelectedItem();\n\n if (item) {\n this.formAdditional.update($(this.containerId + '-item-' + item.id + '-block').innerHTML);\n evt.target.addClassName('_selected');\n } else {\n this.formAdditional.update('');\n evt.target.removeClassName('_selected');\n }\n jQuery(this.form).data('validator').resetForm();\n },\n\n /**\n * @param {Object} evt\n * @return {*}\n */\n findCheckbox: function (evt) {\n if (['a', 'input', 'select'].indexOf(Event.element(evt).tagName.toLowerCase()) !== -1) {\n return false;\n }\n checkbox = false; //eslint-disable-line no-undef\n Event.findElement(evt, 'tr').select('[data-role=\"select-row\"]').each(function (element) { //eslint-disable-line\n if (element.isMassactionCheckbox) {\n checkbox = element; //eslint-disable-line no-undef\n }\n });\n\n return checkbox; //eslint-disable-line no-undef\n },\n\n /**\n * Init checkobox.\n */\n initCheckboxes: function () {\n this.getCheckboxes().each(function (checkbox) { //eslint-disable-line no-extra-bind\n checkbox.isMassactionCheckbox = true; //eslint-disable-line no-undef\n });\n },\n\n /**\n * Check checkbox.\n */\n checkCheckboxes: function () {\n this.getCheckboxes().each(function (checkbox) {\n checkbox.checked = varienStringArray.has(checkbox.value, this.checkedString);\n jQuery(checkbox).trigger('change');\n }.bind(this));\n },\n\n /**\n * @return {Boolean}\n */\n selectAll: function () {\n this.setCheckedValues(this.useSelectAll ? this.getGridIds() : this.getCheckboxesValuesAsString());\n this.checkCheckboxes();\n this.updateCount();\n this.clearLastChecked();\n\n return false;\n },\n\n /**\n * @return {Boolean}\n */\n unselectAll: function () {\n this.setCheckedValues('');\n this.checkCheckboxes();\n this.updateCount();\n this.clearLastChecked();\n\n return false;\n },\n\n /**\n * @return {Boolean}\n */\n selectVisible: function () {\n this.setCheckedValues(this.getCheckboxesValuesAsString());\n this.checkCheckboxes();\n this.updateCount();\n this.clearLastChecked();\n\n return false;\n },\n\n /**\n * @return {Boolean}\n */\n unselectVisible: function () {\n this.getCheckboxesValues().each(function (key) {\n this.checkedString = varienStringArray.remove(key, this.checkedString);\n }.bind(this));\n this.checkCheckboxes();\n this.updateCount();\n this.clearLastChecked();\n\n return false;\n },\n\n /**\n * @param {*} values\n */\n setCheckedValues: function (values) {\n this.checkedString = values;\n },\n\n /**\n * @return {String}\n */\n getCheckedValues: function () {\n return this.checkedString;\n },\n\n /**\n * @return {Array}\n */\n getCheckboxes: function () {\n var result = [];\n\n this.grid.rows.each(function (row) {\n var checkboxes = row.select('[data-role=\"select-row\"]');\n\n checkboxes.each(function (checkbox) {\n result.push(checkbox);\n });\n });\n\n return result;\n },\n\n /**\n * @return {Array}\n */\n getCheckboxesValues: function () {\n var result = [];\n\n this.getCheckboxes().each(function (checkbox) { //eslint-disable-line no-extra-bind\n result.push(checkbox.value);\n });\n\n return result;\n },\n\n /**\n * @return {String}\n */\n getCheckboxesValuesAsString: function () {\n return this.getCheckboxesValues().join(',');\n },\n\n /**\n * @param {Object} checkbox\n */\n setCheckbox: function (checkbox) {\n if (checkbox.checked) {\n this.checkedString = varienStringArray.add(checkbox.value, this.checkedString);\n } else {\n this.checkedString = varienStringArray.remove(checkbox.value, this.checkedString);\n }\n this.updateCount();\n },\n\n /**\n * Update count.\n */\n updateCount: function () {\n var checkboxesTotal = varienStringArray.count(\n this.useSelectAll ? this.getGridIds() : this.getCheckboxesValuesAsString()\n ),\n checkboxesChecked = varienStringArray.count(this.checkedString);\n\n jQuery('[data-role=\"counter\"]', this.count).html(checkboxesChecked);\n\n if (!checkboxesTotal) {\n this.multiselect.addClassName('_disabled');\n } else {\n this.multiselect.removeClassName('_disabled');\n }\n\n if (checkboxesChecked == checkboxesTotal && checkboxesTotal != 0) { //eslint-disable-line eqeqeq\n this.count.removeClassName('_empty');\n this.multiselect.addClassName('_checked').removeClassName('_indeterminate');\n } else if (checkboxesChecked == 0) { //eslint-disable-line eqeqeq\n this.count.addClassName('_empty');\n this.multiselect.removeClassName('_checked').removeClassName('_indeterminate');\n } else {\n this.count.removeClassName('_empty');\n this.multiselect.addClassName('_checked').addClassName('_indeterminate');\n }\n\n if (!this.grid.reloadParams) {\n this.grid.reloadParams = {};\n }\n this.grid.reloadParams[this.formFieldNameInternal] = this.checkedString;\n },\n\n /**\n * @return {*}\n */\n getSelectedItem: function () {\n if (this.getItem(this.select.value)) {\n return this.getItem(this.select.value);\n }\n\n return false;\n },\n\n /**\n * Apply.\n */\n apply: function () {\n var item, fieldName;\n\n if (varienStringArray.count(this.checkedString) == 0) { //eslint-disable-line eqeqeq\n alert({\n content: this.errorText\n });\n\n return;\n }\n\n item = this.getSelectedItem();\n\n if (!item) {\n jQuery(this.form).valid();\n\n return;\n }\n this.currentItem = item;\n fieldName = item.field ? item.field : this.formFieldName;\n\n if (this.currentItem.confirm) {\n confirm({\n content: this.currentItem.confirm,\n actions: {\n confirm: this.onConfirm.bind(this, fieldName, item)\n }\n });\n } else {\n this.onConfirm(fieldName, item);\n }\n },\n\n /**\n * @param {*} fieldName\n * @param {*} item\n */\n onConfirm: function (fieldName, item) {\n this.formHiddens.update('');\n new Insertion.Bottom(this.formHiddens, this.fieldTemplate({\n name: fieldName,\n value: this.checkedString\n }));\n new Insertion.Bottom(this.formHiddens, this.fieldTemplate({\n name: 'massaction_prepare_key',\n value: fieldName\n }));\n\n if (!jQuery(this.form).valid()) {\n return;\n }\n\n if (this.useAjax && item.url) {\n new Ajax.Request(item.url, {\n 'method': 'post',\n 'parameters': this.form.serialize(true),\n 'onComplete': this.onMassactionComplete.bind(this)\n });\n } else if (item.url) {\n this.form.action = item.url;\n this.form.submit();\n }\n },\n\n /**\n * @param {*} transport\n */\n onMassactionComplete: function (transport) {\n var listener;\n\n if (this.currentItem.complete) {\n try {\n listener = this.getListener(this.currentItem.complete) || Prototype.emptyFunction;\n listener(this.grid, this, transport);\n } catch (e) {}\n }\n },\n\n /**\n * @param {*} strValue\n * @return {Object}\n */\n getListener: function (strValue) {\n return eval(strValue); //eslint-disable-line no-eval\n },\n\n /**\n * Init mass select.\n */\n initMassSelect: function () {\n $$('input[data-role=\"select-row\"]').each(function (element) {\n element.observe('click', this.massSelect.bind(this));\n }.bind(this));\n },\n\n /**\n * Clear last checked.\n */\n clearLastChecked: function () {\n this.lastChecked = {\n left: false,\n top: false,\n checkbox: false\n };\n },\n\n /**\n * @param {Object} evt\n */\n massSelect: function (evt) {\n var currentCheckbox, lastCheckbox, start, finish;\n\n if (this.lastChecked.left !== false &&\n this.lastChecked.top !== false &&\n evt.button === 0 &&\n evt.shiftKey === true\n ) {\n currentCheckbox = Event.element(evt);\n lastCheckbox = this.lastChecked.checkbox;\n\n if (lastCheckbox != currentCheckbox) { //eslint-disable-line eqeqeq\n start = this.getCheckboxOrder(lastCheckbox);\n finish = this.getCheckboxOrder(currentCheckbox);\n\n if (start !== false && finish !== false) { //eslint-disable-line max-depth\n this.selectCheckboxRange(\n Math.min(start, finish),\n Math.max(start, finish),\n currentCheckbox.checked\n );\n }\n }\n }\n\n this.lastChecked = {\n left: Event.element(evt).viewportOffset().left,\n top: Event.element(evt).viewportOffset().top,\n checkbox: Event.element(evt) // \"boundary\" checkbox\n };\n },\n\n /**\n * @param {*} curCheckbox\n * @return {Boolean}\n */\n getCheckboxOrder: function (curCheckbox) {\n var order = false;\n\n this.getCheckboxes().each(function (checkbox, key) {\n if (curCheckbox == checkbox) { //eslint-disable-line eqeqeq\n order = key;\n }\n });\n\n return order;\n },\n\n /**\n * @param {*} start\n * @param {*} finish\n * @param {*} isChecked\n */\n selectCheckboxRange: function (start, finish, isChecked) {\n this.getCheckboxes().each(function (checkbox, key) {\n if (key >= start && key <= finish) {\n checkbox.checked = isChecked;\n this.setCheckbox(checkbox);\n }\n }.bind(this));\n }\n };\n\n window.varienGridAction = {\n /**\n * @param {Object} select\n */\n execute: function (select) {\n var config, win;\n\n if (!select.value || !select.value.isJSON()) {\n return;\n }\n\n config = select.value.evalJSON();\n\n if (config.confirm && !window.confirm(config.confirm)) { //eslint-disable-line no-alert\n select.options[0].selected = true;\n\n return;\n }\n\n if (config.popup) {\n win = window.open(config.href, 'action_window', 'width=500,height=600,resizable=1,scrollbars=1');\n win.focus();\n select.options[0].selected = true;\n } else {\n setLocation(config.href);\n }\n }\n };\n\n window.varienStringArray = {\n /**\n * @param {*} str\n * @param {*} haystack\n * @return {*}\n */\n remove: function (str, haystack) {\n haystack = ',' + haystack + ',';\n haystack = haystack.replace(new RegExp(',' + str + ',', 'g'), ',');\n\n return this.trimComma(haystack);\n },\n\n /**\n * @param {*} str\n * @param {*} haystack\n * @return {*}\n */\n add: function (str, haystack) {\n haystack = ',' + haystack + ',';\n\n if (haystack.search(new RegExp(',' + str + ',', 'g'), haystack) === -1) {\n haystack += str + ',';\n }\n\n return this.trimComma(haystack);\n },\n\n /**\n * @param {*} str\n * @param {*} haystack\n * @return {Boolean}\n */\n has: function (str, haystack) {\n haystack = ',' + haystack + ',';\n\n if (haystack.search(new RegExp(',' + str + ',', 'g'), haystack) === -1) {\n return false;\n }\n\n return true;\n },\n\n /**\n * @param {*} haystack\n * @return {*}\n */\n count: function (haystack) {\n var match;\n\n if (typeof haystack != 'string') {\n return 0;\n }\n\n /* eslint-disable no-undef, no-cond-assign, eqeqeq */\n if (match = haystack.match(new RegExp(',', 'g'))) {\n return match.length + 1;\n } else if (haystack.length != 0) {\n return 1;\n }\n\n /* eslint-enable no-undef, no-cond-assign, eqeqeq */\n return 0;\n },\n\n /**\n * @param {*} haystack\n * @param {*} fnc\n */\n each: function (haystack, fnc) {\n var i;\n\n haystack = haystack.split(',');\n\n for (i = 0; i < haystack.length; i++) {\n fnc(haystack[i]);\n }\n },\n\n /**\n * @param {String} string\n * @return {String}\n */\n trimComma: function (string) {\n string = string.replace(new RegExp('^(,+)','i'), '');\n string = string.replace(new RegExp('(,+)$','i'), '');\n\n return string;\n }\n };\n\n window.serializerController = Class.create();\n serializerController.prototype = {\n oldCallbacks: {},\n\n /**\n * @param {*} hiddenDataHolder\n * @param {*} predefinedData\n * @param {*} inputsToManage\n * @param {*} grid\n * @param {*} reloadParamName\n */\n initialize: function (hiddenDataHolder, predefinedData, inputsToManage, grid, reloadParamName) {\n //Grid inputs\n this.tabIndex = 1000;\n this.inputsToManage = inputsToManage;\n this.multidimensionalMode = inputsToManage.length > 0;\n\n //Hash with grid data\n this.gridData = this.getGridDataHash(predefinedData);\n\n //Hidden input data holder\n this.hiddenDataHolder = $(hiddenDataHolder);\n this.hiddenDataHolder.value = this.serializeObject();\n\n this.grid = grid;\n\n // Set old callbacks\n this.setOldCallback('row_click', this.grid.rowClickCallback);\n this.setOldCallback('init_row', this.grid.initRowCallback);\n this.setOldCallback('checkbox_check', this.grid.checkboxCheckCallback);\n\n //Grid\n this.reloadParamName = reloadParamName;\n this.grid.reloadParams = {};\n this.grid.reloadParams[this.reloadParamName + '[]'] = this.getDataForReloadParam();\n this.grid.rowClickCallback = this.rowClick.bind(this);\n this.grid.initRowCallback = this.rowInit.bind(this);\n this.grid.checkboxCheckCallback = this.registerData.bind(this);\n this.grid.rows.each(this.eachRow.bind(this));\n },\n\n /**\n * @param {String} callbackName\n * @param {Function} callback\n */\n setOldCallback: function (callbackName, callback) {\n this.oldCallbacks[callbackName] = callback;\n },\n\n /**\n * @param {String} callbackName\n * @return {Prototype.emptyFunction}\n */\n getOldCallback: function (callbackName) {\n return this.oldCallbacks[callbackName] ? this.oldCallbacks[callbackName] : Prototype.emptyFunction;\n },\n\n /**\n * @param {*} grid\n * @param {*} element\n * @param {*} checked\n */\n registerData: function (grid, element, checked) {\n var i;\n\n if (this.multidimensionalMode) {\n if (checked) {\n /*eslint-disable max-depth*/\n if (element.inputElements) {\n this.gridData.set(element.value, {});\n\n for (i = 0; i < element.inputElements.length; i++) {\n element.inputElements[i].disabled = false;\n this.gridData.get(element.value)[element.inputElements[i].name] =\n element.inputElements[i].value;\n }\n }\n } else {\n if (element.inputElements) {\n for (i = 0; i < element.inputElements.length; i++) {\n element.inputElements[i].disabled = true;\n }\n }\n this.gridData.unset(element.value);\n }\n } else {\n if (checked) { //eslint-disable-line no-lonely-if\n this.gridData.set(element.value, element.value);\n } else {\n this.gridData.unset(element.value);\n }\n }\n\n this.hiddenDataHolder.value = this.serializeObject();\n this.grid.reloadParams = {};\n this.grid.reloadParams[this.reloadParamName + '[]'] = this.getDataForReloadParam();\n this.getOldCallback('checkbox_check')(grid, element, checked);\n\n /*eslint-enable max-depth*/\n },\n\n /**\n * @param {*} row\n */\n eachRow: function (row) {\n this.rowInit(this.grid, row);\n },\n\n /**\n * @param {*} grid\n * @param {*} event\n */\n rowClick: function (grid, event) {\n var trElement = Event.findElement(event, 'tr'),\n isInput = Event.element(event).tagName == 'INPUT', //eslint-disable-line eqeqeq\n checkbox, checked;\n\n if (trElement) {\n checkbox = Element.select(trElement, 'input');\n\n if (checkbox[0] && !checkbox[0].disabled) {\n checked = isInput ? checkbox[0].checked : !checkbox[0].checked;\n this.grid.setCheckboxChecked(checkbox[0], checked);\n }\n }\n this.getOldCallback('row_click')(grid, event);\n },\n\n /**\n * @param {*} event\n */\n inputChange: function (event) {\n var element = Event.element(event);\n\n if (element && element.checkboxElement && element.checkboxElement.checked) {\n this.gridData.get(element.checkboxElement.value)[element.name] = element.value;\n this.hiddenDataHolder.value = this.serializeObject();\n }\n },\n\n /**\n * @param {*} grid\n * @param {*} row\n */\n rowInit: function (grid, row) {\n var checkbox, selectors, inputs, i;\n\n if (this.multidimensionalMode) {\n checkbox = $(row).select('.checkbox')[0];\n selectors = this.inputsToManage.map(function (name) {\n return ['input[name=\"' + name + '\"]', 'select[name=\"' + name + '\"]'];\n });\n inputs = $(row).select.apply($(row), selectors.flatten());\n\n if (checkbox && inputs.length > 0) {\n checkbox.inputElements = inputs;\n\n /* eslint-disable max-depth */\n for (i = 0; i < inputs.length; i++) {\n inputs[i].checkboxElement = checkbox;\n\n if (this.gridData.get(checkbox.value) && this.gridData.get(checkbox.value)[inputs[i].name]) {\n inputs[i].value = this.gridData.get(checkbox.value)[inputs[i].name];\n }\n inputs[i].disabled = !checkbox.checked;\n inputs[i].tabIndex = this.tabIndex++;\n Event.observe(inputs[i], 'keyup', this.inputChange.bind(this));\n Event.observe(inputs[i], 'change', this.inputChange.bind(this));\n }\n }\n }\n\n /* eslint-enable max-depth */\n this.getOldCallback('init_row')(grid, row);\n },\n\n /**\n * Stuff methods.\n *\n * @param {*} _object\n * @return {*}\n */\n getGridDataHash: function (_object) {\n return $H(this.multidimensionalMode ? _object : this.convertArrayToObject(_object));\n },\n\n /**\n * @return {*}\n */\n getDataForReloadParam: function () {\n return this.multidimensionalMode ? this.gridData.keys() : this.gridData.values();\n },\n\n /**\n * @return {*}\n */\n serializeObject: function () {\n var clone;\n\n if (this.multidimensionalMode) {\n clone = this.gridData.clone();\n clone.each(function (pair) {\n clone.set(pair.key, Base64.encode(Object.toQueryString(pair.value)));\n });\n\n return clone.toQueryString();\n }\n\n return this.gridData.values().join('&');\n },\n\n /**\n * @param {Array} _array\n * @return {Object}\n */\n convertArrayToObject: function (_array) {\n var _object = {},\n i, l;\n\n for (i = 0, l = _array.length; i < l; i++) {\n _object[_array[i]] = _array[i];\n }\n\n return _object;\n }\n };\n});\n","mage/adminhtml/events.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* global varienEvents */\n/* eslint-disable strict */\ndefine([\n 'Magento_Ui/js/modal/alert',\n 'prototype'\n], function (alert) {\n // from http://www.someelement.com/2007/03/eventpublisher-custom-events-la-pubsub.html\n window.varienEvents = Class.create();\n\n varienEvents.prototype = {\n /**\n * Initialize.\n */\n initialize: function () {\n this.arrEvents = {};\n this.eventPrefix = '';\n },\n\n /**\n * Attaches a {handler} function to the publisher's {eventName} event for execution upon the event firing\n * @param {String} eventName\n * @param {Function} handler\n * @param {Boolean} [asynchFlag] - Defaults to false if omitted.\n * Indicates whether to execute {handler} asynchronously (true) or not (false).\n */\n attachEventHandler: function (eventName, handler) {\n var asynchVar, handlerObj;\n\n if (typeof handler == 'undefined' || handler == null) {\n return;\n }\n eventName += this.eventPrefix;\n // using an event cache array to track all handlers for proper cleanup\n if (this.arrEvents[eventName] == null) {\n this.arrEvents[eventName] = [];\n }\n //create a custom object containing the handler method and the asynch flag\n asynchVar = arguments.length > 2 ? arguments[2] : false;\n handlerObj = {\n method: handler,\n asynch: asynchVar\n };\n this.arrEvents[eventName].push(handlerObj);\n },\n\n /**\n * Removes a single handler from a specific event\n * @param {String} eventName - The event name to clear the handler from\n * @param {Function} handler - A reference to the handler function to un-register from the event\n */\n removeEventHandler: function (eventName, handler) {\n eventName += this.eventPrefix;\n\n if (this.arrEvents[eventName] != null) {\n this.arrEvents[eventName] = this.arrEvents[eventName].reject(function (obj) {\n return obj.method == handler; //eslint-disable-line eqeqeq\n });\n }\n },\n\n /**\n * Removes all handlers from a single event\n * @param {String} eventName - The event name to clear handlers from\n */\n clearEventHandlers: function (eventName) {\n eventName += this.eventPrefix;\n this.arrEvents[eventName] = null;\n },\n\n /**\n * Removes all handlers from ALL events\n */\n clearAllEventHandlers: function () {\n this.arrEvents = {};\n },\n\n /**\n * Collect and modify value of arg synchronously in succession and return its new value.\n * In order to use, call attachEventHandler and add function handlers with eventName.\n * Then call fireEventReducer with eventName and any argument to have its value accumulatively modified.\n * Event handlers will be applied to argument in order of first attached to last attached.\n * @param {String} eventName\n * @param {*} arg\n */\n fireEventReducer: function (eventName, arg) {\n var evtName = eventName + this.eventPrefix,\n result = arg,\n len,\n i;\n\n if (!this.arrEvents[evtName]) {\n return result;\n }\n\n len = this.arrEvents[evtName].length; //optimization\n\n for (i = 0; i < len; i++) {\n /* eslint-disable max-depth */\n try {\n result = this.arrEvents[evtName][i].method(result);\n } catch (e) {\n if (this.id) {\n alert({\n content: 'error: error in ' + this.id + '.fireEventReducer():\\n\\nevent name: ' +\n eventName + '\\n\\nerror message: ' + e.message\n });\n } else {\n alert({\n content: 'error: error in [unknown object].fireEventReducer():\\n\\nevent name: ' +\n eventName + '\\n\\nerror message: ' + e.message\n });\n }\n }\n /* eslint-disable max-depth */\n }\n\n return result;\n },\n\n /**\n * Fires the event {eventName}, resulting in all registered handlers to be executed.\n * It also collects and returns results of all non-asynchronous handlers\n * @param {String} eventName - The name of the event to fire\n * @param {Object} [args] - Any object, will be passed into the handler function as the only argument\n * @return {Array}\n */\n fireEvent: function (eventName) {\n var evtName = eventName + this.eventPrefix,\n results = [],\n result, len, i, eventArgs, method, eventHandler;\n\n if (this.arrEvents[evtName] != null) {\n len = this.arrEvents[evtName].length; //optimization\n\n for (i = 0; i < len; i++) {\n /* eslint-disable max-depth */\n try {\n if (arguments.length > 1) {\n if (this.arrEvents[evtName][i].asynch) {\n eventArgs = arguments[1];\n method = this.arrEvents[evtName][i].method.bind(this);\n setTimeout(function () { //eslint-disable-line no-loop-func\n method(eventArgs);\n }, 10);\n } else {\n result = this.arrEvents[evtName][i].method(arguments[1]);\n }\n } else {\n if (this.arrEvents[evtName][i].asynch) { //eslint-disable-line no-lonely-if\n eventHandler = this.arrEvents[evtName][i].method;\n setTimeout(eventHandler, 1);\n } else if (\n this.arrEvents &&\n this.arrEvents[evtName] &&\n this.arrEvents[evtName][i] &&\n this.arrEvents[evtName][i].method\n ) {\n result = this.arrEvents[evtName][i].method();\n }\n }\n results.push(result);\n }\n catch (e) {\n if (this.id) {\n alert({\n content: 'error: error in ' + this.id + '.fireEvent():\\n\\nevent name: ' +\n eventName + '\\n\\nerror message: ' + e.message\n });\n } else {\n alert({\n content: 'error: error in [unknown object].fireEvent():\\n\\nevent name: ' +\n eventName + '\\n\\nerror message: ' + e.message\n });\n }\n }\n\n /* eslint-enable max-depth */\n }\n }\n\n return results;\n }\n };\n\n window.varienGlobalEvents = new varienEvents(); //jscs:ignore requireCapitalizedConstructors\n\n return window.varienGlobalEvents;\n});\n","mage/adminhtml/globals.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* global setLocation */\ndefine([\n 'Magento_Ui/js/modal/confirm',\n 'mage/dataPost'\n], function (confirm, dataPost) {\n 'use strict';\n\n /**\n * Set of a temporary methods used to provide\n * backward compatability with a legacy code.\n */\n window.setLocation = function (url) {\n window.location.href = url;\n };\n\n /**\n * Helper for onclick action.\n * @param {String} message\n * @param {String} url\n * @param {Object} postData\n * @returns {Boolean}\n */\n window.deleteConfirm = function (message, url, postData) {\n confirm({\n content: message,\n actions: {\n /**\n * Confirm action.\n */\n confirm: function () {\n if (postData !== undefined) {\n postData.action = url;\n dataPost().postData(postData);\n } else {\n setLocation(url);\n }\n }\n }\n });\n\n return false;\n };\n\n /**\n * Helper for onclick action.\n * @param {String} message\n * @param {String} url\n * @returns {Boolean}\n */\n window.confirmSetLocation = window.deleteConfirm;\n});\n","mage/adminhtml/backup.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 */\n/* global AdminBackup, setLocation */\n/* eslint-disable strict */\ndefine([\n 'jquery',\n 'Magento_Ui/js/modal/modal',\n 'mage/mage',\n 'prototype'\n], function (jQuery) {\n window.AdminBackup = new Class.create();\n\n AdminBackup.prototype = {\n /**\n * Initialize.\n */\n initialize: function () {\n this.reset();\n this.rollbackUrl = this.backupUrl = '';\n },\n\n /**\n * reset.\n */\n reset: function () {\n this.time = 0;\n this.type = '';\n },\n\n /**\n * @param {*} type\n * @return {Boolean}\n */\n backup: function (type) {\n this.reset();\n this.type = type;\n this.requestBackupOptions();\n\n return false;\n },\n\n /**\n * @param {*} type\n * @param {*} time\n * @return {Boolean}\n */\n rollback: function (type, time) {\n this.reset();\n this.time = time;\n this.type = type;\n this.showRollbackWarning();\n\n return false;\n },\n\n /**\n * Show rollback warning.\n */\n showRollbackWarning: function () {\n this.showPopup('rollback-warning');\n },\n\n /**\n * request backup options.\n */\n requestBackupOptions: function () {\n var action;\n\n this.hidePopups();\n action = this.type != 'snapshot' ? 'hide' : 'show'; //eslint-disable-line eqeqeq\n this.showPopup('backup-options');\n\n $$('#exclude-media-checkbox-container').invoke(action);\n },\n\n /**\n * Request password.\n */\n requestPassword: function () {\n this.hidePopups();\n\n this.showPopup('rollback-request-password');\n\n this.type != 'db' ? //eslint-disable-line eqeqeq\n $('use-ftp-checkbox-row').show() :\n $('use-ftp-checkbox-row').hide();\n },\n\n /**\n * Toggle Ftp Credentials Form.\n */\n toggleFtpCredentialsForm: function () {\n $('use_ftp').checked ? $('ftp-credentials-container').show()\n : $('ftp-credentials-container').hide();\n\n $$('#ftp-credentials-container input').each(function (item) {\n if (item.name == 'ftp_path') { //eslint-disable-line eqeqeq\n return;\n }\n $('use_ftp').checked ? item.addClassName('required-entry') : item.removeClassName('required-entry');\n });\n },\n\n /**\n * Submit backup.\n */\n submitBackup: function () {\n var data = {\n 'type': this.type,\n 'maintenance_mode': $('backup_maintenance_mode').checked ? 1 : 0,\n 'backup_name': $('backup_name').value,\n 'exclude_media': $('exclude_media').checked ? 1 : 0\n };\n\n new Ajax.Request(this.backupUrl, {\n onSuccess: function (transport) {\n this.processResponse(transport, 'backup-options');\n }.bind(this),\n method: 'post',\n parameters: data\n });\n\n this.modal.modal('closeModal');\n },\n\n /**\n * Submit rollback.\n */\n submitRollback: function () {\n var data = this.getPostData();\n\n new Ajax.Request(this.rollbackUrl, {\n onSuccess: function (transport) {\n this.processResponse(transport, 'rollback-request-password');\n }.bind(this),\n method: 'post',\n parameters: data\n });\n\n this.modal.modal('closeModal');\n },\n\n /**\n * @param {Object} transport\n * @param {*} popupId\n */\n processResponse: function (transport, popupId) {\n var json;\n\n if (!transport.responseText.isJSON()) {\n return;\n }\n\n json = transport.responseText.evalJSON();\n\n if (json.error) {\n this.showPopup(popupId);\n this.displayError(popupId, json.error);\n\n return;\n }\n\n if (json['redirect_url']) {\n setLocation(json['redirect_url']);\n }\n },\n\n /**\n * @param {*} parentContainer\n * @param {*} message\n */\n displayError: function (parentContainer, message) {\n var messageHtml = this.getErrorMessageHtml(message);\n\n $$('#' + parentContainer + ' .backup-messages .messages').invoke('update', messageHtml);\n $$('#' + parentContainer + ' .backup-messages').invoke('show');\n },\n\n /**\n * @param {*} message\n * @return {String}\n */\n getErrorMessageHtml: function (message) {\n return '<div class=\"message message-error error\"><div>' + message + '</div></div>';\n },\n\n /**\n * @return {*|jQuery}\n */\n getPostData: function () {\n var data = $('rollback-form').serialize(true);\n\n data.time = this.time;\n data.type = this.type;\n\n return data;\n },\n backupConfig: {\n 'backup-options': {\n title: jQuery.mage.__('Backup options'),\n\n /**\n * @return {String}\n */\n content: function () {\n return document.getElementById('backup-options-template').textContent;\n },\n\n /**\n * Action Ok.\n */\n actionOk: function () {\n this.modal.find('#backup-form').validation({\n submitHandler: jQuery.proxy(this.submitBackup, this)\n });\n this.modal.find('#backup-form').submit();\n }\n },\n 'rollback-warning': {\n title: jQuery.mage.__('Warning'),\n\n /**\n * @return {String}\n */\n content: function () {\n return document.getElementById('rollback-warning-template').textContent;\n },\n\n /**\n * Action Ok.\n */\n actionOk: function () {\n this.modal.modal('closeModal');\n this.requestPassword();\n }\n },\n 'rollback-request-password': {\n title: jQuery.mage.__('Backup options'),\n\n /**\n * @return {String}\n */\n content: function () {\n return document.getElementById('rollback-request-password-template').textContent;\n },\n\n /**\n * Action Ok.\n */\n actionOk: function () {\n this.modal.find('#rollback-form').validation({\n submitHandler: jQuery.proxy(this.submitRollback, this)\n });\n this.modal.find('#rollback-form').submit();\n },\n\n /**\n * Opened.\n */\n opened: function () {\n this.toggleFtpCredentialsForm();\n }\n }\n },\n\n /**\n * @param {*} divId\n */\n showPopup: function (divId) {\n var self = this;\n\n this.modal = jQuery('<div/>').attr({\n id: divId\n }).html(this.backupConfig[divId].content()).modal({\n modalClass: 'magento',\n title: this.backupConfig[divId].title,\n type: 'slide',\n\n /**\n * @param {juery.Event} e\n * @param {Object} modal\n */\n closed: function (e, modal) {\n modal.modal.remove();\n },\n\n /**\n * Opened.\n */\n opened: function () {\n if (self.backupConfig[divId].opened) {\n self.backupConfig[divId].opened.call(self);\n }\n },\n buttons: [{\n text: jQuery.mage.__('Cancel'),\n 'class': 'action cancel',\n\n /**\n * Click action.\n */\n click: function () {\n this.closeModal();\n }\n }, {\n text: jQuery.mage.__('Ok'),\n 'class': 'action primary',\n\n /**\n * Click action.\n */\n click: function () {\n self.backupConfig[divId].actionOk.call(self);\n }\n }]\n });\n this.modal.modal('openModal');\n },\n\n /**\n * Hide Popups.\n */\n hidePopups: function () {\n var mask;\n\n $$('.backup-dialog').each(Element.hide);\n mask = $('popup-window-mask');\n\n if (mask) {\n mask.hide();\n }\n }\n };\n});\n","mage/adminhtml/form.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* global varienGlobalEvents, varienWindowOnloadCache, RegionUpdater, FormElementDependenceController */\n/* eslint-disable strict */\ndefine([\n 'jquery',\n 'prototype',\n 'mage/adminhtml/events'\n], function (jQuery) {\n var varienElementMethods;\n\n /*\n * @TODO Need to be removed after refactoring all dependent of the form the components\n */\n (function ($) {\n $(document).ready(function () {\n $(document).on('beforeSubmit', function (e) { //eslint-disable-line max-nested-callbacks\n if (typeof varienGlobalEvents !== 'undefined') {\n varienGlobalEvents.fireEvent('formSubmit', $(e.target).attr('id'));\n }\n });\n });\n })(jQuery);\n\n /**\n * Additional elements methods\n */\n varienElementMethods = {\n /**\n * @param {HTMLElement} element\n */\n setHasChanges: function (element) {\n var elm;\n\n if ($(element) && $(element).hasClassName('no-changes')) {\n return;\n }\n elm = element;\n\n while (elm && elm.tagName != 'BODY') { //eslint-disable-line eqeqeq\n if (elm.statusBar) {\n Element.addClassName($(elm.statusBar), 'changed');\n }\n elm = elm.parentNode;\n }\n },\n\n /**\n * @param {HTMLElement} element\n * @param {*} flag\n * @param {Object} form\n */\n setHasError: function (element, flag, form) {\n var elm = element;\n\n while (elm && elm.tagName != 'BODY') { //eslint-disable-line eqeqeq\n if (elm.statusBar) {\n /* eslint-disable max-depth */\n if (form.errorSections.keys().indexOf(elm.statusBar.id) < 0) {\n form.errorSections.set(elm.statusBar.id, flag);\n }\n\n if (flag) {\n Element.addClassName($(elm.statusBar), 'error');\n\n if (form.canShowError && $(elm.statusBar).show) {\n form.canShowError = false;\n $(elm.statusBar).show();\n }\n form.errorSections.set(elm.statusBar.id, flag);\n } else if (!form.errorSections.get(elm.statusBar.id)) {\n Element.removeClassName($(elm.statusBar), 'error');\n }\n\n /* eslint-enable max-depth */\n }\n elm = elm.parentNode;\n }\n this.canShowElement = false;\n }\n };\n\n Element.addMethods(varienElementMethods);\n\n // Global bind changes\n window.varienWindowOnloadCache = {};\n\n /**\n * @param {*} useCache\n */\n function varienWindowOnload(useCache) {\n var dataElements = $$('input', 'select', 'textarea'),\n i;\n\n for (i = 0; i < dataElements.length; i++) {\n if (dataElements[i] && dataElements[i].id) {\n\n /* eslint-disable max-depth */\n if (!useCache || !varienWindowOnloadCache[dataElements[i].id]) {\n Event.observe(dataElements[i], 'change', dataElements[i].setHasChanges.bind(dataElements[i]));\n\n if (useCache) {\n varienWindowOnloadCache[dataElements[i].id] = true;\n }\n }\n\n /* eslint-disable max-depth */\n }\n }\n }\n Event.observe(window, 'load', varienWindowOnload);\n\n window.RegionUpdater = Class.create();\n RegionUpdater.prototype = {\n /**\n * @param {HTMLElement} countryEl\n * @param {HTMLElement} regionTextEl\n * @param {HTMLElement}regionSelectEl\n * @param {Object} regions\n * @param {*} disableAction\n * @param {*} clearRegionValueOnDisable\n */\n initialize: function (\n countryEl, regionTextEl, regionSelectEl, regions, disableAction, clearRegionValueOnDisable\n ) {\n this.isRegionRequired = true;\n this.countryEl = $(countryEl);\n this.regionTextEl = $(regionTextEl);\n this.regionSelectEl = $(regionSelectEl);\n this.config = regions.config;\n delete regions.config;\n this.regions = regions;\n this.disableAction = typeof disableAction === 'undefined' ? 'hide' : disableAction;\n this.clearRegionValueOnDisable = typeof clearRegionValueOnDisable === 'undefined' ?\n false : clearRegionValueOnDisable;\n\n if (this.regionSelectEl.options.length <= 1) {\n this.update();\n } else {\n this.lastCountryId = this.countryEl.value;\n }\n\n this.countryEl.changeUpdater = this.update.bind(this);\n\n Event.observe(this.countryEl, 'change', this.update.bind(this));\n },\n\n /**\n * @private\n */\n _checkRegionRequired: function () {\n var label, wildCard, elements, that, regionRequired;\n\n if (!this.isRegionRequired) {\n return;\n }\n\n elements = [this.regionTextEl, this.regionSelectEl];\n that = this;\n\n if (typeof this.config == 'undefined') {\n return;\n }\n regionRequired = this.config['regions_required'].indexOf(this.countryEl.value) >= 0;\n\n elements.each(function (currentElement) {\n var form, validationInstance, field, topElement;\n\n if (!currentElement) {\n return;\n }\n form = currentElement.form;\n validationInstance = form ? jQuery(form).data('validation') : null;\n field = currentElement.up('.field') || new Element('div');\n\n if (validationInstance) {\n validationInstance.clearError(currentElement);\n }\n label = $$('label[for=\"' + currentElement.id + '\"]')[0];\n\n if (label) {\n wildCard = label.down('em') || label.down('span.required');\n topElement = label.up('tr') || label.up('li');\n\n if (!that.config['show_all_regions'] && topElement) {\n if (regionRequired) {\n topElement.show();\n } else {\n topElement.hide();\n }\n }\n }\n\n if (label && wildCard) {\n if (!regionRequired) {\n wildCard.hide();\n } else {\n wildCard.show();\n }\n }\n\n //compute the need for the required fields\n if (!regionRequired || !currentElement.visible()) {\n if (field.hasClassName('required')) {\n field.removeClassName('required');\n }\n\n if (currentElement.hasClassName('required-entry')) {\n currentElement.removeClassName('required-entry');\n }\n\n if (currentElement.tagName.toLowerCase() == 'select' && //eslint-disable-line eqeqeq\n currentElement.hasClassName('validate-select')\n ) {\n currentElement.removeClassName('validate-select');\n }\n } else {\n if (!field.hasClassName('required')) {\n field.addClassName('required');\n }\n\n if (!currentElement.hasClassName('required-entry')) {\n currentElement.addClassName('required-entry');\n }\n\n if (currentElement.tagName.toLowerCase() == 'select' && //eslint-disable-line eqeqeq\n !currentElement.hasClassName('validate-select')\n ) {\n currentElement.addClassName('validate-select');\n }\n }\n });\n },\n\n /**\n * Disable region validation.\n */\n disableRegionValidation: function () {\n this.isRegionRequired = false;\n },\n\n /**\n * Update.\n */\n update: function () {\n var option, region, def, regionId;\n\n if (this.regions[this.countryEl.value]) {\n if (this.lastCountryId != this.countryEl.value) { //eslint-disable-line eqeqeq\n def = this.regionSelectEl.getAttribute('defaultValue');\n\n if (this.regionTextEl) {\n if (!def) {\n def = this.regionTextEl.value.toLowerCase();\n }\n this.regionTextEl.value = '';\n }\n\n this.regionSelectEl.options.length = 1;\n\n for (regionId in this.regions[this.countryEl.value]) { //eslint-disable-line guard-for-in\n region = this.regions[this.countryEl.value][regionId];\n\n option = document.createElement('OPTION');\n option.value = regionId;\n option.text = region.name.stripTags();\n option.title = region.name;\n\n if (this.regionSelectEl.options.add) {\n this.regionSelectEl.options.add(option);\n } else {\n this.regionSelectEl.appendChild(option);\n }\n\n if (regionId == def || region.name.toLowerCase() == def || region.code.toLowerCase() == def) { //eslint-disable-line\n this.regionSelectEl.value = regionId;\n }\n }\n }\n\n if (this.disableAction == 'hide') { //eslint-disable-line eqeqeq\n if (this.regionTextEl) {\n this.regionTextEl.style.display = 'none';\n this.regionTextEl.style.disabled = true;\n }\n this.regionSelectEl.style.display = '';\n this.regionSelectEl.disabled = false;\n } else if (this.disableAction == 'disable') { //eslint-disable-line eqeqeq\n if (this.regionTextEl) {\n this.regionTextEl.disabled = true;\n }\n this.regionSelectEl.disabled = false;\n }\n this.setMarkDisplay(this.regionSelectEl, true);\n\n this.lastCountryId = this.countryEl.value;\n } else {\n if (this.disableAction == 'hide') { //eslint-disable-line eqeqeq\n if (this.regionTextEl) {\n this.regionTextEl.style.display = '';\n this.regionTextEl.style.disabled = false;\n }\n this.regionSelectEl.style.display = 'none';\n this.regionSelectEl.disabled = true;\n } else if (this.disableAction == 'disable') { //eslint-disable-line eqeqeq\n if (this.regionTextEl) {\n this.regionTextEl.disabled = false;\n }\n this.regionSelectEl.disabled = true;\n\n if (this.clearRegionValueOnDisable) {\n this.regionSelectEl.value = '';\n }\n } else if (this.disableAction == 'nullify') { //eslint-disable-line eqeqeq\n this.regionSelectEl.options.length = 1;\n this.regionSelectEl.value = '';\n this.regionSelectEl.selectedIndex = 0;\n this.lastCountryId = '';\n }\n this.setMarkDisplay(this.regionSelectEl, false);\n }\n varienGlobalEvents.fireEvent('address_country_changed', this.countryEl);\n this._checkRegionRequired();\n },\n\n /**\n * @param {HTMLElement} elem\n * @param {*} display\n */\n setMarkDisplay: function (elem, display) {\n var marks;\n\n if (elem.parentNode.parentNode) {\n marks = Element.select(elem.parentNode.parentNode, '.required');\n\n if (marks[0]) {\n display ? marks[0].show() : marks[0].hide();\n }\n }\n }\n };\n\n window.regionUpdater = RegionUpdater;\n\n /**\n * Fix errorrs in IE\n */\n Event.pointerX = function (event) {\n try {\n return event.pageX || (event.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft)); //eslint-disable-line\n }\n catch (e) {}\n };\n\n /**\n * @param {jQuery.Event} event\n * @return {*}\n */\n Event.pointerY = function (event) {\n try {\n return event.pageY || (event.clientY + (document.documentElement.scrollTop || document.body.scrollTop)); //eslint-disable-line\n }\n catch (e) {}\n };\n\n /**\n * Observer that watches for dependent form elements\n * If an element depends on 1 or more of other elements,\n * it should show up only when all of them gain specified values\n */\n window.FormElementDependenceController = Class.create();\n FormElementDependenceController.prototype = {\n /**\n * Structure of elements: {\n * 'id_of_dependent_element' : {\n * 'id_of_master_element_1' : 'reference_value',\n * 'id_of_master_element_2' : 'reference_value'\n * 'id_of_master_element_3' : ['reference_value1', 'reference_value2']\n * ...\n * }\n * }\n * @param {Object} elementsMap\n * @param {Object} config\n */\n initialize: function (elementsMap, config) {\n var idTo, idFrom, values, fromId, radioFrom;\n\n if (config) {\n this._config = jQuery.extend(this._config, config);\n }\n\n for (idTo in elementsMap) { //eslint-disable-line guard-for-in\n for (idFrom in elementsMap[idTo]) { //eslint-disable-line guard-for-in\n if ($(idFrom)) {\n Event.observe(\n $(idFrom),\n 'change',\n this.trackChange.bindAsEventListener(this, idTo, elementsMap[idTo])\n );\n } else {\n // Check if radio button\n values = elementsMap[idTo][idFrom].values;\n fromId = $(idFrom + values[0]);\n radioFrom = fromId ? $$('[name=\"' + fromId.name + '\"]') : false;\n\n if (radioFrom) {\n radioFrom.invoke(\n 'on',\n 'change',\n this.trackChange.bindAsEventListener(this, idTo, elementsMap[idTo])\n );\n }\n }\n this.trackChange(null, idTo, elementsMap[idTo]);\n }\n }\n },\n\n /**\n * Misc. config options\n * Keys are underscored intentionally\n */\n _config: {\n 'levels_up': 1 // how many levels up to travel when toggling element\n },\n\n /**\n * Define whether target element should be toggled and show/hide its row\n *\n * @param {Object} e - event\n * @param {String} idTo - id of target element\n * @param {Object} valuesFrom - ids of master elements and reference values\n * @return\n */\n trackChange: function (e, idTo, valuesFrom) {\n // define whether the target should show up\n var shouldShowUp = true,\n idFrom, from, values, isInArray, isNegative, headElement, isInheritCheckboxChecked, target, inputs,\n isAnInputOrSelect, currentConfig, rowElement, fromId, radioFrom;\n\n for (idFrom in valuesFrom) { //eslint-disable-line guard-for-in\n from = $(idFrom);\n\n if (from) {\n values = valuesFrom[idFrom].values;\n isInArray = values.indexOf(from.value) != -1; //eslint-disable-line\n isNegative = valuesFrom[idFrom].negative;\n\n if (!from || isInArray && isNegative || !isInArray && !isNegative) {\n shouldShowUp = false;\n }\n // Check if radio button\n } else {\n values = valuesFrom[idFrom].values;\n fromId = $(idFrom + values[0]);\n\n if (fromId) {\n radioFrom = $$('[name=\"' + fromId.name + '\"]:checked');\n isInArray = radioFrom.length > 0 && values.indexOf(radioFrom[0].value) !== -1;\n isNegative = valuesFrom[idFrom].negative;\n\n if (!radioFrom || isInArray && isNegative || !isInArray && !isNegative) {\n shouldShowUp = false;\n }\n }\n }\n }\n\n // toggle target row\n headElement = $(idTo + '-head');\n isInheritCheckboxChecked = $(idTo + '_inherit') && $(idTo + '_inherit').checked;\n target = $(idTo);\n\n // Target won't always exist (for example, if field type is \"label\")\n if (target) {\n inputs = target.up(this._config['levels_up']).select('input', 'select', 'td');\n isAnInputOrSelect = ['input', 'select'].indexOf(target.tagName.toLowerCase()) != -1; //eslint-disable-line\n\n if (target.type === 'fieldset') {\n inputs = target.select('input', 'select', 'td');\n }\n } else {\n inputs = false;\n isAnInputOrSelect = false;\n }\n\n if (shouldShowUp) {\n currentConfig = this._config;\n\n if (inputs) {\n inputs.each(function (item) {\n // don't touch hidden inputs (and Use Default inputs too), bc they may have custom logic\n if ((!item.type || item.type != 'hidden') && !($(item.id + '_inherit') && $(item.id + '_inherit').checked) && //eslint-disable-line\n !(currentConfig['can_edit_price'] != undefined && !currentConfig['can_edit_price']) //eslint-disable-line\n ) {\n item.disabled = false;\n jQuery(item).removeClass('ignore-validate');\n }\n });\n }\n\n if (headElement) {\n headElement.show();\n\n if (headElement.hasClassName('open') && target) {\n target.show();\n } else if (target) {\n target.hide();\n }\n } else {\n if (target) {\n target.show();\n }\n\n if (isAnInputOrSelect && !isInheritCheckboxChecked) {\n if (target) {\n if (target.getAttribute('readonly')) {\n target.disabled = true;\n } else {\n target.disabled = false;\n }\n }\n\n jQuery('#' + idTo).removeClass('ignore-validate');\n }\n }\n } else {\n if (inputs) {\n inputs.each(function (item) {\n // don't touch hidden inputs (and Use Default inputs too), bc they may have custom logic\n if ((!item.type || item.type != 'hidden') && //eslint-disable-line eqeqeq\n !($(item.id + '_inherit') && $(item.id + '_inherit').checked)\n ) {\n item.disabled = true;\n jQuery(item).addClass('ignore-validate');\n }\n });\n }\n\n if (headElement) {\n headElement.hide();\n }\n\n if (target) {\n target.hide();\n }\n\n if (isAnInputOrSelect && !isInheritCheckboxChecked) {\n if (target) {\n target.disabled = true;\n }\n jQuery('#' + idTo).addClass('ignore-validate');\n }\n\n }\n rowElement = $('row_' + idTo);\n\n if (rowElement == undefined && target) { //eslint-disable-line eqeqeq\n rowElement = target.up(this._config['levels_up']);\n\n if (target.type === 'fieldset') {\n rowElement = target;\n }\n }\n\n if (rowElement) {\n if (shouldShowUp) {\n rowElement.show();\n } else {\n rowElement.hide();\n }\n }\n }\n };\n\n window.varienWindowOnload = varienWindowOnload;\n window.varienElementMethods = varienElementMethods;\n});\n","mage/adminhtml/browser.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* global MediabrowserUtility, FORM_KEY, tinyMceEditors */\n/* eslint-disable strict */\ndefine([\n 'jquery',\n 'wysiwygAdapter',\n 'Magento_Ui/js/modal/prompt',\n 'Magento_Ui/js/modal/confirm',\n 'Magento_Ui/js/modal/alert',\n 'Magento_Ui/js/modal/modal',\n 'jquery/ui',\n 'jquery/jstree/jquery.jstree',\n 'mage/mage'\n], function ($, wysiwyg, prompt, confirm, alert) {\n window.MediabrowserUtility = {\n windowId: 'modal_dialog_message',\n\n /**\n * @return {Number}\n */\n getMaxZIndex: function () {\n var max = 0,\n cn = document.body.childNodes,\n i, el, zIndex;\n\n for (i = 0; i < cn.length; i++) {\n el = cn[i];\n zIndex = el.nodeType == 1 ? parseInt(el.style.zIndex, 10) || 0 : 0; //eslint-disable-line eqeqeq\n\n if (zIndex < 10000) {\n max = Math.max(max, zIndex);\n }\n }\n\n return max + 10;\n },\n\n /**\n * @param {*} url\n * @param {*} width\n * @param {*} height\n * @param {*} title\n * @param {Object} options\n */\n openDialog: function (url, width, height, title, options) {\n var windowId = this.windowId,\n content = '<div class=\"popup-window\" id=\"' + windowId + '\"></div>',\n self = this;\n\n if (this.modal) {\n this.modal.html($(content).html());\n\n if (options && typeof options.closed !== 'undefined') {\n this.modal.modal('option', 'closed', options.closed);\n }\n } else {\n this.modal = $(content).modal($.extend({\n title: title || 'Insert File...',\n modalClass: 'magento',\n type: 'slide',\n buttons: []\n }, options));\n }\n this.modal.modal('openModal');\n $.ajax({\n url: url,\n type: 'get',\n context: $(this),\n showLoader: true\n\n }).done(function (data) {\n self.modal.html(data).trigger('contentUpdated');\n });\n },\n\n /**\n * Close dialog.\n */\n closeDialog: function () {\n this.modal.modal('closeModal');\n }\n };\n\n $.widget('mage.mediabrowser', {\n eventPrefix: 'mediabrowser',\n options: {\n targetElementId: null,\n contentsUrl: null,\n onInsertUrl: null,\n newFolderUrl: null,\n deleteFolderUrl: null,\n deleteFilesUrl: null,\n headerText: null,\n tree: null,\n currentNode: null,\n storeId: null,\n showBreadcrumbs: null,\n hidden: 'no-display'\n },\n\n /**\n * Proxy creation\n * @protected\n */\n _create: function () {\n this._on({\n 'click [data-row=file]': 'selectFile',\n 'dblclick [data-row=file]': 'insert',\n 'click #new_folder': 'newFolder',\n 'click #delete_folder': 'deleteFolder',\n 'click #delete_files': 'deleteFiles',\n 'click #insert_files': 'insertSelectedFiles',\n 'fileuploaddone': '_uploadDone',\n 'click [data-row=breadcrumb]': 'selectFolder'\n });\n this.activeNode = null;\n //tree dont use event bubbling\n this.tree = this.element.find('[data-role=tree]');\n this.tree.on('select_node.jstree', $.proxy(this._selectNode, this));\n },\n\n /**\n * @param {jQuery.Event} event\n * @param {Object} data\n * @private\n */\n _selectNode: function (event, data) {\n var node = data.rslt.obj.data('node');\n\n this.activeNode = node;\n this.element.find('#delete_files, #insert_files').toggleClass(this.options.hidden, true);\n this.element.find('#contents').toggleClass(this.options.hidden, false);\n this.element.find('#delete_folder')\n .toggleClass(this.options.hidden, node.id == 'root'); //eslint-disable-line eqeqeq\n this.element.find('#content_header_text')\n .html(node.id == 'root' ? this.headerText : node.text); //eslint-disable-line eqeqeq\n\n this.drawBreadcrumbs(data);\n this.loadFileList(node);\n },\n\n /**\n * @return {*}\n */\n reload: function (uploaded) {\n return this.loadFileList(this.activeNode, uploaded);\n },\n\n /**\n * @param {Object} element\n * @param {*} value\n */\n insertAtCursor: function (element, value) {\n var sel, startPos, endPos, scrollTop;\n\n if ('selection' in document) {\n //For browsers like Internet Explorer\n element.focus();\n sel = document.selection.createRange();\n sel.text = value;\n element.focus();\n } else if (element.selectionStart || element.selectionStart == '0') { //eslint-disable-line eqeqeq\n //For browsers like Firefox and Webkit based\n startPos = element.selectionStart;\n endPos = element.selectionEnd;\n scrollTop = element.scrollTop;\n element.value = element.value.substring(0, startPos) + value +\n element.value.substring(startPos, endPos) + element.value.substring(endPos, element.value.length);\n element.focus();\n element.selectionStart = startPos + value.length;\n element.selectionEnd = startPos + value.length + element.value.substring(startPos, endPos).length;\n element.scrollTop = scrollTop;\n } else {\n element.value += value;\n element.focus();\n }\n },\n\n /**\n * @param {Object} node\n */\n loadFileList: function (node, uploaded) {\n var contentBlock = this.element.find('#contents');\n\n return $.ajax({\n url: this.options.contentsUrl,\n type: 'GET',\n dataType: 'html',\n data: {\n 'form_key': FORM_KEY,\n node: node.id\n },\n context: contentBlock,\n showLoader: true\n }).done(function (data) {\n contentBlock.html(data).trigger('contentUpdated');\n\n if (uploaded) {\n contentBlock.find('.filecnt:last').click();\n }\n });\n },\n\n /**\n * @param {jQuery.Event} event\n */\n selectFolder: function (event) {\n this.element.find('[data-id=\"' + $(event.currentTarget).data('node').id + '\"]>a').click();\n },\n\n /**\n * Insert selected files.\n */\n insertSelectedFiles: function () {\n this.element.find('[data-row=file].selected').trigger('dblclick');\n },\n\n /**\n * @param {jQuery.Event} event\n */\n selectFile: function (event) {\n var fileRow = $(event.currentTarget);\n\n fileRow.toggleClass('selected');\n this.element.find('[data-row=file]').not(fileRow).removeClass('selected');\n this.element.find('#delete_files, #insert_files')\n .toggleClass(this.options.hidden, !fileRow.is('.selected'));\n fileRow.trigger('selectfile');\n },\n\n /**\n * @private\n */\n _uploadDone: function () {\n this.element.find('.file-row').remove();\n this.reload(true);\n },\n\n /**\n * @param {jQuery.Event} event\n * @return {Boolean}\n */\n insert: function (event) {\n var fileRow = $(event.currentTarget),\n targetEl;\n\n if (!fileRow.prop('id')) {\n return false;\n }\n targetEl = this.getTargetElement();\n\n if (!targetEl.length) {\n MediabrowserUtility.closeDialog();\n throw 'Target element not found for content update';\n }\n\n return $.ajax({\n url: this.options.onInsertUrl,\n data: {\n filename: fileRow.attr('id'),\n node: this.activeNode.id,\n store: this.options.storeId,\n 'as_is': targetEl.is('textarea') ? 1 : 0,\n 'force_static_path': targetEl.data('force_static_path') ? 1 : 0,\n 'form_key': FORM_KEY\n },\n context: this,\n showLoader: true\n }).done($.proxy(function (data) {\n if (targetEl.is('textarea')) {\n this.insertAtCursor(targetEl.get(0), data);\n } else {\n targetEl\n .val(data)\n .data('size', fileRow.data('size'))\n .data('mime-type', fileRow.data('mime-type'))\n .trigger('change');\n }\n MediabrowserUtility.closeDialog();\n targetEl.focus();\n jQuery(targetEl).change();\n }, this));\n },\n\n /**\n * Find document target element in next order:\n * in acive file browser opener:\n * - input field with ID: \"src\" in opener window\n * - input field with ID: \"href\" in opener window\n * in document:\n * - element with target ID\n *\n * return {HTMLElement|null}\n */\n getTargetElement: function () {\n var opener, targetElementId;\n\n if (typeof wysiwyg != 'undefined' && wysiwyg.get(this.options.targetElementId)) {\n opener = this.getMediaBrowserOpener() || window;\n targetElementId = tinyMceEditors.get(this.options.targetElementId).getMediaBrowserTargetElementId();\n\n return $(opener.document.getElementById(targetElementId));\n }\n\n return $('#' + this.options.targetElementId);\n },\n\n /**\n * Return opener Window object if it exists, not closed and editor is active\n *\n * return {Object|null}\n */\n getMediaBrowserOpener: function () {\n if (typeof wysiwyg != 'undefined' &&\n wysiwyg.get(this.options.targetElementId) &&\n typeof tinyMceEditors != 'undefined' &&\n !tinyMceEditors.get(this.options.targetElementId).getMediaBrowserOpener().closed\n ) {\n return tinyMceEditors.get(this.options.targetElementId).getMediaBrowserOpener();\n }\n\n return null;\n },\n\n /**\n * New folder.\n */\n newFolder: function () {\n var self = this;\n\n prompt({\n title: this.options.newFolderPrompt,\n actions: {\n /**\n * @param {*} folderName\n */\n confirm: function (folderName) {\n return $.ajax({\n url: self.options.newFolderUrl,\n dataType: 'json',\n data: {\n name: folderName,\n node: self.activeNode.id,\n store: self.options.storeId,\n 'form_key': FORM_KEY\n },\n context: self.element,\n showLoader: true\n }).done($.proxy(function (data) {\n if (data.error) {\n alert({\n content: data.message\n });\n } else {\n self.tree.jstree(\n 'refresh',\n self.element.find('[data-id=\"' + self.activeNode.id + '\"]')\n );\n }\n }, this));\n }\n }\n });\n },\n\n /**\n * Delete folder.\n */\n deleteFolder: function () {\n var self = this;\n\n confirm({\n content: this.options.deleteFolderConfirmationMessage,\n actions: {\n /**\n * Confirm.\n */\n confirm: function () {\n return $.ajax({\n url: self.options.deleteFolderUrl,\n dataType: 'json',\n data: {\n node: self.activeNode.id,\n store: self.options.storeId,\n 'form_key': FORM_KEY\n },\n context: self.element,\n showLoader: true\n }).done($.proxy(function () {\n self.tree.jstree('refresh', self.activeNode.id);\n }, this));\n },\n\n /**\n * @return {Boolean}\n */\n cancel: function () {\n return false;\n }\n }\n });\n },\n\n /**\n * Delete files.\n */\n deleteFiles: function () {\n var self = this;\n\n confirm({\n content: this.options.deleteFileConfirmationMessage,\n actions: {\n /**\n * Confirm.\n */\n confirm: function () {\n var selectedFiles = self.element.find('[data-row=file].selected'),\n ids = selectedFiles.map(function () {\n return $(this).attr('id');\n }).toArray();\n\n return $.ajax({\n url: self.options.deleteFilesUrl,\n data: {\n files: ids,\n store: self.options.storeId,\n 'form_key': FORM_KEY\n },\n context: self.element,\n showLoader: true\n }).done($.proxy(function () {\n self.reload();\n self.element.find('#delete_files, #insert_files').toggleClass(self.options.hidden, true);\n\n $(window).trigger('fileDeleted.mediabrowser', {\n ids: ids\n });\n }, this));\n },\n\n /**\n * @return {Boolean}\n */\n cancel: function () {\n return false;\n }\n }\n });\n },\n\n /**\n * @param {Object} data\n */\n drawBreadcrumbs: function (data) {\n var node, breadcrumbs;\n\n if (this.element.find('#breadcrumbs').length) {\n this.element.find('#breadcrumbs').remove();\n }\n node = data.rslt.obj.data('node');\n\n if (node.id == 'root') { //eslint-disable-line eqeqeq\n return;\n }\n breadcrumbs = $('<ul class=\"breadcrumbs\" id=\"breadcrumbs\" />');\n $(data.rslt.obj.parents('[data-id]').get().reverse()).add(data.rslt.obj).each(function (index, element) {\n var nodeData = $(element).data('node');\n\n if (index > 0) {\n breadcrumbs.append($('<li>\\/</li>'));\n }\n breadcrumbs.append($('<li />')\n .data('node', nodeData).attr('data-row', 'breadcrumb').text(nodeData.text));\n\n });\n\n breadcrumbs.insertAfter(this.element.find('#content_header'));\n }\n });\n\n return window.MediabrowserUtility;\n});\n","mage/adminhtml/wysiwyg/events.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 afterInitialization: 'afterInitialization',\n afterChangeContent: 'afterChangeContent',\n afterUndo: 'afterUndo',\n afterPaste: 'afterPaste',\n beforeSetContent: 'beforeSetContent',\n afterSetContent: 'afterSetContent',\n afterSave: 'afterSave',\n afterOpenFileBrowser: 'afterOpenFileBrowser',\n afterFormSubmit: 'afterFormSubmit',\n afterBlur: 'afterBlur',\n afterFocus: 'afterFocus'\n };\n});\n","mage/adminhtml/wysiwyg/widget.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* global setLocation, Base64, updateElementAtCursor, varienGlobalEvents */\n/* eslint-disable strict */\ndefine([\n 'jquery',\n 'wysiwygAdapter',\n 'Magento_Ui/js/modal/alert',\n 'jquery/ui',\n 'mage/translate',\n 'mage/mage',\n 'mage/validation',\n 'mage/adminhtml/events',\n 'prototype',\n 'Magento_Ui/js/modal/modal'\n], function (jQuery, wysiwyg, alert) {\n var widgetTools = {\n\n /**\n * Sets the widget to be active and is the scope of the slide out if the value is set\n */\n activeSelectedNode: null,\n editMode: false,\n cursorLocation: 0,\n\n /**\n * Set active selected node.\n *\n * @param {Object} activeSelectedNode\n */\n setActiveSelectedNode: function (activeSelectedNode) {\n this.activeSelectedNode = activeSelectedNode;\n },\n\n /**\n * Get active selected node.\n *\n * @returns {null}\n */\n getActiveSelectedNode: function () {\n return this.activeSelectedNode;\n },\n\n /**\n *\n * @param {Boolean} editMode\n */\n setEditMode: function (editMode) {\n this.editMode = editMode;\n },\n\n /**\n * @param {*} id\n * @param {*} html\n * @return {String}\n */\n getDivHtml: function (id, html) {\n\n if (!html) {\n html = '';\n }\n\n return '<div id=\"' + id + '\">' + html + '</div>';\n },\n\n /**\n * @param {Object} transport\n */\n onAjaxSuccess: function (transport) {\n var response;\n\n if (transport.responseText.isJSON()) {\n response = transport.responseText.evalJSON();\n\n if (response.error) {\n throw response;\n } else if (response.ajaxExpired && response.ajaxRedirect) {\n setLocation(response.ajaxRedirect);\n }\n }\n },\n\n dialogOpened: false,\n\n /**\n * @return {Number}\n */\n getMaxZIndex: function () {\n var max = 0,\n cn = document.body.childNodes,\n i, el, zIndex;\n\n for (i = 0; i < cn.length; i++) {\n el = cn[i];\n zIndex = el.nodeType == 1 ? parseInt(el.style.zIndex, 10) || 0 : 0; //eslint-disable-line eqeqeq\n\n if (zIndex < 10000) {\n max = Math.max(max, zIndex);\n }\n }\n\n return max + 10;\n },\n\n /**\n * @param {String} widgetUrl\n */\n openDialog: function (widgetUrl) {\n var oThis = this,\n title = 'Insert Widget',\n mode = 'new',\n dialog;\n\n if (this.editMode) {\n title = 'Edit Widget';\n mode = 'edit';\n }\n\n if (this.dialogOpened) {\n return;\n }\n\n this.dialogWindow = jQuery('<div/>').modal({\n\n title: jQuery.mage.__(title),\n type: 'slide',\n buttons: [],\n\n /**\n * Opened.\n */\n opened: function () {\n dialog = jQuery(this).addClass('loading magento-message');\n\n widgetUrl += 'mode/' + mode;\n\n new Ajax.Updater($(this), widgetUrl, {\n evalScripts: true,\n\n /**\n * On complete.\n */\n onComplete: function () {\n dialog.removeClass('loading');\n }\n });\n },\n\n /**\n * @param {jQuery.Event} e\n * @param {Object} modal\n */\n closed: function (e, modal) {\n modal.modal.remove();\n oThis.dialogOpened = false;\n }\n });\n\n this.dialogOpened = true;\n this.dialogWindow.modal('openModal');\n }\n },\n WysiwygWidget = {};\n\n WysiwygWidget.Widget = Class.create();\n WysiwygWidget.Widget.prototype = {\n /**\n * @param {HTMLElement} formEl\n * @param {HTMLElement} widgetEl\n * @param {*} widgetOptionsEl\n * @param {*} optionsSourceUrl\n * @param {*} widgetTargetId\n */\n initialize: function (formEl, widgetEl, widgetOptionsEl, optionsSourceUrl, widgetTargetId) {\n $(formEl).insert({\n bottom: widgetTools.getDivHtml(widgetOptionsEl)\n });\n\n this.formEl = formEl;\n this.widgetEl = $(widgetEl);\n this.widgetOptionsEl = $(widgetOptionsEl);\n this.optionsUrl = optionsSourceUrl;\n this.optionValues = new Hash({});\n this.widgetTargetId = widgetTargetId;\n\n if (typeof wysiwyg != 'undefined' && wysiwyg.activeEditor()) { //eslint-disable-line eqeqeq\n this.bMark = wysiwyg.activeEditor().selection.getBookmark();\n }\n\n // disable -- Please Select -- option from being re-selected\n this.widgetEl.querySelector('option').setAttribute('disabled', 'disabled');\n\n Event.observe(this.widgetEl, 'change', this.loadOptions.bind(this));\n\n this.initOptionValues();\n },\n\n /**\n * @return {String}\n */\n getOptionsContainerId: function () {\n return this.widgetOptionsEl.id + '_' + this.widgetEl.value.gsub(/\\//, '_');\n },\n\n /**\n * @param {*} containerId\n */\n switchOptionsContainer: function (containerId) {\n $$('#' + this.widgetOptionsEl.id + ' div[id^=' + this.widgetOptionsEl.id + ']').each(function (e) {\n this.disableOptionsContainer(e.id);\n }.bind(this));\n\n if (containerId != undefined) { //eslint-disable-line eqeqeq\n this.enableOptionsContainer(containerId);\n }\n this._showWidgetDescription();\n },\n\n /**\n * @param {*} containerId\n */\n enableOptionsContainer: function (containerId) {\n $$('#' + containerId + ' .widget-option').each(function (e) {\n e.removeClassName('skip-submit');\n\n if (e.hasClassName('obligatory')) {\n e.removeClassName('obligatory');\n e.addClassName('required-entry');\n }\n });\n $(containerId).removeClassName('no-display');\n },\n\n /**\n * @param {*} containerId\n */\n disableOptionsContainer: function (containerId) {\n\n if ($(containerId).hasClassName('no-display')) {\n return;\n }\n $$('#' + containerId + ' .widget-option').each(function (e) {\n // Avoid submitting fields of unactive container\n if (!e.hasClassName('skip-submit')) {\n e.addClassName('skip-submit');\n }\n // Form validation workaround for unactive container\n if (e.hasClassName('required-entry')) {\n e.removeClassName('required-entry');\n e.addClassName('obligatory');\n }\n });\n $(containerId).addClassName('no-display');\n },\n\n /**\n * Assign widget options values when existing widget selected in WYSIWYG.\n *\n * @return {Boolean}\n */\n initOptionValues: function () {\n var e, widgetCode;\n\n if (!this.wysiwygExists()) {\n return false;\n }\n\n e = this.getWysiwygNode();\n\n if (e.localName === 'span') {\n e = e.firstElementChild;\n }\n\n if (e != undefined && e.id) { //eslint-disable-line eqeqeq\n // attempt to Base64-decode id on selected node; exception is thrown if it is in fact not a widget node\n try {\n widgetCode = Base64.idDecode(e.id);\n } catch (ex) {\n return false;\n }\n\n if (widgetCode.indexOf('{{widget') !== -1) {\n this.optionValues = new Hash({});\n widgetCode.gsub(/([a-z0-9\\_]+)\\s*\\=\\s*[\\\"]{1}([^\\\"]+)[\\\"]{1}/i, function (match) {\n\n if (match[1] == 'type') { //eslint-disable-line eqeqeq\n this.widgetEl.value = match[2];\n } else {\n this.optionValues.set(match[1], match[2]);\n }\n\n }.bind(this));\n\n this.loadOptions();\n }\n }\n },\n\n /**\n * Load options.\n */\n loadOptions: function () {\n var optionsContainerId,\n params,\n msg,\n msgTmpl,\n $wrapper,\n typeName = this.optionValues.get('type_name');\n\n if (!this.widgetEl.value) {\n if (typeName) {\n msgTmpl = jQuery.mage.__('The widget %1 is no longer available. Select a different widget.');\n msg = jQuery.mage.__(msgTmpl).replace('%1', typeName);\n\n jQuery('body').notification('clear').notification('add', {\n error: true,\n message: msg,\n\n /**\n * @param {String} message\n */\n insertMethod: function (message) {\n $wrapper = jQuery('<div/>').html(message);\n\n $wrapper.insertAfter('.modal-slide .page-main-actions');\n }\n });\n }\n this.switchOptionsContainer();\n\n return;\n }\n\n optionsContainerId = this.getOptionsContainerId();\n\n if ($(optionsContainerId) != undefined) { //eslint-disable-line eqeqeq\n this.switchOptionsContainer(optionsContainerId);\n\n return;\n }\n\n this._showWidgetDescription();\n\n params = {\n 'widget_type': this.widgetEl.value,\n values: this.optionValues\n };\n new Ajax.Request(this.optionsUrl, {\n parameters: {\n widget: Object.toJSON(params)\n },\n\n /**\n * On success.\n */\n onSuccess: function (transport) {\n try {\n widgetTools.onAjaxSuccess(transport);\n this.switchOptionsContainer();\n\n if ($(optionsContainerId) == undefined) { //eslint-disable-line eqeqeq\n this.widgetOptionsEl.insert({\n bottom: widgetTools.getDivHtml(optionsContainerId, transport.responseText)\n });\n } else {\n this.switchOptionsContainer(optionsContainerId);\n }\n } catch (e) {\n alert({\n content: e.message\n });\n }\n }.bind(this)\n });\n },\n\n /**\n * @private\n */\n _showWidgetDescription: function () {\n var noteCnt = this.widgetEl.next().down('small'),\n descrCnt = $('widget-description-' + this.widgetEl.selectedIndex),\n description;\n\n if (noteCnt != undefined) { //eslint-disable-line eqeqeq\n description = descrCnt != undefined ? descrCnt.innerHTML : ''; //eslint-disable-line eqeqeq\n noteCnt.update(description);\n }\n },\n\n /**\n * Validate field.\n */\n validateField: function () {\n jQuery(this.widgetEl).valid();\n jQuery('#insert_button').removeClass('disabled');\n },\n\n /**\n * Closes the modal\n */\n closeModal: function () {\n widgetTools.dialogWindow.modal('closeModal');\n },\n\n /* eslint-disable max-depth*/\n /**\n * Insert widget.\n */\n insertWidget: function () {\n var validationResult,\n $form = jQuery('#' + this.formEl),\n formElements,\n i,\n params,\n editor,\n activeNode;\n\n // remove cached validator instance, which caches elements to validate\n jQuery.data($form[0], 'validator', null);\n\n $form.validate({\n /**\n * Ignores elements with .skip-submit, .no-display ancestor elements\n */\n ignore: function () {\n return jQuery(this).closest('.skip-submit, .no-display').length;\n },\n errorClass: 'mage-error'\n });\n\n validationResult = $form.valid();\n\n if (validationResult) {\n formElements = [];\n i = 0;\n Form.getElements($(this.formEl)).each(function (e) {\n\n if (!e.hasClassName('skip-submit')) {\n formElements[i] = e;\n i++;\n }\n });\n\n // Add as_is flag to parameters if wysiwyg editor doesn't exist\n params = Form.serializeElements(formElements);\n\n if (!this.wysiwygExists()) {\n params += '&as_is=1';\n }\n\n new Ajax.Request($(this.formEl).action, {\n parameters: params,\n onComplete: function (transport) {\n try {\n editor = wysiwyg.activeEditor();\n\n widgetTools.onAjaxSuccess(transport);\n widgetTools.dialogWindow.modal('closeModal');\n\n if (editor) {\n editor.focus();\n activeNode = widgetTools.getActiveSelectedNode();\n\n if (activeNode) {\n editor.selection.select(activeNode);\n editor.selection.setContent(transport.responseText);\n } else if (this.bMark) {\n wysiwyg.activeEditor().selection.moveToBookmark(this.bMark);\n }\n }\n\n if (!activeNode) {\n this.updateContent(transport.responseText);\n }\n } catch (e) {\n alert({\n content: e.message\n });\n }\n }.bind(this)\n });\n }\n },\n\n /**\n * @param {Object} content\n */\n updateContent: function (content) {\n var textarea;\n\n if (this.wysiwygExists()) {\n wysiwyg.insertContent(content, false);\n } else {\n textarea = document.getElementById(this.widgetTargetId);\n updateElementAtCursor(textarea, content);\n varienGlobalEvents.fireEvent('tinymceChange');\n jQuery(textarea).change();\n }\n },\n\n /**\n * @return {Boolean}\n */\n wysiwygExists: function () {\n return typeof wysiwyg != 'undefined' && wysiwyg.get(this.widgetTargetId);\n },\n\n /**\n * @return {null|wysiwyg.Editor|*}\n */\n getWysiwyg: function () {\n return wysiwyg.activeEditor();\n },\n\n /**\n * @return {*|Element}\n */\n getWysiwygNode: function () {\n return widgetTools.getActiveSelectedNode() || wysiwyg.activeEditor().selection.getNode();\n }\n };\n\n WysiwygWidget.chooser = Class.create();\n WysiwygWidget.chooser.prototype = {\n\n // HTML element A, on which click event fired when choose a selection\n chooserId: null,\n\n // Source URL for Ajax requests\n chooserUrl: null,\n\n // Chooser config\n config: null,\n\n // Chooser dialog window\n dialogWindow: null,\n\n // Chooser content for dialog window\n dialogContent: null,\n\n overlayShowEffectOptions: null,\n overlayHideEffectOptions: null,\n\n /**\n * @param {*} chooserId\n * @param {*} chooserUrl\n * @param {*} config\n */\n initialize: function (chooserId, chooserUrl, config) {\n this.chooserId = chooserId;\n this.chooserUrl = chooserUrl;\n this.config = config;\n },\n\n /**\n * @return {String}\n */\n getResponseContainerId: function () {\n return 'responseCnt' + this.chooserId;\n },\n\n /**\n * @return {jQuery|*|HTMLElement}\n */\n getChooserControl: function () {\n return $(this.chooserId + 'control');\n },\n\n /**\n * @return {jQuery|*|HTMLElement}\n */\n getElement: function () {\n return $(this.chooserId + 'value');\n },\n\n /**\n * @return {jQuery|*|HTMLElement}\n */\n getElementLabel: function () {\n return $(this.chooserId + 'label');\n },\n\n /**\n * Open.\n */\n open: function () {\n $(this.getResponseContainerId()).show();\n },\n\n /**\n * Close.\n */\n close: function () {\n $(this.getResponseContainerId()).hide();\n this.closeDialogWindow();\n },\n\n /**\n * Choose.\n */\n choose: function () {\n // Open dialog window with previously loaded dialog content\n var responseContainerId;\n\n if (this.dialogContent) {\n this.openDialogWindow(this.dialogContent);\n\n return;\n }\n // Show or hide chooser content if it was already loaded\n responseContainerId = this.getResponseContainerId();\n\n // Otherwise load content from server\n new Ajax.Request(this.chooserUrl, {\n parameters: {\n 'element_value': this.getElementValue(),\n 'element_label': this.getElementLabelText()\n },\n\n /**\n * On success.\n */\n onSuccess: function (transport) {\n try {\n widgetTools.onAjaxSuccess(transport);\n this.dialogContent = widgetTools.getDivHtml(responseContainerId, transport.responseText);\n this.openDialogWindow(this.dialogContent);\n } catch (e) {\n alert({\n content: e.message\n });\n }\n }.bind(this)\n });\n },\n\n /**\n * Open dialog winodw.\n *\n * @param {*} content\n */\n openDialogWindow: function (content) {\n this.dialogWindow = jQuery('<div/>').modal({\n title: this.config.buttons.open,\n type: 'slide',\n buttons: [],\n\n /**\n * Opened.\n */\n opened: function () {\n jQuery(this).addClass('magento-message');\n },\n\n /**\n * @param {jQuery.Event} e\n * @param {Object} modal\n */\n closed: function (e, modal) {\n modal.modal.remove();\n this.dialogWindow = null;\n }\n });\n\n this.dialogWindow.modal('openModal').append(content);\n },\n\n /**\n * Close dialog window.\n */\n closeDialogWindow: function () {\n this.dialogWindow.modal('closeModal').remove();\n },\n\n /**\n * @return {*|Number}\n */\n getElementValue: function () {\n return this.getElement().value;\n },\n\n /**\n * @return {String}\n */\n getElementLabelText: function () {\n return this.getElementLabel().innerHTML;\n },\n\n /**\n * @param {*} value\n */\n setElementValue: function (value) {\n this.getElement().value = value;\n },\n\n /**\n * @param {*} value\n */\n setElementLabel: function (value) {\n this.getElementLabel().innerHTML = value;\n }\n };\n\n window.WysiwygWidget = WysiwygWidget;\n window.widgetTools = widgetTools;\n});\n","mage/adminhtml/wysiwyg/tiny_mce/tinymce4Adapter.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* global popups, tinyMceEditors, MediabrowserUtility, Base64 */\n/* eslint-disable strict */\ndefine([\n 'jquery',\n 'underscore',\n 'tinymce4',\n 'mage/adminhtml/events',\n 'mage/adminhtml/wysiwyg/events',\n 'mage/translate',\n 'prototype',\n 'jquery/ui'\n], function (jQuery, _, tinyMCE4, varienGlobalEvents, wysiwygEvents) {\n 'use strict';\n\n var tinyMce4Wysiwyg = Class.create();\n\n tinyMce4Wysiwyg.prototype = {\n mediaBrowserOpener: null,\n mediaBrowserTargetElementId: null,\n magentoVariablesPlugin: null,\n mode: 'exact',\n\n /**\n * @param {*} htmlId\n * @param {Object} config\n */\n initialize: function (htmlId, config) {\n this.id = htmlId;\n this.config = config;\n\n _.bindAll(\n this,\n 'beforeSetContent',\n 'saveContent',\n 'onChangeContent',\n 'openFileBrowser',\n 'updateTextArea',\n 'onUndo',\n 'removeEvents'\n );\n\n varienGlobalEvents.attachEventHandler('tinymceChange', this.onChangeContent);\n varienGlobalEvents.attachEventHandler('tinymceBeforeSetContent', this.beforeSetContent);\n varienGlobalEvents.attachEventHandler('tinymceSetContent', this.updateTextArea);\n varienGlobalEvents.attachEventHandler('tinymceSaveContent', this.saveContent);\n varienGlobalEvents.attachEventHandler('tinymceUndo', this.onUndo);\n\n if (typeof tinyMceEditors === 'undefined') {\n window.tinyMceEditors = $H({});\n }\n\n tinyMceEditors.set(this.id, this);\n },\n\n /**\n * Ensures the undo operation works properly\n */\n onUndo: function () {\n this.addContentEditableAttributeBackToNonEditableNodes();\n },\n\n /**\n * Setup TinyMCE4 editor\n */\n setup: function (mode) {\n var deferreds = [],\n settings,\n self = this;\n\n this.turnOff();\n\n if (this.config.plugins) {\n this.config.plugins.forEach(function (plugin) {\n var deferred;\n\n self.addPluginToToolbar(plugin.name, '|');\n\n if (!plugin.src) {\n return;\n }\n\n deferred = jQuery.Deferred();\n deferreds.push(deferred);\n\n require([plugin.src], function (factoryFn) {\n if (typeof factoryFn === 'function') {\n factoryFn(plugin.options);\n }\n\n tinyMCE4.PluginManager.load(plugin.name, plugin.src);\n deferred.resolve();\n });\n });\n }\n\n if (jQuery.isReady) {\n tinyMCE4.dom.Event.domLoaded = true;\n }\n\n settings = this.getSettings();\n\n if (mode === 'inline') {\n settings.inline = true;\n\n if (!isNaN(settings.toolbarZIndex)) {\n tinyMCE4.ui.FloatPanel.zIndex = settings.toolbarZIndex;\n }\n\n this.removeEvents(self.id);\n }\n\n jQuery.when.apply(jQuery, deferreds).done(function () {\n tinyMCE4.init(settings);\n this.getPluginButtons().hide();\n this.eventBus.attachEventHandler('open_browser_callback', tinyMceEditors.get(self.id).openFileBrowser);\n }.bind(this));\n },\n\n /**\n * Remove events from instance.\n *\n * @param {String} wysiwygId\n */\n removeEvents: function (wysiwygId) {\n var editor;\n\n if (typeof tinyMceEditors !== 'undefined' && tinyMceEditors.get(wysiwygId)) {\n editor = tinyMceEditors.get(wysiwygId);\n varienGlobalEvents.removeEventHandler('tinymceChange', editor.onChangeContent);\n }\n },\n\n /**\n * Add plugin to the toolbar if not added.\n *\n * @param {String} plugin\n * @param {String} separator\n */\n addPluginToToolbar: function (plugin, separator) {\n var plugins = this.config.tinymce4.plugins.split(' '),\n toolbar = this.config.tinymce4.toolbar.split(' ');\n\n if (plugins.indexOf(plugin) === -1) {\n plugins.push(plugin);\n }\n\n if (toolbar.indexOf(plugin) === -1) {\n toolbar.push(separator || '', plugin);\n }\n\n this.config.tinymce4.plugins = plugins.join(' ');\n this.config.tinymce4.toolbar = toolbar.join(' ');\n },\n\n /**\n * Set the status of the toolbar to disabled or enabled (true for enabled, false for disabled)\n * @param {Boolean} enabled\n */\n setToolbarStatus: function (enabled) {\n var controlIds = this.get(this.getId()).theme.panel.rootControl.controlIdLookup;\n\n _.each(controlIds, function (controlId) {\n controlId.disabled(!enabled);\n controlId.canFocus = enabled;\n\n if (controlId.tooltip) {\n controlId.tooltip().state.set('rendered', enabled);\n\n if (enabled) {\n jQuery(controlId.getEl()).children('button').andSelf().removeAttr('style');\n } else {\n jQuery(controlId.getEl()).children('button').andSelf().attr('style', 'color: inherit;' +\n 'background-color: inherit;' +\n 'border-color: transparent;'\n );\n }\n }\n });\n },\n\n /**\n * @return {Object}\n */\n getSettings: function () {\n var settings,\n eventBus = this.eventBus;\n\n settings = {\n selector: '#' + this.getId(),\n theme: 'modern',\n 'entity_encoding': 'raw',\n 'convert_urls': false,\n 'content_css': this.config.tinymce4['content_css'],\n 'relative_urls': true,\n menubar: false,\n plugins: this.config.tinymce4.plugins,\n toolbar: this.config.tinymce4.toolbar,\n adapter: this,\n\n /**\n * @param {Object} editor\n */\n setup: function (editor) {\n var onChange;\n\n editor.on('BeforeSetContent', function (evt) {\n varienGlobalEvents.fireEvent('tinymceBeforeSetContent', evt);\n eventBus.fireEvent(wysiwygEvents.beforeSetContent);\n });\n\n editor.on('SaveContent', function (evt) {\n varienGlobalEvents.fireEvent('tinymceSaveContent', evt);\n eventBus.fireEvent(wysiwygEvents.afterSave);\n });\n\n editor.on('paste', function (evt) {\n varienGlobalEvents.fireEvent('tinymcePaste', evt);\n eventBus.fireEvent(wysiwygEvents.afterPaste);\n });\n\n editor.on('PostProcess', function (evt) {\n varienGlobalEvents.fireEvent('tinymceSaveContent', evt);\n eventBus.fireEvent(wysiwygEvents.afterSave);\n });\n\n editor.on('undo', function (evt) {\n varienGlobalEvents.fireEvent('tinymceUndo', evt);\n eventBus.fireEvent(wysiwygEvents.afterUndo);\n });\n\n editor.on('focus', function () {\n eventBus.fireEvent(wysiwygEvents.afterFocus);\n });\n\n editor.on('blur', function () {\n eventBus.fireEvent(wysiwygEvents.afterBlur);\n });\n\n /**\n * @param {*} evt\n */\n onChange = function (evt) {\n varienGlobalEvents.fireEvent('tinymceChange', evt);\n eventBus.fireEvent(wysiwygEvents.afterChangeContent);\n };\n\n editor.on('Change', onChange);\n editor.on('keyup', onChange);\n\n editor.on('ExecCommand', function (cmd) {\n varienGlobalEvents.fireEvent('tinymceExecCommand', cmd);\n });\n\n editor.on('init', function (args) {\n varienGlobalEvents.fireEvent('wysiwygEditorInitialized', args.target);\n eventBus.fireEvent(wysiwygEvents.afterInitialization);\n });\n }\n };\n\n if (this.config.baseStaticUrl && this.config.baseStaticDefaultUrl) {\n settings['document_base_url'] = this.config.baseStaticUrl;\n }\n // Set the document base URL\n if (this.config['document_base_url']) {\n settings['document_base_url'] = this.config['document_base_url'];\n }\n\n if (this.config['files_browser_window_url']) {\n /**\n * @param {*} fieldName\n * @param {*} url\n * @param {*} objectType\n * @param {*} w\n */\n settings['file_browser_callback'] = function (fieldName, url, objectType, w) {\n var payload = {\n win: w,\n type: objectType,\n field: fieldName\n };\n\n varienGlobalEvents.fireEvent('open_browser_callback', payload);\n this.eventBus.fireEvent('open_browser_callback', payload);\n }.bind(this);\n }\n\n if (this.config.width) {\n settings.width = this.config.width;\n }\n\n if (this.config.height) {\n settings.height = this.config.height;\n }\n\n if (this.config.plugins) {\n settings.magentoPluginsOptions = {};\n\n _.each(this.config.plugins, function (plugin) {\n settings.magentoPluginsOptions[plugin.name] = plugin.options;\n });\n }\n\n if (this.config.settings) {\n Object.extend(settings, this.config.settings);\n }\n\n return settings;\n },\n\n /**\n * @param {String} id\n */\n get: function (id) {\n return tinyMCE4.get(id);\n },\n\n /**\n * @return {String|null}\n */\n getId: function () {\n return this.id || (this.activeEditor() ? this.activeEditor().id : null) || tinyMceEditors.values()[0].id;\n },\n\n /**\n * @return {Object}\n */\n activeEditor: function () {\n return tinyMCE4.activeEditor;\n },\n\n /**\n * Insert content to active editor.\n *\n * @param {String} content\n * @param {Boolean} ui\n */\n insertContent: function (content, ui) {\n this.activeEditor().execCommand('mceInsertContent', typeof ui !== 'undefined' ? ui : false, content);\n },\n\n /**\n * Replace entire contents of wysiwyg with string content parameter\n *\n * @param {String} content\n */\n setContent: function (content) {\n this.get(this.getId()).setContent(content);\n },\n\n /**\n * Set caret location in WYSIWYG editor.\n *\n * @param {Object} targetElement\n */\n setCaretOnElement: function (targetElement) {\n this.activeEditor().selection.select(targetElement);\n this.activeEditor().selection.collapse();\n },\n\n /**\n * @param {Object} o\n */\n openFileBrowser: function (o) {\n var typeTitle = this.translate('Select Images'),\n storeId = this.config['store_id'] !== null ? this.config['store_id'] : 0,\n frameDialog = jQuery('div.mce-container[role=\"dialog\"]'),\n wUrl = this.config['files_browser_window_url'] +\n 'target_element_id/' + this.getId() + '/' +\n 'store/' + storeId + '/';\n\n this.mediaBrowserOpener = o.win;\n this.mediaBrowserTargetElementId = o.field;\n\n if (typeof o.type !== 'undefined' && o.type !== '') { //eslint-disable-line eqeqeq\n wUrl = wUrl + 'type/' + o.type + '/';\n }\n\n frameDialog.hide();\n jQuery('#mce-modal-block').hide();\n\n require(['mage/adminhtml/browser'], function () {\n MediabrowserUtility.openDialog(wUrl, false, false, typeTitle, {\n /**\n * Closed.\n */\n closed: function () {\n frameDialog.show();\n jQuery('#mce-modal-block').show();\n }\n });\n });\n },\n\n /**\n * @param {String} string\n * @return {String}\n */\n translate: function (string) {\n return jQuery.mage.__ ? jQuery.mage.__(string) : string;\n },\n\n /**\n * @return {null}\n */\n getMediaBrowserOpener: function () {\n return this.mediaBrowserOpener;\n },\n\n /**\n * @return {null}\n */\n getMediaBrowserTargetElementId: function () {\n return this.mediaBrowserTargetElementId;\n },\n\n /**\n * @return {jQuery|*|HTMLElement}\n */\n getToggleButton: function () {\n return $('toggle' + this.getId());\n },\n\n /**\n * Get plugins button.\n */\n getPluginButtons: function () {\n return jQuery('#buttons' + this.getId() + ' > button.plugin');\n },\n\n /**\n * @param {*} mode\n * @return {wysiwygSetup}\n */\n turnOn: function (mode) {\n this.closePopups();\n\n this.setup(mode);\n\n this.getPluginButtons().hide();\n\n tinyMCE4.execCommand('mceAddControl', false, this.getId());\n\n return this;\n },\n\n /**\n * @param {String} name\n */\n closeEditorPopup: function (name) {\n if (typeof popups !== 'undefined' && popups[name] !== undefined && !popups[name].closed) {\n popups[name].close();\n }\n },\n\n /**\n * @return {wysiwygSetup}\n */\n turnOff: function () {\n this.closePopups();\n\n this.getPluginButtons().show();\n\n tinyMCE4.execCommand('mceRemoveEditor', false, this.getId());\n\n return this;\n },\n\n /**\n * Close popups.\n */\n closePopups: function () {\n // close all popups to avoid problems with updating parent content area\n varienGlobalEvents.fireEvent('wysiwygClosePopups');\n this.closeEditorPopup('browser_window' + this.getId());\n },\n\n /**\n * @return {Boolean}\n */\n toggle: function () {\n if (!tinyMCE4.get(this.getId())) {\n this.turnOn();\n\n return true;\n }\n this.turnOff();\n\n return false;\n },\n\n /**\n * On form validation.\n */\n onFormValidation: function () {\n if (tinyMCE4.get(this.getId())) {\n $(this.getId()).value = tinyMCE4.get(this.getId()).getContent();\n }\n },\n\n /**\n * On change content.\n */\n onChangeContent: function () {\n // Add \"changed\" to tab class if it exists\n var tab;\n\n this.updateTextArea();\n\n if (this.config['tab_id']) {\n tab = $$('a[id$=' + this.config['tab_id'] + ']')[0];\n\n if ($(tab) != undefined && $(tab).hasClassName('tab-item-link')) { //eslint-disable-line eqeqeq\n $(tab).addClassName('changed');\n }\n }\n },\n\n /**\n * @param {Object} o\n */\n beforeSetContent: function (o) {\n o.content = this.encodeContent(o.content);\n },\n\n /**\n * @param {Object} o\n */\n saveContent: function (o) {\n o.content = this.decodeContent(o.content);\n },\n\n /**\n * Return the content stored in the WYSIWYG field\n * @param {String} id\n * @return {String}\n */\n getContent: function (id) {\n return id ? this.get(id).getContent() : this.get(this.getId()).getContent();\n },\n\n /**\n * @returns {Object}\n */\n getAdapterPrototype: function () {\n return tinyMce4Wysiwyg;\n },\n\n /**\n * Fix range selection placement when typing. This fixes MAGETWO-84769\n * @param {Object} editor\n */\n fixRangeSelection: function (editor) {\n var selection = editor.selection,\n dom = editor.dom,\n rng = dom.createRng(),\n doc = editor.getDoc(),\n markerHtml,\n marker;\n\n // Validate the range we're trying to fix is contained within the current editors document\n if (!selection.getContent().length && jQuery.contains(doc, selection.getRng().startContainer)) {\n markerHtml = '<span id=\"mce_marker\" data-mce-type=\"bookmark\">\\uFEFF</span>';\n selection.setContent(markerHtml);\n marker = dom.get('mce_marker');\n rng.setStartBefore(marker);\n rng.setEndBefore(marker);\n dom.remove(marker);\n selection.setRng(rng);\n }\n },\n\n /**\n * Update text area.\n */\n updateTextArea: function () {\n var editor = this.get(this.getId()),\n content;\n\n if (!editor || editor.id !== this.activeEditor().id) {\n return;\n }\n\n this.addContentEditableAttributeBackToNonEditableNodes();\n this.fixRangeSelection(editor);\n\n content = editor.getContent();\n content = this.decodeContent(content);\n\n this.getTextArea().val(content).trigger('change');\n },\n\n /**\n * @return {Object} jQuery textarea element\n */\n getTextArea: function () {\n return jQuery('#' + this.getId());\n },\n\n /**\n * Set the status of the editor and toolbar\n *\n * @param {Boolean} enabled\n */\n setEnabledStatus: function (enabled) {\n if (this.activeEditor()) {\n this.activeEditor().getBody().setAttribute('contenteditable', enabled);\n this.activeEditor().readonly = !enabled;\n this.setToolbarStatus(enabled);\n }\n\n if (enabled) {\n this.getTextArea().removeProp('disabled');\n } else {\n this.getTextArea().prop('disabled', 'disabled');\n }\n },\n\n /**\n * Retrieve directives URL with substituted directive value.\n *\n * @param {String} directive\n */\n makeDirectiveUrl: function (directive) {\n return this.config['directives_url']\n .replace(/directive/, 'directive/___directive/' + directive)\n .replace(/\\/$/, '');\n },\n\n /**\n * Convert {{directive}} style attributes syntax to absolute URLs\n * @param {Object} content\n * @return {*}\n */\n encodeDirectives: function (content) {\n // collect all HTML tags with attributes that contain directives\n return content.gsub(/<([a-z0-9\\-\\_]+[^>]+?)([a-z0-9\\-\\_]+=\"[^\"]*?\\{\\{.+?\\}\\}.*?\".*?)>/i, function (match) {\n var attributesString = match[2],\n decodedDirectiveString;\n\n // process tag attributes string\n attributesString = attributesString.gsub(/([a-z0-9\\-\\_]+)=\"(.*?)(\\{\\{.+?\\}\\})(.*?)\"/i, function (m) {\n decodedDirectiveString = encodeURIComponent(Base64.mageEncode(m[3].replace(/"/g, '\"')));\n\n return m[1] + '=\"' + m[2] + this.makeDirectiveUrl(decodedDirectiveString) + m[4] + '\"';\n }.bind(this));\n\n return '<' + match[1] + attributesString + '>';\n }.bind(this));\n },\n\n /**\n * Convert absolute URLs to {{directive}} style attributes syntax\n * @param {Object} content\n * @return {*}\n */\n decodeDirectives: function (content) {\n var directiveUrl = this.makeDirectiveUrl('%directive%').split('?')[0], // remove query string from directive\n // escape special chars in directives url to use in regular expression\n regexEscapedDirectiveUrl = directiveUrl.replace(/([$^.?*!+:=()\\[\\]{}|\\\\])/g, '\\\\$1'),\n regexDirectiveUrl = regexEscapedDirectiveUrl\n .replace(\n '%directive%',\n '([a-zA-Z0-9,_-]+(?:%2[A-Z]|)+\\/?)(?:(?!\").)*'\n ) + '/?(\\\\\\\\?[^\"]*)?', // allow optional query string\n reg = new RegExp(regexDirectiveUrl);\n\n return content.gsub(reg, function (match) {\n return Base64.mageDecode(decodeURIComponent(match[1]).replace(/\\/$/, '')).replace(/\"/g, '"');\n });\n },\n\n /**\n * @param {Object} attributes\n * @return {Object}\n */\n parseAttributesString: function (attributes) {\n var result = {};\n\n // Decode " entity, as regex below does not support encoded quote\n attributes = attributes.replace(/"/g, '\"');\n\n attributes.gsub(\n /(\\w+)(?:\\s*=\\s*(?:(?:\"((?:\\\\.|[^\"])*)\")|(?:'((?:\\\\.|[^'])*)')|([^>\\s]+)))?/,\n function (match) {\n result[match[1]] = match[2];\n }\n );\n\n return result;\n },\n\n /**\n * @param {Object} content\n * @return {*}\n */\n decodeContent: function (content) {\n if (this.config['add_directives']) {\n content = this.decodeDirectives(content);\n }\n\n content = varienGlobalEvents.fireEventReducer('wysiwygDecodeContent', content);\n\n return content;\n },\n\n /**\n * @param {Object} content\n * @return {*}\n */\n encodeContent: function (content) {\n if (this.config['add_directives']) {\n content = this.encodeDirectives(content);\n }\n\n content = varienGlobalEvents.fireEventReducer('wysiwygEncodeContent', content);\n\n return content;\n },\n\n /**\n * Reinstate contenteditable attributes on .mceNonEditable nodes\n */\n addContentEditableAttributeBackToNonEditableNodes: function () {\n jQuery('.mceNonEditable', this.activeEditor().getDoc()).attr('contenteditable', false);\n }\n };\n\n return tinyMce4Wysiwyg.prototype;\n});\n","mage/adminhtml/wysiwyg/tiny_mce/setup.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 'underscore',\n 'wysiwygAdapter',\n 'module',\n 'mage/translate',\n 'prototype',\n 'mage/adminhtml/events',\n 'mage/adminhtml/browser'\n], function (jQuery, _, wysiwygAdapter, module) {\n var baseConfig = module.config().config || {},\n wysiwygSetup = Class.create({\n wysiwygInstance: null\n });\n\n wysiwygSetup.prototype = {\n\n /**\n * @param {*} htmlId\n * @param {Object} config\n */\n initialize: function (htmlId, config) {\n var WysiwygInstancePrototype = new wysiwygAdapter.getAdapterPrototype();\n\n _.bindAll(this, 'openFileBrowser');\n\n config = _.extend({}, baseConfig, config || {});\n this.wysiwygInstance = new WysiwygInstancePrototype(htmlId, config);\n this.wysiwygInstance.eventBus = this.eventBus = new window.varienEvents();\n },\n\n /**\n * @param {*} mode\n */\n setup: function (mode) {\n this.wysiwygInstance.setup(mode);\n },\n\n /**\n * @param {Object} o\n */\n openFileBrowser: function (o) {\n this.wysiwygInstance.openFileBrowser(o);\n },\n\n /**\n * @return {Boolean}\n */\n toggle: function () {\n return this.wysiwygInstance.toggle();\n },\n\n /**\n * On form validation.\n */\n onFormValidation: function () {\n this.wysiwygInstance.onFormValidation();\n },\n\n /**\n * Encodes the content so it can be inserted into the wysiwyg\n * @param {String} content - The content to be encoded\n *\n * @returns {*} - The encoded content\n */\n updateContent: function (content) {\n return this.wysiwygInstance.encodeContent(content);\n }\n\n };\n window.wysiwygSetup = wysiwygSetup;\n\n return wysiwygSetup;\n});\n","mage/adminhtml/wysiwyg/tiny_mce/html5-schema.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 /* eslint-disable max-len */\n\n var schema = {\n blockContent: [\n 'address', 'article', 'aside', 'blockquote', 'details', 'dialog', 'div', 'dl', 'fieldset',\n 'figure', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'header', 'hgroup', 'hr',\n 'menu', 'nav', 'ol', 'p', 'pre', 'section', 'table', 'ul'\n ],\n phrasingContent: [\n '#comment', '#text', 'a', 'abbr', 'audio', 'b', 'bdi', 'bdo', 'br', 'button', 'canvas',\n 'cite','code', 'command', 'datalist', 'del', 'dfn', 'em', 'embed', 'i', 'iframe', 'img',\n 'input', 'ins', 'kbd', 'keygen', 'label', 'map', 'mark', 'meter', 'noscript', 'object',\n 'output', 'picture', 'progress', 'q', 'ruby', 's', 'samp', 'script', 'select', 'small',\n 'span', 'strong', 'sub', 'sup', 'textarea', 'time', 'u', 'var', 'video', 'wbr'\n ],\n blockElements: [\n 'address', 'article', 'aside', 'blockquote', 'caption', 'center', 'datalist', 'dd', 'dir', 'div',\n 'dl', 'dt', 'fieldset', 'figcaption', 'figure', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',\n 'header', 'hgroup', 'hr', 'isindex', 'li', 'menu', 'nav', 'noscript', 'ol', 'optgroup', 'option',\n 'p', 'pre', 'section', 'select', 'table', 'tbody', 'td', 'tfoot', 'th', 'thead', 'tr', 'ul'\n ],\n boolAttrs: [\n 'autoplay', 'checked', 'compact', 'controls', 'declare', 'defer', 'disabled', 'ismap', 'loop',\n 'multiple', 'nohref', 'noresize', 'noshade', 'nowrap', 'readonly', 'selected'\n ],\n shortEnded: [\n 'area', 'base', 'basefont', 'br', 'col', 'embed', 'frame', 'hr', 'img', 'input', 'isindex',\n 'link', 'meta', 'param', 'source', 'track', 'wbr'\n ],\n whiteSpace: [\n 'audio', 'iframe', 'noscript', 'object', 'pre', 'script', 'style', 'textarea', 'video'\n ],\n selfClosing: [\n 'colgroup', 'dd', 'dt', 'li', 'option', 'p', 'td', 'tfoot', 'th', 'thead', 'tr'\n ]\n };\n\n schema.flowContent = schema.blockContent.concat(schema.phrasingContent, ['style']);\n schema.nonEmpty = ['td', 'th', 'iframe', 'video', 'audio', 'object', 'script', 'i', 'em', 'span'].concat(schema.shortEnded);\n\n _.extend(schema, (function (phrasingContent, flowContent) {\n var validElements = [],\n validChildren = [],\n compiled = {},\n globalAttrs,\n rawData;\n\n globalAttrs = [\n 'id', 'dir', 'lang', 'class', 'style', 'title', 'hidden', 'onclick', 'onkeyup',\n 'tabindex', 'dropzone', 'accesskey', 'draggable', 'translate', 'onmouseup',\n 'onkeydown', 'spellcheck', 'ondblclick', 'onmouseout', 'onkeypress', 'contextmenu',\n 'onmousedown', 'onmouseover', 'onmousemove', 'contenteditable'\n ];\n\n rawData = [\n ['html', 'manifest', 'head body'],\n ['head', '', 'base command link meta noscript script style title'],\n ['title hr noscript br'],\n ['base', 'href target'],\n ['link', 'href rel media hreflang type sizes hreflang'],\n ['meta', 'name http-equiv content charset'],\n ['style', 'media type scoped'],\n ['script', 'src async defer type charset'],\n ['body', 'onafterprint onbeforeprint onbeforeunload onblur onerror onfocus ' +\n 'onhashchange onload onmessage onoffline ononline onpagehide onpageshow ' +\n 'onpopstate onresize onscroll onstorage onunload background bgcolor text link vlink alink', flowContent\n ],\n ['caption', '', _.without(flowContent, 'table')],\n ['address dt dd div', '', flowContent],\n ['h1 h2 h3 h4 h5 h6 pre p abbr code var samp kbd sub sup i b u bdo span legend em strong small s cite dfn', '', phrasingContent],\n ['blockquote', 'cite', flowContent],\n ['ol', 'reversed start type', 'li'],\n ['ul', 'type compact', 'li'],\n ['li', 'value type', flowContent],\n ['dl', '', 'dt dd'],\n ['a', 'href target rel media hreflang type charset name rev shape coords download', phrasingContent],\n ['q', 'cite', phrasingContent],\n ['ins del', 'cite datetime', flowContent],\n ['img', 'src sizes srcset alt usemap ismap width height name longdesc align border hspace vspace'],\n ['iframe', 'src name width height longdesc frameborder marginwidth marginheight scrolling align sandbox seamless allowfullscreen', flowContent],\n ['embed', 'src type width height'],\n ['object', 'data type typemustmatch name usemap form width height declare classid code codebase codetype archive standby align border hspace vspace', flowContent.concat(['param'])],\n ['param', 'name value valuetype type'],\n ['map', 'name', flowContent.concat(['area'])],\n ['area', 'alt coords shape href target rel media hreflang type nohref'],\n ['table', 'border summary width frame rules cellspacing cellpadding align bgcolor', 'caption colgroup thead tfoot tbody tr col'],\n ['colgroup', 'span width align char charoff valign', 'col'],\n ['col', 'span'],\n ['tbody thead tfoot', 'align char charoff valign', 'tr'],\n ['tr', 'align char charoff valign bgcolor', 'td th'],\n ['td', 'colspan rowspan headers abbr axis scope align char charoff valign nowrap bgcolor width height', flowContent],\n ['th', 'colspan rowspan headers scope abbr axis align char charoff valign nowrap bgcolor width height accept', flowContent],\n ['form', 'accept-charset action autocomplete enctype method name novalidate target onsubmit onreset', flowContent],\n ['fieldset', 'disabled form name', flowContent.concat(['legend'])],\n ['label', 'form for', phrasingContent],\n ['input', 'accept alt autocomplete checked dirname disabled form formaction formenctype formmethod formnovalidate ' +\n 'formtarget height list max maxlength min multiple name pattern readonly required size src step type value width usemap align'\n ],\n ['button', 'disabled form formaction formenctype formmethod formnovalidate formtarget name type value', phrasingContent],\n ['select', 'disabled form multiple name required size onfocus onblur onchange', 'option optgroup'],\n ['optgroup', 'disabled label', 'option'],\n ['option', 'disabled label selected value'],\n ['textarea', 'cols dirname disabled form maxlength name readonly required rows wrap'],\n ['menu', 'type label', flowContent.concat(['li'])],\n ['noscript', '', flowContent],\n ['wbr'],\n ['ruby', '', phrasingContent.concat(['rt', 'rp'])],\n ['figcaption', '', flowContent],\n ['mark rt rp summary bdi', '', phrasingContent],\n ['canvas', 'width height', flowContent],\n ['video', 'src crossorigin poster preload autoplay mediagroup loop muted controls width height buffered', flowContent.concat(['track', 'source'])],\n ['audio', 'src crossorigin preload autoplay mediagroup loop muted controls buffered volume', flowContent.concat(['track', 'source'])],\n ['picture', '', 'img source'],\n ['source', 'src srcset type media sizes'],\n ['track', 'kind src srclang label default'],\n ['datalist', '', phrasingContent.concat(['option'])],\n ['article section nav aside header footer', '', flowContent],\n ['hgroup', '', 'h1 h2 h3 h4 h5 h6'],\n ['figure', '', flowContent.concat(['figcaption'])],\n ['time', 'datetime', phrasingContent],\n ['dialog', 'open', flowContent],\n ['command', 'type label icon disabled checked radiogroup command'],\n ['output', 'for form name', phrasingContent],\n ['progress', 'value max', phrasingContent],\n ['meter', 'value min max low high optimum', phrasingContent],\n ['details', 'open', flowContent.concat(['summary'])],\n ['keygen', 'autofocus challenge disabled form keytype name'],\n ['script', 'language xml:space'],\n ['style', 'xml:space'],\n ['embed', 'align name hspace vspace'],\n ['br', 'clear'],\n ['applet', 'codebase archive code object alt name width height align hspace vspace'],\n ['font basefont', 'size color face'],\n ['h1 h2 h3 h4 h5 h6 div p legend caption', 'align'],\n ['ol dl menu dir', 'compact'],\n ['pre', 'width xml:space'],\n ['hr', 'align noshade size width'],\n ['isindex', 'prompt'],\n ['col', 'width align char charoff valign'],\n ['input button select textarea', 'autofocus'],\n ['input textarea', 'placeholder onselect onchange onfocus onblur'],\n ['link script img', 'crossorigin']\n ];\n\n rawData.forEach(function (data) {\n var nodes = data[0].split(' '),\n attributes = data[1] || [],\n children = data[2] || [],\n ni = nodes.length,\n nodeName,\n schemaData;\n\n if (typeof attributes === 'string') {\n attributes = attributes.split(' ');\n }\n\n if (typeof children === 'string') {\n children = children.split(' ');\n }\n\n while (ni--) {\n nodeName = nodes[ni];\n schemaData = compiled[nodeName] || {};\n\n compiled[nodeName] = {\n attributes: _.union(schemaData.attributes, globalAttrs, attributes),\n children: _.union(schemaData.children, children)\n };\n }\n });\n\n ['a', 'dfn', 'form', 'meter', 'progress'].forEach(function (nodeName) {\n var node = compiled[nodeName];\n\n node.children = _.without(node.children, nodeName);\n });\n\n _.each(compiled, function (node, nodeName) {\n var filteredAttributes = [];\n\n _.each(node.attributes, function (attribute) { //eslint-disable-line max-nested-callbacks\n // Disallowing usage of 'on*' attributes.\n if (!/^on/.test(attribute)) {\n filteredAttributes.push(attribute);\n }\n });\n\n node.attributes = filteredAttributes;\n\n validElements.push(nodeName + '[' + node.attributes.join('|') + ']');\n validChildren.push(nodeName + '[' + node.children.join('|') + ']');\n });\n\n return {\n nodes: compiled,\n validElements: validElements,\n validChildren: validChildren\n };\n })(schema.phrasingContent, schema.flowContent));\n\n return schema;\n});\n","mage/adminhtml/wysiwyg/tiny_mce/plugins/magentowidget/editor_plugin.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* global tinymce, widgetTools, jQuery, Base64 */\n/* eslint-disable strict */\ndefine([\n 'wysiwygAdapter',\n 'mage/adminhtml/events',\n 'mage/adminhtml/wysiwyg/widget'\n], function (wysiwyg, varienGlobalEvents) {\n return function (config) {\n tinymce.create('tinymce.plugins.magentowidget', {\n\n /**\n * @param {tinymce.Editor} editor - Editor instance that the plugin is initialized in.\n * @param {String} url - Absolute URL to where the plugin is located.\n */\n init: function (editor, url) {\n var self = this;\n\n this.activePlaceholder = null;\n\n editor.addCommand('mceMagentowidget', function (img) {\n if (self.activePlaceholder) {\n img = self.activePlaceholder;\n }\n\n widgetTools.setActiveSelectedNode(img);\n widgetTools.openDialog(\n config['window_url'] + 'widget_target_id/' + editor.getElement().id + '/'\n );\n });\n\n // Register Widget plugin button\n editor.addButton('magentowidget', {\n title: jQuery.mage.__('Insert Widget'),\n cmd: 'mceMagentowidget',\n image: url + '/img/icon.png',\n\n /**\n * Fires after the rendering has completed. This ensures the editor will be instantiated\n */\n onPostRender: function () {\n var ctrl = this;\n\n // Add a node change handler, selects the button in the UI when a image is selected\n editor.on('nodeChange', function (e) {\n var placeholder = e.element;\n\n if (self.isWidgetPlaceholderSelected(placeholder)) {\n widgetTools.setEditMode(true);\n ctrl.active(true);\n } else {\n widgetTools.setEditMode(false);\n ctrl.active(false);\n }\n });\n }\n });\n\n // Add a widget placeholder image double click callback\n editor.on('dblClick', function (e) {\n var placeholder = e.target;\n\n if (self.isWidgetPlaceholderSelected(placeholder)) {\n widgetTools.setEditMode(true);\n this.execCommand('mceMagentowidget', null);\n }\n });\n\n /**\n * Attach event handler for when wysiwyg editor is about to encode its content\n */\n varienGlobalEvents.attachEventHandler('wysiwygEncodeContent', function (content) {\n content = self.encodeWidgets(self.decodeWidgets(content));\n content = self.removeDuplicateAncestorWidgetSpanElement(content);\n\n return content;\n });\n\n /**\n * Attach event handler for when wysiwyg editor is about to decode its content\n */\n varienGlobalEvents.attachEventHandler('wysiwygDecodeContent', function (content) {\n content = self.decodeWidgets(content);\n\n return content;\n });\n\n /**\n * Attach event handler for when popups associated with wysiwyg are about to be closed\n */\n varienGlobalEvents.attachEventHandler('wysiwygClosePopups', function () {\n wysiwyg.closeEditorPopup('widget_window' + wysiwyg.getId());\n });\n },\n\n /**\n * @param {Object} placeholder - Contains the selected node\n * @returns {Boolean}\n */\n isWidgetPlaceholderSelected: function (placeholder) {\n var isSelected = false;\n\n if (placeholder.nodeName &&\n (placeholder.nodeName === 'SPAN' || placeholder.nodeName === 'IMG') &&\n placeholder.className && placeholder.className.indexOf('magento-widget') !== -1\n ) {\n this.activePlaceholder = placeholder;\n isSelected = true;\n } else {\n this.activePlaceholder = null;\n }\n\n return isSelected;\n },\n\n /**\n * Convert {{widget}} style syntax to image placeholder HTML\n * @param {String} content\n * @return {*}\n */\n encodeWidgets: function (content) {\n return content.gsub(/\\{\\{widget(.*?)\\}\\}/i, function (match) {\n var attributes = wysiwyg.parseAttributesString(match[1]),\n imageSrc,\n imageHtml = '';\n\n if (attributes.type) {\n attributes.type = attributes.type.replace(/\\\\\\\\/g, '\\\\');\n imageSrc = config.placeholders[attributes.type];\n\n if (config.types.indexOf(attributes['type_name']) > -1) {\n imageHtml += '<span class=\"magento-placeholder magento-widget mceNonEditable\" ' +\n 'contenteditable=\"false\">';\n } else {\n imageSrc = config['error_image_url'];\n imageHtml += '<span ' +\n 'class=\"magento-placeholder magento-placeholder-error magento-widget mceNonEditable\" ' +\n 'contenteditable=\"false\">';\n }\n\n imageHtml += '<img';\n imageHtml += ' id=\"' + Base64.idEncode(match[0]) + '\"';\n imageHtml += ' src=\"' + imageSrc + '\"';\n imageHtml += ' />';\n\n if (attributes['type_name']) {\n imageHtml += attributes['type_name'];\n }\n\n imageHtml += '</span>';\n\n return imageHtml;\n }\n });\n },\n\n /**\n * Convert image placeholder HTML to {{widget}} style syntax\n * @param {String} content\n * @return {*}\n */\n decodeWidgets: function (content) {\n return content.gsub(\n /(<span class=\"[^\"]*magento-widget[^\"]*\"[^>]*>)?<img([^>]+id=\"[^>]+)>(([^>]*)<\\/span>)?/i,\n function (match) {\n var attributes = wysiwyg.parseAttributesString(match[2]),\n widgetCode;\n\n if (attributes.id) {\n widgetCode = Base64.idDecode(attributes.id);\n\n if (widgetCode.indexOf('{{widget') !== -1) {\n return widgetCode;\n }\n }\n\n return match[0];\n }\n );\n },\n\n /**\n * Tinymce has strange behavior with html and this removes one of its side-effects\n * @param {String} content\n * @return {String}\n */\n removeDuplicateAncestorWidgetSpanElement: function (content) {\n var parser, doc;\n\n if (!window.DOMParser) {\n return content;\n }\n\n parser = new DOMParser();\n doc = parser.parseFromString(content.replace(/"/g, '&quot;'), 'text/html');\n\n [].forEach.call(doc.querySelectorAll('.magento-widget'), function (widgetEl) {\n var widgetChildEl = widgetEl.querySelector('.magento-widget');\n\n if (!widgetChildEl) {\n return;\n }\n\n [].forEach.call(widgetEl.childNodes, function (el) {\n widgetEl.parentNode.insertBefore(el, widgetEl);\n });\n\n widgetEl.parentNode.removeChild(widgetEl);\n });\n\n return doc.body ? doc.body.innerHTML.replace(/&quot;/g, '"') : content;\n },\n\n /**\n * @return {Object}\n */\n getInfo: function () {\n return {\n longname: 'Magento Widget Manager Plugin',\n author: 'Magento Core Team',\n authorurl: 'http://magentocommerce.com',\n infourl: 'http://magentocommerce.com',\n version: '1.0'\n };\n }\n });\n\n // Register plugin\n tinymce.PluginManager.add('magentowidget', tinymce.plugins.magentowidget);\n };\n});\n","mage/adminhtml/wysiwyg/tiny_mce/plugins/magentovariable/editor_plugin.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* global tinymce, MagentovariablePlugin, varienGlobalEvents, Base64 */\n/* eslint-disable strict */\ndefine([\n 'Magento_Variable/js/config-directive-generator',\n 'Magento_Variable/js/custom-directive-generator',\n 'wysiwygAdapter',\n 'jquery'\n], function (configDirectiveGenerator, customDirectiveGenerator, wysiwyg, jQuery) {\n return function (config) {\n tinymce.create('tinymce.plugins.magentovariable', {\n\n /**\n * Initialize editor plugin.\n *\n * @param {tinymce.editor} editor - Editor instance that the plugin is initialized in.\n * @param {String} url - Absolute URL to where the plugin is located.\n */\n init: function (editor, url) {\n var self = this;\n\n /**\n * Add new command to open variables selector slideout.\n */\n editor.addCommand('openVariablesSlideout', function (commandConfig) {\n var selectedElement;\n\n if (commandConfig) {\n selectedElement = commandConfig.selectedElement;\n } else {\n selectedElement = tinymce.activeEditor.selection.getNode();\n }\n MagentovariablePlugin.setEditor(editor);\n MagentovariablePlugin.loadChooser(\n config.url,\n wysiwyg.getId(),\n selectedElement\n );\n });\n\n /**\n * Add button to the editor toolbar.\n */\n editor.addButton('magentovariable', {\n title: jQuery.mage.__('Insert Variable'),\n tooltip: jQuery.mage.__('Insert Variable'),\n cmd: 'openVariablesSlideout',\n image: url + '/img/icon.png',\n\n /**\n * Highlight or dismiss Insert Variable button when variable is selected or deselected.\n */\n onPostRender: function () {\n var _this = this,\n\n /**\n * Toggle active state of Insert Variable button.\n *\n * @param {Object} e\n */\n toggleVariableButton = function (e) {\n _this.active(false);\n\n if (jQuery(e.target).hasClass('magento-variable')) {\n _this.active(true);\n }\n };\n\n editor.on('click', toggleVariableButton);\n editor.on('change', toggleVariableButton);\n }\n });\n\n /**\n * Double click handler on the editor to handle dbl click on variable placeholder.\n */\n editor.on('dblclick', function (evt) {\n if (jQuery(evt.target).hasClass('magento-variable')) {\n editor.selection.collapse(false);\n editor.execCommand('openVariablesSlideout', {\n ui: true,\n selectedElement: evt.target\n });\n }\n });\n\n /**\n * Attach event handler for when wysiwyg editor is about to encode its content\n */\n varienGlobalEvents.attachEventHandler('wysiwygEncodeContent', function (content) {\n content = self.encodeVariables(content);\n\n return content;\n });\n\n /**\n * Attach event handler for when wysiwyg editor is about to decode its content\n */\n varienGlobalEvents.attachEventHandler('wysiwygDecodeContent', function (content) {\n content = self.decodeVariables(content);\n\n return content;\n });\n },\n\n /**\n * Encode variables in content\n *\n * @param {String} content\n * @returns {*}\n */\n encodeVariables: function (content) {\n content = content.gsub(/\\{\\{config path=\\\"([^\\\"]+)\\\"\\}\\}/i, function (match) {\n var path = match[1],\n magentoVariables,\n imageHtml;\n\n magentoVariables = JSON.parse(config.placeholders);\n\n if (magentoVariables[match[1]] && magentoVariables[match[1]]['variable_type'] === 'default') {\n imageHtml = '<span id=\"%id\" class=\"magento-variable magento-placeholder mceNonEditable\">' +\n '%s</span>';\n imageHtml = imageHtml.replace('%s', magentoVariables[match[1]]['variable_name']);\n } else {\n imageHtml = '<span id=\"%id\" class=\"' +\n 'magento-variable magento-placeholder magento-placeholder-error ' +\n 'mceNonEditable' +\n '\">' +\n 'Not found' +\n '</span>';\n }\n\n return imageHtml.replace('%id', Base64.idEncode(path));\n });\n\n content = content.gsub(/\\{\\{customVar code=([^\\}\\\"]+)\\}\\}/i, function (match) {\n var path = match[1],\n magentoVariables,\n imageHtml;\n\n magentoVariables = JSON.parse(config.placeholders);\n\n if (magentoVariables[match[1]] && magentoVariables[match[1]]['variable_type'] === 'custom') {\n imageHtml = '<span id=\"%id\" class=\"magento-variable magento-custom-var magento-placeholder ' +\n 'mceNonEditable\">%s</span>';\n imageHtml = imageHtml.replace('%s', magentoVariables[match[1]]['variable_name']);\n } else {\n imageHtml = '<span id=\"%id\" class=\"' +\n 'magento-variable magento-custom-var magento-placeholder ' +\n 'magento-placeholder-error mceNonEditable' +\n '\">' +\n match[1] +\n '</span>';\n }\n\n return imageHtml.replace('%id', Base64.idEncode(path));\n });\n\n return content;\n },\n\n /**\n * Decode variables in content.\n *\n * @param {String} content\n * @returns {String}\n */\n decodeVariables: function (content) {\n var doc = (new DOMParser()).parseFromString(content.replace(/"/g, '&quot;'), 'text/html');\n\n [].forEach.call(doc.querySelectorAll('span.magento-variable'), function (el) {\n var $el = jQuery(el);\n\n if ($el.hasClass('magento-custom-var')) {\n $el.replaceWith(\n customDirectiveGenerator.processConfig(\n Base64.idDecode(\n $el.attr('id')\n )\n )\n );\n } else {\n $el.replaceWith(\n configDirectiveGenerator.processConfig(\n Base64.idDecode(\n $el.attr('id')\n )\n )\n );\n }\n });\n\n return doc.body ? doc.body.innerHTML.replace(/&quot;/g, '"') : content;\n },\n\n /**\n * @return {Object}\n */\n getInfo: function () {\n return {\n longname: 'Magento Variable Manager Plugin',\n author: 'Magento Core Team',\n authorurl: 'http://magentocommerce.com',\n infourl: 'http://magentocommerce.com',\n version: '1.0'\n };\n }\n });\n\n /**\n * Register plugin\n */\n tinymce.PluginManager.add('magentovariable', tinymce.plugins.magentovariable);\n };\n});\n","mage/view/composite.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 */\n/* eslint-disable strict */\ndefine(['jquery'], function ($) {\n return function () {\n var renderedChildren = {},\n children = {};\n\n return {\n /**\n * @param {*} child\n * @param {String} key\n */\n addChild: function (child, key) {\n children[key] = child;\n },\n\n /**\n * @param {*} root\n */\n render: function (root) {\n $.each(children, function (key, child) {\n var childRoot = $('<div>');\n\n renderedChildren[key] = child.render(childRoot);\n root.append(childRoot);\n });\n }\n };\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/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/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.indexOf(value) === index;\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/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","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\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 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 * @returns {*} Compiled template.\n */\n function render(tmpl, data, castString) {\n var last = tmpl;\n\n while (~tmpl.indexOf(opener)) {\n tmpl = template(tmpl, data);\n\n if (tmpl === last) {\n break;\n }\n\n last = tmpl;\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 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 list[key] = render(value, tmpl, castString);\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/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 'FormData'\n], function (_, $) {\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(mage, moment);\n });\n\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 = this.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 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 .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(this.serialize(data), function (val, name) {\n formData.append(name, val);\n });\n } else if (type === 'simple') {\n formData = this.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) && !value.length) {\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 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/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], function (ko, $, _) {\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 _.each(data, function (node, name) {\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 = this.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","mage/backend/notification.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 'jquery/ui'\n], function ($, mageTemplate) {\n 'use strict';\n\n $.widget('mage.notification', {\n options: {\n templates: {\n global: '<div data-role=\"messages\" id=\"messages\">' +\n '<div class=\"message <% if (data.error) { %>error<% } %>\"><div><%- data.message %></div></div>' +\n '</div>',\n error: '<div data-role=\"messages\" id=\"messages\">' +\n '<div class=\"messages\"><div class=\"message message-error error\">' +\n '<div data-ui-id=\"messages-message-error\"><%- data.message %></div></div>' +\n '</div></div>'\n }\n },\n placeholder: '[data-role=messages]',\n\n /**\n * Notification creation\n * @protected\n */\n _create: function () {\n $(document).on('ajaxComplete ajaxError', $.proxy(this._add, this));\n },\n\n /**\n * Add new message\n * @protected\n * @param {Object} event - object\n * @param {Object} jqXHR - The jQuery XMLHttpRequest object returned by $.ajax()\n */\n _add: function (event, jqXHR) {\n var response;\n\n try {\n response = JSON.parse(jqXHR.responseText);\n\n if (response && response.error && response['html_message']) {\n $(this.placeholder).html(response['html_message']);\n }\n } catch (e) {}\n },\n\n /**\n * Adds new message.\n *\n * @param {Object} data - Data with a message to be displayed.\n */\n add: function (data) {\n var template = data.error ? this.options.templates.error : this.options.templates.global,\n message = mageTemplate(template, {\n data: data\n }),\n messageContainer;\n\n if (typeof data.insertMethod === 'function') {\n data.insertMethod(message);\n } else {\n messageContainer = data.messageContainer || this.placeholder;\n $(messageContainer).prepend(message);\n }\n\n return this;\n },\n\n /**\n * Removes error messages.\n */\n clear: function () {\n $(this.placeholder).html('');\n }\n });\n\n return $.mage.notification;\n});\n","mage/backend/bootstrap.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 'mage/apply/main',\n 'mage/backend/notification',\n 'Magento_Ui/js/lib/knockout/bootstrap',\n 'mage/mage',\n 'mage/translate'\n], function ($, mage, notification) {\n 'use strict';\n\n var bootstrap;\n\n $.ajaxSetup({\n /*\n * @type {string}\n */\n type: 'POST',\n\n /**\n * Ajax before send callback.\n *\n * @param {Object} jqXHR - The jQuery XMLHttpRequest object returned by $.ajax()\n * @param {Object} settings\n */\n beforeSend: function (jqXHR, settings) {\n var formKey = typeof FORM_KEY !== 'undefined' ? FORM_KEY : null;\n\n if (!settings.url.match(new RegExp('[?&]isAjax=true',''))) {\n settings.url = settings.url.match(\n new RegExp('\\\\?', 'g')) ?\n settings.url + '&isAjax=true' :\n settings.url + '?isAjax=true';\n }\n\n if (!settings.data) {\n settings.data = {\n 'form_key': formKey\n };\n } else if ($.type(settings.data) === 'string' &&\n settings.data.indexOf('form_key=') === -1) {\n settings.data += '&' + $.param({\n 'form_key': formKey\n });\n } else if ($.isPlainObject(settings.data) && !settings.data['form_key']) {\n settings.data['form_key'] = formKey;\n }\n },\n\n /**\n * Ajax complete callback.\n *\n * @param {Object} jqXHR - The jQuery XMLHttpRequest object returned by $.ajax()\n */\n complete: function (jqXHR) {\n var jsonObject;\n\n if (jqXHR.readyState === 4) {\n try {\n jsonObject = $.parseJSON(jqXHR.responseText);\n\n if (jsonObject.ajaxExpired && jsonObject.ajaxRedirect) { //eslint-disable-line max-depth\n window.location.replace(jsonObject.ajaxRedirect);\n }\n } catch (e) {}\n }\n },\n\n /**\n * Error callback.\n */\n error: function () {\n $('body').notification('clear')\n .notification('add', {\n error: true,\n message: $.mage.__(\n 'A technical problem with the server created an error. ' +\n 'Try again to continue what you were doing. If the problem persists, try again later.'\n ),\n\n /**\n * @param {String} message\n */\n insertMethod: function (message) {\n var $wrapper = $('<div/>').html(message);\n\n $('.page-main-actions').after($wrapper);\n }\n });\n }\n });\n\n /**\n * Bootstrap application.\n */\n bootstrap = function () {\n /**\n * Init all components defined via data-mage-init attribute\n * and subscribe init action on contentUpdated event\n */\n mage.apply();\n\n /*\n * Initialization of notification widget\n */\n notification({}, $('body'));\n };\n\n $(bootstrap);\n});\n","mage/backend/validation.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* global BASE_URL, alertAlreadyDisplayed */\n(function (factory) {\n 'use strict';\n\n if (typeof define === 'function' && define.amd) {\n define([\n 'jquery',\n 'underscore',\n 'Magento_Ui/js/modal/alert',\n 'jquery/ui',\n 'jquery/validate',\n 'mage/translate',\n 'mage/validation'\n ], factory);\n } else {\n factory(jQuery);\n }\n}(function ($, _, alert) {\n 'use strict';\n\n $.extend(true, $.validator.prototype, {\n /**\n * Focus invalid fields\n */\n focusInvalid: function () {\n if (this.settings.focusInvalid) {\n try {\n $(this.errorList.length && this.errorList[0].element || [])\n .focus()\n .trigger('focusin');\n } catch (e) {\n // ignore IE throwing errors when focusing hidden elements\n }\n }\n },\n\n /**\n * Elements.\n */\n elements: function () {\n var validator = this,\n rulesCache = {};\n\n // select all valid inputs inside the form (no submit or reset buttons)\n return $(this.currentForm)\n .find('input, select, textarea')\n .not(this.settings.forceIgnore)\n .not(':submit, :reset, :image, [disabled]')\n .not(this.settings.ignore)\n .filter(function () {\n if (!this.name && validator.settings.debug && window.console) {\n console.error('%o has no name assigned', this);\n }\n\n // select only the first element for each name, and only those with rules specified\n if (this.name in rulesCache || !validator.objectLength($(this).rules())) {\n return false;\n }\n\n rulesCache[this.name] = true;\n\n return true;\n });\n }\n });\n\n $.extend($.fn, {\n /**\n * ValidationDelegate overridden for those cases where the form is located in another form,\n * to avoid not correct working of validate plug-in\n * @override\n * @param {String} delegate - selector, if event target matched against this selector,\n * then event will be delegated\n * @param {String} type - event type\n * @param {Function} handler - event handler\n * @return {Element}\n */\n validateDelegate: function (delegate, type, handler) {\n return this.on(type, $.proxy(function (event) {\n var target = $(event.target),\n form = target[0].form;\n\n if (form && $(form).is(this) && $.data(form, 'validator') && target.is(delegate)) {\n return handler.apply(target, arguments);\n }\n }, this));\n }\n });\n\n $.widget('mage.validation', $.mage.validation, {\n options: {\n messagesId: 'messages',\n forceIgnore: '',\n ignore: ':disabled, .ignore-validate, .no-display.template, ' +\n ':disabled input, .ignore-validate input, .no-display.template input, ' +\n ':disabled select, .ignore-validate select, .no-display.template select, ' +\n ':disabled textarea, .ignore-validate textarea, .no-display.template textarea',\n errorElement: 'label',\n errorUrl: typeof BASE_URL !== 'undefined' ? BASE_URL : null,\n\n /**\n * @param {HTMLElement} element\n */\n highlight: function (element) {\n if ($.validator.defaults.highlight && $.isFunction($.validator.defaults.highlight)) {\n $.validator.defaults.highlight.apply(this, arguments);\n }\n $(element).trigger('highlight.validate');\n },\n\n /**\n * @param {HTMLElement} element\n */\n unhighlight: function (element) {\n if ($.validator.defaults.unhighlight && $.isFunction($.validator.defaults.unhighlight)) {\n $.validator.defaults.unhighlight.apply(this, arguments);\n }\n $(element).trigger('unhighlight.validate');\n }\n },\n\n /**\n * Validation creation\n * @protected\n */\n _create: function () {\n if (!this.options.submitHandler && $.type(this.options.submitHandler) !== 'function') {\n if (!this.options.frontendOnly && this.options.validationUrl) {\n this.options.submitHandler = $.proxy(this._ajaxValidate, this);\n } else {\n this.options.submitHandler = $.proxy(this._submit, this);\n }\n }\n this.element.on('resetElement', function (e) {\n $(e.target).rules('remove');\n });\n this._super('_create');\n },\n\n /**\n * ajax validation\n * @protected\n */\n _ajaxValidate: function () {\n $.ajax({\n url: this.options.validationUrl,\n type: 'POST',\n dataType: 'json',\n data: this.element.serialize(),\n context: $('body'),\n success: $.proxy(this._onSuccess, this),\n error: $.proxy(this._onError, this),\n showLoader: true,\n dontHide: false\n });\n },\n\n /**\n * Process ajax success.\n *\n * @protected\n * @param {Object} response\n */\n _onSuccess: function (response) {\n if (!response.error) {\n this._submit();\n } else {\n this._showErrors(response);\n $(this.element[0]).trigger('afterValidate.error');\n $('body').trigger('processStop');\n }\n },\n\n /**\n * Submitting a form.\n * @private\n */\n _submit: function () {\n $(this.element[0]).trigger('afterValidate.beforeSubmit');\n this.element[0].submit();\n },\n\n /**\n * Displays errors after backend validation.\n *\n * @param {Object} data - Data that came from backend.\n */\n _showErrors: function (data) {\n $('body').notification('clear')\n .notification('add', {\n error: data.error,\n message: data.message,\n\n /**\n * @param {*} message\n */\n insertMethod: function (message) {\n $('.messages:first').html(message);\n }\n });\n },\n\n /**\n * Tries to retrieve element either by id or by inputs' name property.\n * @param {String} code - String to search by.\n * @returns {jQuery} jQuery element.\n */\n _getByCode: function (code) {\n var parent = this.element[0],\n element;\n\n element = parent.querySelector('#' + code) || parent.querySelector('input[name=' + code + ']');\n\n return $(element);\n },\n\n /**\n * Process ajax error\n * @protected\n */\n _onError: function () {\n $(this.element[0]).trigger('afterValidate.error');\n $('body').trigger('processStop');\n\n if (this.options.errorUrl) {\n location.href = this.options.errorUrl;\n }\n }\n });\n\n _.each({\n 'validate-greater-zero-based-on-option': [\n function (v, el) {\n var optionType = $(el)\n .closest('.form-list')\n .prev('.fieldset-alt')\n .find('select.select-product-option-type'),\n optionTypeVal = optionType.val();\n\n v = Number(v) || 0;\n\n if (optionType && (optionTypeVal == 'checkbox' || optionTypeVal == 'multi') && v <= 0) { //eslint-disable-line\n return false;\n }\n\n return true;\n },\n $.mage.__('Please enter a number greater 0 in this field.')\n ],\n 'validate-rating': [\n function () {\n var ratings = $('#detailed_rating').find('.field-rating'),\n noError = true;\n\n ratings.each(function (index, rating) {\n noError = noError && $(rating).find('input:checked').length > 0;\n });\n\n return noError;\n },\n $.mage.__('Please select one of each ratings above.')\n ],\n 'validate-downloadable-file': [\n function (v, element) {\n var elmParent = $(element).parent(),\n linkType = elmParent.find('input[value=\"file\"]'),\n newFileContainer;\n\n if (linkType.is(':checked') && (v === '' || v === '[]')) {\n newFileContainer = elmParent.find('.new-file');\n\n if (!alertAlreadyDisplayed && (newFileContainer.empty() || newFileContainer.is(':visible'))) {\n window.alertAlreadyDisplayed = true;\n alert({\n content: $.mage.__('There are files that were selected but not uploaded yet. ' +\n 'Please upload or remove them first')\n });\n }\n\n return false;\n }\n\n return true;\n },\n 'Please upload a file.'\n ],\n 'validate-downloadable-url': [\n function (v, element) {\n var linkType = $(element).parent().find('input[value=\"url\"]');\n\n if (linkType.is(':checked') && v === '') {\n return false;\n }\n\n return true;\n },\n $.mage.__('Please specify Url.')\n ]\n }, function (rule, i) {\n rule.unshift(i);\n $.validator.addMethod.apply($.validator, rule);\n });\n\n return $.mage.validation;\n}));\n","mage/backend/editablemultiselect.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 */\n/* global EditableMultiselect */\n/* eslint-disable strict */\ndefine([\n 'jquery',\n 'Magento_Ui/js/modal/alert',\n 'Magento_Ui/js/modal/confirm',\n 'jquery/editableMultiselect/js/jquery.editable',\n 'jquery/editableMultiselect/js/jquery.multiselect'\n], function ($, alert, confirm) {\n /**\n * Editable multiselect wrapper for multiselects\n * This class is defined in global scope ('var' is not needed).\n *\n * @param {Object} settings - settings object.\n * @param {String} settings.add_button_caption - caption of the 'Add New Value' button\n * @param {String} settings.new_url - URL to which new request has to be submitted\n * @param {String} settings.save_url - URL to which save request has to be submitted\n * @param {String} settings.delete_url - URL to which delete request has to be submitted\n * @param {String} settings.delete_confirm_message - confirmation message that is shown to user during\n * delete operation\n * @param {String} settings.target_select_id - HTML ID of target select element\n * @param {Hash} settings.submit_data - extra parameters to send with new/edit/delete requests\n * @param {String} settings.entity_value_name - name of the request parameter that represents select option text\n * @param {String} settings.entity_id_name - name of the request parameter that represents select option value\n * @param {Boolean} settings.is_entry_editable - flag that shows if user can add/edit/remove data\n *\n * @constructor\n */\n window.EditableMultiselect = function (settings) {\n\n this.settings = settings || {};\n this.addButtonCaption = this.settings['add_button_caption'] || 'Add new value';\n this.newUrl = this.settings['new_url'];\n this.saveUrl = this.settings['save_url'];\n this.deleteUrl = this.settings['delete_url'];\n this.deleteConfirmMessage = this.settings['delete_confirm_message'];\n this.targetSelectId = this.settings['target_select_id'];\n this.submitData = this.settings['submit_data'] || {};\n this.entityIdName = this.settings['entity_id_name'] || 'entity_id';\n this.entityValueName = this.settings['entity_value_name'] || 'entity_value';\n this.isEntityEditable = this.settings['is_entity_editable'] || false;\n\n /**\n * Initialize editable multiselect (make it visible in UI)\n */\n EditableMultiselect.prototype.init = function () {\n var self = this,\n mselectOptions = {\n addText: this.addButtonCaption,\n\n /**\n * @param {*} value\n * @param {*} options\n */\n mselectInputSubmitCallback: function (value, options) {\n self.createEntity(value, options);\n }\n },\n mselectList;\n\n if (!this.isEntityEditable) {\n // Override default layout of editable multiselect\n mselectOptions.layout = '<section class=\"block %mselectListClass%\">' +\n '<div class=\"block-content\"><div class=\"%mselectItemsWrapperClass%\">' +\n '%items%' +\n '</div></div>' +\n '<div class=\"%mselectInputContainerClass%\">' +\n '<input type=\"text\" class=\"%mselectInputClass%\" title=\"%inputTitle%\"/>' +\n '<span class=\"%mselectButtonCancelClass%\" title=\"%cancelText%\"></span>' +\n '<span class=\"%mselectButtonSaveClass%\" title=\"Add\"></span>' +\n '</div>' +\n '</section>';\n }\n\n $('#' + this.targetSelectId).multiselect(mselectOptions);\n\n // Make multiselect editable if needed\n if (this.isEntityEditable) {\n this.makeMultiselectEditable();\n\n // Root element of HTML markup that represents select element in UI\n mselectList = $('#' + this.targetSelectId).next();\n this.attachEventsToControls(mselectList);\n }\n };\n\n /**\n * Attach required event handlers to control elements of editable multiselect\n *\n * @param {Object} mselectList\n */\n EditableMultiselect.prototype.attachEventsToControls = function (mselectList) {\n mselectList.on('click.mselect-delete', '.mselect-delete', {\n container: this\n }, function (event) {\n // Pass the clicked button to container\n event.data.container.deleteEntity({\n 'delete_button': this\n });\n });\n\n mselectList.on('click.mselect-checked', '.mselect-list-item input', {\n container: this\n }, function (event) {\n var el = $(this),\n checkedClassName = 'mselect-checked';\n\n el[el.is(':checked') ? 'addClass' : 'removeClass'](checkedClassName);\n event.data.container.makeMultiselectEditable();\n });\n\n mselectList.on('click.mselect-edit', '.mselect-edit', {\n container: this\n }, function (event) {\n event.data.container.makeMultiselectEditable();\n $(this).parent().find('label span').trigger('dblclick');\n });\n };\n\n /**\n * Make multiselect editable\n */\n EditableMultiselect.prototype.makeMultiselectEditable = function () {\n var entityIdName = this.entityIdName,\n entityValueName = this.entityValueName,\n selectList = $('#' + this.targetSelectId).next();\n\n selectList.find('.mselect-list-item:not(.mselect-list-item-not-editable) label span').editable(this.saveUrl,\n {\n type: 'text',\n submit: '<button class=\"mselect-save\" title=\"Save\" type=\"submit\" />',\n cancel: '<span class=\"mselect-cancel\" title=\"Cancel\"></span>',\n event: 'dblclick',\n placeholder: '',\n\n /**\n * Is checked.\n */\n isChecked: function () {\n var that = $(this),\n checked;\n\n if (!that.closest('.mselect-list-item').hasClass('mselect-disabled')) {\n checked = that.parent().find('[type=checkbox]').prop('disabled');\n that.parent().find('[type=checkbox]').prop({\n disabled: !checked\n });\n }\n },\n\n /**\n * @param {*} value\n * @param {Object} sett\n * @return {*}\n */\n data: function (value, sett) {\n var retval;\n\n sett.isChecked.apply(this, [sett]);\n\n if (typeof value === 'string') {\n retval = value.unescapeHTML();\n\n return retval;\n }\n\n return value;\n },\n submitdata: this.submitData,\n onblur: 'cancel',\n name: entityValueName,\n ajaxoptions: {\n dataType: 'json'\n },\n\n /**\n * @param {Object} sett\n * @param {*} original\n */\n onsubmit: function (sett, original) {\n var select = $(original).closest('.mselect-list').prev(),\n current = $(original).closest('.mselect-list-item').index(),\n entityId = select.find('option').eq(current).val(),\n entityInfo = {};\n\n entityInfo[entityIdName] = entityId;\n sett.submitdata = $.extend(sett.submitdata || {}, entityInfo);\n },\n\n /**\n * @param {Object} result\n * @param {Object} sett\n */\n callback: function (result, sett) {\n var select, current;\n\n sett.isChecked.apply(this, [sett]);\n select = $(this).closest('.mselect-list').prev();\n current = $(this).closest('.mselect-list-item').index();\n\n if (result.success) {\n if (typeof result[entityValueName] === 'string') {\n select.find('option').eq(current).val(result[entityIdName]).text(result[entityValueName]);\n $(this).html(result[entityValueName].escapeHTML());\n }\n } else {\n alert({\n content: result['error_message']\n });\n }\n }\n });\n };\n\n /**\n * Callback function that is called when admin adds new value to select\n *\n * @param {*} value\n * @param {Object} options - list of settings of multiselect\n */\n EditableMultiselect.prototype.createEntity = function (value, options) {\n var select, entityIdName, entityValueName, entityInfo, postData, ajaxOptions;\n\n if (!value) {\n return;\n }\n\n select = $('#' + this.targetSelectId),\n entityIdName = this.entityIdName,\n entityValueName = this.entityValueName,\n entityInfo = {};\n entityInfo[entityIdName] = null;\n entityInfo[entityValueName] = value;\n\n postData = $.extend(entityInfo, this.submitData);\n\n ajaxOptions = {\n type: 'POST',\n data: postData,\n dataType: 'json',\n url: this.newUrl,\n\n /**\n * @param {Object} result\n */\n success: function (result) {\n var resultEntityValueName, mselectItemHtml, sectionBlock, itemsWrapper, inputSelector;\n\n if (result.success) {\n resultEntityValueName = '';\n\n if (typeof result[entityValueName] === 'string') {\n resultEntityValueName = result[entityValueName].escapeHTML();\n } else {\n resultEntityValueName = result[entityValueName];\n }\n // Add item to initial select element\n select.append('<option value=\"' + result[entityIdName] + '\" selected=\"selected\">' +\n resultEntityValueName + '</option>');\n // Add editable multiselect item\n mselectItemHtml = $(options.item.replace(/%value%|%label%/gi, resultEntityValueName)\n .replace(/%mselectDisabledClass%|%iseditable%|%isremovable%/gi, '')\n .replace(/%mselectListItemClass%/gi, options.mselectListItemClass))\n .find('[type=checkbox]')\n .attr('checked', true)\n .addClass(options.mselectCheckedClass)\n .end();\n sectionBlock = select.nextAll('section.block:first');\n itemsWrapper = sectionBlock.find('.' + options.mselectItemsWrapperClass + '');\n\n if (itemsWrapper.children('.' + options.mselectListItemClass + '').length) {\n itemsWrapper.children('.' + options.mselectListItemClass + ':last').after(mselectItemHtml);\n } else {\n itemsWrapper.prepend(mselectItemHtml);\n }\n // Trigger blur event on input field, that is used to add new value, to hide it\n inputSelector = '.' + options.mselectInputContainerClass + ' [type=text].' +\n options.mselectInputClass + '';\n sectionBlock.find(inputSelector).trigger('blur');\n } else {\n alert({\n content: result['error_message']\n });\n }\n }\n };\n $.ajax(ajaxOptions);\n };\n\n /**\n * Callback function that is called when user tries to delete value from select\n *\n * @param {Object} options\n */\n EditableMultiselect.prototype.deleteEntity = function (options) {\n var self = this;\n\n if (options['delete_button']) {\n confirm({\n content: this.deleteConfirmMessage,\n actions: {\n /**\n * Confirm.\n */\n confirm: function () {\n // Button that has been clicked\n var deleteButton = $(options['delete_button']),\n index = deleteButton.parent().index(),\n select = deleteButton.closest('.mselect-list').prev(),\n entityId = select.find('option').eq(index).val(),\n entityInfo = {},\n postData, ajaxOptions;\n\n entityInfo[self.entityIdName] = entityId;\n postData = $.extend(entityInfo, self.submitData);\n\n ajaxOptions = {\n type: 'POST',\n data: postData,\n dataType: 'json',\n url: self.deleteUrl,\n\n /**\n * @param {Object} result\n */\n success: function (result) {\n if (result.success) {\n deleteButton.parent().remove();\n select.find('option').eq(index).remove();\n } else {\n alert({\n content: result['error_message']\n });\n }\n }\n };\n $.ajax(ajaxOptions);\n }\n }\n });\n }\n };\n };\n});\n","mage/backend/action-link.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'jquery',\n 'jquery/ui'\n], function ($) {\n 'use strict';\n\n $.widget('mage.actionLink', {\n /**\n * Button creation\n * @protected\n */\n _create: function () {\n this._bind();\n },\n\n /**\n * Bind handler on button click\n * @protected\n */\n _bind: function () {\n var keyCode = $.ui.keyCode;\n\n this._on({\n /**\n * @param {jQuery.Event} e\n */\n mousedown: function (e) {\n this._stopPropogation(e);\n },\n\n /**\n * @param {jQuery.Event} e\n */\n mouseup: function (e) {\n this._stopPropogation(e);\n },\n\n /**\n * @param {jQuery.Event} e\n */\n click: function (e) {\n this._stopPropogation(e);\n this._triggerEvent();\n },\n\n /**\n * @param {jQuery.Event} e\n */\n keydown: function (e) {\n switch (e.keyCode) {\n case keyCode.ENTER:\n case keyCode.NUMPAD_ENTER:\n this._stopPropogation(e);\n this._triggerEvent();\n break;\n }\n },\n\n /**\n * @param {jQuery.Event} e\n */\n keyup: function (e) {\n switch (e.keyCode) {\n case keyCode.ENTER:\n case keyCode.NUMPAD_ENTER:\n this._stopPropogation(e);\n break;\n }\n }\n });\n },\n\n /**\n * @param {Object} e - event object\n * @private\n */\n _stopPropogation: function (e) {\n e.stopImmediatePropagation();\n e.preventDefault();\n },\n\n /**\n * @private\n */\n _triggerEvent: function () {\n $(this.options.related || this.element)\n .trigger(this.options.event, this.options.eventData ? [this.options.eventData] : [{}]);\n }\n });\n\n return $.mage.actionLink;\n});\n","mage/backend/tree-suggest.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n(function (root, factory) {\n 'use strict';\n\n if (typeof define === 'function' && define.amd) {\n define([\n 'jquery',\n 'jquery/ui',\n 'jquery/jstree/jquery.jstree',\n 'mage/backend/suggest'\n ], factory);\n } else {\n factory(root.jQuery);\n }\n}(this, function ($) {\n 'use strict';\n\n /* jscs:disable requireCamelCaseOrUpperCaseIdentifiers */\n var hover_node, dehover_node, select_node, init;\n\n $.extend(true, $, {\n // @TODO: Move method 'treeToList' in file with utility functions\n mage: {\n /**\n * @param {Array} list\n * @param {Object} nodes\n * @param {*} level\n * @param {*} path\n * @return {*}\n */\n treeToList: function (list, nodes, level, path) {\n $.each(nodes, function () {\n if ($.type(this) === 'object') {\n list.push({\n label: this.label,\n id: this.id,\n level: level,\n item: this,\n path: path + this.label\n });\n\n if (this.children) {\n $.mage.treeToList(list, this.children, level + 1, path + this.label + ' / ');\n }\n }\n });\n\n return list;\n }\n }\n });\n\n hover_node = $.jstree._instance.prototype.hover_node;\n dehover_node = $.jstree._instance.prototype.dehover_node;\n select_node = $.jstree._instance.prototype.select_node;\n init = $.jstree._instance.prototype.init;\n\n $.extend(true, $.jstree._instance.prototype, {\n /**\n * @override\n */\n init: function () {\n this.get_container()\n .show()\n .on('keydown', $.proxy(function (e) {\n var o;\n\n if (e.keyCode === $.ui.keyCode.ENTER) {\n o = this.data.ui.hovered || this.data.ui.last_selected || -1;\n this.select_node(o, true);\n }\n }, this));\n init.call(this);\n },\n\n /**\n * @override\n */\n hover_node: function (obj) {\n hover_node.apply(this, arguments);\n obj = this._get_node(obj);\n\n if (!obj.length) {\n return false;\n }\n this.get_container().trigger('hover_node', [{\n item: obj.find('a:first')\n }]);\n },\n\n /**\n * @override\n */\n dehover_node: function () {\n dehover_node.call(this);\n this.get_container().trigger('dehover_node');\n },\n\n /**\n * @override\n */\n select_node: function (o) {\n var node;\n\n select_node.apply(this, arguments);\n node = this._get_node(o);\n\n (node ? $(node) : this.data.ui.last_selected)\n .trigger('select_tree_node');\n }\n });\n\n $.widget('mage.treeSuggest', $.mage.suggest, {\n widgetEventPrefix: 'suggest',\n options: {\n template:\n '<% if (data.items.length) { %>' +\n '<% if (data.allShown()) { %>' +\n '<% if (typeof data.nested === \"undefined\") { %>' +\n '<div style=\"display:none;\" data-mage-init=\"{"jstree":{"plugins":["themes","html_data","ui","hotkeys"],"themes":{"theme":"default","dots":false,"icons":false}}}\">' + //eslint-disable-line max-len\n '<% } %>' +\n '<ul>' +\n '<% _.each(data.items, function(value) { %>' +\n '<li class=\"<% if (data.itemSelected(value)) { %>mage-suggest-selected<% } %>' +\n ' <% if (value.is_active == 0) { %> mage-suggest-not-active<% } %>\">' +\n '<a href=\"#\" <%= data.optionData(value) %>><%- value.label %></a>' +\n '<% if (value.children && value.children.length) { %>' +\n '<%= data.renderTreeLevel(value.children) %>' +\n '<% } %>' +\n '</li>' +\n '<% }); %>' +\n '</ul>' +\n '<% if (typeof data.nested === \"undefined\") { %>' +\n '</div>' +\n '<% } %>' +\n '<% } else { %>' +\n '<ul data-mage-init=\"{"menu":[]}\">' +\n '<% _.each(data.items, function(value) { %>' +\n '<% if (!data.itemSelected(value)) {%>' +\n '<li <%= data.optionData(value) %>>' +\n '<a href=\"#\">' +\n '<span class=\"category-label\"><%- value.label %></span>' +\n '<span class=\"category-path\"><%- value.path %></span>' +\n '</a>' +\n '</li>' +\n '<% } %>' +\n '<% }); %>' +\n '</ul>' +\n '<% } %>' +\n '<% } else { %>' +\n '<span class=\"mage-suggest-no-records\"><%- data.noRecordsText %></span>' +\n '<% } %>',\n controls: {\n selector: ':ui-menu, :mage-menu, .jstree',\n eventsMap: {\n focus: ['menufocus', 'hover_node'],\n blur: ['menublur', 'dehover_node'],\n select: ['menuselect', 'select_tree_node']\n }\n }\n },\n\n /**\n * @override\n */\n _bind: function () {\n this._super();\n this._on({\n /**\n * @param {jQuery.Event} event\n */\n keydown: function (event) {\n var keyCode = $.ui.keyCode;\n\n switch (event.keyCode) {\n case keyCode.LEFT:\n case keyCode.RIGHT:\n\n if (this.isDropdownShown()) {\n event.preventDefault();\n this._proxyEvents(event);\n }\n break;\n }\n }\n });\n },\n\n /**\n * @override\n */\n close: function (e) {\n var eType = e ? e.type : null;\n\n if (eType === 'select_tree_node') {\n this.element.focus();\n } else {\n this._superApply(arguments);\n }\n },\n\n /**\n * @override\n */\n _filterSelected: function (items, context) {\n if (context._allShown) {\n return items;\n }\n\n return this._superApply(arguments);\n },\n\n /**\n * @override\n */\n _prepareDropdownContext: function () {\n var context = this._superApply(arguments),\n optionData = context.optionData,\n templates = this.templates,\n tmplName = this.templateName;\n\n /**\n * @param {Object} item\n * @return {*|String}\n */\n context.optionData = function (item) {\n item = $.extend({}, item);\n delete item.children;\n\n return optionData(item);\n };\n\n return $.extend(context, {\n /**\n * @param {*} children\n * @return {*|jQuery}\n */\n renderTreeLevel: function (children) {\n var _context = $.extend({}, this, {\n items: children,\n nested: true\n }),\n tmpl = templates[tmplName];\n\n tmpl = tmpl({\n data: _context\n });\n\n return $('<div>').append($(tmpl)).html();\n }\n });\n },\n\n /**\n * @override\n */\n _processResponse: function (e, items, context) {\n var control;\n\n if (context && !context._allShown) {\n items = this.filter($.mage.treeToList([], items, 0, ''), this._term);\n }\n control = this.dropdown.find(this._control.selector);\n\n if (control.length && control.hasClass('jstree')) {\n control.jstree('destroy');\n }\n this._superApply([e, items, context]);\n }\n });\n\n return $.mage.treeSuggest;\n}));\n","mage/backend/menu.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n(function (factory) {\n 'use strict';\n\n if (typeof define === 'function' && define.amd) {\n define([\n 'jquery',\n 'jquery/ui'\n ], factory);\n } else {\n factory(jQuery);\n }\n}(function ($) {\n 'use strict';\n\n $.widget('mage.menu', {\n widgetEventPrefix: 'menu',\n version: '1.10.1',\n defaultElement: '<ul>',\n delay: 300,\n options: {\n icons: {\n submenu: 'ui-icon-carat-1-e'\n },\n menus: 'ul',\n position: {\n my: 'left top',\n at: 'right top'\n },\n role: 'menu',\n\n // callbacks\n blur: null,\n focus: null,\n select: null\n },\n\n /**\n * @private\n */\n _create: function () {\n this.activeMenu = this.element;\n // flag used to prevent firing of the click handler\n // as the event bubbles up through nested menus\n this.mouseHandled = false;\n this.element\n .uniqueId()\n .addClass('ui-menu ui-widget ui-widget-content ui-corner-all')\n .toggleClass('ui-menu-icons', !!this.element.find('.ui-icon').length)\n .attr({\n role: this.options.role,\n tabIndex: 0\n })\n // need to catch all clicks on disabled menu\n // not possible through _on\n .bind('click' + this.eventNamespace, $.proxy(function (event) {\n if (this.options.disabled) {\n event.preventDefault();\n }\n }, this));\n\n if (this.options.disabled) {\n this.element\n .addClass('ui-state-disabled')\n .attr('aria-disabled', 'true');\n }\n\n this._on({\n /**\n * Prevent focus from sticking to links inside menu after clicking\n * them (focus should always stay on UL during navigation).\n */\n 'mousedown .ui-menu-item > a': function (event) {\n event.preventDefault();\n },\n\n /**\n * Prevent focus from sticking to links inside menu after clicking\n * them (focus should always stay on UL during navigation).\n */\n 'click .ui-state-disabled > a': function (event) {\n event.preventDefault();\n },\n\n /**\n * @param {jQuery.Event} event\n */\n 'click .ui-menu-item:has(a)': function (event) {\n var target = $(event.target).closest('.ui-menu-item');\n\n if (!this.mouseHandled && target.not('.ui-state-disabled').length) {\n this.mouseHandled = true;\n\n this.select(event);\n // Open submenu on click\n if (target.has('.ui-menu').length) {\n this.expand(event);\n } else if (!this.element.is(':focus')) {\n // Redirect focus to the menu\n this.element.trigger('focus', [true]);\n\n // If the active item is on the top level, let it stay active.\n // Otherwise, blur the active item since it is no longer visible.\n if (this.active && this.active.parents('.ui-menu').length === 1) { //eslint-disable-line\n clearTimeout(this.timer);\n }\n }\n }\n },\n\n /**\n * @param {jQuery.Event} event\n */\n 'mouseenter .ui-menu-item': function (event) {\n var target = $(event.currentTarget);\n\n // Remove ui-state-active class from siblings of the newly focused menu item\n // to avoid a jump caused by adjacent elements both having a class with a border\n target.siblings().children('.ui-state-active').removeClass('ui-state-active');\n this.focus(event, target);\n },\n mouseleave: 'collapseAll',\n 'mouseleave .ui-menu': 'collapseAll',\n\n /**\n * @param {jQuery.Event} event\n * @param {*} keepActiveItem\n */\n focus: function (event, keepActiveItem) {\n // If there's already an active item, keep it active\n // If not, activate the first item\n var item = this.active || this.element.children('.ui-menu-item').eq(0);\n\n if (!keepActiveItem) {\n this.focus(event, item);\n }\n },\n\n /**\n * @param {jQuery.Event} event\n */\n blur: function (event) {\n this._delay(function () {\n if (!$.contains(this.element[0], this.document[0].activeElement)) {\n this.collapseAll(event);\n }\n });\n },\n keydown: '_keydown'\n });\n\n this.refresh();\n\n // Clicks outside of a menu collapse any open menus\n this._on(this.document, {\n /**\n * @param {jQuery.Event} event\n */\n click: function (event) {\n if (!$(event.target).closest('.ui-menu').length) {\n this.collapseAll(event);\n }\n\n // Reset the mouseHandled flag\n this.mouseHandled = false;\n }\n });\n },\n\n /**\n * @private\n */\n _destroy: function () {\n // Destroy (sub)menus\n this.element\n .removeAttr('aria-activedescendant')\n .find('.ui-menu').addBack()\n .removeClass('ui-menu ui-widget ui-widget-content ui-corner-all ui-menu-icons')\n .removeAttr('role')\n .removeAttr('tabIndex')\n .removeAttr('aria-labelledby')\n .removeAttr('aria-expanded')\n .removeAttr('aria-hidden')\n .removeAttr('aria-disabled')\n .removeUniqueId()\n .show();\n\n // Destroy menu items\n this.element.find('.ui-menu-item')\n .removeClass('ui-menu-item')\n .removeAttr('role')\n .removeAttr('aria-disabled')\n .children('a')\n .removeUniqueId()\n .removeClass('ui-corner-all ui-state-hover')\n .removeAttr('tabIndex')\n .removeAttr('role')\n .removeAttr('aria-haspopup')\n .children().each(function () {\n var elem = $(this);\n\n if (elem.data('ui-menu-submenu-carat')) {\n elem.remove();\n }\n });\n\n // Destroy menu dividers\n this.element.find('.ui-menu-divider').removeClass('ui-menu-divider ui-widget-content');\n },\n\n /**\n * @param {jQuery.Event} event\n * @private\n */\n _keydown: function (event) {\n var match, prev, character, skip, regex,\n preventDefault = true;\n\n /**\n * @param {String} value\n */\n function escape(value) {\n return value.replace(/[\\-\\[\\]{}()*+?.,\\\\\\^$|#\\s]/g, '\\\\$&');\n }\n\n switch (event.keyCode) {\n case $.ui.keyCode.PAGE_UP:\n this.previousPage(event);\n break;\n\n case $.ui.keyCode.PAGE_DOWN:\n this.nextPage(event);\n break;\n\n case $.ui.keyCode.HOME:\n this._move('first', 'first', event);\n break;\n\n case $.ui.keyCode.END:\n this._move('last', 'last', event);\n break;\n\n case $.ui.keyCode.UP:\n this.previous(event);\n break;\n\n case $.ui.keyCode.DOWN:\n this.next(event);\n break;\n\n case $.ui.keyCode.LEFT:\n this.collapse(event);\n break;\n\n case $.ui.keyCode.RIGHT:\n if (this.active && !this.active.is('.ui-state-disabled')) {\n this.expand(event);\n }\n break;\n\n case $.ui.keyCode.ENTER:\n case $.ui.keyCode.SPACE:\n this._activate(event);\n break;\n\n case $.ui.keyCode.ESCAPE:\n this.collapse(event);\n break;\n\n default:\n preventDefault = false;\n prev = this.previousFilter || '';\n character = String.fromCharCode(event.keyCode);\n skip = false;\n\n clearTimeout(this.filterTimer);\n\n if (character === prev) {\n skip = true;\n } else {\n character = prev + character;\n }\n\n regex = new RegExp('^' + escape(character), 'i');\n match = this.activeMenu.children('.ui-menu-item').filter(function () {\n return regex.test($(this).children('a').text());\n });\n match = skip && match.index(this.active.next()) !== -1 ?\n this.active.nextAll('.ui-menu-item') :\n match;\n\n // If no matches on the current filter, reset to the last character pressed\n // to move down the menu to the first item that starts with that character\n if (!match.length) {\n character = String.fromCharCode(event.keyCode);\n regex = new RegExp('^' + escape(character), 'i');\n match = this.activeMenu.children('.ui-menu-item').filter(function () {\n return regex.test($(this).children('a').text());\n });\n }\n\n if (match.length) {\n this.focus(event, match);\n\n if (match.length > 1) { //eslint-disable-line max-depth\n this.previousFilter = character;\n this.filterTimer = this._delay(function () {\n delete this.previousFilter;\n }, 1000);\n } else {\n delete this.previousFilter;\n }\n } else {\n delete this.previousFilter;\n }\n }\n\n if (preventDefault) {\n event.preventDefault();\n }\n },\n\n /**\n * @param {jQuery.Event} event\n * @private\n */\n _activate: function (event) {\n if (!this.active.is('.ui-state-disabled')) {\n if (this.active.children('a[aria-haspopup=\"true\"]').length) {\n this.expand(event);\n } else {\n this.select(event);\n }\n }\n },\n\n /**\n * Refresh.\n */\n refresh: function () {\n var menus,\n icon = this.options.icons.submenu,\n submenus = this.element.find(this.options.menus);\n\n // Initialize nested menus\n submenus.filter(':not(.ui-menu)')\n .addClass('ui-menu ui-widget ui-widget-content ui-corner-all')\n .hide()\n .attr({\n role: this.options.role,\n 'aria-hidden': 'true',\n 'aria-expanded': 'false'\n })\n .each(function () {\n var menu = $(this),\n item = menu.prev('a'),\n submenuCarat = $('<span>')\n .addClass('ui-menu-icon ui-icon ' + icon)\n .data('ui-menu-submenu-carat', true);\n\n item\n .attr('aria-haspopup', 'true')\n .prepend(submenuCarat);\n menu.attr('aria-labelledby', item.attr('id'));\n });\n\n menus = submenus.add(this.element);\n\n // Don't refresh list items that are already adapted\n menus.children(':not(.ui-menu-item):has(a)')\n .addClass('ui-menu-item')\n .attr('role', 'presentation')\n .children('a')\n .uniqueId()\n .addClass('ui-corner-all')\n .attr({\n tabIndex: -1,\n role: this._itemRole()\n });\n\n // Initialize unlinked menu-items containing spaces and/or dashes only as dividers\n menus.children(':not(.ui-menu-item)').each(function () {\n var item = $(this);\n\n // hyphen, em dash, en dash\n if (!/[^\\-\\u2014\\u2013\\s]/.test(item.text())) {\n item.addClass('ui-widget-content ui-menu-divider');\n }\n });\n\n // Add aria-disabled attribute to any disabled menu item\n menus.children('.ui-state-disabled').attr('aria-disabled', 'true');\n\n // If the active item has been removed, blur the menu\n if (this.active && !$.contains(this.element[0], this.active[0])) {\n this.blur();\n }\n },\n\n /**\n * @return {*}\n * @private\n */\n _itemRole: function () {\n return {\n menu: 'menuitem',\n listbox: 'option'\n }[this.options.role];\n },\n\n /**\n * @param {String} key\n * @param {*} value\n * @private\n */\n _setOption: function (key, value) {\n if (key === 'icons') {\n this.element.find('.ui-menu-icon')\n .removeClass(this.options.icons.submenu)\n .addClass(value.submenu);\n }\n this._super(key, value);\n },\n\n /**\n * @param {jQuery.Event} event\n * @param {Object} item\n */\n focus: function (event, item) {\n var nested, focused;\n\n this.blur(event, event && event.type === 'focus');\n\n this._scrollIntoView(item);\n\n this.active = item.first();\n focused = this.active.children('a').addClass('ui-state-focus');\n // Only update aria-activedescendant if there's a role\n // otherwise we assume focus is managed elsewhere\n if (this.options.role) {\n this.element.attr('aria-activedescendant', focused.attr('id'));\n }\n\n // Highlight active parent menu item, if any\n this.active\n .parent()\n .closest('.ui-menu-item')\n .children('a:first')\n .addClass('ui-state-active');\n\n if (event && event.type === 'keydown') {\n this._close();\n } else {\n this.timer = this._delay(function () {\n this._close();\n }, this.delay);\n }\n\n nested = item.children('.ui-menu');\n\n if (nested.length && /^mouse/.test(event.type)) {\n this._startOpening(nested);\n }\n this.activeMenu = item.parent();\n\n this._trigger('focus', event, {\n item: item\n });\n },\n\n /**\n * @param {Object} item\n * @private\n */\n _scrollIntoView: function (item) {\n var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight;\n\n if (this._hasScroll()) {\n borderTop = parseFloat($.css(this.activeMenu[0], 'borderTopWidth')) || 0;\n paddingTop = parseFloat($.css(this.activeMenu[0], 'paddingTop')) || 0;\n offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop;\n scroll = this.activeMenu.scrollTop();\n elementHeight = this.activeMenu.height();\n itemHeight = item.height();\n\n if (offset < 0) {\n this.activeMenu.scrollTop(scroll + offset);\n } else if (offset + itemHeight > elementHeight) {\n this.activeMenu.scrollTop(scroll + offset - elementHeight + itemHeight);\n }\n }\n },\n\n /**\n * @param {jQuery.Event} event\n * @param {*} fromFocus\n */\n blur: function (event, fromFocus) {\n if (!fromFocus) {\n clearTimeout(this.timer);\n }\n\n if (!this.active) {\n return;\n }\n\n this.active.children('a').removeClass('ui-state-focus');\n this.active = null;\n\n this._trigger('blur', event, {\n item: this.active\n });\n },\n\n /**\n * @param {*} submenu\n * @private\n */\n _startOpening: function (submenu) {\n clearTimeout(this.timer);\n\n // Don't open if already open fixes a Firefox bug that caused a .5 pixel\n // shift in the submenu position when mousing over the carat icon\n if (submenu.attr('aria-hidden') !== 'true') {\n return;\n }\n\n this.timer = this._delay(function () {\n this._close();\n this._open(submenu);\n }, this.delay);\n },\n\n /**\n * @param {*} submenu\n * @private\n */\n _open: function (submenu) {\n var position = $.extend({\n of: this.active\n }, this.options.position);\n\n clearTimeout(this.timer);\n this.element.find('.ui-menu').not(submenu.parents('.ui-menu'))\n .hide()\n .attr('aria-hidden', 'true');\n\n submenu\n .show()\n .removeAttr('aria-hidden')\n .attr('aria-expanded', 'true')\n .position(position);\n },\n\n /**\n * @param {jQuery.Event} event\n * @param {*} all\n */\n collapseAll: function (event, all) {\n clearTimeout(this.timer);\n this.timer = this._delay(function () {\n // If we were passed an event, look for the submenu that contains the event\n var currentMenu = all ? this.element :\n $(event && event.target).closest(this.element.find('.ui-menu'));\n\n // If we found no valid submenu ancestor, use the main menu to close all sub menus anyway\n if (!currentMenu.length) {\n currentMenu = this.element;\n }\n\n this._close(currentMenu);\n\n this.blur(event);\n this.activeMenu = currentMenu;\n }, this.delay);\n },\n\n // With no arguments, closes the currently active menu - if nothing is active\n // it closes all menus. If passed an argument, it will search for menus BELOW\n /**\n * With no arguments, closes the currently active menu - if nothing is active\n * it closes all menus. If passed an argument, it will search for menus BELOW.\n *\n * @param {*} startMenu\n * @private\n */\n _close: function (startMenu) {\n if (!startMenu) {\n startMenu = this.active ? this.active.parent() : this.element;\n }\n\n startMenu\n .find('.ui-menu')\n .hide()\n .attr('aria-hidden', 'true')\n .attr('aria-expanded', 'false')\n .end()\n .find('a.ui-state-active')\n .removeClass('ui-state-active');\n },\n\n /**\n * @param {jQuery.Event} event\n */\n collapse: function (event) {\n var newItem = this.active &&\n this.active.parent().closest('.ui-menu-item', this.element);\n\n if (newItem && newItem.length) {\n this._close();\n this.focus(event, newItem);\n }\n },\n\n /**\n * @param {jQuery.Event} event\n */\n expand: function (event) {\n var newItem = this.active &&\n this.active\n .children('.ui-menu ')\n .children('.ui-menu-item')\n .first();\n\n if (newItem && newItem.length) {\n this._open(newItem.parent());\n\n // Delay so Firefox will not hide activedescendant change in expanding submenu from AT\n this._delay(function () {\n this.focus(event, newItem);\n });\n }\n },\n\n /**\n * @param {jQuery.Event} event\n */\n next: function (event) {\n this._move('next', 'first', event);\n },\n\n /**\n * @param {jQuery.Event} event\n */\n previous: function (event) {\n this._move('prev', 'last', event);\n },\n\n /**\n * @return {null|Boolean}\n */\n isFirstItem: function () {\n return this.active && !this.active.prevAll('.ui-menu-item').length;\n },\n\n /**\n * @return {null|Boolean}\n */\n isLastItem: function () {\n return this.active && !this.active.nextAll('.ui-menu-item').length;\n },\n\n /**\n * @param {*} direction\n * @param {*} filter\n * @param {jQuery.Event} event\n * @private\n */\n _move: function (direction, filter, event) {\n var next;\n\n if (this.active) {\n if (direction === 'first' || direction === 'last') {\n next = this.active\n [direction === 'first' ? 'prevAll' : 'nextAll']('.ui-menu-item')\n .eq(-1);\n } else {\n next = this.active\n [direction + 'All']('.ui-menu-item')\n .eq(0);\n }\n }\n\n if (!next || !next.length || !this.active) {\n next = this.activeMenu.children('.ui-menu-item')[filter]();\n }\n\n this.focus(event, next);\n },\n\n /**\n * @param {jQuery.Event} event\n */\n nextPage: function (event) {\n var item, base, height;\n\n if (!this.active) {\n this.next(event);\n\n return;\n }\n\n if (this.isLastItem()) {\n return;\n }\n\n if (this._hasScroll()) {\n base = this.active.offset().top;\n height = this.element.height();\n this.active.nextAll('.ui-menu-item').each(function () {\n item = $(this);\n\n return item.offset().top - base - height < 0;\n });\n\n this.focus(event, item);\n } else {\n this.focus(event, this.activeMenu.children('.ui-menu-item')\n [!this.active ? 'first' : 'last']());\n }\n },\n\n /**\n * @param {jQuery.Event} event\n */\n previousPage: function (event) {\n var item, base, height;\n\n if (!this.active) {\n this.next(event);\n\n return;\n }\n\n if (this.isFirstItem()) {\n return;\n }\n\n if (this._hasScroll()) {\n base = this.active.offset().top;\n height = this.element.height();\n this.active.prevAll('.ui-menu-item').each(function () {\n item = $(this);\n\n return item.offset().top - base + height > 0;\n });\n\n this.focus(event, item);\n } else {\n this.focus(event, this.activeMenu.children('.ui-menu-item').first());\n }\n },\n\n /**\n * @return {Boolean}\n * @private\n */\n _hasScroll: function () {\n return this.element.outerHeight() < this.element.prop('scrollHeight');\n },\n\n /**\n * @param {jQuery.Event} event\n */\n select: function (event) {\n // TODO: It should never be possible to not have an active item at this\n // point, but the tests don't trigger mouseenter before click.\n var ui;\n\n this.active = this.active || $(event.target).closest('.ui-menu-item');\n ui = {\n item: this.active\n };\n\n if (!this.active.has('.ui-menu').length) {\n this.collapseAll(event, true);\n }\n this._trigger('select', event, ui);\n }\n });\n\n return $.mage.menu;\n}));\n","mage/backend/jstree-mixin.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 return function () {\n $.jstree._themes = require.s.contexts._.config.baseUrl + 'jquery/jstree/themes/';\n };\n});\n","mage/backend/suggest.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n(function (root, factory) {\n 'use strict';\n\n if (typeof define === 'function' && define.amd) {\n define([\n 'jquery',\n 'mage/template',\n 'mage/mage',\n 'jquery/ui',\n 'mage/backend/menu',\n 'mage/translate'\n ], factory);\n } else {\n factory(root.jQuery, root.mageTemplate);\n }\n}(this, function ($, mageTemplate) {\n 'use strict';\n\n /**\n * Implement base functionality\n */\n $.widget('mage.suggest', {\n widgetEventPrefix: 'suggest',\n options: {\n template: '<% if (data.items.length) { %>' +\n '<% if (!data.term && !data.allShown() && data.recentShown()) { %>' +\n '<h5 class=\"title\"><%- data.recentTitle %></h5>' +\n '<% } %>' +\n '<ul data-mage-init=\\'{\"menu\":[]}\\'>' +\n '<% _.each(data.items, function(value){ %>' +\n '<% if (!data.itemSelected(value)) { %><li <%= data.optionData(value) %>>' +\n '<a href=\"#\"><%- value.label %></a></li><% } %>' +\n '<% }); %>' +\n '<% if (!data.term && !data.allShown() && data.recentShown()) { %>' +\n '<li data-mage-init=\\'{\"actionLink\":{\"event\":\"showAll\"}}\\' class=\"show-all\">' +\n '<a href=\"#\"><%- data.showAllTitle %></a></li>' +\n '<% } %>' +\n '</ul><% } else { %><span class=\"mage-suggest-no-records\"><%- data.noRecordsText %></span><% } %>',\n minLength: 1,\n\n /**\n * @type {(String|Array)}\n */\n source: null,\n delay: 500,\n loadingClass: 'mage-suggest-state-loading',\n events: {},\n appendMethod: 'after',\n controls: {\n selector: ':ui-menu, :mage-menu',\n eventsMap: {\n focus: ['menufocus'],\n blur: ['menublur'],\n select: ['menuselect']\n }\n },\n termAjaxArgument: 'label_part',\n filterProperty: 'label',\n className: null,\n inputWrapper: '<div class=\"mage-suggest\"><div class=\"mage-suggest-inner\"></div></div>',\n dropdownWrapper: '<div class=\"mage-suggest-dropdown\"></div>',\n preventClickPropagation: true,\n currentlySelected: null,\n submitInputOnEnter: true\n },\n\n /**\n * Component's constructor\n * @private\n */\n _create: function () {\n this._term = null;\n this._nonSelectedItem = {\n id: '',\n label: ''\n };\n this.templates = {};\n this._renderedContext = null;\n this._selectedItem = this._nonSelectedItem;\n this._control = this.options.controls || {};\n this._setTemplate();\n this._prepareValueField();\n this._render();\n this._bind();\n },\n\n /**\n * Render base elements for suggest component\n * @private\n */\n _render: function () {\n var wrapper;\n\n this.dropdown = $(this.options.dropdownWrapper).hide();\n wrapper = this.options.className ?\n $(this.options.inputWrapper).addClass(this.options.className) :\n $(this.options.inputWrapper);\n this.element\n .wrap(wrapper)[this.options.appendMethod](this.dropdown)\n .attr('autocomplete', 'off');\n },\n\n /**\n * Define a field for storing item id (find in DOM or create a new one)\n * @private\n */\n _prepareValueField: function () {\n if (this.options.valueField) {\n this.valueField = $(this.options.valueField);\n } else {\n this.valueField = this._createValueField()\n .insertBefore(this.element)\n .attr('name', this.element.attr('name'));\n this.element.removeAttr('name');\n }\n },\n\n /**\n * Create value field which keeps a id for selected option\n * can be overridden in descendants\n * @return {jQuery}\n * @private\n */\n _createValueField: function () {\n return $('<input/>', {\n type: 'hidden'\n });\n },\n\n /**\n * Component's destructor\n * @private\n */\n _destroy: function () {\n this.element\n .unwrap()\n .removeAttr('autocomplete');\n\n if (!this.options.valueField) {\n this.element.attr('name', this.valueField.attr('name'));\n this.valueField.remove();\n }\n\n this.dropdown.remove();\n this._off(this.element, 'keydown keyup blur');\n },\n\n /**\n * Return actual value of an \"input\"-element\n * @return {String}\n * @private\n */\n _value: function () {\n return $.trim(this.element[this.element.is(':input') ? 'val' : 'text']());\n },\n\n /**\n * Pass original event to a control component for handling it as it's own event\n * @param {Object} event - event object\n * @private\n */\n _proxyEvents: function (event) {\n var fakeEvent = $.extend({}, $.Event(event.type), {\n ctrlKey: event.ctrlKey,\n keyCode: event.keyCode,\n which: event.keyCode\n }),\n target = this._control.selector ? this.dropdown.find(this._control.selector) : this.dropdown;\n\n target.trigger(fakeEvent);\n },\n\n /**\n * Bind handlers on specific events\n * @private\n */\n _bind: function () {\n this._on($.extend({\n /**\n * @param {jQuery.Event} event\n */\n keydown: function (event) {\n var keyCode = $.ui.keyCode,\n suggestList,\n hasSuggestedItems,\n hasSelectedItems,\n selectedItem;\n\n switch (event.keyCode) {\n case keyCode.PAGE_UP:\n case keyCode.UP:\n if (!event.shiftKey) {\n event.preventDefault();\n this._proxyEvents(event);\n }\n\n suggestList = event.currentTarget.parentNode.getElementsByTagName('ul')[0];\n hasSuggestedItems = event.currentTarget\n .parentNode.getElementsByTagName('ul')[0].children.length >= 0;\n\n if (hasSuggestedItems) {\n selectedItem = $(suggestList.getElementsByClassName('_active')[0])\n .removeClass('_active').prev().addClass('_active');\n event.currentTarget.value = selectedItem.find('a').text();\n }\n\n break;\n\n case keyCode.PAGE_DOWN:\n case keyCode.DOWN:\n if (!event.shiftKey) {\n event.preventDefault();\n this._proxyEvents(event);\n }\n\n suggestList = event.currentTarget.parentNode.getElementsByTagName('ul')[0];\n hasSuggestedItems = event.currentTarget\n .parentNode.getElementsByTagName('ul')[0].children.length >= 0;\n\n if (hasSuggestedItems) {\n hasSelectedItems = suggestList.getElementsByClassName('_active').length === 0;\n\n if (hasSelectedItems) { //eslint-disable-line max-depth\n selectedItem = $(suggestList.children[0]).addClass('_active');\n event.currentTarget.value = selectedItem.find('a').text();\n } else {\n selectedItem = $(suggestList.getElementsByClassName('_active')[0])\n .removeClass('_active').next().addClass('_active');\n event.currentTarget.value = selectedItem.find('a').text();\n }\n }\n break;\n\n case keyCode.TAB:\n if (this.isDropdownShown()) {\n this._onSelectItem(event, null);\n event.preventDefault();\n }\n break;\n\n case keyCode.ENTER:\n case keyCode.NUMPAD_ENTER:\n this._toggleEnter(event);\n\n if (this.isDropdownShown() && this._focused) {\n this._proxyEvents(event);\n event.preventDefault();\n }\n break;\n\n case keyCode.ESCAPE:\n if (this.isDropdownShown()) {\n event.stopPropagation();\n }\n this.close(event);\n this._blurItem();\n break;\n }\n },\n\n /**\n * @param {jQuery.Event} event\n */\n keyup: function (event) {\n var keyCode = $.ui.keyCode;\n\n switch (event.keyCode) {\n case keyCode.HOME:\n case keyCode.END:\n case keyCode.PAGE_UP:\n case keyCode.PAGE_DOWN:\n case keyCode.ESCAPE:\n case keyCode.UP:\n case keyCode.DOWN:\n case keyCode.LEFT:\n case keyCode.RIGHT:\n case keyCode.TAB:\n break;\n\n case keyCode.ENTER:\n case keyCode.NUMPAD_ENTER:\n if (this.isDropdownShown()) {\n event.preventDefault();\n }\n break;\n default:\n this.search(event);\n }\n },\n\n /**\n * @param {jQuery.Event} event\n */\n blur: function (event) {\n if (!this.preventBlur) {\n this._abortSearch();\n this.close(event);\n this._change(event);\n } else {\n this.element.trigger('focus');\n }\n },\n cut: this.search,\n paste: this.search,\n input: this.search,\n selectItem: this._onSelectItem,\n click: this.search\n }, this.options.events));\n\n this._bindSubmit();\n this._bindDropdown();\n },\n\n /**\n * @param {Object} event\n * @private\n */\n _toggleEnter: function (event) {\n var suggestList,\n activeItems,\n selectedItem;\n\n if (!this.options.submitInputOnEnter) {\n event.preventDefault();\n }\n\n suggestList = $(event.currentTarget.parentNode).find('ul').first();\n activeItems = suggestList.find('._active');\n\n if (activeItems.length >= 0) {\n selectedItem = activeItems.first();\n\n if (selectedItem.find('a') && selectedItem.find('a').attr('href') !== undefined) {\n window.location = selectedItem.find('a').attr('href');\n event.preventDefault();\n }\n }\n },\n\n /**\n * Bind handlers for submit on enter\n * @private\n */\n _bindSubmit: function () {\n this.element.parents('form').on('submit', function (event) {\n if (!this.submitInputOnEnter) {\n event.preventDefault();\n }\n });\n },\n\n /**\n * @param {Object} e - event object\n * @private\n */\n _change: function (e) {\n if (this._term !== this._value()) {\n this._trigger('change', e);\n }\n },\n\n /**\n * Bind handlers for dropdown element on specific events\n * @private\n */\n _bindDropdown: function () {\n var events = {\n /**\n * @param {jQuery.Event} e\n */\n click: function (e) {\n // prevent default browser's behavior of changing location by anchor href\n e.preventDefault();\n },\n\n /**\n * @param {jQuery.Event} e\n */\n mousedown: function (e) {\n e.preventDefault();\n }\n };\n\n $.each(this._control.eventsMap, $.proxy(function (suggestEvent, controlEvents) {\n $.each(controlEvents, $.proxy(function (i, handlerName) {\n switch (suggestEvent) {\n case 'select':\n events[handlerName] = this._onSelectItem;\n break;\n\n case 'focus':\n events[handlerName] = this._focusItem;\n break;\n\n case 'blur':\n events[handlerName] = this._blurItem;\n break;\n }\n }, this));\n }, this));\n\n if (this.options.preventClickPropagation) {\n this._on(this.dropdown, events);\n }\n // Fix for IE 8\n this._on(this.dropdown, {\n /**\n * Mousedown.\n */\n mousedown: function () {\n this.preventBlur = true;\n },\n\n /**\n * Mouseup.\n */\n mouseup: function () {\n this.preventBlur = false;\n }\n });\n },\n\n /**\n * @override\n */\n _trigger: function (type, event) {\n var result = this._superApply(arguments);\n\n if (result === false && event) {\n event.stopImmediatePropagation();\n event.preventDefault();\n }\n\n return result;\n },\n\n /**\n * Handle focus event of options item\n * @param {Object} e - event object\n * @param {Object} ui - object that can contain information about focused item\n * @private\n */\n _focusItem: function (e, ui) {\n if (ui && ui.item) {\n this._focused = $(ui.item).prop('tagName') ?\n this._readItemData(ui.item) :\n ui.item;\n\n this.element.val(this._focused.label);\n this._trigger('focus', e, {\n item: this._focused\n });\n }\n },\n\n /**\n * Handle blur event of options item\n * @private\n */\n _blurItem: function () {\n this._focused = null;\n this.element.val(this._term);\n },\n\n /**\n * @param {Object} e - event object\n * @param {Object} item\n * @private\n */\n _onSelectItem: function (e, item) {\n if (item && $.type(item) === 'object' && $(e.target).is(this.element)) {\n this._focusItem(e, {\n item: item\n });\n }\n\n if (this._trigger('beforeselect', e || null, {\n item: this._focused\n }) === false) {\n return;\n }\n this._selectItem(e);\n this._blurItem();\n this._trigger('select', e || null, {\n item: this._selectedItem\n });\n },\n\n /**\n * Save selected item and hide dropdown\n * @private\n * @param {Object} e - event object\n */\n _selectItem: function (e) {\n if (this._focused) {\n this._selectedItem = this._focused;\n\n if (this._selectedItem !== this._nonSelectedItem) {\n this._term = this._selectedItem.label;\n this.valueField.val(this._selectedItem.id);\n this.close(e);\n }\n }\n },\n\n /**\n * Read option data from item element\n * @param {Element} element\n * @return {Object}\n * @private\n */\n _readItemData: function (element) {\n return element.data('suggestOption') || this._nonSelectedItem;\n },\n\n /**\n * Check if dropdown is shown\n * @return {Boolean}\n */\n isDropdownShown: function () {\n return this.dropdown.is(':visible');\n },\n\n /**\n * Open dropdown\n * @private\n * @param {Object} e - event object\n */\n open: function (e) {\n if (!this.isDropdownShown()) {\n this.element.addClass('_suggest-dropdown-open');\n this.dropdown.show();\n this._trigger('open', e);\n }\n },\n\n /**\n * Close and clear dropdown content\n * @private\n * @param {Object} e - event object\n */\n close: function (e) {\n this._renderedContext = null;\n\n if (this.dropdown.length) {\n this.element.removeClass('_suggest-dropdown-open');\n this.dropdown.hide().empty();\n }\n\n this._trigger('close', e);\n },\n\n /**\n * Acquire content template\n * @private\n */\n _setTemplate: function () {\n this.templateName = 'suggest' + Math.random().toString(36).substr(2);\n\n this.templates[this.templateName] = mageTemplate(this.options.template);\n },\n\n /**\n * Execute search process\n * @public\n * @param {Object} e - event object\n */\n search: function (e) {\n var term = this._value();\n\n if ((this._term !== term || term.length === 0) && !this.preventBlur) {\n this._term = term;\n\n if ($.type(term) === 'string' && term.length >= this.options.minLength) {\n if (this._trigger('search', e) === false) { //eslint-disable-line max-depth\n return;\n }\n this._search(e, term, {});\n } else {\n this._selectedItem = this._nonSelectedItem;\n this._resetSuggestValue();\n }\n }\n },\n\n /**\n * Clear suggest hidden input\n * @private\n */\n _resetSuggestValue: function () {\n this.valueField.val(this._nonSelectedItem.id);\n },\n\n /**\n * Actual search method, can be overridden in descendants\n * @param {Object} e - event object\n * @param {String} term - search phrase\n * @param {Object} context - search context\n * @private\n */\n _search: function (e, term, context) {\n var response = $.proxy(function (items) {\n return this._processResponse(e, items, context || {});\n }, this);\n\n this.element.addClass(this.options.loadingClass);\n\n if (this.options.delay) {\n if ($.type(this.options.data) !== 'undefined') {\n response(this.filter(this.options.data, term));\n }\n clearTimeout(this._searchTimeout);\n this._searchTimeout = this._delay(function () {\n this._source(term, response);\n }, this.options.delay);\n } else {\n this._source(term, response);\n }\n },\n\n /**\n * Extend basic context with additional data (search results, search term)\n * @param {Object} context\n * @return {Object}\n * @private\n */\n _prepareDropdownContext: function (context) {\n return $.extend(context, {\n items: this._items,\n term: this._term,\n\n /**\n * @param {Object} item\n * @return {String}\n */\n optionData: function (item) {\n return 'data-suggest-option=\"' +\n $('<div>').text(JSON.stringify(item)).html().replace(/\"/g, '"') + '\"';\n },\n itemSelected: $.proxy(this._isItemSelected, this),\n noRecordsText: $.mage.__('No records found.')\n });\n },\n\n /**\n * @param {Object} item\n * @return {Boolean}\n * @private\n */\n _isItemSelected: function (item) {\n return item.id == (this._selectedItem && this._selectedItem.id ? //eslint-disable-line eqeqeq\n this._selectedItem.id :\n this.options.currentlySelected);\n },\n\n /**\n * Render content of suggest's dropdown\n * @param {Object} e - event object\n * @param {Array} items - list of label+id objects\n * @param {Object} context - template's context\n * @private\n */\n _renderDropdown: function (e, items, context) {\n var tmpl = this.templates[this.templateName];\n\n this._items = items;\n\n tmpl = tmpl({\n data: this._prepareDropdownContext(context)\n });\n\n $(tmpl).appendTo(this.dropdown.empty());\n\n this.dropdown.trigger('contentUpdated')\n .find(this._control.selector).on('focus', function (event) {\n event.preventDefault();\n });\n\n this._renderedContext = context;\n this.element.removeClass(this.options.loadingClass);\n this.open(e);\n },\n\n /**\n * @param {Object} e\n * @param {Object} items\n * @param {Object} context\n * @private\n */\n _processResponse: function (e, items, context) {\n var renderer = $.proxy(function (i) {\n return this._renderDropdown(e, i, context || {});\n }, this);\n\n if (this._trigger('response', e, [items, renderer]) === false) {\n return;\n }\n this._renderDropdown(e, items, context);\n },\n\n /**\n * Implement search process via spesific source\n * @param {String} term - search phrase\n * @param {Function} response - search results handler, process search result\n * @private\n */\n _source: function (term, response) {\n var o = this.options,\n ajaxData;\n\n if ($.isArray(o.source)) {\n response(this.filter(o.source, term));\n } else if ($.type(o.source) === 'string') {\n ajaxData = {};\n ajaxData[this.options.termAjaxArgument] = term;\n\n this._xhr = $.ajax($.extend(true, {\n url: o.source,\n type: 'POST',\n dataType: 'json',\n data: ajaxData,\n success: $.proxy(function (items) {\n this.options.data = items;\n response.apply(response, arguments);\n }, this)\n }, o.ajaxOptions || {}));\n } else if ($.type(o.source) === 'function') {\n o.source.apply(o.source, arguments);\n }\n },\n\n /**\n * Abort search process\n * @private\n */\n _abortSearch: function () {\n this.element.removeClass(this.options.loadingClass);\n clearTimeout(this._searchTimeout);\n },\n\n /**\n * Perform filtering in advance loaded items and returns search result\n * @param {Array} items - all available items\n * @param {String} term - search phrase\n * @return {Object}\n */\n filter: function (items, term) {\n var matcher = new RegExp(term.replace(/[\\-\\/\\\\\\^$*+?.()|\\[\\]{}]/g, '\\\\$&'), 'i'),\n itemsArray = $.isArray(items) ? items : $.map(items, function (element) {\n return element;\n }),\n property = this.options.filterProperty;\n\n return $.grep(\n itemsArray,\n function (value) {\n return matcher.test(value[property] || value.id || value);\n }\n );\n }\n });\n\n /**\n * Implement show all functionality and storing and display recent searches\n */\n $.widget('mage.suggest', $.mage.suggest, {\n options: {\n showRecent: false,\n showAll: false,\n storageKey: 'suggest',\n storageLimit: 10\n },\n\n /**\n * @override\n */\n _create: function () {\n var recentItems;\n\n if (this.options.showRecent && window.localStorage) {\n recentItems = JSON.parse(localStorage.getItem(this.options.storageKey));\n\n /**\n * @type {Array} - list of recently searched items\n * @private\n */\n this._recentItems = $.isArray(recentItems) ? recentItems : [];\n }\n this._super();\n },\n\n /**\n * @override\n */\n _bind: function () {\n this._super();\n this._on(this.dropdown, {\n /**\n * @param {jQuery.Event} e\n */\n showAll: function (e) {\n e.stopImmediatePropagation();\n e.preventDefault();\n this.element.trigger('showAll');\n }\n });\n\n if (this.options.showRecent || this.options.showAll) {\n this._on({\n /**\n * @param {jQuery.Event} e\n */\n focus: function (e) {\n if (!this.isDropdownShown()) {\n this.search(e);\n }\n },\n showAll: this._showAll\n });\n }\n },\n\n /**\n * @private\n * @param {Object} e - event object\n */\n _showAll: function (e) {\n this._abortSearch();\n this._search(e, '', {\n _allShown: true\n });\n },\n\n /**\n * @override\n */\n search: function (e) {\n if (!this._value()) {\n\n if (this.options.showRecent) {\n\n if (this._recentItems.length) { //eslint-disable-line max-depth\n this._processResponse(e, this._recentItems, {});\n } else {\n this._showAll(e);\n }\n } else if (this.options.showAll) {\n this._showAll(e);\n }\n }\n this._superApply(arguments);\n },\n\n /**\n * @override\n */\n _selectItem: function () {\n this._superApply(arguments);\n\n if (this._selectedItem && this._selectedItem.id && this.options.showRecent) {\n this._addRecent(this._selectedItem);\n }\n },\n\n /**\n * @override\n */\n _prepareDropdownContext: function () {\n var context = this._superApply(arguments);\n\n return $.extend(context, {\n recentShown: $.proxy(function () {\n return this.options.showRecent;\n }, this),\n recentTitle: $.mage.__('Recent items'),\n showAllTitle: $.mage.__('Show all...'),\n\n /**\n * @return {Boolean}\n */\n allShown: function () {\n return !!context._allShown;\n }\n });\n },\n\n /**\n * Add selected item of search result into storage of recents\n * @param {Object} item - label+id object\n * @private\n */\n _addRecent: function (item) {\n this._recentItems = $.grep(this._recentItems, function (obj) {\n return obj.id !== item.id;\n });\n this._recentItems.unshift(item);\n this._recentItems = this._recentItems.slice(0, this.options.storageLimit);\n localStorage.setItem(this.options.storageKey, JSON.stringify(this._recentItems));\n }\n });\n\n /**\n * Implement multi suggest functionality\n */\n $.widget('mage.suggest', $.mage.suggest, {\n options: {\n multiSuggestWrapper: '<ul class=\"mage-suggest-choices\">' +\n '<li class=\"mage-suggest-search-field\" data-role=\"parent-choice-element\"><' +\n 'label class=\"mage-suggest-search-label\"></label></li></ul>',\n choiceTemplate: '<li class=\"mage-suggest-choice button\"><div><%- text %></div>' +\n '<span class=\"mage-suggest-choice-close\" tabindex=\"-1\" ' +\n 'data-mage-init=\\'{\"actionLink\":{\"event\":\"removeOption\"}}\\'></span></li>',\n selectedClass: 'mage-suggest-selected'\n },\n\n /**\n * @override\n */\n _create: function () {\n this.choiceTmpl = mageTemplate(this.options.choiceTemplate);\n\n this._super();\n\n if (this.options.multiselect) {\n this.valueField.hide();\n }\n },\n\n /**\n * @override\n */\n _render: function () {\n this._super();\n\n if (this.options.multiselect) {\n this._renderMultiselect();\n }\n },\n\n /**\n * Render selected options\n * @private\n */\n _renderMultiselect: function () {\n var that = this;\n\n this.element.wrap(this.options.multiSuggestWrapper);\n this.elementWrapper = this.element.closest('[data-role=\"parent-choice-element\"]');\n $(function () {\n that._getOptions()\n .each(function (i, option) {\n option = $(option);\n that._createOption({\n id: option.val(),\n label: option.text()\n });\n });\n });\n },\n\n /**\n * @return {Array} array of DOM-elements\n * @private\n */\n _getOptions: function () {\n return this.valueField.find('option');\n },\n\n /**\n * @override\n */\n _bind: function () {\n this._super();\n\n if (this.options.multiselect) {\n this._on({\n /**\n * @param {jQuery.Event} event\n */\n keydown: function (event) {\n if (event.keyCode === $.ui.keyCode.BACKSPACE) {\n if (!this._value()) {\n this._removeLastAdded(event);\n }\n }\n },\n removeOption: this.removeOption\n });\n }\n },\n\n /**\n * @param {Array} items\n * @return {Array}\n * @private\n */\n _filterSelected: function (items) {\n var options = this._getOptions();\n\n return $.grep(items, function (value) {\n var itemSelected = false;\n\n $.each(options, function () {\n if (value.id == $(this).val()) { //eslint-disable-line eqeqeq\n itemSelected = true;\n }\n });\n\n return !itemSelected;\n });\n },\n\n /**\n * @override\n */\n _processResponse: function (e, items, context) {\n if (this.options.multiselect) {\n items = this._filterSelected(items, context);\n }\n this._superApply([e, items, context]);\n },\n\n /**\n * @override\n */\n _prepareValueField: function () {\n this._super();\n\n if (this.options.multiselect && !this.options.valueField && this.options.selectedItems) {\n $.each(this.options.selectedItems, $.proxy(function (i, item) {\n this._addOption(item);\n }, this));\n }\n },\n\n /**\n * If \"multiselect\" option is set, then do not need to clear value for hidden select, to avoid losing of\n * previously selected items\n * @override\n */\n _resetSuggestValue: function () {\n if (!this.options.multiselect) {\n this._super();\n }\n },\n\n /**\n * @override\n */\n _createValueField: function () {\n if (this.options.multiselect) {\n return $('<select/>', {\n type: 'hidden',\n multiple: 'multiple'\n });\n }\n\n return this._super();\n },\n\n /**\n * @override\n */\n _selectItem: function (e) {\n if (this.options.multiselect) {\n if (this._focused) {\n this._selectedItem = this._focused;\n\n /* eslint-disable max-depth */\n if (this._selectedItem !== this._nonSelectedItem) {\n this._term = '';\n this.element.val(this._term);\n\n if (this._isItemSelected(this._selectedItem)) {\n $(e.target).removeClass(this.options.selectedClass);\n this.removeOption(e, this._selectedItem);\n this._selectedItem = this._nonSelectedItem;\n } else {\n $(e.target).addClass(this.options.selectedClass);\n this._addOption(e, this._selectedItem);\n }\n }\n\n /* eslint-enable max-depth */\n }\n this.close(e);\n } else {\n this._superApply(arguments);\n }\n },\n\n /**\n * @override\n */\n _isItemSelected: function (item) {\n if (this.options.multiselect) {\n return this.valueField.find('option[value=' + item.id + ']').length > 0;\n }\n\n return this._superApply(arguments);\n },\n\n /**\n *\n * @param {Object} item\n * @return {Element}\n * @private\n */\n _createOption: function (item) {\n var option = this._getOption(item);\n\n if (!option.length) {\n option = $('<option>', {\n value: item.id,\n selected: true\n }).text(item.label);\n }\n\n return option.data('renderedOption', this._renderOption(item));\n },\n\n /**\n * Add selected item in to select options\n * @param {Object} e - event object\n * @param {*} item\n * @private\n */\n _addOption: function (e, item) {\n this.valueField.append(this._createOption(item).data('selectTarget', $(e.target)));\n },\n\n /**\n * @param {Object|Element} item\n * @return {Element}\n * @private\n */\n _getOption: function (item) {\n return $(item).prop('tagName') ?\n $(item) :\n this.valueField.find('option[value=' + item.id + ']');\n },\n\n /**\n * Remove last added option\n * @private\n * @param {Object} e - event object\n */\n _removeLastAdded: function (e) {\n var lastAdded = this._getOptions().last();\n\n if (lastAdded.length) {\n this.removeOption(e, lastAdded);\n }\n },\n\n /**\n * Remove item from select options\n * @param {Object} e - event object\n * @param {Object} item\n * @private\n */\n removeOption: function (e, item) {\n var option = this._getOption(item),\n selectTarget = option.data('selectTarget');\n\n if (selectTarget && selectTarget.length) {\n selectTarget.removeClass(this.options.selectedClass);\n }\n\n option.data('renderedOption').remove();\n option.remove();\n },\n\n /**\n * Render visual element of selected item\n * @param {Object} item - selected item\n * @private\n */\n _renderOption: function (item) {\n var tmpl = this.choiceTmpl({\n text: item.label\n });\n\n return $(tmpl)\n .insertBefore(this.elementWrapper)\n .trigger('contentUpdated')\n .on('removeOption', $.proxy(function (e) {\n this.removeOption(e, item);\n }, this));\n }\n });\n\n return $.mage.suggest;\n}));\n","mage/backend/form.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n(function (factory) {\n 'use strict';\n\n if (typeof define === 'function' && define.amd) {\n define([\n 'jquery',\n 'jquery/ui'\n ], factory);\n } else {\n factory(jQuery);\n }\n}(function ($) {\n 'use strict';\n\n $.widget('mage.form', {\n options: {\n handlersData: {\n save: {},\n saveAndContinueEdit: {\n action: {\n args: {\n back: 'edit'\n }\n }\n },\n preview: {\n target: '_blank'\n }\n }\n },\n\n /**\n * Form creation\n * @protected\n */\n _create: function () {\n this._bind();\n },\n\n /**\n * Set form attributes to initial state\n * @protected\n */\n _rollback: function () {\n if (this.oldAttributes) {\n this.element.prop(this.oldAttributes);\n }\n },\n\n /**\n * Check if field value is changed\n * @protected\n * @param {Object} e - event object\n */\n _changesObserver: function (e) {\n var target = $(e.target),\n changed;\n\n if (e.type === 'focus' || e.type === 'focusin') {\n this.currentField = {\n statuses: {\n checked: target.is(':checked'),\n selected: target.is(':selected')\n },\n val: target.val()\n };\n\n } else {\n if (this.currentField) { //eslint-disable-line no-lonely-if\n changed = target.val() !== this.currentField.val ||\n target.is(':checked') !== this.currentField.statuses.checked ||\n target.is(':selected') !== this.currentField.statuses.selected;\n\n if (changed) { //eslint-disable-line max-depth\n target.trigger('changed');\n }\n }\n }\n },\n\n /**\n * Get array with handler names\n * @protected\n * @return {Array} Array of handler names\n */\n _getHandlers: function () {\n var handlers = [];\n\n $.each(this.options.handlersData, function (key) {\n handlers.push(key);\n });\n\n return handlers;\n },\n\n /**\n * Store initial value of form attribute\n * @param {String} attrName - name of attribute\n * @protected\n */\n _storeAttribute: function (attrName) {\n var prop;\n\n this.oldAttributes = this.oldAttributes || {};\n\n if (!this.oldAttributes[attrName]) {\n prop = this.element.attr(attrName);\n this.oldAttributes[attrName] = prop ? prop : '';\n }\n },\n\n /**\n * Bind handlers\n * @protected\n */\n _bind: function () {\n this.element\n .on(this._getHandlers().join(' '), $.proxy(this._submit, this))\n .on('focus blur focusin focusout', $.proxy(this._changesObserver, this));\n },\n\n /**\n * Get action url for form\n * @param {Object|String} data - object with parameters for action url or url string\n * @return {String} action url\n */\n _getActionUrl: function (data) {\n if ($.type(data) === 'object') {\n return this._buildURL(this.oldAttributes.action, data.args);\n }\n\n return $.type(data) === 'string' ? data : this.oldAttributes.action;\n },\n\n /**\n * Add additional parameters into URL\n * @param {String} url - original url\n * @param {Object} params - object with parameters for action url\n * @return {String} action url\n * @private\n */\n _buildURL: function (url, params) {\n var concat = /\\?/.test(url) ? ['&', '='] : ['/', '/'];\n\n url = url.replace(/[\\/&]+$/, '');\n $.each(params, function (key, value) {\n url += concat[0] + key + concat[1] + window.encodeURIComponent(value);\n });\n\n return url + (concat[0] === '/' ? '/' : '');\n },\n\n /**\n * Prepare data for form attributes\n * @protected\n * @param {Object} data\n * @return {Object}\n */\n _processData: function (data) {\n $.each(data, $.proxy(function (attrName, attrValue) {\n this._storeAttribute(attrName);\n\n if (attrName === 'action') {\n data[attrName] = this._getActionUrl(attrValue);\n }\n }, this));\n\n return data;\n },\n\n /**\n * Get additional data before form submit\n * @protected\n * @param {String} handlerName\n * @param {Object} data\n */\n _beforeSubmit: function (handlerName, data) {\n var submitData = {},\n event = new $.Event('beforeSubmit');\n\n this.element.trigger(event, [submitData, handlerName]);\n data = $.extend(\n true, {},\n this.options.handlersData[handlerName] || {},\n submitData,\n data\n );\n this.element.prop(this._processData(data));\n\n return !event.isDefaultPrevented();\n },\n\n /**\n * Submit the form\n * @param {Object} e - event object\n * @param {Object} data - event data object\n */\n _submit: function (e, data) {\n this._rollback();\n\n if (this._beforeSubmit(e.type, data) !== false) {\n this.element.trigger('submit', e);\n }\n }\n });\n\n return $.mage.form;\n}));\n","mage/backend/floating-header.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'jquery',\n 'jquery/ui'\n], function ($) {\n 'use strict';\n\n $.widget('mage.floatingHeader', {\n options: {\n placeholderAttrs: {\n 'class': 'page-actions-placeholder'\n },\n fixedClass: '_fixed',\n hiddenClass: '_hidden',\n title: '.page-title-wrapper .page-title',\n pageMainActions: '.page-main-actions',\n contains: '[data-role=modal]'\n },\n\n /**\n * Widget initialization\n * @private\n */\n _create: function () {\n var title = $(this.options.title).text(),\n wrapped = this.element.find('.page-actions-buttons').children();\n\n if (this.element.parents(this.options.contains).length) {\n return this;\n }\n\n this._setVars();\n this._bind();\n this.element.find('script').remove();\n\n if (wrapped.length) {\n wrapped\n .unwrap() // .page-actions-buttons\n .unwrap(); // .page-actions-inner\n }\n this.element.wrapInner($('<div/>', {\n 'class': 'page-actions-buttons'\n }));\n this.element.wrapInner($('<div/>', {\n 'class': 'page-actions-inner', 'data-title': title\n }));\n },\n\n /**\n * Set privat variables on load, for performance purposes\n * @private\n */\n _setVars: function () {\n this._placeholder = this.element.before($('<div/>', this.options.placeholderAttrs)).prev();\n this._offsetTop = this._placeholder.offset().top;\n this._height = this.element\n .parents(this.options.pageMainActions)\n .outerHeight();\n },\n\n /**\n * Event binding, will monitor scroll and resize events (resize events left for backward compat)\n * @private\n */\n _bind: function () {\n this._on(window, {\n scroll: this._handlePageScroll,\n resize: this._handlePageScroll\n });\n },\n\n /**\n * Event handler for setting fixed positioning\n * @private\n */\n _handlePageScroll: function () {\n var isActive = $(window).scrollTop() > this._offsetTop;\n\n if (isActive) {\n this.element\n .addClass(this.options.fixedClass)\n .parents(this.options.pageMainActions)\n .addClass(this.options.hiddenClass);\n } else {\n this.element\n .removeClass(this.options.fixedClass)\n .parents(this.options.pageMainActions)\n .removeClass(this.options.hiddenClass);\n }\n\n this._placeholder.height(isActive ? this._height : '');\n },\n\n /**\n * Widget destroy functionality\n * @private\n */\n _destroy: function () {\n this._placeholder.remove();\n this._off($(window));\n }\n });\n\n return $.mage.floatingHeader;\n});\n","mage/backend/tabs.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* global FORM_KEY */\n(function (factory) {\n 'use strict';\n\n if (typeof define === 'function' && define.amd) {\n define([\n 'jquery',\n 'jquery/ui'\n ], factory);\n } else {\n factory(jQuery);\n }\n}(function ($) {\n 'use strict';\n\n var rhash, isLocal;\n\n // mage.tabs base functionality\n $.widget('mage.tabs', $.ui.tabs, {\n options: {\n spinner: false,\n groups: null,\n tabPanelClass: '',\n excludedPanel: ''\n },\n\n /**\n * Tabs creation\n * @protected\n */\n _create: function () {\n var activeIndex = this._getTabIndex(this.options.active);\n\n this.options.active = activeIndex >= 0 ? activeIndex : 0;\n this._super();\n },\n\n /**\n * @override\n * @private\n * @return {Array} Array of DOM-elements\n */\n _getList: function () {\n if (this.options.groups) {\n return this.element.find(this.options.groups);\n }\n\n return this._super();\n },\n\n /**\n * Get active anchor\n * @return {Element}\n */\n activeAnchor: function () {\n return this.anchors.eq(this.option('active'));\n },\n\n /**\n * Get tab index by tab id\n * @protected\n * @param {String} id - id of tab\n * @return {Number}\n */\n _getTabIndex: function (id) {\n var anchors = this.anchors ?\n this.anchors :\n this._getList().find('> li > a[href]');\n\n return anchors.index($('#' + id));\n },\n\n /**\n * Switch between tabs\n * @protected\n * @param {Object} event - event object\n * @param {undefined|Object} eventData\n */\n _toggle: function (event, eventData) {\n var anchor = $(eventData.newTab).find('a');\n\n if ($(eventData.newTab).find('a').data().tabType === 'link') {\n location.href = anchor.prop('href');\n } else {\n this._superApply(arguments);\n }\n }\n });\n\n rhash = /#.*$/;\n\n /**\n * @param {*} anchor\n * @return {Boolean}\n */\n isLocal = function (anchor) {\n return anchor.hash.length > 1 &&\n anchor.href.replace(rhash, '') ===\n location.href.replace(rhash, '')\n // support: Safari 5.1\n // Safari 5.1 doesn't encode spaces in window.location\n // but it does encode spaces from anchors (#8777)\n .replace(/\\s/g, '%20');\n };\n\n // Extension for mage.tabs - Move panels in destination element\n $.widget('mage.tabs', $.mage.tabs, {\n /**\n * Move panels in destination element on creation\n * @protected\n * @override\n */\n _create: function () {\n this._super();\n this._movePanelsInDestination(this.panels);\n },\n\n /**\n * Get panel for tab. If panel no exist in tabs container, then find panel in destination element\n * @protected\n * @override\n * @param {Element} tab - tab \"li\" DOM-element\n * @return {Element}\n */\n _getPanelForTab: function (tab) {\n var panel = this._superApply(arguments),\n id;\n\n if (!panel.length) {\n id = $(tab).attr('aria-controls');\n panel = $(this.options.destination).find(this._sanitizeSelector('#' + id));\n }\n\n return panel;\n },\n\n /**\n * @private\n */\n _processTabs: function () {\n var that = this;\n\n this.tablist = this._getList()\n .addClass('ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all')\n .attr('role', 'tablist');\n\n this.tabs = this.tablist.find('> li:has(a[href])')\n .addClass('ui-state-default ui-corner-top')\n .attr({\n role: 'tab',\n tabIndex: -1\n });\n\n this.anchors = this.tabs.map(function () {\n return $('a', this)[ 0 ];\n })\n .addClass('ui-tabs-anchor')\n .attr({\n role: 'presentation',\n tabIndex: -1\n });\n\n this.panels = $();\n\n this.anchors.each(function (i, anchor) {\n var selector, panel, panelId,\n anchorId = $(anchor).uniqueId().attr('id'),\n tab = $(anchor).closest('li'),\n originalAriaControls = tab.attr('aria-controls');\n\n // inline tab\n if (isLocal(anchor)) {\n selector = anchor.hash;\n panel = that.document.find(that._sanitizeSelector(selector));\n // remote tab\n } else {\n panelId = that._tabId(tab);\n selector = '#' + panelId;\n panel = that.document.find(selector);\n\n if (!panel.length) {\n panel = that._createPanel(panelId);\n panel.insertAfter(that.panels[ i - 1 ] || that.tablist);\n }\n panel.attr('aria-live', 'polite');\n }\n\n if (panel.length) {\n that.panels = that.panels.add(panel);\n }\n\n if (originalAriaControls) {\n tab.data('ui-tabs-aria-controls', originalAriaControls);\n }\n tab.attr({\n 'aria-controls': selector.substring(1),\n 'aria-labelledby': anchorId\n });\n panel.attr('aria-labelledby', anchorId);\n\n if (that.options.excludedPanel.indexOf(anchorId + '_content') < 0) {\n panel.addClass(that.options.tabPanelClass);\n }\n });\n\n this.panels\n .addClass('ui-tabs-panel ui-widget-content ui-corner-bottom')\n .attr('role', 'tabpanel');\n },\n\n /**\n * Move panels in destination element\n * @protected\n * @override\n */\n _movePanelsInDestination: function (panels) {\n if (this.options.destination && !panels.parents(this.options.destination).length) {\n this.element.trigger('beforePanelsMove', panels);\n\n panels.find('script:not([type]), script[type=\"text/javascript\"]').remove();\n\n panels.appendTo(this.options.destination)\n .each($.proxy(function (i, panel) {\n $(panel).trigger('move.tabs', this.anchors.eq(i));\n }, this));\n }\n },\n\n /**\n * Move panels in destination element on tabs switching\n * @protected\n * @override\n * @param {Object} event - event object\n * @param {Object} eventData\n */\n _toggle: function (event, eventData) {\n this._movePanelsInDestination(eventData.newPanel);\n this._superApply(arguments);\n }\n });\n\n // Extension for mage.tabs - Ajax functionality for tabs\n $.widget('mage.tabs', $.mage.tabs, {\n options: {\n ajaxOptions: {\n data: {\n isAjax: true,\n 'form_key': typeof FORM_KEY !== 'undefined' ? FORM_KEY : null\n }\n },\n\n /**\n * Replacing href attribute with loaded panel id\n * @param {Object} event - event object\n * @param {Object} ui\n */\n load: function (event, ui) {\n var panel = $(ui.panel);\n\n $(ui.tab).prop('href', '#' + panel.prop('id'));\n panel.trigger('contentUpdated');\n }\n }\n });\n\n // Extension for mage.tabs - Attach event handlers to tabs\n $.widget('mage.tabs', $.mage.tabs, {\n options: {\n tabIdArgument: 'tab',\n tabsBlockPrefix: null\n },\n\n /**\n * Attach event handlers to tabs, on creation\n * @protected\n * @override\n */\n _refresh: function () {\n this._super();\n $.each(this.tabs, $.proxy(function (i, tab) {\n $(this._getPanelForTab(tab))\n .off('changed' + this.eventNamespace)\n .off('highlight.validate' + this.eventNamespace)\n .off('focusin' + this.eventNamespace)\n\n .on('changed' + this.eventNamespace, {\n index: i\n }, $.proxy(this._onContentChange, this))\n .on('highlight.validate' + this.eventNamespace, {\n index: i\n }, $.proxy(this._onInvalid, this))\n .on('focusin' + this.eventNamespace, {\n index: i\n }, $.proxy(this._onFocus, this));\n }, this));\n\n ($(this.options.destination).is('form') ?\n $(this.options.destination) :\n $(this.options.destination).closest('form'))\n .off('beforeSubmit' + this.eventNamespace)\n .on('beforeSubmit' + this.eventNamespace, $.proxy(this._onBeforeSubmit, this));\n },\n\n /**\n * Mark tab as changed if some field inside tab panel is changed\n * @protected\n * @param {Object} e - event object\n */\n _onContentChange: function (e) {\n var cssChanged = '_changed';\n\n this.anchors.eq(e.data.index).addClass(cssChanged);\n this._updateNavTitleMessages(e, cssChanged);\n },\n\n /**\n * Clone messages (tooltips) from anchor to parent element\n * @protected\n * @param {Object} e - event object\n * @param {String} messageType - changed or error\n */\n _updateNavTitleMessages: function (e, messageType) {\n var curAnchor = this.anchors.eq(e.data.index),\n curItem = curAnchor.parents('[data-role=\"container\"]').find('[data-role=\"title\"]'),\n curItemMessages = curItem.find('[data-role=\"title-messages\"]'),\n activeClass = '_active';\n\n if (curItemMessages.is(':empty')) {\n curAnchor\n .find('[data-role=\"item-messages\"]')\n .clone()\n .appendTo(curItemMessages);\n }\n\n curItemMessages.find('.' + messageType).addClass(activeClass);\n },\n\n /**\n * Mark tab as error if some field inside tab panel is not passed validation\n * @param {Object} e - event object\n * @protected\n */\n _onInvalid: function (e) {\n var cssError = '_error',\n fakeEvent = e;\n\n fakeEvent.currentTarget = $(this.anchors).eq(e.data.index);\n this._eventHandler(fakeEvent);\n this.anchors.eq(e.data.index).addClass(cssError).find('.' + cssError).show();\n this._updateNavTitleMessages(e, cssError);\n },\n\n /**\n * Show tab panel if focus event triggered of some field inside tab panel\n * @param {Object} e - event object\n * @protected\n */\n _onFocus: function (e) {\n this.option('_active', e.data.index);\n },\n\n /**\n * Add active tab id in data object when \"beforeSubmit\" event is triggered\n * @param {Object} e - event object\n * @param {Object} data - event data object\n * @protected\n */\n _onBeforeSubmit: function (e, data) { //eslint-disable-line no-unused-vars\n var activeAnchor = this.activeAnchor(),\n activeTabId = activeAnchor.prop('id'),\n options;\n\n if (this.options.tabsBlockPrefix) {\n if (activeAnchor.is('[id*=\"' + this.options.tabsBlockPrefix + '\"]')) {\n activeTabId = activeAnchor.prop('id').substr(this.options.tabsBlockPrefix.length);\n }\n }\n $(this.anchors).removeClass('error');\n options = {\n action: {\n args: {}\n }\n };\n options.action.args[this.options.tabIdArgument] = activeTabId;\n data = data ? $.extend(data, options) : options;\n }\n });\n\n // Extension for mage.tabs - Shadow tabs functionality\n $.widget('mage.tabs', $.mage.tabs, {\n /**\n * Add shadow tabs functionality on creation\n * @protected\n * @override\n */\n _refresh: function () {\n var anchors, shadowTabs, tabs;\n\n this._super();\n anchors = this.anchors;\n shadowTabs = this.options.shadowTabs;\n tabs = this.tabs;\n\n if (shadowTabs) {\n anchors.each($.proxy(function (i, anchor) {\n var anchorId = $(anchor).prop('id');\n\n if (shadowTabs[anchorId]) {\n $(anchor).parents('li').on('click', $.proxy(function () {\n $.each(shadowTabs[anchorId], $.proxy(function (key, id) {\n this.load($(tabs).index($('#' + id).parents('li')), {});\n }, this));\n }, this));\n }\n }, this));\n }\n }\n });\n\n return $.mage.tabs;\n}));\n","mage/backend/button.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n(function (factory) {\n 'use strict';\n\n if (typeof define === 'function' && define.amd) {\n define([\n 'jquery',\n 'jquery/ui'\n ], factory);\n } else {\n factory(jQuery);\n }\n}(function ($) {\n 'use strict';\n\n $.widget('ui.button', $.ui.button, {\n options: {\n eventData: {},\n waitTillResolved: true\n },\n\n /**\n * Button creation.\n * @protected\n */\n _create: function () {\n if (this.options.event) {\n this.options.target = this.options.target || this.element;\n this._bind();\n }\n\n this._super();\n },\n\n /**\n * Bind handler on button click.\n * @protected\n */\n _bind: function () {\n this.element\n .off('click.button')\n .on('click.button', $.proxy(this._click, this));\n },\n\n /**\n * Button click handler.\n * @protected\n */\n _click: function () {\n var options = this.options;\n\n $(options.target).trigger(options.event, [options.eventData]);\n }\n });\n\n return $.ui.button;\n}));\n","Magento_AdvancedSearch/js/testconnection.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 'Magento_Ui/js/modal/alert',\n 'jquery/ui'\n], function ($, alert) {\n 'use strict';\n\n $.widget('mage.testConnection', {\n options: {\n url: '',\n elementId: '',\n successText: '',\n failedText: '',\n fieldMapping: ''\n },\n\n /**\n * Bind handlers to events\n */\n _create: function () {\n this._on({\n 'click': $.proxy(this._connect, this)\n });\n },\n\n /**\n * Method triggers an AJAX request to check search engine connection\n * @private\n */\n _connect: function () {\n var result = this.options.failedText,\n element = $('#' + this.options.elementId),\n self = this,\n params = {},\n msg = '';\n\n element.removeClass('success').addClass('fail');\n $.each($.parseJSON(this.options.fieldMapping), function (key, el) {\n params[key] = $('#' + el).val();\n });\n $.ajax({\n url: this.options.url,\n showLoader: true,\n data: params\n }).done(function (response) {\n if (response.success) {\n element.removeClass('fail').addClass('success');\n result = self.options.successText;\n } else {\n msg = response.errorMessage;\n\n if (msg) {\n alert({\n content: msg\n });\n }\n }\n }).always(function () {\n $('#' + self.options.elementId + '_result').text(result);\n });\n }\n });\n\n return $.mage.testConnection;\n});\n","Magento_Rule/rules.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\n\ndefine([\n 'jquery',\n 'Magento_Ui/js/modal/alert',\n 'mage/translate',\n 'prototype'\n], function (jQuery) {\n\n var VarienRulesForm = new Class.create();\n\n VarienRulesForm.prototype = {\n initialize: function (parent, newChildUrl) {\n this.parent = $(parent);\n this.newChildUrl = newChildUrl;\n this.shownElement = null;\n this.updateElement = null;\n this.chooserSelectedItems = $H({});\n this.readOnly = false;\n\n var elems = this.parent.getElementsByClassName('rule-param');\n\n for (var i = 0; i < elems.length; i++) {\n this.initParam(elems[i]);\n }\n },\n\n setReadonly: function (readonly) {\n this.readOnly = readonly;\n var elems = this.parent.getElementsByClassName('rule-param-remove');\n\n for (var i = 0; i < elems.length; i++) {\n var element = elems[i];\n\n if (this.readOnly) {\n element.hide();\n } else {\n element.show();\n }\n }\n\n var elems = this.parent.getElementsByClassName('rule-param-new-child');\n\n for (var i = 0; i < elems.length; i++) {\n var element = elems[i];\n\n if (this.readOnly) {\n element.hide();\n } else {\n element.show();\n }\n }\n\n var elems = this.parent.getElementsByClassName('rule-param');\n\n for (var i = 0; i < elems.length; i++) {\n var container = elems[i];\n var label = Element.down(container, '.label');\n\n if (label) {\n if (this.readOnly) {\n label.addClassName('label-disabled');\n } else {\n label.removeClassName('label-disabled');\n }\n }\n }\n },\n\n initParam: function (container) {\n container.rulesObject = this;\n var label = Element.down(container, '.label');\n\n if (label) {\n Event.observe(label, 'click', this.showParamInputField.bind(this, container));\n }\n\n var elem = Element.down(container, '.element');\n\n if (elem) {\n var trig = elem.down('.rule-chooser-trigger');\n\n if (trig) {\n Event.observe(trig, 'click', this.toggleChooser.bind(this, container));\n }\n\n var apply = elem.down('.rule-param-apply');\n\n if (apply) {\n Event.observe(apply, 'click', this.hideParamInputField.bind(this, container));\n } else {\n elem = elem.down('.element-value-changer');\n elem.container = container;\n\n if (!elem.multiple) {\n Event.observe(elem, 'change', this.hideParamInputField.bind(this, container));\n\n this.changeVisibilityForValueRuleParam(elem);\n\n }\n Event.observe(elem, 'blur', this.hideParamInputField.bind(this, container));\n }\n }\n\n var remove = Element.down(container, '.rule-param-remove');\n\n if (remove) {\n Event.observe(remove, 'click', this.removeRuleEntry.bind(this, container));\n }\n },\n\n showChooserElement: function (chooser) {\n this.chooserSelectedItems = $H({});\n\n if (chooser.hasClassName('no-split')) {\n this.chooserSelectedItems.set(this.updateElement.value, 1);\n } else {\n var values = this.updateElement.value.split(','),\n s = '';\n\n for (i = 0; i < values.length; i++) {\n s = values[i].strip();\n\n if (s != '') {\n this.chooserSelectedItems.set(s, 1);\n }\n }\n }\n new Ajax.Request(chooser.getAttribute('url'), {\n evalScripts: true,\n parameters: {\n 'form_key': FORM_KEY, 'selected[]': this.chooserSelectedItems.keys()\n },\n onSuccess: function (transport) {\n if (this._processSuccess(transport)) {\n jQuery(chooser).html(transport.responseText);\n this.showChooserLoaded(chooser, transport);\n jQuery(chooser).trigger('contentUpdated');\n }\n }.bind(this),\n onFailure: this._processFailure.bind(this)\n });\n },\n\n showChooserLoaded: function (chooser, transport) {\n chooser.style.display = 'block';\n },\n\n showChooser: function (container, event) {\n var chooser = container.up('li');\n\n if (!chooser) {\n return;\n }\n chooser = chooser.down('.rule-chooser');\n\n if (!chooser) {\n return;\n }\n this.showChooserElement(chooser);\n },\n\n hideChooser: function (container, event) {\n var chooser = container.up('li');\n\n if (!chooser) {\n return;\n }\n chooser = chooser.down('.rule-chooser');\n\n if (!chooser) {\n return;\n }\n chooser.style.display = 'none';\n },\n\n toggleChooser: function (container, event) {\n if (this.readOnly) {\n return false;\n }\n\n var chooser = container.up('li').down('.rule-chooser');\n\n if (!chooser) {\n return;\n }\n\n if (chooser.style.display == 'block') {\n chooser.style.display = 'none';\n this.cleanChooser(container, event);\n } else {\n this.showChooserElement(chooser);\n }\n },\n\n cleanChooser: function (container, event) {\n var chooser = container.up('li').down('.rule-chooser');\n\n if (!chooser) {\n return;\n }\n chooser.innerHTML = '';\n },\n\n showParamInputField: function (container, event) {\n if (this.readOnly) {\n return false;\n }\n\n if (this.shownElement) {\n this.hideParamInputField(this.shownElement, event);\n }\n\n Element.addClassName(container, 'rule-param-edit');\n var elemContainer = Element.down(container, '.element');\n\n var elem = Element.down(elemContainer, 'input.input-text');\n\n jQuery(elem).trigger('contentUpdated');\n\n if (elem) {\n elem.focus();\n\n if (elem && elem.id && elem.id.match(/__value$/)) {\n this.updateElement = elem;\n }\n\n }\n\n var elem = Element.down(elemContainer, '.element-value-changer');\n\n if (elem) {\n elem.focus();\n }\n\n this.shownElement = container;\n },\n\n hideParamInputField: function (container, event) {\n Element.removeClassName(container, 'rule-param-edit');\n var label = Element.down(container, '.label'),\n elem;\n\n if (!container.hasClassName('rule-param-new-child')) {\n elem = Element.down(container, '.element-value-changer');\n\n if (elem && elem.options) {\n var selectedOptions = [];\n\n for (i = 0; i < elem.options.length; i++) {\n if (elem.options[i].selected) {\n selectedOptions.push(elem.options[i].text);\n }\n }\n\n var str = selectedOptions.join(', ');\n\n label.innerHTML = str != '' ? str : '...';\n }\n\n this.changeVisibilityForValueRuleParam(elem);\n\n elem = Element.down(container, 'input.input-text');\n\n if (elem) {\n var str = elem.value.replace(/(^\\s+|\\s+$)/g, '');\n\n elem.value = str;\n\n if (str == '') {\n str = '...';\n } else if (str.length > 30) {\n str = str.substr(0, 30) + '...';\n }\n label.innerHTML = str.escapeHTML();\n }\n } else {\n elem = container.down('.element-value-changer');\n\n if (elem.value) {\n this.addRuleNewChild(elem);\n }\n elem.value = '';\n }\n\n if (elem && elem.id && elem.id.match(/__value$/)) {\n this.hideChooser(container, event);\n this.updateElement = null;\n }\n\n this.shownElement = null;\n },\n\n changeVisibilityForValueRuleParam: function(elem) {\n let parsedElementId = elem.id.split('__');\n if (parsedElementId[2] != 'operator') {\n return false;\n }\n\n let valueElement = jQuery('#' + parsedElementId[0] + '__' + parsedElementId[1] + '__value');\n\n if(elem.value == '<=>') {\n valueElement.closest('.rule-param').hide();\n } else {\n valueElement.closest('.rule-param').show();\n }\n\n return true;\n },\n\n addRuleNewChild: function (elem) {\n var parent_id = elem.id.replace(/^.*__(.*)__.*$/, '$1');\n var children_ul_id = elem.id.replace(/__/g, ':').replace(/[^:]*$/, 'children').replace(/:/g, '__');\n var children_ul = $(this.parent).select('#' + children_ul_id)[0];\n var max_id = 0,\n i;\n var children_inputs = Selector.findChildElements(children_ul, $A(['input.hidden']));\n\n if (children_inputs.length) {\n children_inputs.each(function (el) {\n if (el.id.match(/__type$/)) {\n i = 1 * el.id.replace(/^.*__.*?([0-9]+)__.*$/, '$1');\n max_id = i > max_id ? i : max_id;\n }\n });\n }\n var new_id = parent_id + '--' + (max_id + 1);\n var new_type = elem.value;\n var new_elem = document.createElement('LI');\n\n new_elem.className = 'rule-param-wait';\n new_elem.innerHTML = jQuery.mage.__('This won\\'t take long . . .');\n children_ul.insertBefore(new_elem, $(elem).up('li'));\n\n new Ajax.Request(this.newChildUrl, {\n evalScripts: true,\n parameters: {\n form_key: FORM_KEY, type: new_type.replace('/', '-'), id: new_id\n },\n onComplete: this.onAddNewChildComplete.bind(this, new_elem),\n onSuccess: function (transport) {\n if (this._processSuccess(transport)) {\n $(new_elem).update(transport.responseText);\n }\n }.bind(this),\n onFailure: this._processFailure.bind(this)\n });\n },\n\n _processSuccess: function (transport) {\n if (transport.responseText.isJSON()) {\n var response = transport.responseText.evalJSON();\n\n if (response.error) {\n alert(response.message);\n }\n\n if (response.ajaxExpired && response.ajaxRedirect) {\n setLocation(response.ajaxRedirect);\n }\n\n return false;\n }\n\n return true;\n },\n\n _processFailure: function (transport) {\n location.href = BASE_URL;\n },\n\n onAddNewChildComplete: function (new_elem) {\n if (this.readOnly) {\n return false;\n }\n\n $(new_elem).removeClassName('rule-param-wait');\n var elems = new_elem.getElementsByClassName('rule-param');\n\n for (var i = 0; i < elems.length; i++) {\n this.initParam(elems[i]);\n }\n },\n\n removeRuleEntry: function (container, event) {\n var li = Element.up(container, 'li');\n\n li.parentNode.removeChild(li);\n },\n\n chooserGridInit: function (grid) {\n //grid.reloadParams = {'selected[]':this.chooserSelectedItems.keys()};\n },\n\n chooserGridRowInit: function (grid, row) {\n if (!grid.reloadParams) {\n grid.reloadParams = {\n 'selected[]': this.chooserSelectedItems.keys()\n };\n }\n },\n\n chooserGridRowClick: function (grid, event) {\n var trElement = Event.findElement(event, 'tr');\n var isInput = Event.element(event).tagName == 'INPUT';\n\n if (trElement) {\n var checkbox = Element.select(trElement, 'input');\n\n if (checkbox[0]) {\n var checked = isInput ? checkbox[0].checked : !checkbox[0].checked;\n\n grid.setCheckboxChecked(checkbox[0], checked);\n\n }\n }\n },\n\n chooserGridCheckboxCheck: function (grid, element, checked) {\n if (checked) {\n if (!element.up('th')) {\n this.chooserSelectedItems.set(element.value, 1);\n }\n } else {\n this.chooserSelectedItems.unset(element.value);\n }\n grid.reloadParams = {\n 'selected[]': this.chooserSelectedItems.keys()\n };\n this.updateElement.value = this.chooserSelectedItems.keys().join(', ');\n }\n };\n\n return VarienRulesForm;\n});\n","Magento_Rule/conditions-data-normalizer.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'jquery',\n 'underscore'\n], function ($, _) {\n 'use strict';\n\n /**\n * @constructor\n */\n var ConditionsDataNormalizer = function () {\n this.patterns = {\n validate: /^[a-z0-9_.-][a-z0-9_.-]*(?:\\[(?:\\d*|[a-z0-9_.-]+)\\])*$/i,\n key: /[a-z0-9_.-]+|(?=\\[\\])/gi,\n push: /^$/,\n fixed: /^\\d+$/,\n named: /^[a-z0-9_.-]+$/i\n };\n };\n\n ConditionsDataNormalizer.prototype = {\n /**\n * Will convert an object:\n * {\n * \"foo[bar][1][baz]\": 123,\n * \"foo[bar][1][blah]\": 321\n * \"foo[bar][1--1][ah]\": 456\n * }\n *\n * to\n * {\n * \"foo\": {\n * \"bar\": {\n * \"1\": {\n * \"baz\": 123,\n * \"blah\": 321\n * },\n * \"1--1\": {\n * \"ah\": 456\n * }\n * }\n * }\n * }\n */\n normalize: function normalize(value) {\n var el, _this = this;\n\n this.pushes = {};\n this.data = {};\n\n _.each(value, function (e, i) {\n el = {};\n el[i] = e;\n\n _this._addPair({\n name: i,\n value: e\n });\n });\n\n return this.data;\n },\n\n /**\n * @param {Object} base\n * @param {String} key\n * @param {String} value\n * @return {Object}\n * @private\n */\n _build: function build(base, key, value) {\n base[key] = value;\n\n return base;\n },\n\n /**\n * @param {Object} root\n * @param {String} value\n * @return {*}\n * @private\n */\n _makeObject: function makeObject(root, value) {\n var keys = root.match(this.patterns.key),\n k, idx; // nest, nest, ..., nest\n\n while ((k = keys.pop()) !== undefined) {\n // foo[]\n if (this.patterns.push.test(k)) {\n idx = this._incrementPush(root.replace(/\\[\\]$/, ''));\n value = this._build([], idx, value);\n } // foo[n]\n else if (this.patterns.fixed.test(k)) {\n value = this._build({}, k, value);\n } // foo; foo[bar]\n else if (this.patterns.named.test(k)) {\n value = this._build({}, k, value);\n }\n }\n\n return value;\n },\n\n /**\n * @param {String} key\n * @return {Number}\n * @private\n */\n _incrementPush: function incrementPush(key) {\n if (this.pushes[key] === undefined) {\n this.pushes[key] = 0;\n }\n\n return this.pushes[key]++;\n },\n\n /**\n * @param {Object} pair\n * @return {Object}\n * @private\n */\n _addPair: function addPair(pair) {\n var obj = this._makeObject(pair.name, pair.value);\n\n if (!this.patterns.validate.test(pair.name)) {\n return this;\n }\n\n this.data = $.extend(true, this.data, obj);\n\n return this;\n }\n };\n\n return ConditionsDataNormalizer;\n});\n","Magento_ConfigurableProduct/js/configurable.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**************************** CONFIGURABLE PRODUCT **************************/\n/* global Product, optionsPrice */\ndefine([\n 'jquery',\n 'mage/template',\n 'mage/translate',\n 'prototype'\n], function (jQuery, mageTemplate) {\n 'use strict';\n\n if (typeof Product == 'undefined') {\n window.Product = {};\n }\n\n Product.Config = Class.create();\n Product.Config.prototype = {\n /**\n * Initialize function.\n *\n * @param {Object} config\n */\n initialize: function (config) {\n var separatorIndex, paramsStr, urlValues, i, childSettings, prevSetting, nextSetting;\n\n // Magic preprocessing\n // TODO MAGETWO-31539\n config.taxConfig = {\n showBothPrices: false,\n inclTaxTitle: jQuery.mage.__('Incl. Tax')\n };\n\n this.config = config;\n this.taxConfig = this.config.taxConfig;\n\n if (config.containerId) {\n this.settings = $$('#' + config.containerId + ' ' + '.super-attribute-select');\n } else {\n this.settings = $$('.super-attribute-select');\n }\n this.state = new Hash();\n this.priceTemplate = mageTemplate(this.config.template);\n this.prices = config.prices;\n this.values = {};\n\n // Set default values from config\n if (config.defaultValues) {\n this.values = config.defaultValues;\n }\n\n // Overwrite defaults by url\n separatorIndex = window.location.href.indexOf('#');\n\n if (separatorIndex != -1) { //eslint-disable-line eqeqeq\n paramsStr = window.location.href.substr(separatorIndex + 1);\n urlValues = paramsStr.toQueryParams();\n\n for (i in urlValues) { //eslint-disable-line guard-for-in\n this.values[i] = urlValues[i];\n }\n }\n\n // Overwrite defaults by inputs values if needed\n if (config.inputsInitialized) {\n this.values = {};\n this.settings.each(function (element) {\n var attributeId;\n\n if (element.value) {\n attributeId = element.id.replace(/[a-z]*/, '');\n this.values[attributeId] = element.value;\n }\n }.bind(this));\n }\n\n // Put events to check select reloads\n this.settings.each(function (element) {\n Event.observe(element, 'change', this.configure.bind(this));\n }.bind(this));\n\n // fill state\n this.settings.each(function (element) {\n var attributeId = element.id.replace(/[a-z]*/, '');\n\n if (attributeId && this.config.attributes[attributeId]) {\n element.config = this.config.attributes[attributeId];\n element.attributeId = attributeId;\n this.state[attributeId] = false;\n }\n }.bind(this));\n\n // Init settings dropdown\n childSettings = [];\n\n for (i = this.settings.length - 1; i >= 0; i--) {\n prevSetting = this.settings[i - 1] ? this.settings[i - 1] : false;\n nextSetting = this.settings[i + 1] ? this.settings[i + 1] : false;\n\n if (i === 0) {\n this.fillSelect(this.settings[i]);\n } else {\n this.settings[i].disabled = true;\n }\n $(this.settings[i]).childSettings = childSettings.clone();\n $(this.settings[i]).prevSetting = prevSetting;\n $(this.settings[i]).nextSetting = nextSetting;\n childSettings.push(this.settings[i]);\n }\n\n // Set values to inputs\n this.configureForValues();\n document.observe('dom:loaded', this.configureForValues.bind(this));\n },\n\n /**\n * Configure for values.\n */\n configureForValues: function () {\n if (this.values) {\n this.settings.each(function (element) {\n var attributeId = element.attributeId;\n\n element.value = typeof this.values[attributeId] === 'undefined' ? '' : this.values[attributeId];\n this.configureElement(element);\n }.bind(this));\n }\n },\n\n /**\n * @param {Object} event\n */\n configure: function (event) {\n var element = Event.element(event);\n\n this.configureElement(element);\n },\n\n /**\n * @param {Object} element\n */\n configureElement: function (element) {\n this.reloadOptionLabels(element);\n\n if (element.value) {\n this.state[element.config.id] = element.value;\n\n if (element.nextSetting) {\n element.nextSetting.disabled = false;\n this.fillSelect(element.nextSetting);\n this.resetChildren(element.nextSetting);\n }\n } else {\n this.resetChildren(element);\n }\n this.reloadPrice();\n },\n\n /**\n * @param {Object} element\n */\n reloadOptionLabels: function (element) {\n var selectedPrice = 0,\n option, i;\n\n if (element.options[element.selectedIndex] && element.options[element.selectedIndex].config) {\n option = element.options[element.selectedIndex].config;\n selectedPrice = parseFloat(this.config.optionPrices[option.allowedProducts[0]].finalPrice.amount);\n }\n element.setAttribute('price', selectedPrice);\n\n for (i = 0; i < element.options.length; i++) {\n if (element.options[i].config) {\n element.options[i].setAttribute('price', selectedPrice);\n element.options[i].setAttribute('summarizePrice', 0);\n element.options[i].text = this.getOptionLabel(element.options[i].config, selectedPrice);\n }\n }\n },\n\n /* eslint-disable max-depth */\n /**\n * @param {Object} element\n */\n resetChildren: function (element) {\n var i;\n\n if (element.childSettings) {\n for (i = 0; i < element.childSettings.length; i++) {\n element.childSettings[i].selectedIndex = 0;\n element.childSettings[i].disabled = true;\n\n if (element.config) {\n this.state[element.config.id] = false;\n }\n }\n }\n },\n\n /**\n * @param {Object} element\n */\n fillSelect: function (element) {\n var attributeId = element.id.replace(/[a-z]*/, ''),\n options = this.getAttributeOptions(attributeId),\n prevConfig = false,\n index = 1,\n i, j, allowedProducts;\n\n this.clearSelect(element);\n element.options[0] = new Option('', '');\n element.options[0].innerHTML = this.config.chooseText;\n\n if (element.prevSetting) {\n prevConfig = element.prevSetting.options[element.prevSetting.selectedIndex];\n }\n\n if (options) {\n for (i = 0; i < options.length; i++) {\n allowedProducts = [];\n\n if (prevConfig) {\n for (j = 0; j < options[i].products.length; j++) {\n if (prevConfig.config.allowedProducts &&\n prevConfig.config.allowedProducts.indexOf(options[i].products[j]) > -1\n ) {\n allowedProducts.push(options[i].products[j]);\n }\n }\n } else {\n allowedProducts = options[i].products.clone();\n }\n\n if (allowedProducts.size() > 0) {\n options[i].allowedProducts = allowedProducts;\n element.options[index] = new Option(this.getOptionLabel(options[i]), options[i].id);\n\n if (typeof options[i].price != 'undefined') {\n element.options[index].setAttribute('price', options[i].price);\n }\n element.options[index].config = options[i];\n index++;\n }\n }\n }\n },\n\n //eslint-enable max-depth\n /**\n * @param {Object} option\n */\n getOptionLabel: function (option) {\n return option.label;\n },\n\n /**\n * @param {*} price\n * @param {Boolean} showSign\n * @return {String}\n */\n formatPrice: function (price, showSign) {\n var str = '',\n roundedPrice;\n\n price = parseFloat(price);\n\n if (showSign) {\n if (price < 0) {\n str += '-';\n price = -price;\n } else {\n str += '+';\n }\n }\n\n roundedPrice = Number(Math.round(price + 'e+2') + 'e-2').toString();\n\n if (this.prices && this.prices[roundedPrice]) {\n str += this.prices[roundedPrice];\n } else {\n str += this.priceTemplate({\n data: {\n price: price.toFixed(2)\n }\n });\n }\n\n return str;\n },\n\n /**\n * @param {Object} element\n */\n clearSelect: function (element) {\n var i;\n\n for (i = element.options.length - 1; i >= 0; i--) {\n element.remove(i);\n }\n },\n\n /**\n * @param {*} attributeId\n * @return {*|undefined}\n */\n getAttributeOptions: function (attributeId) {\n if (this.config.attributes[attributeId]) {\n return this.config.attributes[attributeId].options;\n }\n },\n\n /**\n * Reload price.\n *\n * @return {undefined|Number}\n */\n reloadPrice: function () {\n var price = 0,\n oldPrice = 0,\n inclTaxPrice = 0,\n exclTaxPrice = 0,\n i, selected;\n\n if (this.config.disablePriceReload) {\n return undefined;\n }\n\n for (i = this.settings.length - 1; i >= 0; i--) {\n selected = this.settings[i].options[this.settings[i].selectedIndex];\n\n if (selected.config) {\n price += parseFloat(selected.config.price);\n oldPrice += parseFloat(selected.config.oldPrice);\n inclTaxPrice += parseFloat(selected.config.inclTaxPrice);\n exclTaxPrice += parseFloat(selected.config.exclTaxPrice);\n }\n }\n\n optionsPrice.changePrice(\n 'config', {\n 'price': price,\n 'oldPrice': oldPrice,\n 'inclTaxPrice': inclTaxPrice,\n 'exclTaxPrice': exclTaxPrice\n }\n );\n optionsPrice.reload();\n\n return price;\n },\n\n /**\n * Reload old price.\n */\n reloadOldPrice: function () {\n var price, i, selected;\n\n if (this.config.disablePriceReload) {\n return;\n }\n\n if ($('old-price-' + this.config.productId)) {\n\n price = parseFloat(this.config.oldPrice);\n\n for (i = this.settings.length - 1; i >= 0; i--) {\n selected = this.settings[i].options[this.settings[i].selectedIndex];\n\n if (selected.config) {\n price += parseFloat(selected.config.price);\n }\n }\n\n if (price < 0) {\n price = 0;\n }\n price = this.formatPrice(price);\n\n if ($('old-price-' + this.config.productId)) {\n $('old-price-' + this.config.productId).innerHTML = price;\n }\n\n }\n }\n };\n});\n","Magento_ConfigurableProduct/js/configurable-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/catalog/type-events',\n 'collapsible',\n 'Magento_Ui/js/modal/modal',\n 'mage/translate',\n 'domReady!'\n], function ($, productType) {\n 'use strict';\n\n return {\n $block: null,\n hasVariations: null,\n configurationSectionMessageHandler: (function () {\n var title = $('[data-role=\"product-create-configuration-info\"]'),\n buttons = $('[data-action=\"product-create-configuration-buttons\"]'),\n newText = 'Configurations cannot be created for a standard product with downloadable files.' +\n ' To create configurations, first remove all downloadable files.',\n oldText = title.text();\n\n return function (change) {\n if (change) {\n title.text(newText);\n buttons.hide();\n } else {\n title.text(oldText);\n buttons.show();\n }\n };\n }()),\n\n /**\n * Set element disabled\n * @param {Object} $element - jquery instance element\n * @param {Bool} state\n * @param {Bool} triggerEvent\n * @private\n */\n _setElementDisabled: function ($element, state, triggerEvent) {\n if (!$element.is('[data-locked]')) {\n $element.prop('disabled', state);\n\n if (triggerEvent) {\n $element.trigger('change');\n }\n }\n },\n\n /**\n * Show\n */\n show: function () {\n this.configurationSectionMessageHandler(false);\n },\n\n /**\n * Hide\n */\n hide: function () {\n this.configurationSectionMessageHandler(true);\n },\n\n /**\n * Bind all\n */\n bindAll: function () {\n $(document).on('changeConfigurableTypeProduct', function (event, isConfigurable) {\n $(document).trigger('setTypeProduct', isConfigurable ?\n 'configurable' :\n productType.type.init === 'configurable' ? 'simple' : productType.type.init\n );\n });\n $(document).on('changeTypeProduct', this._initType.bind(this));\n },\n\n /**\n * Init type\n * @private\n */\n _initType: function () {\n\n /*var suggestContainer = $('#product-template-suggest-container .action-dropdown > .action-toggle');\n\n\n if (productType.type.current === 'configurable') {\n this._setElementDisabled(suggestContainer.addClass('disabled'), true);\n this._setElementDisabled($('#inventory_qty'), true);\n this._setElementDisabled($('#inventory_stock_availability'), false);\n this._setElementDisabled($('#qty'), true, true);\n this._setElementDisabled($('#quantity_and_stock_status'), false, false);\n } else {\n this._setElementDisabled(suggestContainer.removeClass('disabled'), false);\n this._setElementDisabled($('#inventory_qty'), false);\n this._setElementDisabled($('#inventory_stock_availability'), true);\n this._setElementDisabled($('#qty'), false, true);\n }\n */\n\n /*if (['simple', 'virtual', 'configurable'].indexOf(productType.type.current) < 0) {\n this.hide();\n } else {\n this.show();\n }*/\n\n this.show();\n },\n\n /**\n * Constructor component\n * @param {Object} data - this backend data\n */\n 'Magento_ConfigurableProduct/js/configurable-type-handler': function (data) {\n this.$block = $(data.blockId + ' input[name=\"attributes[]\"]');\n this.hasVariations = data.hasVariations;\n\n //advancedPricingHandler.init();\n //priceTypeHandler.init();\n\n /*if (productType.type.init === 'configurable' && !this.hasVariations) {\n $(document).trigger('setTypeProduct', 'simple');\n }*/\n $(document).trigger('setTypeProduct', 'simple');\n\n this.bindAll();\n this._initType();\n }\n };\n});\n","Magento_ConfigurableProduct/js/components/associated-product-insert-listing.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'underscore',\n 'Magento_Ui/js/form/components/insert-listing'\n], function (_, insertListing) {\n 'use strict';\n\n return insertListing.extend({\n defaults: {\n gridInitialized: false,\n paramsUpdated: false,\n showMassActionColumn: true,\n currentProductId: 0,\n dataScopeAssociatedProduct: 'data.associated_product_ids',\n typeGrid: '',\n product: {},\n rowIndexForChange: undefined,\n changeProductData: [],\n modules: {\n productsProvider: '${ $.productsProvider }',\n productsColumns: '${ $.productsColumns }',\n productsMassAction: '${ $.productsMassAction }',\n modalWithGrid: '${ $.modalWithGrid }',\n productsFilters: '${ $.productsFilters }'\n },\n exports: {\n externalProviderParams: '${ $.externalProvider }:params'\n },\n links: {\n changeProductData: '${ $.provider }:${ $.changeProductProvider }'\n },\n listens: {\n '${ $.externalProvider }:params': '_setFilters _setVisibilityMassActionColumn',\n '${ $.productsProvider }:data': '_handleManualGridOpening',\n '${ $.productsMassAction }:selected': '_handleManualGridSelect'\n }\n },\n\n /**\n * Initialize observables.\n *\n * @returns {Object} Chainable.\n */\n initObservable: function () {\n this._super().observe(\n 'changeProductData'\n );\n\n return this;\n },\n\n /**\n * Get ids of used products.\n *\n * @returns {Array}\n */\n getUsedProductIds: function () {\n var usedProductsIds = this.source.get(this.dataScopeAssociatedProduct);\n\n return usedProductsIds.slice();\n },\n\n /**\n * Request for render content.\n *\n * @returns {Object}\n */\n doRender: function (showMassActionColumn, typeGrid) {\n this.typeGrid = typeGrid;\n this.showMassActionColumn = showMassActionColumn;\n\n if (this.gridInitialized) {\n this.paramsUpdated = false;\n this.productsFilters().clear();\n this._setFilters(this.externalProviderParams);\n this._setVisibilityMassActionColumn();\n }\n\n return this.render();\n },\n\n /**\n * Show grid with assigned product.\n *\n * @returns {Object}\n */\n showGridAssignProduct: function () {\n this.product = {};\n this.rowIndexForChange = undefined;\n\n return this.doRender(true, 'assignProduct');\n },\n\n /**\n * Show grid with changed product.\n *\n * @param {String} rowIndex\n * @param {String} product\n */\n showGridChangeProduct: function (rowIndex, product) {\n this.rowIndexForChange = rowIndex;\n this.product = product;\n this.doRender(false, 'changeProduct');\n },\n\n /**\n * Select product.\n *\n * @param {String} rowIndex\n */\n selectProduct: function (rowIndex) {\n this.changeProductData({\n rowIndex: this.rowIndexForChange,\n product: this.productsProvider().data.items[rowIndex]\n });\n this.modalWithGrid().closeModal();\n },\n\n /**\n * Set visibility state for mass action column\n *\n * @private\n */\n _setVisibilityMassActionColumn: function () {\n this.productsMassAction(function (massActionComponent) {\n this.productsColumns().elems().each(function (rowElement) {\n rowElement.disableAction = this.showMassActionColumn;\n }, this);\n massActionComponent.visible = this.showMassActionColumn;\n }.bind(this));\n },\n\n /**\n * Set filters.\n *\n * @param {Object} params\n * @private\n */\n _setFilters: function (params) {\n var filterModifier = {},\n attrCodes,\n usedProductIds,\n attributes;\n\n params = _.omit(params);\n\n if (!this.paramsUpdated) {\n this.gridInitialized = true;\n this.paramsUpdated = true;\n\n attrCodes = this._getAttributesCodes();\n usedProductIds = this.getUsedProductIds();\n\n if (this.currentProductId) {\n usedProductIds.push(this.currentProductId);\n }\n\n filterModifier['entity_id'] = {\n 'condition_type': 'nin', value: usedProductIds\n };\n attrCodes.each(function (code) {\n filterModifier[code] = {\n 'condition_type': 'notnull'\n };\n });\n\n if (this.typeGrid === 'changeProduct') {\n attributes = JSON.parse(this.product.attributes);\n\n filterModifier = _.extend(filterModifier, _.mapObject(attributes, function (value) {\n return {\n 'condition_type': 'eq',\n 'value': value\n };\n }));\n\n params.filters = attributes;\n } else {\n params.filters = {};\n }\n\n params['attributes_codes'] = attrCodes;\n\n this.set('externalProviderParams', params);\n this.set('externalFiltersModifier', filterModifier);\n }\n },\n\n /**\n * Get attribute codes.\n *\n * @returns {Array}\n * @private\n */\n _getAttributesCodes: function () {\n var attrCodes = this.source.get('data.attribute_codes');\n\n return attrCodes ? attrCodes : [];\n },\n\n /**\n * Get product variations.\n *\n * @returns {Array}\n * @private\n */\n _getProductVariations: function () {\n var matrix = this.source.get('data.configurable-matrix');\n\n return matrix ? matrix : [];\n },\n\n /**\n * Handle manual grid after opening\n * @private\n */\n _handleManualGridOpening: function (data) {\n if (data.items.length && this.typeGrid === 'assignProduct') {\n this.productsColumns().elems().each(function (rowElement) {\n rowElement.disableAction = true;\n });\n\n this._disableRows(data.items);\n }\n },\n\n /**\n * Handle manual selection.\n *\n * @param {Array} selected\n * @private\n */\n _handleManualGridSelect: function (selected) {\n var selectedRows,\n selectedVariationKeys;\n\n if (this.typeGrid === 'assignProduct') {\n selectedRows = _.filter(this.productsProvider().data.items, function (row) {\n return selected.indexOf(row['entity_id']) !== -1;\n });\n selectedVariationKeys = _.values(this._getVariationKeyMap(selectedRows));\n this._disableRows(this.productsProvider().data.items, selectedVariationKeys, selected);\n }\n },\n\n /**\n * Disable rows in grid for products with the same variation key\n *\n * @param {Array} items\n * @param {Array} selectedVariationKeys\n * @param {Array} selected\n * @private\n */\n _disableRows: function (items, selectedVariationKeys, selected) {\n selectedVariationKeys = selectedVariationKeys === undefined ? [] : selectedVariationKeys;\n selected = selected === undefined ? [] : selected;\n this.productsMassAction(function (massaction) {\n var configurableVariationKeys = _.union(\n selectedVariationKeys,\n _.pluck(this._getProductVariations(), 'variationKey')\n ),\n variationKeyMap = this._getVariationKeyMap(items),\n rowsForDisable = _.keys(_.pick(\n variationKeyMap,\n function (variationKey) {\n return configurableVariationKeys.indexOf(variationKey) !== -1;\n }\n ));\n\n massaction.disabled(_.difference(rowsForDisable, selected));\n }.bind(this));\n },\n\n /**\n * Get variation key map used in manual grid.\n *\n * @param {Array} items\n * @returns {Array} [{entity_id: variation-key}, ...]\n * @private\n */\n _getVariationKeyMap: function (items) {\n var variationKeyMap = {};\n\n _.each(items, function (row) {\n variationKeyMap[row['entity_id']] = _.values(\n _.pick(row, this._getAttributesCodes())\n ).sort().join('-');\n\n }, this);\n\n return variationKeyMap;\n }\n });\n});\n","Magento_ConfigurableProduct/js/components/modal-configurable.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 'uiRegistry',\n 'underscore'\n], function (Modal, registry, _) {\n 'use strict';\n\n return Modal.extend({\n defaults: {\n stepWizard: '',\n modules: {\n form: '${ $.formName }'\n }\n },\n\n /**\n * Open modal\n */\n openModal: function () {\n var stepWizard = {};\n\n this.form().validate();\n\n if (this.form().source.get('params.invalid') === false) {\n stepWizard = registry.get('index = ' + this.stepWizard);\n\n if (!_.isUndefined(stepWizard)) {\n stepWizard.open();\n }\n\n this._super();\n }\n }\n });\n});\n","Magento_ConfigurableProduct/js/components/dynamic-rows-configurable.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'underscore',\n 'uiRegistry',\n 'Magento_Ui/js/dynamic-rows/dynamic-rows',\n 'jquery'\n], function (_, registry, dynamicRows, $) {\n 'use strict';\n\n return dynamicRows.extend({\n defaults: {\n actionsListOpened: false,\n canEditField: 'canEdit',\n newProductField: 'newProduct',\n dataScopeAssociatedProduct: 'data.associated_product_ids',\n dataProviderFromGrid: '',\n dataProviderChangeFromGrid: '',\n insertDataFromGrid: [],\n changeDataFromGrid: [],\n dataProviderFromWizard: '',\n insertDataFromWizard: [],\n map: null,\n isEmpty: true,\n isShowAddProductButton: false,\n cacheGridData: [],\n unionInsertData: [],\n deleteProperty: false,\n dataLength: 0,\n identificationProperty: 'id',\n 'attribute_set_id': '',\n attributesTmp: [],\n changedFlag: 'was_changed',\n listens: {\n 'insertDataFromGrid': 'processingInsertDataFromGrid',\n 'insertDataFromWizard': 'processingInsertDataFromWizard',\n 'unionInsertData': 'processingUnionInsertData',\n 'changeDataFromGrid': 'processingChangeDataFromGrid',\n 'isEmpty': 'changeVisibility'\n },\n imports: {\n 'attribute_set_id': '${$.provider}:data.product.attribute_set_id'\n },\n 'exports': {\n 'attribute_set_id': '${$.provider}:data.new-variations-attribute-set-id'\n },\n modules: {\n modalWithGrid: '${ $.modalWithGrid }',\n gridWithProducts: '${ $.gridWithProducts}'\n }\n },\n\n /**\n * Invokes initialize method of parent class,\n * contains initialization logic\n */\n initialize: function () {\n this._super()\n .changeVisibility(this.isEmpty());\n\n return this;\n },\n\n /**\n * Change visibility\n *\n * When isEmpty = true, then visbible = false\n *\n * @param {Boolean} isEmpty\n */\n changeVisibility: function (isEmpty) {\n this.visible(!isEmpty);\n },\n\n /**\n * Open modal with grid.\n *\n * @param {String} rowIndex\n */\n openModalWithGrid: function (rowIndex) {\n var productSource = this.source.get(this.dataScope + '.' + this.index + '.' + rowIndex),\n product = {\n 'id': productSource.id,\n 'attributes': productSource['configurable_attribute']\n };\n\n this.modalWithGrid().openModal();\n this.gridWithProducts().showGridChangeProduct(rowIndex, product);\n },\n\n /**\n * Initialize children\n *\n * @returns {Object} Chainable.\n */\n initChildren: function () {\n var tmpArray = [];\n\n this.recordData.each(function (recordData) {\n tmpArray.push(recordData);\n }, this);\n\n this.unionInsertData(tmpArray);\n\n return this;\n },\n\n /**\n * Delete record\n *\n * @param {Number} index - row index\n */\n deleteRecord: function (index) {\n var tmpArray,\n lastRecord;\n\n this.reRender = false;\n tmpArray = this.getUnionInsertData();\n tmpArray.splice(index, 1);\n\n if (!tmpArray.length) {\n this.attributesTmp = this.source.get('data.attributes');\n this.source.set('data.attributes', []);\n this.cacheGridData = [];\n }\n\n if (parseInt(this.currentPage(), 10) === this.pages()) {\n lastRecord =\n _.findWhere(this.elems(), {\n index: this.startIndex + this.getChildItems().length - 1\n }) ||\n _.findWhere(this.elems(), {\n index: (this.startIndex + this.getChildItems().length - 1).toString()\n });\n\n lastRecord.destroy();\n }\n\n this.unionInsertData(tmpArray);\n\n if (this.pages() < parseInt(this.currentPage(), 10)) {\n this.currentPage(this.pages());\n }\n\n this.reRender = true;\n this.showSpinner(false);\n },\n\n /**\n * Generate associated products\n */\n generateAssociatedProducts: function () {\n var productsIds = [];\n\n this.getUnionInsertData().forEach(function (data) {\n if (data.id !== null) {\n productsIds.push(data.id);\n }\n });\n\n this.source.set(this.dataScopeAssociatedProduct, productsIds);\n },\n\n /**\n * Calls 'initObservable' of parent\n *\n * @returns {Object} Chainable.\n */\n initObservable: function () {\n this._super()\n .observe([\n 'insertDataFromGrid', 'unionInsertData', 'isEmpty', 'isShowAddProductButton', 'actionsListOpened'\n ]);\n\n return this;\n },\n\n /**\n * Get union insert data from source\n *\n * @returns {Array}\n */\n getUnionInsertData: function () {\n var source = this.source.get(this.dataScope + '.' + this.index),\n result = [];\n\n _.each(source, function (data) {\n result.push(data);\n });\n\n return result;\n },\n\n /**\n * Process union insert data.\n *\n * @param {Array} data\n */\n processingUnionInsertData: function (data) {\n var dataCount,\n elemsCount,\n tmpData,\n path,\n attributeCodes = this.source.get('data.attribute_codes');\n\n this.isEmpty(data.length === 0);\n this.isShowAddProductButton(\n (!attributeCodes || data.length > 0 ? data.length : attributeCodes.length) > 0\n );\n\n tmpData = data.slice(this.pageSize * (this.currentPage() - 1),\n this.pageSize * (this.currentPage() - 1) + this.pageSize);\n\n this.source.set(this.dataScope + '.' + this.index, []);\n\n _.each(tmpData, function (row, index) {\n path = this.dataScope + '.' + this.index + '.' + (this.startIndex + index);\n row.attributes = $('<i></i>').text(row.attributes).html();\n row.sku = $('<i></i>').text(row.sku).html();\n this.source.set(path, row);\n }, this);\n\n this.source.set(this.dataScope + '.' + this.index, data);\n this.parsePagesData(data);\n\n // Render\n dataCount = data.length;\n elemsCount = this.elems().length;\n\n if (dataCount > elemsCount) {\n this.getChildItems().each(function (elemData, index) {\n this.addChild(elemData, this.startIndex + index);\n }, this);\n } else {\n for (elemsCount; elemsCount > dataCount; elemsCount--) {\n this.elems()[elemsCount - 1].destroy();\n }\n }\n\n this.generateAssociatedProducts();\n },\n\n /**\n * Parsed data\n *\n * @param {Array} data - array with data\n * about selected records\n */\n processingInsertDataFromGrid: function (data) {\n var changes,\n tmpArray;\n\n if (!data.length) {\n return;\n }\n\n tmpArray = this.getUnionInsertData();\n\n changes = this._checkGridData(data);\n this.cacheGridData = data;\n\n changes.each(function (changedObject) {\n var mappedData = this.mappingValue(changedObject);\n\n mappedData[this.canEditField] = 0;\n mappedData[this.newProductField] = 0;\n mappedData.variationKey = this._getVariationKey(changedObject);\n mappedData['configurable_attribute'] = this._getConfigurableAttribute(changedObject);\n tmpArray.push(mappedData);\n }, this);\n\n // Attributes cannot be changed before regeneration thought wizard\n if (!this.source.get('data.attributes').length) {\n this.source.set('data.attributes', this.attributesTmp);\n }\n this.unionInsertData(tmpArray);\n },\n\n /**\n * Process changes from grid.\n *\n * @param {Object} data\n */\n processingChangeDataFromGrid: function (data) {\n var tmpArray = this.getUnionInsertData(),\n mappedData = this.mappingValue(data.product);\n\n mappedData[this.canEditField] = 0;\n mappedData[this.newProductField] = 0;\n mappedData.variationKey = this._getVariationKey(data.product);\n mappedData['configurable_attribute'] = this._getConfigurableAttribute(data.product);\n tmpArray[data.rowIndex] = mappedData;\n\n this.unionInsertData(tmpArray);\n },\n\n /**\n * Get variation key.\n *\n * @param {Object} data\n * @returns {String}\n * @private\n */\n _getVariationKey: function (data) {\n var attrCodes = this.source.get('data.attribute_codes'),\n key = [];\n\n attrCodes.each(function (code) {\n key.push(data[code]);\n });\n\n return key.sort().join('-');\n },\n\n /**\n * Get configurable attribute.\n *\n * @param {Object} data\n * @returns {String}\n * @private\n */\n _getConfigurableAttribute: function (data) {\n var attrCodes = this.source.get('data.attribute_codes'),\n confAttrs = {};\n\n attrCodes.each(function (code) {\n confAttrs[code] = data[code];\n });\n\n return JSON.stringify(confAttrs);\n },\n\n /**\n * Process data insertion from wizard\n *\n * @param {Object} data\n */\n processingInsertDataFromWizard: function (data) {\n var tmpArray = this.getUnionInsertData(),\n productIdsToDelete = this.source.get(this.dataScopeAssociatedProduct),\n index,\n product = {};\n\n tmpArray = this.unsetArrayItem(\n tmpArray,\n {\n id: null\n }\n );\n\n _.each(data, function (row) {\n if (row.productId) {\n index = _.indexOf(productIdsToDelete, row.productId);\n\n if (index > -1) {\n productIdsToDelete.splice(index, 1);\n tmpArray = this.unsetArrayItem(\n tmpArray,\n {\n id: row.productId\n }\n );\n }\n }\n product = this.getProductData(row);\n\n product[this.changedFlag] = true;\n product[this.canEditField] = row.editable;\n product[this.newProductField] = row.newProduct;\n tmpArray.push(product);\n }, this);\n\n _.each(productIdsToDelete, function (id) {\n tmpArray = this.unsetArrayItem(\n tmpArray,\n {\n id: id\n }\n );\n }, this);\n\n this.unionInsertData(tmpArray);\n },\n\n /**\n *\n * @param {Object} row\n * @returns {Object}\n */\n getProductData: function (row) {\n var product,\n attributesText = '';\n\n _.each(row.options, function (attribute) {\n if (attributesText) {\n attributesText += ', ';\n }\n attributesText += attribute['attribute_label'] + ': ' + attribute.label;\n }, this);\n\n product = {\n 'id': row.productId,\n 'product_link': row.productUrl,\n 'name': $('<i></i>').text(row.name).html(),\n 'sku': $('<i></i>').text(row.sku).html(),\n 'status': row.status,\n 'price': row.price,\n 'price_currency': row.priceCurrency,\n 'price_string': row.priceCurrency + row.price,\n 'weight': row.weight,\n 'qty': row.quantity,\n 'variationKey': row.variationKey,\n 'configurable_attribute': row.attribute,\n 'thumbnail_image': row.images.preview,\n 'media_gallery': row['media_gallery'],\n 'swatch_image': row['swatch_image'],\n 'small_image': row['small_image'],\n image: row.image,\n 'thumbnail': row.thumbnail,\n 'attributes': attributesText\n };\n\n return product;\n },\n\n /**\n * Remove array items matching condition.\n *\n * @param {Array} data\n * @param {Object} condition\n * @returns {Array}\n */\n unsetArrayItem: function (data, condition) {\n var objs = _.where(data, condition);\n\n _.each(objs, function (obj) {\n var index = _.indexOf(data, obj);\n\n if (index > -1) {\n data.splice(index, 1);\n }\n });\n\n return data;\n },\n\n /**\n * Check changed records\n *\n * @param {Array} data - array with records data\n * @returns {Array} Changed records\n */\n _checkGridData: function (data) {\n var cacheLength = this.cacheGridData.length,\n curData = data.length,\n max = cacheLength > curData ? this.cacheGridData : data,\n changes = [],\n obj = {};\n\n max.each(function (record, index) {\n obj[this.map.id] = record[this.map.id];\n\n if (!_.where(this.cacheGridData, obj).length) {\n changes.push(data[index]);\n }\n }, this);\n\n return changes;\n },\n\n /**\n * Mapped value\n */\n mappingValue: function (data) {\n var result = {};\n\n _.each(this.map, function (prop, index) {\n result[index] = data[prop];\n });\n\n return result;\n },\n\n /**\n * Toggle actions list.\n *\n * @param {Number} rowIndex\n * @returns {Object} Chainable.\n */\n toggleActionsList: function (rowIndex) {\n var state = false;\n\n if (rowIndex !== this.actionsListOpened()) {\n state = rowIndex;\n }\n this.actionsListOpened(state);\n\n return this;\n },\n\n /**\n * Close action list.\n *\n * @param {Number} rowIndex\n * @returns {Object} Chainable\n */\n closeList: function (rowIndex) {\n if (this.actionsListOpened() === rowIndex) {\n this.actionsListOpened(false);\n }\n\n return this;\n },\n\n /**\n * Toggle product status.\n *\n * @param {Number} rowIndex\n */\n toggleStatusProduct: function (rowIndex) {\n var tmpArray = this.getUnionInsertData(),\n status = parseInt(tmpArray[rowIndex].status, 10);\n\n if (status === 1) {\n tmpArray[rowIndex].status = 2;\n } else {\n tmpArray[rowIndex].status = 1;\n }\n\n tmpArray[rowIndex][this.changedFlag] = true;\n this.unionInsertData(tmpArray);\n }\n });\n});\n","Magento_ConfigurableProduct/js/components/custom-options-warning.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'Magento_Ui/js/form/components/html'\n], function (Html) {\n 'use strict';\n\n return Html.extend({\n defaults: {\n isConfigurable: false\n },\n\n /**\n * Updates component visibility state.\n *\n * @param {Boolean} variationsEmpty\n * @returns {Boolean}\n */\n updateVisibility: function (variationsEmpty) {\n var isVisible = this.isConfigurable || !variationsEmpty;\n\n this.visible(isVisible);\n\n return isVisible;\n }\n });\n});\n","Magento_ConfigurableProduct/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 'underscore'\n], function (Element, _) {\n 'use strict';\n\n return Element.extend({\n processedFile: {},\n actionsListOpened: false,\n thumbnailUrl: '',\n thumbnail: null,\n smallImage: null,\n defaults: {\n fileInputName: ''\n },\n\n /**\n * Initialize observables.\n *\n * @returns {Object} Chainable.\n */\n initObservable: function () {\n this._super().observe(['processedFile', 'actionsListOpened', 'thumbnailUrl', 'thumbnail', 'smallImage']);\n\n return this;\n },\n\n /** @inheritdoc */\n setInitialValue: function () {\n var value = this.getInitialValue();\n\n if (!_.isString(value)) {\n this._super();\n }\n\n return this;\n },\n\n /**\n * Adds provided file to the files list.\n *\n * @param {Object} file\n * @returns {Object} Chainable.\n */\n addFile: function (file) {\n this.processedFile(this.processFile(file));\n\n this.value(this.processedFile().file);\n\n return this;\n },\n\n /**\n * Toggle actions list.\n *\n * @returns {Object} Chainable.\n */\n toggleActionsList: function () {\n if (this.actionsListOpened()) {\n this.actionsListOpened(false);\n } else {\n this.actionsListOpened(true);\n }\n\n return this;\n },\n\n /**\n * Close action list.\n *\n * @returns {Object} Chainable\n */\n closeList: function () {\n if (this.actionsListOpened()) {\n this.actionsListOpened(false);\n }\n\n return this;\n },\n\n /**\n * Delete Image\n *\n * @returns {Object} Chainable\n */\n deleteImage: function () {\n this.processedFile({});\n this.value(null);\n this.thumbnail(null);\n this.thumbnailUrl(null);\n this.smallImage(null);\n\n return this;\n }\n });\n});\n","Magento_ConfigurableProduct/js/components/price-configurable.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n 'underscore',\n 'uiRegistry',\n 'Magento_Ui/js/form/element/abstract'\n], function (_, registry, Abstract) {\n 'use strict';\n\n return Abstract.extend({\n defaults: {\n imports: {\n isConfigurable: '!ns = ${ $.ns }, index = configurable-matrix:isEmpty'\n },\n modules: {\n createConfigurableButton: '${$.createConfigurableButton}'\n }\n },\n\n /** @inheritdoc */\n initialize: function () {\n this._super();\n // resolve initial disable state\n this.handlePriceValue(this.isConfigurable);\n // add listener to track \"configurable\" type\n this.setListeners({\n isConfigurable: 'handlePriceValue'\n });\n\n return this;\n },\n\n /**\n * Calls 'initObservable' of parent\n *\n * @returns {Object} Chainable.\n */\n initObservable: function () {\n this._super()\n .observe(['content']);\n\n return this;\n },\n\n /**\n * Disable and clear price if product type changed to configurable\n *\n * @param {String} isConfigurable\n */\n handlePriceValue: function (isConfigurable) {\n this.disabled(!!this.isUseDefault() || isConfigurable);\n\n if (isConfigurable) {\n this.clear();\n }\n }\n });\n});\n","Magento_ConfigurableProduct/js/components/container-configurable-handler.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'uiComponent'\n], function (Element) {\n 'use strict';\n\n return Element.extend({\n defaults: {\n listens: {\n '${ $.provider }:data.is_downloadable': 'handleProductType'\n },\n links: {\n isDownloadable: '${ $.provider }:data.is_downloadable'\n },\n modules: {\n createConfigurableButton: '${$.createConfigurableButton}'\n }\n },\n\n /**\n * Invokes initialize method of parent class,\n * contains initialization logic\n */\n initialize: function () {\n this._super();\n this.handleProductType(this.isDownloadable);\n\n return this;\n },\n\n /**\n * Calls 'initObservable' of parent\n *\n * @returns {Object} Chainable.\n */\n initObservable: function () {\n this._super()\n .observe(['content']);\n\n return this;\n },\n\n /**\n * Change content for container and visibility for button\n *\n * @param {String} isDownloadable\n */\n handleProductType: function (isDownloadable) {\n if (isDownloadable === '1') {\n this.content(this.content2);\n\n if (this.createConfigurableButton()) {\n this.createConfigurableButton().visible(false);\n }\n } else {\n this.content(this.content1);\n\n if (this.createConfigurableButton()) {\n this.createConfigurableButton().visible(true);\n }\n }\n }\n });\n});\n","Magento_ConfigurableProduct/js/components/custom-options-price-type.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'underscore',\n 'Magento_Catalog/js/components/custom-options-price-type'\n], function (_, PriceType) {\n 'use strict';\n\n return PriceType.extend({\n defaults: {\n isConfigurable: false,\n isFiltered: null,\n defaultOptions: null,\n filteredOptions: null,\n bannedOptions: []\n },\n\n /**\n * Updates options.\n *\n * @param {Boolean} variationsEmpty\n * @returns {Boolean}\n */\n updateOptions: function (variationsEmpty) {\n var isFiltered = this.isConfigurable || !variationsEmpty,\n value;\n\n if (this.isFiltered !== isFiltered) {\n value = this.value();\n\n this.options(isFiltered ? this.getFilteredOptions() : this.getDefaultOptions());\n this.value(value);\n }\n\n return isFiltered;\n },\n\n /**\n * Get default list of options.\n *\n * @returns {Array}\n */\n getDefaultOptions: function () {\n if (this.defaultOptions === null) {\n this.defaultOptions = this.options();\n }\n\n return this.defaultOptions;\n },\n\n /**\n * Get filtered list of options.\n *\n * @returns {Array}\n */\n getFilteredOptions: function () {\n var defaultOptions;\n\n if (this.filteredOptions === null) {\n defaultOptions = this.getDefaultOptions();\n this.filteredOptions = [];\n\n _.each(defaultOptions, function (option) {\n if (this.bannedOptions.indexOf(option.value) === -1) {\n this.filteredOptions.push(option);\n }\n }, this);\n }\n\n return this.filteredOptions;\n }\n });\n});\n","Magento_ConfigurableProduct/js/options/price-type-handler.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/*\ndefine([\n 'jquery',\n 'Magento_Catalog/catalog/type-events',\n 'notification',\n 'mage/translate'\n], function ($, productType) {\n 'use strict';\n\n return {\n isConfigurable: false,\n messageInited: false,\n messageSelector: '[data-role=product-custom-options-content]',\n isPercentPriceTypeExist: function () {\n var productOptionsContainer = $('#product_options_container_top');\n\n return !!productOptionsContainer.length;\n },\n showWarning: function () {\n if (!this.messageInited) {\n $(this.messageSelector).notification();\n this.messageInited = true;\n }\n this.hideWarning();\n $(this.messageSelector).notification('add', {\n message: $.mage.__('Custom options with price type \"percent\" is not available for ' +\n 'configurable product.'),\n error: false,\n messageContainer: this.messageSelector\n });\n },\n hideWarning: function () {\n $(this.messageSelector).notification('clear');\n },\n init: function () {\n $(document).on('changeTypeProduct', this._initType.bind(this));\n\n $('#product-edit-form-tabs').on('change', '.opt-type > select', function () {\n var selected = $('.opt-type > select :selected'),\n optGroup = selected.parent().attr('label');\n\n if (optGroup === 'Select') {\n $('#product-edit-form-tabs').on(\n 'click',\n '[data-ui-id=\"admin-product-options-options-box-select-option-type-add-select-row-button\"]',\n function () {\n this.percentPriceTypeHandler();\n }.bind(this)\n );\n } else {\n this.percentPriceTypeHandler();\n }\n }.bind(this));\n\n this._initType();\n },\n _initType: function () {\n this.isConfigurable = productType.type.current === 'configurable';\n if (this.isPercentPriceTypeExist()) {\n this.percentPriceTypeHandler();\n }\n },\n percentPriceTypeHandler: function () {\n var priceType = $('[data-attr=\"price-type\"]'),\n optionPercentPriceType = priceType.find('option[value=\"percent\"]');\n\n if (this.isConfigurable) {\n this.showWarning();\n optionPercentPriceType.hide();\n optionPercentPriceType.parent().val() === 'percent' ? optionPercentPriceType.parent().val('fixed') : '';\n } else {\n $(this.messageSelector).notification();\n optionPercentPriceType.show();\n this.hideWarning();\n }\n }\n };\n});\n*/\n","Magento_ConfigurableProduct/js/variations/product-grid.js":"// jscs:disable requireDotNotation\n/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'uiComponent',\n 'jquery',\n 'Magento_Ui/js/core/app',\n 'underscore',\n 'notification',\n 'mage/translate'\n], function (Component, $, bootstrap, _) {\n 'use strict';\n\n return Component.extend({\n defaults: {\n productsGridUrl: null,\n productAttributes: [],\n productsModal: null,\n button: '',\n gridSelector: '[data-grid-id=associated-products-container]',\n modules: {\n productsFilter: '${ $.productsFilter }',\n productsProvider: '${ $.productsProvider }',\n productsMassAction: '${ $.productsMassAction }',\n productsColumns: '${ $.productsColumns }',\n variationsComponent: '${ $.configurableVariations }'\n },\n listens: {\n '${ $.productsProvider }:data': '_showMessageAssociatedGrid _handleManualGridOpening',\n '${ $.productsMassAction }:selected': '_handleManualGridSelect',\n '${ $.configurableVariations }:productMatrix': '_showButtonAddManual _switchProductType'\n }\n },\n\n /**\n * Initialize\n *\n * @param {Array} options\n */\n initialize: function (options) {\n this._super(options);\n this.productsModal = $(this.gridSelector).modal({\n title: $.mage.__('Select Associated Product'),\n type: 'slide',\n buttons: [\n {\n text: $.mage.__('Cancel'),\n\n /** Close modal */\n click: function () {\n this.closeModal();\n }\n }, {\n text: $.mage.__('Done'),\n click: this.close.bind(this, null)\n }\n ]\n });\n\n this.productsProvider(function () {\n this.productsModal.notification();\n }.bind(this));\n this.variationsComponent(function (variation) {\n this._showButtonAddManual(variation.productMatrix());\n }.bind(this));\n\n this._initGrid = _.once(this._initGrid);\n this._switchProductType = _.wrap(this._switchProductType.bind(this), function (func, params) {\n if (!!params.length !== !!this.init) {\n this.init = !!params.length;\n func(params);\n }\n }.bind(this._switchProductType));\n },\n\n /**\n * Initial observerable\n * @returns {*}\n */\n initObservable: function () {\n this._super().observe('button');\n\n return this;\n },\n\n /**\n * init Grid\n * @private\n */\n _initGrid: function (filterData) {\n $.ajax({\n type: 'GET',\n url: this._buildGridUrl(filterData),\n context: $('body')\n }).done(function (data) {\n bootstrap(JSON.parse(data));\n });\n },\n\n /**\n * Select different product in configurations section\n * @see configurable_associated_product_listing.xml\n * @param {Integer} rowIndex\n */\n selectProduct: function (rowIndex) {\n this.close(rowIndex);\n },\n\n /**\n * Open\n * @param {Object} filterData - filter data\n * @param {Object|*} filterData.filters - attribute name\n * @param {Object|*} filterData.filters_modifier - modifier value\n * @param {String} callbackName\n * @param {Boolean} showMassActionColumn\n */\n open: function (filterData, callbackName, showMassActionColumn) {\n this.callbackName = callbackName;\n this.productsMassAction(function (massActionComponent) {\n this.productsColumns().elems().each(function (rowElement) {\n rowElement.disableAction = showMassActionColumn;\n });\n massActionComponent.visible = showMassActionColumn;\n }.bind(this));\n this._setFilter(filterData);\n this._initGrid(filterData);\n this.productsModal.trigger('openModal');\n },\n\n /**\n * Close\n */\n close: function (rowIndex) {\n try {\n if (this.productsMassAction().selected.getLength()) {\n this.variationsComponent()[this.callbackName](this.productsMassAction()\n .selected.map(this.getProductById.bind(this)));\n this.productsMassAction().deselectAll();\n } else if (!_.isNull(rowIndex)) {\n this.variationsComponent()[this.callbackName]([this.getProductByIndex(rowIndex)]);\n }\n this.productsModal.trigger('closeModal');\n } catch (e) {\n if (e.name === 'UserException') {\n this.productsModal.notification('clear');\n this.productsModal.notification('add', {\n message: e.message,\n messageContainer: this.gridSelector\n });\n } else {\n throw e;\n }\n }\n },\n\n /**\n * Get product by id\n * @param {Integer} productId\n * @returns {*}\n */\n getProductById: function (productId) {\n return _.findWhere(this.productsProvider().data.items, {\n 'entity_id': productId\n });\n },\n\n /**\n * Get product\n * @param {Integer} rowIndex\n * @returns {*}\n */\n getProductByIndex: function (rowIndex) {\n return this.productsProvider().data.items[rowIndex];\n },\n\n /**\n * Build grid url\n * @private\n */\n _buildGridUrl: function (filterData) {\n var params = '?' + $.param({\n 'filters': filterData.filters,\n 'attributes_codes': this._getAttributesCodes(),\n 'filters_modifier': filterData['filters_modifier']\n });\n\n return this.productsGridUrl + params;\n },\n\n /**\n * Show button add manual\n * @param {Array} variations\n * @returns {*}\n * @private\n */\n _showButtonAddManual: function (variations) {\n return this.button(variations.length);\n },\n\n /**\n * @param {Array} variations\n * @private\n */\n _switchProductType: function (variations) {\n $(document).trigger('changeConfigurableTypeProduct', variations.length);\n },\n\n /**\n * Get attributes codes used for configurable\n * @private\n */\n _getAttributesCodes: function () {\n return this.variationsComponent().attributes.pluck('code');\n },\n\n /**\n * Show data associated grid\n * @private\n */\n _showMessageAssociatedGrid: function (data) {\n this.productsModal.notification('clear');\n\n if (data.items.length) {\n this.productsModal.notification('add', {\n message: $.mage.__('Choose a new product to delete and replace the current product configuration.'),\n messageContainer: this.gridSelector\n });\n } else {\n this.productsModal.notification('add', {\n message: $.mage.__('For better results, add attributes and attribute values to your products.'),\n messageContainer: this.gridSelector\n });\n }\n },\n\n /**\n * Show manually grid\n */\n showManuallyGrid: function () {\n var filterModifier = _.mapObject(_.object(this._getAttributesCodes(), []), function () {\n return {\n 'condition_type': 'notnull'\n };\n }),\n usedProductIds = _.values(this.variationsComponent().productAttributesMap);\n\n if (usedProductIds && usedProductIds.length > 0) {\n filterModifier['entity_id'] = {\n 'condition_type': 'nin', value: usedProductIds\n };\n }\n\n this.open(\n {\n 'filters_modifier': filterModifier\n },\n 'appendProducts',\n true\n );\n },\n\n /**\n * Handle manual grid after opening\n * @private\n */\n _handleManualGridOpening: function (data) {\n if (data.items.length && this.callbackName == 'appendProducts') { //eslint-disable-line eqeqeq\n this.productsColumns().elems().each(function (rowElement) {\n rowElement.disableAction = true;\n });\n\n this._disableRows(data.items);\n }\n },\n\n /**\n * Disable rows in grid for products with the same variation key\n *\n * @param {Array} items\n * @param {Array} selectedVariationKeys\n * @param {Array} selected\n * @private\n */\n _disableRows: function (items, selectedVariationKeys, selected) {\n selectedVariationKeys = selectedVariationKeys === undefined ? [] : selectedVariationKeys;\n selected = selected === undefined ? [] : selected;\n this.productsMassAction(function (massaction) {\n var configurableVariationKeys = _.union(\n selectedVariationKeys,\n _.pluck(this.variationsComponent().productMatrix(), 'variationKey')\n ),\n variationKeyMap = this._getVariationKeyMap(items),\n rowsForDisable = _.keys(_.pick(\n variationKeyMap,\n function (variationKey) {\n return configurableVariationKeys.indexOf(variationKey) !== -1;\n }\n ));\n\n massaction.disabled(_.difference(rowsForDisable, selected));\n }.bind(this));\n },\n\n /**\n * @private\n */\n _handleManualGridSelect: function (selected) {\n var selectedRows, selectedVariationKeys;\n\n if (this.callbackName == 'appendProducts') { //eslint-disable-line eqeqeq\n selectedRows = _.filter(this.productsProvider().data.items, function (row) {\n return selected.indexOf(row['entity_id']) !== -1;\n });\n selectedVariationKeys = _.values(this._getVariationKeyMap(selectedRows));\n this._disableRows(this.productsProvider().data.items, selectedVariationKeys, selected);\n }\n },\n\n /**\n * Get variation key map used in manual grid.\n *\n * @param {Object} items\n * @returns {Array} [{entity_id: variation-key}, ...]\n * @private\n */\n _getVariationKeyMap: function (items) {\n this._variationKeyMap = {};\n\n _.each(items, function (row) {\n this._variationKeyMap[row['entity_id']] = _.values(\n _.pick(row, this._getAttributesCodes())\n ).sort().join('-');\n\n }, this);\n\n return this._variationKeyMap;\n },\n\n /**\n * Set filter\n * @private\n */\n _setFilter: function (filterData) {\n this.productsProvider(function (provider) {\n provider.params['filters_modifier'] = filterData['filters_modifier'];\n provider.params['attributes_codes'] = this._getAttributesCodes();\n }.bind(this));\n\n this.productsFilter(function (filter) {\n filter.set('filters', _.extend({\n 'filters_modifier': filterData['filters_modifier']\n }, filterData.filters))\n .apply();\n });\n }\n });\n});\n","Magento_ConfigurableProduct/js/variations/variations.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'uiComponent',\n 'jquery',\n 'ko',\n 'underscore',\n 'Magento_Ui/js/modal/alert',\n 'uiRegistry',\n 'mage/translate'\n], function (Component, $, ko, _, alert, registry, $t) {\n 'use strict';\n\n /**\n * @param {*} message\n * @constructor\n */\n function UserException(message) {\n this.message = message;\n this.name = 'UserException';\n }\n UserException.prototype = Object.create(Error.prototype);\n\n return Component.extend({\n defaults: {\n opened: false,\n attributes: [],\n usedAttributes: [],\n attributeCodes: [],\n attributesData: {},\n productMatrix: [],\n variations: [],\n formSaveParams: [],\n productAttributes: [],\n disabledAttributes: [],\n fullAttributes: [],\n rowIndexToEdit: false,\n productAttributesMap: null,\n value: [],\n modules: {\n associatedProductGrid: '${ $.configurableProductGrid }',\n wizardButtonElement: '${ $.wizardModalButtonName }',\n formElement: '${ $.formName }',\n attributeSetHandlerModal: '${ $.attributeSetHandler }'\n },\n imports: {\n attributeSetName: '${ $.provider }:configurableNewAttributeSetName',\n attributeSetId: '${ $.provider }:configurableExistingAttributeSetId',\n attributeSetSelection: '${ $.provider }:configurableAffectedAttributeSet',\n productPrice: '${ $.provider }:data.product.price'\n },\n links: {\n value: '${ $.provider }:${ $.dataScopeVariations }',\n usedAttributes: '${ $.provider }:${ $.dataScopeAttributes }',\n attributesData: '${ $.provider }:${ $.dataScopeAttributesData }',\n attributeCodes: '${ $.provider }:${ $.dataScopeAttributeCodes }',\n skeletonAttributeSet: '${ $.provider }:data.new-variations-attribute-set-id'\n }\n },\n\n /** @inheritdoc */\n initialize: function () {\n this._super();\n\n this.changeButtonWizard();\n this.initProductAttributesMap();\n this.disableConfigurableAttributes(this.productAttributes);\n },\n\n /** @inheritdoc */\n initObservable: function () {\n this._super().observe(\n 'actions opened attributes productMatrix value usedAttributes attributesData attributeCodes'\n );\n\n return this;\n },\n\n /**\n * @param {Object} product\n * @return {Object}\n * @private\n */\n _makeProduct: function (product) {\n var productId = product['entity_id'] || product.productId || null,\n attributes = _.pick(product, this.attributes.pluck('code')),\n options = _.map(attributes, function (option, attribute) {\n var oldOptions = _.findWhere(this.attributes(), {\n code: attribute\n }).options,\n result;\n\n if (_.isFunction(oldOptions)) {\n result = oldOptions.findWhere({\n value: option\n });\n } else {\n result = _.findWhere(oldOptions, {\n value: option\n });\n }\n\n return result;\n }.bind(this));\n\n return {\n attribute: JSON.stringify(attributes),\n editable: false,\n images: {\n preview: product['thumbnail_src']\n },\n name: product.name || product.sku,\n options: options,\n price: parseFloat(Math.round(product.price.replace(/[^\\d.]+/g, '') + 'e+4') + 'e-4').toFixed(4),\n productId: productId,\n productUrl: this.buildProductUrl(productId),\n quantity: product.quantity || null,\n sku: product.sku,\n status: product.status === undefined ? 1 : parseInt(product.status, 10),\n variationKey: this.getVariationKey(options),\n weight: product.weight || null\n };\n },\n\n /**\n * @param {String} name\n * @return {String|Number|Array}\n */\n getProductValue: function (name) {\n name = name.split('/').join('][');\n\n return $('[name=\"product[' + name + ']\"]:enabled:not(.ignore-validate)', this.productForm).val();\n },\n\n /**\n * @param {Object} data\n * @param {String} field\n * @return {String}\n */\n getRowId: function (data, field) {\n var key = data.variationKey;\n\n return 'variations-matrix-' + key + '-' + field;\n },\n\n /**\n * @param {Object} variation\n * @param {String} field\n * @return {String}\n */\n getVariationRowName: function (variation, field) {\n var result;\n\n if (variation.productId) {\n result = 'configurations[' + variation.productId + '][' + field.split('/').join('][') + ']';\n } else {\n result = 'variations-matrix[' + variation.variationKey + '][' + field.split('/').join('][') + ']';\n }\n\n return result;\n },\n\n /**\n * @param {*} variations\n * @param {*} attributes\n */\n render: function (variations, attributes) {\n this.changeButtonWizard();\n this.populateVariationMatrix(variations);\n this.attributes(attributes);\n this.disableConfigurableAttributes(attributes);\n this.handleValue(variations);\n this.handleAttributes();\n },\n\n /**\n * Change button wizard.\n */\n changeButtonWizard: function () {\n if (this.variations.length) {\n this.wizardButtonElement().title(this.wizardModalButtonTitle);\n }\n },\n\n /**\n * @param {Array} variations\n */\n handleValue: function (variations) {\n var tmpArray = [];\n\n _.each(variations, function (variation) {\n var attributes = _.reduce(variation.options, function (memo, option) {\n var attribute = {};\n\n attribute[option['attribute_code']] = option.value;\n\n return _.extend(memo, attribute);\n }, {}),\n gallery = {\n images: {}\n },\n types = {};\n\n _.each(variation.images.images, function (image) {\n gallery.images[image['file_id']] = {\n position: image.position,\n file: image.file,\n disabled: image.disabled,\n label: image.label || ''\n };\n _.each(image.galleryTypes, function (type) {\n types[type] = image.file;\n });\n }, this);\n\n tmpArray.push(_.extend(variation, types, {\n productId: variation.productId || null,\n name: variation.name || variation.sku,\n priceCurrency: this.currencySymbol,\n weight: variation.weight,\n attribute: JSON.stringify(attributes),\n variationKey: this.getVariationKey(variation.options),\n editable: variation.editable === undefined ? 0 : 1,\n productUrl: this.buildProductUrl(variation.productId),\n status: variation.status === undefined ? 1 : parseInt(variation.status, 10),\n newProduct: variation.productId ? 0 : 1,\n 'media_gallery': gallery\n }));\n }, this);\n\n this.value(tmpArray);\n },\n\n /**\n * Handle attributes.\n */\n handleAttributes: function () {\n var tmpArray = [],\n codesArray = [],\n tmpOptions = {},\n option = {},\n position = 0,\n values = {};\n\n _.each(this.attributes(), function (attribute) {\n tmpArray.push(attribute.id);\n codesArray.push(attribute.code);\n values = {};\n _.each(attribute.chosen, function (row) {\n values[row.value] = {\n 'include': '1',\n 'value_index': row.value\n };\n }, this);\n option = {\n 'attribute_id': attribute.id,\n 'code': attribute.code,\n 'label': attribute.label,\n 'position': position,\n 'values': values\n };\n tmpOptions[attribute.id] = option;\n position++;\n }, this);\n\n this.attributesData(tmpOptions);\n this.usedAttributes(tmpArray);\n this.attributeCodes(codesArray);\n },\n\n /**\n * Get attributes options\n * @see use in matrix.phtml\n *\n * @returns {Array}\n */\n getAttributesOptions: function () {\n return this.showVariations() ? this.productMatrix()[0].options : [];\n },\n\n /**\n * @return {Boolean}\n */\n showVariations: function () {\n return this.productMatrix().length > 0;\n },\n\n /**\n * @param {Array} variations\n */\n populateVariationMatrix: function (variations) {\n this.productMatrix([]);\n _.each(variations, function (variation) {\n var attributes = _.reduce(variation.options, function (memo, option) {\n var attribute = {};\n\n attribute[option['attribute_code']] = option.value;\n\n return _.extend(memo, attribute);\n }, {});\n\n this.productMatrix.push(_.extend(variation, {\n productId: variation.productId || null,\n name: variation.name || variation.sku,\n weight: variation.weight,\n attribute: JSON.stringify(attributes),\n variationKey: this.getVariationKey(variation.options),\n editable: variation.editable === undefined ? !variation.productId : variation.editable,\n productUrl: this.buildProductUrl(variation.productId),\n status: variation.status === undefined ? 1 : parseInt(variation.status, 10)\n }));\n }, this);\n },\n\n /**\n * @param {*} productId\n */\n buildProductUrl: function (productId) {\n return this.productUrl.replace('%id%', productId);\n },\n\n /**\n * @param {Object} options\n * @return {String}\n */\n getVariationKey: function (options) {\n return _.pluck(options, 'value').sort().join('-');\n },\n\n /**\n * @param {*} options\n * @return {*|null}\n */\n getProductIdByOptions: function (options) {\n return this.productAttributesMap[this.getVariationKey(options)] || null;\n },\n\n /**\n * Init product attributes map\n */\n initProductAttributesMap: function () {\n if (this.productAttributesMap === null) {\n this.productAttributesMap = {};\n _.each(this.variations, function (product) {\n this.productAttributesMap[this.getVariationKey(product.options)] = product.productId;\n }.bind(this));\n }\n },\n\n /**\n * @param {Array} attributes\n */\n disableConfigurableAttributes: function (attributes) {\n var element;\n\n _.each(this.disabledAttributes, function (attribute) {\n registry.get('inputName = ' + 'product[' + attribute + ']').disabled(false);\n });\n this.disabledAttributes = [];\n\n _.each(attributes, function (attribute) {\n element = registry.get('inputName = ' + 'product[' + attribute.code + ']');\n\n if (!_.isUndefined(element)) {\n element.disabled(true);\n this.disabledAttributes.push(attribute.code);\n }\n }, this);\n },\n\n /**\n * Get currency symbol\n * @returns {String}\n */\n getCurrencySymbol: function () {\n return this.currencySymbol;\n },\n\n /**\n * Chose action for the form save button\n */\n saveFormHandler: function () {\n this.formElement().validate();\n\n if (this.formElement().source.get('params.invalid') === false) {\n this.serializeData();\n }\n\n if (this.checkForNewAttributes()) {\n this.formSaveParams = arguments;\n this.attributeSetHandlerModal().openModal();\n } else {\n if (this.validateForm(this.formElement())) {\n this.clearOutdatedData();\n }\n this.formElement().save(arguments[0], arguments[1]);\n\n if (this.formElement().source.get('params.invalid')) {\n this.unserializeData();\n }\n }\n },\n\n /**\n * @param {Object} formElement\n *\n * Validates each form element and returns true, if all elements are valid.\n */\n validateForm: function (formElement) {\n formElement.validate();\n\n return !formElement.additionalInvalid && !formElement.source.get('params.invalid');\n },\n\n /**\n * Serialize data for specific form fields\n *\n * Serializes some complex data fields\n *\n * Original fields:\n * - configurable-matrix;\n * - associated_product_ids.\n *\n * Serialized fields in request:\n * - configurable-matrix-serialized;\n * - associated_product_ids_serialized.\n */\n serializeData: function () {\n if (this.source.data['configurable-matrix']) {\n this.source.data['configurable-matrix-serialized'] =\n JSON.stringify(this.source.data['configurable-matrix']);\n }\n\n if (this.source.data['associated_product_ids']) {\n this.source.data['associated_product_ids_serialized'] =\n JSON.stringify(this.source.data['associated_product_ids']);\n }\n },\n\n /**\n * Clear outdated data for specific form fields\n *\n * Outdated fields:\n * - configurable-matrix;\n * - associated_product_ids.\n */\n clearOutdatedData: function () {\n if (this.source.data['configurable-matrix']) {\n delete this.source.data['configurable-matrix'];\n }\n\n if (this.source.data['associated_product_ids']) {\n delete this.source.data['associated_product_ids'];\n }\n },\n\n /**\n * Unserialize data for specific form fields\n *\n * Unserializes some fields that were serialized this.serializeData\n */\n unserializeData: function () {\n if (this.source.data['configurable-matrix-serialized']) {\n this.source.data['configurable-matrix'] =\n JSON.parse(this.source.data['configurable-matrix-serialized']);\n delete this.source.data['configurable-matrix-serialized'];\n }\n\n if (this.source.data['associated_product_ids_serialized']) {\n this.source.data['associated_product_ids'] =\n JSON.parse(this.source.data['associated_product_ids_serialized']);\n delete this.source.data['associated_product_ids_serialized'];\n }\n },\n\n /**\n * Check for newly added attributes\n * @returns {Boolean}\n */\n checkForNewAttributes: function () {\n var element, newAttributes = false;\n\n _.each(this.source.get('data.attribute_codes'), function (attribute) {\n element = registry.get('index = ' + attribute);\n\n if (_.isUndefined(element)) {\n newAttributes = true;\n }\n }, this);\n\n return newAttributes;\n },\n\n /**\n * New attributes handler\n * @returns {Boolean}\n */\n addNewAttributeSetHandler: function () {\n var chosenAttributeSetOption;\n\n this.formElement().validate();\n\n if (this.formElement().source.get('params.invalid') === false) {\n chosenAttributeSetOption = this.attributeSetSelection;\n\n if (chosenAttributeSetOption === 'new') {\n this.createNewAttributeSet();\n\n return false;\n }\n\n if (chosenAttributeSetOption === 'existing') {\n this.set(\n 'skeletonAttributeSet',\n this.attributeSetId\n );\n }\n\n this.closeDialogAndProcessForm();\n\n return true;\n }\n\n this.unserializeData();\n\n return false;\n },\n\n /**\n * Handles new attribute set creation\n * @returns {Boolean}\n */\n createNewAttributeSet: function () {\n var messageBoxElement = registry.get('index = affectedAttributeSetError');\n\n messageBoxElement.visible(false);\n\n $.ajax({\n type: 'POST',\n url: this.attributeSetCreationUrl,\n data: {\n gotoEdit: 1,\n 'attribute_set_name': this.attributeSetName,\n 'skeleton_set': this.skeletonAttributeSet,\n 'return_session_messages_only': 1\n },\n dataType: 'json',\n showLoader: true,\n context: this\n }).done(function (data) {\n if (!data.error) {\n this.set(\n 'skeletonAttributeSet',\n data.id\n );\n messageBoxElement.content(data.messages);\n messageBoxElement.visible(true);\n this.closeDialogAndProcessForm();\n } else {\n messageBoxElement.content(data.messages);\n messageBoxElement.visible(true);\n }\n\n return false;\n }).fail(function (xhr) {\n if (xhr.statusText === 'abort') {\n return;\n }\n\n alert({\n content: $t('Something went wrong.')\n });\n });\n\n return false;\n },\n\n /**\n * Closes attribute set handler modal and process product form\n */\n closeDialogAndProcessForm: function () {\n this.attributeSetHandlerModal().closeModal();\n this.formElement().save(this.formSaveParams[0], this.formSaveParams[1]);\n },\n\n /**\n * Retrieves product price\n * @returns {*}\n */\n getProductPrice: function () {\n return this.productPrice;\n }\n });\n});\n","Magento_ConfigurableProduct/js/variations/steps/bulk.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* global FORM_KEY, byteConvert */\ndefine([\n 'uiComponent',\n 'jquery',\n 'ko',\n 'underscore',\n 'Magento_Ui/js/lib/collapsible',\n 'mage/template',\n 'Magento_Ui/js/modal/alert',\n 'Magento_Catalog/js/product-gallery',\n 'jquery/file-uploader',\n 'mage/translate',\n 'Magento_ConfigurableProduct/js/variations/variations'\n], function (Component, $, ko, _, Collapsible, mageTemplate, alert) {\n 'use strict';\n\n return Component.extend({\n defaults: {\n modules: {\n variationsComponent: '${ $.variationsComponent }'\n },\n countVariations: 0,\n attributes: [],\n sections: {},\n images: null,\n price: '',\n quantity: '',\n notificationMessage: {\n text: null,\n error: null\n }\n },\n\n /** @inheritdoc */\n initObservable: function () {\n this._super().observe('countVariations attributes sections');\n\n return this;\n },\n\n /** @inheritdoc */\n initialize: function () {\n var self = this;\n\n this._super();\n this.sections({\n images: {\n label: 'images',\n type: ko.observable('none'),\n value: ko.observable(),\n attribute: ko.observable()\n },\n price: {\n label: 'price',\n type: ko.observable('none'),\n value: ko.observable(),\n attribute: ko.observable(),\n currencySymbol: ''\n },\n quantity: {\n label: 'quantity',\n type: ko.observable('none'),\n value: ko.observable(),\n attribute: ko.observable()\n }\n });\n\n this.variationsComponent(function (variationsComponent) {\n this.sections().price.currencySymbol = variationsComponent.getCurrencySymbol();\n }.bind(this));\n\n /**\n * Make options sections.\n */\n this.makeOptionSections = function () {\n return {\n images: new this.makeImages(null),\n price: this.price,\n quantity: this.quantity\n };\n }.bind(this);\n\n /**\n * @param {Object} images\n * @param {*} typePreview\n */\n this.makeImages = function (images, typePreview) {\n var preview;\n\n if (!images) {\n this.images = [];\n this.preview = self.noImage;\n this.file = null;\n } else {\n this.images = images;\n preview = _.find(this.images, function (image) {\n return _.contains(image.galleryTypes, typePreview);\n });\n\n if (preview) {\n this.file = preview.file;\n this.preview = preview.url;\n } else {\n this.file = null;\n this.preview = self.noImage;\n }\n }\n };\n this.images = new this.makeImages();\n _.each(this.sections(), function (section) {\n section.type.subscribe(function () {\n this.setWizardNotifyMessageDependOnSectionType();\n }.bind(this));\n }, this);\n },\n types: ['each', 'single', 'none'],\n\n /**\n * Set Wizard notify message depend on section type\n */\n setWizardNotifyMessageDependOnSectionType: function () {\n var flag = false;\n\n _.each(this.sections(), function (section) {\n if (section.type() !== 'none') {\n flag = true;\n }\n }, this);\n\n if (flag) {\n this.wizard.setNotificationMessage(\n $.mage.__('Choose this option to delete and replace extension data for all past configurations.')\n );\n } else {\n this.wizard.cleanNotificationMessage();\n }\n },\n\n /**\n * @param {Object} wizard\n */\n render: function (wizard) {\n this.wizard = wizard;\n this.attributes(wizard.data.attributes());\n\n if (this.mode === 'edit') {\n this.setWizardNotifyMessageDependOnSectionType();\n }\n //fill option section data\n this.attributes.each(function (attribute) {\n attribute.chosen.each(function (option) {\n option.sections = ko.observable(this.makeOptionSections());\n }, this);\n }, this);\n //reset section.attribute\n _.each(this.sections(), function (section) {\n section.attribute(null);\n });\n\n this.initCountVariations();\n this.bindGalleries();\n },\n\n /**\n * Init count variations.\n */\n initCountVariations: function () {\n var variations = this.generateVariation(this.attributes()),\n newVariations = _.map(variations, function (options) {\n return this.variationsComponent().getVariationKey(options);\n }.bind(this)),\n existingVariations = _.keys(this.variationsComponent().productAttributesMap);\n\n this.countVariations(_.difference(newVariations, existingVariations).length);\n },\n\n /**\n * @param {Object} attributes - example [['b1', 'b2'],['a1', 'a2', 'a3'],['c1', 'c2', 'c3'],['d1']]\n * @returns {*} example [['b1','a1','c1','d1'],['b1','a1','c2','d1']...]\n */\n generateVariation: function (attributes) {\n return _.reduce(attributes, function (matrix, attribute) {\n var tmp = [];\n\n _.each(matrix, function (variations) {\n _.each(attribute.chosen, function (option) {\n option['attribute_code'] = attribute.code;\n option['attribute_label'] = attribute.label;\n tmp.push(_.union(variations, [option]));\n });\n });\n\n if (!tmp.length) {\n return _.map(attribute.chosen, function (option) {\n option['attribute_code'] = attribute.code;\n option['attribute_label'] = attribute.label;\n\n return [option];\n });\n }\n\n return tmp;\n }, []);\n },\n\n /**\n * @param {*} section\n * @param {Object} options\n * @return {*}\n */\n getSectionValue: function (section, options) {\n switch (this.sections()[section].type()) {\n case 'each':\n return _.find(this.sections()[section].attribute().chosen, function (chosen) {\n return _.find(options, function (option) {\n return chosen.id == option.id; //eslint-disable-line eqeqeq\n });\n }).sections()[section];\n\n case 'single':\n return this.sections()[section].value();\n\n case 'none':\n return this[section];\n }\n },\n\n /**\n * @param {*} node\n * @return {Promise|*}\n */\n getImageProperty: function (node) {\n var types = node.find('[data-role=gallery]').productGallery('option').types,\n images = _.map(node.find('[data-role=image]'), function (image) {\n var imageData = $(image).data('imageData');\n\n imageData.galleryTypes = _.pluck(_.filter(types, function (type) {\n return type.value === imageData.file;\n }), 'code');\n\n return imageData;\n });\n\n return _.reject(images, function (image) {\n return !!image.isRemoved;\n });\n },\n\n /**\n * Fill images section.\n */\n fillImagesSection: function () {\n switch (this.sections().images.type()) {\n case 'each':\n if (this.sections().images.attribute()) {\n this.sections().images.attribute().chosen.each(function (option) {\n option.sections().images = new this.makeImages(\n this.getImageProperty($('[data-role=step-gallery-option-' + option.id + ']')),\n 'thumbnail'\n );\n }, this);\n }\n break;\n\n case 'single':\n this.sections().images.value(new this.makeImages(\n this.getImageProperty($('[data-role=step-gallery-single]')),\n 'thumbnail'\n ));\n break;\n\n default:\n this.sections().images.value(new this.makeImages());\n break;\n }\n },\n\n /**\n * @param {Object} wizard\n */\n force: function (wizard) {\n this.fillImagesSection();\n this.validate();\n this.validateImage();\n wizard.data.sections = this.sections;\n wizard.data.sectionHelper = this.getSectionValue.bind(this);\n wizard.data.variations = this.generateVariation(this.attributes());\n },\n\n /**\n * Validate.\n */\n validate: function () {\n var formValid;\n\n _.each(this.sections(), function (section) {\n switch (section.type()) {\n case 'each':\n if (!section.attribute()) {\n throw new Error($.mage.__('Please select attribute for {section} section.')\n .replace('{section}', section.label));\n }\n break;\n\n case 'single':\n if (!section.value()) {\n throw new Error($.mage.__('Please fill in the values for {section} section.')\n .replace('{section}', section.label));\n }\n break;\n }\n }, this);\n formValid = true;\n _.each($('[data-role=attributes-values-form]'), function (form) {\n formValid = $(form).valid() && formValid;\n });\n\n if (!formValid) {\n throw new Error($.mage.__('Please fill-in correct values.'));\n }\n },\n\n /**\n * Validate image.\n */\n validateImage: function () {\n switch (this.sections().images.type()) {\n case 'each':\n _.each(this.sections().images.attribute().chosen, function (option) {\n if (!option.sections().images.images.length) {\n throw new Error($.mage.__('Please select image(s) for your attribute.'));\n }\n });\n break;\n\n case 'single':\n if (this.sections().images.value().file == null) {\n throw new Error($.mage.__('Please choose image(s).'));\n }\n break;\n }\n },\n\n /**\n * Back.\n */\n back: function () {\n this.setWizardNotifyMessageDependOnSectionType();\n },\n\n /**\n * Bind galleries.\n */\n bindGalleries: function () {\n $('[data-role=bulk-step] [data-role=gallery]').each(function (index, element) {\n var gallery = $(element),\n uploadInput = $(gallery.find('[name=image]')),\n dropZone = $(gallery).find('.image-placeholder');\n\n if (!gallery.data('gallery-initialized')) {\n gallery.mage('productGallery', {\n template: '[data-template=gallery-content]',\n dialogTemplate: '.dialog-template',\n dialogContainerTmpl: '[data-role=img-dialog-container-tmpl]'\n });\n\n uploadInput.fileupload({\n dataType: 'json',\n dropZone: dropZone,\n process: [{\n action: 'load',\n fileTypes: /^image\\/(gif|jpeg|png)$/\n }, {\n action: 'resize',\n maxWidth: 1920,\n maxHeight: 1200\n }, {\n action: 'save'\n }],\n formData: {\n 'form_key': FORM_KEY\n },\n sequentialUploads: true,\n acceptFileTypes: /(\\.|\\/)(gif|jpe?g|png)$/i,\n\n /**\n * @param {jQuery.Event} e\n * @param {Object} data\n */\n add: function (e, data) {\n var progressTmpl = mageTemplate('[data-template=uploader]'),\n fileSize,\n tmpl;\n\n $.each(data.files, function (i, file) {\n fileSize = typeof file.size == 'undefined' ?\n $.mage.__('We could not detect a size.') :\n byteConvert(file.size);\n\n data.fileId = Math.random().toString(33).substr(2, 18);\n\n tmpl = progressTmpl({\n data: {\n name: file.name,\n size: fileSize,\n id: data.fileId\n }\n });\n\n $(tmpl).appendTo(gallery.find('[data-role=uploader]'));\n });\n\n $(this).fileupload('process', data).done(function () {\n data.submit();\n });\n },\n\n /**\n * @param {jQuery.Event} e\n * @param {Object} data\n */\n done: function (e, data) {\n if (data.result && !data.result.error) {\n gallery.trigger('addItem', data.result);\n } else {\n $('#' + data.fileId)\n .delay(2000)\n .hide('highlight');\n alert({\n content: $.mage.__('We don\\'t recognize or support this file extension type.')\n });\n }\n $('#' + data.fileId).remove();\n },\n\n /**\n * @param {jQuery.Event} e\n * @param {Object} data\n */\n progress: function (e, data) {\n var progress = parseInt(data.loaded / data.total * 100, 10),\n progressSelector = '#' + data.fileId + ' .progressbar-container .progressbar';\n\n $(progressSelector).css('width', progress + '%');\n },\n\n /**\n * @param {jQuery.Event} e\n * @param {Object} data\n */\n fail: function (e, data) {\n var progressSelector = '#' + data.fileId;\n\n $(progressSelector).removeClass('upload-progress').addClass('upload-failure')\n .delay(2000)\n .hide('highlight')\n .remove();\n }\n });\n gallery.data('gallery-initialized', 1);\n }\n });\n }\n });\n});\n","Magento_ConfigurableProduct/js/variations/steps/select_attributes.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'uiComponent',\n 'jquery',\n 'underscore',\n 'mage/translate'\n], function (Component, $, _) {\n 'use strict';\n\n /**\n * @param {Function} provider\n */\n var initNewAttributeListener = function (provider) {\n $('[data-role=product-variations-matrix]').on('add', function () {\n provider().reload();\n });\n };\n\n return Component.extend({\n attributesLabels: {},\n stepInitialized: false,\n defaults: {\n modules: {\n multiselect: '${ $.multiselectName }',\n attributeProvider: '${ $.providerName }'\n },\n listens: {\n '${ $.multiselectName }:selected': 'doSelectedAttributesLabels',\n '${ $.multiselectName }:rows': 'doSelectSavedAttributes'\n },\n notificationMessage: {\n text: null,\n error: null\n },\n selectedAttributes: []\n },\n\n /** @inheritdoc */\n initialize: function () {\n this._super();\n this.selected = [];\n\n initNewAttributeListener(this.attributeProvider);\n },\n\n /** @inheritdoc */\n initObservable: function () {\n this._super().observe(['selectedAttributes']);\n\n return this;\n },\n\n /**\n * @param {Object} wizard\n */\n render: function (wizard) {\n this.wizard = wizard;\n this.setNotificationMessage();\n },\n\n /**\n * Set notification message.\n */\n setNotificationMessage: function () {\n /*eslint-disable max-len*/\n var msg = $.mage.__('When you remove or add an attribute, we automatically update all configurations and you will need to recreate current configurations manually.');\n\n /*eslint-enable max-len*/\n\n if (this.mode === 'edit') {\n this.wizard.setNotificationMessage(msg);\n }\n },\n\n /**\n * Do select saved attributes.\n */\n doSelectSavedAttributes: function () {\n if (this.stepInitialized === false) {\n this.stepInitialized = true;\n //cache attributes labels, which can be present on the 2nd page\n _.each(this.initData.attributes, function (attribute) {\n this.attributesLabels[attribute.id] = attribute.label;\n }.bind(this));\n this.multiselect().selected(_.pluck(this.initData.attributes, 'id'));\n }\n },\n\n /**\n * @param {*} selected\n */\n doSelectedAttributesLabels: function (selected) {\n var labels = [];\n\n this.selected = selected;\n _.each(selected, function (attributeId) {\n var attribute;\n\n if (!this.attributesLabels[attributeId]) {\n attribute = _.findWhere(this.multiselect().rows(), {\n 'attribute_id': attributeId\n });\n\n if (attribute) {\n this.attributesLabels[attribute['attribute_id']] = attribute['frontend_label'];\n }\n }\n labels.push(this.attributesLabels[attributeId]);\n }.bind(this));\n this.selectedAttributes(labels.join(', '));\n },\n\n /**\n * @param {Object} wizard\n */\n force: function (wizard) {\n wizard.data.attributesIds = this.multiselect().selected;\n\n if (!wizard.data.attributesIds() || wizard.data.attributesIds().length === 0) {\n throw new Error($.mage.__('Please select attribute(s).'));\n }\n this.setNotificationMessage();\n },\n\n /**\n * Back.\n */\n back: function () {\n }\n });\n});\n","Magento_ConfigurableProduct/js/variations/steps/summary.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'uiComponent',\n 'jquery',\n 'ko',\n 'underscore',\n 'Magento_Ui/js/grid/paging/paging',\n 'mage/translate'\n], function (Component, $, ko, _, paging) {\n 'use strict';\n\n return Component.extend({\n defaults: {\n modules: {\n variationsComponent: '${ $.variationsComponent }',\n modalComponent: '${ $.modalComponent }'\n },\n notificationMessage: {\n text: null,\n error: null\n },\n gridExisting: [],\n gridNew: [],\n gridDeleted: [],\n variationsExisting: [],\n variationsNew: [],\n variationsDeleted: [],\n pagingExisting: paging({\n name: 'configurableWizard.pagingExisting',\n sizesConfig: {\n component: 'Magento_ConfigurableProduct/js/variations/paging/sizes',\n name: 'configurableWizard.pagingExisting_sizes'\n }\n }),\n pagingNew: paging({\n name: 'configurableWizard.pagingNew',\n sizesConfig: {\n component: 'Magento_ConfigurableProduct/js/variations/paging/sizes',\n name: 'configurableWizard.pagingNew_sizes'\n }\n }),\n pagingDeleted: paging({\n name: 'configurableWizard.pagingDeleted',\n sizesConfig: {\n component: 'Magento_ConfigurableProduct/js/variations/paging/sizes',\n name: 'configurableWizard.pagingDeleted_sizes'\n }\n }),\n attributes: [],\n attributesName: [$.mage.__('Images'), $.mage.__('SKU'), $.mage.__('Quantity'), $.mage.__('Price')],\n sections: [],\n gridTemplate: 'Magento_ConfigurableProduct/variations/steps/summary-grid',\n quantityFieldName: 'quantity'\n },\n\n /** @inheritdoc */\n initObservable: function () {\n var pagingObservables = {\n currentNew: ko.getObservable(this.pagingNew, 'current'),\n currentExisting: ko.getObservable(this.pagingExisting, 'current'),\n currentDeleted: ko.getObservable(this.pagingDeleted, 'current'),\n pageSizeNew: ko.getObservable(this.pagingNew, 'pageSize'),\n pageSizeExisting: ko.getObservable(this.pagingExisting, 'pageSize'),\n pageSizeDeleted: ko.getObservable(this.pagingDeleted, 'pageSize')\n };\n\n this._super().observe('gridExisting gridNew gridDeleted attributes sections');\n this.gridExisting.columns = ko.observableArray();\n this.gridNew.columns = ko.observableArray();\n this.gridDeleted.columns = ko.observableArray();\n\n _.each(pagingObservables, function (observable) {\n observable.subscribe(function () {\n this.generateGrid();\n }, this);\n }, this);\n\n return this;\n },\n nextLabelText: $.mage.__('Generate Products'),\n variations: [],\n\n /**\n * @param {*} variations\n * @param {Function} getSectionValue\n */\n calculate: function (variations, getSectionValue) {\n var productSku = this.variationsComponent().getProductValue('sku'),\n productPrice = this.variationsComponent().getProductPrice(),\n productWeight = this.variationsComponent().getProductValue('weight'),\n productName = this.variationsComponent().getProductValue('name'),\n variationsKeys = [],\n gridExisting = [],\n gridNew = [],\n gridDeleted = [];\n\n this.variations = [];\n _.each(variations, function (options) {\n var product, images, sku, name, quantity, price, variation,\n productId = this.variationsComponent().getProductIdByOptions(options);\n\n if (productId) {\n product = _.findWhere(this.variationsComponent().variations, {\n productId: productId\n });\n }\n images = getSectionValue('images', options);\n sku = productSku + _.reduce(options, function (memo, option) {\n return memo + '-' + option.label;\n }, '');\n name = productName + _.reduce(options, function (memo, option) {\n return memo + '-' + option.label;\n }, '');\n quantity = getSectionValue(this.quantityFieldName, options);\n\n if (!quantity && productId) {\n quantity = product[this.quantityFieldName];\n }\n price = getSectionValue('price', options);\n\n if (!price) {\n price = productId ? product.price : productPrice;\n }\n\n if (productId && !images.file) {\n images = product.images;\n }\n variation = {\n options: options,\n images: images,\n sku: sku,\n name: name,\n price: price,\n productId: productId,\n weight: productWeight,\n editable: true\n };\n variation[this.quantityFieldName] = quantity;\n\n if (productId) {\n variation.sku = product.sku;\n variation.weight = product.weight;\n variation.name = product.name;\n gridExisting.push(this.prepareRowForGrid(variation));\n } else {\n gridNew.push(this.prepareRowForGrid(variation));\n }\n this.variations.push(variation);\n variationsKeys.push(this.variationsComponent().getVariationKey(options));\n }, this);\n\n _.each(_.omit(this.variationsComponent().productAttributesMap, variationsKeys), function (productId) {\n gridDeleted.push(this.prepareRowForGrid(\n _.findWhere(this.variationsComponent().variations, {\n productId: productId\n })\n ));\n }.bind(this));\n\n this.variationsExisting = gridExisting;\n this.variationsNew = gridNew;\n this.variationsDeleted = gridDeleted;\n },\n\n /**\n * Generate grid.\n */\n generateGrid: function () {\n var pageExisting = this.pagingExisting.pageSize * this.pagingExisting.current,\n pageNew = this.pagingNew.pageSize * this.pagingNew.current,\n pageDeleted = this.pagingDeleted.pageSize * this.pagingDeleted.current;\n\n this.pagingExisting.totalRecords = this.variationsExisting.length;\n this.gridExisting(this.variationsExisting.slice(pageExisting - this.pagingExisting.pageSize, pageExisting));\n\n this.pagingNew.totalRecords = this.variationsNew.length;\n this.gridNew(this.variationsNew.slice(pageNew - this.pagingNew.pageSize, pageNew));\n\n this.pagingDeleted.totalRecords = this.variationsDeleted.length;\n this.gridDeleted(this.variationsDeleted.slice(pageDeleted - this.pagingDeleted.pageSize, pageDeleted));\n },\n\n /**\n * @param {Object} variation\n * @return {Array}\n */\n prepareRowForGrid: function (variation) {\n var row = [];\n\n row.push(_.extend({\n images: []\n }, variation.images));\n row.push(variation.sku);\n row.push(variation[this.quantityFieldName]);\n _.each(variation.options, function (option) {\n row.push(option.label);\n });\n row.push(this.variationsComponent().getCurrencySymbol() + ' ' + variation.price);\n\n return row;\n },\n\n /**\n * @return {String|*}\n */\n getGridTemplate: function () {\n return this.gridTemplate;\n },\n\n /**\n * @return {*|String}\n */\n getGridId: function () {\n return _.uniqueId('grid_');\n },\n\n /**\n * @param {*} attributes\n * @return {Array}\n */\n getColumnsName: function (attributes) {\n var columns = this.attributesName.slice(0);\n\n attributes.each(function (attribute, index) {\n columns.splice(3 + index, 0, attribute.label);\n }, this);\n\n return columns;\n },\n\n /**\n * @param {Object} wizard\n */\n render: function (wizard) {\n this.wizard = wizard;\n this.sections(wizard.data.sections());\n this.attributes(wizard.data.attributes());\n this.gridNew([]);\n this.gridExisting([]);\n this.gridDeleted([]);\n this.gridExisting.columns(this.getColumnsName(this.wizard.data.attributes));\n this.gridNew.columns(this.getColumnsName(this.wizard.data.attributes));\n this.gridDeleted.columns(this.getColumnsName(this.variationsComponent().productAttributes));\n this.calculate(wizard.data.variations, wizard.data.sectionHelper);\n this.generateGrid();\n },\n\n /**\n * Force.\n */\n force: function () {\n this.variationsComponent().render(this.variations, this.attributes());\n this.modalComponent().closeModal();\n },\n\n /**\n * Back.\n */\n back: function () {\n }\n });\n});\n","Magento_ConfigurableProduct/js/variations/steps/attributes_values.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'uiComponent',\n 'jquery',\n 'ko',\n 'underscore',\n 'mageUtils',\n 'Magento_Ui/js/lib/collapsible',\n 'mage/translate'\n], function (Component, $, ko, _, utils, Collapsible) {\n 'use strict';\n\n //connect items with observableArrays\n ko.bindingHandlers.sortableList = {\n /** @inheritdoc */\n init: function (element, valueAccessor) {\n var list = valueAccessor();\n\n $(element).sortable({\n axis: 'y',\n handle: '[data-role=\"draggable\"]',\n tolerance: 'pointer',\n\n /** @inheritdoc */\n update: function (event, ui) {\n var item = ko.contextFor(ui.item[0]).$data,\n position = ko.utils.arrayIndexOf(ui.item.parent().children(), ui.item[0]);\n\n if (ko.contextFor(ui.item[0]).$index() != position) { //eslint-disable-line eqeqeq\n if (position >= 0) {\n list.remove(item);\n list.splice(position, 0, item);\n }\n ui.item.remove();\n }\n }\n });\n }\n };\n\n return Collapsible.extend({\n defaults: {\n notificationMessage: {\n text: null,\n error: null\n },\n createOptionsUrl: null,\n attributes: [],\n stepInitialized: false\n },\n\n /** @inheritdoc */\n initialize: function () {\n this._super();\n this.createAttribute = _.wrap(this.createAttribute, function () {\n var args = _.toArray(arguments),\n createAttribute = args.shift();\n\n return this.doInitSavedOptions(createAttribute.apply(this, args));\n });\n this.createAttribute = _.memoize(this.createAttribute.bind(this), _.property('id'));\n },\n\n /** @inheritdoc */\n initObservable: function () {\n this._super().observe(['attributes']);\n\n return this;\n },\n\n /**\n * Create option.\n */\n createOption: function () {\n // this - current attribute\n this.options.push({\n value: 0,\n label: '',\n id: utils.uniqueid(),\n 'attribute_id': this.id,\n 'is_new': true\n });\n },\n\n /**\n * @param {Object} option\n */\n saveOption: function (option) {\n if (!_.isEmpty(option.label)) {\n this.options.remove(option);\n this.options.push(option);\n this.chosenOptions.push(option.id);\n }\n },\n\n /**\n * @param {Object} option\n */\n removeOption: function (option) {\n this.options.remove(option);\n },\n\n /**\n * @param {String} attribute\n */\n removeAttribute: function (attribute) {\n this.attributes.remove(attribute);\n this.wizard.setNotificationMessage(\n $.mage.__('An attribute has been removed. This attribute will no longer appear in your configurations.')\n );\n },\n\n /**\n * @param {Object} attribute\n * @param {*} index\n * @return {Object}\n */\n createAttribute: function (attribute, index) {\n attribute.chosenOptions = ko.observableArray([]);\n attribute.options = ko.observableArray(_.map(attribute.options, function (option) {\n option.id = utils.uniqueid();\n\n return option;\n }));\n attribute.opened = ko.observable(this.initialOpened(index));\n attribute.collapsible = ko.observable(true);\n\n return attribute;\n },\n\n /**\n * First 3 attribute panels must be open.\n *\n * @param {Number} index\n * @return {Boolean}\n */\n initialOpened: function (index) {\n return index < 3;\n },\n\n /**\n * Save attribute.\n */\n saveAttribute: function () {\n var errorMessage = $.mage.__('Select options for all attributes or remove unused attributes.');\n\n this.attributes.each(function (attribute) {\n attribute.chosen = [];\n\n if (!attribute.chosenOptions.getLength()) {\n throw new Error(errorMessage);\n }\n attribute.chosenOptions.each(function (id) {\n attribute.chosen.push(attribute.options.findWhere({\n id: id\n }));\n });\n });\n\n if (!this.attributes().length) {\n throw new Error(errorMessage);\n }\n },\n\n /**\n * @param {Object} attribute\n */\n selectAllAttributes: function (attribute) {\n this.chosenOptions(_.pluck(attribute.options(), 'id'));\n },\n\n /**\n * @param {Object} attribute\n */\n deSelectAllAttributes: function (attribute) {\n attribute.chosenOptions.removeAll();\n },\n\n /**\n * @return {Boolean}\n */\n saveOptions: function () {\n var options = [];\n\n this.attributes.each(function (attribute) {\n attribute.chosenOptions.each(function (id) {\n var option = attribute.options.findWhere({\n id: id,\n 'is_new': true\n });\n\n if (option) {\n options.push(option);\n }\n });\n });\n\n if (!options.length) {\n return false;\n }\n $.ajax({\n type: 'POST',\n url: this.createOptionsUrl,\n data: {\n options: options\n },\n showLoader: true\n }).done(function (savedOptions) {\n this.attributes.each(function (attribute) {\n _.each(savedOptions, function (newOptionId, oldOptionId) {\n var option = attribute.options.findWhere({\n id: oldOptionId\n });\n\n if (option) {\n attribute.options.remove(option);\n option['is_new'] = false;\n option.value = newOptionId;\n attribute.options.push(option);\n }\n });\n });\n\n }.bind(this));\n },\n\n /**\n * @param {*} attributeIds\n */\n requestAttributes: function (attributeIds) {\n $.ajax({\n type: 'GET',\n url: this.optionsUrl,\n data: {\n attributes: attributeIds\n },\n showLoader: true\n }).done(function (attributes) {\n attributes = _.sortBy(attributes, function (attribute) {\n return this.wizard.data.attributesIds.indexOf(attribute.id);\n }.bind(this));\n this.attributes(_.map(attributes, this.createAttribute));\n }.bind(this));\n },\n\n /**\n * @param {*} attribute\n * @return {*}\n */\n doInitSavedOptions: function (attribute) {\n var selectedOptions, selectedOptionsIds, selectedAttribute = _.findWhere(this.initData.attributes, {\n id: attribute.id\n });\n\n if (selectedAttribute) {\n selectedOptions = _.pluck(selectedAttribute.chosen, 'value');\n selectedOptionsIds = _.pluck(_.filter(attribute.options(), function (option) {\n return _.contains(selectedOptions, option.value);\n }), 'id');\n attribute.chosenOptions(selectedOptionsIds);\n this.initData.attributes = _.without(this.initData.attributes, selectedAttribute);\n }\n\n return attribute;\n },\n\n /**\n * @param {Object} wizard\n */\n render: function (wizard) {\n this.wizard = wizard;\n this.requestAttributes(wizard.data.attributesIds());\n },\n\n /**\n * @param {Object} wizard\n */\n force: function (wizard) {\n this.saveOptions();\n this.saveAttribute(wizard);\n\n wizard.data.attributes = this.attributes;\n },\n\n /**\n * @param {Object} wizard\n */\n back: function (wizard) {\n wizard.data.attributesIds(this.attributes().pluck('id'));\n }\n });\n});\n","Magento_ConfigurableProduct/js/variations/paging/sizes.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n 'Magento_Ui/js/grid/paging/sizes'\n], function (Sizes) {\n 'use strict';\n\n return Sizes.extend({\n defaults: {\n excludedOptions: ['100', '200']\n },\n\n /**\n * @override\n */\n initialize: function () {\n this._super();\n\n this.excludedOptions.forEach(function (excludedOption) {\n delete this.options[excludedOption];\n }, this);\n this.updateArray();\n\n return this;\n }\n });\n});\n","Magento_User/app-config.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 */\nrequire.config({\n 'waitSeconds': 0,\n 'shim': {\n 'jquery/jstree/jquery.hotkeys': ['jquery'],\n 'jquery/hover-intent': ['jquery'],\n 'mage/adminhtml/backup': ['prototype'],\n 'mage/captcha': ['prototype'],\n 'mage/common': ['jquery'],\n 'mage/webapi': ['jquery'],\n 'ko': {\n exports: 'ko'\n },\n 'moment': {\n exports: 'moment'\n }\n },\n 'paths': {\n 'jquery/ui': 'jquery/jquery-ui-1.9.2',\n 'jquery/validate': 'jquery/jquery.validate',\n 'jquery/hover-intent': 'jquery/jquery.hoverIntent',\n 'jquery/file-uploader': 'jquery/fileUploader/jquery.fileupload-fp',\n 'prototype': 'prototype/prototype-amd',\n 'text': 'requirejs/text',\n 'domReady': 'requirejs/domReady',\n 'ko': 'ko/ko'\n }\n});\n\nrequire(['jquery'], function (jQuery) {\n 'use strict';\n\n jQuery.noConflict();\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_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 treeInitSelectedData: {}\n },\n\n /** @inheritdoc */\n _create: function () {\n this.element.jstree({\n plugins: ['themes', 'json_data', 'ui', 'crrm', 'types', 'vcheckbox', 'hotkeys'],\n vcheckbox: {\n 'two_state': true,\n 'real_checkboxes': true,\n\n /**\n * @param {*} n\n * @return {Array}\n */\n 'real_checkboxes_names': function (n) {\n return ['resource[]', $(n).data('id')];\n }\n },\n 'json_data': {\n data: this.options.treeInitData\n },\n ui: {\n 'select_limit': 0\n },\n hotkeys: {\n space: this._changeState,\n 'return': this._changeState\n },\n types: {\n 'types': {\n 'disabled': {\n 'check_node': false,\n 'uncheck_node': false\n }\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('loaded.jstree', $.proxy(this._checkNodes, this));\n this.element.on('click.jstree', 'a', $.proxy(this._checkNode, this));\n },\n\n /**\n * @param {jQuery.Event} event\n * @private\n */\n _checkNode: function (event) {\n event.stopPropagation();\n this.element.jstree(\n 'change_state',\n event.currentTarget,\n this.element.jstree('is_checked', event.currentTarget)\n );\n },\n\n /**\n * @private\n */\n _checkNodes: function () {\n var $items = $('[data-id=\"' + this.options.treeInitSelectedData.join('\"],[data-id=\"') + '\"]');\n\n $items.removeClass('jstree-unchecked').addClass('jstree-checked');\n $items.children(':checkbox').prop('checked', true);\n },\n\n /**\n * @return {Boolean}\n * @private\n */\n _changeState: function () {\n var element;\n\n if (this.data.ui.hovered) {\n element = this.data.ui.hovered;\n this['change_state'](element, this['is_checked'](element));\n }\n\n return false;\n }\n });\n\n return $.mage.rolesTree;\n});\n","Magento_Paypal/js/rules.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n 'uiClass',\n 'Magento_Ui/js/modal/alert'\n], function (Class, alert) {\n 'use strict';\n\n /**\n * Check is solution enabled\n *\n * @param {*} solution\n * @param {String} enabler\n * @returns {Boolean}\n */\n var isSolutionEnabled = function (solution, enabler) {\n return solution.find(enabler).val() === '1';\n },\n\n /**\n * Check is solution has related solutions enabled\n *\n * @param {Object} data\n * @returns {Boolean}\n */\n hasRelationsEnabled = function (data) {\n var name;\n\n for (name in data.argument) {\n if (\n data.solutionsElements[name] &&\n isSolutionEnabled(data.solutionsElements[name], data.enableButton)\n ) {\n return true;\n }\n }\n\n return false;\n },\n\n /**\n * Set solution select-enabler to certain option\n *\n * @param {*} solution\n * @param {String} enabler\n * @param {Boolean} enabled\n */\n setSolutionSelectEnabled = function (solution, enabler, enabled) {\n enabled = !(enabled || typeof enabled === 'undefined') ? '0' : '1';\n\n solution.find(enabler + ' option[value=' + enabled + ']')\n .prop('selected', true);\n },\n\n /**\n * Set solution property 'disabled' value\n *\n * @param {*} solution\n * @param {String} enabler\n * @param {Boolean} enabled\n */\n setSolutionPropEnabled = function (solution, enabler, enabled) {\n enabled = !(enabled || typeof enabled === 'undefined');\n\n solution.find(enabler).prop('disabled', enabled);\n },\n\n /**\n * Set/unset solution select-enabler label\n *\n * @param {*} solution\n * @param {String} enabler\n * @param {Boolean} enabled\n */\n setSolutionMarkEnabled = function (solution, enabler, enabled) {\n var solutionEnabler = solution.find('label[for=\"' + solution.find(enabler).attr('id') + '\"]');\n\n enabled || typeof enabled === 'undefined' ?\n solutionEnabler.addClass('enabled') :\n solutionEnabler.removeClass('enabled');\n },\n\n /**\n * Set/unset solution section label\n *\n * @param {*} solution\n * @param {Boolean} enabled\n */\n setSolutionSectionMarkEnabled = function (solution, enabled) {\n var solutionSection = solution.find('.section-config');\n\n enabled || typeof enabled === 'undefined' ?\n solutionSection.addClass('enabled') :\n solutionSection.removeClass('enabled');\n },\n\n /**\n * Set/unset solution section inner labels\n *\n * @param {*} solution\n * @param {Boolean} enabled\n */\n setSolutionLabelsMarkEnabled = function (solution, enabled) {\n var solutionLabels = solution.find('label.enabled');\n\n enabled || typeof enabled === 'undefined' ?\n solutionLabels.addClass('enabled') :\n solutionLabels.removeClass('enabled');\n },\n\n /**\n * Set/unset solution usedefault checkbox\n *\n * @param {*} solution\n * @param {String} enabler\n * @param {Boolean} checked\n */\n setSolutionUsedefaultEnabled = function (solution, enabler, checked) {\n checked = !(checked || typeof checked === 'undefined');\n\n solution.find('input[id=\"' + solution.find(enabler).attr('id') + '_inherit\"]')\n .prop('checked', checked);\n },\n\n /**\n * Set solution as disabled\n *\n * @param {*} solution\n * @param {String} enabler\n */\n disableSolution = function (solution, enabler) {\n setSolutionUsedefaultEnabled(solution, enabler);\n setSolutionMarkEnabled(solution, enabler, false);\n setSolutionSelectEnabled(solution, enabler, false);\n setSolutionPropEnabled(solution, enabler, false);\n },\n\n /**\n * Set solution as enabled\n *\n * @param {*} solution\n * @param {String} enabler\n */\n enableSolution = function (solution, enabler) {\n setSolutionUsedefaultEnabled(solution, enabler);\n setSolutionPropEnabled(solution, enabler);\n setSolutionSelectEnabled(solution, enabler);\n setSolutionMarkEnabled(solution, enabler);\n },\n\n /**\n * Lock/unlock solution configuration button\n *\n * @param {*} solution\n * @param {String} buttonConfiguration\n * @param {Boolean} unlock\n */\n setSolutionConfigurationUnlock = function (solution, buttonConfiguration, unlock) {\n var solutionConfiguration = solution.find(buttonConfiguration);\n\n unlock || typeof unlock === 'undefined' ?\n solutionConfiguration.removeClass('disabled').removeAttr('disabled') :\n solutionConfiguration.addClass('disabled').attr('disabled', 'disabled');\n },\n\n /**\n * Forward solution select-enabler changes\n *\n * @param {*} solution\n * @param {String} enabler\n */\n forwardSolutionChange = function (solution, enabler) {\n solution.find(enabler).change();\n },\n\n /**\n * Show/hide dependent fields\n *\n * @param {*} solution\n * @param {String} identifier\n * @param {Boolean} show\n */\n showDependsField = function (solution, identifier, show) {\n show = show || typeof show === 'undefined';\n\n solution.find(identifier).toggle(show);\n solution.find(identifier).closest('tr').toggle(show);\n solution.find(identifier).attr('disabled', !show);\n };\n\n return Class.extend({\n defaults: {\n /**\n * Payment conflicts checker\n */\n executed: false\n },\n\n /**\n * @param {*} $target\n * @param {*} $owner\n * @param {Object} data\n */\n simpleDisable: function ($target, $owner, data) {\n setSolutionSelectEnabled($target, data.enableButton, false);\n setSolutionLabelsMarkEnabled($target, false);\n setSolutionSectionMarkEnabled($target, false);\n },\n\n /**\n * @param {*} $target\n */\n simpleMarkEnable: function ($target) {\n setSolutionSectionMarkEnabled($target);\n },\n\n /**\n * @param {*} $target\n * @param {*} $owner\n * @param {Object} data\n */\n disable: function ($target, $owner, data) {\n this.simpleDisable($target, $owner, data);\n forwardSolutionChange($target, data.enableButton);\n },\n\n /**\n * @param {*} $target\n * @param {*} $owner\n * @param {Object} data\n */\n paypalExpressDisable: function ($target, $owner, data) {\n setSolutionSelectEnabled($target, data.enableButton, false);\n setSolutionLabelsMarkEnabled($target, false);\n forwardSolutionChange($target, data.enableButton);\n },\n\n /**\n * @param {*} $target\n * @param {*} $owner\n * @param {Object} data\n */\n paypalExpressLockConfiguration: function ($target, $owner, data) {\n setSolutionConfigurationUnlock($target, data.buttonConfiguration, false);\n },\n\n /**\n * @param {*} $target\n * @param {*} $owner\n * @param {Object} data\n */\n paypalExpressLockConfigurationConditional: function ($target, $owner, data) {\n if (\n !isSolutionEnabled($target, data.enableInContextPayPal) &&\n hasRelationsEnabled(data)\n ) {\n this.paypalExpressLockConfiguration($target, $owner, data);\n }\n },\n\n /**\n * @param {*} $target\n * @param {*} $owner\n * @param {Object} data\n */\n paypalExpressMarkDisable: function ($target, $owner, data) {\n if (!hasRelationsEnabled(data)) {\n this.simpleDisable($target, $owner, data);\n }\n },\n\n /**\n * @param {*} $target\n * @param {*} $owner\n * @param {Object} data\n */\n paypalExpressUnlockConfiguration: function ($target, $owner, data) {\n if (!hasRelationsEnabled(data)) {\n setSolutionConfigurationUnlock($target, data.buttonConfiguration);\n }\n },\n\n /**\n * @param {*} $target\n * @param {*} $owner\n * @param {Object} data\n */\n paypalBmlDisable: function ($target, $owner, data) {\n disableSolution($target, data.enableBmlPayPal);\n },\n\n /**\n * @param {*} $target\n * @param {*} $owner\n * @param {Object} data\n */\n paypalBmlDisableConditional: function ($target, $owner, data) {\n if (!isSolutionEnabled($target, data.enableButton)) {\n this.paypalBmlDisable($target, $owner, data);\n }\n },\n\n /**\n * @param {*} $target\n * @param {*} $owner\n * @param {Object} data\n */\n paypalBmlEnable: function ($target, $owner, data) {\n enableSolution($target, data.enableBmlPayPal);\n },\n\n /**\n * @param {*} $target\n * @param {*} $owner\n * @param {Object} data\n */\n payflowExpressDisable: function ($target, $owner, data) {\n disableSolution($target, data.enableExpress);\n },\n\n /**\n * @param {*} $target\n * @param {*} $owner\n * @param {Object} data\n */\n payflowExpressDisableConditional: function ($target, $owner, data) {\n if (\n !isSolutionEnabled($target, data.enableButton) ||\n hasRelationsEnabled(data)\n ) {\n this.payflowExpressDisable($target, $owner, data);\n forwardSolutionChange($target, data.enableExpress);\n }\n },\n\n /**\n * @param {*} $target\n * @param {*} $owner\n * @param {Object} data\n */\n payflowExpressEnable: function ($target, $owner, data) {\n enableSolution($target, data.enableExpress);\n forwardSolutionChange($target, data.enableExpress);\n },\n\n /**\n * @param {*} $target\n * @param {*} $owner\n * @param {Object} data\n */\n payflowExpressEnableConditional: function ($target, $owner, data) {\n if (hasRelationsEnabled(data)) {\n setSolutionPropEnabled($target, data.enableExpress, false);\n setSolutionSelectEnabled($target, data.enableExpress);\n setSolutionMarkEnabled($target, data.enableExpress);\n } else {\n disableSolution($target, data.enableExpress);\n }\n },\n\n /**\n * @param {*} $target\n * @param {*} $owner\n * @param {Object} data\n */\n payflowExpressLockConditional: function ($target, $owner, data) {\n if (!isSolutionEnabled($target, data.enableButton)) {\n setSolutionPropEnabled($target, data.enableExpress, false);\n }\n },\n\n /**\n * @param {*} $target\n * @param {*} $owner\n * @param {Object} data\n */\n payflowExpressUsedefaultDisable: function ($target, $owner, data) {\n setSolutionUsedefaultEnabled($target, data.enableExpress, false);\n this.payflowExpressEnable($target, $owner, data);\n forwardSolutionChange($target, data.enableExpress);\n },\n\n /**\n * @param {*} $target\n * @param {*} $owner\n * @param {Object} data\n */\n payflowExpressUsedefaultEnable: function ($target, $owner, data) {\n setSolutionUsedefaultEnabled($target, data.enableExpress);\n this.payflowExpressDisable($target, $owner, data);\n forwardSolutionChange($target, data.enableExpress);\n },\n\n /**\n * @param {*} $target\n * @param {*} $owner\n * @param {Object} data\n */\n payflowBmlDisable: function ($target, $owner, data) {\n disableSolution($target, data.enableBml);\n },\n\n /**\n * @param {*} $target\n * @param {*} $owner\n * @param {Object} data\n */\n payflowBmlDisableConditional: function ($target, $owner, data) {\n if (\n !isSolutionEnabled($target, data.enableButton) ||\n hasRelationsEnabled(data)\n ) {\n this.payflowBmlDisable($target, $owner, data);\n }\n },\n\n /**\n * @param {*} $target\n * @param {*} $owner\n * @param {Object} data\n */\n payflowBmlDisableConditionalExpress: function ($target, $owner, data) {\n if (!isSolutionEnabled($target, data.enableExpress)) {\n this.payflowBmlDisable($target, $owner, data);\n }\n },\n\n /**\n * @param {*} $target\n * @param {*} $owner\n * @param {Object} data\n */\n payflowBmlEnable: function ($target, $owner, data) {\n enableSolution($target, data.enableBml);\n },\n\n /**\n * @param {*} $target\n * @param {*} $owner\n * @param {Object} data\n */\n payflowBmlEnableConditional: function ($target, $owner, data) {\n if (hasRelationsEnabled(data)) {\n setSolutionPropEnabled($target, data.enableBml, false);\n setSolutionSelectEnabled($target, data.enableBml);\n setSolutionMarkEnabled($target, data.enableBml);\n } else {\n disableSolution($target, data.enableBml);\n }\n },\n\n /**\n * @param {*} $target\n * @param {*} $owner\n * @param {Object} data\n */\n payflowBmlLockConditional: function ($target, $owner, data) {\n if (!isSolutionEnabled($target, data.enableButton)) {\n setSolutionPropEnabled($target, data.enableBml, false);\n }\n },\n\n /**\n * @param {*} $target\n * @param {*} $owner\n * @param {Object} data\n */\n inContextEnable: function ($target, $owner, data) {\n enableSolution($target, data.enableInContextPayPal);\n },\n\n /**\n * @param {*} $target\n * @param {*} $owner\n * @param {Object} data\n */\n inContextDisable: function ($target, $owner, data) {\n disableSolution($target, data.enableInContextPayPal);\n },\n\n /**\n * @param {*} $target\n * @param {*} $owner\n * @param {Object} data\n */\n inContextShowMerchantId: function ($target, $owner, data) {\n showDependsField($target, data.dependsMerchantId);\n },\n\n /**\n * @param {*} $target\n * @param {*} $owner\n * @param {Object} data\n */\n inContextHideMerchantId: function ($target, $owner, data) {\n showDependsField($target, data.dependsMerchantId, false);\n },\n\n /**\n * @param {*} $target\n * @param {*} $owner\n * @param {Object} data\n */\n payflowShowSortOrder: function ($target, $owner, data) {\n showDependsField($target, data.dependsBmlSortOrder);\n },\n\n /**\n * @param {*} $target\n * @param {*} $owner\n * @param {Object} data\n */\n payflowHideSortOrder: function ($target, $owner, data) {\n showDependsField($target, data.dependsBmlSortOrder, false);\n },\n\n /**\n * @param {*} $target\n * @param {*} $owner\n * @param {Object} data\n */\n paypalShowSortOrder: function ($target, $owner, data) {\n showDependsField($target, data.dependsBmlApiSortOrder);\n },\n\n /**\n * @param {*} $target\n * @param {*} $owner\n * @param {Object} data\n */\n paypalHideSortOrder: function ($target, $owner, data) {\n showDependsField($target, data.dependsBmlApiSortOrder, false);\n },\n\n /**\n * @param {*} $target\n * @param {*} $owner\n * @param {Object} data\n */\n inContextActivate: function ($target, $owner, data) {\n setSolutionMarkEnabled($target, data.enableInContextPayPal);\n },\n\n /**\n * @param {*} $target\n * @param {*} $owner\n * @param {Object} data\n */\n inContextDeactivate: function ($target, $owner, data) {\n setSolutionMarkEnabled($target, data.enableInContextPayPal, false);\n },\n\n /**\n * @param {*} $target\n * @param {*} $owner\n * @param {Object} data\n */\n inContextDisableConditional: function ($target, $owner, data) {\n if (!isSolutionEnabled($target, data.enableButton)) {\n this.inContextDisable($target, $owner, data);\n }\n },\n\n /**\n * @param {*} $target\n * @param {*} $owner\n * @param {Object} data\n */\n conflict: function ($target, $owner, data) {\n var newLine = String.fromCharCode(10, 13);\n\n if (\n isSolutionEnabled($owner, data.enableButton) &&\n hasRelationsEnabled(data) &&\n !this.executed\n ) {\n this.executed = true;\n alert({\n content: 'The following error(s) occurred:' +\n newLine +\n 'Some PayPal solutions conflict.' +\n newLine +\n 'Please re-enable the previously enabled payment solutions.'\n });\n }\n },\n\n /**\n * @param {*} $target\n * @param {*} $owner\n * @param {Object} data\n */\n removeCreditOption: function ($target, $owner, data) {\n if ($target.find(data.dependsButtonLabel + ' option[value=\"credit\"]').length > 0) {\n $target.find(data.dependsButtonLabel + ' option[value=\"credit\"]').remove();\n }\n },\n\n /**\n * @param {*} $target\n * @param {*} $owner\n * @param {Object} data\n */\n addCreditOption: function ($target, $owner, data) {\n if ($target.find(data.dependsButtonLabel + ' option[value=\"credit\"]').length === 0) {\n $target.find(data.dependsButtonLabel).append('<option value=\"credit\">Credit</option>');\n }\n },\n\n /**\n * @param {*} $target\n * @param {*} $owner\n * @param {Object} data\n */\n removeCreditOptionConditional: function ($target, $owner, data) {\n if ($target.find(data.dependsDisableFundingOptions + ' option[value=\"CREDIT\"]').length === 0 ||\n $target.find(data.dependsDisableFundingOptions + ' option[value=\"CREDIT\"]:selected').length > 0\n ) {\n this.removeCreditOption($target, $owner, data);\n }\n }\n });\n});\n","Magento_Paypal/js/solution.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n 'jquery',\n 'uiClass',\n 'Magento_Paypal/js/rule',\n 'mageUtils',\n 'underscore'\n], function ($, Class, Rule, utils, _) {\n 'use strict';\n\n return Class.extend({\n defaults: {\n\n /**\n * The event corresponding to the state change\n */\n systemEvent: 'change',\n\n /**\n * The rules applied after the page is loaded\n */\n afterLoadRules: [],\n\n /**\n * An attribute of the element responsible for the activation of the payment method (data attribute)\n */\n enableButton: '[data-enable=\"payment\"]',\n\n /**\n * An attribute of the element responsible for the activation of the Payflow Express (data attribute)\n */\n enableExpress: '[data-enable=\"express\"]',\n\n /**\n * An attribute of the element responsible for the activation of the\n * PayPal Express In-Context Checkout Experience (data attribute)\n */\n enableInContextPayPal: '[data-enable=\"in-context-api\"]',\n\n /**\n * An attribute of the element responsible for the activation of the Payflow Bml (data attribute)\n */\n enableBml: '[data-enable=\"bml\"]',\n\n /**\n * An attribute of the element responsible for the activation of the PayPal Bml (data attribute)\n */\n enableBmlPayPal: '[data-enable=\"bml-api\"]',\n\n /**\n * An attribute of the element responsible for the visibility of the PayPal Merchant Id (data attribute)\n */\n dependsMerchantId: '[data-enable=\"merchant-id\"]',\n\n /**\n * An attribute of the element responsible for the visibility of the Payflow Bml Sort Order (data attribute)\n */\n dependsBmlSortOrder: '[data-enable=\"bml-sort-order\"]',\n\n /**\n * An attribute of the element responsible for the visibility of the PayPal Bml Sort Order (data attribute)\n */\n dependsBmlApiSortOrder: '[data-enable=\"bml-api-sort-order\"]',\n\n /**\n * An attribute of the element responsible for the visibility of the\n * button Label credit option (data attribute)\n */\n dependsButtonLabel: '[data-enable=\"button-label\"]',\n\n /**\n * An attribute of the element responsible for the visibility of the\n * button Label credit option on load (data attribute)\n */\n dependsDisableFundingOptions: '[data-enable=\"disable-funding-options\"]',\n\n /**\n * Templates element selectors\n */\n templates: {\n elementSelector: 'div.section-config tr[id$=\"${ $.identifier }\"]:first'\n }\n },\n\n /**\n * Constructor\n *\n * @param {Object} config\n * @param {String} identifier\n * @returns {exports.initialize}\n */\n initialize: function (config, identifier) {\n this.initConfig(config);\n this.$self = this.createElement(identifier);\n\n return this;\n },\n\n /**\n * Initialization events\n *\n * @returns {exports.initEvents}\n */\n initEvents: function () {\n _.each(this.config.events, function (elementEvents, selector) {\n\n var solution = this,\n selectorButton = solution.$self.find(selector),\n $self = solution.$self,\n events = elementEvents;\n\n selectorButton.on(solution.systemEvent, function () {\n _.each(events, function (elementEvent, name) {\n\n var predicate = elementEvent.predicate,\n result = true,\n\n /**\n * @param {Function} functionPredicate\n */\n predicateCallback = function (functionPredicate) {\n result = functionPredicate(solution, predicate.message, predicate.argument);\n\n if (result) {\n $self.trigger(name);\n } else {\n $self.trigger(predicate.event);\n }\n };\n\n if (solution.getValue($(this)) === elementEvent.value ||\n $(this).prop('multiple') && solution.checkMultiselectValue($(this), elementEvent)\n ) {\n if (predicate.name) {\n require([\n 'Magento_Paypal/js/predicate/' + predicate.name\n ], predicateCallback);\n } else {\n $self.trigger(name);\n }\n }\n }, this);\n });\n }, this);\n\n return this;\n },\n\n /**\n * @param {Object} $element\n * @returns {*}\n */\n getValue: function ($element) {\n if ($element.is(':checkbox')) {\n return $element.prop('checked') ? '1' : '0';\n }\n\n return $element.val();\n },\n\n /**\n * Check multiselect value based on include value\n *\n * @param {Object} $element\n * @param {Object} elementEvent\n * @returns {Boolean}\n */\n checkMultiselectValue: function ($element, elementEvent) {\n var isValueSelected = $.inArray(elementEvent.value, $element.val()) >= 0;\n\n if (elementEvent.include) {\n isValueSelected = (isValueSelected ? 'true' : 'false') === elementEvent.include;\n }\n\n return isValueSelected;\n },\n\n /**\n * Adding event listeners\n *\n * @returns {exports.addListeners}\n */\n addListeners: function () {\n\n _.each(this.config.relations, function (rules, targetName) {\n\n var $target = this.createElement(targetName);\n\n _.each(rules, function (instances, instanceName) {\n\n _.each(instances, function (instance) {\n var handler = new Rule({\n name: instanceName,\n $target: $target,\n $owner: this.$self,\n data: {\n buttonConfiguration: this.buttonConfiguration,\n enableButton: this.enableButton,\n enableExpress: this.enableExpress,\n enableInContextPayPal: this.enableInContextPayPal,\n enableBml: this.enableBml,\n enableBmlPayPal: this.enableBmlPayPal,\n dependsMerchantId: this.dependsMerchantId,\n dependsBmlSortOrder: this.dependsBmlSortOrder,\n dependsBmlApiSortOrder: this.dependsBmlApiSortOrder,\n dependsButtonLabel: this.dependsButtonLabel,\n dependsDisableFundingOptions: this.dependsDisableFundingOptions,\n solutionsElements: this.solutionsElements,\n argument: instance.argument\n }\n });\n\n if (instance.event === ':load') {\n this.afterLoadRules.push(handler);\n\n return;\n }\n\n this.$self.on(instance.event, _.bind(handler.apply, handler));\n }, this);\n }, this);\n }, this);\n\n return this;\n },\n\n /**\n * Create a jQuery element according to selector\n *\n * @param {String} identifier\n * @returns {*}\n */\n createElement: function (identifier) {\n if (identifier === ':self') {\n return this.$self;\n }\n\n return $(utils.template(this.templates.elementSelector, {\n 'identifier': identifier\n }));\n },\n\n /**\n * Assign solutions elements\n *\n * @param {Object} elements\n * @returns {exports.setSolutionsElements}\n */\n setSolutionsElements: function (elements) {\n this.solutionsElements = elements;\n\n return this;\n }\n });\n});\n","Magento_Paypal/js/solutions.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n 'jquery',\n 'uiClass',\n 'Magento_Paypal/js/solution',\n 'underscore'\n], function ($, Class, Solution, _) {\n 'use strict';\n\n return Class.extend({\n defaults: {\n\n /**\n * Initialized solutions\n */\n solutions: {},\n\n /**\n * The elements of created solutions\n */\n solutionsElements: {},\n\n /**\n * The selector element responsible for configuration of payment method (CSS class)\n */\n buttonConfiguration: '.button.action-configure'\n },\n\n /**\n * Constructor\n *\n * @param {Object} config\n * @returns {exports.initialize}\n */\n initialize: function (config) {\n this.initConfig(config)\n .initSolutions();\n\n return this;\n },\n\n /**\n * Initialization and configuration solutions\n *\n * @returns {exports.initSolutions}\n */\n initSolutions: function () {\n _.each(this.config.solutions, this.addSolution, this);\n this.initializeSolutions()\n .wipeButtonsConfiguration();\n _.each(this.solutions, this.applicationRules);\n\n return this;\n },\n\n /**\n * The creation and addition of the solution according to the configuration\n *\n * @param {Object} solution\n * @param {String} identifier\n */\n addSolution: function (solution, identifier) {\n this.solutions[identifier] = new Solution({\n config: solution,\n buttonConfiguration: this.buttonConfiguration\n }, identifier);\n this.solutionsElements[identifier] = this.solutions[identifier].$self;\n },\n\n /**\n * Wiping buttons configuration of the payment method\n */\n wipeButtonsConfiguration: function () {\n $(this.buttonConfiguration).removeClass('disabled')\n .removeAttr('disabled');\n },\n\n /**\n * Application of the rules\n *\n * @param {Object} solution\n */\n applicationRules: function (solution) {\n _.each(solution.afterLoadRules, function (rule) {\n rule.apply();\n });\n },\n\n /**\n * Initialize solutions\n *\n * @returns {exports.initializeSolutions}\n */\n initializeSolutions: function () {\n _.each(this.solutions, function (solution) {\n solution.setSolutionsElements(this.solutionsElements)\n .initEvents()\n .addListeners();\n }, this);\n\n return this;\n }\n });\n});\n","Magento_Paypal/js/rule.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n 'uiClass',\n 'Magento_Paypal/js/rules'\n], function (Class, Rules) {\n 'use strict';\n\n return Class.extend({\n\n /**\n * Constructor\n *\n * @param {Object} config\n * @returns {exports.initialize}\n */\n initialize: function (config) {\n this.rules = new Rules();\n this.initConfig(config);\n\n return this;\n },\n\n /**\n * To apply the rule\n */\n apply: function () {\n this.rules[this.name](this.$target, this.$owner, this.data);\n }\n });\n});\n","Magento_Paypal/js/predicate/confirm.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 function (solution, message, argument) {\n var isConfirm = false;\n\n _.every(argument, function (name) {\n if (solution.solutionsElements[name] &&\n solution.solutionsElements[name].find(solution.enableButton).val() == 1 //eslint-disable-line eqeqeq\n ) {\n isConfirm = true;\n\n return !isConfirm;\n }\n\n return !isConfirm;\n }, this);\n\n if (isConfirm) {\n return confirm(message); //eslint-disable-line no-alert\n }\n\n return true;\n };\n});\n","Magento_Paypal/js/payflowpro/vault.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/*browser:true*/\n/*global define*/\ndefine([\n 'jquery',\n 'uiComponent'\n], function ($, Class) {\n 'use strict';\n\n return Class.extend({\n defaults: {\n $selector: null,\n selector: 'edit_form'\n },\n\n /**\n * Set list of observable attributes\n * @returns {exports.initObservable}\n */\n initObservable: function () {\n var self = this;\n\n self.$selector = $('#' + self.selector);\n this._super();\n\n this.initEventHandlers();\n\n return this;\n },\n\n /**\n * Get payment code\n * @returns {String}\n */\n getCode: function () {\n return 'payflowpro';\n },\n\n /**\n * Init event handlers\n */\n initEventHandlers: function () {\n $('#' + this.container).find('[name=\"payment[token_switcher]\"]')\n .on('click', this.setPaymentDetails.bind(this));\n },\n\n /**\n * Store payment details\n */\n setPaymentDetails: function () {\n this.$selector.find('[name=\"payment[public_hash]\"]').val(this.publicHash);\n }\n });\n});\n","Magento_Variable/variables.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* global Variables, updateElementAtCursor, MagentovariablePlugin, Base64 */\ndefine([\n 'jquery',\n 'mage/backend/notification',\n 'mage/translate',\n 'wysiwygAdapter',\n 'uiRegistry',\n 'mage/apply/main',\n 'mageUtils',\n 'Magento_Variable/js/config-directive-generator',\n 'Magento_Variable/js/custom-directive-generator',\n 'Magento_Ui/js/lib/spinner',\n 'jquery/ui',\n 'prototype'\n], function (jQuery, notification, $t, wysiwyg, registry, mageApply, utils, configGenerator, customGenerator, loader) {\n 'use strict';\n\n window.Variables = {\n textareaElementId: null,\n variablesContent: null,\n dialogWindow: null,\n dialogWindowId: 'variables-chooser',\n overlayShowEffectOptions: null,\n overlayHideEffectOptions: null,\n insertFunction: 'Variables.insertVariable',\n selectedPlaceholder: null,\n isEditMode: null,\n editor: null,\n\n /**\n * Initialize Variables handler.\n *\n * @param {*} textareaElementId\n * @param {Function} insertFunction\n * @param {Object} editor\n * @param {Object} selectedPlaceholder\n */\n init: function (textareaElementId, insertFunction, editor, selectedPlaceholder) {\n if ($(textareaElementId)) {\n this.textareaElementId = textareaElementId;\n }\n\n if (insertFunction) {\n this.insertFunction = insertFunction;\n }\n\n if (selectedPlaceholder) {\n this.selectedPlaceholder = selectedPlaceholder;\n }\n\n if (editor) {\n this.editor = editor;\n }\n },\n\n /**\n * Reset data.\n */\n resetData: function () {\n this.variablesContent = null;\n this.dialogWindow = null;\n },\n\n /**\n * Open variables chooser slideout.\n *\n * @param {Object} variables\n */\n openVariableChooser: function (variables) {\n if (variables) {\n this.openDialogWindow(variables);\n }\n },\n\n /**\n * Close variables chooser slideout dialog window.\n */\n closeDialogWindow: function () {\n jQuery('#' + this.dialogWindowId).modal('closeModal');\n },\n\n /**\n * Init ui component grid on the form\n *\n * @return void\n */\n initUiGrid: function () {\n mageApply.apply(document.getElementById(this.dialogWindow));\n jQuery('#' + this.dialogWindowId).applyBindings();\n loader.get('variables_modal.variables_modal.variables').hide();\n },\n\n /**\n * Open slideout dialog window.\n *\n * @param {*} variablesContent\n * @param {Object} selectedElement\n */\n openDialogWindow: function (variablesContent, selectedElement) {\n\n var html = utils.copy(variablesContent),\n self = this;\n\n jQuery('<div id=\"' + this.dialogWindowId + '\">' + html + '</div>').modal({\n title: self.isEditMode ? $t('Edit Variable') : $t('Insert Variable'),\n type: 'slide',\n buttons: self.getButtonsConfig(self.isEditMode),\n\n /**\n * @param {jQuery.Event} e\n * @param {Object} modal\n */\n closed: function (e, modal) {\n modal.modal.remove();\n registry.get(\n 'variables_modal.variables_modal.variables.variable_selector',\n function (radioSelect) {\n radioSelect.selectedVariableCode('');\n }\n );\n }\n });\n\n this.selectedPlaceholder = selectedElement;\n\n this.addNotAvailableMessage(selectedElement);\n\n jQuery('#' + this.dialogWindowId).modal('openModal');\n\n if (typeof selectedElement !== 'undefined') {\n registry.get(\n 'variables_modal.variables_modal.variables.variable_selector',\n function (radioSelect) {\n radioSelect.selectedVariableCode(MagentovariablePlugin.getElementVariablePath(selectedElement));\n }\n );\n }\n },\n\n /**\n * Add message to slide out that variable is no longer available\n *\n * @param {Object} selectedElement\n */\n addNotAvailableMessage: function (selectedElement) {\n var name,\n msg,\n variablePath,\n $wrapper,\n lostVariableClass = 'magento-placeholder-error';\n\n if (\n this.isEditMode &&\n typeof selectedElement !== 'undefined' &&\n jQuery(selectedElement).hasClass(lostVariableClass)\n ) {\n\n variablePath = MagentovariablePlugin.getElementVariablePath(selectedElement);\n name = variablePath.split(':');\n msg = $t('The variable %1 is no longer available. Select a different variable.')\n .replace('%1', name[1]);\n\n jQuery('body').notification('clear')\n .notification('add', {\n error: true,\n message: msg,\n\n /**\n * @param {String} message\n */\n insertMethod: function (message) {\n $wrapper = jQuery('<div/>').html(message);\n\n jQuery('.modal-header .page-main-actions').after($wrapper);\n }\n });\n }\n },\n\n /**\n * Get selected variable directive.\n *\n * @returns {*}\n */\n getVariableCode: function () {\n var code = registry.get('variables_modal.variables_modal.variables.variable_selector')\n .selectedVariableCode(),\n directive = code;\n\n // processing switch here as content must contain only path/code without type\n if (typeof code !== 'undefined') {\n if (code.match('^default:')) {\n directive = configGenerator.processConfig(code.replace('default:', ''));\n } else if (code.match('^custom:')) {\n directive = customGenerator.processConfig(code.replace('custom:', ''));\n }\n\n return directive;\n }\n },\n\n /**\n * Get buttons configuration for slideout dialog.\n *\n * @param {Boolean} isEditMode\n *\n * @returns {Array}\n */\n getButtonsConfig: function (isEditMode) {\n\n var self = this,\n buttonsData;\n\n buttonsData = [\n {\n\n text: $t('Cancel'),\n 'class': 'action-scalable cancel',\n\n /**\n * @param {jQuery.Event} event\n */\n click: function (event) {\n this.closeModal(event);\n }\n },\n {\n\n text: isEditMode ? $t('Save') : $t('Insert Variable'),\n class: 'action-primary ' + (isEditMode ? '' : 'disabled'),\n attr: {\n 'id': 'insert_variable'\n },\n\n /**\n * Insert Variable\n */\n click: function () {\n self.insertVariable(self.getVariableCode());\n }\n }\n ];\n\n return buttonsData;\n },\n\n /**\n * Prepare variables row.\n *\n * @param {String} varValue\n * @param {*} varLabel\n * @return {String}\n * @deprecated This method isn't relevant after ui changes\n */\n prepareVariableRow: function (varValue, varLabel) {\n var value = varValue.replace(/\"/g, '"').replace(/'/g, '\\\\'');\n\n return '<a href=\"#\" onclick=\"' +\n this.insertFunction +\n '(\\'' +\n value +\n '\\');return false;\">' +\n varLabel +\n '</a>';\n },\n\n /**\n * Insert variable into WYSIWYG editor.\n *\n * @param {*} value\n * @return {Object}\n */\n insertVariable: function (value) {\n var windowId = this.dialogWindowId,\n textareaElm, scrollPos, wysiwygEditorFocused;\n\n jQuery('#' + windowId).modal('closeModal');\n textareaElm = $(this.textareaElementId);\n\n //to support switching between wysiwyg editors\n wysiwygEditorFocused = wysiwyg && wysiwyg.activeEditor();\n\n if (wysiwygEditorFocused && wysiwyg.get(this.textareaElementId)) {\n if (jQuery(this.selectedPlaceholder).hasClass('magento-placeholder')) {\n wysiwyg.setCaretOnElement(this.selectedPlaceholder, 1);\n }\n wysiwyg.insertContent(value, false);\n\n if (this.selectedPlaceholder && jQuery(this.selectedPlaceholder).hasClass('magento-placeholder')) {\n this.selectedPlaceholder.remove();\n }\n\n } else if (textareaElm) {\n scrollPos = textareaElm.scrollTop;\n updateElementAtCursor(textareaElm, value);\n textareaElm.focus();\n textareaElm.scrollTop = scrollPos;\n jQuery(textareaElm).change();\n textareaElm = null;\n }\n\n return this;\n }\n\n };\n\n window.MagentovariablePlugin = {\n editor: null,\n variables: null,\n textareaId: null,\n\n /**\n * Bind editor.\n *\n * @param {*} editor\n */\n setEditor: function (editor) {\n this.editor = editor;\n },\n\n /**\n * Load variables chooser.\n *\n * @param {String} url\n * @param {*} textareaId\n * @param {Object} selectedElement\n *\n * @return {Object}\n */\n loadChooser: function (url, textareaId, selectedElement) {\n this.textareaId = textareaId;\n\n new Ajax.Request(url, {\n parameters: {},\n onComplete: function (transport) {\n Variables.init(this.textareaId, 'MagentovariablePlugin.insertVariable', this.editor);\n Variables.isEditMode = !!this.getElementVariablePath(selectedElement);\n this.variablesContent = transport.responseText;\n Variables.openDialogWindow(this.variablesContent, selectedElement);\n Variables.initUiGrid();\n }.bind(this)\n });\n\n return this;\n },\n\n /**\n * Open variables chooser window.\n *\n * @param {*} variables\n * @deprecated This method isn't relevant after ui changes\n */\n openChooser: function (variables) {\n Variables.openVariableChooser(variables);\n },\n\n /**\n * Insert variable.\n *\n * @param {*} value\n *\n * @return {Object}\n */\n insertVariable: function (value) {\n if (this.textareaId) {\n Variables.init(this.textareaId);\n Variables.insertVariable(value);\n } else {\n Variables.closeDialogWindow();\n Variables.insertVariable(value);\n }\n\n return this;\n },\n\n /**\n * Get element variable path.\n *\n * @param {Object} element\n * @returns {String}\n */\n getElementVariablePath: function (element) {\n var type, code;\n\n if (!element || !jQuery(element).hasClass('magento-variable')) {\n return '';\n }\n type = jQuery(element).hasClass('magento-custom-var') ? 'custom' : 'default';\n code = Base64.idDecode(element.getAttribute('id'));\n\n return type + ':' + code;\n }\n };\n});\n","Magento_Variable/js/custom-directive-generator.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 _.extend({\n directiveTemplate: '{{customVar code=%s}}',\n\n /**\n * @param {String} path\n * @return {String}\n */\n processConfig: function (path) {\n return this.directiveTemplate.replace('%s', path);\n }\n\n });\n\n});\n","Magento_Variable/js/config-directive-generator.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 _.extend({\n directiveTemplate: '{{config path=\"%s\"}}',\n\n /**\n * @param {String} path\n * @return {String}\n */\n processConfig: function (path) {\n return this.directiveTemplate.replace('%s', path);\n\n }\n\n });\n\n});\n","Magento_Variable/js/grid/columns/radioselect.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'underscore',\n 'mage/translate',\n 'Magento_Ui/js/grid/columns/column',\n 'jquery'\n], function (_, $t, Column, jQuery) {\n 'use strict';\n\n return Column.extend({\n defaults: {\n bodyTmpl: 'Magento_Variable/grid/cells/radioselect',\n draggable: false,\n sortable: false,\n selectedVariableCode: null,\n selectedVariableType: null\n },\n\n /**\n * Calls 'initObservable' of parent\n *\n * @returns {Object} Chainable.\n */\n initObservable: function () {\n this._super().observe(['selectedVariableCode']);\n\n return this;\n },\n\n /**\n * Remove disable class from Insert Variable button after Variable has been chosen.\n *\n * @return {Boolean}\n */\n selectVariable: function () {\n if (jQuery('#insert_variable').hasClass('disabled')) {\n jQuery('#insert_variable').removeClass('disabled');\n }\n\n return true;\n }\n });\n});\n","Magefan_Blog/js/components/new-category.js":"/**\n * Copyright \u00a9 2016 Ihor Vansach (ihor@magefan.com). All rights reserved.\n * See LICENSE.txt for license details (http://opensource.org/licenses/osl-3.0.php).\n *\n * Glory to Ukraine! Glory to the heroes!\n */\n\ndefine([\n 'Magefan_Blog/js/components/new-tag'\n], function (Select) {\n 'use strict';\n\n return Select.extend({\n\n /**\n * Normalize option object.\n *\n * @param {Object} data - Option object.\n * @returns {Object}\n */\n parseData: function (data) {\n return {\n 'is_active': data.model['is_active'],\n level: data.model['level'],\n value: data.model['category_id'],\n label: data.model['title'],\n parent: data.model['parent_id']\n };\n }\n });\n});\n","Magefan_Blog/js/components/new-tag.js":"/**\n * Copyright \u00a9 2016 Ihor Vansach (ihor@magefan.com). All rights reserved.\n * See LICENSE.txt for license details (http://opensource.org/licenses/osl-3.0.php).\n *\n * Glory to Ukraine! Glory to the heroes!\n */\n\ndefine([\n 'underscore',\n 'Magento_Ui/js/form/element/ui-select'\n], function (_, Select) {\n 'use strict';\n\n function flatten(a, s, cr) {\n var i = 0, c;\n a = _.compact(a);\n cr = cr || [];\n for (i; i < a.length; i++) {\n cr.push(a[i]);\n if (a[i].hasOwnProperty(s)) {\n c = a[i][s];\n delete a[i][s];\n flatten.call(this, c, s, cr);\n }\n }\n return cr;\n }\n\n return Select.extend({\n\n /**\n * Parse data and set it to options.\n *\n * @param {Object} data - Response data object.\n * @returns {Object}\n */\n setParsed: function (data) {\n var option = this.parseData(data),\n copyOptionsTree\n if (data.error) {\n return this;\n }\n\n this.options([]);\n if (!option.parent) {\n this.cacheOptions.tree.push(option);\n copyOptionsTree = JSON.parse(JSON.stringify(this.cacheOptions.tree));\n this.cacheOptions.plain = flatten(copyOptionsTree, this.separator);\n this.options(this.cacheOptions.tree);\n } else {\n this.setOption(option);\n }\n this.set('newOption', option);\n },\n\n /**\n * Normalize option object.\n *\n * @param {Object} data - Option object.\n * @returns {Object}\n */\n parseData: function (data) {\n return {\n 'is_active': \"1\",\n level: 0,\n value: data.model['tag_id'],\n label: data.model['title'],\n parent: 0\n };\n }\n });\n});\n","Magento_Swatches/js/type-change.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\nrequire([\n 'jquery',\n 'mage/translate'\n], function ($) {\n 'use strict';\n\n $(function () {\n\n // disabled select only\n $('select#frontend_input:disabled').each(function () {\n var select = $(this),\n currentValue = select.find('option:selected').val(),\n enabledTypes = ['select', 'swatch_visual', 'swatch_text'],\n warning = $('<label>')\n .hide()\n .text($.mage.__('These changes affect all related products.'))\n .addClass('mage-error')\n .attr({\n generated: true, for: select.attr('id')\n }),\n\n /**\n * Toggle hint about changes types\n */\n toggleWarning = function () {\n if (select.find('option:selected').val() === currentValue) {\n warning.hide();\n } else {\n warning.show();\n }\n },\n\n /**\n * Remove unsupported options\n */\n removeOption = function () {\n if (!~enabledTypes.indexOf($(this).val())) {\n $(this).remove();\n }\n };\n\n // Check current type (allow only: select, swatch_visual, swatch_text)\n if (!~enabledTypes.indexOf(currentValue)) {\n return;\n }\n\n // Enable select and keep only available options (all other will be removed)\n select.removeAttr('disabled').find('option').each(removeOption);\n\n // Add warning on page and event for show/hide it\n select.after(warning).on('change', toggleWarning);\n });\n });\n});\n","Magento_Swatches/js/product-attributes.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 'Magento_Ui/js/modal/alert',\n 'Magento_Ui/js/modal/prompt',\n 'uiRegistry',\n 'collapsable'\n], function ($, alert, prompt, rg) {\n 'use strict';\n\n return function (optionConfig) {\n var activePanelClass = 'selected-type-options',\n swatchProductAttributes = {\n frontendInput: $('#frontend_input'),\n isFilterable: $('#is_filterable'),\n isFilterableInSearch: $('#is_filterable_in_search'),\n backendType: $('#backend_type'),\n usedForSortBy: $('#used_for_sort_by'),\n frontendClass: $('#frontend_class'),\n isWysiwygEnabled: $('#is_wysiwyg_enabled'),\n isHtmlAllowedOnFront: $('#is_html_allowed_on_front'),\n isRequired: $('#is_required'),\n isUnique: $('#is_unique'),\n defaultValueText: $('#default_value_text'),\n defaultValueTextarea: $('#default_value_textarea'),\n defaultValueDate: $('#default_value_date'),\n defaultValueYesno: $('#default_value_yesno'),\n isGlobal: $('#is_global'),\n useProductImageForSwatch: $('#use_product_image_for_swatch'),\n updateProductPreviewImage: $('#update_product_preview_image'),\n usedInProductListing: $('#used_in_product_listing'),\n isVisibleOnFront: $('#is_visible_on_front'),\n position: $('#position'),\n attrTabsFront: $('#product_attribute_tabs_front'),\n\n /**\n * @returns {*|jQuery|HTMLElement}\n */\n get tabsFront() {\n return this.attrTabsFront.length ? this.attrTabsFront.closest('li') : $('#front_fieldset-wrapper');\n },\n selectFields: ['boolean', 'select', 'multiselect', 'price', 'swatch_text', 'swatch_visual'],\n\n /**\n * @this {swatchProductAttributes}\n */\n toggleApplyVisibility: function (select) {\n if ($(select).val() === 1) {\n $(select).next('select').removeClass('no-display');\n $(select).next('select').removeClass('ignore-validate');\n } else {\n $(select).next('select').addClass('no-display');\n $(select).next('select').addClass('ignore-validate');\n $(select).next('select option:selected').each(function () {\n this.selected = false;\n });\n }\n },\n\n /**\n * @this {swatchProductAttributes}\n */\n checkOptionsPanelVisibility: function () {\n var selectOptionsPanel = $('#manage-options-panel'),\n visualOptionsPanel = $('#swatch-visual-options-panel'),\n textOptionsPanel = $('#swatch-text-options-panel');\n\n this._hidePanel(selectOptionsPanel);\n this._hidePanel(visualOptionsPanel);\n this._hidePanel(textOptionsPanel);\n\n switch (this.frontendInput.val()) {\n case 'swatch_visual':\n this._showPanel(visualOptionsPanel);\n break;\n\n case 'swatch_text':\n this._showPanel(textOptionsPanel);\n break;\n\n case 'select':\n case 'multiselect':\n this._showPanel(selectOptionsPanel);\n break;\n }\n },\n\n /**\n * @this {swatchProductAttributes}\n */\n bindAttributeInputType: function () {\n this.checkOptionsPanelVisibility();\n this.switchDefaultValueField();\n\n if (!~$.inArray(this.frontendInput.val(), this.selectFields)) {\n // not in array\n this.isFilterable.selectedIndex = 0;\n this._disable(this.isFilterable);\n this._disable(this.isFilterableInSearch);\n } else {\n // in array\n this._enable(this.isFilterable);\n this._enable(this.isFilterableInSearch);\n this.backendType.val('int');\n }\n\n if (this.frontendInput.val() === 'multiselect' ||\n this.frontendInput.val() === 'gallery' ||\n this.frontendInput.val() === 'textarea'\n ) {\n this._disable(this.usedForSortBy);\n } else {\n this._enable(this.usedForSortBy);\n }\n\n if (this.frontendInput.val() === 'swatch_text') {\n $('.swatch-text-field-0').addClass('required-option');\n } else {\n $('.swatch-text-field-0').removeClass('required-option');\n }\n\n this.setRowVisibility(this.isWysiwygEnabled, false);\n this.setRowVisibility(this.isHtmlAllowedOnFront, false);\n\n switch (this.frontendInput.val()) {\n case 'textarea':\n this.setRowVisibility(this.isWysiwygEnabled, true);\n\n if (this.isWysiwygEnabled.val() === '0') {\n this._enable(this.isHtmlAllowedOnFront);\n }\n this.frontendClass.val('');\n this._disable(this.frontendClass);\n break;\n\n case 'text':\n this.setRowVisibility(this.isHtmlAllowedOnFront, true);\n this._enable(this.frontendClass);\n break;\n\n case 'select':\n case 'multiselect':\n this.setRowVisibility(this.isHtmlAllowedOnFront, true);\n this.frontendClass.val('');\n this._disable(this.frontendClass);\n break;\n default:\n this.frontendClass.val('');\n this._disable(this.frontendClass);\n }\n\n this.switchIsFilterable();\n },\n\n /**\n * @this {swatchProductAttributes}\n */\n switchIsFilterable: function () {\n if (this.isFilterable.selectedIndex === 0) {\n this._disable(this.position);\n } else {\n this._enable(this.position);\n }\n },\n\n /**\n * @this {swatchProductAttributes}\n */\n switchDefaultValueField: function () {\n var currentValue = this.frontendInput.val(),\n defaultValueTextVisibility = false,\n defaultValueTextareaVisibility = false,\n defaultValueDateVisibility = false,\n defaultValueYesnoVisibility = false,\n scopeVisibility = true,\n useProductImageForSwatch = false,\n defaultValueUpdateImage = false,\n optionDefaultInputType = '',\n isFrontTabHidden = false,\n thing = this;\n\n if (!this.frontendInput.length) {\n return;\n }\n\n switch (currentValue) {\n case 'select':\n optionDefaultInputType = 'radio';\n break;\n\n case 'multiselect':\n optionDefaultInputType = 'checkbox';\n break;\n\n case 'date':\n defaultValueDateVisibility = true;\n break;\n\n case 'boolean':\n defaultValueYesnoVisibility = true;\n break;\n\n case 'textarea':\n case 'texteditor':\n defaultValueTextareaVisibility = true;\n break;\n\n case 'media_image':\n defaultValueTextVisibility = false;\n break;\n\n case 'price':\n scopeVisibility = false;\n break;\n\n case 'swatch_visual':\n useProductImageForSwatch = true;\n defaultValueUpdateImage = true;\n defaultValueTextVisibility = false;\n break;\n\n case 'swatch_text':\n useProductImageForSwatch = false;\n defaultValueUpdateImage = true;\n defaultValueTextVisibility = false;\n break;\n default:\n defaultValueTextVisibility = true;\n break;\n }\n\n delete optionConfig.hiddenFields['swatch_visual'];\n delete optionConfig.hiddenFields['swatch_text'];\n\n if (currentValue === 'media_image') {\n this.tabsFront.hide();\n this.setRowVisibility(this.isRequired, false);\n this.setRowVisibility(this.isUnique, false);\n this.setRowVisibility(this.frontendClass, false);\n } else if (optionConfig.hiddenFields[currentValue]) {\n $.each(optionConfig.hiddenFields[currentValue], function (key, option) {\n switch (option) {\n case '_front_fieldset':\n thing.tabsFront.hide();\n isFrontTabHidden = true;\n break;\n\n case '_default_value':\n defaultValueTextVisibility = false;\n defaultValueTextareaVisibility = false;\n defaultValueDateVisibility = false;\n defaultValueYesnoVisibility = false;\n break;\n\n case '_scope':\n scopeVisibility = false;\n break;\n default:\n thing.setRowVisibility($('#' + option), false);\n }\n });\n\n if (!isFrontTabHidden) {\n thing.tabsFront.show();\n }\n\n } else {\n this.tabsFront.show();\n this.showDefaultRows();\n }\n\n this.setRowVisibility(this.defaultValueText, defaultValueTextVisibility);\n this.setRowVisibility(this.defaultValueTextarea, defaultValueTextareaVisibility);\n this.setRowVisibility(this.defaultValueDate, defaultValueDateVisibility);\n this.setRowVisibility(this.defaultValueYesno, defaultValueYesnoVisibility);\n this.setRowVisibility(this.isGlobal, scopeVisibility);\n\n /* swatch attributes */\n this.setRowVisibility(this.useProductImageForSwatch, useProductImageForSwatch);\n this.setRowVisibility(this.updateProductPreviewImage, defaultValueUpdateImage);\n\n $('input[name=\\'default[]\\']').each(function () {\n $(this).attr('type', optionDefaultInputType);\n });\n },\n\n /**\n * @this {swatchProductAttributes}\n */\n showDefaultRows: function () {\n this.setRowVisibility(this.isRequired, true);\n this.setRowVisibility(this.isUnique, true);\n this.setRowVisibility(this.frontendClass, true);\n },\n\n /**\n * @param {Object} el\n * @param {Boolean} isVisible\n * @this {swatchProductAttributes}\n */\n setRowVisibility: function (el, isVisible) {\n if (isVisible) {\n el.show();\n el.closest('.field').show();\n } else {\n el.hide();\n el.closest('.field').hide();\n }\n },\n\n /**\n * @param {Object} el\n * @this {swatchProductAttributes}\n */\n _disable: function (el) {\n el.attr('disabled', 'disabled');\n },\n\n /**\n * @param {Object} el\n * @this {swatchProductAttributes}\n */\n _enable: function (el) {\n if (!el.attr('readonly')) {\n el.removeAttr('disabled');\n }\n },\n\n /**\n * @param {Object} el\n * @this {swatchProductAttributes}\n */\n _showPanel: function (el) {\n el.closest('.fieldset').show();\n el.addClass(activePanelClass);\n this._render(el.attr('id'));\n },\n\n /**\n * @param {Object} el\n * @this {swatchProductAttributes}\n */\n _hidePanel: function (el) {\n el.closest('.fieldset').hide();\n el.removeClass(activePanelClass);\n },\n\n /**\n * @param {String} id\n * @this {swatchProductAttributes}\n */\n _render: function (id) {\n rg.get(id, function () {\n $('#' + id).trigger('render');\n });\n },\n\n /**\n * @param {String} promptMessage\n * @this {swatchProductAttributes}\n */\n saveAttributeInNewSet: function (promptMessage) {\n\n prompt({\n content: promptMessage,\n actions: {\n\n /**\n * @param {String} val\n * @this {actions}\n */\n confirm: function (val) {\n var rules = ['required-entry', 'validate-no-html-tags'],\n newAttributeSetNameInputId = $('#new_attribute_set_name'),\n editForm = $('#edit_form'),\n newAttributeSetName = val,\n i;\n\n if (!newAttributeSetName) {\n return;\n }\n\n for (i = 0; i < rules.length; i++) {\n if (!$.validator.methods[rules[i]](newAttributeSetName)) {\n alert({\n content: $.validator.messages[rules[i]]\n });\n\n return;\n }\n }\n\n if (newAttributeSetNameInputId.length) {\n newAttributeSetNameInputId.val(newAttributeSetName);\n } else {\n editForm.append(new Element('input', {\n type: 'hidden',\n id: newAttributeSetNameInputId,\n name: 'new_attribute_set_name',\n value: newAttributeSetName\n })\n );\n }\n // Temporary solution will replaced after refactoring of attributes functionality\n editForm.triggerHandler('save');\n }\n }\n });\n }\n };\n\n $(function () {\n var editForm = $('#edit_form'),\n swatchVisualPanel = $('#swatch-visual-options-panel'),\n swatchTextPanel = $('#swatch-text-options-panel'),\n tableBody = $(),\n activePanel = $();\n\n $('#frontend_input').bind('change', function () {\n swatchProductAttributes.bindAttributeInputType();\n });\n $('#is_filterable').bind('change', function () {\n swatchProductAttributes.switchIsFilterable();\n });\n\n swatchProductAttributes.bindAttributeInputType();\n\n // @todo: refactor collapsible component\n $('.attribute-popup .collapse, [data-role=\"advanced_fieldset-content\"]')\n .collapsable()\n .collapse('hide');\n\n editForm.on('beforeSubmit', function () {\n var optionContainer, optionsValues;\n\n activePanel = swatchTextPanel.hasClass(activePanelClass) ? swatchTextPanel : swatchVisualPanel;\n optionContainer = activePanel.find('table tbody');\n\n if (activePanel.hasClass(activePanelClass)) {\n optionsValues = $.map(\n optionContainer.find('tr'),\n function (row) {\n return $(row).find('input, select, textarea').serialize();\n }\n );\n $('<input>')\n .attr({\n type: 'hidden',\n name: 'serialized_options'\n })\n .val(JSON.stringify(optionsValues))\n .prependTo(editForm);\n }\n\n tableBody = optionContainer.detach();\n });\n\n editForm.on('afterValidate.error highlight.validate', function () {\n if (activePanel.hasClass(activePanelClass)) {\n activePanel.find('table').append(tableBody);\n $('input[name=\"serialized_options\"]').remove();\n }\n });\n });\n\n window.saveAttributeInNewSet = swatchProductAttributes.saveAttributeInNewSet;\n window.toggleApplyVisibility = swatchProductAttributes.toggleApplyVisibility;\n };\n});\n","Magento_Swatches/js/visual.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* global $break $ $$ FORM_KEY */\n\n/**\n * @api\n */\ndefine([\n 'jquery',\n 'mage/template',\n 'uiRegistry',\n 'jquery/colorpicker/js/colorpicker',\n 'prototype',\n 'jquery/ui'\n], function (jQuery, mageTemplate, rg) {\n 'use strict';\n\n return function (config) {\n var swatchOptionVisualDefaultInputType = 'radio',\n swatchVisualOption = {\n table: $('swatch-visual-options-table'),\n itemCount: 0,\n totalItems: 0,\n rendered: 0,\n isReadOnly: config.isReadOnly,\n template: mageTemplate('#swatch-visual-row-template'),\n\n /**\n * Add new option using template\n *\n * @param {Object} data\n * @param {Object} render\n */\n add: function (data, render) {\n var isNewOption = false,\n element;\n\n if (typeof data.id == 'undefined') {\n data = {\n 'id': 'option_' + this.itemCount,\n 'sort_order': this.itemCount + 1,\n 'empty_class': 'unavailable'\n };\n isNewOption = true;\n } else if (data.defaultswatch0 === '') {\n data['empty_class'] = 'unavailable';\n }\n\n if (!data.intype) {\n data.intype = swatchOptionVisualDefaultInputType;\n }\n\n element = this.template({\n data: data\n });\n\n if (isNewOption && !this.isReadOnly) {\n this.enableNewOptionDeleteButton(data.id);\n }\n this.itemCount++;\n this.totalItems++;\n this.elements += element;\n\n if (render) {\n this.render();\n }\n },\n\n /**\n * ColorPicker initialization process\n */\n initColorPicker: function () {\n var element = this,\n hiddenColorPicker = !jQuery(element).data('colorpickerId');\n\n jQuery(this).ColorPicker({\n\n /**\n * ColorPicker onShow action\n */\n onShow: function () {\n var color = jQuery(element).parent().parent().prev().prev('input').val(),\n menu = jQuery(this).parents('.swatch_sub-menu_container');\n\n menu.hide();\n jQuery(element).ColorPickerSetColor(color);\n },\n\n /**\n * ColorPicker onSubmit action\n *\n * @param {String} hsb\n * @param {String} hex\n * @param {String} rgb\n * @param {String} el\n */\n onSubmit: function (hsb, hex, rgb, el) {\n var container = jQuery(el).parent().parent().prev();\n\n jQuery(el).ColorPickerHide();\n container.parent().removeClass('unavailable');\n container.prev('input').val('#' + hex);\n container.css('background', '#' + hex);\n }\n });\n\n if (hiddenColorPicker) {\n jQuery(this).ColorPickerShow();\n }\n },\n\n /**\n * Remove action\n *\n * @param {Object} event\n */\n remove: function (event) {\n var element = $(Event.findElement(event, 'tr')),\n elementFlags; // !!! Button already have table parent in safari\n\n // Safari workaround\n element.ancestors().each(function (parentItem) {\n if (parentItem.hasClassName('option-row')) {\n element = parentItem;\n throw $break;\n } else if (parentItem.hasClassName('box')) {\n throw $break;\n }\n });\n\n if (element) {\n elementFlags = element.getElementsByClassName('delete-flag');\n\n if (elementFlags[0]) {\n elementFlags[0].value = 1;\n }\n\n element.addClassName('no-display');\n element.addClassName('template');\n element.hide();\n this.totalItems--;\n this.updateItemsCountField();\n }\n },\n\n /**\n * Update items count field\n */\n updateItemsCountField: function () {\n $('swatch-visual-option-count-check').value = this.totalItems > 0 ? '1' : '';\n },\n\n /**\n * Enable delete button for new option\n *\n * @param {String} id\n */\n enableNewOptionDeleteButton: function (id) {\n $$('#delete_button_swatch_container_' + id + ' button').each(function (button) {\n button.enable();\n button.removeClassName('disabled');\n });\n },\n\n /**\n * Bind remove button\n */\n bindRemoveButtons: function () {\n jQuery('#swatch-visual-options-panel').on('click', '.delete-option', this.remove.bind(this));\n },\n\n /**\n * Render options\n */\n render: function () {\n Element.insert($$('[data-role=swatch-visual-options-container]')[0], this.elements);\n this.elements = '';\n },\n\n /**\n * Render elements with delay (performance fix)\n *\n * @param {Object} data\n * @param {Number} from\n * @param {Number} step\n * @param {Number} delay\n * @returns {Boolean}\n */\n renderWithDelay: function (data, from, step, delay) {\n var arrayLength = data.length,\n len;\n\n for (len = from + step; from < len && from < arrayLength; from++) {\n this.add(data[from]);\n }\n this.render();\n\n if (from === arrayLength) {\n this.updateItemsCountField();\n this.rendered = 1;\n jQuery('body').trigger('processStop');\n\n return true;\n }\n setTimeout(this.renderWithDelay.bind(this, data, from, step, delay), delay);\n },\n\n /**\n * Ignore validate action\n */\n ignoreValidate: function () {\n var ignore = '.ignore-validate input, ' +\n '.ignore-validate select, ' +\n '.ignore-validate textarea';\n\n jQuery('#edit_form').data('validator').settings.forceIgnore = ignore;\n }\n };\n\n if ($('add_new_swatch_visual_option_button')) {\n Event.observe(\n 'add_new_swatch_visual_option_button',\n 'click',\n swatchVisualOption.add.bind(swatchVisualOption, {}, true)\n );\n }\n\n jQuery('#swatch-visual-options-panel').on('render', function () {\n swatchVisualOption.ignoreValidate();\n\n if (swatchVisualOption.rendered) {\n return false;\n }\n jQuery('body').trigger('processStart');\n swatchVisualOption.renderWithDelay(config.attributesData, 0, 100, 300);\n swatchVisualOption.bindRemoveButtons();\n jQuery('#swatch-visual-options-panel').on(\n 'click',\n '.colorpicker_handler',\n swatchVisualOption.initColorPicker\n );\n });\n jQuery('body').on('click', function (event) {\n var element = jQuery(event.target);\n\n if (\n element.parents('.swatch_sub-menu_container').length === 1 ||\n element.next('div.swatch_sub-menu_container').length === 1\n ) {\n return true;\n }\n jQuery('.swatch_sub-menu_container').hide();\n });\n\n if (config.isSortable) {\n jQuery(function ($) {\n $('[data-role=swatch-visual-options-container]').sortable({\n distance: 8,\n tolerance: 'pointer',\n cancel: 'input, button',\n axis: 'y',\n\n /**\n * Update component\n */\n update: function () {\n $('[data-role=swatch-visual-options-container] [data-role=order]').each(\n function (index, element) {\n $(element).val(index + 1);\n }\n );\n }\n });\n });\n }\n\n window.swatchVisualOption = swatchVisualOption;\n window.swatchOptionVisualDefaultInputType = swatchOptionVisualDefaultInputType;\n\n rg.set('swatch-visual-options-panel', swatchVisualOption);\n\n jQuery(function ($) {\n\n var swatchComponents = {\n\n /**\n * div wrapper for to hide all evement\n */\n wrapper: null,\n\n /**\n * iframe component to perform file upload without page reload\n */\n iframe: null,\n\n /**\n * form component for upload image\n */\n form: null,\n\n /**\n * Input file component for upload image\n */\n inputFile: null,\n\n /**\n * Create swatch component for upload files\n *\n * @this {swatchComponents}\n * @public\n */\n create: function () {\n this.wrapper = $('<div>').css({\n display: 'none'\n }).appendTo($('body'));\n\n this.iframe = $('<iframe />', {\n id: 'upload_iframe',\n name: 'upload_iframe'\n }).appendTo(this.wrapper);\n\n this.form = $('<form />', {\n id: 'swatch_form_image_upload',\n name: 'swatch_form_image_upload',\n target: 'upload_iframe',\n method: 'post',\n enctype: 'multipart/form-data',\n class: 'ignore-validate',\n action: config.uploadActionUrl\n }).appendTo(this.wrapper);\n\n this.inputFile = $('<input />', {\n type: 'file',\n name: 'datafile',\n class: 'swatch_option_file'\n }).appendTo(this.form);\n\n $('<input />', {\n type: 'hidden',\n name: 'form_key',\n value: FORM_KEY\n }).appendTo(this.form);\n }\n };\n\n /**\n * Create swatch components\n */\n swatchComponents.create();\n\n /**\n * Register event for swatch input[type=file] change\n */\n swatchComponents.inputFile.change(function () {\n var container = $('#' + $(this).attr('data-called-by')).parents().eq(2).children('.swatch_window'),\n\n /**\n * @this {iframe}\n */\n iframeHandler = function () {\n var imageParams = $.parseJSON($(this).contents().find('body').html()),\n fullMediaUrl = imageParams['swatch_path'] + imageParams['file_path'];\n\n container.prev('input').val(imageParams['file_path']);\n container.css({\n 'background-image': 'url(' + fullMediaUrl + ')',\n 'background-size': 'cover'\n });\n container.parent().removeClass('unavailable');\n };\n\n swatchComponents.iframe.off('load');\n swatchComponents.iframe.load(iframeHandler);\n swatchComponents.form.submit();\n $(this).val('');\n });\n\n /**\n * Register event for choose \"upload image\" option\n */\n $(document).on('click', '.btn_choose_file_upload', function () {\n swatchComponents.inputFile.attr('data-called-by', $(this).attr('id'));\n swatchComponents.inputFile.click();\n });\n\n /**\n * Register event for remove option\n */\n $(document).on('click', '.btn_remove_swatch', function () {\n var optionPanel = $(this).parents().eq(2);\n\n optionPanel.children('input').val('');\n optionPanel.children('.swatch_window').css('background', '');\n\n optionPanel.addClass('unavailable');\n\n jQuery('.swatch_sub-menu_container').hide();\n });\n\n /**\n * Toggle color upload chooser\n */\n $(document).on('click', '.swatch_window', function () {\n $(this).next('div').toggle();\n });\n });\n };\n});\n","Magento_Swatches/js/text.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* global $break $ $$ */\n\n/**\n * @api\n */\ndefine([\n 'jquery',\n 'mage/template',\n 'uiRegistry',\n 'jquery/ui',\n 'prototype'\n], function (jQuery, mageTemplate, rg) {\n 'use strict';\n\n return function (config) {\n var swatchOptionTextDefaultInputType = 'radio',\n swatchTextOption = {\n table: $('swatch-text-options-table'),\n itemCount: 0,\n totalItems: 0,\n rendered: 0,\n isReadOnly: config.isReadOnly,\n template: mageTemplate('#swatch-text-row-template'),\n\n /**\n * Add option\n *\n * @param {Object} data\n * @param {Object} render\n */\n add: function (data, render) {\n var isNewOption = false,\n element;\n\n if (typeof data.id == 'undefined') {\n data = {\n 'id': 'option_' + this.itemCount,\n 'sort_order': this.itemCount + 1\n };\n isNewOption = true;\n }\n\n if (!data.intype) {\n data.intype = swatchOptionTextDefaultInputType;\n }\n\n element = this.template({\n data: data\n });\n\n if (isNewOption && !this.isReadOnly) {\n this.enableNewOptionDeleteButton(data.id);\n }\n this.itemCount++;\n this.totalItems++;\n this.elements += element;\n\n if (render) {\n this.render();\n }\n },\n\n /**\n * Remove option\n *\n * @param {Object} event\n */\n remove: function (event) {\n var element = $(Event.findElement(event, 'tr')),\n elementFlags; // !!! Button already have table parent in safari\n\n // Safari workaround\n element.ancestors().each(function (parentItem) {\n if (parentItem.hasClassName('option-row')) {\n element = parentItem;\n throw $break;\n } else if (parentItem.hasClassName('box')) {\n throw $break;\n }\n });\n\n if (element) {\n elementFlags = element.getElementsByClassName('delete-flag');\n\n if (elementFlags[0]) {\n elementFlags[0].value = 1;\n }\n\n element.addClassName('no-display');\n element.addClassName('template');\n element.hide();\n this.totalItems--;\n this.updateItemsCountField();\n }\n },\n\n /**\n * Update items count field\n */\n updateItemsCountField: function () {\n $('swatch-text-option-count-check').value = this.totalItems > 0 ? '1' : '';\n },\n\n /**\n * Enable delete button for new option\n *\n * @param {String} id\n */\n enableNewOptionDeleteButton: function (id) {\n $$('#delete_button_swatch_container_' + id + ' button').each(function (button) {\n button.enable();\n button.removeClassName('disabled');\n });\n },\n\n /**\n * Bind remove button\n */\n bindRemoveButtons: function () {\n jQuery('#swatch-text-options-panel').on('click', '.delete-option', this.remove.bind(this));\n },\n\n /**\n * Render action\n */\n render: function () {\n Element.insert($$('[data-role=swatch-text-options-container]')[0], this.elements);\n this.elements = '';\n },\n\n /**\n * Render action with delay (performance fix)\n *\n * @param {Object} data\n * @param {Number} from\n * @param {Number} step\n * @param {Number} delay\n * @returns {Boolean}\n */\n renderWithDelay: function (data, from, step, delay) {\n var arrayLength = data.length,\n len;\n\n for (len = from + step; from < len && from < arrayLength; from++) {\n this.add(data[from]);\n }\n this.render();\n\n if (from === arrayLength) {\n this.updateItemsCountField();\n this.rendered = 1;\n jQuery('body').trigger('processStop');\n\n return true;\n }\n setTimeout(this.renderWithDelay.bind(this, data, from, step, delay), delay);\n },\n\n /**\n * Ignore validate action\n */\n ignoreValidate: function () {\n var ignore = '.ignore-validate input, ' +\n '.ignore-validate select, ' +\n '.ignore-validate textarea';\n\n jQuery('#edit_form').data('validator').settings.forceIgnore = ignore;\n }\n };\n\n if ($('add_new_swatch_text_option_button')) {\n Event.observe(\n 'add_new_swatch_text_option_button',\n 'click',\n swatchTextOption.add.bind(swatchTextOption, true)\n );\n }\n jQuery('#swatch-text-options-panel').on('render', function () {\n swatchTextOption.ignoreValidate();\n\n if (swatchTextOption.rendered) {\n return false;\n }\n jQuery('body').trigger('processStart');\n swatchTextOption.renderWithDelay(config.attributesData, 0, 100, 300);\n swatchTextOption.bindRemoveButtons();\n });\n\n if (config.isSortable) {\n jQuery(function ($) {\n $('[data-role=swatch-text-options-container]').sortable({\n distance: 8,\n tolerance: 'pointer',\n cancel: 'input, button',\n axis: 'y',\n\n /**\n * Update components\n */\n update: function () {\n $('[data-role=swatch-text-options-container] [data-role=order]').each(\n function (index, element) {\n $(element).val(index + 1);\n }\n );\n }\n });\n });\n }\n\n jQuery(document).ready(function () {\n if (jQuery('#frontend_input').val() !== 'swatch_text') {\n jQuery('.swatch-text-field-0').removeClass('required-option');\n }\n });\n\n window.swatchTextOption = swatchTextOption;\n window.swatchOptionTextDefaultInputType = swatchOptionTextDefaultInputType;\n\n rg.set('swatch-text-options-panel', swatchTextOption);\n };\n});\n","Magento_Swatches/js/form/element/swatch-visual.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* global $break $ FORM_KEY */\n\n/**\n * @api\n */\ndefine([\n 'underscore',\n 'Magento_Ui/js/lib/view/utils/async',\n 'mage/template',\n 'uiRegistry',\n 'prototype',\n 'Magento_Ui/js/form/element/abstract',\n 'jquery/colorpicker/js/colorpicker',\n 'jquery/ui'\n], function (_, jQuery, mageTemplate, rg, prototype, Abstract) {\n 'use strict';\n\n /**\n * Former implementation.\n *\n * @param {*} value\n * @param {Object} container\n * @param {String} uploadUrl\n * @param {String} elementName\n */\n function oldCode(value, container, uploadUrl, elementName) {\n var swatchVisualOption = {\n itemCount: 0,\n totalItems: 0,\n rendered: 0,\n isReadOnly: false,\n\n /**\n * Initialize.\n */\n initialize: function () {\n if (_.isEmpty(value)) {\n container.addClassName('unavailable');\n }\n\n jQuery(container).on(\n 'click',\n '.colorpicker_handler',\n this.initColorPicker\n );\n },\n\n /**\n * ColorPicker initialization process\n */\n initColorPicker: function () {\n var element = this,\n hiddenColorPicker = !jQuery(element).data('colorpickerId');\n\n jQuery(this).ColorPicker({\n\n /**\n * ColorPicker onShow action\n */\n onShow: function () {\n var color = jQuery(element).parent().parent().prev().prev('input').val(),\n menu = jQuery(this).parents('.swatch_sub-menu_container');\n\n menu.hide();\n jQuery(element).ColorPickerSetColor(color);\n },\n\n /**\n * ColorPicker onSubmit action\n *\n * @param {String} hsb\n * @param {String} hex\n * @param {String} rgb\n * @param {String} el\n */\n onSubmit: function (hsb, hex, rgb, el) {\n var localContainer = jQuery(el).parent().parent().prev();\n\n jQuery(el).ColorPickerHide();\n localContainer.parent().removeClass('unavailable');\n localContainer.prev('input').val('#' + hex).trigger('change');\n localContainer.css('background', '#' + hex);\n }\n });\n\n if (hiddenColorPicker) {\n jQuery(this).ColorPickerShow();\n }\n },\n\n /**\n * Remove action\n *\n * @param {Object} event\n */\n remove: function (event) {\n var element = $(Event.findElement(event, 'tr')),\n elementFlags; // !!! Button already have table parent in safari\n\n // Safari workaround\n element.ancestors().each(function (parentItem) {\n if (parentItem.hasClassName('option-row')) {\n element = parentItem;\n throw $break;\n } else if (parentItem.hasClassName('box')) {\n throw $break;\n }\n });\n\n if (element) {\n elementFlags = element.getElementsByClassName('delete-flag');\n\n if (elementFlags[0]) {\n elementFlags[0].value = 1;\n }\n\n element.addClassName('no-display');\n element.addClassName('template');\n element.hide();\n this.totalItems--;\n this.updateItemsCountField();\n }\n },\n\n /**\n * Update items count field\n */\n updateItemsCountField: function () {\n $('swatch-visual-option-count-check').value = this.totalItems > 0 ? '1' : '';\n }\n };\n\n //swatchVisualOption.initColorPicker();\n\n jQuery('body').on('click', function (event) {\n var element = jQuery(event.target);\n\n if (\n element.parents('.swatch_sub-menu_container').length === 1 ||\n element.next('div.swatch_sub-menu_container').length === 1\n ) {\n return true;\n }\n jQuery('.swatch_sub-menu_container').hide();\n });\n\n jQuery(function ($) {\n\n var swatchComponents = {\n\n /**\n * div wrapper for to hide all evement\n */\n wrapper: null,\n\n /**\n * iframe component to perform file upload without page reload\n */\n iframe: null,\n\n /**\n * form component for upload image\n */\n form: null,\n\n /**\n * Input file component for upload image\n */\n inputFile: null,\n\n /**\n * Create swatch component for upload files\n *\n * @this {swatchComponents}\n * @public\n */\n create: function () {\n this.wrapper = $('<div>').css({\n display: 'none'\n }).appendTo($('body'));\n\n this.iframe = $('<iframe />', {\n name: 'upload_iframe_' + elementName\n }).appendTo(this.wrapper);\n\n this.form = $('<form />', {\n name: 'swatch_form_image_upload_' + elementName,\n target: 'upload_iframe_' + elementName,\n method: 'post',\n enctype: 'multipart/form-data',\n class: 'ignore-validate',\n action: uploadUrl\n }).appendTo(this.wrapper);\n\n this.inputFile = $('<input />', {\n type: 'file',\n name: 'datafile',\n class: 'swatch_option_file'\n }).appendTo(this.form);\n\n $('<input />', {\n type: 'hidden',\n name: 'form_key',\n value: FORM_KEY\n }).appendTo(this.form);\n }\n };\n\n swatchVisualOption.initialize();\n\n /**\n * Create swatch components\n */\n swatchComponents.create();\n\n /**\n * Register event for swatch input[type=file] change\n */\n swatchComponents.inputFile.change(function () {\n var localContainer = $('.' + $(this).attr('data-called-by')).parents().eq(2).children('.swatch_window'),\n\n /**\n * @this {iframe}\n */\n iframeHandler = function () {\n var imageParams = $.parseJSON($(this).contents().find('body').html()),\n fullMediaUrl = imageParams['swatch_path'] + imageParams['file_path'];\n\n localContainer.prev('input').val(imageParams['file_path']).trigger('change');\n localContainer.css({\n 'background-image': 'url(' + fullMediaUrl + ')',\n 'background-size': 'cover'\n });\n localContainer.parent().removeClass('unavailable');\n };\n\n swatchComponents.iframe.off('load');\n swatchComponents.iframe.load(iframeHandler);\n swatchComponents.form.submit();\n $(this).val('');\n });\n\n /**\n * Register event for choose \"upload image\" option\n */\n $(container).on('click', '.btn_choose_file_upload', function () {\n swatchComponents.inputFile.attr('data-called-by', $(this).data('class'));\n swatchComponents.inputFile.click();\n });\n\n /**\n * Register event for remove option\n */\n $(container).on('click', '.btn_remove_swatch', function () {\n var optionPanel = $(this).parents().eq(2);\n\n optionPanel.children('input').val('').trigger('change');\n optionPanel.children('.swatch_window').css('background', '');\n optionPanel.addClass('unavailable');\n jQuery('.swatch_sub-menu_container').hide();\n });\n\n /**\n * Toggle color upload chooser\n */\n $(container).on('click', '.swatch_window', function () {\n jQuery('.swatch_sub-menu_container').hide();\n $(this).next('div').toggle();\n });\n });\n }\n\n return Abstract.extend({\n defaults: {\n elementId: 0,\n prefixName: '',\n prefixElementName: '',\n elementName: '',\n value: '',\n uploadUrl: ''\n },\n\n /**\n * Parses options and merges the result with instance\n *\n * @returns {Object} Chainable.\n */\n initConfig: function () {\n this._super();\n\n this.configureDataScope();\n\n return this;\n },\n\n /**\n * Initialize.\n *\n * @returns {Object} Chainable.\n */\n initialize: function () {\n this._super()\n .initOldCode()\n .on('value', this.onChangeColor.bind(this));\n\n return this;\n },\n\n /**\n * Handler function that execute when color changes.\n *\n * @param {String} data - color\n */\n onChangeColor: function (data) {\n if (!data) {\n jQuery('.' + this.elementName).parent().removeClass('unavailable');\n }\n },\n\n /**\n * Initialize wrapped former implementation.\n *\n * @returns {Object} Chainable.\n */\n initOldCode: function () {\n jQuery.async('.' + this.elementName, this.name, function (elem) {\n oldCode(this.value(), elem.parentElement, this.uploadUrl, this.elementName);\n }.bind(this));\n\n return this;\n },\n\n /**\n * Configure data scope.\n */\n configureDataScope: function () {\n var recordId, prefixName;\n\n // Get recordId\n recordId = this.parentName.split('.').last();\n\n prefixName = this.dataScopeToHtmlArray(this.prefixName);\n this.elementName = this.prefixElementName + recordId;\n\n this.inputName = prefixName + '[' + this.elementName + ']';\n this.exportDataLink = 'data.' + this.prefixName + '.' + this.elementName;\n this.exports.value = this.provider + ':' + this.exportDataLink;\n },\n\n /** @inheritdoc */\n destroy: function () {\n this._super();\n\n this.source.remove(this.exportDataLink);\n },\n\n /**\n * Get HTML array from data scope.\n *\n * @param {String} dataScopeString\n * @returns {String}\n */\n dataScopeToHtmlArray: function (dataScopeString) {\n var dataScopeArray, dataScope, reduceFunction;\n\n /**\n * Add new level of nesting.\n *\n * @param {String} prev\n * @param {String} curr\n * @returns {String}\n */\n reduceFunction = function (prev, curr) {\n return prev + '[' + curr + ']';\n };\n\n dataScopeArray = dataScopeString.split('.');\n\n dataScope = dataScopeArray.shift();\n dataScope += dataScopeArray.reduce(reduceFunction, '');\n\n return dataScope;\n }\n });\n});\n","Amazon_Core/js/simplepath.js":"/**\n * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\").\n * You may not use this file except in compliance with the License.\n * A copy of the License is located at\n *\n * http://aws.amazon.com/apache2.0\n *\n * or in the \"license\" file accompanying this file. This file is distributed\n * on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either\n * express or implied. See the License for the specific language governing\n * permissions and limitations under the License.\n */\n/*browser:true*/\n/*global define*/\ndefine(\n [\n 'jquery',\n 'uiComponent',\n 'mage/translate',\n 'jquery/ui',\n 'jquery/validate'\n ],\n function ($, Class, $t) {\n 'use strict';\n var pollTimer, windowOpen = false;\n\n return Class.extend({\n\n defaults: {\n $amazonFields: null,\n $amazonCredentialJson: null,\n $amazonSpBack: null,\n $amazonMerchantId: null,\n selector: 'amazon_payment',\n $container: null,\n pollInterval: 1500,\n $form: null,\n apSimplePathSelector: '#amazon_simplepath',\n apSimplePathBackSelector: '#amazon_simplepath_back',\n },\n\n /**\n * Set list of observable attributes\n * @returns {exports.initObservable}\n */\n initObservable: function () {\n var self = this;\n\n self.$amazonSimplepath = $(self.apSimplePathSelector);\n self.$amazonFields = $('#payment_' + self.getCountry() + '_' + self.selector + ' .form-list');\n self.$amazonCredentialsHeader = $('#payment_' + self.getCountry() + '_' + self.selector\n + '_credentials-head');\n self.$amazonCredentialJson = $('#payment_' + self.getCountry() + '_' + self.selector\n + '_credentials_credentials_json');\n self.$amazonMerchantId = $('#payment_' + self.getCountry() + '_' + self.selector\n + '_credentials_merchant_id').val();\n self.$amazonSpBack = $(self.apSimplePathBackSelector);\n self.$container = $(self.apSimplePathSelector);\n\n if (this.isMultiCurrencyRegion) {\n $('#row_payment_' + self.getCountry() + '_amazon_payment_advanced_sales_options_multicurrency').show();\n $('#row_payment_other_amazon_payment_advanced_sales_options_multicurrency').show();\n }\n else {\n $('#row_payment_' + self.getCountry() + '_amazon_payment_advanced_sales_options_multicurrency').hide();\n $('#row_payment_other_amazon_payment_advanced_sales_options_multicurrency').hide();\n }\n \n if (self.$amazonMerchantId) {\n self.hideAmazonConfig();\n }\n else {\n self.showAmazonConfig();\n }\n\n if (!self.$form) {\n self.generateSimplePathForm();\n }\n\n self._super();\n\n self.initEventHandlers();\n\n return self;\n },\n\n /**\n * Init event handlers\n */\n initEventHandlers: function () {\n var self = this;\n\n self.$amazonSpBack.click(function () {\n self.showAmazonConfig();\n return false;\n });\n\n $('#simplepath-skip').click(function () {\n self.hideAmazonConfig();\n return false;\n });\n\n $('#simplepath_form').on('submit', function () {\n self.setupWindowLaunch();\n });\n\n self.$amazonCredentialJson.on('input', function () {\n self.updateCredentials(self);\n });\n },\n\n /**\n * Detects when a properly formatted JSON block is pasted into the Credentials JSON field\n * and auto populates specified fields.\n *\n * @param self\n */\n updateCredentials: function (self) {\n var elJson = self.$amazonCredentialJson.val(), obj = null, success = true, item = null;\n\n try {\n obj = $.parseJSON($.trim(elJson));\n }\n catch (err) {\n obj = null;\n self.$amazonCredentialJson.val('').attr(\n 'placeholder',\n $t('Invalid JSON credentials entered, please try again.')\n ).focus();\n }\n\n if (obj && typeof obj === 'object') {\n\n for (var prop in obj) {\n if (obj.hasOwnProperty(prop)) {\n item = $('#payment_' + self.getCountry() + '_amazon_payment_credentials_'\n + $.trim(prop));\n\n if (item && item.length) {\n $('#payment_' + self.getCountry() + '_amazon_payment_credentials_'\n + $.trim(prop)).val($.trim(obj[prop]));\n }\n else {\n success = false;\n }\n }\n }\n\n if (success) {\n self.$amazonCredentialJson.val('').attr(\n 'placeholder',\n $t('Credential fields successfully updated and being saved.')\n ).focus();\n $('#save').click();\n }\n else {\n self.$amazonCredentialJson.val('').attr(\n 'placeholder',\n $t('One or more of your credential fields did not parse correctly. ' +\n 'Please review your entry and try again.')\n ).focus();\n }\n }\n },\n\n /**\n * Sets up Amazon merchant key popup and polls for data update upon user completion.\n */\n setupWindowLaunch: function () {\n var self = this,\n heights = [660, 720, 810, 900],\n popupWidth = this.getCountry() !== 'us' ? 768 : 1050, popupHeight = heights[0],\n region = self.region,\n elCheckDefault = $('#payment_' + self.getCountry()\n + '_amazon_payment_credentials_payment_region_inherit:checked'),\n elRegion = $('payment_' + self.getCountry() + '_amazon_payment_credentials_payment_region'),\n elJson = self.$amazonCredentialJson.val();\n\n for (var i in heights) {\n if (heights.hasOwnProperty(i)) {\n popupHeight = window.innerHeight >= heights[i] ? heights[i] : popupHeight;\n }\n }\n\n self.launchPopup(self.amazonUrl, popupWidth, popupHeight);\n\n // flags that popup is open and poll timer can proceed\n windowOpen = true;\n\n // begin polling for feedback\n pollTimer = setTimeout(self.pollForKeys(self), self.pollInterval);\n\n // Save JSON\n $('#save-json').click(function (e) {\n e.stop();\n var json = $('#json-import').value;\n\n if (!json || !json.isJSON()) {\n return;\n }\n elJson.value = json;\n $('#save').click();\n });\n\n // Autoset payment region (for EU/UK)\n if (self.region.indexOf('eu') !== -1) {\n region = 'de';\n }\n\n if (elCheckDefault && elCheckDefault.length) {\n elCheckDefault[0].click();\n }\n\n if (elRegion) {\n elRegion.value = region;\n }\n },\n\n /**\n * Perform Ajax request looking for new keys.\n */\n pollForKeys: function (self) {\n clearTimeout(pollTimer);\n if (windowOpen) {\n $.ajax({\n url: self.pollUrl,\n data: {},\n type: 'GET',\n cache: true,\n dataType: 'json',\n context: this,\n\n /**\n * Response handler\n * @param {Object} response\n */\n success: function (response) {\n // poll controller returns a 0 if invalid and a 1 if valid\n if (response) {\n $('#amazon_reload').show();\n document.location.replace(document.location + '#payment_amazon_payments-head');\n location.reload();\n }\n else {\n pollTimer = setTimeout(self.pollForKeys(self), self.pollInterval);\n }\n }\n });\n }\n },\n\n /**\n * Sets up dynamic form for capturing popup/form input for simple path setup.\n */\n generateSimplePathForm: function () {\n\n this.$form = new Element('form', {\n method: 'post',\n action: this.amazonUrl,\n id: 'simplepath_form',\n target: 'simplepath',\n novalidate: 'novalidate',\n });\n\n this.$container.wrap(this.$form);\n\n // Convert formParams JSON to hidden inputs\n for (var key in this.formParams) {\n if ( $.isPlainObject(this.formParams[key]) || $.isArray(this.formParams[key])) {\n for (var i in this.formParams[key]) {\n if (typeof this.formParams[key][i] !== 'function') {\n $(new Element('input', {\n type: 'hidden',\n name: key,\n value: this.formParams[key][i],\n novalidate: 'novalidate'\n })).appendTo($(\"#simplepath_form\"));\n }\n }\n } else {\n $(new Element('input', {\n type: 'hidden',\n name: key,\n novalidate: 'novalidate',\n value: this.formParams[key]\n })).appendTo($(\"#simplepath_form\"));\n }\n }\n\n // unable to use this.form, had to resort to direct call\n $('#simplepath_form').validate({});\n },\n\n /**\n * display amazon simple path config section\n */\n showAmazonConfig: function () {\n this.$amazonSimplepath.show();\n this.$amazonSpBack.hide();\n if (this.$amazonCredentialsHeader.hasClass('open')) {\n this.$amazonCredentialsHeader.click();\n }\n },\n\n /**\n * hide amazon simple path config.\n */\n hideAmazonConfig: function () {\n this.$amazonSimplepath.hide();\n this.$amazonSpBack.show();\n if (!this.$amazonCredentialsHeader.hasClass('open')) {\n this.$amazonCredentialsHeader.click();\n }\n },\n\n /**\n * Get payment code\n * @returns {String}\n */\n getCountry: function () {\n return this.co.toLowerCase();\n },\n\n /**\n * Generate popup window for simple path process\n * @param url\n * @param requestedWidth\n * @param requestedHeight\n */\n launchPopup: function (url, requestedWidth, requestedHeight) {\n var leftOffset = this.getLeftOffset(requestedWidth),\n topOffset = this.getTopOffset(requestedHeight),\n newWindow = window.open(url, 'simplepath', 'scrollbars=yes, width=' + requestedWidth\n + ', height=' + requestedHeight + ', top=' + topOffset + ', left=' + leftOffset);\n\n if (window.focus) {\n newWindow.focus();\n }\n\n // Set interval to check when this popup window is closed so timeout can be suspended.\n var winTimer = window.setInterval(function () {\n if (newWindow.closed !== false) {\n window.clearInterval(winTimer);\n windowOpen = false;\n }\n });\n },\n\n /**\n * Determine left offset for popup window\n * @param requestedWidth\n * @returns {number}\n */\n getLeftOffset: function (requestedWidth) {\n var dualScreenLeft = window.screenLeft !== undefined ? window.screenLeft : screen.left;\n\n return (this.windowWidth() / 2) - (requestedWidth / 2) + dualScreenLeft;\n },\n\n /**\n * Determine top offset for popup window\n * @param requestedHeight\n * @returns {number}\n */\n getTopOffset: function (requestedHeight) {\n var dualScreenTop = window.screenTop !== undefined ? window.screenTop : screen.top;\n\n return (this.windowHeight() / 2) - (requestedHeight / 2) + dualScreenTop;\n },\n\n /**\n * Determine width of popup window\n * @returns {number}\n */\n windowWidth: function () {\n return window.innerWidth\n || document.documentElement.clientWidth\n || screen.width;\n },\n\n /**\n * Determine window height of popup\n * @returns {number}\n */\n windowHeight: function () {\n return window.innerHeight\n || document.documentElement.clientHeight\n || screen.height;\n }\n }\n );\n }\n);\n","Magento_SalesRule/js/form/element/coupon-type.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'underscore',\n 'uiRegistry',\n 'Magento_Ui/js/form/element/select'\n], function (_, uiRegistry, select) {\n 'use strict';\n\n return select.extend({\n\n /**\n * Hide fields on coupon tab\n */\n onUpdate: function () {\n\n /* eslint-disable eqeqeq */\n if (this.value() != this.displayOnlyForCouponType) {\n uiRegistry.get('sales_rule_form.sales_rule_form.rule_information.use_auto_generation').checked(false);\n }\n\n this.enableDisableFields();\n },\n\n /**\n * Enable/disable fields on Coupons tab\n */\n enableDisableFields: function () {\n var selector,\n isUseAutoGenerationChecked,\n couponType,\n disableAuto;\n\n selector = '[id=sales-rule-form-tab-coupons] input, [id=sales-rule-form-tab-coupons] select, ' +\n '[id=sales-rule-form-tab-coupons] button';\n isUseAutoGenerationChecked = uiRegistry\n .get('sales_rule_form.sales_rule_form.rule_information.use_auto_generation')\n .checked();\n couponType = uiRegistry\n .get('sales_rule_form.sales_rule_form.rule_information.coupon_type')\n .value();\n disableAuto = couponType === 3 || isUseAutoGenerationChecked;\n _.each(\n document.querySelectorAll(selector),\n function (element) {\n element.disabled = !disableAuto;\n }\n );\n }\n });\n});\n","Magento_SalesRule/js/form/element/manage-coupon-codes.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'underscore',\n 'uiRegistry',\n 'Magento_Ui/js/form/components/fieldset',\n 'Magento_Ui/js/lib/view/utils/async'\n], function (_, uiRegistry, fieldset, async) {\n 'use strict';\n\n return fieldset.extend({\n\n /*eslint-disable no-unused-vars*/\n /**\n * Initialize element\n *\n * @returns {Abstract} Chainable\n */\n initialize: function (elems, position) {\n var obj = this;\n\n this._super();\n\n async.async('#sales-rule-form-tab-coupons', document.getElementById('container'), function (node) {\n var useAutoGeneration = uiRegistry.get(\n 'sales_rule_form.sales_rule_form.rule_information.use_auto_generation'\n );\n\n useAutoGeneration.on('checked', function () {\n obj.enableDisableFields();\n });\n obj.enableDisableFields();\n });\n\n return this;\n },\n\n /*eslint-enable no-unused-vars*/\n /*eslint-disable lines-around-comment*/\n\n /**\n * Enable/disable fields on Coupons tab\n */\n enableDisableFields: function () {\n var selector,\n isUseAutoGenerationChecked,\n couponType,\n disableAuto;\n\n selector = '[id=sales-rule-form-tab-coupons] input, [id=sales-rule-form-tab-coupons] select, ' +\n '[id=sales-rule-form-tab-coupons] button';\n isUseAutoGenerationChecked = uiRegistry\n .get('sales_rule_form.sales_rule_form.rule_information.use_auto_generation')\n .checked();\n couponType = uiRegistry\n .get('sales_rule_form.sales_rule_form.rule_information.coupon_type')\n .value();\n /**\n * \\Magento\\Rule\\Model\\AbstractModel::COUPON_TYPE_AUTO\n */\n disableAuto = couponType === 3 || isUseAutoGenerationChecked;\n _.each(\n document.querySelectorAll(selector),\n function (element) {\n element.disabled = !disableAuto;\n }\n );\n }\n });\n});\n","Magento_UrlRewrite/js/url-rewrite-validation.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'jquery',\n 'mage/backend/form',\n 'mage/backend/validation'\n], function ($) {\n 'use strict';\n\n return function (data, element) {\n\n $(element).form().validation({\n validationUrl: data.url\n });\n };\n});\n","Magento_Sales/js/bootstrap/order-create-index.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\nrequire([\n 'Magento_Sales/order/create/giftmessage'\n]);\n","Magento_Sales/js/bootstrap/order-post-action.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\nrequire([\n 'Magento_Sales/order/view/post-wrapper'\n]);\n","Magento_Sales/order/giftoptions_tooltip.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'prototype'\n], function () {\n 'use strict';\n\n var GiftOptionsTooltip = Class.create();\n\n GiftOptionsTooltip.prototype = {\n _tooltipLines: [],\n _tooltipWindow: null,\n _tooltipWindowContent: null,\n _targetLinks: [],\n _eventMouseOver: null,\n _eventMouseOut: null,\n _styleOptions: null,\n _tooltipContentLoaderFunction: null,\n\n /**\n * Initialize tooltip object\n */\n initialize: function () {\n var options = Object.extend({\n 'delta_x': 30,\n 'delta_y': 0,\n zindex: 1000\n });\n\n this._styleOptions = options;\n this._eventMouseOver = this.showTooltip.bindAsEventListener(this);\n this._eventMouseOut = this.hideTooltip.bindAsEventListener(this);\n },\n\n /**\n * Set gift options tooltip window\n *\n * @param {String} windowId\n * @param {String} contentId\n *\n * @return boolean success\n */\n setTooltipWindow: function (windowId, contentId) {\n if (!$(windowId) || !$(contentId)) {\n return false;\n }\n this._tooltipWindow = $(windowId);\n this._tooltipWindowContent = $(contentId);\n $(document.body).insert({\n bottom: this._tooltipWindow\n });\n this.hideTooltip();\n\n return true;\n },\n\n /**\n * Add tooltip to specified link\n *\n * @param {String} linkId\n * @param {String} itemId - identifier of the item related to link\n *\n * @return boolean success\n */\n addTargetLink: function (linkId, itemId) {\n if ($(linkId)) {\n this._targetLinks[linkId] = [];\n this._targetLinks[linkId].object = $(linkId);\n this._targetLinks[linkId].itemId = itemId;\n this._registerEvents(this._targetLinks[linkId].object);\n\n return true;\n }\n\n return false;\n },\n\n /**\n * Detach event listeners from target links when tooltip is destroyed\n */\n destroy: function () {\n var linkId;\n\n for (linkId in this._targetLinks) { //eslint-disable-line guard-for-in\n Event.stopObserving(this._targetLinks[linkId].object, 'mouseover', this._eventMouseOver);\n Event.stopObserving(this._targetLinks[linkId].object, 'mouseout', this._eventMouseOut);\n }\n },\n\n /**\n * Register event listeners\n *\n * @param {HTMLElement} element\n */\n _registerEvents: function (element) {\n Event.observe(element, 'mouseover', this._eventMouseOver);\n Event.observe(element, 'mouseout', this._eventMouseOut);\n },\n\n /**\n * Move tooltip to mouse position\n *\n * @param {Prototype.Event} event\n */\n _moveTooltip: function (event) {\n var mouseX, mouseY;\n\n Event.stop(event);\n mouseX = Event.pointerX(event);\n mouseY = Event.pointerY(event);\n\n this.setStyles(mouseX, mouseY);\n },\n\n /**\n * Show tooltip\n *\n * @param {Object} event\n *\n * @return boolean success\n */\n showTooltip: function (event) {\n var link, itemId, tooltipContent;\n\n Event.stop(event);\n\n if (this._tooltipWindow) {\n link = Event.element(event);\n itemId = this._targetLinks[link.id].itemId;\n tooltipContent = '';\n\n if (Object.isFunction(this._tooltipContentLoaderFunction)) {\n tooltipContent = this._tooltipContentLoaderFunction(itemId);\n }\n\n if (tooltipContent != '') { //eslint-disable-line eqeqeq\n this._updateTooltipWindowContent(tooltipContent);\n this._moveTooltip(event);\n new Element.show(this._tooltipWindow);\n\n return true;\n }\n }\n\n return false;\n },\n\n /**\n * Set tooltip window styles\n *\n * @param {Number} x\n * @param {Number} y\n */\n setStyles: function (x, y) {\n Element.setStyle(this._tooltipWindow, {\n position: 'absolute',\n top: y + this._styleOptions['delta_y'] + 'px',\n left: x + this._styleOptions['delta_x'] + 'px',\n zindex: this._styleOptions.zindex\n });\n },\n\n /**\n * Hide tooltip\n */\n hideTooltip: function () {\n if (this._tooltipWindow) {\n new Element.hide(this._tooltipWindow);\n }\n },\n\n /**\n * Set gift options tooltip content loader function\n * This function should accept at least one parameter that will serve as an item ID\n *\n * @param {Function} loaderFunction - loader function\n */\n setTooltipContentLoaderFunction: function (loaderFunction) {\n this._tooltipContentLoaderFunction = loaderFunction;\n },\n\n /**\n * Update tooltip window content\n *\n * @param {String} content\n */\n _updateTooltipWindowContent: function (content) {\n this._tooltipWindowContent.update(content);\n }\n };\n\n window.giftOptionsTooltip = new GiftOptionsTooltip();\n});\n","Magento_Sales/order/create/scripts.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/confirm',\n 'Magento_Ui/js/modal/alert',\n 'mage/template',\n 'text!Magento_Sales/templates/order/create/shipping/reload.html',\n 'text!Magento_Sales/templates/order/create/payment/reload.html',\n 'mage/translate',\n 'prototype',\n 'Magento_Catalog/catalog/product/composite/configure',\n 'Magento_Ui/js/lib/view/utils/async'\n], function (jQuery, confirm, alert, template, shippingTemplate, paymentTemplate) {\n\n window.AdminOrder = new Class.create();\n\n AdminOrder.prototype = {\n initialize : function(data){\n if(!data) data = {};\n this.loadBaseUrl = false;\n this.customerId = data.customer_id ? data.customer_id : false;\n this.storeId = data.store_id ? data.store_id : false;\n this.quoteId = data['quote_id'] ? data['quote_id'] : false;\n this.currencyId = false;\n this.currencySymbol = data.currency_symbol ? data.currency_symbol : '';\n this.addresses = data.addresses ? data.addresses : $H({});\n this.shippingAsBilling = data.shippingAsBilling ? data.shippingAsBilling : false;\n this.gridProducts = $H({});\n this.gridProductsGift = $H({});\n this.billingAddressContainer = '';\n this.shippingAddressContainer = '';\n this.isShippingMethodReseted = data.shipping_method_reseted ? data.shipping_method_reseted : false;\n this.overlayData = $H({});\n this.giftMessageDataChanged = false;\n this.productConfigureAddFields = {};\n this.productPriceBase = {};\n this.collectElementsValue = true;\n this.isOnlyVirtualProduct = false;\n this.excludedPaymentMethods = [];\n this.summarizePrice = true;\n this.shippingTemplate = template(shippingTemplate, {\n data: {\n title: jQuery.mage.__('Shipping Method'),\n linkText: jQuery.mage.__('Get shipping methods and rates')\n }\n });\n this.paymentTemplate = template(paymentTemplate, {\n data: {\n title: jQuery.mage.__('Payment Method'),\n linkText: jQuery.mage.__('Get available payment methods')\n }\n });\n\n jQuery.async('#order-items', (function(){\n this.dataArea = new OrderFormArea('data', $(this.getAreaId('data')), this);\n this.itemsArea = Object.extend(new OrderFormArea('items', $(this.getAreaId('items')), this), {\n addControlButton: function(button){\n var controlButtonArea = $(this.node).select('.actions')[0];\n if (typeof controlButtonArea != 'undefined') {\n var buttons = controlButtonArea.childElements();\n for (var i = 0; i < buttons.length; i++) {\n if (buttons[i].innerHTML.include(button.getLabel())) {\n return;\n }\n }\n button.insertIn(controlButtonArea, 'top');\n }\n }\n });\n\n var searchButtonId = 'add_products',\n searchButton = new ControlButton(jQuery.mage.__('Add Products'), searchButtonId),\n searchAreaId = this.getAreaId('search');\n searchButton.onClick = function() {\n $(searchAreaId).show();\n var el = this;\n window.setTimeout(function () {\n el.remove();\n }, 10);\n };\n\n if (jQuery('#' + this.getAreaId('items')).is(':visible')) {\n this.dataArea.onLoad = this.dataArea.onLoad.wrap(function(proceed) {\n proceed();\n this._parent.itemsArea.setNode($(this._parent.getAreaId('items')));\n this._parent.itemsArea.onLoad();\n });\n\n this.itemsArea.onLoad = this.itemsArea.onLoad.wrap(function(proceed) {\n proceed();\n if ($(searchAreaId) && !$(searchAreaId).visible() && !$(searchButtonId)) {\n this.addControlButton(searchButton);\n }\n });\n this.areasLoaded();\n this.itemsArea.onLoad();\n }\n }).bind(this));\n\n jQuery('#edit_form')\n .on('submitOrder', function(){\n jQuery(this).trigger('realOrder');\n })\n .on('realOrder', this._realSubmit.bind(this));\n },\n\n areasLoaded: function(){\n },\n\n itemsLoaded: function(){\n },\n\n dataLoaded: function(){\n this.dataShow();\n },\n\n setLoadBaseUrl : function(url){\n this.loadBaseUrl = url;\n },\n\n setAddresses : function(addresses){\n this.addresses = addresses;\n },\n\n addExcludedPaymentMethod : function(method){\n this.excludedPaymentMethods.push(method);\n },\n\n setCustomerId : function(id){\n this.customerId = id;\n this.loadArea('header', true);\n $(this.getAreaId('header')).callback = 'setCustomerAfter';\n $('back_order_top_button').hide();\n $('reset_order_top_button').show();\n },\n\n setCustomerAfter : function () {\n this.customerSelectorHide();\n if (this.storeId) {\n $(this.getAreaId('data')).callback = 'dataLoaded';\n this.loadArea(['data'], true);\n }\n else {\n this.storeSelectorShow();\n }\n },\n\n setStoreId : function(id){\n this.storeId = id;\n this.storeSelectorHide();\n this.sidebarShow();\n //this.loadArea(['header', 'sidebar','data'], true);\n this.dataShow();\n this.loadArea(['header', 'data'], true);\n },\n\n setCurrencyId : function(id){\n this.currencyId = id;\n //this.loadArea(['sidebar', 'data'], true);\n this.loadArea(['data'], true);\n },\n\n setCurrencySymbol : function(symbol){\n this.currencySymbol = symbol;\n },\n\n selectAddress : function(el, container){\n id = el.value;\n if (id.length == 0) {\n id = '0';\n }\n if(this.addresses[id]){\n this.fillAddressFields(container, this.addresses[id]);\n\n }\n else{\n this.fillAddressFields(container, {});\n }\n\n var data = this.serializeData(container);\n data[el.name] = id;\n\n this.resetPaymentMethod();\n if (this.isShippingField(container) && !this.isShippingMethodReseted) {\n this.resetShippingMethod(data);\n } else{\n this.saveData(data);\n }\n },\n\n /**\n * Checks if the field belongs to the shipping address.\n *\n * @param {String} fieldId\n * @return {Boolean}\n */\n isShippingField: function (fieldId) {\n if (this.shippingAsBilling) {\n return fieldId.include('billing');\n }\n\n return fieldId.include('shipping');\n },\n\n /**\n * Checks if the field belongs to the billing address.\n *\n * @param {String} fieldId\n * @return {Boolean}\n */\n isBillingField: function (fieldId) {\n return fieldId.include('billing');\n },\n\n /**\n * Binds events on container form fields.\n *\n * @param {String} container\n */\n bindAddressFields: function (container) {\n var fields = $(container).select('input', 'select', 'textarea'),\n i;\n\n for (i = 0; i < fields.length; i++) {\n jQuery(fields[i]).change(this.changeAddressField.bind(this));\n }\n },\n\n /**\n * Triggers on each form's element changes.\n *\n * @param {Event} event\n */\n changeAddressField: function (event) {\n var field = Event.element(event),\n re = /[^\\[]*\\[([^\\]]*)_address\\]\\[([^\\]]*)\\](\\[(\\d)\\])?/,\n matchRes = field.name.match(re),\n type,\n name,\n data,\n resetShipping = false;\n\n if (!matchRes) {\n return;\n }\n\n type = matchRes[1];\n name = matchRes[2];\n\n if (this.isBillingField(field.id)) {\n data = this.serializeData(this.billingAddressContainer);\n } else {\n data = this.serializeData(this.shippingAddressContainer);\n }\n data = data.toObject();\n\n if (type === 'billing' && this.shippingAsBilling) {\n this.syncAddressField(this.shippingAddressContainer, field.name, field.value);\n resetShipping = true;\n }\n\n if (type === 'shipping' && !this.shippingAsBilling) {\n resetShipping = true;\n }\n\n if (resetShipping) {\n data['reset_shipping'] = true;\n }\n\n data['order[' + type + '_address][customer_address_id]'] = null;\n data['shipping_as_billing'] = +this.shippingAsBilling;\n\n if (name === 'customer_address_id') {\n data['order[' + type + '_address][customer_address_id]'] =\n $('order-' + type + '_address_customer_address_id').value;\n }\n\n this.resetPaymentMethod();\n\n if (data['reset_shipping']) {\n this.resetShippingMethod();\n } else {\n this.saveData(data);\n\n if (name === 'country_id' || name === 'customer_address_id') {\n this.loadArea(['shipping_method', 'billing_method', 'totals', 'items'], true, data);\n }\n }\n },\n\n /**\n * Set address container form field value.\n *\n * @param {String} container - container ID\n * @param {String} fieldName - form field name\n * @param {*} fieldValue - form field value\n */\n syncAddressField: function (container, fieldName, fieldValue) {\n var syncName;\n\n if (this.isBillingField(fieldName)) {\n syncName = fieldName.replace('billing', 'shipping');\n }\n\n $(container).select('[name=\"' + syncName + '\"]').each(function (element) {\n if (~['input', 'textarea', 'select'].indexOf(element.tagName.toLowerCase())) {\n element.value = fieldValue;\n }\n });\n },\n\n fillAddressFields: function(container, data){\n var regionIdElem = false;\n var regionIdElemValue = false;\n\n var fields = $(container).select('input', 'select', 'textarea');\n var re = /[^\\[]*\\[[^\\]]*\\]\\[([^\\]]*)\\](\\[(\\d)\\])?/;\n for(var i=0;i<fields.length;i++){\n // skip input type file @Security error code: 1000\n if (fields[i].tagName.toLowerCase() == 'input' && fields[i].type.toLowerCase() == 'file') {\n continue;\n }\n var matchRes = fields[i].name.match(re);\n if (matchRes === null) {\n continue;\n }\n var name = matchRes[1];\n var index = matchRes[3];\n\n if (index){\n // multiply line\n if (data[name]){\n var values = data[name].split(\"\\n\");\n fields[i].value = values[index] ? values[index] : '';\n } else {\n fields[i].value = '';\n }\n } else if (fields[i].tagName.toLowerCase() == 'select' && fields[i].multiple) {\n // multiselect\n if (data[name]) {\n values = [''];\n if (Object.isString(data[name])) {\n values = data[name].split(',');\n } else if (Object.isArray(data[name])) {\n values = data[name];\n }\n fields[i].setValue(values);\n }\n } else {\n fields[i].setValue(data[name] ? data[name] : '');\n }\n\n if (fields[i].changeUpdater) {\n fields[i].changeUpdater();\n }\n\n if (name == 'region' && data['region_id'] && !data['region']){\n fields[i].value = data['region_id'];\n }\n\n jQuery(fields[i]).trigger('change');\n }\n },\n\n disableShippingAddress : function(flag) {\n this.shippingAsBilling = flag;\n if ($('order-shipping_address_customer_address_id')) {\n $('order-shipping_address_customer_address_id').disabled = flag;\n }\n if ($(this.shippingAddressContainer)) {\n var dataFields = $(this.shippingAddressContainer).select('input', 'select', 'textarea');\n for (var i = 0; i < dataFields.length; i++) {\n dataFields[i].disabled = flag;\n\n if(this.isOnlyVirtualProduct) {\n dataFields[i].setValue('');\n }\n }\n var buttons = $(this.shippingAddressContainer).select('button');\n // Add corresponding class to buttons while disabling them\n for (i = 0; i < buttons.length; i++) {\n buttons[i].disabled = flag;\n if (flag) {\n buttons[i].addClassName('disabled');\n } else {\n buttons[i].removeClassName('disabled');\n }\n }\n }\n },\n\n /**\n * Equals shipping and billing addresses.\n *\n * @param {Boolean} flag\n */\n setShippingAsBilling: function (flag) {\n var data,\n areasToLoad = ['billing_method', 'shipping_address', 'shipping_method', 'totals', 'giftmessage'];\n\n this.disableShippingAddress(flag);\n data = this.serializeData(flag ? this.billingAddressContainer : this.shippingAddressContainer);\n data = data.toObject();\n data['shipping_as_billing'] = flag ? 1 : 0;\n data['reset_shipping'] = 1;\n this.loadArea(areasToLoad, true, data);\n },\n\n /**\n * Replace shipping method area.\n */\n resetShippingMethod: function () {\n if (!this.isOnlyVirtualProduct) {\n $(this.getAreaId('shipping_method')).update(this.shippingTemplate);\n }\n },\n\n /**\n * Replace payment method area.\n */\n resetPaymentMethod: function () {\n $(this.getAreaId('billing_method')).update(this.paymentTemplate);\n },\n\n /**\n * Loads shipping options according to address data.\n *\n * @return {Boolean}\n */\n loadShippingRates: function () {\n var addressContainer = this.shippingAsBilling ?\n 'billingAddressContainer' :\n 'shippingAddressContainer',\n data = this.serializeData(this[addressContainer]).toObject();\n\n data['collect_shipping_rates'] = 1;\n this.isShippingMethodReseted = false;\n this.loadArea(['shipping_method', 'totals'], true, data);\n\n return false;\n },\n\n setShippingMethod: function(method) {\n var data = {};\n\n data['order[shipping_method]'] = method;\n this.loadArea([\n 'shipping_method',\n 'totals',\n 'billing_method'\n ], true, data);\n },\n\n /**\n * Updates available payment\n * methods list according to order data.\n *\n * @return boolean\n */\n loadPaymentMethods: function() {\n var data = this.serializeData(this.billingAddressContainer).toObject();\n\n this.loadArea(['billing_method','totals'], true, data);\n\n return false;\n },\n\n switchPaymentMethod: function(method){\n jQuery('#edit_form')\n .off('submitOrder')\n .on('submitOrder', function(){\n jQuery(this).trigger('realOrder');\n });\n jQuery('#edit_form').trigger('changePaymentMethod', [method]);\n this.setPaymentMethod(method);\n var data = {};\n data['order[payment_method]'] = method;\n this.loadArea(['card_validation'], true, data);\n },\n\n setPaymentMethod : function(method){\n if (this.paymentMethod && $('payment_form_'+this.paymentMethod)) {\n var form = 'payment_form_'+this.paymentMethod;\n [form + '_before', form, form + '_after'].each(function(el) {\n var block = $(el);\n if (block) {\n block.hide();\n block.select('input', 'select', 'textarea').each(function(field) {\n field.disabled = true;\n });\n }\n });\n }\n\n if(!this.paymentMethod || method){\n $('order-billing_method_form').select('input', 'select', 'textarea').each(function(elem){\n if(elem.type != 'radio') elem.disabled = true;\n })\n }\n\n if ($('payment_form_'+method)){\n jQuery('#' + this.getAreaId('billing_method')).trigger('contentUpdated');\n this.paymentMethod = method;\n var form = 'payment_form_'+method;\n [form + '_before', form, form + '_after'].each(function(el) {\n var block = $(el);\n if (block) {\n block.show();\n block.select('input', 'select', 'textarea').each(function(field) {\n field.disabled = false;\n if (!el.include('_before') && !el.include('_after') && !field.bindChange) {\n field.bindChange = true;\n field.paymentContainer = form;\n field.method = method;\n field.observe('change', this.changePaymentData.bind(this))\n }\n },this);\n }\n },this);\n }\n },\n\n changePaymentData : function(event){\n var elem = Event.element(event);\n if(elem && elem.method){\n var data = this.getPaymentData(elem.method);\n if (data) {\n this.loadArea(['card_validation'], true, data);\n } else {\n return;\n }\n }\n },\n\n getPaymentData : function(currentMethod){\n if (typeof(currentMethod) == 'undefined') {\n if (this.paymentMethod) {\n currentMethod = this.paymentMethod;\n } else {\n return false;\n }\n }\n if (this.isPaymentValidationAvailable() == false) {\n return false;\n }\n var data = {};\n var fields = $('payment_form_' + currentMethod).select('input', 'select');\n for(var i=0;i<fields.length;i++){\n data[fields[i].name] = fields[i].getValue();\n }\n if ((typeof data['payment[cc_type]']) != 'undefined' && (!data['payment[cc_type]'] || !data['payment[cc_number]'])) {\n return false;\n }\n return data;\n },\n\n applyCoupon : function(code){\n this.loadArea(['items', 'shipping_method', 'totals', 'billing_method'], true, {'order[coupon][code]':code, reset_shipping: 0});\n this.orderItemChanged = false;\n },\n\n addProduct : function(id){\n this.loadArea(['items', 'shipping_method', 'totals', 'billing_method'], true, {add_product:id, reset_shipping: true});\n },\n\n removeQuoteItem : function(id){\n this.loadArea(['items', 'shipping_method', 'totals', 'billing_method'], true,\n {remove_item:id, from:'quote',reset_shipping: true});\n },\n\n moveQuoteItem : function(id, to){\n this.loadArea(['sidebar_'+to, 'items', 'shipping_method', 'totals', 'billing_method'], this.getAreaId('items'),\n {move_item:id, to:to, reset_shipping: true});\n },\n\n productGridShow : function(buttonElement){\n this.productGridShowButton = buttonElement;\n Element.hide(buttonElement);\n this.showArea('search');\n },\n\n productGridRowInit : function(grid, row){\n var checkbox = $(row).select('.checkbox')[0];\n var inputs = $(row).select('.input-text');\n if (checkbox && inputs.length > 0) {\n checkbox.inputElements = inputs;\n for (var i = 0; i < inputs.length; i++) {\n var input = inputs[i];\n input.checkboxElement = checkbox;\n\n var product = this.gridProducts.get(checkbox.value);\n if (product) {\n var defaultValue = product[input.name];\n if (defaultValue) {\n if (input.name == 'giftmessage') {\n input.checked = true;\n } else {\n input.value = defaultValue;\n }\n }\n }\n\n input.disabled = !checkbox.checked || input.hasClassName('input-inactive');\n\n Event.observe(input,'keyup', this.productGridRowInputChange.bind(this));\n Event.observe(input,'change',this.productGridRowInputChange.bind(this));\n }\n }\n },\n\n productGridRowInputChange : function(event){\n var element = Event.element(event);\n if (element && element.checkboxElement && element.checkboxElement.checked){\n if (element.name!='giftmessage' || element.checked) {\n this.gridProducts.get(element.checkboxElement.value)[element.name] = element.value;\n } else if (element.name=='giftmessage' && this.gridProducts.get(element.checkboxElement.value)[element.name]) {\n delete(this.gridProducts.get(element.checkboxElement.value)[element.name]);\n }\n }\n },\n\n productGridRowClick : function(grid, event){\n var trElement = Event.findElement(event, 'tr');\n var qtyElement = trElement.select('input[name=\"qty\"]')[0];\n var eventElement = Event.element(event);\n var isInputCheckbox = eventElement.tagName == 'INPUT' && eventElement.type == 'checkbox';\n var isInputQty = eventElement.tagName == 'INPUT' && eventElement.name == 'qty';\n if (trElement && !isInputQty) {\n var checkbox = Element.select(trElement, 'input[type=\"checkbox\"]')[0];\n var confLink = Element.select(trElement, 'a')[0];\n var priceColl = Element.select(trElement, '.price')[0];\n if (checkbox) {\n // processing non composite product\n if (confLink.readAttribute('disabled')) {\n var checked = isInputCheckbox ? checkbox.checked : !checkbox.checked;\n grid.setCheckboxChecked(checkbox, checked);\n // processing composite product\n } else if (isInputCheckbox && !checkbox.checked) {\n grid.setCheckboxChecked(checkbox, false);\n // processing composite product\n } else if (!isInputCheckbox || (isInputCheckbox && checkbox.checked)) {\n var listType = confLink.readAttribute('list_type');\n var productId = confLink.readAttribute('product_id');\n if (typeof this.productPriceBase[productId] == 'undefined') {\n var priceBase = priceColl.innerHTML.match(/.*?([\\d,]+\\.?\\d*)/);\n if (!priceBase) {\n this.productPriceBase[productId] = 0;\n } else {\n this.productPriceBase[productId] = parseFloat(priceBase[1].replace(/,/g,''));\n }\n }\n productConfigure.setConfirmCallback(listType, function() {\n // sync qty of popup and qty of grid\n var confirmedCurrentQty = productConfigure.getCurrentConfirmedQtyElement();\n if (qtyElement && confirmedCurrentQty && !isNaN(confirmedCurrentQty.value)) {\n qtyElement.value = confirmedCurrentQty.value;\n }\n // calc and set product price\n var productPrice = this._calcProductPrice();\n if (this._isSummarizePrice()) {\n productPrice += this.productPriceBase[productId];\n }\n productPrice = parseFloat(Math.round(productPrice + \"e+2\") + \"e-2\");\n priceColl.innerHTML = this.currencySymbol + productPrice.toFixed(2);\n // and set checkbox checked\n grid.setCheckboxChecked(checkbox, true);\n }.bind(this));\n productConfigure.setCancelCallback(listType, function() {\n if (!$(productConfigure.confirmedCurrentId) || !$(productConfigure.confirmedCurrentId).innerHTML) {\n grid.setCheckboxChecked(checkbox, false);\n }\n });\n productConfigure.setShowWindowCallback(listType, function() {\n // sync qty of grid and qty of popup\n var formCurrentQty = productConfigure.getCurrentFormQtyElement();\n if (formCurrentQty && qtyElement && !isNaN(qtyElement.value)) {\n formCurrentQty.value = qtyElement.value;\n }\n }.bind(this));\n productConfigure.showItemConfiguration(listType, productId);\n }\n }\n }\n },\n\n /**\n * Is need to summarize price\n */\n _isSummarizePrice: function(elm) {\n if (elm && elm.hasAttribute('summarizePrice')) {\n this.summarizePrice = parseInt(elm.readAttribute('summarizePrice'));\n }\n return this.summarizePrice;\n },\n /**\n * Calc product price through its options\n */\n _calcProductPrice: function () {\n var productPrice = 0;\n var getPriceFields = function (elms) {\n var productPrice = 0;\n var getPrice = function (elm) {\n var optQty = 1;\n if (elm.hasAttribute('qtyId')) {\n if (!$(elm.getAttribute('qtyId')).value) {\n return 0;\n } else {\n optQty = parseFloat($(elm.getAttribute('qtyId')).value);\n }\n }\n if (elm.hasAttribute('price') && !elm.disabled) {\n return parseFloat(elm.readAttribute('price')) * optQty;\n }\n return 0;\n };\n for(var i = 0; i < elms.length; i++) {\n if (elms[i].type == 'select-one' || elms[i].type == 'select-multiple') {\n for(var ii = 0; ii < elms[i].options.length; ii++) {\n if (elms[i].options[ii].selected) {\n if (this._isSummarizePrice(elms[i].options[ii])) {\n productPrice += getPrice(elms[i].options[ii]);\n } else {\n productPrice = getPrice(elms[i].options[ii]);\n }\n }\n }\n }\n else if (((elms[i].type == 'checkbox' || elms[i].type == 'radio') && elms[i].checked)\n || ((elms[i].type == 'file' || elms[i].type == 'text' || elms[i].type == 'textarea' || elms[i].type == 'hidden')\n && Form.Element.getValue(elms[i]))\n ) {\n if (this._isSummarizePrice(elms[i])) {\n productPrice += getPrice(elms[i]);\n } else {\n productPrice = getPrice(elms[i]);\n }\n }\n }\n return productPrice;\n }.bind(this);\n productPrice += getPriceFields($(productConfigure.confirmedCurrentId).getElementsByTagName('input'));\n productPrice += getPriceFields($(productConfigure.confirmedCurrentId).getElementsByTagName('select'));\n productPrice += getPriceFields($(productConfigure.confirmedCurrentId).getElementsByTagName('textarea'));\n return productPrice;\n },\n\n productGridCheckboxCheck : function(grid, element, checked){\n if (checked) {\n if(element.inputElements) {\n this.gridProducts.set(element.value, {});\n var product = this.gridProducts.get(element.value);\n for (var i = 0; i < element.inputElements.length; i++) {\n var input = element.inputElements[i];\n if (!input.hasClassName('input-inactive')) {\n input.disabled = false;\n if (input.name == 'qty' && !input.value) {\n input.value = 1;\n }\n }\n\n if (input.checked || input.name != 'giftmessage') {\n product[input.name] = input.value;\n } else if (product[input.name]) {\n delete(product[input.name]);\n }\n }\n }\n } else {\n if(element.inputElements){\n for(var i = 0; i < element.inputElements.length; i++) {\n element.inputElements[i].disabled = true;\n }\n }\n this.gridProducts.unset(element.value);\n }\n grid.reloadParams = {'products[]':this.gridProducts.keys()};\n },\n\n /**\n * Submit configured products to quote\n */\n productGridAddSelected : function(){\n if(this.productGridShowButton) Element.show(this.productGridShowButton);\n var area = ['search', 'items', 'shipping_method', 'totals', 'giftmessage','billing_method'];\n // prepare additional fields and filtered items of products\n var fieldsPrepare = {};\n var itemsFilter = [];\n var products = this.gridProducts.toObject();\n for (var productId in products) {\n itemsFilter.push(productId);\n var paramKey = 'item['+productId+']';\n for (var productParamKey in products[productId]) {\n paramKey += '['+productParamKey+']';\n fieldsPrepare[paramKey] = products[productId][productParamKey];\n }\n }\n this.productConfigureSubmit('product_to_add', area, fieldsPrepare, itemsFilter);\n productConfigure.clean('quote_items');\n this.hideArea('search');\n this.gridProducts = $H({});\n },\n\n selectCustomer : function(grid, event){\n var element = Event.findElement(event, 'tr');\n if (element.title){\n this.setCustomerId(element.title);\n }\n },\n\n customerSelectorHide : function(){\n this.hideArea('customer-selector');\n },\n\n customerSelectorShow : function(){\n this.showArea('customer-selector');\n },\n\n storeSelectorHide : function(){\n this.hideArea('store-selector');\n },\n\n storeSelectorShow : function(){\n this.showArea('store-selector');\n },\n\n dataHide : function(){\n this.hideArea('data');\n },\n\n dataShow : function(){\n if ($('submit_order_top_button')) {\n $('submit_order_top_button').show();\n }\n this.showArea('data');\n },\n\n clearShoppingCart : function(confirmMessage){\n var self = this;\n\n confirm({\n content: confirmMessage,\n actions: {\n confirm: function() {\n self.collectElementsValue = false;\n order.sidebarApplyChanges({'sidebar[empty_customer_cart]': 1});\n self.collectElementsValue = true;\n }\n }\n });\n },\n\n sidebarApplyChanges : function(auxiliaryParams) {\n if ($(this.getAreaId('sidebar'))) {\n var data = {};\n if (this.collectElementsValue) {\n var elems = $(this.getAreaId('sidebar')).select('input');\n for (var i=0; i < elems.length; i++) {\n if (elems[i].getValue()) {\n data[elems[i].name] = elems[i].getValue();\n }\n }\n }\n if (auxiliaryParams instanceof Object) {\n for (var paramName in auxiliaryParams) {\n data[paramName] = String(auxiliaryParams[paramName]);\n }\n }\n data.reset_shipping = true;\n this.loadArea(['sidebar', 'items', 'shipping_method', 'billing_method','totals', 'giftmessage'], true, data);\n }\n },\n\n sidebarHide : function(){\n if(this.storeId === false && $('page:left') && $('page:container')){\n $('page:left').hide();\n $('page:container').removeClassName('container');\n $('page:container').addClassName('container-collapsed');\n }\n },\n\n sidebarShow : function(){\n if($('page:left') && $('page:container')){\n $('page:left').show();\n $('page:container').removeClassName('container-collapsed');\n $('page:container').addClassName('container');\n }\n },\n\n /**\n * Show configuration of product and add handlers on submit form\n *\n * @param productId\n */\n sidebarConfigureProduct: function (listType, productId, itemId) {\n // create additional fields\n var params = {};\n params.reset_shipping = true;\n params.add_product = productId;\n this.prepareParams(params);\n for (var i in params) {\n if (params[i] === null) {\n unset(params[i]);\n } else if (typeof(params[i]) == 'boolean') {\n params[i] = params[i] ? 1 : 0;\n }\n }\n var fields = [];\n for (var name in params) {\n fields.push(new Element('input', {type: 'hidden', name: name, value: params[name]}));\n }\n // add additional fields before triggered submit\n productConfigure.setBeforeSubmitCallback(listType, function() {\n productConfigure.addFields(fields);\n }.bind(this));\n // response handler\n productConfigure.setOnLoadIFrameCallback(listType, function(response) {\n if (!response.ok) {\n return;\n }\n this.loadArea(['items', 'shipping_method', 'billing_method','totals', 'giftmessage'], true);\n }.bind(this));\n // show item configuration\n itemId = itemId ? itemId : productId;\n productConfigure.showItemConfiguration(listType, itemId);\n return false;\n },\n\n removeSidebarItem : function(id, from){\n this.loadArea(['sidebar_'+from], 'sidebar_data_'+from, {remove_item:id, from:from});\n },\n\n itemsUpdate : function(){\n var area = ['sidebar', 'items', 'shipping_method', 'billing_method','totals', 'giftmessage'];\n // prepare additional fields\n var fieldsPrepare = {update_items: 1};\n var info = $('order-items_grid').select('input', 'select', 'textarea');\n for(var i=0; i<info.length; i++){\n if(!info[i].disabled && (info[i].type != 'checkbox' || info[i].checked)) {\n fieldsPrepare[info[i].name] = info[i].getValue();\n }\n }\n fieldsPrepare = Object.extend(fieldsPrepare, this.productConfigureAddFields);\n this.productConfigureSubmit('quote_items', area, fieldsPrepare);\n this.orderItemChanged = false;\n },\n\n itemsOnchangeBind : function(){\n var elems = $('order-items_grid').select('input', 'select', 'textarea');\n for(var i=0; i<elems.length; i++){\n if(!elems[i].bindOnchange){\n elems[i].bindOnchange = true;\n elems[i].observe('change', this.itemChange.bind(this))\n }\n }\n },\n\n itemChange : function(event){\n this.giftmessageOnItemChange(event);\n this.orderItemChanged = true;\n },\n\n /**\n * Submit batch of configured products\n *\n * @param listType\n * @param area\n * @param fieldsPrepare\n * @param itemsFilter\n */\n productConfigureSubmit : function(listType, area, fieldsPrepare, itemsFilter) {\n // prepare loading areas and build url\n area = this.prepareArea(area);\n this.loadingAreas = area;\n var url = this.loadBaseUrl + 'block/' + area + '?isAjax=true';\n\n // prepare additional fields\n fieldsPrepare = this.prepareParams(fieldsPrepare);\n fieldsPrepare.reset_shipping = 1;\n fieldsPrepare.json = 1;\n\n // create fields\n var fields = [];\n for (var name in fieldsPrepare) {\n fields.push(new Element('input', {type: 'hidden', name: name, value: fieldsPrepare[name]}));\n }\n productConfigure.addFields(fields);\n\n // filter items\n if (itemsFilter) {\n productConfigure.addItemsFilter(listType, itemsFilter);\n }\n\n // prepare and do submit\n productConfigure.addListType(listType, {urlSubmit: url});\n productConfigure.setOnLoadIFrameCallback(listType, function(response){\n this.loadAreaResponseHandler(response);\n }.bind(this));\n productConfigure.submit(listType);\n // clean\n this.productConfigureAddFields = {};\n },\n\n /**\n * Show configuration of quote item\n *\n * @param itemId\n */\n showQuoteItemConfiguration: function(itemId){\n var listType = 'quote_items';\n var qtyElement = $('order-items_grid').select('input[name=\"item\\['+itemId+'\\]\\[qty\\]\"]')[0];\n productConfigure.setConfirmCallback(listType, function() {\n // sync qty of popup and qty of grid\n var confirmedCurrentQty = productConfigure.getCurrentConfirmedQtyElement();\n if (qtyElement && confirmedCurrentQty && !isNaN(confirmedCurrentQty.value)) {\n qtyElement.value = confirmedCurrentQty.value;\n }\n this.productConfigureAddFields['item['+itemId+'][configured]'] = 1;\n this.itemsUpdate();\n\n }.bind(this));\n productConfigure.setShowWindowCallback(listType, function() {\n // sync qty of grid and qty of popup\n var formCurrentQty = productConfigure.getCurrentFormQtyElement();\n if (formCurrentQty && qtyElement && !isNaN(qtyElement.value)) {\n formCurrentQty.value = qtyElement.value;\n }\n }.bind(this));\n productConfigure.showItemConfiguration(listType, itemId);\n },\n\n accountFieldsBind : function(container){\n if($(container)){\n var fields = $(container).select('input', 'select', 'textarea');\n for(var i=0; i<fields.length; i++){\n if(fields[i].id == 'group_id'){\n fields[i].observe('change', this.accountGroupChange.bind(this))\n }\n else{\n fields[i].observe('change', this.accountFieldChange.bind(this))\n }\n }\n }\n },\n\n accountGroupChange : function(){\n this.loadArea(['data'], true, this.serializeData('order-form_account').toObject());\n },\n\n accountFieldChange : function(){\n this.saveData(this.serializeData('order-form_account'));\n },\n\n commentFieldsBind : function(container){\n if($(container)){\n var fields = $(container).select('input', 'textarea');\n for(var i=0; i<fields.length; i++)\n fields[i].observe('change', this.commentFieldChange.bind(this))\n }\n },\n\n commentFieldChange : function(){\n this.saveData(this.serializeData('order-comment'));\n },\n\n giftmessageFieldsBind : function(container){\n if($(container)){\n var fields = $(container).select('input', 'textarea');\n for(var i=0; i<fields.length; i++)\n fields[i].observe('change', this.giftmessageFieldChange.bind(this))\n }\n },\n\n giftmessageFieldChange : function(){\n this.giftMessageDataChanged = true;\n },\n\n giftmessageOnItemChange : function(event) {\n var element = Event.element(event);\n if(element.name.indexOf(\"giftmessage\") != -1 && element.type == \"checkbox\" && !element.checked) {\n var messages = $(\"order-giftmessage\").select('textarea');\n var name;\n for(var i=0; i<messages.length; i++) {\n name = messages[i].id.split(\"_\");\n if(name.length < 2) continue;\n if (element.name.indexOf(\"[\" + name[1] + \"]\") != -1 && messages[i].value != \"\") {\n alert({\n content: \"First, clean the Message field in Gift Message form\"\n });\n element.checked = true;\n }\n }\n }\n },\n\n loadArea : function(area, indicator, params){\n var deferred = new jQuery.Deferred();\n var url = this.loadBaseUrl;\n if (area) {\n area = this.prepareArea(area);\n url += 'block/' + area;\n }\n if (indicator === true) indicator = 'html-body';\n params = this.prepareParams(params);\n params.json = true;\n if (!this.loadingAreas) this.loadingAreas = [];\n if (indicator) {\n this.loadingAreas = area;\n new Ajax.Request(url, {\n parameters:params,\n loaderArea: indicator,\n onSuccess: function(transport) {\n var response = transport.responseText.evalJSON();\n this.loadAreaResponseHandler(response);\n deferred.resolve();\n }.bind(this)\n });\n }\n else {\n new Ajax.Request(url, {\n parameters:params,\n loaderArea: indicator,\n onSuccess: function(transport) {\n deferred.resolve();\n }\n });\n }\n if (typeof productConfigure != 'undefined' && area instanceof Array && area.indexOf('items') != -1) {\n productConfigure.clean('quote_items');\n }\n return deferred.promise();\n },\n\n loadAreaResponseHandler : function (response) {\n if (response.error) {\n alert({\n content: response.message\n });\n }\n if (response.ajaxExpired && response.ajaxRedirect) {\n setLocation(response.ajaxRedirect);\n }\n if (!this.loadingAreas) {\n this.loadingAreas = [];\n }\n if (typeof this.loadingAreas == 'string') {\n this.loadingAreas = [this.loadingAreas];\n }\n if (this.loadingAreas.indexOf('message') == -1) {\n this.loadingAreas.push('message');\n }\n if (response.header) {\n jQuery('.page-actions-inner').attr('data-title', response.header);\n }\n\n for (var i = 0; i < this.loadingAreas.length; i++) {\n var id = this.loadingAreas[i];\n if ($(this.getAreaId(id))) {\n if ('message' != id || response[id]) {\n $(this.getAreaId(id)).update(response[id]);\n }\n if ($(this.getAreaId(id)).callback) {\n this[$(this.getAreaId(id)).callback]();\n }\n }\n }\n },\n\n prepareArea : function(area) {\n if (this.giftMessageDataChanged) {\n return area.without('giftmessage');\n }\n return area;\n },\n\n saveData : function(data){\n this.loadArea(false, false, data);\n },\n\n showArea : function(area){\n var id = this.getAreaId(area);\n if($(id)) {\n $(id).show();\n this.areaOverlay();\n }\n },\n\n hideArea : function(area){\n var id = this.getAreaId(area);\n if($(id)) {\n $(id).hide();\n this.areaOverlay();\n }\n },\n\n areaOverlay : function()\n {\n $H(order.overlayData).each(function(e){\n e.value.fx();\n });\n },\n\n getAreaId : function(area){\n return 'order-'+area;\n },\n\n prepareParams : function(params){\n if (!params) {\n params = {};\n }\n if (!params.customer_id) {\n params.customer_id = this.customerId;\n }\n if (!params.store_id) {\n params.store_id = this.storeId;\n }\n if (!params.currency_id) {\n params.currency_id = this.currencyId;\n }\n if (!params.form_key) {\n params.form_key = FORM_KEY;\n }\n\n if (this.isPaymentValidationAvailable()) {\n var data = this.serializeData('order-billing_method');\n if (data) {\n data.each(function(value) {\n params[value[0]] = value[1];\n });\n }\n } else {\n params['payment[method]'] = this.paymentMethod;\n }\n return params;\n },\n\n /**\n * Prevent from sending credit card information to server for some payment methods\n *\n * @returns {boolean}\n */\n isPaymentValidationAvailable : function(){\n return ((typeof this.paymentMethod) == 'undefined'\n || this.excludedPaymentMethods.indexOf(this.paymentMethod) == -1);\n },\n\n /**\n * Serializes container form elements data.\n *\n * @param {String} container\n * @return {Object}\n */\n serializeData: function (container) {\n var fields = $(container).select('input', 'select', 'textarea'),\n data = Form.serializeElements(fields, true);\n\n return $H(data);\n },\n\n toggleCustomPrice: function(checkbox, elemId, tierBlock) {\n if (checkbox.checked) {\n $(elemId).disabled = false;\n $(elemId).show();\n if($(tierBlock)) $(tierBlock).hide();\n }\n else {\n $(elemId).disabled = true;\n $(elemId).hide();\n if($(tierBlock)) $(tierBlock).show();\n }\n },\n\n submit : function()\n {\n var $editForm = jQuery('#edit_form');\n\n if ($editForm.valid()) {\n $editForm.trigger('processStart');\n $editForm.trigger('submitOrder');\n }\n },\n\n _realSubmit: function () {\n var disableAndSave = function() {\n disableElements('save');\n jQuery('#edit_form').on('invalid-form.validate', function() {\n enableElements('save');\n jQuery('#edit_form').trigger('processStop');\n jQuery('#edit_form').off('invalid-form.validate');\n });\n jQuery('#edit_form').triggerHandler('save');\n }\n if (this.orderItemChanged) {\n var self = this;\n\n jQuery('#edit_form').trigger('processStop');\n\n confirm({\n content: jQuery.mage.__('You have item changes'),\n actions: {\n confirm: function() {\n jQuery('#edit_form').trigger('processStart');\n disableAndSave();\n },\n cancel: function() {\n self.itemsUpdate();\n }\n }\n });\n } else {\n disableAndSave();\n }\n },\n\n overlay : function(elId, show, observe) {\n if (typeof(show) == 'undefined') { show = true; }\n\n var orderObj = this;\n var obj = this.overlayData.get(elId);\n if (!obj) {\n obj = {\n show: show,\n el: elId,\n order: orderObj,\n fx: function(event) {\n this.order.processOverlay(this.el, this.show);\n }\n };\n obj.bfx = obj.fx.bindAsEventListener(obj);\n this.overlayData.set(elId, obj);\n } else {\n obj.show = show;\n Event.stopObserving(window, 'resize', obj.bfx);\n }\n\n Event.observe(window, 'resize', obj.bfx);\n\n this.processOverlay(elId, show);\n },\n\n processOverlay : function(elId, show) {\n var el = $(elId);\n\n if (!el) {\n return;\n }\n\n var parentEl = el.up(1);\n if (show) {\n parentEl.removeClassName('ignore-validate');\n } else {\n parentEl.addClassName('ignore-validate');\n }\n\n if (Prototype.Browser.IE) {\n parentEl.select('select').each(function (elem) {\n if (show) {\n elem.needShowOnSuccess = false;\n elem.style.visibility = '';\n } else {\n elem.style.visibility = 'hidden';\n elem.needShowOnSuccess = true;\n }\n });\n }\n\n parentEl.setStyle({position: 'relative'});\n el.setStyle({\n display: show ? 'none' : ''\n });\n },\n\n validateVat: function(parameters)\n {\n var params = {\n country: $(parameters.countryElementId).value,\n vat: $(parameters.vatElementId).value\n };\n\n if (this.storeId !== false) {\n params.store_id = this.storeId;\n }\n\n var currentCustomerGroupId = $(parameters.groupIdHtmlId)\n ? $(parameters.groupIdHtmlId).value : '';\n\n new Ajax.Request(parameters.validateUrl, {\n parameters: params,\n onSuccess: function(response) {\n var message = '';\n var groupActionRequired = null;\n try {\n response = response.responseText.evalJSON();\n\n if (null === response.group) {\n if (true === response.valid) {\n message = parameters.vatValidMessage;\n } else if (true === response.success) {\n message = parameters.vatInvalidMessage.replace(/%s/, params.vat);\n } else {\n message = parameters.vatValidationFailedMessage;\n }\n } else {\n if (true === response.valid) {\n message = parameters.vatValidAndGroupValidMessage;\n if (0 === response.group) {\n message = parameters.vatValidAndGroupInvalidMessage;\n groupActionRequired = 'inform';\n } else if (currentCustomerGroupId != response.group) {\n message = parameters.vatValidAndGroupChangeMessage;\n groupActionRequired = 'change';\n }\n } else if (response.success) {\n message = parameters.vatInvalidMessage.replace(/%s/, params.vat);\n groupActionRequired = 'inform';\n } else {\n message = parameters.vatValidationFailedMessage;\n groupActionRequired = 'inform';\n }\n }\n } catch (e) {\n message = parameters.vatValidationFailedMessage;\n }\n if (null === groupActionRequired) {\n alert({\n content: message\n });\n }\n else {\n this.processCustomerGroupChange(\n parameters.groupIdHtmlId,\n message,\n parameters.vatCustomerGroupMessage,\n parameters.vatGroupErrorMessage,\n response.group,\n groupActionRequired\n );\n }\n }.bind(this)\n });\n },\n\n processCustomerGroupChange: function(groupIdHtmlId, message, customerGroupMessage, errorMessage, groupId, action)\n {\n var groupMessage = '';\n try {\n var currentCustomerGroupId = $(groupIdHtmlId).value;\n var currentCustomerGroupTitle =\n $$('#' + groupIdHtmlId + ' > option[value=' + currentCustomerGroupId + ']')[0].text;\n var customerGroupOption = $$('#' + groupIdHtmlId + ' > option[value=' + groupId + ']')[0];\n groupMessage = customerGroupMessage.replace(/%s/, customerGroupOption.text);\n } catch (e) {\n groupMessage = errorMessage;\n if (action === 'change') {\n message = '';\n action = 'inform';\n }\n }\n\n if (action === 'change') {\n var confirmText = message.replace(/%s/, customerGroupOption.text);\n confirmText = confirmText.replace(/%s/, currentCustomerGroupTitle);\n if (confirm(confirmText)) {\n $$('#' + groupIdHtmlId + ' option').each(function (o) {\n o.selected = o.readAttribute('value') == groupId;\n });\n this.accountGroupChange();\n }\n } else if (action === 'inform') {\n alert({\n content: message + '\\n' + groupMessage\n });\n }\n }\n };\n\n window.OrderFormArea = Class.create();\n OrderFormArea.prototype = {\n _name: null,\n _node: null,\n _parent: null,\n _callbackName: null,\n\n initialize: function(name, node, parent){\n if(!node)\n return;\n this._name = name;\n this._parent = parent;\n this._callbackName = node.callback;\n if (typeof this._callbackName == 'undefined') {\n this._callbackName = name + 'Loaded';\n node.callback = this._callbackName;\n }\n parent[this._callbackName] = parent[this._callbackName].wrap((function (proceed){\n proceed();\n this.onLoad();\n }).bind(this));\n\n this.setNode(node);\n },\n\n setNode: function(node){\n if (!node.callback) {\n node.callback = this._callbackName;\n }\n this.node = node;\n },\n\n onLoad: function(){\n }\n };\n\n window.ControlButton = Class.create();\n\n ControlButton.prototype = {\n _label: '',\n _node: null,\n\n initialize: function(label, id){\n this._label = label;\n this._node = new Element('button', {\n 'class': 'action-secondary action-add',\n 'type': 'button'\n });\n if (typeof id !== 'undefined') {\n this._node.setAttribute('id', id)\n }\n },\n\n onClick: function(){\n },\n\n insertIn: function(element, position){\n var node = Object.extend(this._node),\n content = {};\n node.observe('click', this.onClick);\n node.update('<span>' + this._label + '</span>');\n content[position] = node;\n Element.insert(element, content);\n },\n\n getLabel: function(){\n return this._label;\n }\n };\n});\n","Magento_Sales/order/create/giftmessage.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/********************* GIFT OPTIONS POPUP ***********************/\n/********************* GIFT OPTIONS SET ***********************/\n\ndefine([\n 'jquery',\n 'jquery/ui',\n 'mage/translate',\n 'mage/validation',\n 'prototype'\n], function (jQuery) {\n\n window.giftMessagesController = {\n toogleRequired: function (source, objects) {\n if (!$(source).value.blank()) {\n objects.each(function (item) {\n $(item).addClassName('required-entry');\n var label = findFieldLabel($(item));\n\n if (label) {\n var span = label.down('span');\n\n if (!span) {\n Element.insert(label, {\n bottom: ' <span class=\"required\">*</span>'\n });\n }\n }\n });\n } else {\n objects.each(function (item) {\n if ($(source).formObj && $(source).formObj.validator) {\n $(source).formObj.validator.reset(item);\n }\n $(item).removeClassName('required-entry');\n var label = findFieldLabel($(item));\n\n if (label) {\n var span = label.down('span');\n\n if (span) {\n Element.remove(span);\n }\n }\n // Hide validation advices if exist\n if ($(item) && $(item).advices) {\n $(item).advices.each(function (pair) {\n if (pair.value != null) pair.value.hide();\n });\n }\n });\n }\n },\n toogleGiftMessage: function (container) {\n if (!$(container).toogleGiftMessage) {\n $(container).toogleGiftMessage = true;\n $(this.getFieldId(container, 'edit')).show();\n $(container).down('.action-link').addClassName('open');\n $(container).down('.default-text').hide();\n $(container).down('.close-text').show();\n } else {\n $(container).toogleGiftMessage = false;\n $(this.getFieldId(container, 'message')).formObj = $(this.getFieldId(container, 'form'));\n var form = jQuery('#' + this.getFieldId(container, 'form'));\n\n jQuery('#' + this.getFieldId(container, 'form')).validate({\n errorClass: 'mage-error'\n });\n\n if (!form.valid()) {\n return false;\n }\n\n new Ajax.Request($(this.getFieldId(container, 'form')).action, {\n parameters: Form.serialize($(this.getFieldId(container, 'form')), true),\n loaderArea: container,\n onComplete: function (transport) {\n\n $(container).down('.action-link').removeClassName('open');\n $(container).down('.default-text').show();\n $(container).down('.close-text').hide();\n $(this.getFieldId(container, 'edit')).hide();\n\n if (transport.responseText.match(/YES/g)) {\n $(container).down('.default-text').down('.edit').show();\n $(container).down('.default-text').down('.add').hide();\n } else {\n $(container).down('.default-text').down('.add').show();\n $(container).down('.default-text').down('.edit').hide();\n }\n\n }.bind(this)\n });\n }\n\n return false;\n },\n saveGiftMessage: function (container) {\n $(this.getFieldId(container, 'message')).formObj = $(this.getFieldId(container, 'form'));\n\n var form = jQuery('#' + this.getFieldId(container, 'form'));\n\n form.validate({\n errorClass: 'mage-error'\n });\n\n if (!form.valid()) {\n return;\n }\n\n new Ajax.Request($(this.getFieldId(container, 'form')).action, {\n parameters: Form.serialize($(this.getFieldId(container, 'form')), true),\n loaderArea: container,\n onSuccess: function (response) {\n var message = '<div class=\"messages\"><div class=\"message message-success success\">' +\n response.responseText +\n '<div data-ui-id=\"messages-message-success\"></div></div></div>';\n\n jQuery('#messages').html(message);\n jQuery(document).scrollTop(0);\n }\n });\n },\n getFieldId: function (container, name) {\n return container + '_' + name;\n }\n };\n\n function findFieldLabel(field) {\n var tdField = $(field).up('td');\n\n if (tdField) {\n var tdLabel = tdField.previous('td');\n\n if (tdLabel) {\n var label = tdLabel.down('label');\n\n if (label) {\n return label;\n }\n }\n }\n\n return false;\n }\n\n window.findFieldLabel = findFieldLabel;\n\n window.GiftOptionsPopup = Class.create();\n GiftOptionsPopup.prototype = {\n //giftOptionsWindowMask: null,\n giftOptionsWindow: null,\n\n initialize: function () {\n $$('.action-link').each(function (el) {\n Event.observe(el, 'click', this.showItemGiftOptions.bind(this));\n }, this);\n\n // Move gift options popup to start of body, because soon it will contain FORM tag that can break DOM layout if within other FORM\n var oldPopupContainer = $('gift_options_configure');\n\n if (oldPopupContainer) {\n oldPopupContainer.remove();\n }\n\n var newPopupContainer = $('gift_options_configure_new');\n\n $(document.body).insert({\n top: newPopupContainer\n });\n newPopupContainer.id = 'gift_options_configure';\n\n // Put controls container inside a FORM tag so we can use Validator\n var form = new Element('form', {\n action: '#', id: 'gift_options_configuration_form', method: 'post'\n });\n var formContents = $('gift_options_form_contents');\n\n if (formContents) {\n formContents.parentNode.appendChild(form);\n form.appendChild(formContents);\n }\n\n this.giftOptionsWindow = $('gift_options_configure');\n\n jQuery(this.giftOptionsWindow).dialog({\n autoOpen: false,\n modal: true,\n resizable: false,\n dialogClass: 'gift-options-popup',\n minWidth: 500,\n width: '75%',\n position: {\n my: 'left+12.5% top',\n at: 'center top',\n of: 'body'\n },\n open: function () {\n jQuery(this).closest('.ui-dialog').addClass('ui-dialog-active');\n\n var topMargin = jQuery(this).closest('.ui-dialog').children('.ui-dialog-titlebar').outerHeight() + 30;\n\n jQuery(this).closest('.ui-dialog').css('margin-top', topMargin);\n },\n close: function () {\n jQuery(this).closest('.ui-dialog').removeClass('ui-dialog-active');\n }\n });\n },\n\n showItemGiftOptions: function (event) {\n var element = Event.element(event).id;\n var itemId = element.sub('gift_options_link_', '');\n\n jQuery(this.giftOptionsWindow).dialog('open');\n\n this.setTitle(itemId);\n\n Event.observe($('gift_options_cancel_button'), 'click', this.onCloseButton.bind(this));\n Event.observe($('gift_options_ok_button'), 'click', this.onOkButton.bind(this));\n Event.stop(event);\n },\n\n setTitle: function (itemId) {\n var productTitleElement = $('order_item_' + itemId + '_title');\n var productTitle = '';\n\n if (productTitleElement) {\n productTitle = productTitleElement.innerHTML;\n }\n jQuery(this.giftOptionsWindow).dialog({\n title: jQuery.mage.__('Gift Options for ') + productTitle\n });\n },\n\n onOkButton: function () {\n var giftOptionsForm = jQuery('#gift_options_configuration_form');\n\n if (!giftOptionsForm.validate({\n errorClass: 'mage-error'\n }).valid()) {\n return false;\n }\n\n if (jQuery.isFunction(giftOptionsForm[0].reset)) {\n giftOptionsForm[0].reset();\n }\n this.closeWindow();\n\n return true;\n },\n\n onCloseButton: function () {\n this.closeWindow();\n },\n\n closeWindow: function () {\n jQuery(this.giftOptionsWindow).dialog('close');\n }\n };\n\n window.GiftMessageSet = Class.create();\n\n GiftMessageSet.prototype = {\n destPrefix: 'current_item_giftmessage_',\n sourcePrefix: 'giftmessage_',\n fields: ['sender', 'recipient', 'message'],\n isObserved: false,\n callback: null,\n\n initialize: function () {\n $$('.action-link').each(function (el) {\n Event.observe(el, 'click', this.setData.bind(this));\n }, this);\n },\n\n setData: function (event) {\n var element = Event.element(event).id;\n\n this.id = element.sub('gift_options_link_', '');\n\n if ($('gift-message-form-data-' + this.id)) {\n this.fields.each(function (el) {\n if ($(this.sourcePrefix + this.id + '_' + el) && $(this.destPrefix + el)) {\n $(this.destPrefix + el).value = $(this.sourcePrefix + this.id + '_' + el).value;\n }\n }, this);\n $('gift_options_giftmessage').show();\n } else if ($('gift_options_giftmessage')) {\n $('gift_options_giftmessage').hide();\n }\n\n if (!this.isObserved) {\n Event.observe('gift_options_ok_button', 'click', this.saveData.bind(this));\n this.isObserved = true;\n }\n },\n\n prepareSaveData: function () {\n var hash = $H();\n\n $$('div[id^=gift_options_data_]').each(function (el) {\n var fields = el.select('input', 'select', 'textarea');\n var data = Form.serializeElements(fields, true);\n\n hash.update(data);\n });\n\n return hash;\n },\n\n setSaveCallback: function (callback) {\n if (typeof callback == 'function') {\n this.callback = callback;\n }\n },\n\n saveData: function (event) {\n this.fields.each(function (el) {\n if ($(this.sourcePrefix + this.id + '_' + el) && $(this.destPrefix + el)) {\n $(this.sourcePrefix + this.id + '_' + el).value = $(this.destPrefix + el).value;\n }\n }, this);\n\n if ($(this.sourcePrefix + this.id + '_form')) {\n $(this.sourcePrefix + this.id + '_form').request();\n } else if (typeof order != 'undefined') {\n var data = this.prepareSaveData();\n var self = this;\n\n jQuery.when(order.loadArea(['items'], true, data.toObject())).done(function () {\n if (self.callback !== null) {\n self.callback();\n }\n });\n }\n }\n };\n\n});\n","Magento_Sales/order/create/form.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* global AdminOrder */\ndefine([\n 'jquery',\n 'Magento_Sales/order/create/scripts'\n], function (jQuery) {\n 'use strict';\n\n var $el = jQuery('#edit_form'),\n config,\n baseUrl,\n order,\n payment;\n\n if (!$el.length || !$el.data('order-config')) {\n return;\n }\n\n config = $el.data('order-config');\n baseUrl = $el.data('load-base-url');\n\n order = new AdminOrder(config);\n order.setLoadBaseUrl(baseUrl);\n\n payment = {\n switchMethod: order.switchPaymentMethod.bind(order)\n };\n\n window.order = order;\n window.payment = payment;\n});\n","Magento_Sales/order/edit/message.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'jquery',\n 'jquery/ui',\n 'Magento_Ui/js/modal/modal',\n 'mage/translate'\n], function ($) {\n 'use strict';\n\n $.widget('mage.orderEditDialog', {\n options: {\n url: null,\n message: null,\n modal: null\n },\n\n /**\n * @protected\n */\n _create: function () {\n this._prepareDialog();\n },\n\n /**\n * Show modal\n */\n showDialog: function () {\n this.options.dialog.html(this.options.message).modal('openModal');\n },\n\n /**\n * Redirect to edit page\n */\n redirect: function () {\n window.location = this.options.url;\n },\n\n /**\n * Prepare modal\n * @protected\n */\n _prepareDialog: function () {\n var self = this;\n\n this.options.dialog = $('<div class=\"ui-dialog-content ui-widget-content\"></div>').modal({\n type: 'popup',\n modalClass: 'edit-order-popup',\n title: $.mage.__('Edit Order'),\n buttons: [{\n text: $.mage.__('Ok'),\n 'class': 'action-primary',\n\n /** @inheritdoc */\n click: function () {\n self.redirect();\n }\n }]\n });\n }\n });\n\n return $.mage.orderEditDialog;\n});\n","Magento_Sales/order/edit/address/form.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 * Currently Magento App stores both region_id and region (as text) values.\n * To prevent missing region (as text) we need to copy it in hidden field.\n * @param {Array} config\n * @param {String} element\n */\n return function (config, element) {\n var form = $(element),\n regionId = form.find('#region_id'),\n\n /**\n * Set region callback\n */\n setRegion = function () {\n form.find('#region').val(regionId.filter(':visible').find(':selected').text());\n };\n\n if (regionId.is('visible')) {\n setRegion();\n }\n\n regionId.on('change', setRegion);\n form.find('#country_id').on('change', setRegion);\n };\n});\n","Magento_Sales/order/view/post-wrapper.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/confirm',\n 'mage/translate'\n], function ($, confirm) {\n 'use strict';\n\n /**\n * @param {String} url\n * @returns {Object}\n */\n function getForm(url) {\n return $('<form>', {\n 'action': url,\n 'method': 'POST'\n }).append($('<input>', {\n 'name': 'form_key',\n 'value': window.FORM_KEY,\n 'type': 'hidden'\n }));\n }\n\n $('#order-view-cancel-button').click(function () {\n var msg = $.mage.__('Are you sure you want to cancel this order?'),\n url = $('#order-view-cancel-button').data('url');\n\n confirm({\n 'content': msg,\n 'actions': {\n\n /**\n * 'Confirm' action handler.\n */\n confirm: function () {\n getForm(url).appendTo('body').submit();\n }\n }\n });\n\n return false;\n });\n\n $('#order-view-hold-button').click(function () {\n var url = $('#order-view-hold-button').data('url');\n\n getForm(url).appendTo('body').submit();\n });\n\n $('#order-view-unhold-button').click(function () {\n var url = $('#order-view-unhold-button').data('url');\n\n getForm(url).appendTo('body').submit();\n });\n});\n","jquery/jquery.tabs.js":"/* ========================================================\n * bootstrap-tab.js v2.0.4\n * http://twitter.github.com/bootstrap/javascript.html#tabs\n * ========================================================\n * Copyright 2012 Twitter, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n * ======================================================== */\n\ndefine([\n \"jquery\"\n], function(jQuery){\n\n\n!function ($) {\n\n \"use strict\"; // jshint ;_;\n\n\n /* TAB CLASS DEFINITION\n * ==================== */\n\n var Tab = function ( element ) {\n this.element = $(element)\n };\n\n Tab.prototype = {\n\n constructor: Tab\n\n , show: function () {\n var $this = this.element\n , $ul = $this.closest('ul:not(.dropdown-menu)')\n , selector = $this.attr('data-target')\n , previous\n , $target\n , e;\n\n if (!selector) {\n selector = $this.attr('href');\n selector = selector && selector.replace(/.*(?=#[^\\s]*$)/, ''); //strip for ie7\n }\n\n if ( $this.parent('li').hasClass('active') ) return;\n\n previous = $ul.find('.active a').last()[0];\n\n e = $.Event('show', {\n relatedTarget: previous\n });\n\n $this.trigger(e);\n\n if (e.isDefaultPrevented()) return;\n\n $target = $(selector);\n\n this.activate($this.parent('li'), $ul);\n this.activate($target, $target.parent(), function () {\n $this.trigger({\n type: 'shown'\n , relatedTarget: previous\n })\n })\n }\n\n , activate: function ( element, container, callback) {\n var $active = container.find('> .active')\n , transition = callback\n && $.support.transition\n && $active.hasClass('fade');\n\n function next() {\n $active\n .removeClass('active')\n .find('> .dropdown-menu > .active')\n .removeClass('active');\n\n element.addClass('active');\n\n if (transition) {\n element[0].offsetWidth; // reflow for transition\n element.addClass('in');\n } else {\n element.removeClass('fade')\n }\n\n if ( element.parent('.dropdown-menu') ) {\n element.closest('li.dropdown').addClass('active')\n }\n\n callback && callback()\n }\n\n transition ?\n $active.one($.support.transition.end, next) :\n next();\n\n $active.removeClass('in')\n }\n };\n\n\n /* TAB PLUGIN DEFINITION\n * ===================== */\n\n $.fn.tab = function ( option ) {\n return this.each(function () {\n var $this = $(this)\n , data = $this.data('tab');\n if (!data) $this.data('tab', (data = new Tab(this)));\n if (typeof option == 'string') data[option]()\n })\n };\n\n $.fn.tab.Constructor = Tab;\n\n\n /* TAB DATA-API\n * ============ */\n\n $(function () {\n $('body').on('click.tab.data-api', '[data-toggle=\"tab\"], [data-toggle=\"pill\"]', function (e) {\n e.preventDefault();\n $(this).tab('show')\n })\n })\n\n}(jQuery);\n\n/* =============================================================\n * bootstrap-collapse.js v2.0.4\n * http://twitter.github.com/bootstrap/javascript.html#collapse\n * =============================================================\n * Copyright 2012 Twitter, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n * ============================================================ */\n\n\n!function ($) {\n\n \"use strict\"; // jshint ;_;\n\n\n /* COLLAPSE PUBLIC CLASS DEFINITION\n * ================================ */\n\n var Collapse = function (element, options) {\n this.$element = $(element);\n this.options = $.extend({}, $.fn.collapse.defaults, options);\n\n if (this.options.parent) {\n this.$parent = $(this.options.parent)\n }\n\n this.options.toggle && this.toggle()\n };\n\n Collapse.prototype = {\n\n constructor: Collapse\n\n , dimension: function () {\n var hasWidth = this.$element.hasClass('width');\n return hasWidth ? 'width' : 'height'\n }\n\n , show: function () {\n var dimension\n , scroll\n , actives\n , hasData;\n\n if (this.transitioning) return;\n\n dimension = this.dimension();\n scroll = $.camelCase(['scroll', dimension].join('-'));\n actives = this.$parent && this.$parent.find('> .accordion-group > .in');\n\n if (actives && actives.length) {\n hasData = actives.data('collapse');\n if (hasData && hasData.transitioning) return;\n actives.collapse('hide');\n hasData || actives.data('collapse', null)\n }\n\n this.$element[dimension](0);\n this.transition('addClass', $.Event('show'), 'shown');\n this.$element[dimension](this.$element[0][scroll]);\n }\n\n , hide: function () {\n var dimension;\n if (this.transitioning) return;\n dimension = this.dimension();\n this.reset(this.$element[dimension]());\n this.transition('removeClass', $.Event('hide'), 'hidden');\n this.$element[dimension](0)\n }\n\n , reset: function (size) {\n var dimension = this.dimension();\n\n this.$element\n .removeClass('collapse')\n [dimension](size || 'auto')\n [0].offsetWidth;\n\n this.$element[size !== null ? 'addClass' : 'removeClass']('collapse');\n\n return this\n }\n\n , transition: function (method, startEvent, completeEvent) {\n var that = this\n , complete = function () {\n if (startEvent.type == 'show') that.reset();\n that.transitioning = 0;\n that.$element.trigger(completeEvent)\n };\n\n this.$element.trigger(startEvent);\n\n if (startEvent.isDefaultPrevented()) return;\n\n this.transitioning = 1;\n\n this.$element[method]('in');\n\n $.support.transition && this.$element.hasClass('collapse') ?\n this.$element.one($.support.transition.end, complete) :\n complete()\n }\n\n , toggle: function () {\n this[this.$element.hasClass('in') ? 'hide' : 'show']();\n }\n\n };\n\n\n /* COLLAPSIBLE PLUGIN DEFINITION\n * ============================== */\n\n $.fn.collapse = function (option) {\n return this.each(function () {\n var $this = $(this)\n , data = $this.data('collapse')\n , options = typeof option == 'object' && option;\n if (!data) $this.data('collapse', (data = new Collapse(this, options)));\n if (typeof option == 'string') data[option]()\n })\n };\n\n $.fn.collapse.defaults = {\n toggle: true\n };\n\n $.fn.collapse.Constructor = Collapse;\n\n\n /* COLLAPSIBLE DATA-API\n * ==================== */\n\n $(function () {\n $('body').on('click.collapse.data-api', '[data-toggle=collapse]', function ( e ) {\n var $this = $(this), href\n , target = $this.attr('data-target')\n || e.preventDefault()\n || (href = $this.attr('href')) && href.replace(/.*(?=#[^\\s]+$)/, '') //strip for ie7\n , option = $(target).data('collapse') ? 'toggle' : $this.data();\n $(target).collapse(option);\n $(this).toggleClass('active');\n })\n })\n\n}(jQuery);\n\n});","jquery/jquery-ui-timepicker-addon.js":"/*! jQuery Timepicker Addon - v1.4.3 - 2013-11-30\n* http://trentrichardson.com/examples/timepicker\n* Copyright (c) 2013 Trent Richardson; Licensed MIT */\n(function (factory) {\n if (typeof define === 'function' && define.amd) {\n define([\n \"jquery\",\n \"jquery/ui\"\n ], factory);\n } else {\n factory(jQuery);\n }\n}(function ($) {\n\n\t/*\n\t* Lets not redefine timepicker, Prevent \"Uncaught RangeError: Maximum call stack size exceeded\"\n\t*/\n\t$.ui.timepicker = $.ui.timepicker || {};\n\tif ($.ui.timepicker.version) {\n\t\treturn;\n\t}\n\n\t/*\n\t* Extend jQueryUI, get it started with our version number\n\t*/\n\t$.extend($.ui, {\n\t\ttimepicker: {\n\t\t\tversion: \"1.4.3\"\n\t\t}\n\t});\n\n\t/* \n\t* Timepicker manager.\n\t* Use the singleton instance of this class, $.timepicker, to interact with the time picker.\n\t* Settings for (groups of) time pickers are maintained in an instance object,\n\t* allowing multiple different settings on the same page.\n\t*/\n\tvar Timepicker = function () {\n\t\tthis.regional = []; // Available regional settings, indexed by language code\n\t\tthis.regional[''] = { // Default regional settings\n\t\t\tcurrentText: 'Now',\n\t\t\tcloseText: 'Done',\n\t\t\tamNames: ['AM', 'A'],\n\t\t\tpmNames: ['PM', 'P'],\n\t\t\ttimeFormat: 'HH:mm',\n\t\t\ttimeSuffix: '',\n\t\t\ttimeOnlyTitle: 'Choose Time',\n\t\t\ttimeText: 'Time',\n\t\t\thourText: 'Hour',\n\t\t\tminuteText: 'Minute',\n\t\t\tsecondText: 'Second',\n\t\t\tmillisecText: 'Millisecond',\n\t\t\tmicrosecText: 'Microsecond',\n\t\t\ttimezoneText: 'Time Zone',\n\t\t\tisRTL: false\n\t\t};\n\t\tthis._defaults = { // Global defaults for all the datetime picker instances\n\t\t\tshowButtonPanel: true,\n\t\t\ttimeOnly: false,\n\t\t\tshowHour: null,\n\t\t\tshowMinute: null,\n\t\t\tshowSecond: null,\n\t\t\tshowMillisec: null,\n\t\t\tshowMicrosec: null,\n\t\t\tshowTimezone: null,\n\t\t\tshowTime: true,\n\t\t\tstepHour: 1,\n\t\t\tstepMinute: 1,\n\t\t\tstepSecond: 1,\n\t\t\tstepMillisec: 1,\n\t\t\tstepMicrosec: 1,\n\t\t\thour: 0,\n\t\t\tminute: 0,\n\t\t\tsecond: 0,\n\t\t\tmillisec: 0,\n\t\t\tmicrosec: 0,\n\t\t\ttimezone: null,\n\t\t\thourMin: 0,\n\t\t\tminuteMin: 0,\n\t\t\tsecondMin: 0,\n\t\t\tmillisecMin: 0,\n\t\t\tmicrosecMin: 0,\n\t\t\thourMax: 23,\n\t\t\tminuteMax: 59,\n\t\t\tsecondMax: 59,\n\t\t\tmillisecMax: 999,\n\t\t\tmicrosecMax: 999,\n\t\t\tminDateTime: null,\n\t\t\tmaxDateTime: null,\n\t\t\tonSelect: null,\n\t\t\thourGrid: 0,\n\t\t\tminuteGrid: 0,\n\t\t\tsecondGrid: 0,\n\t\t\tmillisecGrid: 0,\n\t\t\tmicrosecGrid: 0,\n\t\t\talwaysSetTime: true,\n\t\t\tseparator: ' ',\n\t\t\taltFieldTimeOnly: true,\n\t\t\taltTimeFormat: null,\n\t\t\taltSeparator: null,\n\t\t\taltTimeSuffix: null,\n\t\t\tpickerTimeFormat: null,\n\t\t\tpickerTimeSuffix: null,\n\t\t\tshowTimepicker: true,\n\t\t\ttimezoneList: null,\n\t\t\taddSliderAccess: false,\n\t\t\tsliderAccessArgs: null,\n\t\t\tcontrolType: 'slider',\n\t\t\tdefaultValue: null,\n\t\t\tparse: 'strict'\n\t\t};\n\t\t$.extend(this._defaults, this.regional['']);\n\t};\n\n\t$.extend(Timepicker.prototype, {\n\t\t$input: null,\n\t\t$altInput: null,\n\t\t$timeObj: null,\n\t\tinst: null,\n\t\thour_slider: null,\n\t\tminute_slider: null,\n\t\tsecond_slider: null,\n\t\tmillisec_slider: null,\n\t\tmicrosec_slider: null,\n\t\ttimezone_select: null,\n\t\thour: 0,\n\t\tminute: 0,\n\t\tsecond: 0,\n\t\tmillisec: 0,\n\t\tmicrosec: 0,\n\t\ttimezone: null,\n\t\thourMinOriginal: null,\n\t\tminuteMinOriginal: null,\n\t\tsecondMinOriginal: null,\n\t\tmillisecMinOriginal: null,\n\t\tmicrosecMinOriginal: null,\n\t\thourMaxOriginal: null,\n\t\tminuteMaxOriginal: null,\n\t\tsecondMaxOriginal: null,\n\t\tmillisecMaxOriginal: null,\n\t\tmicrosecMaxOriginal: null,\n\t\tampm: '',\n\t\tformattedDate: '',\n\t\tformattedTime: '',\n\t\tformattedDateTime: '',\n\t\ttimezoneList: null,\n\t\tunits: ['hour', 'minute', 'second', 'millisec', 'microsec'],\n\t\tsupport: {},\n\t\tcontrol: null,\n\n\t\t/* \n\t\t* Override the default settings for all instances of the time picker.\n\t\t* @param {Object} settings object - the new settings to use as defaults (anonymous object)\n\t\t* @return {Object} the manager object\n\t\t*/\n\t\tsetDefaults: function (settings) {\n\t\t\textendRemove(this._defaults, settings || {});\n\t\t\treturn this;\n\t\t},\n\n\t\t/*\n\t\t* Create a new Timepicker instance\n\t\t*/\n\t\t_newInst: function ($input, opts) {\n\t\t\tvar tp_inst = new Timepicker(),\n\t\t\t\tinlineSettings = {},\n\t\t\t\tfns = {},\n\t\t\t\toverrides, i;\n\n\t\t\tfor (var attrName in this._defaults) {\n\t\t\t\tif (this._defaults.hasOwnProperty(attrName)) {\n\t\t\t\t\tvar attrValue = $input.attr('time:' + attrName);\n\t\t\t\t\tif (attrValue) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tinlineSettings[attrName] = eval(attrValue);\n\t\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t\tinlineSettings[attrName] = attrValue;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\toverrides = {\n\t\t\t\tbeforeShow: function (input, dp_inst) {\n\t\t\t\t\tif ($.isFunction(tp_inst._defaults.evnts.beforeShow)) {\n\t\t\t\t\t\treturn tp_inst._defaults.evnts.beforeShow.call($input[0], input, dp_inst, tp_inst);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tonChangeMonthYear: function (year, month, dp_inst) {\n\t\t\t\t\t// Update the time as well : this prevents the time from disappearing from the $input field.\n\t\t\t\t\ttp_inst._updateDateTime(dp_inst);\n\t\t\t\t\tif ($.isFunction(tp_inst._defaults.evnts.onChangeMonthYear)) {\n\t\t\t\t\t\ttp_inst._defaults.evnts.onChangeMonthYear.call($input[0], year, month, dp_inst, tp_inst);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tonClose: function (dateText, dp_inst) {\n\t\t\t\t\tif (tp_inst.timeDefined === true && $input.val() !== '') {\n\t\t\t\t\t\ttp_inst._updateDateTime(dp_inst);\n\t\t\t\t\t}\n\t\t\t\t\tif ($.isFunction(tp_inst._defaults.evnts.onClose)) {\n\t\t\t\t\t\ttp_inst._defaults.evnts.onClose.call($input[0], dateText, dp_inst, tp_inst);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t};\n\t\t\tfor (i in overrides) {\n\t\t\t\tif (overrides.hasOwnProperty(i)) {\n\t\t\t\t\tfns[i] = opts[i] || null;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttp_inst._defaults = $.extend({}, this._defaults, inlineSettings, opts, overrides, {\n\t\t\t\tevnts: fns,\n\t\t\t\ttimepicker: tp_inst // add timepicker as a property of datepicker: $.datepicker._get(dp_inst, 'timepicker');\n\t\t\t});\n\t\t\ttp_inst.amNames = $.map(tp_inst._defaults.amNames, function (val) {\n\t\t\t\treturn val.toUpperCase();\n\t\t\t});\n\t\t\ttp_inst.pmNames = $.map(tp_inst._defaults.pmNames, function (val) {\n\t\t\t\treturn val.toUpperCase();\n\t\t\t});\n\n\t\t\t// detect which units are supported\n\t\t\ttp_inst.support = detectSupport(\n\t\t\t\t\ttp_inst._defaults.timeFormat + \n\t\t\t\t\t(tp_inst._defaults.pickerTimeFormat ? tp_inst._defaults.pickerTimeFormat : '') +\n\t\t\t\t\t(tp_inst._defaults.altTimeFormat ? tp_inst._defaults.altTimeFormat : ''));\n\n\t\t\t// controlType is string - key to our this._controls\n\t\t\tif (typeof(tp_inst._defaults.controlType) === 'string') {\n\t\t\t\tif (tp_inst._defaults.controlType === 'slider' && typeof($.ui.slider) === 'undefined') {\n\t\t\t\t\ttp_inst._defaults.controlType = 'select';\n\t\t\t\t}\n\t\t\t\ttp_inst.control = tp_inst._controls[tp_inst._defaults.controlType];\n\t\t\t}\n\t\t\t// controlType is an object and must implement create, options, value methods\n\t\t\telse {\n\t\t\t\ttp_inst.control = tp_inst._defaults.controlType;\n\t\t\t}\n\n\t\t\t// prep the timezone options\n\t\t\tvar timezoneList = [-720, -660, -600, -570, -540, -480, -420, -360, -300, -270, -240, -210, -180, -120, -60,\n\t\t\t\t\t0, 60, 120, 180, 210, 240, 270, 300, 330, 345, 360, 390, 420, 480, 525, 540, 570, 600, 630, 660, 690, 720, 765, 780, 840];\n\t\t\tif (tp_inst._defaults.timezoneList !== null) {\n\t\t\t\ttimezoneList = tp_inst._defaults.timezoneList;\n\t\t\t}\n\t\t\tvar tzl = timezoneList.length, tzi = 0, tzv = null;\n\t\t\tif (tzl > 0 && typeof timezoneList[0] !== 'object') {\n\t\t\t\tfor (; tzi < tzl; tzi++) {\n\t\t\t\t\ttzv = timezoneList[tzi];\n\t\t\t\t\ttimezoneList[tzi] = { value: tzv, label: $.timepicker.timezoneOffsetString(tzv, tp_inst.support.iso8601) };\n\t\t\t\t}\n\t\t\t}\n\t\t\ttp_inst._defaults.timezoneList = timezoneList;\n\n\t\t\t// set the default units\n\t\t\ttp_inst.timezone = tp_inst._defaults.timezone !== null ? $.timepicker.timezoneOffsetNumber(tp_inst._defaults.timezone) :\n\t\t\t\t\t\t\t((new Date()).getTimezoneOffset() * -1);\n\t\t\ttp_inst.hour = tp_inst._defaults.hour < tp_inst._defaults.hourMin ? tp_inst._defaults.hourMin :\n\t\t\t\t\t\t\ttp_inst._defaults.hour > tp_inst._defaults.hourMax ? tp_inst._defaults.hourMax : tp_inst._defaults.hour;\n\t\t\ttp_inst.minute = tp_inst._defaults.minute < tp_inst._defaults.minuteMin ? tp_inst._defaults.minuteMin :\n\t\t\t\t\t\t\ttp_inst._defaults.minute > tp_inst._defaults.minuteMax ? tp_inst._defaults.minuteMax : tp_inst._defaults.minute;\n\t\t\ttp_inst.second = tp_inst._defaults.second < tp_inst._defaults.secondMin ? tp_inst._defaults.secondMin :\n\t\t\t\t\t\t\ttp_inst._defaults.second > tp_inst._defaults.secondMax ? tp_inst._defaults.secondMax : tp_inst._defaults.second;\n\t\t\ttp_inst.millisec = tp_inst._defaults.millisec < tp_inst._defaults.millisecMin ? tp_inst._defaults.millisecMin :\n\t\t\t\t\t\t\ttp_inst._defaults.millisec > tp_inst._defaults.millisecMax ? tp_inst._defaults.millisecMax : tp_inst._defaults.millisec;\n\t\t\ttp_inst.microsec = tp_inst._defaults.microsec < tp_inst._defaults.microsecMin ? tp_inst._defaults.microsecMin :\n\t\t\t\t\t\t\ttp_inst._defaults.microsec > tp_inst._defaults.microsecMax ? tp_inst._defaults.microsecMax : tp_inst._defaults.microsec;\n\t\t\ttp_inst.ampm = '';\n\t\t\ttp_inst.$input = $input;\n\n\t\t\tif (tp_inst._defaults.altField) {\n\t\t\t\ttp_inst.$altInput = $(tp_inst._defaults.altField).css({\n\t\t\t\t\tcursor: 'pointer'\n\t\t\t\t}).focus(function () {\n\t\t\t\t\t$input.trigger(\"focus\");\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif (tp_inst._defaults.minDate === 0 || tp_inst._defaults.minDateTime === 0) {\n\t\t\t\ttp_inst._defaults.minDate = new Date();\n\t\t\t}\n\t\t\tif (tp_inst._defaults.maxDate === 0 || tp_inst._defaults.maxDateTime === 0) {\n\t\t\t\ttp_inst._defaults.maxDate = new Date();\n\t\t\t}\n\n\t\t\t// datepicker needs minDate/maxDate, timepicker needs minDateTime/maxDateTime..\n\t\t\tif (tp_inst._defaults.minDate !== undefined && tp_inst._defaults.minDate instanceof Date) {\n\t\t\t\ttp_inst._defaults.minDateTime = new Date(tp_inst._defaults.minDate.getTime());\n\t\t\t}\n\t\t\tif (tp_inst._defaults.minDateTime !== undefined && tp_inst._defaults.minDateTime instanceof Date) {\n\t\t\t\ttp_inst._defaults.minDate = new Date(tp_inst._defaults.minDateTime.getTime());\n\t\t\t}\n\t\t\tif (tp_inst._defaults.maxDate !== undefined && tp_inst._defaults.maxDate instanceof Date) {\n\t\t\t\ttp_inst._defaults.maxDateTime = new Date(tp_inst._defaults.maxDate.getTime());\n\t\t\t}\n\t\t\tif (tp_inst._defaults.maxDateTime !== undefined && tp_inst._defaults.maxDateTime instanceof Date) {\n\t\t\t\ttp_inst._defaults.maxDate = new Date(tp_inst._defaults.maxDateTime.getTime());\n\t\t\t}\n\t\t\ttp_inst.$input.bind('focus', function () {\n\t\t\t\ttp_inst._onFocus();\n\t\t\t});\n\n\t\t\treturn tp_inst;\n\t\t},\n\n\t\t/*\n\t\t* add our sliders to the calendar\n\t\t*/\n\t\t_addTimePicker: function (dp_inst) {\n\t\t\tvar currDT = (this.$altInput && this._defaults.altFieldTimeOnly) ? this.$input.val() + ' ' + this.$altInput.val() : this.$input.val();\n\n\t\t\tthis.timeDefined = this._parseTime(currDT);\n\t\t\tthis._limitMinMaxDateTime(dp_inst, false);\n\t\t\tthis._injectTimePicker();\n\t\t},\n\n\t\t/*\n\t\t* parse the time string from input value or _setTime\n\t\t*/\n\t\t_parseTime: function (timeString, withDate) {\n\t\t\tif (!this.inst) {\n\t\t\t\tthis.inst = $.datepicker._getInst(this.$input[0]);\n\t\t\t}\n\n\t\t\tif (withDate || !this._defaults.timeOnly) {\n\t\t\t\tvar dp_dateFormat = $.datepicker._get(this.inst, 'dateFormat');\n\t\t\t\ttry {\n\t\t\t\t\tvar parseRes = parseDateTimeInternal(dp_dateFormat, this._defaults.timeFormat, timeString, $.datepicker._getFormatConfig(this.inst), this._defaults);\n\t\t\t\t\tif (!parseRes.timeObj) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\t$.extend(this, parseRes.timeObj);\n\t\t\t\t} catch (err) {\n\t\t\t\t\t$.timepicker.log(\"Error parsing the date/time string: \" + err +\n\t\t\t\t\t\t\t\t\t\"\\ndate/time string = \" + timeString +\n\t\t\t\t\t\t\t\t\t\"\\ntimeFormat = \" + this._defaults.timeFormat +\n\t\t\t\t\t\t\t\t\t\"\\ndateFormat = \" + dp_dateFormat);\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t} else {\n\t\t\t\tvar timeObj = $.datepicker.parseTime(this._defaults.timeFormat, timeString, this._defaults);\n\t\t\t\tif (!timeObj) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\t$.extend(this, timeObj);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t},\n\n\t\t/*\n\t\t* generate and inject html for timepicker into ui datepicker\n\t\t*/\n\t\t_injectTimePicker: function () {\n\t\t\tvar $dp = this.inst.dpDiv,\n\t\t\t\to = this.inst.settings,\n\t\t\t\ttp_inst = this,\n\t\t\t\tlitem = '',\n\t\t\t\tuitem = '',\n\t\t\t\tshow = null,\n\t\t\t\tmax = {},\n\t\t\t\tgridSize = {},\n\t\t\t\tsize = null,\n\t\t\t\ti = 0,\n\t\t\t\tl = 0;\n\n\t\t\t// Prevent displaying twice\n\t\t\tif ($dp.find(\"div.ui-timepicker-div\").length === 0 && o.showTimepicker) {\n\t\t\t\tvar noDisplay = ' style=\"display:none;\"',\n\t\t\t\t\thtml = '<div class=\"ui-timepicker-div' + (o.isRTL ? ' ui-timepicker-rtl' : '') + '\"><dl>' + '<dt class=\"ui_tpicker_time_label\"' + ((o.showTime) ? '' : noDisplay) + '>' + o.timeText + '</dt>' +\n\t\t\t\t\t\t\t\t'<dd class=\"ui_tpicker_time\"' + ((o.showTime) ? '' : noDisplay) + '></dd>';\n\n\t\t\t\t// Create the markup\n\t\t\t\tfor (i = 0, l = this.units.length; i < l; i++) {\n\t\t\t\t\tlitem = this.units[i];\n\t\t\t\t\tuitem = litem.substr(0, 1).toUpperCase() + litem.substr(1);\n\t\t\t\t\tshow = o['show' + uitem] !== null ? o['show' + uitem] : this.support[litem];\n\n\t\t\t\t\t// Added by Peter Medeiros:\n\t\t\t\t\t// - Figure out what the hour/minute/second max should be based on the step values.\n\t\t\t\t\t// - Example: if stepMinute is 15, then minMax is 45.\n\t\t\t\t\tmax[litem] = parseInt((o[litem + 'Max'] - ((o[litem + 'Max'] - o[litem + 'Min']) % o['step' + uitem])), 10);\n\t\t\t\t\tgridSize[litem] = 0;\n\n\t\t\t\t\thtml += '<dt class=\"ui_tpicker_' + litem + '_label\"' + (show ? '' : noDisplay) + '>' + o[litem + 'Text'] + '</dt>' +\n\t\t\t\t\t\t\t\t'<dd class=\"ui_tpicker_' + litem + '\"><div class=\"ui_tpicker_' + litem + '_slider\"' + (show ? '' : noDisplay) + '></div>';\n\n\t\t\t\t\tif (show && o[litem + 'Grid'] > 0) {\n\t\t\t\t\t\thtml += '<div style=\"padding-left: 1px\"><table class=\"ui-tpicker-grid-label\"><tr>';\n\n\t\t\t\t\t\tif (litem === 'hour') {\n\t\t\t\t\t\t\tfor (var h = o[litem + 'Min']; h <= max[litem]; h += parseInt(o[litem + 'Grid'], 10)) {\n\t\t\t\t\t\t\t\tgridSize[litem]++;\n\t\t\t\t\t\t\t\tvar tmph = $.datepicker.formatTime(this.support.ampm ? 'hht' : 'HH', {hour: h}, o);\n\t\t\t\t\t\t\t\thtml += '<td data-for=\"' + litem + '\">' + tmph + '</td>';\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tfor (var m = o[litem + 'Min']; m <= max[litem]; m += parseInt(o[litem + 'Grid'], 10)) {\n\t\t\t\t\t\t\t\tgridSize[litem]++;\n\t\t\t\t\t\t\t\thtml += '<td data-for=\"' + litem + '\">' + ((m < 10) ? '0' : '') + m + '</td>';\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\thtml += '</tr></table></div>';\n\t\t\t\t\t}\n\t\t\t\t\thtml += '</dd>';\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// Timezone\n\t\t\t\tvar showTz = o.showTimezone !== null ? o.showTimezone : this.support.timezone;\n\t\t\t\thtml += '<dt class=\"ui_tpicker_timezone_label\"' + (showTz ? '' : noDisplay) + '>' + o.timezoneText + '</dt>';\n\t\t\t\thtml += '<dd class=\"ui_tpicker_timezone\" ' + (showTz ? '' : noDisplay) + '></dd>';\n\n\t\t\t\t// Create the elements from string\n\t\t\t\thtml += '</dl></div>';\n\t\t\t\tvar $tp = $(html);\n\n\t\t\t\t// if we only want time picker...\n\t\t\t\tif (o.timeOnly === true) {\n\t\t\t\t\t$tp.prepend('<div class=\"ui-widget-header ui-helper-clearfix ui-corner-all\">' + '<div class=\"ui-datepicker-title\">' + o.timeOnlyTitle + '</div>' + '</div>');\n\t\t\t\t\t$dp.find('.ui-datepicker-header, .ui-datepicker-calendar').hide();\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// add sliders, adjust grids, add events\n\t\t\t\tfor (i = 0, l = tp_inst.units.length; i < l; i++) {\n\t\t\t\t\tlitem = tp_inst.units[i];\n\t\t\t\t\tuitem = litem.substr(0, 1).toUpperCase() + litem.substr(1);\n\t\t\t\t\tshow = o['show' + uitem] !== null ? o['show' + uitem] : this.support[litem];\n\n\t\t\t\t\t// add the slider\n\t\t\t\t\ttp_inst[litem + '_slider'] = tp_inst.control.create(tp_inst, $tp.find('.ui_tpicker_' + litem + '_slider'), litem, tp_inst[litem], o[litem + 'Min'], max[litem], o['step' + uitem]);\n\n\t\t\t\t\t// adjust the grid and add click event\n\t\t\t\t\tif (show && o[litem + 'Grid'] > 0) {\n\t\t\t\t\t\tsize = 100 * gridSize[litem] * o[litem + 'Grid'] / (max[litem] - o[litem + 'Min']);\n\t\t\t\t\t\t$tp.find('.ui_tpicker_' + litem + ' table').css({\n\t\t\t\t\t\t\twidth: size + \"%\",\n\t\t\t\t\t\t\tmarginLeft: o.isRTL ? '0' : ((size / (-2 * gridSize[litem])) + \"%\"),\n\t\t\t\t\t\t\tmarginRight: o.isRTL ? ((size / (-2 * gridSize[litem])) + \"%\") : '0',\n\t\t\t\t\t\t\tborderCollapse: 'collapse'\n\t\t\t\t\t\t}).find(\"td\").click(function (e) {\n\t\t\t\t\t\t\t\tvar $t = $(this),\n\t\t\t\t\t\t\t\t\th = $t.html(),\n\t\t\t\t\t\t\t\t\tn = parseInt(h.replace(/[^0-9]/g), 10),\n\t\t\t\t\t\t\t\t\tap = h.replace(/[^apm]/ig),\n\t\t\t\t\t\t\t\t\tf = $t.data('for'); // loses scope, so we use data-for\n\n\t\t\t\t\t\t\t\tif (f === 'hour') {\n\t\t\t\t\t\t\t\t\tif (ap.indexOf('p') !== -1 && n < 12) {\n\t\t\t\t\t\t\t\t\t\tn += 12;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\t\tif (ap.indexOf('a') !== -1 && n === 12) {\n\t\t\t\t\t\t\t\t\t\t\tn = 0;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\ttp_inst.control.value(tp_inst, tp_inst[f + '_slider'], litem, n);\n\n\t\t\t\t\t\t\t\ttp_inst._onTimeChange();\n\t\t\t\t\t\t\t\ttp_inst._onSelectHandler();\n\t\t\t\t\t\t\t}).css({\n\t\t\t\t\t\t\t\tcursor: 'pointer',\n\t\t\t\t\t\t\t\twidth: (100 / gridSize[litem]) + '%',\n\t\t\t\t\t\t\t\ttextAlign: 'center',\n\t\t\t\t\t\t\t\toverflow: 'hidden'\n\t\t\t\t\t\t\t});\n\t\t\t\t\t} // end if grid > 0\n\t\t\t\t} // end for loop\n\n\t\t\t\t// Add timezone options\n\t\t\t\tthis.timezone_select = $tp.find('.ui_tpicker_timezone').append('<select></select>').find(\"select\");\n\t\t\t\t$.fn.append.apply(this.timezone_select,\n\t\t\t\t$.map(o.timezoneList, function (val, idx) {\n\t\t\t\t\treturn $(\"<option />\").val(typeof val === \"object\" ? val.value : val).text(typeof val === \"object\" ? val.label : val);\n\t\t\t\t}));\n\t\t\t\tif (typeof(this.timezone) !== \"undefined\" && this.timezone !== null && this.timezone !== \"\") {\n\t\t\t\t\tvar local_timezone = (new Date(this.inst.selectedYear, this.inst.selectedMonth, this.inst.selectedDay, 12)).getTimezoneOffset() * -1;\n\t\t\t\t\tif (local_timezone === this.timezone) {\n\t\t\t\t\t\tselectLocalTimezone(tp_inst);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.timezone_select.val(this.timezone);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tif (typeof(this.hour) !== \"undefined\" && this.hour !== null && this.hour !== \"\") {\n\t\t\t\t\t\tthis.timezone_select.val(o.timezone);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tselectLocalTimezone(tp_inst);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tthis.timezone_select.change(function () {\n\t\t\t\t\ttp_inst._onTimeChange();\n\t\t\t\t\ttp_inst._onSelectHandler();\n\t\t\t\t});\n\t\t\t\t// End timezone options\n\t\t\t\t\n\t\t\t\t// inject timepicker into datepicker\n\t\t\t\tvar $buttonPanel = $dp.find('.ui-datepicker-buttonpane');\n\t\t\t\tif ($buttonPanel.length) {\n\t\t\t\t\t$buttonPanel.before($tp);\n\t\t\t\t} else {\n\t\t\t\t\t$dp.append($tp);\n\t\t\t\t}\n\n\t\t\t\tthis.$timeObj = $tp.find('.ui_tpicker_time');\n\n\t\t\t\tif (this.inst !== null) {\n\t\t\t\t\tvar timeDefined = this.timeDefined;\n\t\t\t\t\tthis._onTimeChange();\n\t\t\t\t\tthis.timeDefined = timeDefined;\n\t\t\t\t}\n\n\t\t\t\t// slideAccess integration: http://trentrichardson.com/2011/11/11/jquery-ui-sliders-and-touch-accessibility/\n\t\t\t\tif (this._defaults.addSliderAccess) {\n\t\t\t\t\tvar sliderAccessArgs = this._defaults.sliderAccessArgs,\n\t\t\t\t\t\trtl = this._defaults.isRTL;\n\t\t\t\t\tsliderAccessArgs.isRTL = rtl;\n\t\t\t\t\t\t\n\t\t\t\t\tsetTimeout(function () { // fix for inline mode\n\t\t\t\t\t\tif ($tp.find('.ui-slider-access').length === 0) {\n\t\t\t\t\t\t\t$tp.find('.ui-slider:visible').sliderAccess(sliderAccessArgs);\n\n\t\t\t\t\t\t\t// fix any grids since sliders are shorter\n\t\t\t\t\t\t\tvar sliderAccessWidth = $tp.find('.ui-slider-access:eq(0)').outerWidth(true);\n\t\t\t\t\t\t\tif (sliderAccessWidth) {\n\t\t\t\t\t\t\t\t$tp.find('table:visible').each(function () {\n\t\t\t\t\t\t\t\t\tvar $g = $(this),\n\t\t\t\t\t\t\t\t\t\toldWidth = $g.outerWidth(),\n\t\t\t\t\t\t\t\t\t\toldMarginLeft = $g.css(rtl ? 'marginRight' : 'marginLeft').toString().replace('%', ''),\n\t\t\t\t\t\t\t\t\t\tnewWidth = oldWidth - sliderAccessWidth,\n\t\t\t\t\t\t\t\t\t\tnewMarginLeft = ((oldMarginLeft * newWidth) / oldWidth) + '%',\n\t\t\t\t\t\t\t\t\t\tcss = { width: newWidth, marginRight: 0, marginLeft: 0 };\n\t\t\t\t\t\t\t\t\tcss[rtl ? 'marginRight' : 'marginLeft'] = newMarginLeft;\n\t\t\t\t\t\t\t\t\t$g.css(css);\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}, 10);\n\t\t\t\t}\n\t\t\t\t// end slideAccess integration\n\n\t\t\t\ttp_inst._limitMinMaxDateTime(this.inst, true);\n\t\t\t}\n\t\t},\n\n\t\t/*\n\t\t* This function tries to limit the ability to go outside the\n\t\t* min/max date range\n\t\t*/\n\t\t_limitMinMaxDateTime: function (dp_inst, adjustSliders) {\n\t\t\tvar o = this._defaults,\n\t\t\t\tdp_date = new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay);\n\n\t\t\tif (!this._defaults.showTimepicker) {\n\t\t\t\treturn;\n\t\t\t} // No time so nothing to check here\n\n\t\t\tif ($.datepicker._get(dp_inst, 'minDateTime') !== null && $.datepicker._get(dp_inst, 'minDateTime') !== undefined && dp_date) {\n\t\t\t\tvar minDateTime = $.datepicker._get(dp_inst, 'minDateTime'),\n\t\t\t\t\tminDateTimeDate = new Date(minDateTime.getFullYear(), minDateTime.getMonth(), minDateTime.getDate(), 0, 0, 0, 0);\n\n\t\t\t\tif (this.hourMinOriginal === null || this.minuteMinOriginal === null || this.secondMinOriginal === null || this.millisecMinOriginal === null || this.microsecMinOriginal === null) {\n\t\t\t\t\tthis.hourMinOriginal = o.hourMin;\n\t\t\t\t\tthis.minuteMinOriginal = o.minuteMin;\n\t\t\t\t\tthis.secondMinOriginal = o.secondMin;\n\t\t\t\t\tthis.millisecMinOriginal = o.millisecMin;\n\t\t\t\t\tthis.microsecMinOriginal = o.microsecMin;\n\t\t\t\t}\n\n\t\t\t\tif (dp_inst.settings.timeOnly || minDateTimeDate.getTime() === dp_date.getTime()) {\n\t\t\t\t\tthis._defaults.hourMin = minDateTime.getHours();\n\t\t\t\t\tif (this.hour <= this._defaults.hourMin) {\n\t\t\t\t\t\tthis.hour = this._defaults.hourMin;\n\t\t\t\t\t\tthis._defaults.minuteMin = minDateTime.getMinutes();\n\t\t\t\t\t\tif (this.minute <= this._defaults.minuteMin) {\n\t\t\t\t\t\t\tthis.minute = this._defaults.minuteMin;\n\t\t\t\t\t\t\tthis._defaults.secondMin = minDateTime.getSeconds();\n\t\t\t\t\t\t\tif (this.second <= this._defaults.secondMin) {\n\t\t\t\t\t\t\t\tthis.second = this._defaults.secondMin;\n\t\t\t\t\t\t\t\tthis._defaults.millisecMin = minDateTime.getMilliseconds();\n\t\t\t\t\t\t\t\tif (this.millisec <= this._defaults.millisecMin) {\n\t\t\t\t\t\t\t\t\tthis.millisec = this._defaults.millisecMin;\n\t\t\t\t\t\t\t\t\tthis._defaults.microsecMin = minDateTime.getMicroseconds();\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tif (this.microsec < this._defaults.microsecMin) {\n\t\t\t\t\t\t\t\t\t\tthis.microsec = this._defaults.microsecMin;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tthis._defaults.microsecMin = this.microsecMinOriginal;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tthis._defaults.millisecMin = this.millisecMinOriginal;\n\t\t\t\t\t\t\t\tthis._defaults.microsecMin = this.microsecMinOriginal;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tthis._defaults.secondMin = this.secondMinOriginal;\n\t\t\t\t\t\t\tthis._defaults.millisecMin = this.millisecMinOriginal;\n\t\t\t\t\t\t\tthis._defaults.microsecMin = this.microsecMinOriginal;\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis._defaults.minuteMin = this.minuteMinOriginal;\n\t\t\t\t\t\tthis._defaults.secondMin = this.secondMinOriginal;\n\t\t\t\t\t\tthis._defaults.millisecMin = this.millisecMinOriginal;\n\t\t\t\t\t\tthis._defaults.microsecMin = this.microsecMinOriginal;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tthis._defaults.hourMin = this.hourMinOriginal;\n\t\t\t\t\tthis._defaults.minuteMin = this.minuteMinOriginal;\n\t\t\t\t\tthis._defaults.secondMin = this.secondMinOriginal;\n\t\t\t\t\tthis._defaults.millisecMin = this.millisecMinOriginal;\n\t\t\t\t\tthis._defaults.microsecMin = this.microsecMinOriginal;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ($.datepicker._get(dp_inst, 'maxDateTime') !== null && $.datepicker._get(dp_inst, 'maxDateTime') !== undefined && dp_date) {\n\t\t\t\tvar maxDateTime = $.datepicker._get(dp_inst, 'maxDateTime'),\n\t\t\t\t\tmaxDateTimeDate = new Date(maxDateTime.getFullYear(), maxDateTime.getMonth(), maxDateTime.getDate(), 0, 0, 0, 0);\n\n\t\t\t\tif (this.hourMaxOriginal === null || this.minuteMaxOriginal === null || this.secondMaxOriginal === null || this.millisecMaxOriginal === null) {\n\t\t\t\t\tthis.hourMaxOriginal = o.hourMax;\n\t\t\t\t\tthis.minuteMaxOriginal = o.minuteMax;\n\t\t\t\t\tthis.secondMaxOriginal = o.secondMax;\n\t\t\t\t\tthis.millisecMaxOriginal = o.millisecMax;\n\t\t\t\t\tthis.microsecMaxOriginal = o.microsecMax;\n\t\t\t\t}\n\n\t\t\t\tif (dp_inst.settings.timeOnly || maxDateTimeDate.getTime() === dp_date.getTime()) {\n\t\t\t\t\tthis._defaults.hourMax = maxDateTime.getHours();\n\t\t\t\t\tif (this.hour >= this._defaults.hourMax) {\n\t\t\t\t\t\tthis.hour = this._defaults.hourMax;\n\t\t\t\t\t\tthis._defaults.minuteMax = maxDateTime.getMinutes();\n\t\t\t\t\t\tif (this.minute >= this._defaults.minuteMax) {\n\t\t\t\t\t\t\tthis.minute = this._defaults.minuteMax;\n\t\t\t\t\t\t\tthis._defaults.secondMax = maxDateTime.getSeconds();\n\t\t\t\t\t\t\tif (this.second >= this._defaults.secondMax) {\n\t\t\t\t\t\t\t\tthis.second = this._defaults.secondMax;\n\t\t\t\t\t\t\t\tthis._defaults.millisecMax = maxDateTime.getMilliseconds();\n\t\t\t\t\t\t\t\tif (this.millisec >= this._defaults.millisecMax) {\n\t\t\t\t\t\t\t\t\tthis.millisec = this._defaults.millisecMax;\n\t\t\t\t\t\t\t\t\tthis._defaults.microsecMax = maxDateTime.getMicroseconds();\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tif (this.microsec > this._defaults.microsecMax) {\n\t\t\t\t\t\t\t\t\t\tthis.microsec = this._defaults.microsecMax;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tthis._defaults.microsecMax = this.microsecMaxOriginal;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tthis._defaults.millisecMax = this.millisecMaxOriginal;\n\t\t\t\t\t\t\t\tthis._defaults.microsecMax = this.microsecMaxOriginal;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tthis._defaults.secondMax = this.secondMaxOriginal;\n\t\t\t\t\t\t\tthis._defaults.millisecMax = this.millisecMaxOriginal;\n\t\t\t\t\t\t\tthis._defaults.microsecMax = this.microsecMaxOriginal;\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis._defaults.minuteMax = this.minuteMaxOriginal;\n\t\t\t\t\t\tthis._defaults.secondMax = this.secondMaxOriginal;\n\t\t\t\t\t\tthis._defaults.millisecMax = this.millisecMaxOriginal;\n\t\t\t\t\t\tthis._defaults.microsecMax = this.microsecMaxOriginal;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tthis._defaults.hourMax = this.hourMaxOriginal;\n\t\t\t\t\tthis._defaults.minuteMax = this.minuteMaxOriginal;\n\t\t\t\t\tthis._defaults.secondMax = this.secondMaxOriginal;\n\t\t\t\t\tthis._defaults.millisecMax = this.millisecMaxOriginal;\n\t\t\t\t\tthis._defaults.microsecMax = this.microsecMaxOriginal;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (adjustSliders !== undefined && adjustSliders === true) {\n\t\t\t\tvar hourMax = parseInt((this._defaults.hourMax - ((this._defaults.hourMax - this._defaults.hourMin) % this._defaults.stepHour)), 10),\n\t\t\t\t\tminMax = parseInt((this._defaults.minuteMax - ((this._defaults.minuteMax - this._defaults.minuteMin) % this._defaults.stepMinute)), 10),\n\t\t\t\t\tsecMax = parseInt((this._defaults.secondMax - ((this._defaults.secondMax - this._defaults.secondMin) % this._defaults.stepSecond)), 10),\n\t\t\t\t\tmillisecMax = parseInt((this._defaults.millisecMax - ((this._defaults.millisecMax - this._defaults.millisecMin) % this._defaults.stepMillisec)), 10),\n\t\t\t\t\tmicrosecMax = parseInt((this._defaults.microsecMax - ((this._defaults.microsecMax - this._defaults.microsecMin) % this._defaults.stepMicrosec)), 10);\n\n\t\t\t\tif (this.hour_slider) {\n\t\t\t\t\tthis.control.options(this, this.hour_slider, 'hour', { min: this._defaults.hourMin, max: hourMax });\n\t\t\t\t\tthis.control.value(this, this.hour_slider, 'hour', this.hour - (this.hour % this._defaults.stepHour));\n\t\t\t\t}\n\t\t\t\tif (this.minute_slider) {\n\t\t\t\t\tthis.control.options(this, this.minute_slider, 'minute', { min: this._defaults.minuteMin, max: minMax });\n\t\t\t\t\tthis.control.value(this, this.minute_slider, 'minute', this.minute - (this.minute % this._defaults.stepMinute));\n\t\t\t\t}\n\t\t\t\tif (this.second_slider) {\n\t\t\t\t\tthis.control.options(this, this.second_slider, 'second', { min: this._defaults.secondMin, max: secMax });\n\t\t\t\t\tthis.control.value(this, this.second_slider, 'second', this.second - (this.second % this._defaults.stepSecond));\n\t\t\t\t}\n\t\t\t\tif (this.millisec_slider) {\n\t\t\t\t\tthis.control.options(this, this.millisec_slider, 'millisec', { min: this._defaults.millisecMin, max: millisecMax });\n\t\t\t\t\tthis.control.value(this, this.millisec_slider, 'millisec', this.millisec - (this.millisec % this._defaults.stepMillisec));\n\t\t\t\t}\n\t\t\t\tif (this.microsec_slider) {\n\t\t\t\t\tthis.control.options(this, this.microsec_slider, 'microsec', { min: this._defaults.microsecMin, max: microsecMax });\n\t\t\t\t\tthis.control.value(this, this.microsec_slider, 'microsec', this.microsec - (this.microsec % this._defaults.stepMicrosec));\n\t\t\t\t}\n\t\t\t}\n\n\t\t},\n\n\t\t/*\n\t\t* when a slider moves, set the internal time...\n\t\t* on time change is also called when the time is updated in the text field\n\t\t*/\n\t\t_onTimeChange: function () {\n\t\t\tif (!this._defaults.showTimepicker) {\n return;\n\t\t\t}\n\t\t\tvar hour = (this.hour_slider) ? this.control.value(this, this.hour_slider, 'hour') : false,\n\t\t\t\tminute = (this.minute_slider) ? this.control.value(this, this.minute_slider, 'minute') : false,\n\t\t\t\tsecond = (this.second_slider) ? this.control.value(this, this.second_slider, 'second') : false,\n\t\t\t\tmillisec = (this.millisec_slider) ? this.control.value(this, this.millisec_slider, 'millisec') : false,\n\t\t\t\tmicrosec = (this.microsec_slider) ? this.control.value(this, this.microsec_slider, 'microsec') : false,\n\t\t\t\ttimezone = (this.timezone_select) ? this.timezone_select.val() : false,\n\t\t\t\to = this._defaults,\n\t\t\t\tpickerTimeFormat = o.pickerTimeFormat || o.timeFormat,\n\t\t\t\tpickerTimeSuffix = o.pickerTimeSuffix || o.timeSuffix;\n\n\t\t\tif (typeof(hour) === 'object') {\n\t\t\t\thour = false;\n\t\t\t}\n\t\t\tif (typeof(minute) === 'object') {\n\t\t\t\tminute = false;\n\t\t\t}\n\t\t\tif (typeof(second) === 'object') {\n\t\t\t\tsecond = false;\n\t\t\t}\n\t\t\tif (typeof(millisec) === 'object') {\n\t\t\t\tmillisec = false;\n\t\t\t}\n\t\t\tif (typeof(microsec) === 'object') {\n\t\t\t\tmicrosec = false;\n\t\t\t}\n\t\t\tif (typeof(timezone) === 'object') {\n\t\t\t\ttimezone = false;\n\t\t\t}\n\n\t\t\tif (hour !== false) {\n\t\t\t\thour = parseInt(hour, 10);\n\t\t\t}\n\t\t\tif (minute !== false) {\n\t\t\t\tminute = parseInt(minute, 10);\n\t\t\t}\n\t\t\tif (second !== false) {\n\t\t\t\tsecond = parseInt(second, 10);\n\t\t\t}\n\t\t\tif (millisec !== false) {\n\t\t\t\tmillisec = parseInt(millisec, 10);\n\t\t\t}\n\t\t\tif (microsec !== false) {\n\t\t\t\tmicrosec = parseInt(microsec, 10);\n\t\t\t}\n\t\t\tif (timezone !== false) {\n\t\t\t\ttimezone = timezone.toString();\n\t\t\t}\n\n\t\t\tvar ampm = o[hour < 12 ? 'amNames' : 'pmNames'][0];\n\n\t\t\t// If the update was done in the input field, the input field should not be updated.\n\t\t\t// If the update was done using the sliders, update the input field.\n\t\t\tvar hasChanged = (\n\t\t\t\t\t\thour !== parseInt(this.hour,10) || // sliders should all be numeric\n\t\t\t\t\t\tminute !== parseInt(this.minute,10) || \n\t\t\t\t\t\tsecond !== parseInt(this.second,10) || \n\t\t\t\t\t\tmillisec !== parseInt(this.millisec,10) || \n\t\t\t\t\t\tmicrosec !== parseInt(this.microsec,10) || \n\t\t\t\t\t\t(this.ampm.length > 0 && (hour < 12) !== ($.inArray(this.ampm.toUpperCase(), this.amNames) !== -1)) || \n\t\t\t\t\t\t(this.timezone !== null && timezone !== this.timezone.toString()) // could be numeric or \"EST\" format, so use toString()\n\t\t\t\t\t);\n\n\t\t\tif (hasChanged) {\n\n\t\t\t\tif (hour !== false) {\n\t\t\t\t\tthis.hour = hour;\n\t\t\t\t}\n\t\t\t\tif (minute !== false) {\n\t\t\t\t\tthis.minute = minute;\n\t\t\t\t}\n\t\t\t\tif (second !== false) {\n\t\t\t\t\tthis.second = second;\n\t\t\t\t}\n\t\t\t\tif (millisec !== false) {\n\t\t\t\t\tthis.millisec = millisec;\n\t\t\t\t}\n\t\t\t\tif (microsec !== false) {\n\t\t\t\t\tthis.microsec = microsec;\n\t\t\t\t}\n\t\t\t\tif (timezone !== false) {\n\t\t\t\t\tthis.timezone = timezone;\n\t\t\t\t}\n\n\t\t\t\tif (!this.inst) {\n\t\t\t\t\tthis.inst = $.datepicker._getInst(this.$input[0]);\n\t\t\t\t}\n\n\t\t\t\tthis._limitMinMaxDateTime(this.inst, true);\n\t\t\t}\n\t\t\tif (this.support.ampm) {\n\t\t\t\tthis.ampm = ampm;\n\t\t\t}\n\n\t\t\t// Updates the time within the timepicker\n\t\t\tthis.formattedTime = $.datepicker.formatTime(o.timeFormat, this, o);\n\t\t\tif (this.$timeObj) {\n\t\t\t\tif (pickerTimeFormat === o.timeFormat) {\n\t\t\t\t\tthis.$timeObj.text(this.formattedTime + pickerTimeSuffix);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tthis.$timeObj.text($.datepicker.formatTime(pickerTimeFormat, this, o) + pickerTimeSuffix);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.timeDefined = true;\n\t\t\tif (hasChanged) {\n\t\t\t\tthis._updateDateTime();\n\t\t\t\tthis.$input.focus();\n\t\t\t}\n\t\t},\n\n\t\t/*\n\t\t* call custom onSelect.\n\t\t* bind to sliders slidestop, and grid click.\n\t\t*/\n\t\t_onSelectHandler: function () {\n\t\t\tvar onSelect = this._defaults.onSelect || this.inst.settings.onSelect;\n\t\t\tvar inputEl = this.$input ? this.$input[0] : null;\n\t\t\tif (onSelect && inputEl) {\n\t\t\t\tonSelect.apply(inputEl, [this.formattedDateTime, this]);\n\t\t\t}\n\t\t},\n\n\t\t/*\n\t\t* update our input with the new date time..\n\t\t*/\n\t\t_updateDateTime: function (dp_inst) {\n\t\t\tdp_inst = this.inst || dp_inst;\n\t\t\tvar dtTmp = (dp_inst.currentYear > 0? \n\t\t\t\t\t\t\tnew Date(dp_inst.currentYear, dp_inst.currentMonth, dp_inst.currentDay) : \n\t\t\t\t\t\t\tnew Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay)),\n\t\t\t\tdt = $.datepicker._daylightSavingAdjust(dtTmp),\n\t\t\t\t//dt = $.datepicker._daylightSavingAdjust(new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay)),\n\t\t\t\t//dt = $.datepicker._daylightSavingAdjust(new Date(dp_inst.currentYear, dp_inst.currentMonth, dp_inst.currentDay)),\n\t\t\t\tdateFmt = $.datepicker._get(dp_inst, 'dateFormat'),\n\t\t\t\tformatCfg = $.datepicker._getFormatConfig(dp_inst),\n\t\t\t\ttimeAvailable = dt !== null && this.timeDefined;\n\t\t\tthis.formattedDate = $.datepicker.formatDate(dateFmt, (dt === null ? new Date() : dt), formatCfg);\n\t\t\tvar formattedDateTime = this.formattedDate;\n\t\t\t\n\t\t\t// if a slider was changed but datepicker doesn't have a value yet, set it\n\t\t\tif (dp_inst.lastVal === \"\") {\n dp_inst.currentYear = dp_inst.selectedYear;\n dp_inst.currentMonth = dp_inst.selectedMonth;\n dp_inst.currentDay = dp_inst.selectedDay;\n }\n\n\t\t\t/*\n\t\t\t* remove following lines to force every changes in date picker to change the input value\n\t\t\t* Bug descriptions: when an input field has a default value, and click on the field to pop up the date picker. \n\t\t\t* If the user manually empty the value in the input field, the date picker will never change selected value.\n\t\t\t*/\n\t\t\t//if (dp_inst.lastVal !== undefined && (dp_inst.lastVal.length > 0 && this.$input.val().length === 0)) {\n\t\t\t//\treturn;\n\t\t\t//}\n\n\t\t\tif (this._defaults.timeOnly === true) {\n\t\t\t\tformattedDateTime = this.formattedTime;\n\t\t\t} else if (this._defaults.timeOnly !== true && (this._defaults.alwaysSetTime || timeAvailable)) {\n\t\t\t\tformattedDateTime += this._defaults.separator + this.formattedTime + this._defaults.timeSuffix;\n\t\t\t}\n\n\t\t\tthis.formattedDateTime = formattedDateTime;\n\n\t\t\tif (!this._defaults.showTimepicker) {\n\t\t\t\tthis.$input.val(this.formattedDate);\n\t\t\t} else if (this.$altInput && this._defaults.timeOnly === false && this._defaults.altFieldTimeOnly === true) {\n\t\t\t\tthis.$altInput.val(this.formattedTime);\n\t\t\t\tthis.$input.val(this.formattedDate);\n\t\t\t} else if (this.$altInput) {\n\t\t\t\tthis.$input.val(formattedDateTime);\n\t\t\t\tvar altFormattedDateTime = '',\n\t\t\t\t\taltSeparator = this._defaults.altSeparator ? this._defaults.altSeparator : this._defaults.separator,\n\t\t\t\t\taltTimeSuffix = this._defaults.altTimeSuffix ? this._defaults.altTimeSuffix : this._defaults.timeSuffix;\n\t\t\t\t\n\t\t\t\tif (!this._defaults.timeOnly) {\n\t\t\t\t\tif (this._defaults.altFormat) {\n\t\t\t\t\t\taltFormattedDateTime = $.datepicker.formatDate(this._defaults.altFormat, (dt === null ? new Date() : dt), formatCfg);\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\taltFormattedDateTime = this.formattedDate;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (altFormattedDateTime) {\n\t\t\t\t\t\taltFormattedDateTime += altSeparator;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (this._defaults.altTimeFormat) {\n\t\t\t\t\taltFormattedDateTime += $.datepicker.formatTime(this._defaults.altTimeFormat, this, this._defaults) + altTimeSuffix;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\taltFormattedDateTime += this.formattedTime + altTimeSuffix;\n\t\t\t\t}\n\t\t\t\tthis.$altInput.val(altFormattedDateTime);\n\t\t\t} else {\n\t\t\t\tthis.$input.val(formattedDateTime);\n\t\t\t}\n\n\t\t\tthis.$input.trigger(\"change\");\n\t\t},\n\n\t\t_onFocus: function () {\n\t\t\tif (!this.$input.val() && this._defaults.defaultValue) {\n\t\t\t\tthis.$input.val(this._defaults.defaultValue);\n\t\t\t\tvar inst = $.datepicker._getInst(this.$input.get(0)),\n\t\t\t\t\ttp_inst = $.datepicker._get(inst, 'timepicker');\n\t\t\t\tif (tp_inst) {\n\t\t\t\t\tif (tp_inst._defaults.timeOnly && (inst.input.val() !== inst.lastVal)) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t$.datepicker._updateDatepicker(inst);\n\t\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t\t$.timepicker.log(err);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\t/*\n\t\t* Small abstraction to control types\n\t\t* We can add more, just be sure to follow the pattern: create, options, value\n\t\t*/\n\t\t_controls: {\n\t\t\t// slider methods\n\t\t\tslider: {\n\t\t\t\tcreate: function (tp_inst, obj, unit, val, min, max, step) {\n\t\t\t\t\tvar rtl = tp_inst._defaults.isRTL; // if rtl go -60->0 instead of 0->60\n\t\t\t\t\treturn obj.prop('slide', null).slider({\n\t\t\t\t\t\torientation: \"horizontal\",\n\t\t\t\t\t\tvalue: rtl ? val * -1 : val,\n\t\t\t\t\t\tmin: rtl ? max * -1 : min,\n\t\t\t\t\t\tmax: rtl ? min * -1 : max,\n\t\t\t\t\t\tstep: step,\n\t\t\t\t\t\tslide: function (event, ui) {\n\t\t\t\t\t\t\ttp_inst.control.value(tp_inst, $(this), unit, rtl ? ui.value * -1 : ui.value);\n\t\t\t\t\t\t\ttp_inst._onTimeChange();\n\t\t\t\t\t\t},\n\t\t\t\t\t\tstop: function (event, ui) {\n\t\t\t\t\t\t\ttp_inst._onSelectHandler();\n\t\t\t\t\t\t}\n\t\t\t\t\t});\t\n\t\t\t\t},\n\t\t\t\toptions: function (tp_inst, obj, unit, opts, val) {\n\t\t\t\t\tif (tp_inst._defaults.isRTL) {\n\t\t\t\t\t\tif (typeof(opts) === 'string') {\n\t\t\t\t\t\t\tif (opts === 'min' || opts === 'max') {\n\t\t\t\t\t\t\t\tif (val !== undefined) {\n\t\t\t\t\t\t\t\t\treturn obj.slider(opts, val * -1);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\treturn Math.abs(obj.slider(opts));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn obj.slider(opts);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tvar min = opts.min, \n\t\t\t\t\t\t\tmax = opts.max;\n\t\t\t\t\t\topts.min = opts.max = null;\n\t\t\t\t\t\tif (min !== undefined) {\n\t\t\t\t\t\t\topts.max = min * -1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (max !== undefined) {\n\t\t\t\t\t\t\topts.min = max * -1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn obj.slider(opts);\n\t\t\t\t\t}\n\t\t\t\t\tif (typeof(opts) === 'string' && val !== undefined) {\n\t\t\t\t\t\treturn obj.slider(opts, val);\n\t\t\t\t\t}\n\t\t\t\t\treturn obj.slider(opts);\n\t\t\t\t},\n\t\t\t\tvalue: function (tp_inst, obj, unit, val) {\n\t\t\t\t\tif (tp_inst._defaults.isRTL) {\n\t\t\t\t\t\tif (val !== undefined) {\n\t\t\t\t\t\t\treturn obj.slider('value', val * -1);\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn Math.abs(obj.slider('value'));\n\t\t\t\t\t}\n\t\t\t\t\tif (val !== undefined) {\n\t\t\t\t\t\treturn obj.slider('value', val);\n\t\t\t\t\t}\n\t\t\t\t\treturn obj.slider('value');\n\t\t\t\t}\n\t\t\t},\n\t\t\t// select methods\n\t\t\tselect: {\n\t\t\t\tcreate: function (tp_inst, obj, unit, val, min, max, step) {\n\t\t\t\t\tvar sel = '<select class=\"ui-timepicker-select\" data-unit=\"' + unit + '\" data-min=\"' + min + '\" data-max=\"' + max + '\" data-step=\"' + step + '\">',\n\t\t\t\t\t\tformat = tp_inst._defaults.pickerTimeFormat || tp_inst._defaults.timeFormat;\n\n\t\t\t\t\tfor (var i = min; i <= max; i += step) {\n\t\t\t\t\t\tsel += '<option value=\"' + i + '\"' + (i === val ? ' selected' : '') + '>';\n\t\t\t\t\t\tif (unit === 'hour') {\n\t\t\t\t\t\t\tsel += $.datepicker.formatTime($.trim(format.replace(/[^ht ]/ig, '')), {hour: i}, tp_inst._defaults);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (unit === 'millisec' || unit === 'microsec' || i >= 10) { sel += i; }\n\t\t\t\t\t\telse {sel += '0' + i.toString(); }\n\t\t\t\t\t\tsel += '</option>';\n\t\t\t\t\t}\n\t\t\t\t\tsel += '</select>';\n\n\t\t\t\t\tobj.children('select').remove();\n\n\t\t\t\t\t$(sel).appendTo(obj).change(function (e) {\n\t\t\t\t\t\ttp_inst._onTimeChange();\n\t\t\t\t\t\ttp_inst._onSelectHandler();\n\t\t\t\t\t});\n\n\t\t\t\t\treturn obj;\n\t\t\t\t},\n\t\t\t\toptions: function (tp_inst, obj, unit, opts, val) {\n\t\t\t\t\tvar o = {},\n\t\t\t\t\t\t$t = obj.children('select');\n\t\t\t\t\tif (typeof(opts) === 'string') {\n\t\t\t\t\t\tif (val === undefined) {\n\t\t\t\t\t\t\treturn $t.data(opts);\n\t\t\t\t\t\t}\n\t\t\t\t\t\to[opts] = val;\t\n\t\t\t\t\t}\n\t\t\t\t\telse { o = opts; }\n\t\t\t\t\treturn tp_inst.control.create(tp_inst, obj, $t.data('unit'), $t.val(), o.min || $t.data('min'), o.max || $t.data('max'), o.step || $t.data('step'));\n\t\t\t\t},\n\t\t\t\tvalue: function (tp_inst, obj, unit, val) {\n\t\t\t\t\tvar $t = obj.children('select');\n\t\t\t\t\tif (val !== undefined) {\n\t\t\t\t\t\treturn $t.val(val);\n\t\t\t\t\t}\n\t\t\t\t\treturn $t.val();\n\t\t\t\t}\n\t\t\t}\n\t\t} // end _controls\n\n\t});\n\n\t$.fn.extend({\n\t\t/*\n\t\t* shorthand just to use timepicker.\n\t\t*/\n\t\ttimepicker: function (o) {\n\t\t\to = o || {};\n\t\t\tvar tmp_args = Array.prototype.slice.call(arguments);\n\n\t\t\tif (typeof o === 'object') {\n\t\t\t\ttmp_args[0] = $.extend(o, {\n\t\t\t\t\ttimeOnly: true\n\t\t\t\t});\n\t\t\t}\n\n\t\t\treturn $(this).each(function () {\n\t\t\t\t$.fn.datetimepicker.apply($(this), tmp_args);\n\t\t\t});\n\t\t},\n\n\t\t/*\n\t\t* extend timepicker to datepicker\n\t\t*/\n\t\tdatetimepicker: function (o) {\n\t\t\to = o || {};\n\t\t\tvar tmp_args = arguments;\n\n\t\t\tif (typeof(o) === 'string') {\n\t\t\t\tif (o === 'getDate') {\n\t\t\t\t\treturn $.fn.datepicker.apply($(this[0]), tmp_args);\n\t\t\t\t} else {\n\t\t\t\t\treturn this.each(function () {\n\t\t\t\t\t\tvar $t = $(this);\n\t\t\t\t\t\t$t.datepicker.apply($t, tmp_args);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\treturn this.each(function () {\n\t\t\t\t\tvar $t = $(this);\n\t\t\t\t\t$t.datepicker($.timepicker._newInst($t, o)._defaults);\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t* Public Utility to parse date and time\n\t*/\n\t$.datepicker.parseDateTime = function (dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings) {\n\t\tvar parseRes = parseDateTimeInternal(dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings);\n\t\tif (parseRes.timeObj) {\n\t\t\tvar t = parseRes.timeObj;\n\t\t\tparseRes.date.setHours(t.hour, t.minute, t.second, t.millisec);\n\t\t\tparseRes.date.setMicroseconds(t.microsec);\n\t\t}\n\n\t\treturn parseRes.date;\n\t};\n\n\t/*\n\t* Public utility to parse time\n\t*/\n\t$.datepicker.parseTime = function (timeFormat, timeString, options) {\n\t\tvar o = extendRemove(extendRemove({}, $.timepicker._defaults), options || {}),\n\t\t\tiso8601 = (timeFormat.replace(/\\'.*?\\'/g, '').indexOf('Z') !== -1);\n\n\t\t// Strict parse requires the timeString to match the timeFormat exactly\n\t\tvar strictParse = function (f, s, o) {\n\n\t\t\t// pattern for standard and localized AM/PM markers\n\t\t\tvar getPatternAmpm = function (amNames, pmNames) {\n\t\t\t\tvar markers = [];\n\t\t\t\tif (amNames) {\n\t\t\t\t\t$.merge(markers, amNames);\n\t\t\t\t}\n\t\t\t\tif (pmNames) {\n\t\t\t\t\t$.merge(markers, pmNames);\n\t\t\t\t}\n\t\t\t\tmarkers = $.map(markers, function (val) {\n\t\t\t\t\treturn val.replace(/[.*+?|()\\[\\]{}\\\\]/g, '\\\\$&');\n\t\t\t\t});\n\t\t\t\treturn '(' + markers.join('|') + ')?';\n\t\t\t};\n\n\t\t\t// figure out position of time elements.. cause js cant do named captures\n\t\t\tvar getFormatPositions = function (timeFormat) {\n\t\t\t\tvar finds = timeFormat.toLowerCase().match(/(h{1,2}|m{1,2}|s{1,2}|l{1}|c{1}|t{1,2}|z|'.*?')/g),\n\t\t\t\t\torders = {\n\t\t\t\t\t\th: -1,\n\t\t\t\t\t\tm: -1,\n\t\t\t\t\t\ts: -1,\n\t\t\t\t\t\tl: -1,\n\t\t\t\t\t\tc: -1,\n\t\t\t\t\t\tt: -1,\n\t\t\t\t\t\tz: -1\n\t\t\t\t\t};\n\n\t\t\t\tif (finds) {\n\t\t\t\t\tfor (var i = 0; i < finds.length; i++) {\n\t\t\t\t\t\tif (orders[finds[i].toString().charAt(0)] === -1) {\n\t\t\t\t\t\t\torders[finds[i].toString().charAt(0)] = i + 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn orders;\n\t\t\t};\n\n\t\t\tvar regstr = '^' + f.toString()\n\t\t\t\t\t.replace(/([hH]{1,2}|mm?|ss?|[tT]{1,2}|[zZ]|[lc]|'.*?')/g, function (match) {\n\t\t\t\t\t\t\tvar ml = match.length;\n\t\t\t\t\t\t\tswitch (match.charAt(0).toLowerCase()) {\n\t\t\t\t\t\t\tcase 'h':\n\t\t\t\t\t\t\t\treturn ml === 1 ? '(\\\\d?\\\\d)' : '(\\\\d{' + ml + '})';\n\t\t\t\t\t\t\tcase 'm':\n\t\t\t\t\t\t\t\treturn ml === 1 ? '(\\\\d?\\\\d)' : '(\\\\d{' + ml + '})';\n\t\t\t\t\t\t\tcase 's':\n\t\t\t\t\t\t\t\treturn ml === 1 ? '(\\\\d?\\\\d)' : '(\\\\d{' + ml + '})';\n\t\t\t\t\t\t\tcase 'l':\n\t\t\t\t\t\t\t\treturn '(\\\\d?\\\\d?\\\\d)';\n\t\t\t\t\t\t\tcase 'c':\n\t\t\t\t\t\t\t\treturn '(\\\\d?\\\\d?\\\\d)';\n\t\t\t\t\t\t\tcase 'z':\n\t\t\t\t\t\t\t\treturn '(z|[-+]\\\\d\\\\d:?\\\\d\\\\d|\\\\S+)?';\n\t\t\t\t\t\t\tcase 't':\n\t\t\t\t\t\t\t\treturn getPatternAmpm(o.amNames, o.pmNames);\n\t\t\t\t\t\t\tdefault: // literal escaped in quotes\n\t\t\t\t\t\t\t\treturn '(' + match.replace(/\\'/g, \"\").replace(/(\\.|\\$|\\^|\\\\|\\/|\\(|\\)|\\[|\\]|\\?|\\+|\\*)/g, function (m) { return \"\\\\\" + m; }) + ')?';\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t})\n\t\t\t\t\t.replace(/\\s/g, '\\\\s?') +\n\t\t\t\t\to.timeSuffix + '$',\n\t\t\t\torder = getFormatPositions(f),\n\t\t\t\tampm = '',\n\t\t\t\ttreg;\n\n\t\t\ttreg = s.match(new RegExp(regstr, 'i'));\n\n\t\t\tvar resTime = {\n\t\t\t\thour: 0,\n\t\t\t\tminute: 0,\n\t\t\t\tsecond: 0,\n\t\t\t\tmillisec: 0,\n\t\t\t\tmicrosec: 0\n\t\t\t};\n\n\t\t\tif (treg) {\n\t\t\t\tif (order.t !== -1) {\n\t\t\t\t\tif (treg[order.t] === undefined || treg[order.t].length === 0) {\n\t\t\t\t\t\tampm = '';\n\t\t\t\t\t\tresTime.ampm = '';\n\t\t\t\t\t} else {\n\t\t\t\t\t\tampm = $.inArray(treg[order.t].toUpperCase(), o.amNames) !== -1 ? 'AM' : 'PM';\n\t\t\t\t\t\tresTime.ampm = o[ampm === 'AM' ? 'amNames' : 'pmNames'][0];\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (order.h !== -1) {\n\t\t\t\t\tif (ampm === 'AM' && treg[order.h] === '12') {\n\t\t\t\t\t\tresTime.hour = 0; // 12am = 0 hour\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif (ampm === 'PM' && treg[order.h] !== '12') {\n\t\t\t\t\t\t\tresTime.hour = parseInt(treg[order.h], 10) + 12; // 12pm = 12 hour, any other pm = hour + 12\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tresTime.hour = Number(treg[order.h]);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (order.m !== -1) {\n\t\t\t\t\tresTime.minute = Number(treg[order.m]);\n\t\t\t\t}\n\t\t\t\tif (order.s !== -1) {\n\t\t\t\t\tresTime.second = Number(treg[order.s]);\n\t\t\t\t}\n\t\t\t\tif (order.l !== -1) {\n\t\t\t\t\tresTime.millisec = Number(treg[order.l]);\n\t\t\t\t}\n\t\t\t\tif (order.c !== -1) {\n\t\t\t\t\tresTime.microsec = Number(treg[order.c]);\n\t\t\t\t}\n\t\t\t\tif (order.z !== -1 && treg[order.z] !== undefined) {\n\t\t\t\t\tresTime.timezone = $.timepicker.timezoneOffsetNumber(treg[order.z]);\n\t\t\t\t}\n\n\n\t\t\t\treturn resTime;\n\t\t\t}\n\t\t\treturn false;\n\t\t};// end strictParse\n\n\t\t// First try JS Date, if that fails, use strictParse\n\t\tvar looseParse = function (f, s, o) {\n\t\t\ttry {\n\t\t\t\tvar d = new Date('2012-01-01 ' + s);\n\t\t\t\tif (isNaN(d.getTime())) {\n\t\t\t\t\td = new Date('2012-01-01T' + s);\n\t\t\t\t\tif (isNaN(d.getTime())) {\n\t\t\t\t\t\td = new Date('01/01/2012 ' + s);\n\t\t\t\t\t\tif (isNaN(d.getTime())) {\n\t\t\t\t\t\t\tthrow \"Unable to parse time with native Date: \" + s;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn {\n\t\t\t\t\thour: d.getHours(),\n\t\t\t\t\tminute: d.getMinutes(),\n\t\t\t\t\tsecond: d.getSeconds(),\n\t\t\t\t\tmillisec: d.getMilliseconds(),\n\t\t\t\t\tmicrosec: d.getMicroseconds(),\n\t\t\t\t\ttimezone: d.getTimezoneOffset() * -1\n\t\t\t\t};\n\t\t\t}\n\t\t\tcatch (err) {\n\t\t\t\ttry {\n\t\t\t\t\treturn strictParse(f, s, o);\n\t\t\t\t}\n\t\t\t\tcatch (err2) {\n\t\t\t\t\t$.timepicker.log(\"Unable to parse \\ntimeString: \" + s + \"\\ntimeFormat: \" + f);\n\t\t\t\t}\t\t\t\t\n\t\t\t}\n\t\t\treturn false;\n\t\t}; // end looseParse\n\t\t\n\t\tif (typeof o.parse === \"function\") {\n\t\t\treturn o.parse(timeFormat, timeString, o);\n\t\t}\n\t\tif (o.parse === 'loose') {\n\t\t\treturn looseParse(timeFormat, timeString, o);\n\t\t}\n\t\treturn strictParse(timeFormat, timeString, o);\n\t};\n\n\t/**\n\t * Public utility to format the time\n\t * @param {string} format format of the time\n\t * @param {Object} time Object not a Date for timezones\n\t * @param {Object} [options] essentially the regional[].. amNames, pmNames, ampm\n\t * @returns {string} the formatted time\n\t */\n\t$.datepicker.formatTime = function (format, time, options) {\n\t\toptions = options || {};\n\t\toptions = $.extend({}, $.timepicker._defaults, options);\n\t\ttime = $.extend({\n\t\t\thour: 0,\n\t\t\tminute: 0,\n\t\t\tsecond: 0,\n\t\t\tmillisec: 0,\n\t\t\tmicrosec: 0,\n\t\t\ttimezone: null\n\t\t}, time);\n\n\t\tvar tmptime = format,\n\t\t\tampmName = options.amNames[0],\n\t\t\thour = parseInt(time.hour, 10);\n\n\t\tif (hour > 11) {\n\t\t\tampmName = options.pmNames[0];\n\t\t}\n\n\t\ttmptime = tmptime.replace(/(?:HH?|hh?|mm?|ss?|[tT]{1,2}|[zZ]|[lc]|'.*?')/g, function (match) {\n\t\t\tswitch (match) {\n\t\t\tcase 'HH':\n\t\t\t\treturn ('0' + hour).slice(-2);\n\t\t\tcase 'H':\n\t\t\t\treturn hour;\n\t\t\tcase 'hh':\n\t\t\t\treturn ('0' + convert24to12(hour)).slice(-2);\n\t\t\tcase 'h':\n\t\t\t\treturn convert24to12(hour);\n\t\t\tcase 'mm':\n\t\t\t\treturn ('0' + time.minute).slice(-2);\n\t\t\tcase 'm':\n\t\t\t\treturn time.minute;\n\t\t\tcase 'ss':\n\t\t\t\treturn ('0' + time.second).slice(-2);\n\t\t\tcase 's':\n\t\t\t\treturn time.second;\n\t\t\tcase 'l':\n\t\t\t\treturn ('00' + time.millisec).slice(-3);\n\t\t\tcase 'c':\n\t\t\t\treturn ('00' + time.microsec).slice(-3);\n\t\t\tcase 'z':\n\t\t\t\treturn $.timepicker.timezoneOffsetString(time.timezone === null ? options.timezone : time.timezone, false);\n\t\t\tcase 'Z':\n\t\t\t\treturn $.timepicker.timezoneOffsetString(time.timezone === null ? options.timezone : time.timezone, true);\n\t\t\tcase 'T':\n\t\t\t\treturn ampmName.charAt(0).toUpperCase();\n\t\t\tcase 'TT':\n\t\t\t\treturn ampmName.toUpperCase();\n\t\t\tcase 't':\n\t\t\t\treturn ampmName.charAt(0).toLowerCase();\n\t\t\tcase 'tt':\n\t\t\t\treturn ampmName.toLowerCase();\n\t\t\tdefault:\n\t\t\t\treturn match.replace(/'/g, \"\");\n\t\t\t}\n\t\t});\n\n\t\treturn tmptime;\n\t};\n\n\t/*\n\t* the bad hack :/ override datepicker so it doesn't close on select\n\t// inspired: http://stackoverflow.com/questions/1252512/jquery-datepicker-prevent-closing-picker-when-clicking-a-date/1762378#1762378\n\t*/\n\t$.datepicker._base_selectDate = $.datepicker._selectDate;\n\t$.datepicker._selectDate = function (id, dateStr) {\n\t\tvar inst = this._getInst($(id)[0]),\n\t\t\ttp_inst = this._get(inst, 'timepicker');\n\n\t\tif (tp_inst) {\n\t\t\ttp_inst._limitMinMaxDateTime(inst, true);\n\t\t\tinst.inline = inst.stay_open = true;\n\t\t\t//This way the onSelect handler called from calendarpicker get the full dateTime\n\t\t\tthis._base_selectDate(id, dateStr);\n\t\t\tinst.inline = inst.stay_open = false;\n\t\t\tthis._notifyChange(inst);\n\t\t\tthis._updateDatepicker(inst);\n\t\t} else {\n\t\t\tthis._base_selectDate(id, dateStr);\n\t\t}\n\t};\n\n\t/*\n\t* second bad hack :/ override datepicker so it triggers an event when changing the input field\n\t* and does not redraw the datepicker on every selectDate event\n\t*/\n\t$.datepicker._base_updateDatepicker = $.datepicker._updateDatepicker;\n\t$.datepicker._updateDatepicker = function (inst) {\n\n\t\t// don't popup the datepicker if there is another instance already opened\n\t\tvar input = inst.input[0];\n\t\tif ($.datepicker._curInst && $.datepicker._curInst !== inst && $.datepicker._datepickerShowing && $.datepicker._lastInput !== input) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (typeof(inst.stay_open) !== 'boolean' || inst.stay_open === false) {\n\n\t\t\tthis._base_updateDatepicker(inst);\n\n\t\t\t// Reload the time control when changing something in the input text field.\n\t\t\tvar tp_inst = this._get(inst, 'timepicker');\n\t\t\tif (tp_inst) {\n\t\t\t\ttp_inst._addTimePicker(inst);\n\t\t\t}\n\t\t}\n\t};\n\n\t/*\n\t* third bad hack :/ override datepicker so it allows spaces and colon in the input field\n\t*/\n\t$.datepicker._base_doKeyPress = $.datepicker._doKeyPress;\n\t$.datepicker._doKeyPress = function (event) {\n\t\tvar inst = $.datepicker._getInst(event.target),\n\t\t\ttp_inst = $.datepicker._get(inst, 'timepicker');\n\n\t\tif (tp_inst) {\n\t\t\tif ($.datepicker._get(inst, 'constrainInput')) {\n\t\t\t\tvar ampm = tp_inst.support.ampm,\n\t\t\t\t\ttz = tp_inst._defaults.showTimezone !== null ? tp_inst._defaults.showTimezone : tp_inst.support.timezone,\n\t\t\t\t\tdateChars = $.datepicker._possibleChars($.datepicker._get(inst, 'dateFormat')),\n\t\t\t\t\tdatetimeChars = tp_inst._defaults.timeFormat.toString()\n\t\t\t\t\t\t\t\t\t\t\t.replace(/[hms]/g, '')\n\t\t\t\t\t\t\t\t\t\t\t.replace(/TT/g, ampm ? 'APM' : '')\n\t\t\t\t\t\t\t\t\t\t\t.replace(/Tt/g, ampm ? 'AaPpMm' : '')\n\t\t\t\t\t\t\t\t\t\t\t.replace(/tT/g, ampm ? 'AaPpMm' : '')\n\t\t\t\t\t\t\t\t\t\t\t.replace(/T/g, ampm ? 'AP' : '')\n\t\t\t\t\t\t\t\t\t\t\t.replace(/tt/g, ampm ? 'apm' : '')\n\t\t\t\t\t\t\t\t\t\t\t.replace(/t/g, ampm ? 'ap' : '') + \n\t\t\t\t\t\t\t\t\t\t\t\" \" + tp_inst._defaults.separator + \n\t\t\t\t\t\t\t\t\t\t\ttp_inst._defaults.timeSuffix + \n\t\t\t\t\t\t\t\t\t\t\t(tz ? tp_inst._defaults.timezoneList.join('') : '') + \n\t\t\t\t\t\t\t\t\t\t\t(tp_inst._defaults.amNames.join('')) + (tp_inst._defaults.pmNames.join('')) + \n\t\t\t\t\t\t\t\t\t\t\tdateChars,\n\t\t\t\t\tchr = String.fromCharCode(event.charCode === undefined ? event.keyCode : event.charCode);\n\t\t\t\treturn event.ctrlKey || (chr < ' ' || !dateChars || datetimeChars.indexOf(chr) > -1);\n\t\t\t}\n\t\t}\n\n\t\treturn $.datepicker._base_doKeyPress(event);\n\t};\n\n\t/*\n\t* Fourth bad hack :/ override _updateAlternate function used in inline mode to init altField\n\t* Update any alternate field to synchronise with the main field.\n\t*/\n\t$.datepicker._base_updateAlternate = $.datepicker._updateAlternate;\n\t$.datepicker._updateAlternate = function (inst) {\n\t\tvar tp_inst = this._get(inst, 'timepicker');\n\t\tif (tp_inst) {\n\t\t\tvar altField = tp_inst._defaults.altField;\n\t\t\tif (altField) { // update alternate field too\n\t\t\t\tvar altFormat = tp_inst._defaults.altFormat || tp_inst._defaults.dateFormat,\n\t\t\t\t\tdate = this._getDate(inst),\n\t\t\t\t\tformatCfg = $.datepicker._getFormatConfig(inst),\n\t\t\t\t\taltFormattedDateTime = '', \n\t\t\t\t\taltSeparator = tp_inst._defaults.altSeparator ? tp_inst._defaults.altSeparator : tp_inst._defaults.separator, \n\t\t\t\t\taltTimeSuffix = tp_inst._defaults.altTimeSuffix ? tp_inst._defaults.altTimeSuffix : tp_inst._defaults.timeSuffix,\n\t\t\t\t\taltTimeFormat = tp_inst._defaults.altTimeFormat !== null ? tp_inst._defaults.altTimeFormat : tp_inst._defaults.timeFormat;\n\t\t\t\t\n\t\t\t\taltFormattedDateTime += $.datepicker.formatTime(altTimeFormat, tp_inst, tp_inst._defaults) + altTimeSuffix;\n\t\t\t\tif (!tp_inst._defaults.timeOnly && !tp_inst._defaults.altFieldTimeOnly && date !== null) {\n\t\t\t\t\tif (tp_inst._defaults.altFormat) {\n\t\t\t\t\t\taltFormattedDateTime = $.datepicker.formatDate(tp_inst._defaults.altFormat, date, formatCfg) + altSeparator + altFormattedDateTime;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\taltFormattedDateTime = tp_inst.formattedDate + altSeparator + altFormattedDateTime;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t$(altField).val(altFormattedDateTime);\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\t$.datepicker._base_updateAlternate(inst);\n\t\t}\n\t};\n\n\t/*\n\t* Override key up event to sync manual input changes.\n\t*/\n\t$.datepicker._base_doKeyUp = $.datepicker._doKeyUp;\n\t$.datepicker._doKeyUp = function (event) {\n\t\tvar inst = $.datepicker._getInst(event.target),\n\t\t\ttp_inst = $.datepicker._get(inst, 'timepicker');\n\n\t\tif (tp_inst) {\n\t\t\tif (tp_inst._defaults.timeOnly && (inst.input.val() !== inst.lastVal)) {\n\t\t\t\ttry {\n\t\t\t\t\t$.datepicker._updateDatepicker(inst);\n\t\t\t\t} catch (err) {\n\t\t\t\t\t$.timepicker.log(err);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn $.datepicker._base_doKeyUp(event);\n\t};\n\n\t/*\n\t* override \"Today\" button to also grab the time.\n\t*/\n\t$.datepicker._base_gotoToday = $.datepicker._gotoToday;\n\t$.datepicker._gotoToday = function (id) {\n\t\tvar inst = this._getInst($(id)[0]),\n\t\t\t$dp = inst.dpDiv;\n\t\tthis._base_gotoToday(id);\n\t\tvar tp_inst = this._get(inst, 'timepicker');\n\t\tselectLocalTimezone(tp_inst);\n\t\tvar now = new Date();\n\t\tthis._setTime(inst, now);\n\t\t$('.ui-datepicker-today', $dp).click();\n\t};\n\n\t/*\n\t* Disable & enable the Time in the datetimepicker\n\t*/\n\t$.datepicker._disableTimepickerDatepicker = function (target) {\n\t\tvar inst = this._getInst(target);\n\t\tif (!inst) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar tp_inst = this._get(inst, 'timepicker');\n\t\t$(target).datepicker('getDate'); // Init selected[Year|Month|Day]\n\t\tif (tp_inst) {\n\t\t\tinst.settings.showTimepicker = false;\n\t\t\ttp_inst._defaults.showTimepicker = false;\n\t\t\ttp_inst._updateDateTime(inst);\n\t\t}\n\t};\n\n\t$.datepicker._enableTimepickerDatepicker = function (target) {\n\t\tvar inst = this._getInst(target);\n\t\tif (!inst) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar tp_inst = this._get(inst, 'timepicker');\n\t\t$(target).datepicker('getDate'); // Init selected[Year|Month|Day]\n\t\tif (tp_inst) {\n\t\t\tinst.settings.showTimepicker = true;\n\t\t\ttp_inst._defaults.showTimepicker = true;\n\t\t\ttp_inst._addTimePicker(inst); // Could be disabled on page load\n\t\t\ttp_inst._updateDateTime(inst);\n\t\t}\n\t};\n\n\t/*\n\t* Create our own set time function\n\t*/\n\t$.datepicker._setTime = function (inst, date) {\n\t\tvar tp_inst = this._get(inst, 'timepicker');\n\t\tif (tp_inst) {\n\t\t\tvar defaults = tp_inst._defaults;\n\n\t\t\t// calling _setTime with no date sets time to defaults\n\t\t\ttp_inst.hour = date ? date.getHours() : defaults.hour;\n\t\t\ttp_inst.minute = date ? date.getMinutes() : defaults.minute;\n\t\t\ttp_inst.second = date ? date.getSeconds() : defaults.second;\n\t\t\ttp_inst.millisec = date ? date.getMilliseconds() : defaults.millisec;\n\t\t\ttp_inst.microsec = date ? date.getMicroseconds() : defaults.microsec;\n\n\t\t\t//check if within min/max times.. \n\t\t\ttp_inst._limitMinMaxDateTime(inst, true);\n\n\t\t\ttp_inst._onTimeChange();\n\t\t\ttp_inst._updateDateTime(inst);\n\t\t}\n\t};\n\n\t/*\n\t* Create new public method to set only time, callable as $().datepicker('setTime', date)\n\t*/\n\t$.datepicker._setTimeDatepicker = function (target, date, withDate) {\n\t\tvar inst = this._getInst(target);\n\t\tif (!inst) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar tp_inst = this._get(inst, 'timepicker');\n\n\t\tif (tp_inst) {\n\t\t\tthis._setDateFromField(inst);\n\t\t\tvar tp_date;\n\t\t\tif (date) {\n\t\t\t\tif (typeof date === \"string\") {\n\t\t\t\t\ttp_inst._parseTime(date, withDate);\n\t\t\t\t\ttp_date = new Date();\n\t\t\t\t\ttp_date.setHours(tp_inst.hour, tp_inst.minute, tp_inst.second, tp_inst.millisec);\n\t\t\t\t\ttp_date.setMicroseconds(tp_inst.microsec);\n\t\t\t\t} else {\n\t\t\t\t\ttp_date = new Date(date.getTime());\n\t\t\t\t\ttp_date.setMicroseconds(date.getMicroseconds());\n\t\t\t\t}\n\t\t\t\tif (tp_date.toString() === 'Invalid Date') {\n\t\t\t\t\ttp_date = undefined;\n\t\t\t\t}\n\t\t\t\tthis._setTime(inst, tp_date);\n\t\t\t}\n\t\t}\n\n\t};\n\n\t/*\n\t* override setDate() to allow setting time too within Date object\n\t*/\n\t$.datepicker._base_setDateDatepicker = $.datepicker._setDateDatepicker;\n\t$.datepicker._setDateDatepicker = function (target, date) {\n\t\tvar inst = this._getInst(target);\n\t\tif (!inst) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (typeof(date) === 'string') {\n\t\t\tdate = new Date(date);\n\t\t\tif (!date.getTime()) {\n\t\t\t\t$.timepicker.log(\"Error creating Date object from string.\");\n\t\t\t}\n\t\t}\n\n\t\tvar tp_inst = this._get(inst, 'timepicker');\n\t\tvar tp_date;\n\t\tif (date instanceof Date) {\n\t\t\ttp_date = new Date(date.getTime());\n\t\t\ttp_date.setMicroseconds(date.getMicroseconds());\n\t\t} else {\n\t\t\ttp_date = date;\n\t\t}\n\t\t\n\t\t// This is important if you are using the timezone option, javascript's Date \n\t\t// object will only return the timezone offset for the current locale, so we \n\t\t// adjust it accordingly. If not using timezone option this won't matter..\n\t\t// If a timezone is different in tp, keep the timezone as is\n\t\tif (tp_inst && tp_date) {\n\t\t\t// look out for DST if tz wasn't specified\n\t\t\tif (!tp_inst.support.timezone && tp_inst._defaults.timezone === null) {\n\t\t\t\ttp_inst.timezone = tp_date.getTimezoneOffset() * -1;\n\t\t\t}\n\t\t\tdate = $.timepicker.timezoneAdjust(date, tp_inst.timezone);\n\t\t\ttp_date = $.timepicker.timezoneAdjust(tp_date, tp_inst.timezone);\n\t\t}\n\n\t\tthis._updateDatepicker(inst);\n\t\tthis._base_setDateDatepicker.apply(this, arguments);\n\t\tthis._setTimeDatepicker(target, tp_date, true);\n\t};\n\n\t/*\n\t* override getDate() to allow getting time too within Date object\n\t*/\n\t$.datepicker._base_getDateDatepicker = $.datepicker._getDateDatepicker;\n\t$.datepicker._getDateDatepicker = function (target, noDefault) {\n\t\tvar inst = this._getInst(target);\n\t\tif (!inst) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar tp_inst = this._get(inst, 'timepicker');\n\n\t\tif (tp_inst) {\n\t\t\t// if it hasn't yet been defined, grab from field\n\t\t\tif (inst.lastVal === undefined) {\n\t\t\t\tthis._setDateFromField(inst, noDefault);\n\t\t\t}\n\n\t\t\tvar date = this._getDate(inst);\n\t\t\tif (date && tp_inst._parseTime($(target).val(), tp_inst.timeOnly)) {\n\t\t\t\tdate.setHours(tp_inst.hour, tp_inst.minute, tp_inst.second, tp_inst.millisec);\n\t\t\t\tdate.setMicroseconds(tp_inst.microsec);\n\n\t\t\t\t// This is important if you are using the timezone option, javascript's Date \n\t\t\t\t// object will only return the timezone offset for the current locale, so we \n\t\t\t\t// adjust it accordingly. If not using timezone option this won't matter..\n\t\t\t\tif (tp_inst.timezone != null) {\n\t\t\t\t\t// look out for DST if tz wasn't specified\n\t\t\t\t\tif (!tp_inst.support.timezone && tp_inst._defaults.timezone === null) {\n\t\t\t\t\t\ttp_inst.timezone = date.getTimezoneOffset() * -1;\n\t\t\t\t\t}\n\t\t\t\t\tdate = $.timepicker.timezoneAdjust(date, tp_inst.timezone);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn date;\n\t\t}\n\t\treturn this._base_getDateDatepicker(target, noDefault);\n\t};\n\n\t/*\n\t* override parseDate() because UI 1.8.14 throws an error about \"Extra characters\"\n\t* An option in datapicker to ignore extra format characters would be nicer.\n\t*/\n\t$.datepicker._base_parseDate = $.datepicker.parseDate;\n\t$.datepicker.parseDate = function (format, value, settings) {\n\t\tvar date;\n\t\ttry {\n\t\t\tdate = this._base_parseDate(format, value, settings);\n\t\t} catch (err) {\n\t\t\t// Hack! The error message ends with a colon, a space, and\n\t\t\t// the \"extra\" characters. We rely on that instead of\n\t\t\t// attempting to perfectly reproduce the parsing algorithm.\n\t\t\tif (err.indexOf(\":\") >= 0) {\n\t\t\t\tdate = this._base_parseDate(format, value.substring(0, value.length - (err.length - err.indexOf(':') - 2)), settings);\n\t\t\t\t$.timepicker.log(\"Error parsing the date string: \" + err + \"\\ndate string = \" + value + \"\\ndate format = \" + format);\n\t\t\t} else {\n\t\t\t\tthrow err;\n\t\t\t}\n\t\t}\n\t\treturn date;\n\t};\n\n\t/*\n\t* override formatDate to set date with time to the input\n\t*/\n\t$.datepicker._base_formatDate = $.datepicker._formatDate;\n\t$.datepicker._formatDate = function (inst, day, month, year) {\n\t\tvar tp_inst = this._get(inst, 'timepicker');\n\t\tif (tp_inst) {\n\t\t\ttp_inst._updateDateTime(inst);\n\t\t\treturn tp_inst.$input.val();\n\t\t}\n\t\treturn this._base_formatDate(inst);\n\t};\n\n\t/*\n\t* override options setter to add time to maxDate(Time) and minDate(Time). MaxDate\n\t*/\n\t$.datepicker._base_optionDatepicker = $.datepicker._optionDatepicker;\n\t$.datepicker._optionDatepicker = function (target, name, value) {\n\t\tvar inst = this._getInst(target),\n\t\t\tname_clone;\n\t\tif (!inst) {\n\t\t\treturn null;\n\t\t}\n\n\t\tvar tp_inst = this._get(inst, 'timepicker');\n\t\tif (tp_inst) {\n\t\t\tvar min = null,\n\t\t\t\tmax = null,\n\t\t\t\tonselect = null,\n\t\t\t\toverrides = tp_inst._defaults.evnts,\n\t\t\t\tfns = {},\n\t\t\t\tprop;\n\t\t\tif (typeof name === 'string') { // if min/max was set with the string\n\t\t\t\tif (name === 'minDate' || name === 'minDateTime') {\n\t\t\t\t\tmin = value;\n\t\t\t\t} else if (name === 'maxDate' || name === 'maxDateTime') {\n\t\t\t\t\tmax = value;\n\t\t\t\t} else if (name === 'onSelect') {\n\t\t\t\t\tonselect = value;\n\t\t\t\t} else if (overrides.hasOwnProperty(name)) {\n\t\t\t\t\tif (typeof (value) === 'undefined') {\n\t\t\t\t\t\treturn overrides[name];\n\t\t\t\t\t}\n\t\t\t\t\tfns[name] = value;\n\t\t\t\t\tname_clone = {}; //empty results in exiting function after overrides updated\n\t\t\t\t}\n\t\t\t} else if (typeof name === 'object') { //if min/max was set with the JSON\n\t\t\t\tif (name.minDate) {\n\t\t\t\t\tmin = name.minDate;\n\t\t\t\t} else if (name.minDateTime) {\n\t\t\t\t\tmin = name.minDateTime;\n\t\t\t\t} else if (name.maxDate) {\n\t\t\t\t\tmax = name.maxDate;\n\t\t\t\t} else if (name.maxDateTime) {\n\t\t\t\t\tmax = name.maxDateTime;\n\t\t\t\t}\n\t\t\t\tfor (prop in overrides) {\n\t\t\t\t\tif (overrides.hasOwnProperty(prop) && name[prop]) {\n\t\t\t\t\t\tfns[prop] = name[prop];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (prop in fns) {\n\t\t\t\tif (fns.hasOwnProperty(prop)) {\n\t\t\t\t\toverrides[prop] = fns[prop];\n\t\t\t\t\tif (!name_clone) { name_clone = $.extend({}, name); }\n\t\t\t\t\tdelete name_clone[prop];\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (name_clone && isEmptyObject(name_clone)) { return; }\n\t\t\tif (min) { //if min was set\n\t\t\t\tif (min === 0) {\n\t\t\t\t\tmin = new Date();\n\t\t\t\t} else {\n\t\t\t\t\tmin = new Date(min);\n\t\t\t\t}\n\t\t\t\ttp_inst._defaults.minDate = min;\n\t\t\t\ttp_inst._defaults.minDateTime = min;\n\t\t\t} else if (max) { //if max was set\n\t\t\t\tif (max === 0) {\n\t\t\t\t\tmax = new Date();\n\t\t\t\t} else {\n\t\t\t\t\tmax = new Date(max);\n\t\t\t\t}\n\t\t\t\ttp_inst._defaults.maxDate = max;\n\t\t\t\ttp_inst._defaults.maxDateTime = max;\n\t\t\t} else if (onselect) {\n\t\t\t\ttp_inst._defaults.onSelect = onselect;\n\t\t\t}\n\t\t}\n\t\tif (value === undefined) {\n\t\t\treturn this._base_optionDatepicker.call($.datepicker, target, name);\n\t\t}\n\t\treturn this._base_optionDatepicker.call($.datepicker, target, name_clone || name, value);\n\t};\n\t\n\t/*\n\t* jQuery isEmptyObject does not check hasOwnProperty - if someone has added to the object prototype,\n\t* it will return false for all objects\n\t*/\n\tvar isEmptyObject = function (obj) {\n\t\tvar prop;\n\t\tfor (prop in obj) {\n\t\t\tif (obj.hasOwnProperty(prop)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t};\n\n\t/*\n\t* jQuery extend now ignores nulls!\n\t*/\n\tvar extendRemove = function (target, props) {\n\t\t$.extend(target, props);\n\t\tfor (var name in props) {\n\t\t\tif (props[name] === null || props[name] === undefined) {\n\t\t\t\ttarget[name] = props[name];\n\t\t\t}\n\t\t}\n\t\treturn target;\n\t};\n\n\t/*\n\t* Determine by the time format which units are supported\n\t* Returns an object of booleans for each unit\n\t*/\n\tvar detectSupport = function (timeFormat) {\n\t\tvar tf = timeFormat.replace(/'.*?'/g, '').toLowerCase(), // removes literals\n\t\t\tisIn = function (f, t) { // does the format contain the token?\n\t\t\t\t\treturn f.indexOf(t) !== -1 ? true : false;\n\t\t\t\t};\n\t\treturn {\n\t\t\t\thour: isIn(tf, 'h'),\n\t\t\t\tminute: isIn(tf, 'm'),\n\t\t\t\tsecond: isIn(tf, 's'),\n\t\t\t\tmillisec: isIn(tf, 'l'),\n\t\t\t\tmicrosec: isIn(tf, 'c'),\n\t\t\t\ttimezone: isIn(tf, 'z'),\n\t\t\t\tampm: isIn(tf, 't') && isIn(timeFormat, 'h'),\n\t\t\t\tiso8601: isIn(timeFormat, 'Z')\n\t\t\t};\n\t};\n\n\t/*\n\t* Converts 24 hour format into 12 hour\n\t* Returns 12 hour without leading 0\n\t*/\n\tvar convert24to12 = function (hour) {\n\t\thour %= 12;\n\n\t\tif (hour === 0) {\n\t\t\thour = 12;\n\t\t}\n\n\t\treturn String(hour);\n\t};\n\n\tvar computeEffectiveSetting = function (settings, property) {\n\t\treturn settings && settings[property] ? settings[property] : $.timepicker._defaults[property];\n\t};\n\n\t/*\n\t* Splits datetime string into date and time substrings.\n\t* Throws exception when date can't be parsed\n\t* Returns {dateString: dateString, timeString: timeString}\n\t*/\n\tvar splitDateTime = function (dateTimeString, timeSettings) {\n\t\t// The idea is to get the number separator occurrences in datetime and the time format requested (since time has\n\t\t// fewer unknowns, mostly numbers and am/pm). We will use the time pattern to split.\n\t\tvar separator = computeEffectiveSetting(timeSettings, 'separator'),\n\t\t\tformat = computeEffectiveSetting(timeSettings, 'timeFormat'),\n\t\t\ttimeParts = format.split(separator), // how many occurrences of separator may be in our format?\n\t\t\ttimePartsLen = timeParts.length,\n\t\t\tallParts = dateTimeString.split(separator),\n\t\t\tallPartsLen = allParts.length;\n\n\t\tif (allPartsLen > 1) {\n\t\t\treturn {\n\t\t\t\tdateString: allParts.splice(0, allPartsLen - timePartsLen).join(separator),\n\t\t\t\ttimeString: allParts.splice(0, timePartsLen).join(separator)\n\t\t\t};\n\t\t}\n\n\t\treturn {\n\t\t\tdateString: dateTimeString,\n\t\t\ttimeString: ''\n\t\t};\n\t};\n\n\t/*\n\t* Internal function to parse datetime interval\n\t* Returns: {date: Date, timeObj: Object}, where\n\t* date - parsed date without time (type Date)\n\t* timeObj = {hour: , minute: , second: , millisec: , microsec: } - parsed time. Optional\n\t*/\n\tvar parseDateTimeInternal = function (dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings) {\n\t\tvar date,\n\t\t\tparts,\n\t\t\tparsedTime;\n\n\t\tparts = splitDateTime(dateTimeString, timeSettings);\n\t\tdate = $.datepicker._base_parseDate(dateFormat, parts.dateString, dateSettings);\n\n\t\tif (parts.timeString === '') {\n\t\t\treturn {\n\t\t\t\tdate: date\n\t\t\t};\n\t\t}\n\n\t\tparsedTime = $.datepicker.parseTime(timeFormat, parts.timeString, timeSettings);\n\n\t\tif (!parsedTime) {\n\t\t\tthrow 'Wrong time format';\n\t\t}\n\n\t\treturn {\n\t\t\tdate: date,\n\t\t\ttimeObj: parsedTime\n\t\t};\n\t};\n\n\t/*\n\t* Internal function to set timezone_select to the local timezone\n\t*/\n\tvar selectLocalTimezone = function (tp_inst, date) {\n\t\tif (tp_inst && tp_inst.timezone_select) {\n\t\t\tvar now = date || new Date();\n\t\t\ttp_inst.timezone_select.val(-now.getTimezoneOffset());\n\t\t}\n\t};\n\n\t/*\n\t* Create a Singleton Instance\n\t*/\n\t$.timepicker = new Timepicker();\n\n\t/**\n\t * Get the timezone offset as string from a date object (eg '+0530' for UTC+5.5)\n\t * @param {number} tzMinutes if not a number, less than -720 (-1200), or greater than 840 (+1400) this value is returned\n\t * @param {boolean} iso8601 if true formats in accordance to iso8601 \"+12:45\"\n\t * @return {string}\n\t */\n\t$.timepicker.timezoneOffsetString = function (tzMinutes, iso8601) {\n\t\tif (isNaN(tzMinutes) || tzMinutes > 840 || tzMinutes < -720) {\n\t\t\treturn tzMinutes;\n\t\t}\n\n\t\tvar off = tzMinutes,\n\t\t\tminutes = off % 60,\n\t\t\thours = (off - minutes) / 60,\n\t\t\tiso = iso8601 ? ':' : '',\n\t\t\ttz = (off >= 0 ? '+' : '-') + ('0' + Math.abs(hours)).slice(-2) + iso + ('0' + Math.abs(minutes)).slice(-2);\n\t\t\n\t\tif (tz === '+00:00') {\n\t\t\treturn 'Z';\n\t\t}\n\t\treturn tz;\n\t};\n\n\t/**\n\t * Get the number in minutes that represents a timezone string\n\t * @param {string} tzString formatted like \"+0500\", \"-1245\", \"Z\"\n\t * @return {number} the offset minutes or the original string if it doesn't match expectations\n\t */\n\t$.timepicker.timezoneOffsetNumber = function (tzString) {\n\t\tvar normalized = tzString.toString().replace(':', ''); // excuse any iso8601, end up with \"+1245\"\n\n\t\tif (normalized.toUpperCase() === 'Z') { // if iso8601 with Z, its 0 minute offset\n\t\t\treturn 0;\n\t\t}\n\n\t\tif (!/^(\\-|\\+)\\d{4}$/.test(normalized)) { // possibly a user defined tz, so just give it back\n\t\t\treturn tzString;\n\t\t}\n\n\t\treturn ((normalized.substr(0, 1) === '-' ? -1 : 1) * // plus or minus\n\t\t\t\t\t((parseInt(normalized.substr(1, 2), 10) * 60) + // hours (converted to minutes)\n\t\t\t\t\tparseInt(normalized.substr(3, 2), 10))); // minutes\n\t};\n\n\t/**\n\t * No way to set timezone in js Date, so we must adjust the minutes to compensate. (think setDate, getDate)\n\t * @param {Date} date\n\t * @param {string} toTimezone formatted like \"+0500\", \"-1245\"\n\t * @return {Date}\n\t */\n\t$.timepicker.timezoneAdjust = function (date, toTimezone) {\n\t\tvar toTz = $.timepicker.timezoneOffsetNumber(toTimezone);\n\t\tif (!isNaN(toTz)) {\n\t\t\tdate.setMinutes(date.getMinutes() + -date.getTimezoneOffset() - toTz);\n\t\t}\n\t\treturn date;\n\t};\n\n\t/**\n\t * Calls `timepicker()` on the `startTime` and `endTime` elements, and configures them to\n\t * enforce date range limits.\n\t * n.b. The input value must be correctly formatted (reformatting is not supported)\n\t * @param {Element} startTime\n\t * @param {Element} endTime\n\t * @param {Object} options Options for the timepicker() call\n\t * @return {jQuery}\n\t */\n\t$.timepicker.timeRange = function (startTime, endTime, options) {\n\t\treturn $.timepicker.handleRange('timepicker', startTime, endTime, options);\n\t};\n\n\t/**\n\t * Calls `datetimepicker` on the `startTime` and `endTime` elements, and configures them to\n\t * enforce date range limits.\n\t * @param {Element} startTime\n\t * @param {Element} endTime\n\t * @param {Object} options Options for the `timepicker()` call. Also supports `reformat`,\n\t * a boolean value that can be used to reformat the input values to the `dateFormat`.\n\t * @param {string} method Can be used to specify the type of picker to be added\n\t * @return {jQuery}\n\t */\n\t$.timepicker.datetimeRange = function (startTime, endTime, options) {\n\t\t$.timepicker.handleRange('datetimepicker', startTime, endTime, options);\n\t};\n\n\t/**\n\t * Calls `datepicker` on the `startTime` and `endTime` elements, and configures them to\n\t * enforce date range limits.\n\t * @param {Element} startTime\n\t * @param {Element} endTime\n\t * @param {Object} options Options for the `timepicker()` call. Also supports `reformat`,\n\t * a boolean value that can be used to reformat the input values to the `dateFormat`.\n\t * @return {jQuery}\n\t */\n\t$.timepicker.dateRange = function (startTime, endTime, options) {\n\t\t$.timepicker.handleRange('datepicker', startTime, endTime, options);\n\t};\n\n\t/**\n\t * Calls `method` on the `startTime` and `endTime` elements, and configures them to\n\t * enforce date range limits.\n\t * @param {string} method Can be used to specify the type of picker to be added\n\t * @param {Element} startTime\n\t * @param {Element} endTime\n\t * @param {Object} options Options for the `timepicker()` call. Also supports `reformat`,\n\t * a boolean value that can be used to reformat the input values to the `dateFormat`.\n\t * @return {jQuery}\n\t */\n\t$.timepicker.handleRange = function (method, startTime, endTime, options) {\n\t\toptions = $.extend({}, {\n\t\t\tminInterval: 0, // min allowed interval in milliseconds\n\t\t\tmaxInterval: 0, // max allowed interval in milliseconds\n\t\t\tstart: {}, // options for start picker\n\t\t\tend: {} // options for end picker\n\t\t}, options);\n\n\t\tfunction checkDates(changed, other) {\n\t\t\tvar startdt = startTime[method]('getDate'),\n\t\t\t\tenddt = endTime[method]('getDate'),\n\t\t\t\tchangeddt = changed[method]('getDate');\n\n\t\t\tif (startdt !== null) {\n\t\t\t\tvar minDate = new Date(startdt.getTime()),\n\t\t\t\t\tmaxDate = new Date(startdt.getTime());\n\n\t\t\t\tminDate.setMilliseconds(minDate.getMilliseconds() + options.minInterval);\n\t\t\t\tmaxDate.setMilliseconds(maxDate.getMilliseconds() + options.maxInterval);\n\n\t\t\t\tif (options.minInterval > 0 && minDate > enddt) { // minInterval check\n\t\t\t\t\tendTime[method]('setDate', minDate);\n\t\t\t\t}\n\t\t\t\telse if (options.maxInterval > 0 && maxDate < enddt) { // max interval check\n\t\t\t\t\tendTime[method]('setDate', maxDate);\n\t\t\t\t}\n\t\t\t\telse if (startdt > enddt) {\n\t\t\t\t\tother[method]('setDate', changeddt);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfunction selected(changed, other, option) {\n\t\t\tif (!changed.val()) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tvar date = changed[method].call(changed, 'getDate');\n\t\t\tif (date !== null && options.minInterval > 0) {\n\t\t\t\tif (option === 'minDate') {\n\t\t\t\t\tdate.setMilliseconds(date.getMilliseconds() + options.minInterval);\n\t\t\t\t}\n\t\t\t\tif (option === 'maxDate') {\n\t\t\t\t\tdate.setMilliseconds(date.getMilliseconds() - options.minInterval);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (date.getTime) {\n\t\t\t\tother[method].call(other, 'option', option, date);\n\t\t\t}\n\t\t}\n\n\t\t$.fn[method].call(startTime, $.extend({\n\t\t\tonClose: function (dateText, inst) {\n\t\t\t\tcheckDates($(this), endTime);\n\t\t\t},\n\t\t\tonSelect: function (selectedDateTime) {\n\t\t\t\tselected($(this), endTime, 'minDate');\n\t\t\t}\n\t\t}, options, options.start));\n\t\t$.fn[method].call(endTime, $.extend({\n\t\t\tonClose: function (dateText, inst) {\n\t\t\t\tcheckDates($(this), startTime);\n\t\t\t},\n\t\t\tonSelect: function (selectedDateTime) {\n\t\t\t\tselected($(this), startTime, 'maxDate');\n\t\t\t}\n\t\t}, options, options.end));\n\n\t\tcheckDates(startTime, endTime);\n\t\tselected(startTime, endTime, 'minDate');\n\t\tselected(endTime, startTime, 'maxDate');\n\t\treturn $([startTime.get(0), endTime.get(0)]);\n\t};\n\n\t/**\n\t * Log error or data to the console during error or debugging\n\t * @param {Object} err pass any type object to log to the console during error or debugging\n\t * @return {void}\n\t */\n\t$.timepicker.log = function (err) {\n\t\tif (window.console) {\n\t\t\twindow.console.log(err);\n\t\t}\n\t};\n\n\t/*\n\t * Add util object to allow access to private methods for testability.\n\t */\n\t$.timepicker._util = {\n\t\t_extendRemove: extendRemove,\n\t\t_isEmptyObject: isEmptyObject,\n\t\t_convert24to12: convert24to12,\n\t\t_detectSupport: detectSupport,\n\t\t_selectLocalTimezone: selectLocalTimezone,\n\t\t_computeEffectiveSetting: computeEffectiveSetting,\n\t\t_splitDateTime: splitDateTime,\n\t\t_parseDateTimeInternal: parseDateTimeInternal\n\t};\n\n\t/*\n\t* Microsecond support\n\t*/\n\tif (!Date.prototype.getMicroseconds) {\n\t\tDate.prototype.microseconds = 0;\n\t\tDate.prototype.getMicroseconds = function () { return this.microseconds; };\n\t\tDate.prototype.setMicroseconds = function (m) {\n\t\t\tthis.setMilliseconds(this.getMilliseconds() + Math.floor(m / 1000));\n\t\t\tthis.microseconds = m % 1000;\n\t\t\treturn this;\n\t\t};\n\t}\n\n\t/*\n\t* Keep up with the version\n\t*/\n\t$.timepicker.version = \"1.4.3\";\n\n}));","jquery/jquery-migrate.js":"/*!\n * jQuery Migrate - v1.4.1 - 2016-05-19\n * Copyright jQuery Foundation and other contributors\n */\n(function( jQuery, window, undefined ) {\n// See http://bugs.jquery.com/ticket/13335\n// \"use strict\";\n\n\njQuery.migrateVersion = \"1.4.1\";\n\n\nvar warnedAbout = {};\n\n// List of warnings already given; public read only\njQuery.migrateWarnings = [];\n\n// Set to true to prevent console output; migrateWarnings still maintained\n// jQuery.migrateMute = false;\n\n// Show a message on the console so devs know we're active\nif ( window.console && window.console.log ) {\n\twindow.console.log( \"JQMIGRATE: Migrate is installed\" +\n\t\t( jQuery.migrateMute ? \"\" : \" with logging active\" ) +\n\t\t\", version \" + jQuery.migrateVersion );\n}\n\n// Set to false to disable traces that appear with warnings\nif ( jQuery.migrateTrace === undefined ) {\n\tjQuery.migrateTrace = true;\n}\n\n// Forget any warnings we've already given; public\njQuery.migrateReset = function() {\n\twarnedAbout = {};\n\tjQuery.migrateWarnings.length = 0;\n};\n\nfunction migrateWarn( msg) {\n\tvar console = window.console;\n\tif ( !warnedAbout[ msg ] ) {\n\t\twarnedAbout[ msg ] = true;\n\t\tjQuery.migrateWarnings.push( msg );\n\t\tif ( console && console.warn && !jQuery.migrateMute ) {\n\t\t\tconsole.warn( \"JQMIGRATE: \" + msg );\n\t\t\tif ( jQuery.migrateTrace && console.trace ) {\n\t\t\t\tconsole.trace();\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction migrateWarnProp( obj, prop, value, msg ) {\n\tif ( Object.defineProperty ) {\n\t\t// On ES5 browsers (non-oldIE), warn if the code tries to get prop;\n\t\t// allow property to be overwritten in case some other plugin wants it\n\t\ttry {\n\t\t\tObject.defineProperty( obj, prop, {\n\t\t\t\tconfigurable: true,\n\t\t\t\tenumerable: true,\n\t\t\t\tget: function() {\n\t\t\t\t\tmigrateWarn( msg );\n\t\t\t\t\treturn value;\n\t\t\t\t},\n\t\t\t\tset: function( newValue ) {\n\t\t\t\t\tmigrateWarn( msg );\n\t\t\t\t\tvalue = newValue;\n\t\t\t\t}\n\t\t\t});\n\t\t\treturn;\n\t\t} catch( err ) {\n\t\t\t// IE8 is a dope about Object.defineProperty, can't warn there\n\t\t}\n\t}\n\n\t// Non-ES5 (or broken) browser; just set the property\n\tjQuery._definePropertyBroken = true;\n\tobj[ prop ] = value;\n}\n\nif ( document.compatMode === \"BackCompat\" ) {\n\t// jQuery has never supported or tested Quirks Mode\n\tmigrateWarn( \"jQuery is not compatible with Quirks Mode\" );\n}\n\n\nvar attrFn = jQuery( \"<input/>\", { size: 1 } ).attr(\"size\") && jQuery.attrFn,\n\toldAttr = jQuery.attr,\n\tvalueAttrGet = jQuery.attrHooks.value && jQuery.attrHooks.value.get ||\n\t\tfunction() { return null; },\n\tvalueAttrSet = jQuery.attrHooks.value && jQuery.attrHooks.value.set ||\n\t\tfunction() { return undefined; },\n\trnoType = /^(?:input|button)$/i,\n\trnoAttrNodeType = /^[238]$/,\n\trboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,\n\truseDefault = /^(?:checked|selected)$/i;\n\n// jQuery.attrFn\nmigrateWarnProp( jQuery, \"attrFn\", attrFn || {}, \"jQuery.attrFn is deprecated\" );\n\njQuery.attr = function( elem, name, value, pass ) {\n\tvar lowerName = name.toLowerCase(),\n\t\tnType = elem && elem.nodeType;\n\n\tif ( pass ) {\n\t\t// Since pass is used internally, we only warn for new jQuery\n\t\t// versions where there isn't a pass arg in the formal params\n\t\tif ( oldAttr.length < 4 ) {\n\t\t\tmigrateWarn(\"jQuery.fn.attr( props, pass ) is deprecated\");\n\t\t}\n\t\tif ( elem && !rnoAttrNodeType.test( nType ) &&\n\t\t\t(attrFn ? name in attrFn : jQuery.isFunction(jQuery.fn[name])) ) {\n\t\t\treturn jQuery( elem )[ name ]( value );\n\t\t}\n\t}\n\n\t// Warn if user tries to set `type`, since it breaks on IE 6/7/8; by checking\n\t// for disconnected elements we don't warn on $( \"<button>\", { type: \"button\" } ).\n\tif ( name === \"type\" && value !== undefined && rnoType.test( elem.nodeName ) && elem.parentNode ) {\n\t\tmigrateWarn(\"Can't change the 'type' of an input or button in IE 6/7/8\");\n\t}\n\n\t// Restore boolHook for boolean property/attribute synchronization\n\tif ( !jQuery.attrHooks[ lowerName ] && rboolean.test( lowerName ) ) {\n\t\tjQuery.attrHooks[ lowerName ] = {\n\t\t\tget: function( elem, name ) {\n\t\t\t\t// Align boolean attributes with corresponding properties\n\t\t\t\t// Fall back to attribute presence where some booleans are not supported\n\t\t\t\tvar attrNode,\n\t\t\t\t\tproperty = jQuery.prop( elem, name );\n\t\t\t\treturn property === true || typeof property !== \"boolean\" &&\n\t\t\t\t\t( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ?\n\n\t\t\t\t\tname.toLowerCase() :\n\t\t\t\t\tundefined;\n\t\t\t},\n\t\t\tset: function( elem, value, name ) {\n\t\t\t\tvar propName;\n\t\t\t\tif ( value === false ) {\n\t\t\t\t\t// Remove boolean attributes when set to false\n\t\t\t\t\tjQuery.removeAttr( elem, name );\n\t\t\t\t} else {\n\t\t\t\t\t// value is true since we know at this point it's type boolean and not false\n\t\t\t\t\t// Set boolean attributes to the same name and set the DOM property\n\t\t\t\t\tpropName = jQuery.propFix[ name ] || name;\n\t\t\t\t\tif ( propName in elem ) {\n\t\t\t\t\t\t// Only set the IDL specifically if it already exists on the element\n\t\t\t\t\t\telem[ propName ] = true;\n\t\t\t\t\t}\n\n\t\t\t\t\telem.setAttribute( name, name.toLowerCase() );\n\t\t\t\t}\n\t\t\t\treturn name;\n\t\t\t}\n\t\t};\n\n\t\t// Warn only for attributes that can remain distinct from their properties post-1.9\n\t\tif ( ruseDefault.test( lowerName ) ) {\n\t\t\tmigrateWarn( \"jQuery.fn.attr('\" + lowerName + \"') might use property instead of attribute\" );\n\t\t}\n\t}\n\n\treturn oldAttr.call( jQuery, elem, name, value );\n};\n\n// attrHooks: value\njQuery.attrHooks.value = {\n\tget: function( elem, name ) {\n\t\tvar nodeName = ( elem.nodeName || \"\" ).toLowerCase();\n\t\tif ( nodeName === \"button\" ) {\n\t\t\treturn valueAttrGet.apply( this, arguments );\n\t\t}\n\t\tif ( nodeName !== \"input\" && nodeName !== \"option\" ) {\n\t\t\tmigrateWarn(\"jQuery.fn.attr('value') no longer gets properties\");\n\t\t}\n\t\treturn name in elem ?\n\t\t\telem.value :\n\t\t\tnull;\n\t},\n\tset: function( elem, value ) {\n\t\tvar nodeName = ( elem.nodeName || \"\" ).toLowerCase();\n\t\tif ( nodeName === \"button\" ) {\n\t\t\treturn valueAttrSet.apply( this, arguments );\n\t\t}\n\t\tif ( nodeName !== \"input\" && nodeName !== \"option\" ) {\n\t\t\tmigrateWarn(\"jQuery.fn.attr('value', val) no longer sets properties\");\n\t\t}\n\t\t// Does not return so that setAttribute is also used\n\t\telem.value = value;\n\t}\n};\n\n\nvar matched, browser,\n\toldInit = jQuery.fn.init,\n\toldFind = jQuery.find,\n\toldParseJSON = jQuery.parseJSON,\n\trspaceAngle = /^\\s*</,\n\trattrHashTest = /\\[(\\s*[-\\w]+\\s*)([~|^$*]?=)\\s*([-\\w#]*?#[-\\w#]*)\\s*\\]/,\n\trattrHashGlob = /\\[(\\s*[-\\w]+\\s*)([~|^$*]?=)\\s*([-\\w#]*?#[-\\w#]*)\\s*\\]/g,\n\t// Note: XSS check is done below after string is trimmed\n\trquickExpr = /^([^<]*)(<[\\w\\W]+>)([^>]*)$/;\n\n// $(html) \"looks like html\" rule change\njQuery.fn.init = function( selector, context, rootjQuery ) {\n\tvar match, ret;\n\n\tif ( selector && typeof selector === \"string\" ) {\n\t\tif ( !jQuery.isPlainObject( context ) &&\n\t\t\t\t(match = rquickExpr.exec( jQuery.trim( selector ) )) && match[ 0 ] ) {\n\n\t\t\t// This is an HTML string according to the \"old\" rules; is it still?\n\t\t\tif ( !rspaceAngle.test( selector ) ) {\n\t\t\t\tmigrateWarn(\"$(html) HTML strings must start with '<' character\");\n\t\t\t}\n\t\t\tif ( match[ 3 ] ) {\n\t\t\t\tmigrateWarn(\"$(html) HTML text after last tag is ignored\");\n\t\t\t}\n\n\t\t\t// Consistently reject any HTML-like string starting with a hash (gh-9521)\n\t\t\t// Note that this may break jQuery 1.6.x code that otherwise would work.\n\t\t\tif ( match[ 0 ].charAt( 0 ) === \"#\" ) {\n\t\t\t\tmigrateWarn(\"HTML string cannot start with a '#' character\");\n\t\t\t\tjQuery.error(\"JQMIGRATE: Invalid selector string (XSS)\");\n\t\t\t}\n\n\t\t\t// Now process using loose rules; let pre-1.8 play too\n\t\t\t// Is this a jQuery context? parseHTML expects a DOM element (#178)\n\t\t\tif ( context && context.context && context.context.nodeType ) {\n\t\t\t\tcontext = context.context;\n\t\t\t}\n\n\t\t\tif ( jQuery.parseHTML ) {\n\t\t\t\treturn oldInit.call( this,\n\t\t\t\t\t\tjQuery.parseHTML( match[ 2 ], context && context.ownerDocument ||\n\t\t\t\t\t\t\tcontext || document, true ), context, rootjQuery );\n\t\t\t}\n\t\t}\n\t}\n\n\tret = oldInit.apply( this, arguments );\n\n\t// Fill in selector and context properties so .live() works\n\tif ( selector && selector.selector !== undefined ) {\n\t\t// A jQuery object, copy its properties\n\t\tret.selector = selector.selector;\n\t\tret.context = selector.context;\n\n\t} else {\n\t\tret.selector = typeof selector === \"string\" ? selector : \"\";\n\t\tif ( selector ) {\n\t\t\tret.context = selector.nodeType? selector : context || document;\n\t\t}\n\t}\n\n\treturn ret;\n};\njQuery.fn.init.prototype = jQuery.fn;\n\njQuery.find = function( selector ) {\n\tvar args = Array.prototype.slice.call( arguments );\n\n\t// Support: PhantomJS 1.x\n\t// String#match fails to match when used with a //g RegExp, only on some strings\n\tif ( typeof selector === \"string\" && rattrHashTest.test( selector ) ) {\n\n\t\t// The nonstandard and undocumented unquoted-hash was removed in jQuery 1.12.0\n\t\t// First see if qS thinks it's a valid selector, if so avoid a false positive\n\t\ttry {\n\t\t\tdocument.querySelector( selector );\n\t\t} catch ( err1 ) {\n\n\t\t\t// Didn't *look* valid to qSA, warn and try quoting what we think is the value\n\t\t\tselector = selector.replace( rattrHashGlob, function( _, attr, op, value ) {\n\t\t\t\treturn \"[\" + attr + op + \"\\\"\" + value + \"\\\"]\";\n\t\t\t} );\n\n\t\t\t// If the regexp *may* have created an invalid selector, don't update it\n\t\t\t// Note that there may be false alarms if selector uses jQuery extensions\n\t\t\ttry {\n\t\t\t\tdocument.querySelector( selector );\n\t\t\t\tmigrateWarn( \"Attribute selector with '#' must be quoted: \" + args[ 0 ] );\n\t\t\t\targs[ 0 ] = selector;\n\t\t\t} catch ( err2 ) {\n\t\t\t\tmigrateWarn( \"Attribute selector with '#' was not fixed: \" + args[ 0 ] );\n\t\t\t}\n\t\t}\n\t}\n\n\treturn oldFind.apply( this, args );\n};\n\n// Copy properties attached to original jQuery.find method (e.g. .attr, .isXML)\nvar findProp;\nfor ( findProp in oldFind ) {\n\tif ( Object.prototype.hasOwnProperty.call( oldFind, findProp ) ) {\n\t\tjQuery.find[ findProp ] = oldFind[ findProp ];\n\t}\n}\n\n// Let $.parseJSON(falsy_value) return null\njQuery.parseJSON = function( json ) {\n\tif ( !json ) {\n\t\tmigrateWarn(\"jQuery.parseJSON requires a valid JSON string\");\n\t\treturn null;\n\t}\n\treturn oldParseJSON.apply( this, arguments );\n};\n\njQuery.uaMatch = function( ua ) {\n\tua = ua.toLowerCase();\n\n\tvar match = /(chrome)[ \\/]([\\w.]+)/.exec( ua ) ||\n\t\t/(webkit)[ \\/]([\\w.]+)/.exec( ua ) ||\n\t\t/(opera)(?:.*version|)[ \\/]([\\w.]+)/.exec( ua ) ||\n\t\t/(msie) ([\\w.]+)/.exec( ua ) ||\n\t\tua.indexOf(\"compatible\") < 0 && /(mozilla)(?:.*? rv:([\\w.]+)|)/.exec( ua ) ||\n\t\t[];\n\n\treturn {\n\t\tbrowser: match[ 1 ] || \"\",\n\t\tversion: match[ 2 ] || \"0\"\n\t};\n};\n\n// Don't clobber any existing jQuery.browser in case it's different\nif ( !jQuery.browser ) {\n\tmatched = jQuery.uaMatch( navigator.userAgent );\n\tbrowser = {};\n\n\tif ( matched.browser ) {\n\t\tbrowser[ matched.browser ] = true;\n\t\tbrowser.version = matched.version;\n\t}\n\n\t// Chrome is Webkit, but Webkit is also Safari.\n\tif ( browser.chrome ) {\n\t\tbrowser.webkit = true;\n\t} else if ( browser.webkit ) {\n\t\tbrowser.safari = true;\n\t}\n\n\tjQuery.browser = browser;\n}\n\n// Warn if the code tries to get jQuery.browser\nmigrateWarnProp( jQuery, \"browser\", jQuery.browser, \"jQuery.browser is deprecated\" );\n\n// jQuery.boxModel deprecated in 1.3, jQuery.support.boxModel deprecated in 1.7\njQuery.boxModel = jQuery.support.boxModel = (document.compatMode === \"CSS1Compat\");\nmigrateWarnProp( jQuery, \"boxModel\", jQuery.boxModel, \"jQuery.boxModel is deprecated\" );\nmigrateWarnProp( jQuery.support, \"boxModel\", jQuery.support.boxModel, \"jQuery.support.boxModel is deprecated\" );\n\njQuery.sub = function() {\n\tfunction jQuerySub( selector, context ) {\n\t\treturn new jQuerySub.fn.init( selector, context );\n\t}\n\tjQuery.extend( true, jQuerySub, this );\n\tjQuerySub.superclass = this;\n\tjQuerySub.fn = jQuerySub.prototype = this();\n\tjQuerySub.fn.constructor = jQuerySub;\n\tjQuerySub.sub = this.sub;\n\tjQuerySub.fn.init = function init( selector, context ) {\n\t\tvar instance = jQuery.fn.init.call( this, selector, context, rootjQuerySub );\n\t\treturn instance instanceof jQuerySub ?\n\t\t\tinstance :\n\t\t\tjQuerySub( instance );\n\t};\n\tjQuerySub.fn.init.prototype = jQuerySub.fn;\n\tvar rootjQuerySub = jQuerySub(document);\n\tmigrateWarn( \"jQuery.sub() is deprecated\" );\n\treturn jQuerySub;\n};\n\n// The number of elements contained in the matched element set\njQuery.fn.size = function() {\n\tmigrateWarn( \"jQuery.fn.size() is deprecated; use the .length property\" );\n\treturn this.length;\n};\n\n\nvar internalSwapCall = false;\n\n// If this version of jQuery has .swap(), don't false-alarm on internal uses\nif ( jQuery.swap ) {\n\tjQuery.each( [ \"height\", \"width\", \"reliableMarginRight\" ], function( _, name ) {\n\t\tvar oldHook = jQuery.cssHooks[ name ] && jQuery.cssHooks[ name ].get;\n\n\t\tif ( oldHook ) {\n\t\t\tjQuery.cssHooks[ name ].get = function() {\n\t\t\t\tvar ret;\n\n\t\t\t\tinternalSwapCall = true;\n\t\t\t\tret = oldHook.apply( this, arguments );\n\t\t\t\tinternalSwapCall = false;\n\t\t\t\treturn ret;\n\t\t\t};\n\t\t}\n\t});\n}\n\njQuery.swap = function( elem, options, callback, args ) {\n\tvar ret, name,\n\t\told = {};\n\n\tif ( !internalSwapCall ) {\n\t\tmigrateWarn( \"jQuery.swap() is undocumented and deprecated\" );\n\t}\n\n\t// Remember the old values, and insert the new ones\n\tfor ( name in options ) {\n\t\told[ name ] = elem.style[ name ];\n\t\telem.style[ name ] = options[ name ];\n\t}\n\n\tret = callback.apply( elem, args || [] );\n\n\t// Revert the old values\n\tfor ( name in options ) {\n\t\telem.style[ name ] = old[ name ];\n\t}\n\n\treturn ret;\n};\n\n\n// Ensure that $.ajax gets the new parseJSON defined in core.js\njQuery.ajaxSetup({\n\tconverters: {\n\t\t\"text json\": jQuery.parseJSON\n\t}\n});\n\n\nvar oldFnData = jQuery.fn.data;\n\njQuery.fn.data = function( name ) {\n\tvar ret, evt,\n\t\telem = this[0];\n\n\t// Handles 1.7 which has this behavior and 1.8 which doesn't\n\tif ( elem && name === \"events\" && arguments.length === 1 ) {\n\t\tret = jQuery.data( elem, name );\n\t\tevt = jQuery._data( elem, name );\n\t\tif ( ( ret === undefined || ret === evt ) && evt !== undefined ) {\n\t\t\tmigrateWarn(\"Use of jQuery.fn.data('events') is deprecated\");\n\t\t\treturn evt;\n\t\t}\n\t}\n\treturn oldFnData.apply( this, arguments );\n};\n\n\nvar rscriptType = /\\/(java|ecma)script/i;\n\n// Since jQuery.clean is used internally on older versions, we only shim if it's missing\nif ( !jQuery.clean ) {\n\tjQuery.clean = function( elems, context, fragment, scripts ) {\n\t\t// Set context per 1.8 logic\n\t\tcontext = context || document;\n\t\tcontext = !context.nodeType && context[0] || context;\n\t\tcontext = context.ownerDocument || context;\n\n\t\tmigrateWarn(\"jQuery.clean() is deprecated\");\n\n\t\tvar i, elem, handleScript, jsTags,\n\t\t\tret = [];\n\n\t\tjQuery.merge( ret, jQuery.buildFragment( elems, context ).childNodes );\n\n\t\t// Complex logic lifted directly from jQuery 1.8\n\t\tif ( fragment ) {\n\t\t\t// Special handling of each script element\n\t\t\thandleScript = function( elem ) {\n\t\t\t\t// Check if we consider it executable\n\t\t\t\tif ( !elem.type || rscriptType.test( elem.type ) ) {\n\t\t\t\t\t// Detach the script and store it in the scripts array (if provided) or the fragment\n\t\t\t\t\t// Return truthy to indicate that it has been handled\n\t\t\t\t\treturn scripts ?\n\t\t\t\t\t\tscripts.push( elem.parentNode ? elem.parentNode.removeChild( elem ) : elem ) :\n\t\t\t\t\t\tfragment.appendChild( elem );\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tfor ( i = 0; (elem = ret[i]) != null; i++ ) {\n\t\t\t\t// Check if we're done after handling an executable script\n\t\t\t\tif ( !( jQuery.nodeName( elem, \"script\" ) && handleScript( elem ) ) ) {\n\t\t\t\t\t// Append to fragment and handle embedded scripts\n\t\t\t\t\tfragment.appendChild( elem );\n\t\t\t\t\tif ( typeof elem.getElementsByTagName !== \"undefined\" ) {\n\t\t\t\t\t\t// handleScript alters the DOM, so use jQuery.merge to ensure snapshot iteration\n\t\t\t\t\t\tjsTags = jQuery.grep( jQuery.merge( [], elem.getElementsByTagName(\"script\") ), handleScript );\n\n\t\t\t\t\t\t// Splice the scripts into ret after their former ancestor and advance our index beyond them\n\t\t\t\t\t\tret.splice.apply( ret, [i + 1, 0].concat( jsTags ) );\n\t\t\t\t\t\ti += jsTags.length;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn ret;\n\t};\n}\n\nvar eventAdd = jQuery.event.add,\n\teventRemove = jQuery.event.remove,\n\teventTrigger = jQuery.event.trigger,\n\toldToggle = jQuery.fn.toggle,\n\toldLive = jQuery.fn.live,\n\toldDie = jQuery.fn.die,\n\toldLoad = jQuery.fn.load,\n\tajaxEvents = \"ajaxStart|ajaxStop|ajaxSend|ajaxComplete|ajaxError|ajaxSuccess\",\n\trajaxEvent = new RegExp( \"\\\\b(?:\" + ajaxEvents + \")\\\\b\" ),\n\trhoverHack = /(?:^|\\s)hover(\\.\\S+|)\\b/,\n\thoverHack = function( events ) {\n\t\tif ( typeof( events ) !== \"string\" || jQuery.event.special.hover ) {\n\t\t\treturn events;\n\t\t}\n\t\tif ( rhoverHack.test( events ) ) {\n\t\t\tmigrateWarn(\"'hover' pseudo-event is deprecated, use 'mouseenter mouseleave'\");\n\t\t}\n\t\treturn events && events.replace( rhoverHack, \"mouseenter$1 mouseleave$1\" );\n\t};\n\n// Event props removed in 1.9, put them back if needed; no practical way to warn them\nif ( jQuery.event.props && jQuery.event.props[ 0 ] !== \"attrChange\" ) {\n\tjQuery.event.props.unshift( \"attrChange\", \"attrName\", \"relatedNode\", \"srcElement\" );\n}\n\n// Undocumented jQuery.event.handle was \"deprecated\" in jQuery 1.7\nif ( jQuery.event.dispatch ) {\n\tmigrateWarnProp( jQuery.event, \"handle\", jQuery.event.dispatch, \"jQuery.event.handle is undocumented and deprecated\" );\n}\n\n// Support for 'hover' pseudo-event and ajax event warnings\njQuery.event.add = function( elem, types, handler, data, selector ){\n\tif ( elem !== document && rajaxEvent.test( types ) ) {\n\t\tmigrateWarn( \"AJAX events should be attached to document: \" + types );\n\t}\n\teventAdd.call( this, elem, hoverHack( types || \"\" ), handler, data, selector );\n};\njQuery.event.remove = function( elem, types, handler, selector, mappedTypes ){\n\teventRemove.call( this, elem, hoverHack( types ) || \"\", handler, selector, mappedTypes );\n};\n\njQuery.each( [ \"load\", \"unload\", \"error\" ], function( _, name ) {\n\n\tjQuery.fn[ name ] = function() {\n\t\tvar args = Array.prototype.slice.call( arguments, 0 );\n\n\t\t// If this is an ajax load() the first arg should be the string URL;\n\t\t// technically this could also be the \"Anything\" arg of the event .load()\n\t\t// which just goes to show why this dumb signature has been deprecated!\n\t\t// jQuery custom builds that exclude the Ajax module justifiably die here.\n\t\tif ( name === \"load\" && typeof args[ 0 ] === \"string\" ) {\n\t\t\treturn oldLoad.apply( this, args );\n\t\t}\n\n\t\tmigrateWarn( \"jQuery.fn.\" + name + \"() is deprecated\" );\n\n\t\targs.splice( 0, 0, name );\n\t\tif ( arguments.length ) {\n\t\t\treturn this.bind.apply( this, args );\n\t\t}\n\n\t\t// Use .triggerHandler here because:\n\t\t// - load and unload events don't need to bubble, only applied to window or image\n\t\t// - error event should not bubble to window, although it does pre-1.7\n\t\t// See http://bugs.jquery.com/ticket/11820\n\t\tthis.triggerHandler.apply( this, args );\n\t\treturn this;\n\t};\n\n});\n\njQuery.fn.toggle = function( fn, fn2 ) {\n\n\t// Don't mess with animation or css toggles\n\tif ( !jQuery.isFunction( fn ) || !jQuery.isFunction( fn2 ) ) {\n\t\treturn oldToggle.apply( this, arguments );\n\t}\n\tmigrateWarn(\"jQuery.fn.toggle(handler, handler...) is deprecated\");\n\n\t// Save reference to arguments for access in closure\n\tvar args = arguments,\n\t\tguid = fn.guid || jQuery.guid++,\n\t\ti = 0,\n\t\ttoggler = function( event ) {\n\t\t\t// Figure out which function to execute\n\t\t\tvar lastToggle = ( jQuery._data( this, \"lastToggle\" + fn.guid ) || 0 ) % i;\n\t\t\tjQuery._data( this, \"lastToggle\" + fn.guid, lastToggle + 1 );\n\n\t\t\t// Make sure that clicks stop\n\t\t\tevent.preventDefault();\n\n\t\t\t// and execute the function\n\t\t\treturn args[ lastToggle ].apply( this, arguments ) || false;\n\t\t};\n\n\t// link all the functions, so any of them can unbind this click handler\n\ttoggler.guid = guid;\n\twhile ( i < args.length ) {\n\t\targs[ i++ ].guid = guid;\n\t}\n\n\treturn this.click( toggler );\n};\n\njQuery.fn.live = function( types, data, fn ) {\n\tmigrateWarn(\"jQuery.fn.live() is deprecated\");\n\tif ( oldLive ) {\n\t\treturn oldLive.apply( this, arguments );\n\t}\n\tjQuery( this.context ).on( types, this.selector, data, fn );\n\treturn this;\n};\n\njQuery.fn.die = function( types, fn ) {\n\tmigrateWarn(\"jQuery.fn.die() is deprecated\");\n\tif ( oldDie ) {\n\t\treturn oldDie.apply( this, arguments );\n\t}\n\tjQuery( this.context ).off( types, this.selector || \"**\", fn );\n\treturn this;\n};\n\n// Turn global events into document-triggered events\njQuery.event.trigger = function( event, data, elem, onlyHandlers ){\n\tif ( !elem && !rajaxEvent.test( event ) ) {\n\t\tmigrateWarn( \"Global events are undocumented and deprecated\" );\n\t}\n\treturn eventTrigger.call( this, event, data, elem || document, onlyHandlers );\n};\njQuery.each( ajaxEvents.split(\"|\"),\n\tfunction( _, name ) {\n\t\tjQuery.event.special[ name ] = {\n\t\t\tsetup: function() {\n\t\t\t\tvar elem = this;\n\n\t\t\t\t// The document needs no shimming; must be !== for oldIE\n\t\t\t\tif ( elem !== document ) {\n\t\t\t\t\tjQuery.event.add( document, name + \".\" + jQuery.guid, function() {\n\t\t\t\t\t\tjQuery.event.trigger( name, Array.prototype.slice.call( arguments, 1 ), elem, true );\n\t\t\t\t\t});\n\t\t\t\t\tjQuery._data( this, name, jQuery.guid++ );\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t},\n\t\t\tteardown: function() {\n\t\t\t\tif ( this !== document ) {\n\t\t\t\t\tjQuery.event.remove( document, name + \".\" + jQuery._data( this, name ) );\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t}\n\t\t};\n\t}\n);\n\njQuery.event.special.ready = {\n\tsetup: function() {\n\t\tif ( this === document ) {\n\t\t\tmigrateWarn( \"'ready' event is deprecated\" );\n\t\t}\n\t}\n};\n\nvar oldSelf = jQuery.fn.andSelf || jQuery.fn.addBack,\n\toldFnFind = jQuery.fn.find;\n\njQuery.fn.andSelf = function() {\n\tmigrateWarn(\"jQuery.fn.andSelf() replaced by jQuery.fn.addBack()\");\n\treturn oldSelf.apply( this, arguments );\n};\n\njQuery.fn.find = function( selector ) {\n\tvar ret = oldFnFind.apply( this, arguments );\n\tret.context = this.context;\n\tret.selector = this.selector ? this.selector + \" \" + selector : selector;\n\treturn ret;\n};\n\n\n// jQuery 1.6 did not support Callbacks, do not warn there\nif ( jQuery.Callbacks ) {\n\n\tvar oldDeferred = jQuery.Deferred,\n\t\ttuples = [\n\t\t\t// action, add listener, callbacks, .then handlers, final state\n\t\t\t[ \"resolve\", \"done\", jQuery.Callbacks(\"once memory\"),\n\t\t\t\tjQuery.Callbacks(\"once memory\"), \"resolved\" ],\n\t\t\t[ \"reject\", \"fail\", jQuery.Callbacks(\"once memory\"),\n\t\t\t\tjQuery.Callbacks(\"once memory\"), \"rejected\" ],\n\t\t\t[ \"notify\", \"progress\", jQuery.Callbacks(\"memory\"),\n\t\t\t\tjQuery.Callbacks(\"memory\") ]\n\t\t];\n\n\tjQuery.Deferred = function( func ) {\n\t\tvar deferred = oldDeferred(),\n\t\t\tpromise = deferred.promise();\n\n\t\tdeferred.pipe = promise.pipe = function( /* fnDone, fnFail, fnProgress */ ) {\n\t\t\tvar fns = arguments;\n\n\t\t\tmigrateWarn( \"deferred.pipe() is deprecated\" );\n\n\t\t\treturn jQuery.Deferred(function( newDefer ) {\n\t\t\t\tjQuery.each( tuples, function( i, tuple ) {\n\t\t\t\t\tvar fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];\n\t\t\t\t\t// deferred.done(function() { bind to newDefer or newDefer.resolve })\n\t\t\t\t\t// deferred.fail(function() { bind to newDefer or newDefer.reject })\n\t\t\t\t\t// deferred.progress(function() { bind to newDefer or newDefer.notify })\n\t\t\t\t\tdeferred[ tuple[1] ](function() {\n\t\t\t\t\t\tvar returned = fn && fn.apply( this, arguments );\n\t\t\t\t\t\tif ( returned && jQuery.isFunction( returned.promise ) ) {\n\t\t\t\t\t\t\treturned.promise()\n\t\t\t\t\t\t\t\t.done( newDefer.resolve )\n\t\t\t\t\t\t\t\t.fail( newDefer.reject )\n\t\t\t\t\t\t\t\t.progress( newDefer.notify );\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tnewDefer[ tuple[ 0 ] + \"With\" ](\n\t\t\t\t\t\t\t\tthis === promise ? newDefer.promise() : this,\n\t\t\t\t\t\t\t\tfn ? [ returned ] : arguments\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t\tfns = null;\n\t\t\t}).promise();\n\n\t\t};\n\n\t\tdeferred.isResolved = function() {\n\t\t\tmigrateWarn( \"deferred.isResolved is deprecated\" );\n\t\t\treturn deferred.state() === \"resolved\";\n\t\t};\n\n\t\tdeferred.isRejected = function() {\n\t\t\tmigrateWarn( \"deferred.isRejected is deprecated\" );\n\t\t\treturn deferred.state() === \"rejected\";\n\t\t};\n\n\t\tif ( func ) {\n\t\t\tfunc.call( deferred, deferred );\n\t\t}\n\n\t\treturn deferred;\n\t};\n\n}\n\n})( jQuery, window );\n\n","jquery/jquery.details.js":"/*! http://mths.be/details v0.0.6 by @mathias | includes http://mths.be/noselect v1.0.3 */\ndefine([\n \"jquery\",\n \"modernizr/modernizr.details\"\n], function($){\n\n var proto = $.fn,\n details,\n // :'(\n isOpera = Object.prototype.toString.call(window.opera) == '[object Opera]',\n // Feature test for native `<details>` support\n isDetailsSupported = $('html').hasClass('details'),\n toggleOpen = function($details, $detailsSummary, $detailsNotSummary, toggle) {\n var isOpen = typeof $details.attr('open') == 'string',\n close = isOpen && toggle || !isOpen && !toggle;\n if (close) {\n $details.removeClass('open').prop('open', false).triggerHandler('close.details');\n $detailsSummary.attr('aria-expanded', false);\n $detailsNotSummary.hide();\n } else {\n $details.addClass('open').prop('open', true).triggerHandler('open.details');\n $detailsSummary.attr('aria-expanded', true);\n $detailsNotSummary.show();\n }\n };\n\n /* http://mths.be/noselect v1.0.3 */\n proto.noSelect = function() {\n\n // Since the string 'none' is used three times, storing it in a variable gives better results after minification\n var none = 'none';\n\n // onselectstart and ondragstart for WebKit & IE\n // onmousedown for WebKit & Opera\n return this.bind('selectstart dragstart mousedown', function() {\n return false;\n }).css({\n 'MozUserSelect': none,\n 'msUserSelect': none,\n 'webkitUserSelect': none,\n 'userSelect': none\n });\n\n };\n\n // Execute the fallback only if there\u2019s no native `details` support\n if (isDetailsSupported) {\n details = proto.details = function() {\n\n return this.each(function() {\n var $details = $(this),\n $summary = $('summary', $details).first();\n $summary.attr({\n 'role': 'button',\n 'aria-expanded': $details.prop('open')\n }).on('click.xxx', function() {\n // the value of the `open` property is the old value\n var close = $details.prop('open');\n $summary.attr('aria-expanded', !close);\n $details.triggerHandler((close ? 'close' : 'open') + '.details');\n });\n });\n\n };\n\n details.support = isDetailsSupported;\n\n } else {\n details = proto.details = function() {\n\n // Loop through all `details` elements\n return this.each(function() {\n\n // Store a reference to the current `details` element in a variable\n var $details = $(this),\n // Store a reference to the `summary` element of the current `details` element (if any) in a variable\n $detailsSummary = $('summary', $details).first(),\n // Do the same for the info within the `details` element\n $detailsNotSummary = $details.children(':not(summary)'),\n // This will be used later to look for direct child text nodes\n $detailsNotSummaryContents = $details.contents(':not(summary)');\n\n // If there is no `summary` in the current `details` element\u2026\n if (!$detailsSummary.length) {\n // \u2026create one with default text\n $detailsSummary = $('<summary>').text($.mage.__('Details')).prependTo($details);\n }\n\n // Look for direct child text nodes\n if ($detailsNotSummary.length != $detailsNotSummaryContents.length) {\n // Wrap child text nodes in a `span` element\n $detailsNotSummaryContents.filter(function() {\n // Only keep the node in the collection if it\u2019s a text node containing more than only whitespace\n // http://www.whatwg.org/specs/web-apps/current-work/multipage/common-microsyntaxes.html#space-character\n return this.nodeType == 3 && /[^ \\t\\n\\f\\r]/.test(this.data);\n }).wrap('<span>');\n // There are now no direct child text nodes anymore \u2014 they\u2019re wrapped in `span` elements\n $detailsNotSummary = $details.children(':not(summary)');\n }\n\n // Hide content unless there\u2019s an `open` attribute\n toggleOpen($details, $detailsSummary, $detailsNotSummary);\n\n // Add `role=button` and set the `tabindex` of the `summary` element to `0` to make it keyboard accessible\n $detailsSummary.attr('role', 'button').noSelect().prop('tabIndex', 0).off('click').on('click.details', function() {\n // Focus on the `summary` element\n $detailsSummary.focus();\n // Toggle the `open` and `aria-expanded` attributes and the `open` property of the `details` element and display the additional info\n toggleOpen($details, $detailsSummary, $detailsNotSummary, true);\n }).keyup(function(event) {\n if (32 == event.keyCode || (13 == event.keyCode && !isOpera)) {\n // Space or Enter is pressed \u2014 trigger the `click` event on the `summary` element\n // Opera already seems to trigger the `click` event when Enter is pressed\n event.preventDefault();\n $detailsSummary.click();\n }\n });\n\n });\n\n };\n\n details.support = isDetailsSupported;\n\n }\n\n});\n"} }});