github.com/choria-io/go-choria@v0.28.1-0.20240416190746-b3bf9c7d5a45/docs/themes/hugo-theme-relearn/static/js/url.js (about)

     1  // https://github.com/inexorabletash/polyfill/blob/v0.1.25/url.js
     2  
     3  // URL Polyfill
     4  // Draft specification: https://url.spec.whatwg.org
     5  
     6  // Notes:
     7  // - Primarily useful for parsing URLs and modifying query parameters
     8  // - Should work in IE8+ and everything more modern
     9  
    10  (function (global) {
    11  	'use strict';
    12  
    13  	// Browsers may have:
    14  	// * No global URL object
    15  	// * URL with static methods only - may have a dummy constructor
    16  	// * URL with members except searchParams
    17  	// * Full URL API support
    18  	var origURL = global.URL;
    19  	var nativeURL;
    20  	try{
    21  		if( origURL ){
    22  			nativeURL = new global.URL('http://example.com');
    23  			if( 'searchParams' in nativeURL )
    24  				return;
    25  			if( !('href' in nativeURL) )
    26  				nativeURL = undefined;
    27  		}
    28  	}
    29  	catch( _ ){}
    30  
    31  	// NOTE: Doesn't do the encoding/decoding dance
    32  	function urlencoded_serialize(pairs) {
    33  		var output = '', first = true;
    34  		pairs.forEach(function (pair) {
    35  			var name = encodeURIComponent(pair.name);
    36  			var value = encodeURIComponent(pair.value);
    37  			if( !first ) output += '&';
    38  			output += name + '=' + value;
    39  			first = false;
    40  		});
    41  		return output.replace(/%20/g, '+');
    42  	}
    43  
    44  	// NOTE: Doesn't do the encoding/decoding dance
    45  	function urlencoded_parse(input, isindex) {
    46  		var sequences = input.split('&');
    47  		if( isindex && sequences[0].indexOf('=') === -1 )
    48  			sequences[0] = '=' + sequences[0];
    49  		var pairs = [];
    50  		sequences.forEach(function (bytes) {
    51  			if( bytes.length === 0 ) return;
    52  			var index = bytes.indexOf('=');
    53  			if( index !== -1 ){
    54  				var name = bytes.substring(0, index);
    55  				var value = bytes.substring(index + 1);
    56  			}
    57  			else{
    58  				name = bytes;
    59  				value = '';
    60  			}
    61  			name = name.replace(/\+/g, ' ');
    62  			value = value.replace(/\+/g, ' ');
    63  			pairs.push({ name: name, value: value });
    64  		});
    65  		var output = [];
    66  		pairs.forEach(function (pair) {
    67  			output.push({
    68  				name: decodeURIComponent(pair.name),
    69  				value: decodeURIComponent(pair.value)
    70  			});
    71  		});
    72  		return output;
    73  	}
    74  
    75  	function URLUtils(url) {
    76  		if( nativeURL )
    77  			return new origURL(url);
    78  		var anchor = document.createElement('a');
    79  		anchor.href = url;
    80  		return anchor;
    81  	}
    82  
    83  	function URLSearchParams(init) {
    84  		var $this = this;
    85  		this._list = [];
    86  
    87  		if( init === undefined || init === null )
    88  			init = '';
    89  
    90  		if( Object(init) !== init || !(init instanceof URLSearchParams) )
    91  			init = String(init);
    92  
    93  		if( typeof init === 'string' && init.substring(0, 1) === '?' )
    94  			init = init.substring(1);
    95  
    96  		if( typeof init === 'string' )
    97  			this._list = urlencoded_parse(init);
    98  		else
    99  			this._list = init._list.slice();
   100  
   101  		this._url_object = null;
   102  		this._setList = function (list) { if( !updating ) $this._list = list; };
   103  
   104  		var updating = false;
   105  		this._update_steps = function() {
   106  			if( updating ) return;
   107  			updating = true;
   108  
   109  			if( !$this._url_object ) return;
   110  
   111  			// Partial workaround for IE issue with 'about:'
   112  			if( $this._url_object.protocol === 'about:' &&
   113  				$this._url_object.pathname.indexOf('?') !== -1 ){
   114  				$this._url_object.pathname = $this._url_object.pathname.split('?')[0];
   115  			}
   116  
   117  			$this._url_object.search = urlencoded_serialize($this._list);
   118  
   119  			updating = false;
   120  		};
   121  	}
   122  
   123  	Object.defineProperties(URLSearchParams.prototype, {
   124  		append: {
   125  			value: function (name, value) {
   126  				this._list.push({ name: name, value: value });
   127  				this._update_steps();
   128  			}, writable: true, enumerable: true, configurable: true
   129  		},
   130  
   131  		'delete': {
   132  			value: function (name) {
   133  				for( var i = 0; i < this._list.length; ){
   134  					if( this._list[i].name === name )
   135  						this._list.splice(i, 1);
   136  					else
   137  						++i;
   138  				}
   139  				this._update_steps();
   140  			}, writable: true, enumerable: true, configurable: true
   141  		},
   142  
   143  		get: {
   144  			value: function (name) {
   145  				for( var i = 0; i < this._list.length; ++i ){
   146  					if( this._list[i].name === name )
   147  						return this._list[i].value;
   148  				}
   149  				return null;
   150  			}, writable: true, enumerable: true, configurable: true
   151  		},
   152  
   153  		getAll: {
   154  			value: function (name) {
   155  				var result = [];
   156  				for( var i = 0; i < this._list.length; ++i ){
   157  					if( this._list[i].name === name )
   158  						result.push(this._list[i].value);
   159  				}
   160  				return result;
   161  			}, writable: true, enumerable: true, configurable: true
   162  		},
   163  
   164  		has: {
   165  			value: function (name) {
   166  				for( var i = 0; i < this._list.length; ++i ){
   167  					if( this._list[i].name === name )
   168  						return true;
   169  				}
   170  				return false;
   171  			}, writable: true, enumerable: true, configurable: true
   172  		},
   173  
   174  		set: {
   175  			value: function (name, value) {
   176  				var found = false;
   177  				for( var i = 0; i < this._list.length; ){
   178  					if( this._list[i].name === name ){
   179  						if( !found ){
   180  							this._list[i].value = value;
   181  							found = true;
   182  							++i;
   183  						}
   184  						else{
   185  							this._list.splice(i, 1);
   186  						}
   187  					}
   188  					else{
   189  						++i;
   190  					}
   191  				}
   192  
   193  				if( !found )
   194  					this._list.push({ name: name, value: value });
   195  
   196  				this._update_steps();
   197  			}, writable: true, enumerable: true, configurable: true
   198  		},
   199  
   200  		entries: {
   201  			value: function() {
   202  				var $this = this, index = 0;
   203  				return { next: function() {
   204  					if( index >= $this._list.length )
   205  						return {done: true, value: undefined};
   206  					var pair = $this._list[index++];
   207  					return {done: false, value: [pair.name, pair.value]};
   208  				}};
   209  			}, writable: true, enumerable: true, configurable: true
   210  		},
   211  
   212  		keys: {
   213  			value: function() {
   214  				var $this = this, index = 0;
   215  				return { next: function() {
   216  					if( index >= $this._list.length )
   217  						return {done: true, value: undefined};
   218  					var pair = $this._list[index++];
   219  					return {done: false, value: pair.name};
   220  				}};
   221  			}, writable: true, enumerable: true, configurable: true
   222  		},
   223  
   224  		values: {
   225  			value: function() {
   226  				var $this = this, index = 0;
   227  				return { next: function() {
   228  					if( index >= $this._list.length )
   229  						return {done: true, value: undefined};
   230  					var pair = $this._list[index++];
   231  					return {done: false, value: pair.value};
   232  				}};
   233  			}, writable: true, enumerable: true, configurable: true
   234  		},
   235  
   236  		forEach: {
   237  			value: function(callback) {
   238  				var thisArg = (arguments.length > 1) ? arguments[1] : undefined;
   239  				this._list.forEach(function(pair, _index) {
   240  					callback.call(thisArg, pair.name, pair.value);
   241  				});
   242  
   243  			}, writable: true, enumerable: true, configurable: true
   244  		},
   245  
   246  		toString: {
   247  			value: function () {
   248  				return urlencoded_serialize(this._list);
   249  			}, writable: true, enumerable: false, configurable: true
   250  		}
   251  	});
   252  
   253  	if( 'Symbol' in global && 'iterator' in global.Symbol ){
   254  		Object.defineProperty(URLSearchParams.prototype, global.Symbol.iterator, {
   255  			value: URLSearchParams.prototype.entries,
   256  			writable: true, enumerable: true, configurable: true});
   257  	}
   258  
   259  	function URL(url, base) {
   260  		if( !(this instanceof global.URL) )
   261  			throw new TypeError('Failed to construct "URL": Please use the "new" operator.');
   262  
   263  		if( base ){
   264  			url = (function () {
   265  				if( nativeURL ) return new origURL(url, base).href;
   266  
   267  				var doc;
   268  				// Use another document/base tag/anchor for relative URL resolution, if possible
   269  				if( document.implementation && document.implementation.createHTMLDocument ){
   270  					doc = document.implementation.createHTMLDocument('');
   271  				}
   272  				else if( document.implementation && document.implementation.createDocument ){
   273  					doc = document.implementation.createDocument('http://www.w3.org/1999/xhtml', 'html', null);
   274  					doc.documentElement.appendChild(doc.createElement('head'));
   275  					doc.documentElement.appendChild(doc.createElement('body'));
   276  				}
   277  				else if( window.ActiveXObject ){
   278  					doc = new window.ActiveXObject('htmlfile');
   279  					doc.write('<head></head><body></body>');
   280  					doc.close();
   281  				}
   282  
   283  				if( !doc ) throw Error('base not supported');
   284  
   285  				var baseTag = doc.createElement('base');
   286  				baseTag.href = base;
   287  				doc.getElementsByTagName('head')[0].appendChild(baseTag);
   288  				var anchor = doc.createElement('a');
   289  				anchor.href = url;
   290  				return anchor.href;
   291  			}());
   292  		}
   293  
   294  		// An inner object implementing URLUtils (either a native URL
   295  		// object or an HTMLAnchorElement instance) is used to perform the
   296  		// URL algorithms. With full ES5 getter/setter support, return a
   297  		// regular object For IE8's limited getter/setter support, a
   298  		// different HTMLAnchorElement is returned with properties
   299  		// overridden
   300  
   301  		var instance = URLUtils(url || '');
   302  
   303  		// Detect for ES5 getter/setter support
   304  		// (an Object.defineProperties polyfill that doesn't support getters/setters may throw)
   305  		var ES5_GET_SET = (function() {
   306  			if( !('defineProperties' in Object) ) return false;
   307  			try{
   308  				var obj = {};
   309  				Object.defineProperties(obj, { prop: { 'get': function () { return true; } } });
   310  				return obj.prop;
   311  			}
   312  			catch( _ ){
   313  				return false;
   314  			}
   315  		})();
   316  
   317  		var self = ES5_GET_SET ? this : document.createElement('a');
   318  
   319  		var query_object = new URLSearchParams(
   320  			instance.search ? instance.search.substring(1) : null);
   321  		query_object._url_object = self;
   322  
   323  		Object.defineProperties(self, {
   324  			href: {
   325  				get: function () { return instance.href; },
   326  				set: function (v) { instance.href = v; tidy_instance(); update_steps(); },
   327  				enumerable: true, configurable: true
   328  			},
   329  			origin: {
   330  				get: function () {
   331  					if( 'origin' in instance ) return instance.origin;
   332  					return this.protocol + '//' + this.host;
   333  				},
   334  				enumerable: true, configurable: true
   335  			},
   336  			protocol: {
   337  				get: function () { return instance.protocol; },
   338  				set: function (v) { instance.protocol = v; },
   339  				enumerable: true, configurable: true
   340  			},
   341  			username: {
   342  				get: function () { return instance.username; },
   343  				set: function (v) { instance.username = v; },
   344  				enumerable: true, configurable: true
   345  			},
   346  			password: {
   347  				get: function () { return instance.password; },
   348  				set: function (v) { instance.password = v; },
   349  				enumerable: true, configurable: true
   350  			},
   351  			host: {
   352  				get: function () {
   353  					// IE returns default port in |host|
   354  					var re = {'http:': /:80$/, 'https:': /:443$/, 'ftp:': /:21$/}[instance.protocol];
   355  					return re ? instance.host.replace(re, '') : instance.host;
   356  				},
   357  				set: function (v) { instance.host = v; },
   358  				enumerable: true, configurable: true
   359  			},
   360  			hostname: {
   361  				get: function () { return instance.hostname; },
   362  				set: function (v) { instance.hostname = v; },
   363  				enumerable: true, configurable: true
   364  			},
   365  			port: {
   366  				get: function () { return instance.port; },
   367  				set: function (v) { instance.port = v; },
   368  				enumerable: true, configurable: true
   369  			},
   370  			pathname: {
   371  				get: function () {
   372  					// IE does not include leading '/' in |pathname|
   373  					if( instance.pathname.charAt(0) !== '/' ) return '/' + instance.pathname;
   374  					return instance.pathname;
   375  				},
   376  				set: function (v) { instance.pathname = v; },
   377  				enumerable: true, configurable: true
   378  			},
   379  			search: {
   380  				get: function () { return instance.search; },
   381  				set: function (v) {
   382  					if( instance.search === v ) return;
   383  					instance.search = v; tidy_instance(); update_steps();
   384  				},
   385  				enumerable: true, configurable: true
   386  			},
   387  			searchParams: {
   388  				get: function () { return query_object; },
   389  				enumerable: true, configurable: true
   390  			},
   391  			hash: {
   392  				get: function () { return instance.hash; },
   393  				set: function (v) { instance.hash = v; tidy_instance(); },
   394  				enumerable: true, configurable: true
   395  			},
   396  			toString: {
   397  				value: function() { return instance.toString(); },
   398  				enumerable: false, configurable: true
   399  			},
   400  			valueOf: {
   401  				value: function() { return instance.valueOf(); },
   402  				enumerable: false, configurable: true
   403  			}
   404  		});
   405  
   406  		function tidy_instance() {
   407  			var href = instance.href.replace(/#$|\?$|\?(?=#)/g, '');
   408  			if( instance.href !== href )
   409  				instance.href = href;
   410  		}
   411  
   412  		function update_steps() {
   413  			query_object._setList(instance.search ? urlencoded_parse(instance.search.substring(1)) : []);
   414  			query_object._update_steps();
   415  		}
   416  
   417  		return self;
   418  	}
   419  
   420  	if( origURL ){
   421  		for( var i in origURL ){
   422  			if( Object.prototype.hasOwnProperty.call(origURL, i) && typeof origURL[i] === 'function' )
   423  				URL[i] = origURL[i];
   424  		}
   425  	}
   426  
   427  	global.URL = URL;
   428  	global.URLSearchParams = URLSearchParams;
   429  
   430  }( typeof self !== 'undefined' ? self : this ));