Merge branch 'replacestate-external'

This commit is contained in:
John Bender 2011-08-25 13:05:54 -07:00
commit 49cf3af91a
16 changed files with 445 additions and 146 deletions

View file

@ -45,6 +45,7 @@ JSFILES = js/jquery.ui.widget.js \
js/jquery.mobile.page.js \
js/jquery.mobile.core.js \
js/jquery.mobile.navigation.js \
js/jquery.mobile.navigation.pushstate.js \
js/jquery.mobile.transition.js \
js/jquery.mobile.degradeInputs.js \
js/jquery.mobile.dialog.js \

View file

@ -29,6 +29,7 @@
js/jquery.mobile.page.js,
js/jquery.mobile.core.js,
js/jquery.mobile.navigation.js,
js/jquery.mobile.navigation.pushstate.js,
js/jquery.mobile.transition.js,
js/jquery.mobile.degradeInputs.js,
js/jquery.mobile.dialog.js,

View file

@ -11,6 +11,7 @@ $elements = array(
'jquery.mobile.page.js',
'jquery.mobile.core.js',
'jquery.mobile.navigation.js',
'jquery.mobile.navigation.pushstate.js',
'jquery.mobile.transition.js',
'jquery.mobile.degradeInputs.js',
'jquery.mobile.dialog.js',

View file

@ -47,10 +47,12 @@
// Error response message - appears when an Ajax page request fails
pageLoadErrorMessage: "Error Loading Page",
//automatically initialize the DOM when it's ready
autoInitializePage: true,
pushStateEnabled: true,
// Support conditions that must be met in order to proceed
// default enhanced qualifications are media query support OR IE 7+
gradeA: function(){
@ -164,3 +166,4 @@
return $.find( expr, null, null, [ node ] ).length > 0;
};
})( jQuery, this );

View file

@ -0,0 +1,103 @@
/*
* jQuery Mobile Framework : history.pushState support, layered on top of hashchange
* Copyright (c) jQuery Project
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*/
( function( $, window ) {
// For now, let's Monkeypatch this onto the end of $.mobile._registerInternalEvents
// Scope self to pushStateHandler so we can reference it sanely within the
// methods handed off as event handlers
var pushStateHandler = {},
self = pushStateHandler,
$win = $( window ),
url = $.mobile.path.parseUrl( location.href );
$.extend( pushStateHandler, {
// TODO move to a path helper, this is rather common functionality
initialFilePath: (function() {
return url.pathname + url.search;
})(),
initialHref: url.hrefNoHash,
// Flag for tracking if a Hashchange naturally occurs after each popstate + replace
hashchangeFired: false,
state: function() {
return {
hash: location.hash || "#" + self.initialFilePath,
title: document.title,
// persist across refresh
initialHref: self.initialHref
};
},
// on hash change we want to clean up the url
// NOTE this takes place *after* the vanilla navigation hash change
// handling has taken place and set the state of the DOM
onHashChange: function( e ) {
var href, state;
self.hashchangeFired = true;
// only replaceState when the hash doesn't represent an embeded page
if( $.mobile.path.isPath(location.hash) ) {
// propulate the hash when its not available
state = self.state();
// make the hash abolute with the current href
href = $.mobile.path.makeUrlAbsolute( state.hash.replace("#", ""), location.href );
// replace the current url with the new href and store the state
history.replaceState( state, document.title, href );
}
},
// on popstate (ie back or forward) we need to replace the hash that was there previously
// cleaned up by the additional hash handling
onPopState: function( e ) {
var poppedState = e.originalEvent.state;
// if there's no state its not a popstate we care about, ie chrome's initial popstate
// or forward popstate
if( poppedState ) {
// replace the current url with the equivelant hash so that the hashchange binding in vanilla nav
// can do its thing one triggered below
history.replaceState( poppedState, poppedState.title, poppedState.initialHref + poppedState.hash );
// Urls that reference subpages will fire their own hashchange, so we don't want to trigger 2 in that case.
self.hashchangeFired = false;
setTimeout(function() {
if( !self.hashchangeFired ) {
$win.trigger( "hashchange" );
}
self.hashchangeFired = false;
}, 0);
}
},
init: function() {
$win.bind( "hashchange", self.onHashChange );
// Handle popstate events the occur through history changes
$win.bind( "popstate", self.onPopState );
// if there's no hash, we need to replacestate for returning to home
if ( location.hash === "" ) {
history.replaceState( self.state(), document.title, location.href );
}
}
});
$( function() {
if( $.mobile.pushStateEnabled && $.support.pushState ){
pushStateHandler.init();
}
});
})( jQuery, this );

View file

@ -67,7 +67,7 @@ $.extend( $.support, {
orientation: "orientation" in window,
touch: "ontouchend" in document,
cssTransitions: "WebKitTransitionEvent" in window,
pushState: !!history.pushState,
pushState: "pushState" in history && "replaceState" in history,
mediaquery: $.mobile.media( "only all" ),
cssPseudoElement: !!propExists( "content" ),
boxShadow: !!propExists( "boxShadow" ) && !bb,

View file

@ -16,6 +16,18 @@
}
},
// TODO prevent test suite loads when the browser doesn't support push state
// and push-state false is defined.
setPushStateFor: function( libs ) {
if( $.support.pushState && location.search.indexOf( "push-state" ) >= 0 ) {
$.support.pushState = false;
}
$.each(libs, function(i, l) {
$( "<script>", { src: l }).appendTo("head");
});
},
reloads: {},
reloadLib: function(libName){
@ -26,8 +38,8 @@
};
}
var lib = this.reloads[libName].lib.clone(),
src = lib.attr('src');
var lib = this.reloads[libName].lib.clone(),
src = lib.attr('src');
//NOTE append "cache breaker" to force reload
lib.attr('src', src + "?" + this.reloads[libName].count++);
@ -116,6 +128,17 @@
return returnVal;
};
},
assertUrlLocation: function( args ) {
var parts = $.mobile.path.parseUrl( location.href ),
pathnameOnward = location.href.replace( parts.domain, "" );
if( $.support.pushState ) {
same( pathnameOnward, args.hashOrPush || args.push, args.report );
} else {
same( parts.hash, "#" + (args.hashOrPush || args.hash), args.report );
}
}
};
})(jQuery);

View file

@ -4,11 +4,13 @@
// TODO split out into seperate test files
(function($){
var home = $.mobile.path.parseUrl( location.href ).pathname;
$.mobile.defaultTransition = "none";
module('Basic Linked list', {
module( "Basic Linked list", {
setup: function(){
$.testHelper.openPage("#basic-linked-test");
$.testHelper.openPage( "#basic-linked-test" );
}
});
@ -213,7 +215,7 @@
asyncTest( "changes to the read only page when hash is changed", function() {
$.testHelper.pageSequence([
function(){
$.testHelper.openPage("#read-only-list-test")
$.testHelper.openPage("#read-only-list-test");
},
function(){
@ -588,6 +590,8 @@
ok( $("#enhancetest").trigger("create").find(".ui-listview").length, "enhancements applied" );
});
module( "Cached Linked List" );
var findNestedPages = function(selector){
return $( selector + " #topmost" ).listview( 'childPages' );
};
@ -596,7 +600,7 @@
$.testHelper.pageSequence([
function(){
//reset for relative url refs
$.testHelper.openPage( "#" + location.pathname );
$.testHelper.openPage( "#" + home );
},
function(){
@ -605,7 +609,11 @@
function(){
ok( findNestedPages( "#uncached-nested-list" ).length > 0, "verify that there are nested pages" );
$.testHelper.openPage( "#" + location.pathname + "cache-tests/clear.html" );
$.testHelper.openPage( "#" + home );
},
function() {
$.testHelper.openPage( "#cache-tests/clear.html" );
},
function(){
@ -620,7 +628,7 @@
$.testHelper.pageSequence([
function(){
//reset for relative url refs
$.testHelper.openPage( "#" + location.pathname );
$.testHelper.openPage( "#" + home );
},
function(){
@ -629,7 +637,11 @@
function(){
ok( findNestedPages( "#cached-nested-list" ).length > 0, "verify that there are nested pages" );
$.testHelper.openPage( "#" + location.pathname + "cache-tests/clear.html" );
$.testHelper.openPage( "#" + home );
},
function() {
$.testHelper.openPage( "#cache-tests/clear.html" );
},
function(){
@ -643,7 +655,7 @@
$.testHelper.pageSequence([
function(){
//reset for relative url refs
$.testHelper.openPage( "#" + location.pathname );
$.testHelper.openPage( "#" + home );
},
function(){
@ -652,7 +664,11 @@
function(){
same( $("#cached-nested-list").length, 1 );
$.testHelper.openPage("#" + location.pathname + "cache-tests/clear.html");
$.testHelper.openPage( "#" + home );
},
function() {
$.testHelper.openPage( "#cache-tests/clear.html" );
},
function(){
@ -667,6 +683,11 @@
expect( listPage.find("li").length );
$.testHelper.pageSequence( [
function(){
//reset for relative url refs
$.testHelper.openPage( "#" + home );
},
function() {
$.testHelper.openPage( "#search-filter-test" );
},

View file

@ -26,8 +26,11 @@
<link rel="stylesheet" href="../../../../../themes/default/"/>
<link rel="stylesheet" href="../../../../../external/qunit.css"/>
<script src="../../../../../external/qunit.js"></script>
<script src="../../navigation_base.js"></script>
<script type="text/javascript">
$.testHelper.setPushStateFor([
"../../navigation_base.js"
]);
</script>
</head>
<body>

View file

@ -15,10 +15,14 @@
<link rel="stylesheet" href="../../../external/qunit.css"/>
<script src="../../../external/qunit.js"></script>
<script src="navigation_transitions.js"></script>
<script src="navigation_helpers.js"></script>
<script src="navigation_core.js"></script>
<script src="navigation_paths.js"></script>
<script type="text/javascript">
$.testHelper.setPushStateFor([
"navigation_transitions.js",
"navigation_helper.js",
"navigation_core.js",
"navigation_paths.js"
]);
</script>
</head>
<body>
@ -28,69 +32,69 @@
<ol id="qunit-tests">
</ol>
<div id="harmless-default-page" data-nstest-role="page">
<div id="harmless-default-page" data-nstest-role="page">
</div>
<div id="foo" data-nstest-role="page" class="foo-class">
<div id="foo" data-nstest-role="page" class="foo-class">
<a href="#bar" data-nstest-transition="flip"></a>
</div>
<div id="prefetch" data-nstest-role="page">
<div id="prefetch" data-nstest-role="page">
<a href="prefetched.html" data-nstest-prefetch>Prefetch test</a>
</div>
<div id="foozball" data-nstest-role="page">
<div id="foozball" data-nstest-role="page">
</div>
<div id="bar" data-nstest-role="page">
<div id="bar" data-nstest-role="page">
<a href="#baz"></a>
</div>
<div id="baz" data-nstest-role="page">
<div id="baz" data-nstest-role="page">
<a href="#foo"></a>
</div>
<div id="fade-trans" data-nstest-role="page">
<div id="fade-trans" data-nstest-role="page">
<a href="#flip-trans" data-nstest-transition="fade"></a>
</div>
<div id="flip-trans" data-nstest-role="page">
<div id="flip-trans" data-nstest-role="page">
<a href="#fade-trans" data-nstest-transition="flip"></a>
</div>
<div id="no-trans" data-nstest-role="page">
<div id="no-trans" data-nstest-role="page">
<a href="#pop-trans"></a>
</div>
<div id="pop-trans" data-nstest-role="page">
<div id="pop-trans" data-nstest-role="page">
<a href="#no-trans" data-nstest-transition="pop"></a>
</div>
<div id="default-trans" data-nstest-role="page">
<div id="default-trans" data-nstest-role="page">
<a href="#no-trans"></a>
</div>
<div id="data-url" data-nstest-role="page">
<div id="data-url" data-nstest-role="page">
<a href="data-url-tests/data-url.html"></a>
</div>
<div id="non-data-url" data-nstest-role="page">
<div id="non-data-url" data-nstest-role="page">
<a href="data-url-tests/non-data-url.html"></a>
</div>
<div id="nested-data-url" data-nstest-role="page">
<div id="nested-data-url" data-nstest-role="page">
<a href="data-url-tests/nested.html"></a>
</div>
<div id="single-quotes-data-url" data-nstest-role="page">
<div id="single-quotes-data-url" data-nstest-role="page">
<a href="data-url-tests/single-quotes.html"></a>
</div>
<div id="reverse-attr-data-url" data-nstest-role="page">
<div id="reverse-attr-data-url" data-nstest-role="page">
<a href="data-url-tests/reverse-attr.html"></a>
</div>
<div id="ajax-disabled-form" data-nstest-role="page">
<div id="ajax-disabled-form" data-nstest-role="page">
<form method="POST" id="non-ajax-form" action="/ajax-disabled-form" data-nstest-ajax="false">
</form>
@ -101,7 +105,7 @@
</form>
</div>
<div id="default-trans-dialog" data-nstest-role="page">
<div id="default-trans-dialog" data-nstest-role="page">
<a href="#no-trans-dialog" data-nstest-rel="dialog"></a>
</div>
@ -109,34 +113,34 @@
</div>
<div id="dup-history-first" data-nstest-role="page">
<a href="#dup-history-second" data-nstest-transition="slideup" data-nstest-role="button" >
<a href="#dup-history-second" data-nstest-transition="slideup" data-nstest-role="button" >
Page 2
</a>
</div>
<div id="dup-history-second" data-nstest-role="page">
<a href="#dup-history-first" data-nstest-transition="slideup" data-nstest-role="button">
<a href="#dup-history-first" data-nstest-transition="slideup" data-nstest-role="button">
Page 1
</a>
<a href="#dup-history-dialog" data-nstest-role="button" data-nstest-transition="pop" data-nstest-rel="dialog">Dialog</a>
<a href="#dup-history-dialog" data-nstest-role="button" data-nstest-transition="pop" data-nstest-rel="dialog">Dialog</a>
</div>
<div id="dup-history-dialog" data-nstest-role="dialog">
<div data-nstest-role="header" data-nstest-position="inline">
<h1>Dialog</h1>
</div>
<div data-nstest-role="header" data-nstest-position="inline">
<h1>Dialog</h1>
</div>
</div>
<div id="skip-dialog-first" data-nstest-role="page">
<div data-nstest-role="content">
<a href="#skip-dialog" data-nstest-role="button" data-nstest-transition="pop" data-nstest-rel="dialog">Dialog</a>
</div>
<div data-nstest-role="content">
<a href="#skip-dialog" data-nstest-role="button" data-nstest-transition="pop" data-nstest-rel="dialog">Dialog</a>
</div>
</div>
<div id="skip-dialog" data-nstest-role="dialog">
<div data-nstest-role="content">
<a href="#skip-dialog-second">Page 2</a>
</div>
<div data-nstest-role="content">
<a href="#skip-dialog-second">Page 2</a>
</div>
</div>
<div id="skip-dialog-second" data-nstest-role="page">
@ -145,33 +149,33 @@
<div id="nested-dialog-page" data-nstest-role="page">
<div data-nstest-role="content">
<a href="#nested-dialog-first">Dialog</a>
</div>
<div data-nstest-role="content">
<a href="#nested-dialog-first">Dialog</a>
</div>
</div>
<div id="nested-dialog-first" data-nstest-role="dialog">
<div data-nstest-role="content">
<a href="#nested-dialog-second">Dialog 2</a>
</div>
<div data-nstest-role="content">
<a href="#nested-dialog-second">Dialog 2</a>
</div>
</div>
<div id="nested-dialog-second" data-nstest-role="dialog">
</div>
<div id="relative-after-embeded-page-first" data-nstest-role="page">
<div data-nstest-role="content">
<a href="#relative-after-embeded-page-second">second page</a>
</div>
<div data-nstest-role="content">
<a href="#relative-after-embeded-page-second">second page</a>
</div>
</div>
<div id="relative-after-embeded-page-second" data-nstest-role="page">
<div data-nstest-role="content">
<a href="data-url-tests/data-url.html">file path page</a>
</div>
<div data-nstest-role="content">
<a href="data-url-tests/data-url.html">file path page</a>
</div>
</div>
<div id="ajax-title-page" data-nstest-title="Title Attr 1" data-nstest-role="page">
<div id="ajax-title-page" data-nstest-title="Title Attr 1" data-nstest-role="page">
<a href="title1.html" id="titletest1" data-nstest-transition="none">test</a>
<a href="title2.html" id="titletest2" data-nstest-transition="none">test</a>
<a href="title3.html" id="titletest3" data-nstest-transition="none">test</a>
@ -243,8 +247,8 @@
<input type="hidden" name="foo" value="1">
<input type="hidden" name="bar" value="2">
</form>
<a href="form-tests/form-no-action.html">External page containing form with no action.</a>
</div>
<a href="form-tests/form-no-action.html">External page containing form with no action.</a>
</div>
</div>
<div id="active-state-page1" data-nstest-role="page">

View file

@ -21,21 +21,28 @@
$.testHelper.pageSequence([
function(){
// Navigate from default internal page to another internal page.
$.testHelper.openPage("#internal-page-2");
$.testHelper.openPage( "#internal-page-2" );
},
function(){
// Verify that we are on the 2nd internal page.
same(location.hash, "#internal-page-2", "navigate to internal page");
$.testHelper.assertUrlLocation({
push: location.pathname + "#internal-page-2",
hash: "internal-page-2",
report: "navigate to internal page"
});
// Navigate to a page that is in the base directory. Note that the application
// document and this new page are *NOT* in the same directory.
$("#internal-page-2 .bp1").click();
// document and this new page are *NOT* in the same directory.
$("#internal-page-2 .bp1").click();
},
function(){
// Verify that we are on the expected page.
same(location.hash, "#" + baseDir + "base-page-1.html", "navigate from internal page to page in base directory");
$.testHelper.assertUrlLocation({
hashOrPush: baseDir + "base-page-1.html",
report: "navigate from internal page to page in base directory"
});
// Navigate to another page in the same directory as the current page.
$("#base-page-1 .bp2").click();
@ -43,7 +50,10 @@
function(){
// Verify that we are on the expected page.
same(location.hash, "#" + baseDir + "base-page-2.html", "navigate from base directory page to another base directory page");
$.testHelper.assertUrlLocation({
hashOrPush: baseDir + "base-page-2.html",
report: "navigate from base directory page to another base directory page"
});
// Navigate to another page in a directory that is the sibling of the base.
$("#base-page-2 .cp1").click();
@ -51,7 +61,10 @@
function(){
// Verify that we are on the expected page.
same(location.hash, "#" + contentDir + "content-page-1.html", "navigate from base directory page to a page in a different directory hierarchy");
$.testHelper.assertUrlLocation({
hashOrPush: contentDir + "content-page-1.html",
report: "navigate from base directory page to a page in a different directory hierarchy"
});
// Navigate to another page in a directory that is the sibling of the base.
$("#content-page-1 .cp2").click();
@ -59,7 +72,10 @@
function(){
// Verify that we are on the expected page.
same(location.hash, "#" + contentDir + "content-page-2.html", "navigate to another page within the same non-base directory hierarchy");
$.testHelper.assertUrlLocation({
hashOrPush: contentDir + "content-page-2.html",
report: "navigate to another page within the same non-base directory hierarchy"
});
// Navigate to an internal page.
$("#content-page-2 .ip1").click();
@ -67,7 +83,11 @@
function(){
// Verify that we are on the expected page.
same(location.hash, "#internal-page-1", "navigate from a page in a non-base directory to an internal page");
$.testHelper.assertUrlLocation({
push: location.pathname + "#internal-page-1",
hash: "internal-page-1",
report: "navigate from a page in a non-base directory to an internal page"
});
// Try calling changePage() directly with a relative path.
$.mobile.changePage("base-page-1.html");
@ -75,7 +95,10 @@
function(){
// Verify that we are on the expected page.
same(location.hash, "#" + baseDir + "base-page-1.html", "call changePage() with a filename (no path)");
$.testHelper.assertUrlLocation({
hashOrPush: baseDir + "base-page-1.html",
report: "call changePage() with a filename (no path)"
});
// Try calling changePage() directly with a relative path.
$.mobile.changePage("../content/content-page-1.html");
@ -83,7 +106,10 @@
function(){
// Verify that we are on the expected page.
same(location.hash, "#" + contentDir + "content-page-1.html", "call changePage() with a relative path containing up-level references");
$.testHelper.assertUrlLocation({
hashOrPush: contentDir + "content-page-1.html",
report: "call changePage() with a relative path containing up-level references"
});
// Try calling changePage() with an id
$.mobile.changePage("content-page-2.html");
@ -91,7 +117,10 @@
function(){
// Verify that we are on the expected page.
same(location.hash, "#" + contentDir + "content-page-2.html", "call changePage() with a relative path should resolve relative to current page");
$.testHelper.assertUrlLocation({
hashOrPush: contentDir + "content-page-2.html",
report: "call changePage() with a relative path should resolve relative to current page"
});
// test that an internal page works
$("a.ip2").click();
@ -99,33 +128,47 @@
function(){
// Verify that we are on the expected page.
same(location.hash, "#internal-page-2", "call changePage() with a page id");
$.testHelper.assertUrlLocation({
hash: "internal-page-2",
push: location.pathname + "#internal-page-2",
report: "call changePage() with a page id"
});
// Try calling changePage() with an id
$.mobile.changePage("internal-page-1");
},
function(){
// Verify that we are on the expected page.
$.testHelper.assertUrlLocation({
hash: "internal-page-2",
push: location.pathname + "#internal-page-2",
report: "calling changePage() with a page id that is not prefixed with '#' should not change page"
});
// Previous load should have failed and left us on internal-page-2.
same(location.hash, "#internal-page-2", "calling changePage() with a page id that is not prefixed with '#' should not change page");
start();
}]);
}
]);
});
asyncTest( "internal form with no action submits to document URL", function(){
$.testHelper.pageSequence([
// open our test page
function(){
$.testHelper.openPage("#internal-no-action-form-page");
$.testHelper.openPage( "#internal-no-action-form-page" );
},
function(){
$("#internal-no-action-form-page form").eq(0).submit();
$( "#internal-no-action-form-page form" ).eq( 0 ).submit();
},
function(){
same(location.hash, "#" + location.pathname + "?foo=1&bar=2", "hash should match document url and not base url");
$.testHelper.assertUrlLocation({
hashOrPush: location.pathname + "?foo=1&bar=2",
report: "hash should match document url and not base url"
});
start();
}
]);
@ -140,16 +183,22 @@
function(){
// Make sure we actually navigated to the external page.
same(location.hash, "#" + contentDir + "content-page-1.html", "should be on content-page-1.html");
$.testHelper.assertUrlLocation({
hashOrPush: contentDir + "content-page-1.html",
report: "should be on content-page-1.html"
});
// Now submit the form in the external page.
$("#content-page-1 form").eq(0).submit();
},
function(){
same(location.hash, "#" + contentDir + "content-page-1.html?foo=1&bar=2", "hash should match page url and not document url");
$.testHelper.assertUrlLocation({
hashOrPush: contentDir + "content-page-1.html?foo=1&bar=2",
report: "hash should match page url and not document url"
});
start();
}]);
});
})(jQuery);

View file

@ -2,24 +2,40 @@
* mobile navigation unit tests
*/
(function($){
// TODO move siteDirectory over to the nav path helper
var changePageFn = $.mobile.changePage,
originalTitle = document.title,
siteDirectory = location.pathname.replace(/[^/]+$/, ""),
navigateTestRoot = function(){
$.testHelper.openPage( "#" + location.pathname );
};
originalTitle = document.title,
siteDirectory = location.pathname.replace( /[^/]+$/, "" ),
home = $.mobile.path.parseUrl(location.pathname).directory,
navigateTestRoot = function(){
$.testHelper.openPage( "#" + location.pathname );
};
module('jquery.mobile.navigation.js', {
setup: function(){
$.mobile.changePage = changePageFn;
document.title = originalTitle;
if ( location.hash ) {
var pageReset = function( hash ) {
hash = hash || "";
stop();
$(document).one("changepage", function() {
$(document).one( "changepage", function() {
start();
} );
location.hash = "";
});
location.hash = "#" + hash;
};
// force the page reset for hash based tests
if ( location.hash && !$.support.pushState ) {
pageReset();
}
// force the page reset for all pushstate tests
if ( $.support.pushState ) {
pageReset( home );
}
$.mobile.urlHistory.stack = [];
@ -52,7 +68,7 @@
asyncTest( "external page is cached in the DOM after pagehide", function(){
$.testHelper.pageSequence([
navigateTestRoot,
function(){
$.mobile.changePage( "cached-external.html" );
},
@ -72,30 +88,29 @@
});
asyncTest( "external page is cached in the DOM after pagehide when option is set globally", function(){
$.testHelper.pageSequence([
navigateTestRoot,
function(){
$.mobile.page.prototype.options.domCache = true;
$.mobile.changePage( "external.html" );
},
$.testHelper.pageSequence([
navigateTestRoot,
// page is pulled and displayed in the dom
function(){
same( $( "#external-test" ).length, 1 );
window.history.back();
},
function(){
$.mobile.page.prototype.options.domCache = true;
$.mobile.changePage( "external.html" );
},
// page is pulled and displayed in the dom
function(){
same( $( "#external-test" ).length, 1 );
window.history.back();
},
// external test page is cached in the dom after transitioning away
function(){
same( $( "#external-test" ).length, 1 );
$.mobile.page.prototype.options.domCache = false;
$( "#external-test" ).remove();
start();
}]);
});
// external test page is cached in the dom after transitioning away
function(){
same( $( "#external-test" ).length, 1 );
$.mobile.page.prototype.options.domCache = false;
$( "#external-test" ).remove();
start();
}
]);
});
asyncTest( "forms with data attribute ajax set to false will not call changePage", function(){
var called = false;
var newChangePage = function(){
@ -215,12 +230,17 @@
testListening( $.mobile.hashListeningEnabled );
});
var testDataUrlHash = function(linkSelector, hashRegex){
var testDataUrlHash = function( linkSelector, matches ) {
$.testHelper.pageSequence([
function(){ window.location.hash = ""; },
function(){ $(linkSelector).click(); },
function(){
ok(hashRegex.test(location.hash), "should match the regex");
$.testHelper.assertUrlLocation(
$.extend(matches, {
report: "url or hash should match"
})
);
start();
}
]);
@ -229,19 +249,22 @@
};
test( "when loading a page where data-url is not defined on a sub element hash defaults to the url", function(){
testDataUrlHash("#non-data-url a", new RegExp("^#" + siteDirectory + "data-url-tests/non-data-url.html$"));
testDataUrlHash( "#non-data-url a", {hashOrPush: siteDirectory + "data-url-tests/non-data-url.html"} );
});
test( "data url works for nested paths", function(){
testDataUrlHash("#nested-data-url a", /^#foo\/bar.html$/);
var url = "foo/bar.html";
testDataUrlHash( "#nested-data-url a", {hash: url, push: home + url} );
});
test( "data url works for single quoted paths and roles", function(){
testDataUrlHash("#single-quotes-data-url a", /^#foo\/bar\/single.html$/);
var url = "foo/bar/single.html";
testDataUrlHash( "#single-quotes-data-url a", {hash: url, push: home + url} );
});
test( "data url works when role and url are reversed on the page element", function(){
testDataUrlHash("#reverse-attr-data-url a", /^#foo\/bar\/reverse.html$/);
var url = "foo/bar/reverse.html";
testDataUrlHash( "#reverse-attr-data-url a", {hash: url, push: home + url} );
});
asyncTest( "last entry choosen amongst multiple identical url history stack entries on hash change", function(){
@ -283,7 +306,12 @@
// make sure we're at the first page and not the dialog
function(){
same(location.hash, "#skip-dialog-first", "should be the first page in the sequence");
$.testHelper.assertUrlLocation({
hash: "skip-dialog-first",
push: home + "#skip-dialog-first",
report: "should be the first page in the sequence"
});
start();
}]);
});
@ -307,12 +335,16 @@
// make sure we're on the second page and not the dialog
function(){
same(location.hash, "#skip-dialog-second", "should be the second page after the dialog");
$.testHelper.assertUrlLocation({
hash: "skip-dialog-second",
push: home + "#skip-dialog-second",
report: "should be the second page after the dialog"
});
start();
}]);
});
asyncTest( "going back from a dialog triggered from a dialog should result in the first dialog ", function(){
$.testHelper.pageSequence([
// setup
@ -449,7 +481,11 @@
},
function(){
same(location.hash, "#" + siteDirectory + "data-url-tests/non-data-url.html?foo=bar");
$.testHelper.assertUrlLocation({
hashOrPush: home + "data-url-tests/non-data-url.html?foo=bar",
report: "the hash or url has query params"
});
ok($(".ui-page-active").jqmData("url").indexOf("?foo=bar") > -1, "the query params are in the data url");
start();
}
@ -467,12 +503,20 @@
},
function(){
same(location.hash, "#" + siteDirectory + "data-url-tests/non-data-url.html?foo=bar");
$.testHelper.assertUrlLocation({
hashOrPush: home + "data-url-tests/non-data-url.html?foo=bar",
report: "the hash or url has query params"
});
$("#query-param-anchor").click();
},
function(){
same(location.hash, "#" + siteDirectory + "data-url-tests/non-data-url.html?foo=bar");
$.testHelper.assertUrlLocation({
hashOrPush: home + "data-url-tests/non-data-url.html?foo=bar",
report: "the hash or url still has query params"
});
start();
}
]);
@ -481,7 +525,7 @@
// Special handling inside navigation because query params must be applied to the hash
// or absolute reference and dialogs apply extra information int the hash that must be removed
asyncTest( "query param link from a dialog to itself should be a not add another dialog", function(){
var firstDialogHash;
var firstDialogLoc;
$.testHelper.pageSequence([
// open our test page
@ -502,19 +546,18 @@
// attempt to navigate to the same link
function(){
// store the current hash for comparison (with one dialog hash key)
firstDialogHash = location.hash;
firstDialogLoc = location.hash || location.href;
$("#dialog-param-link-page a").click();
},
function(){
same(location.hash, firstDialogHash, "additional dialog hash key not added");
same(location.hash || location.href, firstDialogLoc, "additional dialog hash key not added");
start();
}
]);
});
asyncTest( "query data passed as string to changePage is appended to URL", function(){
asyncTest( "query data passed as string to changePage is appended to URL", function(){
$.testHelper.pageSequence([
// open our test page
function(){
@ -524,14 +567,17 @@
},
function(){
same(location.hash, "#" + siteDirectory + "form-tests/changepage-data.html?foo=1&bar=2");
$.testHelper.assertUrlLocation({
hashOrPush: home + "form-tests/changepage-data.html?foo=1&bar=2",
report: "the hash or url still has query params"
});
start();
}
]);
});
asyncTest( "query data passed as object to changePage is appended to URL", function(){
$.testHelper.pageSequence([
// open our test page
function(){
@ -544,14 +590,17 @@
},
function(){
same(location.hash, "#" + siteDirectory + "form-tests/changepage-data.html?foo=3&bar=4");
$.testHelper.assertUrlLocation({
hashOrPush: home + "form-tests/changepage-data.html?foo=3&bar=4",
report: "the hash or url still has query params"
});
start();
}
]);
});
asyncTest( "refresh of a dialog url should not duplicate page", function(){
$.testHelper.pageSequence([
// open our test page
function(){
@ -560,15 +609,19 @@
},
function(){
same(location.hash, "#foo&ui-state=dialog", "hash should match what was loaded");
same($(".foo-class").length, 1, "should only have one instance of foo-class in the document");
$.testHelper.assertUrlLocation({
hash: "foo&ui-state=dialog",
push: home + "#foo&ui-state=dialog",
report: "hash should match what was loaded"
});
same( $(".foo-class").length, 1, "should only have one instance of foo-class in the document" );
start();
}
]);
});
asyncTest( "internal form with no action submits to document URL", function(){
$.testHelper.pageSequence([
// open our test page
function(){
@ -580,14 +633,17 @@
},
function(){
same(location.hash, "#" + location.pathname + "?foo=1&bar=2", "hash should match what was loaded");
$.testHelper.assertUrlLocation({
hashOrPush: home + "?foo=1&bar=2",
report: "hash should match what was loaded"
});
start();
}
]);
});
asyncTest( "external page containing form with no action submits to page URL", function(){
$.testHelper.pageSequence([
// open our test page
function(){
@ -603,7 +659,11 @@
},
function(){
same(location.hash, "#" + siteDirectory + "form-tests/form-no-action.html?foo=1&bar=2", "hash should match page url and not document url");
$.testHelper.assertUrlLocation({
hashOrPush: home + "form-tests/form-no-action.html?foo=1&bar=2",
report: "hash should match page url and not document url"
});
start();
}
]);

View file

@ -2,6 +2,9 @@
* mobile navigation path unit tests
*/
(function($){
var url = $.mobile.path.parseUrl( location.href ),
home = location.href.replace( url.domain, "" );
var testPageLoad = function(testPageAnchorSelector, expectedTextValue){
expect( 2 );
@ -9,7 +12,7 @@
function(){
// reset before each test, all tests expect original page
// for relative urls
$.testHelper.openPage( "#" + location.pathname);
$.testHelper.openPage( "#" + home);
},
// open our test page

View file

@ -0,0 +1,10 @@
<!DOCTYPE html>
<html lang="en">
<head>
<!-- forces the base-tests into a push state disabled run and allows for
the test suite runner to pick it up as a seperate test set. See test/unit/ls.php,
test/unit/runner.js, base-tests.html, and tests/jquery.testHelper.js for more. -->
<meta http-equiv="refresh" content="0; url='base-tests.html?push-state=false'">
<body>
</body>
</html>

View file

@ -0,0 +1,10 @@
<!DOCTYPE html>
<html lang="en">
<head>
<!-- forces the base-tests into a push state disabled run and allows for
the test suite runner to pick it up as a seperate test set. See test/unit/ls.php,
test/unit/runner.js, base-tests.html, and tests/jquery.testHelper.js for more. -->
<meta http-equiv="refresh" content="0; url='./?push-state=false'">
<body>
</body>
</html>

View file

@ -17,6 +17,13 @@ $(function() {
// establish a timeout for a given suite in case of async tests hanging
self.testTimer = setTimeout( self.onTimeout, self.testTimeout );
// it might be a redirect with query params for push state
// tests skip this call and expect another
if( !self.frame.QUnit ) {
self.$frameElem.one( "load", self.onFrameLoad );
return;
}
// when the QUnit object reports done in the iframe
// run the onFrameDone method
self.frame.QUnit.done = self.onFrameDone;