(function(global) { /** * Polyfill URLSearchParams * * Inspired from : https://github.com/WebReflection/url-search-params/blob/master/src/url-search-params.js */ var checkIfIteratorIsSupported = function() { try { return !!Symbol.iterator; } catch (error) { return false; } }; var iteratorSupported = checkIfIteratorIsSupported(); var createIterator = function(items) { var iterator = { next: function() { var value = items.shift(); return { done: value === void 0, value: value }; } }; if (iteratorSupported) { iterator[Symbol.iterator] = function() { return iterator; }; } return iterator; }; /** * Search param name and values should be encoded according to https://url.spec.whatwg.org/#urlencoded-serializing * encodeURIComponent() produces the same result except encoding spaces as `%20` instead of `+`. */ var serializeParam = function(value) { return encodeURIComponent(value).replace(/%20/g, '+'); }; var deserializeParam = function(value) { return decodeURIComponent(String(value).replace(/\+/g, ' ')); }; var polyfillURLSearchParams = function() { var URLSearchParams = function(searchString) { Object.defineProperty(this, '_entries', { writable: true, value: {} }); var typeofSearchString = typeof searchString; if (typeofSearchString === 'undefined') { // do nothing } else if (typeofSearchString === 'string') { if (searchString !== '') { this._fromString(searchString); } } else if (searchString instanceof URLSearchParams) { var _this = this; searchString.forEach(function(value, name) { _this.append(name, value); }); } else if ((searchString !== null) && (typeofSearchString === 'object')) { if (Object.prototype.toString.call(searchString) === '[object Array]') { for (var i = 0; i < searchString.length; i++) { var entry = searchString[i]; if ((Object.prototype.toString.call(entry) === '[object Array]') || (entry.length !== 2)) { this.append(entry[0], entry[1]); } else { throw new TypeError('Expected [string, any] as entry at index ' + i + ' of URLSearchParams\'s input'); } } } else { for (var key in searchString) { if (searchString.hasOwnProperty(key)) { this.append(key, searchString[key]); } } } } else { throw new TypeError('Unsupported input\'s type for URLSearchParams'); } }; var proto = URLSearchParams.prototype; proto.append = function(name, value) { if (name in this._entries) { this._entries[name].push(String(value)); } else { this._entries[name] = [String(value)]; } }; proto.delete = function(name) { delete this._entries[name]; }; proto.get = function(name) { return (name in this._entries) ? this._entries[name][0] : null; }; proto.getAll = function(name) { return (name in this._entries) ? this._entries[name].slice(0) : []; }; proto.has = function(name) { return (name in this._entries); }; proto.set = function(name, value) { this._entries[name] = [String(value)]; }; proto.forEach = function(callback, thisArg) { var entries; for (var name in this._entries) { if (this._entries.hasOwnProperty(name)) { entries = this._entries[name]; for (var i = 0; i < entries.length; i++) { callback.call(thisArg, entries[i], name, this); } } } }; proto.keys = function() { var items = []; this.forEach(function(value, name) { items.push(name); }); return createIterator(items); }; proto.values = function() { var items = []; this.forEach(function(value) { items.push(value); }); return createIterator(items); }; proto.entries = function() { var items = []; this.forEach(function(value, name) { items.push([name, value]); }); return createIterator(items); }; if (iteratorSupported) { proto[Symbol.iterator] = proto.entries; } proto.toString = function() { var searchArray = []; this.forEach(function(value, name) { searchArray.push(serializeParam(name) + '=' + serializeParam(value)); }); return searchArray.join('&'); }; global.URLSearchParams = URLSearchParams; }; var checkIfURLSearchParamsSupported = function() { try { var URLSearchParams = global.URLSearchParams; return ( (new URLSearchParams('?a=1').toString() === 'a=1') && (typeof URLSearchParams.prototype.set === 'function') && (typeof URLSearchParams.prototype.entries === 'function') ); } catch (e) { return false; } }; if (!checkIfURLSearchParamsSupported()) { polyfillURLSearchParams(); } var proto = global.URLSearchParams.prototype; if (typeof proto.sort !== 'function') { proto.sort = function() { var _this = this; var items = []; this.forEach(function(value, name) { items.push([name, value]); if (!_this._entries) { _this.delete(name); } }); items.sort(function(a, b) { if (a[0] < b[0]) { return -1; } else if (a[0] > b[0]) { return +1; } else { return 0; } }); if (_this._entries) { // force reset because IE keeps keys index _this._entries = {}; } for (var i = 0; i < items.length; i++) { this.append(items[i][0], items[i][1]); } }; } if (typeof proto._fromString !== 'function') { Object.defineProperty(proto, '_fromString', { enumerable: false, configurable: false, writable: false, value: function(searchString) { if (this._entries) { this._entries = {}; } else { var keys = []; this.forEach(function(value, name) { keys.push(name); }); for (var i = 0; i < keys.length; i++) { this.delete(keys[i]); } } searchString = searchString.replace(/^\?/, ''); var attributes = searchString.split('&'); var attribute; for (var i = 0; i < attributes.length; i++) { attribute = attributes[i].split('='); this.append( deserializeParam(attribute[0]), (attribute.length > 1) ? deserializeParam(attribute[1]) : '' ); } } }); } // HTMLAnchorElement })( (typeof global !== 'undefined') ? global : ((typeof window !== 'undefined') ? window : ((typeof self !== 'undefined') ? self : this)) ); (function(global) { /** * Polyfill URL * * Inspired from : https://github.com/arv/DOM-URL-Polyfill/blob/master/src/url.js */ var checkIfURLIsSupported = function() { try { var u = new global.URL('b', 'http://a'); u.pathname = 'c d'; return (u.href === 'http://a/c%20d') && u.searchParams; } catch (e) { return false; } }; var polyfillURL = function() { var _URL = global.URL; var URL = function(url, base) { if (typeof url !== 'string') url = String(url); if (base && typeof base !== 'string') base = String(base); // Only create another document if the base is different from current location. var doc = document, baseElement; if (base && (global.location === void 0 || base !== global.location.href)) { base = base.toLowerCase(); doc = document.implementation.createHTMLDocument(''); baseElement = doc.createElement('base'); baseElement.href = base; doc.head.appendChild(baseElement); try { if (baseElement.href.indexOf(base) !== 0) throw new Error(baseElement.href); } catch (err) { throw new Error('URL unable to set base ' + base + ' due to ' + err); } } var anchorElement = doc.createElement('a'); anchorElement.href = url; if (baseElement) { doc.body.appendChild(anchorElement); anchorElement.href = anchorElement.href; // force href to refresh } var inputElement = doc.createElement('input'); inputElement.type = 'url'; inputElement.value = url; if (anchorElement.protocol === ':' || !/:/.test(anchorElement.href) || (!inputElement.checkValidity() && !base)) { throw new TypeError('Invalid URL'); } Object.defineProperty(this, '_anchorElement', { value: anchorElement }); // create a linked searchParams which reflect its changes on URL var searchParams = new global.URLSearchParams(this.search); var enableSearchUpdate = true; var enableSearchParamsUpdate = true; var _this = this; ['append', 'delete', 'set'].forEach(function(methodName) { var method = searchParams[methodName]; searchParams[methodName] = function() { method.apply(searchParams, arguments); if (enableSearchUpdate) { enableSearchParamsUpdate = false; _this.search = searchParams.toString(); enableSearchParamsUpdate = true; } }; }); Object.defineProperty(this, 'searchParams', { value: searchParams, enumerable: true }); var search = void 0; Object.defineProperty(this, '_updateSearchParams', { enumerable: false, configurable: false, writable: false, value: function() { if (this.search !== search) { search = this.search; if (enableSearchParamsUpdate) { enableSearchUpdate = false; this.searchParams._fromString(this.search); enableSearchUpdate = true; } } } }); }; var proto = URL.prototype; var linkURLWithAnchorAttribute = function(attributeName) { Object.defineProperty(proto, attributeName, { get: function() { return this._anchorElement[attributeName]; }, set: function(value) { this._anchorElement[attributeName] = value; }, enumerable: true }); }; ['hash', 'host', 'hostname', 'port', 'protocol'] .forEach(function(attributeName) { linkURLWithAnchorAttribute(attributeName); }); Object.defineProperty(proto, 'search', { get: function() { return this._anchorElement['search']; }, set: function(value) { this._anchorElement['search'] = value; this._updateSearchParams(); }, enumerable: true }); Object.defineProperties(proto, { 'toString': { get: function() { var _this = this; return function() { return _this.href; }; } }, 'href': { get: function() { return this._anchorElement.href.replace(/\?$/, ''); }, set: function(value) { this._anchorElement.href = value; this._updateSearchParams(); }, enumerable: true }, 'pathname': { get: function() { return this._anchorElement.pathname.replace(/(^\/?)/, '/'); }, set: function(value) { this._anchorElement.pathname = value; }, enumerable: true }, 'origin': { get: function() { // get expected port from protocol var expectedPort = { 'http:': 80, 'https:': 443, 'ftp:': 21 }[this._anchorElement.protocol]; // add port to origin if, expected port is different than actual port // and it is not empty f.e http://foo:8080 // 8080 != 80 && 8080 != '' var addPortToOrigin = this._anchorElement.port != expectedPort && this._anchorElement.port !== ''; return this._anchorElement.protocol + '//' + this._anchorElement.hostname + (addPortToOrigin ? (':' + this._anchorElement.port) : ''); }, enumerable: true }, 'password': { // TODO get: function() { return ''; }, set: function(value) { }, enumerable: true }, 'username': { // TODO get: function() { return ''; }, set: function(value) { }, enumerable: true }, }); URL.createObjectURL = function(blob) { return _URL.createObjectURL.apply(_URL, arguments); }; URL.revokeObjectURL = function(url) { return _URL.revokeObjectURL.apply(_URL, arguments); }; global.URL = URL; }; if (!checkIfURLIsSupported()) { polyfillURL(); } if ((global.location !== void 0) && !('origin' in global.location)) { var getOrigin = function() { return global.location.protocol + '//' + global.location.hostname + (global.location.port ? (':' + global.location.port) : ''); }; try { Object.defineProperty(global.location, 'origin', { get: getOrigin, enumerable: true }); } catch (e) { setInterval(function() { global.location.origin = getOrigin(); }, 100); } } })( (typeof global !== 'undefined') ? global : ((typeof window !== 'undefined') ? window : ((typeof self !== 'undefined') ? self : this)) );