PageSourceSearch

https://ksmi.kg/wp-content/themes/betheme/js/accessibility.js?ver=26.6.4

js ksmi.kg collected 2026-10-07 03:05:50 UTC 15,788 bytes, 437 lines download raw bytes

1(function($) {
2
3  /* globals jQuery */
4
5  "use strict";
6
7  /**
8   * Accesibility | Keyboard Support
9   PBL
10  */
11
12  var keyboard = {
13
14    keysTriggered: { // multitasking alike
15      Tab: false,  Enter: false, ShiftLeft: false, ShiftRight: false, Escape: false,
16      ArrowLeft: false, ArrowRight: false, ArrowUp: false, ArrowDown: false
17    },
18
19    utils: {
20      isSimpleHamburgerStack: !($('body').hasClass('header-simple') && !$('body').hasClass('mobile-side-slide')),
21      switchExpanded: (el, state) => $(el).attr('aria-expanded', state),
22    },
23
24    menuLinks: $('#menu .menu-item a').not('.menu-toggle').toArray(),
25    subheaderLinks: $('#Subheader a').toArray(),
26    wooPopup:  $('.mfn-header-login').find('a, input').toArray(),
27    contentLinks: [...$('#Content a').toArray(), ...$('#Footer a').toArray()],
28
29    clickListener() {
30
31      jQuery(document).on('keydown', 'a, *[role="link"], button', ( e ) => {
32        let { originalEvent } = e;
33        let { code : keyClicked } = originalEvent;
34
35        if ( keyClicked in this.keysTriggered ) {
36          this.keysTriggered[keyClicked] = true;
37        }
38
39        setTimeout( _ => this.recognizeGesture(e), 1);
40      });
41
42      jQuery(document).on('keyup', 'a, *[role="link"], button', ( e ) => {
43        let { originalEvent } = e;
44        let { code : keyClicked } = originalEvent;
45
46        if ( keyClicked in this.keysTriggered ) {
47          this.keysTriggered[keyClicked] = false;
48        }
49
50        setTimeout( _ => this.recognizeGesture(e), 1);
51      });
52
53      jQuery('#skip-links-menu').one('focus', 'a', function(){
54        $('#skip-links-menu').css('top', '0px');
55      });
56
57    },
58
59    skipLinks() {
60      if( $(':focus').closest('nav').is('#skip-links-menu') ) {
61        $('#skip-links-menu').css('top', '0px');
62      } else {
63        $('#skip-links-menu').css('top', '-200px');
64      }
65    },
66
67    recognizeGesture(e) {
68      let { Tab, ShiftLeft, ShiftRight, ArrowDown, ArrowUp, ArrowLeft, ArrowRight, Enter, Escape } = this.keysTriggered;
69      const focusedElement = $(':focus');
70      let modalOpened = $('*[aria-expanded=true]:not(#menu):not(.sub-menu)');
71      const menuOpened = $('nav#menu').find('*[aria-expanded=true]');
72      const domPrefix = $('body').hasClass('side-slide-is-open') ? '.extras-wrapper ' : '.top_bar_right ';
73      const shouldChangeDirection = () => {
74        let shouldChange = false;
75
76        if ($('body').hasClass('rtl')) shouldChange = true; // RTL
77        if ($('body').hasClass('header-rtl')) shouldChange = true; // Header Right | Ex. Creative Right
78
79        return shouldChange;
80      }
81
82      /* CLOSE MODALS WHEN CURSOR IS OUTSIDE OF IT --- FORCE !!! */
83      if( $(modalOpened).length && !focusedElement.closest(modalOpened).length) {
84          // If Side_slide is opened, then modals should be closed first ALWAYS
85          // classList object| it will recog if item is from DOM, not just a trash code from jquery
86          const elementToClose = Object.values(modalOpened).filter(
87            (modal) => (modal.classList && $(modal).attr('id') !== 'Side_slide')
88          )
89          modalOpened = !elementToClose.length ? modalOpened : $(elementToClose[0]);
90
91          // All other modals are using mfn-close-icon class, Side_slide is exception
92          if( modalOpened.attr('id') !== 'Side_slide' && modalOpened.attr('aria-expanded') == 'true') {
93
94            if( $(modalOpened).siblings('.mfn-close-icon').length ){
95              $(modalOpened).siblings('.mfn-close-icon').trigger('click');
96            } else {
97              $(modalOpened).find('.mfn-close-icon').trigger('click');
98            }
99          }
100
101          this.utils.switchExpanded(modalOpened, false);
102
103          switch(true){
104            case modalOpened.hasClass('woocommerce-MyAccount-navigation'):
105              $(`${domPrefix} .myaccount_button`).trigger('focus');
106              break;
107            case modalOpened.hasClass('mfn-cart-holder'):
108              //modalOpened.find('.mfn-close-icon').trigger('click');
109              $(`${domPrefix} #header_cart`).trigger('focus');
110              break;
111            case modalOpened.attr('id') === 'Side_slide':
112              modalOpened.find('.close').trigger('click');
113              $(`.responsive-menu-toggle`).trigger('focus');
114              break;
115          }
116      }
117
118      /* CLOSE MENU DROPDOWNS WHEN OUTSIDE OF IT --- AVOID HAMBURGER MENU WITH SIMPLE STYLE OF HEADER  !!! */
119      if( $(menuOpened).length && this.utils.isSimpleHamburgerStack ) {
120        if ( !focusedElement.closest(menuOpened).length && !menuOpened.siblings().is(focusedElement) ) {
121          $(menuOpened).attr('aria-expanded','false').slideUp();
122        }
123      }
124
125      /* DOUBLE CHECK OF SUBMENUS ARIA-EXPANDED! */
126      $('.sub-menu[aria-expanded=true]').each( (index, item) => {
127        if ( $(item).css('display') == 'none') {
128          this.utils.switchExpanded(item, false);
129        }
130      })
131
132      if(Enter){
133        switch( true ){
134          //Side slide close by button
135          case focusedElement.hasClass('close'):
136            this.utils.switchExpanded(modalOpened, false);
137            $('.responsive-menu-toggle').trigger('focus');
138            break;
139
140          //Submenu side-slide
141          case focusedElement.hasClass('menu-toggle') && $('body').hasClass('side-slide-is-open'):
142            const submenuSide = focusedElement.siblings('.sub-menu');
143
144            if (submenuSide.css('display') == 'block') {
145              submenuSide.find('a').first().trigger('focus');
146            }
147
148            break;
149
150          //Submenu dropdown
151          case focusedElement.hasClass('menu-toggle') && !$('body').hasClass('side-slide-is-open'):
152            const submenu = focusedElement.siblings('.sub-menu');
153
154            //When hamburger menu with header simple, then break the loop
155            if ( !this.utils.isSimpleHamburgerStack ){
156
157              if ( submenu.attr('aria-expanded') == 'true' ) {
158                this.utils.switchExpanded(submenu, false);
159              } else {
160                this.utils.switchExpanded(submenu, true);
161
162                let submenuItem = submenu.find('a').first();
163                setTimeout(_ => submenuItem.trigger('focus'), 100);
164              }
165
166              break;
167            }
168
169            if (submenu.css('display') != 'none') {
170              this.utils.switchExpanded(submenu, false);
171              submenu.slideUp(0);
172
173              //close deeper arias expanded
174              const subarias = submenu.find('*[aria-expanded=true]');
175              if (subarias.length) {
176                this.utils.switchExpanded(subarias, false);
177                subarias.slideUp();
178              }
179
180            } else {
181              this.utils.switchExpanded(submenu, true);
182
183              let submenuItem = submenu.slideDown(0).find('a').first();
184              setTimeout(_ => submenuItem.trigger('focus'), 100);
185            }
186
187            break;
188
189          // WooCommerce Header Login
190          case focusedElement.hasClass('toggle-login-modal'):
191            $('.woocommerce-MyAccount-navigation').find('a').first().trigger('focus');
192            $('.woocommerce-MyAccount-navigation').attr('aria-expanded', 'true');
193            break;
194
195          // Elements which imitate links
196          case focusedElement.attr('role') === 'link':
197            if( focusedElement.find('.image_links').length ){ //image
198              window.location = focusedElement.find('a').attr('href');
199            } else if( focusedElement.find('.title').length ) { //accordion
200              focusedElement.find('.title').trigger('click');
201            } else if( focusedElement.closest('.mfn-woo-list').length ) {
202              focusedElement.trigger('click');
203            }
204            break;
205
206          //WPML dropdown
207          case focusedElement.attr('data-title') === 'wpml':
208            const langDropdown = focusedElement.siblings('.wpml-lang-dropdown');
209
210            if ( langDropdown.attr('aria-expanded') == 'false' ) {
211              langDropdown.attr('aria-expanded', 'true');
212              langDropdown.find('a').first().trigger('focus');
213            } else {
214              langDropdown.attr('aria-expanded', 'false');
215            }
216            break;
217
218          //WooCommerce Cart Sidebar
219          case focusedElement.hasClass('single_add_to_cart_button'):
220            $('.mfn-cart-holder').find('a').first().trigger('focus');
221            break;
222
223          //Turn on dropdown or sidecart
224          case focusedElement.hasClass('responsive-menu-toggle'):
225            //Sideslide --- socials && extras, order of array is important!
226            if ( $('body').hasClass('mobile-side-slide') ) {
227              this.menuLinks = [
228                ...$('#Side_slide').find('a.close').toArray(),
229                ...$('.extras-wrapper').find('a').toArray(),
230                ...this.menuLinks,
231                ...$('#Side_slide .social').find('a').toArray()
232              ];
233
234              $(this.menuLinks[0]).trigger('focus');
235              focusedElement.trigger('click');
236              this.utils.switchExpanded( $('#Side_slide'), true );
237            }
238
239            break;
240
241          case focusedElement.hasClass('overlay-menu-toggle'):
242            if( $('#overlay-menu ul').attr('aria-expanded') == 'false' ||  $('#overlay-menu ul').attr('aria-expanded') === undefined ){
243              this.utils.switchExpanded( $('#overlay-menu ul'), true );
244
245              $('#overlay-menu').find('.menu-item a').first().trigger('focus');
246            }else{
247              this.utils.switchExpanded($('#overlay-menu ul'), false);
248
249              if( focusedElement.hasClass('close') ) {
250                $('.overlay-menu-toggle').trigger('focus');
251              }
252            }
253            break;
254          }
255
256      } else if(Tab && (ShiftLeft || ShiftRight) ) {
257
258        //Tabs fix, make noticable for tab, overwrite tabindex from -1 to 0
259        $('a.ui-tabs-anchor').attr('tabindex', 0);
260
261        //Skip links, are they triggered?
262        this.skipLinks();
263
264      }else if(Tab) {
265
266        //Tabs fix, make noticable for tab, overwrite tabindex from -1 to 0
267        $('a.ui-tabs-anchor').attr('tabindex', 0);
268
269        //Skip links, are they triggered?
270        this.skipLinks();
271
272        switch( true ) {
273          case focusedElement.closest('li').hasClass('wc-block-product-categories-list-item'): // woocommerce widget -- product category dropdowns
274            if( !focusedElement.closest('.li-expanded').length ){
275              focusedElement.siblings('.cat-expander').trigger('click');
276              focusedElement.siblings('ul').find('a').first().trigger('focus');
277            }
278
279            focusedElement.closest('li').siblings('.li-expanded').each((index, object) => $(object).find('.cat-expander').trigger('click') );
280            break;
281          case focusedElement.is('.overlay-menu-toggle', '.focus') && $('#Overlay').css('display') === 'block': //Overlay
282            $('.overlay-menu-toggle').trigger('focus');
283            break;
284          case focusedElement.is( $(this.contentLinks[this.contentLinks.length-1]) ) && !$('body').hasClass('footer-menu-sticky'): //when reached end of page
285            //if fixed nav, then first, reach that
286            if( $('.fixed-nav').length ) {
287              $('.fixed-nav').first().trigger('focus');
288            } else {
289              $('body a').first().trigger('focus');
290            }
291
292            break;
293        }
294
295      } else if ( Escape ) {
296        var openedSubmenus = Array.from( $('.sub-menu[aria-expanded=true]') );
297        var modals = $('.woocommerce').find('nav[aria-expanded=true]');
298
299
300        if ( $('body').hasClass('side-slide-is-open') && focusedElement.closest('#Side_slide').length) {
301          //side slide
302          this.utils.switchExpanded(modalOpened, false);
303          modalOpened.find('.close').trigger('click');
304
305          $('.responsive-menu-toggle').trigger('focus');
306        } else if( openedSubmenus.length ) {
307          //menus, dropdown
308          var menuItemOpened = $('nav').find('.sub-menu[aria-expanded=true]').siblings('a.menu-toggle');
309
310          openedSubmenus.forEach(submenu => {
311            this.utils.switchExpanded(submenu, false);
312            $(submenu).slideUp();
313          })
314
315          menuItemOpened.trigger('focus');
316        } else if( $('.mfn-header-login').find('nav[aria-expanded=true]').length ) {
317          //side login
318          $('.close-login-modal').trigger('click');
319          this.utils.switchExpanded(modals, false);
320
321          $('.myaccount_button').trigger('focus');
322        } else if( $('.mfn-cart-holder').attr('aria-expanded') == 'true' ) {
323          //side cart
324          $('.mfn-cart-holder').find('.close-mfn-cart').trigger('click');
325          this.utils.switchExpanded($('.mfn-cart-holder'), false);
326
327          $('#header_cart').trigger('focus');
328          return;
329        } else if ( $('.responsive-menu-toggle').hasClass('active') ) {
330          // responsive menu toggle
331          $('.responsive-menu-toggle').trigger('click');
332          $('.responsive-menu-toggle').trigger('focus');
333        }
334
335
336      } else if ( !shouldChangeDirection() ? ArrowRight : ArrowLeft  ) {
337
338        if(focusedElement.closest('li').find('.menu-toggle').length) {
339          const submenu = focusedElement.siblings('.sub-menu');
340
341          if (submenu.css('display') == 'none') {
342            this.utils.switchExpanded(submenu, true);
343
344            //open and focus next submenu
345            let submenuItem = submenu.slideDown(0).find('a').first();
346            setTimeout(_ => submenuItem.trigger('focus'), 100);
347          }
348        }
349
350      } else if ( !shouldChangeDirection() ? ArrowLeft : ArrowRight ) {
351
352        if(focusedElement.closest('ul[aria-expanded=true]').length) {
353          const submenu = focusedElement.closest('.sub-menu');
354
355          //close deeper arias expanded
356          const subarias = submenu.find('*[aria-expanded=true]');
357          if (subarias.length) {
358            this.utils.switchExpanded(subarias, false);
359            subarias.slideUp();
360          }
361        }
362
363      }
364
365    },
366
367    init() {
368
369      if( $('body').hasClass('keyboard-support') ) {
370
371        this.clickListener();
372
373        /* Instead of using WP Walkers, we can do that using JS, quicker, simpler (KISS PRINCIPLE)  */
374        $('.sub-menu').attr('aria-expanded', 'false');
375        $('.menu-toggle, .menu-item a').attr('tabindex', '0');
376
377        /* These containers are changing for multiple templates, change it by JS (DRY PRINCIPLE) */
378        $('#Content').attr('role', 'main');
379        $('#Header_wrapper').attr('role', 'banner').attr('aria-label', mfn.accessibility.translation.headerContainer);
380
381        // Woo Menu
382        $('.woocommerce-MyAccount-navigation').attr('role', 'navigation').attr('aria-expanded', 'false');
383
384        /* Remove aria-expanded for headers which does not open on menu click (responsive-menu-button) */
385        if ( !$('body').is('.header-creative, .header-simple, .header-overlay') ) {
386          $('#menu').removeAttr('aria-expanded');
387        }
388      }
389
390    }
391
392  }
393
394  /**
395   * Accesibility | New tab or _blank target links | PBL
396   */
397
398  var warningLinks = {
399
400    onLinkAlert(){
401      $('a').click(function( e ) {
402
403        const target = $(e.currentTarget);
404        if( (target.attr('target') === '_blank' || target.attr('target') === '0' ) ) {
405          //stop action
406          var answer = confirm ("The link will open in a new tab. Do you want to continue? ");
407          if (!answer) {
408            e.preventDefault();
409          }
410
411        }
412
413      })
414    },
415
416    init(){
417      if ( $('body').hasClass('warning-links') ) {
418        this.onLinkAlert();
419      }
420    }
421
422  }
423
424  /**
425   * $(window).on('load')
426   * window.load
427   */
428
429  $(window).on('load', function() {
430
431    keyboard.init();
432
433    warningLinks.init();
434
435  });
436
437})(jQuery);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.