From 5d2b096ce18dbefa0e6899cc2a80a5c834e3733a Mon Sep 17 00:00:00 2001 From: Felix Arntz Date: Thu, 16 Sep 2021 14:43:24 -0700 Subject: [PATCH 1/4] Remove jQuery in the frontend for Twenty Fifteen. --- .../themes/twentyfifteen/functions.php | 4 +- .../themes/twentyfifteen/js/functions.js | 188 ++++++++++-------- .../js/keyboard-image-navigation.js | 18 +- 3 files changed, 122 insertions(+), 88 deletions(-) diff --git a/src/wp-content/themes/twentyfifteen/functions.php b/src/wp-content/themes/twentyfifteen/functions.php index 4371cb5ca204d..1581b02e3a4ee 100644 --- a/src/wp-content/themes/twentyfifteen/functions.php +++ b/src/wp-content/themes/twentyfifteen/functions.php @@ -391,10 +391,10 @@ function twentyfifteen_scripts() { } if ( is_singular() && wp_attachment_is_image() ) { - wp_enqueue_script( 'twentyfifteen-keyboard-image-navigation', get_template_directory_uri() . '/js/keyboard-image-navigation.js', array( 'jquery' ), '20141210' ); + wp_enqueue_script( 'twentyfifteen-keyboard-image-navigation', get_template_directory_uri() . '/js/keyboard-image-navigation.js', array(), '20210916' ); } - wp_enqueue_script( 'twentyfifteen-script', get_template_directory_uri() . '/js/functions.js', array( 'jquery' ), '20171218', true ); + wp_enqueue_script( 'twentyfifteen-script', get_template_directory_uri() . '/js/functions.js', array(), '20210916', true ); wp_localize_script( 'twentyfifteen-script', 'screenReaderText', diff --git a/src/wp-content/themes/twentyfifteen/js/functions.js b/src/wp-content/themes/twentyfifteen/js/functions.js index eaa3cac3b4524..e068e3a06584f 100644 --- a/src/wp-content/themes/twentyfifteen/js/functions.js +++ b/src/wp-content/themes/twentyfifteen/js/functions.js @@ -5,71 +5,105 @@ * Contains handlers for navigation and widget area. */ -( function( $ ) { - var $body, $window, $sidebar, resizeTimer, - secondary, button; +( function() { + function domReady( callback ) { + if ( document.readyState === 'complete' || document.readyState === 'interactive' ) { + callback(); + } else { + document.addEventListener( 'DOMContentLoaded', callback ); + } + } + + function toggleClass( element, className ) { + if ( -1 !== element.className.indexOf( className ) ) { + element.className = element.className.replace( ' ' + className, '' ); + } else { + element.className += ' ' + className; + } + } + + var sidebar, resizeTimer, secondary, button; function initMainNavigation( container ) { + if ( ! container ) { + return; + } + // Add dropdown toggle that display child menu items. - container.find( '.menu-item-has-children > a' ).after( '' ); + Array.from( container.querySelectorAll( '.menu-item-has-children > a' ) ).forEach( function( menuLink ) { + var dropdownToggle = document.createElement( 'button' ); + dropdownToggle.className = 'dropdown-toggle'; + dropdownToggle.setAttribute( 'aria-expanded', 'false' ); + dropdownToggle.innerHTML = screenReaderText.expand; + menuLink.parentElement.insertBefore( dropdownToggle, menuLink.nextElementSibling ); + } ); // Toggle buttons and submenu items with active children menu items. - container.find( '.current-menu-ancestor > button' ).addClass( 'toggle-on' ); - container.find( '.current-menu-ancestor > .sub-menu' ).addClass( 'toggled-on' ); - - container.find( '.dropdown-toggle' ).on( 'click', function( e ) { - var _this = $( this ); - e.preventDefault(); - _this.toggleClass( 'toggle-on' ); - _this.next( '.children, .sub-menu' ).toggleClass( 'toggled-on' ); - _this.attr( 'aria-expanded', _this.attr( 'aria-expanded' ) === 'false' ? 'true' : 'false' ); - _this.html( _this.html() === screenReaderText.expand ? screenReaderText.collapse : screenReaderText.expand ); + Array.from( container.querySelectorAll( '.current-menu-ancestor > button, .current-menu-ancestor > .sub-menu' ) ).forEach( function( subItem ) { + subItem.className += 'toggle-on'; + } ); + + Array.from( container.querySelectorAll( '.dropdown-toggle' ) ).forEach( function( dropdownToggle ) { + dropdownToggle.addEventListener( 'click', function( e ) { + e.preventDefault(); + toggleClass( this, 'toggle-on' ); + if ( this.nextElementSibling.tagName === 'UL' || this.nextElementSibling.tagName === 'OL' ) { + toggleClass( this.nextElementSibling, 'toggled-on' ); + } + this.setAttribute( 'aria-expanded', this.getAttribute( 'aria-expanded' ) === 'false' ? 'true' : 'false' ); + this.innerHTML = this.innerHTML === screenReaderText.expand ? screenReaderText.collapse : screenReaderText.expand; + } ); } ); } - initMainNavigation( $( '.main-navigation' ) ); + initMainNavigation( document.querySelector( '.main-navigation' ) ); // Re-initialize the main navigation when it is updated, persisting any existing submenu expanded states. - $( document ).on( 'customize-preview-menu-refreshed', function( e, params ) { - if ( 'primary' === params.wpNavMenuArgs.theme_location ) { - initMainNavigation( params.newContainer ); - - // Re-sync expanded states from oldContainer. - params.oldContainer.find( '.dropdown-toggle.toggle-on' ).each(function() { - var containerId = $( this ).parent().prop( 'id' ); - $( params.newContainer ).find( '#' + containerId + ' > .dropdown-toggle' ).triggerHandler( 'click' ); - }); - } - }); + // This is only relevant for the Customize preview where jQuery is expected to be loaded. + if ( window.jQuery ) { + var $ = window.jQuery; + $( document ).on( 'customize-preview-menu-refreshed', function( e, params ) { + if ( 'primary' === params.wpNavMenuArgs.theme_location ) { + // Extract the raw DOM element from the jQuery wrapper here. + initMainNavigation( params.newContainer[0] ); + + // Re-sync expanded states from oldContainer. + params.oldContainer.find( '.dropdown-toggle.toggle-on' ).each(function() { + var containerId = $( this ).parent().prop( 'id' ); + $( params.newContainer ).find( '#' + containerId + ' > .dropdown-toggle' ).triggerHandler( 'click' ); + }); + } + }); + } - secondary = $( '#secondary' ); - button = $( '.site-branding' ).find( '.secondary-toggle' ); + secondary = document.getElementById( 'secondary' ); + button = document.querySelector( '.site-branding .secondary-toggle' ); // Enable menu toggle for small screens. ( function() { var menu, widgets, social; - if ( ! secondary.length || ! button.length ) { + if ( ! secondary || ! button ) { return; } // Hide button if there are no widgets and the menus are missing or empty. - menu = secondary.find( '.nav-menu' ); - widgets = secondary.find( '#widget-area' ); - social = secondary.find( '#social-navigation' ); - if ( ! widgets.length && ! social.length && ( ! menu.length || ! menu.children().length ) ) { - button.hide(); + menu = secondary.querySelector( '.nav-menu' ); + widgets = secondary.querySelector( '#widget-area' ); + social = secondary.querySelector( '#social-navigation' ); + if ( ! widgets && ! social && ( ! menu || ! menu.children.length ) ) { + button.style.display = 'none'; return; } - button.on( 'click.twentyfifteen', function() { - secondary.toggleClass( 'toggled-on' ); - secondary.trigger( 'resize' ); - $( this ).toggleClass( 'toggled-on' ); - if ( $( this, secondary ).hasClass( 'toggled-on' ) ) { - $( this ).attr( 'aria-expanded', 'true' ); - secondary.attr( 'aria-expanded', 'true' ); + button.addEventListener( 'click', function() { + toggleClass( secondary, 'toggled-on' ); + window.dispatchEvent( new Event( 'resize' ) ); + toggleClass( this, 'toggled-on' ); + if ( -1 !== this.className.indexOf( 'toggled-on' ) && -1 !== secondary.className.indexOf( 'toggled-on' ) ) { + this.setAttribute( 'aria-expanded', 'true' ); + secondary.setAttribute( 'aria-expanded', 'true' ); } else { - $( this ).attr( 'aria-expanded', 'false' ); - secondary.attr( 'aria-expanded', 'false' ); + this.setAttribute( 'aria-expanded', 'false' ); + secondary.setAttribute( 'aria-expanded', 'false' ); } } ); } )(); @@ -77,58 +111,56 @@ /** * Add or remove ARIA attributes. * - * Uses jQuery's width() function to determine the size of the window and add - * the default ARIA attributes for the menu toggle if it's visible. + * Determine the size of the window and add the default ARIA attributes + * for the menu toggle if it's visible. * * @since Twenty Fifteen 1.1 */ function onResizeARIA() { - if ( 955 > $window.width() ) { - button.attr( 'aria-expanded', 'false' ); - secondary.attr( 'aria-expanded', 'false' ); - button.attr( 'aria-controls', 'secondary' ); + if ( 955 > document.documentElement.clientWidth ) { + button.setAttribute( 'aria-expanded', 'false' ); + secondary.setAttribute( 'aria-expanded', 'false' ); + button.setAttribute( 'aria-controls', 'secondary' ); } else { - button.removeAttr( 'aria-expanded' ); - secondary.removeAttr( 'aria-expanded' ); - button.removeAttr( 'aria-controls' ); + button.removeAttribute( 'aria-expanded' ); + secondary.removeAttribute( 'aria-expanded' ); + button.removeAttribute( 'aria-controls' ); } } // Sidebar scrolling. function resizeAndScroll() { - var windowPos = $window.scrollTop(), - windowHeight = $window.height(), - sidebarHeight = $sidebar.height(), - bodyHeight = $body.height(); - - if( 955 < $window.width() && bodyHeight > sidebarHeight && ( windowPos + windowHeight ) >= sidebarHeight ) { - $sidebar.css({ - position: 'fixed', - bottom: sidebarHeight > windowHeight ? 0 : 'auto' - }); + var windowPos = document.documentElement.scrollTop, + windowHeight = document.documentElement.clientHeight, + sidebarHeight = sidebar.clientHeight, + bodyHeight = document.body.clientHeight; + + if( 955 < document.documentElement.clientWidth && bodyHeight > sidebarHeight && ( windowPos + windowHeight ) >= sidebarHeight ) { + sidebar.style.position = 'fixed'; + sidebar.style.bottom = sidebarHeight > windowHeight ? 0 : 'auto'; } else { - $sidebar.css('position', 'relative'); + sidebar.style.position = 'relative'; } } - $( document ).ready( function() { - $body = $( document.body ); - $window = $( window ); - $sidebar = $( '#sidebar' ).first(); - - $window - .on( 'scroll.twentyfifteen', resizeAndScroll ) - .on( 'load.twentyfifteen', onResizeARIA ) - .on( 'resize.twentyfifteen', function() { - clearTimeout( resizeTimer ); - resizeTimer = setTimeout( resizeAndScroll, 500 ); - onResizeARIA(); - } ); - $sidebar.on( 'click.twentyfifteen keydown.twentyfifteen', 'button', resizeAndScroll ); + domReady( function() { + sidebar = document.getElementById( 'sidebar' ); + + window.addEventListener( 'scroll', resizeAndScroll ); + window.addEventListener( 'load', onResizeARIA ); + window.addEventListener( 'resize', function() { + clearTimeout( resizeTimer ); + resizeTimer = setTimeout( resizeAndScroll, 500 ); + onResizeARIA(); + } ); + Array.from( sidebar.getElementsByTagName( 'button' ) ).forEach( function( sidebarButton ) { + sidebarButton.addEventListener( 'click', resizeAndScroll ); + sidebarButton.addEventListener( 'keydown', resizeAndScroll ); + } ); for ( var i = 0; i < 6; i++ ) { setTimeout( resizeAndScroll, 100 * i ); } } ); -} )( jQuery ); +} )(); diff --git a/src/wp-content/themes/twentyfifteen/js/keyboard-image-navigation.js b/src/wp-content/themes/twentyfifteen/js/keyboard-image-navigation.js index a2f8afb42e7df..a4a3b92cf7149 100644 --- a/src/wp-content/themes/twentyfifteen/js/keyboard-image-navigation.js +++ b/src/wp-content/themes/twentyfifteen/js/keyboard-image-navigation.js @@ -2,21 +2,23 @@ * Twenty Fifteen keyboard support for image navigation. */ -( function( $ ) { - $( document ).on( 'keydown.twentyfifteen', function( e ) { +( function() { + document.addEventListener( 'keydown', function( e ) { + var previousEl = document.querySelector( '.nav-previous a' ); + var nextEl = document.querySelector( '.nav-next a' ); var url = false; // Left arrow key code. - if ( e.which === 37 ) { - url = $( '.nav-previous a' ).attr( 'href' ); + if ( e.which === 37 && previousEl ) { + url = previousEl.getAttribute( 'href' ); // Right arrow key code. - } else if ( e.which === 39 ) { - url = $( '.nav-next a' ).attr( 'href' ); + } else if ( e.which === 39 && nextEl ) { + url = nextEl.getAttribute( 'href' ); } - if ( url && ( ! $( 'textarea, input' ).is( ':focus' ) ) ) { + if ( url && document.activeElement && document.activeElement.tagName !== 'INPUT' && document.activeElement.tagName !== 'TEXTAREA' ) { window.location = url; } } ); -} )( jQuery ); +} )(); From aa1df7dafd5999b1bd16231232e5d2961e284add Mon Sep 17 00:00:00 2001 From: Felix Arntz Date: Thu, 17 Feb 2022 15:19:42 -0500 Subject: [PATCH 2/4] Address code review feedback, simplify JS. --- .../themes/twentyfifteen/js/functions.js | 36 ++++++++----------- .../js/keyboard-image-navigation.js | 2 +- 2 files changed, 15 insertions(+), 23 deletions(-) diff --git a/src/wp-content/themes/twentyfifteen/js/functions.js b/src/wp-content/themes/twentyfifteen/js/functions.js index e068e3a06584f..82232e0eb56ee 100644 --- a/src/wp-content/themes/twentyfifteen/js/functions.js +++ b/src/wp-content/themes/twentyfifteen/js/functions.js @@ -14,14 +14,6 @@ } } - function toggleClass( element, className ) { - if ( -1 !== element.className.indexOf( className ) ) { - element.className = element.className.replace( ' ' + className, '' ); - } else { - element.className += ' ' + className; - } - } - var sidebar, resizeTimer, secondary, button; function initMainNavigation( container ) { @@ -30,7 +22,7 @@ } // Add dropdown toggle that display child menu items. - Array.from( container.querySelectorAll( '.menu-item-has-children > a' ) ).forEach( function( menuLink ) { + container.querySelectorAll( '.menu-item-has-children > a' ).forEach( function( menuLink ) { var dropdownToggle = document.createElement( 'button' ); dropdownToggle.className = 'dropdown-toggle'; dropdownToggle.setAttribute( 'aria-expanded', 'false' ); @@ -39,16 +31,16 @@ } ); // Toggle buttons and submenu items with active children menu items. - Array.from( container.querySelectorAll( '.current-menu-ancestor > button, .current-menu-ancestor > .sub-menu' ) ).forEach( function( subItem ) { - subItem.className += 'toggle-on'; + container.querySelectorAll( '.current-menu-ancestor > button, .current-menu-ancestor > .sub-menu' ).forEach( function( subItem ) { + subItem.classList.add( 'toggle-on' ); } ); - Array.from( container.querySelectorAll( '.dropdown-toggle' ) ).forEach( function( dropdownToggle ) { + container.querySelectorAll( '.dropdown-toggle' ).forEach( function( dropdownToggle ) { dropdownToggle.addEventListener( 'click', function( e ) { e.preventDefault(); - toggleClass( this, 'toggle-on' ); - if ( this.nextElementSibling.tagName === 'UL' || this.nextElementSibling.tagName === 'OL' ) { - toggleClass( this.nextElementSibling, 'toggled-on' ); + this.classList.toggle( 'toggle-on' ); + if ( this.nextElementSibling && this.nextElementSibling.matches( '.children, .sub-menu' ) { + this.nextElementSibling.classList.toggle( 'toggled-on' ); } this.setAttribute( 'aria-expanded', this.getAttribute( 'aria-expanded' ) === 'false' ? 'true' : 'false' ); this.innerHTML = this.innerHTML === screenReaderText.expand ? screenReaderText.collapse : screenReaderText.expand; @@ -62,7 +54,7 @@ if ( window.jQuery ) { var $ = window.jQuery; $( document ).on( 'customize-preview-menu-refreshed', function( e, params ) { - if ( 'primary' === params.wpNavMenuArgs.theme_location ) { + if ( params.wpNavMenuArgs.theme_location === 'primary' ) { // Extract the raw DOM element from the jQuery wrapper here. initMainNavigation( params.newContainer[0] ); @@ -95,10 +87,10 @@ } button.addEventListener( 'click', function() { - toggleClass( secondary, 'toggled-on' ); + secondary.classList.toggle( 'toggled-on' ); window.dispatchEvent( new Event( 'resize' ) ); - toggleClass( this, 'toggled-on' ); - if ( -1 !== this.className.indexOf( 'toggled-on' ) && -1 !== secondary.className.indexOf( 'toggled-on' ) ) { + this.classList.toggle( 'toggled-on' ); + if ( -1 !== this.classList.contains( 'toggled-on' ) && -1 !== secondary.classList.contains( 'toggled-on' ) ) { this.setAttribute( 'aria-expanded', 'true' ); secondary.setAttribute( 'aria-expanded', 'true' ); } else { @@ -117,7 +109,7 @@ * @since Twenty Fifteen 1.1 */ function onResizeARIA() { - if ( 955 > document.documentElement.clientWidth ) { + if ( document.documentElement.clientWidth < 955 ) { button.setAttribute( 'aria-expanded', 'false' ); secondary.setAttribute( 'aria-expanded', 'false' ); button.setAttribute( 'aria-controls', 'secondary' ); @@ -135,7 +127,7 @@ sidebarHeight = sidebar.clientHeight, bodyHeight = document.body.clientHeight; - if( 955 < document.documentElement.clientWidth && bodyHeight > sidebarHeight && ( windowPos + windowHeight ) >= sidebarHeight ) { + if( document.documentElement.clientWidth > 955 && bodyHeight > sidebarHeight && ( windowPos + windowHeight ) >= sidebarHeight ) { sidebar.style.position = 'fixed'; sidebar.style.bottom = sidebarHeight > windowHeight ? 0 : 'auto'; } else { @@ -153,7 +145,7 @@ resizeTimer = setTimeout( resizeAndScroll, 500 ); onResizeARIA(); } ); - Array.from( sidebar.getElementsByTagName( 'button' ) ).forEach( function( sidebarButton ) { + sidebar.getElementsByTagName( 'button' ).forEach( function( sidebarButton ) { sidebarButton.addEventListener( 'click', resizeAndScroll ); sidebarButton.addEventListener( 'keydown', resizeAndScroll ); } ); diff --git a/src/wp-content/themes/twentyfifteen/js/keyboard-image-navigation.js b/src/wp-content/themes/twentyfifteen/js/keyboard-image-navigation.js index a4a3b92cf7149..8bb05ab3f5edb 100644 --- a/src/wp-content/themes/twentyfifteen/js/keyboard-image-navigation.js +++ b/src/wp-content/themes/twentyfifteen/js/keyboard-image-navigation.js @@ -17,7 +17,7 @@ url = nextEl.getAttribute( 'href' ); } - if ( url && document.activeElement && document.activeElement.tagName !== 'INPUT' && document.activeElement.tagName !== 'TEXTAREA' ) { + if ( url && document.activeElement && ! document.activeElement.matches( 'input, textarea' ) ) { window.location = url; } } ); From 8304919d7b59a8174e34c94bd8d476dfaa50870c Mon Sep 17 00:00:00 2001 From: Felix Arntz Date: Thu, 17 Feb 2022 15:38:07 -0500 Subject: [PATCH 3/4] Update script version. --- src/wp-content/themes/twentyfifteen/functions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-content/themes/twentyfifteen/functions.php b/src/wp-content/themes/twentyfifteen/functions.php index 1581b02e3a4ee..2731c9fda6543 100644 --- a/src/wp-content/themes/twentyfifteen/functions.php +++ b/src/wp-content/themes/twentyfifteen/functions.php @@ -394,7 +394,7 @@ function twentyfifteen_scripts() { wp_enqueue_script( 'twentyfifteen-keyboard-image-navigation', get_template_directory_uri() . '/js/keyboard-image-navigation.js', array(), '20210916' ); } - wp_enqueue_script( 'twentyfifteen-script', get_template_directory_uri() . '/js/functions.js', array(), '20210916', true ); + wp_enqueue_script( 'twentyfifteen-script', get_template_directory_uri() . '/js/functions.js', array(), '20220217', true ); wp_localize_script( 'twentyfifteen-script', 'screenReaderText', From c3b70465132d26c16e70e015088d85bec28d6ca2 Mon Sep 17 00:00:00 2001 From: Felix Arntz Date: Thu, 17 Feb 2022 15:39:39 -0500 Subject: [PATCH 4/4] Fix JS error. --- src/wp-content/themes/twentyfifteen/js/functions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-content/themes/twentyfifteen/js/functions.js b/src/wp-content/themes/twentyfifteen/js/functions.js index 82232e0eb56ee..43e757f863a29 100644 --- a/src/wp-content/themes/twentyfifteen/js/functions.js +++ b/src/wp-content/themes/twentyfifteen/js/functions.js @@ -39,7 +39,7 @@ dropdownToggle.addEventListener( 'click', function( e ) { e.preventDefault(); this.classList.toggle( 'toggle-on' ); - if ( this.nextElementSibling && this.nextElementSibling.matches( '.children, .sub-menu' ) { + if ( this.nextElementSibling && this.nextElementSibling.matches( '.children, .sub-menu' ) ) { this.nextElementSibling.classList.toggle( 'toggled-on' ); } this.setAttribute( 'aria-expanded', this.getAttribute( 'aria-expanded' ) === 'false' ? 'true' : 'false' );