/* * jQuery Mobile Framework : prototype for "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($){ $.fn.fixHeaderFooter = function(options){ return $(this).each(function(){ if( $(this).data('fullscreen') ){ $(this).addClass('ui-page-fullscreen'); } $(this).find('.ui-header').addClass('ui-header-fixed ui-fixed-inline fade'); //should be slidedown $(this).find('.ui-footer').addClass('ui-footer-fixed ui-fixed-inline fade'); //should be slideup }); }; //single controller for all showing,hiding,toggling $.fixedToolbars = (function(){ var currentstate = 'inline', delayTimer, ignoreTargets = 'a,input,textarea,select,button,label,.ui-header-fixed,.ui-footer-fixed', 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 jQuery( '.ui-footer[data-id="'+ thisFooter.data('id') +'"]:not(.ui-footer-duplicate)' ).not(thisFooter); } //before page is shown, check for duplicate footer $('.ui-page').live('beforepageshow', 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('body').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); }); }); function setTop(el){ var fromTop = $(window).scrollTop(), thisTop = el.offset().top, thisCSStop = el.css('top') == 'auto' ? 0 : parseFloat(el.css('top')), screenHeight = window.innerHeight, thisHeight = el.outerHeight(); if( el.is('.ui-header-fixed') ){ return el.css('top', (el.parents('.ui-page').length) ? fromTop - thisTop + thisCSStop : fromTop); } else{ return el.css('top', (el.parents('.ui-page').length) ? -1 * (thisTop - (fromTop + screenHeight) + thisCSStop + thisHeight) : fromTop + screenHeight - thisHeight ); } } //exposed methods return { show: function(immediately){ currentstate = 'overlay'; return $('.ui-header-fixed,.ui-footer-fixed:not(.ui-footer-duplicate)').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'; return $('.ui-header-fixed,.ui-footer-fixed:not(.ui-footer-duplicate)').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);