diff --git a/js/jquery.mobile.navigation.js b/js/jquery.mobile.navigation.js index 2037d6e9..95f55cdf 100644 --- a/js/jquery.mobile.navigation.js +++ b/js/jquery.mobile.navigation.js @@ -116,7 +116,7 @@ clearForward: function(){ urlHistory.stack = urlHistory.stack.slice( 0, urlHistory.activeIndex + 1 ); }, - + //disable hashchange event listener internally to ignore one change //toggled internally when location.hash is updated to match the url of a successful page load ignoreNextHashChange: true @@ -258,7 +258,7 @@ from = toIsArray ? to[0] : $.mobile.activePage; to = toIsArray ? to[1] : to; - + var url = $.type(to) === "string" ? path.stripHash( to ) : "", fileUrl = url, data, @@ -280,7 +280,7 @@ pageTransitionQueue.unshift(arguments); return; } - + isPageTransitioning = true; // if the changePage was sent from a hashChange event @@ -346,7 +346,7 @@ $.mobile.changePage.apply($.mobile, pageTransitionQueue.pop()); } } - + //function for transitioning between two existing pages function transitionPages() { $.mobile.silentScroll(); @@ -360,13 +360,13 @@ if( url.indexOf( "&" + $.mobile.subPageUrlKey ) > -1 ){ to = $( "[data-url='" + url + "']" ); } - + if( from ){ //set as data for returning to that spot from.data( "lastScroll", currScroll); //trigger before show/hide events from.data( "page" )._trigger( "beforehide", { nextPage: to } ); - } + } to.data( "page" )._trigger( "beforeshow", { prevPage: from || $("") } ); function loadComplete(){ @@ -386,7 +386,7 @@ removeActiveLinkClass(); //jump to top or prev scroll, sometimes on iOS the page has not rendered yet. I could only get by this with a setTimeout, but would like to avoid that. - $.mobile.silentScroll( to.data( "lastScroll" ) ); + $.mobile.silentScroll( to.data( "lastScroll" ) ); reFocus( to ); @@ -396,7 +396,7 @@ } //trigger pageshow, define prevPage as either from or empty jQuery obj to.data( "page" )._trigger( "show", null, { prevPage: from || $("") } ); - + //set "to" as activePage $.mobile.activePage = to; @@ -404,7 +404,7 @@ if (duplicateCachedPage !== null) { duplicateCachedPage.remove(); } - + //remove initial build class (only present on first pageshow) $html.removeClass( "ui-mobile-rendering" ); @@ -445,7 +445,7 @@ to.add(from).removeClass("out in reverse " + transition ); if( from ){ from.removeClass( $.mobile.activePageClass ); - } + } loadComplete(); removeContainerClasses(); }); @@ -454,7 +454,7 @@ $.mobile.pageLoading( true ); if( from ){ from.removeClass( $.mobile.activePageClass ); - } + } to.addClass( $.mobile.activePageClass ); loadComplete(); } @@ -497,7 +497,7 @@ if ( to.length && !isFormRequest ) { if( fileUrl && base ){ base.set( fileUrl ); - } + } enhancePage(); transitionPages(); } else { @@ -514,10 +514,15 @@ type: type, data: data, success: function( html ) { - //pre-parse html to check for a data-url, //use it as the new fileUrl, base path, etc - var redirectLoc = / data-url="(.*)"/.test( html ) && RegExp.$1; + var all = $("
"), + redirectLoc; + + //workaround to allow scripts to execute when included in page divs + all.get(0).innerHTML = html; + to = all.find('[data-role="page"], [data-role="dialog"]').first(); + redirectLoc = all.find('[data-url]').data('url'); if( redirectLoc ){ if(base){ @@ -531,11 +536,6 @@ } } - var all = $("
"); - //workaround to allow scripts to execute when included in page divs - all.get(0).innerHTML = html; - to = all.find('[data-role="page"], [data-role="dialog"]').first(); - //rewrite src and href attrs to use a base url if( !$.support.dynamicBaseTag ){ var newPath = path.get( fileUrl ); @@ -619,10 +619,10 @@ $( "a" ).live( "click", function(event) { var $this = $(this), - + //get href, if defined, otherwise fall to null # href = $this.attr( "href" ) || "#", - + //get href, remove same-domain protocol and host url = path.clean( href ), @@ -703,7 +703,7 @@ var to = path.stripHash( location.hash ), //transition is false if it's the first page, undefined otherwise (and may be overridden by default) transition = $.mobile.urlHistory.stack.length === 0 ? false : undefined; - + //if listening is disabled (either globally or temporarily), or it's a dialog hash if( !$.mobile.hashListeningEnabled || !urlHistory.ignoreNextHashChange || (urlHistory.stack.length > 1 && to.indexOf( dialogHashKey ) > -1 && !$.mobile.activePage.is( ".ui-dialog" )) diff --git a/tests/unit/dialog/dialog_events.js b/tests/unit/dialog/dialog_events.js index 54a55c27..57e1e80b 100644 --- a/tests/unit/dialog/dialog_events.js +++ b/tests/unit/dialog/dialog_events.js @@ -2,38 +2,23 @@ * mobile dialog unit tests */ (function($){ - var wait = function(length){ - setTimeout(start, length); - stop(); - }; + module('jquery.mobile.dialog.js'); - module('jquery.mobile.dialog.js', { - setup: function(){ - //bring up the dialog - $("a[href='#foo-dialog']").click(); + asyncTest( "dialog hash is added when the dialog is opened and removed when closed", function(){ + expect( 2 ); - //wait for the dialog to appear - wait(500); - }, - teardown: function(){ + //bring up the dialog + $("a[href='#foo-dialog']").click(); + + setTimeout(function(){ + ok(/&ui-state=dialog/.test(location.hash), "ui-state=dialog =~ location.hash"); // close the dialog $(".ui-dialog .ui-icon-delete").parents("a").click(); - - // wait for the dialog to disappear - wait(500); - } - }); - - test( "dialog hash is added when the dialog is opened", function(){ - ok(/&ui-state=dialog/.test(location.hash), "ui-state=dialog =~ location.hash"); - }); - - asyncTest( "dialog hash param is removed on close", function(){ - $(".ui-dialog .ui-icon-delete").parents("a").click(); + }, 500); setTimeout(function(){ ok(!/&ui-state=dialog/.test(location.hash), "ui-state=dialog !~ location.hash"); start(); - }, 600); + }, 1000); }); })(jQuery); diff --git a/tests/unit/listview/listview_core.js b/tests/unit/listview/listview_core.js index 0ac969f8..86d21feb 100644 --- a/tests/unit/listview/listview_core.js +++ b/tests/unit/listview/listview_core.js @@ -194,7 +194,7 @@ $('.ui-page-active input').trigger('change'); setTimeout(function() { - same($('.ui-page-active li[style="display: none;"]').length, 2); + same($('.ui-page-active li[style^="display: none;"]').length, 2); start(); }, 1000); }); @@ -203,7 +203,7 @@ $('.ui-page-active input').val('a'); $('.ui-page-active input').trigger('change'); setTimeout(function() { - same($('.ui-page-active li[style="display: none;"]').length, 0); + same($('.ui-page-active li[style^="display: none;"]').length, 0); start(); }, 1000); }); diff --git a/tests/unit/navigation/data-url.html b/tests/unit/navigation/data-url.html new file mode 100644 index 00000000..6f8bf224 --- /dev/null +++ b/tests/unit/navigation/data-url.html @@ -0,0 +1,9 @@ + + + + + +
+
+ + diff --git a/tests/unit/navigation/index.html b/tests/unit/navigation/index.html index daeaf3c2..85625249 100644 --- a/tests/unit/navigation/index.html +++ b/tests/unit/navigation/index.html @@ -79,6 +79,14 @@ +
+ +
+ +
+ +
+
diff --git a/tests/unit/navigation/navigation_core.js b/tests/unit/navigation/navigation_core.js index 2300c07b..224ff068 100644 --- a/tests/unit/navigation/navigation_core.js +++ b/tests/unit/navigation/navigation_core.js @@ -37,82 +37,82 @@ same(called, 2, "change page should be called twice"); }); - - + + asyncTest( "anchors with no href attribute will do nothing when clicked", function(){ var fired = false; - + $(window).bind("hashchange.temp", function(){ fired = true; }); - + $( "test" ).appendTo( $.mobile.pageContainer ).click(); - + setTimeout(function(){ start(); same(fired, false, "hash shouldn't change after click"); $(window).unbind("hashchange.temp"); }, 500); }); - - - - + + + + test( "path.get method is working properly", function(){ window.location.hash = "foo" same($.mobile.path.get(), "foo", "get method returns location.hash minus hash character"); same($.mobile.path.get( "#foo/bar/baz.html" ), "foo/bar/", "get method with hash arg returns path with no filename or hash prefix"); same($.mobile.path.get( "#foo/bar/baz.html/" ), "foo/bar/baz.html/", "last segment of hash is retained if followed by a trailing slash"); }); - + test( "path.getFilePath method is working properly", function(){ same($.mobile.path.getFilePath("foo.html" + "&" + $.mobile.subPageUrlKey ), "foo.html", "returns path without sub page key"); }); - - + + test( "path.set method is working properly", function(){ $.mobile.urlHistory.ignoreNextHashChange = false; $.mobile.path.set("foo"); same("foo", window.location.hash.replace(/^#/,""), "sets location.hash properly"); location.hash = ""; }); - + test( "path.makeAbsolute is working properly", function(){ $.mobile.urlHistory.ignoreNextHashChange = false; $.mobile.path.set("bar/"); same( $.mobile.path.makeAbsolute("test.html"), "bar/test.html", "prefixes path with absolute base path from hash"); location.hash = ""; }); - + test( "path.clean is working properly", function(){ var localroot = location.href.split("/").slice(0, 3).join("/"), remoteroot = "http://google.com/", fakepath = "foo/bar/baz.html", localpath = localroot + fakepath, remotepath = remoteroot + fakepath; - + same( $.mobile.path.clean( localpath ), fakepath, "removes location protocol, host, port from same-domain path"); same( $.mobile.path.clean( remotepath ), remotepath, "does nothing to an external domain path"); }); - + test( "path.stripHash is working properly", function(){ same( $.mobile.path.stripHash( "#bar" ), "bar", "returns a hash without the # prefix"); }); - + test( "path.hasProtocol is working properly", function(){ same( $.mobile.path.hasProtocol( "tel:5559999" ), true, "value in tel protocol format has protocol" ); same( $.mobile.path.hasProtocol( location.href ), true, "location href has protocol" ); same( $.mobile.path.hasProtocol( "foo/bar/baz.html" ), false, "simple directory path has no protocol" ); same( $.mobile.path.hasProtocol( "file://foo/bar/baz.html" ), true, "simple directory path with file:// has protocol" ); }); - + test( "path.isRelative is working properly", function(){ same( $.mobile.path.isRelative("#foo/bar"), false, "path starting with a # is not relative" ); same( $.mobile.path.isRelative("/foo/bar"), false, "path starting with a / is not relative" ); same( $.mobile.path.isRelative("http://example.com/foo"), false, "full url path is not relative" ); same( $.mobile.path.isRelative("foo/bar.html"), true, "simple path is relative" ); }); - + test( "path.isExternal is working properly", function(){ same( $.mobile.path.isExternal( location.href ), false, "same domain is not external" ); same( $.mobile.path.isExternal( "http://example.com" ), true, "example.com is external" ); @@ -127,45 +127,45 @@ same($.mobile.path.isExternal("foo"), false, "simple string"); same($.mobile.path.isExternal("#foo"), false, "local id reference"); }); - - + + test( "urlHistory is working properly", function(){ - + //urlHistory same( $.type( $.mobile.urlHistory.stack ), "array", "urlHistory.stack is an array" ); - + //preload the stack $.mobile.urlHistory.stack[0] = { url: "foo", transition: "bar" }; $.mobile.urlHistory.stack[1] = { url: "baz", transition: "shizam" }; $.mobile.urlHistory.stack[2] = { url: "shizoo", transition: "shizaah" }; - + //active index same( $.mobile.urlHistory.activeIndex , 0, "urlHistory.activeIndex is 0" ); - + //getActive same( $.type( $.mobile.urlHistory.getActive() ) , "object", "active item is an object" ); same( $.mobile.urlHistory.getActive().url , "foo", "active item has url foo" ); same( $.mobile.urlHistory.getActive().transition , "bar", "active item has transition bar" ); - + //get prev / next same( $.mobile.urlHistory.getPrev(), undefined, "urlHistory.getPrev() is undefined when active index is 0" ); $.mobile.urlHistory.activeIndex = 1; same( $.mobile.urlHistory.getPrev().url, "foo", "urlHistory.getPrev() has url foo when active index is 1" ); $.mobile.urlHistory.activeIndex = 0; same( $.mobile.urlHistory.getNext().url, "baz", "urlHistory.getNext() has url baz when active index is 0" ); - + //add new $.mobile.urlHistory.activeIndex = 2; $.mobile.urlHistory.addNew("test"); same( $.mobile.urlHistory.stack.length, 4, "urlHistory.addNew() adds an item after the active index" ); same( $.mobile.urlHistory.activeIndex, 3, "urlHistory.addNew() moves the activeIndex to the newly added item" ); - + //clearForward $.mobile.urlHistory.activeIndex = 0; $.mobile.urlHistory.clearForward(); same( $.mobile.urlHistory.stack.length, 1, "urlHistory.clearForward() clears the url stack after the active index" ); }); - + //url listening function testListening( prop ){ prop = false; @@ -181,15 +181,15 @@ prop = true; }, 1000); } - + asyncTest( "ability to disable our hash change event listening internally", function(){ testListening( $.mobile.urlHistory.ignoreNextHashChange ); }); - + asyncTest( "ability to disable our hash change event listening globally", function(){ testListening( $.mobile.hashListeningEnabled ); }); - + asyncTest( "changepage will only run once when a new page is visited", function(){ var called = 0; $.mobile.changePage = function(a,b,c,d,e){ @@ -198,11 +198,32 @@ }; $('#foo a').click(); - + setTimeout(function(){ start(); ok(called == 1, "change page should be called once"); }, 500); }); - + + asyncTest( "when loading a page where data-url is defined on a sub element set the hash with that url", function(){ + location.hash = ""; + $("#data-url a").click(); + + setTimeout(function(){ + ok(location.hash.indexOf("#foo/") >= 0); + start(); + }, 1000); + stop(); + }); + + asyncTest( "when loading a page where data-url is not defined on a sub element hash defaults to the url", function(){ + location.hash = ""; + $("#non-data-url a").click(); + + setTimeout(function(){ + ok(location.hash.indexOf("#non-data-url.html") >= 0); + start(); + }, 1000); + stop(); + }); })(jQuery); diff --git a/tests/unit/navigation/non-data-url.html b/tests/unit/navigation/non-data-url.html new file mode 100644 index 00000000..c1a4d6a8 --- /dev/null +++ b/tests/unit/navigation/non-data-url.html @@ -0,0 +1,9 @@ + + + + + +
+
+ +