Skip to content

Commit 36d58eb

Browse files
authored
Remove jquery usage in theme JS (#331)
* Replace jquery usage in hamburger menu handling * Rewrite revealOnScroll in vanilla JS * Remove reavealOnScroll JS This was used in the feature cards, which were removed in 392e3b6 * Remove animated scrolling when clicking on link * Replace scroll to top JQuery with vanilla JS * Rewrite scrollHeadersAndNavbar in vanilla JS * Port rest of shortcuts code to vanilla JS * Remove jquery
1 parent f31744f commit 36d58eb

6 files changed

Lines changed: 125 additions & 144 deletions

File tree

assets/js/fresh.js

Lines changed: 36 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1,102 +1,47 @@
1-
$(document).ready(function () {
1+
function whenReady() {
22
//Mobile menu toggle
3-
if ($(".navbar-burger").length) {
4-
$(".navbar-burger").on("click", function () {
5-
var menu_id = $(this).attr("data-target");
6-
$(this).toggleClass("is-active");
7-
$("#" + menu_id).toggleClass("is-active");
8-
$(".navbar.is-light").toggleClass("is-dark-mobile");
9-
});
10-
}
11-
12-
//reveal elements on scroll so animations trigger the right way
13-
var $window = $(window),
14-
win_height_padded = $window.height() * 1.1;
3+
const burgers = document.getElementsByClassName("navbar-burger");
4+
if (burgers) {
5+
Array.prototype.map.call(burgers, (burger) => {
6+
burger.addEventListener("click", () => {
7+
burger.classList.toggle("is-active");
158

16-
$window.on("scroll", revealOnScroll);
9+
const menu_id = burger.getAttribute("data-target");
10+
const menu = document.getElementById(menu_id);
11+
menu.classList.toggle("is-active");
1712

18-
function revealOnScroll() {
19-
var scrolled = $window.scrollTop();
20-
$(".revealOnScroll:not(.animated)").each(function () {
21-
var $this = $(this),
22-
offsetTop = $this.offset().top;
23-
24-
if (scrolled + win_height_padded > offsetTop) {
25-
if ($this.data("timeout")) {
26-
window.setTimeout(
27-
function () {
28-
$this.addClass("animated " + $this.data("animation"));
29-
},
30-
parseInt($this.data("timeout"), 10),
31-
);
32-
} else {
33-
$this.addClass("animated " + $this.data("animation"));
34-
}
35-
}
13+
const navbars = document.getElementsByClassName("navbar is-light");
14+
Array.prototype.map.call(navbars, (e) => {
15+
e.classList.toggle("is-dark-mobile");
16+
});
17+
});
3618
});
3719
}
3820

3921
// Back to Top button behaviour
40-
var pxShow = 600;
41-
var scrollSpeed = 500;
42-
$(window).on("scroll", function () {
43-
if ($(window).scrollTop() >= pxShow) {
44-
$("#backtotop").addClass("visible");
45-
} else {
46-
$("#backtotop").removeClass("visible");
22+
const pxShow = 600;
23+
var timer = null;
24+
const backToTop = document.getElementById("backtotop");
25+
26+
window.addEventListener("scroll", () => {
27+
const scrollTop = document.documentElement.scrollTop;
28+
29+
if (timer !== null) {
30+
clearTimeout(timer);
4731
}
48-
});
49-
$("#backtotop a").on("click", function () {
50-
$("html, body").animate(
51-
{
52-
scrollTop: 0,
53-
},
54-
scrollSpeed,
32+
33+
timer = setTimeout(() =>
34+
backToTop.classList.toggle("visible", scrollTop >= pxShow),
5535
);
56-
return false;
5736
});
5837

59-
// Select all links with hashes
60-
$('a[href*="#"]')
61-
// Remove links that don't actually link to anything
62-
.not('[href="#"]')
63-
.not('[href="#0"]')
64-
.on("click", function (event) {
65-
// On-page links
66-
if (
67-
location.pathname.replace(/^\//, "") ==
68-
this.pathname.replace(/^\//, "") &&
69-
location.hostname == this.hostname
70-
) {
71-
// Figure out element to scroll to
72-
var target = $(this.hash);
73-
target = target.length
74-
? target
75-
: $("[name=" + this.hash.slice(1) + "]");
76-
// Does a scroll target exist?
77-
if (target.length) {
78-
// Only prevent default if animation is actually gonna happen
79-
event.preventDefault();
80-
$("html, body").animate(
81-
{
82-
scrollTop: target.offset().top,
83-
},
84-
550,
85-
function () {
86-
// Callback after animation
87-
// Must change focus!
88-
var $target = $(target);
89-
$target.focus();
90-
if ($target.is(":focus")) {
91-
// Checking if the target was focused
92-
return false;
93-
} else {
94-
$target.attr("tabindex", "-1"); // Adding tabindex for elements not focusable
95-
$target.focus(); // Set focus again
96-
}
97-
},
98-
);
99-
}
100-
}
101-
});
102-
});
38+
backToTop.addEventListener("click", () => {
39+
window.scrollTo({ top: 500, behavior: "smooth" });
40+
});
41+
}
42+
43+
if (document.readyState !== "loading") {
44+
whenReady();
45+
} else {
46+
document.addEventListener("DOMContentLoaded", whenReady);
47+
}

assets/js/shortcuts.js

Lines changed: 84 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -22,58 +22,71 @@ function throttle(fn, interval) {
2222
};
2323
}
2424

25+
function scrollNavbar() {
26+
const scrollPosition = document.documentElement.scrollTop;
27+
28+
//Navbar Clone
29+
const navbarClone = document.getElementById("navbar-clone");
30+
31+
// Make navbar sticky, by activating a second, duplicate navbar
32+
// that is fixed to the top of the screen.
33+
navbarClone.classList.toggle("is-active", scrollPosition > 50);
34+
}
35+
2536
// Highlight currently scrolled to header in shortcuts
2637
// Based on https://stackoverflow.com/a/32396543/214686
2738
// and
2839
// https://stackoverflow.com/a/57494988/214686
2940
// which fixes some issues with the first, particularly
3041
// around scrolling upward.
3142
function scrollHeadersAndNavbar() {
32-
var scrollPosition = $(window).scrollTop();
33-
var headers = $(":header[id]");
34-
var allShortcuts = $("#shortcuts > div");
43+
scrollNavbar();
3544

36-
//Navbar Clone
37-
if (scrollPosition > 50) {
38-
$("#navbar-clone").addClass("is-active");
39-
} else {
40-
$("#navbar-clone").removeClass("is-active");
41-
}
45+
const scrollPosition = document.documentElement.scrollTop;
46+
const headers = Array.from(
47+
document.querySelectorAll(":is(h1, h2, h3, h4, h5, h6)[id]"),
48+
);
49+
const allShortcuts = Array.from(
50+
document.querySelectorAll("#shortcuts > div"),
51+
);
4252

43-
headers.each(function () {
44-
var currentSection = $(this);
53+
headers.map((currentSection) => {
4554
// get the position of the section
46-
var sectionTop = currentSection.position().top;
47-
var sectionHeight = currentSection.height();
55+
// emulates JQuery's .position().top
56+
const marginTop = parseInt(getComputedStyle(currentSection).marginTop, 10);
57+
var sectionTop = currentSection.offsetTop - marginTop;
58+
var sectionHeight = currentSection.getBoundingClientRect().height;
4859
var overall = scrollPosition + sectionHeight;
4960
var headerOffset = remToPx(4);
5061

5162
if (scrollPosition < headerOffset) {
52-
allShortcuts.removeClass("active");
53-
return false;
63+
allShortcuts.map((shortcut) => shortcut.classList.remove("active"));
64+
return;
5465
}
5566

5667
// user has scrolled over the top of the section
5768
if (
5869
scrollPosition + headerOffset >= sectionTop &&
5970
scrollPosition < overall
6071
) {
61-
var id = currentSection.attr("id");
62-
var shortcut = $(`#${id}-shortcut`);
63-
if (shortcut.length && !shortcut.hasClass("active")) {
64-
allShortcuts.removeClass("active");
65-
shortcut.addClass("active");
72+
const id = currentSection.id;
73+
const shortcut = document.getElementById(`${id}-shortcut`);
74+
if (shortcut) {
75+
allShortcuts.map((shortcut) => shortcut.classList.remove("active"));
76+
shortcut.classList.add("active");
6677
}
6778
}
6879
});
6980
}
7081

82+
const throttledScrollHeadersAndNavbar = throttle(scrollHeadersAndNavbar, 100);
83+
7184
function bindScroll() {
72-
$(window).scroll(throttle(scrollHeadersAndNavbar, 100));
85+
window.addEventListener("scroll", throttledScrollHeadersAndNavbar);
7386
}
7487

7588
function unbindScroll() {
76-
$(window).unbind("scroll");
89+
window.removeEventListener("scroll", throttledScrollHeadersAndNavbar);
7790
}
7891

7992
function remToPx(rem) {
@@ -93,53 +106,77 @@ function setupShortcuts(shortcutDepth = 2) {
93106
}
94107

95108
// Content Page Shortcuts
96-
const shortcutsTarget = $("#shortcuts");
97-
if (shortcutsTarget.length > 0) {
98-
$(classes).map(function (idx, el) {
109+
const shortcutsTarget = document.getElementById("shortcuts");
110+
if (shortcutsTarget) {
111+
const classElements = Array.from(document.querySelectorAll(classes));
112+
classElements.map((el) => {
99113
const title = el.textContent;
100114
const elId = el.id;
101115
// Gets the element type (e.g. h2, h3)
102-
const elType = $(el).get(0).tagName;
116+
const elType = el.tagName;
103117
// Adds snake-case title as an id attribute to target element
104-
shortcutsTarget.append(
118+
shortcutsTarget.insertAdjacentHTML(
119+
"beforeend",
105120
`<div id="${elId}-shortcut" class="shortcuts-${elType}" href="#${elId}">${title}</div>`,
106121
);
107122

108-
const shortcut = $(`#${elId}-shortcut`);
109-
shortcut.click(function () {
123+
const shortcut = document.getElementById(`${elId}-shortcut`);
124+
shortcut.addEventListener("click", () => {
125+
event.preventDefault();
126+
110127
// We don't want the shortcuts to flash through highlights while
111128
// we scroll to the desired header
112129
unbindScroll();
113130

114131
// Replace what's in the location bar, without changing browser history
115132
// and without triggering a page scroll
116133
history.replaceState(null, null, `#${elId}`);
117-
118-
let distance = $(`#${elId}`).offset().top - 60;
119-
$([document.documentElement, document.body]).animate(
120-
{
121-
scrollTop: distance,
122-
},
123-
300,
124-
null,
125-
function () {
126-
$("#shortcuts > div").removeClass("active");
127-
shortcut.addClass("active");
128-
129-
// Done moving to clicked header; re-enable
130-
// scroll highlighting of shortcuts
131-
bindScroll();
132-
},
134+
const shortcutDivs = Array.from(
135+
document.querySelectorAll("#shortcuts > div"),
133136
);
137+
shortcutDivs.forEach((e) => e.classList.remove("active"));
138+
shortcut.classList.add("active");
139+
140+
let headerOffset = el.offsetTop - 60;
141+
scrollToThen(headerOffset, () => {
142+
// Done moving to clicked header; re-enable
143+
// scroll highlighting of shortcuts
144+
bindScroll();
145+
146+
// After scroll, display the navbar, if necessary
147+
scrollNavbar();
148+
});
134149
});
135150
});
136151
}
137152

138153
// Removes the shortcuts container if no shortcuts exist.
139154
// Also removes the 'Get Help' link.
140-
if ($("#shortcuts div").length < 1) {
141-
$(".shortcuts-container").css("display", "none");
155+
const shortcuts = Array.from(document.querySelectorAll("#shortcuts div"));
156+
if (shortcuts.length == 0) {
157+
const shortcutsContainer = document.getElementById("shortcuts-container");
158+
shortcutsContainer.style.display = "none";
142159
}
143160

144161
bindScroll();
145162
}
163+
164+
/**
165+
* Modified from https://stackoverflow.com/a/55686711/214686
166+
*/
167+
function scrollToThen(offset, callback) {
168+
const onScroll = throttle(() => {
169+
const fixedOffset = offset.toFixed();
170+
if (window.pageYOffset.toFixed() === fixedOffset) {
171+
window.removeEventListener("scroll", onScroll);
172+
callback();
173+
}
174+
}, 100);
175+
176+
window.addEventListener("scroll", onScroll);
177+
onScroll();
178+
window.scrollTo({
179+
top: offset,
180+
/* behavior: 'smooth' */ /* too slow? */
181+
});
182+
}

assets/theme-css/shortcuts.css

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
.shortcuts-container {
1+
#shortcuts-container {
22
position: sticky;
33
align-self: flex-start;
44
top: 6rem;
@@ -42,7 +42,7 @@
4242
}
4343

4444
@media only screen and (max-width: 1090px) {
45-
.shortcuts-container {
45+
#shortcuts-container {
4646
display: none;
4747
}
4848
}

layouts/partials/javascript.html

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
{{- $inServerMode := .Site.IsServer -}}
22

3-
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
43
<!-- Font Awesome -->
54
<script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.2/js/all.min.js"></script>
65
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.2/css/all.min.css" />

layouts/partials/section/section.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<section class="content-padding flex-row">
2-
<div class="shortcuts-container">
2+
<div id="shortcuts-container">
33
<div><i class="fa-solid fa-list"></i> On this page</div>
44
<div id="shortcuts"></div>
55
</div>

layouts/partials/single/content.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<section class="content-padding flex-row">
2-
<div class="shortcuts-container">
3-
<div><i class="fa-solid fa-list"></i> On this page</div>
2+
<div id="shortcuts-container">
3+
<div><i class="fa-solid fa-list"></i> On this page</div>
44
<div id="shortcuts"></div>
55
</div>
66
<div class="content-container">

0 commit comments

Comments
 (0)