diff --git a/css/structure/jquery.mobile.core.css b/css/structure/jquery.mobile.core.css index dc39cedf..7dc5abd4 100644 --- a/css/structure/jquery.mobile.core.css +++ b/css/structure/jquery.mobile.core.css @@ -59,6 +59,8 @@ div.ui-mobile-viewport { overflow-x: hidden; } .ui-loading .ui-mobile-viewport { overflow: hidden !important; } .ui-loading .ui-loader { display: block; } .ui-loading .ui-page { overflow: hidden; } +.ui-loading-inline { min-height: 35px; position: relative; } +.ui-loader-inline .ui-icon-loading { display: block; margin: 0 auto; position: absolute; left: 50%; top: 50%; margin: -17px 0 0 -17px; width: 35px; height: 35px; background-color: rgba(0,0,0,.1); } .ui-loader { display: none; position: absolute; opacity: .85; z-index: 100; left: 50%; width: 200px; margin-left: -130px; margin-top: -35px; padding: 10px 30px; } .ui-loader h1 { font-size: 15px; text-align: center; } .ui-loader .ui-icon { position: static; display: block; opacity: .9; margin: 0 auto; width: 35px; height: 35px; background-color: transparent; } diff --git a/docs/pages/dialog.html b/docs/pages/dialog.html index a8dcfbf6..7f49e583 100644 --- a/docs/pages/dialog.html +++ b/docs/pages/dialog.html @@ -22,7 +22,7 @@

Delete page?

-

This is a regular page, styled as a dialog. To create a dialog, just link to a normal page and include a transition and data-rel="dialog" attribute.

+

This is a regular page, styled as a dialog. To create a dialog, just link to a normal page and include a transition and data-rel="dialog" attribute.

Sounds good Cancel
diff --git a/docs/pages/fetchlinks.html b/docs/pages/fetchlinks.html new file mode 100644 index 00000000..c47ba778 --- /dev/null +++ b/docs/pages/fetchlinks.html @@ -0,0 +1,87 @@ + + + + + + jQuery Mobile Framework - Dialog Example + + + + + + + + + + +
+
+ +

AJAX Fetch Links

+

A standard link with a href pointing to a local anchor (#foo) or external page (foo.html) will trigger a full animated page change via the AJAX nav system with the default transition.

+
<a href="dialog.html">Link</a>
+
+ +

A dialog is made by adding data-rel="dialog" to a link to display the page with an inset appearance and the default dialog transition.

+ +
<a href="dialog.html" data-rel="dialog">Link</a>
+
+

A fetch link is created by adding the data-target attribute to a link. This tells the framework to not change pages and instead load the href into the target DOM element on the current page when the link is clicked. The target can be any jQuery selector (or restrict to ID only?).

+ +

Alternate Content

+ + + +

Grouped Fetch Links

+ +
+

A fetch link is created by adding the data-target attribute to a link. This tells the framework to not change pages and instead load the href into the target DOM element on the current page when the link is clicked. The target can be any jQuery selector (or restrict to ID only?).

+

Alternate Content

+
+ + +
<a href="dialog.html" data-target=".quote">
+
+ + +
+

To be replaced.

+
+ + + +

The content fragment from the loaded page can be specified. By default, the framework will load in the contents of the data-role="page" container (not the page wrapper itself), but it's possible to specify what content from the page to pull into the target by adding a data-fragment attribute to the link with any jQuery selector.

+ +
<a href="dialog.html" data-target=".quote" data-fragment="[data-role='content']">
+
+ +

The target method for a link can be specified by adding the data-method attribute to a link. This specifies whether to replace, append, prepend, or insert the content before or after the target element. By default, an external href will replace the target.

+ +
<a href="dialog.html" data-target=".quote" data-method="after">
+
+ + + +

A breakpoint option will automatically load the fetch link if the screen width is larger than the specified value instead of waiting for the link to be clicked. The data-breakpoint attribute on the link specifies the min-width pixel value to load the link.

+ +
<a href="dialog.html" data-target=".quote" data-breakpoint="500">
+
+ + +

Local Fetch Links

+

Similar to above but examples use local hrefs (#foo) and there isn't a need for a data-fragment attribute since we're already specifying that in the href.

+ + +
+

“You will not apply my precept,” he said, shaking his head. “How often have I said to you that when you have eliminated the impossible, whatever remains, however improbable, must be the truth?”

+
Arthur Conan Doyle
+ Sherlock Holmes: The Sign of the Four +
+ +
+ +
+ + + + diff --git a/js/index.php b/js/index.php index f3376871..84edb8af 100644 --- a/js/index.php +++ b/js/index.php @@ -36,6 +36,7 @@ $files = array( 'jquery.mobile.links.js', 'jquery.mobile.fixHeaderFooter.js', 'jquery.mobile.fixHeaderFooter.native.js', + 'jquery.mobile.fetchlinks.js', 'jquery.mobile.init.js' ); diff --git a/js/jquery.mobile.fetchlinks.js b/js/jquery.mobile.fetchlinks.js new file mode 100644 index 00000000..524bfd16 --- /dev/null +++ b/js/jquery.mobile.fetchlinks.js @@ -0,0 +1,95 @@ +(function( $, undefined ) { + +$.widget( "mobile.fetchlink", $.mobile.widget, { + options: { + initSelector: ":jqmData(role='fetchlink')" + }, + _create: function() { + + + $( this.element ) + .click(function() { + var el = $( this ), + url = el.attr( "href" ), + target = el.data( "target" ), + targetEl = target && $( target ) || el, + fragment = el.data( "fragment" ), + load = fragment || ":jqmData(role='page')", + threshold = screen.width > parseInt( el.data( "breakpoint" ) || 0 ), + methods = [ "append", "prepend", "replace", "before", "after" ], + method = "html", + url; + + if ( threshold ) { + for( var ml = methods.length, i=0; i < ml; i++ ){ + if( el.is( "[data-include='" + methods[ i ] + "']" ) ){ + method = methods[ i ]; + } + } + + if ( method === "replace" ){ + method += "With"; + } + + if ( url && method ) { + + targetEl.ajaxStart(function(){ + var $el = $(this); + + $el + .addClass('ui-loading-inline') + .trigger('inlineLoader') + .height( $el.height() ); + }); + + $.get( url, function( resp ) { + var rscript = /)<[^<]*)*<\/script>/gi, + data = $( $("
").append( resp.replace( rscript, "" ) ).find( load ) ) + responseEl = !fragment ? $( data.html() ) : data, + normalizePath = function( sel, attr ) { + responseEl.find( sel ).each(function() { + var $el = $(this), + oPath = $el.attr( attr ); + + $el.attr( attr, $.mobile.path.parseUrl( url ).directory + oPath ); + }); + + }; + + normalizePath( 'img', 'src' ); + normalizePath( 'a', 'href'); + + setTimeout(function() { + targetEl[ method ]( responseEl.addClass('fade in') ); + + responseEl + .trigger( "create" ) + .trigger( "fetchlink", { target : targetEl, data: responseEl }); + + targetEl + .removeClass('ui-loading-inline') + .height('auto'); + }, 300); + }); + } + } + return false; + }); + + } +}); + +$( document ).bind( "inlineLoader", function( e ){ + $( e.target ).children().removeClass('fade in').addClass('fade out'); + + setTimeout(function() { + $( e.target ).html( "
" ); + }, 300); +}); + +//auto self-init widgets +$( document ).bind( "pagecreate create", function( e ){ + $( $.mobile.fetchlink.prototype.options.initSelector, e.target ).fetchlink(); +}); + +})( jQuery ); diff --git a/js/jquery.mobile.navigation.js b/js/jquery.mobile.navigation.js index 9d070bdb..7ea1fc2e 100755 --- a/js/jquery.mobile.navigation.js +++ b/js/jquery.mobile.navigation.js @@ -1211,7 +1211,7 @@ } // The base URL for any given element depends on the page it resides in. - function getClosestBaseUrl( ele ) + $.mobile.getClosestBaseUrl = function( ele ) { // Find the closest page and extract out its url. var url = $( ele ).closest( ".ui-page" ).jqmData( "url" ), diff --git a/js/jquery.mobile.page.sections.js b/js/jquery.mobile.page.sections.js index 3cc6450b..5b771cbc 100644 --- a/js/jquery.mobile.page.sections.js +++ b/js/jquery.mobile.page.sections.js @@ -4,84 +4,98 @@ (function( $, undefined ) { -$.mobile.page.prototype.options.backBtnText = "Back"; -$.mobile.page.prototype.options.addBackBtn = false; -$.mobile.page.prototype.options.backBtnTheme = null; -$.mobile.page.prototype.options.headerTheme = "a"; -$.mobile.page.prototype.options.footerTheme = "a"; -$.mobile.page.prototype.options.contentTheme = null; - -$( document ).delegate( ":jqmData(role='page'), :jqmData(role='dialog')", "pagecreate", function( e ) { +$.widget( "mobile.sections", $.mobile.widget, { + options: { + initSelector : ":jqmData(role='page'), :jqmData(role='dialog')", + sectionSelector : ":jqmData(role='header'), :jqmData(role='footer'), :jqmData(role='content')", + backBtnText : "top", + addBackBtn : null, + backBtnTheme : ":jqmData(role='navbar')", + headerTheme : "a", + footerTheme : "a", + contentTheme : null + }, - var $page = $( this ), - o = $page.data( "page" ).options, - pageRole = $page.jqmData( "role" ), - pageTheme = o.theme; - - $( ":jqmData(role='header'), :jqmData(role='footer'), :jqmData(role='content')", this ).each(function() { - var $this = $( this ), - role = $this.jqmData( "role" ), - theme = $this.jqmData( "theme" ), - contentTheme = theme || o.contentTheme || ( pageRole === "dialog" && pageTheme ), - $headeranchors, - leftbtn, - rightbtn, - backBtn; - - $this.addClass( "ui-" + role ); + _create: function() { + var self = this; - //apply theming and markup modifications to page,header,content,footer - if ( role === "header" || role === "footer" ) { - - var thisTheme = theme || ( role === "header" ? o.headerTheme : o.footerTheme ) || pageTheme; + $( self.options.initSelector ).each(function() { + var $page = $( this ), + o = self.options, + pageRole = $page.jqmData( "role" ), + pageTheme = o.theme; + + $( o.sectionSelector, this ).each(function() { + var $this = $( this ), + role = $this.jqmData( "role" ), + theme = $this.jqmData( "theme" ), + contentTheme = theme || o.contentTheme || ( pageRole === "dialog" && pageTheme ), + $headeranchors, + leftbtn, + rightbtn, + backBtn; + + $this.addClass( "ui-" + role ); - $this - //add theme class - .addClass( "ui-bar-" + thisTheme ) - // Add ARIA role - .attr( "role", role === "header" ? "banner" : "contentinfo" ); + //apply theming and markup modifications to page,header,content,footer + if ( role === "header" || role === "footer" ) { + var thisTheme = theme || ( role === "header" ? o.headerTheme : o.footerTheme ) || pageTheme; - // Right,left buttons - $headeranchors = $this.children( "a" ); - leftbtn = $headeranchors.hasClass( "ui-btn-left" ); - rightbtn = $headeranchors.hasClass( "ui-btn-right" ); + $this + //add theme class + .addClass( "ui-bar-" + thisTheme ) + // Add ARIA role + .attr( "role", role === "header" ? "banner" : "contentinfo" ); - leftbtn = leftbtn || $headeranchors.eq( 0 ).not( ".ui-btn-right" ).addClass( "ui-btn-left" ).length; - - rightbtn = rightbtn || $headeranchors.eq( 1 ).addClass( "ui-btn-right" ).length; - - // Auto-add back btn on pages beyond first view - if ( o.addBackBtn && - role === "header" && - $( ".ui-page" ).length > 1 && - $this.jqmData( "url" ) !== $.mobile.path.stripHash( location.hash ) && - !leftbtn ) { + // Right,left buttons + $headeranchors = $this.children( "a" ); + leftbtn = $headeranchors.hasClass( "ui-btn-left" ); + rightbtn = $headeranchors.hasClass( "ui-btn-right" ); - backBtn = $( ""+ o.backBtnText +"" ) - // If theme is provided, override default inheritance - .attr( "data-"+ $.mobile.ns +"theme", o.backBtnTheme || thisTheme ) - .prependTo( $this ); - } + leftbtn = leftbtn || $headeranchors.eq( 0 ).not( ".ui-btn-right" ).addClass( "ui-btn-left" ).length; - // Page title - $this.children( "h1, h2, h3, h4, h5, h6" ) - .addClass( "ui-title" ) - // Regardless of h element number in src, it becomes h1 for the enhanced page - .attr({ - "tabindex": "0", - "role": "heading", - "aria-level": "1" - }); + rightbtn = rightbtn || $headeranchors.eq( 1 ).addClass( "ui-btn-right" ).length; - } else if ( role === "content" ) { - if ( contentTheme ) { - $this.addClass( "ui-body-" + ( contentTheme ) ); - } + // Auto-add back btn on pages beyond first view + if ( o.addBackBtn && + role === "header" && + $( ".ui-page" ).length > 1 && + $this.jqmData( "url" ) !== $.mobile.path.stripHash( location.hash ) && + !leftbtn ) { - // Add ARIA role - $this.attr( "role", "main" ); - } - }); + backBtn = $( ""+ o.backBtnText +"" ) + // If theme is provided, override default inheritance + .attr( "data-"+ $.mobile.ns +"theme", o.backBtnTheme || thisTheme ) + .prependTo( $this ); + } + + // Page title + $this.children( "h1, h2, h3, h4, h5, h6" ) + .addClass( "ui-title" ) + // Regardless of h element number in src, it becomes h1 for the enhanced page + .attr({ + "tabindex": "0", + "role": "heading", + "aria-level": "1" + }); + + } else if ( role === "content" ) { + if ( contentTheme ) { + $this.addClass( "ui-body-" + ( contentTheme ) ); + } + + // Add ARIA role + $this.attr( "role", "main" ); + } + + }); + + }); + } }); -})( jQuery ); \ No newline at end of file +$( document ).bind( "pagecreate create", function( e ) { + $( e.target ).sections(); +}); + +})( jQuery );