Skip to content

Instantly share code, notes, and snippets.

@gabrielmiller
Last active August 29, 2015 14:07
Show Gist options
  • Save gabrielmiller/c750d3c231c8673683d0 to your computer and use it in GitHub Desktop.
Save gabrielmiller/c750d3c231c8673683d0 to your computer and use it in GitHub Desktop.
AngularJS URL Parser Service
/**
* @ngdoc service
* @name utilityService
* @description Contains utility methods for formatting
* @requires $interpolate
*/
angular.module('resApp').factory('utilityService', function($interpolate) {
/**
* @ngdoc method
* @name utilityService#parseUrl
* @description Parses a URL
* @param {String} URL to be prepared
* @param {String} Regex to use for matches
* {'strict','lite','loose','performant'}
* @return {Object} Parsed URL's components
*
* This code is adapted from parseUri 1.2.2 by Steven Levithan
* http://blog.stevenlevithan.com/archives/parseuri
*
* Performant regex taken from http://jsperf.com/url-parsing
*
* WARNING: Objects returned may differ based on the requested regex
*
*/
function parseUrl(urlToParse, regex) {
urlParser = {
options: {
keys: {
defaults: ["source", "protocol", "authority", "userInfo", "user", "password", "host", "port", "relative", "path", "directory", "file", "query", "anchor"],
lite: ["href", "origin", "protocol", "username", "password", "host", "hostname", "port", "pathname", "search", "host"],
performant: ["href", "withoutHash", "url", "origin", "protocol", "protocolseparator", "credentialedhost", "credentials", "username", "password", "host", "hostname", "port", "pathname", "segment1", "segment2", "search", "hash"],
},
parser: {
strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,
lite: /^(?:(?:(([^:\/#\?]+:)?(?:(?:\/\/)(?:(?:(?:([^:@\/#\?]+)(?:\:([^:@\/#\?]*))?)@)?(([^:\/#\?\]\[]+|\[[^\/\]@#?]+\])(?:\:([0-9]+))?))?)?)?((?:\/?(?:[^\/\?#]+\/+)*)(?:[^\?#]*)))?(\?[^#]+)?)(#.*)?/,
loose: /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/,
performant: /^(((([^:\/#\?]+:)?(?:(\/\/)((?:(([^:@\/#\?]+)(?:\:([^:@\/#\?]+))?)@)?(([^:\/#\?\]\[]+|\[[^\/\]@#?]+\])(?:\:([0-9]+))?))?)?)?((\/?(?:[^\/\?#]+\/+)*)([^\?#]*)))?(\?[^#]+)?)(#.*)?/
}
}
};
if (!(regex in urlParser.options.keys)) {
regex = "loose";
}
var regexKeys;
if (regex === "loose" || regex === "strict") {
regexKeys = "defaults";
} else {
regexKeys = regex;
}
var options = urlParser.options,
mode = options.parser[regex].exec(urlToParse),
url = {},
length = urlParser.options.keys[regexKeys].length - 1;
while (length--) {
url[options.keys[regex][length]] = mode[length] || "";
}
return url;
}
/**
* @ngdoc method
* @name utilityService#prepareUrl
* @description Parses a URL and returns it prepared for use externally
* or internally. Returns "#" if URL is empty or otherwise
* invalid.
* @param {Boolean} Domain is external
* @param {String} URL to be prepared
* @return {String} Prepared URL
*/
function prepareUrl(isExternal, url) {
console.log(url);
var failSafe = "#";
if (url === "") {
return failSafe;
}
var defaultProtocol = "http:",
interpolation = $interpolate('{{protocol}}//{{host}}/{{path}}{{search}}{{hash}}'),
parsedUrl = parseUrl(url, "loose"),
validProtocols = {
"http:": true,
"https:": true,
"ftp:": true
};
console.log(parsedUrl);
// Enforce that a protocol is set on external URLs
if (isExternal) {
if (!(parsedUrl.protocol in validProtocols)) {
parsedUrl.protocol = defaultProtocol;
}
if (parsedUrl.host === "") {
return failSafe;
}
}
return interpolation(parsedUrl);
}
return {
parseUrl: parseUrl,
prepareUrl: prepareUrl,
};
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment