; define("js/bundles/bootstrap", function(){}); /** * Copyright © Vaimo Group. All rights reserved. * See LICENSE_VAIMO.txt for license details. */ ;define('Vaimo_BauhausSe/js/mock/momentjs-mock', [], function () { 'use strict'; var Moment = function (value, format) { try { this.date = new Date(value); } catch (e) {} }; Moment.prototype.isValid = function () { try { return !!this.date && this.date.toString() !== new Date(0).toString(); } catch (e) { return false; } }; Moment.prototype.format = function () { var result = ''; try { result = this.date ? this.date.toString() : ''; } catch (e) {} return result; }; Moment.prototype.unix = function () { try { return this.date.getTime(); } catch (e) { return -1; } }; var momentFactory = function (value, format) { return new Moment(value, format); }; momentFactory.utc = function (value, format) { return new Moment(value, format); }; return momentFactory; }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('Magento_Customer/js/section-config',['underscore'], function (_) { 'use strict'; var baseUrls = [], sections = [], clientSideSections = [], sectionNames = [], canonize; /** * @param {String} url * @return {String} */ canonize = function (url) { var route = url; _.some(baseUrls, function (baseUrl) { route = url.replace(baseUrl, ''); return route !== url; }); return route.replace(/^\/?index.php\/?/, '').toLowerCase(); }; return { /** * Returns a list of sections which should be invalidated for given URL. * @param {String} url - URL which was requested. * @return {Object} - List of sections to invalidate. */ getAffectedSections: function (url) { var route = canonize(url), actions = _.find(sections, function (val, section) { var matched; // Covers the case where "*" works as a glob pattern. if (section.indexOf('*') >= 0) { section = section.replace(/\*/g, '[^/]+') + '$'; matched = route.match(section); return matched && matched[0] === route; } return route.indexOf(section) === 0; }); return _.union(_.toArray(actions), sections['*']); }, /** * Filters the list of given sections to the ones defined as client side. * @param {Object} allSections - List of sections to check. * @return {Object} - List of filtered sections. */ filterClientSideSections: function (allSections) { return _.difference(allSections, clientSideSections); }, /** * Tells if section is defined as client side. * @param {String} sectionName - Name of the section to check. * @return {Boolean} */ isClientSideSection: function (sectionName) { return _.contains(clientSideSections, sectionName); }, /** * Returns array of section names. * @returns {Array} */ getSectionNames: function () { return sectionNames; }, /** * @param {Object} options * @constructor */ 'Magento_Customer/js/section-config': function (options) { baseUrls = options.baseUrls; sections = options.sections; clientSideSections = options.clientSideSections; sectionNames = options.sectionNames; } }; }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /* eslint-disable strict */ define('mage/url',[], function () { var baseUrl = ''; return { /** * @param {String} url */ setBaseUrl: function (url) { baseUrl = url; }, /** * @param {String} path * @return {*} */ build: function (path) { if (path.indexOf(baseUrl) !== -1) { return path; } return baseUrl + path; } }; }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('mage/storage',['jquery', 'mage/url'], function ($, urlBuilder) { 'use strict'; return { /** * Perform asynchronous GET request to server. * @param {String} url * @param {Boolean} global * @param {String} contentType * @param {Object} headers * @returns {Deferred} */ get: function (url, global, contentType, headers) { headers = headers || {}; global = global === undefined ? true : global; contentType = contentType || 'application/json'; return $.ajax({ url: urlBuilder.build(url), type: 'GET', global: global, contentType: contentType, headers: headers }); }, /** * Perform asynchronous POST request to server. * @param {String} url * @param {String} data * @param {Boolean} global * @param {String} contentType * @param {Object} headers * @param {Boolean} async * @returns {Deferred} */ post: function (url, data, global, contentType, headers, async) { headers = headers || {}; global = global === undefined ? true : global; contentType = contentType || 'application/json'; async = async === undefined ? true : async; return $.ajax({ url: urlBuilder.build(url), type: 'POST', data: data, global: global, contentType: contentType, headers: headers, async: async }); }, /** * Perform asynchronous PUT request to server. * @param {String} url * @param {String} data * @param {Boolean} global * @param {String} contentType * @param {Object} headers * @returns {Deferred} */ put: function (url, data, global, contentType, headers) { var ajaxSettings = {}; headers = headers || {}; global = global === undefined ? true : global; contentType = contentType || 'application/json'; ajaxSettings.url = urlBuilder.build(url); ajaxSettings.type = 'PUT'; ajaxSettings.data = data; ajaxSettings.global = global; ajaxSettings.contentType = contentType; ajaxSettings.headers = headers; return $.ajax(ajaxSettings); }, /** * Perform asynchronous DELETE request to server. * @param {String} url * @param {Boolean} global * @param {String} contentType * @param {Object} headers * @returns {Deferred} */ delete: function (url, global, contentType, headers) { headers = headers || {}; global = global === undefined ? true : global; contentType = contentType || 'application/json'; return $.ajax({ url: urlBuilder.build(url), type: 'DELETE', global: global, contentType: contentType, headers: headers }); } }; }); /*! js-cookie v3.0.5 | MIT */ ; (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define('js-cookie/js.cookie',factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, (function () { var current = global.Cookies; var exports = global.Cookies = factory(); exports.noConflict = function () { global.Cookies = current; return exports; }; })()); })(this, (function () { 'use strict'; /* eslint-disable no-var */ function assign (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { target[key] = source[key]; } } return target } /* eslint-enable no-var */ /* eslint-disable no-var */ var defaultConverter = { read: function (value) { if (value[0] === '"') { value = value.slice(1, -1); } return value.replace(/(%[\dA-F]{2})+/gi, decodeURIComponent) }, write: function (value) { return encodeURIComponent(value).replace( /%(2[346BF]|3[AC-F]|40|5[BDE]|60|7[BCD])/g, decodeURIComponent ) } }; /* eslint-enable no-var */ /* eslint-disable no-var */ function init (converter, defaultAttributes) { function set (name, value, attributes) { if (typeof document === 'undefined') { return } attributes = assign({}, defaultAttributes, attributes); if (typeof attributes.expires === 'number') { attributes.expires = new Date(Date.now() + attributes.expires * 864e5); } if (attributes.expires) { attributes.expires = attributes.expires.toUTCString(); } name = encodeURIComponent(name) .replace(/%(2[346B]|5E|60|7C)/g, decodeURIComponent) .replace(/[()]/g, escape); var stringifiedAttributes = ''; for (var attributeName in attributes) { if (!attributes[attributeName]) { continue } stringifiedAttributes += '; ' + attributeName; if (attributes[attributeName] === true) { continue } // Considers RFC 6265 section 5.2: // ... // 3. If the remaining unparsed-attributes contains a %x3B (";") // character: // Consume the characters of the unparsed-attributes up to, // not including, the first %x3B (";") character. // ... stringifiedAttributes += '=' + attributes[attributeName].split(';')[0]; } return (document.cookie = name + '=' + converter.write(value, name) + stringifiedAttributes) } function get (name) { if (typeof document === 'undefined' || (arguments.length && !name)) { return } // To prevent the for loop in the first place assign an empty array // in case there are no cookies at all. var cookies = document.cookie ? document.cookie.split('; ') : []; var jar = {}; for (var i = 0; i < cookies.length; i++) { var parts = cookies[i].split('='); var value = parts.slice(1).join('='); try { var found = decodeURIComponent(parts[0]); jar[found] = converter.read(value, found); if (name === found) { break } } catch (e) {} } return name ? jar[name] : jar } return Object.create( { set, get, remove: function (name, attributes) { set( name, '', assign({}, attributes, { expires: -1 }) ); }, withAttributes: function (attributes) { return init(this.converter, assign({}, this.attributes, attributes)) }, withConverter: function (converter) { return init(assign({}, this.converter, converter), this.attributes) } }, { attributes: { value: Object.freeze(defaultAttributes) }, converter: { value: Object.freeze(converter) } } ) } var api = init(defaultConverter, { path: '/' }); /* eslint-enable no-var */ return api; })); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('js-cookie/cookie-wrapper',[ 'jquery', 'js-cookie/js.cookie' ], function ($, cookie) { 'use strict'; window.Cookies = window.Cookies || cookie; var config = $.cookie = function (key, value, options) { if (value !== undefined) { options = $.extend({}, config.defaults, options); return cookie.set(key, value, options); } var result = key ? undefined : {}, cookies = document.cookie ? document.cookie.split('; ') : [], i; for (i = 0; i < cookies.length; i++) { var parts = cookies[i].split('='), name = config.raw ? parts.shift() : decodeURIComponent(parts.shift()), cookieValue = parts.join('='); if (key && key === name) { result = decodeURIComponent(cookieValue.replace('/\\+/g', ' ')); break; } if (!key && (cookieValue = decodeURIComponent(cookieValue.replace('/\\+/g', ' '))) !== undefined) { result[name] = cookieValue; } } return result; }; config.defaults = {}; $.removeCookie = function (key, options) { if ($.cookie(key) === undefined) { return false; } $.cookie(key, '', $.extend({}, options, { expires: -1 })); return !$.cookie(key); }; }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('jquery/jquery.cookie',[ 'jquery', 'js-cookie/cookie-wrapper' ], function () { }); /* * JS Storage Plugin * * Copyright (c) 2019 Julien Maurel * * Licensed under the MIT license: * http://www.opensource.org/licenses/mit-license.php * * Project home: * https://github.com/julien-maurel/js-storage * * Version: 1.1.0 */ (function (factory) { var registeredInModuleLoader = false; if (typeof define === 'function' && define.amd) { define('js-storage/js.storage',['jquery', 'jquery/jquery.cookie'], factory); registeredInModuleLoader = true; } if (typeof exports === 'object') { module.exports = factory(); registeredInModuleLoader = true; } if (!registeredInModuleLoader) { var OldStorages = window.Storages; var api = window.Storages = factory(); api.noConflict = function () { window.Storages = OldStorages; return api; }; } }(function () { // Variables used by utilities functions (like isPlainObject...) var class2type = {}; var toString = class2type.toString; var hasOwn = class2type.hasOwnProperty; var fnToString = hasOwn.toString; var ObjectFunctionString = fnToString.call(Object); var getProto = Object.getPrototypeOf; var apis = {}; // Prefix to use with cookie fallback var cookie_local_prefix = "ls_"; var cookie_session_prefix = "ss_"; // Get items from a storage function _get() { var storage = this._type, l = arguments.length, s = window[storage], a = arguments, a0 = a[0], vi, ret, tmp, i, j; if (l < 1) { throw new Error('Minimum 1 argument must be given'); } else if (Array.isArray(a0)) { // If second argument is an array, return an object with value of storage for each item in this array ret = {}; for (i in a0) { if (a0.hasOwnProperty(i)) { vi = a0[i]; try { ret[vi] = JSON.parse(s.getItem(vi)); } catch (e) { ret[vi] = s.getItem(vi); } } } return ret; } else if (l == 1) { // If only 1 argument, return value directly try { return JSON.parse(s.getItem(a0)); } catch (e) { return s.getItem(a0); } } else { // If more than 1 argument, parse storage to retrieve final value to return it // Get first level try { ret = JSON.parse(s.getItem(a0)); if (!ret) { throw new ReferenceError(a0 + ' is not defined in this storage'); } } catch (e) { throw new ReferenceError(a0 + ' is not defined in this storage'); } // Parse next levels for (i = 1; i < l - 1; i++) { ret = ret[a[i]]; if (ret === undefined) { throw new ReferenceError([].slice.call(a, 0, i + 1).join('.') + ' is not defined in this storage'); } } // If last argument is an array, return an object with value for each item in this array // Else return value normally if (Array.isArray(a[i])) { tmp = ret; ret = {}; for (j in a[i]) { if (a[i].hasOwnProperty(j)) { ret[a[i][j]] = tmp[a[i][j]]; } } return ret; } else { return ret[a[i]]; } } } // Set items of a storage function _set() { var storage = this._type, l = arguments.length, s = window[storage], a = arguments, a0 = a[0], a1 = a[1], vi, to_store = isNaN(a1) ? {} : [], type, tmp, i; if (l < 1 || !_isPlainObject(a0) && l < 2) { throw new Error('Minimum 2 arguments must be given or first parameter must be an object'); } else if (_isPlainObject(a0)) { // If first argument is an object, set values of storage for each property of this object for (i in a0) { if (a0.hasOwnProperty(i)) { vi = a0[i]; if (!_isPlainObject(vi) && !this.alwaysUseJson) { s.setItem(i, vi); } else { s.setItem(i, JSON.stringify(vi)); } } } return a0; } else if (l == 2) { // If only 2 arguments, set value of storage directly if (typeof a1 === 'object' || this.alwaysUseJson) { s.setItem(a0, JSON.stringify(a1)); } else { s.setItem(a0, a1); } return a1; } else { // If more than 3 arguments, parse storage to retrieve final node and set value // Get first level try { tmp = s.getItem(a0); if (tmp != null) { to_store = JSON.parse(tmp); } } catch (e) { } tmp = to_store; // Parse next levels and set value for (i = 1; i < l - 2; i++) { vi = a[i]; type = isNaN(a[i + 1]) ? "object" : "array"; if (!tmp[vi] || type == "object" && !_isPlainObject(tmp[vi]) || type == "array" && !Array.isArray(tmp[vi])) { if (type == "array") tmp[vi] = []; else tmp[vi] = {}; } tmp = tmp[vi]; } tmp[a[i]] = a[i + 1]; s.setItem(a0, JSON.stringify(to_store)); return to_store; } } // Remove items from a storage function _remove() { var storage = this._type, l = arguments.length, s = window[storage], a = arguments, a0 = a[0], to_store, tmp, i, j; if (l < 1) { throw new Error('Minimum 1 argument must be given'); } else if (Array.isArray(a0)) { // If first argument is an array, remove values from storage for each item of this array for (i in a0) { if (a0.hasOwnProperty(i)) { s.removeItem(a0[i]); } } return true; } else if (l == 1) { // If only 2 arguments, remove value from storage directly s.removeItem(a0); return true; } else { // If more than 2 arguments, parse storage to retrieve final node and remove value // Get first level try { to_store = tmp = JSON.parse(s.getItem(a0)); } catch (e) { throw new ReferenceError(a0 + ' is not defined in this storage'); } // Parse next levels and remove value for (i = 1; i < l - 1; i++) { tmp = tmp[a[i]]; if (tmp === undefined) { throw new ReferenceError([].slice.call(a, 1, i).join('.') + ' is not defined in this storage'); } } // If last argument is an array,remove value for each item in this array // Else remove value normally if (Array.isArray(a[i])) { for (j in a[i]) { if (a[i].hasOwnProperty(j)) { delete tmp[a[i][j]]; } } } else { delete tmp[a[i]]; } s.setItem(a0, JSON.stringify(to_store)); return true; } } // Remove all items from a storage function _removeAll(reinit_ns) { var keys = _keys.call(this), i; for (i in keys) { if (keys.hasOwnProperty(i)) { _remove.call(this, keys[i]); } } // Reinitialize all namespace storages if (reinit_ns) { for (i in apis.namespaceStorages) { if (apis.namespaceStorages.hasOwnProperty(i)) { _createNamespace(i); } } } } // Check if items of a storage are empty function _isEmpty() { var l = arguments.length, a = arguments, a0 = a[0], i; if (l == 0) { // If no argument, test if storage is empty return (_keys.call(this).length == 0); } else if (Array.isArray(a0)) { // If first argument is an array, test each item of this array and return true only if all items are empty for (i = 0; i < a0.length; i++) { if (!_isEmpty.call(this, a0[i])) { return false; } } return true; } else { // If at least 1 argument, try to get value and test it try { var v = _get.apply(this, arguments); // Convert result to an object (if last argument is an array, _get return already an object) and test each item if (!Array.isArray(a[l - 1])) { v = {'totest': v}; } for (i in v) { if (v.hasOwnProperty(i) && !( (_isPlainObject(v[i]) && _isEmptyObject(v[i])) || (Array.isArray(v[i]) && !v[i].length) || (typeof v[i] !== 'boolean' && !v[i]) )) { return false; } } return true; } catch (e) { return true; } } } // Check if items of a storage exist function _isSet() { var l = arguments.length, a = arguments, a0 = a[0], i; if (l < 1) { throw new Error('Minimum 1 argument must be given'); } if (Array.isArray(a0)) { // If first argument is an array, test each item of this array and return true only if all items exist for (i = 0; i < a0.length; i++) { if (!_isSet.call(this, a0[i])) { return false; } } return true; } else { // For other case, try to get value and test it try { var v = _get.apply(this, arguments); // Convert result to an object (if last argument is an array, _get return already an object) and test each item if (!Array.isArray(a[l - 1])) { v = {'totest': v}; } for (i in v) { if (v.hasOwnProperty(i) && !(v[i] !== undefined && v[i] !== null)) { return false; } } return true; } catch (e) { return false; } } } // Get keys of a storage or of an item of the storage function _keys() { var storage = this._type, l = arguments.length, s = window[storage], keys = [], o = {}; // If at least 1 argument, get value from storage to retrieve keys // Else, use storage to retrieve keys if (l > 0) { o = _get.apply(this, arguments); } else { o = s; } if (o && o._cookie) { // If storage is a cookie, use js-cookie to retrieve keys var cookies = Cookies.get(); for (var key in cookies) { if (cookies.hasOwnProperty(key) && key != '') { keys.push(key.replace(o._prefix, '')); } } } else { for (var i in o) { if (o.hasOwnProperty(i)) { keys.push(i); } } } return keys; } // Create new namespace storage function _createNamespace(name) { if (!name || typeof name != "string") { throw new Error('First parameter must be a string'); } if (storage_available) { if (!window.localStorage.getItem(name)) { window.localStorage.setItem(name, '{}'); } if (!window.sessionStorage.getItem(name)) { window.sessionStorage.setItem(name, '{}'); } } else { if (!window.localCookieStorage.getItem(name)) { window.localCookieStorage.setItem(name, '{}'); } if (!window.sessionCookieStorage.getItem(name)) { window.sessionCookieStorage.setItem(name, '{}'); } } var ns = { localStorage: _extend({}, apis.localStorage, {_ns: name}), sessionStorage: _extend({}, apis.sessionStorage, {_ns: name}) }; if (cookies_available) { if (!window.cookieStorage.getItem(name)) { window.cookieStorage.setItem(name, '{}'); } ns.cookieStorage = _extend({}, apis.cookieStorage, {_ns: name}); } apis.namespaceStorages[name] = ns; return ns; } // Test if storage is natively available on browser function _testStorage(name) { var foo = 'jsapi'; try { if (!window[name]) { return false; } window[name].setItem(foo, foo); window[name].removeItem(foo); return true; } catch (e) { return false; } } // Test if a variable is a plain object (from jQuery) function _isPlainObject(obj) { var proto, Ctor; // Detect obvious negatives // Use toString instead of jQuery.type to catch host objects if (!obj || toString.call(obj) !== "[object Object]") { return false; } proto = getProto(obj); // Objects with no prototype (e.g., `Object.create( null )`) are plain if (!proto) { return true; } // Objects with prototype are plain iff they were constructed by a global Object function Ctor = hasOwn.call(proto, "constructor") && proto.constructor; return typeof Ctor === "function" && fnToString.call(Ctor) === ObjectFunctionString; } // Test if a variable is an empty object (from jQuery) function _isEmptyObject(obj) { var name; for (name in obj) { return false; } return true; } // Merge objects function _extend() { var i = 1; var result = arguments[0]; for (; i < arguments.length; i++) { var attributes = arguments[i]; for (var key in attributes) { if (attributes.hasOwnProperty(key)) { result[key] = attributes[key]; } } } return result; } // Check if storages are natively available on browser and check is js-cookie is present var storage_available = _testStorage('localStorage'); var cookies_available = typeof Cookies !== 'undefined'; // Namespace object var storage = { _type: '', _ns: '', _callMethod: function (f, a) { a = Array.prototype.slice.call(a); var p = [], a0 = a[0]; if (this._ns) { p.push(this._ns); } if (typeof a0 === 'string' && a0.indexOf('.') !== -1) { a.shift(); [].unshift.apply(a, a0.split('.')); } [].push.apply(p, a); return f.apply(this, p); }, // Define if plugin always use JSON to store values (even to store simple values like string, int...) or not alwaysUseJson: false, // Get items. If no parameters and storage have a namespace, return all namespace get: function () { if (!storage_available && !cookies_available){ return null; } return this._callMethod(_get, arguments); }, // Set items set: function () { var l = arguments.length, a = arguments, a0 = a[0]; if (l < 1 || !_isPlainObject(a0) && l < 2) { throw new Error('Minimum 2 arguments must be given or first parameter must be an object'); } if (!storage_available && !cookies_available){ return null; } // If first argument is an object and storage is a namespace storage, set values individually if (_isPlainObject(a0) && this._ns) { for (var i in a0) { if (a0.hasOwnProperty(i)) { this._callMethod(_set, [i, a0[i]]); } } return a0; } else { var r = this._callMethod(_set, a); if (this._ns) { return r[a0.split('.')[0]]; } else { return r; } } }, // Delete items remove: function () { if (arguments.length < 1) { throw new Error('Minimum 1 argument must be given'); } if (!storage_available && !cookies_available){ return null; } return this._callMethod(_remove, arguments); }, // Delete all items removeAll: function (reinit_ns) { if (!storage_available && !cookies_available){ return null; } if (this._ns) { this._callMethod(_set, [{}]); return true; } else { return this._callMethod(_removeAll, [reinit_ns]); } }, // Items empty isEmpty: function () { if (!storage_available && !cookies_available){ return null; } return this._callMethod(_isEmpty, arguments); }, // Items exists isSet: function () { if (arguments.length < 1) { throw new Error('Minimum 1 argument must be given'); } if (!storage_available && !cookies_available){ return null; } return this._callMethod(_isSet, arguments); }, // Get keys of items keys: function () { if (!storage_available && !cookies_available){ return null; } return this._callMethod(_keys, arguments); } }; // Use js-cookie for compatibility with old browsers and give access to cookieStorage if (cookies_available) { // sessionStorage is valid for one window/tab. To simulate that with cookie, we set a name for the window and use it for the name of the cookie if (!window.name) { window.name = Math.floor(Math.random() * 100000000); } var cookie_storage = { _cookie: true, _prefix: '', _expires: null, _path: null, _domain: null, _secure: false, setItem: function (n, v) { Cookies.set(this._prefix + n, v, {expires: this._expires, path: this._path, domain: this._domain, secure: this._secure}); }, getItem: function (n) { return Cookies.get(this._prefix + n); }, removeItem: function (n) { return Cookies.remove(this._prefix + n, {path: this._path}); }, clear: function () { var cookies = Cookies.get(); for (var key in cookies) { if (cookies.hasOwnProperty(key) && key != '') { if (!this._prefix && key.indexOf(cookie_local_prefix) === -1 && key.indexOf(cookie_session_prefix) === -1 || this._prefix && key.indexOf(this._prefix) === 0) { Cookies.remove(key); } } } }, setExpires: function (e) { this._expires = e; return this; }, setPath: function (p) { this._path = p; return this; }, setDomain: function (d) { this._domain = d; return this; }, setSecure: function (s) { this._secure = s; return this; }, setConf: function (c) { if (c.path) { this._path = c.path; } if (c.domain) { this._domain = c.domain; } if (c.secure) { this._secure = c.secure; } if (c.expires) { this._expires = c.expires; } return this; }, setDefaultConf: function () { this._path = this._domain = this._expires = null; this._secure = false; } }; if (!storage_available) { window.localCookieStorage = _extend({}, cookie_storage, { _prefix: cookie_local_prefix, _expires: 365 * 10, _secure: true }); window.sessionCookieStorage = _extend({}, cookie_storage, { _prefix: cookie_session_prefix + window.name + '_', _secure: true }); } window.cookieStorage = _extend({}, cookie_storage); // cookieStorage API apis.cookieStorage = _extend({}, storage, { _type: 'cookieStorage', setExpires: function (e) { window.cookieStorage.setExpires(e); return this; }, setPath: function (p) { window.cookieStorage.setPath(p); return this; }, setDomain: function (d) { window.cookieStorage.setDomain(d); return this; }, setSecure: function (s) { window.cookieStorage.setSecure(s); return this; }, setConf: function (c) { window.cookieStorage.setConf(c); return this; }, setDefaultConf: function () { window.cookieStorage.setDefaultConf(); return this; } }); } // Get a new API on a namespace apis.initNamespaceStorage = function (ns) { return _createNamespace(ns); }; if (storage_available) { // localStorage API apis.localStorage = _extend({}, storage, {_type: 'localStorage'}); // sessionStorage API apis.sessionStorage = _extend({}, storage, {_type: 'sessionStorage'}); } else { // localStorage API apis.localStorage = _extend({}, storage, {_type: 'localCookieStorage'}); // sessionStorage API apis.sessionStorage = _extend({}, storage, {_type: 'sessionCookieStorage'}); } // List of all namespace storage apis.namespaceStorages = {}; // Remove all items in all storages apis.removeAllStorages = function (reinit_ns) { apis.localStorage.removeAll(reinit_ns); apis.sessionStorage.removeAll(reinit_ns); if (apis.cookieStorage) { apis.cookieStorage.removeAll(reinit_ns); } if (!reinit_ns) { apis.namespaceStorages = {}; } }; // About alwaysUseJson // By default, all values are string on html storages and the plugin don't use json to store simple values (strings, int, float...) // So by default, if you do storage.setItem('test',2), value in storage will be "2", not 2 // If you set this property to true, all values set with the plugin will be stored as json to have typed values in any cases apis.alwaysUseJsonInStorage = function (value) { storage.alwaysUseJson = value; apis.localStorage.alwaysUseJson = value; apis.sessionStorage.alwaysUseJson = value; if (apis.cookieStorage) { apis.cookieStorage.alwaysUseJson = value; } }; return apis; })); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('jquery/jquery-storageapi',[ 'jquery', 'js-storage/js.storage' ], function ($, storage) { 'use strict'; if (window.cookieStorage) { var cookiesConfig = window.cookiesConfig || {}; $.extend(window.cookieStorage, { _secure: !!cookiesConfig.secure, _samesite: cookiesConfig.samesite ? cookiesConfig.samesite : 'lax', /** * Set value under name * @param {String} name * @param {String} value * @param {Object} [options] */ setItem: function (name, value, options) { var _default = { expires: this._expires, path: this._path, domain: this._domain, secure: this._secure, samesite: this._samesite }; $.cookie(this._prefix + name, value, $.extend(_default, options || {})); }, /** * Set default options * @param {Object} c * @returns {storage} */ setConf: function (c) { if (c.path) { this._path = c.path; } if (c.domain) { this._domain = c.domain; } if (c.expires) { this._expires = c.expires; } if (typeof c.secure !== 'undefined') { this._secure = c.secure; } if (typeof c.samesite !== 'undefined') { this._samesite = c.samesite; } return this; } }); } $.alwaysUseJsonInStorage = $.alwaysUseJsonInStorage || storage.alwaysUseJsonInStorage; $.cookieStorage = $.cookieStorage || storage.cookieStorage; $.initNamespaceStorage = $.initNamespaceStorage || storage.initNamespaceStorage; $.localStorage = $.localStorage || storage.localStorage; $.namespaceStorages = $.namespaceStorages || storage.namespaceStorages; $.removeAllStorages = $.removeAllStorages || storage.removeAllStorages; $.sessionStorage = $.sessionStorage || storage.sessionStorage; }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /** * @api */ define('Magento_Customer/js/customer-data',[ 'jquery', 'underscore', 'ko', 'Magento_Customer/js/section-config', 'mage/url', 'mage/storage', 'jquery/jquery-storageapi' ], function ($, _, ko, sectionConfig, url) { 'use strict'; var options = {}, storage, storageInvalidation, invalidateCacheBySessionTimeOut, invalidateCacheByCloseCookieSession, dataProvider, buffer, customerData, deferred = $.Deferred(); url.setBaseUrl(window.BASE_URL); options.sectionLoadUrl = url.build('customer/section/load'); /** * @param {Object} invalidateOptions */ invalidateCacheBySessionTimeOut = function (invalidateOptions) { var date; if (new Date($.localStorage.get('mage-cache-timeout')) < new Date()) { storage.removeAll(); } date = new Date(Date.now() + parseInt(invalidateOptions.cookieLifeTime, 10) * 1000); $.localStorage.set('mage-cache-timeout', date); }; /** * Invalidate Cache By Close Cookie Session */ invalidateCacheByCloseCookieSession = function () { var isLoggedIn = parseInt(options.isLoggedIn, 10) || 0; if (!$.cookieStorage.isSet('mage-cache-sessid')) { storage.removeAll(); } if (!$.localStorage.isSet('mage-customer-login')) { $.localStorage.set('mage-customer-login', isLoggedIn); } if ($.localStorage.get('mage-customer-login') !== isLoggedIn) { $.localStorage.set('mage-customer-login', isLoggedIn); storage.removeAll(); } $.cookieStorage.set('mage-cache-sessid', true); }; dataProvider = { /** * @param {Object} sectionNames * @return {Object} */ getFromStorage: function (sectionNames) { var result = {}; _.each(sectionNames, function (sectionName) { result[sectionName] = storage.get(sectionName); }); return result; }, /** * @param {Object} sectionNames * @param {Boolean} forceNewSectionTimestamp * @return {*} */ getFromServer: function (sectionNames, forceNewSectionTimestamp) { var parameters; sectionNames = sectionConfig.filterClientSideSections(sectionNames); parameters = _.isArray(sectionNames) && sectionNames.indexOf('*') < 0 ? { sections: sectionNames.join(',') } : []; parameters['force_new_section_timestamp'] = forceNewSectionTimestamp; return $.getJSON(options.sectionLoadUrl, parameters).fail(function (jqXHR) { throw new Error(jqXHR); }); } }; /** * @param {Function} target * @param {String} sectionName * @return {*} */ ko.extenders.disposableCustomerData = function (target, sectionName) { var sectionDataIds, newSectionDataIds = {}; target.subscribe(function () { setTimeout(function () { storage.remove(sectionName); sectionDataIds = $.cookieStorage.get('section_data_ids') || {}; _.each(sectionDataIds, function (data, name) { if (name !== sectionName) { newSectionDataIds[name] = data; } }); $.cookieStorage.set('section_data_ids', newSectionDataIds); }, 3000); }); return target; }; buffer = { data: {}, /** * @param {String} sectionName */ bind: function (sectionName) { this.data[sectionName] = ko.observable({}); }, /** * @param {String} sectionName * @return {Object} */ get: function (sectionName) { if (!this.data[sectionName]) { this.bind(sectionName); } return this.data[sectionName]; }, /** * @return {Array} */ keys: function () { return _.keys(this.data); }, /** * @param {String} sectionName * @param {Object} sectionData */ notify: function (sectionName, sectionData) { if (!this.data[sectionName]) { this.bind(sectionName); } this.data[sectionName](sectionData); }, /** * @param {Object} sections */ update: function (sections) { var sectionId = 0, sectionDataIds = $.cookieStorage.get('section_data_ids') || {}; _.each(sections, function (sectionData, sectionName) { sectionId = sectionData['data_id']; sectionDataIds[sectionName] = sectionId; storage.set(sectionName, sectionData); storageInvalidation.remove(sectionName); buffer.notify(sectionName, sectionData); }); $.cookieStorage.set('section_data_ids', sectionDataIds); }, /** * @param {Object} sections */ remove: function (sections) { _.each(sections, function (sectionName) { storage.remove(sectionName); if (!sectionConfig.isClientSideSection(sectionName)) { storageInvalidation.set(sectionName, true); } }); } }; customerData = { /** * Customer data initialization */ init: function () { var expiredSectionNames = this.getExpiredSectionNames(); if (expiredSectionNames.length > 0) { _.each(dataProvider.getFromStorage(storage.keys()), function (sectionData, sectionName) { buffer.notify(sectionName, sectionData); }); this.reload(expiredSectionNames, false); } else { _.each(dataProvider.getFromStorage(storage.keys()), function (sectionData, sectionName) { buffer.notify(sectionName, sectionData); }); if (!_.isEmpty(storageInvalidation.keys())) { this.reload(storageInvalidation.keys(), false); } } if (!_.isEmpty($.cookieStorage.get('section_data_clean'))) { this.reload(sectionConfig.getSectionNames(), true); $.cookieStorage.set('section_data_clean', ''); } if (this._request) { this._request.done(function(){deferred.resolve()}); return; } deferred.resolve(); }, /** * Storage init */ initStorage: function () { $.cookieStorage.setConf({ path: '/', expires: new Date(Date.now() + parseInt(options.cookieLifeTime, 10) * 1000) }); if (options.cookieDomain) { $.cookieStorage.setConf({ domain: options.cookieDomain }); } storage = $.initNamespaceStorage('mage-cache-storage').localStorage; storageInvalidation = $.initNamespaceStorage('mage-cache-storage-section-invalidation').localStorage; }, /** * Retrieve the list of sections that has expired since last page reload. * * Sections can expire due to lifetime constraints or due to inconsistent storage information * (validated by cookie data). * * @return {Array} */ getExpiredSectionNames: function () { var expiredSectionNames = [], cookieSectionTimestamps = $.cookieStorage.get('section_data_ids') || {}, sectionLifetime = options.expirableSectionLifetime * 60, currentTimestamp = Math.floor(Date.now() / 1000), sectionData; // process sections that can expire due to lifetime constraints _.each(options.expirableSectionNames, function (sectionName) { sectionData = storage.get(sectionName); if (typeof sectionData === 'object' && sectionData['data_id'] + sectionLifetime <= currentTimestamp) { expiredSectionNames.push(sectionName); } }); // process sections that can expire due to storage information inconsistency _.each(cookieSectionTimestamps, function (cookieSectionTimestamp, sectionName) { if (storage !== undefined) { sectionData = storage.get(sectionName); } if (typeof sectionData === 'undefined' || typeof sectionData === 'object' && cookieSectionTimestamp !== sectionData['data_id'] ) { expiredSectionNames.push(sectionName); } }); //remove expired section names of previously installed/enable modules expiredSectionNames = _.intersection(expiredSectionNames, sectionConfig.getSectionNames()); return _.uniq(expiredSectionNames); }, /** * Check if some sections have to be reloaded. * * @deprecated Use getExpiredSectionNames instead. * * @return {Boolean} */ needReload: function () { var expiredSectionNames = this.getExpiredSectionNames(); return expiredSectionNames.length > 0; }, /** * Retrieve the list of expired keys. * * @deprecated Use getExpiredSectionNames instead. * * @return {Array} */ getExpiredKeys: function () { return this.getExpiredSectionNames(); }, /** * @param {String} sectionName * @return {*} */ get: function (sectionName) { this._requestOnDemand(sectionName); return buffer.get(sectionName); }, _requestOnDemand: function(sectionName) { if (buffer.keys().indexOf(sectionName) !== -1 || sectionName === 'messages') return; (this._demandList = this._demandList || []).push(sectionName); clearTimeout(this._demandTimeout); this._demandTimeout = setTimeout(function() {deferred.done(function () { var list = customerData._demandList.filter(function(sectionName) { var data = buffer.get(sectionName)(); if (typeof data === 'object' && Object.keys(data).length) return false; return data; }); if (!list.length) return; customerData.reload(list, false, false); })}, 100); }, /** * @param {String} sectionName * @param {Object} sectionData */ set: function (sectionName, sectionData) { var data = {}; data[sectionName] = sectionData; buffer.update(data); }, /** * Avoid using this function directly 'cause of possible performance drawbacks. * Each customer section reload brings new non-cached ajax request. * * @param {Array} sectionNames * @param {Boolean} forceNewSectionTimestamp * @return {*} */ reload: function (sectionNames, forceNewSectionTimestamp, isOverlayShown) { customerData._request = dataProvider.getFromServer(sectionNames, forceNewSectionTimestamp).done(function (sections) { $(document).trigger('customer-data-reload', [sectionNames]); buffer.update(sections); }); if (isOverlayShown !== false) { require(['vaimo/overlay'], function(overlay){ overlay.open('customer-data'); customerData._request.always(function () {overlay.close('customer-data')}); }) } return customerData._request; }, /** * @param {Array} sectionNames */ invalidate: function (sectionNames) { var sectionDataIds, sectionsNamesForInvalidation; sectionsNamesForInvalidation = _.contains(sectionNames, '*') ? sectionConfig.getSectionNames() : sectionNames; $(document).trigger('customer-data-invalidate', [sectionsNamesForInvalidation]); buffer.remove(sectionsNamesForInvalidation); sectionDataIds = $.cookieStorage.get('section_data_ids') || {}; // Invalidate section in cookie (increase version of section with 1000) _.each(sectionsNamesForInvalidation, function (sectionName) { if (!sectionConfig.isClientSideSection(sectionName)) { sectionDataIds[sectionName] += 1000; } }); $.cookieStorage.set('section_data_ids', sectionDataIds); }, /** * Checks if customer data is initialized. * * @returns {jQuery.Deferred} */ getInitCustomerData: function () { return deferred.promise(); }, /** * Reload sections on ajax complete * * @param {Object} jsonResponse * @param {Object} settings */ onAjaxComplete: function (jsonResponse, settings) { var sections, redirects; if (settings.type.match(/post|put|delete/i) && !settings.isSkipCustomerDataUpdates) { sections = sectionConfig.getAffectedSections(settings.url); if (sections && sections.length) { this.invalidate(sections); redirects = ['redirect', 'backUrl']; if (_.isObject(jsonResponse) && !_.isEmpty(_.pick(jsonResponse, redirects))) { //eslint-disable-line return; } this.reload(sections, true); } } }, /** * @param {Object} settings * @constructor */ 'Magento_Customer/js/customer-data': function (settings) { options = settings; customerData.initStorage(); invalidateCacheBySessionTimeOut(settings); invalidateCacheByCloseCookieSession(); customerData.init(); } }; /** * Events listener */ $(document).on('ajaxComplete', function (event, xhr, settings) { customerData.onAjaxComplete(xhr.responseJSON, settings); }); /** * Events listener */ $(document).on('submit', function (event) { var sections; if (event.target.method.match(/post|put|delete/i)) { sections = sectionConfig.getAffectedSections(event.target.action); if (sections) { customerData.invalidate(sections); } } }); return customerData; }); /** * Copyright © Vaimo Group. All rights reserved. * See LICENSE_VAIMO.txt for license details. */ define('Vaimo_BauhausCustomer/js/reload-customer-data',['Magento_Customer/js/customer-data'],customerData=> customerData.getInitCustomerData().done(a=> !(customerData.get('customer')() && customerData.get('customer')().lastname) && customerData.reload([], false, false) )) ; define('Vaimo_BauhausSe/js/mock/empty', [],()=>{}); /*! jQuery UI - v1.13.2 - 2023-02-16 * http://jqueryui.com * Includes: widget.js, position.js, data.js, disable-selection.js, focusable.js, form-reset-mixin.js, keycode.js, labels.js, scroll-parent.js, tabbable.js, unique-id.js, widgets/draggable.js, widgets/resizable.js, widgets/accordion.js, widgets/button.js, widgets/checkboxradio.js, widgets/controlgroup.js, widgets/dialog.js, widgets/mouse.js, widgets/slider.js, widgets/tabs.js * Copyright jQuery Foundation and other contributors; Licensed MIT */ ( function( factory ) { "use strict"; if ( typeof define === "function" && define.amd ) { // AMD. Register as an anonymous module. define( 'Vaimo_BauhausSe/jquery/jquery-ui',[ "jquery" ], factory ); } else { // Browser globals factory( jQuery ); } } )( function( $ ) { "use strict"; $.ui = $.ui || {}; var version = $.ui.version = "1.13.2"; /*! * jQuery UI Widget 1.13.2 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license */ //>>label: Widget //>>group: Core //>>description: Provides a factory for creating stateful widgets with a common API. //>>docs: http://api.jqueryui.com/jQuery.widget/ //>>demos: http://jqueryui.com/widget/ var widgetUuid = 0; var widgetHasOwnProperty = Array.prototype.hasOwnProperty; var widgetSlice = Array.prototype.slice; $.cleanData = ( function( orig ) { return function( elems ) { var events, elem, i; for ( i = 0; ( elem = elems[ i ] ) != null; i++ ) { // Only trigger remove when necessary to save time events = $._data( elem, "events" ); if ( events && events.remove ) { $( elem ).triggerHandler( "remove" ); } } orig( elems ); }; } )( $.cleanData ); $.widget = function( name, base, prototype ) { var existingConstructor, constructor, basePrototype; // ProxiedPrototype allows the provided prototype to remain unmodified // so that it can be used as a mixin for multiple widgets (#8876) var proxiedPrototype = {}; var namespace = name.split( "." )[ 0 ]; name = name.split( "." )[ 1 ]; var fullName = namespace + "-" + name; if ( !prototype ) { prototype = base; base = $.Widget; } if ( Array.isArray( prototype ) ) { prototype = $.extend.apply( null, [ {} ].concat( prototype ) ); } // Create selector for plugin $.expr.pseudos[ fullName.toLowerCase() ] = function( elem ) { return !!$.data( elem, fullName ); }; $[ namespace ] = $[ namespace ] || {}; existingConstructor = $[ namespace ][ name ]; constructor = $[ namespace ][ name ] = function( options, element ) { // Allow instantiation without "new" keyword if ( !this || !this._createWidget ) { return new constructor( options, element ); } // Allow instantiation without initializing for simple inheritance // must use "new" keyword (the code above always passes args) if ( arguments.length ) { this._createWidget( options, element ); } }; // Extend with the existing constructor to carry over any static properties $.extend( constructor, existingConstructor, { version: prototype.version, // Copy the object used to create the prototype in case we need to // redefine the widget later _proto: $.extend( {}, prototype ), // Track widgets that inherit from this widget in case this widget is // redefined after a widget inherits from it _childConstructors: [] } ); basePrototype = new base(); // We need to make the options hash a property directly on the new instance // otherwise we'll modify the options hash on the prototype that we're // inheriting from basePrototype.options = $.widget.extend( {}, basePrototype.options ); $.each( prototype, function( prop, value ) { if ( typeof value !== "function" ) { proxiedPrototype[ prop ] = value; return; } proxiedPrototype[ prop ] = ( function() { function _super() { return base.prototype[ prop ].apply( this, arguments ); } function _superApply( args ) { return base.prototype[ prop ].apply( this, args ); } return function() { var __super = this._super; var __superApply = this._superApply; var returnValue; this._super = _super; this._superApply = _superApply; returnValue = value.apply( this, arguments ); this._super = __super; this._superApply = __superApply; return returnValue; }; } )(); } ); constructor.prototype = $.widget.extend( basePrototype, { // TODO: remove support for widgetEventPrefix // always use the name + a colon as the prefix, e.g., draggable:start // don't prefix for widgets that aren't DOM-based widgetEventPrefix: existingConstructor ? ( basePrototype.widgetEventPrefix || name ) : name }, proxiedPrototype, { constructor: constructor, namespace: namespace, widgetName: name, widgetFullName: fullName } ); // If this widget is being redefined then we need to find all widgets that // are inheriting from it and redefine all of them so that they inherit from // the new version of this widget. We're essentially trying to replace one // level in the prototype chain. if ( existingConstructor ) { $.each( existingConstructor._childConstructors, function( i, child ) { var childPrototype = child.prototype; // Redefine the child widget using the same prototype that was // originally used, but inherit from the new version of the base $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto ); } ); // Remove the list of existing child constructors from the old constructor // so the old child constructors can be garbage collected delete existingConstructor._childConstructors; } else { base._childConstructors.push( constructor ); } $.widget.bridge( name, constructor ); return constructor; }; $.widget.extend = function( target ) { var input = widgetSlice.call( arguments, 1 ); var inputIndex = 0; var inputLength = input.length; var key; var value; for ( ; inputIndex < inputLength; inputIndex++ ) { for ( key in input[ inputIndex ] ) { value = input[ inputIndex ][ key ]; if ( widgetHasOwnProperty.call( input[ inputIndex ], key ) && value !== undefined ) { // Clone objects if ( $.isPlainObject( value ) ) { target[ key ] = $.isPlainObject( target[ key ] ) ? $.widget.extend( {}, target[ key ], value ) : // Don't extend strings, arrays, etc. with objects $.widget.extend( {}, value ); // Copy everything else by reference } else { target[ key ] = value; } } } } return target; }; $.widget.bridge = function( name, object ) { var fullName = object.prototype.widgetFullName || name; $.fn[ name ] = function( options ) { var isMethodCall = typeof options === "string"; var args = widgetSlice.call( arguments, 1 ); var returnValue = this; if ( isMethodCall ) { // If this is an empty collection, we need to have the instance method // return undefined instead of the jQuery instance if ( !this.length && options === "instance" ) { returnValue = undefined; } else { this.each( function() { var methodValue; var instance = $.data( this, fullName ); if ( options === "instance" ) { returnValue = instance; return false; } if ( !instance ) { return $.error( "cannot call methods on " + name + " prior to initialization; " + "attempted to call method '" + options + "'" ); } if ( typeof instance[ options ] !== "function" || options.charAt( 0 ) === "_" ) { return $.error( "no such method '" + options + "' for " + name + " widget instance" ); } methodValue = instance[ options ].apply( instance, args ); if ( methodValue !== instance && methodValue !== undefined ) { returnValue = methodValue && methodValue.jquery ? returnValue.pushStack( methodValue.get() ) : methodValue; return false; } } ); } } else { // Allow multiple hashes to be passed on init if ( args.length ) { options = $.widget.extend.apply( null, [ options ].concat( args ) ); } this.each( function() { var instance = $.data( this, fullName ); if ( instance ) { instance.option( options || {} ); if ( instance._init ) { instance._init(); } } else { $.data( this, fullName, new object( options, this ) ); } } ); } return returnValue; }; }; $.Widget = function( /* options, element */ ) {}; $.Widget._childConstructors = []; $.Widget.prototype = { widgetName: "widget", widgetEventPrefix: "", defaultElement: "<div>", options: { classes: {}, disabled: false, // Callbacks create: null }, _createWidget: function( options, element ) { element = $( element || this.defaultElement || this )[ 0 ]; this.element = $( element ); this.uuid = widgetUuid++; this.eventNamespace = "." + this.widgetName + this.uuid; this.bindings = $(); this.hoverable = $(); this.focusable = $(); this.classesElementLookup = {}; if ( element !== this ) { $.data( element, this.widgetFullName, this ); this._on( true, this.element, { remove: function( event ) { if ( event.target === element ) { this.destroy(); } } } ); this.document = $( element.style ? // Element within the document element.ownerDocument : // Element is window or document element.document || element ); this.window = $( this.document[ 0 ].defaultView || this.document[ 0 ].parentWindow ); } this.options = $.widget.extend( {}, this.options, this._getCreateOptions(), options ); this._create(); if ( this.options.disabled ) { this._setOptionDisabled( this.options.disabled ); } this._trigger( "create", null, this._getCreateEventData() ); this._init(); }, _getCreateOptions: function() { return {}; }, _getCreateEventData: $.noop, _create: $.noop, _init: $.noop, destroy: function() { var that = this; this._destroy(); $.each( this.classesElementLookup, function( key, value ) { that._removeClass( value, key ); } ); // We can probably remove the unbind calls in 2.0 // all event bindings should go through this._on() this.element .off( this.eventNamespace ) .removeData( this.widgetFullName ); this.widget() .off( this.eventNamespace ) .removeAttr( "aria-disabled" ); // Clean up events and states this.bindings.off( this.eventNamespace ); }, _destroy: $.noop, widget: function() { return this.element; }, option: function( key, value ) { var options = key; var parts; var curOption; var i; if ( arguments.length === 0 ) { // Don't return a reference to the internal hash return $.widget.extend( {}, this.options ); } if ( typeof key === "string" ) { // Handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } } options = {}; parts = key.split( "." ); key = parts.shift(); if ( parts.length ) { curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] ); for ( i = 0; i < parts.length - 1; i++ ) { curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {}; curOption = curOption[ parts[ i ] ]; } key = parts.pop(); if ( arguments.length === 1 ) { return curOption[ key ] === undefined ? null : curOption[ key ]; } curOption[ key ] = value; } else { if ( arguments.length === 1 ) { return this.options[ key ] === undefined ? null : this.options[ key ]; } options[ key ] = value; } } this._setOptions( options ); return this; }, _setOptions: function( options ) { var key; for ( key in options ) { this._setOption( key, options[ key ] ); } return this; }, _setOption: function( key, value ) { if ( key === "classes" ) { this._setOptionClasses( value ); } this.options[ key ] = value; if ( key === "disabled" ) { this._setOptionDisabled( value ); } return this; }, _setOptionClasses: function( value ) { var classKey, elements, currentElements; for ( classKey in value ) { currentElements = this.classesElementLookup[ classKey ]; if ( value[ classKey ] === this.options.classes[ classKey ] || !currentElements || !currentElements.length ) { continue; } // We are doing this to create a new jQuery object because the _removeClass() call // on the next line is going to destroy the reference to the current elements being // tracked. We need to save a copy of this collection so that we can add the new classes // below. elements = $( currentElements.get() ); this._removeClass( currentElements, classKey ); // We don't use _addClass() here, because that uses this.options.classes // for generating the string of classes. We want to use the value passed in from // _setOption(), this is the new value of the classes option which was passed to // _setOption(). We pass this value directly to _classes(). elements.addClass( this._classes( { element: elements, keys: classKey, classes: value, add: true } ) ); } }, _setOptionDisabled: function( value ) { this._toggleClass( this.widget(), this.widgetFullName + "-disabled", null, !!value ); // If the widget is becoming disabled, then nothing is interactive if ( value ) { this._removeClass( this.hoverable, null, "ui-state-hover" ); this._removeClass( this.focusable, null, "ui-state-focus" ); } }, enable: function() { return this._setOptions( { disabled: false } ); }, disable: function() { return this._setOptions( { disabled: true } ); }, _classes: function( options ) { var full = []; var that = this; options = $.extend( { element: this.element, classes: this.options.classes || {} }, options ); function bindRemoveEvent() { var nodesToBind = []; options.element.each( function( _, element ) { var isTracked = $.map( that.classesElementLookup, function( elements ) { return elements; } ) .some( function( elements ) { return elements.is( element ); } ); if ( !isTracked ) { nodesToBind.push( element ); } } ); that._on( $( nodesToBind ), { remove: "_untrackClassesElement" } ); } function processClassString( classes, checkOption ) { var current, i; for ( i = 0; i < classes.length; i++ ) { current = that.classesElementLookup[ classes[ i ] ] || $(); if ( options.add ) { bindRemoveEvent(); current = $( $.uniqueSort( current.get().concat( options.element.get() ) ) ); } else { current = $( current.not( options.element ).get() ); } that.classesElementLookup[ classes[ i ] ] = current; full.push( classes[ i ] ); if ( checkOption && options.classes[ classes[ i ] ] ) { full.push( options.classes[ classes[ i ] ] ); } } } if ( options.keys ) { processClassString( options.keys.match( /\S+/g ) || [], true ); } if ( options.extra ) { processClassString( options.extra.match( /\S+/g ) || [] ); } return full.join( " " ); }, _untrackClassesElement: function( event ) { var that = this; $.each( that.classesElementLookup, function( key, value ) { if ( $.inArray( event.target, value ) !== -1 ) { that.classesElementLookup[ key ] = $( value.not( event.target ).get() ); } } ); this._off( $( event.target ) ); }, _removeClass: function( element, keys, extra ) { return this._toggleClass( element, keys, extra, false ); }, _addClass: function( element, keys, extra ) { return this._toggleClass( element, keys, extra, true ); }, _toggleClass: function( element, keys, extra, add ) { add = ( typeof add === "boolean" ) ? add : extra; var shift = ( typeof element === "string" || element === null ), options = { extra: shift ? keys : extra, keys: shift ? element : keys, element: shift ? this.element : element, add: add }; options.element.toggleClass( this._classes( options ), add ); return this; }, _on: function( suppressDisabledCheck, element, handlers ) { var delegateElement; var instance = this; // No suppressDisabledCheck flag, shuffle arguments if ( typeof suppressDisabledCheck !== "boolean" ) { handlers = element; element = suppressDisabledCheck; suppressDisabledCheck = false; } // No element argument, shuffle and use this.element if ( !handlers ) { handlers = element; element = this.element; delegateElement = this.widget(); } else { element = delegateElement = $( element ); this.bindings = this.bindings.add( element ); } $.each( handlers, function( event, handler ) { function handlerProxy() { // Allow widgets to customize the disabled handling // - disabled as an array instead of boolean // - disabled class as method for disabling individual parts if ( !suppressDisabledCheck && ( instance.options.disabled === true || $( this ).hasClass( "ui-state-disabled" ) ) ) { return; } return ( typeof handler === "string" ? instance[ handler ] : handler ) .apply( instance, arguments ); } // Copy the guid so direct unbinding works if ( typeof handler !== "string" ) { handlerProxy.guid = handler.guid = handler.guid || handlerProxy.guid || $.guid++; } var match = event.match( /^([\w:-]*)\s*(.*)$/ ); var eventName = match[ 1 ] + instance.eventNamespace; var selector = match[ 2 ]; if ( selector ) { delegateElement.on( eventName, selector, handlerProxy ); } else { element.on( eventName, handlerProxy ); } } ); }, _off: function( element, eventName ) { eventName = ( eventName || "" ).split( " " ).join( this.eventNamespace + " " ) + this.eventNamespace; element.off( eventName ); // Clear the stack to avoid memory leaks (#10056) this.bindings = $( this.bindings.not( element ).get() ); this.focusable = $( this.focusable.not( element ).get() ); this.hoverable = $( this.hoverable.not( element ).get() ); }, _delay: function( handler, delay ) { function handlerProxy() { return ( typeof handler === "string" ? instance[ handler ] : handler ) .apply( instance, arguments ); } var instance = this; return setTimeout( handlerProxy, delay || 0 ); }, _hoverable: function( element ) { this.hoverable = this.hoverable.add( element ); this._on( element, { mouseenter: function( event ) { this._addClass( $( event.currentTarget ), null, "ui-state-hover" ); }, mouseleave: function( event ) { this._removeClass( $( event.currentTarget ), null, "ui-state-hover" ); } } ); }, _focusable: function( element ) { this.focusable = this.focusable.add( element ); this._on( element, { focusin: function( event ) { this._addClass( $( event.currentTarget ), null, "ui-state-focus" ); }, focusout: function( event ) { this._removeClass( $( event.currentTarget ), null, "ui-state-focus" ); } } ); }, _trigger: function( type, event, data ) { var prop, orig; var callback = this.options[ type ]; data = data || {}; event = $.Event( event ); event.type = ( type === this.widgetEventPrefix ? type : this.widgetEventPrefix + type ).toLowerCase(); // The original event may come from any element // so we need to reset the target on the new event event.target = this.element[ 0 ]; // Copy original event properties over to the new event orig = event.originalEvent; if ( orig ) { for ( prop in orig ) { if ( !( prop in event ) ) { event[ prop ] = orig[ prop ]; } } } this.element.trigger( event, data ); return !( typeof callback === "function" && callback.apply( this.element[ 0 ], [ event ].concat( data ) ) === false || event.isDefaultPrevented() ); } }; $.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) { $.Widget.prototype[ "_" + method ] = function( element, options, callback ) { if ( typeof options === "string" ) { options = { effect: options }; } var hasOptions; var effectName = !options ? method : options === true || typeof options === "number" ? defaultEffect : options.effect || defaultEffect; options = options || {}; if ( typeof options === "number" ) { options = { duration: options }; } else if ( options === true ) { options = {}; } hasOptions = !$.isEmptyObject( options ); options.complete = callback; if ( options.delay ) { element.delay( options.delay ); } if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) { element[ method ]( options ); } else if ( effectName !== method && element[ effectName ] ) { element[ effectName ]( options.duration, options.easing, callback ); } else { element.queue( function( next ) { $( this )[ method ](); if ( callback ) { callback.call( element[ 0 ] ); } next(); } ); } }; } ); var widget = $.widget; /*! * jQuery UI Position 1.13.2 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license * * http://api.jqueryui.com/position/ */ //>>label: Position //>>group: Core //>>description: Positions elements relative to other elements. //>>docs: http://api.jqueryui.com/position/ //>>demos: http://jqueryui.com/position/ ( function() { var cachedScrollbarWidth, max = Math.max, abs = Math.abs, rhorizontal = /left|center|right/, rvertical = /top|center|bottom/, roffset = /[\+\-]\d+(\.[\d]+)?%?/, rposition = /^\w+/, rpercent = /%$/, _position = $.fn.position; function getOffsets( offsets, width, height ) { return [ parseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ), parseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 ) ]; } function parseCss( element, property ) { return parseInt( $.css( element, property ), 10 ) || 0; } function isWindow( obj ) { return obj != null && obj === obj.window; } function getDimensions( elem ) { var raw = elem[ 0 ]; if ( raw.nodeType === 9 ) { return { width: elem.width(), height: elem.height(), offset: { top: 0, left: 0 } }; } if ( isWindow( raw ) ) { return { width: elem.width(), height: elem.height(), offset: { top: elem.scrollTop(), left: elem.scrollLeft() } }; } if ( raw.preventDefault ) { return { width: 0, height: 0, offset: { top: raw.pageY, left: raw.pageX } }; } return { width: elem.outerWidth(), height: elem.outerHeight(), offset: elem.offset() }; } $.position = { scrollbarWidth: function() { if ( cachedScrollbarWidth !== undefined ) { return cachedScrollbarWidth; } var w1, w2, div = $( "<div style=" + "'display:block;position:absolute;width:200px;height:200px;overflow:hidden;'>" + "<div style='height:300px;width:auto;'></div></div>" ), innerDiv = div.children()[ 0 ]; $( "body" ).append( div ); w1 = innerDiv.offsetWidth; div.css( "overflow", "scroll" ); w2 = innerDiv.offsetWidth; if ( w1 === w2 ) { w2 = div[ 0 ].clientWidth; } div.remove(); return ( cachedScrollbarWidth = w1 - w2 ); }, getScrollInfo: function( within ) { var overflowX = within.isWindow || within.isDocument ? "" : within.element.css( "overflow-x" ), overflowY = within.isWindow || within.isDocument ? "" : within.element.css( "overflow-y" ), hasOverflowX = overflowX === "scroll" || ( overflowX === "auto" && within.width < within.element[ 0 ].scrollWidth ), hasOverflowY = overflowY === "scroll" || ( overflowY === "auto" && within.height < within.element[ 0 ].scrollHeight ); return { width: hasOverflowY ? $.position.scrollbarWidth() : 0, height: hasOverflowX ? $.position.scrollbarWidth() : 0 }; }, getWithinInfo: function( element ) { var withinElement = $( element || window ), isElemWindow = isWindow( withinElement[ 0 ] ), isDocument = !!withinElement[ 0 ] && withinElement[ 0 ].nodeType === 9, hasOffset = !isElemWindow && !isDocument; return { element: withinElement, isWindow: isElemWindow, isDocument: isDocument, offset: hasOffset ? $( element ).offset() : { left: 0, top: 0 }, scrollLeft: withinElement.scrollLeft(), scrollTop: withinElement.scrollTop(), width: withinElement.outerWidth(), height: withinElement.outerHeight() }; } }; $.fn.position = function( options ) { if ( !options || !options.of ) { return _position.apply( this, arguments ); } // Make a copy, we don't want to modify arguments options = $.extend( {}, options ); var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions, // Make sure string options are treated as CSS selectors target = typeof options.of === "string" ? $( document ).find( options.of ) : $( options.of ), within = $.position.getWithinInfo( options.within ), scrollInfo = $.position.getScrollInfo( within ), collision = ( options.collision || "flip" ).split( " " ), offsets = {}; dimensions = getDimensions( target ); if ( target[ 0 ].preventDefault ) { // Force left top to allow flipping options.at = "left top"; } targetWidth = dimensions.width; targetHeight = dimensions.height; targetOffset = dimensions.offset; // Clone to reuse original targetOffset later basePosition = $.extend( {}, targetOffset ); // Force my and at to have valid horizontal and vertical positions // if a value is missing or invalid, it will be converted to center $.each( [ "my", "at" ], function() { var pos = ( options[ this ] || "" ).split( " " ), horizontalOffset, verticalOffset; if ( pos.length === 1 ) { pos = rhorizontal.test( pos[ 0 ] ) ? pos.concat( [ "center" ] ) : rvertical.test( pos[ 0 ] ) ? [ "center" ].concat( pos ) : [ "center", "center" ]; } pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center"; pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center"; // Calculate offsets horizontalOffset = roffset.exec( pos[ 0 ] ); verticalOffset = roffset.exec( pos[ 1 ] ); offsets[ this ] = [ horizontalOffset ? horizontalOffset[ 0 ] : 0, verticalOffset ? verticalOffset[ 0 ] : 0 ]; // Reduce to just the positions without the offsets options[ this ] = [ rposition.exec( pos[ 0 ] )[ 0 ], rposition.exec( pos[ 1 ] )[ 0 ] ]; } ); // Normalize collision option if ( collision.length === 1 ) { collision[ 1 ] = collision[ 0 ]; } if ( options.at[ 0 ] === "right" ) { basePosition.left += targetWidth; } else if ( options.at[ 0 ] === "center" ) { basePosition.left += targetWidth / 2; } if ( options.at[ 1 ] === "bottom" ) { basePosition.top += targetHeight; } else if ( options.at[ 1 ] === "center" ) { basePosition.top += targetHeight / 2; } atOffset = getOffsets( offsets.at, targetWidth, targetHeight ); basePosition.left += atOffset[ 0 ]; basePosition.top += atOffset[ 1 ]; return this.each( function() { var collisionPosition, using, elem = $( this ), elemWidth = elem.outerWidth(), elemHeight = elem.outerHeight(), marginLeft = parseCss( this, "marginLeft" ), marginTop = parseCss( this, "marginTop" ), collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) + scrollInfo.width, collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) + scrollInfo.height, position = $.extend( {}, basePosition ), myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() ); if ( options.my[ 0 ] === "right" ) { position.left -= elemWidth; } else if ( options.my[ 0 ] === "center" ) { position.left -= elemWidth / 2; } if ( options.my[ 1 ] === "bottom" ) { position.top -= elemHeight; } else if ( options.my[ 1 ] === "center" ) { position.top -= elemHeight / 2; } position.left += myOffset[ 0 ]; position.top += myOffset[ 1 ]; collisionPosition = { marginLeft: marginLeft, marginTop: marginTop }; $.each( [ "left", "top" ], function( i, dir ) { if ( $.ui.position[ collision[ i ] ] ) { $.ui.position[ collision[ i ] ][ dir ]( position, { targetWidth: targetWidth, targetHeight: targetHeight, elemWidth: elemWidth, elemHeight: elemHeight, collisionPosition: collisionPosition, collisionWidth: collisionWidth, collisionHeight: collisionHeight, offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ], my: options.my, at: options.at, within: within, elem: elem } ); } } ); if ( options.using ) { // Adds feedback as second argument to using callback, if present using = function( props ) { var left = targetOffset.left - position.left, right = left + targetWidth - elemWidth, top = targetOffset.top - position.top, bottom = top + targetHeight - elemHeight, feedback = { target: { element: target, left: targetOffset.left, top: targetOffset.top, width: targetWidth, height: targetHeight }, element: { element: elem, left: position.left, top: position.top, width: elemWidth, height: elemHeight }, horizontal: right < 0 ? "left" : left > 0 ? "right" : "center", vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle" }; if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) { feedback.horizontal = "center"; } if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) { feedback.vertical = "middle"; } if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) { feedback.important = "horizontal"; } else { feedback.important = "vertical"; } options.using.call( this, props, feedback ); }; } elem.offset( $.extend( position, { using: using } ) ); } ); }; $.ui.position = { fit: { left: function( position, data ) { var within = data.within, withinOffset = within.isWindow ? within.scrollLeft : within.offset.left, outerWidth = within.width, collisionPosLeft = position.left - data.collisionPosition.marginLeft, overLeft = withinOffset - collisionPosLeft, overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset, newOverRight; // Element is wider than within if ( data.collisionWidth > outerWidth ) { // Element is initially over the left side of within if ( overLeft > 0 && overRight <= 0 ) { newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - withinOffset; position.left += overLeft - newOverRight; // Element is initially over right side of within } else if ( overRight > 0 && overLeft <= 0 ) { position.left = withinOffset; // Element is initially over both left and right sides of within } else { if ( overLeft > overRight ) { position.left = withinOffset + outerWidth - data.collisionWidth; } else { position.left = withinOffset; } } // Too far left -> align with left edge } else if ( overLeft > 0 ) { position.left += overLeft; // Too far right -> align with right edge } else if ( overRight > 0 ) { position.left -= overRight; // Adjust based on position and margin } else { position.left = max( position.left - collisionPosLeft, position.left ); } }, top: function( position, data ) { var within = data.within, withinOffset = within.isWindow ? within.scrollTop : within.offset.top, outerHeight = data.within.height, collisionPosTop = position.top - data.collisionPosition.marginTop, overTop = withinOffset - collisionPosTop, overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset, newOverBottom; // Element is taller than within if ( data.collisionHeight > outerHeight ) { // Element is initially over the top of within if ( overTop > 0 && overBottom <= 0 ) { newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - withinOffset; position.top += overTop - newOverBottom; // Element is initially over bottom of within } else if ( overBottom > 0 && overTop <= 0 ) { position.top = withinOffset; // Element is initially over both top and bottom of within } else { if ( overTop > overBottom ) { position.top = withinOffset + outerHeight - data.collisionHeight; } else { position.top = withinOffset; } } // Too far up -> align with top } else if ( overTop > 0 ) { position.top += overTop; // Too far down -> align with bottom edge } else if ( overBottom > 0 ) { position.top -= overBottom; // Adjust based on position and margin } else { position.top = max( position.top - collisionPosTop, position.top ); } } }, flip: { left: function( position, data ) { var within = data.within, withinOffset = within.offset.left + within.scrollLeft, outerWidth = within.width, offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left, collisionPosLeft = position.left - data.collisionPosition.marginLeft, overLeft = collisionPosLeft - offsetLeft, overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft, myOffset = data.my[ 0 ] === "left" ? -data.elemWidth : data.my[ 0 ] === "right" ? data.elemWidth : 0, atOffset = data.at[ 0 ] === "left" ? data.targetWidth : data.at[ 0 ] === "right" ? -data.targetWidth : 0, offset = -2 * data.offset[ 0 ], newOverRight, newOverLeft; if ( overLeft < 0 ) { newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - outerWidth - withinOffset; if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) { position.left += myOffset + atOffset + offset; } } else if ( overRight > 0 ) { newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + atOffset + offset - offsetLeft; if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) { position.left += myOffset + atOffset + offset; } } }, top: function( position, data ) { var within = data.within, withinOffset = within.offset.top + within.scrollTop, outerHeight = within.height, offsetTop = within.isWindow ? within.scrollTop : within.offset.top, collisionPosTop = position.top - data.collisionPosition.marginTop, overTop = collisionPosTop - offsetTop, overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop, top = data.my[ 1 ] === "top", myOffset = top ? -data.elemHeight : data.my[ 1 ] === "bottom" ? data.elemHeight : 0, atOffset = data.at[ 1 ] === "top" ? data.targetHeight : data.at[ 1 ] === "bottom" ? -data.targetHeight : 0, offset = -2 * data.offset[ 1 ], newOverTop, newOverBottom; if ( overTop < 0 ) { newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - outerHeight - withinOffset; if ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) { position.top += myOffset + atOffset + offset; } } else if ( overBottom > 0 ) { newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset + offset - offsetTop; if ( newOverTop > 0 || abs( newOverTop ) < overBottom ) { position.top += myOffset + atOffset + offset; } } } }, flipfit: { left: function() { $.ui.position.flip.left.apply( this, arguments ); $.ui.position.fit.left.apply( this, arguments ); }, top: function() { $.ui.position.flip.top.apply( this, arguments ); $.ui.position.fit.top.apply( this, arguments ); } } }; } )(); var position = $.ui.position; /*! * jQuery UI :data 1.13.2 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license */ //>>label: :data Selector //>>group: Core //>>description: Selects elements which have data stored under the specified key. //>>docs: http://api.jqueryui.com/data-selector/ var data = $.extend( $.expr.pseudos, { data: $.expr.createPseudo ? $.expr.createPseudo( function( dataName ) { return function( elem ) { return !!$.data( elem, dataName ); }; } ) : // Support: jQuery <1.8 function( elem, i, match ) { return !!$.data( elem, match[ 3 ] ); } } ); /*! * jQuery UI Disable Selection 1.13.2 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license */ //>>label: disableSelection //>>group: Core //>>description: Disable selection of text content within the set of matched elements. //>>docs: http://api.jqueryui.com/disableSelection/ // This file is deprecated var disableSelection = $.fn.extend( { disableSelection: ( function() { var eventType = "onselectstart" in document.createElement( "div" ) ? "selectstart" : "mousedown"; return function() { return this.on( eventType + ".ui-disableSelection", function( event ) { event.preventDefault(); } ); }; } )(), enableSelection: function() { return this.off( ".ui-disableSelection" ); } } ); /*! * jQuery UI Focusable 1.13.2 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license */ //>>label: :focusable Selector //>>group: Core //>>description: Selects elements which can be focused. //>>docs: http://api.jqueryui.com/focusable-selector/ // Selectors $.ui.focusable = function( element, hasTabindex ) { var map, mapName, img, focusableIfVisible, fieldset, nodeName = element.nodeName.toLowerCase(); if ( "area" === nodeName ) { map = element.parentNode; mapName = map.name; if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) { return false; } img = $( "img[usemap='#" + mapName + "']" ); return img.length > 0 && img.is( ":visible" ); } if ( /^(input|select|textarea|button|object)$/.test( nodeName ) ) { focusableIfVisible = !element.disabled; if ( focusableIfVisible ) { // Form controls within a disabled fieldset are disabled. // However, controls within the fieldset's legend do not get disabled. // Since controls generally aren't placed inside legends, we skip // this portion of the check. fieldset = $( element ).closest( "fieldset" )[ 0 ]; if ( fieldset ) { focusableIfVisible = !fieldset.disabled; } } } else if ( "a" === nodeName ) { focusableIfVisible = element.href || hasTabindex; } else { focusableIfVisible = hasTabindex; } return focusableIfVisible && $( element ).is( ":visible" ) && visible( $( element ) ); }; // Support: IE 8 only // IE 8 doesn't resolve inherit to visible/hidden for computed values function visible( element ) { var visibility = element.css( "visibility" ); while ( visibility === "inherit" ) { element = element.parent(); visibility = element.css( "visibility" ); } return visibility === "visible"; } $.extend( $.expr.pseudos, { focusable: function( element ) { return $.ui.focusable( element, $.attr( element, "tabindex" ) != null ); } } ); var focusable = $.ui.focusable; // Support: IE8 Only // IE8 does not support the form attribute and when it is supplied. It overwrites the form prop // with a string, so we need to find the proper form. var form = $.fn._form = function() { return typeof this[ 0 ].form === "string" ? this.closest( "form" ) : $( this[ 0 ].form ); }; /*! * jQuery UI Form Reset Mixin 1.13.2 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license */ //>>label: Form Reset Mixin //>>group: Core //>>description: Refresh input widgets when their form is reset //>>docs: http://api.jqueryui.com/form-reset-mixin/ var formResetMixin = $.ui.formResetMixin = { _formResetHandler: function() { var form = $( this ); // Wait for the form reset to actually happen before refreshing setTimeout( function() { var instances = form.data( "ui-form-reset-instances" ); $.each( instances, function() { this.refresh(); } ); } ); }, _bindFormResetHandler: function() { this.form = this.element._form(); if ( !this.form.length ) { return; } var instances = this.form.data( "ui-form-reset-instances" ) || []; if ( !instances.length ) { // We don't use _on() here because we use a single event handler per form this.form.on( "reset.ui-form-reset", this._formResetHandler ); } instances.push( this ); this.form.data( "ui-form-reset-instances", instances ); }, _unbindFormResetHandler: function() { if ( !this.form.length ) { return; } var instances = this.form.data( "ui-form-reset-instances" ); instances.splice( $.inArray( this, instances ), 1 ); if ( instances.length ) { this.form.data( "ui-form-reset-instances", instances ); } else { this.form .removeData( "ui-form-reset-instances" ) .off( "reset.ui-form-reset" ); } } }; /*! * jQuery UI Keycode 1.13.2 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license */ //>>label: Keycode //>>group: Core //>>description: Provide keycodes as keynames //>>docs: http://api.jqueryui.com/jQuery.ui.keyCode/ var keycode = $.ui.keyCode = { BACKSPACE: 8, COMMA: 188, DELETE: 46, DOWN: 40, END: 35, ENTER: 13, ESCAPE: 27, HOME: 36, LEFT: 37, PAGE_DOWN: 34, PAGE_UP: 33, PERIOD: 190, RIGHT: 39, SPACE: 32, TAB: 9, UP: 38 }; /*! * jQuery UI Labels 1.13.2 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license */ //>>label: labels //>>group: Core //>>description: Find all the labels associated with a given input //>>docs: http://api.jqueryui.com/labels/ var labels = $.fn.labels = function() { var ancestor, selector, id, labels, ancestors; if ( !this.length ) { return this.pushStack( [] ); } // Check control.labels first if ( this[ 0 ].labels && this[ 0 ].labels.length ) { return this.pushStack( this[ 0 ].labels ); } // Support: IE <= 11, FF <= 37, Android <= 2.3 only // Above browsers do not support control.labels. Everything below is to support them // as well as document fragments. control.labels does not work on document fragments labels = this.eq( 0 ).parents( "label" ); // Look for the label based on the id id = this.attr( "id" ); if ( id ) { // We don't search against the document in case the element // is disconnected from the DOM ancestor = this.eq( 0 ).parents().last(); // Get a full set of top level ancestors ancestors = ancestor.add( ancestor.length ? ancestor.siblings() : this.siblings() ); // Create a selector for the label based on the id selector = "label[for='" + $.escapeSelector( id ) + "']"; labels = labels.add( ancestors.find( selector ).addBack( selector ) ); } // Return whatever we have found for labels return this.pushStack( labels ); }; /*! * jQuery UI Scroll Parent 1.13.2 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license */ //>>label: scrollParent //>>group: Core //>>description: Get the closest ancestor element that is scrollable. //>>docs: http://api.jqueryui.com/scrollParent/ var scrollParent = $.fn.scrollParent = function( includeHidden ) { var position = this.css( "position" ), excludeStaticParent = position === "absolute", overflowRegex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/, scrollParent = this.parents().filter( function() { var parent = $( this ); if ( excludeStaticParent && parent.css( "position" ) === "static" ) { return false; } return overflowRegex.test( parent.css( "overflow" ) + parent.css( "overflow-y" ) + parent.css( "overflow-x" ) ); } ).eq( 0 ); return position === "fixed" || !scrollParent.length ? $( this[ 0 ].ownerDocument || document ) : scrollParent; }; /*! * jQuery UI Tabbable 1.13.2 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license */ //>>label: :tabbable Selector //>>group: Core //>>description: Selects elements which can be tabbed to. //>>docs: http://api.jqueryui.com/tabbable-selector/ var tabbable = $.extend( $.expr.pseudos, { tabbable: function( element ) { var tabIndex = $.attr( element, "tabindex" ), hasTabindex = tabIndex != null; return ( !hasTabindex || tabIndex >= 0 ) && $.ui.focusable( element, hasTabindex ); } } ); /*! * jQuery UI Unique ID 1.13.2 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license */ //>>label: uniqueId //>>group: Core //>>description: Functions to generate and remove uniqueId's //>>docs: http://api.jqueryui.com/uniqueId/ var uniqueId = $.fn.extend( { uniqueId: ( function() { var uuid = 0; return function() { return this.each( function() { if ( !this.id ) { this.id = "ui-id-" + ( ++uuid ); } } ); }; } )(), removeUniqueId: function() { return this.each( function() { if ( /^ui-id-\d+$/.test( this.id ) ) { $( this ).removeAttr( "id" ); } } ); } } ); // This file is deprecated var ie = $.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() ); /*! * jQuery UI Mouse 1.13.2 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license */ //>>label: Mouse //>>group: Widgets //>>description: Abstracts mouse-based interactions to assist in creating certain widgets. //>>docs: http://api.jqueryui.com/mouse/ var mouseHandled = false; $( document ).on( "mouseup", function() { mouseHandled = false; } ); var widgetsMouse = $.widget( "ui.mouse", { version: "1.13.2", options: { cancel: "input, textarea, button, select, option", distance: 1, delay: 0 }, _mouseInit: function() { var that = this; this.element .on( "mousedown." + this.widgetName, function( event ) { return that._mouseDown( event ); } ) .on( "click." + this.widgetName, function( event ) { if ( true === $.data( event.target, that.widgetName + ".preventClickEvent" ) ) { $.removeData( event.target, that.widgetName + ".preventClickEvent" ); event.stopImmediatePropagation(); return false; } } ); this.started = false; }, // TODO: make sure destroying one instance of mouse doesn't mess with // other instances of mouse _mouseDestroy: function() { this.element.off( "." + this.widgetName ); if ( this._mouseMoveDelegate ) { this.document .off( "mousemove." + this.widgetName, this._mouseMoveDelegate ) .off( "mouseup." + this.widgetName, this._mouseUpDelegate ); } }, _mouseDown: function( event ) { // don't let more than one widget handle mouseStart if ( mouseHandled ) { return; } this._mouseMoved = false; // We may have missed mouseup (out of window) if ( this._mouseStarted ) { this._mouseUp( event ); } this._mouseDownEvent = event; var that = this, btnIsLeft = ( event.which === 1 ), // event.target.nodeName works around a bug in IE 8 with // disabled inputs (#7620) elIsCancel = ( typeof this.options.cancel === "string" && event.target.nodeName ? $( event.target ).closest( this.options.cancel ).length : false ); if ( !btnIsLeft || elIsCancel || !this._mouseCapture( event ) ) { return true; } this.mouseDelayMet = !this.options.delay; if ( !this.mouseDelayMet ) { this._mouseDelayTimer = setTimeout( function() { that.mouseDelayMet = true; }, this.options.delay ); } if ( this._mouseDistanceMet( event ) && this._mouseDelayMet( event ) ) { this._mouseStarted = ( this._mouseStart( event ) !== false ); if ( !this._mouseStarted ) { event.preventDefault(); return true; } } // Click event may never have fired (Gecko & Opera) if ( true === $.data( event.target, this.widgetName + ".preventClickEvent" ) ) { $.removeData( event.target, this.widgetName + ".preventClickEvent" ); } // These delegates are required to keep context this._mouseMoveDelegate = function( event ) { return that._mouseMove( event ); }; this._mouseUpDelegate = function( event ) { return that._mouseUp( event ); }; this.document .on( "mousemove." + this.widgetName, this._mouseMoveDelegate ) .on( "mouseup." + this.widgetName, this._mouseUpDelegate ); event.preventDefault(); mouseHandled = true; return true; }, _mouseMove: function( event ) { // Only check for mouseups outside the document if you've moved inside the document // at least once. This prevents the firing of mouseup in the case of IE<9, which will // fire a mousemove event if content is placed under the cursor. See #7778 // Support: IE <9 if ( this._mouseMoved ) { // IE mouseup check - mouseup happened when mouse was out of window if ( $.ui.ie && ( !document.documentMode || document.documentMode < 9 ) && !event.button ) { return this._mouseUp( event ); // Iframe mouseup check - mouseup occurred in another document } else if ( !event.which ) { // Support: Safari <=8 - 9 // Safari sets which to 0 if you press any of the following keys // during a drag (#14461) if ( event.originalEvent.altKey || event.originalEvent.ctrlKey || event.originalEvent.metaKey || event.originalEvent.shiftKey ) { this.ignoreMissingWhich = true; } else if ( !this.ignoreMissingWhich ) { return this._mouseUp( event ); } } } if ( event.which || event.button ) { this._mouseMoved = true; } if ( this._mouseStarted ) { this._mouseDrag( event ); return event.preventDefault(); } if ( this._mouseDistanceMet( event ) && this._mouseDelayMet( event ) ) { this._mouseStarted = ( this._mouseStart( this._mouseDownEvent, event ) !== false ); if ( this._mouseStarted ) { this._mouseDrag( event ); } else { this._mouseUp( event ); } } return !this._mouseStarted; }, _mouseUp: function( event ) { this.document .off( "mousemove." + this.widgetName, this._mouseMoveDelegate ) .off( "mouseup." + this.widgetName, this._mouseUpDelegate ); if ( this._mouseStarted ) { this._mouseStarted = false; if ( event.target === this._mouseDownEvent.target ) { $.data( event.target, this.widgetName + ".preventClickEvent", true ); } this._mouseStop( event ); } if ( this._mouseDelayTimer ) { clearTimeout( this._mouseDelayTimer ); delete this._mouseDelayTimer; } this.ignoreMissingWhich = false; mouseHandled = false; event.preventDefault(); }, _mouseDistanceMet: function( event ) { return ( Math.max( Math.abs( this._mouseDownEvent.pageX - event.pageX ), Math.abs( this._mouseDownEvent.pageY - event.pageY ) ) >= this.options.distance ); }, _mouseDelayMet: function( /* event */ ) { return this.mouseDelayMet; }, // These are placeholder methods, to be overriden by extending plugin _mouseStart: function( /* event */ ) {}, _mouseDrag: function( /* event */ ) {}, _mouseStop: function( /* event */ ) {}, _mouseCapture: function( /* event */ ) { return true; } } ); // $.ui.plugin is deprecated. Use $.widget() extensions instead. var plugin = $.ui.plugin = { add: function( module, option, set ) { var i, proto = $.ui[ module ].prototype; for ( i in set ) { proto.plugins[ i ] = proto.plugins[ i ] || []; proto.plugins[ i ].push( [ option, set[ i ] ] ); } }, call: function( instance, name, args, allowDisconnected ) { var i, set = instance.plugins[ name ]; if ( !set ) { return; } if ( !allowDisconnected && ( !instance.element[ 0 ].parentNode || instance.element[ 0 ].parentNode.nodeType === 11 ) ) { return; } for ( i = 0; i < set.length; i++ ) { if ( instance.options[ set[ i ][ 0 ] ] ) { set[ i ][ 1 ].apply( instance.element, args ); } } } }; var safeActiveElement = $.ui.safeActiveElement = function( document ) { var activeElement; // Support: IE 9 only // IE9 throws an "Unspecified error" accessing document.activeElement from an <iframe> try { activeElement = document.activeElement; } catch ( error ) { activeElement = document.body; } // Support: IE 9 - 11 only // IE may return null instead of an element // Interestingly, this only seems to occur when NOT in an iframe if ( !activeElement ) { activeElement = document.body; } // Support: IE 11 only // IE11 returns a seemingly empty object in some cases when accessing // document.activeElement from an <iframe> if ( !activeElement.nodeName ) { activeElement = document.body; } return activeElement; }; var safeBlur = $.ui.safeBlur = function( element ) { // Support: IE9 - 10 only // If the <body> is blurred, IE will switch windows, see #9420 if ( element && element.nodeName.toLowerCase() !== "body" ) { $( element ).trigger( "blur" ); } }; /*! * jQuery UI Draggable 1.13.2 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license */ //>>label: Draggable //>>group: Interactions //>>description: Enables dragging functionality for any element. //>>docs: http://api.jqueryui.com/draggable/ //>>demos: http://jqueryui.com/draggable/ //>>css.structure: ../../themes/base/draggable.css $.widget( "ui.draggable", $.ui.mouse, { version: "1.13.2", widgetEventPrefix: "drag", options: { addClasses: true, appendTo: "parent", axis: false, connectToSortable: false, containment: false, cursor: "auto", cursorAt: false, grid: false, handle: false, helper: "original", iframeFix: false, opacity: false, refreshPositions: false, revert: false, revertDuration: 500, scope: "default", scroll: true, scrollSensitivity: 20, scrollSpeed: 20, snap: false, snapMode: "both", snapTolerance: 20, stack: false, zIndex: false, // Callbacks drag: null, start: null, stop: null }, _create: function() { if ( this.options.helper === "original" ) { this._setPositionRelative(); } if ( this.options.addClasses ) { this._addClass( "ui-draggable" ); } this._setHandleClassName(); this._mouseInit(); }, _setOption: function( key, value ) { this._super( key, value ); if ( key === "handle" ) { this._removeHandleClassName(); this._setHandleClassName(); } }, _destroy: function() { if ( ( this.helper || this.element ).is( ".ui-draggable-dragging" ) ) { this.destroyOnClear = true; return; } this._removeHandleClassName(); this._mouseDestroy(); }, _mouseCapture: function( event ) { var o = this.options; // Among others, prevent a drag on a resizable-handle if ( this.helper || o.disabled || $( event.target ).closest( ".ui-resizable-handle" ).length > 0 ) { return false; } //Quit if we're not on a valid handle this.handle = this._getHandle( event ); if ( !this.handle ) { return false; } this._blurActiveElement( event ); this._blockFrames( o.iframeFix === true ? "iframe" : o.iframeFix ); return true; }, _blockFrames: function( selector ) { this.iframeBlocks = this.document.find( selector ).map( function() { var iframe = $( this ); return $( "<div>" ) .css( "position", "absolute" ) .appendTo( iframe.parent() ) .outerWidth( iframe.outerWidth() ) .outerHeight( iframe.outerHeight() ) .offset( iframe.offset() )[ 0 ]; } ); }, _unblockFrames: function() { if ( this.iframeBlocks ) { this.iframeBlocks.remove(); delete this.iframeBlocks; } }, _blurActiveElement: function( event ) { var activeElement = $.ui.safeActiveElement( this.document[ 0 ] ), target = $( event.target ); // Don't blur if the event occurred on an element that is within // the currently focused element // See #10527, #12472 if ( target.closest( activeElement ).length ) { return; } // Blur any element that currently has focus, see #4261 $.ui.safeBlur( activeElement ); }, _mouseStart: function( event ) { var o = this.options; //Create and append the visible helper this.helper = this._createHelper( event ); this._addClass( this.helper, "ui-draggable-dragging" ); //Cache the helper size this._cacheHelperProportions(); //If ddmanager is used for droppables, set the global draggable if ( $.ui.ddmanager ) { $.ui.ddmanager.current = this; } /* * - Position generation - * This block generates everything position related - it's the core of draggables. */ //Cache the margins of the original element this._cacheMargins(); //Store the helper's css position this.cssPosition = this.helper.css( "position" ); this.scrollParent = this.helper.scrollParent( true ); this.offsetParent = this.helper.offsetParent(); this.hasFixedAncestor = this.helper.parents().filter( function() { return $( this ).css( "position" ) === "fixed"; } ).length > 0; //The element's absolute position on the page minus margins this.positionAbs = this.element.offset(); this._refreshOffsets( event ); //Generate the original position this.originalPosition = this.position = this._generatePosition( event, false ); this.originalPageX = event.pageX; this.originalPageY = event.pageY; //Adjust the mouse offset relative to the helper if "cursorAt" is supplied if ( o.cursorAt ) { this._adjustOffsetFromHelper( o.cursorAt ); } //Set a containment if given in the options this._setContainment(); //Trigger event + callbacks if ( this._trigger( "start", event ) === false ) { this._clear(); return false; } //Recache the helper size this._cacheHelperProportions(); //Prepare the droppable offsets if ( $.ui.ddmanager && !o.dropBehaviour ) { $.ui.ddmanager.prepareOffsets( this, event ); } // Execute the drag once - this causes the helper not to be visible before getting its // correct position this._mouseDrag( event, true ); // If the ddmanager is used for droppables, inform the manager that dragging has started // (see #5003) if ( $.ui.ddmanager ) { $.ui.ddmanager.dragStart( this, event ); } return true; }, _refreshOffsets: function( event ) { this.offset = { top: this.positionAbs.top - this.margins.top, left: this.positionAbs.left - this.margins.left, scroll: false, parent: this._getParentOffset(), relative: this._getRelativeOffset() }; this.offset.click = { left: event.pageX - this.offset.left, top: event.pageY - this.offset.top }; }, _mouseDrag: function( event, noPropagation ) { // reset any necessary cached properties (see #5009) if ( this.hasFixedAncestor ) { this.offset.parent = this._getParentOffset(); } //Compute the helpers position this.position = this._generatePosition( event, true ); this.positionAbs = this._convertPositionTo( "absolute" ); //Call plugins and callbacks and use the resulting position if something is returned if ( !noPropagation ) { var ui = this._uiHash(); if ( this._trigger( "drag", event, ui ) === false ) { this._mouseUp( new $.Event( "mouseup", event ) ); return false; } this.position = ui.position; } this.helper[ 0 ].style.left = this.position.left + "px"; this.helper[ 0 ].style.top = this.position.top + "px"; if ( $.ui.ddmanager ) { $.ui.ddmanager.drag( this, event ); } return false; }, _mouseStop: function( event ) { //If we are using droppables, inform the manager about the drop var that = this, dropped = false; if ( $.ui.ddmanager && !this.options.dropBehaviour ) { dropped = $.ui.ddmanager.drop( this, event ); } //if a drop comes from outside (a sortable) if ( this.dropped ) { dropped = this.dropped; this.dropped = false; } if ( ( this.options.revert === "invalid" && !dropped ) || ( this.options.revert === "valid" && dropped ) || this.options.revert === true || ( typeof this.options.revert === "function" && this.options.revert.call( this.element, dropped ) ) ) { $( this.helper ).animate( this.originalPosition, parseInt( this.options.revertDuration, 10 ), function() { if ( that._trigger( "stop", event ) !== false ) { that._clear(); } } ); } else { if ( this._trigger( "stop", event ) !== false ) { this._clear(); } } return false; }, _mouseUp: function( event ) { this._unblockFrames(); // If the ddmanager is used for droppables, inform the manager that dragging has stopped // (see #5003) if ( $.ui.ddmanager ) { $.ui.ddmanager.dragStop( this, event ); } // Only need to focus if the event occurred on the draggable itself, see #10527 if ( this.handleElement.is( event.target ) ) { // The interaction is over; whether or not the click resulted in a drag, // focus the element this.element.trigger( "focus" ); } return $.ui.mouse.prototype._mouseUp.call( this, event ); }, cancel: function() { if ( this.helper.is( ".ui-draggable-dragging" ) ) { this._mouseUp( new $.Event( "mouseup", { target: this.element[ 0 ] } ) ); } else { this._clear(); } return this; }, _getHandle: function( event ) { return this.options.handle ? !!$( event.target ).closest( this.element.find( this.options.handle ) ).length : true; }, _setHandleClassName: function() { this.handleElement = this.options.handle ? this.element.find( this.options.handle ) : this.element; this._addClass( this.handleElement, "ui-draggable-handle" ); }, _removeHandleClassName: function() { this._removeClass( this.handleElement, "ui-draggable-handle" ); }, _createHelper: function( event ) { var o = this.options, helperIsFunction = typeof o.helper === "function", helper = helperIsFunction ? $( o.helper.apply( this.element[ 0 ], [ event ] ) ) : ( o.helper === "clone" ? this.element.clone().removeAttr( "id" ) : this.element ); if ( !helper.parents( "body" ).length ) { helper.appendTo( ( o.appendTo === "parent" ? this.element[ 0 ].parentNode : o.appendTo ) ); } // Http://bugs.jqueryui.com/ticket/9446 // a helper function can return the original element // which wouldn't have been set to relative in _create if ( helperIsFunction && helper[ 0 ] === this.element[ 0 ] ) { this._setPositionRelative(); } if ( helper[ 0 ] !== this.element[ 0 ] && !( /(fixed|absolute)/ ).test( helper.css( "position" ) ) ) { helper.css( "position", "absolute" ); } return helper; }, _setPositionRelative: function() { if ( !( /^(?:r|a|f)/ ).test( this.element.css( "position" ) ) ) { this.element[ 0 ].style.position = "relative"; } }, _adjustOffsetFromHelper: function( obj ) { if ( typeof obj === "string" ) { obj = obj.split( " " ); } if ( Array.isArray( obj ) ) { obj = { left: +obj[ 0 ], top: +obj[ 1 ] || 0 }; } if ( "left" in obj ) { this.offset.click.left = obj.left + this.margins.left; } if ( "right" in obj ) { this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; } if ( "top" in obj ) { this.offset.click.top = obj.top + this.margins.top; } if ( "bottom" in obj ) { this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; } }, _isRootNode: function( element ) { return ( /(html|body)/i ).test( element.tagName ) || element === this.document[ 0 ]; }, _getParentOffset: function() { //Get the offsetParent and cache its position var po = this.offsetParent.offset(), document = this.document[ 0 ]; // This is a special case where we need to modify a offset calculated on start, since the // following happened: // 1. The position of the helper is absolute, so it's position is calculated based on the // next positioned parent // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't // the document, which means that the scroll is included in the initial calculation of the // offset of the parent, and never recalculated upon drag if ( this.cssPosition === "absolute" && this.scrollParent[ 0 ] !== document && $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) { po.left += this.scrollParent.scrollLeft(); po.top += this.scrollParent.scrollTop(); } if ( this._isRootNode( this.offsetParent[ 0 ] ) ) { po = { top: 0, left: 0 }; } return { top: po.top + ( parseInt( this.offsetParent.css( "borderTopWidth" ), 10 ) || 0 ), left: po.left + ( parseInt( this.offsetParent.css( "borderLeftWidth" ), 10 ) || 0 ) }; }, _getRelativeOffset: function() { if ( this.cssPosition !== "relative" ) { return { top: 0, left: 0 }; } var p = this.element.position(), scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] ); return { top: p.top - ( parseInt( this.helper.css( "top" ), 10 ) || 0 ) + ( !scrollIsRootNode ? this.scrollParent.scrollTop() : 0 ), left: p.left - ( parseInt( this.helper.css( "left" ), 10 ) || 0 ) + ( !scrollIsRootNode ? this.scrollParent.scrollLeft() : 0 ) }; }, _cacheMargins: function() { this.margins = { left: ( parseInt( this.element.css( "marginLeft" ), 10 ) || 0 ), top: ( parseInt( this.element.css( "marginTop" ), 10 ) || 0 ), right: ( parseInt( this.element.css( "marginRight" ), 10 ) || 0 ), bottom: ( parseInt( this.element.css( "marginBottom" ), 10 ) || 0 ) }; }, _cacheHelperProportions: function() { this.helperProportions = { width: this.helper.outerWidth(), height: this.helper.outerHeight() }; }, _setContainment: function() { var isUserScrollable, c, ce, o = this.options, document = this.document[ 0 ]; this.relativeContainer = null; if ( !o.containment ) { this.containment = null; return; } if ( o.containment === "window" ) { this.containment = [ $( window ).scrollLeft() - this.offset.relative.left - this.offset.parent.left, $( window ).scrollTop() - this.offset.relative.top - this.offset.parent.top, $( window ).scrollLeft() + $( window ).width() - this.helperProportions.width - this.margins.left, $( window ).scrollTop() + ( $( window ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top ]; return; } if ( o.containment === "document" ) { this.containment = [ 0, 0, $( document ).width() - this.helperProportions.width - this.margins.left, ( $( document ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top ]; return; } if ( o.containment.constructor === Array ) { this.containment = o.containment; return; } if ( o.containment === "parent" ) { o.containment = this.helper[ 0 ].parentNode; } c = $( o.containment ); ce = c[ 0 ]; if ( !ce ) { return; } isUserScrollable = /(scroll|auto)/.test( c.css( "overflow" ) ); this.containment = [ ( parseInt( c.css( "borderLeftWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingLeft" ), 10 ) || 0 ), ( parseInt( c.css( "borderTopWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingTop" ), 10 ) || 0 ), ( isUserScrollable ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) - ( parseInt( c.css( "borderRightWidth" ), 10 ) || 0 ) - ( parseInt( c.css( "paddingRight" ), 10 ) || 0 ) - this.helperProportions.width - this.margins.left - this.margins.right, ( isUserScrollable ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) - ( parseInt( c.css( "borderBottomWidth" ), 10 ) || 0 ) - ( parseInt( c.css( "paddingBottom" ), 10 ) || 0 ) - this.helperProportions.height - this.margins.top - this.margins.bottom ]; this.relativeContainer = c; }, _convertPositionTo: function( d, pos ) { if ( !pos ) { pos = this.position; } var mod = d === "absolute" ? 1 : -1, scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] ); return { top: ( // The absolute mouse position pos.top + // Only for relative positioned nodes: Relative offset from element to offset parent this.offset.relative.top * mod + // The offsetParent's offset without borders (offset + border) this.offset.parent.top * mod - ( ( this.cssPosition === "fixed" ? -this.offset.scroll.top : ( scrollIsRootNode ? 0 : this.offset.scroll.top ) ) * mod ) ), left: ( // The absolute mouse position pos.left + // Only for relative positioned nodes: Relative offset from element to offset parent this.offset.relative.left * mod + // The offsetParent's offset without borders (offset + border) this.offset.parent.left * mod - ( ( this.cssPosition === "fixed" ? -this.offset.scroll.left : ( scrollIsRootNode ? 0 : this.offset.scroll.left ) ) * mod ) ) }; }, _generatePosition: function( event, constrainPosition ) { var containment, co, top, left, o = this.options, scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] ), pageX = event.pageX, pageY = event.pageY; // Cache the scroll if ( !scrollIsRootNode || !this.offset.scroll ) { this.offset.scroll = { top: this.scrollParent.scrollTop(), left: this.scrollParent.scrollLeft() }; } /* * - Position constraining - * Constrain the position to a mix of grid, containment. */ // If we are not dragging yet, we won't check for options if ( constrainPosition ) { if ( this.containment ) { if ( this.relativeContainer ) { co = this.relativeContainer.offset(); containment = [ this.containment[ 0 ] + co.left, this.containment[ 1 ] + co.top, this.containment[ 2 ] + co.left, this.containment[ 3 ] + co.top ]; } else { containment = this.containment; } if ( event.pageX - this.offset.click.left < containment[ 0 ] ) { pageX = containment[ 0 ] + this.offset.click.left; } if ( event.pageY - this.offset.click.top < containment[ 1 ] ) { pageY = containment[ 1 ] + this.offset.click.top; } if ( event.pageX - this.offset.click.left > containment[ 2 ] ) { pageX = containment[ 2 ] + this.offset.click.left; } if ( event.pageY - this.offset.click.top > containment[ 3 ] ) { pageY = containment[ 3 ] + this.offset.click.top; } } if ( o.grid ) { //Check for grid elements set to 0 to prevent divide by 0 error causing invalid // argument errors in IE (see ticket #6950) top = o.grid[ 1 ] ? this.originalPageY + Math.round( ( pageY - this.originalPageY ) / o.grid[ 1 ] ) * o.grid[ 1 ] : this.originalPageY; pageY = containment ? ( ( top - this.offset.click.top >= containment[ 1 ] || top - this.offset.click.top > containment[ 3 ] ) ? top : ( ( top - this.offset.click.top >= containment[ 1 ] ) ? top - o.grid[ 1 ] : top + o.grid[ 1 ] ) ) : top; left = o.grid[ 0 ] ? this.originalPageX + Math.round( ( pageX - this.originalPageX ) / o.grid[ 0 ] ) * o.grid[ 0 ] : this.originalPageX; pageX = containment ? ( ( left - this.offset.click.left >= containment[ 0 ] || left - this.offset.click.left > containment[ 2 ] ) ? left : ( ( left - this.offset.click.left >= containment[ 0 ] ) ? left - o.grid[ 0 ] : left + o.grid[ 0 ] ) ) : left; } if ( o.axis === "y" ) { pageX = this.originalPageX; } if ( o.axis === "x" ) { pageY = this.originalPageY; } } return { top: ( // The absolute mouse position pageY - // Click offset (relative to the element) this.offset.click.top - // Only for relative positioned nodes: Relative offset from element to offset parent this.offset.relative.top - // The offsetParent's offset without borders (offset + border) this.offset.parent.top + ( this.cssPosition === "fixed" ? -this.offset.scroll.top : ( scrollIsRootNode ? 0 : this.offset.scroll.top ) ) ), left: ( // The absolute mouse position pageX - // Click offset (relative to the element) this.offset.click.left - // Only for relative positioned nodes: Relative offset from element to offset parent this.offset.relative.left - // The offsetParent's offset without borders (offset + border) this.offset.parent.left + ( this.cssPosition === "fixed" ? -this.offset.scroll.left : ( scrollIsRootNode ? 0 : this.offset.scroll.left ) ) ) }; }, _clear: function() { this._removeClass( this.helper, "ui-draggable-dragging" ); if ( this.helper[ 0 ] !== this.element[ 0 ] && !this.cancelHelperRemoval ) { this.helper.remove(); } this.helper = null; this.cancelHelperRemoval = false; if ( this.destroyOnClear ) { this.destroy(); } }, // From now on bulk stuff - mainly helpers _trigger: function( type, event, ui ) { ui = ui || this._uiHash(); $.ui.plugin.call( this, type, [ event, ui, this ], true ); // Absolute position and offset (see #6884 ) have to be recalculated after plugins if ( /^(drag|start|stop)/.test( type ) ) { this.positionAbs = this._convertPositionTo( "absolute" ); ui.offset = this.positionAbs; } return $.Widget.prototype._trigger.call( this, type, event, ui ); }, plugins: {}, _uiHash: function() { return { helper: this.helper, position: this.position, originalPosition: this.originalPosition, offset: this.positionAbs }; } } ); $.ui.plugin.add( "draggable", "connectToSortable", { start: function( event, ui, draggable ) { var uiSortable = $.extend( {}, ui, { item: draggable.element } ); draggable.sortables = []; $( draggable.options.connectToSortable ).each( function() { var sortable = $( this ).sortable( "instance" ); if ( sortable && !sortable.options.disabled ) { draggable.sortables.push( sortable ); // RefreshPositions is called at drag start to refresh the containerCache // which is used in drag. This ensures it's initialized and synchronized // with any changes that might have happened on the page since initialization. sortable.refreshPositions(); sortable._trigger( "activate", event, uiSortable ); } } ); }, stop: function( event, ui, draggable ) { var uiSortable = $.extend( {}, ui, { item: draggable.element } ); draggable.cancelHelperRemoval = false; $.each( draggable.sortables, function() { var sortable = this; if ( sortable.isOver ) { sortable.isOver = 0; // Allow this sortable to handle removing the helper draggable.cancelHelperRemoval = true; sortable.cancelHelperRemoval = false; // Use _storedCSS To restore properties in the sortable, // as this also handles revert (#9675) since the draggable // may have modified them in unexpected ways (#8809) sortable._storedCSS = { position: sortable.placeholder.css( "position" ), top: sortable.placeholder.css( "top" ), left: sortable.placeholder.css( "left" ) }; sortable._mouseStop( event ); // Once drag has ended, the sortable should return to using // its original helper, not the shared helper from draggable sortable.options.helper = sortable.options._helper; } else { // Prevent this Sortable from removing the helper. // However, don't set the draggable to remove the helper // either as another connected Sortable may yet handle the removal. sortable.cancelHelperRemoval = true; sortable._trigger( "deactivate", event, uiSortable ); } } ); }, drag: function( event, ui, draggable ) { $.each( draggable.sortables, function() { var innermostIntersecting = false, sortable = this; // Copy over variables that sortable's _intersectsWith uses sortable.positionAbs = draggable.positionAbs; sortable.helperProportions = draggable.helperProportions; sortable.offset.click = draggable.offset.click; if ( sortable._intersectsWith( sortable.containerCache ) ) { innermostIntersecting = true; $.each( draggable.sortables, function() { // Copy over variables that sortable's _intersectsWith uses this.positionAbs = draggable.positionAbs; this.helperProportions = draggable.helperProportions; this.offset.click = draggable.offset.click; if ( this !== sortable && this._intersectsWith( this.containerCache ) && $.contains( sortable.element[ 0 ], this.element[ 0 ] ) ) { innermostIntersecting = false; } return innermostIntersecting; } ); } if ( innermostIntersecting ) { // If it intersects, we use a little isOver variable and set it once, // so that the move-in stuff gets fired only once. if ( !sortable.isOver ) { sortable.isOver = 1; // Store draggable's parent in case we need to reappend to it later. draggable._parent = ui.helper.parent(); sortable.currentItem = ui.helper .appendTo( sortable.element ) .data( "ui-sortable-item", true ); // Store helper option to later restore it sortable.options._helper = sortable.options.helper; sortable.options.helper = function() { return ui.helper[ 0 ]; }; // Fire the start events of the sortable with our passed browser event, // and our own helper (so it doesn't create a new one) event.target = sortable.currentItem[ 0 ]; sortable._mouseCapture( event, true ); sortable._mouseStart( event, true, true ); // Because the browser event is way off the new appended portlet, // modify necessary variables to reflect the changes sortable.offset.click.top = draggable.offset.click.top; sortable.offset.click.left = draggable.offset.click.left; sortable.offset.parent.left -= draggable.offset.parent.left - sortable.offset.parent.left; sortable.offset.parent.top -= draggable.offset.parent.top - sortable.offset.parent.top; draggable._trigger( "toSortable", event ); // Inform draggable that the helper is in a valid drop zone, // used solely in the revert option to handle "valid/invalid". draggable.dropped = sortable.element; // Need to refreshPositions of all sortables in the case that // adding to one sortable changes the location of the other sortables (#9675) $.each( draggable.sortables, function() { this.refreshPositions(); } ); // Hack so receive/update callbacks work (mostly) draggable.currentItem = draggable.element; sortable.fromOutside = draggable; } if ( sortable.currentItem ) { sortable._mouseDrag( event ); // Copy the sortable's position because the draggable's can potentially reflect // a relative position, while sortable is always absolute, which the dragged // element has now become. (#8809) ui.position = sortable.position; } } else { // If it doesn't intersect with the sortable, and it intersected before, // we fake the drag stop of the sortable, but make sure it doesn't remove // the helper by using cancelHelperRemoval. if ( sortable.isOver ) { sortable.isOver = 0; sortable.cancelHelperRemoval = true; // Calling sortable's mouseStop would trigger a revert, // so revert must be temporarily false until after mouseStop is called. sortable.options._revert = sortable.options.revert; sortable.options.revert = false; sortable._trigger( "out", event, sortable._uiHash( sortable ) ); sortable._mouseStop( event, true ); // Restore sortable behaviors that were modfied // when the draggable entered the sortable area (#9481) sortable.options.revert = sortable.options._revert; sortable.options.helper = sortable.options._helper; if ( sortable.placeholder ) { sortable.placeholder.remove(); } // Restore and recalculate the draggable's offset considering the sortable // may have modified them in unexpected ways. (#8809, #10669) ui.helper.appendTo( draggable._parent ); draggable._refreshOffsets( event ); ui.position = draggable._generatePosition( event, true ); draggable._trigger( "fromSortable", event ); // Inform draggable that the helper is no longer in a valid drop zone draggable.dropped = false; // Need to refreshPositions of all sortables just in case removing // from one sortable changes the location of other sortables (#9675) $.each( draggable.sortables, function() { this.refreshPositions(); } ); } } } ); } } ); $.ui.plugin.add( "draggable", "cursor", { start: function( event, ui, instance ) { var t = $( "body" ), o = instance.options; if ( t.css( "cursor" ) ) { o._cursor = t.css( "cursor" ); } t.css( "cursor", o.cursor ); }, stop: function( event, ui, instance ) { var o = instance.options; if ( o._cursor ) { $( "body" ).css( "cursor", o._cursor ); } } } ); $.ui.plugin.add( "draggable", "opacity", { start: function( event, ui, instance ) { var t = $( ui.helper ), o = instance.options; if ( t.css( "opacity" ) ) { o._opacity = t.css( "opacity" ); } t.css( "opacity", o.opacity ); }, stop: function( event, ui, instance ) { var o = instance.options; if ( o._opacity ) { $( ui.helper ).css( "opacity", o._opacity ); } } } ); $.ui.plugin.add( "draggable", "scroll", { start: function( event, ui, i ) { if ( !i.scrollParentNotHidden ) { i.scrollParentNotHidden = i.helper.scrollParent( false ); } if ( i.scrollParentNotHidden[ 0 ] !== i.document[ 0 ] && i.scrollParentNotHidden[ 0 ].tagName !== "HTML" ) { i.overflowOffset = i.scrollParentNotHidden.offset(); } }, drag: function( event, ui, i ) { var o = i.options, scrolled = false, scrollParent = i.scrollParentNotHidden[ 0 ], document = i.document[ 0 ]; if ( scrollParent !== document && scrollParent.tagName !== "HTML" ) { if ( !o.axis || o.axis !== "x" ) { if ( ( i.overflowOffset.top + scrollParent.offsetHeight ) - event.pageY < o.scrollSensitivity ) { scrollParent.scrollTop = scrolled = scrollParent.scrollTop + o.scrollSpeed; } else if ( event.pageY - i.overflowOffset.top < o.scrollSensitivity ) { scrollParent.scrollTop = scrolled = scrollParent.scrollTop - o.scrollSpeed; } } if ( !o.axis || o.axis !== "y" ) { if ( ( i.overflowOffset.left + scrollParent.offsetWidth ) - event.pageX < o.scrollSensitivity ) { scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft + o.scrollSpeed; } else if ( event.pageX - i.overflowOffset.left < o.scrollSensitivity ) { scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft - o.scrollSpeed; } } } else { if ( !o.axis || o.axis !== "x" ) { if ( event.pageY - $( document ).scrollTop() < o.scrollSensitivity ) { scrolled = $( document ).scrollTop( $( document ).scrollTop() - o.scrollSpeed ); } else if ( $( window ).height() - ( event.pageY - $( document ).scrollTop() ) < o.scrollSensitivity ) { scrolled = $( document ).scrollTop( $( document ).scrollTop() + o.scrollSpeed ); } } if ( !o.axis || o.axis !== "y" ) { if ( event.pageX - $( document ).scrollLeft() < o.scrollSensitivity ) { scrolled = $( document ).scrollLeft( $( document ).scrollLeft() - o.scrollSpeed ); } else if ( $( window ).width() - ( event.pageX - $( document ).scrollLeft() ) < o.scrollSensitivity ) { scrolled = $( document ).scrollLeft( $( document ).scrollLeft() + o.scrollSpeed ); } } } if ( scrolled !== false && $.ui.ddmanager && !o.dropBehaviour ) { $.ui.ddmanager.prepareOffsets( i, event ); } } } ); $.ui.plugin.add( "draggable", "snap", { start: function( event, ui, i ) { var o = i.options; i.snapElements = []; $( o.snap.constructor !== String ? ( o.snap.items || ":data(ui-draggable)" ) : o.snap ) .each( function() { var $t = $( this ), $o = $t.offset(); if ( this !== i.element[ 0 ] ) { i.snapElements.push( { item: this, width: $t.outerWidth(), height: $t.outerHeight(), top: $o.top, left: $o.left } ); } } ); }, drag: function( event, ui, inst ) { var ts, bs, ls, rs, l, r, t, b, i, first, o = inst.options, d = o.snapTolerance, x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width, y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height; for ( i = inst.snapElements.length - 1; i >= 0; i-- ) { l = inst.snapElements[ i ].left - inst.margins.left; r = l + inst.snapElements[ i ].width; t = inst.snapElements[ i ].top - inst.margins.top; b = t + inst.snapElements[ i ].height; if ( x2 < l - d || x1 > r + d || y2 < t - d || y1 > b + d || !$.contains( inst.snapElements[ i ].item.ownerDocument, inst.snapElements[ i ].item ) ) { if ( inst.snapElements[ i ].snapping ) { if ( inst.options.snap.release ) { inst.options.snap.release.call( inst.element, event, $.extend( inst._uiHash(), { snapItem: inst.snapElements[ i ].item } ) ); } } inst.snapElements[ i ].snapping = false; continue; } if ( o.snapMode !== "inner" ) { ts = Math.abs( t - y2 ) <= d; bs = Math.abs( b - y1 ) <= d; ls = Math.abs( l - x2 ) <= d; rs = Math.abs( r - x1 ) <= d; if ( ts ) { ui.position.top = inst._convertPositionTo( "relative", { top: t - inst.helperProportions.height, left: 0 } ).top; } if ( bs ) { ui.position.top = inst._convertPositionTo( "relative", { top: b, left: 0 } ).top; } if ( ls ) { ui.position.left = inst._convertPositionTo( "relative", { top: 0, left: l - inst.helperProportions.width } ).left; } if ( rs ) { ui.position.left = inst._convertPositionTo( "relative", { top: 0, left: r } ).left; } } first = ( ts || bs || ls || rs ); if ( o.snapMode !== "outer" ) { ts = Math.abs( t - y1 ) <= d; bs = Math.abs( b - y2 ) <= d; ls = Math.abs( l - x1 ) <= d; rs = Math.abs( r - x2 ) <= d; if ( ts ) { ui.position.top = inst._convertPositionTo( "relative", { top: t, left: 0 } ).top; } if ( bs ) { ui.position.top = inst._convertPositionTo( "relative", { top: b - inst.helperProportions.height, left: 0 } ).top; } if ( ls ) { ui.position.left = inst._convertPositionTo( "relative", { top: 0, left: l } ).left; } if ( rs ) { ui.position.left = inst._convertPositionTo( "relative", { top: 0, left: r - inst.helperProportions.width } ).left; } } if ( !inst.snapElements[ i ].snapping && ( ts || bs || ls || rs || first ) ) { if ( inst.options.snap.snap ) { inst.options.snap.snap.call( inst.element, event, $.extend( inst._uiHash(), { snapItem: inst.snapElements[ i ].item } ) ); } } inst.snapElements[ i ].snapping = ( ts || bs || ls || rs || first ); } } } ); $.ui.plugin.add( "draggable", "stack", { start: function( event, ui, instance ) { var min, o = instance.options, group = $.makeArray( $( o.stack ) ).sort( function( a, b ) { return ( parseInt( $( a ).css( "zIndex" ), 10 ) || 0 ) - ( parseInt( $( b ).css( "zIndex" ), 10 ) || 0 ); } ); if ( !group.length ) { return; } min = parseInt( $( group[ 0 ] ).css( "zIndex" ), 10 ) || 0; $( group ).each( function( i ) { $( this ).css( "zIndex", min + i ); } ); this.css( "zIndex", ( min + group.length ) ); } } ); $.ui.plugin.add( "draggable", "zIndex", { start: function( event, ui, instance ) { var t = $( ui.helper ), o = instance.options; if ( t.css( "zIndex" ) ) { o._zIndex = t.css( "zIndex" ); } t.css( "zIndex", o.zIndex ); }, stop: function( event, ui, instance ) { var o = instance.options; if ( o._zIndex ) { $( ui.helper ).css( "zIndex", o._zIndex ); } } } ); var widgetsDraggable = $.ui.draggable; /*! * jQuery UI Resizable 1.13.2 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license */ //>>label: Resizable //>>group: Interactions //>>description: Enables resize functionality for any element. //>>docs: http://api.jqueryui.com/resizable/ //>>demos: http://jqueryui.com/resizable/ //>>css.structure: ../../themes/base/core.css //>>css.structure: ../../themes/base/resizable.css //>>css.theme: ../../themes/base/theme.css $.widget( "ui.resizable", $.ui.mouse, { version: "1.13.2", widgetEventPrefix: "resize", options: { alsoResize: false, animate: false, animateDuration: "slow", animateEasing: "swing", aspectRatio: false, autoHide: false, classes: { "ui-resizable-se": "ui-icon ui-icon-gripsmall-diagonal-se" }, containment: false, ghost: false, grid: false, handles: "e,s,se", helper: false, maxHeight: null, maxWidth: null, minHeight: 10, minWidth: 10, // See #7960 zIndex: 90, // Callbacks resize: null, start: null, stop: null }, _num: function( value ) { return parseFloat( value ) || 0; }, _isNumber: function( value ) { return !isNaN( parseFloat( value ) ); }, _hasScroll: function( el, a ) { if ( $( el ).css( "overflow" ) === "hidden" ) { return false; } var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop", has = false; if ( el[ scroll ] > 0 ) { return true; } // TODO: determine which cases actually cause this to happen // if the element doesn't have the scroll set, see if it's possible to // set the scroll try { el[ scroll ] = 1; has = ( el[ scroll ] > 0 ); el[ scroll ] = 0; } catch ( e ) { // `el` might be a string, then setting `scroll` will throw // an error in strict mode; ignore it. } return has; }, _create: function() { var margins, o = this.options, that = this; this._addClass( "ui-resizable" ); $.extend( this, { _aspectRatio: !!( o.aspectRatio ), aspectRatio: o.aspectRatio, originalElement: this.element, _proportionallyResizeElements: [], _helper: o.helper || o.ghost || o.animate ? o.helper || "ui-resizable-helper" : null } ); // Wrap the element if it cannot hold child nodes if ( this.element[ 0 ].nodeName.match( /^(canvas|textarea|input|select|button|img)$/i ) ) { this.element.wrap( $( "<div class='ui-wrapper'></div>" ).css( { overflow: "hidden", position: this.element.css( "position" ), width: this.element.outerWidth(), height: this.element.outerHeight(), top: this.element.css( "top" ), left: this.element.css( "left" ) } ) ); this.element = this.element.parent().data( "ui-resizable", this.element.resizable( "instance" ) ); this.elementIsWrapper = true; margins = { marginTop: this.originalElement.css( "marginTop" ), marginRight: this.originalElement.css( "marginRight" ), marginBottom: this.originalElement.css( "marginBottom" ), marginLeft: this.originalElement.css( "marginLeft" ) }; this.element.css( margins ); this.originalElement.css( "margin", 0 ); // support: Safari // Prevent Safari textarea resize this.originalResizeStyle = this.originalElement.css( "resize" ); this.originalElement.css( "resize", "none" ); this._proportionallyResizeElements.push( this.originalElement.css( { position: "static", zoom: 1, display: "block" } ) ); // Support: IE9 // avoid IE jump (hard set the margin) this.originalElement.css( margins ); this._proportionallyResize(); } this._setupHandles(); if ( o.autoHide ) { $( this.element ) .on( "mouseenter", function() { if ( o.disabled ) { return; } that._removeClass( "ui-resizable-autohide" ); that._handles.show(); } ) .on( "mouseleave", function() { if ( o.disabled ) { return; } if ( !that.resizing ) { that._addClass( "ui-resizable-autohide" ); that._handles.hide(); } } ); } this._mouseInit(); }, _destroy: function() { this._mouseDestroy(); this._addedHandles.remove(); var wrapper, _destroy = function( exp ) { $( exp ) .removeData( "resizable" ) .removeData( "ui-resizable" ) .off( ".resizable" ); }; // TODO: Unwrap at same DOM position if ( this.elementIsWrapper ) { _destroy( this.element ); wrapper = this.element; this.originalElement.css( { position: wrapper.css( "position" ), width: wrapper.outerWidth(), height: wrapper.outerHeight(), top: wrapper.css( "top" ), left: wrapper.css( "left" ) } ).insertAfter( wrapper ); wrapper.remove(); } this.originalElement.css( "resize", this.originalResizeStyle ); _destroy( this.originalElement ); return this; }, _setOption: function( key, value ) { this._super( key, value ); switch ( key ) { case "handles": this._removeHandles(); this._setupHandles(); break; case "aspectRatio": this._aspectRatio = !!value; break; default: break; } }, _setupHandles: function() { var o = this.options, handle, i, n, hname, axis, that = this; this.handles = o.handles || ( !$( ".ui-resizable-handle", this.element ).length ? "e,s,se" : { n: ".ui-resizable-n", e: ".ui-resizable-e", s: ".ui-resizable-s", w: ".ui-resizable-w", se: ".ui-resizable-se", sw: ".ui-resizable-sw", ne: ".ui-resizable-ne", nw: ".ui-resizable-nw" } ); this._handles = $(); this._addedHandles = $(); if ( this.handles.constructor === String ) { if ( this.handles === "all" ) { this.handles = "n,e,s,w,se,sw,ne,nw"; } n = this.handles.split( "," ); this.handles = {}; for ( i = 0; i < n.length; i++ ) { handle = String.prototype.trim.call( n[ i ] ); hname = "ui-resizable-" + handle; axis = $( "<div>" ); this._addClass( axis, "ui-resizable-handle " + hname ); axis.css( { zIndex: o.zIndex } ); this.handles[ handle ] = ".ui-resizable-" + handle; if ( !this.element.children( this.handles[ handle ] ).length ) { this.element.append( axis ); this._addedHandles = this._addedHandles.add( axis ); } } } this._renderAxis = function( target ) { var i, axis, padPos, padWrapper; target = target || this.element; for ( i in this.handles ) { if ( this.handles[ i ].constructor === String ) { this.handles[ i ] = this.element.children( this.handles[ i ] ).first().show(); } else if ( this.handles[ i ].jquery || this.handles[ i ].nodeType ) { this.handles[ i ] = $( this.handles[ i ] ); this._on( this.handles[ i ], { "mousedown": that._mouseDown } ); } if ( this.elementIsWrapper && this.originalElement[ 0 ] .nodeName .match( /^(textarea|input|select|button)$/i ) ) { axis = $( this.handles[ i ], this.element ); padWrapper = /sw|ne|nw|se|n|s/.test( i ) ? axis.outerHeight() : axis.outerWidth(); padPos = [ "padding", /ne|nw|n/.test( i ) ? "Top" : /se|sw|s/.test( i ) ? "Bottom" : /^e$/.test( i ) ? "Right" : "Left" ].join( "" ); target.css( padPos, padWrapper ); this._proportionallyResize(); } this._handles = this._handles.add( this.handles[ i ] ); } }; // TODO: make renderAxis a prototype function this._renderAxis( this.element ); this._handles = this._handles.add( this.element.find( ".ui-resizable-handle" ) ); this._handles.disableSelection(); this._handles.on( "mouseover", function() { if ( !that.resizing ) { if ( this.className ) { axis = this.className.match( /ui-resizable-(se|sw|ne|nw|n|e|s|w)/i ); } that.axis = axis && axis[ 1 ] ? axis[ 1 ] : "se"; } } ); if ( o.autoHide ) { this._handles.hide(); this._addClass( "ui-resizable-autohide" ); } }, _removeHandles: function() { this._addedHandles.remove(); }, _mouseCapture: function( event ) { var i, handle, capture = false; for ( i in this.handles ) { handle = $( this.handles[ i ] )[ 0 ]; if ( handle === event.target || $.contains( handle, event.target ) ) { capture = true; } } return !this.options.disabled && capture; }, _mouseStart: function( event ) { var curleft, curtop, cursor, o = this.options, el = this.element; this.resizing = true; this._renderProxy(); curleft = this._num( this.helper.css( "left" ) ); curtop = this._num( this.helper.css( "top" ) ); if ( o.containment ) { curleft += $( o.containment ).scrollLeft() || 0; curtop += $( o.containment ).scrollTop() || 0; } this.offset = this.helper.offset(); this.position = { left: curleft, top: curtop }; this.size = this._helper ? { width: this.helper.width(), height: this.helper.height() } : { width: el.width(), height: el.height() }; this.originalSize = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() }; this.sizeDiff = { width: el.outerWidth() - el.width(), height: el.outerHeight() - el.height() }; this.originalPosition = { left: curleft, top: curtop }; this.originalMousePosition = { left: event.pageX, top: event.pageY }; this.aspectRatio = ( typeof o.aspectRatio === "number" ) ? o.aspectRatio : ( ( this.originalSize.width / this.originalSize.height ) || 1 ); cursor = $( ".ui-resizable-" + this.axis ).css( "cursor" ); $( "body" ).css( "cursor", cursor === "auto" ? this.axis + "-resize" : cursor ); this._addClass( "ui-resizable-resizing" ); this._propagate( "start", event ); return true; }, _mouseDrag: function( event ) { var data, props, smp = this.originalMousePosition, a = this.axis, dx = ( event.pageX - smp.left ) || 0, dy = ( event.pageY - smp.top ) || 0, trigger = this._change[ a ]; this._updatePrevProperties(); if ( !trigger ) { return false; } data = trigger.apply( this, [ event, dx, dy ] ); this._updateVirtualBoundaries( event.shiftKey ); if ( this._aspectRatio || event.shiftKey ) { data = this._updateRatio( data, event ); } data = this._respectSize( data, event ); this._updateCache( data ); this._propagate( "resize", event ); props = this._applyChanges(); if ( !this._helper && this._proportionallyResizeElements.length ) { this._proportionallyResize(); } if ( !$.isEmptyObject( props ) ) { this._updatePrevProperties(); this._trigger( "resize", event, this.ui() ); this._applyChanges(); } return false; }, _mouseStop: function( event ) { this.resizing = false; var pr, ista, soffseth, soffsetw, s, left, top, o = this.options, that = this; if ( this._helper ) { pr = this._proportionallyResizeElements; ista = pr.length && ( /textarea/i ).test( pr[ 0 ].nodeName ); soffseth = ista && this._hasScroll( pr[ 0 ], "left" ) ? 0 : that.sizeDiff.height; soffsetw = ista ? 0 : that.sizeDiff.width; s = { width: ( that.helper.width() - soffsetw ), height: ( that.helper.height() - soffseth ) }; left = ( parseFloat( that.element.css( "left" ) ) + ( that.position.left - that.originalPosition.left ) ) || null; top = ( parseFloat( that.element.css( "top" ) ) + ( that.position.top - that.originalPosition.top ) ) || null; if ( !o.animate ) { this.element.css( $.extend( s, { top: top, left: left } ) ); } that.helper.height( that.size.height ); that.helper.width( that.size.width ); if ( this._helper && !o.animate ) { this._proportionallyResize(); } } $( "body" ).css( "cursor", "auto" ); this._removeClass( "ui-resizable-resizing" ); this._propagate( "stop", event ); if ( this._helper ) { this.helper.remove(); } return false; }, _updatePrevProperties: function() { this.prevPosition = { top: this.position.top, left: this.position.left }; this.prevSize = { width: this.size.width, height: this.size.height }; }, _applyChanges: function() { var props = {}; if ( this.position.top !== this.prevPosition.top ) { props.top = this.position.top + "px"; } if ( this.position.left !== this.prevPosition.left ) { props.left = this.position.left + "px"; } if ( this.size.width !== this.prevSize.width ) { props.width = this.size.width + "px"; } if ( this.size.height !== this.prevSize.height ) { props.height = this.size.height + "px"; } this.helper.css( props ); return props; }, _updateVirtualBoundaries: function( forceAspectRatio ) { var pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b, o = this.options; b = { minWidth: this._isNumber( o.minWidth ) ? o.minWidth : 0, maxWidth: this._isNumber( o.maxWidth ) ? o.maxWidth : Infinity, minHeight: this._isNumber( o.minHeight ) ? o.minHeight : 0, maxHeight: this._isNumber( o.maxHeight ) ? o.maxHeight : Infinity }; if ( this._aspectRatio || forceAspectRatio ) { pMinWidth = b.minHeight * this.aspectRatio; pMinHeight = b.minWidth / this.aspectRatio; pMaxWidth = b.maxHeight * this.aspectRatio; pMaxHeight = b.maxWidth / this.aspectRatio; if ( pMinWidth > b.minWidth ) { b.minWidth = pMinWidth; } if ( pMinHeight > b.minHeight ) { b.minHeight = pMinHeight; } if ( pMaxWidth < b.maxWidth ) { b.maxWidth = pMaxWidth; } if ( pMaxHeight < b.maxHeight ) { b.maxHeight = pMaxHeight; } } this._vBoundaries = b; }, _updateCache: function( data ) { this.offset = this.helper.offset(); if ( this._isNumber( data.left ) ) { this.position.left = data.left; } if ( this._isNumber( data.top ) ) { this.position.top = data.top; } if ( this._isNumber( data.height ) ) { this.size.height = data.height; } if ( this._isNumber( data.width ) ) { this.size.width = data.width; } }, _updateRatio: function( data ) { var cpos = this.position, csize = this.size, a = this.axis; if ( this._isNumber( data.height ) ) { data.width = ( data.height * this.aspectRatio ); } else if ( this._isNumber( data.width ) ) { data.height = ( data.width / this.aspectRatio ); } if ( a === "sw" ) { data.left = cpos.left + ( csize.width - data.width ); data.top = null; } if ( a === "nw" ) { data.top = cpos.top + ( csize.height - data.height ); data.left = cpos.left + ( csize.width - data.width ); } return data; }, _respectSize: function( data ) { var o = this._vBoundaries, a = this.axis, ismaxw = this._isNumber( data.width ) && o.maxWidth && ( o.maxWidth < data.width ), ismaxh = this._isNumber( data.height ) && o.maxHeight && ( o.maxHeight < data.height ), isminw = this._isNumber( data.width ) && o.minWidth && ( o.minWidth > data.width ), isminh = this._isNumber( data.height ) && o.minHeight && ( o.minHeight > data.height ), dw = this.originalPosition.left + this.originalSize.width, dh = this.originalPosition.top + this.originalSize.height, cw = /sw|nw|w/.test( a ), ch = /nw|ne|n/.test( a ); if ( isminw ) { data.width = o.minWidth; } if ( isminh ) { data.height = o.minHeight; } if ( ismaxw ) { data.width = o.maxWidth; } if ( ismaxh ) { data.height = o.maxHeight; } if ( isminw && cw ) { data.left = dw - o.minWidth; } if ( ismaxw && cw ) { data.left = dw - o.maxWidth; } if ( isminh && ch ) { data.top = dh - o.minHeight; } if ( ismaxh && ch ) { data.top = dh - o.maxHeight; } // Fixing jump error on top/left - bug #2330 if ( !data.width && !data.height && !data.left && data.top ) { data.top = null; } else if ( !data.width && !data.height && !data.top && data.left ) { data.left = null; } return data; }, _getPaddingPlusBorderDimensions: function( element ) { var i = 0, widths = [], borders = [ element.css( "borderTopWidth" ), element.css( "borderRightWidth" ), element.css( "borderBottomWidth" ), element.css( "borderLeftWidth" ) ], paddings = [ element.css( "paddingTop" ), element.css( "paddingRight" ), element.css( "paddingBottom" ), element.css( "paddingLeft" ) ]; for ( ; i < 4; i++ ) { widths[ i ] = ( parseFloat( borders[ i ] ) || 0 ); widths[ i ] += ( parseFloat( paddings[ i ] ) || 0 ); } return { height: widths[ 0 ] + widths[ 2 ], width: widths[ 1 ] + widths[ 3 ] }; }, _proportionallyResize: function() { if ( !this._proportionallyResizeElements.length ) { return; } var prel, i = 0, element = this.helper || this.element; for ( ; i < this._proportionallyResizeElements.length; i++ ) { prel = this._proportionallyResizeElements[ i ]; // TODO: Seems like a bug to cache this.outerDimensions // considering that we are in a loop. if ( !this.outerDimensions ) { this.outerDimensions = this._getPaddingPlusBorderDimensions( prel ); } prel.css( { height: ( element.height() - this.outerDimensions.height ) || 0, width: ( element.width() - this.outerDimensions.width ) || 0 } ); } }, _renderProxy: function() { var el = this.element, o = this.options; this.elementOffset = el.offset(); if ( this._helper ) { this.helper = this.helper || $( "<div></div>" ).css( { overflow: "hidden" } ); this._addClass( this.helper, this._helper ); this.helper.css( { width: this.element.outerWidth(), height: this.element.outerHeight(), position: "absolute", left: this.elementOffset.left + "px", top: this.elementOffset.top + "px", zIndex: ++o.zIndex //TODO: Don't modify option } ); this.helper .appendTo( "body" ) .disableSelection(); } else { this.helper = this.element; } }, _change: { e: function( event, dx ) { return { width: this.originalSize.width + dx }; }, w: function( event, dx ) { var cs = this.originalSize, sp = this.originalPosition; return { left: sp.left + dx, width: cs.width - dx }; }, n: function( event, dx, dy ) { var cs = this.originalSize, sp = this.originalPosition; return { top: sp.top + dy, height: cs.height - dy }; }, s: function( event, dx, dy ) { return { height: this.originalSize.height + dy }; }, se: function( event, dx, dy ) { return $.extend( this._change.s.apply( this, arguments ), this._change.e.apply( this, [ event, dx, dy ] ) ); }, sw: function( event, dx, dy ) { return $.extend( this._change.s.apply( this, arguments ), this._change.w.apply( this, [ event, dx, dy ] ) ); }, ne: function( event, dx, dy ) { return $.extend( this._change.n.apply( this, arguments ), this._change.e.apply( this, [ event, dx, dy ] ) ); }, nw: function( event, dx, dy ) { return $.extend( this._change.n.apply( this, arguments ), this._change.w.apply( this, [ event, dx, dy ] ) ); } }, _propagate: function( n, event ) { $.ui.plugin.call( this, n, [ event, this.ui() ] ); if ( n !== "resize" ) { this._trigger( n, event, this.ui() ); } }, plugins: {}, ui: function() { return { originalElement: this.originalElement, element: this.element, helper: this.helper, position: this.position, size: this.size, originalSize: this.originalSize, originalPosition: this.originalPosition }; } } ); /* * Resizable Extensions */ $.ui.plugin.add( "resizable", "animate", { stop: function( event ) { var that = $( this ).resizable( "instance" ), o = that.options, pr = that._proportionallyResizeElements, ista = pr.length && ( /textarea/i ).test( pr[ 0 ].nodeName ), soffseth = ista && that._hasScroll( pr[ 0 ], "left" ) ? 0 : that.sizeDiff.height, soffsetw = ista ? 0 : that.sizeDiff.width, style = { width: ( that.size.width - soffsetw ), height: ( that.size.height - soffseth ) }, left = ( parseFloat( that.element.css( "left" ) ) + ( that.position.left - that.originalPosition.left ) ) || null, top = ( parseFloat( that.element.css( "top" ) ) + ( that.position.top - that.originalPosition.top ) ) || null; that.element.animate( $.extend( style, top && left ? { top: top, left: left } : {} ), { duration: o.animateDuration, easing: o.animateEasing, step: function() { var data = { width: parseFloat( that.element.css( "width" ) ), height: parseFloat( that.element.css( "height" ) ), top: parseFloat( that.element.css( "top" ) ), left: parseFloat( that.element.css( "left" ) ) }; if ( pr && pr.length ) { $( pr[ 0 ] ).css( { width: data.width, height: data.height } ); } // Propagating resize, and updating values for each animation step that._updateCache( data ); that._propagate( "resize", event ); } } ); } } ); $.ui.plugin.add( "resizable", "containment", { start: function() { var element, p, co, ch, cw, width, height, that = $( this ).resizable( "instance" ), o = that.options, el = that.element, oc = o.containment, ce = ( oc instanceof $ ) ? oc.get( 0 ) : ( /parent/.test( oc ) ) ? el.parent().get( 0 ) : oc; if ( !ce ) { return; } that.containerElement = $( ce ); if ( /document/.test( oc ) || oc === document ) { that.containerOffset = { left: 0, top: 0 }; that.containerPosition = { left: 0, top: 0 }; that.parentData = { element: $( document ), left: 0, top: 0, width: $( document ).width(), height: $( document ).height() || document.body.parentNode.scrollHeight }; } else { element = $( ce ); p = []; $( [ "Top", "Right", "Left", "Bottom" ] ).each( function( i, name ) { p[ i ] = that._num( element.css( "padding" + name ) ); } ); that.containerOffset = element.offset(); that.containerPosition = element.position(); that.containerSize = { height: ( element.innerHeight() - p[ 3 ] ), width: ( element.innerWidth() - p[ 1 ] ) }; co = that.containerOffset; ch = that.containerSize.height; cw = that.containerSize.width; width = ( that._hasScroll( ce, "left" ) ? ce.scrollWidth : cw ); height = ( that._hasScroll( ce ) ? ce.scrollHeight : ch ); that.parentData = { element: ce, left: co.left, top: co.top, width: width, height: height }; } }, resize: function( event ) { var woset, hoset, isParent, isOffsetRelative, that = $( this ).resizable( "instance" ), o = that.options, co = that.containerOffset, cp = that.position, pRatio = that._aspectRatio || event.shiftKey, cop = { top: 0, left: 0 }, ce = that.containerElement, continueResize = true; if ( ce[ 0 ] !== document && ( /static/ ).test( ce.css( "position" ) ) ) { cop = co; } if ( cp.left < ( that._helper ? co.left : 0 ) ) { that.size.width = that.size.width + ( that._helper ? ( that.position.left - co.left ) : ( that.position.left - cop.left ) ); if ( pRatio ) { that.size.height = that.size.width / that.aspectRatio; continueResize = false; } that.position.left = o.helper ? co.left : 0; } if ( cp.top < ( that._helper ? co.top : 0 ) ) { that.size.height = that.size.height + ( that._helper ? ( that.position.top - co.top ) : that.position.top ); if ( pRatio ) { that.size.width = that.size.height * that.aspectRatio; continueResize = false; } that.position.top = that._helper ? co.top : 0; } isParent = that.containerElement.get( 0 ) === that.element.parent().get( 0 ); isOffsetRelative = /relative|absolute/.test( that.containerElement.css( "position" ) ); if ( isParent && isOffsetRelative ) { that.offset.left = that.parentData.left + that.position.left; that.offset.top = that.parentData.top + that.position.top; } else { that.offset.left = that.element.offset().left; that.offset.top = that.element.offset().top; } woset = Math.abs( that.sizeDiff.width + ( that._helper ? that.offset.left - cop.left : ( that.offset.left - co.left ) ) ); hoset = Math.abs( that.sizeDiff.height + ( that._helper ? that.offset.top - cop.top : ( that.offset.top - co.top ) ) ); if ( woset + that.size.width >= that.parentData.width ) { that.size.width = that.parentData.width - woset; if ( pRatio ) { that.size.height = that.size.width / that.aspectRatio; continueResize = false; } } if ( hoset + that.size.height >= that.parentData.height ) { that.size.height = that.parentData.height - hoset; if ( pRatio ) { that.size.width = that.size.height * that.aspectRatio; continueResize = false; } } if ( !continueResize ) { that.position.left = that.prevPosition.left; that.position.top = that.prevPosition.top; that.size.width = that.prevSize.width; that.size.height = that.prevSize.height; } }, stop: function() { var that = $( this ).resizable( "instance" ), o = that.options, co = that.containerOffset, cop = that.containerPosition, ce = that.containerElement, helper = $( that.helper ), ho = helper.offset(), w = helper.outerWidth() - that.sizeDiff.width, h = helper.outerHeight() - that.sizeDiff.height; if ( that._helper && !o.animate && ( /relative/ ).test( ce.css( "position" ) ) ) { $( this ).css( { left: ho.left - cop.left - co.left, width: w, height: h } ); } if ( that._helper && !o.animate && ( /static/ ).test( ce.css( "position" ) ) ) { $( this ).css( { left: ho.left - cop.left - co.left, width: w, height: h } ); } } } ); $.ui.plugin.add( "resizable", "alsoResize", { start: function() { var that = $( this ).resizable( "instance" ), o = that.options; $( o.alsoResize ).each( function() { var el = $( this ); el.data( "ui-resizable-alsoresize", { width: parseFloat( el.width() ), height: parseFloat( el.height() ), left: parseFloat( el.css( "left" ) ), top: parseFloat( el.css( "top" ) ) } ); } ); }, resize: function( event, ui ) { var that = $( this ).resizable( "instance" ), o = that.options, os = that.originalSize, op = that.originalPosition, delta = { height: ( that.size.height - os.height ) || 0, width: ( that.size.width - os.width ) || 0, top: ( that.position.top - op.top ) || 0, left: ( that.position.left - op.left ) || 0 }; $( o.alsoResize ).each( function() { var el = $( this ), start = $( this ).data( "ui-resizable-alsoresize" ), style = {}, css = el.parents( ui.originalElement[ 0 ] ).length ? [ "width", "height" ] : [ "width", "height", "top", "left" ]; $.each( css, function( i, prop ) { var sum = ( start[ prop ] || 0 ) + ( delta[ prop ] || 0 ); if ( sum && sum >= 0 ) { style[ prop ] = sum || null; } } ); el.css( style ); } ); }, stop: function() { $( this ).removeData( "ui-resizable-alsoresize" ); } } ); $.ui.plugin.add( "resizable", "ghost", { start: function() { var that = $( this ).resizable( "instance" ), cs = that.size; that.ghost = that.originalElement.clone(); that.ghost.css( { opacity: 0.25, display: "block", position: "relative", height: cs.height, width: cs.width, margin: 0, left: 0, top: 0 } ); that._addClass( that.ghost, "ui-resizable-ghost" ); // DEPRECATED // TODO: remove after 1.12 if ( $.uiBackCompat !== false && typeof that.options.ghost === "string" ) { // Ghost option that.ghost.addClass( this.options.ghost ); } that.ghost.appendTo( that.helper ); }, resize: function() { var that = $( this ).resizable( "instance" ); if ( that.ghost ) { that.ghost.css( { position: "relative", height: that.size.height, width: that.size.width } ); } }, stop: function() { var that = $( this ).resizable( "instance" ); if ( that.ghost && that.helper ) { that.helper.get( 0 ).removeChild( that.ghost.get( 0 ) ); } } } ); $.ui.plugin.add( "resizable", "grid", { resize: function() { var outerDimensions, that = $( this ).resizable( "instance" ), o = that.options, cs = that.size, os = that.originalSize, op = that.originalPosition, a = that.axis, grid = typeof o.grid === "number" ? [ o.grid, o.grid ] : o.grid, gridX = ( grid[ 0 ] || 1 ), gridY = ( grid[ 1 ] || 1 ), ox = Math.round( ( cs.width - os.width ) / gridX ) * gridX, oy = Math.round( ( cs.height - os.height ) / gridY ) * gridY, newWidth = os.width + ox, newHeight = os.height + oy, isMaxWidth = o.maxWidth && ( o.maxWidth < newWidth ), isMaxHeight = o.maxHeight && ( o.maxHeight < newHeight ), isMinWidth = o.minWidth && ( o.minWidth > newWidth ), isMinHeight = o.minHeight && ( o.minHeight > newHeight ); o.grid = grid; if ( isMinWidth ) { newWidth += gridX; } if ( isMinHeight ) { newHeight += gridY; } if ( isMaxWidth ) { newWidth -= gridX; } if ( isMaxHeight ) { newHeight -= gridY; } if ( /^(se|s|e)$/.test( a ) ) { that.size.width = newWidth; that.size.height = newHeight; } else if ( /^(ne)$/.test( a ) ) { that.size.width = newWidth; that.size.height = newHeight; that.position.top = op.top - oy; } else if ( /^(sw)$/.test( a ) ) { that.size.width = newWidth; that.size.height = newHeight; that.position.left = op.left - ox; } else { if ( newHeight - gridY <= 0 || newWidth - gridX <= 0 ) { outerDimensions = that._getPaddingPlusBorderDimensions( this ); } if ( newHeight - gridY > 0 ) { that.size.height = newHeight; that.position.top = op.top - oy; } else { newHeight = gridY - outerDimensions.height; that.size.height = newHeight; that.position.top = op.top + os.height - newHeight; } if ( newWidth - gridX > 0 ) { that.size.width = newWidth; that.position.left = op.left - ox; } else { newWidth = gridX - outerDimensions.width; that.size.width = newWidth; that.position.left = op.left + os.width - newWidth; } } } } ); var widgetsResizable = $.ui.resizable; /*! * jQuery UI Accordion 1.13.2 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license */ //>>label: Accordion //>>group: Widgets /* eslint-disable max-len */ //>>description: Displays collapsible content panels for presenting information in a limited amount of space. /* eslint-enable max-len */ //>>docs: http://api.jqueryui.com/accordion/ //>>demos: http://jqueryui.com/accordion/ //>>css.structure: ../../themes/base/core.css //>>css.structure: ../../themes/base/accordion.css //>>css.theme: ../../themes/base/theme.css var widgetsAccordion = $.widget( "ui.accordion", { version: "1.13.2", options: { active: 0, animate: {}, classes: { "ui-accordion-header": "ui-corner-top", "ui-accordion-header-collapsed": "ui-corner-all", "ui-accordion-content": "ui-corner-bottom" }, collapsible: false, event: "click", header: function( elem ) { return elem.find( "> li > :first-child" ).add( elem.find( "> :not(li)" ).even() ); }, heightStyle: "auto", icons: { activeHeader: "ui-icon-triangle-1-s", header: "ui-icon-triangle-1-e" }, // Callbacks activate: null, beforeActivate: null }, hideProps: { borderTopWidth: "hide", borderBottomWidth: "hide", paddingTop: "hide", paddingBottom: "hide", height: "hide" }, showProps: { borderTopWidth: "show", borderBottomWidth: "show", paddingTop: "show", paddingBottom: "show", height: "show" }, _create: function() { var options = this.options; this.prevShow = this.prevHide = $(); this._addClass( "ui-accordion", "ui-widget ui-helper-reset" ); this.element.attr( "role", "tablist" ); // Don't allow collapsible: false and active: false / null if ( !options.collapsible && ( options.active === false || options.active == null ) ) { options.active = 0; } this._processPanels(); // handle negative values if ( options.active < 0 ) { options.active += this.headers.length; } this._refresh(); }, _getCreateEventData: function() { return { header: this.active, panel: !this.active.length ? $() : this.active.next() }; }, _createIcons: function() { var icon, children, icons = this.options.icons; if ( icons ) { icon = $( "<span>" ); this._addClass( icon, "ui-accordion-header-icon", "ui-icon " + icons.header ); icon.prependTo( this.headers ); children = this.active.children( ".ui-accordion-header-icon" ); this._removeClass( children, icons.header ) ._addClass( children, null, icons.activeHeader ) ._addClass( this.headers, "ui-accordion-icons" ); } }, _destroyIcons: function() { this._removeClass( this.headers, "ui-accordion-icons" ); this.headers.children( ".ui-accordion-header-icon" ).remove(); }, _destroy: function() { var contents; // Clean up main element this.element.removeAttr( "role" ); // Clean up headers this.headers .removeAttr( "role aria-expanded aria-selected aria-controls tabIndex" ) .removeUniqueId(); this._destroyIcons(); // Clean up content panels contents = this.headers.next() .css( "display", "" ) .removeAttr( "role aria-hidden aria-labelledby" ) .removeUniqueId(); if ( this.options.heightStyle !== "content" ) { contents.css( "height", "" ); } }, _setOption: function( key, value ) { if ( key === "active" ) { // _activate() will handle invalid values and update this.options this._activate( value ); return; } if ( key === "event" ) { if ( this.options.event ) { this._off( this.headers, this.options.event ); } this._setupEvents( value ); } this._super( key, value ); // Setting collapsible: false while collapsed; open first panel if ( key === "collapsible" && !value && this.options.active === false ) { this._activate( 0 ); } if ( key === "icons" ) { this._destroyIcons(); if ( value ) { this._createIcons(); } } }, _setOptionDisabled: function( value ) { this._super( value ); this.element.attr( "aria-disabled", value ); // Support: IE8 Only // #5332 / #6059 - opacity doesn't cascade to positioned elements in IE // so we need to add the disabled class to the headers and panels this._toggleClass( null, "ui-state-disabled", !!value ); this._toggleClass( this.headers.add( this.headers.next() ), null, "ui-state-disabled", !!value ); }, _keydown: function( event ) { if ( event.altKey || event.ctrlKey ) { return; } var keyCode = $.ui.keyCode, length = this.headers.length, currentIndex = this.headers.index( event.target ), toFocus = false; switch ( event.keyCode ) { case keyCode.RIGHT: case keyCode.DOWN: toFocus = this.headers[ ( currentIndex + 1 ) % length ]; break; case keyCode.LEFT: case keyCode.UP: toFocus = this.headers[ ( currentIndex - 1 + length ) % length ]; break; case keyCode.SPACE: case keyCode.ENTER: this._eventHandler( event ); break; case keyCode.HOME: toFocus = this.headers[ 0 ]; break; case keyCode.END: toFocus = this.headers[ length - 1 ]; break; } if ( toFocus ) { $( event.target ).attr( "tabIndex", -1 ); $( toFocus ).attr( "tabIndex", 0 ); $( toFocus ).trigger( "focus" ); event.preventDefault(); } }, _panelKeyDown: function( event ) { if ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) { $( event.currentTarget ).prev().trigger( "focus" ); } }, refresh: function() { var options = this.options; this._processPanels(); // Was collapsed or no panel if ( ( options.active === false && options.collapsible === true ) || !this.headers.length ) { options.active = false; this.active = $(); // active false only when collapsible is true } else if ( options.active === false ) { this._activate( 0 ); // was active, but active panel is gone } else if ( this.active.length && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) { // all remaining panel are disabled if ( this.headers.length === this.headers.find( ".ui-state-disabled" ).length ) { options.active = false; this.active = $(); // activate previous panel } else { this._activate( Math.max( 0, options.active - 1 ) ); } // was active, active panel still exists } else { // make sure active index is correct options.active = this.headers.index( this.active ); } this._destroyIcons(); this._refresh(); }, _processPanels: function() { var prevHeaders = this.headers, prevPanels = this.panels; if ( typeof this.options.header === "function" ) { this.headers = this.options.header( this.element ); } else { this.headers = this.element.find( this.options.header ); } this._addClass( this.headers, "ui-accordion-header ui-accordion-header-collapsed", "ui-state-default" ); this.panels = this.headers.next().filter( ":not(.ui-accordion-content-active)" ).hide(); this._addClass( this.panels, "ui-accordion-content", "ui-helper-reset ui-widget-content" ); // Avoid memory leaks (#10056) if ( prevPanels ) { this._off( prevHeaders.not( this.headers ) ); this._off( prevPanels.not( this.panels ) ); } }, _refresh: function() { var maxHeight, options = this.options, heightStyle = options.heightStyle, parent = this.element.parent(); this.active = this._findActive( options.active ); this._addClass( this.active, "ui-accordion-header-active", "ui-state-active" ) ._removeClass( this.active, "ui-accordion-header-collapsed" ); this._addClass( this.active.next(), "ui-accordion-content-active" ); this.active.next().show(); this.headers .attr( "role", "tab" ) .each( function() { var header = $( this ), headerId = header.uniqueId().attr( "id" ), panel = header.next(), panelId = panel.uniqueId().attr( "id" ); header.attr( "aria-controls", panelId ); panel.attr( "aria-labelledby", headerId ); } ) .next() .attr( "role", "tabpanel" ); this.headers .not( this.active ) .attr( { "aria-selected": "false", "aria-expanded": "false", tabIndex: -1 } ) .next() .attr( { "aria-hidden": "true" } ) .hide(); // Make sure at least one header is in the tab order if ( !this.active.length ) { this.headers.eq( 0 ).attr( "tabIndex", 0 ); } else { this.active.attr( { "aria-selected": "true", "aria-expanded": "true", tabIndex: 0 } ) .next() .attr( { "aria-hidden": "false" } ); } this._createIcons(); this._setupEvents( options.event ); if ( heightStyle === "fill" ) { maxHeight = parent.height(); this.element.siblings( ":visible" ).each( function() { var elem = $( this ), position = elem.css( "position" ); if ( position === "absolute" || position === "fixed" ) { return; } maxHeight -= elem.outerHeight( true ); } ); this.headers.each( function() { maxHeight -= $( this ).outerHeight( true ); } ); this.headers.next() .each( function() { $( this ).height( Math.max( 0, maxHeight - $( this ).innerHeight() + $( this ).height() ) ); } ) .css( "overflow", "auto" ); } else if ( heightStyle === "auto" ) { maxHeight = 0; this.headers.next() .each( function() { var isVisible = $( this ).is( ":visible" ); if ( !isVisible ) { $( this ).show(); } maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() ); if ( !isVisible ) { $( this ).hide(); } } ) .height( maxHeight ); } }, _activate: function( index ) { var active = this._findActive( index )[ 0 ]; // Trying to activate the already active panel if ( active === this.active[ 0 ] ) { return; } // Trying to collapse, simulate a click on the currently active header active = active || this.active[ 0 ]; this._eventHandler( { target: active, currentTarget: active, preventDefault: $.noop } ); }, _findActive: function( selector ) { return typeof selector === "number" ? this.headers.eq( selector ) : $(); }, _setupEvents: function( event ) { var events = { keydown: "_keydown" }; if ( event ) { $.each( event.split( " " ), function( index, eventName ) { events[ eventName ] = "_eventHandler"; } ); } this._off( this.headers.add( this.headers.next() ) ); this._on( this.headers, events ); this._on( this.headers.next(), { keydown: "_panelKeyDown" } ); this._hoverable( this.headers ); this._focusable( this.headers ); }, _eventHandler: function( event ) { var activeChildren, clickedChildren, options = this.options, active = this.active, clicked = $( event.currentTarget ), clickedIsActive = clicked[ 0 ] === active[ 0 ], collapsing = clickedIsActive && options.collapsible, toShow = collapsing ? $() : clicked.next(), toHide = active.next(), eventData = { oldHeader: active, oldPanel: toHide, newHeader: collapsing ? $() : clicked, newPanel: toShow }; event.preventDefault(); if ( // click on active header, but not collapsible ( clickedIsActive && !options.collapsible ) || // allow canceling activation ( this._trigger( "beforeActivate", event, eventData ) === false ) ) { return; } options.active = collapsing ? false : this.headers.index( clicked ); // When the call to ._toggle() comes after the class changes // it causes a very odd bug in IE 8 (see #6720) this.active = clickedIsActive ? $() : clicked; this._toggle( eventData ); // Switch classes // corner classes on the previously active header stay after the animation this._removeClass( active, "ui-accordion-header-active", "ui-state-active" ); if ( options.icons ) { activeChildren = active.children( ".ui-accordion-header-icon" ); this._removeClass( activeChildren, null, options.icons.activeHeader ) ._addClass( activeChildren, null, options.icons.header ); } if ( !clickedIsActive ) { this._removeClass( clicked, "ui-accordion-header-collapsed" ) ._addClass( clicked, "ui-accordion-header-active", "ui-state-active" ); if ( options.icons ) { clickedChildren = clicked.children( ".ui-accordion-header-icon" ); this._removeClass( clickedChildren, null, options.icons.header ) ._addClass( clickedChildren, null, options.icons.activeHeader ); } this._addClass( clicked.next(), "ui-accordion-content-active" ); } }, _toggle: function( data ) { var toShow = data.newPanel, toHide = this.prevShow.length ? this.prevShow : data.oldPanel; // Handle activating a panel during the animation for another activation this.prevShow.add( this.prevHide ).stop( true, true ); this.prevShow = toShow; this.prevHide = toHide; if ( this.options.animate ) { this._animate( toShow, toHide, data ); } else { toHide.hide(); toShow.show(); this._toggleComplete( data ); } toHide.attr( { "aria-hidden": "true" } ); toHide.prev().attr( { "aria-selected": "false", "aria-expanded": "false" } ); // if we're switching panels, remove the old header from the tab order // if we're opening from collapsed state, remove the previous header from the tab order // if we're collapsing, then keep the collapsing header in the tab order if ( toShow.length && toHide.length ) { toHide.prev().attr( { "tabIndex": -1, "aria-expanded": "false" } ); } else if ( toShow.length ) { this.headers.filter( function() { return parseInt( $( this ).attr( "tabIndex" ), 10 ) === 0; } ) .attr( "tabIndex", -1 ); } toShow .attr( "aria-hidden", "false" ) .prev() .attr( { "aria-selected": "true", "aria-expanded": "true", tabIndex: 0 } ); }, _animate: function( toShow, toHide, data ) { var total, easing, duration, that = this, adjust = 0, boxSizing = toShow.css( "box-sizing" ), down = toShow.length && ( !toHide.length || ( toShow.index() < toHide.index() ) ), animate = this.options.animate || {}, options = down && animate.down || animate, complete = function() { that._toggleComplete( data ); }; if ( typeof options === "number" ) { duration = options; } if ( typeof options === "string" ) { easing = options; } // fall back from options to animation in case of partial down settings easing = easing || options.easing || animate.easing; duration = duration || options.duration || animate.duration; if ( !toHide.length ) { return toShow.animate( this.showProps, duration, easing, complete ); } if ( !toShow.length ) { return toHide.animate( this.hideProps, duration, easing, complete ); } total = toShow.show().outerHeight(); toHide.animate( this.hideProps, { duration: duration, easing: easing, step: function( now, fx ) { fx.now = Math.round( now ); } } ); toShow .hide() .animate( this.showProps, { duration: duration, easing: easing, complete: complete, step: function( now, fx ) { fx.now = Math.round( now ); if ( fx.prop !== "height" ) { if ( boxSizing === "content-box" ) { adjust += fx.now; } } else if ( that.options.heightStyle !== "content" ) { fx.now = Math.round( total - toHide.outerHeight() - adjust ); adjust = 0; } } } ); }, _toggleComplete: function( data ) { var toHide = data.oldPanel, prev = toHide.prev(); this._removeClass( toHide, "ui-accordion-content-active" ); this._removeClass( prev, "ui-accordion-header-active" ) ._addClass( prev, "ui-accordion-header-collapsed" ); // Work around for rendering bug in IE (#5421) if ( toHide.length ) { toHide.parent()[ 0 ].className = toHide.parent()[ 0 ].className; } this._trigger( "activate", null, data ); } } ); /*! * jQuery UI Controlgroup 1.13.2 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license */ //>>label: Controlgroup //>>group: Widgets //>>description: Visually groups form control widgets //>>docs: http://api.jqueryui.com/controlgroup/ //>>demos: http://jqueryui.com/controlgroup/ //>>css.structure: ../../themes/base/core.css //>>css.structure: ../../themes/base/controlgroup.css //>>css.theme: ../../themes/base/theme.css var controlgroupCornerRegex = /ui-corner-([a-z]){2,6}/g; var widgetsControlgroup = $.widget( "ui.controlgroup", { version: "1.13.2", defaultElement: "<div>", options: { direction: "horizontal", disabled: null, onlyVisible: true, items: { "button": "input[type=button], input[type=submit], input[type=reset], button, a", "controlgroupLabel": ".ui-controlgroup-label", "checkboxradio": "input[type='checkbox'], input[type='radio']", "selectmenu": "select", "spinner": ".ui-spinner-input" } }, _create: function() { this._enhance(); }, // To support the enhanced option in jQuery Mobile, we isolate DOM manipulation _enhance: function() { this.element.attr( "role", "toolbar" ); this.refresh(); }, _destroy: function() { this._callChildMethod( "destroy" ); this.childWidgets.removeData( "ui-controlgroup-data" ); this.element.removeAttr( "role" ); if ( this.options.items.controlgroupLabel ) { this.element .find( this.options.items.controlgroupLabel ) .find( ".ui-controlgroup-label-contents" ) .contents().unwrap(); } }, _initWidgets: function() { var that = this, childWidgets = []; // First we iterate over each of the items options $.each( this.options.items, function( widget, selector ) { var labels; var options = {}; // Make sure the widget has a selector set if ( !selector ) { return; } if ( widget === "controlgroupLabel" ) { labels = that.element.find( selector ); labels.each( function() { var element = $( this ); if ( element.children( ".ui-controlgroup-label-contents" ).length ) { return; } element.contents() .wrapAll( "<span class='ui-controlgroup-label-contents'></span>" ); } ); that._addClass( labels, null, "ui-widget ui-widget-content ui-state-default" ); childWidgets = childWidgets.concat( labels.get() ); return; } // Make sure the widget actually exists if ( !$.fn[ widget ] ) { return; } // We assume everything is in the middle to start because we can't determine // first / last elements until all enhancments are done. if ( that[ "_" + widget + "Options" ] ) { options = that[ "_" + widget + "Options" ]( "middle" ); } else { options = { classes: {} }; } // Find instances of this widget inside controlgroup and init them that.element .find( selector ) .each( function() { var element = $( this ); var instance = element[ widget ]( "instance" ); // We need to clone the default options for this type of widget to avoid // polluting the variable options which has a wider scope than a single widget. var instanceOptions = $.widget.extend( {}, options ); // If the button is the child of a spinner ignore it // TODO: Find a more generic solution if ( widget === "button" && element.parent( ".ui-spinner" ).length ) { return; } // Create the widget if it doesn't exist if ( !instance ) { instance = element[ widget ]()[ widget ]( "instance" ); } if ( instance ) { instanceOptions.classes = that._resolveClassesValues( instanceOptions.classes, instance ); } element[ widget ]( instanceOptions ); // Store an instance of the controlgroup to be able to reference // from the outermost element for changing options and refresh var widgetElement = element[ widget ]( "widget" ); $.data( widgetElement[ 0 ], "ui-controlgroup-data", instance ? instance : element[ widget ]( "instance" ) ); childWidgets.push( widgetElement[ 0 ] ); } ); } ); this.childWidgets = $( $.uniqueSort( childWidgets ) ); this._addClass( this.childWidgets, "ui-controlgroup-item" ); }, _callChildMethod: function( method ) { this.childWidgets.each( function() { var element = $( this ), data = element.data( "ui-controlgroup-data" ); if ( data && data[ method ] ) { data[ method ](); } } ); }, _updateCornerClass: function( element, position ) { var remove = "ui-corner-top ui-corner-bottom ui-corner-left ui-corner-right ui-corner-all"; var add = this._buildSimpleOptions( position, "label" ).classes.label; this._removeClass( element, null, remove ); this._addClass( element, null, add ); }, _buildSimpleOptions: function( position, key ) { var direction = this.options.direction === "vertical"; var result = { classes: {} }; result.classes[ key ] = { "middle": "", "first": "ui-corner-" + ( direction ? "top" : "left" ), "last": "ui-corner-" + ( direction ? "bottom" : "right" ), "only": "ui-corner-all" }[ position ]; return result; }, _spinnerOptions: function( position ) { var options = this._buildSimpleOptions( position, "ui-spinner" ); options.classes[ "ui-spinner-up" ] = ""; options.classes[ "ui-spinner-down" ] = ""; return options; }, _buttonOptions: function( position ) { return this._buildSimpleOptions( position, "ui-button" ); }, _checkboxradioOptions: function( position ) { return this._buildSimpleOptions( position, "ui-checkboxradio-label" ); }, _selectmenuOptions: function( position ) { var direction = this.options.direction === "vertical"; return { width: direction ? "auto" : false, classes: { middle: { "ui-selectmenu-button-open": "", "ui-selectmenu-button-closed": "" }, first: { "ui-selectmenu-button-open": "ui-corner-" + ( direction ? "top" : "tl" ), "ui-selectmenu-button-closed": "ui-corner-" + ( direction ? "top" : "left" ) }, last: { "ui-selectmenu-button-open": direction ? "" : "ui-corner-tr", "ui-selectmenu-button-closed": "ui-corner-" + ( direction ? "bottom" : "right" ) }, only: { "ui-selectmenu-button-open": "ui-corner-top", "ui-selectmenu-button-closed": "ui-corner-all" } }[ position ] }; }, _resolveClassesValues: function( classes, instance ) { var result = {}; $.each( classes, function( key ) { var current = instance.options.classes[ key ] || ""; current = String.prototype.trim.call( current.replace( controlgroupCornerRegex, "" ) ); result[ key ] = ( current + " " + classes[ key ] ).replace( /\s+/g, " " ); } ); return result; }, _setOption: function( key, value ) { if ( key === "direction" ) { this._removeClass( "ui-controlgroup-" + this.options.direction ); } this._super( key, value ); if ( key === "disabled" ) { this._callChildMethod( value ? "disable" : "enable" ); return; } this.refresh(); }, refresh: function() { var children, that = this; this._addClass( "ui-controlgroup ui-controlgroup-" + this.options.direction ); if ( this.options.direction === "horizontal" ) { this._addClass( null, "ui-helper-clearfix" ); } this._initWidgets(); children = this.childWidgets; // We filter here because we need to track all childWidgets not just the visible ones if ( this.options.onlyVisible ) { children = children.filter( ":visible" ); } if ( children.length ) { // We do this last because we need to make sure all enhancment is done // before determining first and last $.each( [ "first", "last" ], function( index, value ) { var instance = children[ value ]().data( "ui-controlgroup-data" ); if ( instance && that[ "_" + instance.widgetName + "Options" ] ) { var options = that[ "_" + instance.widgetName + "Options" ]( children.length === 1 ? "only" : value ); options.classes = that._resolveClassesValues( options.classes, instance ); instance.element[ instance.widgetName ]( options ); } else { that._updateCornerClass( children[ value ](), value ); } } ); // Finally call the refresh method on each of the child widgets. this._callChildMethod( "refresh" ); } } } ); /*! * jQuery UI Checkboxradio 1.13.2 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license */ //>>label: Checkboxradio //>>group: Widgets //>>description: Enhances a form with multiple themeable checkboxes or radio buttons. //>>docs: http://api.jqueryui.com/checkboxradio/ //>>demos: http://jqueryui.com/checkboxradio/ //>>css.structure: ../../themes/base/core.css //>>css.structure: ../../themes/base/button.css //>>css.structure: ../../themes/base/checkboxradio.css //>>css.theme: ../../themes/base/theme.css $.widget( "ui.checkboxradio", [ $.ui.formResetMixin, { version: "1.13.2", options: { disabled: null, label: null, icon: true, classes: { "ui-checkboxradio-label": "ui-corner-all", "ui-checkboxradio-icon": "ui-corner-all" } }, _getCreateOptions: function() { var disabled, labels, labelContents; var options = this._super() || {}; // We read the type here, because it makes more sense to throw a element type error first, // rather then the error for lack of a label. Often if its the wrong type, it // won't have a label (e.g. calling on a div, btn, etc) this._readType(); labels = this.element.labels(); // If there are multiple labels, use the last one this.label = $( labels[ labels.length - 1 ] ); if ( !this.label.length ) { $.error( "No label found for checkboxradio widget" ); } this.originalLabel = ""; // We need to get the label text but this may also need to make sure it does not contain the // input itself. // The label contents could be text, html, or a mix. We wrap all elements // and read the wrapper's `innerHTML` to get a string representation of // the label, without the input as part of it. labelContents = this.label.contents().not( this.element[ 0 ] ); if ( labelContents.length ) { this.originalLabel += labelContents .clone() .wrapAll( "<div></div>" ) .parent() .html(); } // Set the label option if we found label text if ( this.originalLabel ) { options.label = this.originalLabel; } disabled = this.element[ 0 ].disabled; if ( disabled != null ) { options.disabled = disabled; } return options; }, _create: function() { var checked = this.element[ 0 ].checked; this._bindFormResetHandler(); if ( this.options.disabled == null ) { this.options.disabled = this.element[ 0 ].disabled; } this._setOption( "disabled", this.options.disabled ); this._addClass( "ui-checkboxradio", "ui-helper-hidden-accessible" ); this._addClass( this.label, "ui-checkboxradio-label", "ui-button ui-widget" ); if ( this.type === "radio" ) { this._addClass( this.label, "ui-checkboxradio-radio-label" ); } if ( this.options.label && this.options.label !== this.originalLabel ) { this._updateLabel(); } else if ( this.originalLabel ) { this.options.label = this.originalLabel; } this._enhance(); if ( checked ) { this._addClass( this.label, "ui-checkboxradio-checked", "ui-state-active" ); } this._on( { change: "_toggleClasses", focus: function() { this._addClass( this.label, null, "ui-state-focus ui-visual-focus" ); }, blur: function() { this._removeClass( this.label, null, "ui-state-focus ui-visual-focus" ); } } ); }, _readType: function() { var nodeName = this.element[ 0 ].nodeName.toLowerCase(); this.type = this.element[ 0 ].type; if ( nodeName !== "input" || !/radio|checkbox/.test( this.type ) ) { $.error( "Can't create checkboxradio on element.nodeName=" + nodeName + " and element.type=" + this.type ); } }, // Support jQuery Mobile enhanced option _enhance: function() { this._updateIcon( this.element[ 0 ].checked ); }, widget: function() { return this.label; }, _getRadioGroup: function() { var group; var name = this.element[ 0 ].name; var nameSelector = "input[name='" + $.escapeSelector( name ) + "']"; if ( !name ) { return $( [] ); } if ( this.form.length ) { group = $( this.form[ 0 ].elements ).filter( nameSelector ); } else { // Not inside a form, check all inputs that also are not inside a form group = $( nameSelector ).filter( function() { return $( this )._form().length === 0; } ); } return group.not( this.element ); }, _toggleClasses: function() { var checked = this.element[ 0 ].checked; this._toggleClass( this.label, "ui-checkboxradio-checked", "ui-state-active", checked ); if ( this.options.icon && this.type === "checkbox" ) { this._toggleClass( this.icon, null, "ui-icon-check ui-state-checked", checked ) ._toggleClass( this.icon, null, "ui-icon-blank", !checked ); } if ( this.type === "radio" ) { this._getRadioGroup() .each( function() { var instance = $( this ).checkboxradio( "instance" ); if ( instance ) { instance._removeClass( instance.label, "ui-checkboxradio-checked", "ui-state-active" ); } } ); } }, _destroy: function() { this._unbindFormResetHandler(); if ( this.icon ) { this.icon.remove(); this.iconSpace.remove(); } }, _setOption: function( key, value ) { // We don't allow the value to be set to nothing if ( key === "label" && !value ) { return; } this._super( key, value ); if ( key === "disabled" ) { this._toggleClass( this.label, null, "ui-state-disabled", value ); this.element[ 0 ].disabled = value; // Don't refresh when setting disabled return; } this.refresh(); }, _updateIcon: function( checked ) { var toAdd = "ui-icon ui-icon-background "; if ( this.options.icon ) { if ( !this.icon ) { this.icon = $( "<span>" ); this.iconSpace = $( "<span> </span>" ); this._addClass( this.iconSpace, "ui-checkboxradio-icon-space" ); } if ( this.type === "checkbox" ) { toAdd += checked ? "ui-icon-check ui-state-checked" : "ui-icon-blank"; this._removeClass( this.icon, null, checked ? "ui-icon-blank" : "ui-icon-check" ); } else { toAdd += "ui-icon-blank"; } this._addClass( this.icon, "ui-checkboxradio-icon", toAdd ); if ( !checked ) { this._removeClass( this.icon, null, "ui-icon-check ui-state-checked" ); } this.icon.prependTo( this.label ).after( this.iconSpace ); } else if ( this.icon !== undefined ) { this.icon.remove(); this.iconSpace.remove(); delete this.icon; } }, _updateLabel: function() { // Remove the contents of the label ( minus the icon, icon space, and input ) var contents = this.label.contents().not( this.element[ 0 ] ); if ( this.icon ) { contents = contents.not( this.icon[ 0 ] ); } if ( this.iconSpace ) { contents = contents.not( this.iconSpace[ 0 ] ); } contents.remove(); this.label.append( this.options.label ); }, refresh: function() { var checked = this.element[ 0 ].checked, isDisabled = this.element[ 0 ].disabled; this._updateIcon( checked ); this._toggleClass( this.label, "ui-checkboxradio-checked", "ui-state-active", checked ); if ( this.options.label !== null ) { this._updateLabel(); } if ( isDisabled !== this.options.disabled ) { this._setOptions( { "disabled": isDisabled } ); } } } ] ); var widgetsCheckboxradio = $.ui.checkboxradio; /*! * jQuery UI Button 1.13.2 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license */ //>>label: Button //>>group: Widgets //>>description: Enhances a form with themeable buttons. //>>docs: http://api.jqueryui.com/button/ //>>demos: http://jqueryui.com/button/ //>>css.structure: ../../themes/base/core.css //>>css.structure: ../../themes/base/button.css //>>css.theme: ../../themes/base/theme.css $.widget( "ui.button", { version: "1.13.2", defaultElement: "<button>", options: { classes: { "ui-button": "ui-corner-all" }, disabled: null, icon: null, iconPosition: "beginning", label: null, showLabel: true }, _getCreateOptions: function() { var disabled, // This is to support cases like in jQuery Mobile where the base widget does have // an implementation of _getCreateOptions options = this._super() || {}; this.isInput = this.element.is( "input" ); disabled = this.element[ 0 ].disabled; if ( disabled != null ) { options.disabled = disabled; } this.originalLabel = this.isInput ? this.element.val() : this.element.html(); if ( this.originalLabel ) { options.label = this.originalLabel; } return options; }, _create: function() { if ( !this.option.showLabel & !this.options.icon ) { this.options.showLabel = true; } // We have to check the option again here even though we did in _getCreateOptions, // because null may have been passed on init which would override what was set in // _getCreateOptions if ( this.options.disabled == null ) { this.options.disabled = this.element[ 0 ].disabled || false; } this.hasTitle = !!this.element.attr( "title" ); // Check to see if the label needs to be set or if its already correct if ( this.options.label && this.options.label !== this.originalLabel ) { if ( this.isInput ) { this.element.val( this.options.label ); } else { this.element.html( this.options.label ); } } this._addClass( "ui-button", "ui-widget" ); this._setOption( "disabled", this.options.disabled ); this._enhance(); if ( this.element.is( "a" ) ) { this._on( { "keyup": function( event ) { if ( event.keyCode === $.ui.keyCode.SPACE ) { event.preventDefault(); // Support: PhantomJS <= 1.9, IE 8 Only // If a native click is available use it so we actually cause navigation // otherwise just trigger a click event if ( this.element[ 0 ].click ) { this.element[ 0 ].click(); } else { this.element.trigger( "click" ); } } } } ); } }, _enhance: function() { if ( !this.element.is( "button" ) ) { this.element.attr( "role", "button" ); } if ( this.options.icon ) { this._updateIcon( "icon", this.options.icon ); this._updateTooltip(); } }, _updateTooltip: function() { this.title = this.element.attr( "title" ); if ( !this.options.showLabel && !this.title ) { this.element.attr( "title", this.options.label ); } }, _updateIcon: function( option, value ) { var icon = option !== "iconPosition", position = icon ? this.options.iconPosition : value, displayBlock = position === "top" || position === "bottom"; // Create icon if ( !this.icon ) { this.icon = $( "<span>" ); this._addClass( this.icon, "ui-button-icon", "ui-icon" ); if ( !this.options.showLabel ) { this._addClass( "ui-button-icon-only" ); } } else if ( icon ) { // If we are updating the icon remove the old icon class this._removeClass( this.icon, null, this.options.icon ); } // If we are updating the icon add the new icon class if ( icon ) { this._addClass( this.icon, null, value ); } this._attachIcon( position ); // If the icon is on top or bottom we need to add the ui-widget-icon-block class and remove // the iconSpace if there is one. if ( displayBlock ) { this._addClass( this.icon, null, "ui-widget-icon-block" ); if ( this.iconSpace ) { this.iconSpace.remove(); } } else { // Position is beginning or end so remove the ui-widget-icon-block class and add the // space if it does not exist if ( !this.iconSpace ) { this.iconSpace = $( "<span> </span>" ); this._addClass( this.iconSpace, "ui-button-icon-space" ); } this._removeClass( this.icon, null, "ui-wiget-icon-block" ); this._attachIconSpace( position ); } }, _destroy: function() { this.element.removeAttr( "role" ); if ( this.icon ) { this.icon.remove(); } if ( this.iconSpace ) { this.iconSpace.remove(); } if ( !this.hasTitle ) { this.element.removeAttr( "title" ); } }, _attachIconSpace: function( iconPosition ) { this.icon[ /^(?:end|bottom)/.test( iconPosition ) ? "before" : "after" ]( this.iconSpace ); }, _attachIcon: function( iconPosition ) { this.element[ /^(?:end|bottom)/.test( iconPosition ) ? "append" : "prepend" ]( this.icon ); }, _setOptions: function( options ) { var newShowLabel = options.showLabel === undefined ? this.options.showLabel : options.showLabel, newIcon = options.icon === undefined ? this.options.icon : options.icon; if ( !newShowLabel && !newIcon ) { options.showLabel = true; } this._super( options ); }, _setOption: function( key, value ) { if ( key === "icon" ) { if ( value ) { this._updateIcon( key, value ); } else if ( this.icon ) { this.icon.remove(); if ( this.iconSpace ) { this.iconSpace.remove(); } } } if ( key === "iconPosition" ) { this._updateIcon( key, value ); } // Make sure we can't end up with a button that has neither text nor icon if ( key === "showLabel" ) { this._toggleClass( "ui-button-icon-only", null, !value ); this._updateTooltip(); } if ( key === "label" ) { if ( this.isInput ) { this.element.val( value ); } else { // If there is an icon, append it, else nothing then append the value // this avoids removal of the icon when setting label text this.element.html( value ); if ( this.icon ) { this._attachIcon( this.options.iconPosition ); this._attachIconSpace( this.options.iconPosition ); } } } this._super( key, value ); if ( key === "disabled" ) { this._toggleClass( null, "ui-state-disabled", value ); this.element[ 0 ].disabled = value; if ( value ) { this.element.trigger( "blur" ); } } }, refresh: function() { // Make sure to only check disabled if its an element that supports this otherwise // check for the disabled class to determine state var isDisabled = this.element.is( "input, button" ) ? this.element[ 0 ].disabled : this.element.hasClass( "ui-button-disabled" ); if ( isDisabled !== this.options.disabled ) { this._setOptions( { disabled: isDisabled } ); } this._updateTooltip(); } } ); // DEPRECATED if ( $.uiBackCompat !== false ) { // Text and Icons options $.widget( "ui.button", $.ui.button, { options: { text: true, icons: { primary: null, secondary: null } }, _create: function() { if ( this.options.showLabel && !this.options.text ) { this.options.showLabel = this.options.text; } if ( !this.options.showLabel && this.options.text ) { this.options.text = this.options.showLabel; } if ( !this.options.icon && ( this.options.icons.primary || this.options.icons.secondary ) ) { if ( this.options.icons.primary ) { this.options.icon = this.options.icons.primary; } else { this.options.icon = this.options.icons.secondary; this.options.iconPosition = "end"; } } else if ( this.options.icon ) { this.options.icons.primary = this.options.icon; } this._super(); }, _setOption: function( key, value ) { if ( key === "text" ) { this._super( "showLabel", value ); return; } if ( key === "showLabel" ) { this.options.text = value; } if ( key === "icon" ) { this.options.icons.primary = value; } if ( key === "icons" ) { if ( value.primary ) { this._super( "icon", value.primary ); this._super( "iconPosition", "beginning" ); } else if ( value.secondary ) { this._super( "icon", value.secondary ); this._super( "iconPosition", "end" ); } } this._superApply( arguments ); } } ); $.fn.button = ( function( orig ) { return function( options ) { var isMethodCall = typeof options === "string"; var args = Array.prototype.slice.call( arguments, 1 ); var returnValue = this; if ( isMethodCall ) { // If this is an empty collection, we need to have the instance method // return undefined instead of the jQuery instance if ( !this.length && options === "instance" ) { returnValue = undefined; } else { this.each( function() { var methodValue; var type = $( this ).attr( "type" ); var name = type !== "checkbox" && type !== "radio" ? "button" : "checkboxradio"; var instance = $.data( this, "ui-" + name ); if ( options === "instance" ) { returnValue = instance; return false; } if ( !instance ) { return $.error( "cannot call methods on button" + " prior to initialization; " + "attempted to call method '" + options + "'" ); } if ( typeof instance[ options ] !== "function" || options.charAt( 0 ) === "_" ) { return $.error( "no such method '" + options + "' for button" + " widget instance" ); } methodValue = instance[ options ].apply( instance, args ); if ( methodValue !== instance && methodValue !== undefined ) { returnValue = methodValue && methodValue.jquery ? returnValue.pushStack( methodValue.get() ) : methodValue; return false; } } ); } } else { // Allow multiple hashes to be passed on init if ( args.length ) { options = $.widget.extend.apply( null, [ options ].concat( args ) ); } this.each( function() { var type = $( this ).attr( "type" ); var name = type !== "checkbox" && type !== "radio" ? "button" : "checkboxradio"; var instance = $.data( this, "ui-" + name ); if ( instance ) { instance.option( options || {} ); if ( instance._init ) { instance._init(); } } else { if ( name === "button" ) { orig.call( $( this ), options ); return; } $( this ).checkboxradio( $.extend( { icon: false }, options ) ); } } ); } return returnValue; }; } )( $.fn.button ); $.fn.buttonset = function() { if ( !$.ui.controlgroup ) { $.error( "Controlgroup widget missing" ); } if ( arguments[ 0 ] === "option" && arguments[ 1 ] === "items" && arguments[ 2 ] ) { return this.controlgroup.apply( this, [ arguments[ 0 ], "items.button", arguments[ 2 ] ] ); } if ( arguments[ 0 ] === "option" && arguments[ 1 ] === "items" ) { return this.controlgroup.apply( this, [ arguments[ 0 ], "items.button" ] ); } if ( typeof arguments[ 0 ] === "object" && arguments[ 0 ].items ) { arguments[ 0 ].items = { button: arguments[ 0 ].items }; } return this.controlgroup.apply( this, arguments ); }; } var widgetsButton = $.ui.button; /*! * jQuery UI Dialog 1.13.2 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license */ //>>label: Dialog //>>group: Widgets //>>description: Displays customizable dialog windows. //>>docs: http://api.jqueryui.com/dialog/ //>>demos: http://jqueryui.com/dialog/ //>>css.structure: ../../themes/base/core.css //>>css.structure: ../../themes/base/dialog.css //>>css.theme: ../../themes/base/theme.css $.widget( "ui.dialog", { version: "1.13.2", options: { appendTo: "body", autoOpen: true, buttons: [], classes: { "ui-dialog": "ui-corner-all", "ui-dialog-titlebar": "ui-corner-all" }, closeOnEscape: true, closeText: "Close", draggable: true, hide: null, height: "auto", maxHeight: null, maxWidth: null, minHeight: 150, minWidth: 150, modal: false, position: { my: "center", at: "center", of: window, collision: "fit", // Ensure the titlebar is always visible using: function( pos ) { var topOffset = $( this ).css( pos ).offset().top; if ( topOffset < 0 ) { $( this ).css( "top", pos.top - topOffset ); } } }, resizable: true, show: null, title: null, width: 300, // Callbacks beforeClose: null, close: null, drag: null, dragStart: null, dragStop: null, focus: null, open: null, resize: null, resizeStart: null, resizeStop: null }, sizeRelatedOptions: { buttons: true, height: true, maxHeight: true, maxWidth: true, minHeight: true, minWidth: true, width: true }, resizableRelatedOptions: { maxHeight: true, maxWidth: true, minHeight: true, minWidth: true }, _create: function() { this.originalCss = { display: this.element[ 0 ].style.display, width: this.element[ 0 ].style.width, minHeight: this.element[ 0 ].style.minHeight, maxHeight: this.element[ 0 ].style.maxHeight, height: this.element[ 0 ].style.height }; this.originalPosition = { parent: this.element.parent(), index: this.element.parent().children().index( this.element ) }; this.originalTitle = this.element.attr( "title" ); if ( this.options.title == null && this.originalTitle != null ) { this.options.title = this.originalTitle; } // Dialogs can't be disabled if ( this.options.disabled ) { this.options.disabled = false; } this._createWrapper(); this.element .show() .removeAttr( "title" ) .appendTo( this.uiDialog ); this._addClass( "ui-dialog-content", "ui-widget-content" ); this._createTitlebar(); this._createButtonPane(); if ( this.options.draggable && $.fn.draggable ) { this._makeDraggable(); } if ( this.options.resizable && $.fn.resizable ) { this._makeResizable(); } this._isOpen = false; this._trackFocus(); }, _init: function() { if ( this.options.autoOpen ) { this.open(); } }, _appendTo: function() { var element = this.options.appendTo; if ( element && ( element.jquery || element.nodeType ) ) { return $( element ); } return this.document.find( element || "body" ).eq( 0 ); }, _destroy: function() { var next, originalPosition = this.originalPosition; this._untrackInstance(); this._destroyOverlay(); this.element .removeUniqueId() .css( this.originalCss ) // Without detaching first, the following becomes really slow .detach(); this.uiDialog.remove(); if ( this.originalTitle ) { this.element.attr( "title", this.originalTitle ); } next = originalPosition.parent.children().eq( originalPosition.index ); // Don't try to place the dialog next to itself (#8613) if ( next.length && next[ 0 ] !== this.element[ 0 ] ) { next.before( this.element ); } else { originalPosition.parent.append( this.element ); } }, widget: function() { return this.uiDialog; }, disable: $.noop, enable: $.noop, close: function( event ) { var that = this; if ( !this._isOpen || this._trigger( "beforeClose", event ) === false ) { return; } this._isOpen = false; this._focusedElement = null; this._destroyOverlay(); this._untrackInstance(); if ( !this.opener.filter( ":focusable" ).trigger( "focus" ).length ) { // Hiding a focused element doesn't trigger blur in WebKit // so in case we have nothing to focus on, explicitly blur the active element // https://bugs.webkit.org/show_bug.cgi?id=47182 $.ui.safeBlur( $.ui.safeActiveElement( this.document[ 0 ] ) ); } this._hide( this.uiDialog, this.options.hide, function() { that._trigger( "close", event ); } ); }, isOpen: function() { return this._isOpen; }, moveToTop: function() { this._moveToTop(); }, _moveToTop: function( event, silent ) { var moved = false, zIndices = this.uiDialog.siblings( ".ui-front:visible" ).map( function() { return +$( this ).css( "z-index" ); } ).get(), zIndexMax = Math.max.apply( null, zIndices ); if ( zIndexMax >= +this.uiDialog.css( "z-index" ) ) { this.uiDialog.css( "z-index", zIndexMax + 1 ); moved = true; } if ( moved && !silent ) { this._trigger( "focus", event ); } return moved; }, open: function() { var that = this; if ( this._isOpen ) { if ( this._moveToTop() ) { this._focusTabbable(); } return; } this._isOpen = true; this.opener = $( $.ui.safeActiveElement( this.document[ 0 ] ) ); this._size(); this._position(); this._createOverlay(); this._moveToTop( null, true ); // Ensure the overlay is moved to the top with the dialog, but only when // opening. The overlay shouldn't move after the dialog is open so that // modeless dialogs opened after the modal dialog stack properly. if ( this.overlay ) { this.overlay.css( "z-index", this.uiDialog.css( "z-index" ) - 1 ); } this._show( this.uiDialog, this.options.show, function() { that._focusTabbable(); that._trigger( "focus" ); } ); // Track the dialog immediately upon opening in case a focus event // somehow occurs outside of the dialog before an element inside the // dialog is focused (#10152) this._makeFocusTarget(); this._trigger( "open" ); }, _focusTabbable: function() { // Set focus to the first match: // 1. An element that was focused previously // 2. First element inside the dialog matching [autofocus] // 3. Tabbable element inside the content element // 4. Tabbable element inside the buttonpane // 5. The close button // 6. The dialog itself var hasFocus = this._focusedElement; if ( !hasFocus ) { hasFocus = this.element.find( "[autofocus]" ); } if ( !hasFocus.length ) { hasFocus = this.element.find( ":tabbable" ); } if ( !hasFocus.length ) { hasFocus = this.uiDialogButtonPane.find( ":tabbable" ); } if ( !hasFocus.length ) { hasFocus = this.uiDialogTitlebarClose.filter( ":tabbable" ); } if ( !hasFocus.length ) { hasFocus = this.uiDialog; } hasFocus.eq( 0 ).trigger( "focus" ); }, _restoreTabbableFocus: function() { var activeElement = $.ui.safeActiveElement( this.document[ 0 ] ), isActive = this.uiDialog[ 0 ] === activeElement || $.contains( this.uiDialog[ 0 ], activeElement ); if ( !isActive ) { this._focusTabbable(); } }, _keepFocus: function( event ) { event.preventDefault(); this._restoreTabbableFocus(); // support: IE // IE <= 8 doesn't prevent moving focus even with event.preventDefault() // so we check again later this._delay( this._restoreTabbableFocus ); }, _createWrapper: function() { this.uiDialog = $( "<div>" ) .hide() .attr( { // Setting tabIndex makes the div focusable tabIndex: -1, role: "dialog" } ) .appendTo( this._appendTo() ); this._addClass( this.uiDialog, "ui-dialog", "ui-widget ui-widget-content ui-front" ); this._on( this.uiDialog, { keydown: function( event ) { if ( this.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode && event.keyCode === $.ui.keyCode.ESCAPE ) { event.preventDefault(); this.close( event ); return; } // Prevent tabbing out of dialogs if ( event.keyCode !== $.ui.keyCode.TAB || event.isDefaultPrevented() ) { return; } var tabbables = this.uiDialog.find( ":tabbable" ), first = tabbables.first(), last = tabbables.last(); if ( ( event.target === last[ 0 ] || event.target === this.uiDialog[ 0 ] ) && !event.shiftKey ) { this._delay( function() { first.trigger( "focus" ); } ); event.preventDefault(); } else if ( ( event.target === first[ 0 ] || event.target === this.uiDialog[ 0 ] ) && event.shiftKey ) { this._delay( function() { last.trigger( "focus" ); } ); event.preventDefault(); } }, mousedown: function( event ) { if ( this._moveToTop( event ) ) { this._focusTabbable(); } } } ); // We assume that any existing aria-describedby attribute means // that the dialog content is marked up properly // otherwise we brute force the content as the description if ( !this.element.find( "[aria-describedby]" ).length ) { this.uiDialog.attr( { "aria-describedby": this.element.uniqueId().attr( "id" ) } ); } }, _createTitlebar: function() { var uiDialogTitle; this.uiDialogTitlebar = $( "<div>" ); this._addClass( this.uiDialogTitlebar, "ui-dialog-titlebar", "ui-widget-header ui-helper-clearfix" ); this._on( this.uiDialogTitlebar, { mousedown: function( event ) { // Don't prevent click on close button (#8838) // Focusing a dialog that is partially scrolled out of view // causes the browser to scroll it into view, preventing the click event if ( !$( event.target ).closest( ".ui-dialog-titlebar-close" ) ) { // Dialog isn't getting focus when dragging (#8063) this.uiDialog.trigger( "focus" ); } } } ); // Support: IE // Use type="button" to prevent enter keypresses in textboxes from closing the // dialog in IE (#9312) this.uiDialogTitlebarClose = $( "<button type='button'></button>" ) .button( { label: $( "<a>" ).text( this.options.closeText ).html(), icon: "ui-icon-closethick", showLabel: false } ) .appendTo( this.uiDialogTitlebar ); this._addClass( this.uiDialogTitlebarClose, "ui-dialog-titlebar-close" ); this._on( this.uiDialogTitlebarClose, { click: function( event ) { event.preventDefault(); this.close( event ); } } ); uiDialogTitle = $( "<span>" ).uniqueId().prependTo( this.uiDialogTitlebar ); this._addClass( uiDialogTitle, "ui-dialog-title" ); this._title( uiDialogTitle ); this.uiDialogTitlebar.prependTo( this.uiDialog ); this.uiDialog.attr( { "aria-labelledby": uiDialogTitle.attr( "id" ) } ); }, _title: function( title ) { if ( this.options.title ) { title.text( this.options.title ); } else { title.html( " " ); } }, _createButtonPane: function() { this.uiDialogButtonPane = $( "<div>" ); this._addClass( this.uiDialogButtonPane, "ui-dialog-buttonpane", "ui-widget-content ui-helper-clearfix" ); this.uiButtonSet = $( "<div>" ) .appendTo( this.uiDialogButtonPane ); this._addClass( this.uiButtonSet, "ui-dialog-buttonset" ); this._createButtons(); }, _createButtons: function() { var that = this, buttons = this.options.buttons; // If we already have a button pane, remove it this.uiDialogButtonPane.remove(); this.uiButtonSet.empty(); if ( $.isEmptyObject( buttons ) || ( Array.isArray( buttons ) && !buttons.length ) ) { this._removeClass( this.uiDialog, "ui-dialog-buttons" ); return; } $.each( buttons, function( name, props ) { var click, buttonOptions; props = typeof props === "function" ? { click: props, text: name } : props; // Default to a non-submitting button props = $.extend( { type: "button" }, props ); // Change the context for the click callback to be the main element click = props.click; buttonOptions = { icon: props.icon, iconPosition: props.iconPosition, showLabel: props.showLabel, // Deprecated options icons: props.icons, text: props.text }; delete props.click; delete props.icon; delete props.iconPosition; delete props.showLabel; // Deprecated options delete props.icons; if ( typeof props.text === "boolean" ) { delete props.text; } $( "<button></button>", props ) .button( buttonOptions ) .appendTo( that.uiButtonSet ) .on( "click", function() { click.apply( that.element[ 0 ], arguments ); } ); } ); this._addClass( this.uiDialog, "ui-dialog-buttons" ); this.uiDialogButtonPane.appendTo( this.uiDialog ); }, _makeDraggable: function() { var that = this, options = this.options; function filteredUi( ui ) { return { position: ui.position, offset: ui.offset }; } this.uiDialog.draggable( { cancel: ".ui-dialog-content, .ui-dialog-titlebar-close", handle: ".ui-dialog-titlebar", containment: "document", start: function( event, ui ) { that._addClass( $( this ), "ui-dialog-dragging" ); that._blockFrames(); that._trigger( "dragStart", event, filteredUi( ui ) ); }, drag: function( event, ui ) { that._trigger( "drag", event, filteredUi( ui ) ); }, stop: function( event, ui ) { var left = ui.offset.left - that.document.scrollLeft(), top = ui.offset.top - that.document.scrollTop(); options.position = { my: "left top", at: "left" + ( left >= 0 ? "+" : "" ) + left + " " + "top" + ( top >= 0 ? "+" : "" ) + top, of: that.window }; that._removeClass( $( this ), "ui-dialog-dragging" ); that._unblockFrames(); that._trigger( "dragStop", event, filteredUi( ui ) ); } } ); }, _makeResizable: function() { var that = this, options = this.options, handles = options.resizable, // .ui-resizable has position: relative defined in the stylesheet // but dialogs have to use absolute or fixed positioning position = this.uiDialog.css( "position" ), resizeHandles = typeof handles === "string" ? handles : "n,e,s,w,se,sw,ne,nw"; function filteredUi( ui ) { return { originalPosition: ui.originalPosition, originalSize: ui.originalSize, position: ui.position, size: ui.size }; } this.uiDialog.resizable( { cancel: ".ui-dialog-content", containment: "document", alsoResize: this.element, maxWidth: options.maxWidth, maxHeight: options.maxHeight, minWidth: options.minWidth, minHeight: this._minHeight(), handles: resizeHandles, start: function( event, ui ) { that._addClass( $( this ), "ui-dialog-resizing" ); that._blockFrames(); that._trigger( "resizeStart", event, filteredUi( ui ) ); }, resize: function( event, ui ) { that._trigger( "resize", event, filteredUi( ui ) ); }, stop: function( event, ui ) { var offset = that.uiDialog.offset(), left = offset.left - that.document.scrollLeft(), top = offset.top - that.document.scrollTop(); options.height = that.uiDialog.height(); options.width = that.uiDialog.width(); options.position = { my: "left top", at: "left" + ( left >= 0 ? "+" : "" ) + left + " " + "top" + ( top >= 0 ? "+" : "" ) + top, of: that.window }; that._removeClass( $( this ), "ui-dialog-resizing" ); that._unblockFrames(); that._trigger( "resizeStop", event, filteredUi( ui ) ); } } ) .css( "position", position ); }, _trackFocus: function() { this._on( this.widget(), { focusin: function( event ) { this._makeFocusTarget(); this._focusedElement = $( event.target ); } } ); }, _makeFocusTarget: function() { this._untrackInstance(); this._trackingInstances().unshift( this ); }, _untrackInstance: function() { var instances = this._trackingInstances(), exists = $.inArray( this, instances ); if ( exists !== -1 ) { instances.splice( exists, 1 ); } }, _trackingInstances: function() { var instances = this.document.data( "ui-dialog-instances" ); if ( !instances ) { instances = []; this.document.data( "ui-dialog-instances", instances ); } return instances; }, _minHeight: function() { var options = this.options; return options.height === "auto" ? options.minHeight : Math.min( options.minHeight, options.height ); }, _position: function() { // Need to show the dialog to get the actual offset in the position plugin var isVisible = this.uiDialog.is( ":visible" ); if ( !isVisible ) { this.uiDialog.show(); } this.uiDialog.position( this.options.position ); if ( !isVisible ) { this.uiDialog.hide(); } }, _setOptions: function( options ) { var that = this, resize = false, resizableOptions = {}; $.each( options, function( key, value ) { that._setOption( key, value ); if ( key in that.sizeRelatedOptions ) { resize = true; } if ( key in that.resizableRelatedOptions ) { resizableOptions[ key ] = value; } } ); if ( resize ) { this._size(); this._position(); } if ( this.uiDialog.is( ":data(ui-resizable)" ) ) { this.uiDialog.resizable( "option", resizableOptions ); } }, _setOption: function( key, value ) { var isDraggable, isResizable, uiDialog = this.uiDialog; if ( key === "disabled" ) { return; } this._super( key, value ); if ( key === "appendTo" ) { this.uiDialog.appendTo( this._appendTo() ); } if ( key === "buttons" ) { this._createButtons(); } if ( key === "closeText" ) { this.uiDialogTitlebarClose.button( { // Ensure that we always pass a string label: $( "<a>" ).text( "" + this.options.closeText ).html() } ); } if ( key === "draggable" ) { isDraggable = uiDialog.is( ":data(ui-draggable)" ); if ( isDraggable && !value ) { uiDialog.draggable( "destroy" ); } if ( !isDraggable && value ) { this._makeDraggable(); } } if ( key === "position" ) { this._position(); } if ( key === "resizable" ) { // currently resizable, becoming non-resizable isResizable = uiDialog.is( ":data(ui-resizable)" ); if ( isResizable && !value ) { uiDialog.resizable( "destroy" ); } // Currently resizable, changing handles if ( isResizable && typeof value === "string" ) { uiDialog.resizable( "option", "handles", value ); } // Currently non-resizable, becoming resizable if ( !isResizable && value !== false ) { this._makeResizable(); } } if ( key === "title" ) { this._title( this.uiDialogTitlebar.find( ".ui-dialog-title" ) ); } }, _size: function() { // If the user has resized the dialog, the .ui-dialog and .ui-dialog-content // divs will both have width and height set, so we need to reset them var nonContentHeight, minContentHeight, maxContentHeight, options = this.options; // Reset content sizing this.element.show().css( { width: "auto", minHeight: 0, maxHeight: "none", height: 0 } ); if ( options.minWidth > options.width ) { options.width = options.minWidth; } // Reset wrapper sizing // determine the height of all the non-content elements nonContentHeight = this.uiDialog.css( { height: "auto", width: options.width } ) .outerHeight(); minContentHeight = Math.max( 0, options.minHeight - nonContentHeight ); maxContentHeight = typeof options.maxHeight === "number" ? Math.max( 0, options.maxHeight - nonContentHeight ) : "none"; if ( options.height === "auto" ) { this.element.css( { minHeight: minContentHeight, maxHeight: maxContentHeight, height: "auto" } ); } else { this.element.height( Math.max( 0, options.height - nonContentHeight ) ); } if ( this.uiDialog.is( ":data(ui-resizable)" ) ) { this.uiDialog.resizable( "option", "minHeight", this._minHeight() ); } }, _blockFrames: function() { this.iframeBlocks = this.document.find( "iframe" ).map( function() { var iframe = $( this ); return $( "<div>" ) .css( { position: "absolute", width: iframe.outerWidth(), height: iframe.outerHeight() } ) .appendTo( iframe.parent() ) .offset( iframe.offset() )[ 0 ]; } ); }, _unblockFrames: function() { if ( this.iframeBlocks ) { this.iframeBlocks.remove(); delete this.iframeBlocks; } }, _allowInteraction: function( event ) { if ( $( event.target ).closest( ".ui-dialog" ).length ) { return true; } // TODO: Remove hack when datepicker implements // the .ui-front logic (#8989) return !!$( event.target ).closest( ".ui-datepicker" ).length; }, _createOverlay: function() { if ( !this.options.modal ) { return; } var jqMinor = $.fn.jquery.substring( 0, 4 ); // We use a delay in case the overlay is created from an // event that we're going to be cancelling (#2804) var isOpening = true; this._delay( function() { isOpening = false; } ); if ( !this.document.data( "ui-dialog-overlays" ) ) { // Prevent use of anchors and inputs // This doesn't use `_on()` because it is a shared event handler // across all open modal dialogs. this.document.on( "focusin.ui-dialog", function( event ) { if ( isOpening ) { return; } var instance = this._trackingInstances()[ 0 ]; if ( !instance._allowInteraction( event ) ) { event.preventDefault(); instance._focusTabbable(); // Support: jQuery >=3.4 <3.6 only // Focus re-triggering in jQuery 3.4/3.5 makes the original element // have its focus event propagated last, breaking the re-targeting. // Trigger focus in a delay in addition if needed to avoid the issue // See https://github.com/jquery/jquery/issues/4382 if ( jqMinor === "3.4." || jqMinor === "3.5." ) { instance._delay( instance._restoreTabbableFocus ); } } }.bind( this ) ); } this.overlay = $( "<div>" ) .appendTo( this._appendTo() ); this._addClass( this.overlay, null, "ui-widget-overlay ui-front" ); this._on( this.overlay, { mousedown: "_keepFocus" } ); this.document.data( "ui-dialog-overlays", ( this.document.data( "ui-dialog-overlays" ) || 0 ) + 1 ); }, _destroyOverlay: function() { if ( !this.options.modal ) { return; } if ( this.overlay ) { var overlays = this.document.data( "ui-dialog-overlays" ) - 1; if ( !overlays ) { this.document.off( "focusin.ui-dialog" ); this.document.removeData( "ui-dialog-overlays" ); } else { this.document.data( "ui-dialog-overlays", overlays ); } this.overlay.remove(); this.overlay = null; } } } ); // DEPRECATED // TODO: switch return back to widget declaration at top of file when this is removed if ( $.uiBackCompat !== false ) { // Backcompat for dialogClass option $.widget( "ui.dialog", $.ui.dialog, { options: { dialogClass: "" }, _createWrapper: function() { this._super(); this.uiDialog.addClass( this.options.dialogClass ); }, _setOption: function( key, value ) { if ( key === "dialogClass" ) { this.uiDialog .removeClass( this.options.dialogClass ) .addClass( value ); } this._superApply( arguments ); } } ); } var widgetsDialog = $.ui.dialog; /*! * jQuery UI Slider 1.13.2 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license */ //>>label: Slider //>>group: Widgets //>>description: Displays a flexible slider with ranges and accessibility via keyboard. //>>docs: http://api.jqueryui.com/slider/ //>>demos: http://jqueryui.com/slider/ //>>css.structure: ../../themes/base/core.css //>>css.structure: ../../themes/base/slider.css //>>css.theme: ../../themes/base/theme.css var widgetsSlider = $.widget( "ui.slider", $.ui.mouse, { version: "1.13.2", widgetEventPrefix: "slide", options: { animate: false, classes: { "ui-slider": "ui-corner-all", "ui-slider-handle": "ui-corner-all", // Note: ui-widget-header isn't the most fittingly semantic framework class for this // element, but worked best visually with a variety of themes "ui-slider-range": "ui-corner-all ui-widget-header" }, distance: 0, max: 100, min: 0, orientation: "horizontal", range: false, step: 1, value: 0, values: null, // Callbacks change: null, slide: null, start: null, stop: null }, // Number of pages in a slider // (how many times can you page up/down to go through the whole range) numPages: 5, _create: function() { this._keySliding = false; this._mouseSliding = false; this._animateOff = true; this._handleIndex = null; this._detectOrientation(); this._mouseInit(); this._calculateNewMax(); this._addClass( "ui-slider ui-slider-" + this.orientation, "ui-widget ui-widget-content" ); this._refresh(); this._animateOff = false; }, _refresh: function() { this._createRange(); this._createHandles(); this._setupEvents(); this._refreshValue(); }, _createHandles: function() { var i, handleCount, options = this.options, existingHandles = this.element.find( ".ui-slider-handle" ), handle = "<span tabindex='0'></span>", handles = []; handleCount = ( options.values && options.values.length ) || 1; if ( existingHandles.length > handleCount ) { existingHandles.slice( handleCount ).remove(); existingHandles = existingHandles.slice( 0, handleCount ); } for ( i = existingHandles.length; i < handleCount; i++ ) { handles.push( handle ); } this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( this.element ) ); this._addClass( this.handles, "ui-slider-handle", "ui-state-default" ); this.handle = this.handles.eq( 0 ); this.handles.each( function( i ) { $( this ) .data( "ui-slider-handle-index", i ) .attr( "tabIndex", 0 ); } ); }, _createRange: function() { var options = this.options; if ( options.range ) { if ( options.range === true ) { if ( !options.values ) { options.values = [ this._valueMin(), this._valueMin() ]; } else if ( options.values.length && options.values.length !== 2 ) { options.values = [ options.values[ 0 ], options.values[ 0 ] ]; } else if ( Array.isArray( options.values ) ) { options.values = options.values.slice( 0 ); } } if ( !this.range || !this.range.length ) { this.range = $( "<div>" ) .appendTo( this.element ); this._addClass( this.range, "ui-slider-range" ); } else { this._removeClass( this.range, "ui-slider-range-min ui-slider-range-max" ); // Handle range switching from true to min/max this.range.css( { "left": "", "bottom": "" } ); } if ( options.range === "min" || options.range === "max" ) { this._addClass( this.range, "ui-slider-range-" + options.range ); } } else { if ( this.range ) { this.range.remove(); } this.range = null; } }, _setupEvents: function() { this._off( this.handles ); this._on( this.handles, this._handleEvents ); this._hoverable( this.handles ); this._focusable( this.handles ); }, _destroy: function() { this.handles.remove(); if ( this.range ) { this.range.remove(); } this._mouseDestroy(); }, _mouseCapture: function( event ) { var position, normValue, distance, closestHandle, index, allowed, offset, mouseOverHandle, that = this, o = this.options; if ( o.disabled ) { return false; } this.elementSize = { width: this.element.outerWidth(), height: this.element.outerHeight() }; this.elementOffset = this.element.offset(); position = { x: event.pageX, y: event.pageY }; normValue = this._normValueFromMouse( position ); distance = this._valueMax() - this._valueMin() + 1; this.handles.each( function( i ) { var thisDistance = Math.abs( normValue - that.values( i ) ); if ( ( distance > thisDistance ) || ( distance === thisDistance && ( i === that._lastChangedValue || that.values( i ) === o.min ) ) ) { distance = thisDistance; closestHandle = $( this ); index = i; } } ); allowed = this._start( event, index ); if ( allowed === false ) { return false; } this._mouseSliding = true; this._handleIndex = index; this._addClass( closestHandle, null, "ui-state-active" ); closestHandle.trigger( "focus" ); offset = closestHandle.offset(); mouseOverHandle = !$( event.target ).parents().addBack().is( ".ui-slider-handle" ); this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : { left: event.pageX - offset.left - ( closestHandle.width() / 2 ), top: event.pageY - offset.top - ( closestHandle.height() / 2 ) - ( parseInt( closestHandle.css( "borderTopWidth" ), 10 ) || 0 ) - ( parseInt( closestHandle.css( "borderBottomWidth" ), 10 ) || 0 ) + ( parseInt( closestHandle.css( "marginTop" ), 10 ) || 0 ) }; if ( !this.handles.hasClass( "ui-state-hover" ) ) { this._slide( event, index, normValue ); } this._animateOff = true; return true; }, _mouseStart: function() { return true; }, _mouseDrag: function( event ) { var position = { x: event.pageX, y: event.pageY }, normValue = this._normValueFromMouse( position ); this._slide( event, this._handleIndex, normValue ); return false; }, _mouseStop: function( event ) { this._removeClass( this.handles, null, "ui-state-active" ); this._mouseSliding = false; this._stop( event, this._handleIndex ); this._change( event, this._handleIndex ); this._handleIndex = null; this._clickOffset = null; this._animateOff = false; return false; }, _detectOrientation: function() { this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal"; }, _normValueFromMouse: function( position ) { var pixelTotal, pixelMouse, percentMouse, valueTotal, valueMouse; if ( this.orientation === "horizontal" ) { pixelTotal = this.elementSize.width; pixelMouse = position.x - this.elementOffset.left - ( this._clickOffset ? this._clickOffset.left : 0 ); } else { pixelTotal = this.elementSize.height; pixelMouse = position.y - this.elementOffset.top - ( this._clickOffset ? this._clickOffset.top : 0 ); } percentMouse = ( pixelMouse / pixelTotal ); if ( percentMouse > 1 ) { percentMouse = 1; } if ( percentMouse < 0 ) { percentMouse = 0; } if ( this.orientation === "vertical" ) { percentMouse = 1 - percentMouse; } valueTotal = this._valueMax() - this._valueMin(); valueMouse = this._valueMin() + percentMouse * valueTotal; return this._trimAlignValue( valueMouse ); }, _uiHash: function( index, value, values ) { var uiHash = { handle: this.handles[ index ], handleIndex: index, value: value !== undefined ? value : this.value() }; if ( this._hasMultipleValues() ) { uiHash.value = value !== undefined ? value : this.values( index ); uiHash.values = values || this.values(); } return uiHash; }, _hasMultipleValues: function() { return this.options.values && this.options.values.length; }, _start: function( event, index ) { return this._trigger( "start", event, this._uiHash( index ) ); }, _slide: function( event, index, newVal ) { var allowed, otherVal, currentValue = this.value(), newValues = this.values(); if ( this._hasMultipleValues() ) { otherVal = this.values( index ? 0 : 1 ); currentValue = this.values( index ); if ( this.options.values.length === 2 && this.options.range === true ) { newVal = index === 0 ? Math.min( otherVal, newVal ) : Math.max( otherVal, newVal ); } newValues[ index ] = newVal; } if ( newVal === currentValue ) { return; } allowed = this._trigger( "slide", event, this._uiHash( index, newVal, newValues ) ); // A slide can be canceled by returning false from the slide callback if ( allowed === false ) { return; } if ( this._hasMultipleValues() ) { this.values( index, newVal ); } else { this.value( newVal ); } }, _stop: function( event, index ) { this._trigger( "stop", event, this._uiHash( index ) ); }, _change: function( event, index ) { if ( !this._keySliding && !this._mouseSliding ) { //store the last changed value index for reference when handles overlap this._lastChangedValue = index; this._trigger( "change", event, this._uiHash( index ) ); } }, value: function( newValue ) { if ( arguments.length ) { this.options.value = this._trimAlignValue( newValue ); this._refreshValue(); this._change( null, 0 ); return; } return this._value(); }, values: function( index, newValue ) { var vals, newValues, i; if ( arguments.length > 1 ) { this.options.values[ index ] = this._trimAlignValue( newValue ); this._refreshValue(); this._change( null, index ); return; } if ( arguments.length ) { if ( Array.isArray( arguments[ 0 ] ) ) { vals = this.options.values; newValues = arguments[ 0 ]; for ( i = 0; i < vals.length; i += 1 ) { vals[ i ] = this._trimAlignValue( newValues[ i ] ); this._change( null, i ); } this._refreshValue(); } else { if ( this._hasMultipleValues() ) { return this._values( index ); } else { return this.value(); } } } else { return this._values(); } }, _setOption: function( key, value ) { var i, valsLength = 0; if ( key === "range" && this.options.range === true ) { if ( value === "min" ) { this.options.value = this._values( 0 ); this.options.values = null; } else if ( value === "max" ) { this.options.value = this._values( this.options.values.length - 1 ); this.options.values = null; } } if ( Array.isArray( this.options.values ) ) { valsLength = this.options.values.length; } this._super( key, value ); switch ( key ) { case "orientation": this._detectOrientation(); this._removeClass( "ui-slider-horizontal ui-slider-vertical" ) ._addClass( "ui-slider-" + this.orientation ); this._refreshValue(); if ( this.options.range ) { this._refreshRange( value ); } // Reset positioning from previous orientation this.handles.css( value === "horizontal" ? "bottom" : "left", "" ); break; case "value": this._animateOff = true; this._refreshValue(); this._change( null, 0 ); this._animateOff = false; break; case "values": this._animateOff = true; this._refreshValue(); // Start from the last handle to prevent unreachable handles (#9046) for ( i = valsLength - 1; i >= 0; i-- ) { this._change( null, i ); } this._animateOff = false; break; case "step": case "min": case "max": this._animateOff = true; this._calculateNewMax(); this._refreshValue(); this._animateOff = false; break; case "range": this._animateOff = true; this._refresh(); this._animateOff = false; break; } }, _setOptionDisabled: function( value ) { this._super( value ); this._toggleClass( null, "ui-state-disabled", !!value ); }, //internal value getter // _value() returns value trimmed by min and max, aligned by step _value: function() { var val = this.options.value; val = this._trimAlignValue( val ); return val; }, //internal values getter // _values() returns array of values trimmed by min and max, aligned by step // _values( index ) returns single value trimmed by min and max, aligned by step _values: function( index ) { var val, vals, i; if ( arguments.length ) { val = this.options.values[ index ]; val = this._trimAlignValue( val ); return val; } else if ( this._hasMultipleValues() ) { // .slice() creates a copy of the array // this copy gets trimmed by min and max and then returned vals = this.options.values.slice(); for ( i = 0; i < vals.length; i += 1 ) { vals[ i ] = this._trimAlignValue( vals[ i ] ); } return vals; } else { return []; } }, // Returns the step-aligned value that val is closest to, between (inclusive) min and max _trimAlignValue: function( val ) { if ( val <= this._valueMin() ) { return this._valueMin(); } if ( val >= this._valueMax() ) { return this._valueMax(); } var step = ( this.options.step > 0 ) ? this.options.step : 1, valModStep = ( val - this._valueMin() ) % step, alignValue = val - valModStep; if ( Math.abs( valModStep ) * 2 >= step ) { alignValue += ( valModStep > 0 ) ? step : ( -step ); } // Since JavaScript has problems with large floats, round // the final value to 5 digits after the decimal point (see #4124) return parseFloat( alignValue.toFixed( 5 ) ); }, _calculateNewMax: function() { var max = this.options.max, min = this._valueMin(), step = this.options.step, aboveMin = Math.round( ( max - min ) / step ) * step; max = aboveMin + min; if ( max > this.options.max ) { //If max is not divisible by step, rounding off may increase its value max -= step; } this.max = parseFloat( max.toFixed( this._precision() ) ); }, _precision: function() { var precision = this._precisionOf( this.options.step ); if ( this.options.min !== null ) { precision = Math.max( precision, this._precisionOf( this.options.min ) ); } return precision; }, _precisionOf: function( num ) { var str = num.toString(), decimal = str.indexOf( "." ); return decimal === -1 ? 0 : str.length - decimal - 1; }, _valueMin: function() { return this.options.min; }, _valueMax: function() { return this.max; }, _refreshRange: function( orientation ) { if ( orientation === "vertical" ) { this.range.css( { "width": "", "left": "" } ); } if ( orientation === "horizontal" ) { this.range.css( { "height": "", "bottom": "" } ); } }, _refreshValue: function() { var lastValPercent, valPercent, value, valueMin, valueMax, oRange = this.options.range, o = this.options, that = this, animate = ( !this._animateOff ) ? o.animate : false, _set = {}; if ( this._hasMultipleValues() ) { this.handles.each( function( i ) { valPercent = ( that.values( i ) - that._valueMin() ) / ( that._valueMax() - that._valueMin() ) * 100; _set[ that.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%"; $( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate ); if ( that.options.range === true ) { if ( that.orientation === "horizontal" ) { if ( i === 0 ) { that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { left: valPercent + "%" }, o.animate ); } if ( i === 1 ) { that.range[ animate ? "animate" : "css" ]( { width: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } ); } } else { if ( i === 0 ) { that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { bottom: ( valPercent ) + "%" }, o.animate ); } if ( i === 1 ) { that.range[ animate ? "animate" : "css" ]( { height: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } ); } } } lastValPercent = valPercent; } ); } else { value = this.value(); valueMin = this._valueMin(); valueMax = this._valueMax(); valPercent = ( valueMax !== valueMin ) ? ( value - valueMin ) / ( valueMax - valueMin ) * 100 : 0; _set[ this.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%"; this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate ); if ( oRange === "min" && this.orientation === "horizontal" ) { this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { width: valPercent + "%" }, o.animate ); } if ( oRange === "max" && this.orientation === "horizontal" ) { this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { width: ( 100 - valPercent ) + "%" }, o.animate ); } if ( oRange === "min" && this.orientation === "vertical" ) { this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { height: valPercent + "%" }, o.animate ); } if ( oRange === "max" && this.orientation === "vertical" ) { this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { height: ( 100 - valPercent ) + "%" }, o.animate ); } } }, _handleEvents: { keydown: function( event ) { var allowed, curVal, newVal, step, index = $( event.target ).data( "ui-slider-handle-index" ); switch ( event.keyCode ) { case $.ui.keyCode.HOME: case $.ui.keyCode.END: case $.ui.keyCode.PAGE_UP: case $.ui.keyCode.PAGE_DOWN: case $.ui.keyCode.UP: case $.ui.keyCode.RIGHT: case $.ui.keyCode.DOWN: case $.ui.keyCode.LEFT: event.preventDefault(); if ( !this._keySliding ) { this._keySliding = true; this._addClass( $( event.target ), null, "ui-state-active" ); allowed = this._start( event, index ); if ( allowed === false ) { return; } } break; } step = this.options.step; if ( this._hasMultipleValues() ) { curVal = newVal = this.values( index ); } else { curVal = newVal = this.value(); } switch ( event.keyCode ) { case $.ui.keyCode.HOME: newVal = this._valueMin(); break; case $.ui.keyCode.END: newVal = this._valueMax(); break; case $.ui.keyCode.PAGE_UP: newVal = this._trimAlignValue( curVal + ( ( this._valueMax() - this._valueMin() ) / this.numPages ) ); break; case $.ui.keyCode.PAGE_DOWN: newVal = this._trimAlignValue( curVal - ( ( this._valueMax() - this._valueMin() ) / this.numPages ) ); break; case $.ui.keyCode.UP: case $.ui.keyCode.RIGHT: if ( curVal === this._valueMax() ) { return; } newVal = this._trimAlignValue( curVal + step ); break; case $.ui.keyCode.DOWN: case $.ui.keyCode.LEFT: if ( curVal === this._valueMin() ) { return; } newVal = this._trimAlignValue( curVal - step ); break; } this._slide( event, index, newVal ); }, keyup: function( event ) { var index = $( event.target ).data( "ui-slider-handle-index" ); if ( this._keySliding ) { this._keySliding = false; this._stop( event, index ); this._change( event, index ); this._removeClass( $( event.target ), null, "ui-state-active" ); } } } } ); /*! * jQuery UI Tabs 1.13.2 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license */ //>>label: Tabs //>>group: Widgets //>>description: Transforms a set of container elements into a tab structure. //>>docs: http://api.jqueryui.com/tabs/ //>>demos: http://jqueryui.com/tabs/ //>>css.structure: ../../themes/base/core.css //>>css.structure: ../../themes/base/tabs.css //>>css.theme: ../../themes/base/theme.css $.widget( "ui.tabs", { version: "1.13.2", delay: 300, options: { active: null, classes: { "ui-tabs": "ui-corner-all", "ui-tabs-nav": "ui-corner-all", "ui-tabs-panel": "ui-corner-bottom", "ui-tabs-tab": "ui-corner-top" }, collapsible: false, event: "click", heightStyle: "content", hide: null, show: null, // Callbacks activate: null, beforeActivate: null, beforeLoad: null, load: null }, _isLocal: ( function() { var rhash = /#.*$/; return function( anchor ) { var anchorUrl, locationUrl; anchorUrl = anchor.href.replace( rhash, "" ); locationUrl = location.href.replace( rhash, "" ); // Decoding may throw an error if the URL isn't UTF-8 (#9518) try { anchorUrl = decodeURIComponent( anchorUrl ); } catch ( error ) {} try { locationUrl = decodeURIComponent( locationUrl ); } catch ( error ) {} return anchor.hash.length > 1 && anchorUrl === locationUrl; }; } )(), _create: function() { var that = this, options = this.options; this.running = false; this._addClass( "ui-tabs", "ui-widget ui-widget-content" ); this._toggleClass( "ui-tabs-collapsible", null, options.collapsible ); this._processTabs(); options.active = this._initialActive(); // Take disabling tabs via class attribute from HTML // into account and update option properly. if ( Array.isArray( options.disabled ) ) { options.disabled = $.uniqueSort( options.disabled.concat( $.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) { return that.tabs.index( li ); } ) ) ).sort(); } // Check for length avoids error when initializing empty list if ( this.options.active !== false && this.anchors.length ) { this.active = this._findActive( options.active ); } else { this.active = $(); } this._refresh(); if ( this.active.length ) { this.load( options.active ); } }, _initialActive: function() { var active = this.options.active, collapsible = this.options.collapsible, locationHash = location.hash.substring( 1 ); if ( active === null ) { // check the fragment identifier in the URL if ( locationHash ) { this.tabs.each( function( i, tab ) { if ( $( tab ).attr( "aria-controls" ) === locationHash ) { active = i; return false; } } ); } // Check for a tab marked active via a class if ( active === null ) { active = this.tabs.index( this.tabs.filter( ".ui-tabs-active" ) ); } // No active tab, set to false if ( active === null || active === -1 ) { active = this.tabs.length ? 0 : false; } } // Handle numbers: negative, out of range if ( active !== false ) { active = this.tabs.index( this.tabs.eq( active ) ); if ( active === -1 ) { active = collapsible ? false : 0; } } // Don't allow collapsible: false and active: false if ( !collapsible && active === false && this.anchors.length ) { active = 0; } return active; }, _getCreateEventData: function() { return { tab: this.active, panel: !this.active.length ? $() : this._getPanelForTab( this.active ) }; }, _tabKeydown: function( event ) { var focusedTab = $( $.ui.safeActiveElement( this.document[ 0 ] ) ).closest( "li" ), selectedIndex = this.tabs.index( focusedTab ), goingForward = true; if ( this._handlePageNav( event ) ) { return; } switch ( event.keyCode ) { case $.ui.keyCode.RIGHT: case $.ui.keyCode.DOWN: selectedIndex++; break; case $.ui.keyCode.UP: case $.ui.keyCode.LEFT: goingForward = false; selectedIndex--; break; case $.ui.keyCode.END: selectedIndex = this.anchors.length - 1; break; case $.ui.keyCode.HOME: selectedIndex = 0; break; case $.ui.keyCode.SPACE: // Activate only, no collapsing event.preventDefault(); clearTimeout( this.activating ); this._activate( selectedIndex ); return; case $.ui.keyCode.ENTER: // Toggle (cancel delayed activation, allow collapsing) event.preventDefault(); clearTimeout( this.activating ); // Determine if we should collapse or activate this._activate( selectedIndex === this.options.active ? false : selectedIndex ); return; default: return; } // Focus the appropriate tab, based on which key was pressed event.preventDefault(); clearTimeout( this.activating ); selectedIndex = this._focusNextTab( selectedIndex, goingForward ); // Navigating with control/command key will prevent automatic activation if ( !event.ctrlKey && !event.metaKey ) { // Update aria-selected immediately so that AT think the tab is already selected. // Otherwise AT may confuse the user by stating that they need to activate the tab, // but the tab will already be activated by the time the announcement finishes. focusedTab.attr( "aria-selected", "false" ); this.tabs.eq( selectedIndex ).attr( "aria-selected", "true" ); this.activating = this._delay( function() { this.option( "active", selectedIndex ); }, this.delay ); } }, _panelKeydown: function( event ) { if ( this._handlePageNav( event ) ) { return; } // Ctrl+up moves focus to the current tab if ( event.ctrlKey && event.keyCode === $.ui.keyCode.UP ) { event.preventDefault(); this.active.trigger( "focus" ); } }, // Alt+page up/down moves focus to the previous/next tab (and activates) _handlePageNav: function( event ) { if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP ) { this._activate( this._focusNextTab( this.options.active - 1, false ) ); return true; } if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN ) { this._activate( this._focusNextTab( this.options.active + 1, true ) ); return true; } }, _findNextTab: function( index, goingForward ) { var lastTabIndex = this.tabs.length - 1; function constrain() { if ( index > lastTabIndex ) { index = 0; } if ( index < 0 ) { index = lastTabIndex; } return index; } while ( $.inArray( constrain(), this.options.disabled ) !== -1 ) { index = goingForward ? index + 1 : index - 1; } return index; }, _focusNextTab: function( index, goingForward ) { index = this._findNextTab( index, goingForward ); this.tabs.eq( index ).trigger( "focus" ); return index; }, _setOption: function( key, value ) { if ( key === "active" ) { // _activate() will handle invalid values and update this.options this._activate( value ); return; } this._super( key, value ); if ( key === "collapsible" ) { this._toggleClass( "ui-tabs-collapsible", null, value ); // Setting collapsible: false while collapsed; open first panel if ( !value && this.options.active === false ) { this._activate( 0 ); } } if ( key === "event" ) { this._setupEvents( value ); } if ( key === "heightStyle" ) { this._setupHeightStyle( value ); } }, _sanitizeSelector: function( hash ) { return hash ? hash.replace( /[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, "\\$&" ) : ""; }, refresh: function() { var options = this.options, lis = this.tablist.children( ":has(a[href])" ); // Get disabled tabs from class attribute from HTML // this will get converted to a boolean if needed in _refresh() options.disabled = $.map( lis.filter( ".ui-state-disabled" ), function( tab ) { return lis.index( tab ); } ); this._processTabs(); // Was collapsed or no tabs if ( options.active === false || !this.anchors.length ) { options.active = false; this.active = $(); // was active, but active tab is gone } else if ( this.active.length && !$.contains( this.tablist[ 0 ], this.active[ 0 ] ) ) { // all remaining tabs are disabled if ( this.tabs.length === options.disabled.length ) { options.active = false; this.active = $(); // activate previous tab } else { this._activate( this._findNextTab( Math.max( 0, options.active - 1 ), false ) ); } // was active, active tab still exists } else { // make sure active index is correct options.active = this.tabs.index( this.active ); } this._refresh(); }, _refresh: function() { this._setOptionDisabled( this.options.disabled ); this._setupEvents( this.options.event ); this._setupHeightStyle( this.options.heightStyle ); this.tabs.not( this.active ).attr( { "aria-selected": "false", "aria-expanded": "false", tabIndex: -1 } ); this.panels.not( this._getPanelForTab( this.active ) ) .hide() .attr( { "aria-hidden": "true" } ); // Make sure one tab is in the tab order if ( !this.active.length ) { this.tabs.eq( 0 ).attr( "tabIndex", 0 ); } else { this.active .attr( { "aria-selected": "true", "aria-expanded": "true", tabIndex: 0 } ); this._addClass( this.active, "ui-tabs-active", "ui-state-active" ); this._getPanelForTab( this.active ) .show() .attr( { "aria-hidden": "false" } ); } }, _processTabs: function() { var that = this, prevTabs = this.tabs, prevAnchors = this.anchors, prevPanels = this.panels; this.tablist = this._getList().attr( "role", "tablist" ); this._addClass( this.tablist, "ui-tabs-nav", "ui-helper-reset ui-helper-clearfix ui-widget-header" ); // Prevent users from focusing disabled tabs via click this.tablist .on( "mousedown" + this.eventNamespace, "> li", function( event ) { if ( $( this ).is( ".ui-state-disabled" ) ) { event.preventDefault(); } } ) // Support: IE <9 // Preventing the default action in mousedown doesn't prevent IE // from focusing the element, so if the anchor gets focused, blur. // We don't have to worry about focusing the previously focused // element since clicking on a non-focusable element should focus // the body anyway. .on( "focus" + this.eventNamespace, ".ui-tabs-anchor", function() { if ( $( this ).closest( "li" ).is( ".ui-state-disabled" ) ) { this.blur(); } } ); this.tabs = this.tablist.find( "> li:has(a[href])" ) .attr( { role: "tab", tabIndex: -1 } ); this._addClass( this.tabs, "ui-tabs-tab", "ui-state-default" ); this.anchors = this.tabs.map( function() { return $( "a", this )[ 0 ]; } ) .attr( { tabIndex: -1 } ); this._addClass( this.anchors, "ui-tabs-anchor" ); this.panels = $(); this.anchors.each( function( i, anchor ) { var selector, panel, panelId, anchorId = $( anchor ).uniqueId().attr( "id" ), tab = $( anchor ).closest( "li" ), originalAriaControls = tab.attr( "aria-controls" ); // Inline tab if ( that._isLocal( anchor ) ) { selector = anchor.hash; panelId = selector.substring( 1 ); panel = that.element.find( that._sanitizeSelector( selector ) ); // remote tab } else { // If the tab doesn't already have aria-controls, // generate an id by using a throw-away element panelId = tab.attr( "aria-controls" ) || $( {} ).uniqueId()[ 0 ].id; selector = "#" + panelId; panel = that.element.find( selector ); if ( !panel.length ) { panel = that._createPanel( panelId ); panel.insertAfter( that.panels[ i - 1 ] || that.tablist ); } panel.attr( "aria-live", "polite" ); } if ( panel.length ) { that.panels = that.panels.add( panel ); } if ( originalAriaControls ) { tab.data( "ui-tabs-aria-controls", originalAriaControls ); } tab.attr( { "aria-controls": panelId, "aria-labelledby": anchorId } ); panel.attr( "aria-labelledby", anchorId ); } ); this.panels.attr( "role", "tabpanel" ); this._addClass( this.panels, "ui-tabs-panel", "ui-widget-content" ); // Avoid memory leaks (#10056) if ( prevTabs ) { this._off( prevTabs.not( this.tabs ) ); this._off( prevAnchors.not( this.anchors ) ); this._off( prevPanels.not( this.panels ) ); } }, // Allow overriding how to find the list for rare usage scenarios (#7715) _getList: function() { return this.tablist || this.element.find( "ol, ul" ).eq( 0 ); }, _createPanel: function( id ) { return $( "<div>" ) .attr( "id", id ) .data( "ui-tabs-destroy", true ); }, _setOptionDisabled: function( disabled ) { var currentItem, li, i; if ( Array.isArray( disabled ) ) { if ( !disabled.length ) { disabled = false; } else if ( disabled.length === this.anchors.length ) { disabled = true; } } // Disable tabs for ( i = 0; ( li = this.tabs[ i ] ); i++ ) { currentItem = $( li ); if ( disabled === true || $.inArray( i, disabled ) !== -1 ) { currentItem.attr( "aria-disabled", "true" ); this._addClass( currentItem, null, "ui-state-disabled" ); } else { currentItem.removeAttr( "aria-disabled" ); this._removeClass( currentItem, null, "ui-state-disabled" ); } } this.options.disabled = disabled; this._toggleClass( this.widget(), this.widgetFullName + "-disabled", null, disabled === true ); }, _setupEvents: function( event ) { var events = {}; if ( event ) { $.each( event.split( " " ), function( index, eventName ) { events[ eventName ] = "_eventHandler"; } ); } this._off( this.anchors.add( this.tabs ).add( this.panels ) ); // Always prevent the default action, even when disabled this._on( true, this.anchors, { click: function( event ) { event.preventDefault(); } } ); this._on( this.anchors, events ); this._on( this.tabs, { keydown: "_tabKeydown" } ); this._on( this.panels, { keydown: "_panelKeydown" } ); this._focusable( this.tabs ); this._hoverable( this.tabs ); }, _setupHeightStyle: function( heightStyle ) { var maxHeight, parent = this.element.parent(); if ( heightStyle === "fill" ) { maxHeight = parent.height(); maxHeight -= this.element.outerHeight() - this.element.height(); this.element.siblings( ":visible" ).each( function() { var elem = $( this ), position = elem.css( "position" ); if ( position === "absolute" || position === "fixed" ) { return; } maxHeight -= elem.outerHeight( true ); } ); this.element.children().not( this.panels ).each( function() { maxHeight -= $( this ).outerHeight( true ); } ); this.panels.each( function() { $( this ).height( Math.max( 0, maxHeight - $( this ).innerHeight() + $( this ).height() ) ); } ) .css( "overflow", "auto" ); } else if ( heightStyle === "auto" ) { maxHeight = 0; this.panels.each( function() { maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() ); } ).height( maxHeight ); } }, _eventHandler: function( event ) { var options = this.options, active = this.active, anchor = $( event.currentTarget ), tab = anchor.closest( "li" ), clickedIsActive = tab[ 0 ] === active[ 0 ], collapsing = clickedIsActive && options.collapsible, toShow = collapsing ? $() : this._getPanelForTab( tab ), toHide = !active.length ? $() : this._getPanelForTab( active ), eventData = { oldTab: active, oldPanel: toHide, newTab: collapsing ? $() : tab, newPanel: toShow }; event.preventDefault(); if ( tab.hasClass( "ui-state-disabled" ) || // tab is already loading tab.hasClass( "ui-tabs-loading" ) || // can't switch durning an animation this.running || // click on active header, but not collapsible ( clickedIsActive && !options.collapsible ) || // allow canceling activation ( this._trigger( "beforeActivate", event, eventData ) === false ) ) { return; } options.active = collapsing ? false : this.tabs.index( tab ); this.active = clickedIsActive ? $() : tab; if ( this.xhr ) { this.xhr.abort(); } if ( !toHide.length && !toShow.length ) { $.error( "jQuery UI Tabs: Mismatching fragment identifier." ); } if ( toShow.length ) { this.load( this.tabs.index( tab ), event ); } this._toggle( event, eventData ); }, // Handles show/hide for selecting tabs _toggle: function( event, eventData ) { var that = this, toShow = eventData.newPanel, toHide = eventData.oldPanel; this.running = true; function complete() { that.running = false; that._trigger( "activate", event, eventData ); } function show() { that._addClass( eventData.newTab.closest( "li" ), "ui-tabs-active", "ui-state-active" ); if ( toShow.length && that.options.show ) { that._show( toShow, that.options.show, complete ); } else { toShow.show(); complete(); } } // Start out by hiding, then showing, then completing if ( toHide.length && this.options.hide ) { this._hide( toHide, this.options.hide, function() { that._removeClass( eventData.oldTab.closest( "li" ), "ui-tabs-active", "ui-state-active" ); show(); } ); } else { this._removeClass( eventData.oldTab.closest( "li" ), "ui-tabs-active", "ui-state-active" ); toHide.hide(); show(); } toHide.attr( "aria-hidden", "true" ); eventData.oldTab.attr( { "aria-selected": "false", "aria-expanded": "false" } ); // If we're switching tabs, remove the old tab from the tab order. // If we're opening from collapsed state, remove the previous tab from the tab order. // If we're collapsing, then keep the collapsing tab in the tab order. if ( toShow.length && toHide.length ) { eventData.oldTab.attr( "tabIndex", -1 ); } else if ( toShow.length ) { this.tabs.filter( function() { return $( this ).attr( "tabIndex" ) === 0; } ) .attr( "tabIndex", -1 ); } toShow.attr( "aria-hidden", "false" ); eventData.newTab.attr( { "aria-selected": "true", "aria-expanded": "true", tabIndex: 0 } ); }, _activate: function( index ) { var anchor, active = this._findActive( index ); // Trying to activate the already active panel if ( active[ 0 ] === this.active[ 0 ] ) { return; } // Trying to collapse, simulate a click on the current active header if ( !active.length ) { active = this.active; } anchor = active.find( ".ui-tabs-anchor" )[ 0 ]; this._eventHandler( { target: anchor, currentTarget: anchor, preventDefault: $.noop } ); }, _findActive: function( index ) { return index === false ? $() : this.tabs.eq( index ); }, _getIndex: function( index ) { // meta-function to give users option to provide a href string instead of a numerical index. if ( typeof index === "string" ) { index = this.anchors.index( this.anchors.filter( "[href$='" + $.escapeSelector( index ) + "']" ) ); } return index; }, _destroy: function() { if ( this.xhr ) { this.xhr.abort(); } this.tablist .removeAttr( "role" ) .off( this.eventNamespace ); this.anchors .removeAttr( "role tabIndex" ) .removeUniqueId(); this.tabs.add( this.panels ).each( function() { if ( $.data( this, "ui-tabs-destroy" ) ) { $( this ).remove(); } else { $( this ).removeAttr( "role tabIndex " + "aria-live aria-busy aria-selected aria-labelledby aria-hidden aria-expanded" ); } } ); this.tabs.each( function() { var li = $( this ), prev = li.data( "ui-tabs-aria-controls" ); if ( prev ) { li .attr( "aria-controls", prev ) .removeData( "ui-tabs-aria-controls" ); } else { li.removeAttr( "aria-controls" ); } } ); this.panels.show(); if ( this.options.heightStyle !== "content" ) { this.panels.css( "height", "" ); } }, enable: function( index ) { var disabled = this.options.disabled; if ( disabled === false ) { return; } if ( index === undefined ) { disabled = false; } else { index = this._getIndex( index ); if ( Array.isArray( disabled ) ) { disabled = $.map( disabled, function( num ) { return num !== index ? num : null; } ); } else { disabled = $.map( this.tabs, function( li, num ) { return num !== index ? num : null; } ); } } this._setOptionDisabled( disabled ); }, disable: function( index ) { var disabled = this.options.disabled; if ( disabled === true ) { return; } if ( index === undefined ) { disabled = true; } else { index = this._getIndex( index ); if ( $.inArray( index, disabled ) !== -1 ) { return; } if ( Array.isArray( disabled ) ) { disabled = $.merge( [ index ], disabled ).sort(); } else { disabled = [ index ]; } } this._setOptionDisabled( disabled ); }, load: function( index, event ) { index = this._getIndex( index ); var that = this, tab = this.tabs.eq( index ), anchor = tab.find( ".ui-tabs-anchor" ), panel = this._getPanelForTab( tab ), eventData = { tab: tab, panel: panel }, complete = function( jqXHR, status ) { if ( status === "abort" ) { that.panels.stop( false, true ); } that._removeClass( tab, "ui-tabs-loading" ); panel.removeAttr( "aria-busy" ); if ( jqXHR === that.xhr ) { delete that.xhr; } }; // Not remote if ( this._isLocal( anchor[ 0 ] ) ) { return; } this.xhr = $.ajax( this._ajaxSettings( anchor, event, eventData ) ); // Support: jQuery <1.8 // jQuery <1.8 returns false if the request is canceled in beforeSend, // but as of 1.8, $.ajax() always returns a jqXHR object. if ( this.xhr && this.xhr.statusText !== "canceled" ) { this._addClass( tab, "ui-tabs-loading" ); panel.attr( "aria-busy", "true" ); this.xhr .done( function( response, status, jqXHR ) { // support: jQuery <1.8 // http://bugs.jquery.com/ticket/11778 setTimeout( function() { panel.html( response ); that._trigger( "load", event, eventData ); complete( jqXHR, status ); }, 1 ); } ) .fail( function( jqXHR, status ) { // support: jQuery <1.8 // http://bugs.jquery.com/ticket/11778 setTimeout( function() { complete( jqXHR, status ); }, 1 ); } ); } }, _ajaxSettings: function( anchor, event, eventData ) { var that = this; return { // Support: IE <11 only // Strip any hash that exists to prevent errors with the Ajax request url: anchor.attr( "href" ).replace( /#.*$/, "" ), beforeSend: function( jqXHR, settings ) { return that._trigger( "beforeLoad", event, $.extend( { jqXHR: jqXHR, ajaxSettings: settings }, eventData ) ); } }; }, _getPanelForTab: function( tab ) { var id = $( tab ).attr( "aria-controls" ); return this.element.find( this._sanitizeSelector( "#" + id ) ); } } ); // DEPRECATED // TODO: Switch return back to widget declaration at top of file when this is removed if ( $.uiBackCompat !== false ) { // Backcompat for ui-tab class (now ui-tabs-tab) $.widget( "ui.tabs", $.ui.tabs, { _processTabs: function() { this._superApply( arguments ); this._addClass( this.tabs, "ui-tab" ); } } ); } var widgetsTabs = $.ui.tabs; } ); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /** * @api */ define('uiRegistry',[ 'jquery', 'underscore' ], function ($, _) { 'use strict'; var privateData = new WeakMap(); /** * Extracts private item storage associated * with a provided registry instance. * * @param {Object} container * @returns {Object} */ function getItems(container) { return privateData.get(container).items; } /** * Extracts private requests array associated * with a provided registry instance. * * @param {Object} container * @returns {Array} */ function getRequests(container) { return privateData.get(container).requests; } /** * Wrapper function used for convenient access to the elements. * See 'async' method for examples of usage and comparison * with a regular 'get' method. * * @param {(String|Object|Function)} name - Key of the requested element. * @param {Registry} registry - Instance of a registry * where to search for the element. * @param {(Function|String)} [method] - Optional callback function * or a name of the elements' method which * will be invoked when element is available in registry. * @returns {*} */ function async(name, registry, method) { var args = _.toArray(arguments).slice(3); if (_.isString(method)) { registry.get(name, function (component) { component[method].apply(component, args); }); } else if (_.isFunction(method)) { registry.get(name, method); } else if (!args.length) { return registry.get(name); } } /** * Checks that every property of the query object * is present and equal to the corresponding * property in target object. * Note that non-strict comparison is used. * * @param {Object} query - Query object. * @param {Object} target - Target object. * @returns {Boolean} */ function compare(query, target) { var matches = true, index, keys, key; if (!_.isObject(query) || !_.isObject(target)) { return false; } keys = Object.getOwnPropertyNames(query); index = keys.length; while (matches && index--) { key = keys[index]; /* eslint-disable eqeqeq */ if (target[key] != query[key]) { matches = false; } /* eslint-enable eqeqeq */ } return matches; } /** * Explodes incoming string into object if * string is defined as a set of key = value pairs. * * @param {(String|*)} query - String to be processed. * @returns {Object|*} Either created object or an unmodified incoming * value if conversion was not possible. * @example Sample conversions. * 'key = value, key2 = value2' * => {key: 'value', key2: 'value2'} */ function explode(query) { var result = {}, index, data; if (typeof query !== 'string' || !~query.indexOf('=')) { return query; } query = query.split(','); index = query.length; while (index--) { data = query[index].split('='); result[data[0].trim()] = data[1].trim(); } return result; } /** * Extracts items from the provided data object * which matches specified search criteria. * * @param {Object} data - Data object where to perform a lookup. * @param {(String|Object|Function)} query - Search criteria. * @param {Boolean} findAll - Flag that defines whether to * search for all applicable items or to stop on a first found entry. * @returns {Array|Object|*} */ function find(data, query, findAll) { var iterator, item; query = explode(query); if (typeof query === 'string') { item = data[query]; if (findAll) { return item ? [item] : []; } return item; } iterator = !_.isFunction(query) ? compare.bind(null, query) : query; return findAll ? _.filter(data, iterator) : _.find(data, iterator); } /** * @constructor */ function Registry() { var data = { items: {}, requests: [] }; this._updateRequests = _.debounce(this._updateRequests.bind(this), 10); privateData.set(this, data); } Registry.prototype = { constructor: Registry, /** * Retrieves item from registry which matches specified search criteria. * * @param {(Object|String|Function|Array)} query - Search condition (see examples). * @param {Function} [callback] - Callback that will be invoked when * all of the requested items are available. * @returns {*} * * @example Requesting item by it's name. * var obj = {index: 'test', sample: true}; * * registry.set('first', obj); * registry.get('first') === obj; * => true * * @example Requesting item with a specific properties. * registry.get('sample = 1, index = test') === obj; * => true * registry.get('sample = 0, index = foo') === obj; * => false * * @example Declaring search criteria as an object. * registry.get({sample: true}) === obj; * => true; * * @example Providing custom search handler. * registry.get(function (item) { return item.sample === true; }) === obj; * => true * * @example Sample asynchronous request declaration. * registry.get('index = test', function (item) {}); * * @example Requesting multiple elements. * registry.set('second', {index: 'test2'}); * registry.get(['first', 'second'], function (first, second) {}); */ get: function (query, callback) { if (typeof callback !== 'function') { return find(getItems(this), query); } this._addRequest(query, callback); }, /** * Sets provided item to the registry. * * @param {String} id - Item's identifier. * @param {*} item - Item's data. * returns {Registry} Chainable. */ set: function (id, item) { getItems(this)[id] = item; this._updateRequests(); return this; }, /** * Removes specified item from registry. * Note that search query is not applicable. * * @param {String} id - Item's identifier. * @returns {Registry} Chainable. */ remove: function (id) { delete getItems(this)[id]; return this; }, /** * Retrieves a collection of elements that match * provided search criteria. * * @param {(Object|String|Function)} query - Search query. * See 'get' method for the syntax examples. * @returns {Array} Found elements. */ filter: function (query) { return find(getItems(this), query, true); }, /** * Checks that at least one element in collection * matches provided search criteria. * * @param {(Object|String|Function)} query - Search query. * See 'get' method for the syntax examples. * @returns {Boolean} */ has: function (query) { return !!this.get(query); }, /** * Checks that registry contains a provided item. * * @param {*} item - Item to be checked. * @returns {Boolean} */ contains: function (item) { return _.contains(getItems(this), item); }, /** * Extracts identifier of an item if it's present in registry. * * @param {*} item - Item whose identifier will be extracted. * @returns {String|Undefined} */ indexOf: function (item) { return _.findKey(getItems(this), function (elem) { return item === elem; }); }, /** * Same as a 'get' method except that it returns * a promise object instead of invoking provided callback. * * @param {(String|Function|Object|Array)} query - Search query. * See 'get' method for the syntax examples. * @returns {jQueryPromise} */ promise: function (query) { var defer = $.Deferred(), callback = defer.resolve.bind(defer); this.get(query, callback); return defer.promise(); }, /** * Creates a wrapper function over the provided search query * in order to provide somehow more convenient access to the * registry's items. * * @param {(String|Object|Function)} query - Search criteria. * See 'get' method for the syntax examples. * @returns {Function} * * @example Comparison with a 'get' method on retrieving items. * var module = registry.async('name'); * * module(); * => registry.get('name'); * * @example Asynchronous request. * module(function (component) {}); * => registry.get('name', function (component) {}); * * @example Requesting item and invoking it's method with specified parameters. * module('trigger', true); * => registry.get('name', function (component) { * component.trigger(true); * }); */ async: function (query) { return async.bind(null, query, this); }, /** * Creates new instance of a Registry. * * @returns {Registry} New instance. */ create: function () { return new Registry; }, /** * Adds new request to the queue or resolves it immediately * if all of the required items are available. * * @private * @param {(Object|String|Function|Array)} queries - Search criteria. * See 'get' method for the syntax examples. * @param {Function} callback - Callback that will be invoked when * all of the requested items are available. * @returns {Registry} */ _addRequest: function (queries, callback) { var request; if (!Array.isArray(queries)) { queries = queries ? [queries] : []; } request = { queries: queries.map(explode), callback: callback }; this._canResolve(request) ? this._resolveRequest(request) : getRequests(this).push(request); return this; }, /** * Updates requests list resolving applicable items. * * @private * @returns {Registry} Chainable. */ _updateRequests: function () { getRequests(this) .filter(this._canResolve, this) .forEach(this._resolveRequest, this); return this; }, /** * Resolves provided request invoking it's callback * with items specified in query parameters. * * @private * @param {Object} request - Request object. * @returns {Registry} Chainable. */ _resolveRequest: function (request) { var requests = getRequests(this), items = request.queries.map(this.get, this), index = requests.indexOf(request); request.callback.apply(null, items); if (~index) { requests.splice(index, 1); } return this; }, /** * Checks if provided request can be resolved. * * @private * @param {Object} request - Request object. * @returns {Boolean} */ _canResolve: function (request) { var queries = request.queries; return queries.every(this.has, this); } }; return new Registry; }); define("Magento_Ui/js/lib/registry/registry", function(){}); /** * Copyright © Vaimo Group. All rights reserved. * See LICENSE_VAIMO.txt for license details. */ define('Vaimo_BauhausSe/js/mixins/lib/core/element/element', ['uiRegistry'], function (registry) { 'use strict'; return function (uiElement) { return uiElement.extend({ useSource: function (cb) { if (!this.provider) {return null} if (this.source) { cb(this.source); return; } registry.get(this.provider, cb); }, }); }; }); /** * Copyright © Vaimo Group. All rights reserved. * See LICENSE_VAIMO.txt for license details. */ define('Vaimo_BauhausSe/js/mixins/modal', [ 'jquery', 'jquery/ui' ], function ($) {'use strict'; return function (originalWidget) { const prototype = originalWidget.prototype; let activePopup = undefined; function closeOther(context) { if (activePopup) { const localPopup = activePopup; localPopup.canPopupBeClosed = true; localPopup.closeModal(); localPopup._close();/*skipping transition events (instead of messing with transitionEvent option)*/ } activePopup = context; } $.widget(prototype.namespace + '.' + prototype.widgetName, $[prototype.namespace][prototype.widgetName], { options: { canPopupBeClosedTimeoutTime: 100 }, /** * @inheritDoc */ _close: function () { this._super(); $(document).trigger('closeModal', this.modal); this.element.trigger('closeModalOnElement', this.modal); }, /** * @inheritDoc */ openModal: function () { if (this.options.isOpen) { this.canPopupBeClosed = true; } else { closeOther(this); this.canPopupBeClosed = false; window.clearTimeout(this.canPopupBeClosedTimeout); this.canPopupBeClosedTimeout = window.setTimeout((function () { this.canPopupBeClosed = true; }).bind(this), this.options.canPopupBeClosedTimeoutTime); } const chain = this._super(); $(document).trigger('afterOpenModal', this.modal); return chain; }, /** * @inheritDoc */ closeModal: function () { if (this.canPopupBeClosed) { activePopup = undefined; return this._super(); } return this.element; }, /** * @inheritDoc */ _destroyOverlay: function () { if (this.overlay) { return this._super(); } return undefined; } }); return $[prototype.namespace][prototype.widgetName]; }}); /** * Copyright © Vaimo Group. All rights reserved. * See LICENSE_VAIMO.txt for license details. */ define('Vaimo_BauhausSe/js/mixins/page-cache-mixin', [ 'jquery', 'uiRegistry', 'jquery/ui' ], function ($, registry) { 'use strict'; return function () { var widgetNameSplit = 'mage.formKey'.split('.'); var prototype = { namespace: widgetNameSplit[0], widgetName: widgetNameSplit[1] }; $.widget(prototype.namespace + '.' + prototype.widgetName, $[prototype.namespace][prototype.widgetName], { _create: function () { this._super.apply(this, arguments); registry.set('formKeyIsSet', $.mage.cookies.get('form_key')); }, }); return $[prototype.namespace][prototype.widgetName]; }; }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('mage/apply/scripts',[ 'underscore', 'jquery' ], function (_, $) { 'use strict'; var scriptSelector = 'script[type="text/x-magento-init"]', dataAttr = 'data-mage-init', virtuals = []; /** * Adds components to the virtual list. * * @param {Object} components */ function addVirtual(components) { virtuals.push({ el: false, data: components }); } /** * Merges provided data with a current data * of a elements' "data-mage-init" attribute. * * @param {Object} components - Object with components and theirs configuration. * @param {HTMLElement} elem - Element whose data should be modified. */ function setData(components, elem) { var data = elem.getAttribute(dataAttr); data = data ? JSON.parse(data) : {}; _.each(components, function (obj, key) { if (_.has(obj, 'mixins')) { data[key] = data[key] || {}; data[key].mixins = data[key].mixins || []; data[key].mixins = data[key].mixins.concat(obj.mixins); delete obj.mixins; } }); data = $.extend(true, data, components); data = JSON.stringify(data); elem.setAttribute(dataAttr, data); } /** * Search for the elements by privded selector and extends theirs data. * * @param {Object} components - Object with components and theirs configuration. * @param {String} selector - Selector for the elements. */ function processElems(components, selector) { var elems, iterator; if (selector === '*') { addVirtual(components); return; } elems = document.querySelectorAll(selector); iterator = setData.bind(null, components); _.toArray(elems).forEach(iterator); } /** * Parses content of a provided script node. * Note: node will be removed from DOM. * * @param {HTMLScriptElement} node - Node to be processed. * @returns {Object} */ function getNodeData(node) { var data = node.textContent; node.parentNode.removeChild(node); return JSON.parse(data); } /** * Parses 'script' tags with a custom type attribute and moves it's data * to a 'data-mage-init' attribute of an element found by provided selector. * Note: All found script nodes will be removed from DOM. * * @returns {Array} An array of components not assigned to the specific element. * * @example Sample declaration. * <script type="text/x-magento-init"> * { * "body": { * "path/to/component": {"foo": "bar"} * } * } * </script> * * @example Providing data without selector. * { * "*": { * "path/to/component": {"bar": "baz"} * } * } */ return function () { var nodes = document.querySelectorAll(scriptSelector); _.toArray(nodes) .map(getNodeData) .forEach(function (item) { _.each(item, processElems); }); return virtuals.splice(0, virtuals.length); }; }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('mage/apply/main',[ 'underscore', 'jquery', './scripts' ], function (_, $, processScripts) { 'use strict'; var dataAttr = 'data-mage-init', nodeSelector = '[' + dataAttr + ']'; /** * Initializes components assigned to a specified element via data-* attribute. * * @param {HTMLElement} el - Element to initialize components with. * @param {Object|String} config - Initial components' config. * @param {String} component - Components' path. */ function init(el, config, component) { require([component], function (fn) { var $el; try {if (typeof fn === 'object' && typeof fn[component] === 'function') { fn = fn[component].bind(fn); } if (_.isFunction(fn)) { fn = fn.bind(null, config, el); } else { $el = $(el); if ($el[component]) { // eslint-disable-next-line jquery-no-bind-unbind fn = $el[component].bind($el, config); } }}catch(e){console.error(e)} // Init module in separate task to prevent blocking main thread. setTimeout(typeof fn === 'function' ? fn : (console.warn(`No component executable found for "${component}"`),a=>a)); }, function (error) { if ('console' in window && typeof window.console.error === 'function') { console.error(error); } return true; }); } /** * Parses elements 'data-mage-init' attribute as a valid JSON data. * Note: data-mage-init attribute will be removed. * * @param {HTMLElement} el - Element whose attribute should be parsed. * @returns {Object} */ function getData(el) { var data = el.getAttribute(dataAttr); el.removeAttribute(dataAttr); return { el: el, data: JSON.parse(data) }; } return { /** * Initializes components assigned to HTML elements via [data-mage-init]. * * @example Sample 'data-mage-init' declaration. * data-mage-init='{"path/to/component": {"foo": "bar"}}' */ apply: function (context) { var virtuals = processScripts(!context ? document : context), nodes = document.querySelectorAll(nodeSelector); _.toArray(nodes) .map(getData) .concat(virtuals) .forEach(function (itemContainer) { var element = itemContainer.el; _.each(itemContainer.data, function (obj, key) { if (obj.mixins) { require(obj.mixins, function () { //eslint-disable-line max-nested-callbacks var i, len; for (i = 0, len = arguments.length; i < len; i++) { $.extend( true, itemContainer.data[key], arguments[i](itemContainer.data[key], element) ); } delete obj.mixins; init.call(null, element, obj, key); }); } else { init.call(null, element, obj, key); } } ); }); }, applyFor: init }; }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('mage/mage',[ 'jquery', 'mage/apply/main' ], function ($, mage) { 'use strict'; /** * Main namespace for Magento extensions * @type {Object} */ $.mage = $.mage || {}; /** * Plugin mage, initialize components on elements * @param {String} name - Components' path. * @param {Object} config - Components' config. * @returns {JQuery} Chainable. */ $.fn.mage = function (name, config) { config = config || {}; this.each(function (index, el) { mage.applyFor(el, config, name); }); return this; }; $.extend($.mage, { /** * Handle all components declared via data attribute * @return {Object} $.mage */ init: function () { mage.apply(); return this; }, /** * Method handling redirects and page refresh * @param {String} url - redirect URL * @param {(undefined|String)} type - 'assign', 'reload', 'replace' * @param {(undefined|Number)} timeout - timeout in milliseconds before processing the redirect or reload * @param {(undefined|Boolean)} forced - true|false used for 'reload' only */ redirect: function (url, type, timeout, forced) { var _redirect; forced = !!forced; timeout = timeout || 0; type = type || 'assign'; /** * @private */ _redirect = function () { window.location[type](type === 'reload' ? forced : url); }; timeout ? setTimeout(_redirect, timeout) : _redirect(); }, /** * Checks if provided string is a valid selector. * @param {String} selector - Selector to check. * @returns {Boolean} */ isValidSelector: function (selector) { try { document.querySelector(selector); return true; } catch (e) { return false; } } }); /** * Init components inside of dynamically updated elements */ $(document).on('contentUpdated', 'body', function () { if (mage) { mage.apply(); } }); return $.mage; }); if (typeof window === 'undefined') { /*TODO: remove after Magento will understand they've commited load (text.js replaces requirejs' text.js) file that cannot work in no broswers environment*/ /** * @license RequireJS text 2.0.12 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/requirejs/text for details */ /*jslint regexp: true */ /*global require, XMLHttpRequest, ActiveXObject, define, window, process, Packages, java, location, Components, FileUtils */ define('text', ['module'], function (module) { 'use strict'; var text, fs, Cc, Ci, xpcIsWindows, progIds = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'], xmlRegExp = /^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im, bodyRegExp = /<body[^>]*>\s*([\s\S]+)\s*<\/body>/im, hasLocation = typeof location !== 'undefined' && location.href, defaultProtocol = hasLocation && location.protocol && location.protocol.replace(/\:/, ''), defaultHostName = hasLocation && location.hostname, defaultPort = hasLocation && (location.port || undefined), buildMap = {}, masterConfig = (module.config && module.config()) || {}; text = { version: '2.0.12', strip: function (content) { //Strips <?xml ...?> declarations so that external SVG and XML //documents can be added to a document without worry. Also, if the string //is an HTML document, only the part inside the body tag is returned. if (content) { content = content.replace(xmlRegExp, ""); var matches = content.match(bodyRegExp); if (matches) { content = matches[1]; } } else { content = ""; } return content; }, jsEscape: function (content) { return content.replace(/(['\\])/g, '\\$1') .replace(/[\f]/g, "\\f") .replace(/[\b]/g, "\\b") .replace(/[\n]/g, "\\n") .replace(/[\t]/g, "\\t") .replace(/[\r]/g, "\\r") .replace(/[\u2028]/g, "\\u2028") .replace(/[\u2029]/g, "\\u2029"); }, createXhr: masterConfig.createXhr || function () { //Would love to dump the ActiveX crap in here. Need IE 6 to die first. var xhr, i, progId; if (typeof XMLHttpRequest !== "undefined") { return new XMLHttpRequest(); } else if (typeof ActiveXObject !== "undefined") { for (i = 0; i < 3; i += 1) { progId = progIds[i]; try { xhr = new ActiveXObject(progId); } catch (e) {} if (xhr) { progIds = [progId]; // so faster next time break; } } } return xhr; }, /** * Parses a resource name into its component parts. Resource names * look like: module/name.ext!strip, where the !strip part is * optional. * @param {String} name the resource name * @returns {Object} with properties "moduleName", "ext" and "strip" * where strip is a boolean. */ parseName: function (name) { var modName, ext, temp, strip = false, index = name.indexOf("."), isRelative = name.indexOf('./') === 0 || name.indexOf('../') === 0; if (index !== -1 && (!isRelative || index > 1)) { modName = name.substring(0, index); ext = name.substring(index + 1, name.length); } else { modName = name; } temp = ext || modName; index = temp.indexOf("!"); if (index !== -1) { //Pull off the strip arg. strip = temp.substring(index + 1) === "strip"; temp = temp.substring(0, index); if (ext) { ext = temp; } else { modName = temp; } } return { moduleName: modName, ext: ext, strip: strip }; }, xdRegExp: /^((\w+)\:)?\/\/([^\/\\]+)/, /** * Is an URL on another domain. Only works for browser use, returns * false in non-browser environments. Only used to know if an * optimized .js version of a text resource should be loaded * instead. * @param {String} url * @returns Boolean */ useXhr: function (url, protocol, hostname, port) { var uProtocol, uHostName, uPort, match = text.xdRegExp.exec(url); if (!match) { return true; } uProtocol = match[2]; uHostName = match[3]; uHostName = uHostName.split(':'); uPort = uHostName[1]; uHostName = uHostName[0]; return (!uProtocol || uProtocol === protocol) && (!uHostName || uHostName.toLowerCase() === hostname.toLowerCase()) && ((!uPort && !uHostName) || uPort === port); }, finishLoad: function (name, strip, content, onLoad) { content = strip ? text.strip(content) : content; if (masterConfig.isBuild) { buildMap[name] = content; } onLoad(content); }, load: function (name, req, onLoad, config) { //Name has format: some.module.filext!strip //The strip part is optional. //if strip is present, then that means only get the string contents //inside a body tag in an HTML string. For XML/SVG content it means //removing the <?xml ...?> declarations so the content can be inserted //into the current doc without problems. // Do not bother with the work if a build and text will // not be inlined. if (config && config.isBuild && !config.inlineText) { onLoad(); return; } masterConfig.isBuild = config && config.isBuild; var parsed = text.parseName(name), nonStripName = parsed.moduleName + (parsed.ext ? '.' + parsed.ext : ''), url = req.toUrl(nonStripName), useXhr = (masterConfig.useXhr) || text.useXhr; // Do not load if it is an empty: url if (url.indexOf('empty:') === 0) { onLoad(); return; } //Load the text. Use XHR if possible and in a browser. if (!hasLocation || useXhr(url, defaultProtocol, defaultHostName, defaultPort)) { text.get(url, function (content) { text.finishLoad(name, parsed.strip, content, onLoad); }, function (err) { if (onLoad.error) { onLoad.error(err); } }); } else { //Need to fetch the resource across domains. Assume //the resource has been optimized into a JS module. Fetch //by the module name + extension, but do not include the //!strip part to avoid file system issues. req([nonStripName], function (content) { text.finishLoad(parsed.moduleName + '.' + parsed.ext, parsed.strip, content, onLoad); }); } }, write: function (pluginName, moduleName, write, config) { if (buildMap.hasOwnProperty(moduleName)) { var content = text.jsEscape(buildMap[moduleName]); write.asModule(pluginName + "!" + moduleName, "define(function () { return '" + content + "';});\n"); } }, writeFile: function (pluginName, moduleName, req, write, config) { var parsed = text.parseName(moduleName), extPart = parsed.ext ? '.' + parsed.ext : '', nonStripName = parsed.moduleName + extPart, //Use a '.js' file name so that it indicates it is a //script that can be loaded across domains. fileName = req.toUrl(parsed.moduleName + extPart) + '.js'; //Leverage own load() method to load plugin value, but only //write out values that do not have the strip argument, //to avoid any potential issues with ! in file names. text.load(nonStripName, req, function (value) { //Use own write() method to construct full module value. //But need to create shell that translates writeFile's //write() to the right interface. var textWrite = function (contents) { return write(fileName, contents); }; textWrite.asModule = function (moduleName, contents) { return write.asModule(moduleName, fileName, contents); }; text.write(pluginName, nonStripName, textWrite, config); }, config); } }; if (masterConfig.env === 'node' || (!masterConfig.env && typeof process !== "undefined" && process.versions && !!process.versions.node && !process.versions['node-webkit'])) { //Using special require.nodeRequire, something added by r.js. fs = require.nodeRequire('fs'); text.get = function (url, callback, errback) { try { var file = fs.readFileSync(url, 'utf8'); //Remove BOM (Byte Mark Order) from utf8 files if it is there. if (file.indexOf('\uFEFF') === 0) { file = file.substring(1); } callback(file); } catch (e) { if (errback) { errback(e); } } }; } else if (masterConfig.env === 'xhr' || (!masterConfig.env && text.createXhr())) { text.get = function (url, callback, errback, headers) { var xhr = text.createXhr(), header; xhr.open('GET', url, true); //Allow plugins direct access to xhr headers if (headers) { for (header in headers) { if (headers.hasOwnProperty(header)) { xhr.setRequestHeader(header.toLowerCase(), headers[header]); } } } //Allow overrides specified in config if (masterConfig.onXhr) { masterConfig.onXhr(xhr, url); } xhr.onreadystatechange = function (evt) { var status, err; //Do not explicitly handle errors, those should be //visible via console output in the browser. if (xhr.readyState === 4) { status = xhr.status || 0; if (status > 399 && status < 600) { //An http 4xx or 5xx error. Signal an error. err = new Error(url + ' HTTP status: ' + status); err.xhr = xhr; if (errback) { errback(err); } } else { callback(xhr.responseText); } if (masterConfig.onXhrComplete) { masterConfig.onXhrComplete(xhr, url); } } }; xhr.send(null); }; } else if (masterConfig.env === 'rhino' || (!masterConfig.env && typeof Packages !== 'undefined' && typeof java !== 'undefined')) { //Why Java, why is this so awkward? text.get = function (url, callback) { var stringBuffer, line, encoding = "utf-8", file = new java.io.File(url), lineSeparator = java.lang.System.getProperty("line.separator"), input = new java.io.BufferedReader(new java.io.InputStreamReader(new java.io.FileInputStream(file), encoding)), content = ''; try { stringBuffer = new java.lang.StringBuffer(); line = input.readLine(); // Byte Order Mark (BOM) - The Unicode Standard, version 3.0, page 324 // http://www.unicode.org/faq/utf_bom.html // Note that when we use utf-8, the BOM should appear as "EF BB BF", but it doesn't due to this bug in the JDK: // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058 if (line && line.length() && line.charAt(0) === 0xfeff) { // Eat the BOM, since we've already found the encoding on this file, // and we plan to concatenating this buffer with others; the BOM should // only appear at the top of a file. line = line.substring(1); } if (line !== null) { stringBuffer.append(line); } while ((line = input.readLine()) !== null) { stringBuffer.append(lineSeparator); stringBuffer.append(line); } //Make sure we return a JavaScript string and not a Java string. content = String(stringBuffer.toString()); //String } finally { input.close(); } callback(content); }; } else if (masterConfig.env === 'xpconnect' || (!masterConfig.env && typeof Components !== 'undefined' && Components.classes && Components.interfaces)) { //Avert your gaze! Cc = Components.classes; Ci = Components.interfaces; Components.utils['import']('resource://gre/modules/FileUtils.jsm'); xpcIsWindows = ('@mozilla.org/windows-registry-key;1' in Cc); text.get = function (url, callback) { var inStream, convertStream, fileObj, readData = {}; if (xpcIsWindows) { url = url.replace(/\//g, '\\'); } fileObj = new FileUtils.File(url); //XPCOM, you so crazy try { inStream = Cc['@mozilla.org/network/file-input-stream;1'] .createInstance(Ci.nsIFileInputStream); inStream.init(fileObj, 1, 0, false); convertStream = Cc['@mozilla.org/intl/converter-input-stream;1'] .createInstance(Ci.nsIConverterInputStream); convertStream.init(inStream, "utf-8", inStream.available(), Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER); convertStream.readString(inStream.available(), readData); convertStream.close(); inStream.close(); callback(readData.value); } catch (e) { throw new Error((fileObj && fileObj.path || '') + ': ' + e); } }; } return text; }); } else { /** * Copyright © Vaimo Group. All rights reserved. * See LICENSE_VAIMO.txt for license details. */ /* inspired by http://github.com/requirejs/text */ /*global XMLHttpRequest, XDomainRequest */ define('text', ['module'], function (module) { 'use strict'; var xmlRegExp = /^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im, bodyRegExp = /<body[^>]*>\s*([\s\S]+)\s*<\/body>/im, stripReg = /!strip$/i, defaultConfig = module.config && module.config() || {}; /** * Strips <?xml ...?> declarations so that external SVG and XML documents can be * added to a document without worry. * Also, if the string is an HTML document, only the part inside the body tag is returned. * * @param {String} external * @returns {String} */ function stripContent(external) { var matches; if (!external) { return ''; } matches = external.match(bodyRegExp); external = matches ? matches[1] : external.replace(xmlRegExp, ''); return external; } /** * Checks that url match current location * * @param {String} url * @returns {Boolean} */ function sameDomain(url) { var uProtocol, uHostName, uPort, xdRegExp = /^([\w:]+)?\/\/([^\/\\]+)/i, location = window.location, match = xdRegExp.exec(url); if (!match) { return true; } uProtocol = match[1]; uHostName = match[2]; uHostName = uHostName.split(':'); uPort = uHostName[1] || ''; uHostName = uHostName[0]; return (!uProtocol || uProtocol === location.protocol) && (!uHostName || uHostName.toLowerCase() === location.hostname.toLowerCase()) && (!uPort && !uHostName || uPort === location.port); } /** * @returns {XMLHttpRequest|XDomainRequest|null} */ function createRequest(url) { var xhr = new XMLHttpRequest(); if (!sameDomain(url) && typeof XDomainRequest !== 'undefined') { xhr = new XDomainRequest(); } return xhr; } /** * XHR requester. Returns value to callback. * * @param {String} url * @param {Function} callback * @param {Function} fail * @param {Object} headers */ function getContent(url, callback, fail, headers) { var xhr = createRequest(url), header; xhr.open('GET', url); /*eslint-disable max-depth */ if ('setRequestHeader' in xhr && headers) { for (header in headers) { if (headers.hasOwnProperty(header)) { xhr.setRequestHeader(header.toLowerCase(), headers[header]); } } } /** * @inheritdoc */ xhr.onreadystatechange = function () { var status, err; //Do not explicitly handle errors, those should be //visible via console output in the browser. if (xhr.readyState === 4) { status = xhr.status || 0; if (status > 399 && status < 600) { //An http 4xx or 5xx error. Signal an error. err = new Error(url + ' HTTP status: ' + status); err.xhr = xhr; if (fail) { fail(err); } } else { callback(xhr.responseText); if (defaultConfig.onXhrComplete) { defaultConfig.onXhrComplete(xhr, url); } } } }; /*eslint-enable max-depth */ if (defaultConfig.onXhr) { defaultConfig.onXhr(xhr, url); } xhr.send(); } /** * Main method used by RequireJs. * * @param {String} name - has format: some.module.filext!strip * @param {Function} req * @param {Function|undefined} onLoad */ function loadContent(name, req, onLoad) { var toStrip = stripReg.test(name), url = req.toUrl(name.replace(stripReg, '')), headers = defaultConfig.headers; getContent(url, function (content) { content = toStrip ? stripContent(content) : content; onLoad(content); }, onLoad.error, headers); } return { load: loadContent, get: getContent }; }); } ; define('text!js-translation.json',[],function () { return '{" Example: ":" Exempel: "," is required.":" \\u00e4r obligatorisk.","${ $.visible } out of ${ $.total } visible":"${ $.visible } av ${ $.total } synliga","%1 items":"%1 artiklar","%price \\/unit":"%price \\/st","%qty items in stock":"%qty st i weblager","* Required Fields":"* Obligatoriska f\\u00e4lt","-- Please Select Billing Agreement--":"-- Var god v\\u00e4lj faktureringsavtal --","<strong>%s<\\/strong> was not uploaded<br\\/>":"<strong>%s<\\/strong> laddades inte upp.<br\\/>","A positive or negative non-decimal number please":"Ett positivt eller negativt tal, ej decimaltal tack.","Account Number":"Kontonummer","Action":"\\u00c5tg\\u00e4rd","Actions":"\\u00c5tg\\u00e4rder","Actual Price":"Faktiskt pris","Add":"L\\u00e4gg till","Add New User":"L\\u00e4gg till ny anv\\u00e4ndare","Add all to favorites":"G\\u00f6r alla till favoriter","Add to Cart":"L\\u00e4gg i varukorg","Add to Wish List":"L\\u00e4gg till i favoriter","Added":"Tillagd","Added to Wish List":"Tillagd i favoriter","Added to the Shopping Cart":"Tillagt i varukorgen","Adding...":"L\\u00e4gg i varukorg","Address":"Adress","Address and city":"Adress och postort","An error occurred":"Ett fel uppstod","Apply":"Anv\\u00e4nd","Apply Discount":"Till\\u00e4mpa rabatt","Apply Discount Code":"Till\\u00e4mpa rabattkod","Are you sure you want to delete this address?":"\\u00c4r du s\\u00e4ker p\\u00e5 att du vill ta bort denna adress?","Are you sure you would like to remove this item from the shopping cart?":"\\u00c4r du s\\u00e4ker p\\u00e5 att du vill ta bort denna produkt fr\\u00e5n varukorgen?","Assign":"Tilldela","Attention":"Meddelande","Attention: Captcha is case sensitive.":"Notera: Captcha \\u00e4r skiftesl\\u00e4gesk\\u00e4nsligt.","Availability":"Tillg\\u00e4nglighet","Available bonus points:":"Tillg\\u00e4ngliga bonuspo\\u00e4ng:","BAUHAUS Company Service":"BAUHAUS F\\u00f6retagsservice","Back":"Tillbaka","Backup options":"Backup-val","BankID did not open?":"\\u00d6ppnades inte BankID?","Bauhaus in store sales system":"BAUHAUS varuhusf\\u00f6rs\\u00e4ljning","Billing & shipping address":"Fakturerings- och leveransadress","Billing Address":"Faktureringsadress","Book advice":"Boka r\\u00e5dgivning","Book_send_request_e_s_p":"Boka","Brands":"Varum\\u00e4rken","Browse to find or drag image here":"Bl\\u00e4ddra eller dra bild hit","Buy one product and get another one with a discount.":"K\\u00f6p en produkt och f\\u00e5 en annan till en rabatt","Campaign":"Kampanj","Cancel":"Avbryt","Cancel coupon":"Avbryt kupong","Cannot deliver to box address!":"Kan inte leverera till boxadress!","Card Number":"Kortnummer","Card Verification Number":"Verifieringsnummer f\\u00f6r Bankkort","Card Verification Number Visual Reference":"Visuell referens f\\u00f6r verifieringsnummer f\\u00f6r bankkort","Card type does not match credit card number.":"Korttyp matchar inte kreditkortsnummer.","Carrier Title":"Expedit\\u00f6r titel","Cart Subtotal":"Orderv\\u00e4rde","Categories":"Kategorier","Change":"\\u00c4ndra","Change pickup location":"\\u00c4ndra postombud","Changes have been made to this section that have not been saved.":"\\u00c4ndringar har gjorts i den h\\u00e4r sektionen, men inte sparats.","Choose a selection...":"V\\u00e4lj ett alternativ...","Choose service point":"V\\u00e4lj postombud","Choose store":"V\\u00e4lj Varuhus","City":"Stad","City, Country":"Ort, Land","Clear All":"Rensa alla","Clear all":"Rensa alla filter","Click for price":"Klicka f\\u00f6r pris","Close":"St\\u00e4ng","Closed":"St\\u00e4ngd","Company":"F\\u00f6retag","Company Name":"F\\u00f6retagsnamn (juridiskt):","Confirm":"Bekr\\u00e4fta","Confirm Email Address":"Bekr\\u00e4fta e-postadress","Contact details":"Kontaktuppgifter","Continue":"Forts\\u00e4tt","Continue to PayPal":"Forts\\u00e4tt till PayPal","Continue with BankID":"Forts\\u00e4tt med BankID","Could not add your %s code.":"Ditt %s kunde tyv\\u00e4rr inte l\\u00e4ggas till.","Create an Account":"Skapa ett konto","Creating an account has many benefits:":"Att registrera sig som kund hos oss har m\\u00e5nga f\\u00f6rdelar","Credit Card Information":"Bankkortsinformation","Credit Card Number":"Bankkortsnummer","Credit Terms and Conditions":"Kreditvillkor","Credit card number does not match credit card type.":"Kreditkortsnummer matchar inte typ av kreditkort.","Custom":"Anpassad","Customer Card Number":"Kundkortsnummer","Day":"Dag","Default":"F\\u00f6rvalt","Default View":"F\\u00f6rvald vy","Delete":"Ta bort","Delete image":"Ta bort bild","Deliver to:":"Leverans till:","Delivery Terms and Conditions":"Leveransvillkor","Delivery to another address":"Leverera till en annan adress","Delivery to project address":"Leverera till projektadress","Description":"Beskrivning","Deselect All":"Avmarkera alla","Deselect All on This Page":"Avmarkera alla p\\u00e5 den h\\u00e4r sidan","Discard selections":"Inget alternativ","Discount":"Rabatt","Do not have Mobile BankID?":"Har du inte mobilt BankID?","Done":"Klart","Earliest %s":"Tidigast %s","Edit":"\\u00c4ndra","Edit User":"\\u00c4ndra anv\\u00e4ndare","Edit Your Cart":"\\u00c4ndra i din varukorg","Edit project":"Redigera projekt","Email Address":"E-postadress","Empty Value.":"Tomt v\\u00e4rde.","Energy label":"Energietikett","Enter discount code":"Ange rabattkod","Enter your destination to get a shipping estimate.":"V\\u00e4lj destination f\\u00f6r att f\\u00e5 en uppskattad fraktkostnad.","Error":"Fel uppstod","Estimate Shipping and Tax":"Ber\\u00e4kna frakt och moms","Estimate Tax":"Ber\\u00e4kna moms","Estimated Total":"Summa","Excl. Tax":"Exkl. moms","Expiration Date":"Utg\\u00e5ngsdatum","Export":"Exportera","Field ":"F\\u00e4lt ","File you are trying to upload exceeds maximum file size limit.":"Storleken p\\u00e5 filen du f\\u00f6rs\\u00f6ker ladda upp \\u00e4r st\\u00f6rre \\u00e4n gr\\u00e4nsen.","File you are trying to upload exceeds maximum of %s.":"Storleken p\\u00e5 filen du f\\u00f6rs\\u00f6ker ladda upp \\u00e4r st\\u00f6rre \\u00e4n %s.","Fill in the form and we will call you":"Fyll i formul\\u00e4ret s\\u00e5 ringer vi upp dig","Fill in the form and we will contact you":"Fyll i formul\\u00e4ret s\\u00e5 kontakta vi upp dig","Filters":"Filtrera","Final Price":"Slutpris","First Name":"F\\u00f6rnamn","Forgot Your Password?":"Gl\\u00f6mt ditt l\\u00f6senord?","Forgot an Item?":"Gl\\u00f6mt en produkt?","Friday":"Fredag","From %1":"Fr\\u00e5n %1","From:":"Fr\\u00e5n:","Full Name":"Fullst\\u00e4ndigt namn","Gift Message (optional)":"Presentmeddelande (valfritt)","Go to Checkout":"G\\u00e5 till kassan","Go to Details Page":"G\\u00e5 till detaljsidan","Go to Home Page":"G\\u00e5 till startsidan","Grand Total":"Att betala","Guest checkout is disabled.":"G\\u00e4stkassan \\u00e4r inaktiverad.","HTML tags are not allowed.":"HTML taggar \\u00e4r till\\u00e5tna","Help":"Hj\\u00e4lp","Holidays":"H\\u00f6gtider","Home":"Hem","If you believe it is the right one you can ignore this notice.":"Du kan ignorera detta meddelande om du \\u00e4r s\\u00e4ker p\\u00e5 att postkoden \\u00e4r korrekt.","In stock in:":"I lager i:","In stock online":"I lager online","Incl. Tax":"Inkl. moms","Incorrect Captcha":"Felaktig Captcha","Incorrect credit card expiration date.":"Felaktigt kreditkorts utg\\u00e5ngsdatum.","Insert Widget":"L\\u00e4gg till Widget","Invalid date":"Ogiltigt datum","Invalid format.":"Ogiltigt format.","Item in Cart":"Artikel i varukorg","Items in Cart":"Artiklar i varukorg","Keyword":"Nyckelord","Last Name":"Efternamn","Let us perform a quick verification":"L\\u00e5t oss g\\u00f6ra en snabb verifiering","Letters only please":"Endast bokst\\u00e4ver, tack","Letters or punctuation only please":"Endast bokst\\u00e4ver och skiljetecken, tack","Letters, numbers, spaces or underscores only please":"Endast bokst\\u00e4ver, siffror, mellanslag eller understreck, tack","Loading":"Laddar","Loading...":"Laddar...","Log out":"Logga ut","Login":"Logga in","Login or Register":"Logga in eller skapa konto","Make Check payable to:":"G\\u00f6r checken p\\u00e5:","Manual order session has been cleaned":"Manuell ordningssession har rensats","Max":"Maximalt","Medium":"Medel","Message":"Meddelande","Message:":"Meddelande:","Method %s does not exist on jQuery.decorate":"Metoden %s existerar inte p\\u00e5 jQuery.decorate","Min":"Minst","Minimum of different classes of characters in password is %1. Classes of characters: Lower Case, Upper Case, Digits, Special Characters.":"V\\u00e4nligen ange ett starkt l\\u00f6senord som inneh\\u00e5ller b\\u00e5de sm\\u00e5 och stora bokst\\u00e4ver, siffror samt specialtecken.","Mobile Number":"Mobilnummer","Monday":"M\\u00e5ndag","Month":"M\\u00e5nad","Multiple choices":"Flera val","Multiple deliveries":"Flera leveranser","My Cart":"Varukorgen","My billing and shipping address are the same":"Min faktura- och leveransadress \\u00e4r desamma.","Name":"Namn","New Address":"Ny adress","New View":"Ny vy","New item":"Nyhet","Next":"N\\u00e4sta","No":"Nej","No Password":"Inget l\\u00f6senord","No Payment Methods":"Inga betals\\u00e4tt","No Payment method available.":"Inget betals\\u00e4tt tillg\\u00e4ngligt.","No filter for:":"Inget filter f\\u00f6r:","No records found.":"Inga poster har hittats.","No results for \\"%1\\", try again.":"Inga tr\\u00e4ffar p\\u00e5 \\"%1\\", f\\u00f6rs\\u00f6k igen.","No white space please":"Inga blanksteg, tack","Not yet calculated":"\\u00c4nnu ej ber\\u00e4knad","Not you?":"Inte du?","Number must start with {0}":"Numret m\\u00e5ste b\\u00f6rja med {0}","Off":"Av","Ok, close":"Ok, st\\u00e4ng","On":"P\\u00e5","Open BankID app on mobile device":"\\u00d6ppna BankID-appen p\\u00e5 din mobila enhet","Open BankID app on this device":"\\u00d6ppna BankID p\\u00e5 den h\\u00e4r enheten","Options":"Alternativ","Or":"Eller","Ord. Price:":"Ord. pris:","Order Summary":"Granska best\\u00e4llning","Order number":"Ert ordernummer","Other addresses montage service could be ordered for":"Annan adress som montaget \\u00f6nskas utf\\u00f6ras p\\u00e5","Other available goods with the same discount":"Varor med samma rabatt","Out of stock":"Ej i lager","Out of stock online":"Tillf\\u00e4lligt slut p\\u00e5 n\\u00e4tet","Outgoing":"Utg\\u00e5ende","Page":"Sida","Pages and guides":"Sidor & guider","Password":"L\\u00f6senord","Payment Information":"Information om betalning","Payment Method":"Betalningss\\u00e4tt","Person SSN":"Personnummer","Pick-up Terms and Conditions":"Villkor","Place Order":"L\\u00e4gg best\\u00e4llning","Please Select":"V\\u00e4nligen v\\u00e4lj","Please choose a payment method.":"V\\u00e4nligen v\\u00e4lj betalningsmetod.","Please enter %s characters.":"V\\u00e4nligen ange %s tecken.","Please enter 6 or more characters. Leading and trailing spaces will be ignored.":"V\\u00e4nligen ange 6 eller fler tecken. Mellanslag i b\\u00f6rjan och slutet ignoreras.","Please enter 7 or more characters, using both numeric and alphabetic.":"V\\u00e4nligen ange 7 eller fler tecken, b\\u00e5de numeriska och alfabetiska.","Please enter a correct date":"V\\u00e4nligen ange ett korrekt datum","Please enter a date between %min and %max.":"V\\u00e4nligen ange ett datum mellan %min och %max.","Please enter a date from the past.":"V\\u00e4nligen ange ett datum som har passerat.","Please enter a number 0 or greater in this field.":"V\\u00e4nligen ange en siffra 0 eller st\\u00f6rre i detta f\\u00e4lt.","Please enter a number greater than 0 in this field.":"V\\u00e4nligen ange ett tal som \\u00e4r st\\u00f6rre \\u00e4n 0 i detta f\\u00e4lt.","Please enter a valid $ amount. For example $100.00.":"V\\u00e4nligen ange ett giltigt belopp. Exempelvis 100.","Please enter a valid IP v4 address.":"V\\u00e4nligen ange en giltig IP v4-adress.","Please enter a valid IP v6 address.":"V\\u00e4nligen ange en giltig IP v6 address.","Please enter a valid URL Key (Ex: \\"example-page\\", \\"example-page.html\\" or \\"anotherlevel\\/example-page\\").":"V\\u00e4nligen ange en giltig URL-key (t.ex. \\"exempelsida\\", \\"exempelsida.html\\" eller \\"annansida\\/exempelsida\\").","Please enter a valid URL. For example http:\\/\\/www.example.com or www.example.com.":"V\\u00e4nligen ange en giltig url, t.ex. http:\\/\\/www.exempel.com or www.exempel.com.","Please enter a valid URL. Protocol is required (http:\\/\\/, https:\\/\\/ or ftp:\\/\\/).":"V\\u00e4nligen ange en giltig URL. Protokoll kr\\u00e4vs (http:\\/\\/, https:\\/\\/ eller ftp:\\/\\/).","Please enter a valid XML-identifier (Ex: something_1, block5, id-4).":"V\\u00e4nligen ange en giltig XML-identifierare (t.ex: something_1, block5, id-4).","Please enter a valid address":"V\\u00e4nligen ange en giltig adress","Please enter a valid credit card number.":"V\\u00e4nligen ange ett giltigt bankkortsnummer.","Please enter a valid credit card verification number.":"Ange ett giltigt kreditkort kontrollnummer.","Please enter a valid date.":"V\\u00e4nligen ange ett giltigt datum.","Please enter a valid day (1-%1).":"V\\u00e4nligen ange en giltig dag (1-%1).","Please enter a valid email address (Ex: johndoe@domain.com).":"V\\u00e4nligen ange en giltig e-postadress utan otill\\u00e5tna tecken som \\u00c5,\\u00c4,\\u00d6. Tex: namn@example.com","Please enter a valid email address.":"V\\u00e4nligen ange en giltig e-postadress.","Please enter a valid fax number (Ex: 123-456-7890).":"V\\u00e4nligen ange ett giltigt faxnummer (t.ex: 123-456-7890).","Please enter a valid mobile number, for example 0721111111":"V\\u00e4nligen ange ett giltigt mobilnummer, exempelvis 0721111111","Please enter a valid number in this field.":"V\\u00e4nligen ange ett giltigt nummer i detta f\\u00e4lt.","Please enter a valid phone number. For example (123) 456-7890 or 123-456-7890.":"V\\u00e4nligen ange ett giltigt telefonnummer, exempelvis 08-123 456.","Please enter a valid social security number (Ex: 123-45-6789).":"V\\u00e4nligen ange ett giltigt personnummer, exempelvis 010101-0106.","Please enter a valid time, between 00:00 am and 12:00 pm":"V\\u00e4nligen ange en giltig tid, mellan 00:00 fm och 12:00 em","Please enter a valid time, between 00:00 and 23:59":"V\\u00e4nligen ange en giltig tid, mellan 00:00 och 23:59","Please enter a valid value from list":"V\\u00e4nligen ange ett giltigt v\\u00e4rde fr\\u00e5n listan","Please enter a valid value, ex: 10,20,30":"V\\u00e4nligen ange ett giltigt v\\u00e4rde, t.ex. 10, 20, 30","Please enter a valid year (1900-%1).":"V\\u00e4nligen ange ett giltigt \\u00e5r (1900-%1).","Please enter a valid zip code (Ex: 90602 or 90602-1234).":"V\\u00e4nligen ange ett giltigt postnummer (t.ex: 12345 eller 123 45).","Please enter a valid zip code.":"V\\u00e4nligen ange ett giltigt postnummer.","Please enter a value greater than or equal to %s.":"V\\u00e4nligen ange ett v\\u00e4rde st\\u00f6rre \\u00e4n eller lika med %s.","Please enter a value greater than or equal to {0}.":"V\\u00e4nligen ange ett v\\u00e4rde st\\u00f6rre \\u00e4n eller lika med {0}.","Please enter a value less than or equal to %s.":"V\\u00e4nligen ange ett v\\u00e4rde mindre \\u00e4n eller lika med %s.","Please enter a value less than or equal to {0}.":"V\\u00e4nligen ange ett v\\u00e4rde mindre \\u00e4n eller lika med {0}.","Please enter at least {0} characters":"V\\u00e4nligen ange minst {0} tecken","Please enter at least {0} words.":"V\\u00e4nligen ange minst {0} ord.","Please enter between {0} and {1} words.":"V\\u00e4nligen ange mellan {0} och {1} ord.","Please enter issue number or start date for switch\\/solo card type.":"Ange ett l\\u00f6pnummer eller startdatum f\\u00f6r switch\\/solo korttyp.","Please enter less or equal than {0} characters.":"Numret ska vara max {0} tecken.","Please enter less or equal than {0} symbols.":"V\\u00e4nligen ange mindre \\u00e4n eller lika med {0} symboler.","Please enter more or equal than {0} characters.":"Numret ska vara minst {0} tecken.","Please enter more or equal than {0} symbols.":"V\\u00e4nligen ange st\\u00f6rre \\u00e4n eller lika med {0} symboler.","Please enter positive number in this field.":"V\\u00e4nligen ange positiva tal i detta f\\u00e4lt.","Please enter the same value again.":"V\\u00e4nligen se till att dina l\\u00f6senord \\u00f6verensst\\u00e4mmer.","Please enter {0} words or less.":"V\\u00e4nligen ange {0} ord eller f\\u00e4rre.","Please input a valid CSS-length (Ex: 100px, 77pt, 20em, .5ex or 50%).":"V\\u00e4nligen ange en giltig CSS-l\\u00e4ngd (t.ex: 100px, 77pt, 20em, .5ex or 50%).","Please make sure your Email Addresses match.":"V\\u00e4nligen se till att dina E-postadresserna matchar","Please make sure your organisation ssn is correct.":"Kontrollera att ni har skrivit in ett korrekt organisationsnummer.","Please make sure your passwords match.":"V\\u00e4nligen se till att dina l\\u00f6senord \\u00f6verensst\\u00e4mmer.","Please make sure your postal code is %1 characters long.":"Se till att du har angett ett %1-symbols l\\u00e5ngt postnummer.","Please make sure your social security number is correct":"Kontrollera att ni har skrivit in ett korrekt personnummer","Please make sure your social security number is correct.":"Kontrollera att ni har skrivit in ett korrekt personnummer.","Please make sure your social security number is {0} or {1} numbers long.":"Se till att du har angett ett {0}-nummer eller {1}-nummer l\\u00e5ngt personnummer.","Please make sure your social security number is {0} symbols long.":"V\\u00e4nligen ange ditt personnummer med {0} siffror","Please rate the delivery.":"V\\u00e4nligen betygs\\u00e4tt leveransen.","Please select State\\/Province.":"V\\u00e4nligen v\\u00e4lj region.","Please select an option.":"V\\u00e4nligen v\\u00e4lj ett alternativ.","Please select one of the options.":"V\\u00e4nligen v\\u00e4lj ett av alternativen.","Please select store":"V\\u00e4nligen ange varuhus","Please specify a valid mobile number":"V\\u00e4nligen ange ett giltigt mobilnummer","Please specify a valid phone number":"V\\u00e4nligen ange ett giltigt telefonnummer","Please specify the quantity of product(s).":"V\\u00e4nligen ange antal av produkt(er).","Please try again with another form of payment.":"V\\u00e4nligen f\\u00f6rs\\u00f6k igen med ett annat betals\\u00e4tt.","Please upload {0} or less files.":"Sn\\u00e4lla ladda upp {0} eller mindre filer","Please use letters only (a-z or A-Z) in this field.":"V\\u00e4nligen anv\\u00e4nd endast bokst\\u00e4ver (a-\\u00f6 eller A-\\u00d6) i detta f\\u00e4lt.","Please use only letters (a-z or A-Z) or numbers (0-9) in this field. No spaces or other characters are allowed.":"V\\u00e4nligen anv\\u00e4nd endast bokst\\u00e4ver (a-z eller A-Z) eller siffror (0-9) i detta f\\u00e4lt. Inga mellanslag eller andra tecken \\u00e4r till\\u00e5tna.","Please use only letters (a-z or A-Z), numbers (0-9) or spaces only in this field.":"V\\u00e4nligen anv\\u00e4nd endast bokst\\u00e4ver (a-z eller A-Z), siffror (0-9) eller mellanslag i detta f\\u00e4lt.","Please use only letters (a-z or A-Z), numbers (0-9) or underscore (_) in this field, and the first character should be a letter.":"V\\u00e4nligen anv\\u00e4nd endast bokst\\u00e4ver (a-z eller A-Z), siffror (0-9) eller understreck (_) i detta f\\u00e4lt, f\\u00f6rsta tecknet ska vara en bokstav.","Please use only letters (a-z or A-Z), numbers (0-9), spaces and \\"#\\" in this field.":"V\\u00e4nligen anv\\u00e4nd endast bokst\\u00e4ver (a-z eller A-Z), siffror (0-9), mellanslag och \\"#\\" i detta f\\u00e4lt.","Please use tag SCRIPT with SRC attribute or with proper content to include JavaScript to the document.":"V\\u00e4nligen anv\\u00e4nd taggen SCRIPT med SRC-attribut eller med korrekt inneh\\u00e5ll f\\u00f6r att inkludera JavaScript i dokumentet.","Please use this date format: dd\\/mm\\/yyyy. For example 17\\/03\\/2006 for the 17th of March, 2006.":"V\\u00e4nligen ange datum enligt formatet: dd\\/mm\\/\\u00e5\\u00e5\\u00e5\\u00e5. Exempelvis 17\\/03\\/2006 f\\u00f6r den 17:e mars, 2006.","Please wait...":"V\\u00e4nligen v\\u00e4nta...","Please, fill both fields with first and last name of the person who will pick up your order":"V\\u00e4nligen fyll i f\\u00f6r och efternamn p\\u00e5 den person som ska h\\u00e4mta best\\u00e4llningen","Please, fill both name and surname of the person":"V\\u00e4nligen skriv b\\u00e5de f\\u00f6rnamn och efternamn","Point camera at the QR Code below":"Rikta kameran mot QR-koden","Popular search terms":"Popul\\u00e4ra s\\u00f6kord","Postcode":"Postnummer","Previous":"F\\u00f6reg\\u00e5ende","Previous price:":"Tidigare pris:","Price":"Pris","Proceed":"Forts\\u00e4tt","Proceed to Checkout":"Till kassan","Product sheet":"Produktinformationsblad","Products":"Produkter","Provided Zip\\/Postal Code seems to be invalid.":"Angiven postkod verkar vara ogiltig.","Purchase Order Number":"Best\\u00e4llningsnummer","Qty":"Antal","Receive a copy by e-mail":"Skicka en e-postkopia till dig sj\\u00e4lv","Recent items":"Senaste artiklarna","Recently added item(s)":"Nyligen tillagda produkter","Related Products":"Andra k\\u00f6pte ocks\\u00e5","Reload captcha":"Ladda om captcha","Remember Me":"Kom ih\\u00e5g mig","Remove":"Ta bort","Remove all":"T\\u00f6m varukorg","Remove image":"Ta bort bild","Remove item":"Ta bort artikel","Replace":"Ers\\u00e4tt","Request for Bauhaus installation service":"BAUHAUS Montageservice Intresseanm\\u00e4lan","Reset":"Nollst\\u00e4ll","Review & Payments":"Granska & Betala","Saturday":"L\\u00f6rdag","Save":"Spara","Save Address":"Spara adress","Save for later use.":"Spara f\\u00f6r senare anv\\u00e4ndning.","Save in address book":"Spara i adressboken","Save new project":"Skapa nytt projekt","Search":"S\\u00f6k","Search by keyword":"S\\u00f6k p\\u00e5 nyckelord","Search for other ...":"S\\u00f6k","See Details":"Se detaljer","See all results":"S\\u00f6kresultat","See price":"Nytt l\\u00e4gre pris","See price before order confirmation.":"Se pris innan orderbekr\\u00e4ftelse.","Select":"V\\u00e4lj","Select All":"V\\u00e4lj alla","Select All on This Page":"V\\u00e4lj alla p\\u00e5 denna sida","Select Date":"V\\u00e4lj Datum","Select Method":"V\\u00e4lj s\\u00e4tt","Select Store":"V\\u00e4lj butik","Select all":"V\\u00e4lj alla","Select one project":"V\\u00e4lj ett projekt","Select the desired credit":"V\\u00e4lj \\u00f6nskad kredit","Select the discounted product and add it to the shopping cart":"V\\u00e4lj den rabatterade produkten och l\\u00e4gg till i kundvagnen","Select the product":"V\\u00e4lj produkten","Select time":"Tid","Select...":"V\\u00e4lj...","Selected":"Vald","Selected service point is not available. Please, choose another one from the list.":"Postombud \\u00e4r inte tillg\\u00e4ngligt. V\\u00e4nligen v\\u00e4lj ett annat fr\\u00e5n listan.","Send":"Skicka","Send Check to:":"Skicka check till:","Service points selection is not available for your postcode.":"Postombud \\u00e4r inte tillg\\u00e4ngligt f\\u00f6r ditt postnummer.","Ship Here":"Leverera Hit","Ship To:":"Leverera till:","Shipping":"Frakt","Shipping Address":"Leveransadress","Shipping Method":"Leveranss\\u00e4tt","Shipping Method:":"Leveranss\\u00e4tt:","Shipping Methods":"Frakts\\u00e4tt","Show":"Visa","Show all":"Visa allt","Show all...":"Visa alla...","Show less":"Visa mindre","Show more":"Visa fler","Show more locations":"Visa fler postombud","Show more products":"Visa fler produkter","Show previous results":"Visa fler produkter","Showing %1 results for ":"%1 s\\u00f6kresultat f\\u00f6r ","Sign In":"Logga in","Social Security Number":"Personnummer","Some problems occurred during this request. Please, try again later.":"Ett problem uppstod vid f\\u00f6rfr\\u00e5gan. V\\u00e4nligen f\\u00f6rs\\u00f6k igen senare.","Something went wrong":"N\\u00e5got gick fel","Something went wrong.":"N\\u00e5got gick fel.","Sorry, but something went wrong.":"Tyv\\u00e4rr, n\\u00e5got gick fel.","Sorry, something went wrong. Please try again later.":"F\\u00f6rl\\u00e5t, n\\u00e5got gick fel. V\\u00e4nligen f\\u00f6rs\\u00f6k igen senare.","Sorry, the information is temporarily unavailable. Please, try later.":"Beklagar, informationen \\u00e4r inte tillg\\u00e4nglig f\\u00f6r tillf\\u00e4llet. V\\u00e4nligen f\\u00f6rs\\u00f6k senare.","Sort by:":"Sorterar p\\u00e5:","Store":"Butik","Store Credit":"Butikskredit","Strong":"Starkt","Submit":"Skicka","Subtotal":"Orderv\\u00e4rde","Summary":"Sammanfattning","Sunday":"S\\u00f6ndag","Tap Scan QR Code button":"Tryck p\\u00e5 Skanna QR-kod","Tax":"Moms","Technical problem occurred. Please try again later.":"Ett tekniskt problem intr\\u00e4ffade. Var god f\\u00f6rs\\u00f6k igen senare.","Telephone":"Telefonnummer","Terms and Conditions BAUHAUS My account":"Allm\\u00e4nna villkor BAUHAUS Mitt konto","Thank you, %1!":"Tack, %1!","The amount is not within the specified range.":"Beloppet \\u00e4r inte inom angivet intervall","The date is not within the specified range.":"Datumet \\u00e4r inte inom det specificerade intervallet.","The document will open in the new browser window, do you want to continue?":"Dokumentet kommer att \\u00f6ppnas i en ny flik, vill du forts\\u00e4tta?","The fewest you may purchase is %1.":"L\\u00e4gst antal f\\u00f6r k\\u00f6p \\u00e4r %1.","The field isn\'t complete.":"F\\u00e4ltet \\u00e4r inte komplett.","The value is not within the specified range.":"V\\u00e4rdet \\u00e4r inte inom angivet intervall.","This is a required field.":"Detta \\u00e4r ett obligatoriskt f\\u00e4lt.","This product is out of stock.":"Denna produkt finns inte i lager.","This tab contains invalid data. Please resolve this before saving.":"Den h\\u00e4r fliken inneh\\u00e5ller ogiltiga data. L\\u00f6s detta innan du sparar.","Thursday":"Torsdag","To check out, please sign in with your email address.":"F\\u00f6r att avsluta k\\u00f6pet, logga in med din e-postadress.","To:":"Till:","Total":"Totalsumma","Total incl. tax":"Totalsumma inkl. moms","Translate":"\\u00d6vers\\u00e4tt","Try again":"Prova igen","Tuesday":"Tisdag","Unable to clean the manual order session":"Det gick inte att reng\\u00f6ra den manuella ordersessionen","Update":"Uppdatera","Upload":"Ladda upp","Upload more":"Ladda upp fler","Use Default Value":"Anv\\u00e4nd f\\u00f6rvalt v\\u00e4rde","Use Mobile BankID on another device":"Anv\\u00e4nd BankID p\\u00e5 en annan enhet","Use tax deduction":"Anv\\u00e4nd Rot-Avdrag\\/Gr\\u00f6n Teknik","Username":"Anv\\u00e4ndarnamn","Verify with BankID to continue":"Verifiera med BankID f\\u00f6r att forts\\u00e4tta.","Very Strong":"Mycket Starkt","View Details":"Se detaljer","View and Edit Cart":"Visa och redigera varukorg","View {{nbHits}} products":"Visar {{nbHits}} produkter","Vul hier een geldige datum in.":"V\\u00e4nligen ange ett giltigt datum h\\u00e4r.","Warning":"Varning","We also sent you a copy of the request to your email.":"Vi har \\u00e4ven skickat en kopia av beg\\u00e4ran till din e-post.","We can\'t create the Wish List right now.":"Vi kan inte skapa \\u00f6nskelistan just nu.","We couldn\'t find any records.":"Vi kunde inte hitta n\\u00e5gra uppgifter.","We don\'t recognize or support this file extension type.":"Vi k\\u00e4nner inte igen eller st\\u00f6djer denna fil\\u00e4ndelsetypen.","We have registered your request.":"Vi har registrerat din beg\\u00e4ran.","We will contact you via the contact details you have provided in your application.":"Vi kommer att kontakta dig via de kontaktuppgifter du angivit i din ans\\u00f6kan.","Weak":"Svagt","Wednesday":"Onsdag","Week":"Vecka","Welcome, %1!":"V\\u00e4lkommen, %1!","What can we help you with?":"Vad kan vi hj\\u00e4lpa dig med?","What can we help you with? Describe your opinion":"Vad kan vi hj\\u00e4lpa dig med?","What do you need help with?":"Vad beh\\u00f6ver du hj\\u00e4lp med? ","What is PayPal?":"Vad \\u00e4r PayPal?","What is this?":"Vad \\u00e4r detta?","What\'s this?":"Vad \\u00e4r detta?","Year":"\\u00c5r","Yes":"Ja","You already have an account with us. Sign in or continue as guest.":"Du har redan ett konto hos oss. Logga in eller forts\\u00e4tt som g\\u00e4st.","You are in {1}. You are logged in as {2}.":"Ditt varuhus \\u00e4r {1}. Du \\u00e4r inloggad som {2}","You can buy this product only in quantities of %1 at a time.":"Online s\\u00e4ljs denna vara i antal av %1 st \\u00e5t g\\u00e5ngen","You can create an account after checkout.":"Du kan skapa ett konto efter att k\\u00f6pet \\u00e4r klart.","You can track your order status by creating an account.":"Du kan sp\\u00e5ra din orderstatus genom att skapa ett nytt konto.","You cart will be converted to selected delivery type after adding product to the cart":"Din varukorg kommer att \\u00e4ndras till valt leveranss\\u00e4tt efter att produkten lagts i din varukorg","You do not have enough bonus points":"Du har inte tillr\\u00e4ckligt med bonuspo\\u00e4ng","You have chosen home delivery.":"Du har valt hemleverans.","You have chosen pick-up.":"Du har valt upph\\u00e4mtning.","You have no items in your shopping cart.":"Du har inga produkter i din varukorg.","You have successfully saved your edits.":"Du har sparat dina \\u00e4ndringar.","You haven\'t selected any items!":"Du har inte valt n\\u00e5gra artiklar!","You may also be interested in these products":"Du kan ocks\\u00e5 vara intresserad av dessa produkter","You save:":"Du sparar:","You will be redirected to the PayPal website when you place an order.":"N\\u00e4r du \\u00e4r klar med best\\u00e4llningen f\\u00f6rflyttas du till PayPal.","You\'re currently reading page":"Du l\\u00e4ser just nu sida","Your %s %s was added.":"Ditt %s %s \\u00e4r tillagt!","Your Full Name":"Fullst\\u00e4ndigt namn","Your Store":"Ditt varuhus","Your ZIP-code must be in the range 902xx-xxxx to 905-xx-xxxx":"Ditt postnummer m\\u00e5ste vara inom 902xx-xxxx till 905-xx-xxxx","Your cart":"Din varukorg","Your coupon was successfully applied.":"Din kupong lades till.","Your coupon was successfully removed.":"Din kupong togs bort.","edit":"\\u00e4ndra","ending":"avslutar","expires":"utg\\u00e5r","from":"Fr\\u00e5n","more":"mer","of":"av","options":"alternativ","or":"eller","per page":"per sida","records found":"artiklar hittades","select all":"v\\u00e4lj alla","selected":"vald","to":"till","unselect all":"Avmarkera alla"}';}); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('Magento_Translation/js/mage-translation-dictionary',[ 'text!js-translation.json' ], function (dict) { 'use strict'; return JSON.parse(dict); }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('mage/translate',[ 'jquery', 'mage/mage', 'mageTranslationDictionary', 'underscore' ], function ($, mage, dictionary, _) { 'use strict'; $.extend(true, $, { mage: { translate: (function () { /** * Key-value translations storage * @type {Object} * @private */ var _data = dictionary; return { /** * Add new translation (two string parameters) or several translations (object) */ add: function () { if (arguments.length > 1) { _data[arguments[0]] = arguments[1]; } else if (typeof arguments[0] === 'object') { $.extend(_data, arguments[0]); } }, /** * Make a translation with parsing (to handle case when _data represents tuple) * @param {String} text * @return {String} */ translate: function (text) { return typeof _data[text] !== 'undefined' ? _data[text] : text; } }; }()) } }); $.mage.__ = $.proxy($.mage.translate.translate, $.mage.translate); // Provide i18n wrapper to be used in underscore templates for translation _.extend(_, { /** * Make a translation using $.mage.__ * * @param {String} text * @return {String} */ i18n: function (text) { return $.mage.__(text); } }); return $.mage.__; }); /** * Copyright © Vaimo Group. All rights reserved. * See LICENSE_VAIMO.txt for license details. */ define('Vaimo_BauhausSe/js/mixins/validation', ['jquery', 'mage/translate'], ($, $t) => {'use strict'; return function (target) { $.validator.addMethod( 'validate-email', //In the domain part we explicitely restrict 'xn--' combination, because browser transforms any non-ASCII characters to ASCII-like that starts with 'xn--' function (value) { return !value || /^([a-z0-9,!\#\$%&'\*\+\/=\?\^_`\{\|\}~-])+(\.([a-z0-9,!\#\$%&'\*\+\/=\?\^_`\{\|\}~-])+)*@((?!.*xn--)[a-z0-9-]+(\.(?!xn--)[a-z0-9-]+)*\.[a-z]{2,})$/i.test(value); }, $t('Please enter a valid email address (Ex: johndoe@domain.com).') ); return target; }; }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('mage/collapsible',[ 'jquery', 'jquery-ui-modules/widget', 'jquery-ui-modules/core', 'jquery/jquery-storageapi', 'mage/mage' ], function ($) { 'use strict'; var hideProps = {}, showProps = {}; hideProps.height = 'hide'; showProps.height = 'show'; $.widget('mage.collapsible', { options: { active: false, disabled: false, collapsible: true, header: '[data-role=title]', content: '[data-role=content]', trigger: '[data-role=trigger]', closedState: null, openedState: null, disabledState: null, ajaxUrlElement: '[data-ajax=true]', ajaxContent: false, loadingClass: null, saveState: false, animate: false, icons: { activeHeader: null, header: null }, collateral: { element: null, openedState: null } }, /** * @private */ _create: function () { this.storage = $.localStorage; this.icons = false; if (typeof this.options.icons === 'string') { this.options.icons = JSON.parse(this.options.icons); } this._processPanels(); this._processState(); this._refresh(); if (this.options.icons.header && this.options.icons.activeHeader) { this._createIcons(); this.icons = true; } this.element.on('dimensionsChanged', function (e) { if (e.target && e.target.classList.contains('active')) { this._scrollToTopIfNotVisible(); } }.bind(this)); this._bind('click'); this._trigger('created'); }, /** * @private */ _refresh: function () { this.trigger.attr('tabIndex', 0); if (this.options.active && !this.options.disabled) { if (this.options.openedState) { this.element.addClass(this.options.openedState); } if (this.options.collateral.element && this.options.collateral.openedState) { $(this.options.collateral.element).addClass(this.options.collateral.openedState); } if (this.options.ajaxContent) { this._loadContent(); } // ARIA (updates aria attributes) this.header.attr({ 'aria-selected': false }); } else if (this.options.disabled) { this.disable(); } else { this.content.hide(); if (this.options.closedState) { this.element.addClass(this.options.closedState); } } }, /** * Processing the state: * If deep linking is used and the anchor is the id of the content or the content contains this id, * and the collapsible element is a nested one having collapsible parents, in order to see the content, * all the parents must be expanded. * @private */ _processState: function () { var anchor = window.location.hash, isValid = $.mage.isValidSelector(anchor), urlPath = window.location.pathname.replace(/\./g, ''), state; this.stateKey = encodeURIComponent(urlPath + this.element.attr('id')); if (isValid && ($(this.content.find(anchor)).length > 0 || this.content.attr('id') === anchor.replace('#', '')) ) { this.element.parents('[data-collapsible=true]').collapsible('forceActivate'); if (!this.options.disabled) { this.options.active = true; if (this.options.saveState) { //eslint-disable-line max-depth this.storage.set(this.stateKey, true); } } } else if (this.options.saveState && !this.options.disabled) { state = this.storage.get(this.stateKey); if (typeof state === 'undefined' || state === null) { this.storage.set(this.stateKey, this.options.active); } else if (state === true) { this.options.active = true; } else if (state === false) { this.options.active = false; } } }, /** * @private */ _createIcons: function () { var icons = this.options.icons; if (icons) { $('<span>') .addClass(icons.header) .attr('data-role', 'icons') .prependTo(this.header); if (this.options.active && !this.options.disabled) { this.header.children('[data-role=icons]') .removeClass(icons.header) .addClass(icons.activeHeader); } } }, /** * @private */ _destroyIcons: function () { this.header .children('[data-role=icons]') .remove(); }, /** * @private */ _destroy: function () { var options = this.options; this.element.removeAttr('data-collapsible'); this.trigger.removeAttr('tabIndex'); if (options.openedState) { this.element.removeClass(options.openedState); } if (this.options.collateral.element && this.options.collateral.openedState) { $(this.options.collateral.element).removeClass(this.options.collateral.openedState); } if (options.closedState) { this.element.removeClass(options.closedState); } if (options.disabledState) { this.element.removeClass(options.disabledState); } if (this.icons) { this._destroyIcons(); } }, /** * @private */ _processPanels: function () { var headers, triggers; this.element.attr('data-collapsible', 'true'); if (typeof this.options.header === 'object') { this.header = this.options.header; } else { headers = this.element.find(this.options.header); if (headers.length > 0) { this.header = headers.eq(0); } else { this.header = this.element; } } if (typeof this.options.content === 'object') { this.content = this.options.content; } else { this.content = this.header.next(this.options.content).eq(0); } // ARIA (init aria attributes) if (this.header.attr('id')) { this.content.attr('aria-labelledby', this.header.attr('id')); } if (this.content.attr('id')) { this.header.attr('aria-controls', this.content.attr('id')); } this.header .attr({ 'role': 'tab', 'aria-selected': this.options.active, 'aria-expanded': this.options.active }); // For collapsible widget only (not tabs or accordion) if (this.header.parent().attr('role') !== 'presentation') { this.header .parent() .attr('role', 'tablist'); } this.content.attr({ 'role': 'tabpanel', 'aria-hidden': !this.options.active }); if (typeof this.options.trigger === 'object') { this.trigger = this.options.trigger; } else { triggers = this.header.find(this.options.trigger); if (triggers.length > 0) { this.trigger = triggers.eq(0); } else { this.trigger = this.header; } } }, /** * @param {jQuery.Event} event * @private */ _keydown: function (event) { var keyCode; if (event.altKey || event.ctrlKey) { return; } keyCode = $.ui.keyCode; switch (event.keyCode) { case keyCode.SPACE: case keyCode.ENTER: this._eventHandler(event); break; } }, /** * @param {jQuery.Event} event * @private */ _bind: function (event) { var self = this; this.events = { keydown: '_keydown' }; if (event) { $.each(event.split(' '), function (index, eventName) { self.events[eventName] = '_eventHandler'; }); } this._off(this.trigger); if (!this.options.disabled) { this._on(this.trigger, this.events); } }, /** * Disable. */ disable: function () { this.options.disabled = true; this._off(this.trigger); this.forceDeactivate(); if (this.options.disabledState) { this.element.addClass(this.options.disabledState); } this.trigger.attr('tabIndex', -1); }, /** * Enable. */ enable: function () { this.options.disabled = false; this._on(this.trigger, this.events); this.forceActivate(); if (this.options.disabledState) { this.element.removeClass(this.options.disabledState); } this.trigger.attr('tabIndex', 0); }, /** * @param {jQuery.Event} event * @private */ _eventHandler: function (event) { if (this.options.active && this.options.collapsible) { this.deactivate(); } else { this.activate(); } event.preventDefault(); }, /** * @param {*} prop * @private */ _animate: function (prop) { var duration, easing, animate = this.options.animate; if (typeof animate === 'number') { duration = animate; } if (typeof animate === 'string') { animate = JSON.parse(animate); } duration = duration || animate.duration; easing = animate.easing; this.content.animate(prop, duration, easing); }, /** * Deactivate. */ deactivate: function () { if (this.options.animate) { this._animate(hideProps); } else { this.content.hide(); } this._close(); }, /** * Force deactivate. */ forceDeactivate: function () { this.content.hide(); this._close(); }, /** * @private */ _close: function () { this.options.active = false; if (this.options.saveState) { this.storage.set(this.stateKey, false); } if (this.options.openedState) { this.element.removeClass(this.options.openedState); } if (this.options.collateral.element && this.options.collateral.openedState) { $(this.options.collateral.element).removeClass(this.options.collateral.openedState); } if (this.options.closedState) { this.element.addClass(this.options.closedState); } if (this.icons) { this.header.children('[data-role=icons]') .removeClass(this.options.icons.activeHeader) .addClass(this.options.icons.header); } // ARIA (updates aria attributes) this.header.attr({ 'aria-selected': 'false', 'aria-expanded': 'false' }); this.content.attr({ 'aria-hidden': 'true' }); this.element.trigger('dimensionsChanged', { opened: false }); }, /** * Activate. * * @return void; */ activate: function () { if (this.options.disabled) { return; } if (this.options.animate) { this._animate(showProps); } else { this.content.show(); } this._open(); }, /** * Force activate. */ forceActivate: function () { if (!this.options.disabled) { this.content.show(); this._open(); } }, /** * @private */ _open: function () { this.element.trigger('beforeOpen'); this.options.active = true; if (this.options.ajaxContent) { this._loadContent(); } if (this.options.saveState) { this.storage.set(this.stateKey, true); } if (this.options.openedState) { this.element.addClass(this.options.openedState); } if (this.options.collateral.element && this.options.collateral.openedState) { $(this.options.collateral.element).addClass(this.options.collateral.openedState); } if (this.options.closedState) { this.element.removeClass(this.options.closedState); } if (this.icons) { this.header.children('[data-role=icons]') .removeClass(this.options.icons.header) .addClass(this.options.icons.activeHeader); } // ARIA (updates aria attributes) this.header.attr({ 'aria-selected': 'true', 'aria-expanded': 'true' }); this.content.attr({ 'aria-hidden': 'false' }); this.element.trigger('dimensionsChanged', { opened: true }); }, /** * @private */ _loadContent: function () { var url = this.element.find(this.options.ajaxUrlElement).attr('href'), that = this; if (url) { that.xhr = $.get({ url: url, dataType: 'html' }, function () { }); } if (that.xhr && that.xhr.statusText !== 'canceled') { if (that.options.loadingClass) { that.element.addClass(that.options.loadingClass); } that.content.attr('aria-busy', 'true'); that.xhr.done(function (response) { setTimeout(function () { that.content.html(response); }, 1); }); that.xhr.always(function (jqXHR, status) { setTimeout(function () { if (status === 'abort') { that.content.stop(false, true); } if (that.options.loadingClass) { that.element.removeClass(that.options.loadingClass); } that.content.removeAttr('aria-busy'); if (jqXHR === that.xhr) { delete that.xhr; } }, 1); }); } }, /** * @private */ _scrollToTopIfNotVisible: function () { if (this._isElementOutOfViewport()) { this.header[0].scrollIntoView(); } }, /** * @private * @return {Boolean} */ _isElementOutOfViewport: function () { var headerRect = this.header[0].getBoundingClientRect(), contentRect = this.content.get().length ? this.content[0].getBoundingClientRect() : false, headerOut, contentOut; headerOut = headerRect.bottom - headerRect.height < 0 || headerRect.right - headerRect.width < 0 || headerRect.left + headerRect.width > window.innerWidth || headerRect.top + headerRect.height > window.innerHeight; contentOut = contentRect ? contentRect.bottom - contentRect.height < 0 || contentRect.right - contentRect.width < 0 || contentRect.left + contentRect.width > window.innerWidth || contentRect.top + contentRect.height > window.innerHeight : false; return headerOut ? headerOut : contentOut; } }); return $.mage.collapsible; }); /** * Copyright © Vaimo Group. All rights reserved. * See LICENSE_VAIMO.txt for license details. */ define('Vaimo_BauhausSe/js/mixins/tabs', [ 'jquery', 'mage/collapsible', 'jquery/ui' ], function ($, collapsible) { 'use strict'; return function (originalWidget) { $.widget(originalWidget.prototype.namespace + '.' + originalWidget.prototype.widgetName, $[originalWidget.prototype.namespace][originalWidget.prototype.widgetName], { options: { filterIdAttr: '' }, _destroy: function () { this._super(); $.each(this.collapsibles, function () { $(this).off('beforeOpen'); }); }, openByElement: function ($el) { var $collapsible = this.collapsibles.filter($el); if ($collapsible.length) { $collapsible.collapsible('activate'); } }, closeByElement: function ($el) { var $collapsible = this.collapsibles.filter($el); if ($collapsible.length) { $collapsible.collapsible('deactivate'); } }, setActiveCollapsibleByCollapsibleId: function (id) { var collapsibleWidget = this.getCollapsibleById(id); if (!collapsibleWidget) {return} collapsibleWidget.activate(); }, deactivateCollapsibleByCollapsibleId: function (id) { var collapsibleWidget = this.getCollapsibleById(id); if (!collapsibleWidget) {return} collapsibleWidget.deactivate(); }, getCollapsibleById: function(id) { if (!id) {return} for (var i = 0; i < this.collapsibleWidgets.length; i++) { if (this.collapsibleWidgets[i].element.attr(this.options.filterIdAttr) === id) { return this.collapsibleWidgets[i]; } } }, getActiveCollapsibleId: function () { for (var i = 0; i < this.collapsibleWidgets.length; i++) { if (this.collapsibleWidgets[i].options.active) { return this.collapsibleWidgets[i].element.attr(this.options.filterIdAttr); } } return ''; }, _instantiateCollapsible: function (element, index, active, disabled) { if (!this.collapsibleWidgets) { this.collapsibleWidgets = []; } this.collapsibleWidgets.push(collapsible($.extend({}, this.options, { active: active, disabled: disabled, header: this.headers.eq(index), content: this.contents.eq(index), trigger: this.triggers.eq(index) }), element )); }, }); return $[originalWidget.prototype.namespace][originalWidget.prototype.widgetName]; }; }); /** * Copyright © Vaimo Group. All rights reserved. * See LICENSE_VAIMO.txt for license details. */ define('Vaimo_BauhausSe/js/mixins/collapsible', [ 'jquery', 'cssTimeout', 'jquery/ui' ], function ($, cssTimeout) { 'use strict'; return function (originalWidget) { var prototype = originalWidget.prototype; $.widget(prototype.namespace + '.' + prototype.widgetName, $[prototype.namespace][prototype.widgetName], { options: { focusBottom: false, $scrollToBottomElement: null, focusTop: false, }, /** * Animate callback */ animateCallback: function(prop) { this.element.trigger('dimensionsChangedDone'); if (this.options.focusBottom && this.options.$scrollToBottomElement && prop.height === 'show') { $('html, body').animate({ scrollTop: this.options.$scrollToBottomElement.offset().top + this.options.$scrollToBottomElement.height() + 'px' }, cssTimeout); } if (this.options.focusTop && prop.height === 'show') { setTimeout(function(){ this.element[0].scrollIntoView(); }.bind(this), cssTimeout); } }, /** * Add animate */ _animate: function (prop) { var duration, easing, animate = this.options.animate; if (typeof animate === 'number') { duration = animate; } if (typeof animate === 'string') { animate = JSON.parse(animate); } duration = duration || animate.duration; easing = animate.easing; this.content.animate(prop, duration, easing, this.animateCallback.bind(this, prop)); }, /** * The difference from parent method is removing of ! inside condition that was added in 2.3.3 and looks like a bug, * cause in that case the method name and what is does is not valid. The item is scrolled when it is NOT out of viewport actually * @param {HTMLElement} elem * @private */ _scrollToTopIfVisible: function (elem) { if (this._isElementOutOfViewport(elem)) { elem.scrollIntoView(); } }, }); return $[prototype.namespace][prototype.widgetName]; }; }); /** * Copyright © Vaimo Group. All rights reserved. * See LICENSE_VAIMO.txt for license details. */ define('Vaimo_BauhausSe/js/mixins/library/core/collection-mixin', [], () => {'use strict'; return (uiComponent) => uiComponent.extend({ getChildElemByIndex: function (index) { return this.elems().filter(el => el.index === index); }, getChildElemByGroup: function (groupName) { return this.elems().filter(el => el.groupName === groupName); } })}); /** * Copyright © Vaimo Group. All rights reserved. * See LICENSE_VAIMO.txt for license details. */ define('Vaimo_BauhausSe/js/mixins/lib/knockout/template/renderer', [], () => { 'use strict'; return (target) => { const selfClosingTags = ['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', 'track', 'wbr']; const tagNameRegexp = /\w+/; const tagRegexp = /(<[^>]+\/>)/ig; const tagEndSlashRegexp = /\/>$/; const orig = target.parseTemplate; target.parseTemplate = function(html) { return orig.apply(target, [target.fixCustomSelfClosingNodes(html)].concat(Array.prototype.splice.call(arguments, 1, arguments.length))); }; target.fixCustomSelfClosingNodes = function(htmlString) { try { return htmlString.replace(tagRegexp, tag => { const tagName = tag.match(tagNameRegexp); if (!(tagName && tagName[0])) { console.error('tagName match failed on ' + tag); return tag; } if (selfClosingTags.indexOf(tagName[0]) !== -1) return tag; return tag.replace(tagEndSlashRegexp, '>') + '</' + tagName[0] + '>'; }); }catch(e) { try { }catch (e) { console.error(e); return htmlString; } } } return target; } }); /** * Copyright © Vaimo Group. All rights reserved. * See LICENSE_VAIMO.txt for license details. */ define('Vaimo_BauhausSe/js/mixins/view/theme-messages-mixin', ['ko'], ko => {'use strict'; return target => target.extend({ initialize: function () { this._super(); this.observe({commonOutputMessages: this._getCommonMessages(), messagesIds: []}); this.aggregatedMessages = ko.observableArray([ () => this.cookieMessages ? this.cookieMessages : [], this.commonOutputMessages ]); this.messages.subscribe(() => { this.messagesIds([]); this.commonOutputMessages(this._getCommonMessages()); }); }, addMessage: function(msg) { if (!this.additionalMessages) { this.additionalMessages = ko.observableArray([]); this.aggregatedMessages.push(this.additionalMessages); } this.additionalMessages.push(msg); window.scrollTo(0, 0); }, _getCommonMessages: function() { return this.messages().messages || []; }, setMessageId: function (idx) { const msgIds = this.messagesIds(); msgIds.push(idx); this.messagesIds(msgIds); } })}); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('mage/utils/strings',[ 'underscore' ], function (_) { 'use strict'; var jsonRe = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/; return { /** * Attempts to convert string to one of the primitive values, * or to parse it as a valid json object. * * @param {String} str - String to be processed. * @returns {*} */ castString: function (str) { try { str = str === 'true' ? true : str === 'false' ? false : str === 'null' ? null : +str + '' === str ? +str : jsonRe.test(str) ? JSON.parse(str) : str; } catch (e) { } return str; }, /** * Splits string by separator if it's possible, * otherwise returns the incoming value. * * @param {(String|Array|*)} str - String to split. * @param {String} [separator=' '] - Seperator based on which to split the string. * @returns {Array|*} Splitted string or the incoming value. */ stringToArray: function (str, separator) { separator = separator || ' '; return typeof str === 'string' ? str.split(separator) : str; }, /** * Converts the incoming string which consists * of a specified delimiters into a format commonly used in form elements. * * @param {String} name - The incoming string. * @param {String} [separator='.'] * @returns {String} Serialized string. * * @example * utils.serializeName('one.two.three'); * => 'one[two][three]'; */ serializeName: function (name, separator) { var result; separator = separator || '.'; name = name.split(separator); result = name.shift(); name.forEach(function (part) { result += '[' + part + ']'; }); return result; }, /** * Checks wether the incoming value is not empty, * e.g. not 'null' or 'undefined' * * @param {*} value - Value to check. * @returns {Boolean} */ isEmpty: function (value) { return value === '' || _.isUndefined(value) || _.isNull(value); }, /** * Adds 'prefix' to the 'part' value if it was provided. * * @param {String} prefix * @param {String} part * @returns {String} */ fullPath: function (prefix, part) { return prefix ? prefix + '.' + part : part; }, /** * Splits incoming string and returns its' part specified by offset. * * @param {String} parts * @param {Number} [offset] * @param {String} [delimiter=.] * @returns {String} */ getPart: function (parts, offset, delimiter) { delimiter = delimiter || '.'; parts = parts.split(delimiter); offset = this.formatOffset(parts, offset); parts.splice(offset, 1); return parts.join(delimiter) || ''; }, /** * Converts nameThroughCamelCase to name-through-minus * * @param {String} string * @returns {String} */ camelCaseToMinus: function camelCaseToMinus(string) { return ('' + string) .split('') .map(function (symbol, index) { return index ? symbol.toUpperCase() === symbol ? '-' + symbol.toLowerCase() : symbol : symbol.toLowerCase(); }) .join(''); }, /** * Converts name-through-minus to nameThroughCamelCase * * @param {String} string * @returns {String} */ minusToCamelCase: function minusToCamelCase(string) { return ('' + string) .split('-') .map(function (part, index) { return index ? part.charAt(0).toUpperCase() + part.slice(1) : part; }) .join(''); } }; }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('mage/utils/arrays',[ 'underscore', './strings' ], function (_, utils) { 'use strict'; /** * Defines index of an item in a specified container. * * @param {*} item - Item whose index should be defined. * @param {Array} container - Container upon which to perform search. * @returns {Number} */ function getIndex(item, container) { var index = container.indexOf(item); if (~index) { return index; } return _.findIndex(container, function (value) { return value && value.name === item; }); } return { /** * Facade method to remove/add value from/to array * without creating a new instance. * * @param {Array} arr - Array to be modified. * @param {*} value - Value to add/remove. * @param {Boolean} add - Flag that specfies operation. * @returns {Utils} Chainable. */ toggle: function (arr, value, add) { return add ? this.add(arr, value) : this.remove(arr, value); }, /** * Removes the incoming value from array in case * without creating a new instance of it. * * @param {Array} arr - Array to be modified. * @param {*} value - Value to be removed. * @returns {Utils} Chainable. */ remove: function (arr, value) { var index = arr.indexOf(value); if (~index) { arr.splice(index, 1); } return this; }, /** * Adds the incoming value to array if * it's not alredy present in there. * * @param {Array} arr - Array to be modifed. * @param {...*} arguments - Values to be added. * @returns {Utils} Chainable. */ add: function (arr) { var values = _.toArray(arguments).slice(1); values.forEach(function (value) { if (!~arr.indexOf(value)) { arr.push(value); } }); return this; }, /** * Inserts specified item into container at a specified position. * * @param {*} item - Item to be inserted into container. * @param {Array} container - Container of items. * @param {*} [position=-1] - Position at which item should be inserted. * Position can represent: * - specific index in container * - item which might already be present in container * - structure with one of these properties: after, before * @returns {Boolean|*} * - true if element has changed its' position * - false if nothing has changed * - inserted value if it wasn't present in container */ insert: function (item, container, position) { var currentIndex = getIndex(item, container), newIndex, target; if (typeof position === 'undefined') { position = -1; } else if (typeof position === 'string') { position = isNaN(+position) ? position : +position; } newIndex = position; if (~currentIndex) { target = container.splice(currentIndex, 1)[0]; if (typeof item === 'string') { item = target; } } if (typeof position !== 'number') { target = position.after || position.before || position; newIndex = getIndex(target, container); if (~newIndex && (position.after || newIndex >= currentIndex)) { newIndex++; } } if (newIndex < 0) { newIndex += container.length + 1; } container[newIndex] ? container.splice(newIndex, 0, item) : container[newIndex] = item; return !~currentIndex ? item : currentIndex !== newIndex; }, /** * @param {Array} elems * @param {Number} offset * @return {Number|*} */ formatOffset: function (elems, offset) { if (utils.isEmpty(offset)) { offset = -1; } offset = +offset; if (offset < 0) { offset += elems.length + 1; } return offset; } }; }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('mage/utils/objects',[ 'ko', 'jquery', 'underscore', 'mage/utils/strings' ], function (ko, $, _, stringUtils) { 'use strict'; var primitives = [ 'undefined', 'boolean', 'number', 'string' ]; /** * Sets nested property of a specified object. * @private * * @param {Object} parent - Object to look inside for the properties. * @param {Array} path - Splitted path the property. * @param {*} value - Value of the last property in 'path' array. * returns {*} New value for the property. */ function setNested(parent, path, value) { var last = path.pop(), len = path.length, pi = 0, part = path[pi]; for (; pi < len; part = path[++pi]) { if (!_.isObject(parent[part])) { parent[part] = {}; } parent = parent[part]; } if (typeof parent[last] === 'function') { parent[last](value); } else { parent[last] = value; } return value; } /** * Retrieves value of a nested property. * @private * * @param {Object} parent - Object to look inside for the properties. * @param {Array} path - Splitted path the property. * @returns {*} Value of the property. */ function getNested(parent, path) { var exists = true, len = path.length, pi = 0; for (; pi < len && exists; pi++) { parent = parent[path[pi]]; if (typeof parent === 'undefined') { exists = false; } } if (exists) { if (ko.isObservable(parent)) { parent = parent(); } return parent; } } /** * Removes property from a specified object. * @private * * @param {Object} parent - Object from which to remove property. * @param {Array} path - Splitted path to the property. */ function removeNested(parent, path) { var field = path.pop(); parent = getNested(parent, path); if (_.isObject(parent)) { delete parent[field]; } } return { /** * Retrieves or defines objects' property by a composite path. * * @param {Object} data - Container for the properties specified in path. * @param {String} path - Objects' properties divided by dots. * @param {*} [value] - New value for the last property. * @returns {*} Returns value of the last property in chain. * * @example * utils.nested({}, 'one.two', 3); * => { one: {two: 3} } */ nested: function (data, path, value) { var action = arguments.length > 2 ? setNested : getNested; path = path ? path.split('.') : []; return action(data, path, value); }, /** * Removes nested property from an object. * * @param {Object} data - Data source. * @param {String} path - Path to the property e.g. 'one.two.three' */ nestedRemove: function (data, path) { path = path.split('.'); removeNested(data, path); }, /** * Flattens objects' nested properties. * * @param {Object} data - Object to flatten. * @param {String} [separator='.'] - Objects' keys separator. * @returns {Object} Flattened object. * * @example Example with a default separator. * utils.flatten({one: { two: { three: 'value'} }}); * => { 'one.two.three': 'value' }; * * @example Example with a custom separator. * utils.flatten({one: { two: { three: 'value'} }}, '=>'); * => {'one=>two=>three': 'value'}; */ flatten: function (data, separator, parent, result) { separator = separator || '.'; result = result || {}; if (!data) { return result; } // UnderscoreJS each breaks when an object has a length property so we use Object.keys _.each(Object.keys(data), function (name) { var node = data[name]; if ({}.toString.call(node) === '[object Function]') { return; } if (parent) { name = parent + separator + name; } typeof node === 'object' ? this.flatten(node, separator, name, result) : result[name] = node; }, this); return result; }, /** * Opposite operation of the 'flatten' method. * * @param {Object} data - Previously flattened object. * @param {String} [separator='.'] - Keys separator. * @returns {Object} Object with nested properties. * * @example Example using custom separator. * utils.unflatten({'one=>two': 'value'}, '=>'); * => { * one: { two: 'value' } * }; */ unflatten: function (data, separator) { var result = {}; separator = separator || '.'; _.each(data, function (value, nodes) { nodes = nodes.split(separator); setNested(result, nodes, value); }); return result; }, /** * Same operation as 'flatten' method, * but returns objects' keys wrapped in '[]'. * * @param {Object} data - Object that should be serialized. * @returns {Object} Serialized data. * * @example * utils.serialize({one: { two: { three: 'value'} }}); * => { 'one[two][three]': 'value' } */ serialize: function (data) { var result = {}; data = this.flatten(data); _.each(data, function (value, keys) { keys = stringUtils.serializeName(keys); value = _.isUndefined(value) ? '' : value; result[keys] = value; }, this); return result; }, /** * Performs deep extend of specified objects. * * @returns {Object|Array} Extended object. */ extend: function () { var args = _.toArray(arguments); args.unshift(true); return $.extend.apply($, args); }, /** * Performs a deep clone of a specified object. * * @param {(Object|Array)} data - Data that should be copied. * @returns {Object|Array} Cloned object. */ copy: function (data) { var result = data, isArray = Array.isArray(data), placeholder; if (this.isObject(data) || isArray) { placeholder = isArray ? [] : {}; result = this.extend(placeholder, data); } return result; }, /** * Performs a deep clone of a specified object. * Doesn't save links to original object. * * @param {*} original - Object to clone * @returns {*} */ hardCopy: function (original) { if (original === null || typeof original !== 'object') { return original; } return JSON.parse(JSON.stringify(original)); }, /** * Removes specified nested properties from the target object. * * @param {Object} target - Object whose properties should be removed. * @param {(...String|Array|Object)} list - List that specifies properties to be removed. * @returns {Object} Modified object. * * @example Basic usage * var obj = {a: {b: 2}, c: 'a'}; * * omit(obj, 'a.b'); * => {'a.b': 2}; * obj => {a: {}, c: 'a'}; * * @example Various syntaxes that would return same result * omit(obj, ['a.b', 'c']); * omit(obj, 'a.b', 'c'); * omit(obj, {'a.b': true, 'c': true}); */ omit: function (target, list) { var removed = {}, ignored = list; if (this.isObject(list)) { ignored = []; _.each(list, function (value, key) { if (value) { ignored.push(key); } }); } else if (_.isString(list)) { ignored = _.toArray(arguments).slice(1); } _.each(ignored, function (path) { var value = this.nested(target, path); if (!_.isUndefined(value)) { removed[path] = value; this.nestedRemove(target, path); } }, this); return removed; }, /** * Checks if provided value is a plain object. * * @param {*} value - Value to be checked. * @returns {Boolean} */ isObject: function (value) { var objProto = Object.prototype; return typeof value == 'object' ? objProto.toString.call(value) === '[object Object]' : false; }, /** * * @param {*} value * @returns {Boolean} */ isPrimitive: function (value) { return value === null || ~primitives.indexOf(typeof value); }, /** * Iterates over obj props/array elems recursively, applying action to each one * * @param {Object|Array} data - Data to be iterated. * @param {Function} action - Callback to be called with each item as an argument. * @param {Number} [maxDepth=7] - Max recursion depth. */ forEachRecursive: function (data, action, maxDepth) { maxDepth = typeof maxDepth === 'number' && !isNaN(maxDepth) ? maxDepth - 1 : 7; if (!_.isFunction(action) || _.isFunction(data) || maxDepth < 0) { return; } if (!_.isObject(data)) { action(data); return; } _.each(data, function (value) { this.forEachRecursive(value, action, maxDepth); }, this); action(data); }, /** * Maps obj props/array elems recursively * * @param {Object|Array} data - Data to be iterated. * @param {Function} action - Callback to transform each item. * @param {Number} [maxDepth=7] - Max recursion depth. * * @returns {Object|Array} */ mapRecursive: function (data, action, maxDepth) { var newData; maxDepth = typeof maxDepth === 'number' && !isNaN(maxDepth) ? maxDepth - 1 : 7; if (!_.isFunction(action) || _.isFunction(data) || maxDepth < 0) { return data; } if (!_.isObject(data)) { return action(data); } if (_.isArray(data)) { newData = _.map(data, function (item) { return this.mapRecursive(item, action, maxDepth); }, this); return action(newData); } newData = _.mapObject(data, function (val, key) { if (data.hasOwnProperty(key)) { return this.mapRecursive(val, action, maxDepth); } return val; }, this); return action(newData); }, /** * Removes empty(in common sence) obj props/array elems * * @param {*} data - Data to be cleaned. * @returns {*} */ removeEmptyValues: function (data) { if (!_.isObject(data)) { return data; } if (_.isArray(data)) { return data.filter(function (item) { return !this.isEmptyObj(item); }, this); } return _.omit(data, this.isEmptyObj.bind(this)); }, /** * Checks that argument of any type is empty in common sence: * empty string, string with spaces only, object without own props, empty array, null or undefined * * @param {*} val - Value to be checked. * @returns {Boolean} */ isEmptyObj: function (val) { return _.isObject(val) && _.isEmpty(val) || this.isEmpty(val) || val && val.trim && this.isEmpty(val.trim()); } }; }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('mage/utils/compare',[ 'underscore', 'mage/utils/objects' ], function (_, utils) { 'use strict'; var result = []; /** * Checks if all of the provided arrays contains equal values. * * @param {(Boolean|Array)} [keepOrder=false] * @param {Array} target * @returns {Boolean} */ function equalArrays(keepOrder, target) { var args = _.toArray(arguments), arrays; if (!Array.isArray(keepOrder)) { arrays = args.slice(2); } else { target = keepOrder; keepOrder = false; arrays = args.slice(1); } if (!arrays.length) { return true; } return arrays.every(function (array) { if (array === target) { return true; } else if (array.length !== target.length) { return false; } else if (!keepOrder) { return !_.difference(target, array).length; } return array.every(function (value, index) { return target[index] === value; }); }); } /** * Checks if two values are different. * * @param {*} a - First value. * @param {*} b - Second value. * @returns {Boolean} */ function isDifferent(a, b) { var oldIsPrimitive = utils.isPrimitive(a); if (Array.isArray(a) && Array.isArray(b)) { return !equalArrays(true, a, b); } return oldIsPrimitive ? a !== b : true; } /** * @param {String} prefix * @param {String} part */ function getPath(prefix, part) { return prefix ? prefix + '.' + part : part; } /** * Checks if object has own specified property. * * @param {*} obj - Value to be checked. * @param {String} key - Key of the property. * @returns {Boolean} */ function hasOwn(obj, key) { return Object.prototype.hasOwnProperty.call(obj, key); } /** * @param {Array} changes */ function getContainers(changes) { var containers = {}, indexed = _.indexBy(changes, 'path'); _.each(indexed, function (change, name) { var path; name.split('.').forEach(function (part) { path = getPath(path, part); if (path in indexed) { return; } (containers[path] = containers[path] || []).push(change); }); }); return containers; } /** * @param {String} path * @param {String} name * @param {String} type * @param {String} newValue * @param {String} oldValue */ function addChange(path, name, type, newValue, oldValue) { var data; data = { path: path, name: name, type: type }; if (type !== 'remove') { data.value = newValue; data.oldValue = oldValue; } else { data.oldValue = newValue; } result.push(data); } /** * @param {String} ns * @param {String} name * @param {String} type * @param {String} iterator * @param {String} placeholder */ function setAll(ns, name, type, iterator, placeholder) { var key; if (arguments.length > 4) { type === 'add' ? addChange(ns, name, 'update', iterator, placeholder) : addChange(ns, name, 'update', placeholder, iterator); } else { addChange(ns, name, type, iterator); } if (!utils.isObject(iterator)) { return; } for (key in iterator) { if (hasOwn(iterator, key)) { setAll(getPath(ns, key), key, type, iterator[key]); } } } /*eslint-disable max-depth*/ /** * @param {Object} old * @param {Object} current * @param {String} ns * @param {String} name */ function compare(old, current, ns, name) { var key, oldIsObj = utils.isObject(old), newIsObj = utils.isObject(current); if (oldIsObj && newIsObj) { for (key in old) { if (hasOwn(old, key) && !hasOwn(current, key)) { setAll(getPath(ns, key), key, 'remove', old[key]); } } for (key in current) { if (hasOwn(current, key)) { hasOwn(old, key) ? compare(old[key], current[key], getPath(ns, key), key) : setAll(getPath(ns, key), key, 'add', current[key]); } } } else if (oldIsObj) { setAll(ns, name, 'remove', old, current); } else if (newIsObj) { setAll(ns, name, 'add', current, old); } else if (isDifferent(old, current)) { addChange(ns, name, 'update', current, old); } } /*eslint-enable max-depth*/ return { /** * * @returns {Object} */ compare: function () { var changes; compare.apply(null, arguments); changes = result.splice(0); return { containers: getContainers(changes), changes: changes, equal: !changes.length }; }, equalArrays: equalArrays }; }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('mage/utils/misc',[ 'underscore', 'jquery', 'mage/utils/objects' ], function (_, $, utils) { 'use strict'; var defaultAttributes, ajaxSettings, map; defaultAttributes = { method: 'post', enctype: 'multipart/form-data' }; ajaxSettings = { default: { method: 'POST', cache: false, processData: false, contentType: false }, simple: { method: 'POST', dataType: 'json' } }; map = { 'D': 'DDD', 'dd': 'DD', 'd': 'D', 'EEEE': 'dddd', 'EEE': 'ddd', 'e': 'd', 'yyyy': 'YYYY', 'yy': 'YY', 'y': 'YYYY', 'a': 'A' }; return { /** * Generates a unique identifier. * * @param {Number} [size=7] - Length of a resulting identifier. * @returns {String} */ uniqueid: function (size) { var code = Math.random() * 25 + 65 | 0, idstr = String.fromCharCode(code); size = size || 7; while (idstr.length < size) { code = Math.floor(Math.random() * 42 + 48); if (code < 58 || code > 64) { idstr += String.fromCharCode(code); } } return idstr; }, /** * Limits function call. * * @param {Object} owner * @param {String} target * @param {Number} limit */ limit: function (owner, target, limit) { var fn = owner[target]; owner[target] = _.debounce(fn.bind(owner), limit); }, /** * Converts mage date format to a moment.js format. * * @param {String} mageFormat * @returns {String} */ normalizeDate: function (mageFormat) { var result = mageFormat; _.each(map, function (moment, mage) { result = result.replace( new RegExp(mage + '(?=([^\u0027]*\u0027[^\u0027]*\u0027)*[^\u0027]*$)'), moment ); }); result = result.replace(/'(.*?)'/g, '[$1]'); return result; }, /** * Puts provided value in range of min and max parameters. * * @param {Number} value - Value to be located. * @param {Number} min - Min value. * @param {Number} max - Max value. * @returns {Number} */ inRange: function (value, min, max) { return Math.min(Math.max(min, value), max); }, /** * Serializes and sends data via POST request. * * @param {Object} options - Options object that consists of * a 'url' and 'data' properties. * @param {Object} attrs - Attributes that will be added to virtual form. */ submit: function (options, attrs) { var form = document.createElement('form'), data = utils.serialize(options.data), attributes = _.extend({}, defaultAttributes, attrs || {}); if (!attributes.action) { attributes.action = options.url; } data['form_key'] = window.FORM_KEY; _.each(attributes, function (value, name) { form.setAttribute(name, value); }); data = _.map( data, function (value, name) { return '<input type="hidden" ' + 'name="' + _.escape(name) + '" ' + 'value="' + _.escape(value) + '"' + ' />'; } ).join(''); form.insertAdjacentHTML('afterbegin', data); document.body.appendChild(form); form.submit(); }, /** * Serializes and sends data via AJAX POST request. * * @param {Object} options - Options object that consists of * a 'url' and 'data' properties. * @param {Object} config */ ajaxSubmit: function (options, config) { var t = new Date().getTime(), settings; options.data['form_key'] = window.FORM_KEY; options.data = this.prepareFormData(options.data, config.ajaxSaveType); settings = _.extend({}, ajaxSettings[config.ajaxSaveType], options || {}); if (!config.ignoreProcessEvents) { $('body').trigger('processStart'); } return $.ajax(settings) .done(function (data) { if (config.response) { data.t = t; config.response.data(data); config.response.status(undefined); config.response.status(!data.error); } }) .fail(function () { if (config.response) { config.response.status(undefined); config.response.status(false); config.response.data({ error: true, messages: 'Something went wrong.', t: t }); } }) .always(function () { if (!config.ignoreProcessEvents) { $('body').trigger('processStop'); } }); }, /** * Creates FormData object and append this data. * * @param {Object} data * @param {String} type * @returns {FormData} */ prepareFormData: function (data, type) { var formData; if (type === 'default') { formData = new FormData(); _.each(utils.serialize(data), function (val, name) { formData.append(name, val); }); } else if (type === 'simple') { formData = utils.serialize(data); } return formData; }, /** * Filters data object. Finds properties with suffix * and sets their values to properties with the same name without suffix. * * @param {Object} data - The data object that should be filtered * @param {String} suffix - The string by which data object should be filtered * @param {String} separator - The string that is separator between property and suffix * * @returns {Object} Filtered data object */ filterFormData: function (data, suffix, separator) { data = data || {}; suffix = suffix || 'prepared-for-send'; separator = separator || '-'; _.each(data, function (value, key) { if (_.isObject(value) && !Array.isArray(value)) { this.filterFormData(value, suffix, separator); } else if (_.isString(key) && ~key.indexOf(suffix)) { data[key.split(separator)[0]] = value; delete data[key]; } }, this); return data; }, /** * Replaces special characters with their corresponding HTML entities. * * @param {String} string - Text to escape. * @returns {String} Escaped text. */ escape: function (string) { return string ? $('<p></p>').text(string).html().replace(/"/g, '"') : string; }, /** * Replaces symbol codes with their unescaped counterparts. * * @param {String} data * * @returns {String} */ unescape: function (data) { var unescaped = _.unescape(data), mapCharacters = { ''': '\'' }; _.each(mapCharacters, function (value, key) { unescaped = unescaped.replace(key, value); }); return unescaped; }, /** * Converts PHP IntlFormatter format to moment format. * * @param {String} format - PHP format * @returns {String} - moment compatible formatting */ convertToMomentFormat: function (format) { var newFormat; newFormat = format.replace(/yyyy|yy|y/, 'YYYY'); // replace the year newFormat = newFormat.replace(/dd|d/g, 'DD'); // replace the date return newFormat; }, /** * Get Url Parameters. * * @param {String} url - Url string * @returns {Object} */ getUrlParameters: function (url) { var params = {}, queries = url.split('?'), temp, i, l; if (!queries[1]) { return params; } queries = queries[1].split('&'); for (i = 0, l = queries.length; i < l; i++) { temp = queries[i].split('='); if (temp[1]) { params[temp[0]] = decodeURIComponent(temp[1].replace(/\+/g, '%20')); } else { params[temp[0]] = ''; } } return params; } }; }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /* eslint-disable no-shadow */ define('mage/utils/template',[ 'jquery', 'underscore', 'mage/utils/objects', 'mage/utils/strings' ], function ($, _, utils, stringUtils) { 'use strict'; var tmplSettings = _.templateSettings, interpolate = /\$\{([\s\S]+?)\}/g, opener = '${', template, hasStringTmpls; /** * Identifies whether ES6 templates are supported. */ hasStringTmpls = (function () { var testString = 'var foo = "bar"; return `${ foo }` === foo'; try { return Function(testString)(); } catch (e) { return false; } })(); /** * Objects can specify how to use templating for their properties - getting that configuration. * * To disable rendering for all properties of your object add __disableTmpl: true. * To disable for specific property add __disableTmpl: {propertyName: true}. * To limit recursion for a specific property add __disableTmpl: {propertyName: numberOfCycles}. * * @param {String} tmpl * @param {Object | undefined} target * @returns {Boolean|Object} */ function isTmplIgnored(tmpl, target) { var parsedTmpl; try { parsedTmpl = JSON.parse(tmpl); if (typeof parsedTmpl === 'object') { return tmpl.includes('__disableTmpl'); } } catch (e) { } if (typeof target !== 'undefined') { if (typeof target === 'object' && target.hasOwnProperty('__disableTmpl')) { return target.__disableTmpl; } } return false; } if (hasStringTmpls) { /*eslint-disable no-unused-vars, no-eval*/ /** * Evaluates template string using ES6 templates. * * @param {String} tmpl - Template string. * @param {Object} $ - Data object used in a template. * @returns {String} Compiled template. */ template = function (tmpl, $) { return eval('`' + tmpl + '`'); }; /*eslint-enable no-unused-vars, no-eval*/ } else { /** * Fallback function used when ES6 templates are not supported. * Uses underscore templates renderer. * * @param {String} tmpl - Template string. * @param {Object} data - Data object used in a template. * @returns {String} Compiled template. */ template = function (tmpl, data) { var cached = tmplSettings.interpolate; tmplSettings.interpolate = interpolate; tmpl = _.template(tmpl, { variable: '$' })(data); tmplSettings.interpolate = cached; return tmpl; }; } /** * Checks if provided value contains template syntax. * * @param {*} value - Value to be checked. * @returns {Boolean} */ function isTemplate(value) { return typeof value === 'string' && value.indexOf(opener) !== -1 && // the below pattern almost always indicates an accident which should not cause template evaluation // refuse to evaluate value.indexOf('${{') === -1; } /** * Iteratively processes provided string * until no templates syntax will be found. * * @param {String} tmpl - Template string. * @param {Object} data - Data object used in a template. * @param {Boolean} [castString=false] - Flag that indicates whether template * should be casted after evaluation to a value of another type or * that it should be leaved as a string. * @param {Number|undefined} maxCycles - Maximum number of rendering cycles, can be 0. * @returns {*} Compiled template. */ function render(tmpl, data, castString, maxCycles) { var last = tmpl, cycles = 0; while (~tmpl.indexOf(opener) && (typeof maxCycles === 'undefined' || cycles < maxCycles)) { if (!isTmplIgnored(tmpl)) { tmpl = template(tmpl, data); } if (tmpl === last) { break; } last = tmpl; cycles++; } return castString ? stringUtils.castString(tmpl) : tmpl; } return { /** * Applies provided data to the template. * * @param {Object|String} tmpl * @param {Object} [data] - Data object to match with template. * @param {Boolean} [castString=false] - Flag that indicates whether template * should be casted after evaluation to a value of another type or * that it should be leaved as a string. * @returns {*} * * @example Template defined as a string. * var source = { foo: 'Random Stuff', bar: 'Some' }; * * utils.template('${ $.bar } ${ $.foo }', source); * => 'Some Random Stuff'; * * @example Template defined as an object. * var tmpl = { * key: {'${ $.$data.bar }': '${ $.$data.foo }'}, * foo: 'bar', * x1: 2, x2: 5, * delta: '${ $.x2 - $.x1 }', * baz: 'Upper ${ $.foo.toUpperCase() }' * }; * * utils.template(tmpl, source); * => { * key: {'Some': 'Random Stuff'}, * foo: 'bar', * x1: 2, x2: 5, * delta: 3, * baz: 'Upper BAR' * }; */ template: function (tmpl, data, castString, dontClone) { if (typeof tmpl === 'string') { return render(tmpl, data, castString); } if (!dontClone) { tmpl = utils.copy(tmpl); } tmpl.$data = data || {}; /** * Template iterator function. */ _.each(tmpl, function iterate(value, key, list) { var disabled, maxCycles; if (key === '$data') { return; } if (isTemplate(key)) { delete list[key]; key = render(key, tmpl); list[key] = value; } if (isTemplate(value)) { //Getting template disabling settings, can be true for all disabled and separate settings //for each property. disabled = isTmplIgnored(value, list); if (typeof disabled === 'object' && disabled.hasOwnProperty(key) && disabled[key] !== false) { //Checking if specific settings for a property provided. maxCycles = disabled[key]; } if (disabled === true || maxCycles === true) { //Rendering for all properties is disabled. maxCycles = 0; } list[key] = render(value, tmpl, castString, maxCycles); } else if ($.isPlainObject(value) || Array.isArray(value)) { _.each(value, iterate); } }); delete tmpl.$data; return tmpl; } }; }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('mage/utils/main',['require','underscore','./arrays','./compare','./misc','./objects','./strings','./template'],function (require) { 'use strict'; var utils = {}, _ = require('underscore'), root = typeof self == 'object' && self.self === self && self || typeof global == 'object' && global.global === global && global || Function('return this')() || {}; root._ = _; return _.extend( utils, require('./arrays'), require('./compare'), require('./misc'), require('./objects'), require('./strings'), require('./template') ); }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('Magento_Ui/js/lib/core/events',[ 'ko', 'underscore' ], function (ko, _) { 'use strict'; var eventsMap = new WeakMap(); /** * Returns events map or a specific event * data associated with a provided object. * * @param {Object} obj - Key in the events weakmap. * @param {String} [name] - Name of the event. * @returns {Map|Array|Boolean} */ function getEvents(obj, name) { var events = eventsMap.get(obj); if (!events) { return false; } return name ? events.get(name) : events; } /** * Adds new event handler. * * @param {Object} obj - Key in the events weakmap. * @param {String} ns - Callback namespace. * @param {Function} callback - Event callback. * @param {String} name - Name of the event. */ function addHandler(obj, ns, callback, name) { var events = getEvents(obj), observable, data; observable = !ko.isObservable(obj[name]) ? ko.getObservable(obj, name) : obj[name]; if (observable) { observable.subscribe(callback); return; } if (!events) { events = new Map(); eventsMap.set(obj, events); } data = { callback: callback, ns: ns }; // Vaimo patch: allow KO observable to be skipped to force event to trigger even when no changes // encountered. Having exclamation mark in the end of the event name bypasses the ko.getObservable // part of this script. if (name.substr(-1) === '!' && name.length > 1) { name = name.substr(0, name.length - 1); } events.has(name) ? events.get(name).push(data) : events.set(name, [data]); } /** * Invokes provided callbacks with a specified arguments. * * @param {Array} handlers * @param {Array} args * @returns {Boolean} */ function trigger(handlers, args) { var bubble = true, callback; handlers.forEach(function (handler) { callback = handler.callback; if (callback.apply(null, args) === false) { bubble = false; } }); return bubble; } return { /** * Calls callback when name event is triggered. * @param {String} events * @param {Function} callback * @param {Function} ns * @return {Object} reference to this */ on: function (events, callback, ns) { var iterator; if (arguments.length < 2) { ns = callback; } iterator = addHandler.bind(null, this, ns); _.isObject(events) ? _.each(events, iterator) : iterator(callback, events); return this; }, /** * Removed callback from listening to target event * @param {String} ns * @return {Object} reference to this */ off: function (ns) { var storage = getEvents(this); if (!storage) { return this; } storage.forEach(function (handlers, name) { handlers = handlers.filter(function (handler) { return !ns ? false : handler.ns !== ns; }); handlers.length ? storage.set(name, handlers) : storage.delete(name); }); return this; }, /** * Triggers event and executes all attached callbacks. * * @param {String} name - Name of the event to be triggered. * @returns {Boolean} */ trigger: function (name) { var handlers, args; handlers = getEvents(this, name), args = _.toArray(arguments).slice(1); if (!handlers || !name) { return true; } return trigger(handlers, args); } }; }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /** * Utility methods used to wrap and extend functions. * * @example Usage of a 'wrap' method with arguments delegation. * var multiply = function (a, b) { * return a * b; * }; * * multiply = module.wrap(multiply, function (orig) { * return 'Result is: ' + orig(); * }); * * multiply(2, 2); * => 'Result is: 4' * * @example Usage of 'wrapSuper' method. * var multiply = function (a, b) { * return a * b; * }; * * var obj = { * multiply: module.wrapSuper(multiply, function () { * return 'Result is: ' + this._super(); * }); * }; * * obj.multiply(2, 2); * => 'Result is: 4' */ define('mage/utils/wrapper',[ 'underscore' ], function (_) { 'use strict'; /** * Checks if string has a '_super' substring. */ var superReg = /\b_super\b/; return { /** * Wraps target function with a specified wrapper, which will receive * reference to the original function as a first argument. * * @param {Function} target - Function to be wrapped. * @param {Function} wrapper - Wrapper function. * @returns {Function} Wrapper function. */ wrap: function (target, wrapper) { if (!_.isFunction(target) || !_.isFunction(wrapper)) { return wrapper; } return function () { var args = _.toArray(arguments), ctx = this, _super; /** * Function that will be passed to the wrapper. * If no arguments will be passed to it, then the original * function will be called with an arguments of a wrapper function. */ _super = function () { var superArgs = arguments.length ? arguments : args.slice(1); return target.apply(ctx, superArgs); }; args.unshift(_super); return wrapper.apply(ctx, args); }; }, /** * Wraps the incoming function to implement support of the '_super' method. * * @param {Function} target - Function to be wrapped. * @param {Function} wrapper - Wrapper function. * @returns {Function} Wrapped function. */ wrapSuper: function (target, wrapper) { if (!this.hasSuper(wrapper) || !_.isFunction(target)) { return wrapper; } return function () { var _super = this._super, args = arguments, result; /** * Temporary define '_super' method which * contains call to the original function. */ this._super = function () { var superArgs = arguments.length ? arguments : args; return target.apply(this, superArgs); }; result = wrapper.apply(this, args); this._super = _super; return result; }; }, /** * Checks wether the incoming method contains calls of the '_super' method. * * @param {Function} fn - Function to be checked. * @returns {Boolean} */ hasSuper: function (fn) { return _.isFunction(fn) && superReg.test(fn); }, /** * Extends target object with provided extenders. * If property in target and extender objects is a function, * then it will be wrapped using 'wrap' method. * * @param {Object} target - Object to be extended. * @param {...Object} extenders - Multiple extenders objects. * @returns {Object} Modified target object. */ extend: function (target) { var extenders = _.toArray(arguments).slice(1), iterator = this._extend.bind(this, target); extenders.forEach(iterator); return target; }, /** * Same as the 'extend' method, but operates only on one extender object. * * @private * @param {Object} target * @param {Object} extender */ _extend: function (target, extender) { _.each(extender, function (value, key) { target[key] = this.wrap(target[key], extender[key]); }, this); } }; }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('Magento_Ui/js/lib/core/class',[ 'underscore', 'mageUtils', 'mage/utils/wrapper' ], function (_, utils, wrapper) { 'use strict'; var Class; /** * Returns property of an object if * it's his own property. * * @param {Object} obj - Object whose property should be retrieved. * @param {String} prop - Name of the property. * @returns {*} Value of the property or false. */ function getOwn(obj, prop) { return _.isObject(obj) && obj.hasOwnProperty(prop) && obj[prop]; } /** * Creates constructor function which allows * initialization without usage of a 'new' operator. * * @param {Object} protoProps - Prototypal properties of a new constructor. * @param {Function} constructor * @returns {Function} Created constructor. */ function createConstructor(protoProps, constructor) { var UiClass = constructor; if (!UiClass) { /** * Default constructor function. */ UiClass = function () { var obj = this; if (!_.isObject(obj) || Object.getPrototypeOf(obj) !== UiClass.prototype) { obj = Object.create(UiClass.prototype); } obj.initialize.apply(obj, arguments); return obj; }; } UiClass.prototype = protoProps; UiClass.prototype.constructor = UiClass; return UiClass; } Class = createConstructor({ /** * Entry point to the initialization of constructor's instance. * * @param {Object} [options={}] * @returns {Class} Chainable. */ initialize: function (options) { this.initConfig(options); return this; }, /** * Recursively extends data specified in constructors' 'defaults' * property with provided options object. Evaluates resulting * object using string templates (see: mage/utils/template.js). * * @param {Object} [options={}] * @returns {Class} Chainable. */ initConfig: function (options) { var defaults = this.constructor.defaults, config = utils.extend({}, defaults, options || {}), ignored = config.ignoreTmpls || {}, cached = utils.omit(config, ignored); config = utils.template(config, this, false, true); _.each(cached, function (value, key) { utils.nested(config, key, value); }); return _.extend(this, config); } }); _.extend(Class, { defaults: { ignoreTmpls: { templates: true } }, /** * Creates new constructor based on a current prototype properties, * extending them with properties specified in 'exender' object. * * @param {Object} [extender={}] * @returns {Function} New constructor. */ extend: function (extender) { var parent = this, parentProto = parent.prototype, childProto = Object.create(parentProto), child = createConstructor(childProto, getOwn(extender, 'constructor')), defaults; extender = extender || {}; defaults = extender.defaults; delete extender.defaults; _.each(extender, function (method, name) { childProto[name] = wrapper.wrapSuper(parentProto[name], method); }); child.defaults = utils.extend({}, parent.defaults || {}); if (defaults) { utils.extend(child.defaults, defaults); extender.defaults = defaults; } return _.extend(child, { __super__: parentProto, extend: parent.extend }); } }); return Class; }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('Magento_Ui/js/lib/core/element/links',[ 'ko', 'underscore', 'mageUtils', 'uiRegistry' ], function (ko, _, utils, registry) { 'use strict'; /** * Parse provided data. * * @param {String} placeholder * @param {String} data * @param {String} direction * @returns {Boolean|Object} */ function parseData(placeholder, data, direction) { if (typeof data !== 'string') { return false; } data = data.split(':'); if (!data[0]) { return false; } if (!data[1]) { data[1] = data[0]; data[0] = placeholder; } return { target: data[0], property: data[1], direction: direction }; } /** * Check if value not empty. * * @param {*} value * @returns {Boolean} */ function notEmpty(value) { return typeof value !== 'undefined' && value != null; } /** * Update value for linked component. * * @param {Object} data * @param {Object} owner * @param {Object} target * @param {*} value */ function updateValue(data, owner, target, value) { var component = target.component, property = target.property, linked = data.linked; if (data.mute) { return; } if (linked) { linked.mute = true; } if (owner.component !== target.component) { value = data.inversionValue ? !utils.copy(value) : utils.copy(value); } component.set(property, value, owner); if (property === 'disabled' && value) { component.set('validate', value, owner); } if (linked) { linked.mute = false; } } /** * Get value form owner component property. * * @param {Object} owner * @returns {*} */ function getValue(owner) { var component = owner.component, property = owner.property; return component.get(property); } /** * Format provided params to object. * * @param {String} ownerComponent * @param {String} targetComponent * @param {String} ownerProp * @param {String} targetProp * @param {String} direction * @returns {Object} */ function form(ownerComponent, targetComponent, ownerProp, targetProp, direction) { var result, tmp; result = { owner: { component: ownerComponent, property: ownerProp }, target: { component: targetComponent, property: targetProp } }; if (direction === 'exports') { tmp = result.owner; result.owner = result.target; result.target = tmp; } return result; } /** * Set data to linked property. * * @param {Object} map * @param {Object} data */ function setLinked(map, data) { var match; if (!map) { return; } match = _.findWhere(map, { linked: false, target: data.target, property: data.property }); if (match) { match.linked = data; data.linked = match; } } /** * Set data by direction. * * @param {Object} maps * @param {String} property * @param {Object} data */ function setData(maps, property, data) { var direction = data.direction, map = maps[direction]; data.linked = false; (map[property] = map[property] || []).push(data); direction = direction === 'imports' ? 'exports' : 'imports'; setLinked(maps[direction][property], data); } /** * Set links for components. * * @param {String} target * @param {String} owner * @param {Object} data * @param {String} property * @param {Boolean} immediate */ function setLink(target, owner, data, property, immediate) { var direction = data.direction, formated = form(target, owner, data.property, property, direction), callback, value; owner = formated.owner; target = formated.target; callback = updateValue.bind(null, data, owner, target); owner.component.on(owner.property, callback, target.component.name); if (immediate) { value = getValue(owner); if (notEmpty(value)) { updateValue(data, owner, target, value); } } } /** * Transfer data between components. * * @param {Object} owner * @param {Object} data */ function transfer(owner, data) { var args = _.toArray(arguments); if (data.target.substr(0, 1) === '!') { data.target = data.target.substr(1); data.inversionValue = true; } if (owner.name === data.target) { args.unshift(owner); setLink.apply(null, args); } else { registry.get(data.target, function (target) { args.unshift(target); setLink.apply(null, args); }); } } return { /** * Assign listeners. * * @param {Object} listeners * @returns {Object} Chainable */ setListeners: function (listeners) { var owner = this, data; _.each(listeners, function (callbacks, sources) { sources = sources.split(' '); callbacks = callbacks.split(' '); sources.forEach(function (target) { callbacks.forEach(function (callback) {//eslint-disable-line max-nested-callbacks data = parseData(owner.name, target, 'imports'); if (data) { setData(owner.maps, callback, data); transfer(owner, data, callback); } }); }); }); return this; }, /** * Set links in provided direction. * * @param {Object} links * @param {String} direction * @returns {Object} Chainable */ setLinks: function (links, direction) { var owner = this, property, data; for (property in links) { if (links.hasOwnProperty(property)) { data = parseData(owner.name, links[property], direction); if (data) {//eslint-disable-line max-depth setData(owner.maps, property, data); transfer(owner, data, property, true); } } } return this; } }; }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('Magento_Ui/js/lib/core/storage/local',[ 'underscore', 'uiRegistry', 'mageUtils', 'uiEvents' ], function (_, registry, utils, EventsBus) { 'use strict'; var root = 'appData', localStorage, hasSupport, storage; /** * Flag which indicates whether localStorage is supported. */ hasSupport = (function () { var key = '_storageSupported'; try { localStorage = window.localStorage; localStorage.setItem(key, 'true'); if (localStorage.getItem(key) === 'true') { localStorage.removeItem(key); return true; } return false; } catch (e) { return false; } })(); if (!hasSupport) { localStorage = { _data: {}, /** * Sets value of the specified item. * * @param {String} key - Key of the property. * @param {*} value - Properties' value. */ setItem: function (key, value) { this._data[key] = value + ''; }, /** * Retrieves specified item. * * @param {String} key - Key of the property to be retrieved. */ getItem: function (key) { return this._data[key]; }, /** * Removes specified item. * * @param {String} key - Key of the property to be removed. */ removeItem: function (key) { delete this._data[key]; }, /** * Removes all items. */ clear: function () { this._data = {}; } }; } /** * Extracts and parses data stored in localStorage by the * key specified in 'root' variable. * * @returns {Object} */ function getRoot() { var data = localStorage.getItem(root), result = {}; if (!_.isNull(data) && typeof data != 'undefined') { result = JSON.parse(data); } return result; } /** * Writes provided data to the localStorage. * * @param {*} data - Data to be stored. */ function setRoot(data) { localStorage.setItem(root, JSON.stringify(data)); } /** * Provides methods to work with a localStorage * as a single nested structure. */ storage = _.extend({ /** * Retrieves value of the specified property. * * @param {String} path - Path to the property. * * @example Retrieving data. * localStorage => * 'appData' => ' * "one": {"two": "three"} * ' * storage.get('one.two') * => "three" * * storage.get('one') * => {"two": "three"} */ get: function (path) { var data = getRoot(); return utils.nested(data, path); }, /** * Sets specified data to the localStorage. * * @param {String} path - Path of the property. * @param {*} value - Value of the property. * * @example Setting data. * storage.set('one.two', 'four'); * => localStorage => * 'appData' => ' * "one": {"two": "four"} * ' */ set: function (path, value) { var data = getRoot(); utils.nested(data, path, value); setRoot(data); }, /** * Removes specified data from the localStorage. * * @param {String} path - Path to the property that should be removed. * * @example Removing data. * storage.remove('one.two', 'four'); * => localStorage => * 'appData' => ' * "one": {} * ' */ remove: function (path) { var data = getRoot(); utils.nestedRemove(data, path); setRoot(data); } }, EventsBus); registry.set('localStorage', storage); return storage; }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /** * @api */ define('Magento_Ui/js/lib/core/element/element',[ 'ko', 'underscore', 'mageUtils', 'uiRegistry', 'uiEvents', 'uiClass', './links', '../storage/local' ], function (ko, _, utils, registry, Events, Class, links) { 'use strict'; var Element; /** * Creates observable property using knockouts' * 'observableArray' or 'observable' methods, * depending on a type of 'value' parameter. * * @param {Object} obj - Object to whom property belongs. * @param {String} key - Key of the property. * @param {*} value - Initial value. */ function observable(obj, key, value) { var method = Array.isArray(value) ? 'observableArray' : 'observable'; if (_.isFunction(obj[key]) && !ko.isObservable(obj[key])) { return; } if (ko.isObservable(value)) { value = value(); } ko.isObservable(obj[key]) ? obj[key](value) : obj[key] = ko[method](value); } /** * Creates observable property using 'track' method. * * @param {Object} obj - Object to whom property belongs. * @param {String} key - Key of the property. * @param {*} value - Initial value. */ function accessor(obj, key, value) { if (_.isFunction(obj[key]) || ko.isObservable(obj[key])) { return; } obj[key] = value; if (!ko.es5.isTracked(obj, key)) { ko.track(obj, [key]); } } Element = _.extend({ defaults: { _requested: {}, containers: [], exports: {}, imports: {}, links: {}, listens: {}, name: '', ns: '${ $.name.split(".")[0] }', provider: '', registerNodes: true, source: null, statefull: {}, template: '', tracks: {}, storageConfig: { provider: 'localStorage', namespace: '${ $.name }', path: '${ $.storageConfig.provider }:${ $.storageConfig.namespace }' }, maps: { imports: {}, exports: {} }, modules: { storage: '${ $.storageConfig.provider }' } }, /** * Initializes model instance. * * @returns {Element} Chainable. */ initialize: function () { this._super() .initObservable() .initModules() .initStatefull() .initLinks() .initUnique(); return this; }, /** * Initializes observable properties. * * @returns {Element} Chainable. */ initObservable: function () { _.each(this.tracks, function (enabled, key) { if (enabled) { this.track(key); } }, this); return this; }, /** * Parses 'modules' object and creates * async wrappers for specified components. * * @returns {Element} Chainable. */ initModules: function () { _.each(this.modules, function (name, property) { if (name) { this[property] = this.requestModule(name); } }, this); if (!_.isFunction(this.source)) { this.source = registry.get(this.provider); } return this; }, /** * Called when current element was injected to another component. * * @param {Object} parent - Instance of a 'parent' component. * @returns {Collection} Chainable. */ initContainer: function (parent) { this.containers.push(parent); return this; }, /** * Initializes statefull properties * based on the keys of 'statefull' object. * * @returns {Element} Chainable. */ initStatefull: function () { _.each(this.statefull, function (path, key) { if (path) { this.setStatefull(key, path); } }, this); return this; }, /** * Initializes links between properties. * * @returns {Element} Chainbale. */ initLinks: function () { return this.setListeners(this.listens) .setLinks(this.links, 'imports') .setLinks(this.links, 'exports') .setLinks(this.exports, 'exports') .setLinks(this.imports, 'imports'); }, /** * Initializes listeners of the unique property. * * @returns {Element} Chainable. */ initUnique: function () { var update = this.onUniqueUpdate.bind(this), uniqueNs = this.uniqueNs; this.hasUnique = this.uniqueProp && uniqueNs; if (this.hasUnique) { this.source.on(uniqueNs, update, this.name); } return this; }, /** * Makes specified property to be stored automatically. * * @param {String} key - Name of the property * that will be stored. * @param {String} [path=key] - Path to the property in storage. * @returns {Element} Chainable. */ setStatefull: function (key, path) { var link = {}; path = !_.isString(path) || !path ? key : path; link[key] = this.storageConfig.path + '.' + path; this.setLinks(link, 'imports') .setLinks(link, 'exports'); return this; }, /** * Updates property specified in uniqueNs * if elements' unique property is set to 'true'. * * @returns {Element} Chainable. */ setUnique: function () { var property = this.uniqueProp; if (this[property]()) { this.source.set(this.uniqueNs, this.name); } return this; }, /** * Creates 'async' wrapper for the specified component * using uiRegistry 'async' method and caches it * in a '_requested' components object. * * @param {String} name - Name of requested component. * @returns {Function} Async module wrapper. */ requestModule: function (name) { var requested = this._requested; if (!requested[name]) { requested[name] = registry.async(name); } return requested[name]; }, /** * Returns path to elements' template. * * @returns {String} */ getTemplate: function () { return this.template; }, /** * Checks if template was specified for an element. * * @returns {Boolean} */ hasTemplate: function () { return !!this.template; }, /** * Returns value of the nested property. * * @param {String} path - Path to the property. * @returns {*} Value of the property. */ get: function (path) { return utils.nested(this, path); }, /** * Sets provided value as a value of the specified nested property. * Triggers changes notifications, if value has mutated. * * @param {String} path - Path to property. * @param {*} value - New value of the property. * @returns {Element} Chainable. */ set: function (path, value) { var data = this.get(path), diffs; diffs = !_.isFunction(data) && !this.isTracked(path) ? utils.compare(data, value, path) : false; utils.nested(this, path, value); if (diffs) { this._notifyChanges(diffs); } return this; }, /** * Removes nested property from the object. * * @param {String} path - Path to the property. * @returns {Element} Chainable. */ remove: function (path) { var data = utils.nested(this, path), diffs; if (_.isUndefined(data) || _.isFunction(data)) { return this; } diffs = utils.compare(data, undefined, path); utils.nestedRemove(this, path); this._notifyChanges(diffs); return this; }, /** * Creates observable properties for the current object. * * If 'useTrack' flag is set to 'true' then each property will be * created with a ES5 get/set accessor descriptors, instead of * making them an observable functions. * See 'knockout-es5' library for more information. * * @param {Boolean} [useAccessors=false] - Whether to create an * observable function or to use property accesessors. * @param {(Object|String|Array)} properties - List of observable properties. * @returns {Element} Chainable. * * @example Sample declaration and equivalent knockout methods. * this.key = 'value'; * this.array = ['value']; * * this.observe(['key', 'array']); * => * this.key = ko.observable('value'); * this.array = ko.observableArray(['value']); * * @example Another syntaxes of the previous example. * this.observe({ * key: 'value', * array: ['value'] * }); */ observe: function (useAccessors, properties) { var model = this, trackMethod; if (typeof useAccessors !== 'boolean') { properties = useAccessors; useAccessors = false; } trackMethod = useAccessors ? accessor : observable; if (_.isString(properties)) { properties = properties.split(' '); } if (Array.isArray(properties)) { properties.forEach(function (key) { trackMethod(model, key, model[key]); }); } else if (typeof properties === 'object') { _.each(properties, function (value, key) { trackMethod(model, key, value); }); } return this; }, /** * Delegates call to 'observe' method but * with a predefined 'useAccessors' flag. * * @param {(String|Array|Object)} properties - List of observable properties. * @returns {Element} Chainable. */ track: function (properties) { this.observe(true, properties); return this; }, /** * Checks if specified property is tracked. * * @param {String} property - Property to be checked. * @returns {Boolean} */ isTracked: function (property) { return ko.es5.isTracked(this, property); }, /** * Invokes subscribers for the provided changes. * * @param {Object} diffs - Object with changes descriptions. * @returns {Element} Chainable. */ _notifyChanges: function (diffs) { diffs.changes.forEach(function (change) { this.trigger(change.path, change.value, change); }, this); _.each(diffs.containers, function (changes, name) { var value = utils.nested(this, name); this.trigger(name, value, changes); }, this); return this; }, /** * Extracts all stored data and sets it to element. * * @returns {Element} Chainable. */ restore: function () { var ns = this.storageConfig.namespace, storage = this.storage(); if (storage) { utils.extend(this, storage.get(ns)); } return this; }, /** * Stores value of the specified property in components' storage module. * * @param {String} property * @param {*} [data=this[property]] * @returns {Element} Chainable. */ store: function (property, data) { var ns = this.storageConfig.namespace, path = utils.fullPath(ns, property); if (arguments.length < 2) { data = this.get(property); } this.storage('set', path, data); return this; }, /** * Extracts specified property from storage. * * @param {String} [property] - Name of the property * to be extracted. If not specified then all of the * stored will be returned. * @returns {*} */ getStored: function (property) { var ns = this.storageConfig.namespace, path = utils.fullPath(ns, property), storage = this.storage(), data; if (storage) { data = storage.get(path); } return data; }, /** * Removes stored property. * * @param {String} property - Property to be removed from storage. * @returns {Element} Chainable. */ removeStored: function (property) { var ns = this.storageConfig.namespace, path = utils.fullPath(ns, property); this.storage('remove', path); return this; }, /** * Destroys current instance along with all of its' children. * @param {Boolean} skipUpdate - skip collection update when element to be destroyed. */ destroy: function (skipUpdate) { this._dropHandlers() ._clearRefs(skipUpdate); }, /** * Removes events listeners. * @private * * @returns {Element} Chainable. */ _dropHandlers: function () { this.off(); if (_.isFunction(this.source)) { this.source().off(this.name); } else if (this.source) { this.source.off(this.name); } return this; }, /** * Removes all references to current instance and * calls 'destroy' method on all of its' children. * @private * @param {Boolean} skipUpdate - skip collection update when element to be destroyed. * * @returns {Element} Chainable. */ _clearRefs: function (skipUpdate) { registry.remove(this.name); this.containers.forEach(function (parent) { parent.removeChild(this, skipUpdate); }, this); return this; }, /** * Overrides 'EventsBus.trigger' method to implement events bubbling. * * @param {...*} arguments - Any number of arguments that should be passed to the events' handler. * @returns {Boolean} False if event bubbling was canceled. */ bubble: function () { var args = _.toArray(arguments), bubble = this.trigger.apply(this, args), result; if (!bubble) { return false; } this.containers.forEach(function (parent) { result = parent.bubble.apply(parent, args); if (result === false) { bubble = false; } }); return !!bubble; }, /** * Callback which fires when property under uniqueNs has changed. */ onUniqueUpdate: function (name) { var active = name === this.name, property = this.uniqueProp; this[property](active); }, /** * Clean data form data source. * * @returns {Element} */ cleanData: function () { if (this.source && this.source.componentType === 'dataSource') { if (this.elems) { _.each(this.elems(), function (val) { val.cleanData(); }); } else { this.source.remove(this.dataScope); } } return this; }, /** * Fallback data. */ cacheData: function () { this.cachedComponent = utils.copy(this); }, /** * Update configuration in component. * * @param {*} oldValue * @param {*} newValue * @param {String} path - path to value. * @returns {Element} */ updateConfig: function (oldValue, newValue, path) { var names = path.split('.'), index = _.lastIndexOf(names, 'config') + 1; names = names.splice(index, names.length - index).join('.'); this.set(names, newValue); return this; } }, Events, links); return Class.extend(Element); }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /** * @api */ define('Magento_Ui/js/lib/core/collection',[ 'underscore', 'mageUtils', 'uiRegistry', 'uiElement' ], function (_, utils, registry, Element) { 'use strict'; /** * Removes non plain object items from the specified array. * * @param {Array} container - Array whose value should be filtered. * @returns {Array} */ function compact(container) { return _.values(container).filter(utils.isObject); } /** * Defines index of an item in a specified container. * * @param {*} item - Item whose index should be defined. * @param {Array} container - Container upon which to perform search. * @returns {Number} */ function _findIndex(item, container) { var index = _.findKey(container, function (value) { return value === item; }); if (typeof index === 'undefined') { index = _.findKey(container, function (value) { return value && value.name === item; }); } return typeof index === 'undefined' ? -1 : index; } /** * Inserts specified item into container at a specified position. * * @param {*} item - Item to be inserted into container. * @param {Array} container - Container of items. * @param {*} [position=-1] - Position at which item should be inserted. * Position can represent: * - specific index in container * - item which might already be present in container * - structure with one of these properties: after, before * @returns {Boolean|*} * - true if element has changed its' position * - false if nothing has changed * - inserted value if it wasn't present in container */ function _insertAt(item, container, position) { var currentIndex = _findIndex(item, container), newIndex, target; if (typeof position === 'undefined') { position = -1; } else if (typeof position === 'string') { position = isNaN(+position) ? position : +position; } newIndex = position; if (~currentIndex) { target = container.splice(currentIndex, 1)[0]; if (typeof item === 'string') { item = target; } } if (typeof position !== 'number') { target = position.after || position.before || position; newIndex = _findIndex(target, container); if (~newIndex && (position.after || newIndex >= currentIndex)) { newIndex++; } } if (newIndex < 0) { newIndex += container.length + 1; } container[newIndex] ? container.splice(newIndex, 0, item) : container[newIndex] = item; return !~currentIndex ? item : currentIndex !== newIndex; } return Element.extend({ defaults: { template: 'ui/collection', _elems: [], ignoreTmpls: { childDefaults: true } }, /** * Initializes observable properties. * * @returns {Model} Chainable. */ initObservable: function () { this._super() .observe({ elems: [] }); return this; }, /** * Called when another element was added to current component. * * @param {Object} elem - Instance of an element that was added. * @returns {Collection} Chainable. */ initElement: function (elem) { elem.initContainer(this); return this; }, /** * Returns instance of a child found by provided index. * * @param {String} index - Index of a child. * @returns {Object} */ getChild: function (index) { return _.findWhere(this.elems(), { index: index }); }, /** * Requests specified components to insert * them into 'elems' array starting from provided position. * * @param {(String|Array)} elems - Name of the component to insert. * @param {Number} [position=-1] - Position at which to insert elements. * @returns {Collection} Chainable. */ insertChild: function (elems, position) { var container = this._elems, insert = this._insert.bind(this), update; if (!Array.isArray(elems)) { elems = [elems]; } elems.map(function (item) { return item.elem ? _insertAt(item.elem, container, item.position) : _insertAt(item, container, position); }).forEach(function (item) { if (item === true) { update = true; } else if (_.isString(item)) { registry.get(item, insert); } else if (utils.isObject(item)) { insert(item); } }); if (update) { this._updateCollection(); } return this; }, /** * Removes specified child from collection. * * @param {(Object|String)} elem - Child or index of a child to be removed. * @param {Boolean} skipUpdate - skip collection update when element to be destroyed. * * @returns {Collection} Chainable. */ removeChild: function (elem, skipUpdate) { if (_.isString(elem)) { elem = this.getChild(elem); } if (elem) { utils.remove(this._elems, elem); if (!skipUpdate) { this._updateCollection(); } } return this; }, /** * Destroys collection children with its' elements. */ destroyChildren: function () { this.elems.each(function (elem) { elem.destroy(true); }); this._updateCollection(); }, /** * Clear data. Call method "clear" * in child components * * @returns {Object} Chainable. */ clear: function () { var elems = this.elems(); _.each(elems, function (elem) { if (_.isFunction(elem.clear)) { elem.clear(); } }, this); return this; }, /** * Checks if specified child exists in collection. * * @param {String} index - Index of a child. * @returns {Boolean} */ hasChild: function (index) { return !!this.getChild(index); }, /** * Creates 'async' wrapper for the specified child * using uiRegistry 'async' method and caches it * in a '_requested' components object. * * @param {String} index - Index of a child. * @returns {Function} Async module wrapper. */ requestChild: function (index) { var name = this.formChildName(index); return this.requestModule(name); }, /** * Creates complete child name based on a provided index. * * @param {String} index - Index of a child. * @returns {String} */ formChildName: function (index) { return this.name + '.' + index; }, /** * Retrieves requested region. * Creates region if it was not created yet * * @returns {ObservableArray} */ getRegion: function (name) { var regions = this.regions = this.regions || {}; if (!regions[name]) { regions[name] = []; this.observe.call(regions, name); } return regions[name]; }, /** * Checks if the specified region has any elements * associated with it. * * @param {String} name * @returns {Boolean} */ regionHasElements: function (name) { var region = this.getRegion(name); return region().length > 0; }, /** * Replaces specified regions' data with a provided one. * Creates region if it was not created yet. * * @param {Array} items - New regions' data. * @param {String} name - Name of the region. * @returns {Collection} Chainable. */ updateRegion: function (items, name) { this.getRegion(name)(items); return this; }, /** * Destroys collection along with its' elements. */ destroy: function () { this._super(); this.elems.each('destroy'); }, /** * Inserts provided component into 'elems' array at a specified position. * @private * * @param {Object} elem - Element to insert. */ _insert: function (elem) { var index = _.findKey(this._elems, function (value) { return value === elem.name; }); if (typeof index !== 'undefined') { this._elems[index] = elem; } this._updateCollection() .initElement(elem); }, /** * Synchronizes multiple elements arrays with a core '_elems' container. * Performs elemets grouping by theirs 'displayArea' property. * @private * * @returns {Collection} Chainable. */ _updateCollection: function () { var _elems = compact(this._elems), grouped; grouped = _elems.filter(function (elem) { return elem.displayArea && _.isString(elem.displayArea); }); grouped = _.groupBy(grouped, 'displayArea'); _.each(grouped, this.updateRegion, this); _.each(this.regions, function (items) { var hasObsoleteComponents = items().length && !_.intersection(_elems, items()).length; if (hasObsoleteComponents) { items.removeAll(); } }); this.elems(_elems); return this; }, /** * Tries to call specified method of a current component, * otherwise delegates attempt to its' children. * * @param {String} target - Name of the method. * @param {...*} parameters - Arguments that will be passed to method. * @returns {*} Result of the method calls. */ delegate: function (target) { var args = _.toArray(arguments); target = this[target]; if (_.isFunction(target)) { return target.apply(this, args.slice(1)); } return this._delegate(args); }, /** * Calls 'delegate' method of all of it's children components. * @private * * @param {Array} args - An array of arguments to pass to the next delegation call. * @returns {Array} An array of delegation results. */ _delegate: function (args) { var result; result = this.elems.map(function (elem) { var target; if (!_.isFunction(elem.delegate)) { target = elem[args[0]]; if (_.isFunction(target)) { return target.apply(elem, args.slice(1)); } } else { return elem.delegate.apply(elem, args); } }); return _.flatten(result); } }); }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('Magento_Checkout/js/view/cart-item-renderer',[ 'uiComponent' ], function (Component) { 'use strict'; return Component.extend({ /** * Prepare the product name value to be rendered as HTML * * @param {String} productName * @return {String} */ getProductNameUnsanitizedHtml: function (productName) { // product name has already escaped on backend return productName; }, /** * Prepare the given option value to be rendered as HTML * * @param {String} optionValue * @return {String} */ getOptionValueUnsanitizedHtml: function (optionValue) { // option value has already escaped on backend return optionValue; } }); }); /** * Copyright © Vaimo Group. All rights reserved. * See LICENSE_VAIMO.txt for license details. */ define('Vaimo_BauhausSe/js/mock/auth-pop',[],function(){return{showModal:function(){return true},createPopUp:function(){return true}}}) ; /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('mage/template',[ 'underscore' ], function (_) { 'use strict'; /** * Checks if provided string is a valid DOM selector. * * @param {String} selector - Selector to be checked. * @returns {Boolean} */ function isSelector(selector) { try { document.querySelector(selector); return true; } catch (e) { return false; } } /** * Unescapes characters used in underscore templates. * * @param {String} str - String to be processed. * @returns {String} */ function unescape(str) { return str.replace(/<%|%3C%/g, '<%').replace(/%>|%%3E/g, '%>'); } /** * If 'tmpl' is a valid selector, returns target node's innerHTML if found. * Else, returns empty string and emits console warning. * If 'tmpl' is not a selector, returns 'tmpl' as is. * * @param {String} tmpl * @returns {String} */ function getTmplString(tmpl) { if (isSelector(tmpl)) { tmpl = document.querySelector(tmpl); if (tmpl) { tmpl = tmpl.innerHTML.trim(); } else { console.warn('No template was found by selector: ' + tmpl); tmpl = ''; } } return unescape(tmpl); } /** * Compiles or renders template provided either * by selector or by the template string. * * @param {String} tmpl - Template string or selector. * @param {(Object|Array|Function)} [data] - Data object with which to render template. * @returns {String|Function} */ return function (tmpl, data) { var render; tmpl = getTmplString(tmpl); render = _.template(tmpl); return !_.isUndefined(data) ? render(data) : render; }; }); define('text!ui/template/modal/modal-popup.html',[],function () { return '<!--\n/**\n * Copyright © Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n-->\n\n<aside role="dialog"\n class="modal-<%- data.type %> <%- data.modalClass %>\n <% if(data.responsive){ %><%- data.responsiveClass %><% } %>\n <% if(data.innerScroll){ %><%- data.innerScrollClass %><% } %>"\n <% if(data.title){ %> aria-labelledby="modal-title-<%- data.id %>"<% } %>\n aria-describedby="modal-content-<%- data.id %>"\n data-role="modal"\n data-type="<%- data.type %>"\n tabindex="0">\n <div data-role="focusable-start" tabindex="0"></div>\n <div class="modal-inner-wrap"\n data-role="focusable-scope">\n <header class="modal-header">\n <% if(data.title || data.subTitle){ %>\n <h1 id="modal-title-<%- data.id %>" class="modal-title"\n data-role="title">\n <% if(data.title){ %>\n <%= data.title %>\n <% } %>\n\n <% if(data.subTitle){ %>\n <span class="modal-subtitle"\n data-role="subTitle">\n <%= data.subTitle %>\n </span>\n <% } %>\n </h1>\n <% } %>\n <button\n class="action-close"\n data-role="closeBtn"\n type="button">\n <span><%= data.closeText %></span>\n </button>\n </header>\n <div id="modal-content-<%- data.id %>"\n class="modal-content"\n data-role="content"></div>\n <% if(data.buttons.length > 0){ %>\n <footer class="modal-footer">\n <% _.each(data.buttons, function(button) { %>\n <button\n class="<%- button.class %>"\n type="button"\n data-role="action"><span><%= button.text %></span></button>\n <% }); %>\n </footer>\n <% } %>\n </div>\n <div data-role="focusable-end" tabindex="0"></div>\n</aside>\n';}); define('text!ui/template/modal/modal-slide.html',[],function () { return '<!--\n/**\n * Copyright © Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n-->\n\n<aside role="dialog"\n class="modal-<%- data.type %> <%- data.modalClass %>\n <% if(data.innerScroll){ %><%- data.innerScrollClass %><% } %>"\n <% if(data.title){ %> aria-labelledby="modal-title-<%- data.id %>"<% } %>\n aria-describedby="modal-content-<%- data.id %>"\n data-role="modal"\n data-type="<%- data.type %>"\n tabindex="0">\n <div data-role="focusable-start" tabindex="0"></div>\n <div class="modal-inner-wrap"\n data-role="focusable-scope">\n <header class="modal-header">\n <% if(data.title || data.subTitle){ %>\n <h1 id="modal-title-<%- data.id %>" class="modal-title"\n data-role="title">\n <% if(data.title){ %>\n <%= data.title %>\n <% } %>\n\n <% if(data.subTitle){ %>\n <span class="modal-subtitle"\n data-role="subTitle">\n <%= data.subTitle %>\n </span>\n <% } %>\n </h1>\n <% } %>\n <button\n class="action-close"\n data-role="closeBtn"\n type="button">\n <span><%= data.closeText %></span>\n </button>\n <% if(data.buttons.length > 0){ %>\n <div class="page-main-actions">\n <div class="page-actions">\n <div class="page-actions-buttons">\n <% _.each(data.buttons, function(button) { %>\n <button\n class="<%- button.class %>"\n type="button"\n data-role="action"><span><%= button.text %></span>\n </button>\n <% }); %>\n </div>\n </div>\n </div>\n <% } %>\n </header>\n <div id="modal-content-<%- data.id %>" class="modal-content" data-role="content"></div>\n </div>\n <div data-role="focusable-end" tabindex="0"></div>\n</aside>\n';}); define('text!ui/template/modal/modal-custom.html',[],function () { return '<!--\n/**\n * Copyright © Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n-->\n\n<aside role="dialog"\n class="modal-<%- data.type %> <%- data.modalClass %>\n <% if(data.responsive){ %><%- data.responsiveClass %><% } %>\n <% if(data.innerScroll){ %><%- data.innerScrollClass %><% } %>"\n <% if(data.title){ %> aria-labelledby="modal-title-<%- data.id %>"<% } %>\n aria-describedby="modal-content-<%- data.id %>"\n data-role="modal"\n data-type="<%- data.type %>"\n tabindex="0">\n <div data-role="focusable-start" tabindex="0"></div>\n <div class="modal-inner-wrap"\n data-role="focusable-scope">\n <header class="modal-header">\n <% if(data.title || data.subTitle){ %>\n <h1 id="modal-title-<%- data.id %>" class="modal-title"\n data-role="title">\n <% if(data.title){ %>\n <%= data.title %>\n <% } %>\n\n <% if(data.subTitle){ %>\n <span class="modal-subtitle"\n data-role="subTitle">\n <%= data.subTitle %>\n </span>\n <% } %>\n </h1>\n <% } %>\n <button\n class="action-close"\n data-role="closeBtn"\n type="button">\n <span><%= data.closeText %></span>\n </button>\n </header>\n <div id="modal-content-<%- data.id %>" class="modal-content" data-role="content"></div>\n <% if(data.buttons.length > 0){ %>\n <footer class="modal-footer">\n <% _.each(data.buttons, function(button) { %>\n <button class="<%- button.class %>"\n type="button"\n data-role="action">\n <span><%= button.text %></span>\n </button>\n <% }); %>\n </footer>\n <% } %>\n </div>\n <div data-role="focusable-end" tabindex="0"></div>\n</aside>\n';}); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /** * @api */ define('Magento_Ui/js/lib/key-codes',[], function () { 'use strict'; return { 13: 'enterKey', 27: 'escapeKey', 40: 'pageDownKey', 38: 'pageUpKey', 32: 'spaceKey', 9: 'tabKey', 37: 'pageLeftKey', 39: 'pageRightKey', 17: 'ctrlKey', 18: 'altKey', 16: 'shiftKey', 191: 'forwardSlashKey', 66: 'bKey', 73: 'iKey', 85: 'uKey' }; }); /*! * zIndex plugin from jQuery UI Core - v1.10.4 * http://jqueryui.com * * Copyright 2014 jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license * * http://api.jqueryui.com/category/ui-core/ */ define('jquery/z-index',[ 'jquery' ], function ($, undefined) { // plugins $.fn.extend({ zIndex: function (zIndex) { if (zIndex !== undefined) { return this.css("zIndex", zIndex); } if (this.length) { var elem = $(this[0]), position, value; while (elem.length && elem[0] !== document) { // Ignore z-index if position is set to a value where z-index is ignored by the browser // This makes behavior of this function consistent across browsers // WebKit always returns auto if the element is positioned position = elem.css("position"); if (position === "absolute" || position === "relative" || position === "fixed") { // IE returns 0 when zIndex is not specified // other browsers return a string // we ignore the case of nested elements with an explicit value of 0 // <div style="z-index: -10;"><div style="z-index: 0;"></div></div> value = parseInt(elem.css("zIndex"), 10); if (!isNaN(value) && value !== 0) { return value; } } elem = elem.parent(); } } return 0; } }); }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /** * @api */ define('Magento_Ui/js/modal/modal',[ 'jquery', 'underscore', 'mage/template', 'text!ui/template/modal/modal-popup.html', 'text!ui/template/modal/modal-slide.html', 'text!ui/template/modal/modal-custom.html', 'Magento_Ui/js/lib/key-codes', 'jquery-ui-modules/widget', 'jquery-ui-modules/core', 'mage/translate', 'jquery/z-index' ], function ($, _, template, popupTpl, slideTpl, customTpl, keyCodes) { 'use strict'; /** * Detect browser transition end event. * @return {String|undefined} - transition event. */ var transitionEvent = (function () { var transition, elementStyle = document.createElement('div').style, transitions = { 'transition': 'transitionend', 'OTransition': 'oTransitionEnd', 'MozTransition': 'transitionend', 'WebkitTransition': 'webkitTransitionEnd' }; for (transition in transitions) { if (elementStyle[transition] !== undefined && transitions.hasOwnProperty(transition)) { return transitions[transition]; } } })(); /** * Modal Window Widget */ $.widget('mage.modal', { options: { id: null, type: 'popup', title: '', subTitle: '', modalClass: '', focus: '[data-role="closeBtn"]', autoOpen: false, clickableOverlay: true, popupTpl: popupTpl, slideTpl: slideTpl, customTpl: customTpl, modalVisibleClass: '_show', parentModalClass: '_has-modal', innerScrollClass: '_inner-scroll', responsive: false, innerScroll: false, modalTitle: '[data-role="title"]', modalSubTitle: '[data-role="subTitle"]', modalBlock: '[data-role="modal"]', modalCloseBtn: '[data-role="closeBtn"]', modalContent: '[data-role="content"]', modalAction: '[data-role="action"]', focusableScope: '[data-role="focusable-scope"]', focusableStart: '[data-role="focusable-start"]', focusableEnd: '[data-role="focusable-end"]', appendTo: 'body', wrapperClass: 'modals-wrapper', overlayClass: 'modals-overlay', responsiveClass: 'modal-slide', trigger: '', modalLeftMargin: 45, closeText: $.mage.__('Close'), buttons: [{ text: $.mage.__('Ok'), class: '', attr: {}, /** * Default action on button click */ click: function (event) { this.closeModal(event); } }], keyEventHandlers: { /** * Tab key press handler, * set focus to elements */ tabKey: function () { if (document.activeElement === this.modal[0]) { this._setFocus('start'); } }, /** * Escape key press handler, * close modal window * @param {Object} event - event */ escapeKey: function (event) { if (this.options.isOpen && this.modal.find(document.activeElement).length || this.options.isOpen && this.modal[0] === document.activeElement) { this.closeModal(event); } } } }, /** * Creates modal widget. */ _create: function () { _.bindAll( this, 'keyEventSwitcher', '_tabSwitcher', 'closeModal' ); this.options.id = this.uuid; this.options.transitionEvent = transitionEvent; this._createWrapper(); this._renderModal(); this._createButtons(); if (this.options.trigger) { $(document).on('click', this.options.trigger, _.bind(this.toggleModal, this)); } this._on(this.modal.find(this.options.modalCloseBtn), { 'click': this.options.modalCloseBtnHandler ? this.options.modalCloseBtnHandler : this.closeModal }); this._on(this.element, { 'openModal': this.openModal, 'closeModal': this.closeModal }); this.options.autoOpen ? this.openModal() : false; }, /** * Returns element from modal node. * @return {Object} - element. */ _getElem: function (elem) { return this.modal.find(elem); }, /** * Gets visible modal count. * * @return {Number} - visible modal count. */ _getVisibleCount: function () { var modals = this.modalWrapper.find(this.options.modalBlock); return modals.filter('.' + this.options.modalVisibleClass).length; }, /** * Gets count of visible modal by slide type. * * @return {Number} - visible modal count. */ _getVisibleSlideCount: function () { var elems = this.modalWrapper.find('[data-type="slide"]'); return elems.filter('.' + this.options.modalVisibleClass).length; }, /** * Listener key events. * Call handler function if it exists */ keyEventSwitcher: function (event) { var key = keyCodes[event.keyCode]; if (this.options.keyEventHandlers.hasOwnProperty(key)) { this.options.keyEventHandlers[key].apply(this, arguments); } }, /** * Set title for modal. * * @param {String} title */ setTitle: function (title) { var $title = this.modal.find(this.options.modalTitle), $subTitle = this.modal.find(this.options.modalSubTitle); $title.text(title); $title.append($subTitle); }, /** * Set sub title for modal. * * @param {String} subTitle */ setSubTitle: function (subTitle) { this.options.subTitle = subTitle; this.modal.find(this.options.modalSubTitle).html(subTitle); }, /** * Toggle modal. * * @return {Element} - current element. */ toggleModal: function () { if (this.options.isOpen === true) { this.closeModal(); } else { this.openModal(); } }, /** * Open modal. * * @return {Element} - current element. */ openModal: function () { this.options.isOpen = true; this.focussedElement = document.activeElement; this._createOverlay(); this._setActive(); this._setKeyListener(); this.modal.one(this.options.transitionEvent, _.bind(this._setFocus, this, 'end', 'opened')); this.modal.one(this.options.transitionEvent, _.bind(this._trigger, this, 'opened')); this.modal.addClass(this.options.modalVisibleClass); if (!this.options.transitionEvent) { this._trigger('opened'); } return this.element; }, /** * Set focus to element. * @param {String} position - can be "start" and "end" * positions. * If position is "end" - sets focus to first * focusable element in modal window scope. * If position is "start" - sets focus to last * focusable element in modal window scope * * @param {String} type - can be "opened" or false * If type is "opened" - looks to "this.options.focus" * property and sets focus */ _setFocus: function (position, type) { var focusableElements, infelicity; if (type === 'opened' && this.options.focus) { this.modal.find($(this.options.focus)).trigger('focus'); } else if (type === 'opened' && !this.options.focus) { this.modal.find(this.options.focusableScope).trigger('focus'); } else if (position === 'end') { this.modal.find(this.options.modalCloseBtn).trigger('focus'); } else if (position === 'start') { infelicity = 2; //Constant for find last focusable element focusableElements = this.modal.find(':focusable'); focusableElements.eq(focusableElements.length - infelicity).trigger('focus'); } }, /** * Set events listener when modal is opened. */ _setKeyListener: function () { this.modal.find(this.options.focusableStart).on('focusin', this._tabSwitcher); this.modal.find(this.options.focusableEnd).on('focusin', this._tabSwitcher); this.modal.on('keydown', this.keyEventSwitcher); }, /** * Remove events listener when modal is closed. */ _removeKeyListener: function () { this.modal.find(this.options.focusableStart).off('focusin', this._tabSwitcher); this.modal.find(this.options.focusableEnd).off('focusin', this._tabSwitcher); this.modal.off('keydown', this.keyEventSwitcher); }, /** * Switcher for focus event. * @param {Object} e - event */ _tabSwitcher: function (e) { var target = $(e.target); if (target.is(this.options.focusableStart)) { this._setFocus('start'); } else if (target.is(this.options.focusableEnd)) { this._setFocus('end'); } }, /** * Close modal. * * @return {Element} - current element. */ closeModal: function () { var that = this; this._removeKeyListener(); this.options.isOpen = false; this.modal.one(this.options.transitionEvent, function () { that._close(); }); this.modal.removeClass(this.options.modalVisibleClass); if (!this.options.transitionEvent) { that._close(); } return this.element; }, /** * Helper for closeModal function. */ _close: function () { var trigger = _.bind(this._trigger, this, 'closed', this.modal); $(this.focussedElement).trigger('focus'); this._destroyOverlay(); this._unsetActive(); _.defer(trigger, this); }, /** * Set z-index and margin for modal and overlay. */ _setActive: function () { var zIndex = this.modal.zIndex(), baseIndex = zIndex + this._getVisibleCount(); if (this.modal.data('active')) { return; } this.modal.data('active', true); this.overlay.zIndex(++baseIndex); this.prevOverlayIndex = this.overlay.zIndex(); this.modal.zIndex(this.overlay.zIndex() + 1); if (this._getVisibleSlideCount()) { this.modal.css('marginLeft', this.options.modalLeftMargin * this._getVisibleSlideCount()); } }, /** * Unset styles for modal and set z-index for previous modal. */ _unsetActive: function () { this.modal.removeAttr('style'); this.modal.data('active', false); if (this.overlay) { this.overlay.zIndex(this.prevOverlayIndex - 1); } }, /** * Creates wrapper to hold all modals. */ _createWrapper: function () { this.modalWrapper = $(this.options.appendTo).find('.' + this.options.wrapperClass); if (!this.modalWrapper.length) { this.modalWrapper = $('<div></div>') .addClass(this.options.wrapperClass) .appendTo(this.options.appendTo); } }, /** * Compile template and append to wrapper. */ _renderModal: function () { $(template( this.options[this.options.type + 'Tpl'], { data: this.options })).appendTo(this.modalWrapper); this.modal = this.modalWrapper.find(this.options.modalBlock).last(); this.element.appendTo(this._getElem(this.options.modalContent)); if (this.element.is(':hidden')) { this.element.show(); } }, /** * Creates buttons pane. */ _createButtons: function () { this.buttons = this._getElem(this.options.modalAction); _.each(this.options.buttons, function (btn, key) { var button = this.buttons[key]; if (btn.attr) { $(button).attr(btn.attr); } if (btn.class) { $(button).addClass(btn.class); } if (!btn.click) { btn.click = this.closeModal; } $(button).on('click', _.bind(btn.click, this)); }, this); }, /** * Creates overlay, append it to wrapper, set previous click event on overlay. */ _createOverlay: function () { var events, outerClickHandler = this.options.outerClickHandler || this.closeModal; this.overlay = $('.' + this.options.overlayClass); if (!this.overlay.length) { $(this.options.appendTo).addClass(this.options.parentModalClass); this.overlay = $('<div></div>') .addClass(this.options.overlayClass) .appendTo(this.modalWrapper); } events = $._data(this.overlay.get(0), 'events'); events ? this.prevOverlayHandler = events.click[0].handler : false; this.options.clickableOverlay ? this.overlay.off().on('click', outerClickHandler) : false; }, /** * Destroy overlay. */ _destroyOverlay: function () { if (this._getVisibleCount()) { this.overlay.off().on('click', this.prevOverlayHandler); } else { $(this.options.appendTo).removeClass(this.options.parentModalClass); this.overlay.remove(); this.overlay = null; } } }); return $.mage.modal; }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /** * @api */ define('Magento_Ui/js/modal/confirm',[ 'jquery', 'underscore', 'mage/translate', 'jquery-ui-modules/widget', 'Magento_Ui/js/modal/modal' ], function ($, _, $t) { 'use strict'; $.widget('mage.confirm', $.mage.modal, { options: { modalClass: 'confirm', title: '', focus: '.action-accept', actions: { /** * Callback always - called on all actions. */ always: function () {}, /** * Callback confirm. */ confirm: function () {}, /** * Callback cancel. */ cancel: function () {} }, buttons: [{ text: $t('Cancel'), class: 'action-secondary action-dismiss', /** * Click handler. */ click: function (event) { this.closeModal(event); } }, { text: $t('OK'), class: 'action-primary action-accept', /** * Click handler. */ click: function (event) { this.closeModal(event, true); } }] }, /** * Create widget. */ _create: function () { this._super(); this.modal.find(this.options.modalCloseBtn).off().on('click', _.bind(this.closeModal, this)); this.openModal(); }, /** * Remove modal window. */ _remove: function () { this.modal.remove(); }, /** * Open modal window. */ openModal: function () { return this._super(); }, /** * Close modal window. */ closeModal: function (event, result) { result = result || false; if (result) { this.options.actions.confirm(event); } else { this.options.actions.cancel(event); } this.options.actions.always(event); this.element.on('confirmclosed', _.bind(this._remove, this)); return this._super(); } }); return function (config) { return $('<div></div>').html(config.content).confirm(config); }; }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /** * @api */ define('Magento_Ui/js/modal/alert',[ 'jquery', 'underscore', 'jquery-ui-modules/widget', 'Magento_Ui/js/modal/confirm', 'mage/translate' ], function ($, _) { 'use strict'; $.widget('mage.alert', $.mage.confirm, { options: { modalClass: 'confirm', title: $.mage.__('Attention'), actions: { /** * Callback always - called on all actions. */ always: function () {} }, buttons: [{ text: $.mage.__('OK'), class: 'action-primary action-accept', /** * Click handler. */ click: function () { this.closeModal(true); } }] }, /** * Close modal window. */ closeModal: function () { this.options.actions.always(); this.element.on('alertclosed', _.bind(this._remove, this)); return this._super(); } }); return function (config) { return $('<div></div>').html(config.content).alert(config); }; }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('mage/cookies',[ 'jquery', 'mage/mage', 'js-cookie/cookie-wrapper' ], function ($) { 'use strict'; /** * Helper for cookies manipulation * @returns {CookieHelper} * @constructor */ var CookieHelper = function () { /** * Cookie default values. * @type {Object} */ this.defaults = { expires: null, path: '/', domain: null, secure: false, lifetime: null, samesite: 'lax' }; /** * Calculate cookie expiration date based on its lifetime. * @param {Object} options - Cookie option values * @return {Date|null} Calculated cookie expiration date or null if no lifetime provided. * @private */ function lifetimeToExpires(options, defaults) { var expires, lifetime; lifetime = options.lifetime || defaults.lifetime; if (lifetime && lifetime > 0) { expires = options.expires || new Date(); return new Date(expires.getTime() + lifetime * 1000); } return null; } /** * Set a cookie's value by cookie name based on optional cookie options. * @param {String} name - The name of the cookie. * @param {String} value - The cookie's value. * @param {Object} options - Optional options (e.g. lifetime, expires, path, etc.) */ this.set = function (name, value, options) { var expires, path, domain, secure, samesite; options = $.extend({}, this.defaults, options || {}); expires = lifetimeToExpires(options, this.defaults) || options.expires; path = options.path; domain = options.domain; secure = options.secure; samesite = options.samesite; document.cookie = name + '=' + encodeURIComponent(value) + (expires ? '; expires=' + expires.toUTCString() : '') + (path ? '; path=' + path : '') + (domain ? '; domain=' + domain : '') + (secure ? '; secure' : '') + '; samesite=' + (samesite ? samesite : 'lax'); }; /** * Get a cookie's value by cookie name. * @param {String} name - The name of the cookie. * @return {(null|String)} */ this.get = function (name) { var arg = name + '=', aLength = arg.length, cookie = document.cookie, cLength = cookie.length, i = 0, j = 0; while (i < cLength) { j = i + aLength; if (cookie.substring(i, j) === arg) { return this.getCookieVal(j); } i = cookie.indexOf(' ', i) + 1; if (i === 0) { break; } } return null; }; /** * Clear a cookie's value by name. * @param {String} name - The name of the cookie being cleared. */ this.clear = function (name) { if (this.get(name)) { this.set(name, '', { expires: new Date('Jan 01 1970 00:00:01 GMT') }); } }; /** * Return URI decoded cookie component value (e.g. expires, path, etc.) based on a * numeric offset in the document's cookie value. * @param {Number} offset - Offset into the document's cookie value. * @return {String} */ this.getCookieVal = function (offset) { var cookie = document.cookie, endstr = cookie.indexOf(';', offset); if (endstr === -1) { endstr = cookie.length; } return decodeURIComponent(cookie.substring(offset, endstr)); }; return this; }; $.extend(true, $, { mage: { cookies: new CookieHelper() } }); return function (pageOptions) { $.extend($.mage.cookies.defaults, pageOptions); $.extend($.cookie.defaults, $.mage.cookies.defaults); }; }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('Magento_Checkout/js/sidebar',[ 'jquery', 'Magento_Customer/js/model/authentication-popup', 'Magento_Customer/js/customer-data', 'Magento_Ui/js/modal/alert', 'Magento_Ui/js/modal/confirm', 'underscore', 'jquery-ui-modules/widget', 'mage/decorate', 'mage/collapsible', 'mage/cookies', 'jquery-ui-modules/effect-fade' ], function ($, authenticationPopup, customerData, alert, confirm, _) { 'use strict'; $.widget('mage.sidebar', { options: { isRecursive: true, minicart: { maxItemsVisible: 3 } }, scrollHeight: 0, shoppingCartUrl: window.checkout.shoppingCartUrl, /** * Create sidebar. * @private */ _create: function () { this._initContent(); }, /** * Update sidebar block. */ update: function () { $(this.options.targetElement).trigger('contentUpdated'); this._calcHeight(); }, /** * @private */ _initContent: function () { var self = this, events = {}; this.element.decorate('list', this.options.isRecursive); /** * @param {jQuery.Event} event */ events['click ' + this.options.button.close] = function (event) { event.stopPropagation(); $(self.options.targetElement).dropdownDialog('close'); }; events['click ' + this.options.button.checkout] = $.proxy(function () { var cart = customerData.get('cart'), customer = customerData.get('customer'), element = $(this.options.button.checkout); if (!customer().firstname && cart().isGuestCheckoutAllowed === false) { // set URL for redirect on successful login/registration. It's postprocessed on backend. $.cookie('login_redirect', this.options.url.checkout); if (this.options.url.isRedirectRequired) { element.prop('disabled', true); location.href = this.options.url.loginUrl; } else { authenticationPopup.showModal(); } return false; } element.prop('disabled', true); location.href = this.options.url.checkout; }, this); /** * @param {jQuery.Event} event */ events['click ' + this.options.button.remove] = function (event) { event.stopPropagation(); confirm({ content: self.options.confirmMessage, actions: { /** @inheritdoc */ confirm: function () { self._removeItem($(event.currentTarget)); }, /** @inheritdoc */ always: function (e) { e.stopImmediatePropagation(); } } }); }; /** * @param {jQuery.Event} event */ events['keyup ' + this.options.item.qty] = function (event) { self._showItemButton($(event.target)); }; /** * @param {jQuery.Event} event */ events['change ' + this.options.item.qty] = function (event) { self._showItemButton($(event.target)); }; /** * @param {jQuery.Event} event */ events['change ' + this.options.item.qty] = function (event) { self._showItemButton($(event.target)); }; /** * @param {jQuery.Event} event */ events['click ' + this.options.item.button] = function (event) { event.stopPropagation(); self._updateItemQty($(event.currentTarget)); }; /** * @param {jQuery.Event} event */ events['focusout ' + this.options.item.qty] = function (event) { self._validateQty($(event.currentTarget)); }; this._on(this.element, events); this._calcHeight(); }, /** * @param {HTMLElement} elem * @private */ _showItemButton: function (elem) { var itemId = elem.data('cart-item'), itemQty = elem.data('item-qty'); if (this._isValidQty(itemQty, elem.val())) { $('#update-cart-item-' + itemId).show('fade', 300); } else if (elem.val() == 0) { //eslint-disable-line eqeqeq this._hideItemButton(elem); } else { this._hideItemButton(elem); } }, /** * @param {*} origin - origin qty. 'data-item-qty' attribute. * @param {*} changed - new qty. * @returns {Boolean} * @private */ _isValidQty: function (origin, changed) { return origin != changed && //eslint-disable-line eqeqeq changed.length > 0 && changed - 0 == changed && //eslint-disable-line eqeqeq changed - 0 > 0; }, /** * @param {Object} elem * @private */ _validateQty: function (elem) { var itemQty = elem.data('item-qty'); if (!this._isValidQty(itemQty, elem.val())) { elem.val(itemQty); } }, /** * @param {HTMLElement} elem * @private */ _hideItemButton: function (elem) { var itemId = elem.data('cart-item'); $('#update-cart-item-' + itemId).hide('fade', 300); }, /** * @param {HTMLElement} elem * @private */ _updateItemQty: function (elem) { var itemId = elem.data('cart-item'); this._ajax(this.options.url.update, { 'item_id': itemId, 'item_qty': $('#cart-item-' + itemId + '-qty').val() }, elem, this._updateItemQtyAfter); }, /** * Update content after update qty * * @param {HTMLElement} elem */ _updateItemQtyAfter: function (elem) { var productData = this._getProductById(Number(elem.data('cart-item'))); if (!_.isUndefined(productData)) { $(document).trigger('ajax:updateCartItemQty'); if (window.location.href === this.shoppingCartUrl) { window.location.reload(false); } } this._hideItemButton(elem); }, /** * @param {HTMLElement} elem * @private */ _removeItem: function (elem) { var itemId = elem.data('cart-item'); this._ajax(this.options.url.remove, { 'item_id': itemId }, elem, this._removeItemAfter); }, /** * Update content after item remove * * @param {Object} elem * @private */ _removeItemAfter: function (elem) { var productData = this._getProductById(Number(elem.data('cart-item'))); if (!_.isUndefined(productData)) { $(document).trigger('ajax:removeFromCart', { productIds: [productData['product_id']], productInfo: [ { 'id': productData['product_id'] } ] }); if (window.location.href.indexOf(this.shoppingCartUrl) === 0) { window.location.reload(); } } }, /** * Retrieves product data by Id. * * @param {Number} productId - product Id * @returns {Object|undefined} * @private */ _getProductById: function (productId) { return _.find(customerData.get('cart')().items, function (item) { return productId === Number(item['item_id']); }); }, /** * @param {String} url - ajax url * @param {Object} data - post data for ajax call * @param {Object} elem - element that initiated the event * @param {Function} callback - callback method to execute after AJAX success */ _ajax: function (url, data, elem, callback) { $.extend(data, { 'form_key': $.mage.cookies.get('form_key') }); $.ajax({ url: url, data: data, type: 'post', dataType: 'json', context: this, /** @inheritdoc */ beforeSend: function () { elem.attr('disabled', 'disabled'); }, /** @inheritdoc */ complete: function () { elem.attr('disabled', null); } }) .done(function (response) { var msg; if (response.success) { callback.call(this, elem, response); } else { msg = response['error_message']; if (msg) { alert({ content: msg }); } } }) .fail(function (error) { console.log(JSON.stringify(error)); }); }, /** * Calculate height of minicart list * * @private */ _calcHeight: function () { var self = this, height = 0, counter = this.options.minicart.maxItemsVisible, target = $(this.options.minicart.list), outerHeight; self.scrollHeight = 0; target.children().each(function () { if ($(this).find('.options').length > 0) { $(this).collapsible(); } outerHeight = $(this).outerHeight(true); if (counter-- > 0) { height += outerHeight; } self.scrollHeight += outerHeight; }); target.parent().height(height); } }); return $.mage.sidebar; }); /** * * Author: Gianluca Guarini * Contact: gianluca.guarini@gmail.com * Website: http://www.gianlucaguarini.com/ * Twitter: @gianlucaguarini * * Copyright (c) Gianluca Guarini * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. **/ /* global jQuery */ (function(doc, win) { if (typeof doc.createEvent !== 'function') return false // no tap events here // helpers var pointerEvent = function(type) { var lo = type.toLowerCase(), ms = 'MS' + type return navigator.msPointerEnabled ? ms : window.PointerEvent ? lo : false }, touchEvent = function(name) { return 'on' + name in window ? name : false }, defaults = { useJquery: !win.IGNORE_JQUERY && typeof jQuery !== 'undefined', swipeThreshold: win.SWIPE_THRESHOLD || 100, tapThreshold: win.TAP_THRESHOLD || 150, // range of time where a tap event could be detected dbltapThreshold: win.DBL_TAP_THRESHOLD || 200, // delay needed to detect a double tap longtapThreshold: win.LONG_TAP_THRESHOLD || 1000, // delay needed to detect a long tap tapPrecision: win.TAP_PRECISION / 2 || 60 / 2, // touch events boundaries ( 60px by default ) justTouchEvents: win.JUST_ON_TOUCH_DEVICES }, // was initially triggered a "touchstart" event? wasTouch = false, touchevents = { touchstart: touchEvent('touchstart') || pointerEvent('PointerDown'), touchend: touchEvent('touchend') || pointerEvent('PointerUp'), touchmove: touchEvent('touchmove') || pointerEvent('PointerMove') }, isTheSameFingerId = function(e) { return !e.pointerId || typeof pointerId === 'undefined' || e.pointerId === pointerId }, setListener = function(elm, events, callback) { var eventsArray = events.split(' '), i = eventsArray.length while (i--) { elm.addEventListener(eventsArray[i], callback, false) } }, getPointerEvent = function(event) { var hasTargetTouches = Boolean(event.targetTouches && event.targetTouches.length) switch (true) { case Boolean(event.target.touches): return event.target.touches[0] case hasTargetTouches && typeof event.targetTouches[0].pageX !== 'undefined': return event.targetTouches[0] case hasTargetTouches && Boolean(event.targetTouches[0].touches): return event.targetTouches[0].touches[0] default: return event } }, isMultipleTouches = function(event) { return (event.targetTouches || event.target.touches || []).length > 1 }, getTimestamp = function() { return new Date().getTime() }, sendEvent = function(elm, eventName, originalEvent, data) { var customEvent = doc.createEvent('Event') customEvent.originalEvent = originalEvent data = data || {} data.x = currX data.y = currY // jquery if (defaults.useJquery) { customEvent = jQuery.Event(eventName, {originalEvent: originalEvent}) jQuery(elm).trigger(customEvent, data) } // addEventListener if (customEvent.initEvent) { for (var key in data) { customEvent[key] = data[key] } customEvent.initEvent(eventName, true, true) elm.dispatchEvent(customEvent) } // detect all the inline events // also on the parent nodes while (elm) { // inline if (elm['on' + eventName]) elm['on' + eventName](customEvent) elm = elm.parentNode } }, onTouchStart = function(e) { /** * Skip all the mouse events * events order: * Chrome: * touchstart * touchmove * touchend * mousedown * mousemove * mouseup <- this must come always after a "touchstart" * * Safari * touchstart * mousedown * touchmove * mousemove * touchend * mouseup <- this must come always after a "touchstart" */ if (!isTheSameFingerId(e) || isMultipleTouches(e)) return pointerId = e.pointerId // it looks like it was a touch event! if (e.type !== 'mousedown') wasTouch = true // skip this event we don't need to track it now if (e.type === 'mousedown' && wasTouch) return var pointer = getPointerEvent(e) // caching the current x cachedX = currX = pointer.pageX // caching the current y cachedY = currY = pointer.pageY longtapTimer = setTimeout(function() { sendEvent(e.target, 'longtap', e) target = e.target }, defaults.longtapThreshold) // we will use these variables on the touchend events timestamp = getTimestamp() tapNum++ }, onTouchEnd = function(e) { if (!isTheSameFingerId(e) || isMultipleTouches(e)) return pointerId = undefined // skip the mouse events if previously a touch event was dispatched // and reset the touch flag if (e.type === 'mouseup' && wasTouch) { wasTouch = false return } var eventsArr = [], now = getTimestamp(), deltaY = cachedY - currY, deltaX = cachedX - currX // clear the previous timer if it was set clearTimeout(dblTapTimer) // kill the long tap timer clearTimeout(longtapTimer) if (deltaX <= -defaults.swipeThreshold) eventsArr.push('swiperight') if (deltaX >= defaults.swipeThreshold) eventsArr.push('swipeleft') if (deltaY <= -defaults.swipeThreshold) eventsArr.push('swipedown') if (deltaY >= defaults.swipeThreshold) eventsArr.push('swipeup') if (eventsArr.length) { for (var i = 0; i < eventsArr.length; i++) { var eventName = eventsArr[i] sendEvent(e.target, eventName, e, { distance: { x: Math.abs(deltaX), y: Math.abs(deltaY) } }) } // reset the tap counter tapNum = 0 } else { if ( cachedX >= currX - defaults.tapPrecision && cachedX <= currX + defaults.tapPrecision && cachedY >= currY - defaults.tapPrecision && cachedY <= currY + defaults.tapPrecision ) { if (timestamp + defaults.tapThreshold - now >= 0) { // Here you get the Tap event sendEvent(e.target, tapNum >= 2 && target === e.target ? 'dbltap' : 'tap', e) target= e.target } } // reset the tap counter dblTapTimer = setTimeout(function() { tapNum = 0 }, defaults.dbltapThreshold) } }, onTouchMove = function(e) { if (!isTheSameFingerId(e)) return // skip the mouse move events if the touch events were previously detected if (e.type === 'mousemove' && wasTouch) return var pointer = getPointerEvent(e) currX = pointer.pageX currY = pointer.pageY }, tapNum = 0, pointerId, currX, currY, cachedX, cachedY, timestamp, target, dblTapTimer, longtapTimer //setting the events listeners // we need to debounce the callbacks because some devices multiple events are triggered at same time setListener(doc, touchevents.touchstart + (defaults.justTouchEvents ? '' : ' mousedown'), onTouchStart) setListener(doc, touchevents.touchend + (defaults.justTouchEvents ? '' : ' mouseup'), onTouchEnd) setListener(doc, touchevents.touchmove + (defaults.justTouchEvents ? '' : ' mousemove'), onTouchMove) // Configure the tocca default options at any time win.tocca = function(options) { for (var opt in options) { defaults[opt] = options[opt] } return defaults } })(document, window) ; define("jquery/jquery.mobile.custom", function(){}); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('mage/dataPost',[ 'jquery', 'mage/template', 'Magento_Ui/js/modal/confirm', 'jquery-ui-modules/widget' ], function ($, mageTemplate, uiConfirm) { 'use strict'; $.widget('mage.dataPost', { options: { formTemplate: '<form action="<%- data.action %>" method="post">' + '<% _.each(data.data, function(value, index) { %>' + '<input name="<%- index %>" value="<%- value %>">' + '<% }) %></form>', postTrigger: ['a[data-post]', 'button[data-post]', 'span[data-post]'], formKeyInputSelector: 'input[name="form_key"]' }, /** @inheritdoc */ _create: function () { this._bind(); }, /** @inheritdoc */ _bind: function () { var events = {}; $.each(this.options.postTrigger, function (index, value) { events['click ' + value] = '_postDataAction'; }); this._on(events); }, /** * Handler for click. * * @param {Object} e * @private */ _postDataAction: function (e) { var params = $(e.currentTarget).data('post'); e.preventDefault(); this.postData(params); }, /** * Data post action. * * @param {Object} params */ postData: function (params) { var formKey = $(this.options.formKeyInputSelector).val(), $form, input; if (formKey) { params.data['form_key'] = formKey; } $form = $(mageTemplate(this.options.formTemplate, { data: params })); if (params.files) { $form[0].enctype = 'multipart/form-data'; $.each(params.files, function (key, files) { if (files instanceof FileList) { input = document.createElement('input'); input.type = 'file'; input.name = key; input.files = files; $form[0].appendChild(input); } }); } if (params.data.confirmation) { uiConfirm({ content: params.data.confirmationMessage, actions: { /** @inheritdoc */ confirm: function () { $form.appendTo('body').hide().trigger('submit'); } } }); } else { $form.appendTo('body').hide().trigger('submit'); } } }); $(document).dataPost(); return $.mage.dataPost; }); define('text!ui/template/tooltip/tooltip.html',[],function () { return '<!--\n/**\n * Copyright © Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n-->\n<div data-tooltip="tooltip-wrapper" class="data-tooltip-wrapper <%= data.tooltipClasses %>">\n <div class="data-tooltip-tail"></div>\n <div class="data-tooltip">\n <% if(data.closeButton){ %>\n <button type="button" class="action-close">\n <span translate="\'Close\'"></span>\n </button>\n <% } %>\n <div class="data-tooltip-content"></div>\n </div>\n</div>\n';}); define('text!ui/template/collection.html',[],function () { return '<!--\n/**\n * Copyright © Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n-->\n<each args="data: elems, as: \'element\'">\n <render if="hasTemplate()"></render>\n</each>\n';}); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /** * Is being used by knockout template engine to store template to. */ define('Magento_Ui/js/lib/knockout/template/observable_source',[ 'ko', 'uiClass' ], function (ko, Class) { 'use strict'; return Class.extend({ /** * Initializes templateName, _data, nodes properties. * * @param {template} template - identifier of template */ initialize: function (template) { this.templateName = template; this._data = {}; this.nodes = ko.observable([]); }, /** * Data setter. If only one arguments passed, returns corresponding value. * Else, writes into it. * @param {String} key - key to write to or to read from * @param {*} value * @return {*} - if 1 arg provided, Returns _data[key] property */ data: function (key, value) { if (arguments.length === 1) { return this._data[key]; } this._data[key] = value; } }); }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('Magento_Ui/js/lib/knockout/template/loader',[ 'jquery' ], function ($) { 'use strict'; var licenseRegExp = /<!--[\s\S]*?-->/, defaultPlugin = 'text', defaultExt = 'html'; /** * Checks of provided string contains a file extension. * * @param {String} str - String to be checked. * @returns {Boolean} */ function hasFileExtension(str) { return !!~str.indexOf('.') && !!str.split('.').pop(); } /** * Checks if provided string contains a requirejs's plugin reference. * * @param {String} str - String to be checked. * @returns {Boolean} */ function hasPlugin(str) { return !!~str.indexOf('!'); } /** * Checks if provided string is a full path to the file. * * @param {String} str - String to be checked. * @returns {Boolean} */ function isFullPath(str) { return !!~str.indexOf('://'); } /** * Removes license comment from the provided string. * * @param {String} content - String to be processed. * @returns {String} */ function removeLicense(content) { return content.replace(licenseRegExp, function (match) { return ~match.indexOf('/**') ? '' : match; }); } return { /** * Attempts to extract template by provided path from * a DOM element and falls back to a file loading if * none of the DOM nodes was found. * * @param {String} path - Path to the template or a DOM selector. * @returns {jQueryPromise} */ loadTemplate: function (path) { var content = this.loadFromNode(path), defer; if (content) { defer = $.Deferred(); defer.resolve(content); return defer.promise(); } return this.loadFromFile(path); }, /** * Loads template from external file by provided * path, which will be preliminary formatted. * * @param {String} path - Path to the template. * @returns {jQueryPromise} */ loadFromFile: function (path) { var loading = $.Deferred(); path = this.formatPath(path); require([path], function (template) { template = removeLicense(template); loading.resolve(template); }, function (err) { loading.reject(err); }); return loading.promise(); }, /** * Attempts to extract content of a node found by provided selector. * * @param {String} selector - Node's selector (not necessary valid). * @returns {String|Boolean} If specified node doesn't exists * 'false' will be returned, otherwise returns node's content. */ loadFromNode: function (selector) { var node; try { node = document.getElementById(selector) || document.querySelector(selector); return node ? node.innerHTML : false; } catch (e) { return false; } }, /** * Adds requirejs's plugin and file extension to * to the provided string if it's necessary. * * @param {String} path - Path to be processed. * @returns {String} Formatted path. */ formatPath: function (path) { var result = path; if (!hasPlugin(path)) { result = defaultPlugin + '!' + result; } if (isFullPath(path)) { return result; } if (!hasFileExtension(path)) { result += '.' + defaultExt; } return result.replace(/^([^\/]+)/g, '$1/template'); } }; }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('Magento_Ui/js/lib/knockout/template/renderer',[ 'jquery', 'underscore', './loader' ], function ($, _, loader) { 'use strict'; var colonReg = /\\:/g, renderedTemplatePromises = {}, attributes = {}, elements = {}, globals = [], renderer, preset; renderer = { /** * Loads template by provided path and * than converts it's content to html. * * @param {String} tmplPath - Path to the template. * @returns {jQueryPromise} * @alias getRendered */ render: function (tmplPath) { var cachedPromise = renderedTemplatePromises[tmplPath]; if (!cachedPromise) { cachedPromise = renderedTemplatePromises[tmplPath] = loader .loadTemplate(tmplPath) .then(renderer.parseTemplate); } return cachedPromise; }, /** * @ignore */ getRendered: function (tmplPath) { return renderer.render(tmplPath); }, /** * Parses provided string as html content * and returns an array of DOM elements. * * @param {String} html - String to be processed. * @returns {Array} */ parseTemplate: function (html) { var fragment = document.createDocumentFragment(); $(fragment).append(html); return renderer.normalize(fragment); }, /** * Processes custom attributes and nodes of provided DOM element. * * @param {HTMLElement} content - Element to be processed. * @returns {Array} An array of content's child nodes. */ normalize: function (content) { globals.forEach(function (handler) { handler(content); }); return _.toArray(content.childNodes); }, /** * Adds new global content handler. * * @param {Function} handler - Function which will be invoked for * an every content passed to 'normalize' method. * @returns {Renderer} Chainable. */ addGlobal: function (handler) { if (!_.contains(globals, handler)) { globals.push(handler); } return this; }, /** * Removes specified global content handler. * * @param {Function} handler - Handler to be removed. * @returns {Renderer} Chainable. */ removeGlobal: function (handler) { var index = globals.indexOf(handler); if (~index) { globals.splice(index, 1); } return this; }, /** * Adds new custom attribute handler. * * @param {String} id - Attribute identifier. * @param {(Object|Function)} [config={}] * @returns {Renderer} Chainable. */ addAttribute: function (id, config) { var data = { name: id, binding: id, handler: renderer.handlers.attribute }; if (_.isFunction(config)) { data.handler = config; } else if (_.isObject(config)) { _.extend(data, config); } data.id = id; attributes[id] = data; return this; }, /** * Removes specified attribute handler. * * @param {String} id - Attribute identifier. * @returns {Renderer} Chainable. */ removeAttribute: function (id) { delete attributes[id]; return this; }, /** * Adds new custom node handler. * * @param {String} id - Node identifier. * @param {(Object|Function)} [config={}] * @returns {Renderer} Chainable. */ addNode: function (id, config) { var data = { name: id, binding: id, handler: renderer.handlers.node }; if (_.isFunction(config)) { data.handler = config; } else if (_.isObject(config)) { _.extend(data, config); } data.id = id; elements[id] = data; return this; }, /** * Removes specified custom node handler. * * @param {String} id - Node identifier. * @returns {Renderer} Chainable. */ removeNode: function (id) { delete elements[id]; return this; }, /** * Checks if provided DOM element is a custom node. * * @param {HTMLElement} node - Node to be checked. * @returns {Boolean} */ isCustomNode: function (node) { return _.some(elements, function (elem) { return elem.name.toUpperCase() === node.tagName; }); }, /** * Processes custom attributes of a content's child nodes. * * @param {HTMLElement} content - DOM element to be processed. */ processAttributes: function (content) { var repeat; repeat = _.some(attributes, function (attr) { var attrName = attr.name, nodes = content.querySelectorAll('[' + attrName + ']'), handler = attr.handler; return _.toArray(nodes).some(function (node) { var data = node.getAttribute(attrName); return handler(node, data, attr) === true; }); }); if (repeat) { renderer.processAttributes(content); } }, /** * Processes custom nodes of a provided content. * * @param {HTMLElement} content - DOM element to be processed. */ processNodes: function (content) { var repeat; repeat = _.some(elements, function (element) { var nodes = content.querySelectorAll(element.name), handler = element.handler; return _.toArray(nodes).some(function (node) { var data = node.getAttribute('args'); return handler(node, data, element) === true; }); }); if (repeat) { renderer.processNodes(content); } }, /** * Wraps provided string in curly braces if it's necessary. * * @param {String} args - String to be wrapped. * @returns {String} Wrapped string. */ wrapArgs: function (args) { if (~args.indexOf('\\:')) { args = args.replace(colonReg, ':'); } else if (~args.indexOf(':') && !~args.indexOf('}')) { args = '{' + args + '}'; } return args; }, /** * Wraps child nodes of provided DOM element * with knockout's comment tag. * * @param {HTMLElement} node - Node whose children should be wrapped. * @param {String} binding - Name of the binding for the opener comment tag. * @param {String} data - Data associated with a binding. * * @example * <div id="example"><span/></div> * wrapChildren(document.getElementById('example'), 'foreach', 'data'); * => * <div id="example"> * <!-- ko foreach: data --> * <span></span> * <!-- /ko --> * </div> */ wrapChildren: function (node, binding, data) { var tag = this.createComment(binding, data), $node = $(node); $node.prepend(tag.open); $node.append(tag.close); }, /** * Wraps specified node with knockout's comment tag. * * @param {HTMLElement} node - Node to be wrapped. * @param {String} binding - Name of the binding for the opener comment tag. * @param {String} data - Data associated with a binding. * * @example * <div id="example"></div> * wrapNode(document.getElementById('example'), 'foreach', 'data'); * => * <!-- ko foreach: data --> * <div id="example"></div> * <!-- /ko --> */ wrapNode: function (node, binding, data) { var tag = this.createComment(binding, data), $node = $(node); $node.before(tag.open); $node.after(tag.close); }, /** * Creates knockouts' comment tag for the provided binding. * * @param {String} binding - Name of the binding. * @param {String} data - Data associated with a binding. * @returns {Object} Object with an open and close comment elements. */ createComment: function (binding, data) { return { open: document.createComment(' ko ' + binding + ': ' + data + ' '), close: document.createComment(' /ko ') }; } }; renderer.handlers = { /** * Basic node handler. Replaces custom nodes * with a corresponding knockout's comment tag. * * @param {HTMLElement} node - Node to be processed. * @param {String} data * @param {Object} element * @returns {Boolean} True * * @example Sample syntaxes conversions. * <with args="model"> * <span/> * </with> * => * <!-- ko with: model--> * <span/> * <!-- /ko --> */ node: function (node, data, element) { data = renderer.wrapArgs(data); renderer.wrapNode(node, element.binding, data); $(node).replaceWith(node.childNodes); return true; }, /** * Base attribute handler. Replaces custom attributes with * a corresponding knockouts' data binding. * * @param {HTMLElement} node - Node to be processed. * @param {String} data - Data associated with a binding. * @param {Object} attr - Attribute definition. * * @example Sample syntaxes conversions. * <div text="label"></div> * => * <div data-bind="text: label"></div> */ attribute: function (node, data, attr) { data = renderer.wrapArgs(data); renderer.bindings.add(node, attr.binding, data); node.removeAttribute(attr.name); }, /** * Wraps provided node with a knockouts' comment tag. * * @param {HTMLElement} node - Node that will be wrapped. * @param {String} data - Data associated with a binding. * @param {Object} attr - Attribute definition. * * @example * <div outereach="data" class="test"></div> * => * <!-- ko foreach: data --> * <div class="test"></div> * <!-- /ko --> */ wrapAttribute: function (node, data, attr) { data = renderer.wrapArgs(data); renderer.wrapNode(node, attr.binding, data); node.removeAttribute(attr.name); } }; renderer.bindings = { /** * Appends binding string to the current * 'data-bind' attribute of provided node. * * @param {HTMLElement} node - DOM element whose 'data-bind' attribute will be extended. * @param {String} name - Name of a binding. * @param {String} data - Data associated with the binding. */ add: function (node, name, data) { var bindings = this.get(node); if (bindings) { bindings += ', '; } bindings += name; if (data) { bindings += ': ' + data; } this.set(node, bindings); }, /** * Extracts value of a 'data-bind' attribute from provided node. * * @param {HTMLElement} node - Node whose attribute to be extracted. * @returns {String} */ get: function (node) { return node.getAttribute('data-bind') || ''; }, /** * Sets 'data-bind' attribute of the specified node * to the provided value. * * @param {HTMLElement} node - Node whose attribute will be altered. * @param {String} bindings - New value of 'data-bind' attribute. */ set: function (node, bindings) { node.setAttribute('data-bind', bindings); } }; renderer .addGlobal(renderer.processAttributes) .addGlobal(renderer.processNodes); /** * Collection of default binding conversions. */ preset = { nodes: _.object([ 'if', 'text', 'with', 'scope', 'ifnot', 'foreach', 'component' ], Array.prototype), attributes: _.object([ 'css', 'attr', 'html', 'with', 'text', 'click', 'event', 'submit', 'enable', 'disable', 'options', 'visible', 'template', 'hasFocus', 'textInput', 'component', 'uniqueName', 'optionsText', 'optionsValue', 'checkedValue', 'selectedOptions' ], Array.prototype) }; _.extend(preset.attributes, { if: renderer.handlers.wrapAttribute, ifnot: renderer.handlers.wrapAttribute, innerif: { binding: 'if' }, innerifnot: { binding: 'ifnot' }, outereach: { binding: 'foreach', handler: renderer.handlers.wrapAttribute }, foreach: { name: 'each' }, value: { name: 'ko-value' }, style: { name: 'ko-style' }, checked: { name: 'ko-checked' }, disabled: { name: 'ko-disabled', binding: 'disable' }, focused: { name: 'ko-focused', binding: 'hasFocus' }, /** * Custom 'render' attribute handler function. Wraps child elements * of a node with knockout's 'ko template:' comment tag. * * @param {HTMLElement} node - Element to be processed. * @param {String} data - Data specified in 'render' attribute of a node. */ render: function (node, data) { data = data || 'getTemplate()'; data = renderer.wrapArgs(data); renderer.wrapChildren(node, 'template', data); node.removeAttribute('render'); } }); _.extend(preset.nodes, { foreach: { name: 'each' }, /** * Custom 'render' node handler function. * Replaces node with knockout's 'ko template:' comment tag. * * @param {HTMLElement} node - Element to be processed. * @param {String} data - Data specified in 'args' attribute of a node. */ render: function (node, data) { data = data || 'getTemplate()'; data = renderer.wrapArgs(data); renderer.wrapNode(node, 'template', data); $(node).replaceWith(node.childNodes); } }); _.each(preset.attributes, function (data, id) { renderer.addAttribute(id, data); }); _.each(preset.nodes, function (data, id) { renderer.addNode(id, data); }); return renderer; }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('Magento_Ui/js/lib/logger/levels-pool',[ 'underscore' ], function (_) { 'use strict'; var LEVELS, CODE_MAP; LEVELS = { NONE: 0, ERROR: 1, WARN: 2, INFO: 3, DEBUG: 4, ALL: 5 }; CODE_MAP = _.invert(LEVELS); return { /** * Returns the list of available log levels. * * @returns {Object} */ getLevels: function () { return LEVELS; }, /** * Returns name of the log level that matches to the provided code. * * @returns {String} */ getNameByCode: function (code) { return CODE_MAP[code]; } }; }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('Magento_Ui/js/lib/logger/logger',[ './levels-pool' ], function (logLevels) { 'use strict'; var levels = logLevels.getLevels(); /** * @param {LogOutputHandler} outputHandler * @param {LogEntryFactory} entryFactory */ function Logger(outputHandler, entryFactory) { /** * An array of log entries. * * @protected * @type {Array<LogEntry>} */ this.entries_ = []; /** * Current display level. * * @protected * @type {Number} */ this.displayLevel_ = levels.ERROR; /** * An array of display criteria. * * @protected * @type {Array<LogCriteria>} */ this.displayCriteria_ = []; /** * @protected * @type {LogEntryFactory} */ this.entryFactory_ = entryFactory; /** * @protected * @type {Array<LogOutputHandler>} */ this.outputHandlers_ = [outputHandler]; this.addDisplayCriteria(this.matchesLevel_); } /** * Swaps current display level with the provided one. * * @param {Number} level - Level's code. */ Logger.prototype.setDisplayLevel = function (level) { var levelName = logLevels.getNameByCode(level); if (!levelName) { throw new TypeError('The provided level is not defined in the levels list.'); } this.displayLevel_ = level; }; /** * Sets up the criteria by which log entries will be filtered out from the output. * * @param {LogCriteria} criteria */ Logger.prototype.addDisplayCriteria = function (criteria) { this.displayCriteria_.push(criteria); }; /** * Removes previously defined criteria. * * @param {LogCriteria} criteria */ Logger.prototype.removeDisplayCriteria = function (criteria) { var index = this.displayCriteria_.indexOf(criteria); if (~index) { this.displayCriteria_.splice(index, 1); } }; /** * @param {String} message * @param {Object} [messageData] * @returns {LogEntry} */ Logger.prototype.error = function (message, messageData) { return this.log_(message, levels.ERROR, messageData); }; /** * @param {String} message * @param {Object} [messageData] * @returns {LogEntry} */ Logger.prototype.warn = function (message, messageData) { return this.log_(message, levels.WARN, messageData); }; /** * @param {String} message * @param {Object} [messageData] * @returns {LogEntry} */ Logger.prototype.info = function (message, messageData) { return this.log_(message, levels.INFO, messageData); }; /** * @param {String} message * @param {Object} [messageData] * @returns {LogEntry} */ Logger.prototype.debug = function (message, messageData) { return this.log_(message, levels.DEBUG, messageData); }; /** * @protected * @param {String} message * @param {Number} level * @param {Object} [messageData] * @returns {LogEntry} */ Logger.prototype.log_ = function (message, level, messageData) { var entry = this.createEntry_(message, level, messageData); this.entries_.push(entry); if (this.matchesCriteria_(entry)) { this.processOutput_(entry); } return entry; }; /** * @protected * @param {String} message * @param {Number} level * @param {Object} [messageData] * @returns {LogEntry} */ Logger.prototype.createEntry_ = function (message, level, messageData) { return this.entryFactory_.createEntry(message, level, messageData); }; /** * Returns an array of log entries that have been added to the logger. * * @param {LogCriteria} [criteria] - Optional filter criteria. * @returns {Array<LogEntry>} */ Logger.prototype.getEntries = function (criteria) { if (criteria) { return this.entries_.filter(criteria); } return this.entries_; }; /** * @param {LogCriteria} [criteria] */ Logger.prototype.dump = function (criteria) { var entries; if (!criteria) { criteria = this.matchesCriteria_; } entries = this.entries_.filter(criteria, this); this.outputHandlers_.forEach(function (handler) { handler.dump(entries); }); }; /** * @protected * @param {LogEntry} entry */ Logger.prototype.processOutput_ = function (entry) { this.outputHandlers_.forEach(function (handler) { handler.show(entry); }); }; /** * @protected * @param {LogEntry} entry * @returns {Boolean} */ Logger.prototype.matchesCriteria_ = function (entry) { return this.displayCriteria_.every(function (criteria) { return criteria.call(this, entry); }, this); }; /** * Checks that the level of provided entry passes the "displayLevel_" threshold. * * @protected * @param {LogEntry} entry - Entry to be checked. * @returns {Boolean} */ Logger.prototype.matchesLevel_ = function (entry) { return entry.level <= this.displayLevel_; }; return Logger; }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('Magento_Ui/js/lib/logger/entry',[ './levels-pool' ], function (logLevels) { 'use strict'; /** * @param {String} message * @param {Number} level * @param {Object} [data] */ function LogEntry(message, level, data) { /** * @readonly * @type {Number} */ this.timestamp = Date.now(); /** * @readonly * @type {Number} */ this.level = level; /** * @readonly * @type {String} */ this.levelName = logLevels.getNameByCode(level); /** * @readonly * @type {Object} */ this.data = data; /** * @readonly * @type {String} */ this.message = message; } return LogEntry; }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('Magento_Ui/js/lib/logger/entry-factory',[ './entry' ], function (LogEntry) { 'use strict'; return { /** * @param {String} message * @param {Number} level * @param {Object} [messageData] * @returns {LogEntry} */ createEntry: function (message, level, messageData) { return new LogEntry(message, level, messageData); } }; }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('Magento_Ui/js/lib/logger/console-output-handler',[ './levels-pool' ], function (logLevels) { 'use strict'; var levels = logLevels.getLevels(); /** * @param {LogFormatter} formatter */ function ConsoleOutputHandler(formatter) { /** * @protected * @type {LogFormatter} */ this.formatter_ = formatter; } /** * Display data of the provided entry to the console. * * @param {LogEntry} entry - Entry to be displayed. */ ConsoleOutputHandler.prototype.show = function (entry) { var displayString = this.formatter_.process(entry); switch (entry.level) { case levels.ERROR: console.error(displayString); break; case levels.WARN: console.warn(displayString); break; case levels.INFO: console.info(displayString); break; case levels.DEBUG: console.log(displayString); break; } }; /** * Displays the array of entries. * * @param {Array<LogEntry>} entries */ ConsoleOutputHandler.prototype.dump = function (entries) { entries.forEach(this.show, this); }; return ConsoleOutputHandler; }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('Magento_Ui/js/lib/logger/formatter',[ 'moment', 'mage/utils/template' ], function (moment, mageTemplate) { 'use strict'; /** * @param {String} dateFormat * @param {String} template */ function LogFormatter(dateFormat, template) { /** * @protected * @type {String} */ this.dateFormat_ = 'YYYY-MM-DD hh:mm:ss'; /** * @protected * @type {String} */ this.template_ = '[${ $.date }] [${ $.entry.levelName }] ${ $.message }'; if (dateFormat) { this.dateFormat_ = dateFormat; } if (template) { this.template_ = template; } } /** * @param {LogEntry} entry * @returns {String} */ LogFormatter.prototype.process = function (entry) { var message = mageTemplate.template(entry.message, entry.data), date = moment(entry.timestamp).format(this.dateFormat_); return mageTemplate.template(this.template_, { date: date, entry: entry, message: message }); }; return LogFormatter; }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('Magento_Ui/js/lib/logger/message-pool',[],function () { 'use strict'; var MESSAGES = { templateStartLoading: 'The "${ $.template }" template requested by the "${$.component}" component started loading.', templateLoadedFromServer: 'The "${ $.template }" template requested by the "${$.component}" component was loaded from server."', templateLoadedFromCache: 'The "${ $.template }" template requested by the "${$.component}" component was loaded from cache."', templateLoadingFail: 'Failed to load the "${ $.template }" template requested by "${$.component}".', componentStartInitialization: 'Component "${$.component}" start initialization with instance name "${$.componentName}".', componentStartLoading: ' Started loading the "${$.component}" component.', componentFinishLoading: 'The "${$.component}" component was loaded.', componentLoadingFail: 'Failed to load the "${$.component}" component.', depsLoadingFail: 'Could not get the declared "${$.deps}" dependency for the "${$.component}" instance.', depsStartRequesting: 'Requesting the "${$.deps}" dependency for the "${$.component}" instance.', depsFinishRequesting: 'The "${$.deps}" dependency for the "${$.component}" instance was received.', requestingComponent: 'Requesting the "${$.component}" component.', requestingComponentIsLoaded: 'The requested "${$.component}" component was received.', requestingComponentIsFailed: 'Could not get the requested "${$.component}" component.' }; return { /** * Returns message that matches the provided code. * * @param {String} code - Message's identifier * @returns {String} */ getMessage: function (code) { return MESSAGES[code]; }, /** * Adds a new message to the poll. * * @param {String} code - Message's identifier. * @param {String} message - Text of the message */ addMessage: function (code, message) { MESSAGES[code] = message; }, /** * Tells whether message with provide code exists in the poll. * * @param {String} code - Message's identifier. * @returns {Boolean} */ hasMessage: function (code) { return MESSAGES.hasOwnProperty(code); } }; }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('Magento_Ui/js/lib/logger/logger-utils',[], function () { 'use strict'; /** * Utils methods for logger * @param {Logger} logger */ function LogUtils(logger) { this.logger = logger; } /** * Method for logging asynchronous operations * @param {Promise} promise * @param {Object} config */ LogUtils.prototype.asyncLog = function (promise, config) { var levels, messages, wait; config = config || {}; levels = config.levels || this.createLevels(); messages = config.messages || this.createMessages(); wait = config.wait || 5000; this.logger[levels.requested](messages.requested, config.data); setTimeout(function () { promise.state() === 'pending' ? this.logger[levels.failed](messages.failed, config.data) : this.logger[levels.loaded](messages.loaded, config.data); }.bind(this), wait); }; /** * Method that creates object of messages * @param {String} requested - log message that showing that request for class is started * @param {String} loaded - log message that show when requested class is loaded * @param {String} failed - log message that show when requested class is failed * @returns {Object} */ LogUtils.prototype.createMessages = function (requested, loaded, failed) { return { requested: requested || '', loaded: loaded || '', failed: failed || '' }; }; /** * Method that creates object of log levels * @param {String} requested - log message that showing that request for class is started * @param {String} loaded - log message that show when requested class is loaded * @param {String} failed - log message that show when requested class is failed * @returns {Object} */ LogUtils.prototype.createLevels = function (requested, loaded, failed) { return { requested: requested || 'info', loaded: loaded || 'info', failed: failed || 'warn' }; }; return LogUtils; }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('Magento_Ui/js/lib/logger/console-logger',[ './logger', './entry-factory', './console-output-handler', './formatter', './message-pool', './levels-pool', 'Magento_Ui/js/lib/core/storage/local', 'underscore', './logger-utils' ], function (Logger, entryFactory, ConsoleHandler, Formatter, messagePoll, levelsPoll, storage, _, LoggerUtils) { 'use strict'; var STORAGE_NAMESPACE = 'CONSOLE_LOGGER'; /** * Singleton Logger's sub-class instance of which is configured to display its * messages to the console. It also provides the support of predefined messages * and persists its display level. */ function ConsoleLogger() { var formatter = new Formatter(), consoleHandler = new ConsoleHandler(formatter), savedLevel = storage.get(STORAGE_NAMESPACE), utils = new LoggerUtils(this); Logger.call(this, consoleHandler, entryFactory); if (savedLevel) { this.displayLevel_ = savedLevel; } this.utils = utils; this.messages = messagePoll; this.levels = levelsPoll.getLevels(); } _.extend(ConsoleLogger, Logger); ConsoleLogger.prototype = Object.create(Logger.prototype); ConsoleLogger.prototype.constructor = ConsoleLogger; /** * Overrides parent method to save the provided display level. * * @override */ ConsoleLogger.prototype.setDisplayLevel = function (level) { Logger.prototype.setDisplayLevel.call(this, level); storage.set(STORAGE_NAMESPACE, level); }; /** * Adds the support of predefined messages. * * @protected * @override */ ConsoleLogger.prototype.createEntry_ = function (message, level, data) { var code; if (messagePoll.hasMessage(message)) { data = data || {}; code = message; message = messagePoll.getMessage(code); data.messageCode = code; } return Logger.prototype.createEntry_.call(this, message, level, data); }; return new ConsoleLogger(); }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('Magento_Ui/js/lib/knockout/template/engine',[ 'jquery', 'ko', 'underscore', './observable_source', './renderer', '../../logger/console-logger' ], function ($, ko, _, Source, renderer, consoleLogger) { 'use strict'; var RemoteTemplateEngine, NativeTemplateEngine = ko.nativeTemplateEngine, sources = {}; /** * Remote template engine class. Is used to be able to load remote templates via knockout template binding. */ RemoteTemplateEngine = function () { // Instance reference for closure. var engine = this, // Decorate the builtin Knockout "template" binding to track synchronous template renders. origUpdate = ko.bindingHandlers.template.update; /** * Counter to track the number of currently running render tasks (both synchronous and asynchronous). * @type {Number} * @private */ this._rendersOutstanding = 0; /** * Use a jQuery object as an event bus (but any event emitter with on/off/emit methods could work) * @type {jQuery} * @private */ this._events = $(this); /** * Rendered templates * @type {Object} * @private */ this._templatesRendered = {}; /*eslint-disable no-unused-vars*/ /** * Decorate update method * * @param {HTMLElement} element * @param {Function} valueAccessor * @param {Object} allBindings * @param {Object} viewModel * @param {ko.bindingContext} bindingContext * @returns {*} */ ko.bindingHandlers.template.update = function (element, valueAccessor, allBindings, viewModel, bindingContext) { /*eslint-enable no-unused-vars*/ var options = ko.utils.peekObservable(valueAccessor()), templateName, isSync, updated; if (typeof options === 'object') { if (options.templateEngine && options.templateEngine !== engine) { return origUpdate.apply(this, arguments); } if (!options.name) { consoleLogger.error('Could not find template name', options); } templateName = options.name; } else if (typeof options === 'string') { templateName = options; } else { consoleLogger.error('Could not build a template binding', options); } engine._trackRender(templateName); isSync = engine._hasTemplateLoaded(templateName); updated = origUpdate.apply(this, arguments); if (isSync) { engine._releaseRender(templateName, 'sync'); } return updated; }; }; /** * Creates unique template identifier based on template name and it's extenders (optional) * @param {String} templateName * @return {String} - unique template identifier */ function createTemplateIdentifier(templateName) { return templateName; } RemoteTemplateEngine.prototype = new NativeTemplateEngine; RemoteTemplateEngine.prototype.constructor = RemoteTemplateEngine; /** * When an asynchronous render task begins, increment the internal counter for tracking when renders are complete. * @private */ RemoteTemplateEngine.prototype._trackRender = function (templateName) { var rendersForTemplate = this._templatesRendered[templateName] !== undefined ? this._templatesRendered[templateName] : 0; this._rendersOutstanding++; this._templatesRendered[templateName] = rendersForTemplate + 1; this._resolveRenderWaits(); }; /** * When an asynchronous render task ends, decrement the internal counter for tracking when renders are complete. * @private */ RemoteTemplateEngine.prototype._releaseRender = function (templateName) { var rendersForTemplate = this._templatesRendered[templateName]; this._rendersOutstanding--; this._templatesRendered[templateName] = rendersForTemplate - 1; this._resolveRenderWaits(); }; /** * Check to see if renders are complete and trigger events for listeners. * @private */ RemoteTemplateEngine.prototype._resolveRenderWaits = function () { if (this._rendersOutstanding === 0) { this._events.triggerHandler('finishrender'); } }; /** * Get a promise for the end of the current run of renders, both sync and async. * @return {jQueryPromise} - promise that resolves when render completes */ RemoteTemplateEngine.prototype.waitForFinishRender = function () { var defer = $.Deferred(); this._events.one('finishrender', defer.resolve); return defer.promise(); }; /** * Returns true if this template has already been asynchronously loaded and will be synchronously rendered. * @param {String} templateName * @returns {Boolean} * @private */ RemoteTemplateEngine.prototype._hasTemplateLoaded = function (templateName) { // Sources object will have cached template once makeTemplateSource has run return sources.hasOwnProperty(templateName); }; /** * Overrided method of native knockout template engine. * Caches template after it's unique name and renders in once. * If template name is not typeof string, delegates work to knockout.templateSources.anonymousTemplate. * @param {*} template * @param {HTMLElement} templateDocument - document * @param {Object} options - options, passed to template binding * @param {ko.bindingContext} bindingContext * @returns {TemplateSource} Object with methods 'nodes' and 'data'. */ RemoteTemplateEngine.prototype.makeTemplateSource = function (template, templateDocument, options, bindingContext) { var engine = this, source, templateId; if (typeof template === 'string') { templateId = createTemplateIdentifier(template); source = sources[templateId]; if (!source) { source = new Source(template); source.requestedBy = bindingContext.$data.name; sources[templateId] = source; consoleLogger.info('templateStartLoading', { template: templateId, component: bindingContext.$data.name }); renderer.render(template).then(function (rendered) { consoleLogger.info('templateLoadedFromServer', { template: templateId, component: bindingContext.$data.name }); source.nodes(rendered); engine._releaseRender(templateId, 'async'); }).fail(function () { consoleLogger.error('templateLoadingFail', { template: templateId, component: bindingContext.$data.name }); }); } if (source.requestedBy !== bindingContext.$data.name) { consoleLogger.info('templateLoadedFromCache', { template: templateId, component: bindingContext.$data.name }); } return source; } else if (template.nodeType === 1 || template.nodeType === 8) { source = new ko.templateSources.anonymousTemplate(template); return source; } throw new Error('Unknown template type: ' + template); }; /** * Overrided method of native knockout template engine. * Should return array of html elements. * @param {TemplateSource} templateSource - object with methods 'nodes' and 'data'. * @return {Array} - array of html elements */ RemoteTemplateEngine.prototype.renderTemplateSource = function (templateSource) { var nodes = templateSource.nodes(); return ko.utils.cloneNodes(nodes); }; /** * Overrided method of native knockout template engine. * Created in order to invoke makeTemplateSource method with custom set of params. * @param {*} template - template identifier * @param {ko.bindingContext} bindingContext * @param {Object} options - options, passed to template binding * @param {HTMLElement} templateDocument - document * @return {Array} - array of html elements */ RemoteTemplateEngine.prototype.renderTemplate = function (template, bindingContext, options, templateDocument) { var templateSource = this.makeTemplateSource(template, templateDocument, options, bindingContext); return this.renderTemplateSource(templateSource); }; return new RemoteTemplateEngine; }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('Magento_Ui/js/lib/knockout/extender/bound-nodes',[ 'ko', 'underscore', 'mage/utils/wrapper', 'uiEvents' ], function (ko, _, wrapper, Events) { 'use strict'; var nodesMap = new WeakMap(); /** * Returns a array of nodes associated with a specified model. * * @param {Object} model * @returns {Undefined|Array} */ function getBounded(model) { return nodesMap.get(model); } /** * Removes specified node to models' associations list, if it's * a root node (node is not a descendant of any previously added nodes). * Triggers 'addNode' event. * * @param {Object} model * @param {HTMLElement} node */ function addBounded(model, node) { var nodes = getBounded(model), isRoot; if (!nodes) { nodesMap.set(model, [node]); Events.trigger.call(model, 'addNode', node); return; } isRoot = nodes.every(function (bounded) { return !bounded.contains(node); }); if (isRoot) { nodes.push(node); Events.trigger.call(model, 'addNode', node); } } /** * Removes specified node from models' associations list. * Triggers 'removeNode' event. * * @param {Object} model * @param {HTMLElement} node */ function removeBounded(model, node) { var nodes = getBounded(model), index; if (!nodes) { return; } index = nodes.indexOf(node); if (~index) { nodes.splice(index, 0); Events.trigger.call(model, 'removeNode', node); } if (!nodes.length) { nodesMap.delete(model); } } /** * Returns node's first sibling of 'element' type within the common component scope * * @param {HTMLElement} node * @param {*} data * @returns {HTMLElement} */ function getElement(node, data) { var elem; while (node.nextElementSibling) { node = node.nextElementSibling; if (node.nodeType === 1 && ko.dataFor(node) === data) { elem = node; break; } } return elem; } wrapper.extend(ko, { /** * Extends knockouts' 'applyBindings' * to track nodes associated with model. * * @param {Function} orig - Original 'applyBindings' method. * @param {Object} ctx * @param {HTMLElement} node - Original 'applyBindings' method. */ applyBindings: function (orig, ctx, node) { var result = orig(), data = ctx && (ctx.$data || ctx); if (node && node.nodeType === 8) { node = getElement(node, data); } if (!node || node.nodeType !== 1) { return result; } if (data && data.registerNodes) { addBounded(data, node); } return result; }, /** * Extends knockouts' cleanNode * to track nodes associated with model. * * @param {Function} orig - Original 'cleanNode' method. * @param {HTMLElement} node - Original 'cleanNode' method. */ cleanNode: function (orig, node) { var result = orig(), data; if (node.nodeType !== 1) { return result; } data = ko.dataFor(node); if (data && data.registerNodes) { removeBounded(data, node); } return result; } }); return { /** * Returns root nodes associated with a model. If callback is provided, * will iterate through all of the present nodes triggering callback * for each of it. Also it will subscribe to the 'addNode' event. * * @param {Object} model * @param {Function} [callback] * @returns {Array|Undefined} */ get: function (model, callback) { var nodes = getBounded(model) || []; if (!_.isFunction(callback)) { return nodes; } nodes.forEach(function (node) { callback(node); }); this.add.apply(this, arguments); }, /** * Subscribes to adding of nodes associated with a model. * * @param {Object} model */ add: function (model) { var args = _.toArray(arguments).slice(1); args.unshift('addNode'); Events.on.apply(model, args); }, /** * Subscribes to removal of nodes associated with a model. * * @param {Object} model */ remove: function (model) { var args = _.toArray(arguments).slice(1); args.unshift('removeNode'); Events.on.apply(model, args); }, /** * Removes subscriptions from the model. * * @param {Object} model */ off: function (model) { var args = _.toArray(arguments).slice(1); Events.off.apply(model, args); } }; }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('Magento_Ui/js/lib/view/utils/bindings',[ 'ko', 'jquery', 'underscore' ], function (ko, $, _) { 'use strict'; /** * Checks if provided value is a dom element. * * @param {*} node - Value to be checked. * @returns {Boolean} */ function isDomElement(node) { return typeof node === 'object' && node.tagName && node.nodeType; } /** * Removes from the provided array all non-root nodes located inside * of the comment element as long as the closing comment tags. * * @param {(Array|ArrayLike)} nodes - An array of nodes to be processed. * @returns {Array} */ function normalize(nodes) { var result; nodes = _.toArray(nodes); result = nodes.slice(); nodes.forEach(function (node) { if (node.nodeType === 8) { result = !ko.virtualElements.hasBindingValue(node) ? _.without(result, node) : _.difference(result, ko.virtualElements.childNodes(node)); } }); return result; } /** * Extends binding context of each item in the collection. * * @param {...Object} extenders - Multiple extender objects to be applied to the context. * @returns {jQueryCollection} Chainable. */ $.fn.extendCtx = function () { var nodes = normalize(this), extenders = _.toArray(arguments); nodes.forEach(function (node) { var ctx = ko.contextFor(node), data = [ctx].concat(extenders); _.extend.apply(_, data); }); return this; }; /** * Evaluates bindings specified in each DOM element of collection. * * @param {(HTMLElement|Object)} [ctx] - Context to use for bindings evaluation. * If not specified then current context of a collections' item will be used. * @returns {jQueryCollection} Chainable. */ $.fn.applyBindings = function (ctx) { var nodes = normalize(this), nodeCtx; if (isDomElement(ctx)) { ctx = ko.contextFor(ctx); } nodes.forEach(function (node) { nodeCtx = ctx || ko.contextFor(node); ko.applyBindings(nodeCtx, node); }); return this; }; /** * Adds specified bindings to each DOM element in * collection and evaluates them with provided context. * * @param {(Object|Function)} data - Either bindings object or a function * which returns bindings data for each element in collection. * @param {(HTMLElement|Object)} [ctx] - Context to use for bindings evaluation. * If not specified then current context of a collections' item will be used. * @returns {jQueryCollection} Chainable. */ $.fn.bindings = function (data, ctx) { var nodes = normalize(this), bindings = data, nodeCtx; if (isDomElement(ctx)) { ctx = ko.contextFor(ctx); } nodes.forEach(function (node) { nodeCtx = ctx || ko.contextFor(node); if (_.isFunction(data)) { bindings = data(nodeCtx, node); } ko.applyBindingsToNode(node, bindings, nodeCtx); }); return this; }; }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('Magento_Ui/js/lib/knockout/bindings/i18n',[ 'jquery', 'ko', 'module', '../template/renderer', 'mage/translate' ], function ($, ko, module, renderer) { 'use strict'; var locations = { 'legend': 'Caption for the fieldset element', 'label': 'Label for an input element.', 'button': 'Push button', 'a': 'Link label', 'b': 'Bold text', 'strong': 'Strong emphasized text', 'i': 'Italic text', 'em': 'Emphasized text', 'u': 'Underlined text', 'sup': 'Superscript text', 'sub': 'Subscript text', 'span': 'Span element', 'small': 'Smaller text', 'big': 'Bigger text', 'address': 'Contact information', 'blockquote': 'Long quotation', 'q': 'Short quotation', 'cite': 'Citation', 'caption': 'Table caption', 'abbr': 'Abbreviated phrase', 'acronym': 'An acronym', 'var': 'Variable part of a text', 'dfn': 'Term', 'strike': 'Strikethrough text', 'del': 'Deleted text', 'ins': 'Inserted text', 'h1': 'Heading level 1', 'h2': 'Heading level 2', 'h3': 'Heading level 3', 'h4': 'Heading level 4', 'h5': 'Heading level 5', 'h6': 'Heading level 6', 'center': 'Centered text', 'select': 'List options', 'img': 'Image', 'input': 'Form element' }, /** * Generates [data-translate] attribute's value * @param {Object} translationData * @param {String} location */ composeTranslateAttr = function (translationData, location) { var obj = [{ 'shown': translationData.shown, 'translated': translationData.translated, 'original': translationData.original, 'location': locations[location] || 'Text' }]; return JSON.stringify(obj); }, /** * Sets text for the element * @param {Object} el * @param {String} text */ setText = function (el, text) { $(el).text(text); }, /** * Sets [data-translate] attribute for the element * @param {Object} el - The element which is binded * @param {String} original - The original value of the element */ setTranslateProp = function (el, original) { var location = $(el).prop('tagName').toLowerCase(), translated = $.mage.__(original), translationData = { shown: translated, translated: translated, original: original }, translateAttr = composeTranslateAttr(translationData, location); $(el).attr('data-translate', translateAttr); setText(el, translationData.shown); }, /** * Checks if node represents ko virtual node (nodeType === 8, nodeName === '#comment'). * * @param {HTMLElement} node * @returns {Boolean} */ isVirtualElement = function (node) { return node.nodeType === 8; }, /** * Checks if it's real DOM element * in case of virtual element, returns span wrapper * @param {Object} el * @param {bool} isUpdate * @return {Object} el */ getRealElement = function (el, isUpdate) { if (isVirtualElement(el)) { if (isUpdate) { return $(el).next('span'); } return $('<span></span>').insertAfter(el); } return el; }, /** * execute i18n binding * @param {Object} element * @param {Function} valueAccessor * @param {bool} isUpdate */ execute = function (element, valueAccessor, isUpdate) { var original = ko.unwrap(valueAccessor() || ''), el = getRealElement(element, isUpdate), inlineTranslation = (module.config() || {}).inlineTranslation; if (inlineTranslation) { setTranslateProp(el, original); } else { setText(el, $.mage.__(original)); } }; /** * i18n binding * @property {Function} init * @property {Function} update */ ko.bindingHandlers.i18n = { /** * init i18n binding * @param {Object} element * @param {Function} valueAccessor */ init: function (element, valueAccessor) { execute(element, valueAccessor); }, /** * update i18n binding * @param {Object} element * @param {Function} valueAccessor */ update: function (element, valueAccessor) { execute(element, valueAccessor, true); } }; ko.virtualElements.allowedBindings.i18n = true; renderer .addNode('translate', { binding: 'i18n' }) .addAttribute('translate', { binding: 'i18n' }); }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /** Creates scope binding and registers in to ko.bindingHandlers object */ define('Magento_Ui/js/lib/knockout/bindings/scope',[ 'ko', 'uiRegistry', 'mage/translate', '../template/renderer', 'jquery', '../../logger/console-logger' ], function (ko, registry, $t, renderer, $, consoleLogger) { 'use strict'; /** * Creates child context with passed component param as $data. Extends context with $t helper. * Applies bindings to descendant nodes. * @param {HTMLElement} el - element to apply bindings to. * @param {ko.bindingContext} bindingContext - instance of ko.bindingContext, passed to binding initially. * @param {Promise} promise - instance of jQuery promise * @param {Object} component - component instance to attach to new context */ function applyComponents(el, bindingContext, promise, component) { promise.resolve(); component = bindingContext.createChildContext(component); ko.utils.extend(component, { $t: $t }); ko.utils.arrayForEach(ko.virtualElements.childNodes(el), ko.cleanNode); ko.applyBindingsToDescendants(component, el); } ko.bindingHandlers.scope = { /** * Scope binding's init method. * @returns {Object} - Knockout declaration for it to let binding control descendants. */ init: function () { return { controlsDescendantBindings: true }; }, /** * Reads params passed to binding, parses component declarations. * Fetches for those found and attaches them to the new context. * @param {HTMLElement} el - Element to apply bindings to. * @param {Function} valueAccessor - Function that returns value, passed to binding. * @param {Object} allBindings - Object, which represents all bindings applied to element. * @param {Object} viewModel - Object, which represents view model binded to el. * @param {ko.bindingContext} bindingContext - Instance of ko.bindingContext, passed to binding initially. */ update: function (el, valueAccessor, allBindings, viewModel, bindingContext) { var component = valueAccessor(), promise = $.Deferred(), apply = applyComponents.bind(this, el, bindingContext, promise), loggerUtils = consoleLogger.utils; if (typeof component === 'string') { loggerUtils.asyncLog( promise, { data: { component: component }, messages: loggerUtils.createMessages( 'requestingComponent', 'requestingComponentIsLoaded', 'requestingComponentIsFailed' ) } ); registry.get(component, apply); } else if (typeof component === 'function') { component(apply); } } }; ko.virtualElements.allowedBindings.scope = true; renderer .addNode('scope') .addAttribute('scope', { name: 'ko-scope' }); }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('Magento_Ui/js/lib/knockout/bindings/range',[ 'ko', 'jquery', 'underscore', '../template/renderer' ], function (ko, $, _, renderer) { 'use strict'; var isTouchDevice = !_.isUndefined(document.ontouchstart), sliderFn = 'slider', sliderModule = 'jquery-ui-modules/slider'; if (isTouchDevice) { sliderFn = 'touchSlider'; sliderModule = 'mage/touch-slider'; } ko.bindingHandlers.range = { /** * Initializes binding and a slider update. * * @param {HTMLElement} element * @param {Function} valueAccessor */ init: function (element, valueAccessor) { var config = valueAccessor(), value = config.value; _.extend(config, { value: value(), /** * Callback which is being called when sliders' value changes. * * @param {Event} event * @param {Object} ui */ slide: function (event, ui) { value(ui.value); } }); require([sliderModule], function () { $(element)[sliderFn](config); }); }, /** * Updates sliders' plugin configuration. * * @param {HTMLElement} element * @param {Function} valueAccessor */ update: function (element, valueAccessor) { var config = valueAccessor(); config.value = ko.unwrap(config.value); require([sliderModule], function () { $(element)[sliderFn]('option', config); }); } }; renderer.addAttribute('range'); }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('Magento_Ui/js/lib/knockout/bindings/mage-init',[ 'ko', 'underscore', 'mage/apply/main' ], function (ko, _, mage) { 'use strict'; ko.bindingHandlers.mageInit = { /** * Initializes components assigned to HTML elements. * * @param {HTMLElement} el * @param {Function} valueAccessor */ init: function (el, valueAccessor) { var data = valueAccessor(); _.each(data, function (config, component) { mage.applyFor(el, config, component); }); } }; }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('Magento_Ui/js/lib/knockout/bindings/keyboard',[ 'ko', '../template/renderer' ], function (ko, renderer) { 'use strict'; ko.bindingHandlers.keyboard = { /** * Attaches keypress handlers to element * @param {HTMLElement} el - Element, that binding is applied to * @param {Function} valueAccessor - Function that returns value, passed to binding * @param {Object} allBindings - all bindings object * @param {Object} viewModel - reference to viewmodel */ init: function (el, valueAccessor, allBindings, viewModel) { var map = valueAccessor(); ko.utils.registerEventHandler(el, 'keyup', function (e) { var callback = map[e.keyCode]; if (callback) { return callback.call(viewModel, e); } }); } }; renderer.addAttribute('keyboard'); }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('Magento_Ui/js/lib/knockout/bindings/optgroup',[ 'ko', 'mageUtils' ], function (ko, utils) { 'use strict'; var captionPlaceholder = {}, optgroupTmpl = '<optgroup label="${ $.label }"></optgroup>', nbspRe = / /g, optionsText, optionsValue, optionTitle; ko.bindingHandlers.optgroup = { /** * @param {*} element */ init: function (element) { if (ko.utils.tagNameLower(element) !== 'select') { throw new Error('options binding applies only to SELECT elements'); } // Remove all existing <option>s. while (element.length > 0) { element.remove(0); } }, /** * @param {*} element * @param {*} valueAccessor * @param {*} allBindings */ update: function (element, valueAccessor, allBindings) { var selectWasPreviouslyEmpty = element.length === 0, previousScrollTop = !selectWasPreviouslyEmpty && element.multiple ? element.scrollTop : null, includeDestroyed = allBindings.get('optionsIncludeDestroyed'), arrayToDomNodeChildrenOptions = {}, captionValue, unwrappedArray = ko.utils.unwrapObservable(valueAccessor()), filteredArray, previousSelectedValues, itemUpdate = false, callback = setSelectionCallback,//eslint-disable-line no-use-before-define nestedOptionsLevel = -1; optionsText = ko.utils.unwrapObservable(allBindings.get('optionsText')) || 'text'; optionsValue = ko.utils.unwrapObservable(allBindings.get('optionsValue')) || 'value'; optionTitle = optionsText + 'title'; if (element.multiple) { previousSelectedValues = ko.utils.arrayMap( selectedOptions(),//eslint-disable-line no-use-before-define ko.selectExtensions.readValue ); } else { previousSelectedValues = element.selectedIndex >= 0 ? [ko.selectExtensions.readValue(element.options[element.selectedIndex])] : []; } if (unwrappedArray) { if (typeof unwrappedArray.length === 'undefined') { // Coerce single value into array unwrappedArray = [unwrappedArray]; } // Filter out any entries marked as destroyed filteredArray = ko.utils.arrayFilter(unwrappedArray, function (item) { if (item && !item.label) { return false; } return includeDestroyed || item === undefined || item === null || !ko.utils.unwrapObservable(item._destroy); }); filteredArray.map(recursivePathBuilder, null);//eslint-disable-line no-use-before-define } /** * @param {*} option */ arrayToDomNodeChildrenOptions.beforeRemove = function (option) { element.removeChild(option); }; if (allBindings.has('optionsAfterRender')) { /** * @param {*} arrayEntry * @param {*} newOptions */ callback = function (arrayEntry, newOptions) { setSelectionCallback(arrayEntry, newOptions);//eslint-disable-line no-use-before-define ko.dependencyDetection.ignore( allBindings.get('optionsAfterRender'), null, [newOptions[0], arrayEntry !== captionPlaceholder ? arrayEntry : undefined] ); }; } filteredArray = formatOptions(filteredArray);//eslint-disable-line no-use-before-define ko.utils.setDomNodeChildrenFromArrayMapping( element, filteredArray, optionNodeFromArray,//eslint-disable-line no-use-before-define arrayToDomNodeChildrenOptions, callback ); ko.dependencyDetection.ignore(function () { var selectionChanged; if (allBindings.get('valueAllowUnset') && allBindings.has('value')) { // The model value is authoritative, so make sure its value is the one selected ko.selectExtensions.writeValue( element, ko.utils.unwrapObservable(allBindings.get('value')), true /* allowUnset */ ); } else { // Determine if the selection has changed as a result of updating the options list if (element.multiple) { // For a multiple-select box, compare the new selection count to the previous one // But if nothing was selected before, the selection can't have changed selectionChanged = previousSelectedValues.length && selectedOptions().length < //eslint-disable-line no-use-before-define previousSelectedValues.length; } else { // For a single-select box, compare the current value to the previous value // But if nothing was selected before or nothing is selected now, // just look for a change in selection selectionChanged = previousSelectedValues.length && element.selectedIndex >= 0 ? ko.selectExtensions.readValue(element.options[element.selectedIndex]) !== previousSelectedValues[0] : previousSelectedValues.length || element.selectedIndex >= 0; } // Ensure consistency between model value and selected option. // If the dropdown was changed so that selection is no longer the same, // notify the value or selectedOptions binding. if (selectionChanged) { ko.utils.triggerEvent(element, 'change'); } } }); /*eslint-enable max-len, no-use-before-define*/ if (previousScrollTop && Math.abs(previousScrollTop - element.scrollTop) > 20) { element.scrollTop = previousScrollTop; } /** * @returns {*} */ function selectedOptions() { return ko.utils.arrayFilter(element.options, function (node) { return node.selected; }); } /** * @param {*} object * @param {*} predicate * @param {*} defaultValue * @returns {*} */ function applyToObject(object, predicate, defaultValue) { var predicateType = typeof predicate; if (predicateType === 'function') { // run it against the data value return predicate(object); } else if (predicateType === 'string') { // treat it as a property name on the data value return object[predicate]; } return defaultValue; } /** * @param {*} obj */ function recursivePathBuilder(obj) { obj[optionTitle] = (this && this[optionTitle] ? this[optionTitle] + '/' : '') + obj[optionsText].trim(); if (Array.isArray(obj[optionsValue])) { obj[optionsValue].map(recursivePathBuilder, obj); } } /** * @param {Array} arrayEntry * @param {*} oldOptions * @returns {*[]} */ function optionNodeFromArray(arrayEntry, oldOptions) { var option; if (oldOptions.length) { previousSelectedValues = oldOptions[0].selected ? [ko.selectExtensions.readValue(oldOptions[0])] : []; itemUpdate = true; } if (arrayEntry === captionPlaceholder) { // empty value, label === caption option = element.ownerDocument.createElement('option'); ko.utils.setTextContent(option, allBindings.get('optionsCaption')); ko.selectExtensions.writeValue(option, undefined); } else if (typeof arrayEntry[optionsValue] === 'undefined') { // empty value === optgroup if (arrayEntry.__disableTmpl) { option = '<optgroup label="' + arrayEntry[optionsText] + '"></optgroup>'; } else { option = utils.template(optgroupTmpl, { label: arrayEntry[optionsText], title: arrayEntry[optionsText + 'title'] }); } option = ko.utils.parseHtmlFragment(option)[0]; } else { option = element.ownerDocument.createElement('option'); option.setAttribute('data-title', arrayEntry[optionsText + 'title']); ko.selectExtensions.writeValue(option, arrayEntry[optionsValue]); ko.utils.setTextContent(option, arrayEntry[optionsText]); } return [option]; } /** * @param {*} newOptions */ function setSelectionCallback(newOptions) { var isSelected; // IE6 doesn't like us to assign selection to OPTION nodes before they're added to the document. // That's why we first added them without selection. Now it's time to set the selection. if (previousSelectedValues.length && newOptions.value) { isSelected = ko.utils.arrayIndexOf( previousSelectedValues, ko.selectExtensions.readValue(newOptions.value) ) >= 0; ko.utils.setOptionNodeSelectionState(newOptions.value, isSelected); // If this option was changed from being selected during a single-item update, notify the change if (itemUpdate && !isSelected) { ko.dependencyDetection.ignore(ko.utils.triggerEvent, null, [element, 'change']); } } } /** * @param {*} string * @param {Number} times * @returns {Array} */ function strPad(string, times) { return new Array(times + 1).join(string); } /** * @param {*} options * @returns {Array} */ function formatOptions(options) { var res = []; nestedOptionsLevel++; if (!nestedOptionsLevel) { // zero level // If caption is included, add it to the array if (allBindings.has('optionsCaption')) { captionValue = ko.utils.unwrapObservable(allBindings.get('optionsCaption')); // If caption value is null or undefined, don't show a caption if (//eslint-disable-line max-depth captionValue !== null && captionValue !== undefined && captionValue !== false ) { res.push(captionPlaceholder); } } } ko.utils.arrayForEach(options, function (option) { var value = applyToObject(option, optionsValue, option), label = applyToObject(option, optionsText, value) || '', disabled = applyToObject(option, 'disabled', false) || false, obj = {}, space = '\u2007\u2007\u2007'; obj[optionTitle] = applyToObject(option, optionsText + 'title', value); if (disabled) { obj.disabled = disabled; } if (option.hasOwnProperty('__disableTmpl')) { obj.__disableTmpl = option.__disableTmpl; } label = label.replace(nbspRe, '').trim(); if (Array.isArray(value)) { obj[optionsText] = strPad(' ', nestedOptionsLevel * 4) + label; res.push(obj); res = res.concat(formatOptions(value)); } else { obj[optionsText] = strPad(space, nestedOptionsLevel * 2) + label; obj[optionsValue] = value; res.push(obj); } }); nestedOptionsLevel--; return res; } } }; }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('Magento_Ui/js/lib/knockout/bindings/after-render',[ 'ko', '../template/renderer' ], function (ko, renderer) { 'use strict'; ko.bindingHandlers.afterRender = { /** * Binding init callback. */ init: function (element, valueAccessor, allBindings, viewModel) { var callback = valueAccessor(); if (typeof callback === 'function') { callback.call(viewModel, element, viewModel); } } }; renderer.addAttribute('afterRender'); }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('Magento_Ui/js/lib/knockout/bindings/autoselect',[ 'ko', 'jquery', '../template/renderer' ], function (ko, $, renderer) { 'use strict'; /** * 'Focus' event handler. * * @param {EventObject} e */ function onFocus(e) { e.target.select(); } ko.bindingHandlers.autoselect = { /** * Adds event handler which automatically * selects inputs' element text when field gets focused. */ init: function (element, valueAccessor) { var enabled = ko.unwrap(valueAccessor()); if (enabled !== false) { $(element).on('focus', onFocus); } } }; renderer.addAttribute('autoselect'); }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /** Creates outerClick binding and registers in to ko.bindingHandlers object */ define('Magento_Ui/js/lib/knockout/bindings/outer_click',[ 'ko', 'jquery', 'underscore', '../template/renderer' ], function (ko, $, _, renderer) { 'use strict'; var defaults = { onlyIfVisible: true }; /** * Checks if element sis visible. * * @param {Element} el * @returns {Boolean} */ function isVisible(el) { var style = window.getComputedStyle(el), visibility = { display: 'none', visibility: 'hidden', opacity: '0' }, visible = true; _.each(visibility, function (val, key) { if (style[key] === val) { visible = false; } }); return visible; } /** * Document click handler which in case if event target is not * a descendant of provided container element, * invokes specified in configuration callback. * * @param {HTMLElement} container * @param {Object} config * @param {EventObject} e */ function onOuterClick(container, config, e) { var target = e.target, callback = config.callback; if (container === target || container.contains(target)) { return; } if (config.onlyIfVisible) { if (!_.isNull(container.offsetParent) && isVisible(container)) { callback(); } } else { callback(); } } /** * Prepares configuration for the binding based * on a default properties and provided options. * * @param {(Object|Function)} [options={}] * @returns {Object} */ function buildConfig(options) { var config = {}; if (_.isFunction(options)) { options = { callback: options }; } else if (!_.isObject(options)) { options = {}; } return _.extend(config, defaults, options); } ko.bindingHandlers.outerClick = { /** * Initializes outer click binding. */ init: function (element, valueAccessor) { var config = buildConfig(valueAccessor()), outerClick = onOuterClick.bind(null, element, config), isTouchDevice = typeof document.ontouchstart !== 'undefined'; if (isTouchDevice) { $(document).on('touchstart', outerClick); ko.utils.domNodeDisposal.addDisposeCallback(element, function () { $(document).off('touchstart', outerClick); }); } else { $(document).on('click', outerClick); ko.utils.domNodeDisposal.addDisposeCallback(element, function () { $(document).off('click', outerClick); }); } } }; renderer.addAttribute('outerClick'); }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('Magento_Ui/js/lib/knockout/bindings/fadeVisible',[ 'jquery', 'ko' ], function ($, ko) { 'use strict'; ko.bindingHandlers.fadeVisible = { /** * Initially set the element to be instantly visible/hidden depending on the value. * * @param {HTMLElement} element * @param {Function} valueAccessor */ init: function (element, valueAccessor) { var value = valueAccessor(); // Use "unwrapObservable" so we can handle values that may or may not be observable $(element).toggle(ko.unwrap(value)); }, /** * Whenever the value subsequently changes, slowly fade the element in or out. * * @param {HTMLElement} element * @param {Function} valueAccessor */ update: function (element, valueAccessor) { var value = valueAccessor(); ko.unwrap(value) ? $(element).fadeIn() : $(element).fadeOut(); } }; }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('Magento_Ui/js/lib/knockout/bindings/collapsible',[ 'ko', 'jquery', 'underscore', '../template/renderer' ], function (ko, $, _, renderer) { 'use strict'; var collapsible, defaults; defaults = { closeOnOuter: true, onTarget: false, openClass: '_active', as: '$collapsible' }; collapsible = { /** * Sets 'opened' property to true. */ open: function () { this.opened(true); }, /** * Sets 'opened' property to false. */ close: function () { this.opened(false); }, /** * Toggles value of the 'opened' property. */ toggle: function () { this.opened(!this.opened()); } }; /** * Document click handler which in case if event target is not * a descendant of provided container element, closes collapsible model. * * @param {HTMLElement} container * @param {Object} model * @param {EventObject} e */ function onOuterClick(container, model, e) { var target = e.target; if (target !== container && !container.contains(target)) { model.close(); } } /** * Creates 'css' binding which toggles * class specified in 'name' parameter. * * @param {Object} model * @param {String} name * @returns {Object} */ function getClassBinding(model, name) { var binding = {}; binding[name] = model.opened; return { css: binding }; } /** * Prepares configuration for the binding based * on a default properties and provided options. * * @param {Object} [options={}] * @returns {Object} Complete instance configuration. */ function buildConfig(options) { if (typeof options !== 'object') { options = {}; } return _.extend({}, defaults, options); } ko.bindingHandlers.collapsible = { /** * Initializes 'collapsible' binding. */ init: function (element, valueAccessor, allBindings, viewModel, bindingCtx) { var $collapsible = Object.create(collapsible), config = buildConfig(valueAccessor()), outerClick, bindings; _.bindAll($collapsible, 'open', 'close', 'toggle'); $collapsible.opened = ko.observable(!!config.opened); bindingCtx[config.as] = $collapsible; if (config.closeOnOuter) { outerClick = onOuterClick.bind(null, element, $collapsible); $(document).on('click', outerClick); ko.utils.domNodeDisposal.addDisposeCallback(element, function () { $(document).off('click', outerClick); }); } if (config.openClass) { bindings = getClassBinding($collapsible, config.openClass); ko.applyBindingsToNode(element, bindings, bindingCtx); } if (config.onTarget) { $(element).on('click', $collapsible.toggle); } if (viewModel && _.isFunction(viewModel.on)) { viewModel.on({ close: $collapsible.close, open: $collapsible.open, toggleOpened: $collapsible.toggle }); } } }; ko.bindingHandlers.closeCollapsible = { /** * Creates listener for the click event on provided DOM element, * which closes associated with it collapsible model. */ init: function (element, valueAccessor, allBindings, viewModel, bindingCtx) { var name = valueAccessor() || defaults.as, $collapsible = bindingCtx[name]; if ($collapsible) { $(element).on('click', $collapsible.close); } } }; ko.bindingHandlers.openCollapsible = { /** * Creates listener for the click event on provided DOM element, * which opens associated with it collapsible model. */ init: function (element, valueAccessor, allBindings, viewModel, bindingCtx) { var name = valueAccessor() || defaults.as, $collapsible = bindingCtx[name]; if ($collapsible) { $(element).on('click', $collapsible.open); } } }; ko.bindingHandlers.toggleCollapsible = { /** * Creates listener for the click event on provided DOM element, * which toggles associated with it collapsible model. */ init: function (element, valueAccessor, allBindings, viewModel, bindingCtx) { var name = valueAccessor() || defaults.as, $collapsible = bindingCtx[name]; if ($collapsible) { $(element).on('click', $collapsible.toggle); } } }; renderer .addAttribute('collapsible') .addAttribute('openCollapsible') .addAttribute('closeCollapsible') .addAttribute('toggleCollapsible'); }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('Magento_Ui/js/lib/knockout/bindings/staticChecked',[ 'ko', '../template/renderer' ], function (ko, renderer) { 'use strict'; ko.bindingHandlers.staticChecked = { 'after': ['value', 'attr'], /** * Implements same functionality as a standard 'checked' binding, * but with a difference that it wont' change values array if * value of DOM element changes. */ init: function (element, valueAccessor, allBindings) { var isCheckbox = element.type === 'checkbox', isRadio = element.type === 'radio', isValueArray, oldElemValue, useCheckedValue, checkedValue, updateModel, updateView; if (!isCheckbox && !isRadio) { return; } checkedValue = ko.pureComputed(function () { if (allBindings.has('checkedValue')) { return ko.utils.unwrapObservable(allBindings.get('checkedValue')); } else if (allBindings.has('value')) { return ko.utils.unwrapObservable(allBindings.get('value')); } return element.value; }); isValueArray = isCheckbox && ko.utils.unwrapObservable(valueAccessor()) instanceof Array; oldElemValue = isValueArray ? checkedValue() : undefined; useCheckedValue = isRadio || isValueArray; /** * Updates values array if it's necessary. */ updateModel = function () { var isChecked = element.checked, elemValue = useCheckedValue ? checkedValue() : isChecked, modelValue; if (ko.computedContext.isInitial()) { return; } if (isRadio && !isChecked) { return; } modelValue = ko.dependencyDetection.ignore(valueAccessor); if (isValueArray) { if (oldElemValue !== elemValue) { oldElemValue = elemValue; } else { ko.utils.addOrRemoveItem(modelValue, elemValue, isChecked); } } else { ko.expressionRewriting.writeValueToProperty(modelValue, allBindings, 'checked', elemValue, true); } }; /** * Updates checkbox state. */ updateView = function () { var modelValue = ko.utils.unwrapObservable(valueAccessor()); if (isValueArray) { element.checked = ko.utils.arrayIndexOf(modelValue, checkedValue()) >= 0; } else if (isCheckbox) { element.checked = modelValue; } else { element.checked = checkedValue() === modelValue; } }; ko.computed(updateModel, null, { disposeWhenNodeIsRemoved: element }); ko.utils.registerEventHandler(element, 'click', updateModel); ko.computed(updateView, null, { disposeWhenNodeIsRemoved: element }); } }; ko.expressionRewriting._twoWayBindings.staticChecked = true; renderer.addAttribute('staticChecked'); }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('Magento_Ui/js/lib/knockout/bindings/simple-checked',[ 'ko', '../template/renderer' ], function (ko, renderer) { 'use strict'; ko.bindingHandlers.simpleChecked = { 'after': ['attr'], /** * Implements same functionality as a standard 'simpleChecked' binding, * but with a difference that it wont' change values array if * value of DOM element changes. */ init: function (element, valueAccessor) { var isCheckbox = element.type === 'checkbox', isRadio = element.type === 'radio', updateView, updateModel; if (!isCheckbox && !isRadio) { return; } /** * Updates checked observable */ updateModel = function () { var modelValue = ko.dependencyDetection.ignore(valueAccessor), isChecked = element.checked; if (ko.computedContext.isInitial()) { return; } if (modelValue.peek() === isChecked) { return; } if (isRadio && !isChecked) { return; } modelValue(isChecked); }; /** * Updates checkbox state */ updateView = function () { var modelValue = ko.utils.unwrapObservable(valueAccessor()); element.checked = !!modelValue; }; ko.utils.registerEventHandler(element, 'change', updateModel); ko.computed(updateModel, null, { disposeWhenNodeIsRemoved: element }); ko.computed(updateView, null, { disposeWhenNodeIsRemoved: element }); } }; ko.expressionRewriting._twoWayBindings.simpleChecked = true; renderer.addAttribute('simpleChecked'); renderer.addAttribute('simple-checked', { binding: 'simpleChecked' }); }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('Magento_Ui/js/lib/knockout/bindings/bind-html',[ 'ko', 'underscore', 'mage/apply/main', '../template/renderer' ], function (ko, _, mage, renderer) { 'use strict'; /** * Set html to node element. * * @param {HTMLElement} el - Element to apply bindings to. * @param {Function} html - Observable html content. */ function setHtml(el, html) { ko.utils.emptyDomNode(el); html = ko.utils.unwrapObservable(html); if (!_.isNull(html) && !_.isUndefined(html)) { if (!_.isString(html)) { html = html.toString(); } el.innerHTML = html; } } /** * Apply bindings and call magento attributes parser. * * @param {HTMLElement} el - Element to apply bindings to. * @param {ko.bindingContext} ctx - Instance of ko.bindingContext, passed to binding initially. */ function applyComponents(el, ctx) { ko.utils.arrayForEach(el.childNodes, ko.cleanNode); ko.applyBindingsToDescendants(ctx, el); mage.apply(); } ko.bindingHandlers.bindHtml = { /** * Scope binding's init method. * * @returns {Object} - Knockout declaration for it to let binding control descendants. */ init: function () { return { controlsDescendantBindings: true }; }, /** * Reads params passed to binding. * Set html to node element, apply bindings and call magento attributes parser. * * @param {HTMLElement} el - Element to apply bindings to. * @param {Function} valueAccessor - Function that returns value, passed to binding. * @param {Object} allBindings - Object, which represents all bindings applied to element. * @param {Object} viewModel - Object, which represents view model binded to el. * @param {ko.bindingContext} bindingContext - Instance of ko.bindingContext, passed to binding initially. */ update: function (el, valueAccessor, allBindings, viewModel, bindingContext) { setHtml(el, valueAccessor()); applyComponents(el, bindingContext); } }; renderer.addAttribute('bindHtml'); }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('Magento_Ui/js/lib/knockout/bindings/tooltip',[ 'jquery', 'ko', 'underscore', 'mage/template', 'text!ui/template/tooltip/tooltip.html', '../template/renderer' ], function ($, ko, _, template, tooltipTmpl, renderer) { 'use strict'; var tooltip, defaults, positions, transformProp, checkedPositions = {}, iterator = 0, previousTooltip, tooltipData, positionData = {}, tooltipsCollection = {}, isTouchDevice = (function () { return 'ontouchstart' in document.documentElement; })(), CLICK_EVENT = (function () { return isTouchDevice ? 'touchstart' : 'click'; })(); defaults = { tooltipWrapper: '[data-tooltip=tooltip-wrapper]', tooltipContentBlock: 'data-tooltip-content', closeButtonClass: 'action-close', tailClass: 'data-tooltip-tail', action: 'hover', delay: 300, track: false, step: 20, position: 'top', closeButton: false, showed: false, strict: true, center: false, closeOnScroll: true }; tooltipData = { tooltipClasses: '', trigger: false, timeout: 0, element: false, event: false, targetElement: {}, showed: false, currentID: 0 }; /** * Polyfill for css transform */ transformProp = (function () { var style = document.createElement('div').style, base = 'Transform', vendors = ['webkit', 'moz', 'ms', 'o'], vi = vendors.length, property; if (typeof style.transform !== 'undefined') { return 'transform'; } while (vi--) { property = vendors[vi] + base; if (typeof style[property] !== 'undefined') { return property; } } })(); positions = { /*eslint max-depth: [0, 0]*/ map: { horizontal: { s: 'w', p: 'left' }, vertical: { s: 'h', p: 'top' } }, /** * Wrapper function to get tooltip data (position, className, etc) * * @param {Object} s - object with sizes and positions elements * @returns {Object} tooltip data (position, className, etc) */ top: function (s) { return positions._topLeftChecker(s, positions.map, 'vertical', '_bottom', 'top', 'right'); }, /** * Wrapper function to get tooltip data (position, className, etc) * * @param {Object} s - object with sizes and positions elements * @returns {Object} tooltip data (position, className, etc) */ left: function (s) { return positions._topLeftChecker(s, positions.map, 'horizontal', '_right', 'left', 'top'); }, /** * Wrapper function to get tooltip data (position, className, etc) * * @param {Object} s - object with sizes and positions elements * @returns {Object} tooltip data (position, className, etc) */ bottom: function (s) { return positions._bottomRightChecker(s, positions.map, 'vertical', '_top', 'bottom', 'left'); }, /** * Wrapper function to get tooltip data (position, className, etc) * * @param {Object} s - object with sizes and positions elements * @returns {Object} tooltip data (position, className, etc) */ right: function (s) { return positions._bottomRightChecker(s, positions.map, 'horizontal', '_left', 'right', 'bottom'); }, /** * Check can tooltip setted on current position or not. If can't setted - delegate call. * * @param {Object} s - object with sizes and positions elements * @param {Object} map - mapping for get direction positions * @param {String} direction - vertical or horizontal * @param {String} className - class whats should be setted to tooltip * @param {String} side - parent method name * @param {String} delegate - method name if tooltip can't be setted in current position * @returns {Object} tooltip data (position, className, etc) */ _topLeftChecker: function (s, map, direction, className, side, delegate) { var result = { position: {} }, config = tooltip.getTooltip(tooltipData.currentID), startPosition = !config.strict ? s.eventPosition : s.elementPosition, changedDirection; checkedPositions[side] = true; if ( startPosition[map[direction].p] - s.tooltipSize[map[direction].s] - config.step > s.scrollPosition[map[direction].p] ) { result.position[map[direction].p] = startPosition[map[direction].p] - s.tooltipSize[map[direction].s] - config.step; result.className = className; result.side = side; changedDirection = direction === 'vertical' ? 'horizontal' : 'vertical'; result = positions._normalize(s, result, config, delegate, map, changedDirection); } else if (!checkedPositions[delegate]) { result = positions[delegate].apply(null, arguments); } else { result = positions.positionCenter(s, result); } return result; }, /** * Check can tooltip setted on current position or not. If can't setted - delegate call. * * @param {Object} s - object with sizes and positions elements * @param {Object} map - mapping for get direction positions * @param {String} direction - vertical or horizontal * @param {String} className - class whats should be setted to tooltip * @param {String} side - parent method name * @param {String} delegate - method name if tooltip can't be setted in current position * @returns {Object} tooltip data (position, className, etc) */ _bottomRightChecker: function (s, map, direction, className, side, delegate) { var result = { position: {} }, config = tooltip.getTooltip(tooltipData.currentID), startPosition = !config.strict ? s.eventPosition : { top: s.elementPosition.top + s.elementSize.h, left: s.elementPosition.left + s.elementSize.w }, changedDirection; checkedPositions[side] = true; if ( startPosition[map[direction].p] + s.tooltipSize[map[direction].s] + config.step < s.scrollPosition[map[direction].p] + s.windowSize[map[direction].s] ) { result.position[map[direction].p] = startPosition[map[direction].p] + config.step; result.className = className; result.side = side; changedDirection = direction === 'vertical' ? 'horizontal' : 'vertical'; result = positions._normalize(s, result, config, delegate, map, changedDirection); } else if (!checkedPositions[delegate]) { result = positions[delegate].apply(null, arguments); } else { result = positions.positionCenter(s, result); } return result; }, /** * Centered tooltip if tooltip does not fit in window * * @param {Object} s - object with sizes and positions elements * @param {Object} data - current data (position, className, etc) * @returns {Object} tooltip data (position, className, etc) */ positionCenter: function (s, data) { data = positions._positionCenter(s, data, 'horizontal', positions.map); data = positions._positionCenter(s, data, 'vertical', positions.map); return data; }, /** * Centered tooltip side * * @param {Object} s - object with sizes and positions elements * @param {Object} data - current data (position, className, etc) * @param {String} direction - vertical or horizontal * @param {Object} map - mapping for get direction positions * @returns {Object} tooltip data (position, className, etc) */ _positionCenter: function (s, data, direction, map) { if (s.tooltipSize[map[direction].s] < s.windowSize[map[direction].s]) { data.position[map[direction].p] = (s.windowSize[map[direction].s] - s.tooltipSize[map[direction].s]) / 2 + s.scrollPosition[map[direction].p]; } else { data.position[map[direction].p] = s.scrollPosition[map[direction].p]; data.tooltipSize = {}; data.tooltipSize[map[direction].s] = s.windowSize[map[direction].s]; } return data; }, /** * Normalize horizontal or vertical position. * * @param {Object} s - object with sizes and positions elements * @param {Object} data - current data (position, className, etc) * @param {Object} config - tooltip config * @param {String} delegate - method name if tooltip can't be setted in current position * @param {Object} map - mapping for get direction positions * @param {String} direction - vertical or horizontal * @returns {Object} tooltip data (position, className, etc) */ _normalize: function (s, data, config, delegate, map, direction) { var startPosition = !config.center ? s.eventPosition : { left: s.elementPosition.left + s.elementSize.w / 2, top: s.elementPosition.top + s.elementSize.h / 2 }, depResult; if (startPosition[map[direction].p] - s.tooltipSize[map[direction].s] / 2 > s.scrollPosition[map[direction].p] && startPosition[map[direction].p] + s.tooltipSize[map[direction].s] / 2 < s.scrollPosition[map[direction].p] + s.windowSize[map[direction].s] ) { data.position[map[direction].p] = startPosition[map[direction].p] - s.tooltipSize[map[direction].s] / 2; } else { /*eslint-disable no-lonely-if*/ if (!checkedPositions[delegate]) { depResult = positions[delegate].apply(null, arguments); if (depResult.hasOwnProperty('className')) { data = depResult; } else { data = positions._normalizeTail(s, data, config, delegate, map, direction, startPosition); } } else { data = positions._normalizeTail(s, data, config, delegate, map, direction, startPosition); } } return data; }, /** * Calc tail position. * * @param {Object} s - object with sizes and positions elements * @param {Object} data - current data (position, className, etc) * @param {Object} config - tooltip config * @param {String} delegate - method name if tooltip can't be setted in current position * @param {Object} map - mapping for get direction positions * @param {String} direction - vertical or horizontal * @param {Object} startPosition - start position * @returns {Object} tooltip data (position, className, etc) */ _normalizeTail: function (s, data, config, delegate, map, direction, startPosition) { data.tail = {}; if (s.tooltipSize[map[direction].s] < s.windowSize[map[direction].s]) { if ( startPosition[map[direction].p] > s.windowSize[map[direction].s] / 2 + s.scrollPosition[map[direction].p] ) { data.position[map[direction].p] = s.windowSize[map[direction].s] + s.scrollPosition[map[direction].p] - s.tooltipSize[map[direction].s]; data.tail[map[direction].p] = startPosition[map[direction].p] - s.tooltipSize[map[direction].s] / 2 - data.position[map[direction].p]; } else { data.position[map[direction].p] = s.scrollPosition[map[direction].p]; data.tail[map[direction].p] = startPosition[map[direction].p] - s.tooltipSize[map[direction].s] / 2 - data.position[map[direction].p]; } } else { data.position[map[direction].p] = s.scrollPosition[map[direction].p]; data.tail[map[direction].p] = s.eventPosition[map[direction].p] - s.windowSize[map[direction].s] / 2; data.tooltipSize = {}; data.tooltipSize[map[direction].s] = s.windowSize[map[direction].s]; } return data; } }; tooltip = { /** * Set new tooltip to tooltipCollection, save config, and add unic id * * @param {Object} config - tooltip config * @returns {String} tooltip id */ setTooltip: function (config) { var property = 'id-' + iterator; tooltipsCollection[property] = config; iterator++; return property; }, /** * Get tooltip config by id * * @param {String} id - tooltip id * @returns {Object} tooltip config */ getTooltip: function (id) { return tooltipsCollection[id]; }, /** * Set content to current tooltip * * @param {Object} tooltipElement - tooltip element * @param {Object} viewModel - tooltip view model * @param {String} id - tooltip id * @param {Object} bindingCtx - tooltip context * @param {Object} event - action event */ setContent: function (tooltipElement, viewModel, id, bindingCtx, event) { var html = $(tooltipElement).html(), config = tooltip.getTooltip(id), body = $('body'); tooltipData.currentID = id; tooltipData.trigger = $(event.currentTarget); tooltip.setTargetData(event); body.on('mousemove.setTargetData', tooltip.setTargetData); tooltip.clearTimeout(id); tooltipData.timeout = _.delay(function () { body.off('mousemove.setTargetData', tooltip.setTargetData); if (tooltipData.trigger[0] === tooltipData.targetElement) { tooltip.destroy(id); event.stopPropagation(); tooltipElement = tooltip.createTooltip(id); tooltipElement.find('.' + defaults.tooltipContentBlock).append(html); tooltipElement.applyBindings(bindingCtx); tooltip.setHandlers(id); tooltip.setPosition(tooltipElement, id); previousTooltip = id; } }, config.delay); }, /** * Set position to current tooltip * * @param {Object} tooltipElement - tooltip element * @param {String} id - tooltip id */ setPosition: function (tooltipElement, id) { var config = tooltip.getTooltip(id); tooltip.sizeData = { windowSize: { h: $(window).outerHeight(), w: $(window).outerWidth() }, scrollPosition: { top: $(window).scrollTop(), left: $(window).scrollLeft() }, tooltipSize: { h: tooltipElement.outerHeight(), w: tooltipElement.outerWidth() }, elementSize: { h: tooltipData.trigger.outerHeight(), w: tooltipData.trigger.outerWidth() }, elementPosition: tooltipData.trigger.offset(), eventPosition: this.getEventPosition(tooltipData.event) }; _.extend(positionData, positions[config.position](tooltip.sizeData)); tooltipElement.css(positionData.position); tooltipElement.addClass(positionData.className); tooltip._setTooltipSize(positionData, tooltipElement); tooltip._setTailPosition(positionData, tooltipElement); checkedPositions = {}; }, /** * Check position data and change tooltip size if needs * * @param {Object} data - position data * @param {Object} tooltipElement - tooltip element */ _setTooltipSize: function (data, tooltipElement) { if (data.tooltipSize) { data.tooltipSize.w ? tooltipElement.css('width', data.tooltipSize.w) : tooltipElement.css('height', data.tooltipSize.h); } }, /** * Check position data and set position to tail * * @param {Object} data - position data * @param {Object} tooltipElement - tooltip element */ _setTailPosition: function (data, tooltipElement) { var tail, tailMargin; if (data.tail) { tail = tooltipElement.find('.' + defaults.tailClass); if (data.tail.left) { tailMargin = parseInt(tail.css('margin-left'), 10); tail.css('margin-left', tailMargin + data.tail.left); } else { tailMargin = parseInt(tail.css('margin-top'), 10); tail.css('margin-top', tailMargin + data.tail.top); } } }, /** * Resolves position for tooltip * * @param {Object} event * @returns {Object} */ getEventPosition: function (event) { var position = { left: event.originalEvent && event.originalEvent.pageX || 0, top: event.originalEvent && event.originalEvent.pageY || 0 }; if (position.left === 0 && position.top === 0) { _.extend(position, event.target.getBoundingClientRect()); } return position; }, /** * Close tooltip if action happened outside handler and tooltip element * * @param {String} id - tooltip id * @param {Object} event - action event */ outerClick: function (id, event) { var tooltipElement = $(event.target).parents(defaults.tooltipWrapper)[0], isTrigger = event.target === tooltipData.trigger[0] || $.contains(tooltipData.trigger[0], event.target); if (tooltipData.showed && tooltipElement !== tooltipData.element[0] && !isTrigger) { tooltip.destroy(id); } }, /** * Parse keydown event and if event trigger is escape key - close tooltip * * @param {Object} event - action event */ keydownHandler: function (event) { if (tooltipData.showed && event.keyCode === 27) { tooltip.destroy(tooltipData.currentID); } }, /** * Change tooltip position when track is enabled * * @param {Object} event - current event */ track: function (event) { var inequality = {}, map = positions.map, translate = { left: 'translateX', top: 'translateY' }, eventPosition = { left: event.pageX, top: event.pageY }, tooltipSize = { w: tooltipData.element.outerWidth(), h: tooltipData.element.outerHeight() }, direction = positionData.side === 'bottom' || positionData.side === 'top' ? 'horizontal' : 'vertical'; inequality[map[direction].p] = eventPosition[map[direction].p] - (positionData.position[map[direction].p] + tooltipSize[map[direction].s] / 2); if (positionData.position[map[direction].p] + inequality[map[direction].p] + tooltip.sizeData.tooltipSize[map[direction].s] > tooltip.sizeData.windowSize[map[direction].s] + tooltip.sizeData.scrollPosition[map[direction].p] || inequality[map[direction].p] + positionData.position[map[direction].p] < tooltip.sizeData.scrollPosition[map[direction].p]) { return false; } tooltipData.element[0].style[transformProp] = translate[map[direction].p] + '(' + inequality[map[direction].p] + 'px)'; }, /** * Set handlers to tooltip * * @param {String} id - tooltip id */ setHandlers: function (id) { var config = tooltip.getTooltip(id); if (config.track) { tooltipData.trigger.on('mousemove.track', tooltip.track); } if (config.action === 'click') { $(window).on(CLICK_EVENT + '.outerClick', tooltip.outerClick.bind(null, id)); } if (config.closeButton) { $('.' + config.closeButtonClass).on('click.closeButton', tooltip.destroy.bind(null, id)); } if (config.closeOnScroll) { document.addEventListener('scroll', tooltip.destroy, true); $(window).on('scroll.tooltip', tooltip.outerClick.bind(null, id)); } $(window).on('keydown.tooltip', tooltip.keydownHandler); $(window).on('resize.outerClick', tooltip.outerClick.bind(null, id)); }, /** * Toggle tooltip * * @param {Object} tooltipElement - tooltip element * @param {Object} viewModel - tooltip view model * @param {String} id - tooltip id */ toggleTooltip: function (tooltipElement, viewModel, id) { if (previousTooltip === id && tooltipData.showed) { tooltip.destroy(id); return false; } tooltip.setContent.apply(null, arguments); return false; }, /** * Create tooltip and append to DOM * * @param {String} id - tooltip id * @returns {Object} tooltip element */ createTooltip: function (id) { var body = $('body'), config = tooltip.getTooltip(id); $(template(tooltipTmpl, { data: config })).appendTo(body); tooltipData.showed = true; tooltipData.element = $(config.tooltipWrapper); return tooltipData.element; }, /** * Check action and clean timeout * * @param {String} id - tooltip id */ clearTimeout: function (id) { var config = tooltip.getTooltip(id); if (config.action === 'hover') { clearTimeout(tooltipData.timeout); } }, /** * Check previous tooltip */ checkPreviousTooltip: function () { if (!tooltipData.timeout) { tooltip.destroy(); } }, /** * Destroy tooltip instance */ destroy: function () { if (tooltipData.element) { tooltipData.element.remove(); tooltipData.showed = false; } positionData = {}; tooltipData.timeout = false; tooltip.removeHandlers(); }, /** * Remove tooltip handlers */ removeHandlers: function () { $('.' + defaults.closeButtonClass).off('click.closeButton'); tooltipData.trigger.off('mousemove.track'); document.removeEventListener('scroll', tooltip.destroy, true); $(window).off('scroll.tooltip'); $(window).off(CLICK_EVENT + '.outerClick'); $(window).off('keydown.tooltip'); $(window).off('resize.outerClick'); }, /** * Set target element * * @param {Object} event - current event */ setTargetData: function (event) { tooltipData.event = event; //TODO: bug chrome v.49; Link to issue https://bugs.chromium.org/p/chromium/issues/detail?id=161464 if (event.timeStamp - (tooltipData.timestamp || 0) < 1) { return; } if (event.type === 'mousemove') { tooltipData.targetElement = event.target; } else { tooltipData.targetElement = event.currentTarget; tooltipData.timestamp = event.timeStamp; } }, /** * Merged user config with defaults configuration * * @param {Object} config - user config * @returns {Object} merged config */ processingConfig: function (config) { return _.extend({}, defaults, config); } }; ko.bindingHandlers.tooltip = { /** * Initialize tooltip * * @param {Object} elem - tooltip DOM element * @param {Function} valueAccessor - ko observable property, tooltip data * @param {Object} allBindings - all bindings on current element * @param {Object} viewModel - current element viewModel * @param {Object} bindingCtx - current element binding context */ init: function (elem, valueAccessor, allBindings, viewModel, bindingCtx) { var config = tooltip.processingConfig(valueAccessor()), $parentScope = config.parentScope ? $(config.parentScope) : $(elem).parent(), tooltipId; $(elem).addClass('hidden'); if (isTouchDevice) { config.action = 'click'; } tooltipId = tooltip.setTooltip(config); if (config.action === 'hover') { $parentScope.on( 'mouseenter', config.trigger, tooltip.setContent.bind(null, elem, viewModel, tooltipId, bindingCtx) ); $parentScope.on( 'mouseleave', config.trigger, tooltip.checkPreviousTooltip.bind(null, tooltipId) ); } else if (config.action === 'click') { $parentScope.on( 'click', config.trigger, tooltip.toggleTooltip.bind(null, elem, viewModel, tooltipId, bindingCtx) ); } return { controlsDescendantBindings: true }; } }; renderer.addAttribute('tooltip'); }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('Magento_Ui/js/lib/knockout/extender/observable_array',[ 'ko', 'underscore' ], function (ko, _) { 'use strict'; /** * Iterator function. * * @param {String} callback * @param {Array} args * @param {Object} elem * @returns {*} */ function iterator(callback, args, elem) { callback = elem[callback]; if (_.isFunction(callback)) { return callback.apply(elem, args); } return callback; } /** * Wrapper function. * * @param {String} method * @returns {Function} */ function wrapper(method) { return function (iteratee) { var callback = iteratee, elems = this(), args = _.toArray(arguments); if (_.isString(iteratee)) { callback = iterator.bind(null, iteratee, args.slice(1)); args.unshift(callback); } args.unshift(elems); return _[method].apply(_, args); }; } _.extend(ko.observableArray.fn, { each: wrapper('each'), map: wrapper('map'), filter: wrapper('filter'), some: wrapper('some'), every: wrapper('every'), groupBy: wrapper('groupBy'), sortBy: wrapper('sortBy'), /** * Wrapper for underscore findWhere function. * * @param {Object} properties * @return {Object} */ findWhere: function (properties) { return _.findWhere(this(), properties); }, /** * Wrapper for underscore contains function. * * @param {*} value * @return {Boolean} */ contains: function (value) { return _.contains(this(), value); }, /** * Inverse contains call. * * @return {Boolean} */ hasNo: function () { return !this.contains.apply(this, arguments); }, /** * Getter for length property. * * @return {Number} */ getLength: function () { return this().length; }, /** * Create object with keys that gets from each object property. * * @return {Object} */ indexBy: function (key) { return _.indexBy(this(), key); }, /** * Returns a copy of the array with all instances of the values removed. * * @return {Array} */ without: function () { var args = Array.prototype.slice.call(arguments); args.unshift(this()); return _.without.apply(_, args); }, /** * Returns the first element of an array. * * @return {*} */ first: function () { return _.first(this()); }, /** * Returns the last element of an array * * @return {*} */ last: function () { return _.last(this()); }, /** * Iterate and pick provided properties. * * @return {Array} */ pluck: function () { var args = Array.prototype.slice.call(arguments); args.unshift(this()); return _.pluck.apply(_, args); } }); }); // REPEAT binding for Knockout http://knockoutjs.com/ // (c) Michael Best // License: MIT (http://www.opensource.org/licenses/mit-license.php) // Version 2.1.0 (function(factory) { if (typeof define === 'function' && define.amd) { // [1] AMD anonymous module define('knockoutjs/knockout-repeat',['knockout'], factory); } else if (typeof exports === 'object') { // [2] commonJS factory(require('knockout')); } else { // [3] No module loader (plain <script> tag) - put directly in global namespace factory(window.ko); } })(function(ko) { if (!ko.virtualElements) throw Error('Repeat requires at least Knockout 2.1'); var ko_bindingFlags = ko.bindingFlags || {}; var ko_unwrap = ko.utils.unwrapObservable; var koProtoName = '__ko_proto__'; if (ko.version >= "3.0.0") { // In Knockout 3.0.0, use the node preprocessor to replace a node with a repeat binding with a virtual element var provider = ko.bindingProvider.instance, previousPreprocessFn = provider.preprocessNode; provider.preprocessNode = function(node) { var newNodes, nodeBinding; if (!previousPreprocessFn || !(newNodes = previousPreprocessFn.call(this, node))) { if (node.nodeType === 1 && (nodeBinding = node.getAttribute('data-bind'))) { if (/^\s*repeat\s*:/.test(nodeBinding)) { var leadingComment = node.ownerDocument.createComment('ko ' + nodeBinding), trailingComment = node.ownerDocument.createComment('/ko'); node.parentNode.insertBefore(leadingComment, node); node.parentNode.insertBefore(trailingComment, node.nextSibling); node.removeAttribute('data-bind'); newNodes = [leadingComment, node, trailingComment]; } } } return newNodes; }; } ko.virtualElements.allowedBindings.repeat = true; ko.bindingHandlers.repeat = { flags: ko_bindingFlags.contentBind | ko_bindingFlags.canUseVirtual, init: function(element, valueAccessor, allBindingsAccessor, xxx, bindingContext) { // Read and set fixed options--these options cannot be changed var repeatParam = ko_unwrap(valueAccessor()); if (repeatParam && typeof repeatParam == 'object' && !('length' in repeatParam)) { var repeatIndex = repeatParam.index, repeatData = repeatParam.item, repeatStep = repeatParam.step, repeatReversed = repeatParam.reverse, repeatBind = repeatParam.bind, repeatInit = repeatParam.init, repeatUpdate = repeatParam.update; } // Set default values for options that need it repeatIndex = repeatIndex || '$index'; repeatData = repeatData || ko.bindingHandlers.repeat.itemName || '$item'; repeatStep = repeatStep || 1; repeatReversed = repeatReversed || false; var parent = element.parentNode, placeholder; if (element.nodeType == 8) { // virtual element // Extract the "children" and find the single element node var childNodes = ko.utils.arrayFilter(ko.virtualElements.childNodes(element), function(node) { return node.nodeType == 1;}); if (childNodes.length !== 1) { throw Error("Repeat binding requires a single element to repeat"); } ko.virtualElements.emptyNode(element); // The placeholder is the closing comment normally, or the opening comment if reversed placeholder = repeatReversed ? element : element.nextSibling; // The element to repeat is the contained element element = childNodes[0]; } else { // regular element // First clean the element node and remove node's binding var origBindString = element.getAttribute('data-bind'); ko.cleanNode(element); element.removeAttribute('data-bind'); // Original element is no longer needed: delete it and create a placeholder comment placeholder = element.ownerDocument.createComment('ko_repeatplaceholder ' + origBindString); parent.replaceChild(placeholder, element); } // extract and remove a data-repeat-bind attribute, if present if (!repeatBind) { repeatBind = element.getAttribute('data-repeat-bind'); if (repeatBind) { element.removeAttribute('data-repeat-bind'); } } // Make a copy of the element node to be copied for each repetition var cleanNode = element.cloneNode(true); if (typeof repeatBind == "string") { cleanNode.setAttribute('data-bind', repeatBind); repeatBind = null; } // Set up persistent data var lastRepeatCount = 0, notificationObservable = ko.observable(), repeatArray, arrayObservable; if (repeatInit) { repeatInit(parent); } var subscribable = ko.computed(function() { function makeArrayItemAccessor(index) { var f = function(newValue) { var item = repeatArray[index]; // Reading the value of the item if (!arguments.length) { notificationObservable(); // for dependency tracking return ko_unwrap(item); } // Writing a value to the item if (ko.isObservable(item)) { item(newValue); } else if (arrayObservable && arrayObservable.splice) { arrayObservable.splice(index, 1, newValue); } else { repeatArray[index] = newValue; } return this; }; // Pretend that our accessor function is an observable f[koProtoName] = ko.observable; return f; } function makeBinding(item, index, context) { return repeatArray ? function() { return repeatBind.call(bindingContext.$data, item, index, context); } : function() { return repeatBind.call(bindingContext.$data, index, context); } } // Read and set up variable options--these options can change and will update the binding var paramObservable = valueAccessor(), repeatParam = ko_unwrap(paramObservable), repeatCount = 0; if (repeatParam && typeof repeatParam == 'object') { if ('length' in repeatParam) { repeatArray = repeatParam; repeatCount = repeatArray.length; } else { if ('foreach' in repeatParam) { repeatArray = ko_unwrap(paramObservable = repeatParam.foreach); if (repeatArray && typeof repeatArray == 'object' && 'length' in repeatArray) { repeatCount = repeatArray.length || 0; } else { repeatCount = repeatArray || 0; repeatArray = null; } } // If a count value is provided (>0), always output that number of items if ('count' in repeatParam) repeatCount = ko_unwrap(repeatParam.count) || repeatCount; // If a limit is provided, don't output more than the limit if ('limit' in repeatParam) repeatCount = Math.min(repeatCount, ko_unwrap(repeatParam.limit)) || repeatCount; } arrayObservable = repeatArray && ko.isObservable(paramObservable) ? paramObservable : null; } else { repeatCount = repeatParam || 0; } // Remove nodes from end if array is shorter for (; lastRepeatCount > repeatCount; lastRepeatCount-=repeatStep) { ko.removeNode(repeatReversed ? placeholder.nextSibling : placeholder.previousSibling); } // Notify existing nodes of change notificationObservable.notifySubscribers(); // Add nodes to end if array is longer (also initially populates nodes) for (; lastRepeatCount < repeatCount; lastRepeatCount+=repeatStep) { // Clone node and add to document var newNode = cleanNode.cloneNode(true); parent.insertBefore(newNode, repeatReversed ? placeholder.nextSibling : placeholder); newNode.setAttribute('data-repeat-index', lastRepeatCount); // Apply bindings to inserted node if (repeatArray && repeatData == '$data') { var newContext = bindingContext.createChildContext(makeArrayItemAccessor(lastRepeatCount)); } else { var newContext = bindingContext.extend(); if (repeatArray) newContext[repeatData] = makeArrayItemAccessor(lastRepeatCount); } newContext[repeatIndex] = lastRepeatCount; if (repeatBind) { var result = ko.applyBindingsToNode(newNode, makeBinding(newContext[repeatData], lastRepeatCount, newContext), newContext, true), shouldBindDescendants = result && result.shouldBindDescendants; } if (!repeatBind || (result && shouldBindDescendants !== false)) { ko.applyBindings(newContext, newNode); } } if (repeatUpdate) { repeatUpdate(parent); } }, null, {disposeWhenNodeIsRemoved: placeholder}); return { controlsDescendantBindings: true, subscribable: subscribable }; } }; }); /*! Knockout Fast Foreach v0.4.1 (2015-07-17T14:06:15.974Z) By: Brian M Hunt (C) 2015 License: MIT Adds `fastForEach` to `ko.bindingHandlers`. */ (function (root, factory) { if (typeof define === 'function' && define.amd) { define('knockoutjs/knockout-fast-foreach',['knockout'], factory); } else if (typeof exports === 'object') { module.exports = factory(require('knockout')); } else { root.KnockoutFastForeach = factory(root.ko); } }(this, function (ko) { "use strict"; // index.js // -------- // Fast For Each // // Employing sound techniques to make a faster Knockout foreach binding. // -------- // Utilities // from https://github.com/jonschlinkert/is-plain-object function isPlainObject(o) { return !!o && typeof o === 'object' && o.constructor === Object; } // From knockout/src/virtualElements.js var commentNodesHaveTextProperty = document && document.createComment("test").text === "<!--test-->"; var startCommentRegex = commentNodesHaveTextProperty ? /^<!--\s*ko(?:\s+([\s\S]+))?\s*-->$/ : /^\s*ko(?:\s+([\s\S]+))?\s*$/; var supportsDocumentFragment = document && typeof document.createDocumentFragment === "function"; function isVirtualNode(node) { return (node.nodeType === 8) && startCommentRegex.test(commentNodesHaveTextProperty ? node.text : node.nodeValue); } // Get a copy of the (possibly virtual) child nodes of the given element, // put them into a container, then empty the given node. function makeTemplateNode(sourceNode) { var container = document.createElement("div"); var parentNode; if (sourceNode.content) { // For e.g. <template> tags parentNode = sourceNode.content; } else if (sourceNode.tagName === 'SCRIPT') { parentNode = document.createElement("div"); parentNode.innerHTML = sourceNode.text; } else { // Anything else e.g. <div> parentNode = sourceNode; } ko.utils.arrayForEach(ko.virtualElements.childNodes(parentNode), function (child) { // FIXME - This cloneNode could be expensive; we may prefer to iterate over the // parentNode children in reverse (so as not to foul the indexes as childNodes are // removed from parentNode when inserted into the container) if (child) { container.insertBefore(child.cloneNode(true), null); } }); return container; } function insertAllAfter(containerNode, nodeOrNodeArrayToInsert, insertAfterNode) { var frag, len, i; // poor man's node and array check, should be enough for this if (typeof nodeOrNodeArrayToInsert.nodeType !== "undefined" && typeof nodeOrNodeArrayToInsert.length === "undefined") { throw new Error("Expected a single node or a node array"); } if (typeof nodeOrNodeArrayToInsert.nodeType !== "undefined") { ko.virtualElements.insertAfter(containerNode, nodeOrNodeArrayToInsert, insertAfterNode); return; } if (nodeOrNodeArrayToInsert.length === 1) { ko.virtualElements.insertAfter(containerNode, nodeOrNodeArrayToInsert[0], insertAfterNode); return; } if (supportsDocumentFragment) { frag = document.createDocumentFragment(); for (i = 0, len = nodeOrNodeArrayToInsert.length; i !== len; ++i) { frag.appendChild(nodeOrNodeArrayToInsert[i]); } ko.virtualElements.insertAfter(containerNode, frag, insertAfterNode); } else { // Nodes are inserted in reverse order - pushed down immediately after // the last node for the previous item or as the first node of element. for (i = nodeOrNodeArrayToInsert.length - 1; i >= 0; --i) { var child = nodeOrNodeArrayToInsert[i]; if (!child) { return; } ko.virtualElements.insertAfter(containerNode, child, insertAfterNode); } } } // Mimic a KO change item 'add' function valueToChangeAddItem(value, index) { return { status: 'added', value: value, index: index }; } function isAdditionAdjacentToLast(changeIndex, arrayChanges) { return changeIndex > 0 && changeIndex < arrayChanges.length && arrayChanges[changeIndex].status === "added" && arrayChanges[changeIndex - 1].status === "added" && arrayChanges[changeIndex - 1].index === arrayChanges[changeIndex].index - 1; } function FastForEach(spec) { this.element = spec.element; this.container = isVirtualNode(this.element) ? this.element.parentNode : this.element; this.$context = spec.$context; this.data = spec.data; this.as = spec.as; this.noContext = spec.noContext; this.templateNode = makeTemplateNode( spec.name ? document.getElementById(spec.name).cloneNode(true) : spec.element ); this.afterQueueFlush = spec.afterQueueFlush; this.beforeQueueFlush = spec.beforeQueueFlush; this.changeQueue = []; this.lastNodesList = []; this.indexesToDelete = []; this.rendering_queued = false; // Remove existing content. ko.virtualElements.emptyNode(this.element); // Prime content var primeData = ko.unwrap(this.data); if (primeData.map) { this.onArrayChange(primeData.map(valueToChangeAddItem)); } // Watch for changes if (ko.isObservable(this.data)) { if (!this.data.indexOf) { // Make sure the observable is trackable. this.data = this.data.extend({trackArrayChanges: true}); } this.changeSubs = this.data.subscribe(this.onArrayChange, this, 'arrayChange'); } } FastForEach.animateFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.msRequestAnimationFrame || function(cb) { return window.setTimeout(cb, 1000 / 60); }; FastForEach.prototype.dispose = function () { if (this.changeSubs) { this.changeSubs.dispose(); } }; // If the array changes we register the change. FastForEach.prototype.onArrayChange = function (changeSet) { var self = this; var changeMap = { added: [], deleted: [] }; for (var i = 0, len = changeSet.length; i < len; i++) { // the change is appended to a last change info object when both are 'added' and have indexes next to each other // here I presume that ko is sending changes in monotonic order (in index variable) which happens to be true, tested with push and splice with multiple pushed values if (isAdditionAdjacentToLast(i, changeSet)) { var batchValues = changeMap.added[changeMap.added.length - 1].values; if (!batchValues) { // transform the last addition into a batch addition object var lastAddition = changeMap.added.pop(); var batchAddition = { isBatch: true, status: 'added', index: lastAddition.index, values: [lastAddition.value] }; batchValues = batchAddition.values; changeMap.added.push(batchAddition); } batchValues.push(changeSet[i].value); } else { changeMap[changeSet[i].status].push(changeSet[i]); } } if (changeMap.deleted.length > 0) { this.changeQueue.push.apply(this.changeQueue, changeMap.deleted); this.changeQueue.push({status: 'clearDeletedIndexes'}); } this.changeQueue.push.apply(this.changeQueue, changeMap.added); // Once a change is registered, the ticking count-down starts for the processQueue. if (this.changeQueue.length > 0 && !this.rendering_queued) { this.rendering_queued = true; FastForEach.animateFrame.call(window, function () { self.processQueue(); }); } }; // Reflect all the changes in the queue in the DOM, then wipe the queue. FastForEach.prototype.processQueue = function () { var self = this; // Callback so folks can do things before the queue flush. if (typeof this.beforeQueueFlush === 'function') { this.beforeQueueFlush(this.changeQueue); } ko.utils.arrayForEach(this.changeQueue, function (changeItem) { // console.log(self.data(), "CI", JSON.stringify(changeItem, null, 2), JSON.stringify($(self.element).text())) self[changeItem.status](changeItem); // console.log(" ==> ", JSON.stringify($(self.element).text())) }); this.rendering_queued = false; // Callback so folks can do things. if (typeof this.afterQueueFlush === 'function') { this.afterQueueFlush(this.changeQueue); } this.changeQueue = []; }; // Process a changeItem with {status: 'added', ...} FastForEach.prototype.added = function (changeItem) { var index = changeItem.index; var valuesToAdd = changeItem.isBatch ? changeItem.values : [changeItem.value]; var referenceElement = this.lastNodesList[index - 1] || null; // gather all childnodes for a possible batch insertion var allChildNodes = []; for (var i = 0, len = valuesToAdd.length; i < len; ++i) { var templateClone = this.templateNode.cloneNode(true); var childContext; if (this.noContext) { childContext = this.$context.extend({ '$item': valuesToAdd[i] }); } else { childContext = this.$context.createChildContext(valuesToAdd[i], this.as || null); } // apply bindings first, and then process child nodes, because bindings can add childnodes ko.applyBindingsToDescendants(childContext, templateClone); var childNodes = ko.virtualElements.childNodes(templateClone); // Note discussion at https://github.com/angular/angular.js/issues/7851 allChildNodes.push.apply(allChildNodes, Array.prototype.slice.call(childNodes)); this.lastNodesList.splice(index + i, 0, childNodes[childNodes.length - 1]); } insertAllAfter(this.element, allChildNodes, referenceElement); }; // Process a changeItem with {status: 'deleted', ...} FastForEach.prototype.deleted = function (changeItem) { var index = changeItem.index; var ptr = this.lastNodesList[index], // We use this.element because that will be the last previous node // for virtual element lists. lastNode = this.lastNodesList[index - 1] || this.element; do { ptr = ptr.previousSibling; ko.removeNode((ptr && ptr.nextSibling) || ko.virtualElements.firstChild(this.element)); } while (ptr && ptr !== lastNode); // The "last node" in the DOM from which we begin our delets of the next adjacent node is // now the sibling that preceded the first node of this item. this.lastNodesList[index] = this.lastNodesList[index - 1]; this.indexesToDelete.push(index); }; // We batch our deletion of item indexes in our parallel array. // See brianmhunt/knockout-fast-foreach#6/#8 FastForEach.prototype.clearDeletedIndexes = function () { // We iterate in reverse on the presumption (following the unit tests) that KO's diff engine // processes diffs (esp. deletes) monotonically ascending i.e. from index 0 -> N. for (var i = this.indexesToDelete.length - 1; i >= 0; --i) { this.lastNodesList.splice(this.indexesToDelete[i], 1); } this.indexesToDelete = []; }; ko.bindingHandlers.fastForEach = { // Valid valueAccessors: // [] // ko.observable([]) // ko.observableArray([]) // ko.computed // {data: array, name: string, as: string} init: function init(element, valueAccessor, bindings, vm, context) { var value = valueAccessor(), ffe; if (isPlainObject(value)) { value.element = value.element || element; value.$context = context; ffe = new FastForEach(value); } else { ffe = new FastForEach({ element: element, data: ko.unwrap(context.$rawData) === value ? context.$rawData : value, $context: context }); } ko.utils.domNodeDisposal.addDisposeCallback(element, function () { ffe.dispose(); }); return {controlsDescendantBindings: true}; }, // Export for testing, debugging, and overloading. FastForEach: FastForEach }; ko.virtualElements.allowedBindings.fastForEach = true; })); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('Magento_Ui/js/lib/knockout/bindings/bootstrap',['require','../template/renderer','./i18n','./scope','./range','./mage-init','./keyboard','./optgroup','./after-render','./autoselect','./outer_click','./fadeVisible','./collapsible','./staticChecked','./simple-checked','./bind-html','./tooltip','knockoutjs/knockout-repeat','knockoutjs/knockout-fast-foreach'],function (require) { 'use strict'; var renderer = require('../template/renderer'); renderer.addAttribute('repeat', renderer.handlers.wrapAttribute); renderer.addAttribute('outerfasteach', { binding: 'fastForEach', handler: renderer.handlers.wrapAttribute }); renderer .addNode('repeat') .addNode('fastForEach'); return { i18n: require('./i18n'), scope: require('./scope'), range: require('./range'), mageInit: require('./mage-init'), keyboard: require('./keyboard'), optgroup: require('./optgroup'), afterRender: require('./after-render'), autoselect: require('./autoselect'), outerClick: require('./outer_click'), fadeVisible: require('./fadeVisible'), collapsible: require('./collapsible'), staticChecked: require('./staticChecked'), simpleChecked: require('./simple-checked'), bindHtml: require('./bind-html'), tooltip: require('./tooltip'), repeat: require('knockoutjs/knockout-repeat'), fastForEach: require('knockoutjs/knockout-fast-foreach') }; }); /*! * Knockout ES5 plugin - https://github.com/SteveSanderson/knockout-es5 * Copyright (c) Steve Sanderson * MIT license */ (function(global, undefined) { 'use strict'; var ko; // Model tracking // -------------- // // This is the central feature of Knockout-ES5. We augment model objects by converting properties // into ES5 getter/setter pairs that read/write an underlying Knockout observable. This means you can // use plain JavaScript syntax to read/write the property while still getting the full benefits of // Knockout's automatic dependency detection and notification triggering. // // For comparison, here's Knockout ES3-compatible syntax: // // var firstNameLength = myModel.user().firstName().length; // Read // myModel.user().firstName('Bert'); // Write // // ... versus Knockout-ES5 syntax: // // var firstNameLength = myModel.user.firstName.length; // Read // myModel.user.firstName = 'Bert'; // Write // `ko.track(model)` converts each property on the given model object into a getter/setter pair that // wraps a Knockout observable. Optionally specify an array of property names to wrap; otherwise we // wrap all properties. If any of the properties are already observables, we replace them with // ES5 getter/setter pairs that wrap your original observable instances. In the case of readonly // ko.computed properties, we simply do not define a setter (so attempted writes will be ignored, // which is how ES5 readonly properties normally behave). // // By design, this does *not* recursively walk child object properties, because making literally // everything everywhere independently observable is usually unhelpful. When you do want to track // child object properties independently, define your own class for those child objects and put // a separate ko.track call into its constructor --- this gives you far more control. /** * @param {object} obj * @param {object|array.<string>} propertyNamesOrSettings * @param {boolean} propertyNamesOrSettings.deep Use deep track. * @param {array.<string>} propertyNamesOrSettings.fields Array of property names to wrap. * todo: @param {array.<string>} propertyNamesOrSettings.exclude Array of exclude property names to wrap. * todo: @param {function(string, *):boolean} propertyNamesOrSettings.filter Function to filter property * names to wrap. A function that takes ... params * @return {object} */ function track(obj, propertyNamesOrSettings) { if (!obj || typeof obj !== 'object') { throw new Error('When calling ko.track, you must pass an object as the first parameter.'); } var propertyNames; if ( isPlainObject(propertyNamesOrSettings) ) { // defaults propertyNamesOrSettings.deep = propertyNamesOrSettings.deep || false; propertyNamesOrSettings.fields = propertyNamesOrSettings.fields || Object.getOwnPropertyNames(obj); propertyNamesOrSettings.lazy = propertyNamesOrSettings.lazy || false; wrap(obj, propertyNamesOrSettings.fields, propertyNamesOrSettings); } else { propertyNames = propertyNamesOrSettings || Object.getOwnPropertyNames(obj); wrap(obj, propertyNames, {}); } return obj; } // fix for ie var rFunctionName = /^function\s*([^\s(]+)/; function getFunctionName( ctor ){ if (ctor.name) { return ctor.name; } return (ctor.toString().trim().match( rFunctionName ) || [])[1]; } function canTrack(obj) { return obj && typeof obj === 'object' && getFunctionName(obj.constructor) === 'Object'; } function createPropertyDescriptor(originalValue, prop, map) { var isObservable = ko.isObservable(originalValue); var isArray = !isObservable && Array.isArray(originalValue); var observable = isObservable ? originalValue : isArray ? ko.observableArray(originalValue) : ko.observable(originalValue); map[prop] = function () { return observable; }; // add check in case the object is already an observable array if (isArray || (isObservable && 'push' in observable)) { notifyWhenPresentOrFutureArrayValuesMutate(ko, observable); } return { configurable: true, enumerable: true, get: observable, set: ko.isWriteableObservable(observable) ? observable : undefined }; } function createLazyPropertyDescriptor(originalValue, prop, map) { if (ko.isObservable(originalValue)) { // no need to be lazy if we already have an observable return createPropertyDescriptor(originalValue, prop, map); } var observable; function getOrCreateObservable(value, writing) { if (observable) { return writing ? observable(value) : observable; } if (Array.isArray(value)) { observable = ko.observableArray(value); notifyWhenPresentOrFutureArrayValuesMutate(ko, observable); return observable; } return (observable = ko.observable(value)); } map[prop] = function () { return getOrCreateObservable(originalValue); }; return { configurable: true, enumerable: true, get: function () { return getOrCreateObservable(originalValue)(); }, set: function (value) { getOrCreateObservable(value, true); } }; } function wrap(obj, props, options) { if (!props.length) { return; } var allObservablesForObject = getAllObservablesForObject(obj, true); var descriptors = {}; props.forEach(function (prop) { // Skip properties that are already tracked if (prop in allObservablesForObject) { return; } // Skip properties where descriptor can't be redefined if (Object.getOwnPropertyDescriptor(obj, prop).configurable === false){ return; } var originalValue = obj[prop]; descriptors[prop] = (options.lazy ? createLazyPropertyDescriptor : createPropertyDescriptor) (originalValue, prop, allObservablesForObject); if (options.deep && canTrack(originalValue)) { wrap(originalValue, Object.keys(originalValue), options); } }); Object.defineProperties(obj, descriptors); } function isPlainObject( obj ){ return !!obj && typeof obj === 'object' && obj.constructor === Object; } // Lazily created by `getAllObservablesForObject` below. Has to be created lazily because the // WeakMap factory isn't available until the module has finished loading (may be async). var objectToObservableMap; // Gets or creates the hidden internal key-value collection of observables corresponding to // properties on the model object. function getAllObservablesForObject(obj, createIfNotDefined) { if (!objectToObservableMap) { objectToObservableMap = weakMapFactory(); } var result = objectToObservableMap.get(obj); if (!result && createIfNotDefined) { result = {}; objectToObservableMap.set(obj, result); } return result; } // Removes the internal references to observables mapped to the specified properties // or the entire object reference if no properties are passed in. This allows the // observables to be replaced and tracked again. function untrack(obj, propertyNames) { if (!objectToObservableMap) { return; } if (arguments.length === 1) { objectToObservableMap['delete'](obj); } else { var allObservablesForObject = getAllObservablesForObject(obj, false); if (allObservablesForObject) { propertyNames.forEach(function(propertyName) { delete allObservablesForObject[propertyName]; }); } } } // Computed properties // ------------------- // // The preceding code is already sufficient to upgrade ko.computed model properties to ES5 // getter/setter pairs (or in the case of readonly ko.computed properties, just a getter). // These then behave like a regular property with a getter function, except they are smarter: // your evaluator is only invoked when one of its dependencies changes. The result is cached // and used for all evaluations until the next time a dependency changes). // // However, instead of forcing developers to declare a ko.computed property explicitly, it's // nice to offer a utility function that declares a computed getter directly. // Implements `ko.defineProperty` function defineComputedProperty(obj, propertyName, evaluatorOrOptions) { var ko = this, computedOptions = { owner: obj, deferEvaluation: true }; if (typeof evaluatorOrOptions === 'function') { computedOptions.read = evaluatorOrOptions; } else { if ('value' in evaluatorOrOptions) { throw new Error('For ko.defineProperty, you must not specify a "value" for the property. ' + 'You must provide a "get" function.'); } if (typeof evaluatorOrOptions.get !== 'function') { throw new Error('For ko.defineProperty, the third parameter must be either an evaluator function, ' + 'or an options object containing a function called "get".'); } computedOptions.read = evaluatorOrOptions.get; computedOptions.write = evaluatorOrOptions.set; } obj[propertyName] = ko.computed(computedOptions); track.call(ko, obj, [propertyName]); return obj; } // Array handling // -------------- // // Arrays are special, because unlike other property types, they have standard mutator functions // (`push`/`pop`/`splice`/etc.) and it's desirable to trigger a change notification whenever one of // those mutator functions is invoked. // // Traditionally, Knockout handles this by putting special versions of `push`/`pop`/etc. on observable // arrays that mutate the underlying array and then trigger a notification. That approach doesn't // work for Knockout-ES5 because properties now return the underlying arrays, so the mutator runs // in the context of the underlying array, not any particular observable: // // // Operates on the underlying array value // myModel.someCollection.push('New value'); // // To solve this, Knockout-ES5 detects array values, and modifies them as follows: // 1. Associates a hidden subscribable with each array instance that it encounters // 2. Intercepts standard mutators (`push`/`pop`/etc.) and makes them trigger the subscribable // Then, for model properties whose values are arrays, the property's underlying observable // subscribes to the array subscribable, so it can trigger a change notification after mutation. // Given an observable that underlies a model property, watch for any array value that might // be assigned as the property value, and hook into its change events function notifyWhenPresentOrFutureArrayValuesMutate(ko, observable) { var watchingArraySubscription = null; ko.computed(function () { // Unsubscribe to any earlier array instance if (watchingArraySubscription) { watchingArraySubscription.dispose(); watchingArraySubscription = null; } // Subscribe to the new array instance var newArrayInstance = observable(); if (newArrayInstance instanceof Array) { watchingArraySubscription = startWatchingArrayInstance(ko, observable, newArrayInstance); } }); } // Listens for array mutations, and when they happen, cause the observable to fire notifications. // This is used to make model properties of type array fire notifications when the array changes. // Returns a subscribable that can later be disposed. function startWatchingArrayInstance(ko, observable, arrayInstance) { var subscribable = getSubscribableForArray(ko, arrayInstance); return subscribable.subscribe(observable); } // Lazily created by `getSubscribableForArray` below. Has to be created lazily because the // WeakMap factory isn't available until the module has finished loading (may be async). var arraySubscribablesMap; // Gets or creates a subscribable that fires after each array mutation function getSubscribableForArray(ko, arrayInstance) { if (!arraySubscribablesMap) { arraySubscribablesMap = weakMapFactory(); } var subscribable = arraySubscribablesMap.get(arrayInstance); if (!subscribable) { subscribable = new ko.subscribable(); arraySubscribablesMap.set(arrayInstance, subscribable); var notificationPauseSignal = {}; wrapStandardArrayMutators(arrayInstance, subscribable, notificationPauseSignal); addKnockoutArrayMutators(ko, arrayInstance, subscribable, notificationPauseSignal); } return subscribable; } // After each array mutation, fires a notification on the given subscribable function wrapStandardArrayMutators(arrayInstance, subscribable, notificationPauseSignal) { ['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'].forEach(function(fnName) { var origMutator = arrayInstance[fnName]; arrayInstance[fnName] = function() { var result = origMutator.apply(this, arguments); if (notificationPauseSignal.pause !== true) { subscribable.notifySubscribers(this); } return result; }; }); } // Adds Knockout's additional array mutation functions to the array function addKnockoutArrayMutators(ko, arrayInstance, subscribable, notificationPauseSignal) { ['remove', 'removeAll', 'destroy', 'destroyAll', 'replace'].forEach(function(fnName) { // Make it a non-enumerable property for consistency with standard Array functions Object.defineProperty(arrayInstance, fnName, { enumerable: false, value: function() { var result; // These additional array mutators are built using the underlying push/pop/etc. // mutators, which are wrapped to trigger notifications. But we don't want to // trigger multiple notifications, so pause the push/pop/etc. wrappers and // delivery only one notification at the end of the process. notificationPauseSignal.pause = true; try { // Creates a temporary observableArray that can perform the operation. result = ko.observableArray.fn[fnName].apply(ko.observableArray(arrayInstance), arguments); } finally { notificationPauseSignal.pause = false; } subscribable.notifySubscribers(arrayInstance); return result; } }); }); } // Static utility functions // ------------------------ // // Since Knockout-ES5 sets up properties that return values, not observables, you can't // trivially subscribe to the underlying observables (e.g., `someProperty.subscribe(...)`), // or tell them that object values have mutated, etc. To handle this, we set up some // extra utility functions that can return or work with the underlying observables. // Returns the underlying observable associated with a model property (or `null` if the // model or property doesn't exist, or isn't associated with an observable). This means // you can subscribe to the property, e.g.: // // ko.getObservable(model, 'propertyName') // .subscribe(function(newValue) { ... }); function getObservable(obj, propertyName) { if (!obj || typeof obj !== 'object') { return null; } var allObservablesForObject = getAllObservablesForObject(obj, false); if (allObservablesForObject && propertyName in allObservablesForObject) { return allObservablesForObject[propertyName](); } return null; } // Returns a boolean indicating whether the property on the object has an underlying // observables. This does the check in a way not to create an observable if the // object was created with lazily created observables function isTracked(obj, propertyName) { if (!obj || typeof obj !== 'object') { return false; } var allObservablesForObject = getAllObservablesForObject(obj, false); return !!allObservablesForObject && propertyName in allObservablesForObject; } // Causes a property's associated observable to fire a change notification. Useful when // the property value is a complex object and you've modified a child property. function valueHasMutated(obj, propertyName) { var observable = getObservable(obj, propertyName); if (observable) { observable.valueHasMutated(); } } // Module initialisation // --------------------- // // When this script is first evaluated, it works out what kind of module loading scenario // it is in (Node.js or a browser `<script>` tag), stashes a reference to its dependencies // (currently that's just the WeakMap shim), and then finally attaches itself to whichever // instance of Knockout.js it can find. // A function that returns a new ES6-compatible WeakMap instance (using ES5 shim if needed). // Instantiated by prepareExports, accounting for which module loader is being used. var weakMapFactory; // Extends a Knockout instance with Knockout-ES5 functionality function attachToKo(ko) { ko.track = track; ko.untrack = untrack; ko.getObservable = getObservable; ko.valueHasMutated = valueHasMutated; ko.defineProperty = defineComputedProperty; // todo: test it, maybe added it to ko. directly ko.es5 = { getAllObservablesForObject: getAllObservablesForObject, notifyWhenPresentOrFutureArrayValuesMutate: notifyWhenPresentOrFutureArrayValuesMutate, isTracked: isTracked }; } // Determines which module loading scenario we're in, grabs dependencies, and attaches to KO function prepareExports() { if (typeof exports === 'object' && typeof module === 'object') { // Node.js case - load KO and WeakMap modules synchronously ko = require('knockout'); var WM = require('../lib/weakmap'); attachToKo(ko); weakMapFactory = function() { return new WM(); }; module.exports = ko; } else if (typeof define === 'function' && define.amd) { define('knockoutjs/knockout-es5',['knockout'], function(koModule) { ko = koModule; attachToKo(koModule); weakMapFactory = function() { return new global.WeakMap(); }; return koModule; }); } else if ('ko' in global) { // Non-module case - attach to the global instance, and assume a global WeakMap constructor ko = global.ko; attachToKo(global.ko); weakMapFactory = function() { return new global.WeakMap(); }; } } prepareExports(); })(this); /** * @license RequireJS domReady 2.0.1 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/requirejs/domReady for details */ /*jslint */ /*global require: false, define: false, requirejs: false, window: false, clearInterval: false, document: false, self: false, setInterval: false */ define('domReady',[],function () { 'use strict'; var isTop, testDiv, scrollIntervalId, isBrowser = typeof window !== "undefined" && window.document, isPageLoaded = !isBrowser, doc = isBrowser ? document : null, readyCalls = []; function runCallbacks(callbacks) { var i; for (i = 0; i < callbacks.length; i += 1) { callbacks[i](doc); } } function callReady() { var callbacks = readyCalls; if (isPageLoaded) { //Call the DOM ready callbacks if (callbacks.length) { readyCalls = []; runCallbacks(callbacks); } } } /** * Sets the page as loaded. */ function pageLoaded() { if (!isPageLoaded) { isPageLoaded = true; if (scrollIntervalId) { clearInterval(scrollIntervalId); } callReady(); } } if (isBrowser) { if (document.addEventListener) { //Standards. Hooray! Assumption here that if standards based, //it knows about DOMContentLoaded. document.addEventListener("DOMContentLoaded", pageLoaded, false); window.addEventListener("load", pageLoaded, false); } else if (window.attachEvent) { window.attachEvent("onload", pageLoaded); testDiv = document.createElement('div'); try { isTop = window.frameElement === null; } catch (e) {} //DOMContentLoaded approximation that uses a doScroll, as found by //Diego Perini: http://javascript.nwbox.com/IEContentLoaded/, //but modified by other contributors, including jdalton if (testDiv.doScroll && isTop && window.external) { scrollIntervalId = setInterval(function () { try { testDiv.doScroll(); pageLoaded(); } catch (e) {} }, 30); } } //Check if document is no longer loading, and if so, just trigger page load //listeners. Latest webkit browsers also use "interactive", and //will fire the onDOMContentLoaded before "interactive" but not after //entering "interactive" or "complete". More details: //http://dev.w3.org/html5/spec/the-end.html#the-end //http://stackoverflow.com/questions/3665561/document-readystate-of-interactive-vs-ondomcontentloaded //Hmm, this is more complicated on further use, see "firing too early" //bug: https://github.com/requirejs/domReady/issues/1 //so removing the || document.readyState === "interactive" test. //There is still a window.onload binding that should get fired if //DOMContentLoaded is missed. if (document.readyState !== "loading") { // Handle it asynchronously to allow scripts the opportunity to delay ready setTimeout(pageLoaded); } } /** START OF PUBLIC API **/ /** * Registers a callback for DOM ready. If DOM is already ready, the * callback is called immediately. * @param {Function} callback */ function domReady(callback) { if (isPageLoaded) { callback(doc); } else { readyCalls.push(callback); } return domReady; } domReady.version = '2.0.1'; /** * Loader Plugin API method */ domReady.load = function (name, req, onLoad, config) { if (config.isBuild) { onLoad(null); } else { domReady(onLoad); } }; /** END OF PUBLIC API **/ return domReady; }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /** Loads all available knockout bindings, sets custom template engine, initializes knockout on page */ define('Magento_Ui/js/lib/knockout/bootstrap',[ 'ko', './template/engine', 'knockoutjs/knockout-es5', './bindings/bootstrap', './extender/observable_array', './extender/bound-nodes', 'domReady!' ], function (ko, templateEngine) { 'use strict'; ko.uid = 0; ko.setTemplateEngine(templateEngine); try { ko.applyBindings(); }catch(e) { (console.error || console.log)(e); window.dataLayer && window.dataLayer.push({ 'event': 'Knockout error', 'error': { 'url': window.location.href, 'message': e.message, 'stack': e.stack } }); } }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('Magento_Ui/js/core/renderer/types',[ 'underscore', 'mageUtils' ], function (_, utils) { 'use strict'; var store = {}; /** * Flatten a nested data. * * @param {Object} data * @returns {Object} */ function flatten(data) { var extender = data.extends || [], result = {}; extender = utils.stringToArray(extender); extender.push(data); extender.forEach(function (item) { if (_.isString(item)) { item = store[item] || {}; } utils.extend(result, item); }); delete result.extends; return result; } return { /** * Set types to store object. * * @param {Object} types */ set: function (types) { types = types || {}; utils.extend(store, types); _.each(types, function (data, type) { store[type] = flatten(data); }); }, /** * Get type from store object. * * @param {String} type * @returns {*|{}} */ get: function (type) { return store[type] || {}; } }; }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('Magento_Ui/js/core/renderer/layout',[ 'underscore', 'jquery', 'mageUtils', 'uiRegistry', './types', '../../lib/logger/console-logger' ], function (_, $, utils, registry, types, consoleLogger) { 'use strict'; var templates = registry.create(), layout = {}, cachedConfig = {}; /** * Build name from parent name and node name * * @param {Object} parent * @param {Object} node * @param {String} [name] * @returns {String} */ function getNodeName(parent, node, name) { var parentName = parent && parent.name; if (typeof name !== 'string') { name = node.name || name; } return utils.fullPath(parentName, name); } /** * Get node type from node or parent. * * @param {Object} parent * @param {Object} node * @returns {String} */ function getNodeType(parent, node) { return node.type || parent && parent.childType; } /** * Get data scope based on parent data scope and node data scope. * * @param {Object} parent * @param {Object} node * @returns {String} */ function getDataScope(parent, node) { var dataScope = node.dataScope, parentScope = parent && parent.dataScope; return !utils.isEmpty(parentScope) ? !utils.isEmpty(dataScope) ? parentScope + '.' + dataScope : parentScope : dataScope || ''; } /** * Load node dependencies on other instances. * * @param {Object} node * @returns {jQueryPromise} */ function loadDeps(node) { var loaded = $.Deferred(), loggerUtils = consoleLogger.utils; if (node.deps) { consoleLogger.utils.asyncLog( loaded, { data: { component: node.name, deps: node.deps }, messages: loggerUtils.createMessages( 'depsStartRequesting', 'depsFinishRequesting', 'depsLoadingFail' ) } ); } registry.get(node.deps, function (deps) { node.provider = node.extendProvider ? deps && deps.name : node.provider; loaded.resolve(node); }); return loaded.promise(); } /** * Load node component file via requirejs. * * @param {Object} node * @returns {jQueryPromise} */ function loadSource(node) { var loaded = $.Deferred(), source = node.component; consoleLogger.info('componentStartLoading', { component: node.component }); require([source], function (constr) { consoleLogger.info('componentFinishLoading', { component: node.component }); loaded.resolve(node, constr); }, function () { consoleLogger.error('componentLoadingFail', { component: node.component }); }); return loaded.promise(); } /** * Create a new component instance and set it to the registry. * * @param {Object} node * @param {Function} Constr */ function initComponent(node, Constr) { var component = new Constr(_.omit(node, 'children')); consoleLogger.info('componentStartInitialization', { component: node.component, componentName: node.name }); registry.set(node.name, component); } /** * Application entry point. * * @param {Object} nodes * @param {Object} parent * @param {Boolean} cached * @param {Boolean} merge * @returns {Boolean|undefined} */ function run(nodes, parent, cached, merge) { if (_.isBoolean(merge) && merge) { layout.merge(nodes); return false; } if (cached) { cachedConfig[_.keys(nodes)[0]] = JSON.parse(JSON.stringify(nodes)); } _.each(nodes || [], layout.iterator.bind(layout, parent)); } _.extend(layout, { /** * Determines if node ready to be added or process it. * * @param {Object} parent * @param {Object|String} node */ iterator: function (parent, node) { var action = _.isString(node) ? this.addChild : this.process; action.apply(this, arguments); }, /** * Prepare component. * * @param {Object} parent * @param {Object} node * @param {String} name * @returns {Object} */ process: function (parent, node, name) { if (!parent && node.parent) { return this.waitParent(node, name); } if (node.nodeTemplate) { return this.waitTemplate.apply(this, arguments); } node = this.build.apply(this, arguments); if (!registry.has(node.name)) { this.addChild(parent, node) .manipulate(node) .initComponent(node); } if (node) { run(node.children, node); } return this; }, /** * Detailed processing of component config. * * @param {Object} parent * @param {Object} node * @param {String} name * @returns {Boolean|Object} */ build: function (parent, node, name) { var defaults = parent && parent.childDefaults || {}, children = this.filterDisabledChildren(node.children), type = getNodeType(parent, node), dataScope = getDataScope(parent, node), component, extendDeps = true, nodeName; node.children = false; node.extendProvider = true; if (node.config && node.config.provider || node.provider) { node.extendProvider = false; } if (node.config && node.config.deps || node.deps) { extendDeps = false; } node = utils.extend({ }, types.get(type), defaults, node); nodeName = getNodeName(parent, node, name); if (registry.has(nodeName)) { component = registry.get(nodeName); component.children = children; return component; } if (extendDeps && parent && parent.deps && type) { node.deps = parent.deps; } _.extend(node, node.config || {}, { index: node.name || name, name: nodeName, dataScope: dataScope, parentName: utils.getPart(nodeName, -2), parentScope: utils.getPart(dataScope, -2) }); node.children = children; node.componentType = node.type; delete node.type; delete node.config; if (children) { node.initChildCount = _.size(children); } if (node.isTemplate) { node.isTemplate = false; templates.set(node.name, node); registry.get(node.parentName, function (parentComp) { parentComp.childTemplate = node; }); return false; } if (node.componentDisabled === true) { return false; } return node; }, /** * Filter out all disabled components. * * @param {Object} children * @returns {*} */ filterDisabledChildren: function (children) { var cIds; //cleanup children config.componentDisabled = true if (children && typeof children === 'object') { cIds = Object.keys(children); if (cIds) { _.each(cIds, function (cId) { if (typeof children[cId] === 'object' && children[cId].hasOwnProperty('config') && typeof children[cId].config === 'object' && children[cId].config.hasOwnProperty('componentDisabled') && children[cId].config.componentDisabled === true) { delete children[cId]; } }); } } return children; }, /** * Init component. * * @param {Object} node * @returns {Object} */ initComponent: function (node) { if (!node.component) { return this; } loadDeps(node) .then(loadSource) .done(initComponent); return this; } }); _.extend(layout, { /** * Loading component marked as isTemplate. * * @param {Object} parent * @param {Object} node * @returns {Object} */ waitTemplate: function (parent, node) { var args = _.toArray(arguments); templates.get(node.nodeTemplate, function () { this.applyTemplate.apply(this, args); }.bind(this)); return this; }, /** * Waiting for parent component and process provided component. * * @param {Object} node * @param {String} name * @returns {Object} */ waitParent: function (node, name) { var process = this.process.bind(this); registry.get(node.parent, function (parent) { process(parent, node, name); }); return this; }, /** * Processing component marked as isTemplate. * * @param {Object} parent * @param {Object} node * @param {String} name */ applyTemplate: function (parent, node, name) { var template = templates.get(node.nodeTemplate); node = utils.extend({}, template, node); delete node.nodeTemplate; this.process(parent, node, name); } }); _.extend(layout, { /** * Determines inserting strategy. * * @param {Object} node * @returns {Object} */ manipulate: function (node) { var name = node.name; if (node.appendTo) { this.insert(name, node.appendTo, -1); } if (node.prependTo) { this.insert(name, node.prependTo, 0); } if (node.insertTo) { this.insertTo(name, node.insertTo); } return this; }, /** * Insert component to provide target and position. * * @param {Object|String} item * @param {Object} target * @param {Number} position * @returns {Object} */ insert: function (item, target, position) { registry.get(target, function (container) { container.insertChild(item, position); }); return this; }, /** * Insert component into multiple targets. * * @param {Object} item * @param {Array} targets * @returns {Object} */ insertTo: function (item, targets) { _.each(targets, function (info, target) { this.insert(item, target, info.position); }, this); return this; }, /** * Add provided child to parent. * * @param {Object} parent * @param {Object|String} child * @returns {Object} */ addChild: function (parent, child) { var name; if (parent && parent.component) { name = child.name || child; this.insert(name, parent.name, child.sortOrder); } return this; }, /** * Merge components configuration with cached configuration. * * @param {Array} components */ merge: function (components) { var cachedKey = _.keys(components)[0], compared = utils.compare(cachedConfig[cachedKey], components), remove = this.filterComponents(this.getByProperty(compared.changes, 'type', 'remove'), true), update = this.getByProperty(compared.changes, 'type', 'update'), dataSources = this.getDataSources(components), names, index, name, component; _.each(dataSources, function (val, key) { name = key.replace(/\.children|\.config/g, ''); component = registry.get(name); component.cacheData(); component.updateConfig( true, this.getFullConfig(key, components), this.getFullConfig(key, cachedConfig[cachedKey]) ); }, this); _.each(remove, function (val) { component = registry.get(val.path); if (component) { component.destroy(); } }); update = _.compact(_.filter(update, function (val) { return !_.isEqual(val.oldValue, val.value); })); _.each(update, function (val) { names = val.path.split('.'); index = Math.max(_.lastIndexOf(names, 'config'), _.lastIndexOf(names, 'children') + 2); name = _.without(names.splice(0, index), 'children', 'config').join('.'); component = registry.get(name); if (val.name === 'sortOrder' && component) { registry.get(component.parentName).insertChild(component, val.value); } else if (component) { component.updateConfig( val.oldValue, val.value, val.path ); } }, this); run(components, undefined, true); }, /** * Recursive dataSource assignment. * * @param {Object} config * @param {String} parentPath * @returns {Object} */ getDataSources: function (config, parentPath) { var dataSources = {}, key, obj; /* eslint-disable no-loop-func, max-depth */ for (key in config) { if (config.hasOwnProperty(key)) { if ( key === 'type' && config[key] === 'dataSource' && config.hasOwnProperty('config') ) { dataSources[parentPath + '.config'] = config.config; } else if (_.isObject(config[key])) { obj = this.getDataSources(config[key], utils.fullPath(parentPath, key)); _.each(obj, function (value, path) { dataSources[path] = value; }); } } } /* eslint-enable no-loop-func, max-depth */ return dataSources; }, /** * Configuration getter. * * @param {String} path * @param {Object} config * @returns {Boolean|Object} */ getFullConfig: function (path, config) { var index; path = path.split('.'); index = _.lastIndexOf(path, 'config'); if (!~index) { return false; } path = path.splice(0, index); _.each(path, function (val) { config = config[val]; }); return config.config; }, /** * Filter data by property and value. * * @param {Object} data * @param {String} prop * @param {*} propValue */ getByProperty: function (data, prop, propValue) { return _.filter(data, function (value) { return value[prop] === propValue; }); }, /** * Filter components. * * @param {Array} data * @param {Boolean} splitPath * @param {Number} index * @param {String} separator * @param {String} keyName * @returns {Array} */ filterComponents: function (data, splitPath, index, separator, keyName) { var result = [], names, length; index = -2; separator = '.' || separator; keyName = 'children' || keyName; _.each(data, function (val) { names = val.path.split(separator); length = names.length; if (names[length + index] === keyName) { val.path = splitPath ? _.without(names, keyName).join(separator) : val.path; result.push(val); } }); return result; } }); return run; }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('Magento_Ui/js/core/app',[ './renderer/types', './renderer/layout', '../lib/knockout/bootstrap' ], function (types, layout) { 'use strict'; return function (data, merge) { types.set(data.types); layout(data.components, undefined, true, merge); }; }); /** * Copyright © Vaimo Group. All rights reserved. * See LICENSE_VAIMO.txt for license details. */ define('js/mixins/sidebar',[ 'jquery', 'vaimo/overlay', 'Magento_Ui/js/modal/alert', 'jquery/ui' ], function ($, overlay, alert) { 'use strict'; return function (originalWidget) { $.widget(originalWidget.prototype.namespace + '.' + originalWidget.prototype.widgetName, $[originalWidget.prototype.namespace][originalWidget.prototype.widgetName], { _create: function () { this._superApply(arguments); this.element.on('input', this.options.item.qty, (function (e) { let $input = $(e.target); $input .parents(this.options.productItemSelector) .eq(0) .find(this.options.item.qtyText) .text($input.val() || 1); }).bind(this)); let self = this, events = {}, handlersObjs = [ { eventName: 'click ' + self.options.button.remove, handler: function (e) { e.stopPropagation(); self._removeItem($(e.currentTarget)); } }, { eventName: 'click ' + self.options.item.button, handler: function (e) { e.stopPropagation(); self._updateItemQty($(e.currentTarget)); } } ]; handlersObjs.forEach(function(obj) { events[obj.eventName] = obj.handler; }); self._off(self.element, handlersObjs.map(function (obj) { return obj.eventName}).join(',')); self._on(self.element, events); }, _removeItemAfter: function (elem) { this._superApply(arguments); elem.css({'pointerEvents': 'none'}); }, removeItem: function (id) { this._ajax(this.options.url.remove, { 'item_id': id }, $(), this._removeItemAfter); }, updateItemQty: function (id, val, cb) { this._ajax(this.options.url.update, { 'item_id': id, 'item_qty': val }, $(), function() { cb(); this._updateItemQtyAfter.apply(this, arguments); }, cb); }, _ajax: function (url, data, elem, callback, callbackFail) { callbackFail = callbackFail || function(){}; callback = callback || function(){}; $.extend(data, { 'form_key': $.mage.cookies.get('form_key') }); $.ajax({ url: url, data: data, type: 'post', dataType: 'json', context: this, /** @inheritdoc */ beforeSend: function () { elem.attr('disabled', 'disabled'); overlay.open('sidebar'); }, /** @inheritdoc */ complete: function () { elem.attr('disabled', null); overlay.close('sidebar'); } }) .done(function (response) { let msg; if (response.success) { callback.call(this, elem, response); } else { callbackFail.call(this, elem, response); this._onCartActionAjaxFail(); msg = response['error_message']; if (msg) { alert({ content: msg }); } } }) .fail(function (error) { callbackFail.call(this, elem, error); window.console.log(JSON.stringify(error)); this._onCartActionAjaxFail(); }); }, _onCartActionAjaxFail: function () { $(document).trigger('sidebarFailedAjax'); }, _showItemButton: function (elem) { let itemId = elem.data('cart-item'), itemQty = elem.data('item-qty'); if (this._isValidQty(itemQty, elem.val())) { $('#update-cart-item-' + itemId).show(); return; } this._hideItemButton(elem); }, _hideItemButton: function (elem) { let itemId = elem.data('cart-item'); $('#update-cart-item-' + itemId).hide(); } }); return $[originalWidget.prototype.namespace][originalWidget.prototype.widgetName]; }; }); /** * Copyright © Vaimo Group. All rights reserved. * See LICENSE_VAIMO.txt for license details. */ define('js/mixins/dynamic-components',[],function() {return function(registry) {'use strict'; function initComponent(component, js) { require(['Magento_Ui/js/core/app'], function(coreApp) { const components = {components: {}}; components.components[component] = { component: js }; coreApp(components); }) } const list = { 'Banner': initComponent.bind(0, 'Banner', 'Banner'), 'algolia-simple-html': initComponent.bind(0, 'algolia-simple-html', 'simple-html'), 'algolia-price': initComponent.bind(0, 'algolia-price', 'AlgoliaPrice') } const get = registry.get; registry.get = function(name) { if (typeof list[name] === 'function') { list[name](); delete list[name]; } return get.apply(registry, arguments) } return registry; } }); /** * Copyright © Vaimo Group. All rights reserved. * See LICENSE_VAIMO.txt for license details. */ define('js/mixins/form/element/abstract',['ko', 'Magento_Ui/js/lib/validation/validator', 'uiRegistry'], (ko, validator, registry)=>{'use strict'; return Abstract => { return Abstract.extend({ defaults: { listens: { '${ $.provider }:${ $.customScope ? $.customScope + "." : ""}data.resetFormBlock': 'reset', '${ $.provider }:${ $.customScope ? $.customScope + "." : ""}data.resetInputValidationStarted': 'resetInputValidationStarted' } }, initObservable: function () { const result = this._super(); if (this.analyzeThis) { this.observe(this.analyzeThis); } this.observe({'_inputValidationStarted': false}); this.noError = ko.computed(function () { const error = this.error(); return this._inputValidationStarted() ? !error : false; }, this); this.doAfterRenderAction = typeof this.afterRenderAction === 'undefined' ? function(){} : this.doAfterRenderAction.bind(this); return result; }, initialize: function () { const result = this._super(); if (this.value()) { this.validate(); } return result; }, _setClasses: function () { const result = this._super(); this.additionalClasses['_no-error'] = this.noError if (this.additionalDynamicClasses) { for (let i in this.additionalDynamicClasses) { if (this[this.additionalDynamicClasses[i]]) { this.additionalClasses[i] = this[this.additionalDynamicClasses[i]]; } } } return result; }, validate: function () { const result = this._super(); this._inputValidationStarted(!!result.target.value()); return result; }, resetInputValidationStarted: function() { this._inputValidationStarted(false); this.error(false); }, satisfyCuriosityForValidationStatus: function () { const value = this.value(); const result = validator(this.validation, value, this.validationParams); const isValid = this.disabled() || !this.visible() || result.passed; if (!isValid && this.source) { this.source.set('params.spyInvalidErrorCollector', Object.assign(this.source.get('params.spyInvalidErrorCollector') || {}, {[this.index]: result})); this.source.set('params.spyInvalid', true); } return { valid: isValid, target: this }; }, doAfterRenderAction: function () { try { const root = window[this.afterRenderAction.root]; return root[this.afterRenderAction.action].bind(root); } catch(e) {return ''} }, onUpdate: function () { if (!this.preventUpdateBubble) { this.bubble('update', this.hasChanged()); } this.validate(); } }); }; }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('Magento_Customer/js/invalidation-processor',[ 'underscore', 'uiElement', 'Magento_Customer/js/customer-data' ], function (_, Element, customerData) { 'use strict'; return Element.extend({ /** * Initialize object */ initialize: function () { this._super(); this.process(customerData); }, /** * Process all rules in loop, each rule can invalidate some sections in customer data * * @param {Object} customerDataObject */ process: function (customerDataObject) { _.each(this.invalidationRules, function (rule, ruleName) { _.each(rule, function (ruleArgs, rulePath) { require([rulePath], function (Rule) { var currentRule = new Rule(ruleArgs); if (!_.isFunction(currentRule.process)) { throw new Error('Rule ' + ruleName + ' should implement invalidationProcessor interface'); } currentRule.process(customerDataObject); }); }); }); } }); }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('Magento_Persistent/js/view/customer-data-mixin',[ 'jquery', 'mage/utils/wrapper' ], function ($, wrapper) { 'use strict'; var mixin = { /** * Check if persistent section is expired due to lifetime. * * @param {Function} originFn - Original method. * @return {Array} */ getExpiredSectionNames: function (originFn) { var expiredSections = originFn(), storage = $.initNamespaceStorage('mage-cache-storage').localStorage, currentTimestamp = Math.floor(Date.now() / 1000), persistentIndex = expiredSections.indexOf('persistent'), persistentLifeTime = 0, sectionData; if (window.persistent !== undefined && window.persistent.expirationLifetime !== undefined) { persistentLifeTime = window.persistent.expirationLifetime; } if (persistentIndex !== -1) { sectionData = storage.get('persistent'); if (typeof sectionData === 'object' && sectionData['data_id'] + persistentLifeTime >= currentTimestamp ) { expiredSections.splice(persistentIndex, 1); } } return expiredSections; }, /** * @param {Object} settings * @constructor */ 'Magento_Customer/js/customer-data': function (originFn) { let mageCacheTimeout = new Date($.localStorage.get('mage-cache-timeout')), mageCacheSessId = $.cookieStorage.isSet('mage-cache-sessid'); originFn(); if (window.persistent !== undefined && (mageCacheTimeout < new Date() || !mageCacheSessId)) { this.reload(['persistent','cart'],true); } } }; /** * Override default customer-data.getExpiredSectionNames(). */ return function (target) { return wrapper.extend(target, mixin); }; }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('Magento_Customer/js/invalidation-rules/website-rule',[ 'uiClass' ], function (Element) { 'use strict'; return Element.extend({ defaults: { scopeConfig: {} }, /** * Takes website id from current customer data and compare it with current website id * If customer belongs to another scope, we need to invalidate current section * * @param {Object} customerData */ process: function (customerData) { var customer = customerData.get('customer'); if (this.scopeConfig && customer() && ~~customer().websiteId !== ~~this.scopeConfig.websiteId && ~~customer().websiteId !== 0) { customerData.reload(['customer']); } } }); }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('mage/loader',[ 'jquery', 'vaimo/overlay', 'jquery-ui-modules/widget', 'mage/translate' ], function ($, overlay) { 'use strict'; $.widget('mage.loader', { loaderStarted: 0, /** * Loader creation * @protected */ _create: function () { this._bind(); }, /** * Bind on ajax events * @protected */ _bind: function () { this._on({ 'processStop': 'hide', 'processStart': 'show', 'show.loader': 'show', 'hide.loader': 'hide', 'contentUpdated.loader': '_contentUpdated' }); }, /** * Verify loader present after content updated * * This will be cleaned up by the task MAGETWO-11070 * * @param {EventObject} e * @private */ _contentUpdated: function (e) { this.show(e); }, /** * Show loader */ show: function (e, ctx) { this.loaderStarted++; overlay.open(); return false; }, /** * Hide loader */ hide: function () { if (this.loaderStarted > 0) { this.loaderStarted--; if (this.loaderStarted === 0) { overlay.close(); } } return false; }, /** * Destroy loader */ _destroy: function () { this.spinner.remove(); } }); /** * This widget takes care of registering the needed loader listeners on the body */ $.widget('mage.loaderAjax', { options: { defaultContainer: '[data-container=body]', loadingClass: 'ajax-loading' }, /** * @private */ _create: function () { this._bind(); // There should only be one instance of this widget, and it should be attached // to the body only. Having it on the page twice will trigger multiple processStarts. if (window.console && !this.element.is(this.options.defaultContainer) && $.mage.isDevMode(undefined)) { console.warn('This widget is intended to be attached to the body, not below.'); } }, /** * @private */ _bind: function () { $(document).on({ 'ajaxSend': this._onAjaxSend.bind(this), 'ajaxComplete': this._onAjaxComplete.bind(this) }); }, /** * @param {Object} loaderContext * @return {*} * @private */ _getJqueryObj: function (loaderContext) { var ctx; // Check to see if context is jQuery object or not. if (loaderContext) { if (loaderContext.jquery) { ctx = loaderContext; } else { ctx = $(loaderContext); } } else { ctx = $('[data-container="body"]'); } return ctx; }, /** * @param {jQuery.Event} e * @param {Object} jqxhr * @param {Object} settings * @private */ _onAjaxSend: function (e, jqxhr, settings) { var ctx; $(this.options.defaultContainer) .addClass(this.options.loadingClass) .attr({ 'aria-busy': true }); if (settings && settings.showLoader) { ctx = this._getJqueryObj(settings.loaderContext); ctx.trigger('processStart'); // Check to make sure the loader is there on the page if not report it on the console. // NOTE that this check should be removed before going live. It is just an aid to help // in finding the uses of the loader that maybe broken. if (window.console && !ctx.parents('[data-role="loader"]').length) { console.warn('Expected to start loader but did not find one in the dom'); } } }, /** * @param {jQuery.Event} e * @param {Object} jqxhr * @param {Object} settings * @private */ _onAjaxComplete: function (e, jqxhr, settings) { $(this.options.defaultContainer) .removeClass(this.options.loadingClass) .attr('aria-busy', false); if (settings && settings.showLoader) { this._getJqueryObj(settings.loaderContext).trigger('processStop'); } } }); return { loader: $.mage.loader, loaderAjax: $.mage.loaderAjax }; }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('mage/bootstrap',[ 'jquery', 'mage/apply/main', 'Magento_Ui/js/lib/knockout/bootstrap' ], function ($, mage) { 'use strict'; $.ajaxSetup({ cache: false }); /** * Init all components defined via data-mage-init attribute. * Execute in a separate task to prevent main thread blocking. */ setTimeout(mage.apply); }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('mage/common',[ 'jquery', 'domReady!' ], function ($) { 'use strict'; /* Form with auto submit feature */ $('form[data-auto-submit="true"]').trigger('submit'); //Add form keys. $(document).on( 'submit', 'form', function (e) { var formKeyElement, existingFormKeyElement, isKeyPresentInForm, isActionExternal, baseUrl = window.BASE_URL, form = $(e.target), formKey = $('input[name="form_key"]').val(), formMethod = form.prop('method'), formAction = form.prop('action'); isActionExternal = formAction.indexOf(baseUrl) !== 0; existingFormKeyElement = form.find('input[name="form_key"]'); isKeyPresentInForm = existingFormKeyElement.length; /* Verifies that existing auto-added form key is a direct form child element, protection from a case when one form contains another form. */ if (isKeyPresentInForm && existingFormKeyElement.attr('auto-added-form-key') === '1') { isKeyPresentInForm = form.find('> input[name="form_key"]').length; } if (formKey && !isKeyPresentInForm && !isActionExternal && formMethod !== 'get') { formKeyElement = document.createElement('input'); formKeyElement.setAttribute('type', 'hidden'); formKeyElement.setAttribute('name', 'form_key'); formKeyElement.setAttribute('value', formKey); formKeyElement.setAttribute('auto-added-form-key', '1'); form.get(0).appendChild(formKeyElement); } } ); }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('mage/smart-keyboard-handler',[ 'jquery' ], function ($) { 'use strict'; /** * @return {Object} * @constructor */ function KeyboardHandler() { var body = $('body'), focusState = false, tabFocusClass = '_keyfocus', productsGrid = '[data-container="product-grid"]', catalogProductsGrid = $(productsGrid), CODE_TAB = 9; /** * Handle logic, when onTabKeyPress fired at first. * Then it changes state. */ function onFocusInHandler() { focusState = true; body.addClass(tabFocusClass) .off('focusin.keyboardHandler', onFocusInHandler); } /** * Handle logic to remove state after onTabKeyPress to normal. */ function onClickHandler() { focusState = false; body.removeClass(tabFocusClass) .off('click', onClickHandler); } /** * Tab key onKeypress handler. Apply main logic: * - call differ actions onTabKeyPress and onClick */ function smartKeyboardFocus() { $(document).on('keydown keypress', function (event) { if (event.which === CODE_TAB && !focusState) { body .on('focusin.keyboardHandler', onFocusInHandler) .on('click', onClickHandler); } }); // ARIA support for catalog grid products if (catalogProductsGrid.length) { body.on('focusin.gridProducts', productsGrid, function () { if (body.hasClass(tabFocusClass)) { $(this).addClass('active'); } }); body.on('focusout.gridProducts', productsGrid, function () { $(this).removeClass('active'); }); } } /** * Attach smart focus on specific element. * @param {jQuery} element */ function handleFocus(element) { element.on('focusin.emulateTabFocus', function () { focusState = true; body.addClass(tabFocusClass); element.off(); }); element.on('focusout.emulateTabFocus', function () { focusState = false; body.removeClass(tabFocusClass); element.off(); }); } return { apply: smartKeyboardFocus, focus: handleFocus }; } return new KeyboardHandler; }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('mage/tabs',[ 'jquery', 'jquery-ui-modules/widget', 'jquery/ui-modules/widgets/tabs', 'mage/mage', 'mage/collapsible' ], function ($) { 'use strict'; $.widget('mage.tabs', { options: { active: 0, disabled: [], openOnFocus: true, collapsible: false, collapsibleElement: '[data-role=collapsible]', header: '[data-role=title]', content: '[data-role=content]', trigger: '[data-role=trigger]', closedState: null, openedState: null, disabledState: null, ajaxUrlElement: '[data-ajax=true]', ajaxContent: false, loadingClass: null, saveState: false, animate: false, icons: { activeHeader: null, header: null } }, /** * @private */ _create: function () { if (typeof this.options.disabled === 'string') { this.options.disabled = this.options.disabled.split(' ').map(function (item) { return parseInt(item, 10); }); } this._processPanels(); this._handleDeepLinking(); this._processTabIndex(); this._closeOthers(); this._bind(); }, /** * @private */ _destroy: function () { $.each(this.collapsibles, function () { $(this).collapsible('destroy'); }); }, /** * If deep linking is used, all sections must be closed but the one that contains the anchor. * @private */ _handleDeepLinking: function () { var self = this, anchor = window.location.hash, isValid = $.mage.isValidSelector(anchor), anchorId = anchor.replace('#', ''); if (anchor && isValid) { $.each(self.contents, function (i) { if ($(this).attr('id') === anchorId || $(this).find('#' + anchorId).length) { self.collapsibles.not(self.collapsibles.eq(i)).collapsible('forceDeactivate'); return false; } }); } }, /** * When the widget gets instantiated, the first tab that is not disabled receive focusable property * All tabs receive tabIndex 0 * @private */ _processTabIndex: function () { var self = this; self.triggers.attr('tabIndex', 0); $.each(this.collapsibles, function (i) { self.triggers.attr('tabIndex', 0); self.triggers.eq(i).attr('tabIndex', 0); }); }, /** * Prepare the elements for instantiating the collapsible widget * @private */ _processPanels: function () { var isNotNested = this._isNotNested.bind(this); this.contents = this.element .find(this.options.content) .filter(isNotNested); this.collapsibles = this.element .find(this.options.collapsibleElement) .filter(isNotNested); this.collapsibles .attr('role', 'presentation') .parent() .attr('role', 'tablist'); this.headers = this.element .find(this.options.header) .filter(isNotNested); if (this.headers.length === 0) { this.headers = this.collapsibles; } this.triggers = this.element .find(this.options.trigger) .filter(isNotNested); if (this.triggers.length === 0) { this.triggers = this.headers; } this._callCollapsible(); }, /** * Checks if element is not in nested container to keep the correct scope of collapsible * @param {Number} index * @param {HTMLElement} element * @private * @return {Boolean} */ _isNotNested: function (index, element) { var parentContent = $(element).parents(this.options.content); return !parentContent.length || !this.element.find(parentContent).length; }, /** * Setting the disabled and active tabs and calling instantiation of collapsible * @private */ _callCollapsible: function () { var self = this, disabled = false, active = false; $.each(this.collapsibles, function (i) { disabled = active = false; if ($.inArray(i, self.options.disabled) !== -1) { disabled = true; } if (i === self.options.active) { active = true; } self._instantiateCollapsible(this, i, active, disabled); }); }, /** * Instantiate collapsible. * * @param {HTMLElement} element * @param {Number} index * @param {*} active * @param {*} disabled * @private */ _instantiateCollapsible: function (element, index, active, disabled) { $(element).collapsible( $.extend({}, this.options, { active: active, disabled: disabled, header: this.headers.eq(index), content: this.contents.eq(index), trigger: this.triggers.eq(index) }) ); }, /** * Adding callback to close others tabs when one gets opened * @private */ _closeOthers: function () { var self = this; $.each(this.collapsibles, function () { $(this).on('beforeOpen', function () { self.collapsibles.not(this).collapsible('forceDeactivate'); }); }); }, /** * @param {*} index */ activate: function (index) { this._toggleActivate('activate', index); }, /** * @param {*} index */ deactivate: function (index) { this._toggleActivate('deactivate', index); }, /** * @param {*} action * @param {*} index * @private */ _toggleActivate: function (action, index) { this.collapsibles.eq(index).collapsible(action); }, /** * @param {*} index */ disable: function (index) { this._toggleEnable('disable', index); }, /** * @param {*} index */ enable: function (index) { this._toggleEnable('enable', index); }, /** * @param {*} action * @param {*} index * @private */ _toggleEnable: function (action, index) { var self = this; if (Array.isArray(index)) { $.each(index, function () { self.collapsibles.eq(this).collapsible(action); }); } else if (index === undefined) { this.collapsibles.collapsible(action); } else { this.collapsibles.eq(index).collapsible(action); } }, /** * @param {jQuery.Event} event * @private */ _keydown: function (event) { var self = this, keyCode, toFocus, toFocusIndex, enabledTriggers, length, currentIndex, nextToFocus; if (event.altKey || event.ctrlKey) { return; } keyCode = $.ui.keyCode; toFocus = false; enabledTriggers = []; $.each(this.triggers, function () { if (!self.collapsibles.eq(self.triggers.index($(this))).collapsible('option', 'disabled')) { enabledTriggers.push(this); } }); length = $(enabledTriggers).length; currentIndex = $(enabledTriggers).index(event.target); /** * @param {String} direction * @return {*} */ nextToFocus = function (direction) { if (length > 0) { if (direction === 'right') { toFocusIndex = (currentIndex + 1) % length; } else { toFocusIndex = (currentIndex + length - 1) % length; } return enabledTriggers[toFocusIndex]; } return event.target; }; switch (event.keyCode) { case keyCode.RIGHT: case keyCode.DOWN: toFocus = nextToFocus('right'); break; case keyCode.LEFT: case keyCode.UP: toFocus = nextToFocus('left'); break; case keyCode.HOME: toFocus = enabledTriggers[0]; break; case keyCode.END: toFocus = enabledTriggers[length - 1]; break; } if (toFocus) { toFocusIndex = this.triggers.index(toFocus); $(event.target).attr('tabIndex', -1); $(toFocus).attr('tabIndex', 0); toFocus.focus(); if (this.options.openOnFocus) { this.activate(toFocusIndex); } event.preventDefault(); } }, /** * @private */ _bind: function () { var events = { keydown: '_keydown' }; this._off(this.triggers); this._on(this.triggers, events); } }); return $.mage.tabs; }); /*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas, David Knight. MIT license */ window.matchMedia || (window.matchMedia = function() { "use strict"; // For browsers that support matchMedium api such as IE 9 and webkit var styleMedia = (window.styleMedia || window.media); // For those that don't support matchMedium if (!styleMedia) { var style = document.createElement('style'), script = document.getElementsByTagName('script')[0], info = null; style.type = 'text/css'; style.id = 'matchmediajs-test'; if (!script) { document.head.appendChild(style); } else { script.parentNode.insertBefore(style, script); } // 'style.currentStyle' is used by IE <= 8 and 'window.getComputedStyle' for all other browsers info = ('getComputedStyle' in window) && window.getComputedStyle(style, null) || style.currentStyle; styleMedia = { matchMedium: function(media) { var text = '@media ' + media + '{ #matchmediajs-test { width: 1px; } }'; // 'style.styleSheet' is used by IE <= 8 and 'style.textContent' for all other browsers if (style.styleSheet) { style.styleSheet.cssText = text; } else { style.textContent = text; } // Test if media query is true or false return info.width === '1px'; } }; } return function(media) { return { matches: styleMedia.matchMedium(media || 'all'), media: media || 'all' }; }; }()); /*! matchMedia() polyfill addListener/removeListener extension. Author & copyright (c) 2012: Scott Jehl. Dual MIT/BSD license */ (function() { // Bail out for browsers that have addListener support if (window.matchMedia && window.matchMedia('all').addListener) { return false; } var localMatchMedia = window.matchMedia, hasMediaQueries = localMatchMedia('only all').matches, isListening = false, timeoutID = 0, // setTimeout for debouncing 'handleChange' queries = [], // Contains each 'mql' and associated 'listeners' if 'addListener' is used handleChange = function(evt) { // Debounce clearTimeout(timeoutID); timeoutID = setTimeout(function() { for (var i = 0, il = queries.length; i < il; i++) { var mql = queries[i].mql, listeners = queries[i].listeners || [], matches = localMatchMedia(mql.media).matches; // Update mql.matches value and call listeners // Fire listeners only if transitioning to or from matched state if (matches !== mql.matches) { mql.matches = matches; for (var j = 0, jl = listeners.length; j < jl; j++) { listeners[j].call(window, mql); } } } }, 30); }; window.matchMedia = function(media) { var mql = localMatchMedia(media), listeners = [], index = 0; mql.addListener = function(listener) { // Changes would not occur to css media type so return now (Affects IE <= 8) if (!hasMediaQueries) { return; } // Set up 'resize' listener for browsers that support CSS3 media queries (Not for IE <= 8) // There should only ever be 1 resize listener running for performance if (!isListening) { isListening = true; window.addEventListener('resize', handleChange, true); } // Push object only if it has not been pushed already if (index === 0) { index = queries.push({ mql: mql, listeners: listeners }); } listeners.push(listener); }; mql.removeListener = function(listener) { for (var i = 0, il = listeners.length; i < il; i++) { if (listeners[i] === listener) { listeners.splice(i, 1); } } }; return mql; }; }()); window.mediaCheck = function(options) { var mq; function mqChange(mq, options) { if (mq.matches) { if (typeof options.entry === "function") { options.entry(); } } else if (typeof options.exit === "function") { options.exit(); } }; mq = window.matchMedia(options.media); mq.addListener(function() { mqChange(mq, options); }); mqChange(mq, options); }; define("matchMedia", (function (global) { return function () { var ret, fn; return ret || global.mediaCheck; }; }(this))); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /** * @api */ define('Magento_Ui/js/form/element/abstract',[ 'underscore', 'mageUtils', 'uiLayout', 'uiElement', 'Magento_Ui/js/lib/validation/validator' ], function (_, utils, layout, Element, validator) { 'use strict'; return Element.extend({ defaults: { visible: true, preview: '', focused: false, required: false, disabled: false, valueChangedByUser: false, elementTmpl: 'ui/form/element/input', tooltipTpl: 'ui/form/element/helper/tooltip', fallbackResetTpl: 'ui/form/element/helper/fallback-reset', 'input_type': 'input', placeholder: false, description: '', labelVisible: true, label: '', error: '', warn: '', notice: '', customScope: '', default: '', isDifferedFromDefault: false, showFallbackReset: false, additionalClasses: {}, isUseDefault: '', serviceDisabled: false, valueUpdate: false, // ko binding valueUpdate switcherConfig: { component: 'Magento_Ui/js/form/switcher', name: '${ $.name }_switcher', target: '${ $.name }', property: 'value' }, listens: { visible: 'setPreview', value: 'setDifferedFromDefault', '${ $.provider }:data.reset': 'reset', '${ $.provider }:data.overload': 'overload', '${ $.provider }:${ $.customScope ? $.customScope + "." : ""}data.validate': 'validate', 'isUseDefault': 'toggleUseDefault' }, ignoreTmpls: { value: true }, links: { value: '${ $.provider }:${ $.dataScope }' } }, /** * Invokes initialize method of parent class, * contains initialization logic */ initialize: function () { _.bindAll(this, 'reset'); this._super() .setInitialValue() ._setClasses() .initSwitcher(); return this; }, /** * Checks if component has error. * * @returns {Object} */ checkInvalid: function () { return this.error() && this.error().length ? this : null; }, /** * Initializes observable properties of instance * * @returns {Abstract} Chainable. */ initObservable: function () { var rules = this.validation = this.validation || {}; this._super(); this.observe('error disabled focused preview visible value warn notice isDifferedFromDefault') .observe('isUseDefault serviceDisabled') .observe({ 'required': !!rules['required-entry'] }); return this; }, /** * Initializes regular properties of instance. * * @returns {Abstract} Chainable. */ initConfig: function () { var uid = utils.uniqueid(), name, valueUpdate, scope; this._super(); scope = this.dataScope.split('.'); name = scope.length > 1 ? scope.slice(1) : scope; valueUpdate = this.showFallbackReset ? 'afterkeydown' : this.valueUpdate; _.extend(this, { uid: uid, noticeId: 'notice-' + uid, errorId: 'error-' + uid, tooltipId: 'tooltip-' + uid, inputName: utils.serializeName(name.join('.')), valueUpdate: valueUpdate }); return this; }, /** * Initializes switcher element instance. * * @returns {Abstract} Chainable. */ initSwitcher: function () { if (this.switcherConfig.enabled) { layout([this.switcherConfig]); } return this; }, /** * Sets initial value of the element and subscribes to it's changes. * * @returns {Abstract} Chainable. */ setInitialValue: function () { this.initialValue = this.getInitialValue(); if (this.value.peek() !== this.initialValue) { this.value(this.initialValue); } this.on('value', this.onUpdate.bind(this)); this.isUseDefault(this.disabled()); return this; }, /** * Extends 'additionalClasses' object. * * @returns {Abstract} Chainable. */ _setClasses: function () { var additional = this.additionalClasses; if (_.isString(additional)) { this.additionalClasses = {}; if (additional.trim().length) { additional = additional.trim().split(' '); additional.forEach(function (name) { if (name.length) { this.additionalClasses[name] = true; } }, this); } } _.extend(this.additionalClasses, { _required: this.required, _error: this.error, _warn: this.warn, _disabled: this.disabled }); return this; }, /** * Gets initial value of element * * @returns {*} Elements' value. */ getInitialValue: function () { var values = [this.value(), this.default], value; values.some(function (v) { if (v !== null && v !== undefined) { value = v; return true; } return false; }); return this.normalizeData(value); }, /** * Sets 'value' as 'hidden' property's value, triggers 'toggle' event, * sets instance's hidden identifier in params storage based on * 'value'. * * @returns {Abstract} Chainable. */ setVisible: function (isVisible) { this.visible(isVisible); return this; }, /** * Show element. * * @returns {Abstract} Chainable. */ show: function () { this.visible(true); return this; }, /** * Hide element. * * @returns {Abstract} Chainable. */ hide: function () { this.visible(false); return this; }, /** * Disable element. * * @returns {Abstract} Chainable. */ disable: function () { this.disabled(true); return this; }, /** * Enable element. * * @returns {Abstract} Chainable. */ enable: function () { this.disabled(false); return this; }, /** * * @param {(String|Object)} rule * @param {(Object|Boolean)} [options] * @returns {Abstract} Chainable. */ setValidation: function (rule, options) { var rules = utils.copy(this.validation), changed; if (_.isObject(rule)) { _.extend(this.validation, rule); } else { this.validation[rule] = options; } changed = !utils.compare(rules, this.validation).equal; if (changed) { this.required(!!rules['required-entry']); this.validate(); } return this; }, /** * Returns unwrapped preview observable. * * @returns {String} Value of the preview observable. */ getPreview: function () { return this.value(); }, /** * Checks if element has addons * * @returns {Boolean} */ hasAddons: function () { return this.addbefore || this.addafter; }, /** * Checks if element has service setting * * @returns {Boolean} */ hasService: function () { return this.service && this.service.template; }, /** * Defines if value has changed. * * @returns {Boolean} */ hasChanged: function () { var notEqual = this.value() !== this.initialValue; return !this.visible() ? false : notEqual; }, /** * Checks if 'value' is not empty. * * @returns {Boolean} */ hasData: function () { return !utils.isEmpty(this.value()); }, /** * Sets value observable to initialValue property. * * @returns {Abstract} Chainable. */ reset: function () { this.value(this.initialValue); this.error(false); return this; }, /** * Sets current state as initial. */ overload: function () { this.setInitialValue(); this.bubble('update', this.hasChanged()); }, /** * Clears 'value' property. * * @returns {Abstract} Chainable. */ clear: function () { this.value(''); return this; }, /** * Converts values like 'null' or 'undefined' to an empty string. * * @param {*} value - Value to be processed. * @returns {*} */ normalizeData: function (value) { return utils.isEmpty(value) ? '' : value; }, /** * Validates itself by it's validation rules using validator object. * If validation of a rule did not pass, writes it's message to * 'error' observable property. * * @returns {Object} Validate information. */ validate: function () { var value = this.value(), result = validator(this.validation, value, this.validationParams), message = !this.disabled() && this.visible() ? result.message : '', isValid = this.disabled() || !this.visible() || result.passed; this.error(message); this.error.valueHasMutated(); this.bubble('error', message); //TODO: Implement proper result propagation for form if (this.source && !isValid) { this.source.set('params.invalid', true); } return { valid: isValid, target: this }; }, /** * Callback that fires when 'value' property is updated. */ onUpdate: function () { this.bubble('update', this.hasChanged()); this.validate(); }, /** * Restore value to default */ restoreToDefault: function () { this.value(this.default); this.focused(true); }, /** * Update whether value differs from default value */ setDifferedFromDefault: function () { var value = typeof this.value() != 'undefined' && this.value() !== null ? this.value() : '', defaultValue = typeof this.default != 'undefined' && this.default !== null ? this.default : ''; this.isDifferedFromDefault(value !== defaultValue); }, /** * @param {Boolean} state */ toggleUseDefault: function (state) { this.disabled(state); if (this.source && this.hasService()) { this.source.set('data.use_default.' + this.index, Number(state)); } }, /** * Callback when value is changed by user */ userChanges: function () { this.valueChangedByUser = true; }, /** * Returns correct id for 'aria-describedby' accessibility attribute * * @returns {Boolean|String} */ getDescriptionId: function () { var id = false; if (this.error()) { id = this.errorId; } else if (this.notice()) { id = this.noticeId; } return id; } }); }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('Magento_PageCache/js/form-key-provider',[],function () { 'use strict'; return function (settings) { var formKey, inputElements, inputSelector = 'input[name="form_key"]'; /** * Set form_key cookie * @private */ function setFormKeyCookie(value) { var expires, secure, date = new Date(), cookiesConfig = window.cookiesConfig || {}, isSecure = !!cookiesConfig.secure, samesite = cookiesConfig.samesite || 'lax'; date.setTime(date.getTime() + 86400000); expires = '; expires=' + date.toUTCString(); secure = isSecure ? '; secure' : ''; samesite = '; samesite=' + samesite; document.cookie = 'form_key=' + (value || '') + expires + secure + '; path=/' + samesite; } /** * Retrieves form key from cookie * @private */ function getFormKeyCookie() { var cookie, i, nameEQ = 'form_key=', cookieArr = document.cookie.split(';'); for (i = 0; i < cookieArr.length; i++) { cookie = cookieArr[i]; while (cookie.charAt(0) === ' ') { cookie = cookie.substring(1, cookie.length); } if (cookie.indexOf(nameEQ) === 0) { return cookie.substring(nameEQ.length, cookie.length); } } return null; } /** * Get form key from UI input hidden * @private */ function getFormKeyFromUI() { return document.querySelector(inputSelector).value; } /** * Generate form key string * @private */ function generateFormKeyString() { var result = '', length = 16, chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; while (length--) { result += chars[Math.round(Math.random() * (chars.length - 1))]; } return result; } /** * Init form_key inputs with value * @private */ function initFormKey() { formKey = getFormKeyCookie(); if (settings && settings.isPaginationCacheEnabled && !formKey) { formKey = getFormKeyFromUI(); setFormKeyCookie(formKey); } if (!formKey) { formKey = generateFormKeyString(); setFormKeyCookie(formKey); } inputElements = document.querySelectorAll(inputSelector); if (inputElements.length) { Array.prototype.forEach.call(inputElements, function (element) { element.setAttribute('value', formKey); }); } } initFormKey(); }; }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('Magento_PurchaseOrderRule/js/validation/messages',[ 'jquery', 'mage/mage', 'mage/translate' ], function ($) { 'use strict'; $('.form-create-purchase-order-rule').mage('validation', { messages: { 'conditions[0][value]': { 'validate-digits': $.mage.__('Please enter a whole number.') } } }); }); /** * Copyright © Vaimo Group. All rights reserved. * See LICENSE_VAIMO.txt for license details. */ define('js/mixins/menu-mixin',['jquery', 'vaimo/headerState'], function ($, headerState) { 'use strict'; return function (Menu) { Menu.prototype._onMenuRequested = (function (parentMethod) { return function () { parentMethod.apply(this, arguments); headerState.subscribe("isSearchPopupOpened", this.hide.bind(this)); } })(Menu.prototype._onMenuRequested); Menu.prototype._onTopLevelClicked = (function (parentMethod) { return function ($foldEl, isOpen) { parentMethod.apply(this, arguments); this._handleHeaderState(!isOpen); } })(Menu.prototype._onTopLevelClicked); Menu.prototype._beforeResize = (function (parentMethod) { return function () { parentMethod.apply(this, arguments); headerState.setState('isMobileMenu', this._isMob()); } })(Menu.prototype._beforeResize); Menu.prototype._handleHeaderState = function(isOpen) { headerState.setState('isMenuActive', isOpen); }; return Menu; }; }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /** * A loose JavaScript version of Magento\Framework\Escaper * * Due to differences in how XML/HTML is processed in PHP vs JS there are a couple of minor differences in behavior * from the PHP counterpart. * * The first difference is that the default invocation of escapeHtml without allowedTags will double-escape existing * entities as the intention of such an invocation is that the input isn't supposed to contain any HTML. * * The second difference is that escapeHtml will not escape quotes. Since the input is actually being processed by the * DOM there is no chance of quotes being mixed with HTML syntax. And, since escapeHtml is not * intended to be used with raw injection into a HTML attribute, this is acceptable. * * @api */ define('Magento_Security/js/escaper',[], function () { 'use strict'; return { neverAllowedElements: ['script', 'img', 'embed', 'iframe', 'video', 'source', 'object', 'audio'], generallyAllowedAttributes: ['id', 'class', 'href', 'title', 'style'], forbiddenAttributesByElement: { a: ['style'] }, /** * Escape a string for safe injection into HTML * * @param {String} data * @param {Array|null} allowedTags * @returns {String} */ escapeHtml: function (data, allowedTags) { var domParser = new DOMParser(), fragment = domParser.parseFromString('<div></div>', 'text/html'); fragment = fragment.body.childNodes[0]; allowedTags = typeof allowedTags === 'object' && allowedTags.length ? allowedTags : null; if (allowedTags) { fragment.innerHTML = data || ''; allowedTags = this._filterProhibitedTags(allowedTags); this._removeComments(fragment); this._removeNotAllowedElements(fragment, allowedTags); this._removeNotAllowedAttributes(fragment); return fragment.innerHTML; } fragment.textContent = data || ''; return fragment.innerHTML; }, /** * Remove the always forbidden tags from a list of provided tags * * @param {Array} tags * @returns {Array} * @private */ _filterProhibitedTags: function (tags) { return tags.filter(function (n) { return this.neverAllowedElements.indexOf(n) === -1; }.bind(this)); }, /** * Remove comment nodes from the given node * * @param {Node} node * @private */ _removeComments: function (node) { var treeWalker = node.ownerDocument.createTreeWalker( node, NodeFilter.SHOW_COMMENT, function () { return NodeFilter.FILTER_ACCEPT; }, false ), nodesToRemove = []; while (treeWalker.nextNode()) { nodesToRemove.push(treeWalker.currentNode); } nodesToRemove.forEach(function (nodeToRemove) { nodeToRemove.parentNode.removeChild(nodeToRemove); }); }, /** * Strip the given node of all disallowed tags while permitting any nested text nodes * * @param {Node} node * @param {Array|null} allowedTags * @private */ _removeNotAllowedElements: function (node, allowedTags) { var treeWalker = node.ownerDocument.createTreeWalker( node, NodeFilter.SHOW_ELEMENT, function (currentNode) { return allowedTags.indexOf(currentNode.nodeName.toLowerCase()) === -1 ? NodeFilter.FILTER_ACCEPT // SKIP instead of REJECT because REJECT also rejects child nodes : NodeFilter.FILTER_SKIP; }, false ), nodesToRemove = []; while (treeWalker.nextNode()) { if (allowedTags.indexOf(treeWalker.currentNode.nodeName.toLowerCase()) === -1) { nodesToRemove.push(treeWalker.currentNode); } } nodesToRemove.forEach(function (nodeToRemove) { nodeToRemove.parentNode.replaceChild( node.ownerDocument.createTextNode(nodeToRemove.textContent), nodeToRemove ); }); }, /** * Remove any invalid attributes from the given node * * @param {Node} node * @private */ _removeNotAllowedAttributes: function (node) { var treeWalker = node.ownerDocument.createTreeWalker( node, NodeFilter.SHOW_ELEMENT, function () { return NodeFilter.FILTER_ACCEPT; }, false ), i, attribute, nodeName, attributesToRemove = []; while (treeWalker.nextNode()) { for (i = 0; i < treeWalker.currentNode.attributes.length; i++) { attribute = treeWalker.currentNode.attributes[i]; nodeName = treeWalker.currentNode.nodeName.toLowerCase(); if (this.generallyAllowedAttributes.indexOf(attribute.name) === -1 || // eslint-disable-line max-depth,max-len this._checkHrefValue(attribute) || this.forbiddenAttributesByElement[nodeName] && this.forbiddenAttributesByElement[nodeName].indexOf(attribute.name) !== -1 ) { attributesToRemove.push(attribute); } } } attributesToRemove.forEach(function (attributeToRemove) { attributeToRemove.ownerElement.removeAttribute(attributeToRemove.name); }); }, /** * Check that attribute contains script content * * @param {Object} attribute * @private */ _checkHrefValue: function (attribute) { return attribute.nodeName === 'href' && attribute.nodeValue.startsWith('javascript'); } }; }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('Magento_PageCache/js/page-cache',[ 'jquery', 'domReady', 'consoleLogger', 'Magento_PageCache/js/form-key-provider', 'jquery-ui-modules/widget', 'mage/cookies' ], function ($, domReady, consoleLogger, formKeyInit) { 'use strict'; /** * Helper. Generate random string * TODO: Merge with mage/utils * @param {String} chars - list of symbols * @param {Number} length - length for need string * @returns {String} */ function generateRandomString(chars, length) { var result = ''; length = length > 0 ? length : 1; while (length--) { result += chars[Math.round(Math.random() * (chars.length - 1))]; } return result; } /** * Nodes tree to flat list converter * @returns {Array} */ $.fn.comments = function () { var elements = [], contents, elementContents; /** * @param {jQuery} element - Comment holder */ (function lookup(element) { var iframeHostName; // prevent cross origin iframe content reading if ($(element).prop('tagName') === 'IFRAME') { iframeHostName = $('<a>').prop('href', $(element).prop('src')) .prop('hostname'); if (window.location.hostname !== iframeHostName) { return []; } } /** * Rewrite jQuery contents(). * * @param {jQuery} elem */ contents = function (elem) { return $.map(elem, function (el) { try { return el.nodeName.toLowerCase() === 'iframe' ? el.contentDocument || (el.contentWindow ? el.contentWindow.document : []) : $.merge([], el.childNodes); } catch (e) { consoleLogger.error(e); return []; } }); }; elementContents = contents($(element)); $.each(elementContents, function (index, el) { switch (el.nodeType) { case 1: // ELEMENT_NODE lookup(el); break; case 8: // COMMENT_NODE elements.push(el); break; case 9: // DOCUMENT_NODE lookup($(el).find('body')); break; } }); })(this); return elements; }; /** * FormKey Widget - this widget is generating from key, saves it to cookie and * @deprecated see Magento/PageCache/view/frontend/web/js/form-key-provider.js */ $.widget('mage.formKey', { options: { inputSelector: 'input[name="form_key"]', allowedCharacters: '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', length: 16 }, /** * Creates widget 'mage.formKey' * @private */ _create: function () { var formKey = $.mage.cookies.get('form_key'), options = { secure: window.cookiesConfig ? window.cookiesConfig.secure : false }; if (!formKey) { formKey = generateRandomString(this.options.allowedCharacters, this.options.length); $.mage.cookies.set('form_key', formKey, options); } $(this.options.inputSelector).val(formKey); } }); /** * PageCache Widget * Handles additional ajax request for rendering user private content. */ $.widget('mage.pageCache', { options: { url: '/', patternPlaceholderOpen: /^ BLOCK (.+) $/, patternPlaceholderClose: /^ \/BLOCK (.+) $/, versionCookieName: 'private_content_version', handles: [] }, /** * Creates widget 'mage.pageCache' * @private */ _create: function () { var placeholders, version = $.mage.cookies.get(this.options.versionCookieName); if (!version) { return; } placeholders = this._searchPlaceholders(this.element.comments()); if (placeholders && placeholders.length) { this._ajax(placeholders, version); } }, /** * Parse page for placeholders. * @param {Array} elements * @returns {Array} * @private */ _searchPlaceholders: function (elements) { var placeholders = [], tmp = {}, ii, len, el, matches, name; if (!(elements && elements.length)) { return placeholders; } for (ii = 0, len = elements.length; ii < len; ii++) { el = elements[ii]; matches = this.options.patternPlaceholderOpen.exec(el.nodeValue); name = null; if (matches) { name = matches[1]; tmp[name] = { name: name, openElement: el }; } else { matches = this.options.patternPlaceholderClose.exec(el.nodeValue); if (matches) { //eslint-disable-line max-depth name = matches[1]; if (tmp[name]) { //eslint-disable-line max-depth tmp[name].closeElement = el; placeholders.push(tmp[name]); delete tmp[name]; } } } } return placeholders; }, /** * Parse for page and replace placeholders * @param {Object} placeholder * @param {Object} html * @protected */ _replacePlaceholder: function (placeholder, html) { var startReplacing = false, prevSibling = null, parent, contents, yy, len, element; if (!placeholder || !html) { return; } parent = $(placeholder.openElement).parent(); contents = parent.contents(); for (yy = 0, len = contents.length; yy < len; yy++) { element = contents[yy]; if (element == placeholder.openElement) { //eslint-disable-line eqeqeq startReplacing = true; } if (startReplacing) { $(element).remove(); } else if (element.nodeType != 8) { //eslint-disable-line eqeqeq //due to comment tag doesn't have siblings we try to find it manually prevSibling = element; } if (element == placeholder.closeElement) { //eslint-disable-line eqeqeq break; } } if (prevSibling) { $(prevSibling).after(html); } else { $(parent).prepend(html); } // trigger event to use mage-data-init attribute $(parent).trigger('contentUpdated'); }, /** * AJAX helper * @param {Object} placeholders * @param {String} version * @private */ _ajax: function (placeholders, version) { var ii, data = { blocks: [], handles: this.options.handles, originalRequest: this.options.originalRequest, version: version }; for (ii = 0; ii < placeholders.length; ii++) { data.blocks.push(placeholders[ii].name); } data.blocks = JSON.stringify(data.blocks.sort()); data.handles = JSON.stringify(data.handles); data.originalRequest = JSON.stringify(data.originalRequest); $.ajax({ url: this.options.url, data: data, type: 'GET', cache: true, dataType: 'json', context: this, /** * Response handler * @param {Object} response */ success: function (response) { var placeholder, i; for (i = 0; i < placeholders.length; i++) { placeholder = placeholders[i]; if (response.hasOwnProperty(placeholder.name)) { this._replacePlaceholder(placeholder, response[placeholder.name]); } } } }); } }); domReady(function () { formKeyInit(); }); return { 'pageCache': $.mage.pageCache, 'formKey': $.mage.formKey }; }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('Magento_Customer/js/view/customer',[ 'uiComponent', 'Magento_Customer/js/customer-data' ], function (Component, customerData) { 'use strict'; return Component.extend({ /** @inheritdoc */ initialize: function () { this._super(); this.customer = customerData.get('customer'); } }); }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('Magento_Wishlist/js/view/wishlist',[ 'uiComponent', 'Magento_Customer/js/customer-data' ], function (Component, customerData) { 'use strict'; return Component.extend({ /** @inheritdoc */ initialize: function () { this._super(); this.wishlist = customerData.get('wishlist'); } }); }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('Magento_Catalog/js/view/image',[ 'uiComponent' ], function (Component) { 'use strict'; return Component.extend({ /** @inheritdoc */ initialize: function () { this._super(); this.template = window.checkout.imageTemplate || this.template; } }); }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('Magento_Catalog/js/product/storage/ids-storage',[ 'jquery', 'underscore', 'ko', 'mageUtils', 'jquery/jquery-storageapi' ], function ($, _, ko, utils) { 'use strict'; /** * Set data to localStorage with support check. * * @param {String} namespace * @param {Object} data */ function setLocalStorageItem(namespace, data) { try { window.localStorage.setItem(namespace, JSON.stringify(data)); } catch (e) { console.warn('localStorage is unavailable - skipping local caching of product data'); console.error(e); } } return { /** * Class name */ name: 'IdsStorage', /** * Initializes class * * @return Chainable. */ initialize: function () { if (!this.data) { this.data = ko.observable({}); } this.initCustomerDataReloadListener() .initLocalStorage() .cachesDataFromLocalStorage() .initDataListener(); return this; }, /** * Gets data from local storage by current namespace * * @return {Object}. */ getDataFromLocalStorage: function () { return this.localStorage.get(); }, /** * Caches data from local storage to local scope * * @return Chainable. */ cachesDataFromLocalStorage: function () { this.data(this.getDataFromLocalStorage()); return this; }, /** * Initialize localStorage * * @return Chainable. */ initLocalStorage: function () { this.localStorage = $.initNamespaceStorage(this.namespace).localStorage; return this; }, /** * Initializes listener to "data" property */ initDataListener: function () { this.data.subscribe(this.internalDataHandler.bind(this)); }, /** * Initialize listener to customer data reload * * @return Chainable. */ initCustomerDataReloadListener: function () { $(document).on('customer-data-reload', function (event, sections) { if ((_.isEmpty(sections) || _.contains(sections, this.namespace)) && ~~this.allowToSendRequest) { this.localStorage.removeAll(); this.data(); } }.bind(this)); return this; }, /** * Initializes handler to "data" property update */ internalDataHandler: function (data) { setLocalStorageItem(this.namespace, data); }, /** * Initializes handler to storage update */ externalDataHandler: function (data) { data = data.items ? data.items : data; this.set(_.extend(utils.copy(this.data()), data)); } }; }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('Magento_Catalog/js/product/query-builder',[ 'underscore' ], function (_) { 'use strict'; return { /** * Build query to get id * * @param {Object} data */ buildQuery: function (data) { var filters = []; _.each(data, function (value, key) { filters.push({ field: key, value: value, 'condition_type': 'in' }); }); return { searchCriteria: { filterGroups: [ { filters: filters } ] } }; } }; } ); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('Magento_Catalog/js/product/storage/data-storage',[ 'jquery', 'underscore', 'ko', 'mageUtils', 'Magento_Catalog/js/product/query-builder', 'Magento_Customer/js/customer-data', 'jquery/jquery-storageapi' ], function ($, _, ko, utils, queryBuilder, customerData) { 'use strict'; /** * Process data from API request * * @param {Object} data * @returns {Object} */ function getParsedDataFromServer(data) { var result = {}; _.each(data.items, function (item) { if (item.id) { result[item.id] = item; } } ); return { items: result }; } /** * Set data to localStorage with support check. * * @param {String} namespace * @param {Object} data */ function setLocalStorageItem(namespace, data) { try { window.localStorage.setItem(namespace, JSON.stringify(data)); } catch (e) { console.warn('localStorage is unavailable - skipping local caching of product data'); console.error(e); } } return { /** * Class name */ name: 'DataStorage', request: {}, customerDataProvider: 'product_data_storage', /** * Initialize class * * @return Chainable. */ initialize: function () { if (!this.data) { this.data = ko.observable({}); } this.initLocalStorage() .initCustomerDataReloadListener() .cachesDataFromLocalStorage() .initDataListener() .initProvideStorage() .initProviderListener(); return this; }, /** * Initialize listener to customer data reload * * @return Chainable. */ initCustomerDataReloadListener: function () { $(document).on('customer-data-invalidate', this._flushProductStorage.bind(this)); return this; }, /** * Flush product storage * * @private * @return void */ _flushProductStorage: function (event, sections) { if (_.isEmpty(sections) || _.contains(sections, 'product_data_storage')) { this.localStorage.removeAll(); } }, /** * Initialize listener to data property * * @return Chainable. */ initDataListener: function () { this.data.subscribe(this.dataHandler.bind(this)); return this; }, /** * Initialize provider storage * * @return Chainable. */ initProvideStorage: function () { this.providerHandler(customerData.get(this.customerDataProvider)()); return this; }, /** * Handler to update "data" property. * Sets data to localStorage * * @param {Object} data */ dataHandler: function (data) { if (_.isEmpty(data)) { this.localStorage.removeAll(); } else { setLocalStorageItem(this.namespace, data); } }, /** * Handler to update data in provider. * * @param {Object} data */ providerHandler: function (data) { var currentData = utils.copy(this.data()), ids = _.keys(data.items); if (data.items && ids.length) { //we can extend only items data = data.items; this.data(_.extend(currentData, data)); } }, /** * Sets data ids * * @param {String} currency * @param {String} store * @param {Object} ids */ setIds: function (currency, store, ids) { if (!this.hasInCache(currency, store, ids)) { this.loadDataFromServer(currency, store, ids); } else { this.data.valueHasMutated(); } }, /** * Gets data from "data" property by identifiers * * @param {String} currency * @param {String} store * @param {Object} productIdentifiers * * @return {Object} data. */ getDataByIdentifiers: function (currency, store, productIdentifiers) { var data = {}, dataCollection = this.data(), id; for (id in productIdentifiers) { if (productIdentifiers.hasOwnProperty(id)) { data[id] = dataCollection[id]; } } return data; }, /** * Checks has cached data or not * * @param {String} currency * @param {String} store * @param {Object} ids * * @return {Boolean} */ hasInCache: function (currency, store, ids) { var data = this.data(), id; for (id in ids) { if (!data.hasOwnProperty(id) || data[id]['currency_code'] !== currency || ~~data[id]['store_id'] !== ~~store ) { return false; } } return true; }, /** * Load data from server by ids * * @param {String} currency * @param {String} store * @param {Object} ids * * @return void */ loadDataFromServer: function (currency, store, ids) { var idsArray = _.keys(ids), prepareAjaxParams = { 'entity_id': idsArray.join(',') }; if (this.request.sent && this.hasIdsInSentRequest(ids)) { return; } this.request = { sent: true, data: ids }; this.updateRequestConfig.data = queryBuilder.buildQuery(prepareAjaxParams); this.updateRequestConfig.data['store_id'] = store; this.updateRequestConfig.data['currency_code'] = currency; $.ajax(this.updateRequestConfig).done(function (data) { this.request = {}; this.providerHandler(getParsedDataFromServer(data)); }.bind(this)); }, /** * Each product page consist product cache data, * this function prepare those data to appropriate view, and save it * * @param {Object} data */ addDataFromPageCache: function (data) { this.providerHandler(getParsedDataFromServer(data)); }, /** * @param {Object} ids * @returns {Boolean} */ hasIdsInSentRequest: function (ids) { var sentDataIds, currentDataIds; if (this.request.data) { sentDataIds = _.keys(this.request.data); currentDataIds = _.keys(ids); return _.every(currentDataIds, function (id) { return _.lastIndexOf(sentDataIds, id) !== -1; }); } return false; }, /** * Initialize provider listener * * @return Chainable. */ initProviderListener: function () { customerData.get(this.customerDataProvider).subscribe(this.providerHandler.bind(this)); return this; }, /** * Caches data from local storage to local scope * * @return Chainable. */ cachesDataFromLocalStorage: function () { this.data(this.getDataFromLocalStorage()); return this; }, /** * Gets data from local storage by current namespace * * @return {Object}. */ getDataFromLocalStorage: function () { return this.localStorage.get(); }, /** * Initialize localStorage * * @return Chainable. */ initLocalStorage: function () { this.localStorage = $.initNamespaceStorage(this.namespace).localStorage; return this; } }; }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('Magento_Catalog/js/product/storage/ids-storage-compare',[ 'underscore', 'ko', 'mageUtils', 'Magento_Customer/js/customer-data', 'Magento_Catalog/js/product/storage/ids-storage' ], function (_, ko, utils, customerData, idsStorage) { 'use strict'; return _.extend(utils.copy(idsStorage), { /** * Class name */ name: 'IdsStorageCompare', /** * Initializes class * * @return Chainable. */ initialize: function () { if (!this.data) { this.data = ko.observable({}); } if (this.provider && window.checkout && window.checkout.baseUrl) { this.providerDataHandler(customerData.get(this.provider)()); this.initProviderListener(); } this.initLocalStorage() .cachesDataFromLocalStorage() .initDataListener(); return this; }, /** * Initializes listener for external data provider */ initProviderListener: function () { customerData.get(this.provider).subscribe(this.providerDataHandler.bind(this)); }, /** * Initializes handler for external data provider update * * @param {Object} data */ providerDataHandler: function (data) { data = data.items || data; data = this.prepareData(data); this.add(data); }, /** * Prepares data to correct interface * * @param {Object} data * * @returns {Object} data */ prepareData: function (data) { var result = {}, scopeId; _.each(data, function (item) { if (typeof item.productScope !== 'undefined') { scopeId = item.productScope === 'store' ? window.checkout.storeId : item.productScope === 'group' ? window.checkout.storeGroupId : window.checkout.websiteId; result[item.productScope + '-' + scopeId + '-' + item.id] = { 'added_at': new Date().getTime() / 1000, 'product_id': item.id, 'scope_id': scopeId }; } else { result[item.id] = { 'added_at': new Date().getTime() / 1000, 'product_id': item.id }; } }); return result; } }); }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('Magento_Catalog/js/product/storage/storage-service',[ 'jquery', 'underscore', 'mageUtils', 'mage/translate', 'Magento_Catalog/js/product/storage/ids-storage', 'Magento_Catalog/js/product/storage/data-storage', 'Magento_Catalog/js/product/storage/ids-storage-compare' ], function ($, _, utils, $t, IdsStorage, DataStore, IdsStorageCompare) { 'use strict'; return (function () { var /** * {Object} storages - list of storages */ storages = {}, /** * {Object} classes - list of classes */ classes = {}, /** * {Object} prototype - methods that will be added to all storage classes to prototype property. */ prototype = { /** * Sets data to storage * * @param {*} data */ set: function (data) { if (!utils.compare(data, this.data()).equal) { this.data(data); } }, /** * Adds some data to current storage data * * @param {*} data */ add: function (data) { if (!_.isEmpty(data)) { this.data(_.extend(utils.copy(this.data()), data)); } }, /** * Gets current storage data * * @returns {*} data */ get: function () { return this.data(); } }, /** * Required properties to storage */ storagesInterface = { data: 'function', initialize: 'function', namespace: 'string' }, /** * Private service methods */ _private = { /** * Overrides class method and add ability use _super to call parent method * * @param {Object} extensionMethods * @param {Object} originInstance */ overrideClassMethods: function (extensionMethods, originInstance) { var methodsName = _.keys(extensionMethods), i = 0, length = methodsName.length; for (i; i < length; i++) { if (_.isFunction(originInstance[methodsName[i]])) { originInstance[methodsName[i]] = extensionMethods[methodsName[i]]; } } return originInstance; }, /** * Checks is storage implement interface * * @param {Object} classInstance * * @returns {Boolean} */ isImplementInterface: function (classInstance) { _.each(storagesInterface, function (key, value) { if (typeof classInstance[key] !== value) { return false; } }); return true; } }, /** * Subscribers list */ subsctibers = {}; (function () { /** * @param {Object} config * @return void */ classes[IdsStorage.name] = function (config) { _.extend(this, IdsStorage, config); }; /** * @param {Object} config * @return void */ classes[IdsStorageCompare.name] = function (config) { _.extend(this, IdsStorageCompare, config); }; /** * @param {Object} config * @return void */ classes[DataStore.name] = function (config) { _.extend(this, DataStore, config); }; _.each(classes, function (classItem) { classItem.prototype = prototype; }); })(); return { /** * Creates new storage or returns if storage with declared namespace exist * * @param {Object} config - storage config * @throws {Error} * @returns {Object} storage instance */ createStorage: function (config) { var instance, initialized; if (storages[config.namespace]) { return storages[config.namespace]; } instance = new classes[config.className](config); if (_private.isImplementInterface(instance)) { initialized = storages[config.namespace] = instance.initialize(); this.processSubscribers(initialized, config); return initialized; } throw new Error('Class ' + config.className + $t('does not implement Storage Interface')); }, /** * Process subscribers * * Differentiate subscribers by their namespaces: recently_viewed or recently_compared * and process callbacks. Callbacks can be add through onStorageInit function * * @param {Object} initialized * @param {Object} config * @return void */ processSubscribers: function (initialized, config) { if (subsctibers[config.namespace]) { _.each(subsctibers[config.namespace], function (callback) { callback(initialized); }); delete subsctibers[config.namespace]; } }, /** * Listens storage creating by namespace * * @param {String} namespace * @param {Function} callback * @return void */ onStorageInit: function (namespace, callback) { if (storages[namespace]) { callback(storages[namespace]); } else { subsctibers[namespace] ? subsctibers[namespace].push(callback) : subsctibers[namespace] = [callback]; } }, /** * Gets storage by namespace * * @param {String} namespace * * @returns {Object} storage insance */ getStorage: function (namespace) { return storages[namespace]; } }; })(); }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define('Magento_Catalog/js/storage-manager',[ 'underscore', 'uiElement', 'mageUtils', 'Magento_Catalog/js/product/storage/storage-service', 'Magento_Customer/js/section-config', 'jquery' ], function (_, Element, utils, storage, sectionConfig, $) { 'use strict'; /** * Flush events, that are clones of the same customer data sections * Events listener */ $(document).on('submit', function (event) { var sections; if (event.target.method.match(/post|put|delete/i)) { sections = sectionConfig.getAffectedSections(event.target.action); if (sections && window.localStorage) { _.each(sections, function (section) { window.localStorage.removeItem(section); }); } } }); return Element.extend({ defaults: { defaultNamespace: { lifetime: 1000 }, storagesConfiguration: { 'recently_viewed_product': { namespace: 'recently_viewed_product', className: 'IdsStorage', lifetime: '${ $.defaultNamespace.lifetime }', requestConfig: { typeId: '${ $.storagesConfiguration.recently_viewed_product.namespace }' }, savePrevious: { namespace: '${ $.storagesConfiguration.recently_viewed_product.namespace }' + '_previous', className: '${ $.storagesConfiguration.recently_viewed_product.className }' }, allowToSendRequest: 0 }, 'recently_compared_product': { namespace: 'recently_compared_product', className: 'IdsStorageCompare', provider: 'compare-products', lifetime: '${ $.defaultNamespace.lifetime }', requestConfig: { typeId: '${ $.storagesConfiguration.recently_compared_product.namespace }' }, savePrevious: { namespace: '${ $.storagesConfiguration.recently_compared_product.namespace }' + '_previous', className: '${ $.storagesConfiguration.recently_compared_product.className }' }, allowToSendRequest: 0 }, 'product_data_storage': { namespace: 'product_data_storage', className: 'DataStorage', allowToSendRequest: 0, updateRequestConfig: { url: '', method: 'GET', dataType: 'json' } } }, requestConfig: { method: 'POST', dataType: 'json', ajaxSaveType: 'default', ignoreProcessEvents: true }, requestSent: 0 }, /** * Initializes provider component. * * @returns {Object} Chainable. */ initialize: function () { this._super() .prepareStoragesConfig() .initStorages() .initStartData() .initUpdateStorageDataListener(); return this; }, /** * Initializes storages. * * @returns {Object} Chainable. */ initStorages: function () { _.each(this.storagesNamespace, function (name) { this[name] = storage.createStorage(this.storagesConfiguration[name]); if (this.storagesConfiguration[name].savePrevious) { this[name].previous = storage.createStorage(this.storagesConfiguration[name].savePrevious); } }.bind(this)); return this; }, /** * Initializes start data. * * @returns {Object} Chainable. */ initStartData: function () { _.each(this.storagesNamespace, function (name) { this.updateDataHandler(name, this[name].get()); }.bind(this)); return this; }, /** * Prepare storages congfig. * * @returns {Object} Chainable. */ prepareStoragesConfig: function () { this.storagesNamespace = _.keys(this.storagesConfiguration); _.each(this.storagesNamespace, function (name) { this.storagesConfiguration[name].requestConfig = _.extend( utils.copy(this.requestConfig), this.storagesConfiguration[name].requestConfig ); }.bind(this)); return this; }, /** * Prepare date in UTC format (in GMT), and calculate unix timestamp based in seconds * * @returns {Number} * @private */ getUtcTime: function () { return new Date().getTime() / 1000; }, /** * Initializes listeners to storages "data" property. */ initUpdateStorageDataListener: function () { _.each(this.storagesNamespace, function (name) { if (this[name].data) { this[name].data.subscribe(this.updateDataHandler.bind(this, name)); } }.bind(this)); }, /** * Handlers for storages "data" property */ updateDataHandler: function (name, data) { var previousData = this[name].previous ? this[name].previous.get() : false; if (!_.isEmpty(previousData) && !_.isEmpty(data) && !utils.compare(data, previousData).equal) { this[name].set(data); this[name].previous.set(data); this.sendRequest(name, data); } else if ( _.isEmpty(previousData) && !_.isEmpty(data) ) { this[name].set(data); this.sendRequest(name, data); } }, /** * Gets last updated time * * @param {String} name - storage name */ getLastUpdate: function (name) { return window.localStorage.getItem(this[name].namespace + '_last_update'); }, /** * Sets last updated time * * @param {String} name - storage name */ setLastUpdate: function (name) { window.localStorage.setItem(this[name].namespace + '_last_update', this.getUtcTime()); }, /** * Request handler * * @param {String} name - storage name */ requestHandler: function (name) { this.setLastUpdate(name); this.requestSent = 1; }, /** * Sends request to server to gets data * * @param {String} name - storage name * @param {Object} data - ids */ sendRequest: function (name, data) { var params = utils.copy(this.storagesConfiguration[name].requestConfig), url = params.syncUrl, typeId = params.typeId; if (this.requestSent || !~~this.storagesConfiguration[name].allowToSendRequest) { return; } delete params.typeId; delete params.url; this.requestSent = 1; return utils.ajaxSubmit({ url: url, data: { ids: data, 'type_id': typeId } }, params).done(this.requestHandler.bind(this, name)); } }); }); /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /** * @api */ define('Magento_Theme/js/view/messages',[ 'jquery', 'uiComponent', 'Magento_Customer/js/customer-data', 'underscore', 'escaper', 'jquery/jquery-storageapi' ], function ($, Component, customerData, _, escaper) { 'use strict'; return Component.extend({ defaults: { cookieMessages: [], cookieMessagesObservable: [], messages: [], allowedTags: ['div', 'span', 'b', 'strong', 'i', 'em', 'u', 'a'] }, /** * Extends Component object by storage observable messages. */ initialize: function () { this._super().observe( [ 'cookieMessagesObservable' ] ); // The "cookieMessages" variable is not used anymore. It exists for backward compatibility; to support // merchants who have overwritten "messages.phtml" which would still point to cookieMessages instead of the // observable variant (also see https://github.com/magento/magento2/pull/37309). this.cookieMessages = _.unique($.cookieStorage.get('mage-messages'), 'text'); this.cookieMessagesObservable(this.cookieMessages); this.messages = customerData.get('messages').extend({ disposableCustomerData: 'messages' }); $.mage.cookies.set('mage-messages', '', { samesite: 'strict', domain: '' }); }, /** * Prepare the given message to be rendered as HTML * * @param {String} message * @return {String} */ prepareMessageForHtml: function (message) { return escaper.escapeHtml(message, this.allowedTags); }, purgeMessages: function () { if (!_.isEmpty(this.messages().messages)) { customerData.set('messages', {}); } } }); }); /** * Copyright © Vaimo Group. All rights reserved. * See LICENSE_VAIMO.txt for license details. */ /** * Cloned vendor/magento/module-catalog/view/base/web/js/price-utils.js as in case of mixing there is still need to copy * 85% of file. And rest 15% is barely not used. * Need to clone appears to prevent corruption of globalPriceFormat with options passed inside each formatPrice call. * * @api */ define('Magento_Catalog/js/price-utils',['jquery', 'price-format-config'], function ($, priceFormatConfig) { 'use strict'; var globalPriceFormat = { requiredPrecision: 2, precision: 2, integerRequired: 1, decimalSymbol: ',', groupSymbol: ' ', groupLength: 3 }; /** * Repeats {string} {times} times * @param {String} string * @param {Number} times * @return {String} */ function stringPad(string, times) { return (new Array(times + 1)).join(string); } /** * Format the price with the compliance to the specified locale * * @param {Number} amount * @param {Object} format * @param {Boolean} isShowSign */ function formatPriceLocale(amount, format, isShowSign) { var s = '', precision, pattern, locale, r; format = _.extend(globalPriceFormat, format); precision = isNaN(format.requiredPrecision = Math.abs(format.requiredPrecision)) ? 2 : format.requiredPrecision; pattern = format.pattern || '%s'; locale = window.LOCALE || 'en-US'; if (isShowSign === undefined || isShowSign === true) { s = amount < 0 ? '-' : isShowSign ? '+' : ''; } else if (isShowSign === false) { s = ''; } pattern = pattern.indexOf('{sign}') < 0 ? s + pattern : pattern.replace('{sign}', s); amount = Number(Math.round(Math.abs(+amount || 0) + 'e+' + precision) + ('e-' + precision)); r = amount.toLocaleString(locale, {minimumFractionDigits: precision}); return pattern.replace('%s', r).replace(/^\s\s*/, '').replace(/\s\s*$/, ''); } /** * Formatter for price amount * @param {Number} amount * @param {Object} format * @param {Boolean} isShowSign * @return {String} Formatted value */ function formatPrice(amount, format, isShowSign) { var s = '', precision, integerRequired, decimalSymbol, groupSymbol, groupLength, pattern, i, pad, j, re, r, am; format = $.extend(true, {}, $.extend(true, {}, globalPriceFormat), $.extend(true, {}, priceFormatConfig), format || {}); // copied from price-option.js | Could be refactored with varien/js.js precision = isNaN(format.requiredPrecision = Math.abs(format.requiredPrecision)) ? 2 : format.requiredPrecision; integerRequired = isNaN(format.integerRequired = Math.abs(format.integerRequired)) ? 1 : format.integerRequired; decimalSymbol = format.decimalSymbol === undefined ? ',' : format.decimalSymbol; groupSymbol = format.groupSymbol === undefined ? '.' : format.groupSymbol; groupLength = format.groupLength === undefined ? 3 : format.groupLength; pattern = format.pattern || '%s'; if (isShowSign === undefined || isShowSign === true) { s = amount < 0 ? '-' : isShowSign ? '+' : ''; } else if (isShowSign === false) { s = ''; } pattern = pattern.indexOf('{sign}') < 0 ? s + pattern : pattern.replace('{sign}', s); // we're avoiding the usage of to fixed, and using round instead with the e representation to address // numbers like 1.005 = 1.01. Using ToFixed to only provide trailig zeroes in case we have a whole number i = parseInt( amount = Number(Math.round(Math.abs(+amount || 0) + 'e+' + precision) + ('e-' + precision)), 10 ) + ''; pad = i.length < integerRequired ? integerRequired - i.length : 0; i = stringPad('0', pad) + i; j = i.length > groupLength ? i.length % groupLength : 0; re = new RegExp('(\\d{' + groupLength + '})(?=\\d)', 'g'); // replace(/-/, 0) is only for fixing Safari bug which appears // when Math.abs(0).toFixed() executed on '0' number. // Result is '0.-0' :( am = Number(Math.round(Math.abs(amount - i) + 'e+' + precision) + ('e-' + precision)); r = (j ? i.substr(0, j) + groupSymbol : '') + i.substr(j).replace(re, '$1' + groupSymbol) + (precision ? decimalSymbol + am.toFixed(precision).replace(/-/, 0).slice(2) : ''); return pattern.replace('%s', r).replace(/^\s\s*/, '').replace(/\s\s*$/, ''); } /** * Deep clone of Object. Doesn't support functions * @param {Object} obj * @return {Object} */ function objectDeepClone(obj) { return JSON.parse(JSON.stringify(obj)); } /** * Helper to find ID in name attribute * @param {jQuery} element * @returns {undefined|String} */ function findOptionId(element) { var re, id, name; if (!element) { return id; } name = $(element).attr('name'); if (name.indexOf('[') !== -1) { re = /\[([^\]]+)?\]/; } else { re = /_([^\]]+)?_/; // just to support file-type-option } id = re.exec(name) && re.exec(name)[1]; if (id) { return id; } } return { formatPriceLocale: formatPriceLocale, formatPrice: formatPrice, deepClone: objectDeepClone, strPad: stringPad, findOptionId: findOptionId }; }); /** * Copyright © Vaimo Group. All rights reserved. * See LICENSE_VAIMO.txt for license details. */ define('Magento_Checkout/js/view/minicart',[ 'uiComponent', 'Magento_Customer/js/customer-data', 'jquery', 'ko', 'underscore', 'Magento_Catalog/js/price-utils', 'mage/translate', 'vaimo/overlay', 'postcodeUtils', 'uiRegistry', 'vaimo/headerState', 'mage/storage', 'jquery/jquery-storageapi' ], function (Component, customerData, $, ko, _, priceUtils, $t, overlay, postcodeUtils, registry, headerState) { 'use strict'; return Component.extend({ shoppingCartUrl: window.checkout.shoppingCartUrl, maxItemsToDisplay: window.checkout.maxItemsToDisplay, cart: {}, isLoading: ko.observable(false), addToCartCalls: 0, minicartSelector: '[data-block="minicart"]', sidebarOptions: { 'targetElement': '', 'url': { 'checkout': window.checkout.checkoutUrl, 'update': window.checkout.updateItemQtyUrl, 'remove': window.checkout.removeItemUrl, 'loginUrl': window.checkout.customerLoginUrl, 'isRedirectRequired': window.checkout.isRedirectRequired }, 'button': { 'checkout': '[data-minicart-goto-checkout]', 'remove': '[data-cart-item-remove]' }, 'showcart': { 'parent': 'span.counter', 'qty': 'span.counter-number', 'label': 'span.counter-label' }, 'minicart': { 'list': '#mini-cart', 'content': '#minicart-content-wrapper', 'qty': 'div.items-total', 'subtotal': 'div.subtotal span.price', 'maxItemsVisible': window.checkout.minicartMaxItemsVisible }, 'item': { 'qty': ':input.cart-item-qty', 'qtyText': '[data-minicart-qty-text]', 'button': ':button.update-cart-item' }, 'confirmMessage': $t('Are you sure you would like to remove this item from the shopping cart?'), 'productItemSelector': '' }, autoCloseTimeout: 3000, dropDownDialogSelector: '[data-role="dropdownDialog"]', productItemSelector: '[data-role=product-item]', deliveryMessageText: $t('You have chosen home delivery.'), afterAddToCart: 'minicart--after-add-to-cart', productSku: 'data-product-sku', availableItemIdPrefix: '#available-accessories-item-', initialize: function () { this.$filteringProductNameEl = $('<div/>'); this.filteringProductNameRegexp = /([\/.,\-:;!?|])/gmi; this.$miniCart = $(this.minicartSelector); this.$dropDownDialog = this.$miniCart.find(this.dropDownDialogSelector); this._initCartParam('minicart_is_defined')(false); this._initCartParam('summary_count').subscribe((function (value) { this._initCartParam('minicart_is_defined')(true); if (value <= 0) { this.closeMinicart(); } }).bind(this)); this.$miniCart .on('dropdowndialogopen', (function () { this.initSidebar(); this.$miniCart.removeClass(this.afterAddToCart); registry.set('initSatellitePostcode', true); }).bind(this)) .on('dropdowndialogclose', (function () { clearTimeout(this.closeCartAfterFetchTimeout); }).bind(this)) .on('contentLoading', (function () { this.addToCartCalls++; this.isLoading(true); }).bind(this)); customerData.getInitCustomerData().done(function () { var cartData = customerData.get('cart'); this.update(cartData()); cartData.subscribe(function(updatedCart) { this.addToCartCalls--; this.isLoading(this.addToCartCalls > 0); this.update(updatedCart); this.initSidebar(); $(document).on('sidebarFailedAjax', this.closeMinicart.bind(this)); }.bind(this)); if (cartData()['website_id'] !== window.checkout.websiteId) { customerData.reload(['cart'], false, false); } }.bind(this)); this.isLoading.subscribe(function(response) { if (response) { overlay.open(); headerState.setState('isMinicartLoading', true); } else { overlay.close(); headerState.setState('isMinicartLoading', false); this.$dropDownDialog.simpleDropdown('open', {noHeaderStateTrigger: true}); this.$miniCart.addClass(this.afterAddToCart); $('body').removeClass('no-scroll'); clearTimeout(this.closeCartAfterFetchTimeout); this.closeCartAfterFetchTimeout = window.setTimeout((function () { this.$dropDownDialog.simpleDropdown('close'); }).bind(this), this.autoCloseTimeout); } }.bind(this)); this.observe({deliveryMessage: this.deliveryMessageText, postcode: undefined}); return this._super(); }, initSidebar: function () { require(['sidebar'], (function(){ if (this.$miniCart.data('mageSidebar')) { this.$miniCart.sidebar('update'); } if (!$(this.productItemSelector).length) { return; } this.$miniCart.trigger('contentUpdated'); this.$miniCart.sidebar($.extend(true, { targetElement: this.$dropDownDialog, productItemSelector: this.productItemSelector }, this.sidebarOptions)); registry.set('minicartComponent', this.$miniCart); }).bind(this)); }, closeMinicart: function () { this.$dropDownDialog.simpleDropdown('close'); }, getItemRenderer: function (productType) { return this.itemRenderer[productType] || 'defaultRenderer'; }, update: function (updatedCart) { _.each(updatedCart, function (value, key) { if (!this.cart.hasOwnProperty(key)) { this.cart[key] = ko.observable(); } this.cart[key](value); }, this); }, getCartParam: function (name) { this._initCartParam(name); return this.cart[name](); }, _initCartParam: function (name) { if (!_.isUndefined(name)) { if (!this.cart.hasOwnProperty(name)) { this.cart[name] = ko.observable(); } } return this.cart[name]; }, getCartItems: function () { var result = this.getUpdatedItem(); for (var i = 0; i < result.length; i++) { result[i]['display_product_name'] = (this.$filteringProductNameEl.html(result[i]['product_name']).text() || '') .replace(this.filteringProductNameRegexp, '$1<wbr/>'); } return result; }, getUpdatedItem: function () { var result = (this.getCartParam('items') || []).slice(parseInt(-this.maxItemsToDisplay, 10)); for (var i = 0; i < result.length; i++) { const incitoResult = $('.active[data-id=' + result[i]['product_sku'] + ']').attr('data-id'); if (result[i]['product_sku'] === $(this.availableItemIdPrefix + result[i]['product_id']).attr(this.productSku)) { result[i]['is_updated'] = 'updated'; break } else if (result[i]['product_sku'] === $('.product-sku-' + result[i]['product_sku']).attr(this.productSku)) { result[i]['is_updated'] = 'updated'; break } else if (typeof incitoResult !== 'undefined' && result[i]['product_sku'] === incitoResult) { result[i]['is_updated'] = 'updated'; } } return result; }, getCartLineItemsCount: function () { var items = this.getCartParam('items') || []; return parseInt(items.length, 10); }, formatPrice: function (amount) { return priceUtils.formatPrice(amount); }, getCartCount: function () { const count = parseInt(this.getCartParam('summary_count')); return count > 99 ? '99+' : count; }, getLabelTotalPrice: function () { if (this.getCartParam('isB2b')) { return this.getCartParam('grand_total_excl_tax') } return this.getCartParam('grand_total_incl_tax'); }, isCartEmpty: function() { const hasItems = this.getCartCount() === 0; return this.getCartParam('minicart_is_defined') && hasItems }, isCartFull: function() { const hasItems = this.getCartCount() !== 0; return this.getCartParam('minicart_is_defined') && hasItems }, getFormattedPostcode: function() { const postcode = this.postcode(); return postcode ? postcodeUtils.format(postcode) : ''; } }); });