From 24968cfb84a3426ba64636ab681921c7ec3373bc Mon Sep 17 00:00:00 2001 From: Jon Froehlich Date: Mon, 15 Jun 2026 08:35:52 -0700 Subject: [PATCH] Vanilla navbar collapse; remove dead back-to-top + jQuery Easing (#1288) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Track A (#1253): replaces the Bootstrap 3 collapse data-api on the mobile navbar with a small vanilla-JS handler, and clears out dead front-end code uncovered while doing it. top-navbar.js rewritten in vanilla JS (no jQuery): - Toggles the mobile menu via the `in` class (same class Bootstrap's CSS already styles; desktop layout is unchanged — handled purely by CSS). - Keeps `aria-expanded` in sync; closes on nav-link click, outside click, and Escape (Escape returns focus to the toggle — an a11y improvement). - Dropped two behaviors that were already dead: the `top-nav-scrolled` scroll handler (no CSS rule for that class anywhere) and the jQuery-Easing "page-scroll" smooth scroll (only on the logo, whose href is a page URL, so it errored and fell through to normal navigation). Removed as dead code: - backtop.js — never included in any template; no `#back-top` element exists. - backtop.css + img/up-arrow.png — styled that nonexistent button. - jquery.easing.min.js — its only consumer was the page-scroll handler above. base.html: dropped the backtop.css link, the jquery.easing script, the navbar toggle's `data-toggle="collapse"`/`data-target` attrs (now vanilla), and the now-meaningless `page-scroll` class on the brand link. Verified locally: all pages 200, removed refs gone from served HTML, and the mobile toggle (open/close, nav-link, outside-click, Escape) works in-browser. Co-Authored-By: Claude Opus 4.8 (1M context) --- website/static/website/css/backtop.css | 83 -------------- website/static/website/img/up-arrow.png | Bin 548 -> 0 bytes website/static/website/js/backtop.js | 27 ----- .../static/website/js/jquery.easing.min.js | 44 -------- website/static/website/js/top-navbar.js | 102 ++++++++++++------ website/templates/website/base.html | 10 +- 6 files changed, 73 insertions(+), 193 deletions(-) delete mode 100644 website/static/website/css/backtop.css delete mode 100644 website/static/website/img/up-arrow.png delete mode 100644 website/static/website/js/backtop.js delete mode 100644 website/static/website/js/jquery.easing.min.js diff --git a/website/static/website/css/backtop.css b/website/static/website/css/backtop.css deleted file mode 100644 index 2885d36e..00000000 --- a/website/static/website/css/backtop.css +++ /dev/null @@ -1,83 +0,0 @@ -/**** Automatic Show/Hide Scroll-Up Up Arrow ****/ - -#back-top { - position: fixed; - bottom: 10px; - left: 25px; - z-index: 1000; -} - -@media (max-width: 768px) { - #back-top a { - width: 25px; - display: block; - text-align: center; - font: 5px/100% Arial, Helvetica, sans-serif; - text-transform: uppercase; - text-decoration: none; - color: rgba(0,0,0,0.7); - /* transition */ - -webkit-transition: 1s; - -moz-transition: 1s; - transition: 1s; - } - - #back-top span { - width: 25px; - height: 25px; - display: block; - margin-bottom: 7px; - background: rgba(0,0,0,0.4) url(../img/up-arrow.png) no-repeat center center; - background-size: 100% 100%; - /* rounded corners */ - -webkit-border-radius: 5px; - -moz-border-radius: 5px; - border-radius: 5px; - /* transition */ - -webkit-transition: 1s; - -moz-transition: 1s; - transition: 1s; - } -} - -@media (min-width: 769px) { - #back-top a { - width: 75px; - display: block; - text-align: center; - font: 11px/100% Arial, Helvetica, sans-serif; - text-transform: uppercase; - text-decoration: none; - color: rgba(0,0,0,0.7); - /* transition */ - -webkit-transition: 1s; - -moz-transition: 1s; - transition: 1s; - } - - #back-top span { - width: 75px; - height: 75px; - display: block; - margin-bottom: 7px; - background: rgba(0,0,0,0.4) url(../img/up-arrow.png) no-repeat center center; - /* rounded corners */ - -webkit-border-radius: 15px; - -moz-border-radius: 15px; - border-radius: 15px; - /* transition */ - -webkit-transition: 1s; - -moz-transition: 1s; - transition: 1s; - } -} - -#back-top a:hover { - color: rgba(0,0,0,0.7); -} - -/* arrow icon (span tag) */ - -#back-top a:hover span { - background-color: rgba(0, 0, 0, 0.7); -} \ No newline at end of file diff --git a/website/static/website/img/up-arrow.png b/website/static/website/img/up-arrow.png deleted file mode 100644 index eee3e2fdbe039c01bb37658fdc828c2598618ba8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 548 zcmeAS@N?(olHy`uVBq!ia0vp^7C>yx!3HGtggiF@Db50q$YKTtZeb8+WSBKa0w~B{ z;_2(k{(wWCU(v!hIy{Skf$^}Xi(^Q}y|*`fy_o_&4MMY8}1~(ymVbo?}Bs9-A6*N@3}X6p{0Q?V>M!tbglY@fRZDEMF-Yvt{eVJvG@-|bh(w~lvBxWO3^^r?DXO5wbp zwljC#IA|L1c)9=T{IuJ}-=`gDs@nYFyAJ=963#U%?6o~VFLL02n7wQE>}9S8q#hKp zRNl^vVaaiiIj68biY13Vrc+@((CEVo>w{RTou)o0dKf@}6@Vp<~Q%czGFgD9Ev)BCNt^CHUk;!Dkr2NZX`N2is8B2tZ`&!JK zX;CyqWvfGL`$0qtSFiRX@U^8f7 h offset) { - // console.log("Showing scroll top button!!!") - $('#back-top').fadeIn(duration); - } - else { - // console.log("Hiding scroll top button") - $('#back-top').fadeOut(duration); - } - }); - - // scroll body to 0px on click - $('#back-top a').click(function () { - $('body,html').animate({ - scrollTop: 0 - }, 800); - return false; - }); -}); diff --git a/website/static/website/js/jquery.easing.min.js b/website/static/website/js/jquery.easing.min.js deleted file mode 100644 index 6cf5f20c..00000000 --- a/website/static/website/js/jquery.easing.min.js +++ /dev/null @@ -1,44 +0,0 @@ -/* - * jQuery Easing v1.3 - http://gsgd.co.uk/sandbox/jquery/easing/ - * - * Uses the built in easing capabilities added In jQuery 1.1 - * to offer multiple easing options - * - * TERMS OF USE - EASING EQUATIONS - * - * Open source under the BSD License. - * - * Copyright © 2001 Robert Penner - * All rights reserved. - * - * TERMS OF USE - jQuery Easing - * - * Open source under the BSD License. - * - * Copyright © 2008 George McGinley Smith - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * Neither the name of the author nor the names of contributors may be used to endorse - * or promote products derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * -*/ -jQuery.easing.jswing=jQuery.easing.swing;jQuery.extend(jQuery.easing,{def:"easeOutQuad",swing:function(e,f,a,h,g){return jQuery.easing[jQuery.easing.def](e,f,a,h,g)},easeInQuad:function(e,f,a,h,g){return h*(f/=g)*f+a},easeOutQuad:function(e,f,a,h,g){return -h*(f/=g)*(f-2)+a},easeInOutQuad:function(e,f,a,h,g){if((f/=g/2)<1){return h/2*f*f+a}return -h/2*((--f)*(f-2)-1)+a},easeInCubic:function(e,f,a,h,g){return h*(f/=g)*f*f+a},easeOutCubic:function(e,f,a,h,g){return h*((f=f/g-1)*f*f+1)+a},easeInOutCubic:function(e,f,a,h,g){if((f/=g/2)<1){return h/2*f*f*f+a}return h/2*((f-=2)*f*f+2)+a},easeInQuart:function(e,f,a,h,g){return h*(f/=g)*f*f*f+a},easeOutQuart:function(e,f,a,h,g){return -h*((f=f/g-1)*f*f*f-1)+a},easeInOutQuart:function(e,f,a,h,g){if((f/=g/2)<1){return h/2*f*f*f*f+a}return -h/2*((f-=2)*f*f*f-2)+a},easeInQuint:function(e,f,a,h,g){return h*(f/=g)*f*f*f*f+a},easeOutQuint:function(e,f,a,h,g){return h*((f=f/g-1)*f*f*f*f+1)+a},easeInOutQuint:function(e,f,a,h,g){if((f/=g/2)<1){return h/2*f*f*f*f*f+a}return h/2*((f-=2)*f*f*f*f+2)+a},easeInSine:function(e,f,a,h,g){return -h*Math.cos(f/g*(Math.PI/2))+h+a},easeOutSine:function(e,f,a,h,g){return h*Math.sin(f/g*(Math.PI/2))+a},easeInOutSine:function(e,f,a,h,g){return -h/2*(Math.cos(Math.PI*f/g)-1)+a},easeInExpo:function(e,f,a,h,g){return(f==0)?a:h*Math.pow(2,10*(f/g-1))+a},easeOutExpo:function(e,f,a,h,g){return(f==g)?a+h:h*(-Math.pow(2,-10*f/g)+1)+a},easeInOutExpo:function(e,f,a,h,g){if(f==0){return a}if(f==g){return a+h}if((f/=g/2)<1){return h/2*Math.pow(2,10*(f-1))+a}return h/2*(-Math.pow(2,-10*--f)+2)+a},easeInCirc:function(e,f,a,h,g){return -h*(Math.sqrt(1-(f/=g)*f)-1)+a},easeOutCirc:function(e,f,a,h,g){return h*Math.sqrt(1-(f=f/g-1)*f)+a},easeInOutCirc:function(e,f,a,h,g){if((f/=g/2)<1){return -h/2*(Math.sqrt(1-f*f)-1)+a}return h/2*(Math.sqrt(1-(f-=2)*f)+1)+a},easeInElastic:function(f,h,e,l,k){var i=1.70158;var j=0;var g=l;if(h==0){return e}if((h/=k)==1){return e+l}if(!j){j=k*0.3}if(g= 768px regardless of the + * `in` class); this script only toggles the `in` class at mobile widths. + * + * Behavior: + * - Toggle button opens/closes the menu and keeps `aria-expanded` in sync. + * - Clicking a nav link closes the open menu. + * - Clicking outside the navbar closes the open menu. + * - Escape closes the open menu and returns focus to the toggle (a11y). + * + * Note: the previous version also added a `top-nav-scrolled` class on scroll + * (no CSS rule existed for it — a no-op) and a jQuery-Easing "page-scroll" + * smooth scroll that only targeted the logo's page URL (it errored and fell + * through to normal navigation). Both were dead and have been dropped. */ +(function () { + 'use strict'; -// $(document).ready(function() { -// // Your code here -// console.log("LOADING TOP NAVBAR JS!!!"); -// console.log("navbar-white", "{{navbar_white}}"); -// }); - -// jQuery to collapse the navbar on scroll -$(window).scroll(function() { - if ($(".navbar").offset().top > 50) { - $(".navbar-fixed-top").addClass("top-nav-scrolled"); - } else { - $(".navbar-fixed-top").removeClass("top-nav-scrolled"); + document.addEventListener('DOMContentLoaded', function () { + var toggle = document.querySelector('.navbar-toggle'); + var collapse = document.getElementById('navbar-main-collapse'); + if (!toggle || !collapse) { + return; } -}); - -// jQuery for page scrolling feature - requires jQuery Easing plugin -$(function() { - $('a.page-scroll').bind('click', function(event) { - var $anchor = $(this); - $('html, body').stop().animate({ - scrollTop: $($anchor.attr('href')).offset().top - }, 1500, 'easeInOutExpo'); - event.preventDefault(); + + function isOpen() { + return collapse.classList.contains('in'); + } + + function openMenu() { + collapse.classList.add('in'); + toggle.setAttribute('aria-expanded', 'true'); + } + + function closeMenu() { + collapse.classList.remove('in'); + toggle.setAttribute('aria-expanded', 'false'); + } + + toggle.addEventListener('click', function (event) { + event.preventDefault(); + if (isOpen()) { + closeMenu(); + } else { + openMenu(); + } + }); + + // Close the open mobile menu when a nav link inside it is clicked. + collapse.addEventListener('click', function (event) { + if (isOpen() && event.target.closest('a')) { + closeMenu(); + } }); -}); -// Closes the Responsive Menu on Menu Item Click -$('.navbar-collapse ul li a').click(function() { - $('.navbar-toggle:visible').click(); -}); + // Close the open menu when clicking anywhere outside the navbar. + document.addEventListener('click', function (event) { + if (isOpen() && !event.target.closest('.navbar')) { + closeMenu(); + } + }); + + // Close on Escape and restore focus to the toggle for keyboard users. + document.addEventListener('keydown', function (event) { + if (event.key === 'Escape' && isOpen()) { + closeMenu(); + toggle.focus(); + } + }); + }); +})(); diff --git a/website/templates/website/base.html b/website/templates/website/base.html index 56f2352d..67caee0b 100644 --- a/website/templates/website/base.html +++ b/website/templates/website/base.html @@ -89,7 +89,6 @@ - - {% block external_scripts %}{% endblock %} @@ -151,10 +149,8 @@