From 8e262a783bf03d24bbf1724469b6d33bec4be0bc Mon Sep 17 00:00:00 2001 From: Felix Arntz Date: Thu, 16 Sep 2021 14:45:35 -0700 Subject: [PATCH 1/4] Remove jQuery in the frontend for Twenty Twelve. --- .../themes/twentytwelve/functions.php | 2 +- .../themes/twentytwelve/js/navigation.js | 85 +++++++++++++------ 2 files changed, 62 insertions(+), 25 deletions(-) diff --git a/src/wp-content/themes/twentytwelve/functions.php b/src/wp-content/themes/twentytwelve/functions.php index a4df147cb2640..ed74b5b489d8d 100644 --- a/src/wp-content/themes/twentytwelve/functions.php +++ b/src/wp-content/themes/twentytwelve/functions.php @@ -199,7 +199,7 @@ function twentytwelve_scripts_styles() { } // Adds JavaScript for handling the navigation menu hide-and-show behavior. - wp_enqueue_script( 'twentytwelve-navigation', get_template_directory_uri() . '/js/navigation.js', array( 'jquery' ), '20141205', true ); + wp_enqueue_script( 'twentytwelve-navigation', get_template_directory_uri() . '/js/navigation.js', array(), '20210916', true ); $font_url = twentytwelve_get_font_url(); if ( ! empty( $font_url ) ) { diff --git a/src/wp-content/themes/twentytwelve/js/navigation.js b/src/wp-content/themes/twentytwelve/js/navigation.js index f7141bff7eefa..6411c20e0d1c6 100644 --- a/src/wp-content/themes/twentytwelve/js/navigation.js +++ b/src/wp-content/themes/twentytwelve/js/navigation.js @@ -3,6 +3,40 @@ * accessibility for submenu items. */ ( function() { + function getParentElements( element, selector ) { + var parentElements = []; + + while ( element.parentElement !== null ) { + if ( ! selector || element.parentElement.matches( selector ) ) { + parentElements.push( element.parentElement ); + } + + element = element.parentElement; + } + + return parentElements; + } + + function getSiblingElements( element, selector ) { + var siblingElements = []; + + Array.from( element.parentElement.children ).forEach( function( sibling ) { + if ( sibling !== element && ( ! selector || sibling.matches( selector ) ) ) { + siblingElements.push( sibling ); + } + } ); + + return siblingElements; + } + + function toggleClass( element, className ) { + if ( -1 !== element.className.indexOf( className ) ) { + element.className = element.className.replace( ' ' + className, '' ); + } else { + element.className += ' ' + className; + } + } + var nav = document.getElementById( 'site-navigation' ), button, menu; if ( ! nav ) { return; @@ -25,31 +59,34 @@ menu.className = 'nav-menu'; } - if ( -1 !== button.className.indexOf( 'toggled-on' ) ) { - button.className = button.className.replace( ' toggled-on', '' ); - menu.className = menu.className.replace( ' toggled-on', '' ); - } else { - button.className += ' toggled-on'; - menu.className += ' toggled-on'; - } + toggleClass( button, 'toggled-on' ); + toggleClass( menu, 'toggled-on' ); }; -} )(); -// Better focus for hidden submenu items for accessibility. -( function( $ ) { - $( '.main-navigation' ).find( 'a' ).on( 'focus.twentytwelve blur.twentytwelve', function() { - $( this ).parents( '.menu-item, .page_item' ).toggleClass( 'focus' ); + // Better focus for hidden submenu items for accessibility. + function toggleParentsFocusClass() { + getParentElements( this, '.menu-item, .page_item' ).forEach( function( parentElement ) { + toggleClass( parentElement, 'focus' ); + } ); + } + Array.from( document.querySelector( '.main-navigation' ).getElementsByTagName( 'a' ) ).forEach( function( menuLink ) { + menuLink.addEventListener( 'focus', toggleParentsFocusClass ); + menuLink.addEventListener( 'blur', toggleParentsFocusClass ); } ); - if ( 'ontouchstart' in window ) { - $('body').on( 'touchstart.twentytwelve', '.menu-item-has-children > a, .page_item_has_children > a', function( e ) { - var el = $( this ).parent( 'li' ); - - if ( ! el.hasClass( 'focus' ) ) { - e.preventDefault(); - el.toggleClass( 'focus' ); - el.siblings( '.focus').removeClass( 'focus' ); - } - } ); - } -} )( jQuery ); + if ( 'ontouchstart' in window ) { + Array.from( document.querySelectorAll( '.menu-item-has-children > a, .page_item_has_children > a' ) ).forEach( function( menuLink ) { + menuLink.addEventListener( 'touchstart', function( e ) { + var el = getParentElements( this, 'li' )[0]; + + if ( -1 === el.className.indexOf( 'focus' ) ) { + e.preventDefault(); + el.className += ' focus'; + getSiblingElements( el, '.focus' ).forEach( function( siblingElement ) { + siblingElement.className.replace( ' focus', '' ); + } ); + } + } ); + } ); + } +} )(); From dfacf4358979d8376b3bfb2aed02d4f6dfb4acbc Mon Sep 17 00:00:00 2001 From: Felix Arntz Date: Thu, 17 Feb 2022 15:36:50 -0500 Subject: [PATCH 2/4] Address code review feedback, simplify JS. --- .../themes/twentytwelve/js/navigation.js | 43 +++++++++++-------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/src/wp-content/themes/twentytwelve/js/navigation.js b/src/wp-content/themes/twentytwelve/js/navigation.js index 6411c20e0d1c6..181084765a874 100644 --- a/src/wp-content/themes/twentytwelve/js/navigation.js +++ b/src/wp-content/themes/twentytwelve/js/navigation.js @@ -20,7 +20,7 @@ function getSiblingElements( element, selector ) { var siblingElements = []; - Array.from( element.parentElement.children ).forEach( function( sibling ) { + element.parentElement.children.forEach( function( sibling ) { if ( sibling !== element && ( ! selector || sibling.matches( selector ) ) ) { siblingElements.push( sibling ); } @@ -29,14 +29,6 @@ return siblingElements; } - function toggleClass( element, className ) { - if ( -1 !== element.className.indexOf( className ) ) { - element.className = element.className.replace( ' ' + className, '' ); - } else { - element.className += ' ' + className; - } - } - var nav = document.getElementById( 'site-navigation' ), button, menu; if ( ! nav ) { return; @@ -55,35 +47,50 @@ } button.onclick = function() { - if ( -1 === menu.className.indexOf( 'nav-menu' ) ) { + if ( ! menu.classList.contains( 'nav-menu' ) ) { menu.className = 'nav-menu'; } - toggleClass( button, 'toggled-on' ); - toggleClass( menu, 'toggled-on' ); + button.classList.toggle( 'toggled-on' ); + menu.classList.toggle( 'toggled-on' ); }; // Better focus for hidden submenu items for accessibility. function toggleParentsFocusClass() { getParentElements( this, '.menu-item, .page_item' ).forEach( function( parentElement ) { - toggleClass( parentElement, 'focus' ); + parentElement.classList.toggle( 'focus' ); } ); } - Array.from( document.querySelector( '.main-navigation' ).getElementsByTagName( 'a' ) ).forEach( function( menuLink ) { + document.querySelector( '.main-navigation' ).getElementsByTagName( 'a' ).forEach( function( menuLink ) { menuLink.addEventListener( 'focus', toggleParentsFocusClass ); menuLink.addEventListener( 'blur', toggleParentsFocusClass ); } ); if ( 'ontouchstart' in window ) { - Array.from( document.querySelectorAll( '.menu-item-has-children > a, .page_item_has_children > a' ) ).forEach( function( menuLink ) { + document.body.addEventListener( 'touchstart', function( e ) { + for ( var target = e.target; target && target != this; target = target.parentNode ) { + if ( target.matches( '.menu-item-has-children > a, .page_item_has_children > a' ) ) { + var el = getParentElements( target, 'li' )[0]; + if ( el.classList.contains( 'focus' ) ) { + e.preventDefault(); + el.classList.add( 'focus' ); + getSiblingElements( el, '.focus' ).forEach( function( siblingElement ) { + siblingElement.classList.remove( 'focus' ); + } ); + } + break; + } + } + } ); + document.querySelectorAll( '.menu-item-has-children > a, .page_item_has_children > a' ).forEach( function( menuLink ) { menuLink.addEventListener( 'touchstart', function( e ) { var el = getParentElements( this, 'li' )[0]; - if ( -1 === el.className.indexOf( 'focus' ) ) { + if ( el.classList.contains( 'focus' ) ) { e.preventDefault(); - el.className += ' focus'; + el.classList.add( 'focus' ); getSiblingElements( el, '.focus' ).forEach( function( siblingElement ) { - siblingElement.className.replace( ' focus', '' ); + siblingElement.classList.remove( 'focus' ); } ); } } ); From 36962d0488a46c2a5dfe3eb98553fbe296dbcacd Mon Sep 17 00:00:00 2001 From: Felix Arntz Date: Thu, 17 Feb 2022 15:37:27 -0500 Subject: [PATCH 3/4] Update script version. --- src/wp-content/themes/twentytwelve/functions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-content/themes/twentytwelve/functions.php b/src/wp-content/themes/twentytwelve/functions.php index 2fa8cf7a21e16..cc050cf447b14 100644 --- a/src/wp-content/themes/twentytwelve/functions.php +++ b/src/wp-content/themes/twentytwelve/functions.php @@ -199,7 +199,7 @@ function twentytwelve_scripts_styles() { } // Adds JavaScript for handling the navigation menu hide-and-show behavior. - wp_enqueue_script( 'twentytwelve-navigation', get_template_directory_uri() . '/js/navigation.js', array(), '20210916', true ); + wp_enqueue_script( 'twentytwelve-navigation', get_template_directory_uri() . '/js/navigation.js', array(), '20220217', true ); $font_url = twentytwelve_get_font_url(); if ( ! empty( $font_url ) ) { From 4738656583f96580e5aa18d1b6bf4f62a61d64ef Mon Sep 17 00:00:00 2001 From: adamsilverstein Date: Mon, 6 Jul 2026 12:47:13 -0700 Subject: [PATCH 4/4] Twenty Twelve: Fix runtime bugs in vanilla JS navigation script. - Iterate HTMLCollection with a for loop in getSiblingElements() and use querySelectorAll() for menu links, as HTMLCollection has no forEach and both calls threw a TypeError, breaking the whole script. - Restore the negated focus check in the touchstart handler so the first tap on a parent menu item opens the submenu instead of navigating immediately, matching the original jQuery behavior. - Drop the duplicate per-link touchstart listeners in favor of the single delegated handler, which also covers dynamically added items. - Register the delegated touchstart listener as non-passive so preventDefault() works; browsers default to passive touch listeners on body. --- .../themes/twentytwelve/functions.php | 2 +- .../themes/twentytwelve/js/navigation.js | 37 +++++++------------ 2 files changed, 15 insertions(+), 24 deletions(-) diff --git a/src/wp-content/themes/twentytwelve/functions.php b/src/wp-content/themes/twentytwelve/functions.php index d3dd62b02abed..36655a7c1e718 100644 --- a/src/wp-content/themes/twentytwelve/functions.php +++ b/src/wp-content/themes/twentytwelve/functions.php @@ -202,7 +202,7 @@ function twentytwelve_scripts_styles() { 'twentytwelve-navigation', get_template_directory_uri() . '/js/navigation.js', array(), - '20260705', + '20260706', array( 'in_footer' => false, // Because involves header. 'strategy' => 'defer', diff --git a/src/wp-content/themes/twentytwelve/js/navigation.js b/src/wp-content/themes/twentytwelve/js/navigation.js index f52b3b9d86b91..6055b55784567 100644 --- a/src/wp-content/themes/twentytwelve/js/navigation.js +++ b/src/wp-content/themes/twentytwelve/js/navigation.js @@ -18,13 +18,15 @@ } function getSiblingElements( element, selector ) { - var siblingElements = []; + var siblingElements = [], + children = element.parentElement.children, + i; - element.parentElement.children.forEach( function( sibling ) { - if ( sibling !== element && ( ! selector || sibling.matches( selector ) ) ) { - siblingElements.push( sibling ); + for ( i = 0; i < children.length; i++ ) { + if ( children[ i ] !== element && ( ! selector || children[ i ].matches( selector ) ) ) { + siblingElements.push( children[ i ] ); } - } ); + } return siblingElements; } @@ -70,17 +72,19 @@ parentElement.classList.toggle( 'focus' ); } ); } - document.querySelector( '.main-navigation' ).getElementsByTagName( 'a' ).forEach( function( menuLink ) { + nav.querySelectorAll( 'a' ).forEach( function( menuLink ) { menuLink.addEventListener( 'focus', toggleParentsFocusClass ); menuLink.addEventListener( 'blur', toggleParentsFocusClass ); } ); + // Use event delegation so the handler also covers dynamically added menu items. if ( 'ontouchstart' in window ) { document.body.addEventListener( 'touchstart', function( e ) { - for ( var target = e.target; target && target != this; target = target.parentNode ) { + var target, el; + for ( target = e.target; target && target !== this; target = target.parentNode ) { if ( target.matches( '.menu-item-has-children > a, .page_item_has_children > a' ) ) { - var el = getParentElements( target, 'li' )[0]; - if ( el.classList.contains( 'focus' ) ) { + el = getParentElements( target, 'li' )[0]; + if ( el && ! el.classList.contains( 'focus' ) ) { e.preventDefault(); el.classList.add( 'focus' ); getSiblingElements( el, '.focus' ).forEach( function( siblingElement ) { @@ -90,19 +94,6 @@ break; } } - } ); - document.querySelectorAll( '.menu-item-has-children > a, .page_item_has_children > a' ).forEach( function( menuLink ) { - menuLink.addEventListener( 'touchstart', function( e ) { - var el = getParentElements( this, 'li' )[0]; - - if ( el.classList.contains( 'focus' ) ) { - e.preventDefault(); - el.classList.add( 'focus' ); - getSiblingElements( el, '.focus' ).forEach( function( siblingElement ) { - siblingElement.classList.remove( 'focus' ); - } ); - } - } ); - } ); + }, { passive: false } ); // Explicitly non-passive, as browsers default to passive touch listeners on body. } } )();