1$(document).ready(() => { 2 const $button = $('#back-to-top'); 3 const $footer = $('footer.footer'); 4 const $mainColumn = $('.column-main'); 5 const $leftSidebar = $('.column-left'); 6 const $rightSidebar = $('.column-right'); 7 let lastScrollTop = 0; 8 const rightMargin = 20; 9 const bottomMargin = 20; 10 let lastState = null; 11 const state = { 12 base: { 13 classname: 'card has-text-centered', 14 left: '', 15 width: 64, 16 bottom: bottomMargin 17 } 18 }; 19 state['desktop-hidden'] = Object.assign({}, state.base, { 20 classname: state.base.classname + ' rise-up' 21 }); 22 state['desktop-visible'] = Object.assign({}, state['desktop-hidden'], { 23 classname: state['desktop-hidden'].classname + ' fade-in' 24 }); 25 state['desktop-dock'] = Object.assign({}, state['desktop-visible'], { 26 classname: state['desktop-visible'].classname + ' fade-in is-rounded', 27 width: 40 28 }); 29 state['mobile-hidden'] = Object.assign({}, state.base, { 30 classname: state.base.classname + ' fade-in', 31 right: rightMargin 32 }); 33 state['mobile-visible'] = Object.assign({}, state['mobile-hidden'], { 34 classname: state['mobile-hidden'].classname + ' rise-up' 35 }); 36 37 function isStateEquals(prev, next) { 38 return ![].concat(Object.keys(prev), Object.keys(next)).some(key => { 39 return !Object.prototype.hasOwnProperty.call(prev, key) 40 || !Object.prototype.hasOwnProperty.call(next, key) 41 || next[key] !== prev[key]; 42 }); 43 } 44 45 function applyState(state) { 46 if (lastState !== null && isStateEquals(lastState, state)) { 47 return; 48 } 49 $button.attr('class', state.classname); 50 for (const prop in state) { 51 if (prop === 'classname') { 52 continue; 53 } 54 $button.css(prop, state[prop]); 55 } 56 lastState = state; 57 } 58 59 function isDesktop() { 60 return window.innerWidth >= 1078; 61 } 62 63 function isTablet() { 64 return window.innerWidth >= 768 && !isDesktop(); 65 } 66 67 function isScrollUp() { 68 return $(window).scrollTop() < lastScrollTop && $(window).scrollTop() > 0; 69 } 70 71 function hasLeftSidebar() { 72 return $leftSidebar.length > 0; 73 } 74 75 function hasRightSidebar() { 76 return $rightSidebar.length > 0; 77 } 78 79 function getRightSidebarBottom() { 80 if (!hasRightSidebar()) { 81 return 0; 82 } 83 return Math.max.apply(null, $rightSidebar.find('.widget').map(function() { 84 return $(this).offset().top + $(this).outerHeight(true); 85 })); 86 } 87 88 function getScrollTop() { 89 return $(window).scrollTop(); 90 } 91 92 function getScrollBottom() { 93 return $(window).scrollTop() + $(window).height(); 94 } 95 96 function getButtonWidth() { 97 return $button.outerWidth(true); 98 } 99 100 function getButtonHeight() { 101 return $button.outerHeight(true); 102 } 103 104 function updateScrollTop() { 105 lastScrollTop = $(window).scrollTop(); 106 } 107 108 function update() { 109 // desktop mode or tablet mode with only right sidebar enabled 110 if (isDesktop() || (isTablet() && !hasLeftSidebar() && hasRightSidebar())) { 111 let nextState; 112 const padding = ($mainColumn.outerWidth() - $mainColumn.width()) / 2; 113 const maxLeft = $(window).width() - getButtonWidth() - rightMargin; 114 const maxBottom = $footer.offset().top + (getButtonHeight() / 2) + bottomMargin; 115 if (getScrollTop() === 0 || getScrollBottom() < getRightSidebarBottom() + padding + getButtonHeight()) { 116 nextState = state['desktop-hidden']; 117 } else if (getScrollBottom() < maxBottom) { 118 nextState = state['desktop-visible']; 119 } else { 120 nextState = Object.assign({}, state['desktop-dock'], { 121 bottom: getScrollBottom() - maxBottom + bottomMargin 122 }); 123 } 124 125 const left = $mainColumn.offset().left + $mainColumn.outerWidth() + padding; 126 nextState = Object.assign({}, nextState, { 127 left: Math.min(left, maxLeft) 128 }); 129 applyState(nextState); 130 } else { 131 // mobile and tablet mode 132 if (!isScrollUp()) { 133 applyState(state['mobile-hidden']); 134 } else { 135 applyState(state['mobile-visible']); 136 } 137 updateScrollTop(); 138 } 139 } 140 141 update(); 142 $(window).resize(update); 143 $(window).scroll(update); 144 145 $('#back-to-top').on('click', () => { 146 if (CSS && CSS.supports && CSS.supports('(scroll-behavior: smooth)')) { 147 window.scroll({ top: 0, behavior: 'smooth' }); 148 } else { 149 $('body, html').animate({ scrollTop: 0 }, 400); 150 } 151 }); 152});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.