Created
January 24, 2012 16:53
-
-
Save draeton/1671095 to your computer and use it in GitHub Desktop.
A URL parsing utility
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* ngbs.u.anchor - A URL parsing utility | |
*/ | |
/*global ngbs */ | |
var ngbs = ngbs || {}; | |
ngbs.u = ngbs.u || {}; | |
ngbs.u.anchor = (function (window, document, location) { | |
"use strict"; | |
/** | |
* isObject | |
* Type check | |
* @private | |
* @return {Boolean} | |
*/ | |
var isObject = function (o) { | |
return typeof o === "object" && o !== null; | |
}; | |
/** | |
* isArray | |
* Type check | |
* @private | |
* @return {Boolean} | |
*/ | |
var isArray = function (o) { | |
return Object.prototype.toString.call(o) === "[object Array]"; | |
}; | |
/** | |
* extend | |
* Object extend | |
* @private | |
* @return {Object} | |
*/ | |
var extend = function (o, o2) { | |
var args = Array.prototype.slice.call(arguments, 2), i; | |
for (i in o2) { | |
if (o2.hasOwnProperty(i)) { | |
o[i] = o2[i]; | |
} | |
} | |
if (args.length) { | |
args.unshift(o); | |
extend.apply(this, args); | |
} | |
return o; | |
}; | |
/** | |
* append | |
* Append a key-value pair to an object | |
* @private | |
*/ | |
var append = function (o, key, val) { | |
if (isObject(o) && o.hasOwnProperty(key)) { | |
if (isArray(o[key])) { | |
o[key].push(val); | |
} else { | |
o[key] = [o[key], val]; | |
} | |
} else { | |
o[key] = val; | |
} | |
}; | |
/** | |
* stringify | |
* Turn a key value pair into a string | |
* @private | |
* @return {String} | |
*/ | |
var stringify = function (key, val, eq, sep) { | |
var s = "", i, l; | |
if (isArray(val)) { | |
for (i = 0, l = val.length; i < l; i++) { | |
s += sep + key + eq + val[i]; | |
} | |
} else { | |
s += sep + key + eq + val; | |
} | |
return s; | |
}; | |
/** | |
* update | |
* Update the value of a key | |
* @private | |
*/ | |
var update = function (o, key, val) { | |
if (isObject(o)) { | |
if (typeof val === "undefined") { | |
delete o[key]; | |
} else { | |
o[key] = val; | |
} | |
} | |
}; | |
/** | |
* Private methods to add to the Anchor prototype | |
* @lends Anchor | |
*/ | |
var privateMethods = { | |
/** | |
* toObject_ | |
* Turn a search or hash into an object | |
* @private | |
* @param {String} type Either "search" or "hash" | |
* @return {Object} | |
*/ | |
toObject_: function (type) { | |
var str, eq, sep, list, map, i, l, pair; | |
if (type === "search") { | |
str = this.anchor.search.replace(/^\?/, ""); | |
eq = this.seq; | |
sep = this.ssp; | |
} else { | |
str = this.anchor.hash.replace(/^\#/, ""); | |
eq = this.heq; | |
sep = this.hsp; | |
} | |
list = str.split(sep); | |
map = {}; | |
for (i = 0, l = list.length; i < l; i++) { | |
pair = list[i].split(eq); | |
if (pair[0] !== "") { | |
append(map, pair[0], pair[1]); | |
} | |
} | |
return map; | |
}, | |
/** | |
* toString_ | |
* Turn an object into a str for search or hash | |
* @private | |
* @param {String} type Either "search" or "hash" | |
* @param {Object} map Key-value map of parameters | |
* @return {String} | |
*/ | |
toString_: function (type, map) { | |
var str = "", eq, sep, i; | |
if (type === "search") { | |
eq = this.seq; | |
sep = this.ssp; | |
} else { | |
eq = this.heq; | |
sep = this.hsp; | |
} | |
for (i in map) { | |
if (map.hasOwnProperty(i)) { | |
str += stringify(i, map[i], eq, sep); | |
} | |
} | |
return str.replace(new RegExp("^\\" + sep), ""); | |
}, | |
/** | |
* getUrlVars_ | |
* Get search and hash vars | |
* @private | |
* @param {String} type Either "search" or "hash" | |
* @return {Object} | |
*/ | |
getUrlVars_: function (type) { | |
var vars; | |
vars = { | |
search: this.toObject_("search"), | |
hash: this.toObject_("hash") | |
}; | |
return type ? vars[type] : vars; | |
}, | |
/** | |
* setUrlVars_ | |
* Set search and hash vars | |
* @private | |
* @param {String} type Either "search" or "hash" | |
* @param {Object} map Key-value map of parameters | |
* @return {Anchor} | |
*/ | |
setUrlVars_: function (type, map) { | |
var vars = this.getUrlVars_(type), | |
i; | |
for (i in map) { | |
if (map.hasOwnProperty(i)) { | |
update(vars, i, map[i]); | |
} | |
} | |
return this.toString_(type, vars); | |
} | |
}; | |
/** | |
* Public methods to add to the Anchor prototype | |
* @lends Anchor | |
*/ | |
var publicMethods = { | |
/** | |
* getSearchVars | |
* Return a key-value object with the parameters in the URL search | |
* @return {Object} | |
*/ | |
getSearchVars: function () { | |
return this.getUrlVars_("search"); | |
}, | |
/** | |
* getHashVars | |
* Return a key-value object with the parameters in the URL hash | |
* @return {Object} | |
*/ | |
getHashVars: function () { | |
return this.getUrlVars_("hash"); | |
}, | |
/** | |
* getUrlVars | |
* Return combined url variables | |
* @return {Object} | |
*/ | |
getUrlVars: function () { | |
var vars = this.getUrlVars_(), | |
search = vars.search, | |
hash = vars.hash, | |
combined = extend(search, hash); | |
return combined; | |
}, | |
/** | |
* setSearchVars | |
* Sets parameters using a key-value object in the URL search; returns this | |
* @param {Object} map The key-value object | |
* @return {Anchor} | |
*/ | |
setSearchVars: function (map) { | |
this.anchor.search = this.setUrlVars_("search", map); | |
return this; | |
}, | |
/** | |
* setSearchVar | |
* Sets the key parameter to val in the URL search; returns this | |
* @param {String} key The name of the parameter | |
* @param {String} val The value of the parameter | |
* @return {Anchor} | |
*/ | |
setSearchVar: function (key, val) { | |
var o = {}; | |
o[key] = val; | |
return this.setSearchVars(o); | |
}, | |
/** | |
* setHashVars | |
* Sets parameters using a key-value object in the URL hash; returns this | |
* @param {Object} map The key-value object | |
* @return {Anchor} | |
*/ | |
setHashVars: function (map) { | |
this.anchor.hash = this.setUrlVars_("hash", map); | |
return this; | |
}, | |
/** | |
* setHashVar | |
* Sets the key parameter to val in the URL hash; returns this | |
* @param {String} key The name of the parameter | |
* @param {String} val The value of the parameter | |
* @return {Anchor} | |
*/ | |
setHashVar: function (key, val) { | |
var o = {}; | |
o[key] = val; | |
return this.setHashVars(o); | |
}, | |
/** | |
* delSearchVar | |
* Deletes the key parameter from the URL search; returns this | |
* @param {String} key The name of the parameter | |
* @return {Anchor} | |
*/ | |
delSearchVar: function (key) { | |
return this.setSearchVar(key); | |
}, | |
/** | |
* delHashVar | |
* Deletes the key parameter from the URL hash; returns this | |
* @param {String} key The name of the parameter | |
* @return {Anchor} | |
*/ | |
delHashVar: function (key) { | |
return this.setHashVar(key); | |
}, | |
/** | |
* toString | |
* Used for type coercion of Anchor instance to string | |
* @return {String} | |
*/ | |
toString: function () { | |
return this.anchor.href; | |
} | |
}; | |
/** | |
* nativeGetter | |
* Returns a get method that aliases a native anchor property | |
* @private | |
* @param {String} prop The property name | |
* @return {Function} | |
*/ | |
var nativeGetter = function (prop) { | |
return function () { | |
return this.anchor[prop]; | |
}; | |
}; | |
// Native get methods to add to the Anchor prototype | |
var nativeMethods = (function () { | |
var methods = {}, props, prop, i, l; | |
props = ["href", "protocol", "host", "hostname", "port", "pathname", "search", "hash"]; | |
for (i = 0, l = props.length; i < l; i++) { | |
prop = props[i]; | |
methods[prop] = nativeGetter(prop); | |
} | |
return methods; | |
}()); | |
// regular expression URL test for protocol | |
var regexP = /^(http|https|ftp):/; | |
/** | |
* Anchor | |
* Constructor and prototype | |
* @constructor | |
* @param {String} href | |
* @param {String} [searchEq] Optional search equal operator; default of "=" | |
* @param {String} [searchSep] Optional search separator operator; default of "&" | |
* @param {String} [hashEq] Optional hash equal operator; default of "=" | |
* @param {String} [hashSep] Optional hash separator operator; default of "&" | |
* @return {Anchor} | |
*/ | |
var Anchor = function (href, /* optional */ searchEq, searchSep, hashEq, hashSep) { | |
if (typeof href === "undefined" || href === "") { | |
throw new Error("The href argument must be defined and non-empty."); | |
} | |
this.anchor = this.a = document.createElement("a"); | |
this.anchor.href = href; | |
// this forces the anchor to fill out the full path | |
if (!regexP.test(this.anchor.protocol)) { | |
this.anchor.protocol = location.protocol; | |
} | |
if (!this.anchor.hostname) { | |
this.anchor.hostname = location.hostname; | |
} | |
this.seq = searchEq || "="; | |
this.ssp = searchSep || "&"; | |
this.heq = hashEq || "="; | |
this.hsp = hashSep || "&"; | |
}; | |
Anchor.prototype = extend({}, nativeMethods, privateMethods, publicMethods); | |
/** | |
* Anchor.factory | |
* Create an Anchor instance | |
* @return {Anchor} | |
*/ | |
Anchor.factory = function (href, /* optional */ searchEq, searchSep, hashEq, hashSep) { | |
return new Anchor(href, searchEq, searchSep, hashEq, hashSep); | |
}; | |
/** | |
* Anchor.getQuery | |
* Legacy method alias for ngbs.u.getQuery | |
* @param {String|Array|Undefined} key The parameter name, or an array of names, or undefined for all values | |
* @return {String|Object|Boolean} | |
*/ | |
Anchor.factory.getQuery = function (key) { | |
var href = location.href, | |
t = new Anchor(href), | |
vars = t.getUrlVars(), | |
result = {}, | |
l; | |
if (typeof key === "string" && vars[key]) { | |
return vars[key]; | |
} | |
if (isArray(key)) { | |
l = key.length; | |
while (l--) { | |
result[key[l]] = false; | |
if (vars[key[l]]) { | |
result[key[l]] = vars[key[l]]; | |
} | |
} | |
return result; | |
} | |
if (typeof key === "undefined") { | |
return vars; | |
} | |
return false; | |
}; | |
// return the factory method for ngbs.u.anchor | |
return Anchor.factory; | |
}(window, document, location)); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment