Skip to content

Instantly share code, notes, and snippets.

@arv
Created November 21, 2011 23:56
Show Gist options
  • Star 15 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save arv/1384398 to your computer and use it in GitHub Desktop.
Save arv/1384398 to your computer and use it in GitHub Desktop.
JavaScript + DOM implementation of http://dvcs.w3.org/hg/url/raw-file/tip/Overview.html
<!DOCTYPE html>
<script src="url.js"></script>
<script>
var url = new URL('http://www.example.com/a/b/c.html?p=q&r=s&p&p=t#hash');
for (var key in url) {
console.log(key, url[key]);
}
</script>
var URL = (function() {
function parseSearch(s) {
var result = [];
var k = 0;
var parts = s.slice(1).split('&');
for (var i = 0; i < parts.length; i++) {
var part = parts[i];
var key = part.split('=', 1)[0];
if (key) {
var value = part.slice(key.length + 1);
result[k++] = [key, value];
}
}
return result;
}
function serializeParsed(array) {
return array.map(function(pair) {
return pair[1] !== '' ? pair.join('=') : pair[0];
}).join('&');
}
function URL(url, base) {
if (!url)
throw new TypeError('Invalid argument');
var doc = document.implementation.createHTMLDocument('');
if (base) {
var baseElement = doc.createElement('base');
baseElement.href = base || window.lo;
doc.head.appendChild(baseElement);
}
var anchorElement = doc.createElement('a');
anchorElement.href = url;
doc.body.appendChild(anchorElement);
if (anchorElement.href === '')
throw new TypeError('Invalid URL');
Object.defineProperty(this, '_anchorElement', {value: anchorElement});
}
URL.prototype = {
toString: function() {
return this.href;
},
get href() {
return this._anchorElement.href;
},
set href(value) {
this._anchorElement.href = value;
},
get protocol() {
return this._anchorElement.protocol;
},
set protocol(value) {
this._anchorElement.protocol = value;
},
// NOT IMPLEMENTED
// get username() {
// return this._anchorElement.username;
// },
// set username(value) {
// this._anchorElement.username = value;
// },
// get password() {
// return this._anchorElement.password;
// },
// set password(value) {
// this._anchorElement.password = value;
// },
// get origin() {
// return this._anchorElement.origin;
// },
get host() {
return this._anchorElement.host;
},
set host(value) {
this._anchorElement.host = value;
},
get hostname() {
return this._anchorElement.hostname;
},
set hostname(value) {
this._anchorElement.hostname = value;
},
get port() {
return this._anchorElement.port;
},
set port(value) {
this._anchorElement.port = value;
},
get pathname() {
return this._anchorElement.pathname;
},
set pathname(value) {
this._anchorElement.pathname = value;
},
get search() {
return this._anchorElement.search;
},
set search(value) {
this._anchorElement.search = value;
},
get hash() {
return this._anchorElement.hash;
},
set hash(value) {
this._anchorElement.hash = value;
},
get filename() {
var match;
if ((match = this.pathname.match(/\/([^\/]+)$/)))
return match[1];
return '';
},
set filename(value) {
var match, pathname = this.pathname;
if ((match = pathname.match(/\/([^\/]+)$/)))
this.pathname = pathname.slice(0, -match[1].length) + value;
else
this.pathname = value;
},
get parameterNames() {
var seen = Object.create(null);
return parseSearch(this.search).map(function(pair) {
return pair[0];
}).filter(function(key) {
if (key in seen)
return false;
seen[key] = true;
return true;
});
},
getParameter: function(name) {
return this.getParameterAll(name).pop();
},
getParameterAll: function(name) {
name = String(name);
var result = [];
var k = 0;
parseSearch(this.search).forEach(function(pair) {
if (pair[0] === name)
result[k++] = pair[1];
});
return result;
},
appendParameter: function(name, values) {
if (!Array.isArray(values))
values = [values];
var parsed = parseSearch(this.search);
for (var i = 0; i < values.length; i++) {
parsed.push([name, values[i]]);
}
this.search = serializeParsed(parsed);
},
clearParameter: function(name) {
this.search = serializeParsed(
parseSearch(this.search).filter(function(pair) {
return pair[0] !== name;
}));
},
};
var oldURL = window.URL || window.webkitURL || window.mozURL;
URL.createObjectURL = function(blob) {
return oldURL.createObjectURL.apply(oldURL, arguments);
};
URL.revokeObjectURL = function(url) {
return oldURL.revokeObjectURL.apply(oldURL, arguments);
};
// Methods should not be enumerable.
Object.defineProperty(URL.prototype, 'toString', {enumerable: false});
Object.defineProperty(URL.prototype, 'getParameter', {enumerable: false});
Object.defineProperty(URL.prototype, 'getParameterAll', {enumerable: false});
Object.defineProperty(URL.prototype, 'appendParameter', {enumerable: false});
Object.defineProperty(URL.prototype, 'clearParameter', {enumerable: false});
Object.defineProperty(URL, 'createObjectURL', {enumerable: false});
Object.defineProperty(URL, 'revokeObjectURL', {enumerable: false});
return URL;
})();
@samth
Copy link

samth commented Nov 22, 2011

I think you need to use window.URL for modern Firefox. window.mozURL is undefined in Firefox Nightly 11.

@arv
Copy link
Author

arv commented Nov 22, 2011 via email

@Yaffle
Copy link

Yaffle commented Nov 22, 2011

Hello, guys!
i have this code https://gist.github.com/1235332 for URL resolving, may be it's better to include this and not use DOM ?

Without DOM this script will work under node.js and WebWorkers and performnace will be increased.

@arv
Copy link
Author

arv commented Nov 22, 2011

This gist was created in response to https://bugs.webkit.org/show_bug.cgi?id=71968 which is about adding a URL host object to WebKit.

Implementing a correct URL object in JS requires thousands of lines of code that needs to be downloaded over and over. All browsers already ship with C++ implementations of URLs already so we want to leverage this.

@Yaffle
Copy link

Yaffle commented Apr 22, 2013

@arv, the algorithm is described at the spec. - https://dvcs.w3.org/hg/url/raw-file/tip/Overview.html#concept-url-parser
do not think it requires thousands of lines of code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment