mirror of
https://github.com/Hopiu/jquery-mobile.git
synced 2026-03-21 16:30:26 +00:00
197 lines
No EOL
6.8 KiB
JavaScript
197 lines
No EOL
6.8 KiB
JavaScript
/*
|
|
* jQuery Mobile Framework : "fixHeaderFooter" plugin - on-demand positioning for headers,footers
|
|
* Copyright (c) jQuery Project
|
|
* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses.
|
|
* Note: Code is in draft form and is subject to change
|
|
*/
|
|
(function($, undefined ) {
|
|
$.fn.fixHeaderFooter = function(options){
|
|
if( !$.support.scrollTop ){ return $(this); }
|
|
return $(this).each(function(){
|
|
if( $(this).data('fullscreen') ){ $(this).addClass('ui-page-fullscreen'); }
|
|
$(this).find('.ui-header[data-position="fixed"]').addClass('ui-header-fixed ui-fixed-inline fade'); //should be slidedown
|
|
$(this).find('.ui-footer[data-position="fixed"]').addClass('ui-footer-fixed ui-fixed-inline fade'); //should be slideup
|
|
});
|
|
};
|
|
|
|
//single controller for all showing,hiding,toggling
|
|
$.fixedToolbars = (function(){
|
|
if( !$.support.scrollTop ){ return; }
|
|
var currentstate = 'inline',
|
|
delayTimer,
|
|
ignoreTargets = 'a,input,textarea,select,button,label,.ui-header-fixed,.ui-footer-fixed',
|
|
toolbarSelector = '.ui-header-fixed:first, .ui-footer-fixed:not(.ui-footer-duplicate):last',
|
|
stickyFooter, //for storing quick references to duplicate footers
|
|
supportTouch = $.support.touch,
|
|
touchStartEvent = supportTouch ? "touchstart" : "mousedown",
|
|
touchStopEvent = supportTouch ? "touchend" : "mouseup",
|
|
stateBefore = null,
|
|
scrollTriggered = false;
|
|
|
|
$(function() {
|
|
$(document)
|
|
.bind(touchStartEvent,function(event){
|
|
if( $(event.target).closest(ignoreTargets).length ){ return; }
|
|
stateBefore = currentstate;
|
|
$.fixedToolbars.hide(true);
|
|
})
|
|
.bind('scrollstart',function(event){
|
|
if( $(event.target).closest(ignoreTargets).length ){ return; } //because it could be a touchmove...
|
|
scrollTriggered = true;
|
|
if(stateBefore == null){ stateBefore = currentstate; }
|
|
$.fixedToolbars.hide(true);
|
|
})
|
|
.bind(touchStopEvent,function(event){
|
|
if( $(event.target).closest(ignoreTargets).length ){ return; }
|
|
if( !scrollTriggered ){
|
|
$.fixedToolbars.toggle(stateBefore);
|
|
stateBefore = null;
|
|
}
|
|
})
|
|
.bind('scrollstop',function(event){
|
|
if( $(event.target).closest(ignoreTargets).length ){ return; }
|
|
scrollTriggered = false;
|
|
$.fixedToolbars.toggle( stateBefore == 'overlay' ? 'inline' : 'overlay' );
|
|
stateBefore = null;
|
|
});
|
|
|
|
//function to return another footer already in the dom with the same data-id
|
|
function findStickyFooter(el){
|
|
var thisFooter = el.find('[data-role="footer"]');
|
|
return $( '.ui-footer[data-id="'+ thisFooter.data('id') +'"]:not(.ui-footer-duplicate)' ).not(thisFooter);
|
|
}
|
|
|
|
//before page is shown, check for duplicate footer
|
|
$('.ui-page').live('pagebeforeshow', function(event, ui){
|
|
stickyFooter = findStickyFooter( $(event.target) );
|
|
if( stickyFooter.length ){
|
|
//if the existing footer is the first of its kind, create a placeholder before stealing it
|
|
if( stickyFooter.parents('.ui-page:eq(0)').find('.ui-footer[data-id="'+ stickyFooter.data('id') +'"]').length == 1 ){
|
|
stickyFooter.before( stickyFooter.clone().addClass('ui-footer-duplicate') );
|
|
}
|
|
$(event.target).find('[data-role="footer"]').addClass('ui-footer-duplicate');
|
|
stickyFooter.appendTo($.pageContainer).css('top',0);
|
|
setTop(stickyFooter);
|
|
}
|
|
});
|
|
|
|
//after page is shown, append footer to new page
|
|
$('.ui-page').live('pageshow', function(event, ui){
|
|
if( stickyFooter && stickyFooter.length ){
|
|
stickyFooter.appendTo(event.target).css('top',0);
|
|
}
|
|
$.fixedToolbars.show(true);
|
|
});
|
|
|
|
});
|
|
|
|
// element.getBoundingClientRect() is broken in iOS 3.2.1 on the iPad. The
|
|
// coordinates inside of the rect it returns don't have the page scroll position
|
|
// factored out of it like the other platforms do. To get around this,
|
|
// we'll just calculate the top offset the old fashioned way until core has
|
|
// a chance to figure out how to handle this situation.
|
|
//
|
|
// TODO: We'll need to get rid of getOffsetTop() once a fix gets folded into core.
|
|
|
|
function getOffsetTop(ele)
|
|
{
|
|
var top = 0;
|
|
if (ele)
|
|
{
|
|
var op = ele.offsetParent, body = document.body;
|
|
top = ele.offsetTop;
|
|
while (ele && ele != body)
|
|
{
|
|
top += ele.scrollTop || 0;
|
|
if (ele == op)
|
|
{
|
|
top += op.offsetTop;
|
|
op = ele.offsetParent;
|
|
}
|
|
ele = ele.parentNode;
|
|
}
|
|
}
|
|
return top;
|
|
}
|
|
|
|
function setTop(el){
|
|
var fromTop = $(window).scrollTop(),
|
|
thisTop = getOffsetTop(el[0]), // el.offset().top returns the wrong value on iPad iOS 3.2.1, call our workaround instead.
|
|
thisCSStop = el.css('top') == 'auto' ? 0 : parseFloat(el.css('top')),
|
|
screenHeight = window.innerHeight,
|
|
thisHeight = el.outerHeight(),
|
|
useRelative = el.parents('.ui-page:not(.ui-page-fullscreen)').length,
|
|
relval;
|
|
if( el.is('.ui-header-fixed') ){
|
|
relval = fromTop - thisTop + thisCSStop;
|
|
if( relval < thisTop){ relval = 0; }
|
|
return el.css('top', ( useRelative ) ? relval : fromTop);
|
|
}
|
|
else{
|
|
//relval = -1 * (thisTop - (fromTop + screenHeight) + thisCSStop + thisHeight);
|
|
//if( relval > thisTop ){ relval = 0; }
|
|
relval = fromTop + screenHeight - thisHeight - thisTop;
|
|
return el.css('top', ( useRelative ) ? relval : fromTop + screenHeight - thisHeight );
|
|
}
|
|
}
|
|
|
|
//exposed methods
|
|
return {
|
|
show: function(immediately){
|
|
currentstate = 'overlay';
|
|
var $ap = $.mobile.activePage ? $.mobile.activePage : $(".ui-page-active");
|
|
return $ap.children( toolbarSelector ).each(function(){
|
|
var el = $(this),
|
|
fromTop = $(window).scrollTop(),
|
|
thisTop = el.offset().top,
|
|
screenHeight = window.innerHeight,
|
|
thisHeight = el.outerHeight(),
|
|
alreadyVisible = (el.is('.ui-header-fixed') && fromTop <= thisTop + thisHeight) || (el.is('.ui-footer-fixed') && thisTop <= fromTop + screenHeight);
|
|
|
|
//add state class
|
|
el.addClass('ui-fixed-overlay').removeClass('ui-fixed-inline');
|
|
|
|
if( !alreadyVisible && !immediately ){
|
|
el.addClass('in').animationComplete(function(){
|
|
el.removeClass('in');
|
|
});
|
|
}
|
|
setTop(el);
|
|
});
|
|
},
|
|
hide: function(immediately){
|
|
currentstate = 'inline';
|
|
var $ap = $.mobile.activePage ? $.mobile.activePage : $(".ui-page-active");
|
|
return $ap.children( toolbarSelector ).each(function(){
|
|
var el = $(this);
|
|
|
|
//add state class
|
|
el.addClass('ui-fixed-inline').removeClass('ui-fixed-overlay');
|
|
|
|
if(immediately){
|
|
el.css('top',0);
|
|
}
|
|
else{
|
|
if( el.css('top') !== 'auto' && parseFloat(el.css('top')) !== 0 ){
|
|
var classes = 'out reverse';
|
|
el.addClass(classes).animationComplete(function(){
|
|
el.removeClass(classes);
|
|
el.css('top',0);
|
|
});
|
|
}
|
|
}
|
|
});
|
|
},
|
|
hideAfterDelay: function(){
|
|
delayTimer = setTimeout(function(){
|
|
$.fixedToolbars.hide();
|
|
}, 3000);
|
|
},
|
|
toggle: function(from){
|
|
if(from){ currentstate = from; }
|
|
return (currentstate == 'overlay') ? $.fixedToolbars.hide() : $.fixedToolbars.show();
|
|
}
|
|
};
|
|
})();
|
|
|
|
})(jQuery); |