Skip to content
This repository was archived by the owner on Oct 8, 2021. It is now read-only.

Commit cb636c5

Browse files
committed
abstract path helpers
1 parent f0ce8c7 commit cb636c5

File tree

4 files changed

+22
-300
lines changed

4 files changed

+22
-300
lines changed

js/index.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@
2020
'widgets/page.js',
2121
'jquery.mobile.core.js',
2222
'widgets/loader.js',
23-
'navigation/event.js',
23+
'navigation/events/navigate.js',
24+
'navigation/path.js',
25+
'navigation/navigate.js',
2426
'jquery.mobile.navigation.js',
2527
'jquery.mobile.navigation.pushstate.js',
2628
'jquery.mobile.transition.js',

js/jquery.mobile.navigation.js

Lines changed: 3 additions & 283 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
define( [
77
"jquery",
88
"./jquery.mobile.core",
9+
"./navigation/path",
910
"./jquery.mobile.events",
1011
"./jquery.mobile.support",
1112
"depend!./jquery.hashchange[jquery]",
@@ -20,288 +21,7 @@ define( [
2021
$head = $( 'head' ),
2122

2223
//url path helpers for use in relative url management
23-
path = {
24-
25-
// This scary looking regular expression parses an absolute URL or its relative
26-
// variants (protocol, site, document, query, and hash), into the various
27-
// components (protocol, host, path, query, fragment, etc that make up the
28-
// URL as well as some other commonly used sub-parts. When used with RegExp.exec()
29-
// or String.match, it parses the URL into a results array that looks like this:
30-
//
31-
// [0]: http://jblas:password@mycompany.com:8080/mail/inbox?msg=1234&type=unread#msg-content
32-
// [1]: http://jblas:password@mycompany.com:8080/mail/inbox?msg=1234&type=unread
33-
// [2]: http://jblas:password@mycompany.com:8080/mail/inbox
34-
// [3]: http://jblas:password@mycompany.com:8080
35-
// [4]: http:
36-
// [5]: //
37-
// [6]: jblas:password@mycompany.com:8080
38-
// [7]: jblas:password
39-
// [8]: jblas
40-
// [9]: password
41-
// [10]: mycompany.com:8080
42-
// [11]: mycompany.com
43-
// [12]: 8080
44-
// [13]: /mail/inbox
45-
// [14]: /mail/
46-
// [15]: inbox
47-
// [16]: ?msg=1234&type=unread
48-
// [17]: #msg-content
49-
//
50-
urlParseRE: /^(((([^:\/#\?]+:)?(?:(\/\/)((?:(([^:@\/#\?]+)(?:\:([^:@\/#\?]+))?)@)?(([^:\/#\?\]\[]+|\[[^\/\]@#?]+\])(?:\:([0-9]+))?))?)?)?((\/?(?:[^\/\?#]+\/+)*)([^\?#]*)))?(\?[^#]+)?)(#.*)?/,
51-
52-
// Abstraction to address xss (Issue #4787) by removing the authority in
53-
// browsers that auto decode it. All references to location.href should be
54-
// replaced with a call to this method so that it can be dealt with properly here
55-
getLocation: function( url ) {
56-
var uri = url ? this.parseUrl( url ) : location,
57-
hash = this.parseUrl( url || location.href ).hash;
58-
59-
// mimic the browser with an empty string when the hash is empty
60-
hash = hash === "#" ? "" : hash;
61-
62-
// Make sure to parse the url or the location object for the hash because using location.hash
63-
// is autodecoded in firefox, the rest of the url should be from the object (location unless
64-
// we're testing) to avoid the inclusion of the authority
65-
return uri.protocol + "//" + uri.host + uri.pathname + uri.search + hash;
66-
},
67-
68-
parseLocation: function() {
69-
return this.parseUrl( this.getLocation() );
70-
},
71-
72-
//Parse a URL into a structure that allows easy access to
73-
//all of the URL components by name.
74-
parseUrl: function( url ) {
75-
// If we're passed an object, we'll assume that it is
76-
// a parsed url object and just return it back to the caller.
77-
if ( $.type( url ) === "object" ) {
78-
return url;
79-
}
80-
81-
var matches = path.urlParseRE.exec( url || "" ) || [];
82-
83-
// Create an object that allows the caller to access the sub-matches
84-
// by name. Note that IE returns an empty string instead of undefined,
85-
// like all other browsers do, so we normalize everything so its consistent
86-
// no matter what browser we're running on.
87-
return {
88-
href: matches[ 0 ] || "",
89-
hrefNoHash: matches[ 1 ] || "",
90-
hrefNoSearch: matches[ 2 ] || "",
91-
domain: matches[ 3 ] || "",
92-
protocol: matches[ 4 ] || "",
93-
doubleSlash: matches[ 5 ] || "",
94-
authority: matches[ 6 ] || "",
95-
username: matches[ 8 ] || "",
96-
password: matches[ 9 ] || "",
97-
host: matches[ 10 ] || "",
98-
hostname: matches[ 11 ] || "",
99-
port: matches[ 12 ] || "",
100-
pathname: matches[ 13 ] || "",
101-
directory: matches[ 14 ] || "",
102-
filename: matches[ 15 ] || "",
103-
search: matches[ 16 ] || "",
104-
hash: matches[ 17 ] || ""
105-
};
106-
},
107-
108-
//Turn relPath into an asbolute path. absPath is
109-
//an optional absolute path which describes what
110-
//relPath is relative to.
111-
makePathAbsolute: function( relPath, absPath ) {
112-
if ( relPath && relPath.charAt( 0 ) === "/" ) {
113-
return relPath;
114-
}
115-
116-
relPath = relPath || "";
117-
absPath = absPath ? absPath.replace( /^\/|(\/[^\/]*|[^\/]+)$/g, "" ) : "";
118-
119-
var absStack = absPath ? absPath.split( "/" ) : [],
120-
relStack = relPath.split( "/" );
121-
for ( var i = 0; i < relStack.length; i++ ) {
122-
var d = relStack[ i ];
123-
switch ( d ) {
124-
case ".":
125-
break;
126-
case "..":
127-
if ( absStack.length ) {
128-
absStack.pop();
129-
}
130-
break;
131-
default:
132-
absStack.push( d );
133-
break;
134-
}
135-
}
136-
return "/" + absStack.join( "/" );
137-
},
138-
139-
//Returns true if both urls have the same domain.
140-
isSameDomain: function( absUrl1, absUrl2 ) {
141-
return path.parseUrl( absUrl1 ).domain === path.parseUrl( absUrl2 ).domain;
142-
},
143-
144-
//Returns true for any relative variant.
145-
isRelativeUrl: function( url ) {
146-
// All relative Url variants have one thing in common, no protocol.
147-
return path.parseUrl( url ).protocol === "";
148-
},
149-
150-
//Returns true for an absolute url.
151-
isAbsoluteUrl: function( url ) {
152-
return path.parseUrl( url ).protocol !== "";
153-
},
154-
155-
//Turn the specified realtive URL into an absolute one. This function
156-
//can handle all relative variants (protocol, site, document, query, fragment).
157-
makeUrlAbsolute: function( relUrl, absUrl ) {
158-
if ( !path.isRelativeUrl( relUrl ) ) {
159-
return relUrl;
160-
}
161-
162-
if ( absUrl === undefined ) {
163-
absUrl = documentBase;
164-
}
165-
166-
var relObj = path.parseUrl( relUrl ),
167-
absObj = path.parseUrl( absUrl ),
168-
protocol = relObj.protocol || absObj.protocol,
169-
doubleSlash = relObj.protocol ? relObj.doubleSlash : ( relObj.doubleSlash || absObj.doubleSlash ),
170-
authority = relObj.authority || absObj.authority,
171-
hasPath = relObj.pathname !== "",
172-
pathname = path.makePathAbsolute( relObj.pathname || absObj.filename, absObj.pathname ),
173-
search = relObj.search || ( !hasPath && absObj.search ) || "",
174-
hash = relObj.hash;
175-
176-
return protocol + doubleSlash + authority + pathname + search + hash;
177-
},
178-
179-
//Add search (aka query) params to the specified url.
180-
addSearchParams: function( url, params ) {
181-
var u = path.parseUrl( url ),
182-
p = ( typeof params === "object" ) ? $.param( params ) : params,
183-
s = u.search || "?";
184-
return u.hrefNoSearch + s + ( s.charAt( s.length - 1 ) !== "?" ? "&" : "" ) + p + ( u.hash || "" );
185-
},
186-
187-
convertUrlToDataUrl: function( absUrl ) {
188-
var u = path.parseUrl( absUrl );
189-
if ( path.isEmbeddedPage( u ) ) {
190-
// For embedded pages, remove the dialog hash key as in getFilePath(),
191-
// and remove otherwise the Data Url won't match the id of the embedded Page.
192-
return u.hash
193-
.split( dialogHashKey )[0]
194-
.replace( /^#/, "" )
195-
.replace( /\?.*$/, "" );
196-
} else if ( path.isSameDomain( u, documentBase ) ) {
197-
return u.hrefNoHash.replace( documentBase.domain, "" ).split( dialogHashKey )[0];
198-
}
199-
200-
return window.decodeURIComponent(absUrl);
201-
},
202-
203-
//get path from current hash, or from a file path
204-
get: function( newPath ) {
205-
if ( newPath === undefined ) {
206-
newPath = path.parseLocation().hash;
207-
}
208-
return path.stripHash( newPath ).replace( /[^\/]*\.[^\/*]+$/, '' );
209-
},
210-
211-
//return the substring of a filepath before the sub-page key, for making a server request
212-
getFilePath: function( path ) {
213-
var splitkey = '&' + $.mobile.subPageUrlKey;
214-
return path && path.split( splitkey )[0].split( dialogHashKey )[0];
215-
},
216-
217-
//set location hash to path
218-
set: function( path ) {
219-
location.hash = path;
220-
},
221-
222-
//test if a given url (string) is a path
223-
//NOTE might be exceptionally naive
224-
isPath: function( url ) {
225-
return ( /\// ).test( url );
226-
},
227-
228-
//return a url path with the window's location protocol/hostname/pathname removed
229-
clean: function( url ) {
230-
return url.replace( documentBase.domain, "" );
231-
},
232-
233-
//just return the url without an initial #
234-
stripHash: function( url ) {
235-
return url.replace( /^#/, "" );
236-
},
237-
238-
//remove the preceding hash, any query params, and dialog notations
239-
cleanHash: function( hash ) {
240-
return path.stripHash( hash.replace( /\?.*$/, "" ).replace( dialogHashKey, "" ) );
241-
},
242-
243-
isHashValid: function( hash ) {
244-
return ( /^#[^#]+$/ ).test( hash );
245-
},
246-
247-
//check whether a url is referencing the same domain, or an external domain or different protocol
248-
//could be mailto, etc
249-
isExternal: function( url ) {
250-
var u = path.parseUrl( url );
251-
return u.protocol && u.domain !== documentUrl.domain ? true : false;
252-
},
253-
254-
hasProtocol: function( url ) {
255-
return ( /^(:?\w+:)/ ).test( url );
256-
},
257-
258-
//check if the specified url refers to the first page in the main application document.
259-
isFirstPageUrl: function( url ) {
260-
// We only deal with absolute paths.
261-
var u = path.parseUrl( path.makeUrlAbsolute( url, documentBase ) ),
262-
263-
// Does the url have the same path as the document?
264-
samePath = u.hrefNoHash === documentUrl.hrefNoHash || ( documentBaseDiffers && u.hrefNoHash === documentBase.hrefNoHash ),
265-
266-
// Get the first page element.
267-
fp = $.mobile.firstPage,
268-
269-
// Get the id of the first page element if it has one.
270-
fpId = fp && fp[0] ? fp[0].id : undefined;
271-
272-
// The url refers to the first page if the path matches the document and
273-
// it either has no hash value, or the hash is exactly equal to the id of the
274-
// first page element.
275-
return samePath && ( !u.hash || u.hash === "#" || ( fpId && u.hash.replace( /^#/, "" ) === fpId ) );
276-
},
277-
278-
isEmbeddedPage: function( url ) {
279-
var u = path.parseUrl( url );
280-
281-
//if the path is absolute, then we need to compare the url against
282-
//both the documentUrl and the documentBase. The main reason for this
283-
//is that links embedded within external documents will refer to the
284-
//application document, whereas links embedded within the application
285-
//document will be resolved against the document base.
286-
if ( u.protocol !== "" ) {
287-
return ( u.hash && ( u.hrefNoHash === documentUrl.hrefNoHash || ( documentBaseDiffers && u.hrefNoHash === documentBase.hrefNoHash ) ) );
288-
}
289-
return ( /^#/ ).test( u.href );
290-
},
291-
292-
293-
// Some embedded browsers, like the web view in Phone Gap, allow cross-domain XHR
294-
// requests if the document doing the request was loaded via the file:// protocol.
295-
// This is usually to allow the application to "phone home" and fetch app specific
296-
// data. We normally let the browser handle external/cross-domain urls, but if the
297-
// allowCrossDomainPages option is true, we will allow cross-domain http/https
298-
// requests to go through our page loading logic.
299-
isPermittedCrossDomainRequest: function( docUrl, reqUrl ) {
300-
return $.mobile.allowCrossDomainPages &&
301-
docUrl.protocol === "file:" &&
302-
reqUrl.search( /^https?:/ ) !== -1;
303-
}
304-
},
24+
path = $.mobile.path,
30525

30626
//will be defined when a link is clicked and given an active class
30727
$activeClickedLink = null,
@@ -1486,7 +1206,7 @@ define( [
14861206

14871207
// We should probably fire the "navigate" event from those places that make calls to _handleHashChange,
14881208
// and have _handleHashChange hook into the "navigate" event instead of triggering it here
1489-
$.mobile.pageContainer.trigger( navEvent );
1209+
// $.mobile.pageContainer.trigger( navEvent );
14901210
if ( navEvent.isDefaultPrevented() ) {
14911211
return;
14921212
}

js/jquery.mobile.navigation.pushstate.js

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -42,21 +42,7 @@ define( [ "jquery", "./jquery.mobile.navigation", "depend!./jquery.hashchange[jq
4242
initialHref: self.initialHref
4343
};
4444
},
45-
46-
resetUIKeys: function( url ) {
47-
var dialog = $.mobile.dialogHashKey,
48-
subkey = "&" + $.mobile.subPageUrlKey,
49-
dialogIndex = url.indexOf( dialog );
50-
51-
if ( dialogIndex > -1 ) {
52-
url = url.slice( 0, dialogIndex ) + "#" + url.slice( dialogIndex );
53-
} else if ( url.indexOf( subkey ) > -1 ) {
54-
url = url.split( subkey ).join( "#" + subkey );
55-
}
56-
57-
return url;
58-
},
59-
45+
6046
// TODO sort out a single barrier to hashchange functionality
6147
nextHashChangePrevented: function( value ) {
6248
$.mobile.urlHistory.ignoreNextHashChange = value;
@@ -88,7 +74,7 @@ define( [ "jquery", "./jquery.mobile.navigation", "depend!./jquery.hashchange[jq
8874
href = $.mobile.path.makeUrlAbsolute( hash, resolutionUrl );
8975

9076
if ( isPath ) {
91-
href = self.resetUIKeys( href );
77+
href = $.mobile.path.resetUIKeys( href );
9278
}
9379

9480
// replace the current url with the new href and store the state

js/navigation/path.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,20 @@ define([
289289
return $.mobile.allowCrossDomainPages &&
290290
docUrl.protocol === "file:" &&
291291
reqUrl.search( /^https?:/ ) !== -1;
292+
},
293+
294+
resetUIKeys: function( url ) {
295+
var dialog = $.mobile.dialogHashKey,
296+
subkey = "&" + $.mobile.subPageUrlKey,
297+
dialogIndex = url.indexOf( dialog );
298+
299+
if ( dialogIndex > -1 ) {
300+
url = url.slice( 0, dialogIndex ) + "#" + url.slice( dialogIndex );
301+
} else if ( url.indexOf( subkey ) > -1 ) {
302+
url = url.split( subkey ).join( "#" + subkey );
303+
}
304+
305+
return url;
292306
}
293307
};
294308

0 commit comments

Comments
 (0)