2 * mobile navigation unit tests
5 // TODO move siteDirectory over to the nav path helper
6 var changePageFn = $.mobile.changePage,
7 originalTitle = document.title,
8 originalLinkBinding = $.mobile.linkBindingEnabled,
9 siteDirectory = location.pathname.replace( /[^/]+$/, "" ),
10 home = $.mobile.path.parseUrl(location.pathname).directory,
11 homeWithSearch = home + location.search,
12 navigateTestRoot = function(){
13 $.testHelper.openPage( "#" + location.pathname + location.search );
16 module('jquery.mobile.navigation.js', {
18 $.mobile.changePage = changePageFn;
19 document.title = originalTitle;
21 var pageReset = function( hash ) {
26 $(document).one( "pagechange", function() {
30 location.hash = "#" + hash;
33 // force the page reset for hash based tests
34 if ( location.hash && !$.support.pushState ) {
38 // force the page reset for all pushstate tests
39 if ( $.support.pushState ) {
40 pageReset( homeWithSearch );
44 $.mobile.urlHistory.stack = [];
45 $.mobile.urlHistory.activeIndex = 0;
46 $.Event.prototype.which = undefined;
47 $.mobile.linkBindingEnabled = originalLinkBinding;
51 asyncTest( "window.history.back() from external to internal page", function(){
53 $.testHelper.pageSequence([
57 $.testHelper.openPage("#active-state-page1");
61 ok( $.mobile.activePage[0] === $( "#active-state-page1" )[ 0 ], "successful navigation to internal page." );
63 //location.hash = siteDirectory + "external.html";
64 $.mobile.changePage("external.html");
68 ok( $.mobile.activePage[0] !== $( "#active-state-page1" )[ 0 ], "successful navigation to external page." );
70 window.history.back();
74 ok( $.mobile.activePage[0] === $( "#active-state-page1" )[ 0 ], "successful navigation back to internal page." );
81 asyncTest( "external page is removed from the DOM after pagehide", function(){
82 $.testHelper.pageSequence([
86 $.mobile.changePage( "external.html" );
89 // page is pulled and displayed in the dom
91 same( $( "#external-test" ).length, 1 );
92 window.history.back();
95 // external-test is *NOT* cached in the dom after transitioning away
97 same( $( "#external-test" ).length, 0 );
103 asyncTest( "preventDefault on pageremove event can prevent external page from being removed from the DOM", function(){
104 var preventRemoval = true,
105 removeCallback = function( e ) {
106 if ( preventRemoval ) {
111 $( document ).bind( "pageremove", removeCallback );
113 $.testHelper.pageSequence([
117 $.mobile.changePage( "external.html" );
120 // page is pulled and displayed in the dom
122 same( $( "#external-test" ).length, 1 );
123 window.history.back();
126 // external-test *IS* cached in the dom after transitioning away
128 same( $( "#external-test" ).length, 1 );
130 // Switch back to the page again!
131 $.mobile.changePage( "external.html" );
134 // page is still present and displayed in the dom
136 same( $( "#external-test" ).length, 1 );
138 // Now turn off our removal prevention.
139 preventRemoval = false;
141 window.history.back();
144 // external-test is *NOT* cached in the dom after transitioning away
146 same( $( "#external-test" ).length, 0 );
147 $( document ).unbind( "pageremove", removeCallback );
153 asyncTest( "external page is cached in the DOM after pagehide", function(){
154 $.testHelper.pageSequence([
158 $.mobile.changePage( "cached-external.html" );
161 // page is pulled and displayed in the dom
163 same( $( "#external-test-cached" ).length, 1 );
164 window.history.back();
167 // external test page is cached in the dom after transitioning away
169 same( $( "#external-test-cached" ).length, 1 );
175 asyncTest( "external page is cached in the DOM after pagehide when option is set globally", function(){
176 $.testHelper.pageSequence([
180 $.mobile.page.prototype.options.domCache = true;
181 $.mobile.changePage( "external.html" );
184 // page is pulled and displayed in the dom
186 same( $( "#external-test" ).length, 1 );
187 window.history.back();
190 // external test page is cached in the dom after transitioning away
192 same( $( "#external-test" ).length, 1 );
193 $.mobile.page.prototype.options.domCache = false;
194 $( "#external-test" ).remove();
199 asyncTest( "page last scroll distance is remembered while navigating to and from pages", function(){
200 $.testHelper.pageSequence([
202 $( "body" ).height( $( window ).height() + 500 );
203 $.mobile.changePage( "external.html" );
207 // wait for the initial scroll to 0
208 setTimeout( function() {
209 window.scrollTo( 0, 300 );
210 same( $(window).scrollTop(), 300, "scrollTop is 300 after setting it" );
213 // wait for the scrollstop to fire and for the scroll to be
214 // recorded 100 ms afterward (see changes made to handle hash
215 // scrolling in some browsers)
216 setTimeout( navigateTestRoot, 500 );
224 // Give the silentScroll function some time to kick in.
225 setTimeout(function() {
226 same( $(window).scrollTop(), 300, "scrollTop is 300 after returning to the page" );
227 $( "body" ).height( "" );
234 asyncTest( "forms with data attribute ajax set to false will not call changePage", function(){
236 var newChangePage = function(){
240 $.testHelper.sequence([
241 // avoid initial page load triggering changePage early
243 $.mobile.changePage = newChangePage;
245 $('#non-ajax-form').one('submit', function(event){
246 ok(true, 'submit callbacks are fired');
247 event.preventDefault();
252 ok(!called, "change page should not be called");
257 asyncTest( "forms with data attribute ajax not set or set to anything but false will call changePage", function(){
259 newChangePage = function(){
263 $.testHelper.sequence([
264 // avoid initial page load triggering changePage early
266 $.mobile.changePage = newChangePage;
267 $('#ajax-form, #rand-ajax-form').submit();
271 ok(called >= 2, "change page should be called at least twice");
277 asyncTest( "anchors with no href attribute will do nothing when clicked", function(){
280 $(window).bind("hashchange.temp", function(){
284 $( "<a>test</a>" ).appendTo( $.mobile.firstPage ).click();
286 setTimeout(function(){
287 same(fired, false, "hash shouldn't change after click");
288 $(window).unbind("hashchange.temp");
293 test( "urlHistory is working properly", function(){
296 same( $.type( $.mobile.urlHistory.stack ), "array", "urlHistory.stack is an array" );
299 $.mobile.urlHistory.stack[0] = { url: "foo", transition: "bar" };
300 $.mobile.urlHistory.stack[1] = { url: "baz", transition: "shizam" };
301 $.mobile.urlHistory.stack[2] = { url: "shizoo", transition: "shizaah" };
304 same( $.mobile.urlHistory.activeIndex , 0, "urlHistory.activeIndex is 0" );
307 same( $.type( $.mobile.urlHistory.getActive() ) , "object", "active item is an object" );
308 same( $.mobile.urlHistory.getActive().url , "foo", "active item has url foo" );
309 same( $.mobile.urlHistory.getActive().transition , "bar", "active item has transition bar" );
312 same( $.mobile.urlHistory.getPrev(), undefined, "urlHistory.getPrev() is undefined when active index is 0" );
313 $.mobile.urlHistory.activeIndex = 1;
314 same( $.mobile.urlHistory.getPrev().url, "foo", "urlHistory.getPrev() has url foo when active index is 1" );
315 $.mobile.urlHistory.activeIndex = 0;
316 same( $.mobile.urlHistory.getNext().url, "baz", "urlHistory.getNext() has url baz when active index is 0" );
319 $.mobile.urlHistory.activeIndex = 2;
320 $.mobile.urlHistory.addNew("test");
321 same( $.mobile.urlHistory.stack.length, 4, "urlHistory.addNew() adds an item after the active index" );
322 same( $.mobile.urlHistory.activeIndex, 3, "urlHistory.addNew() moves the activeIndex to the newly added item" );
325 $.mobile.urlHistory.activeIndex = 0;
326 $.mobile.urlHistory.clearForward();
327 same( $.mobile.urlHistory.stack.length, 1, "urlHistory.clearForward() clears the url stack after the active index" );
331 function testListening( prop ){
332 var stillListening = false;
333 $(document).bind("pagebeforehide", function(){
334 stillListening = true;
336 location.hash = "foozball";
337 setTimeout(function(){
338 ok( prop == stillListening, prop + " = false disables default hashchange event handler");
345 asyncTest( "ability to disable our hash change event listening internally", function(){
346 testListening( ! $.mobile.urlHistory.ignoreNextHashChange );
349 asyncTest( "ability to disable our hash change event listening globally", function(){
350 testListening( $.mobile.hashListeningEnabled );
353 var testDataUrlHash = function( linkSelector, matches ) {
354 $.testHelper.pageSequence([
355 function(){ window.location.hash = ""; },
356 function(){ $(linkSelector).click(); },
358 $.testHelper.assertUrlLocation(
360 report: "url or hash should match"
371 test( "when loading a page where data-url is not defined on a sub element hash defaults to the url", function(){
372 testDataUrlHash( "#non-data-url a", {hashOrPush: siteDirectory + "data-url-tests/non-data-url.html"} );
375 test( "data url works for nested paths", function(){
376 var url = "foo/bar.html";
377 testDataUrlHash( "#nested-data-url a", {hash: url, push: home + url} );
380 test( "data url works for single quoted paths and roles", function(){
381 var url = "foo/bar/single.html";
382 testDataUrlHash( "#single-quotes-data-url a", {hash: url, push: home + url} );
385 test( "data url works when role and url are reversed on the page element", function(){
386 var url = "foo/bar/reverse.html";
387 testDataUrlHash( "#reverse-attr-data-url a", {hash: url, push: home + url} );
390 asyncTest( "last entry choosen amongst multiple identical url history stack entries on hash change", function(){
391 // make sure the stack is clear after initial page load an any other delayed page loads
392 // TODO better browser state management
393 $.mobile.urlHistory.stack = [];
394 $.mobile.urlHistory.activeIndex = 0;
396 $.testHelper.pageSequence([
397 function(){ $.testHelper.openPage("#dup-history-first"); },
398 function(){ $("#dup-history-first a").click(); },
399 function(){ $("#dup-history-second a:first").click(); },
400 function(){ $("#dup-history-first a").click(); },
401 function(){ $("#dup-history-second a:last").click(); },
402 function(){ $("#dup-history-dialog a:contains('Close')").click(); },
405 // fourth page (third index) in the stack to account for first page being hash manipulation,
406 // the third page is dup-history-second which has two entries in history
407 // the test is to make sure the index isn't 1 in this case, or the first entry for dup-history-second
408 same($.mobile.urlHistory.activeIndex, 3, "should be the fourth page in the stack");
413 asyncTest( "going back from a page entered from a dialog skips the dialog and goes to the previous page", function(){
414 $.testHelper.pageSequence([
416 function(){ $.testHelper.openPage("#skip-dialog-first"); },
418 // transition to the dialog
419 function(){ $("#skip-dialog-first a").click(); },
421 // transition to the second page
422 function(){ $("#skip-dialog a").click(); },
424 // transition past the dialog via data-rel=back link on the second page
425 function(){ $("#skip-dialog-second a").click(); },
427 // make sure we're at the first page and not the dialog
429 $.testHelper.assertUrlLocation({
430 hash: "skip-dialog-first",
431 push: homeWithSearch + "#skip-dialog-first",
432 report: "should be the first page in the sequence"
439 asyncTest( "going forward from a page entered from a dialog skips the dialog and goes to the next page", function(){
440 $.testHelper.pageSequence([
442 function(){ $.testHelper.openPage("#skip-dialog-first"); },
444 // transition to the dialog
445 function(){ $("#skip-dialog-first a").click(); },
447 // transition to the second page
448 function(){ $("#skip-dialog a").click(); },
450 // transition to back past the dialog
451 function(){ window.history.back(); },
453 // transition to the second page past the dialog through history
454 function(){ window.history.forward(); },
456 // make sure we're on the second page and not the dialog
458 $.testHelper.assertUrlLocation({
459 hash: "skip-dialog-second",
460 push: homeWithSearch + "#skip-dialog-second",
461 report: "should be the second page after the dialog"
468 asyncTest( "going back from a dialog triggered from a dialog should result in the first dialog ", function(){
469 $.testHelper.pageSequence([
471 function(){ $.testHelper.openPage("#nested-dialog-page"); },
473 // transition to the dialog
474 function(){ $("#nested-dialog-page a").click(); },
476 // transition to the second dialog
477 function(){ $("#nested-dialog-first a").click(); },
479 // transition to back to the first dialog
480 function(){ window.history.back(); },
482 // make sure we're on first dialog
484 same($(".ui-page-active")[0], $("#nested-dialog-first")[0], "should be the first dialog");
489 asyncTest( "loading a relative file path after an embeded page works", function(){
490 $.testHelper.pageSequence([
491 // transition second page
492 function(){ $.testHelper.openPage("#relative-after-embeded-page-first"); },
494 // transition second page
495 function(){ $("#relative-after-embeded-page-first a").click(); },
497 // transition to the relative ajax loaded page
498 function(){ $("#relative-after-embeded-page-second a").click(); },
500 // make sure the page was loaded properly via ajax
502 // data attribute intentionally left without namespace
503 same($(".ui-page-active").data("other"), "for testing", "should be relative ajax loaded page");
508 asyncTest( "Page title updates properly when clicking back to previous page", function(){
509 $.testHelper.pageSequence([
511 $.testHelper.openPage("#relative-after-embeded-page-first");
515 window.history.back();
519 same(document.title, "jQuery Mobile Navigation Test Suite");
525 asyncTest( "Page title updates properly when clicking a link back to first page", function(){
526 var title = document.title;
528 $.testHelper.pageSequence([
530 $.testHelper.openPage("#ajax-title-page");
534 $("#titletest1").click();
538 same(document.title, "Title Tag");
539 $.mobile.activePage.find("#title-check-link").click();
543 same(document.title, title);
549 asyncTest( "Page title updates properly from title tag when loading an external page", function(){
550 $.testHelper.pageSequence([
552 $.testHelper.openPage("#ajax-title-page");
556 $("#titletest1").click();
560 same(document.title, "Title Tag");
566 asyncTest( "Page title updates properly from data-title attr when loading an external page", function(){
567 $.testHelper.pageSequence([
569 $.testHelper.openPage("#ajax-title-page");
573 $("#titletest2").click();
577 same(document.title, "Title Attr");
583 asyncTest( "Page title updates properly from heading text in header when loading an external page", function(){
584 $.testHelper.pageSequence([
586 $.testHelper.openPage("#ajax-title-page");
590 $("#titletest3").click();
594 same(document.title, "Title Heading");
600 asyncTest( "Page links to the current active page result in the same active page", function(){
601 $.testHelper.pageSequence([
603 $.testHelper.openPage("#self-link");
607 $("a[href='#self-link']").click();
611 same($.mobile.activePage[0], $("#self-link")[0], "self-link page is still the active page" );
617 asyncTest( "links on subdirectory pages with query params append the params and load the page", function(){
618 $.testHelper.pageSequence([
620 $.testHelper.openPage("#data-url-tests/non-data-url.html");
624 $("#query-param-anchor").click();
628 $.testHelper.assertUrlLocation({
629 hashOrPush: home + "data-url-tests/non-data-url.html?foo=bar",
630 report: "the hash or url has query params"
633 ok($(".ui-page-active").jqmData("url").indexOf("?foo=bar") > -1, "the query params are in the data url");
639 asyncTest( "identical query param link doesn't add additional set of query params", function(){
640 $.testHelper.pageSequence([
642 $.testHelper.openPage("#data-url-tests/non-data-url.html");
646 $("#query-param-anchor").click();
650 $.testHelper.assertUrlLocation({
651 hashOrPush: home + "data-url-tests/non-data-url.html?foo=bar",
652 report: "the hash or url has query params"
655 $("#query-param-anchor").click();
659 $.testHelper.assertUrlLocation({
660 hashOrPush: home + "data-url-tests/non-data-url.html?foo=bar",
661 report: "the hash or url still has query params"
669 // Special handling inside navigation because query params must be applied to the hash
670 // or absolute reference and dialogs apply extra information int the hash that must be removed
671 asyncTest( "query param link from a dialog to itself should be a not add another dialog", function(){
674 $.testHelper.pageSequence([
675 // open our test page
677 $.testHelper.openPage("#dialog-param-link");
680 // navigate to the subdirectory page with the query link
682 $("#dialog-param-link a").click();
685 // navigate to the query param self reference link
687 $("#dialog-param-link-page a").click();
690 // attempt to navigate to the same link
692 // store the current hash for comparison (with one dialog hash key)
693 firstDialogLoc = location.hash || location.href;
694 $("#dialog-param-link-page a").click();
698 same(location.hash || location.href, firstDialogLoc, "additional dialog hash key not added");
704 asyncTest( "query data passed as string to changePage is appended to URL", function(){
705 $.testHelper.pageSequence([
706 // open our test page
708 $.mobile.changePage( "form-tests/changepage-data.html", {
714 $.testHelper.assertUrlLocation({
715 hashOrPush: home + "form-tests/changepage-data.html?foo=1&bar=2",
716 report: "the hash or url still has query params"
724 asyncTest( "query data passed as object to changePage is appended to URL", function(){
725 $.testHelper.pageSequence([
726 // open our test page
728 $.mobile.changePage( "form-tests/changepage-data.html", {
737 $.testHelper.assertUrlLocation({
738 hashOrPush: home + "form-tests/changepage-data.html?foo=3&bar=4",
739 report: "the hash or url still has query params"
747 asyncTest( "refresh of a dialog url should not duplicate page", function(){
748 $.testHelper.pageSequence([
749 // open our test page
751 same($(".foo-class").length, 1, "should only have one instance of foo-class in the document");
752 location.hash = "#foo&ui-state=dialog";
756 $.testHelper.assertUrlLocation({
757 hash: "foo&ui-state=dialog",
758 push: homeWithSearch + "#foo&ui-state=dialog",
759 report: "hash should match what was loaded"
762 same( $(".foo-class").length, 1, "should only have one instance of foo-class in the document" );
768 asyncTest( "internal form with no action submits to document URL", function(){
769 $.testHelper.pageSequence([
770 // open our test page
772 $.testHelper.openPage("#internal-no-action-form-page");
776 $("#internal-no-action-form-page form").eq(0).submit();
780 $.testHelper.assertUrlLocation({
781 hashOrPush: home + "?foo=1&bar=2",
782 report: "hash should match what was loaded"
790 asyncTest( "external page containing form with no action submits to page URL", function(){
791 $.testHelper.pageSequence([
792 // open our test page
794 $.testHelper.openPage("#internal-no-action-form-page");
798 $("#internal-no-action-form-page a").eq(0).click();
802 $("#external-form-no-action-page form").eq(0).submit();
806 $.testHelper.assertUrlLocation({
807 hashOrPush: home + "form-tests/form-no-action.html?foo=1&bar=2",
808 report: "hash should match page url and not document url"
816 asyncTest( "handling of active button state when navigating", 1, function(){
818 $.testHelper.pageSequence([
819 // open our test page
821 $.testHelper.openPage("#active-state-page1");
825 $("#active-state-page1 a").eq(0).click();
829 $("#active-state-page2 a").eq(0).click();
833 ok(!$("#active-state-page1 a").hasClass( $.mobile.activeBtnClass ), "No button should not have class " + $.mobile.activeBtnClass );
839 // issue 2444 https://github.com/jquery/jquery-mobile/issues/2444
840 // results from preventing spurious hash changes
841 asyncTest( "dialog should return to its parent page when open and closed multiple times", function() {
842 $.testHelper.pageSequence([
843 // open our test page
845 $.testHelper.openPage("#default-trans-dialog");
849 $.mobile.activePage.find( "a" ).click();
853 window.history.back();
857 same( $.mobile.activePage[0], $( "#default-trans-dialog" )[0] );
858 $.mobile.activePage.find( "a" ).click();
862 window.history.back();
866 same( $.mobile.activePage[0], $( "#default-trans-dialog" )[0] );
872 asyncTest( "clicks with middle mouse button are ignored", function() {
873 $.testHelper.pageSequence([
875 $.testHelper.openPage( "#odd-clicks-page" );
879 $( "#right-or-middle-click" ).click();
882 // make sure the page is opening first without the mocked button click value
883 // only necessary to prevent issues with test specific fixtures
885 same($.mobile.activePage[0], $("#odd-clicks-page-dest")[0]);
886 $.testHelper.openPage( "#odd-clicks-page" );
888 // mock the which value to simulate a middle click
889 $.Event.prototype.which = 2;
893 $( "#right-or-middle-click" ).click();
896 function( timeout ) {
897 ok( timeout, "page event handler timed out due to ignored click" );
898 ok($.mobile.activePage[0] !== $("#odd-clicks-page-dest")[0], "pages are not the same");
904 asyncTest( "disabling link binding disables navigation via links and highlighting", function() {
905 $.mobile.linkBindingEnabled = false;
907 $.testHelper.pageSequence([
909 $.testHelper.openPage("#bar");
913 $.mobile.activePage.find( "a" ).click();
916 function( timeout ) {
917 ok( !$.mobile.activePage.find( "a" ).hasClass( $.mobile.activeBtnClass ), "vlick handler doesn't add the activebtn class" );
918 ok( timeout, "no page change was fired" );
924 asyncTest( "handling of button active state when navigating by clicking back button", 1, function(){
925 $.testHelper.pageSequence([
926 // open our test page
928 $.testHelper.openPage("#active-state-page1");
932 $("#active-state-page1 a").eq(0).click();
936 $("#active-state-page2 a").eq(1).click();
940 $("#active-state-page1 a").eq(0).click();
944 ok(!$("#active-state-page2 a").hasClass( $.mobile.activeBtnClass ), "No button should not have class " + $.mobile.activeBtnClass );
950 asyncTest( "can navigate to dynamically injected page with dynamically injected link", function(){
951 $.testHelper.pageSequence([
952 // open our test page
954 $.testHelper.openPage("#inject-links-page");
958 var $ilpage = $( "#inject-links-page" ),
959 $link = $( "<a href='#injected-test-page'>injected-test-page link</a>" );
961 // Make sure we actually navigated to the expected page.
962 ok( $.mobile.activePage[ 0 ] == $ilpage[ 0 ], "navigated successfully to #inject-links-page" );
964 // Now dynamically insert a page.
965 $ilpage.parent().append( "<div data-role='page' id='injected-test-page'>testing...</div>" );
967 // Now inject a link to this page dynamically and attempt to navigate
968 // to the page we just inserted.
969 $link.appendTo( $ilpage ).click();
973 // Make sure we actually navigated to the expected page.
974 ok( $.mobile.activePage[ 0 ] == $( "#injected-test-page" )[ 0 ], "navigated successfully to #injected-test-page" );
981 asyncTest( "application url with dialogHashKey loads application's first page", function(){
982 $.testHelper.pageSequence([
983 // open our test page
985 // Navigate to any page except the first page of the application.
986 $.testHelper.openPage("#foo");
990 ok( $.mobile.activePage[ 0 ] === $( "#foo" )[ 0 ], "navigated successfully to #foo" );
992 // Now navigate to an hash that contains just a dialogHashKey.
993 $.mobile.changePage("#" + $.mobile.dialogHashKey);
997 // Make sure we actually navigated to the first page.
998 ok( $.mobile.activePage[ 0 ] === $.mobile.firstPage[ 0 ], "navigated successfully to first-page" );
1000 // Now make sure opening the page didn't result in page duplication.
1001 ok( $.mobile.firstPage.hasClass( "first-page" ), "first page has expected class" );
1002 same( $( ".first-page" ).length, 1, "first page was not duplicated" );
1009 asyncTest( "navigate to non-existent internal page throws pagechangefailed", function(){
1010 var pagechangefailed = false,
1011 pageChangeFailedCB = function( e ) {
1012 pagechangefailed = true;
1015 $( document ).bind( "pagechangefailed", pageChangeFailedCB );
1017 $.testHelper.pageSequence([
1018 // open our test page
1020 // Make sure there's only one copy of the first-page in the DOM to begin with.
1021 ok( $.mobile.firstPage.hasClass( "first-page" ), "first page has expected class" );
1022 same( $( ".first-page" ).length, 1, "first page was not duplicated" );
1024 // Navigate to any page except the first page of the application.
1025 $.testHelper.openPage("#foo");
1029 var $foo = $( "#foo" );
1030 ok( $.mobile.activePage[ 0 ] === $foo[ 0 ], "navigated successfully to #foo" );
1031 same( pagechangefailed, false, "no page change failures" );
1033 // Now navigate to a non-existent page.
1034 $foo.find( "#bad-internal-page-link" ).click();
1038 // Make sure a pagechangefailed event was triggered.
1039 same( pagechangefailed, true, "pagechangefailed dispatched" );
1041 // Make sure we didn't navigate away from #foo.
1042 ok( $.mobile.activePage[ 0 ] === $( "#foo" )[ 0 ], "did not navigate away from #foo" );
1044 // Now make sure opening the page didn't result in page duplication.
1045 same( $( ".first-page" ).length, 1, "first page was not duplicated" );
1047 $( document ).unbind( "pagechangefailed", pageChangeFailedCB );
1054 asyncTest( "prefetched links with data rel dialog result in a dialog", function() {
1055 $.testHelper.pageSequence([
1056 // open our test page
1058 // Navigate to any page except the first page of the application.
1059 $.testHelper.openPage("#prefetched-dialog-page");
1063 $("#prefetched-dialog-link").click();
1067 ok( $.mobile.activePage.is(".ui-dialog"), "prefetched page is rendered as a dialog" );
1073 asyncTest( "first page gets reloaded if pruned from the DOM", function(){
1074 var hideCallbackTriggered = false;
1076 function hideCallback( e, data )
1078 var page = e.target;
1079 ok( ( page === $.mobile.firstPage[ 0 ] ), "hide called with prevPage set to firstPage");
1080 if ( page === $.mobile.firstPage[ 0 ] ) {
1083 hideCallbackTriggered = true;
1086 $(document).bind('pagehide', hideCallback);
1088 $.testHelper.pageSequence([
1090 // Make sure the first page is actually in the DOM.
1091 ok( $.mobile.firstPage.parent().length !== 0, "first page is currently in the DOM" );
1093 // Make sure the first page is the active page.
1094 ok( $.mobile.activePage[ 0 ] === $.mobile.firstPage[ 0 ], "first page is the active page" );
1096 // Now make sure the first page has an id that we can use to reload it.
1097 ok( $.mobile.firstPage[ 0 ].id, "first page has an id" );
1099 // Make sure there is only one first page in the DOM.
1100 same( $( ".first-page" ).length, 1, "only one instance of the first page in the DOM" );
1102 // Navigate to any page except the first page of the application.
1103 $.testHelper.openPage("#foo");
1107 // Make sure the active page is #foo.
1108 ok( $.mobile.activePage[ 0 ] === $( "#foo" )[ 0 ], "navigated successfully to #foo" );
1110 // Make sure our hide callback was triggered.
1111 ok( hideCallbackTriggered, "hide callback was triggered" );
1113 // Make sure the first page was actually pruned from the document.
1114 ok( $.mobile.firstPage.parent().length === 0, "first page was pruned from the DOM" );
1115 same( $( ".first-page" ).length, 0, "no instance of the first page in the DOM" );
1117 // Remove our hideCallback.
1118 $(document).unbind('pagehide', hideCallback);
1120 // Navigate back to the first page!
1121 $.testHelper.openPage( "#" + $.mobile.firstPage[0].id );
1125 var firstPage = $( ".first-page" );
1127 // We should only have one first page in the document at any time!
1128 same( firstPage.length, 1, "single instance of first page recreated in the DOM" );
1130 // Make sure the first page in the DOM is actually a different DOM element than the original
1131 // one we started with.
1132 ok( $.mobile.firstPage[ 0 ] !== firstPage[ 0 ], "first page is a new DOM element");
1134 // Make sure we actually navigated to the new first page.
1135 ok( $.mobile.activePage[ 0 ] === firstPage[ 0 ], "navigated successfully to new first-page");
1137 // Reset the $.mobile.firstPage for subsequent tests.
1138 // XXX: Should we just get rid of the new one and restore the old?
1139 $.mobile.firstPage = $.mobile.activePage;
1146 asyncTest( "test that clicks are ignored where data-ajax='false' parents exist", function() {
1147 var $disabledByParent = $( "#unhijacked-link-by-parent" ),
1148 $disabledByAttr = $( "#unhijacked-link-by-attr" );
1150 $.mobile.ignoreContentEnabled = true;
1152 $.testHelper.pageSequence([
1154 $.mobile.changePage( "#link-hijacking-test" );
1158 $( "#hijacked-link" ).trigger( 'click' );
1162 ok( $.mobile.activePage.is("#link-hijacking-destination"), "nav works for links to hijacking destination" );
1163 window.history.back();
1167 $disabledByParent.trigger( 'click' );
1171 ok( $.mobile.activePage.is("#link-hijacking-test"), "click should be ignored keeping the active mobile page the same as before" );
1175 $disabledByAttr.trigger( 'click' );
1179 ok( $.mobile.activePage.is("#link-hijacking-test"), "click should be ignored keeping the active mobile page the same as before" );
1181 $.mobile.ignoreContentEnabled = false;
1187 asyncTest( "test that *vclicks* are ignored where data-ajax='false' parents exist", function() {
1188 var $disabledByParent = $( "#unhijacked-link-by-parent" ),
1189 $disabledByAttr = $( "#unhijacked-link-by-attr" ),
1190 $hijacked = $( "#hijacked-link" );
1192 $.mobile.ignoreContentEnabled = true;
1194 $.testHelper.pageSequence([
1196 $.mobile.changePage( "#link-hijacking-test" );
1200 // force the active button class
1201 $hijacked.addClass( $.mobile.activeBtnClass );
1202 $hijacked.trigger( 'vclick' );
1203 ok( $hijacked.hasClass( $.mobile.activeBtnClass ), "active btn class is added to the link per normal" );
1205 $disabledByParent.trigger( 'vclick' );
1206 ok( !$disabledByParent.hasClass( $.mobile.activeBtnClass ), "active button class is never added to the link" );
1208 $disabledByAttr.trigger( 'vclick' );
1209 ok( !$disabledByAttr.hasClass( $.mobile.activeBtnClass ), "active button class is never added to the link" );
1211 $.mobile.ignoreContentEnabled = false;