Make WordPress Themes

Changeset 357931


Ignore:
Timestamp:
11/08/2026 01:47:36 AM (68 minutes ago)
Author:
themedropbox
Message:

New version of News Box Plus - 1.0.9

Location:
news-box-plus/1.0.9
Files:
2 added
7 edited
1 copied

Legend:

Unmodified
Added
Removed
  • news-box-plus/1.0.9/assets/css/main.css

    r344112 r357931  
    649649
    650650}
     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  
    11/**
    2  * Script for mobile menu
     2 * Accessible Mobile Menu with Focus Trap & Dropdown Toggles
    33 *
    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
    616 */
    717
    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  
    8080        wp_enqueue_style('news-box-plus-main', get_stylesheet_directory_uri() . '/assets/css/main.css', array(), '', 'all');
    8181        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);
    8382}
    8483add_action('wp_enqueue_scripts', 'news_box_plus_enqueue_child_styles');
    … …  
    116115}
    117116add_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 */
     123function 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}
     137add_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 */
     147function 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 */
     188function 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}
     198add_action('wp_enqueue_scripts', 'news_box_plus_enqueue_mobile_menu', 20);
  • news-box-plus/1.0.9/header.php

    r196842 r357931  
    3434        <div id="page" class="site">
    3535                <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'); ?>
    3736
    3837                <header id="masthead" class="site-header">
     38                        <?php do_action('news_box_plus_mobile_menu'); ?>
    3939                        <?php if (get_header_image()) : ?>
    4040                                <div class="header-banner">
  • news-box-plus/1.0.9/inc/latest-bar-menu.php

    r196842 r357931  
    99
    1010// 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 */
    1144function news_box_plus_mobile_menu_output()
    1245{
    1346?>
    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>
    31113
    32114<?php
    … …  
    44126            'menu_id'        => 'primary-menu',
    45127            'menu_class'        => 'news-box-menu',
    46         ));
     128                'fallback_cb'       => 'news_box_plus_menu_fallback',
     129                ));
    47130        ?>
    48131    </nav><!-- #site-navigation -->
  • news-box-plus/1.0.9/readme.txt

    r344112 r357931  
    22
    33Contributors: nalam
    4 Requires at least: 4.0
     4Requires at least: 6.0
    55Tested up to: 7.1
    66Tags: 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.7
    8 Requires PHP: 5.6
     7Stable tag: 1.0.9
     8Requires PHP: 7.4
    99License: GNU General Public License v2 or later
    1010License URI: http://www.gnu.org/licenses/gpl-2.0.html
    … …  
    7171== Changelog ==
    7272
     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.
    7385= 1.0.7 =
    7486* Polished blog post card styles for better readability
  • news-box-plus/1.0.9/style.css

    r344112 r357931  
    55Theme URI:  https://wpthemespace.com/product/news-box-plus/
    66Template:     news-box
    7 Version: 1.0.7
     7Version: 1.0.9
    88Tested up to: 7.1
    9 Requires PHP: 5.6
     9Requires at least: 6.0
     10Requires PHP: 7.4
    1011Description: 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.
    1112Tags: 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
    1213Text Domain: news-box-plus
    1314License:        GNU General Public License v2 or later
    14 License URI:    http://www.gnu.org/licenses/gpl-2.0.html
     15License URI: https://www.gnu.org/licenses/gpl-2.0.html
    1516*
    1617*/
     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.