PageSourceSearch

https://bienali.com/Modules/Menu/2_0_0/js/Menu-mobile.js?rls=20260909

js bienali.com collected 2026-10-06 16:44:35 UTC 7,383 bytes, 189 lines download raw bytes

1(function ($) { // Mobile Menu
2  var buildMenu = true;
3
4  // todo: when more regression time is available, consider changing this initializer to use asi_getSmallestViewportWidth()
5  window.asi_screenWidth = !window.jQuery ? (window.screen.width || window.innerWidth) : $(window).width();
6  window.asi_resizeHandlerLock = false;
7  
8  function consolidateMenus() {
9    if ($('#mobile-menu').length) {
10      return false;
11    }
12
13    function mobileToggle(toggleText) {
14      return $('<a class="toggle-nav" href="#"><div class="mobile-menu-icon"><span></span></div> ' + (toggleText ? toggleText : 'Menu') + '</a>');
15    }
16
17    var $nav = $('<nav id="mobile-menu" class="mobile-menu"></nav>');
18    var $ul = $('<ul />');
19    var $endUserList = $('.EndUserStatus .tabs li').clone(),
20      $headerMenuList = $('header .Menu .tabs>li').clone(),
21      $sectionMenuList = $('section .Menu .tabs');
22
23    $ul.append($headerMenuList);
24    $ul.append($endUserList);
25    $nav.append(mobileToggle());
26    $nav.append($ul);
27
28    $sectionMenuList.wrapAll('<nav class="mobile-menu"></nav>').parent().prepend(mobileToggle('Side Menu'));
29
30    $('body').append($nav);
31    $('.mobile-menu a.toggle-nav').on('click', function(e) {
32      e.preventDefault();
33      e.stopPropagation();
34      $(this).parent().toggleClass('active');
35    });
36
37    $('.mobile-menu').on('click touchstart', 'li>a', function() {
38      var $this = $(this);
39      if ($this.next('ul.dropdown').length) {
40        $('.mobile-menu li.active').not($(this).parents('li')).removeClass('active');
41        $(this).parent('li').toggleClass('active');
42        return false;
43      }
44      return true;
45    });
46
47    return true;
48  }
49
50  function asi_getSmallestViewportWidth() {
51    // for the purpose of logic using this function, we want to know size of currently-viewable viewport
52    // different browsers report "viewable viewport" size inconsistently, sometimes reporting the entire (larger) document's size
53    // so we will look for the smallest number out of all relevant methods 
54    // except that iPhone safari aways reports width of phone in portrait mode, regardless of orientation, so smallest is always "width in portrait"
55    var jqW = $(window).width();
56    
57    var orientation = window.orientation !== undefined ? window.orientation : window.screen && window.screen.orientation ? window.screen.orientation.angle : undefined;
58
59    var wsW = window.screen.width;
60    var wsAw = window.screen.availWidth;
61    var wsH = window.screen.height;
62    var wsAh = window.screen.availHeight;
63    var wIw = window.innerWidth;
64    var ret = 9999;
65    if (jqW && jqW < ret) ret = jqW;
66    if (wsW && wsW < ret) ret = wsW;
67    if (wsAw && wsAw < ret) ret = wsAw;
68    if (wIw && wIw < ret) ret = wIw;
69
70    // this is a "heuristic" determination assuming that 1) entire documents fits in the viewport, 2) wsW was chosen as "smallest", but 3) phone is in landscape orientation and 4) (implicitely) that wsW < wsH 
71    // i.e. if this is a phone that always reports "width in portait mode as wsW", but phone is in landscape, overwrite the width to be wsH
72    if (Math.abs(orientation) === 90 && wsW < wsH && ret === wsW) {
73      ret = wsH;
74    }
75    return ret;
76  }
77
78  function setScreenWidth() {
79    var viewport = document.querySelector("meta[name=viewport]");
80    // at time of writing this correct report of asi_getSmallestViewportWidth() depends on width=device-width being present (chicken-and-egg problem)
81    // downside of unneccessarily changing viewport's content is unneccessary firing of "resize" event
82    // todo: consider finding a way to limit this condition further, body only executes when asi_getSmallestViewportWidth() is (or about to become) under mobile menu threshold
83    if (viewport) {
84      viewport.setAttribute('content', 'width=device-width, initial-scale=1.0');
85    }
86
87    window.asi_screenWidth = asi_getSmallestViewportWidth();
88  }
89
90  function addClass(e, className) {
91    if (!e) return;
92
93    if (typeof e.classList === "object") {
94      if (!e.classList.contains(className)) {
95        e.classList.add(className);
96      }
97    } else {
98      $(e).addClass(className);
99    }
100  }
101
102  function removeClass(e, className) {
103    if (!e) return;
104
105    if (typeof e.classList === "object") {
106      e.classList.remove(className);
107    } else {
108      $(e).removeClass(className);
109    }
110  }
111
112  function changeWindowClass() {
113    var viewport = document.querySelector('meta[name=viewport]');
114    if (!viewport) {
115      var metaTag = document.createElement('meta');
116      metaTag.name = 'viewport';
117      metaTag.content = '';
118      document.getElementsByTagName('head')[0].appendChild(metaTag);
119      viewport = document.querySelector('meta[name=viewport]');
120    }
121    var el = document.getElementsByTagName('body')[0];
122    if (window.asi_screenWidth <= 480) { // todo: consider evaluating actual media query
123      viewport.setAttribute('content', 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0');
124      if (buildMenu) {
125        consolidateMenus();
126        buildMenu = false;
127      }
128      removeClass(el, 'tablet');
129      addClass(el, 'mobile');
130    } else if (window.asi_screenWidth < 768) { // todo: consider evaluating actual media query
131      viewport.setAttribute('content', 'width=device-width, initial-scale=.45, user-scalable=yes');
132      removeClass(el, 'mobile');
133      addClass(el, 'tablet');
134    } else {
135      viewport.setAttribute('content', '');
136      removeClass(el, 'mobile');
137      removeClass(el, 'tablet');
138    }
139  }
140
141  changeWindowClass();
142
143  $(document).ready(function() {
144    $.ui.dialog.prototype.options.autoReposition = true;
145
146    // todo: consider evaluating actual media query
147    if (window.asi_screenWidth <= (parseInt(window.mobileMenuWidth) || 480)) {
148      consolidateMenus();
149    }
150
151    $(window).on('resize orientationchange', function(event) {
152      // idea is to a) handle only one of possibly many events during orientation change, and 
153      // b) give the browser a little time before we query for viewport size
154      if (window.asi_resizeHandlerLock) {
155        // don't do anything - already handled 
156        return;
157      }
158
159      //window.console.trace(event.type);
160      window.asi_resizeHandlerLock = true;
161      window.asi_resizeHandler = setTimeout(function() {
162        try {
163          var vpw = asi_getSmallestViewportWidth();
164          if (vpw === window.asi_screenWidth) {
165            return;
166          }
167          setScreenWidth();
168          changeWindowClass();
169          $('.ui-tooltip').remove(); // remove tooltips
170          $('.ui-dialog-content:visible').each(function() { // reposition modal
171            if ($(this).dialog) {
172              $(this).dialog('option', 'position', $(this).dialog('option', 'position'));
173            }
174          });
175        } finally {
176          window.asi_resizeHandlerLock = false;
177        }
178      }, 100);
179    });
180
181    $(document).on('click touchstart', function(event) {
182      if (!$(event.target).closest('#mobile-menu').length && !$(event.target).is('#mobile-menu')) {
183        if ($('#mobile-menu').hasClass('active')) {
184          $('#mobile-menu').removeClass('active');
185        }
186      }
187    });
188  });
189})(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.