2012-01-18 17:19:06 +00:00
|
|
|
//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
|
|
|
|
|
//>>description: Behavior for "fixed" headers and footers
|
|
|
|
|
//>>label: Fixedtoolbar
|
|
|
|
|
|
2012-01-24 22:43:24 +00:00
|
|
|
define( [ "jquery", "./jquery.mobile.widget", "./jquery.mobile.core", "./jquery.mobile.navigation", "./jquery.mobile.page", "./jquery.mobile.page.sections", "./jquery.mobile.zoom" ], function( $ ) {
|
2012-01-18 17:19:06 +00:00
|
|
|
//>>excludeEnd("jqmBuildExclude");
|
|
|
|
|
(function( $, undefined ) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
$.widget( "mobile.fixedtoolbar", $.mobile.widget, {
|
|
|
|
|
options: {
|
|
|
|
|
visibleOnPageShow: true,
|
|
|
|
|
togglePageZoom: true,
|
|
|
|
|
transition: "fade", //can be none, fade, slide (slide maps to slideup or slidedown)
|
|
|
|
|
fullscreen: false,
|
|
|
|
|
tapToggle: true,
|
2012-01-25 15:15:40 +00:00
|
|
|
updatePagePadding: true,
|
2012-01-18 17:19:06 +00:00
|
|
|
|
|
|
|
|
// Browser detection! Weeee, here we go...
|
|
|
|
|
// Unfortunately, position:fixed is costly, not to mention probably impossible, to feature-detect accurately.
|
|
|
|
|
// Some tests exist, but they currently return false results in critical devices and browsers, which could lead to a broken experience.
|
|
|
|
|
// Testing fixed positioning is also pretty obtrusive to page load, requiring injected elements and scrolling the window
|
|
|
|
|
// The following function serves to rule out some popular browsers with known fixed-positioning issues
|
|
|
|
|
// This is a plugin option like any other, so feel free to improve or overwrite it
|
|
|
|
|
supportBlacklist: function(){
|
|
|
|
|
var ua = navigator.userAgent,
|
|
|
|
|
platform = navigator.platform,
|
|
|
|
|
// Rendering engine is Webkit, and capture major version
|
|
|
|
|
wkmatch = ua.match( /AppleWebKit\/([0-9]+)/ ),
|
|
|
|
|
wkversion = !!wkmatch && wkmatch[ 1 ],
|
|
|
|
|
ffmatch = ua.match( /Fennec\/([0-9]+)/ ),
|
|
|
|
|
ffversion = !!ffmatch && ffmatch[ 1 ],
|
|
|
|
|
operammobilematch = ua.match( /Opera Mobile\/([0-9]+)/ ),
|
|
|
|
|
omversion = !!operammobilematch && operammobilematch[ 1 ],
|
|
|
|
|
|
|
|
|
|
w = window;
|
|
|
|
|
|
|
|
|
|
if(
|
|
|
|
|
// iOS 4.3 and older : Platform is iPhone/Pad/Touch and Webkit version is less than 534 (ios5)
|
|
|
|
|
( ( platform.indexOf( "iPhone" ) > -1 || platform.indexOf( "iPad" ) > -1 || platform.indexOf( "iPod" ) > -1 ) && wkversion && wkversion < 534 )
|
|
|
|
|
||
|
|
|
|
|
// Opera Mini
|
|
|
|
|
( w.operamini && ({}).toString.call( w.operamini ) === "[object OperaMini]" )
|
|
|
|
|
||
|
|
|
|
|
( operammobilematch && omverson < 7458 )
|
|
|
|
|
||
|
|
|
|
|
//Android lte 2.1: Platform is Android and Webkit version is less than 533 (Android 2.2)
|
|
|
|
|
( ua.indexOf( "Android" ) > -1 && wkversion && wkversion < 533 )
|
|
|
|
|
||
|
|
|
|
|
// Firefox Mobile before 6.0 -
|
|
|
|
|
( ffversion && ffversion < 6 )
|
|
|
|
|
||
|
|
|
|
|
// WebOS less than 3
|
|
|
|
|
( "palmGetResource" in window && wkversion && wkversion < 534 )
|
|
|
|
|
){
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
},
|
|
|
|
|
initSelector: ":jqmData(position='fixed')"
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
_create: function() {
|
|
|
|
|
|
|
|
|
|
var self = this,
|
|
|
|
|
o = self.options,
|
|
|
|
|
$el = self.element,
|
|
|
|
|
tbtype = $el.is( ".ui-header" ) ? "header" : "footer",
|
|
|
|
|
$page = $el.closest(".ui-page");
|
|
|
|
|
|
|
|
|
|
// Feature detecting support for
|
|
|
|
|
if( o.supportBlacklist() ){
|
|
|
|
|
self.destroy();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$el.addClass( "ui-"+ tbtype +"-fixed" );
|
|
|
|
|
|
|
|
|
|
// "fullscreen" overlay positioning
|
2012-01-26 05:18:00 +00:00
|
|
|
if( $el.jqmData( "fullscreen" ) ){
|
2012-01-18 17:19:06 +00:00
|
|
|
$el.addClass( "ui-"+ tbtype +"-fullscreen" );
|
|
|
|
|
$page.addClass( "ui-page-" + tbtype + "-fullscreen" );
|
|
|
|
|
}
|
|
|
|
|
// If not fullscreen, add class to page to set top or bottom padding
|
|
|
|
|
else{
|
|
|
|
|
$page.addClass( "ui-page-" + tbtype + "-fixed" );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
self._addTransitionClass();
|
|
|
|
|
self._bindPageEvents();
|
|
|
|
|
self._bindToggleHandlers();
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
_addTransitionClass: function(){
|
|
|
|
|
var tclass = this.options.transition;
|
|
|
|
|
|
|
|
|
|
if( tclass && tclass !== "none" ){
|
|
|
|
|
// use appropriate slide for header or footer
|
|
|
|
|
if( tclass === "slide" ){
|
|
|
|
|
tclass = this.element.is( ".ui-header" ) ? "slidedown" : "slideup";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.element.addClass( tclass );
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
_bindPageEvents: function(){
|
|
|
|
|
var self = this,
|
|
|
|
|
o = self.options,
|
|
|
|
|
$el = self.element;
|
|
|
|
|
|
|
|
|
|
//page event bindings
|
2012-01-19 07:11:41 +00:00
|
|
|
// Fixed toolbars require page zoom to be disabled, otherwise usability issues crop up
|
|
|
|
|
// This method is meant to disable zoom while a fixed-positioned toolbar page is visible
|
2012-01-18 17:19:06 +00:00
|
|
|
$el.closest( ".ui-page" )
|
|
|
|
|
.bind( "pagebeforeshow", function(){
|
2012-01-25 10:32:51 +00:00
|
|
|
if( o.togglePageZoom ){
|
2012-01-25 10:39:13 +00:00
|
|
|
$.mobile.zoom.disable( true );
|
2012-01-18 17:19:06 +00:00
|
|
|
}
|
|
|
|
|
if( o.visibleOnPageShow ){
|
|
|
|
|
self.show();
|
|
|
|
|
}
|
|
|
|
|
} )
|
2012-01-25 15:15:40 +00:00
|
|
|
.bind( "webkitAnimationStart animationstart", function(){
|
|
|
|
|
if( o.updatePagePadding ){
|
|
|
|
|
self.updatePagePadding();
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
.bind( "pageshow", function(){
|
|
|
|
|
self.updatePagePadding();
|
|
|
|
|
if( o.updatePagePadding ){
|
|
|
|
|
$( window ).bind( "throttledresize." + self.widgetName, function(){
|
|
|
|
|
self.updatePagePadding();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
})
|
2012-01-25 10:39:13 +00:00
|
|
|
.bind( "pagebeforehide", function(){
|
2012-01-25 10:32:51 +00:00
|
|
|
if( o.togglePageZoom ){
|
2012-01-25 10:39:13 +00:00
|
|
|
$.mobile.zoom.enable( true );
|
2012-01-18 17:19:06 +00:00
|
|
|
}
|
2012-01-25 15:15:40 +00:00
|
|
|
if( o.updatePagePadding ){
|
|
|
|
|
$( window ).unbind( "throttledresize." + self.widgetName );
|
|
|
|
|
}
|
2012-01-18 17:19:06 +00:00
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
|
Added an experimental "updatePagePadding" method, which allows developers to adjust the page element's padding to accommodate a taller toolbar, so there is no overlap.
Addresses Issue #3484
Caveats:
- This method must be called when the toolbar is visible, meaning you'll see a visible jump when a page is shown. For this reason, I'm hesitant to recommend this feature. It would be a lot smoother to set the page padding in a custom CSS file to make up for whatever EM height your toolbars happen to be.
- Height is set in Pixels, meaning changes in font size could render it inaccurate. If we want to set height in ems, we'll need to add an em conversion utility function to jQM.
- To ensure it works properly, this method will need to be called on page show, and at any time a content reflow might occur: resize, orientationchange, zoom?
This method is not currently called automatically.
It can be called like this: $(".ui-header-fixed").fixedtoolbar( "updatePagePadding" );
2012-01-25 11:26:04 +00:00
|
|
|
_visible: false,
|
|
|
|
|
|
|
|
|
|
// This will set the content element's top or bottom padding equal to the toolbar's height
|
|
|
|
|
updatePagePadding: function() {
|
|
|
|
|
var $el = this.element,
|
|
|
|
|
header = $el.is( ".ui-header" );
|
|
|
|
|
|
|
|
|
|
// This behavior only applies to "fixed", not "fullscreen"
|
|
|
|
|
if( this.options.fullscreen ){ return; }
|
|
|
|
|
|
|
|
|
|
$el.closest( ".ui-page" ).css( "padding-" + ( header ? "top" : "bottom" ), $el.height() );
|
|
|
|
|
},
|
2012-01-18 17:19:06 +00:00
|
|
|
|
|
|
|
|
show: function(){
|
|
|
|
|
var hideClass = "ui-fixed-hidden",
|
|
|
|
|
$el = this.element,
|
2012-01-23 20:52:49 +00:00
|
|
|
$win = $( window ),
|
|
|
|
|
scroll = $win.scrollTop(),
|
2012-01-18 17:19:06 +00:00
|
|
|
elHeight = $el.height(),
|
|
|
|
|
pHeight = $el.closest( ".ui-page" ).height(),
|
2012-01-23 20:52:49 +00:00
|
|
|
viewportHeight = Math.min( screen.height, $win.height() ),
|
2012-01-18 17:19:06 +00:00
|
|
|
tbtype = $el.is( ".ui-header" ) ? "header" : "footer";
|
|
|
|
|
|
|
|
|
|
if( this.options.transition && this.options.transition !== "none" &&
|
|
|
|
|
(
|
|
|
|
|
( tbtype === "header" && !this.options.fullscreen && scroll > elHeight ) ||
|
|
|
|
|
( tbtype === "footer" && !this.options.fullscreen && scroll + viewportHeight < pHeight - elHeight )
|
|
|
|
|
) || this.options.fullscreen ){
|
|
|
|
|
$el
|
|
|
|
|
.removeClass( "out " + hideClass )
|
|
|
|
|
.addClass( "in" );
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
$el.removeClass( hideClass );
|
|
|
|
|
}
|
|
|
|
|
this._visible = true;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
hide: function(){
|
|
|
|
|
var hideClass = "ui-fixed-hidden",
|
|
|
|
|
$el = this.element,
|
2012-01-23 20:52:49 +00:00
|
|
|
$win = $( window ),
|
|
|
|
|
scroll = $win.scrollTop(),
|
2012-01-18 17:19:06 +00:00
|
|
|
elHeight = $el.height(),
|
|
|
|
|
pHeight = $el.closest( ".ui-page" ).height(),
|
2012-01-23 20:52:49 +00:00
|
|
|
viewportHeight = Math.min( screen.height, $win.height() ),
|
2012-01-18 17:19:06 +00:00
|
|
|
tbtype = $el.is( ".ui-header" ) ? "header" : "footer";
|
|
|
|
|
|
|
|
|
|
if( this.options.transition && this.options.transition !== "none" &&
|
|
|
|
|
(
|
|
|
|
|
( tbtype === "header" && !this.options.fullscreen && scroll > elHeight ) ||
|
|
|
|
|
( tbtype === "footer" && !this.options.fullscreen && scroll + viewportHeight < pHeight - elHeight )
|
|
|
|
|
) || this.options.fullscreen ){
|
|
|
|
|
$el
|
|
|
|
|
.removeClass( "in" )
|
|
|
|
|
.addClass( "out" )
|
|
|
|
|
.animationComplete( function(){
|
|
|
|
|
$el.addClass( hideClass );
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
this.element.addClass( hideClass );
|
|
|
|
|
}
|
|
|
|
|
this._visible = false;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
toggle: function(){
|
|
|
|
|
this[ this._visible ? "hide" : "show" ]();
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
_bindToggleHandlers: function(){
|
|
|
|
|
var self = this,
|
|
|
|
|
o = self.options,
|
|
|
|
|
$el = self.element;
|
|
|
|
|
|
|
|
|
|
// tap toggle
|
|
|
|
|
$el.closest( ".ui-page" )
|
|
|
|
|
.bind( "vclick", function( e ){
|
|
|
|
|
if( o.tapToggle && $el.find( e.target ).length === 0 ){
|
|
|
|
|
self.toggle();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
destroy: function(){
|
|
|
|
|
this.element.removeClass( "ui-header-fixed ui-footer-fixed ui-header-fullscreen ui-footer-fullscreen in out fade slidedown slideup ui-fixed-hidden" )
|
|
|
|
|
this.element.closest( ".ui-page" ).removeClass( "ui-page-header-fixed ui-page-footer-fixed ui-page-header-fullscreen ui-page-footer-fullscreen" );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
//auto self-init widgets
|
|
|
|
|
$( document ).bind( "pagecreate create", function( e ){
|
|
|
|
|
$( $.mobile.fixedtoolbar.prototype.options.initSelector, e.target ).fixedtoolbar();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
})( jQuery );
|
|
|
|
|
//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
|
|
|
|
|
});
|
|
|
|
|
//>>excludeEnd("jqmBuildExclude");
|