PageSourceSearch

https://www.theautochannel.com/js/url-search-params-polyfill.js

js theautochannel.com collected 2026-10-01 10:40:53 UTC 8,794 bytes, 308 lines download raw bytes

1/**
2 *
3 *
4 * @author Jerry Bendy <[email protected]>
5 * @licence MIT
6 *
7 */
8
9(function(self) {
10    'use strict';
11
12    var nativeURLSearchParams = self.URLSearchParams ? self.URLSearchParams : null,
13        isSupportObjectConstructor = nativeURLSearchParams && (new nativeURLSearchParams({a: 1})).toString() === 'a=1',
14        // There is a bug in safari 10.1 (and earlier) that incorrectly decodes `%2B` as an empty space and not a plus.
15        decodesPlusesCorrectly = nativeURLSearchParams && (new nativeURLSearchParams('s=%2B').get('s') === '+'),
16        __URLSearchParams__ = "__URLSearchParams__",
17        prototype = URLSearchParamsPolyfill.prototype,
18        iterable = !!(self.Symbol && self.Symbol.iterator);
19
20    if (nativeURLSearchParams && isSupportObjectConstructor && decodesPlusesCorrectly) {
21        return;
22    }
23
24
25    /**
26     * Make a URLSearchParams instance
27     *
28     * @param {object|string|URLSearchParams} search
29     * @constructor
30     */
31    function URLSearchParamsPolyfill(search) {
32        search = search || "";
33
34        // support construct object with another URLSearchParams instance
35        if (search instanceof URLSearchParams || search instanceof URLSearchParamsPolyfill) {
36            search = search.toString();
37        }
38        this [__URLSearchParams__] = parseToDict(search);
39    }
40
41
42    /**
43     * Appends a specified key/value pair as a new search parameter.
44     *
45     * @param {string} name
46     * @param {string} value
47     */
48    prototype.append = function(name, value) {
49        appendTo(this [__URLSearchParams__], name, value);
50    };
51
52    /**
53     * Deletes the given search parameter, and its associated value,
54     * from the list of all search parameters.
55     *
56     * @param {string} name
57     */
58    prototype.delete = function(name) {
59        delete this [__URLSearchParams__] [name];
60    };
61
62    /**
63     * Returns the first value associated to the given search parameter.
64     *
65     * @param {string} name
66     * @returns {string|null}
67     */
68    prototype.get = function(name) {
69        var dict = this [__URLSearchParams__];
70        return name in dict ? dict[name][0] : null;
71    };
72
73    /**
74     * Returns all the values association with a given search parameter.
75     *
76     * @param {string} name
77     * @returns {Array}
78     */
79    prototype.getAll = function(name) {
80        var dict = this [__URLSearchParams__];
81        return name in dict ? dict [name].slice(0) : [];
82    };
83
84    /**
85     * Returns a Boolean indicating if such a search parameter exists.
86     *
87     * @param {string} name
88     * @returns {boolean}
89     */
90    prototype.has = function(name) {
91        return name in this [__URLSearchParams__];
92    };
93
94    /**
95     * Sets the value associated to a given search parameter to
96     * the given value. If there were several values, delete the
97     * others.
98     *
99     * @param {string} name
100     * @param {string} value
101     */
102    prototype.set = function set(name, value) {
103        this [__URLSearchParams__][name] = ['' + value];
104    };
105
106    /**
107     * Returns a string containg a query string suitable for use in a URL.
108     *
109     * @returns {string}
110     */
111    prototype.toString = function() {
112        var dict = this[__URLSearchParams__], query = [], i, key, name, value;
113        for (key in dict) {
114            name = encode(key);
115            for (i = 0, value = dict[key]; i < value.length; i++) {
116                query.push(name + '=' + encode(value[i]));
117            }
118        }
119        return query.join('&');
120    };
121
122    // There is a bug in Safari 10.1 and `Proxy`ing it is not enough.
123    var forSureUsePolyfill = !decodesPlusesCorrectly;
124    var useProxy = (!forSureUsePolyfill && nativeURLSearchParams && !isSupportObjectConstructor && self.Proxy)
125    /*
126     * Apply polifill to global object and append other prototype into it
127     */
128    self.URLSearchParams = useProxy ?
129        // Safari 10.0 doesn't support Proxy, so it won't extend URLSearchParams on safari 10.0
130        new Proxy(nativeURLSearchParams, {
131            construct: function(target, args) {
132                return new target((new URLSearchParamsPolyfill(args[0]).toString()));
133            }
134        }) :
135        URLSearchParamsPolyfill;
136
137
138    var USPProto = self.URLSearchParams.prototype;
139
140    USPProto.polyfill = true;
141
142    /**
143     *
144     * @param {function} callback
145     * @param {object} thisArg
146     */
147    USPProto.forEach = USPProto.forEach || function(callback, thisArg) {
148        var dict = parseToDict(this.toString());
149        Object.getOwnPropertyNames(dict).forEach(function(name) {
150            dict[name].forEach(function(value) {
151                callback.call(thisArg, value, name, this);
152            }, this);
153        }, this);
154    };
155
156    /**
157     * Sort all name-value pairs
158     */
159    USPProto.sort = USPProto.sort || function() {
160        var dict = parseToDict(this.toString()), keys = [], k, i, j;
161        for (k in dict) {
162            keys.push(k);
163        }
164        keys.sort();
165
166        for (i = 0; i < keys.length; i++) {
167            this.delete(keys[i]);
168        }
169        for (i = 0; i < keys.length; i++) {
170            var key = keys[i], values = dict[key];
171            for (j = 0; j < values.length; j++) {
172                this.append(key, values[j]);
173            }
174        }
175    };
176
177    /**
178     * Returns an iterator allowing to go through all keys of
179     * the key/value pairs contained in this object.
180     *
181     * @returns {function}
182     */
183    USPProto.keys = USPProto.keys || function() {
184        var items = [];
185        this.forEach(function(item, name) {
186            items.push(name);
187        });
188        return makeIterator(items);
189    };
190
191    /**
192     * Returns an iterator allowing to go through all values of
193     * the key/value pairs contained in this object.
194     *
195     * @returns {function}
196     */
197    USPProto.values = USPProto.values || function() {
198        var items = [];
199        this.forEach(function(item) {
200            items.push(item);
201        });
202        return makeIterator(items);
203    };
204
205    /**
206     * Returns an iterator allowing to go through all key/value
207     * pairs contained in this object.
208     *
209     * @returns {function}
210     */
211    USPProto.entries = USPProto.entries || function() {
212        var items = [];
213        this.forEach(function(item, name) {
214            items.push([name, item]);
215        });
216        return makeIterator(items);
217    };
218
219
220    if (iterable) {
221        USPProto[self.Symbol.iterator] = USPProto[self.Symbol.iterator] || USPProto.entries;
222    }
223
224
225    function encode(str) {
226        var replace = {
227            '!': '%21',
228            "'": '%27',
229            '(': '%28',
230            ')': '%29',
231            '~': '%7E',
232            '%20': '+',
233            '%00': '\x00'
234        };
235        return encodeURIComponent(str).replace(/[!'\(\)~]|%20|%00/g, function(match) {
236            return replace[match];
237        });
238    }
239
240    function decode(str) {
241        return decodeURIComponent(str.replace(/\+/g, ' '));
242    }
243
244    function makeIterator(arr) {
245        var iterator = {
246            next: function() {
247                var value = arr.shift();
248                return {done: value === undefined, value: value};
249            }
250        };
251
252        if (iterable) {
253            iterator[self.Symbol.iterator] = function() {
254                return iterator;
255            };
256        }
257
258        return iterator;
259    }
260
261    function parseToDict(search) {
262        var dict = {};
263
264        if (typeof search === "object") {
265            for (var key in search) {
266                if (search.hasOwnProperty(key)) {
267                    appendTo(dict, key, search[key])
268                }
269            }
270
271        } else {
272            // remove first '?'
273            if (search.indexOf("?") === 0) {
274                search = search.slice(1);
275            }
276
277            var pairs = search.split("&");
278            for (var j = 0; j < pairs.length; j++) {
279                var value = pairs [j],
280                    index = value.indexOf('=');
281
282                if (-1 < index) {
283                    appendTo(dict, decode(value.slice(0, index)), decode(value.slice(index + 1)));
284
285                } else {
286                    if (value) {
287                        appendTo(dict, decode(value), '');
288                    }
289                }
290            }
291        }
292
293        return dict;
294    }
295
296    function appendTo(dict, name, value) {
297        var val = typeof value === 'string' ? value : (
298            value !== null && typeof value.toString === 'function' ? value.toString() : JSON.stringify(value)
299        )
300
301        if (name in dict) {
302            dict[name].push(val);
303        } else {
304            dict[name] = [val];
305        }
306    }
307
308})(typeof global !== 'undefined' ? global : (typeof window !== 'undefined' ? window : this));

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.