mirror of
https://github.com/cotes2020/jekyll-theme-chirpy.git
synced 2025-12-18 21:53:26 +00:00
Hide topbar when mobile orientation in landscape mode (resolve #459)
This commit is contained in:
36
_javascript/commons/scroll-helper.js
Normal file
36
_javascript/commons/scroll-helper.js
Normal file
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* A tool for smooth scrolling and topbar switcher
|
||||
*/
|
||||
const ScrollHelper = (function () {
|
||||
const $body = $("body");
|
||||
const ATTR_TOPBAR_VISIBLE = "topbar-visible";
|
||||
const topbarHeight = $("#topbar-wrapper").outerHeight();
|
||||
|
||||
let scrollUpCount = 0; // the number of times the scroll up was triggered by ToC or anchor
|
||||
let topbarLocked = false;
|
||||
let orientationLocked = false;
|
||||
|
||||
return {
|
||||
hideTopbar: () => $body.attr(ATTR_TOPBAR_VISIBLE, false),
|
||||
showTopbar: () => $body.attr(ATTR_TOPBAR_VISIBLE, true),
|
||||
|
||||
// scroll up
|
||||
|
||||
addScrollUpTask: () => {
|
||||
scrollUpCount += 1;
|
||||
if (!topbarLocked) { topbarLocked = true; }
|
||||
},
|
||||
popScrollUpTask: () => scrollUpCount -= 1,
|
||||
hasScrollUpTask: () => scrollUpCount > 0,
|
||||
topbarLocked: () => topbarLocked === true,
|
||||
unlockTopbar: () => topbarLocked = false,
|
||||
getTopbarHeight: () => topbarHeight,
|
||||
|
||||
// orientation change
|
||||
|
||||
orientationLocked: () => orientationLocked === true,
|
||||
lockOrientation: () => orientationLocked = true,
|
||||
unLockOrientation: () => orientationLocked = false
|
||||
};
|
||||
|
||||
}());
|
||||
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
* Hide Header on scroll down
|
||||
*/
|
||||
|
||||
$(function() {
|
||||
const $topbarWrapper = $("#topbar-wrapper");
|
||||
const $topbarTitle = $("#topbar-title");
|
||||
const $panel = $("#panel-wrapper");
|
||||
const $searchInput = $("#search-input");
|
||||
|
||||
const CLASS_TOPBAR_UP = "topbar-up";
|
||||
const CLASS_TOPBAR_DOWN = "topbar-down";
|
||||
const ATTR_TOC_SCROLLING_UP = "toc-scrolling-up"; // topbar locked
|
||||
|
||||
let didScroll;
|
||||
let lastScrollTop = 0;
|
||||
|
||||
const delta = $topbarWrapper.outerHeight();
|
||||
const topbarHeight = $topbarWrapper.outerHeight();
|
||||
|
||||
function hasScrolled() {
|
||||
let st = $(this).scrollTop();
|
||||
|
||||
/* Make sure they scroll more than delta */
|
||||
if (Math.abs(lastScrollTop - st) <= delta) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (st > lastScrollTop ) { // Scroll Down
|
||||
if (st > topbarHeight) {
|
||||
$topbarWrapper.removeClass(CLASS_TOPBAR_DOWN).addClass(CLASS_TOPBAR_UP);
|
||||
$panel.removeClass(CLASS_TOPBAR_DOWN);
|
||||
|
||||
if ($searchInput.is(":focus")) {
|
||||
$searchInput.blur(); /* remove focus */
|
||||
}
|
||||
}
|
||||
} else {// Scroll up
|
||||
// did not reach the bottom of the document, i.e., still have space to scroll up
|
||||
if (st + $(window).height() < $(document).height()) {
|
||||
let tocScrollingUp = $topbarWrapper.attr(ATTR_TOC_SCROLLING_UP);
|
||||
if (typeof tocScrollingUp !== "undefined") {
|
||||
if (tocScrollingUp === "false") {
|
||||
$topbarWrapper.removeAttr(ATTR_TOC_SCROLLING_UP);
|
||||
}
|
||||
|
||||
} else {
|
||||
$topbarWrapper.removeClass(CLASS_TOPBAR_UP).addClass(CLASS_TOPBAR_DOWN);
|
||||
$panel.addClass(CLASS_TOPBAR_DOWN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lastScrollTop = st;
|
||||
}
|
||||
|
||||
$(window).scroll(function(event) {
|
||||
if ($topbarTitle.is(":hidden")) {
|
||||
didScroll = true;
|
||||
}
|
||||
});
|
||||
|
||||
setInterval(function() {
|
||||
if (didScroll) {
|
||||
hasScrolled();
|
||||
didScroll = false;
|
||||
}
|
||||
}, 250);
|
||||
|
||||
});
|
||||
90
_javascript/commons/topbar-switcher.js
Normal file
90
_javascript/commons/topbar-switcher.js
Normal file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Hide Header on scroll down
|
||||
*/
|
||||
|
||||
$(function() {
|
||||
const $searchInput = $("#search-input");
|
||||
const delta = ScrollHelper.getTopbarHeight();
|
||||
|
||||
let didScroll;
|
||||
let lastScrollTop = 0;
|
||||
|
||||
function hasScrolled() {
|
||||
let st = $(this).scrollTop();
|
||||
|
||||
/* Make sure they scroll more than delta */
|
||||
if (Math.abs(lastScrollTop - st) <= delta) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (st > lastScrollTop ) { // Scroll Down
|
||||
ScrollHelper.hideTopbar();
|
||||
|
||||
if ($searchInput.is(":focus")) {
|
||||
$searchInput.blur(); /* remove focus */
|
||||
}
|
||||
|
||||
} else { // Scroll up
|
||||
// has not yet scrolled to the bottom of the screen, that is, there is still space for scrolling
|
||||
if (st + $(window).height() < $(document).height()) {
|
||||
|
||||
if (ScrollHelper.hasScrollUpTask()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ScrollHelper.topbarLocked()) { // avoid redundant scroll up event from smooth scrolling
|
||||
ScrollHelper.unlockTopbar();
|
||||
} else {
|
||||
if (ScrollHelper.orientationLocked()) { // avoid device auto scroll up on orientation change
|
||||
ScrollHelper.unLockOrientation();
|
||||
} else {
|
||||
ScrollHelper.showTopbar();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lastScrollTop = st;
|
||||
|
||||
} // hasScrolled()
|
||||
|
||||
function handleLandscape() {
|
||||
if ($(window).scrollTop() === 0) {
|
||||
return;
|
||||
}
|
||||
ScrollHelper.lockOrientation();
|
||||
ScrollHelper.hideTopbar();
|
||||
}
|
||||
|
||||
if (screen.orientation) {
|
||||
screen.orientation.onchange = () => {
|
||||
const type = screen.orientation.type;
|
||||
if (type === "landscape-primary" || type === "landscape-secondary") {
|
||||
handleLandscape();
|
||||
}
|
||||
};
|
||||
|
||||
} else {
|
||||
// for the browsers that not support `window.screen.orientation` API
|
||||
$(window).on("orientationchange",() => {
|
||||
if ($(window).width() < $(window).height()) { // before rotating, it is still in portrait mode.
|
||||
handleLandscape();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$(window).scroll(() => {
|
||||
if (didScroll) {
|
||||
return;
|
||||
}
|
||||
didScroll = true;
|
||||
});
|
||||
|
||||
setInterval(() => {
|
||||
if (didScroll) {
|
||||
hasScrolled();
|
||||
didScroll = false;
|
||||
}
|
||||
}, 250);
|
||||
|
||||
});
|
||||
@@ -14,17 +14,22 @@ $(function() {
|
||||
}
|
||||
|
||||
const defaultTitleText = $topbarTitle.text().trim();
|
||||
let titleText = $pageTitle.text().trim();
|
||||
let pageTitleText = $pageTitle.text().trim();
|
||||
let hasScrolled = false;
|
||||
let lastScrollTop = 0;
|
||||
|
||||
if ($("#page-category").length || $("#page-tag").length) {
|
||||
/* The title in Category or Tag page will be "<title> <count_of_posts>" */
|
||||
if (/\s/.test(titleText)) {
|
||||
titleText = titleText.replace(/[0-9]/g, "").trim();
|
||||
if (/\s/.test(pageTitleText)) {
|
||||
pageTitleText = pageTitleText.replace(/[0-9]/g, "").trim();
|
||||
}
|
||||
}
|
||||
|
||||
// When the page is scrolled down and then refreshed, the topbar title needs to be initialized
|
||||
if ($pageTitle.offset().top < $(window).scrollTop()) {
|
||||
$topbarTitle.text(pageTitleText);
|
||||
}
|
||||
|
||||
let options = {
|
||||
rootMargin: '-48px 0px 0px 0px', // 48px equals to the topbar height (3rem)
|
||||
threshold: [0, 1]
|
||||
@@ -43,7 +48,7 @@ $(function() {
|
||||
|
||||
if (isScrollDown) {
|
||||
if (heading.intersectionRatio === 0) {
|
||||
$topbarTitle.text(titleText);
|
||||
$topbarTitle.text(pageTitleText);
|
||||
}
|
||||
} else {
|
||||
if (heading.intersectionRatio === 1) {
|
||||
|
||||
@@ -8,21 +8,16 @@
|
||||
*/
|
||||
|
||||
$(function() {
|
||||
const $topbarWrapper = $("#topbar-wrapper");
|
||||
const topbarHeight = $topbarWrapper.outerHeight();
|
||||
const $topbarTitle = $("#topbar-title");
|
||||
|
||||
const ATTR_TOC_SCROLLING = "toc-scrolling-up";
|
||||
const SCROLL_MARK = "scroll-focus";
|
||||
const REM = 16; // in pixels
|
||||
let tocScrollUpCount = 0;
|
||||
const ATTR_SCROLL_FOCUS = "scroll-focus";
|
||||
|
||||
$("a[href*='#']")
|
||||
.not("[href='#']")
|
||||
.not("[href='#0']")
|
||||
.click(function(event) {
|
||||
|
||||
if (this.pathname.replace(/^\//, "") !== location.pathname.replace(/^\//, "")) {
|
||||
if (this.pathname.replace(/^\//, "") !==
|
||||
location.pathname.replace(/^\//, "")) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -36,9 +31,8 @@ $(function() {
|
||||
let selector = hash.includes(":") ? hash.replace(/\:/g, "\\:") : hash;
|
||||
let $target = $(selector);
|
||||
|
||||
let parent = $(this).parent().prop("tagName");
|
||||
let isAnchor = RegExp(/^H\d/).test(parent);
|
||||
let isMobileViews = !$topbarTitle.is(":hidden");
|
||||
let isMobileViews = $topbarTitle.is(":visible");
|
||||
let isPortrait = $(window).width() < $(window).height();
|
||||
|
||||
if (typeof $target === "undefined") {
|
||||
return;
|
||||
@@ -50,26 +44,20 @@ $(function() {
|
||||
history.pushState(null, null, hash);
|
||||
}
|
||||
|
||||
let curOffset = isAnchor ? $(this).offset().top : $(window).scrollTop();
|
||||
let curOffset = $(window).scrollTop();
|
||||
let destOffset = $target.offset().top -= REM / 2;
|
||||
|
||||
if (destOffset < curOffset) { // scroll up
|
||||
if (!isAnchor && !toFootnote) { // trigger by ToC item
|
||||
if (!isMobileViews) { // on desktop/tablet screens
|
||||
$topbarWrapper.removeClass("topbar-down").addClass("topbar-up");
|
||||
// Send message to `${JS_ROOT}/commons/topbar-switch.js`
|
||||
$topbarWrapper.attr(ATTR_TOC_SCROLLING, true);
|
||||
tocScrollUpCount += 1;
|
||||
}
|
||||
ScrollHelper.hideTopbar();
|
||||
ScrollHelper.addScrollUpTask();
|
||||
|
||||
if (isMobileViews && isPortrait) {
|
||||
destOffset -= ScrollHelper.getTopbarHeight();
|
||||
}
|
||||
|
||||
if ((isAnchor || toFootnoteRef) && isMobileViews) {
|
||||
destOffset -= topbarHeight;
|
||||
}
|
||||
|
||||
} else {
|
||||
if (isMobileViews) {
|
||||
destOffset -= topbarHeight;
|
||||
} else { // scroll down
|
||||
if (isMobileViews && isPortrait) {
|
||||
destOffset -= ScrollHelper.getTopbarHeight();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,18 +67,18 @@ $(function() {
|
||||
$target.focus();
|
||||
|
||||
/* clean up old scroll mark */
|
||||
if ($(`[${SCROLL_MARK}=true]`).length) {
|
||||
$(`[${SCROLL_MARK}=true]`).attr(SCROLL_MARK, false);
|
||||
if ($(`[${ATTR_SCROLL_FOCUS}=true]`).length) {
|
||||
$(`[${ATTR_SCROLL_FOCUS}=true]`).attr(ATTR_SCROLL_FOCUS, false);
|
||||
}
|
||||
|
||||
/* Clean :target links */
|
||||
if ($(":target").length) { /* element that visited by the URL with hash */
|
||||
$(":target").attr(SCROLL_MARK, false);
|
||||
$(":target").attr(ATTR_SCROLL_FOCUS, false);
|
||||
}
|
||||
|
||||
/* set scroll mark to footnotes */
|
||||
if (toFootnote || toFootnoteRef) {
|
||||
$target.attr(SCROLL_MARK, true);
|
||||
$target.attr(ATTR_SCROLL_FOCUS, true);
|
||||
}
|
||||
|
||||
if ($target.is(":focus")) { /* Checking if the target was focused */
|
||||
@@ -100,12 +88,8 @@ $(function() {
|
||||
$target.focus(); /* Set focus again */
|
||||
}
|
||||
|
||||
if (typeof $topbarWrapper.attr(ATTR_TOC_SCROLLING) !== "undefined") {
|
||||
tocScrollUpCount -= 1;
|
||||
|
||||
if (tocScrollUpCount <= 0) {
|
||||
$topbarWrapper.attr(ATTR_TOC_SCROLLING, "false");
|
||||
}
|
||||
if (ScrollHelper.hasScrollUpTask()) {
|
||||
ScrollHelper.popScrollUpTask();
|
||||
}
|
||||
});
|
||||
}); /* click() */
|
||||
|
||||
Reference in New Issue
Block a user