$(document).ready(function () { var $button = $('#back-to-top'); var $footer = $('footer.footer'); var $mainColumn = $('.column-main'); var $leftSidebar = $('.column-left'); var $rightSidebar = $('.column-right'); var lastScrollTop = 0; var rightMargin = 20; var bottomMargin = 20; var lastState = null; var state = { base: { classname: 'card has-text-centered', left: '', width: 64, bottom: bottomMargin, 'border-radius': 4 } }; state['desktop-hidden'] = Object.assign({}, state.base, { classname: state.base.classname + ' rise-up', }); state['desktop-visible'] = Object.assign({}, state['desktop-hidden'], { classname: state['desktop-hidden'].classname + ' fade-in', }); state['desktop-dock'] = Object.assign({}, state['desktop-visible'], { classname: state['desktop-visible'].classname + ' fade-in', width: 40, 'border-radius': '50%' }); state['mobile-hidden'] = Object.assign({}, state.base, { classname: state.base.classname + ' fade-in', right: rightMargin }); state['mobile-visible'] = Object.assign({}, state['mobile-hidden'], { classname: state['mobile-hidden'].classname + ' rise-up', }); function isStateEquals(prev, next) { for (var prop in prev) { if (!next.hasOwnProperty(prop) || next[prop] !== prev[prop]) { return false; } } for (var prop in next) { if (!prev.hasOwnProperty(prop) || prev[prop] !== prev[prop]) { return false; } } return true; } function applyState(state) { if (lastState !== null && isStateEquals(lastState, state)) { return; } $button.attr('class', state.classname); for (let prop in state) { if (prop === 'classname') { continue; } $button.css(prop, state[prop]); } lastState = state; } function isDesktop() { return window.innerWidth >= 1078; } function isTablet() { return window.innerWidth >= 768 && !isDesktop(); } function isScrollUp() { return $(window).scrollTop() < lastScrollTop && $(window).scrollTop() > 0; } function hasLeftSidebar() { return $leftSidebar.length > 0; } function hasRightSidebar() { return $rightSidebar.length > 0; } function getRightSidebarBottom() { if (!hasRightSidebar()) { return 0; } return Math.max.apply(null, $rightSidebar.find('.widget').map(function () { return $(this).offset().top + $(this).outerHeight(true); })); } function getScrollTop() { return $(window).scrollTop(); } function getScrollBottom() { return $(window).scrollTop() + $(window).height(); } function getButtonWidth() { return $button.outerWidth(true); } function getButtonHeight() { return $button.outerHeight(true); } function updateScrollTop() { lastScrollTop = $(window).scrollTop(); } function update() { // desktop mode or tablet mode with only right sidebar enabled if (isDesktop() || (isTablet() && !hasLeftSidebar() && hasRightSidebar())) { var nextState; var padding = ($mainColumn.outerWidth() - $mainColumn.width()) / 2; var maxLeft = $(window).width() - getButtonWidth() - rightMargin; var maxBottom = $footer.offset().top + getButtonHeight() / 2 + bottomMargin; if (getScrollTop() == 0 || getScrollBottom() < getRightSidebarBottom() + padding + getButtonHeight()) { nextState = state['desktop-hidden']; } else if (getScrollBottom() < maxBottom) { nextState = state['desktop-visible']; } else { nextState = Object.assign({}, state['desktop-dock'], { bottom: getScrollBottom() - maxBottom + bottomMargin }); } var left = $mainColumn.offset().left + $mainColumn.outerWidth() + padding; nextState = Object.assign({}, nextState, { left: Math.min(left, maxLeft) }); applyState(nextState); } else { // mobile and tablet mode if (!isScrollUp()) { applyState(state['mobile-hidden']); } else { applyState(state['mobile-visible']); } updateScrollTop(); } } update(); $(window).resize(update); $(window).scroll(update); $('#back-to-top').on('click', function () { $('body, html').animate({ scrollTop: 0 }, 400); }); });