Skip to content

Commit 326f1df

Browse files
committed
Added fetchlink behavior on a per-link level, normalized incoming href/src.
1 parent 4b416c6 commit 326f1df

File tree

7 files changed

+279
-80
lines changed

7 files changed

+279
-80
lines changed

css/structure/jquery.mobile.core.css

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ div.ui-mobile-viewport { overflow-x: hidden; }
5959
.ui-loading .ui-mobile-viewport { overflow: hidden !important; }
6060
.ui-loading .ui-loader { display: block; }
6161
.ui-loading .ui-page { overflow: hidden; }
62+
.ui-loading-inline { min-height: 35px; position: relative; }
63+
.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); }
6264
.ui-loader { display: none; position: absolute; opacity: .85; z-index: 100; left: 50%; width: 200px; margin-left: -130px; margin-top: -35px; padding: 10px 30px; }
6365
.ui-loader h1 { font-size: 15px; text-align: center; }
6466
.ui-loader .ui-icon { position: static; display: block; opacity: .9; margin: 0 auto; width: 35px; height: 35px; background-color: transparent; }

docs/pages/dialog.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ <h1>Dialog</h1>
2222

2323
<div data-role="content" data-theme="c">
2424
<h1>Delete page?</h1>
25-
<p>This is a regular page, styled as a dialog. To create a dialog, just link to a normal page and include a transition and <code>data-rel="dialog"</code> attribute.</p>
25+
<p class="inner-content">This is a regular page, styled as a dialog. To create a dialog, just link to a normal page and include a transition and <code>data-rel="dialog"</code> attribute.</p>
2626
<a href="docs-dialogs.html" data-role="button" data-rel="back" data-theme="b">Sounds good</a>
2727
<a href="docs-dialogs.html" data-role="button" data-rel="back" data-theme="c">Cancel</a>
2828
</div>

docs/pages/fetchlinks.html

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1">
6+
<title>jQuery Mobile Framework - Dialog Example</title>
7+
<link rel="stylesheet" href="../../css/themes/default/" />
8+
<link rel="stylesheet" href="../_assets/css/jqm-docs.css"/>
9+
<script src="../../js/jquery.js"></script>
10+
<script src="../../experiments/themeswitcher/jquery.mobile.themeswitcher.js"></script>
11+
<script src="../_assets/js/jqm-docs.js"></script>
12+
<script src="../../js/"></script>
13+
14+
</head>
15+
<body>
16+
17+
<div data-role="page">
18+
<div data-role="content">
19+
20+
<h2>AJAX Fetch Links</h2>
21+
<p>A <a href="dialog.html">standard link</a> 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.</p>
22+
<pre><code>&lt;a href=&quot;dialog.html&quot;&gt;Link&lt;/a&gt;
23+
</code></pre>
24+
25+
<p>A <a href="dialog.html" data-rel="dialog">dialog</a> is made by adding <code>data-rel="dialog"</code> to a link to display the page with an inset appearance and the default dialog transition.</p>
26+
27+
<pre><code>&lt;a href=&quot;dialog.html&quot; <strong>data-rel=&quot;dialog&quot;</strong>&gt;Link&lt;/a&gt;
28+
</code></pre>
29+
<p>A <a data-role="fetchlink" data-target=".quote" href="../lists/lists-thumbnails.html">fetch link</a> is created by adding the <code>data-target</code> attribute to a link. This tells the framework to <strong>not</strong> change pages and instead load the <code>href</code> 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?). </p>
30+
31+
<p><a data-role="fetchlink" data-target=".quote" href="dialog.html" data-fragment=".inner-content">Alternate Content</a></p>
32+
33+
34+
35+
<h2>Grouped Fetch Links</h2>
36+
37+
<div data-role="fetchlink" data-target=".quote" data-fragment=".inner-content">
38+
<p>A <a href="../lists/lists-thumbnails.html">fetch link</a> is created by adding the <code>data-target</code> attribute to a link. This tells the framework to <strong>not</strong> change pages and instead load the <code>href</code> 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?). </p>
39+
<p><a href="dialog.html">Alternate Content</a></p>
40+
</div>
41+
42+
43+
<pre><code>&lt;a href=&quot;dialog.html&quot; <strong>data-target=&quot;.quote&quot;</strong>&gt;
44+
</code></pre>
45+
46+
47+
<div class="quote">
48+
<p>To be replaced.</p>
49+
</div>
50+
51+
52+
53+
<p>The <a href="dialog.html" data-role="fetchlink" data-target=".quote" data-fragment="[data-role='content']">content fragment</a> from the loaded page can be specified. By default, the framework will load in the <strong>contents</strong> of the <code>data-role=&quot;page&quot;</code> 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 <code>data-fragment</code> attribute to the link with any jQuery selector.</p>
54+
55+
<pre><code>&lt;a href=&quot;dialog.html&quot; data-target=&quot;.quote&quot; <strong>data-fragment=&quot;[data-role='content']&quot;</strong>&gt;
56+
</code></pre>
57+
58+
<p>The <a data-role="fetchlink" href="dialog.html" data-target=".quote" data-method="before">target method</a> for a link can be specified by adding the <code>data-method</code> attribute to a link. This specifies whether to <code>replace</code>, <code>append</code>, <code>prepend</code>, or insert the content <code>before</code> or <code>after</code> the target element. By default, an external href will replace the target.</p>
59+
60+
<pre><code>&lt;a href=&quot;dialog.html&quot; data-target=&quot;.quote&quot; <strong>data-method=&quot;after&quot;</strong>&gt;
61+
</code></pre>
62+
63+
64+
65+
<p>A <a href="dialog.html" data-role="fetchlink" data-target=".quote" data-breakpoint="500">breakpoint option</a> 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 <code>data-breakpoint</code> attribute on the link specifies the min-width pixel value to load the link.</p>
66+
67+
<pre><code>&lt;a href=&quot;dialog.html&quot; data-target=&quot;.quote&quot; <strong>data-breakpoint=&quot;500&quot;</strong>&gt;
68+
</code></pre>
69+
70+
71+
<h2>Local Fetch Links</h2>
72+
<p>Similar to above but examples use local hrefs (#foo) and there isn't a need for a <code>data-fragment</code> attribute since we're already specifying that in the href.</p>
73+
74+
75+
<blockquote class="bq">
76+
<p>“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?”</p>
77+
<address>Arthur Conan Doyle</address>
78+
<cite>Sherlock Holmes: The Sign of the Four</cite>
79+
</blockquote>
80+
81+
</div>
82+
83+
</div>
84+
85+
86+
</body>
87+
</html>

js/index.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
'jquery.mobile.links.js',
3737
'jquery.mobile.fixHeaderFooter.js',
3838
'jquery.mobile.fixHeaderFooter.native.js',
39+
'jquery.mobile.fetchlinks.js',
3940
'jquery.mobile.init.js'
4041
);
4142

js/jquery.mobile.fetchlinks.js

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
(function( $, undefined ) {
2+
3+
$.widget( "mobile.fetchlink", $.mobile.widget, {
4+
options: {
5+
initSelector: ":jqmData(role='fetchlink')"
6+
},
7+
_create: function() {
8+
9+
10+
$( this.element )
11+
.click(function() {
12+
var el = $( this ),
13+
url = el.attr( "href" ),
14+
target = el.data( "target" ),
15+
targetEl = target && $( target ) || el,
16+
fragment = el.data( "fragment" ),
17+
load = fragment || ":jqmData(role='page')",
18+
threshold = screen.width > parseInt( el.data( "breakpoint" ) || 0 ),
19+
methods = [ "append", "prepend", "replace", "before", "after" ],
20+
method = "html",
21+
url;
22+
23+
if ( threshold ) {
24+
for( var ml = methods.length, i=0; i < ml; i++ ){
25+
if( el.is( "[data-include='" + methods[ i ] + "']" ) ){
26+
method = methods[ i ];
27+
}
28+
}
29+
30+
if ( method === "replace" ){
31+
method += "With";
32+
}
33+
34+
if ( url && method ) {
35+
36+
targetEl.ajaxStart(function(){
37+
var $el = $(this);
38+
39+
$el
40+
.addClass('ui-loading-inline')
41+
.trigger('inlineLoader')
42+
.height( $el.height() );
43+
});
44+
45+
$.get( url, function( resp ) {
46+
var rscript = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
47+
data = $( $("<div/>").append( resp.replace( rscript, "" ) ).find( load ) )
48+
responseEl = !fragment ? $( data.html() ) : data,
49+
normalizePath = function( sel, attr ) {
50+
responseEl.find( sel ).each(function() {
51+
var $el = $(this),
52+
oPath = $el.attr( attr );
53+
54+
$el.attr( attr, $.mobile.path.parseUrl( url ).directory + oPath );
55+
});
56+
57+
};
58+
59+
normalizePath( 'img', 'src' );
60+
normalizePath( 'a', 'href');
61+
62+
setTimeout(function() {
63+
targetEl[ method ]( responseEl.addClass('fade in') );
64+
65+
responseEl
66+
.trigger( "create" )
67+
.trigger( "fetchlink", { target : targetEl, data: responseEl });
68+
69+
targetEl
70+
.removeClass('ui-loading-inline')
71+
.height('auto');
72+
}, 300);
73+
});
74+
}
75+
}
76+
return false;
77+
});
78+
79+
}
80+
});
81+
82+
$( document ).bind( "inlineLoader", function( e ){
83+
$( e.target ).children().removeClass('fade in').addClass('fade out');
84+
85+
setTimeout(function() {
86+
$( e.target ).html( "<div class='ui-loader-inline fade in'><span class='ui-icon ui-icon-loading spin'></span></div>" );
87+
}, 300);
88+
});
89+
90+
//auto self-init widgets
91+
$( document ).bind( "pagecreate create", function( e ){
92+
$( $.mobile.fetchlink.prototype.options.initSelector, e.target ).fetchlink();
93+
});
94+
95+
})( jQuery );

js/jquery.mobile.navigation.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1211,7 +1211,7 @@
12111211
}
12121212

12131213
// The base URL for any given element depends on the page it resides in.
1214-
function getClosestBaseUrl( ele )
1214+
$.mobile.getClosestBaseUrl = function( ele )
12151215
{
12161216
// Find the closest page and extract out its url.
12171217
var url = $( ele ).closest( ".ui-page" ).jqmData( "url" ),

js/jquery.mobile.page.sections.js

Lines changed: 92 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -4,84 +4,98 @@
44

55
(function( $, undefined ) {
66

7-
$.mobile.page.prototype.options.backBtnText = "Back";
8-
$.mobile.page.prototype.options.addBackBtn = false;
9-
$.mobile.page.prototype.options.backBtnTheme = null;
10-
$.mobile.page.prototype.options.headerTheme = "a";
11-
$.mobile.page.prototype.options.footerTheme = "a";
12-
$.mobile.page.prototype.options.contentTheme = null;
13-
14-
$( document ).delegate( ":jqmData(role='page'), :jqmData(role='dialog')", "pagecreate", function( e ) {
7+
$.widget( "mobile.sections", $.mobile.widget, {
8+
options: {
9+
initSelector : ":jqmData(role='page'), :jqmData(role='dialog')",
10+
sectionSelector : ":jqmData(role='header'), :jqmData(role='footer'), :jqmData(role='content')",
11+
backBtnText : "top",
12+
addBackBtn : null,
13+
backBtnTheme : ":jqmData(role='navbar')",
14+
headerTheme : "a",
15+
footerTheme : "a",
16+
contentTheme : null
17+
},
1518

16-
var $page = $( this ),
17-
o = $page.data( "page" ).options,
18-
pageRole = $page.jqmData( "role" ),
19-
pageTheme = o.theme;
20-
21-
$( ":jqmData(role='header'), :jqmData(role='footer'), :jqmData(role='content')", this ).each(function() {
22-
var $this = $( this ),
23-
role = $this.jqmData( "role" ),
24-
theme = $this.jqmData( "theme" ),
25-
contentTheme = theme || o.contentTheme || ( pageRole === "dialog" && pageTheme ),
26-
$headeranchors,
27-
leftbtn,
28-
rightbtn,
29-
backBtn;
30-
31-
$this.addClass( "ui-" + role );
32-
33-
//apply theming and markup modifications to page,header,content,footer
34-
if ( role === "header" || role === "footer" ) {
35-
36-
var thisTheme = theme || ( role === "header" ? o.headerTheme : o.footerTheme ) || pageTheme;
37-
38-
$this
39-
//add theme class
40-
.addClass( "ui-bar-" + thisTheme )
41-
// Add ARIA role
42-
.attr( "role", role === "header" ? "banner" : "contentinfo" );
43-
44-
// Right,left buttons
45-
$headeranchors = $this.children( "a" );
46-
leftbtn = $headeranchors.hasClass( "ui-btn-left" );
47-
rightbtn = $headeranchors.hasClass( "ui-btn-right" );
48-
49-
leftbtn = leftbtn || $headeranchors.eq( 0 ).not( ".ui-btn-right" ).addClass( "ui-btn-left" ).length;
50-
51-
rightbtn = rightbtn || $headeranchors.eq( 1 ).addClass( "ui-btn-right" ).length;
52-
53-
// Auto-add back btn on pages beyond first view
54-
if ( o.addBackBtn &&
55-
role === "header" &&
56-
$( ".ui-page" ).length > 1 &&
57-
$this.jqmData( "url" ) !== $.mobile.path.stripHash( location.hash ) &&
58-
!leftbtn ) {
59-
60-
backBtn = $( "<a href='#' class='ui-btn-left' data-"+ $.mobile.ns +"rel='back' data-"+ $.mobile.ns +"icon='arrow-l'>"+ o.backBtnText +"</a>" )
61-
// If theme is provided, override default inheritance
62-
.attr( "data-"+ $.mobile.ns +"theme", o.backBtnTheme || thisTheme )
63-
.prependTo( $this );
64-
}
65-
66-
// Page title
67-
$this.children( "h1, h2, h3, h4, h5, h6" )
68-
.addClass( "ui-title" )
69-
// Regardless of h element number in src, it becomes h1 for the enhanced page
70-
.attr({
71-
"tabindex": "0",
72-
"role": "heading",
73-
"aria-level": "1"
74-
});
75-
76-
} else if ( role === "content" ) {
77-
if ( contentTheme ) {
78-
$this.addClass( "ui-body-" + ( contentTheme ) );
79-
}
80-
81-
// Add ARIA role
82-
$this.attr( "role", "main" );
83-
}
84-
});
19+
_create: function() {
20+
var self = this;
21+
22+
$( self.options.initSelector ).each(function() {
23+
var $page = $( this ),
24+
o = self.options,
25+
pageRole = $page.jqmData( "role" ),
26+
pageTheme = o.theme;
27+
28+
$( o.sectionSelector, this ).each(function() {
29+
var $this = $( this ),
30+
role = $this.jqmData( "role" ),
31+
theme = $this.jqmData( "theme" ),
32+
contentTheme = theme || o.contentTheme || ( pageRole === "dialog" && pageTheme ),
33+
$headeranchors,
34+
leftbtn,
35+
rightbtn,
36+
backBtn;
37+
38+
$this.addClass( "ui-" + role );
39+
40+
//apply theming and markup modifications to page,header,content,footer
41+
if ( role === "header" || role === "footer" ) {
42+
var thisTheme = theme || ( role === "header" ? o.headerTheme : o.footerTheme ) || pageTheme;
43+
44+
$this
45+
//add theme class
46+
.addClass( "ui-bar-" + thisTheme )
47+
// Add ARIA role
48+
.attr( "role", role === "header" ? "banner" : "contentinfo" );
49+
50+
// Right,left buttons
51+
$headeranchors = $this.children( "a" );
52+
leftbtn = $headeranchors.hasClass( "ui-btn-left" );
53+
rightbtn = $headeranchors.hasClass( "ui-btn-right" );
54+
55+
leftbtn = leftbtn || $headeranchors.eq( 0 ).not( ".ui-btn-right" ).addClass( "ui-btn-left" ).length;
56+
57+
rightbtn = rightbtn || $headeranchors.eq( 1 ).addClass( "ui-btn-right" ).length;
58+
59+
// Auto-add back btn on pages beyond first view
60+
if ( o.addBackBtn &&
61+
role === "header" &&
62+
$( ".ui-page" ).length > 1 &&
63+
$this.jqmData( "url" ) !== $.mobile.path.stripHash( location.hash ) &&
64+
!leftbtn ) {
65+
66+
backBtn = $( "<a href='#' class='ui-btn-left' data-"+ $.mobile.ns +"rel='back' data-"+ $.mobile.ns +"icon='arrow-l'>"+ o.backBtnText +"</a>" )
67+
// If theme is provided, override default inheritance
68+
.attr( "data-"+ $.mobile.ns +"theme", o.backBtnTheme || thisTheme )
69+
.prependTo( $this );
70+
}
71+
72+
// Page title
73+
$this.children( "h1, h2, h3, h4, h5, h6" )
74+
.addClass( "ui-title" )
75+
// Regardless of h element number in src, it becomes h1 for the enhanced page
76+
.attr({
77+
"tabindex": "0",
78+
"role": "heading",
79+
"aria-level": "1"
80+
});
81+
82+
} else if ( role === "content" ) {
83+
if ( contentTheme ) {
84+
$this.addClass( "ui-body-" + ( contentTheme ) );
85+
}
86+
87+
// Add ARIA role
88+
$this.attr( "role", "main" );
89+
}
90+
91+
});
92+
93+
});
94+
}
95+
});
96+
97+
$( document ).bind( "pagecreate create", function( e ) {
98+
$( e.target ).sections();
8599
});
86100

87-
})( jQuery );
101+
})( jQuery );

0 commit comments

Comments
 (0)