| (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; |
| }; |
| |
| if (!('URLSearchParams' in global) || (new global.URLSearchParams('?a=1').toString() !== 'a=1')) { |
| 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%20d'; |
| 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); |
| |
| // 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)) { |
| 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 |
| } |
| |
| if (anchorElement.protocol === ':' || !/:/.test(anchorElement.href)) { |
| 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)) |
| ); |