diff --git a/js/jquery.mobile.navigation.js b/js/jquery.mobile.navigation.js
index 7153dc72..c1b1e1b2 100644
--- a/js/jquery.mobile.navigation.js
+++ b/js/jquery.mobile.navigation.js
@@ -14,6 +14,113 @@
//url path helpers for use in relative url management
path = {
+ // This scary looking regular expression parses an absolute URL or its relative
+ // variants (protocol, site, document, query, and hash), into the various
+ // components (protocol, host, path, query, fragment, etc that make up the
+ // URL as well as some other commonly used sub-parts. When used with RegExp.exec()
+ // or String.match, it parses the URL into a results array that looks like this:
+ //
+ // [0]: http://jblas:password@mycompany.com:8080/mail/inbox?msg=1234&type=unread#msg-content
+ // [1]: http://jblas:password@mycompany.com:8080
+ // [2]: http:
+ // [3]: jblas:password@mycompany.com:8080
+ // [4]: jblas:password
+ // [5]: jblas
+ // [6]: password
+ // [7]: mycompany.com:8080
+ // [8]: mycompany.com
+ // [9]: 8080
+ // [10]: /mail/inbox
+ // [11]: /mail/
+ // [12]: inbox
+ // [13]: ?msg=1234&type=unread
+ // [14]: #msg-content
+ //
+ urlParseRE: /^(([^:\/#\?]+:)?\/\/((?:(([^:@\/#\?]+)(?:\:([^:@\/#\?]+))?)@)?(([^:\/#\?]+)(?:\:([0-9]+))?))?)?((\/?(?:[^\/\?#]+\/)*)([^\?#]*))?(\?[^#]+)?(#.*)?/,
+
+ // Parse a URL into a structure that allows easy access to
+ // all of the URL components by name.
+ parseUrl: function( url ) {
+ var u = url || "",
+ matches = path.urlParseRE.exec(url),
+ results;
+ if ( matches ) {
+ results = {
+ href: matches[0],
+ domain: matches[1],
+ protocol: matches[2],
+ authority: matches[3],
+ username: matches[5],
+ password: matches[6],
+ host: matches[7],
+ hostname: matches[8],
+ port: matches[9],
+ pathname: matches[10],
+ directory: matches[11],
+ filename: matches[12],
+ search: matches[13],
+ hash: matches[14]
+ };
+ }
+ return results || {};
+ },
+
+ // Turn relPath into an asbolute path. absPath is
+ // an optional absolute path which describes what
+ // relPath is relative to.
+ makePathAbsolute: function( relPath, absPath ) {
+ if ( relPath && relPath.charAt( 0 ) === "/" ) {
+ return relPath
+ }
+
+ relPath = relPath || "";
+ absPath = absPath ? absPath.replace( /^\/|\/?[^\/]*$/g, "" ) : "";
+
+ var absStack = absPath ? absPath.split( "/" ) : [],
+ relStack = relPath.split("/");
+ for ( var i = 0; i < relStack.length; i++ ) {
+ var d = relStack[ i ];
+ switch ( d ) {
+ case ".":
+ break;
+ case "..":
+ if ( absStack.length ) {
+ absStack.pop();
+ }
+ break;
+ default:
+ absStack.push( d );
+ break;
+ }
+ }
+ return "/" + absStack.join( "/" );
+ },
+
+ // Returns true for any relative variant.
+ isRelativeUrl: function( url ) {
+ // All relative Url variants have one thing in common, no protocol.
+ return path.parseUrl(url).protocol === undefined;
+ },
+
+ // Turn the specified realtive URL into an absolute one. This function
+ // can handle all relative variants (protocol, site, document, query, fragment).
+ makeUrlAbsolute: function( relUrl, absUrl ) {
+ if ( !path.isRelativeUrl(relUrl) ) {
+ return relUrl;
+ }
+
+ var relObj = path.parseUrl(relUrl),
+ absObj = path.parseUrl(absUrl),
+ protocol = relObj.protocol || absObj.protocol,
+ authority = relObj.authority || absObj.authority || "",
+ hasPath = relObj.pathname !== undefined,
+ pathname = path.isRelativeUrl() ? path.makePathAbsolute( relObj.pathname || absObj.filename, absObj.pathname ) : relObj.pathName,
+ search = relObj.search || ( hasPath ? "" : absObj.search ),
+ hash = relObj.hash || "";
+
+ return protocol + "//" + authority + pathname + search + hash;
+ },
+
//get path from current hash, or from a file path
get: function( newPath ) {
if( newPath === undefined ) {
@@ -45,7 +152,7 @@
makeAbsolute: function( url ) {
var isHashPath = path.isPath( location.hash );
- if(path.isQuery( url )) {
+ if( path.isQuery( url ) ) {
// if the path is a list of query params and the hash is a path
// append the query params to the hash (without params or dialog keys).
// otherwise use the pathname and append the query params
@@ -192,45 +299,30 @@
//existing base tag?
$base = $head.children( "base" ),
- //get domain path
- //(note: use explicit protocol here, protocol-relative urls won't work as expected on localhost)
- docBase = location.protocol + "//" + location.host,
+ //tuck away the original document URL
+ documentUrl = location.href,
- //initialPath for first page load without hash. pathname (href - search)
- initialPath = docBase + location.pathname;
+ //extract out the domain and path of the documentUrl
+ documentDomainPath = documentUrl.replace(/[\?#].*/, ""),
- //already a base element?
- if ( $base.length ) {
- var href = $base.attr( "href" );
- if ( href ) {
- if ( href.search( /^[^:\/]+:\/\/[^\/]+\/?/ ) === -1 ) {
- //the href is not absolute, we need to turn it into one
- docBase = docBase + href;
- }
- else {
- //the href is an absolute url
- docBase = href;
- }
- }
-
- //make sure docBase ends with a slash
- docBase = docBase + ( docBase.charAt( docBase.length - 1 ) === "/" ? " " : "/" );
- }
+ //if the document has an embedded base tag, documentBase is set to its
+ //initial value. If a base tag does not exist, then we default to the documentDomainPath.
+ documentBase = $base.length ? path.makePathAbsolute( $base.attr( "href" ), documentDomainPath ) : documentDomainPath;
//base element management, defined depending on dynamic base tag support
var base = $.support.dynamicBaseTag ? {
//define base element, for use in routing asset urls that are referenced in Ajax-requested markup
- element: ( $base.length ? $base : $( "", { href: initialPath } ).prependTo( $head ) ),
+ element: ( $base.length ? $base : $( "", { href: documentBase } ).prependTo( $head ) ),
//set the generated BASE element's href attribute to a new page's base path
set: function( href ) {
- base.element.attr( "href", docBase + path.get( href ) );
+ base.element.attr( "href", path.makeUrlAbsolute( href, documentBase ) );
},
//set the generated BASE element's href attribute to a new page's base path
reset: function() {
- base.element.attr( "href", initialPath );
+ base.element.attr( "href", documentBase );
}
} : undefined;