// Stop scrolling at footer. // // This can be added to elements with `position: fixed` to stop them from // overflowing on the footer. // // Usage: // // GOVUK.stopScrollingAtFooter.addEl($(node), $(node).height()); // // Height is passed in separatly incase the scrolling element has no height // itself.
;(function (global) {
'use strict' var $ = global.jQuery var GOVUK = global.GOVUK || {} var stopScrollingAtFooter = { _pollingId: null, _isPolling: false, _hasScrollEvt: false, _els: [], addEl: function ($fixedEl, height) { var fixedOffset if (!$fixedEl.length) { return } fixedOffset = parseInt($fixedEl.css('top'), 10) fixedOffset = isNaN(fixedOffset) ? 0 : fixedOffset stopScrollingAtFooter.updateFooterTop() $(global).on('govuk.pageSizeChanged', stopScrollingAtFooter.updateFooterTop) var $siblingEl = $('<div></div>') $siblingEl.insertBefore($fixedEl) var fixedTop = $siblingEl.offset().top - $siblingEl.position().top $siblingEl.remove() var el = { $fixedEl: $fixedEl, height: height + fixedOffset, fixedTop: height + fixedTop, state: 'fixed' } stopScrollingAtFooter._els.push(el) stopScrollingAtFooter.initTimeout() }, updateFooterTop: function () { var footer = $('.js-footer:eq(0)') if (footer.length === 0) { return 0 } stopScrollingAtFooter.footerTop = footer.offset().top - 10 }, initTimeout: function () { if (stopScrollingAtFooter._hasScrollEvt === false) { $(window).scroll(stopScrollingAtFooter.onScroll) stopScrollingAtFooter._hasScrollEvt = true } }, onScroll: function () { if (stopScrollingAtFooter._isPolling === false) { stopScrollingAtFooter.startPolling() } }, startPolling: (function () { if (window.requestAnimationFrame) { return function () { var callback = function () { stopScrollingAtFooter.checkScroll() if (stopScrollingAtFooter._isPolling === true) { stopScrollingAtFooter.startPolling() } } stopScrollingAtFooter._pollingId = window.requestAnimationFrame(callback) stopScrollingAtFooter._isPolling = true } } else { return function () { stopScrollingAtFooter._pollingId = window.setInterval(stopScrollingAtFooter.checkScroll, 16) stopScrollingAtFooter._isPolling = true } } }()), stopPolling: (function () { if (window.requestAnimationFrame) { return function () { window.cancelAnimationFrame(stopScrollingAtFooter._pollingId) stopScrollingAtFooter._isPolling = false } } else { return function () { window.clearInterval(stopScrollingAtFooter._pollingId) stopScrollingAtFooter._isPolling = false } } }()), checkScroll: function () { var cachedScrollTop = $(window).scrollTop() if ((cachedScrollTop < (stopScrollingAtFooter.cachedScrollTop + 2)) && (cachedScrollTop > (stopScrollingAtFooter.cachedScrollTop - 2))) { stopScrollingAtFooter.stopPolling() return } else { stopScrollingAtFooter.cachedScrollTop = cachedScrollTop } $.each(stopScrollingAtFooter._els, function (i, el) { var bottomOfEl = cachedScrollTop + el.height if (bottomOfEl > stopScrollingAtFooter.footerTop) { stopScrollingAtFooter.stick(el) } else { stopScrollingAtFooter.unstick(el) } }) }, stick: function (el) { if (el.state === 'fixed' && el.$fixedEl.css('position') === 'fixed') { el.$fixedEl.css({ 'position': 'absolute', 'top': stopScrollingAtFooter.footerTop - el.fixedTop }) el.state = 'absolute' } }, unstick: function (el) { if (el.state === 'absolute') { el.$fixedEl.css({ 'position': '', 'top': '' }) el.state = 'fixed' } } } GOVUK.stopScrollingAtFooter = stopScrollingAtFooter $(global).load(function () { $(global).trigger('govuk.pageSizeChanged') }) global.GOVUK = GOVUK
})(window)