Skip to content

Commit 3a096bc

Browse files
committed
Added window.URL polyfill.
fix phaserjs#3069
1 parent 8e0c4ad commit 3a096bc

2 files changed

Lines changed: 323 additions & 0 deletions

File tree

v3/src/polyfills/URL.js

Lines changed: 322 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,322 @@
1+
var g = (typeof global !== 'undefined') ? global
2+
: ((typeof window !== 'undefined') ? window
3+
: ((typeof self !== 'undefined') ? self : this));
4+
5+
6+
(function(global) {
7+
/**
8+
* Polyfill URLSearchParams
9+
*
10+
* Inspired from : https://github.com/WebReflection/url-search-params/blob/master/src/url-search-params.js
11+
*/
12+
13+
var checkIfIteratorIsSupported = function() {
14+
try {
15+
return !!Symbol.iterator;
16+
} catch(error) {
17+
return false;
18+
}
19+
};
20+
21+
22+
var iteratorSupported = checkIfIteratorIsSupported();
23+
24+
var createIterator = function(items) {
25+
var iterator = {
26+
next: function() {
27+
var value = items.shift();
28+
return { done: value === void 0, value: value };
29+
}
30+
};
31+
32+
if(iteratorSupported) {
33+
iterator[Symbol.iterator] = function() {
34+
return iterator;
35+
};
36+
}
37+
38+
return iterator;
39+
};
40+
41+
var polyfillURLSearchParams= function() {
42+
43+
var URLSearchParams = function(searchString) {
44+
Object.defineProperty(this, '_entries', { value: {} });
45+
46+
if(typeof searchString === 'string') {
47+
if(searchString !== '') {
48+
searchString = searchString.replace(/^\?/, '');
49+
var attributes = searchString.split('&');
50+
var attribute;
51+
for(var i = 0; i < attributes.length; i++) {
52+
attribute = attributes[i].split('=');
53+
this.append(
54+
decodeURIComponent(attribute[0]),
55+
(attribute.length > 1) ? decodeURIComponent(attribute[1]) : ''
56+
);
57+
}
58+
}
59+
} else if(searchString instanceof URLSearchParams) {
60+
var _this = this;
61+
searchString.forEach(function(value, name) {
62+
_this.append(value, name);
63+
});
64+
}
65+
};
66+
67+
var proto = URLSearchParams.prototype;
68+
69+
proto.append = function(name, value) {
70+
if(name in this._entries) {
71+
this._entries[name].push(value.toString());
72+
} else {
73+
this._entries[name] = [value.toString()];
74+
}
75+
};
76+
77+
proto.delete = function(name) {
78+
delete this._entries[name];
79+
};
80+
81+
proto.get = function(name) {
82+
return (name in this._entries) ? this._entries[name][0] : null;
83+
};
84+
85+
proto.getAll = function(name) {
86+
return (name in this._entries) ? this._entries[name].slice(0) : [];
87+
};
88+
89+
proto.has = function(name) {
90+
return (name in this._entries);
91+
};
92+
93+
proto.set = function(name, value) {
94+
this._entries[name] = [value.toString()];
95+
};
96+
97+
proto.forEach = function(callback, thisArg) {
98+
var entries;
99+
for(var name in this._entries) {
100+
if(this._entries.hasOwnProperty(name)) {
101+
entries = this._entries[name];
102+
for(var i = 0; i < entries.length; i++) {
103+
callback.call(thisArg, entries[i], name, this);
104+
}
105+
}
106+
}
107+
};
108+
109+
proto.keys = function() {
110+
var items = [];
111+
this.forEach(function(value, name) { items.push(name); });
112+
return createIterator(items);
113+
};
114+
115+
proto.values = function() {
116+
var items = [];
117+
this.forEach(function(value) { items.push(value); });
118+
return createIterator(items);
119+
};
120+
121+
proto.entries = function() {
122+
var items = [];
123+
this.forEach(function(value, name) { items.push([name, value]); });
124+
return createIterator(items);
125+
};
126+
127+
if(iteratorSupported) {
128+
proto[Symbol.iterator] = proto.entries;
129+
}
130+
131+
proto.toString = function() {
132+
var searchString = '';
133+
this.forEach(function(value, name) {
134+
if(searchString.length > 0) searchString+= '&';
135+
searchString += encodeURIComponent(name) + '=' + encodeURIComponent(value);
136+
});
137+
return searchString;
138+
};
139+
140+
global.URLSearchParams = URLSearchParams;
141+
};
142+
143+
if(!('URLSearchParams' in global)) {
144+
polyfillURLSearchParams();
145+
}
146+
147+
// HTMLAnchorElement
148+
149+
})(g);
150+
151+
(function(global) {
152+
/**
153+
* Polyfill URL
154+
*
155+
* Inspired from : https://github.com/arv/DOM-URL-Polyfill/blob/master/src/url.js
156+
*/
157+
158+
var checkIfURLIsSupported = function() {
159+
try {
160+
var u = new URL('b', 'http://a');
161+
u.pathname = 'c%20d';
162+
return (u.href === 'http://a/c%20d') && u.searchParams;
163+
} catch(e) {
164+
return false;
165+
}
166+
};
167+
168+
169+
var polyfillURL = function() {
170+
var _URL = global.URL;
171+
172+
var URL = function(url, base) {
173+
if(typeof url !== 'string') throw new TypeError('Failed to construct \'URL\': Invalid URL');
174+
175+
var doc = document.implementation.createHTMLDocument('');
176+
window.doc = doc;
177+
if(base) {
178+
var baseElement = doc.createElement('base');
179+
baseElement.href = base;
180+
doc.head.appendChild(baseElement);
181+
}
182+
183+
var anchorElement = doc.createElement('a');
184+
anchorElement.href = url;
185+
doc.body.appendChild(anchorElement);
186+
anchorElement.href = anchorElement.href; // force href to refresh
187+
188+
if(anchorElement.protocol === ':' || !/:/.test(anchorElement.href)) {
189+
throw new TypeError('Invalid URL');
190+
}
191+
192+
Object.defineProperty(this, '_anchorElement', {
193+
value: anchorElement
194+
});
195+
};
196+
197+
var proto = URL.prototype;
198+
199+
var linkURLWithAnchorAttribute = function(attributeName) {
200+
Object.defineProperty(proto, attributeName, {
201+
get: function() {
202+
return this._anchorElement[attributeName];
203+
},
204+
set: function(value) {
205+
this._anchorElement[attributeName] = value;
206+
},
207+
enumerable: true
208+
});
209+
};
210+
211+
['hash', 'host', 'hostname', 'port', 'protocol', 'search']
212+
.forEach(function(attributeName) {
213+
linkURLWithAnchorAttribute(attributeName);
214+
});
215+
216+
Object.defineProperties(proto, {
217+
218+
'toString': {
219+
get: function() {
220+
var _this = this;
221+
return function() {
222+
return _this.href;
223+
};
224+
}
225+
},
226+
227+
'href' : {
228+
get: function() {
229+
return this._anchorElement.href.replace(/\?$/,'');
230+
},
231+
set: function(value) {
232+
this._anchorElement.href = value;
233+
},
234+
enumerable: true
235+
},
236+
237+
'pathname' : {
238+
get: function() {
239+
return this._anchorElement.pathname.replace(/(^\/?)/,'/');
240+
},
241+
set: function(value) {
242+
this._anchorElement.pathname = value;
243+
},
244+
enumerable: true
245+
},
246+
247+
'origin': {
248+
get: function() {
249+
return this._anchorElement.protocol + '//' + this._anchorElement.hostname + (this._anchorElement.port ? (':' + this._anchorElement.port) : '');
250+
},
251+
enumerable: true
252+
},
253+
254+
'password': { // TODO
255+
get: function() {
256+
return '';
257+
},
258+
set: function(value) {
259+
},
260+
enumerable: true
261+
},
262+
263+
'username': { // TODO
264+
get: function() {
265+
return '';
266+
},
267+
set: function(value) {
268+
},
269+
enumerable: true
270+
},
271+
272+
'searchParams': {
273+
get: function() {
274+
var searchParams = new URLSearchParams(this.search);
275+
var _this = this;
276+
['append', 'delete', 'set'].forEach(function(methodName) {
277+
var method = searchParams[methodName];
278+
searchParams[methodName] = function() {
279+
method.apply(searchParams, arguments);
280+
_this.search = searchParams.toString();
281+
};
282+
});
283+
return searchParams;
284+
},
285+
enumerable: true
286+
}
287+
});
288+
289+
URL.createObjectURL = function(blob) {
290+
return _URL.createObjectURL.apply(_URL, arguments);
291+
};
292+
293+
URL.revokeObjectURL = function(url) {
294+
return _URL.revokeObjectURL.apply(_URL, arguments);
295+
};
296+
297+
global.URL = URL;
298+
299+
};
300+
301+
if(!checkIfURLIsSupported()) {
302+
polyfillURL();
303+
}
304+
305+
if((global.location !== void 0) && !('origin' in global.location)) {
306+
var getOrigin = function() {
307+
return global.location.protocol + '//' + global.location.hostname + (global.location.port ? (':' + global.location.port) : '');
308+
};
309+
310+
try {
311+
Object.defineProperty(global.location, 'origin', {
312+
get: getOrigin,
313+
enumerable: true
314+
});
315+
} catch(e) {
316+
setInterval(function() {
317+
global.location.origin = getOrigin();
318+
}, 100);
319+
}
320+
}
321+
322+
})(g);

v3/src/polyfills/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ require('./Math.trunc');
77
require('./performance.now');
88
require('./requestAnimationFrame');
99
require('./Uint32Array');
10+
require('./URL');

0 commit comments

Comments
 (0)