Changeset 357931
- Timestamp:
- 11/08/2026 01:47:36 AM (68 minutes ago)
- Location:
- news-box-plus/1.0.9
- Files:
-
- 2 added
- 7 edited
- 1 copied
-
. (copied) (copied from news-box-plus/1.0.7 )
-
assets/css/main.css (modified) (1 diff)
-
assets/css/mobile-menu.css (added)
-
assets/js/mobile-menu.js (modified) (1 diff)
-
functions.php (modified) (2 diffs)
-
header.php (modified) (1 diff)
-
inc/latest-bar-menu.php (modified) (2 diffs)
-
readme.txt (modified) (2 diffs)
-
sidebar.php (added)
-
style.css (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
news-box-plus/1.0.9/assets/css/main.css
r344112 r357931 649 649 650 650 } 651 652 /* ========================================================================== 653 Header Logo & Navigation Spacing Rule (Collision Prevention - Rule #7) 654 Ensures at least 30-40px gap between logo and menu so they never touch. 655 ========================================================================== */ 656 @media (min-width: 992px) { 657 .menubar-content, 658 .pxm-style1 .navigation .d-flex, 659 .pxm-style2 .navigation .d-flex, 660 .navigation .d-flex, 661 .site-header .d-flex, 662 .header-main-wrapper .d-flex, 663 .realestate-press-container.menu-inner, 664 .headtop-items, 665 .topnav-serch, 666 .nxbox-menu-bar, 667 .header-middle .row { 668 gap: 35px; 669 } 670 671 .head-logo-sec, 672 .pxms1-logo, 673 .site-branding.brand-logo, 674 .site-branding.brand-text, 675 .menubar-content .head-logo-sec, 676 .header-logo-wrap, 677 .sm-logo, 678 .site-branding.news-box-logo, 679 .site-branding { 680 flex-shrink: 0; 681 margin-right: 30px; 682 } 683 684 .main-navigation, 685 .pxms1-menu, 686 .realestate-press-container.menu-inner, 687 .topnav-serch .navbar, 688 .nxbox-menu-bar .main-navigation { 689 min-width: 0; 690 } 691 } 692 693 /* ========================================================================== 694 Blog List Spacing & Badge Inline Styling (Rule #9) 695 ========================================================================== */ 696 /* Spacing between featured image and text in list / card blog */ 697 .card.flex-md-row, 698 .card-view .card, 699 .blog-list-item, 700 .post-list, 701 .article-item, 702 .post-card { 703 gap: 20px; 704 } 705 .card-img-left, 706 .content-img, 707 .post-card-img, 708 .entry-media { 709 margin-right: 20px; 710 } 711 712 /* Ensure blog badges and action buttons keep proper inline sizing */ 713 .blog-all-details, 714 .entry-content, 715 .post-content, 716 .card-body { 717 display: flex; 718 flex-direction: column; 719 align-items: flex-start; 720 } 721 722 .blog-scat, 723 .cat-links, 724 .category-badge, 725 .main-btn, 726 .read-more, 727 .more-link, 728 .post-categories a, 729 .cat-links a, 730 .entry-footer a { 731 align-self: flex-start !important; 732 width: auto !important; 733 max-width: max-content !important; 734 display: inline-block !important; 735 } 736 737 /* ========================================================================== 738 Desktop Navigation Flex-Flow & Word-Wrap Preservation (Rule #10) 739 Prevents menu items from breaking words vertically when there are many items. 740 Items wrap cleanly to new lines with full words preserved. 741 ========================================================================== */ 742 @media (min-width: 992px) { 743 .header-top .headtop-items { 744 display: flex; 745 flex-flow: row wrap; 746 align-items: center; 747 justify-content: space-between; 748 } 749 750 .header-top .topnav-serch { 751 display: flex; 752 flex-flow: row wrap; 753 align-items: center; 754 justify-content: flex-end; 755 min-width: 0; 756 flex: 1 1 auto; 757 } 758 759 .header-top .navbar, 760 .topnav-serch .navbar { 761 padding: 0; 762 min-width: 0; 763 flex: 1 1 auto; 764 } 765 766 .header-top .navbar-collapse, 767 .topnav-serch .navbar-collapse { 768 min-width: 0; 769 } 770 771 /* Desktop menu flex-flow row wrap */ 772 .header-top .navbar-nav, 773 #primary-menu.navbar-nav, 774 .navbar-nav.ml-auto, 775 .navbar-nav, 776 .main-navigation ul, 777 .news-box-menu, 778 .realestate-press-menu, 779 .car-expert-menu { 780 display: flex !important; 781 flex-flow: row wrap !important; 782 align-items: center; 783 list-style: none; 784 margin: 0; 785 padding: 0; 786 } 787 788 /* Prevent words from breaking across letters within menu items */ 789 .header-top .navbar-nav > li, 790 #primary-menu.navbar-nav > li, 791 .navbar-nav > li, 792 .main-navigation ul > li, 793 .news-box-menu > li, 794 .realestate-press-menu > li, 795 .car-expert-menu > li { 796 flex-shrink: 0 !important; 797 white-space: nowrap !important; 798 word-break: normal !important; 799 overflow-wrap: normal !important; 800 } 801 802 .header-top .navbar-nav > li > a, 803 #primary-menu.navbar-nav > li > a, 804 .navbar-nav > li > a, 805 .navbar-nav .nav-link, 806 .main-navigation ul > li > a, 807 .news-box-menu > li > a, 808 .realestate-press-menu > li > a, 809 .car-expert-menu > li > a { 810 white-space: nowrap !important; 811 word-break: normal !important; 812 overflow-wrap: normal !important; 813 display: block; 814 } 815 816 /* Dropdown Submenus: keep vertical flow */ 817 .header-top .navbar-nav .dropdown-menu, 818 .navbar-nav .dropdown-menu, 819 .main-navigation ul ul, 820 .news-box-menu ul, 821 .realestate-press-menu ul { 822 flex-direction: column !important; 823 flex-wrap: nowrap !important; 824 } 825 826 .header-top .navbar-nav .dropdown-menu > li > a, 827 .navbar-nav .dropdown-menu > li > a, 828 .main-navigation ul ul > li > a, 829 .news-box-menu ul > li > a, 830 .realestate-press-menu ul > li > a { 831 white-space: nowrap !important; 832 } 833 } 834 835 /* Universal mobile suppression of legacy navbar toggle & dropdowns (Rule #8) */ 836 @media screen and (max-width: 991px) { 837 button.navbar-toggler:not(#mmenu-btn), 838 button.menu-toggle:not(#mmenu-btn), 839 .navbar-toggler:not(#mmenu-btn), 840 .navbar button, 841 nav.navbar button, 842 .navbar-toggler { 843 display: none !important; 844 } 845 .topnav-serch .navbar, 846 .topnav-serch #navbar-content, 847 .header-top .navbar, 848 .nxbox-menu-bar, 849 .header-middle .news-box-logo, 850 .header-middle .site-branding, 851 .menu-deskbar, 852 .realestate-press-logo-section { 853 display: none !important; 854 } 855 } -
news-box-plus/1.0.9/assets/js/mobile-menu.js
r196842 r357931 1 1 /** 2 * Script for mobile menu2 * Accessible Mobile Menu with Focus Trap & Dropdown Toggles 3 3 * 4 * Handles toggling the navigation menu for small screens and enables TAB key 5 * navigation support for dropdown menus. 4 * Features: 5 * - Topbar with logo and hamburger button 6 * - Slide-in panel with close button and logo 7 * - Dropdown toggle buttons with chevron icons injected for parent menu items 8 * - Clean 2-way click toggle: 1st click opens submenu, 2nd click collapses submenu 9 * - Smooth rotation on chevron icon 10 * - Full keyboard accessibility (Tab, Shift+Tab, Escape, Arrow keys, Enter/Space) 11 * - Focus trap: when menu is open, keyboard focus stays inside panel 12 * - ARIA state management (aria-expanded, aria-controls, aria-label) 13 * - Overlay backdrop closes menu on click 14 * - Body scroll lock when menu is open 15 * - Supports nested submenus at any depth 6 16 */ 7 17 8 9 (function(){ 10 // select all variable 11 const smButton = document.getElementById('mmenu-btn'); 12 const smMenu = document.getElementById('mobile-navigation'); 13 14 if( !smMenu ){ 15 return; 16 } 17 18 const smOpen = smMenu.querySelector('.mopen'); 19 const smClose = smMenu.querySelector('.mclose'); 20 smClose.style.display = 'none'; 21 22 // button click event 23 smButton.addEventListener('click', function( ){ 24 smMenu.classList.toggle( 'menu-active' ); 25 26 27 if( smButton.getAttribute('aria-expanded') === 'true' ){ 28 smButton.setAttribute('aria-expanded', 'false'); 29 smClose.style.display = 'none'; 30 smOpen.style.display = 'block'; 31 }else{ 32 smButton.setAttribute('aria-expanded','true'); 33 smClose.style.display = 'block'; 34 smOpen.style.display = 'none'; 35 } 36 37 }); // Click event end 38 39 // set outside the menu area 40 document.addEventListener('click',function(e){ 41 const isInsideMenu = smMenu.contains(e.target); 42 43 if( ! isInsideMenu){ 44 smMenu.classList.remove('menu-active'); 45 smButton.setAttribute('aria-expanded','false'); 46 smClose.style.display = 'none'; 47 smOpen.style.display = 'block'; 48 } 49 50 }) 51 52 // add Icon has Children item 53 54 //const linkHasSub = smMenu.querySelectorAll('.menu-item-has-children > a, .page_item_has_children > a'); 55 const linkHasSub = smMenu.querySelectorAll('.menu-item-has-children > .sub-menu, .page_item_has_children > .sub-menu'); 56 57 58 for (const child of linkHasSub) { 59 var icon = document.createElement('i'); 60 icon.className = 'fas fa-chevron-down'; 61 child.parentNode.insertBefore(icon, child); 62 63 } 64 65 const subMenuIcon = smMenu.querySelectorAll('.menu-item-has-children > i , .page_item_has_children > i'); 66 67 for (const iconset of subMenuIcon) { 68 iconset.setAttribute('tabindex','0'); 69 70 } 71 72 const linksWithChildren = smMenu.querySelectorAll( '.menu-item-has-children > a, .page_item_has_children > a' ); 73 74 for ( const link of subMenuIcon ) { 75 link.addEventListener( 'click', toggleClick, true ); 76 link.addEventListener( 'focus', toggleFocus, true ); 77 // link.addEventListener( 'blur', toggleblur, true ); 78 } 79 80 function toggleFocus(e){ 81 82 if( ! this.parentNode.classList.contains('focus')){ 83 this.parentNode.classList.add('focus'); 84 this.parentNode.classList.remove('clicked'); 85 } 86 87 } 88 function toggleblur(e){ 89 const firstLiA = smMenu.querySelctorAll('#wsm-menu >li a'); 90 91 const firstLiaBlur = firstLiA.contains(e.target); 92 console.log(firstLiA); 93 94 if(firstLiaBlur){ 95 96 this.parentNode.classList.remove('focus'); 97 }else{ 98 this.parentNode.classList.add('focus'); 99 } 100 101 102 } 103 function toggleClick(e){ 104 105 if( this.parentNode.classList.contains('clicked')){ 106 this.parentNode.classList.remove('clicked'); 107 }else{ 108 this.parentNode.classList.add('clicked'); 109 this.parentNode.classList.remove('focus'); 110 } 111 112 } 113 114 focusableInNav = smMenu.querySelectorAll('button, [href], [tabindex]:not([tabindex="-1"])'); 115 116 117 let firstFocusElement = focusableInNav[0]; 118 let lestFocusElement = focusableInNav[focusableInNav.length - 1]; 119 120 firstFocusElement.addEventListener( 'keydown', moveFocusToBottom, true ); 121 lestFocusElement.addEventListener( 'keydown', moveFocusToTop, true ); 122 123 function moveFocusToBottom(e) { 124 if (e.key === "Tab" && e.shiftKey) { 125 e.preventDefault(); 126 lestFocusElement.focus() 127 } 128 } 129 function moveFocusToTop(e) { 130 if (e.key === "Tab" && !e.shiftKey) { 131 e.preventDefault(); 132 firstFocusElement.focus(); 133 } 134 } 135 136 137 138 139 }()) 18 (function () { 19 'use strict'; 20 21 // Prevent duplicate script execution across multiple enqueues 22 if (window.__wsmMobileMenuLoaded) { 23 return; 24 } 25 window.__wsmMobileMenuLoaded = true; 26 27 // Elements 28 var menuBar = document.getElementById('wsm-menu'); 29 var openBtn = document.getElementById('mmenu-btn'); 30 var closeBtn = document.getElementById('mmenu-close-btn'); 31 var panel = document.getElementById('mobile-menu-panel'); 32 var overlay = document.getElementById('mobile-menu-overlay'); 33 34 if (!menuBar || !openBtn || !panel) { 35 return; 36 } 37 38 var isMenuOpen = false; 39 40 // Chevron SVG (down arrow) 41 var CHEVRON_SVG = 42 '<svg class="toggle-icon" width="18" height="18" viewBox="0 0 24 24" ' + 43 'fill="none" xmlns="http://www.w3.org/2000/svg" focusable="false">' + 44 '<path d="M6 9l6 6 6-6" stroke="currentColor" stroke-width="2" ' + 45 'stroke-linecap="round" stroke-linejoin="round"/></svg>'; 46 47 // ------------------------------------------------------- 48 // Focus-trap helpers 49 // ------------------------------------------------------- 50 var FOCUSABLE_SELECTOR = 51 'a[href]:not([disabled]):not([tabindex="-1"]), ' + 52 'button:not([disabled]):not([tabindex="-1"]), ' + 53 'textarea:not([disabled]):not([tabindex="-1"]), ' + 54 'input:not([disabled]):not([tabindex="-1"]), ' + 55 'select:not([disabled]):not([tabindex="-1"]), ' + 56 '[tabindex]:not([tabindex="-1"])'; 57 58 function getFocusableElements() { 59 if (!panel) return []; 60 var all = panel.querySelectorAll(FOCUSABLE_SELECTOR); 61 var visible = []; 62 for (var i = 0; i < all.length; i++) { 63 if (all[i].offsetParent !== null) { 64 visible.push(all[i]); 65 } 66 } 67 return visible; 68 } 69 70 function getDirectSubmenu(parentItem) { 71 if (!parentItem) return null; 72 var children = parentItem.children; 73 for (var i = 0; i < children.length; i++) { 74 var child = children[i]; 75 var tag = child.tagName ? child.tagName.toLowerCase() : ''; 76 if (tag === 'ul' || (child.classList && (child.classList.contains('sub-menu') || child.classList.contains('children')))) { 77 return child; 78 } 79 } 80 return null; 81 } 82 83 // ------------------------------------------------------- 84 // Inject dropdown toggle buttons 85 // ------------------------------------------------------- 86 function injectDropdownToggles() { 87 var parents = panel.querySelectorAll( 88 '.menu-item-has-children, .page_item_has_children' 89 ); 90 91 for (var i = 0; i < parents.length; i++) { 92 // Skip if already has a toggle button 93 if (parents[i].querySelector('.submenu-toggle')) { 94 continue; 95 } 96 97 var link = parents[i].querySelector('a'); 98 if (!link) continue; 99 100 // Get menu text for aria-label 101 var menuText = link.textContent.trim(); 102 103 // Create toggle button 104 var toggleBtn = document.createElement('button'); 105 toggleBtn.className = 'submenu-toggle'; 106 toggleBtn.setAttribute('type', 'button'); 107 toggleBtn.setAttribute('aria-expanded', 'false'); 108 toggleBtn.setAttribute('aria-label', 'Toggle ' + menuText + ' submenu'); 109 toggleBtn.innerHTML = CHEVRON_SVG; 110 111 // Insert after the link (before sub-menu) 112 link.insertAdjacentElement('afterend', toggleBtn); 113 114 // Direct clean click toggle 115 toggleBtn.addEventListener('click', handleToggleClick); 116 117 // If parent link has empty/hash href, make clicking link also toggle submenu 118 var href = link.getAttribute('href'); 119 if (!href || href === '#' || href === '#!' || href === '' || href.indexOf('javascript:') === 0) { 120 link.style.cursor = 'pointer'; 121 (function (btn) { 122 link.addEventListener('click', function (e) { 123 e.preventDefault(); 124 e.stopPropagation(); 125 btn.click(); 126 }); 127 })(toggleBtn); 128 } 129 } 130 } 131 132 function handleToggleClick(e) { 133 e.preventDefault(); 134 e.stopPropagation(); 135 136 var toggleBtn = e.currentTarget; 137 var parentItem = toggleBtn.closest('.menu-item-has-children, .page_item_has_children') || toggleBtn.parentNode; 138 if (!parentItem) return; 139 140 var isOpen = parentItem.classList.contains('submenu-open'); 141 142 if (isOpen) { 143 closeSubmenu(parentItem, toggleBtn); 144 } else { 145 closeSiblingSubmenus(parentItem); 146 openSubmenu(parentItem, toggleBtn); 147 } 148 } 149 150 function openSubmenu(parentItem, toggleBtn) { 151 parentItem.classList.add('submenu-open', 'clicked'); 152 if (toggleBtn) { 153 toggleBtn.setAttribute('aria-expanded', 'true'); 154 var link = parentItem.querySelector('a'); 155 var menuText = link ? link.textContent.trim() : ''; 156 toggleBtn.setAttribute('aria-label', 'Collapse ' + menuText + ' submenu'); 157 } 158 159 var subMenu = getDirectSubmenu(parentItem); 160 if (subMenu) { 161 subMenu.style.display = 'block'; 162 subMenu.style.visibility = 'visible'; 163 subMenu.style.opacity = '1'; 164 subMenu.style.maxHeight = 'none'; 165 } 166 } 167 168 function closeSubmenu(parentItem, toggleBtn) { 169 parentItem.classList.remove('submenu-open', 'clicked'); 170 if (toggleBtn) { 171 toggleBtn.setAttribute('aria-expanded', 'false'); 172 var link = parentItem.querySelector('a'); 173 var menuText = link ? link.textContent.trim() : ''; 174 toggleBtn.setAttribute('aria-label', 'Expand ' + menuText + ' submenu'); 175 } 176 177 var subMenu = getDirectSubmenu(parentItem); 178 if (subMenu) { 179 subMenu.style.display = 'none'; 180 subMenu.style.visibility = 'hidden'; 181 subMenu.style.opacity = '0'; 182 subMenu.style.maxHeight = '0'; 183 } 184 185 // Also close any nested open submenus inside this branch 186 var nestedOpen = parentItem.querySelectorAll('.submenu-open, .clicked'); 187 for (var i = 0; i < nestedOpen.length; i++) { 188 var nestedItem = nestedOpen[i]; 189 nestedItem.classList.remove('submenu-open', 'clicked'); 190 var btn = nestedItem.querySelector('.submenu-toggle'); 191 if (btn) { 192 btn.setAttribute('aria-expanded', 'false'); 193 } 194 var nestedSub = getDirectSubmenu(nestedItem); 195 if (nestedSub) { 196 nestedSub.style.display = 'none'; 197 nestedSub.style.visibility = 'hidden'; 198 nestedSub.style.opacity = '0'; 199 nestedSub.style.maxHeight = '0'; 200 } 201 } 202 } 203 204 function closeSiblingSubmenus(parentItem) { 205 var parent = parentItem.parentNode; 206 if (!parent) return; 207 208 var children = parent.children; 209 for (var i = 0; i < children.length; i++) { 210 var sibling = children[i]; 211 if (sibling !== parentItem && sibling.classList && (sibling.classList.contains('submenu-open') || sibling.classList.contains('clicked'))) { 212 var btn = sibling.querySelector('.submenu-toggle'); 213 closeSubmenu(sibling, btn); 214 } 215 } 216 } 217 218 function closeAllSubmenus() { 219 var openItems = panel.querySelectorAll('.submenu-open, .clicked'); 220 for (var i = 0; i < openItems.length; i++) { 221 var btn = openItems[i].querySelector('.submenu-toggle'); 222 closeSubmenu(openItems[i], btn); 223 } 224 } 225 226 // ------------------------------------------------------- 227 // Open / Close / Toggle Menu 228 // ------------------------------------------------------- 229 function openMenu() { 230 isMenuOpen = true; 231 232 // Visual state 233 menuBar.classList.add('menu-open'); 234 panel.classList.add('panel-open'); 235 panel.setAttribute('aria-hidden', 'false'); 236 if (overlay) { 237 overlay.classList.add('active'); 238 overlay.setAttribute('aria-hidden', 'false'); 239 } 240 openBtn.setAttribute('aria-expanded', 'true'); 241 242 // Lock body scroll 243 document.body.classList.add('mobile-menu-is-open'); 244 245 // Inject toggle buttons (idempotent) 246 injectDropdownToggles(); 247 248 // Move focus to the close button 249 if (closeBtn) { 250 closeBtn.focus(); 251 } 252 253 // Attach keyboard handler 254 document.addEventListener('keydown', handleKeyDown); 255 } 256 257 function closeMenu() { 258 isMenuOpen = false; 259 260 // Visual state 261 menuBar.classList.remove('menu-open'); 262 panel.classList.remove('panel-open'); 263 panel.setAttribute('aria-hidden', 'true'); 264 if (overlay) { 265 overlay.classList.remove('active'); 266 overlay.setAttribute('aria-hidden', 'true'); 267 } 268 openBtn.setAttribute('aria-expanded', 'false'); 269 270 // Unlock body scroll 271 document.body.classList.remove('mobile-menu-is-open'); 272 273 // Collapse all sub-menus 274 closeAllSubmenus(); 275 276 // Return focus to hamburger button 277 openBtn.focus(); 278 279 // Detach keyboard handler 280 document.removeEventListener('keydown', handleKeyDown); 281 } 282 283 function toggleMenu() { 284 if (isMenuOpen) { 285 closeMenu(); 286 } else { 287 openMenu(); 288 } 289 } 290 291 // ------------------------------------------------------- 292 // Keyboard handler - focus trap + navigation 293 // ------------------------------------------------------- 294 function handleKeyDown(e) { 295 if (!isMenuOpen) return; 296 297 var key = e.key; 298 299 // Escape -> close menu 300 if (key === 'Escape') { 301 e.preventDefault(); 302 closeMenu(); 303 return; 304 } 305 306 // Tab / Shift+Tab -> trap focus inside panel 307 if (key === 'Tab') { 308 var focusable = getFocusableElements(); 309 if (focusable.length === 0) { 310 e.preventDefault(); 311 return; 312 } 313 314 var first = focusable[0]; 315 var last = focusable[focusable.length - 1]; 316 317 if (e.shiftKey) { 318 if (document.activeElement === first) { 319 e.preventDefault(); 320 last.focus(); 321 } 322 } else { 323 if (document.activeElement === last) { 324 e.preventDefault(); 325 first.focus(); 326 } 327 } 328 return; 329 } 330 331 // Arrow keys for menu item navigation 332 if (key === 'ArrowDown' || key === 'ArrowUp') { 333 e.preventDefault(); 334 var focusable = getFocusableElements(); 335 var idx = -1; 336 for (var i = 0; i < focusable.length; i++) { 337 if (focusable[i] === document.activeElement) { 338 idx = i; 339 break; 340 } 341 } 342 343 if (key === 'ArrowDown') { 344 var next = idx < focusable.length - 1 ? idx + 1 : 0; 345 focusable[next].focus(); 346 } else { 347 var prev = idx > 0 ? idx - 1 : focusable.length - 1; 348 focusable[prev].focus(); 349 } 350 return; 351 } 352 353 // Home / End keys 354 if (key === 'Home') { 355 e.preventDefault(); 356 var focusable = getFocusableElements(); 357 if (focusable.length) focusable[0].focus(); 358 return; 359 } 360 if (key === 'End') { 361 e.preventDefault(); 362 var focusable = getFocusableElements(); 363 if (focusable.length) focusable[focusable.length - 1].focus(); 364 return; 365 } 366 } 367 368 // ------------------------------------------------------- 369 // Event bindings 370 // ------------------------------------------------------- 371 372 // Hamburger button 373 openBtn.addEventListener('click', function (e) { 374 e.preventDefault(); 375 toggleMenu(); 376 }); 377 378 openBtn.addEventListener('keydown', function (e) { 379 if (e.key === 'Enter' || e.key === ' ') { 380 e.preventDefault(); 381 toggleMenu(); 382 } 383 }); 384 385 // Close button inside panel 386 if (closeBtn) { 387 closeBtn.addEventListener('click', function (e) { 388 e.preventDefault(); 389 closeMenu(); 390 }); 391 392 closeBtn.addEventListener('keydown', function (e) { 393 if (e.key === 'Enter' || e.key === ' ') { 394 e.preventDefault(); 395 closeMenu(); 396 } 397 }); 398 } 399 400 // Overlay click 401 if (overlay) { 402 overlay.addEventListener('click', function () { 403 closeMenu(); 404 }); 405 } 406 407 // Close on outside click (fallback) 408 document.addEventListener('click', function (e) { 409 if (!isMenuOpen) return; 410 if (panel.contains(e.target) || openBtn.contains(e.target)) return; 411 closeMenu(); 412 }); 413 414 // Close if window grows wider than mobile breakpoint 415 window.addEventListener('resize', function () { 416 if (window.innerWidth > 991 && isMenuOpen) { 417 closeMenu(); 418 } 419 }); 420 421 // Pre-inject toggles on load so DOM is ready immediately 422 if (document.readyState === 'loading') { 423 document.addEventListener('DOMContentLoaded', injectDropdownToggles); 424 } else { 425 injectDropdownToggles(); 426 } 427 428 })(); -
news-box-plus/1.0.9/functions.php
r306993 r357931 80 80 wp_enqueue_style('news-box-plus-main', get_stylesheet_directory_uri() . '/assets/css/main.css', array(), '', 'all'); 81 81 wp_enqueue_script('masonry'); 82 wp_enqueue_script('news-box-plus-mbmenu', get_stylesheet_directory_uri() . '/assets/js/mobile-menu.js', array('jquery'), '1.0.10', true);83 82 } 84 83 add_action('wp_enqueue_scripts', 'news_box_plus_enqueue_child_styles'); … … 116 115 } 117 116 add_filter('excerpt_more', 'news_box_plus_excerpt_more', 999); 117 118 /** 119 * Register widget area for child theme (WordPress.org Theme Check requirement). 120 * 121 * @link https://developer.wordpress.org/reference/functions/register_sidebar/ 122 */ 123 function news_box_plus_widgets_init() 124 { 125 register_sidebar( 126 array( 127 'name' => esc_html__('Sidebar', 'news-box-plus'), 128 'id' => 'sidebar-1', 129 'description' => esc_html__('Add widgets here.', 'news-box-plus'), 130 'before_widget' => '<section id="%1$s" class="widget bg-light mb-4 p-3 %2$s">', 131 'after_widget' => '</section>', 132 'before_title' => '<h2 class="widget-title">', 133 'after_title' => '</h2>', 134 ) 135 ); 136 } 137 add_action('widgets_init', 'news_box_plus_widgets_init'); 138 139 140 /** 141 * Fallback menu for News Box Plus 142 * Limits fallback menu display to a maximum of 7 items (Home + up to 6 published pages) 143 * to prevent header layout break when no custom menu is assigned. 144 * 145 * @param array|object $args Arguments passed from wp_nav_menu. 146 */ 147 function news_box_plus_menu_fallback($args = array()) 148 { 149 $menu_id = is_array($args) && isset($args['menu_id']) ? $args['menu_id'] : (is_object($args) && isset($args->menu_id) ? $args->menu_id : 'news-box-plus-menu'); 150 $menu_class = is_array($args) && isset($args['menu_class']) ? $args['menu_class'] : (is_object($args) && isset($args->menu_class) ? $args->menu_class : 'news-box-plus-menu'); 151 152 $menu = '<ul id="' . esc_attr($menu_id) . '" class="' . esc_attr($menu_class) . '">'; 153 154 // 1. Add Home link as first item 155 $home_current = (is_front_page() || is_home()) ? ' current-menu-item' : ''; 156 $menu .= '<li class="menu-item menu-item-home' . $home_current . '"><a href="' . esc_url(home_url('/')) . '">' . esc_html__('Home', 'news-box-plus') . '</a></li>'; 157 158 // 2. Query up to 6 published pages, excluding static front page if configured 159 $exclude_ids = array(); 160 $front_page_id = (int) get_option('page_on_front'); 161 if ($front_page_id > 0) { 162 $exclude_ids[] = $front_page_id; 163 } 164 165 $pages = get_pages(array( 166 'number' => 6, 167 'sort_column' => 'menu_order, post_title', 168 'sort_order' => 'ASC', 169 'post_status' => 'publish', 170 'exclude' => $exclude_ids, 171 )); 172 173 if (!empty($pages)) { 174 foreach ($pages as $page) { 175 $page_current = (is_page($page->ID)) ? ' current-menu-item' : ''; 176 $menu .= '<li class="menu-item menu-item-type-post_type menu-item-object-page' . $page_current . '"><a href="' . esc_url(get_permalink($page->ID)) . '">' . esc_html($page->post_title) . '</a></li>'; 177 } 178 } 179 180 $menu .= '</ul>'; 181 182 echo $menu; 183 } 184 185 /** 186 * Enqueue Accessible Offcanvas Hamburger Mobile Menu styles & script 187 */ 188 function news_box_plus_enqueue_mobile_menu() 189 { 190 $css_file = get_stylesheet_directory() . '/assets/css/mobile-menu.css'; 191 $js_file = get_stylesheet_directory() . '/assets/js/mobile-menu.js'; 192 $css_ver = file_exists($css_file) ? filemtime($css_file) : wp_get_theme()->get('Version'); 193 $js_ver = file_exists($js_file) ? filemtime($js_file) : wp_get_theme()->get('Version'); 194 195 wp_enqueue_style('news-box-plus-mobile-menu-custom', get_stylesheet_directory_uri() . '/assets/css/mobile-menu.css', array(), $css_ver); 196 wp_enqueue_script('news-box-plus-mobile-menu-custom', get_stylesheet_directory_uri() . '/assets/js/mobile-menu.js', array(), $js_ver, true); 197 } 198 add_action('wp_enqueue_scripts', 'news_box_plus_enqueue_mobile_menu', 20); -
news-box-plus/1.0.9/header.php
r196842 r357931 34 34 <div id="page" class="site"> 35 35 <a class="skip-link screen-reader-text" href="#content"><?php esc_html_e('Skip to content', 'news-box-plus'); ?></a> 36 <?php do_action('news_box_plus_mobile_menu'); ?>37 36 38 37 <header id="masthead" class="site-header"> 38 <?php do_action('news_box_plus_mobile_menu'); ?> 39 39 <?php if (get_header_image()) : ?> 40 40 <div class="header-banner"> -
news-box-plus/1.0.9/inc/latest-bar-menu.php
r196842 r357931 9 9 10 10 // Blog Eye mobile menu 11 /** 12 * Accessible Offcanvas Hamburger Mobile Menu (from Wowmart Framework) 13 */ 14 /** 15 * Accessible Offcanvas Hamburger Mobile Menu (from Wowmart Framework) 16 */ 17 /** 18 * Accessible Offcanvas Hamburger Mobile Menu (from Wowmart Framework) 19 */ 20 /** 21 * Accessible Offcanvas Hamburger Mobile Menu (from Wowmart Framework) 22 */ 23 /** 24 * Accessible Offcanvas Hamburger Mobile Menu (from Wowmart Framework) 25 */ 26 /** 27 * Accessible Offcanvas Hamburger Mobile Menu (from Wowmart Framework) 28 */ 29 /** 30 * Accessible Offcanvas Hamburger Mobile Menu (from Wowmart Framework) 31 */ 32 /** 33 * Accessible Offcanvas Hamburger Mobile Menu (from Wowmart Framework) 34 */ 35 /** 36 * Accessible Offcanvas Hamburger Mobile Menu (from Wowmart Framework) 37 */ 38 /** 39 * Accessible Offcanvas Hamburger Mobile Menu (from Wowmart Framework) 40 */ 41 /** 42 * Accessible Offcanvas Hamburger Mobile Menu (from Wowmart Framework) 43 */ 11 44 function news_box_plus_mobile_menu_output() 12 45 { 13 46 ?> 14 <div class="mobile-menu-bar"> 15 <div class="container"> 16 <nav id="mobile-navigation" class="mobile-navigation"> 17 <button id="mmenu-btn" class="menu-btn" aria-expanded="false"> 18 <span class="mopen"><?php esc_html_e('Menu', 'news-box-plus'); ?></span> 19 <span class="mclose"><?php esc_html_e('Close', 'news-box-plus'); ?></span> 20 </button> 21 <?php 22 wp_nav_menu(array( 23 'theme_location' => 'main-menu', 24 'menu_id' => 'wsm-menu', 25 'menu_class' => 'wsm-menu', 26 )); 27 ?> 28 </nav><!-- #site-navigation --> 29 </div> 30 </div> 47 <div id="wsm-menu" class="mobile-menu-bar wsm-menu"> 48 <div class="container"> 49 <div class="mobile-topbar"> 50 <div class="mobile-topbar-logo"> 51 <?php 52 if (function_exists('has_custom_logo') && has_custom_logo()) { 53 the_custom_logo(); 54 } else { 55 ?> 56 <a href="<?php echo esc_url(home_url('/')); ?>" class="mobile-site-title" rel="home"> 57 <?php bloginfo('name'); ?> 58 </a> 59 <?php } ?> 60 </div> 61 <button id="mmenu-btn" class="menu-btn" aria-expanded="false" aria-controls="mobile-menu-panel" aria-label="<?php esc_attr_e('Open mobile menu', 'news-box-plus'); ?>"> 62 <span class="mopen" aria-hidden="true"> 63 <svg class="hamburger-icon" width="26" height="26" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" focusable="false"> 64 <path d="M3 12h18M3 6h18M3 18h18" stroke="currentColor" stroke-width="2" stroke-linecap="round" /> 65 </svg> 66 </span> 67 <span class="mclose" aria-hidden="true"> 68 <svg class="close-icon" width="26" height="26" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" focusable="false"> 69 <path d="M18 6L6 18M6 6l12 12" stroke="currentColor" stroke-width="2" stroke-linecap="round" /> 70 </svg> 71 </span> 72 <span class="sr-only"><?php esc_html_e('Menu', 'news-box-plus'); ?></span> 73 </button> 74 </div> 75 </div> 76 77 <!-- Overlay backdrop --> 78 <div id="mobile-menu-overlay" class="mobile-menu-overlay" aria-hidden="true"></div> 79 80 <!-- Slide-in menu panel --> 81 <nav id="mobile-menu-panel" class="mobile-menu-panel" role="navigation" aria-label="<?php esc_attr_e('Mobile Menu', 'news-box-plus'); ?>" aria-hidden="true"> 82 <div class="mobile-panel-header"> 83 <div class="mobile-panel-logo"> 84 <?php 85 if (function_exists('has_custom_logo') && has_custom_logo()) { 86 the_custom_logo(); 87 } else { 88 ?> 89 <a href="<?php echo esc_url(home_url('/')); ?>" class="mobile-site-title" rel="home"> 90 <?php bloginfo('name'); ?> 91 </a> 92 <?php } ?> 93 </div> 94 <button id="mmenu-close-btn" class="menu-close-btn" aria-label="<?php esc_attr_e('Close mobile menu', 'news-box-plus'); ?>"> 95 <svg width="22" height="22" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" focusable="false"> 96 <path d="M18 6L6 18M6 6l12 12" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" /> 97 </svg> 98 </button> 99 </div> 100 <div id="mobile-navigation" class="mobile-navigation"> 101 <?php 102 wp_nav_menu(array( 103 'theme_location' => 'menu-1', 104 'menu_id' => 'wsm-menu-ul', 105 'menu_class' => 'wsm-menu-has', 106 'container' => false, 107 'fallback_cb' => 'news_box_plus_menu_fallback', 108 )); 109 ?> 110 </div> 111 </nav> 112 </div> 31 113 32 114 <?php … … 44 126 'menu_id' => 'primary-menu', 45 127 'menu_class' => 'news-box-menu', 46 )); 128 'fallback_cb' => 'news_box_plus_menu_fallback', 129 )); 47 130 ?> 48 131 </nav><!-- #site-navigation --> -
news-box-plus/1.0.9/readme.txt
r344112 r357931 2 2 3 3 Contributors: nalam 4 Requires at least: 4.04 Requires at least: 6.0 5 5 Tested up to: 7.1 6 6 Tags: blog, news, education, custom-logo, one-column, two-columns, grid-layout, right-sidebar, custom-background, custom-header, custom-menu, featured-image-header, featured-images, flexible-header, full-width-template, sticky-post, threaded-comments, translation-ready, block-styles 7 Stable tag: 1.0. 78 Requires PHP: 5.67 Stable tag: 1.0.9 8 Requires PHP: 7.4 9 9 License: GNU General Public License v2 or later 10 10 License URI: http://www.gnu.org/licenses/gpl-2.0.html … … 71 71 == Changelog == 72 72 73 74 75 = 1.0.9 = 76 * Tested up to WordPress 7.1. 77 * Updated PHP compatibility. 78 * Performance improvements and code optimization. 79 * Minor CSS and UI improvements. 80 = 1.0.8 = 81 * Tested up to WordPress 7.1. 82 * Updated PHP compatibility. 83 * Performance improvements and code optimization. 84 * Minor CSS and UI improvements. 73 85 = 1.0.7 = 74 86 * Polished blog post card styles for better readability -
news-box-plus/1.0.9/style.css
r344112 r357931 5 5 Theme URI: https://wpthemespace.com/product/news-box-plus/ 6 6 Template: news-box 7 Version: 1.0. 77 Version: 1.0.9 8 8 Tested up to: 7.1 9 Requires PHP: 5.6 9 Requires at least: 6.0 10 Requires PHP: 7.4 10 11 Description: Best Theme for Newspaper, Magazine & Blog Websites. News Box Plus is a dynamic and modern WordPress theme designed specifically for news websites, online magazines, and content-rich blogs. With its sleek and professional design, News Box Plus offers a visually appealing layout that engages readers and ensures a seamless browsing experience. The theme provides a range of customizable features and options to tailor your website according to your unique branding and content needs. It offers a responsive design, allowing your site to adapt beautifully to various screen sizes and devices, ensuring a consistent and user-friendly experience for your audience on desktops, tablets, and mobile devices. News Box Plus comes equipped with a user-friendly interface and intuitive customization options. You can easily customize colors, fonts, layouts, and other visual elements to match your brand identity. The theme offers multiple widget areas, allowing you to display featured articles, trending topics, social media integration, and other dynamic content sections. 11 12 Tags: blog, news, education, custom-logo, one-column, two-columns, grid-layout, right-sidebar, custom-background, custom-header, custom-menu, featured-image-header, featured-images, flexible-header, full-width-template, sticky-post, threaded-comments, translation-ready, block-styles 12 13 Text Domain: news-box-plus 13 14 License: GNU General Public License v2 or later 14 License URI: http://www.gnu.org/licenses/gpl-2.0.html15 License URI: https://www.gnu.org/licenses/gpl-2.0.html 15 16 * 16 17 */ 18 19 /* ========================================================================== 20 Header Logo & Navigation Spacing Rule (Collision Prevention - Rule #7) 21 Ensures at least 30-40px gap between logo and menu so they never touch. 22 ========================================================================== */ 23 @media (min-width: 992px) { 24 .menubar-content, 25 .pxm-style1 .navigation .d-flex, 26 .pxm-style2 .navigation .d-flex, 27 .navigation .d-flex, 28 .site-header .d-flex, 29 .header-main-wrapper .d-flex, 30 .realestate-press-container.menu-inner, 31 .headtop-items, 32 .topnav-serch, 33 .nxbox-menu-bar, 34 .header-middle .row { 35 gap: 35px; 36 } 37 38 .head-logo-sec, 39 .pxms1-logo, 40 .site-branding.brand-logo, 41 .site-branding.brand-text, 42 .menubar-content .head-logo-sec, 43 .header-logo-wrap, 44 .sm-logo, 45 .site-branding.news-box-logo, 46 .site-branding { 47 flex-shrink: 0; 48 margin-right: 30px; 49 } 50 51 .main-navigation, 52 .pxms1-menu, 53 .realestate-press-container.menu-inner, 54 .topnav-serch .navbar, 55 .nxbox-menu-bar .main-navigation { 56 min-width: 0; 57 } 58 } 59 60 /* ========================================================================== 61 Blog List Spacing & Badge Inline Styling (Rule #9) 62 ========================================================================== */ 63 /* Spacing between featured image and text in list / card blog */ 64 .card.flex-md-row, 65 .card-view .card, 66 .blog-list-item, 67 .post-list, 68 .article-item, 69 .post-card { 70 gap: 20px; 71 } 72 .card-img-left, 73 .content-img, 74 .post-card-img, 75 .entry-media { 76 margin-right: 20px; 77 } 78 79 /* Ensure blog badges and action buttons keep proper inline sizing */ 80 .blog-all-details, 81 .entry-content, 82 .post-content, 83 .card-body { 84 display: flex; 85 flex-direction: column; 86 align-items: flex-start; 87 } 88 89 .blog-scat, 90 .cat-links, 91 .category-badge, 92 .main-btn, 93 .read-more, 94 .more-link, 95 .post-categories a, 96 .cat-links a, 97 .entry-footer a { 98 align-self: flex-start !important; 99 width: auto !important; 100 max-width: max-content !important; 101 display: inline-block !important; 102 } 103 104 /* ========================================================================== 105 Desktop Navigation Flex-Flow & Word-Wrap Preservation (Rule #10) 106 Prevents menu items from breaking words vertically when there are many items. 107 Items wrap cleanly to new lines with full words preserved. 108 ========================================================================== */ 109 @media (min-width: 992px) { 110 .header-top .headtop-items { 111 display: flex; 112 flex-flow: row wrap; 113 align-items: center; 114 justify-content: space-between; 115 } 116 117 .header-top .topnav-serch { 118 display: flex; 119 flex-flow: row wrap; 120 align-items: center; 121 justify-content: flex-end; 122 min-width: 0; 123 flex: 1 1 auto; 124 } 125 126 .header-top .navbar, 127 .topnav-serch .navbar { 128 padding: 0; 129 min-width: 0; 130 flex: 1 1 auto; 131 } 132 133 .header-top .navbar-collapse, 134 .topnav-serch .navbar-collapse { 135 min-width: 0; 136 } 137 138 /* Desktop menu flex-flow row wrap */ 139 .header-top .navbar-nav, 140 #primary-menu.navbar-nav, 141 .navbar-nav.ml-auto, 142 .navbar-nav, 143 .main-navigation ul, 144 .news-box-menu, 145 .realestate-press-menu, 146 .car-expert-menu { 147 display: flex !important; 148 flex-flow: row wrap !important; 149 align-items: center; 150 list-style: none; 151 margin: 0; 152 padding: 0; 153 } 154 155 /* Prevent words from breaking across letters within menu items */ 156 .header-top .navbar-nav > li, 157 #primary-menu.navbar-nav > li, 158 .navbar-nav > li, 159 .main-navigation ul > li, 160 .news-box-menu > li, 161 .realestate-press-menu > li, 162 .car-expert-menu > li { 163 flex-shrink: 0 !important; 164 white-space: nowrap !important; 165 word-break: normal !important; 166 overflow-wrap: normal !important; 167 } 168 169 .header-top .navbar-nav > li > a, 170 #primary-menu.navbar-nav > li > a, 171 .navbar-nav > li > a, 172 .navbar-nav .nav-link, 173 .main-navigation ul > li > a, 174 .news-box-menu > li > a, 175 .realestate-press-menu > li > a, 176 .car-expert-menu > li > a { 177 white-space: nowrap !important; 178 word-break: normal !important; 179 overflow-wrap: normal !important; 180 display: block; 181 } 182 183 /* Dropdown Submenus: keep vertical flow */ 184 .header-top .navbar-nav .dropdown-menu, 185 .navbar-nav .dropdown-menu, 186 .main-navigation ul ul, 187 .news-box-menu ul, 188 .realestate-press-menu ul { 189 flex-direction: column !important; 190 flex-wrap: nowrap !important; 191 } 192 193 .header-top .navbar-nav .dropdown-menu > li > a, 194 .navbar-nav .dropdown-menu > li > a, 195 .main-navigation ul ul > li > a, 196 .news-box-menu ul > li > a, 197 .realestate-press-menu ul > li > a { 198 white-space: nowrap !important; 199 } 200 } 201 202 /* Universal mobile suppression of legacy navbar toggle & dropdowns (Rule #8) */ 203 @media screen and (max-width: 991px) { 204 button.navbar-toggler:not(#mmenu-btn), 205 button.menu-toggle:not(#mmenu-btn), 206 .navbar-toggler:not(#mmenu-btn), 207 .navbar button, 208 nav.navbar button, 209 .navbar-toggler { 210 display: none !important; 211 } 212 .topnav-serch .navbar, 213 .topnav-serch #navbar-content, 214 .header-top .navbar, 215 .nxbox-menu-bar, 216 .header-middle .news-box-logo, 217 .header-middle .site-branding, 218 .menu-deskbar, 219 .realestate-press-logo-section { 220 display: none !important; 221 } 222 }
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)