From 91a5b8c09871c5dd940ee859651b979b4a75c3a9 Mon Sep 17 00:00:00 2001 From: scottjehl Date: Mon, 6 Dec 2010 11:40:28 -0500 Subject: [PATCH 1/3] Changed the way submit buttons work. Now, form input/button elements are appended to a div-based "button", invisibly filling its width and height. The user now interacts directly with the native control, rather than having to trigger a click from another anchor (which formerly prevented some native submit event handling from working). A workaround is still included to ensure the input's name/value is submitted along with the form when it's not a type=reset, as this is necessary for the button data to appear in the serialized form data. --- js/jquery.mobile.forms.button.js | 46 ++++++++++--------------- themes/default/jquery.mobile.button.css | 2 +- 2 files changed, 20 insertions(+), 28 deletions(-) diff --git a/js/jquery.mobile.forms.button.js b/js/jquery.mobile.forms.button.js index 2afeb732..31db9786 100644 --- a/js/jquery.mobile.forms.button.js +++ b/js/jquery.mobile.forms.button.js @@ -17,36 +17,11 @@ $.widget( "mobile.button", $.mobile.widget, { }, _create: function(){ var $el = this.element, - o = this.options, - type = $el.attr('type'); - $el - .addClass('ui-btn-hidden') - .attr('tabindex','-1'); + o = this.options; //add ARIA role - this.button = $( "", { - "href": "#", - "role": "button", - "aria-label": $el.attr( "type" ) - } ) + this.button = $( "
" ) .text( $el.text() || $el.val() ) - .insertBefore( $el ) - .click(function(e){ - if(!o.disabled){ - if ( $el.attr("type") !== "reset" ){ - var $buttonPlaceholder = $("", - {type: "hidden", name: $el.attr("name"), value: $el.attr("value")}) - .insertBefore($el); - - } - $el.submit(); - $buttonPlaceholder.remove(); - } - else{ - $el.trigger("click") - } - e.preventDefault(); - }) .buttonMarkup({ theme: o.theme, icon: o.icon, @@ -55,7 +30,24 @@ $.widget( "mobile.button", $.mobile.widget, { corners: o.corners, shadow: o.shadow, iconshadow: o.iconshadow + }) + .insertBefore( $el ) + .append( $el.addClass('ui-btn-hidden') ); + + //add hidden input during submit + if( $el.attr('type') !== 'reset' ){ + $el.click(function(){ + var $buttonPlaceholder = $("", + {type: "hidden", name: $el.attr("name"), value: $el.attr("value")}) + .insertBefore($el); + + //bind to doc to remove after submit handling + $(document).submit(function(){ + $buttonPlaceholder.remove(); + }); }); + } + }, enable: function(){ diff --git a/themes/default/jquery.mobile.button.css b/themes/default/jquery.mobile.button.css index 2ae040d7..0b10abba 100644 --- a/themes/default/jquery.mobile.button.css +++ b/themes/default/jquery.mobile.button.css @@ -50,4 +50,4 @@ .ui-btn-icon-top .ui-icon { top: 5px; } .ui-btn-icon-bottom .ui-icon { bottom: 5px; } /*hiding native button,inputs */ -.ui-btn-hidden { position: absolute; left: -9999px; } +.ui-btn-hidden { position: absolute; top: 0; left: 0; width: 100%; height: 100%; -webkit-appearance: button; opacity: 0; cursor: pointer; } From 008e7e4c37eb5b17dc92be5779479e56b5933043 Mon Sep 17 00:00:00 2001 From: scottjehl Date: Mon, 6 Dec 2010 09:01:45 -0500 Subject: [PATCH 2/3] changed to reference local js,css --- docs/pages/multipage-template.html | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/pages/multipage-template.html b/docs/pages/multipage-template.html index 6ae5dc62..9674a425 100755 --- a/docs/pages/multipage-template.html +++ b/docs/pages/multipage-template.html @@ -3,9 +3,8 @@ Page Title - - - + + From 80d56e655bac8aa6205a0c1f5a9877493a5ced71 Mon Sep 17 00:00:00 2001 From: scottjehl Date: Tue, 7 Dec 2010 12:05:10 -0500 Subject: [PATCH 3/3] Changed page navigation scripting to use data-url attributes instead of IDs for storing page URLs. This fixes a number of issues, most importantly #477, which exposed a conflict between jQuery's selector engine that would result in un-enhanced pages whenever linking between two pages in the same directory. The shift away from interal ID attribute usage also allows users to bind page events (pagecreate, pagebeforecreate) to a page div by its ID, which was a frequent cause of confusion when it didn't work as expected in former versions of the framework. Seemingly unrelated: these commits allow you to specify data-role="dialog" in multipage and single page templates. In multipage templates, the role must be on the page (a link with data-rel alone will not work in multi-page). This addresses issue number 464, but may need further testing for obscure scenarios. Fixes #477 (Pages are not enhanced when linking to a filename without a path) Fixes #493 (Click the same link twice -> blank page) Fixes #513 (closing dialog + returning to the same dialog) Fixes #550 (changePage() not updating hash for internal pages - breaks ) Fixes #464 (Dialogs don't work within multi-pages) Fixes #633 (Recent change to prevent same-page requests breaks select menu close button) Fixes #599 (Page ids & page specific events) Fixes #634 (After a bad page request, base url is not reset to current path) booya. --- docs/_assets/js/jqm-docs.js | 3 +- docs/api/events.html | 25 +++++++- docs/pages/docs-pages.html | 2 +- .../jquery.mobile.themeswitcher.js | 7 +-- js/jquery.mobile.core.js | 4 ++ js/jquery.mobile.dialog.js | 2 +- js/jquery.mobile.listview.js | 4 +- js/jquery.mobile.navigation.js | 63 +++++++++---------- 8 files changed, 65 insertions(+), 45 deletions(-) diff --git a/docs/_assets/js/jqm-docs.js b/docs/_assets/js/jqm-docs.js index 7dc84c78..72279730 100644 --- a/docs/_assets/js/jqm-docs.js +++ b/docs/_assets/js/jqm-docs.js @@ -1,7 +1,7 @@ //set up the theme switcher on the homepage $('div').live('pagecreate',function(event){ if( !$(this).is('.ui-dialog')){ - $('
Switch theme') + $('Switch theme') .buttonMarkup({ 'icon':'gear', 'inline': true, @@ -12,7 +12,6 @@ $('div').live('pagecreate',function(event){ .wrap('
') .click(function(){ $.themeswitcher(); - return false; }); } event.stopPropagation(); diff --git a/docs/api/events.html b/docs/api/events.html index a8802a33..219115d9 100755 --- a/docs/api/events.html +++ b/docs/api/events.html @@ -95,10 +95,33 @@ $('div').live('pagehide',function(event, ui){
Triggered on the page being initialized, after initialization occurs.
+ +
+		
+$('#aboutPage').live('pagebeforecreate',function(event){
+  alert('This page was just inserted into the dom!');
+});
+
+$('#aboutPage').live('pagecreate',function(event){
+  alert('This page was just enhanced by jQuery Mobile!');
+});
+		
+		
+

Note that by binding to pagebeforecreate and returning false, you can prevent the page plugin from making its manipulations.

+
+		
+$('#aboutPage').live('pagebeforecreate',function(event){
+  //run your own enhancement scripting here...
+  return false;
+});
+
+		
+		
+
-

Note on Page IDs: Page elements in jQuery Mobile utilize the ID attribute for storing the location from which they came. When you place an ID attribute on a page that is brought into jQuery Mobile's single-page environment through Ajax, jQuery Mobile wraps that page with a new "page" div element, preserving any CSS references to your ID. However, this means that your ID attribute is no longer on the "page" element, so you must keep this in mind when binding to page events (pagebeforecreate, pagecreate, etc). To avoid issues, try using a class if possible.

+

Note on Page IDs in Alpha 2 release (no longer an issue): In jQuery Mobile Alpha 2 and older, page elements utilized the ID attribute for storing the location from which they came. When you place an ID attribute on a page that is brought into jQuery Mobile's single-page environment through Ajax, jQuery Mobile wraps that page with a new "page" div element, preserving any CSS references to your ID. However, this means that your ID attribute is no longer on the "page" element, so you must keep this in mind when binding to page events (pagebeforecreate, pagecreate, etc). To avoid issues, try using a class if possible.

diff --git a/docs/pages/docs-pages.html b/docs/pages/docs-pages.html index dfa1f46c..8a2fc415 100755 --- a/docs/pages/docs-pages.html +++ b/docs/pages/docs-pages.html @@ -160,7 +160,7 @@ </body> - View multi-page template + View multi-page template

diff --git a/experiments/themeswitcher/jquery.mobile.themeswitcher.js b/experiments/themeswitcher/jquery.mobile.themeswitcher.js index 248f8a3c..726448d4 100644 --- a/experiments/themeswitcher/jquery.mobile.themeswitcher.js +++ b/experiments/themeswitcher/jquery.mobile.themeswitcher.js @@ -1,10 +1,11 @@ //quick & dirty theme switcher, written to potentially work as a bookmarklet (function($){ $.themeswitcher = function(){ + if( $('[data-url=themeswitcher]').length ){ return; } var themesDir = 'http://jquerymobile.com/test/themes/', themes = ['default','valencia'], currentPage = $.mobile.activePage, - menuPage = $( '
' + + menuPage = $( '
' + '
' + '
Switch Theme:
'+ '
'+ @@ -32,8 +33,6 @@ //create page, listview menuPage.page(); - - //change page now - $.mobile.changePage([currentPage, menuPage], 'pop', false); + }; })(jQuery); diff --git a/js/jquery.mobile.core.js b/js/jquery.mobile.core.js index 11709e9f..8de48421 100644 --- a/js/jquery.mobile.core.js +++ b/js/jquery.mobile.core.js @@ -120,6 +120,10 @@ //find present pages var $pages = $("[data-role='page']"); + $pages.each(function(){ + $(this).attr('data-url', $(this).attr('id')); + }); + //set up active page $.mobile.startPage = $.mobile.activePage = $pages.first(); diff --git a/js/jquery.mobile.dialog.js b/js/jquery.mobile.dialog.js index 28e8a6ab..c61bd76a 100644 --- a/js/jquery.mobile.dialog.js +++ b/js/jquery.mobile.dialog.js @@ -44,7 +44,7 @@ $.widget( "mobile.dialog", $.mobile.widget, { if( $el.is('.ui-page-active') ){ self.close(); $el.bind('pagehide',function(){ - $.mobile.updateHash( $prevPage.attr('id'), true); + $.mobile.updateHash( $prevPage.attr('data-url'), true); }); } }); diff --git a/js/jquery.mobile.listview.js b/js/jquery.mobile.listview.js index 80b0f643..cc564109 100644 --- a/js/jquery.mobile.listview.js +++ b/js/jquery.mobile.listview.js @@ -290,7 +290,7 @@ $.widget( "mobile.listview", $.mobile.widget, { _createSubPages: function() { var parentList = this.element, parentPage = parentList.closest( ".ui-page" ), - parentId = parentPage.attr( "id" ), + parentId = parentPage.data( "url" ), o = this.options, self = this, persistentFooterID = parentPage.find( "[data-role='footer']" ).data( "id" ); @@ -308,7 +308,7 @@ $.widget( "mobile.listview", $.mobile.widget, { .after( persistentFooterID ? $( "
", { "data-role": "footer", "data-id": persistentFooterID, "class": "ui-footer-duplicate" } ) : "" ) .parent() .attr({ - id: id, + "data-url": id, "data-theme": theme, "data-count-theme": countTheme }) diff --git a/js/jquery.mobile.navigation.js b/js/jquery.mobile.navigation.js index 4f758fd5..75cd50e3 100644 --- a/js/jquery.mobile.navigation.js +++ b/js/jquery.mobile.navigation.js @@ -20,14 +20,19 @@ newPath = location.hash; } newPath = newPath.replace(/#/,'').split('/'); - newPath.pop(); + if(newPath.length){ + var lastSegment = newPath[newPath.length-1]; + if( lastSegment.indexOf('.') > -1 || lastSegment == ''){ + newPath.pop(); + } + } return newPath.join('/') + (newPath.length ? '/' : ''); }, //return the substring of a filepath before the sub-page key, for making a server request getFilePath: function( path ){ var splitkey = '&' + $.mobile.subPageUrlKey; - return path.indexOf( splitkey ) > -1 ? path.split( splitkey )[0] : path; + return path && path.indexOf( splitkey ) > -1 ? path.split( splitkey )[0] : path; }, set: function( path, disableListening){ @@ -36,7 +41,7 @@ }, //location pathname from intial directory request - origin: null, + origin: '', setOrigin: function(){ path.origin = path.get( location.protocol + '//' + location.host + location.pathname ); @@ -85,7 +90,6 @@ //set location pathname from intial directory request path.setOrigin(); - /* internal utility functions @@ -134,7 +138,7 @@ // changepage function $.mobile.changePage = function( to, transition, back, changeHash){ - + //from is always the currently viewed page var toIsArray = $.type(to) === "array", from = toIsArray ? to[0] : $.mobile.activePage, @@ -147,11 +151,13 @@ back = (back !== undefined) ? back : ( urlStack.length > 1 && urlStack[ urlStack.length - 2 ].url === url ), transition = (transition !== undefined) ? transition : $.mobile.defaultTransition; + //If we are trying to transition to the same page that we are currently on ignore the request. - if(urlStack.length > 1 && url === urlStack[urlStack.length -1].url) { + if(urlStack.length > 1 && url === urlStack[urlStack.length -1].url && !toIsArray ) { return; } + if( $.type(to) === "object" && to.url ){ url = to.url, data = to.data, @@ -163,6 +169,9 @@ data = undefined; } } + + + //reset base to pathname for new request if(base){ base.reset(); } @@ -243,9 +252,12 @@ function enhancePage(){ //set next page role, if defined - if ( nextPageRole ) { - to.attr( "data-role", nextPageRole ); - nextPageRole = undefined; + if ( nextPageRole || to.data('role') == 'dialog' ) { + changeHash = false; + if(nextPageRole){ + to.attr( "data-role", nextPageRole ); + nextPageRole = null; + } } //run page plugin @@ -254,11 +266,11 @@ //if url is a string if( url ){ - to = $( "[id='" + url + "']" ), + to = $( "[data-url='" + url + "']" ); fileUrl = path.getFilePath(url); } else{ //find base url of element, if avail - var toID = to.attr('id'), + var toID = to.attr('data-url'), toIDfileurl = path.getFilePath(toID); if(toID != toIDfileurl){ @@ -287,13 +299,12 @@ type: type, data: data, success: function( html ) { - if(base){ base.set(fileUrl); } var all = $("
"); //workaround to allow scripts to execute when included in page divs all.get(0).innerHTML = html; - to = all.find('[data-role="page"]'); + to = all.find('[data-role="page"], [data-role="dialog"]').first(); //rewrite src and href attrs to use a base url if( !$.support.dynamicBaseTag ){ @@ -310,24 +321,9 @@ } }); } - - //preserve ID on a retrieved page - if ( to.attr('id') ) { - //wrap page and transfer data-attrs if it has an ID - var copyAttrs = ['data-role', 'data-theme', 'data-fullscreen'], //TODO: more page-level attrs? - wrapper = to.wrap( "
" ).parent(); - - $.each(copyAttrs,function(i){ - if( to.attr( copyAttrs[ i ] ) ){ - wrapper.attr( copyAttrs[ i ], to.attr( copyAttrs[ i ] ) ); - to.removeAttr( copyAttrs[ i ] ); - } - }); - to = wrapper; - } to - .attr( "id", fileUrl ) + .attr( "data-url", fileUrl ) .appendTo( $.mobile.pageContainer ); enhancePage(); @@ -336,6 +332,7 @@ error: function() { $.mobile.pageLoading( true ); removeActiveLinkClass(true); + base.set(path.get()); $("

Error Loading Page

") .css({ "display": "block", "opacity": 0.96, "top": $(window).scrollTop() + 100 }) .appendTo( $.mobile.pageContainer ) @@ -349,8 +346,6 @@ }; - - /* Event Bindings - hashchange, submit, and click */ @@ -386,6 +381,7 @@ //click routing - direct to HTTP or Ajax, accordingly $( "a" ).live( "click", function(event) { + if( !$.mobile.ajaxLinksEnabled ){ return; } var $this = $(this), //get href, remove same-domain protocol and host @@ -418,8 +414,7 @@ else { //use ajax var transition = $this.data( "transition" ), - back = $this.data( "back" ), - changeHashOnSuccess = !$this.is( "[data-rel="+ $.mobile.nonHistorySelectors +"]" ); + back = $this.data( "back" ); nextPageRole = $this.attr( "data-rel" ); @@ -430,7 +425,7 @@ href.replace(/^#/,''); - $.mobile.changePage(href, transition, back, changeHashOnSuccess); + $.mobile.changePage(href, transition, back); } event.preventDefault(); });