/******/ (function() { // webpackBootstrap /******/ var __webpack_modules__ = ([ /* 0 */, /* 1 */ /***/ (function() { /*** @module up */ window.up = { version: '2.2.0-rc1' }; /***/ }), /* 2 */ /***/ (function() { up.mockable = function (originalFn) { var spy; var mockableFn = function () { return (spy || originalFn).apply(null, arguments); }; mockableFn.mock = function () { return spy = jasmine.createSpy('mockable', originalFn); }; document.addEventListener('up:framework:reset', function () { return spy = null; }); return mockableFn; }; /***/ }), /* 3 */ /***/ (function() { var __spreadArray = (this && this.__spreadArray) || function (to, from) { for (var i = 0, il = from.length, j = to.length; i < il; i++, j++) to[j] = from[i]; return to; }; /*- Utility functions ================= The `up.util` module contains functions to facilitate the work with basic JavaScript values like lists, strings or functions. You will recognize many functions form other utility libraries like [Lodash](https://lodash.com/). While feature parity with Lodash is not a goal of `up.util`, you might find it sufficient to not include another library in your asset bundle. @module up.util */ up.util = (function () { /*- A function that does nothing. @function up.util.noop @experimental */ function noop() { } /*- A function that returns a resolved promise. @function up.util.asyncNoop @internal */ function asyncNoop() { return Promise.resolve(); } /*- Ensures that the given function can only be called a single time. Subsequent calls will return the return value of the first call. Note that this is a simple implementation that doesn't distinguish between argument lists. @function up.util.memoize @internal */ function memoize(func) { var cachedValue, cached; return function () { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } if (cached) { return cachedValue; } else { cached = true; return cachedValue = func.apply(this, args); } }; } /*- Returns if the given port is the default port for the given protocol. @function up.util.isStandardPort @internal */ function isStandardPort(protocol, port) { port = port.toString(); return (((port === "") || (port === "80")) && (protocol === 'http:')) || ((port === "443") && (protocol === 'https:')); } var NORMALIZE_URL_DEFAULTS = { host: 'cross-domain', stripTrailingSlash: false, search: true, hash: false }; /*- Normalizes the given URL or path. @function up.util.normalizeURL @param {boolean} [options.host='cross-domain'] Whether to include protocol, hostname and port in the normalized URL. By default the host is only included if it differ's from the page's hostname. @param {boolean} [options.hash=false] Whether to include an `#hash` anchor in the normalized URL @param {boolean} [options.search=true] Whether to include a `?query` string in the normalized URL @param {boolean} [options.stripTrailingSlash=false] Whether to strip a trailing slash from the pathname @return {string} The normalized URL. @internal */ function normalizeURL(urlOrAnchor, options) { options = newOptions(options, NORMALIZE_URL_DEFAULTS); var parts = parseURL(urlOrAnchor); var normalized = ''; if (options.host === 'cross-domain') { options.host = isCrossOrigin(parts); } if (options.host) { normalized += parts.protocol + "//" + parts.hostname; // Once we drop IE11 we can just use { host }, which contains port and hostname // and also handles standard ports. // See https://developer.mozilla.org/en-US/docs/Web/API/URL/host if (!isStandardPort(parts.protocol, parts.port)) { normalized += ":" + parts.port; } } var pathname = parts.pathname; if (options.stripTrailingSlash) { pathname = pathname.replace(/\/$/, ''); } normalized += pathname; if (options.search) { normalized += parts.search; } if (options.hash) { normalized += parts.hash; } return normalized; } function urlWithoutHost(url) { return normalizeURL(url, { host: false }); } function matchURLs(leftURL, rightURL) { return normalizeURL(leftURL) === normalizeURL(rightURL); } // We're calling isCrossOrigin() a lot. // Accessing location.protocol and location.hostname every time // is much slower than comparing cached strings. // https://jsben.ch/kBATt var APP_PROTOCOL = location.protocol; var APP_HOSTNAME = location.hostname; function isCrossOrigin(urlOrAnchor) { // If the given URL does not contain a hostname we know it cannot be cross-origin. // In that case we don't need to parse the URL. if (isString(urlOrAnchor) && (urlOrAnchor.indexOf('//') === -1)) { return false; } var parts = parseURL(urlOrAnchor); return (APP_HOSTNAME !== parts.hostname) || (APP_PROTOCOL !== parts.protocol); } /*- Parses the given URL into components such as hostname and path. If the given URL is not fully qualified, it is assumed to be relative to the current page. ### Example ```js let parsed = up.util.parseURL('/path?foo=value') parsed.pathname // => '/path' parsed.search // => '/?foo=value' parsed.hash // => '' ``` @function up.util.parseURL @return {Object} The parsed URL as an object with `protocol`, `hostname`, `port`, `pathname`, `search` and `hash` properties. @stable */ function parseURL(urlOrLink) { var link; if (isJQuery(urlOrLink)) { // In case someone passed us a $link, unwrap it link = up.element.get(urlOrLink); } else if (urlOrLink.pathname) { // If we are handed a parsed URL, just return it link = urlOrLink; } else { link = document.createElement('a'); link.href = urlOrLink; } // In IE11 the #hostname and #port properties of unqualified URLs are empty strings. // We can fix this by setting the link's { href } on the link itself. if (!link.hostname) { link.href = link.href; } // Some IEs don't include a leading slash in the #pathname property. // We have confirmed this in IE11 and earlier. if (link.pathname[0] !== '/') { // Only copy the link into an object when we need to (to change a property). // Note that we're parsing a lot of URLs for [up-active]. link = pick(link, ['protocol', 'hostname', 'port', 'pathname', 'search', 'hash']); link.pathname = '/' + link.pathname; } return link; } /*- @function up.util.normalizeMethod @internal */ function normalizeMethod(method) { return method ? method.toUpperCase() : 'GET'; } /*- @function up.util.methodAllowsPayload @internal */ function methodAllowsPayload(method) { return (method !== 'GET') && (method !== 'HEAD'); } // Remove with IE11 function assignPolyfill(target) { var sources = []; for (var _i = 1; _i < arguments.length; _i++) { sources[_i - 1] = arguments[_i]; } for (var _a = 0, sources_1 = sources; _a < sources_1.length; _a++) { var source = sources_1[_a]; for (var key in source) { target[key] = source[key]; } } return target; } /*- Merge the own properties of one or more `sources` into the `target` object. @function up.util.assign @param {Object} target @param {Array} sources... @stable */ var assign = Object.assign || assignPolyfill; // Remove with IE11 function valuesPolyfill(object) { return Object.keys(object).map(function (key) { return object[key]; }); } /*- Returns an array of values of the given object. @function up.util.values @param {Object} object @return {Array} @stable */ var objectValues = Object.values || valuesPolyfill; function iteratee(block) { if (isString(block)) { return function (item) { return item[block]; }; } else { return block; } } /*- Translate all items in an array to new array of items. @function up.util.map @param {Array} array @param {Function(element, index): any|String} block A function that will be called with each element and (optional) iteration index. You can also pass a property name as a String, which will be collected from each item in the array. @return {Array} A new array containing the result of each function call. @stable */ function map(array, block) { if (array.length === 0) { return []; } block = iteratee(block); var mapped = []; for (var i = 0; i < array.length; i++) { var element = array[i]; mapped.push(block(element, i)); } return mapped; } /*- @function up.util.mapObject @internal */ function mapObject(array, pairer) { var merger = function (object, pair) { object[pair[0]] = pair[1]; return object; }; return map(array, pairer).reduce(merger, {}); } /*- Calls the given function for each element (and, optional, index) of the given array. @function up.util.each @param {Array} array @param {Function(element, index)} block A function that will be called with each element and (optional) iteration index. @stable */ function each(array, block) { // note that the native Array.forEach is very slow (https://jsperf.com/fast-array-foreach) for (var i = 0; i < array.length; i++) { block(array[i], i); } } function eachIterator(iterator, callback) { var entry; while ((entry = iterator.next()) && !entry.done) { callback(entry.value); } } /*- Returns whether the given argument is `null`. @function up.util.isNull @param object @return {boolean} @stable */ function isNull(object) { return object === null; } /*- Returns whether the given argument is `undefined`. @function up.util.isUndefined @param object @return {boolean} @stable */ function isUndefined(object) { return object === undefined; } /*- Returns whether the given argument is not `undefined`. @function up.util.isDefined @param object @return {boolean} @stable */ var isDefined = negate(isUndefined); /*- Returns whether the given argument is either `undefined` or `null`. Note that empty strings or zero are *not* considered to be "missing". For the opposite of `up.util.isMissing()` see [`up.util.isGiven()`](/up.util.isGiven). @function up.util.isMissing @param object @return {boolean} @stable */ function isMissing(object) { return isUndefined(object) || isNull(object); } /*- Returns whether the given argument is neither `undefined` nor `null`. Note that empty strings or zero *are* considered to be "given". For the opposite of `up.util.isGiven()` see [`up.util.isMissing()`](/up.util.isMissing). @function up.util.isGiven @param object @return {boolean} @stable */ var isGiven = negate(isMissing); // isNan = (object) -> // isNumber(value) && value != +value /*- Return whether the given argument is considered to be blank. By default, this function returns `true` for: - `undefined` - `null` - Empty strings - Empty arrays - A plain object without own enumerable properties All other arguments return `false`. To check implement blank-ness checks for user-defined classes, see `up.util.isBlank.key`. @function up.util.isBlank @param value The value is to check. @return {boolean} Whether the value is blank. @stable */ function isBlank(value) { if (isMissing(value)) { return true; } if (isObject(value) && value[isBlank.key]) { return value[isBlank.key](); } if (isString(value) || isList(value)) { return value.length === 0; } if (isOptions(value)) { return Object.keys(value).length === 0; } return false; } /*- This property contains the name of a method that user-defined classes may implement to hook into the `up.util.isBlank()` protocol. ### Example We have a user-defined `Account` class that we want to use with `up.util.isBlank()`: ```js class Account { constructor(email) { this.email = email } [up.util.isBlank.key]() { return up.util.isBlank(this.email) } } ``` Note that the protocol method is not actually named `'up.util.isBlank.key'`. Instead it is named after the *value* of the `up.util.isBlank.key` property. To do so, the code sample above is using a [computed property name](https://medium.com/front-end-weekly/javascript-object-creation-356e504173a8) in square brackets. We may now use `Account` instances with `up.util.isBlank()`: ```js let foo = new Account('foo@foo.com') let bar = new Account('') console.log(up.util.isBlank(foo)) // prints false console.log(up.util.isBlank(bar)) // prints true ``` @property up.util.isBlank.key @experimental */ isBlank.key = 'up.util.isBlank'; /*- Returns the given argument if the argument is [present](/up.util.isPresent), otherwise returns `undefined`. @function up.util.presence @param value @param {Function(value): boolean} [tester=up.util.isPresent] The function that will be used to test whether the argument is present. @return {any|undefined} @stable */ function presence(value, tester) { if (tester === void 0) { tester = isPresent; } if (tester(value)) { return value; } } /*- Returns whether the given argument is not [blank](/up.util.isBlank). @function up.util.isPresent @param object @return {boolean} @stable */ var isPresent = negate(isBlank); /*- Returns whether the given argument is a function. @function up.util.isFunction @param object @return {boolean} @stable */ function isFunction(object) { return typeof (object) === 'function'; } /*- Returns whether the given argument is a string. @function up.util.isString @param object @return {boolean} @stable */ function isString(object) { return (typeof (object) === 'string') || object instanceof String; } /*- Returns whether the given argument is a boolean value. @function up.util.isBoolean @param object @return {boolean} @stable */ function isBoolean(object) { return (typeof (object) === 'boolean') || object instanceof Boolean; } /*- Returns whether the given argument is a number. Note that this will check the argument's *type*. It will return `false` for a string like `"123"`. @function up.util.isNumber @param object @return {boolean} @stable */ function isNumber(object) { return (typeof (object) === 'number') || object instanceof Number; } /*- Returns whether the given argument is an options hash, Differently from [`up.util.isObject()`], this returns false for functions, jQuery collections, promises, `FormData` instances and arrays. @function up.util.isOptions @param object @return {boolean} @internal */ function isOptions(object) { return (typeof (object) === 'object') && !isNull(object) && (isUndefined(object.constructor) || (object.constructor === Object)); } /*- Returns whether the given argument is an object. This also returns `true` for functions, which may behave like objects in JavaScript. @function up.util.isObject @param object @return {boolean} @stable */ function isObject(object) { var typeOfResult = typeof (object); return ((typeOfResult === 'object') && !isNull(object)) || (typeOfResult === 'function'); } /*- Returns whether the given argument is a [DOM element](https://developer.mozilla.org/de/docs/Web/API/Element). @function up.util.isElement @param object @return {boolean} @stable */ function isElement(object) { return object instanceof Element; } /*- Returns whether the given argument is a [regular expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp). @function up.util.isRegExp @param object @return {boolean} @internal */ function isRegExp(object) { return object instanceof RegExp; } /*- Returns whether the given argument is a [jQuery collection](https://learn.jquery.com/using-jquery-core/jquery-object/). @function up.util.isJQuery @param object @return {boolean} @stable */ function isJQuery(object) { return up.browser.canJQuery() && object instanceof jQuery; } /*- @function up.util.isElementish @param object @return {boolean} @internal */ function isElementish(object) { var _a; return !!(object && (object.addEventListener || ((_a = object[0]) === null || _a === void 0 ? void 0 : _a.addEventListener))); } /*- Returns whether the given argument is an object with a `then` method. @function up.util.isPromise @param object @return {boolean} @stable */ function isPromise(object) { return isObject(object) && isFunction(object.then); } /*- Returns whether the given argument is an array. @function up.util.isArray @param object @return {boolean} @stable */ // https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray var isArray = Array.isArray; /*- Returns whether the given argument is a `FormData` instance. Always returns `false` in browsers that don't support `FormData`. @function up.util.isFormData @param object @return {boolean} @internal */ function isFormData(object) { return object instanceof FormData; } /*- Converts the given [array-like value](/up.util.isList) into an array. If the given value is already an array, it is returned unchanged. @function up.util.toArray @param object @return {Array} @stable */ function toArray(value) { return isArray(value) ? value : copyArrayLike(value); } /*- Returns whether the given argument is an array-like value. Return true for `Array`, a [`NodeList`](https://developer.mozilla.org/en-US/docs/Web/API/NodeList), the [arguments object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments) or a jQuery collection. Use [`up.util.isArray()`](/up.util.isArray) to test whether a value is an actual `Array`. @function up.util.isList @param value @return {boolean} @stable */ function isList(value) { return isArray(value) || isNodeList(value) || isArguments(value) || isJQuery(value) || isHTMLCollection(value); } /*- Returns whether the given value is a [`NodeList`](https://developer.mozilla.org/en-US/docs/Web/API/NodeList). `NodeLists` are array-like objects returned by [`document.querySelectorAll()`](https://developer.mozilla.org/en-US/docs/Web/API/Element/querySelectorAll). @function up.util.isNodeList @param value @return {boolean} @internal */ function isNodeList(value) { return value instanceof NodeList; } function isHTMLCollection(value) { return value instanceof HTMLCollection; } /*- Returns whether the given value is an [arguments object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments). @function up.util.isArguments @param value @return {boolean} @internal */ function isArguments(value) { return Object.prototype.toString.call(value) === '[object Arguments]'; } function nullToUndefined(value) { if (!isNull(value)) { return value; } } /*- Returns the given value if it is [array-like](/up.util.isList), otherwise returns an array with the given value as its only element. ### Example ```js up.util.wrapList([1, 2, 3]) // => [1, 2, 3] up.util.wrapList('foo') // => ['foo'] ``` @function up.util.wrapList @param {any} value @return {Array|NodeList|jQuery} @experimental */ function wrapList(value) { if (isList(value)) { return value; } else if (isMissing(value)) { return []; } else { return [value]; } } /*- Returns a shallow copy of the given value. ### Copying protocol - By default `up.util.copy()` can copy [array-like values](/up.util.isList), plain objects and `Date` instances. - Array-like objects are copied into new arrays. - Unsupported types of values are returned unchanged. - To make the copying protocol work with user-defined class, see `up.util.copy.key`. - Immutable objects, like strings or numbers, do not need to be copied. @function up.util.copy @param {any} object @return {any} @stable */ function copy(value) { if (isObject(value) && value[copy.key]) { value = value[copy.key](); } else if (isList(value)) { value = copyArrayLike(value); } else if (isOptions(value)) { value = assign({}, value); } return value; } function copyArrayLike(arrayLike) { return Array.prototype.slice.call(arrayLike); } /*- This property contains the name of a method that user-defined classes may implement to hook into the `up.util.copy()` protocol. ### Example We have a user-defined `Account` class that we want to use with `up.util.copy()`: ```js class Account { constructor(email) { this.email = email } [up.util.copy.key]() { return new Account(this.email) } } ``` Note that the protocol method is not actually named `'up.util.copy.key'`. Instead it is named after the *value* of the `up.util.copy.key` property. To do so, the code sample above is using a [computed property name](https://medium.com/front-end-weekly/javascript-object-creation-356e504173a8) in square brackets. We may now use `Account` instances with `up.util.copy()`: ``` original = new User('foo@foo.com') copy = up.util.copy(original) console.log(copy.email) // prints 'foo@foo.com' original.email = 'bar@bar.com' // change the original console.log(copy.email) // still prints 'foo@foo.com' ``` @property up.util.copy.key @param {string} key @experimental */ copy.key = 'up.util.copy'; // Implement up.util.copy protocol for Date Date.prototype[copy.key] = function () { return new Date(+this); }; // ###** // Returns a deep copy of the given array or object. // // @function up.util.deepCopy // @param {Object|Array} object // @return {Object|Array} // @internal // ### // deepCopy = (object) -> // copy(object, true) /*- Creates a new object by merging together the properties from the given objects. @function up.util.merge @param {Array} sources... @return Object @stable */ function merge() { var sources = []; for (var _i = 0; _i < arguments.length; _i++) { sources[_i] = arguments[_i]; } return assign.apply(void 0, __spreadArray([{}], sources)); } /*- @function up.util.mergeDefined @param {Array} sources... @return Object @internal */ function mergeDefined() { var sources = []; for (var _i = 0; _i < arguments.length; _i++) { sources[_i] = arguments[_i]; } var result = {}; for (var _a = 0, sources_2 = sources; _a < sources_2.length; _a++) { var source = sources_2[_a]; if (source) { for (var key in source) { var value = source[key]; if (isDefined(value)) { result[key] = value; } } } } return result; } /*- Creates an options hash from the given argument and some defaults. The semantics of this function are confusing. We want to get rid of this in the future. @function up.util.options @param {Object} object @param {Object} [defaults] @return {Object} @internal */ function newOptions(object, defaults) { if (defaults) { return merge(defaults, object); } else if (object) { return copy(object); } else { return {}; } } function parseArgIntoOptions(args, argKey) { var options = extractOptions(args); if (isDefined(args[0])) { options = copy(options); options[argKey] = args[0]; } return options; } /*- Passes each element in the given [array-like value](/up.util.isList) to the given function. Returns the first element for which the function returns a truthy value. If no object matches, returns `undefined`. @function up.util.find @param {List} list @param {Function(value): boolean} tester @return {T|undefined} @stable */ function findInList(list, tester) { tester = iteratee(tester); var match; for (var _i = 0, list_1 = list; _i < list_1.length; _i++) { var element = list_1[_i]; if (tester(element)) { match = element; break; } } return match; } /*- Returns whether the given function returns a truthy value for any element in the given [array-like value](/up.util.isList). @function up.util.some @param {List} list @param {Function(value, index): boolean} tester A function that will be called with each element and (optional) iteration index. @return {boolean} @stable */ function some(list, tester) { return !!findResult(list, tester); } /*- Consecutively calls the given function which each element in the given array. Returns the first truthy return value. Returned `undefined` iff the function does not return a truthy value for any element in the array. @function up.util.findResult @param {Array} array @param {Function(element): any} tester A function that will be called with each element and (optional) iteration index. @return {any|undefined} @experimental */ function findResult(array, tester) { tester = iteratee(tester); for (var i = 0; i < array.length; i++) { var result = tester(array[i], i); if (result) { return result; } } } /*- Returns whether the given function returns a truthy value for all elements in the given [array-like value](/up.util.isList). @function up.util.every @param {List} list @param {Function(element, index): boolean} tester A function that will be called with each element and (optional) iteration index. @return {boolean} @experimental */ function every(list, tester) { tester = iteratee(tester); var match = true; for (var i = 0; i < list.length; i++) { if (!tester(list[i], i)) { match = false; break; } } return match; } /*- Returns all elements from the given array that are neither `null` or `undefined`. @function up.util.compact @param {Array} array @return {Array} @stable */ function compact(array) { return filterList(array, isGiven); } function compactObject(object) { return pickBy(object, isGiven); } /*- Returns the given array without duplicates. @function up.util.uniq @param {Array} array @return {Array} @stable */ function uniq(array) { if (array.length < 2) { return array; } return setToArray(arrayToSet(array)); } /*- This function is like [`uniq`](/up.util.uniq), accept that the given function is invoked for each element to generate the value for which uniquness is computed. @function up.util.uniqBy @param {Array} array @param {Function(value): any} array @return {Array} @experimental */ function uniqBy(array, mapper) { if (array.length < 2) { return array; } mapper = iteratee(mapper); var seenElements = new Set(); return filterList(array, function (elem, index) { var mapped = mapper(elem, index); if (seenElements.has(mapped)) { return false; } else { seenElements.add(mapped); return true; } }); } /*- @function up.util.setToArray @internal */ function setToArray(set) { var array = []; set.forEach(function (elem) { return array.push(elem); }); return array; } /*- @function up.util.arrayToSet @internal */ function arrayToSet(array) { var set = new Set(); array.forEach(function (elem) { return set.add(elem); }); return set; } /*- Returns all elements from the given [array-like value](/up.util.isList) that return a truthy value when passed to the given function. @function up.util.filter @param {List} list @param {Function(value, index): boolean} tester @return {Array} @stable */ function filterList(list, tester) { tester = iteratee(tester); var matches = []; each(list, function (element, index) { if (tester(element, index)) { return matches.push(element); } }); return matches; } /*- Returns all elements from the given [array-like value](/up.util.isList) that do not return a truthy value when passed to the given function. @function up.util.reject @param {List} list @param {Function(element, index): boolean} tester @return {Array} @stable */ function reject(list, tester) { tester = negate(iteratee(tester)); return filterList(list, tester); } /*- Returns the intersection of the given two arrays. Implementation is not optimized. Don't use it for large arrays. @function up.util.intersect @internal */ function intersect(array1, array2) { return filterList(array1, function (element) { return contains(array2, element); }); } /*- Waits for the given number of milliseconds, the runs the given callback. Instead of `up.util.timer(0, fn)` you can also use [`up.util.task(fn)`](/up.util.task). @function up.util.timer @param {number} millis @param {Function()} callback @return {number} The ID of the scheduled timeout. You may pass this ID to `clearTimeout()` to un-schedule the timeout. @stable */ function scheduleTimer(millis, callback) { return setTimeout(callback, millis); } /*- Pushes the given function to the [JavaScript task queue](https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/) (also "macrotask queue"). Equivalent to calling `setTimeout(fn, 0)`. Also see `up.util.microtask()`. @function up.util.task @param {Function()} block @stable */ function queueTask(task) { return setTimeout(task); } /*- Pushes the given function to the [JavaScript microtask queue](https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/). @function up.util.microtask @param {Function()} task @return {Promise} A promise that is resolved with the return value of `task`. If `task` throws an error, the promise is rejected with that error. @experimental */ function queueMicrotask(task) { return Promise.resolve().then(task); } function abortableMicrotask(task) { var aborted = false; queueMicrotask(function () { if (!aborted) { return task(); } }); return function () { return aborted = true; }; } /*- Returns the last element of the given array. @function up.util.last @param {Array} array @return {T} @stable */ function last(array) { return array[array.length - 1]; } /*- Returns whether the given value contains another value. If `value` is a string, this returns whether `subValue` is a sub-string of `value`. If `value` is an array, this returns whether `subValue` is an element of `value`. @function up.util.contains @param {Array|string} value @param {Array|string} subValue @stable */ function contains(value, subValue) { return value.indexOf(subValue) >= 0; } /*- Returns whether `object`'s entries are a superset of `subObject`'s entries. @function up.util.objectContains @param {Object} object @param {Object} subObject @internal */ function objectContains(object, subObject) { var reducedValue = pick(object, Object.keys(subObject)); return isEqual(subObject, reducedValue); } /*- Returns a copy of the given object that only contains the given keys. @function up.util.pick @param {Object} object @param {Array} keys @return {Object} @stable */ function pick(object, keys) { var filtered = {}; for (var _i = 0, keys_1 = keys; _i < keys_1.length; _i++) { var key = keys_1[_i]; if (key in object) { filtered[key] = object[key]; } } return filtered; } /*- Returns a copy of the given object that only contains properties that pass the given tester function. @function up.util.pickBy @param {Object} object @param {Function} tester A function that will be called with each property. The arguments are the property value, key and the entire object. @return {Object} @experimental */ function pickBy(object, tester) { tester = iteratee(tester); var filtered = {}; for (var key in object) { var value = object[key]; if (tester(value, key, object)) { filtered[key] = object[key]; } } return filtered; } /*- Returns a copy of the given object that contains all except the given keys. @function up.util.omit @param {Object} object @param {Array} keys @stable */ function omit(object, keys) { return pickBy(object, function (_value, key) { return !contains(keys, key); }); } /*- Returns a promise that will never be resolved. @function up.util.unresolvablePromise @internal */ function unresolvablePromise() { return new Promise(noop); } /*- Removes the given element from the given array. This changes the given array. @function up.util.remove @param {Array} array The array to change. @param {T} element The element to remove. @return {T|undefined} The removed element, or `undefined` if the array didn't contain the element. @stable */ function remove(array, element) { var index = array.indexOf(element); if (index >= 0) { array.splice(index, 1); return element; } } /*- If the given `value` is a function, calls the function with the given `args`. Otherwise it just returns `value`. ### Example ```js up.util.evalOption(5) // => 5 let fn = () => 1 + 2 up.util.evalOption(fn) // => 3 ``` @function up.util.evalOption @param {any} value @param {Array} ...args @return {any} @experimental */ function evalOption(value) { var args = []; for (var _i = 1; _i < arguments.length; _i++) { args[_i - 1] = arguments[_i]; } return isFunction(value) ? value.apply(void 0, args) : value; } var ESCAPE_HTML_ENTITY_MAP = { "&": "&", "<": "<", ">": ">", '"': '"', "'": ''' }; /*- Escapes the given string of HTML by replacing control chars with their HTML entities. @function up.util.escapeHTML @param {string} string The text that should be escaped. @stable */ function escapeHTML(string) { return string.replace(/[&<>"']/g, function (char) { return ESCAPE_HTML_ENTITY_MAP[char]; }); } /*- @function up.util.escapeRegExp @internal */ function escapeRegExp(string) { // From https://github.com/benjamingr/RegExp.escape return string.replace(/[\\^$*+?.()|[\]{}]/g, '\\$&'); } /*- Deletes the property with the given key from the given object and returns its value. @function up.util.pluckKey @param {Object} object @param {string} key @return {any} @experimental */ function pluckKey(object, key) { var value = object[key]; delete object[key]; return value; } function renameKey(object, oldKey, newKey) { return object[newKey] = pluckKey(object, oldKey); } function extractLastArg(args, tester) { if (tester(last(args))) { return args.pop(); } } // extractFirstArg = (args, tester) -> // firstArg = args[0] // if tester(firstArg) // return args.shift() function extractCallback(args) { return extractLastArg(args, isFunction); } function extractOptions(args) { return extractLastArg(args, isOptions) || {}; } // partial = (fn, fixedArgs...) -> // return (callArgs...) -> // fn.apply(this, fixedArgs.concat(callArgs)) // // partialRight = (fn, fixedArgs...) -> // return (callArgs...) -> // fn.apply(this, callArgs.concat(fixedArgs)) //function throttle(callback, limit) { // From https://jsfiddle.net/jonathansampson/m7G64/ // var wait = false // Initially, we're not waiting // return function () { // We return a throttled function // if (!wait) { // If we're not waiting // callback.call() // Execute users function // wait = true // Prevent future invocations // setTimeout(function () { // After a period of time // wait = false // And allow future invocations // }, limit) // } // } //} function identity(arg) { return arg; } // ###** // ### // parsePath = (input) -> // path = [] // pattern = /([^\.\[\]\"\']+)|\[\'([^\']+?)\'\]|\[\"([^\"]+?)\"\]|\[([^\]]+?)\]/g // while match = pattern.exec(input) // path.push(match[1] || match[2] || match[3] || match[4]) // path // ###** // Given an async function that will return a promise, returns a proxy function // with an additional `.promise` attribute. // // When the proxy is called, the inner function is called. // The proxy's `.promise` attribute is available even before the function is called // and will resolve when the inner function's returned promise resolves. // // If the inner function does not return a promise, the proxy's `.promise` attribute // will resolve as soon as the inner function returns. // // @function up.util.previewable // @internal // ### // previewable = (fun) -> // deferred = newDeferred() // preview = (args...) -> // funValue = fun(args...) // # If funValue is again a Promise, it will defer resolution of `deferred` // # until `funValue` is resolved. // deferred.resolve(funValue) // funValue // preview.promise = deferred.promise() // preview /*- @function up.util.sequence @param {Array} functions @return {Function()} A function that will call all `functions` if called. @internal */ function sequence(functions) { // No need for an expensive map() if we're passed a single function. if (functions.length === 1) { return functions[0]; } return function () { return map(functions, function (fn) { return fn(); }); }; } // ###** // @function up.util.race // @internal // ### // race = (promises...) -> // raceDone = newDeferred() // each promises, (promise) -> // promise.then -> raceDone.resolve() // raceDone.promise() // ###** // Returns `'left'` if the center of the given element is in the left 50% of the screen. // Otherwise returns `'right'`. // // @function up.util.horizontalScreenHalf // @internal // ### // horizontalScreenHalf = (element) -> // elementDims = element.getBoundingClientRect() // elementMid = elementDims.left + 0.5 * elementDims.width // screenMid = 0.5 * up.viewport.rootWidth() // if elementMid < screenMid // 'left' // else // 'right' /*- Flattens the given `array` a single depth level. ### Example ```js let nested = [1, [2, 3], [4]] up.util.flatten(nested) // => [1, 2, 3, 4] @function up.util.flatten @param {Array} array An array which might contain other arrays @return {Array} The flattened array @experimental */ function flatten(array) { var flattened = []; for (var _i = 0, array_1 = array; _i < array_1.length; _i++) { var object = array_1[_i]; if (isList(object)) { flattened.push.apply(flattened, object); } else { flattened.push(object); } } return flattened; } // flattenObject = (object) -> // result = {} // for key, value of object // result[key] = value // result /*- Maps each element using a mapping function, then [flattens](/up.util.flatten) the result into a new array. @function up.util.flatMap @param {Array} array @param {Function(element)} mapping @return {Array} @experimental */ function flatMap(array, block) { return flatten(map(array, block)); } /*- Returns whether the given value is truthy. @function up.util.isTruthy @internal */ function isTruthy(object) { return !!object; } /*- Sets the given callback as both fulfillment and rejection handler for the given promise. [Unlike `promise#finally()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/finally#Description), `up.util.always()` may change the settlement value of the given promise. @function up.util.always @internal */ function always(promise, callback) { return promise.then(callback, callback); } // mutedFinally = (promise, callback) -> // # Use finally() instead of always() so we don't accidentally // # register a rejection handler, which would prevent an "Uncaught in Exception" error. // finallyDone = promise.finally(callback) // // # Since finally's return value is itself a promise with the same state // # as `promise`, we don't want to see "Uncaught in Exception". // # If we didn't do this, we couldn't mute rejections in `promise`: // # // # promise = new Promise(...) // # promise.finally(function() { ... }) // # up.util.muteRejection(promise) // has no effect // muteRejection(finallyDone) // // # Return the original promise and *not* finally's return value. // return promise /*- Registers an empty rejection handler with the given promise. This prevents browsers from printing "Uncaught (in promise)" to the error console when the promise is rejected. This is helpful for event handlers where it is clear that no rejection handler will be registered: up.on('submit', 'form[up-target]', (event, $form) => { promise = up.submit($form) up.util.muteRejection(promise) }) Does nothing if passed a missing value. @function up.util.muteRejection @param {Promise|undefined|null} promise @return {Promise} @internal */ function muteRejection(promise) { return promise === null || promise === void 0 ? void 0 : promise.catch(noop); } /*- @function up.util.newDeferred @internal */ function newDeferred() { var resolveFn; var rejectFn; var nativePromise = new Promise(function (givenResolve, givenReject) { resolveFn = givenResolve; rejectFn = givenReject; }); nativePromise.resolve = resolveFn; nativePromise.reject = rejectFn; nativePromise.promise = function () { return nativePromise; }; // just return self return nativePromise; } // ###** // Calls the given block. If the block throws an exception, // a rejected promise is returned instead. // // @function up.util.rejectOnError // @internal // ### // rejectOnError = (block) -> // try // block() // catch error // Promise.reject(error) function asyncify(block) { // The side effects of this should be sync, otherwise we could // just do `Promise.resolve().then(block)`. try { return Promise.resolve(block()); } catch (error) { return Promise.reject(error); } } // sum = (list, block) -> // block = iteratee(block) // totalValue = 0 // for entry in list // entryValue = block(entry) // if isGiven(entryValue) # ignore undefined/null, like SQL would do // totalValue += entryValue // totalValue function isBasicObjectProperty(k) { return Object.prototype.hasOwnProperty(k); } /*- Returns whether the two arguments are equal by value. ### Comparison protocol - By default `up.util.isEqual()` can compare strings, numbers, [array-like values](/up.util.isList), plain objects and `Date` objects. - To make the copying protocol work with user-defined classes, see `up.util.isEqual.key`. - Objects without a defined comparison protocol are defined by reference (`===`). @function up.util.isEqual @param {any} a @param {any} b @return {boolean} Whether the arguments are equal by value. @experimental */ function isEqual(a, b) { if (a === null || a === void 0 ? void 0 : a.valueOf) { a = a.valueOf(); } // Date, String objects, Number objects if (b === null || b === void 0 ? void 0 : b.valueOf) { b = b.valueOf(); } // Date, String objects, Number objects if (typeof (a) !== typeof (b)) { return false; } else if (isList(a) && isList(b)) { return isEqualList(a, b); } else if (isObject(a) && a[isEqual.key]) { return a[isEqual.key](b); } else if (isOptions(a) && isOptions(b)) { var aKeys = Object.keys(a); var bKeys = Object.keys(b); if (isEqualList(aKeys, bKeys)) { return every(aKeys, function (aKey) { return isEqual(a[aKey], b[aKey]); }); } else { return false; } } else { return a === b; } } /*- This property contains the name of a method that user-defined classes may implement to hook into the `up.util.isEqual()` protocol. ### Example We have a user-defined `Account` class that we want to use with `up.util.isEqual()`: ``` class Account { constructor(email) { this.email = email } [up.util.isEqual.key](other) { return this.email === other.email } } ``` Note that the protocol method is not actually named `'up.util.isEqual.key'`. Instead it is named after the *value* of the `up.util.isEqual.key` property. To do so, the code sample above is using a [computed property name](https://medium.com/front-end-weekly/javascript-object-creation-356e504173a8) in square brackets. We may now use `Account` instances with `up.util.isEqual()`: ```js let one = new User('foo@foo.com') let two = new User('foo@foo.com') let three = new User('bar@bar.com') up.util.isEqual(one, two) // returns true up.util.isEqual(one, three) // returns false ``` @property up.util.isEqual.key @param {string} key @experimental */ isEqual.key = 'up.util.isEqual'; function isEqualList(a, b) { return (a.length === b.length) && every(a, function (elem, index) { return isEqual(elem, b[index]); }); } function splitValues(value, separator) { if (separator === void 0) { separator = ' '; } if (isString(value)) { value = value.split(separator); value = map(value, function (v) { return v.trim(); }); value = filterList(value, isPresent); return value; } else { return wrapList(value); } } function endsWith(string, search) { return string.substring(string.length - search.length) === search; } function simpleEase(x) { // easing: http://fooplot.com/?lang=de#W3sidHlwZSI6MCwiZXEiOiJ4PDAuNT8yKngqeDp4Kig0LXgqMiktMSIsImNvbG9yIjoiIzEzRjIxNyJ9LHsidHlwZSI6MCwiZXEiOiJzaW4oKHheMC43LTAuNSkqcGkpKjAuNSswLjUiLCJjb2xvciI6IiMxQTUyRUQifSx7InR5cGUiOjEwMDAsIndpbmRvdyI6WyItMS40NyIsIjEuNzgiLCItMC41NSIsIjEuNDUiXX1d // easing nice: sin((x^0.7-0.5)*pi)*0.5+0.5 // easing performant: x < 0.5 ? 2*x*x : x*(4 - x*2)-1 // https://jsperf.com/easings/1 // Math.sin((Math.pow(x, 0.7) - 0.5) * Math.PI) * 0.5 + 0.5 return x < 0.5 ? 2 * x * x : (x * (4 - (x * 2))) - 1; } function wrapValue(constructor) { var args = []; for (var _i = 1; _i < arguments.length; _i++) { args[_i - 1] = arguments[_i]; } return (args[0] instanceof constructor) ? args[0] : new (constructor.bind.apply(constructor, __spreadArray([void 0], args)))(); } // wrapArray = (objOrArray) -> // if isUndefined(objOrArray) // [] // else if isArray(objOrArray) // objOrArray // else // [objOrArray] var nextUid = 0; function uid() { return nextUid++; } /*- Returns a copy of the given list, in reversed order. @function up.util.reverse @param {List} list @return {Array} @internal */ function reverse(list) { return copy(list).reverse(); } // ###** // Returns a copy of the given `object` with the given `prefix` removed // from its camel-cased keys. // // @function up.util.unprefixKeys // @param {Object} object // @param {string} prefix // @return {Object} // @internal // ### // unprefixKeys = (object, prefix) -> // unprefixed = {} // prefixLength = prefix.length // for key, value of object // if key.indexOf(prefix) == 0 // key = unprefixCamelCase(key, prefixLength) // unprefixed[key] = value // unprefixed // replaceValue = (value, matchValue, replaceValueFn) -> // if value == matchValue // return replaceValueFn() // else // return value function renameKeys(object, renameKeyFn) { var renamed = {}; for (var key in object) { renamed[renameKeyFn(key)] = object[key]; } return renamed; } function camelToKebabCase(str) { return str.replace(/[A-Z]/g, function (char) { return '-' + char.toLowerCase(); }); } function prefixCamelCase(str, prefix) { return prefix + upperCaseFirst(str); } function unprefixCamelCase(str, prefix) { var pattern = new RegExp('^' + prefix + '(.+)$'); var match = str.match(pattern); if (match) { return lowerCaseFirst(match[1]); } } function lowerCaseFirst(str) { return str[0].toLowerCase() + str.slice(1); } function upperCaseFirst(str) { return str[0].toUpperCase() + str.slice(1); } function defineGetter(object, prop, get) { Object.defineProperty(object, prop, { get: get }); } function defineDelegates(object, props, targetProvider) { wrapList(props).forEach(function (prop) { Object.defineProperty(object, prop, { get: function () { var target = targetProvider.call(this); var value = target[prop]; if (isFunction(value)) { value = value.bind(target); } return value; }, set: function (newValue) { var target = targetProvider.call(this); target[prop] = newValue; } }); }); } function stringifyArg(arg) { var string; var maxLength = 200; var closer = ''; if (isString(arg)) { string = arg.replace(/[\n\r\t ]+/g, ' '); string = string.replace(/^[\n\r\t ]+/, ''); string = string.replace(/[\n\r\t ]$/, ''); // string = "\"#{string}\"" // closer = '"' } else if (isUndefined(arg)) { // JSON.stringify(undefined) is actually undefined string = 'undefined'; } else if (isNumber(arg) || isFunction(arg)) { string = arg.toString(); } else if (isArray(arg)) { string = "[" + map(arg, stringifyArg).join(', ') + "]"; closer = ']'; } else if (isJQuery(arg)) { string = "$(" + map(arg, stringifyArg).join(', ') + ")"; closer = ')'; } else if (isElement(arg)) { string = "<" + arg.tagName.toLowerCase(); for (var _i = 0, _a = ['id', 'name', 'class']; _i < _a.length; _i++) { var attr = _a[_i]; var value = arg.getAttribute(attr); if (value) { string += " " + attr + "=\"" + value + "\""; } } string += ">"; closer = '>'; } else if (isRegExp(arg)) { string = arg.toString(); } else { // object, array try { string = JSON.stringify(arg); } catch (error) { if (error.name === 'TypeError') { string = '(circular structure)'; } else { throw error; } } } if (string.length > maxLength) { string = string.substr(0, maxLength) + " \u2026"; string += closer; } return string; } var SPRINTF_PLACEHOLDERS = /\%[oOdisf]/g; function secondsSinceEpoch() { return Math.floor(Date.now() * 0.001); } /*- See https://developer.mozilla.org/en-US/docs/Web/API/Console#Using_string_substitutions @function up.util.sprintf @internal */ function sprintf(message) { var args = []; for (var _i = 1; _i < arguments.length; _i++) { args[_i - 1] = arguments[_i]; } return sprintfWithFormattedArgs.apply(void 0, __spreadArray([identity, message], args)); } /*- @function up.util.sprintfWithFormattedArgs @internal */ function sprintfWithFormattedArgs(formatter, message) { var args = []; for (var _i = 2; _i < arguments.length; _i++) { args[_i - 2] = arguments[_i]; } if (!message) { return ''; } var i = 0; return message.replace(SPRINTF_PLACEHOLDERS, function () { var arg = args[i]; arg = formatter(stringifyArg(arg)); i += 1; return arg; }); } // Remove with IE11. // When removed we can also remove muteRejection(), as this is the only caller. function allSettled(promises) { return Promise.all(map(promises, muteRejection)); } function negate(fn) { return function () { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } return !fn.apply(void 0, args); }; } return { parseURL: parseURL, normalizeURL: normalizeURL, urlWithoutHost: urlWithoutHost, matchURLs: matchURLs, normalizeMethod: normalizeMethod, methodAllowsPayload: methodAllowsPayload, assign: assign, assignPolyfill: assignPolyfill, copy: copy, copyArrayLike: copyArrayLike, merge: merge, mergeDefined: mergeDefined, options: newOptions, parseArgIntoOptions: parseArgIntoOptions, each: each, eachIterator: eachIterator, map: map, flatMap: flatMap, mapObject: mapObject, findResult: findResult, some: some, every: every, find: findInList, filter: filterList, reject: reject, intersect: intersect, compact: compact, compactObject: compactObject, uniq: uniq, uniqBy: uniqBy, last: last, isNull: isNull, isDefined: isDefined, isUndefined: isUndefined, isGiven: isGiven, isMissing: isMissing, isPresent: isPresent, isBlank: isBlank, presence: presence, isObject: isObject, isFunction: isFunction, isString: isString, isBoolean: isBoolean, isNumber: isNumber, isElement: isElement, isJQuery: isJQuery, isElementish: isElementish, isPromise: isPromise, isOptions: isOptions, isArray: isArray, isFormData: isFormData, isNodeList: isNodeList, isArguments: isArguments, isList: isList, isRegExp: isRegExp, timer: scheduleTimer, contains: contains, objectContains: objectContains, toArray: toArray, pick: pick, pickBy: pickBy, omit: omit, unresolvablePromise: unresolvablePromise, remove: remove, memoize: memoize, pluckKey: pluckKey, renameKey: renameKey, extractOptions: extractOptions, extractCallback: extractCallback, noop: noop, asyncNoop: asyncNoop, identity: identity, escapeHTML: escapeHTML, escapeRegExp: escapeRegExp, sequence: sequence, evalOption: evalOption, flatten: flatten, isTruthy: isTruthy, newDeferred: newDeferred, always: always, muteRejection: muteRejection, asyncify: asyncify, isBasicObjectProperty: isBasicObjectProperty, isCrossOrigin: isCrossOrigin, task: queueTask, microtask: queueMicrotask, abortableMicrotask: abortableMicrotask, isEqual: isEqual, splitValues: splitValues, endsWith: endsWith, wrapList: wrapList, wrapValue: wrapValue, simpleEase: simpleEase, values: objectValues, arrayToSet: arrayToSet, setToArray: setToArray, uid: uid, upperCaseFirst: upperCaseFirst, lowerCaseFirst: lowerCaseFirst, getter: defineGetter, delegate: defineDelegates, reverse: reverse, prefixCamelCase: prefixCamelCase, unprefixCamelCase: unprefixCamelCase, camelToKebabCase: camelToKebabCase, nullToUndefined: nullToUndefined, sprintf: sprintf, sprintfWithFormattedArgs: sprintfWithFormattedArgs, renameKeys: renameKeys, timestamp: secondsSinceEpoch, allSettled: allSettled, negate: negate }; })(); /***/ }), /* 4 */ /***/ (function() { up.error = (function () { var u = up.util; function build(message, props) { if (props === void 0) { props = {}; } if (u.isArray(message)) { message = u.sprintf.apply(u, message); } var error = new Error(message); u.assign(error, props); return error; } // Custom error classes is hard when we transpile to ES5. // Hence we create a class-like construct. // See https://webcodr.io/2018/04/why-custom-errors-in-javascript-with-babel-are-broken/ function errorInterface(name, init) { if (init === void 0) { init = build; } var fn = function () { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } var error = init.apply(void 0, args); error.name = name; return error; }; fn.is = function (error) { return error.name === name; }; fn.async = function () { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } return Promise.reject(fn.apply(void 0, args)); }; return fn; } var failed = errorInterface('up.Failed'); // Emulate the exception that aborted fetch() would throw var aborted = errorInterface('AbortError', function (message) { return build(message || 'Aborted'); }); var notImplemented = errorInterface('up.NotImplemented'); var notApplicable = errorInterface('up.NotApplicable', function (change, reason) { return build("Cannot apply change: " + change + " (" + reason + ")"); }); var invalidSelector = errorInterface('up.InvalidSelector', function (selector) { return build("Cannot parse selector: " + selector); }); function emitGlobal(error) { // Emit an ErrorEvent on window.onerror for exception tracking tools var message = error.message; up.emit(window, 'error', { message: message, error: error, log: false }); } return { failed: failed, aborted: aborted, invalidSelector: invalidSelector, notApplicable: notApplicable, notImplemented: notImplemented, emitGlobal: emitGlobal }; })(); /***/ }), /* 5 */ /***/ (function() { // This object will gain properties when users load the optional unpoly-migrate.js up.migrate = { config: {} }; /***/ }), /* 6 */ /***/ (function() { /*- Browser support =============== Unpoly supports all modern browsers. ### Chrome, Firefox, Edge, Safari Full support. ### Internet Explorer 11 Full support with a `Promise` polyfill like [es6-promise](https://github.com/stefanpenner/es6-promise) (2.4 KB).\ Support may be removed when Microsoft retires IE11 in [June 2022](https://blogs.windows.com/windowsexperience/2021/05/19/the-future-of-internet-explorer-on-windows-10-is-in-microsoft-edge/). ### Internet Explorer 10 or lower Unpoly will not boot or [run compilers](/up.compiler), leaving you with a classic server-side application. @module up.browser */ up.browser = (function () { var u = up.util; /*- Makes a full-page request, replacing the entire browser environment with a new page from the server response. Also see `up.Request#loadPage()`. @function up.browser.loadPage @param {string} options.url The URL to load. @param {string} [options.method='get'] The method for the request. Methods other than GET or POST will be [wrapped](/up.protocol.config#config.methodParam) in a POST request. @param {Object|Array|FormData|string} [options.params] @experimental */ function loadPage(requestsAttrs) { new up.Request(requestsAttrs).loadPage(); } /*- Submits the given form with a full page load. For mocking in specs. @function up.browser.submitForm @internal */ function submitForm(form) { form.submit(); } function isIE11() { return 'ActiveXObject' in window; // this is undefined, but the key is set } /*- Returns whether this browser supports manipulation of the current URL via [`history.pushState`](https://developer.mozilla.org/en-US/docs/Web/API/History/pushState). When `pushState` (e.g. through [`up.follow()`](/up.follow)), it will gracefully fall back to a full page load. Note that Unpoly will not use `pushState` if the initial page was loaded with a request method other than GET. @function up.browser.canPushState @return {boolean} @internal */ function canPushState() { // We cannot use pushState if the initial request method is a POST for two reasons: // // 1. Unpoly replaces the initial state so it can handle the pop event when the // user goes back to the initial URL later. If the initial request was a POST, // Unpoly will wrongly assumed that it can restore the state by reloading with GET. // // 2. Some browsers have a bug where the initial request method is used for all // subsequently pushed states. That means if the user reloads the page on a later // GET state, the browser will wrongly attempt a POST request. // This issue affects Safari 9 and 10 (last tested in 2017-08). // Modern Firefoxes, Chromes and IE10+ don't have this behavior. // // The way that we work around this is that we don't support pushState if the // initial request method was anything other than GET (but allow the rest of the // Unpoly framework to work). This way Unpoly will fall back to full page loads until // the framework was booted from a GET request. return history.pushState && up.protocol.initialRequestMethod() === 'GET'; } /*- Returns whether this browser supports promises. @function up.browser.canPromise @return {boolean} @internal */ function canPromise() { return !!window.Promise; } var canFormatLog = u.negate(isIE11); var canPassiveEventListener = u.negate(isIE11); // Don't memoize so a build may publish window.jQuery after Unpoly was loaded function canJQuery() { return !!window.jQuery; } // IE11: Use the browser.cookies API instead. function popCookie(name) { var _a; var value = (_a = document.cookie.match(new RegExp(name + "=(\\w+)"))) === null || _a === void 0 ? void 0 : _a[1]; if (value) { document.cookie = name + '=;Max-Age=0;Path=/'; return value; } } var getJQuery = function () { if (!canJQuery()) { up.fail('jQuery must be published as window.jQuery'); } return jQuery; }; /*- @return {boolean} @function up.browser.ensureConfirmed @param {string} options.confirm @param {boolean} options.preload @internal */ function assertConfirmed(options) { var confirmed = !options.confirm || window.confirm(options.confirm); if (!confirmed) { throw up.error.aborted('User canceled action'); } return true; } /*- Returns whether Unpoly supports the current browser. If this returns `false` Unpoly will prevent itself from booting and ignores all registered [event handlers](/up.on) and [compilers](/up.compiler). This leaves you with a classic server-side application. This is usually a better fallback than loading incompatible Javascript and causing many errors on load. @function up.browser.isSupported @stable */ function isSupported() { return !supportIssue(); } function supportIssue() { if (!canPromise()) { return "Browser doesn't support promises"; } if (document.compatMode === 'BackCompat') { return 'Browser is in quirks mode (missing DOCTYPE?)'; } } return { loadPage: loadPage, submitForm: submitForm, canPushState: canPushState, canFormatLog: canFormatLog, canPassiveEventListener: canPassiveEventListener, canJQuery: canJQuery, assertConfirmed: assertConfirmed, isSupported: isSupported, supportIssue: supportIssue, popCookie: popCookie, get jQuery() { return getJQuery(); }, isIE11: isIE11 }; })(); /***/ }), /* 7 */ /***/ (function() { var __spreadArray = (this && this.__spreadArray) || function (to, from) { for (var i = 0, il = from.length, j = to.length; i < il; i++, j++) to[j] = from[i]; return to; }; /*- DOM helpers =========== The `up.element` module offers functions for DOM manipulation and traversal. It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_obj_all.asp) and works across all [supported browsers](/up.browser). @module up.element */ up.element = (function () { var u = up.util; var MATCH_FN_NAME = up.browser.isIE11() ? 'msMatchesSelector' : 'matches'; /*- Returns the first descendant element matching the given selector. @function first @param {Element} [parent=document] The parent element whose descendants to search. If omitted, all elements in the `document` will be searched. @param {string} selector The CSS selector to match. @return {Element|undefined|null} The first element matching the selector. Returns `null` or `undefined` if no element macthes. @internal */ function first() { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } var selector = args.pop(); var root = args[0] || document; return root.querySelector(selector); } /*- Returns all descendant elements matching the given selector. @function up.element.all @param {Element} [parent=document] The parent element whose descendants to search. If omitted, all elements in the `document` will be searched. @param {string} selector The CSS selector to match. @return {NodeList|Array} A list of all elements matching the selector. Returns an empty list if there are no matches. @stable */ function all() { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } var selector = args.pop(); var root = args[0] || document; return root.querySelectorAll(selector); } /*- Returns a list of the given parent's descendants matching the given selector. The list will also include the parent element if it matches the selector itself. @function up.element.subtree @param {Element} parent The parent element for the search. @param {string} selector The CSS selector to match. @return {NodeList|Array} A list of all matching elements. @stable */ function subtree(root, selector) { var results = []; if (matches(root, selector)) { results.push(root); } results.push.apply(results, all(root, selector)); return results; } /*- Returns whether the given element is either the given root element or its descendants. @function isInSubtree @internal */ function isInSubtree(root, selectorOrElement) { var element = getOne(selectorOrElement); return root.contains(element); } /*- Returns the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree. @function up.element.closest @param {Element} element The element on which to start the search. @param {string} selector The CSS selector to match. @return {Element|null|undefined} element The matching element. Returns `null` or `undefined` if no element matches. @stable */ function closest(element, selector) { if (element.closest) { return element.closest(selector); // If the browser doesn't support Element#closest, we mimic the behavior. } else if (matches(element, selector)) { return element; } else { return ancestor(element, selector); } } /*- Returns whether the given element matches the given CSS selector. To match against a non-standard selector like `:main`, use `up.fragment.matches()` instead. @function up.element.matches @param {Element} element The element to check. @param {string} selector The CSS selector to match. @return {boolean} Whether `element` matches `selector`. @stable */ function matches(element, selector) { var _a; return (_a = element[MATCH_FN_NAME]) === null || _a === void 0 ? void 0 : _a.call(element, selector); } /*- @function up.element.ancestor @internal */ function ancestor(element, selector) { var parentElement = element.parentElement; if (parentElement) { if (matches(parentElement, selector)) { return parentElement; } else { return ancestor(parentElement, selector); } } } function around(element, selector) { return getList(closest(element, selector), subtree(element, selector)); } /*- Returns the native [Element](https://developer.mozilla.org/en-US/docs/Web/API/Element) for the given value. ### Casting rules - If given an element, returns that element. - If given a CSS selector string, returns the first element matching that selector. - If given a jQuery collection , returns the first element in the collection. Throws an error if the collection contains more than one element. - If given any other argument (`undefined`, `null`, `document`, `window`โ€ฆ), returns the argument unchanged. @function up.element.get @param {Element} [parent=document] The parent element whose descendants to search if `value` is a CSS selector string. If omitted, all elements in the `document` will be searched. @param {Element|jQuery|string} value The value to look up. @return {Element} The obtained `Element`. @stable */ function getOne() { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } var value = args.pop(); if (u.isElement(value)) { // Return an element before we run any other expensive checks return value; } else if (u.isString(value)) { return first.apply(void 0, __spreadArray(__spreadArray([], args), [value])); } else if (u.isList(value)) { if (value.length > 1) { up.fail('up.element.get(): Cannot cast multiple elements (%o) to a single element', value); } return value[0]; } else { // undefined, null, Window, Document, DocumentFragment, ... return value; } } /*- Composes a list of elements from the given arguments. ### Casting rules - If given a string, returns the all elements matching that string. - If given any other argument, returns the argument [wrapped as a list](/up.util.wrapList). ### Example ```javascript $jquery = $('.jquery') // returns jQuery (2) [div.jquery, div.jquery] nodeList = document.querySelectorAll('.node') // returns NodeList (2) [div.node, div.node] element = document.querySelector('.element') // returns Element div.element selector = '.selector' // returns String '.selector' elements = up.element.list($jquery, nodeList, undefined, element, selector) // returns [div.jquery, div.jquery, div.node, div.node, div.element, div.selector] ``` @function up.element.list @param {Array|String|undefined|null>} ...args @return {Array} @internal */ function getList() { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } return u.flatMap(args, valueToList); } function valueToList(value) { if (u.isString(value)) { return all(value); } else { return u.wrapList(value); } } // assertIsElement = (element) -> // unless u.isElement(element) // up.fail('Not an element: %o', element) /*- Removes the given element from the DOM tree. If you don't need IE11 support you may also use the built-in [`Element#remove()`](https://developer.mozilla.org/en-US/docs/Web/API/ChildNode/remove) to the same effect. @function up.element.remove @param {Element} element The element to remove. @stable */ function remove(element) { // IE does not support Element#remove() var parent = element.parentNode; if (parent) { parent.removeChild(element); } } /*- Hides the given element. The element is hidden by setting an [inline style](https://www.codecademy.com/articles/html-inline-styles) of `{ display: none }`. Also see `up.element.show()`. @function up.element.hide @param {Element} element @stable */ function hide(element) { element.style.display = 'none'; } /*- Shows the given element. Also see `up.element.hide()`. ### Limitations The element is shown by setting an [inline style](https://www.codecademy.com/articles/html-inline-styles) of `{ display: '' }`. You might have CSS rules causing the element to remain hidden after calling `up.element.show(element)`. Unpoly will not handle such cases in order to keep this function performant. As a workaround, you may manually set the `element.style.display` property. Also see discussion in jQuery issues [#88](https://github.com/jquery/jquery.com/issues/88), [#2057](https://github.com/jquery/jquery/issues/2057) and [this WHATWG mailing list post](http://lists.w3.org/Archives/Public/public-whatwg-archive/2014Apr/0094.html). @function up.element.show @param {Element} element @stable */ function show(element) { element.style.display = ''; } /*- Display or hide the given element, depending on its current visibility. @function up.element.toggle @param {Element} element @param {boolean} [newVisible] Pass `true` to show the element or `false` to hide it. If omitted, the element will be hidden if shown and shown if hidden. @stable */ function toggle(element, newVisible) { if (newVisible == null) { newVisible = !isVisible(element); } (newVisible ? show : hide)(element); } // trace = (fn) -> // (args...) -> // console.debug("Calling %o with %o", fn, args) // fn(args...) /*- Adds or removes the given class from the given element. If you don't need IE11 support you may also use the built-in [`Element#classList.toggle(className)`](https://developer.mozilla.org/en-US/docs/Web/API/Element/classList) to the same effect. @function up.element.toggleClass @param {Element} element The element for which to add or remove the class. @param {string} className The class which should be added or removed. @param {Boolean} [newPresent] Pass `true` to add the class to the element or `false` to remove it. If omitted, the class will be added if missing and removed if present. @stable */ function toggleClass(element, klass, newPresent) { var list = element.classList; if (newPresent == null) { newPresent = !list.contains(klass); } if (newPresent) { return list.add(klass); } else { return list.remove(klass); } } function toggleAttr(element, attr, value, newPresent) { if (newPresent == null) { newPresent = !element.hasAttribute(attr); } if (newPresent) { return element.setAttribute(attr, value); } else { return element.removeAttribute(attr); } } /*- Sets all key/values from the given object as attributes on the given element. ### Example up.element.setAttrs(element, { title: 'Tooltip', tabindex: 1 }) @function up.element.setAttrs @param {Element} element The element on which to set attributes. @param {Object} attributes An object of attributes to set. @stable */ function setAttrs(element, attrs) { for (var key in attrs) { var value = attrs[key]; if (u.isGiven(value)) { element.setAttribute(key, value); } else { element.removeAttribute(key); } } } function setTemporaryAttrs(element, attrs) { var oldAttrs = {}; for (var _i = 0, _a = Object.keys(attrs); _i < _a.length; _i++) { var key = _a[_i]; oldAttrs[key] = element.getAttribute(key); } setAttrs(element, attrs); return function () { return setAttrs(element, oldAttrs); }; } /*- @function up.element.metaContent @internal */ function metaContent(name) { var _a; var selector = "meta" + attributeSelector('name', name); return (_a = first(selector)) === null || _a === void 0 ? void 0 : _a.getAttribute('content'); } /*- @function up.element.insertBefore @internal */ function insertBefore(existingElement, newElement) { existingElement.insertAdjacentElement('beforebegin', newElement); } // insertAfter = (existingElement, newElement) -> // existingElement.insertAdjacentElement('afterend', newElement) /*- Replaces the given old element with the given new element. The old element will be removed from the DOM tree. If you don't need IE11 support you may also use the built-in [`Element#replaceWith()`](https://developer.mozilla.org/en-US/docs/Web/API/ChildNode/replaceWith) to the same effect. @function up.element.replace @param {Element} oldElement @param {Element} newElement @stable */ function replace(oldElement, newElement) { oldElement.parentElement.replaceChild(newElement, oldElement); } /*- Creates an element matching the given CSS selector. The created element will not yet be attached to the DOM tree. Attach it with [`Element#appendChild()`](https://developer.mozilla.org/en-US/docs/Web/API/Node/appendChild) or use `up.element.affix()` to create an attached element. Use `up.hello()` to activate JavaScript behavior within the created element. ### Examples To create an element with a given tag name: element = up.element.createFromSelector('span') // element is To create an element with a given class: element = up.element.createFromSelector('.klass') // element is
To create an element with a given ID: element = up.element.createFromSelector('#foo') // element is
To create an element with a given boolean attribute: element = up.element.createFromSelector('[attr]') // element is
To create an element with a given attribute value: element = up.element.createFromSelector('[attr="value"]') // element is
You may also pass an object of attribute names/values as a second argument: element = up.element.createFromSelector('div', { attr: 'value' }) // element is
You may set the element's inner text by passing a `{ text }` option (HTML control characters will be escaped): element = up.element.createFromSelector('div', { text: 'inner text' }) // element is
inner text
You may set the element's inner HTML by passing a `{ content }` option: element = up.element.createFromSelector('div', { content: 'inner text' }) // element is
inner text
You may set inline styles by passing an object of CSS properties as a second argument: element = up.element.createFromSelector('div', { style: { color: 'red' }}) // element is
@function up.element.createFromSelector @param {string} selector The CSS selector from which to create an element. @param {Object} [attrs] An object of attributes to set on the created element. @param {Object} [attrs.text] The [text content](https://developer.mozilla.org/en-US/docs/Web/API/Node/textContent) of the created element. @param {Object} [attrs.content] The [inner HTML](https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML) of the created element. @param {Object} [attrs.style] An object of CSS properties that will be set as the inline style of the created element. The given object may use kebab-case or camelCase keys. @return {Element} The created element. @stable */ function createFromSelector(selector, attrs) { // Extract attribute values before we do anything else. // Attribute values might contain spaces, and then we would incorrectly // split depths at that space. var attrValues = []; var selectorWithoutAttrValues = selector.replace(/\[([\w-]+)(?:[\~\|\^\$\*]?=(["'])?([^\2\]]*?)\2)?\]/g, function (_match, attrName, _quote, attrValue) { attrValues.push(attrValue || ''); return "[" + attrName + "]"; }); var depths = selectorWithoutAttrValues.split(/[ >]+/); var rootElement; var depthElement; var previousElement; var _loop_1 = function (depthSelector) { var tagName; depthSelector = depthSelector.replace(/^[\w-]+/, function (match) { tagName = match; return ''; }); depthElement = document.createElement(tagName || 'div'); if (!rootElement) { rootElement = depthElement; } depthSelector = depthSelector.replace(/\#([\w-]+)/, function (_match, id) { depthElement.id = id; return ''; }); depthSelector = depthSelector.replace(/\.([\w-]+)/g, function (_match, className) { depthElement.classList.add(className); return ''; }); // If we have stripped out attrValues at the beginning of the function, // they have been replaced with the attribute name only (as "[name]"). if (attrValues.length) { depthSelector = depthSelector.replace(/\[([\w-]+)\]/g, function (_match, attrName) { depthElement.setAttribute(attrName, attrValues.shift()); return ''; }); } if (depthSelector !== '') { throw up.error.invalidSelector(selector); } previousElement === null || previousElement === void 0 ? void 0 : previousElement.appendChild(depthElement); previousElement = depthElement; }; for (var _i = 0, depths_1 = depths; _i < depths_1.length; _i++) { var depthSelector = depths_1[_i]; _loop_1(depthSelector); } if (attrs) { var value = void 0; if (value = u.pluckKey(attrs, 'class')) { for (var _a = 0, _b = u.wrapList(value); _a < _b.length; _a++) { var klass = _b[_a]; rootElement.classList.add(klass); } } if (value = u.pluckKey(attrs, 'style')) { setInlineStyle(rootElement, value); } if (value = u.pluckKey(attrs, 'text')) { // Use .textContent instead of .innerText, since .textContent preserves line breaks. rootElement.textContent = value; } if (value = u.pluckKey(attrs, 'content')) { rootElement.innerHTML = value; } setAttrs(rootElement, attrs); } return rootElement; } /*- Creates an element matching the given CSS selector and attaches it to the given parent element. To create a detached element from a selector, see `up.element.createFromSelector()`. Use `up.hello()` to activate JavaScript behavior within the created element. ### Example ```js element = up.element.affix(document.body, '.klass') element.parentElement // returns document.body element.className // returns 'klass' ``` @function up.element.affix @param {Element} parent The parent to which to attach the created element. @param {string} [position='beforeend'] The position of the new element in relation to `parent`. Can be one of the following values: - `'beforebegin'`: Before `parent`, as a new sibling. - `'afterbegin'`: Just inside `parent`, before its first child. - `'beforeend'`: Just inside `parent`, after its last child. - `'afterend'`: After `parent`, as a new sibling. @param {string} selector The CSS selector from which to create an element. @param {Object} attrs An object of attributes to set on the created element. @param {Object} attrs.text The [text content](https://developer.mozilla.org/en-US/docs/Web/API/Node/textContent) of the created element. @param {Object} attrs.style An object of CSS properties that will be set as the inline style of the created element. The given object may use kebab-case or camelCase keys. @return {Element} The created element. @stable */ function affix(parent) { var args = []; for (var _i = 1; _i < arguments.length; _i++) { args[_i - 1] = arguments[_i]; } var position, selector; var attributes = u.extractOptions(args); if (args.length === 2) { position = args[0], selector = args[1]; } else { position = 'beforeend'; selector = args[0]; } var element = createFromSelector(selector, attributes); // https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentElement parent.insertAdjacentElement(position, element); return element; } /*- Returns a CSS selector that matches the given element as good as possible. Alias for `up.fragment.toTarget()`. @function up.element.toSelector @param {string|Element|jQuery} The element for which to create a selector. @stable */ function toSelector() { var _a; var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } return (_a = up.fragment).toTarget.apply(_a, args); } var SINGLETON_TAG_NAMES = ['HTML', 'BODY', 'HEAD', 'TITLE']; var SINGLETON_PATTERN = new RegExp('\\b(' + SINGLETON_TAG_NAMES.join('|') + ')\\b', 'i'); /*- @function up.element.isSingleton @internal */ var isSingleton = up.mockable(function (element) { return matches(element, SINGLETON_TAG_NAMES.join(',')); }); function isSingletonSelector(selector) { return SINGLETON_PATTERN.test(selector); } function elementTagName(element) { return element.tagName.toLowerCase(); } /*- @function up.element.attributeSelector @internal */ function attributeSelector(attribute, value) { value = value.replace(/"/g, '\\"'); return "[" + attribute + "=\"" + value + "\"]"; } function trueAttributeSelector(attribute) { return "[" + attribute + "]:not([" + attribute + "=false])"; } function idSelector(id) { if (id.match(/^[a-z0-9\-_]+$/i)) { return "#" + id; } else { return attributeSelector('id', id); } } /*- @function up.element.classSelector @internal */ function classSelector(klass) { klass = klass.replace(/:/g, '\\:'); return "." + klass; } /*- Always creates a full document with a root, even if the given `html` is only a fragment. @function up.element.createDocumentFromHTML @internal */ function createDocumentFromHTML(html) { return new DOMParser().parseFromString(html, 'text/html'); } /*- Creates an element from the given HTML fragment. Use `up.hello()` to activate JavaScript behavior within the created element. ### Example ```js element = up.element.createFromHTML('
text
') element.className // returns 'foo' element.children[0] // returns element element.children[0].textContent // returns 'text' ``` @function up.element.createFromHTML @stable */ function createFromHTML(html) { // (1) We cannot use createDocumentFromHTML() here, since up.ResponseDoc // needs to create