PageSourceSearch

https://www.cityofbelmont.org/wp-content/plugins/wp-proud-core/mod…/assets/js/proud-navbar.js?ver=7.1.2

js cityofbelmont.org collected 2026-10-02 10:37:13 UTC 7,045 bytes, 243 lines download raw bytes

1(function($, Proud) {
2
3  // Proudnav
4  var proudNav = (function() {
5
6    var layerOpen = {
7      menu: false,
8      search: false,
9      answers: false,
10    },
11    layerClasses = {
12      'menu': 'menu-nav-open',
13      'search': 'search-active',
14      'answers': 'active-311'
15    },
16    $body,
17    self = {};
18
19    // Closes overlays + menus
20    // localLayers = ['menu', 'search']
21    self.closeLayers = function(localLayers, callback) {
22      // Default is all
23      localLayers = localLayers || lodash.keys(layerOpen);
24      var classes = [];
25      lodash.map(localLayers, function(layer) {
26        classes.push(layerClasses[layer]);
27        layerOpen[layer] = false;
28      });
29      // Remove
30      $body.removeClass(classes.join(' '));
31      if(callback) {
32        callback();
33      }
34    };
35
36    // Closes overlays + menus
37    self.openLayer = function(layer, callback) {
38      setTimeout(function() {
39        $body.addClass(layerClasses[layer]);
40        layerOpen[layer] = true;
41        $body.trigger('scroll');
42        if(callback) {
43          callback();
44        }
45      }, 50);
46    };
47
48    self.toggleMenu = function() {
49      // Just close everything
50      if(layerOpen.menu) {
51        self.closeLayers();
52        return;
53      }
54      else {
55        self.closeLayers(['answers', 'search']);
56        self.openLayer('menu');
57      }
58    };
59
60    self.toggleOverlay = function(item, callback) {
61      var thisLayer, otherLayer;
62      switch(item) {
63        case 'answers':
64        case 'payments':
65        case 'report':
66        case 'status':
67          thisLayer = 'answers';
68          otherLayer = 'search';
69          break;
70
71        case 'search':
72          thisLayer = 'search';
73          otherLayer = 'answers';
74          break;
75      }
76
77      // Close all
78      if(layerOpen[thisLayer]) {
79        self.closeLayers(null, callback);
80      }
81      else {
82        // Close others, open ours
83        self.closeLayers([otherLayer, 'menu'], callback);
84        self.openLayer(thisLayer, callback);
85      }
86    };
87
88    self.triggerOverlay = function(data, hash, classOverride) {
89      if(classOverride) {
90        layerClasses[data] = classOverride;
91      }
92
93      $body.trigger({
94        type:     "proudNavClick",
95        event:    data,
96        hash:     hash,
97        callback: function(open, scrollId, scrollOffset, forceClose, callback) {
98          // Scrollto id
99          if(scrollId) {
100            var $scroll = $("#" + scrollId),
101                scrollOffset = scrollOffset || 0,
102                offset = $body.hasClass('admin-bar') ? 170 : 100;
103            if($scroll.length) {
104              $('html, body').animate({
105                  scrollTop: $scroll.offset().top - (offset + scrollOffset)
106              }, 200);
107            }
108          }
109          // Oper layer
110          if(open) {
111            self.toggleOverlay(data, callback);
112          }
113          // Force close layers
114          if(forceClose) {
115            self.closeLayers(forceClose, callback);
116          }
117        }
118      });
119    };
120
121    // Align the fixed hamburger with the visible logo row.
122    //
123    // On topbar-enabled sites the action toolbar lives inside the topbar, whose
124    // height changes with viewport width: the official statement and action
125    // icons sit on one row when wide and wrap to two rows when narrow. The
126    // hamburger is position:fixed, so a static CSS top can't track that. Measure
127    // the logo row (.navbar-header-region) and centre the button on it. Using
128    // the rect also accounts for the admin bar automatically. Non-topbar sites
129    // keep their CSS offset untouched.
130    self.positionMenuButton = function() {
131      // Run for both topbar layouts: the full topbar (proud-navbar-topbar-active)
132      // and the default mobile-only top bar (proud-navbar-topbar-mobile-only-active).
133      // The latter relied on static CSS offsets that ignored the WordPress admin
134      // bar, so the fixed button drifted off the logo row when logged in.
135      if (!$body ||
136          (!$body.hasClass('proud-navbar-topbar-active') &&
137           !$body.hasClass('proud-navbar-topbar-mobile-only-active'))) {
138        return;
139      }
140      var $button = $('#menu-button');
141      var region = document.querySelector('.navbar-header-region');
142      if (!$button.length || !region) {
143        return;
144      }
145      // Only when the mobile hamburger is showing; clear our override otherwise
146      // so the desktop layout is unaffected.
147      if ($button.css('display') === 'none') {
148        $button.css('top', '');
149        return;
150      }
151      var r = region.getBoundingClientRect();
152      var top = r.top + window.pageYOffset + (r.height - $button.outerHeight()) / 2;
153      $button.css('top', Math.round(top) + 'px');
154    };
155
156    $(document).ready(function() {
157      $body = $('body');
158
159      // Listen for esc key
160      $body.keydown(function(e) {  //keypress did not work with ESC;
161        if (e.which == '27') {
162          var closing = true;
163          lodash.map(layerOpen, function(val) {
164            if(val && closing) {
165              self.closeLayers();
166              closing = false;
167            }
168          });
169        }
170      });
171
172      self.positionMenuButton();
173      $(window).on(
174        'resize.proudNavbarButton orientationchange.proudNavbarButton load.proudNavbarButton',
175        function() { self.positionMenuButton(); }
176      );
177    })
178
179    return self;
180  })();
181
182  Proud.proudNav = proudNav;
183
184  Proud.behaviors.proudNavbar = { attach: function(context, settings) {
185
186    var $body = $('body');
187
188    // Click top buttons
189    $('[data-proud-navbar]').once('proud-navbar', function() {
190      var $self = $(this);
191      $self.click(function(e) {
192        // Allow for link override
193        if(!$self.data('click-external')) {
194          e.preventDefault();
195          var data = $self.data('proud-navbar');
196
197          if(data) {
198            proudNav.triggerOverlay(data, $self.data('proud-navbar-hash'));
199          }
200        }
201      });
202    });
203
204    // Focus out timer
205    var menuItemTimer = null;
206
207    // mobile menu open
208    $('#menu-button').once('proud-navbar', function() {
209      $(this).click(function(e) {
210        e.preventDefault();
211        if (menuItemTimer) {
212          clearTimeout(menuItemTimer);
213        }
214        if(!$body.hasClass('menu-nav-open')) {
215          $('#main-menu').children(":first").children().focus();
216        }
217        proudNav.toggleMenu();
218      });
219    });
220
221    // On main menu focus (tabbing) open up menu
222    $('#main-menu').once('proud-main-menu', function() {
223      $('a', $(this)).on('focusin', function () {
224        clearTimeout(menuItemTimer);
225        proudNav.openLayer('menu');
226      }).on('focusout', function () {
227        menuItemTimer = setTimeout(function() {
228          proudNav.closeLayers(['menu']);
229        }, 100);
230      });
231    });
232
233    // close overlay
234    $('#overlay-311-close, #overlay-search-close').once('proud-navbar', function() {
235      $(this).click(function(e) {
236        e.preventDefault();
237        proudNav.closeLayers();
238      });
239    });
240
241  }};
242})(jQuery, Proud);
243

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.