PageSourceSearch

https://cityofnovi.org/scripts/global.js

js cityofnovi.org collected 2026-09-24 20:09:05 UTC 12,818 bytes, 392 lines download raw bytes

1// [Mobile] Focus on header search bar when displays
2
3var headerMobileSrcBtn = document.getElementById('headerSearchButton')
4var headerSrcBar = document.getElementById('headerSearchInput')
5
6if (headerMobileSrcBtn) {
7    headerMobileSrcBtn.addEventListener('click', () => {
8        headerSrcBar.focus()
9    })
10}
11
12
13// On scroll
14
15// var alertTopbar = document.getElementById('alertTopbar')
16var siteHeader = document.getElementById('siteHeader')
17var mobileMenuHelper = document.getElementById('btnNavMobileHelper')
18
19window.addEventListener('scroll', () => {
20
21    if (window.scrollY > 100) {
22        // if (alertTopbar) {
23        //     alertTopbar.classList.add('d-none')
24        // }
25        siteHeader.classList.add('sticky')
26    }
27    if (window.scrollY < 99) {
28        // if (alertTopbar) {
29        //     alertTopbar.classList.remove('d-none')
30        // }
31        siteHeader.classList.remove('sticky')
32    }
33    
34})
35
36
37// Custom contact form / error accessibility
38
39var alertScrollTo = document.querySelector('.alert-scrollto')
40
41if (alertScrollTo) {
42    alertScrollTo.scrollIntoView()
43}
44
45
46// Load-more button
47    
48for (var container of document.querySelectorAll('.loadmore-container')) {
49
50    var loadmoreItems = container.querySelectorAll('.loadmore-item')
51    var loadmoreBtn = container.querySelector('.loadmore-btn')
52    var splitStart = loadmoreBtn.getAttribute('data-split-start')
53
54    if (loadmoreItems.length > splitStart) loadmoreBtn.classList.remove('d-none')
55    
56    for (var i in loadmoreItems) {
57        if (i > splitStart - 1) loadmoreItems[i].classList.add('d-none')
58    }
59    
60    loadmoreBtn.addEventListener('click', event => {
61
62        var counter = event.target.getAttribute('data-split-size')
63        var eventTargetItems = event.target.closest('.loadmore-container').querySelectorAll('.loadmore-item')
64
65        for (var j in eventTargetItems) {
66
67            if (eventTargetItems[j].classList)
68            {
69                if (eventTargetItems[j].classList.contains('d-none') && (counter > 0)) {
70                    eventTargetItems[j].classList.remove('d-none')
71                    counter --
72                }
73    
74                if (!eventTargetItems[j].classList.contains('d-none') && j >= eventTargetItems.length -1) {
75                    event.target.classList.add('d-none')
76                }
77            }
78            
79        }
80
81    })
82
83}
84
85
86// Quick-Links bar that works with cookies
87
88var quicklinksBar = document.getElementById('quicklinksBar')
89var qlbarToggleButton = document.getElementById('qlbarToggleButton')
90var cookieQuicklinksBar = 'novicityquicklinksbar'
91
92if (quicklinksBar) {
93
94    if (!Cookies.get(cookieQuicklinksBar))
95        Cookies.set(cookieQuicklinksBar)
96    
97    if (Cookies.get(cookieQuicklinksBar) == 'undefined') {
98        var bsCollapse = new bootstrap.Collapse(quicklinksBar, {
99            show: true
100        })
101    }
102    
103    qlbarToggleButton.addEventListener('click', () => {
104        if (Cookies.get(cookieQuicklinksBar) == 'undefined')
105            Cookies.set(cookieQuicklinksBar, true)
106        else
107            Cookies.set(cookieQuicklinksBar)
108    })
109
110}
111
112
113// Home Hero Card Slider
114
115const homeHeroCardSwiper = new Swiper('.hero-card-slider', {
116    navigation: {
117        nextEl: '.hero-card-wrapper .swiper-button-next',
118        prevEl: '.hero-card-wrapper .swiper-button-prev'
119    },
120    keyboard: {
121        enabled: true
122    }
123})
124// checkSwiperNavigation(homeHeroCardSwiper, '.hero-card-navigation')
125
126
127// Home News Slideshow
128
129const homeNewsSwiper = new Swiper('.news-carousel', {
130    slidesPerView: 1,
131    spaceBetween: 10,
132    breakpoints: {
133        576: {
134            slidesPerView: 2
135        },
136        768: {
137            slidesPerView: 3
138        },
139        992: {
140            slidesPerView: 3,
141            spaceBetween: 20
142        },
143        1200: {
144            slidesPerView: 4,
145            spaceBetween: 30
146        }
147    },
148    navigation: {
149        nextEl: '.news-carousel-wrapper .swiper-button-next',
150        prevEl: '.news-carousel-wrapper .swiper-button-prev'
151    },
152    keyboard: {
153        enabled: true
154    }
155})
156
157
158// Park Gallery Slideshow
159
160const parkSlider = new Swiper('.park-slider', {
161    navigation: {
162        nextEl: '.park-slider .swiper-button-next',
163        prevEl: '.park-slider .swiper-button-prev'
164    },
165    keyboard: {
166        enabled: true
167    },
168    loop: true
169})
170// checkSwiperNavigation(parkSlider, '.swiper-navigation')
171
172
173// function checkSwiperNavigation(slider, navigation) {
174
175//     if (slider.slides.length <= 1) {
176//         var nav = document.querySelector(navigation)
177//         if (nav) nav.classList.add('d-none')
178//     }
179
180// }
181
182
183// Commission Application Form: show/hide checkboxes
184
185// document.addEventListener('DOMContentLoaded', function() {
186
187//     var bcafFieldsets = document.querySelectorAll('#form-4c4e6003-ede6-4950-a62f-ab0f7ea3e154 fieldset')
188
189//     for (set of bcafFieldsets) {
190//         var inputText = set.querySelector('.shortanswer input')
191//         var multiplechoice = set.querySelector('.shortanswer + .multiplechoice')
192
193//         if (inputText && multiplechoice) {
194//             inputText.addEventListener('input', event => {
195//                 if (event.target.value.trim() != '') {
196//                     event.target.closest('.shortanswer').nextElementSibling.classList.add('d-block')
197//                 } else {
198//                     event.target.closest('.shortanswer').nextElementSibling.classList.remove('d-block')
199//                 }
200//             })
201//         }
202//     }
203
204// })
205
206
207// Bootstrap Accordion helper script
208
209document.addEventListener('DOMContentLoaded', function() {
210
211    var accordions = document.querySelectorAll('.accordion')
212
213    for (accordion of accordions) {
214        var accordionId = accordion.getAttribute('id')
215        var accordionCollapses = accordion.querySelectorAll('.accordion-collapse')
216
217        for (collapse of accordionCollapses) {
218            collapse.setAttribute('data-bs-parent', `#${accordionId}`)
219        }
220    }
221
222    var tabAccordions = document.querySelectorAll('.accordion-to-tabs')
223
224    for (tab of tabAccordions) {
225        tab.querySelector('.accordion-button').classList.remove('collapsed')
226        tab.querySelector('.accordion-collapse').classList.add('show')
227    }
228
229})
230
231
232// Search popup
233
234document.addEventListener("DOMContentLoaded", function() {
235
236    var searchForm = document.getElementById('quickSearchModalForm')
237
238    searchForm.addEventListener('submit', function(event) {
239        
240        event.preventDefault()
241        
242        var query = document.getElementById('quickSearchModalInput').value
243        var filter = document.querySelector('input[name="radioQuickSearch"]:checked').getAttribute('data-filter')
244        
245        if (filter == "generic") {
246            // window.location.href = `/search?q=${query}&exactphrase=on&orderby=Most+recently+updated`            
247            window.location.href = `/search?query=${query}&mode=Exact+phrase&orderby=Most+recently+updated`
248        }
249
250        if (filter == "meetings") {
251            window.location.href = `/agendas-minutes?query=${query}&q="${query}"&mode=Exact+phrase`
252        }
253    })
254
255})
256
257
258// Google quick search
259
260/*var headerSearchForm = document.getElementById('headerSearchForm')
261var headerSearchInput = document.getElementById('headerSearchInput')
262var headerSearchQuery = headerSearchInput.value;
263var siteUrl = 'unovidev.muniweb.com';
264
265headerSearchInput.addEventListener('change', event => {
266    headerSearchQuery = event.target.value
267})
268
269headerSearchForm.addEventListener('submit', event => {
270    event.preventDefault()
271    var googleUrl = `https://www.google.com/search?q=${headerSearchQuery}+site%3A${siteUrl}`
272    window.open(googleUrl, '_blank')
273})*/
274
275
276// Tables
277
278var tables = document.querySelectorAll('table:not([class]):not([id])')
279
280for (table of tables) {
281    if (!table.classList.contains('table')) {
282        table.classList.add('table')
283    }
284}
285
286
287// Fix wrong links to map gallery page
288
289document.querySelectorAll('a[href^="https://novi.maps.arcgis.com/apps/webappviewer"]').forEach(function(a) { // with https
290    a.setAttribute('href', '/community/map-gallery')
291    a.setAttribute('target', '_self')
292})
293document.querySelectorAll('a[href^="http://novi.maps.arcgis.com/apps/webappviewer"]').forEach(function(a) { // without https
294    a.setAttribute('href', '/community/map-gallery')
295    a.setAttribute('target', '_self')
296})
297
298
299// Do Not Knock Registry
300
301const txtStreetNumber = document.getElementById('doNotKnock_txtstreetnumber');
302const selStreetName = document.getElementById('doNotKnock_selstreetname');
303const doNotKnock_streetname = document.getElementById('doNotKnock_streetname');
304const doNotKnock_suffix = document.getElementById('doNotKnock_suffix');
305const doNotKnock_streetdir = document.getElementById('doNotKnock_streetdir');
306const doNotKnock_apartment = document.getElementById('doNotKnock_apartment');
307const doNotKnock_city = document.getElementById('doNotKnock_city');
308const doNotKnock_state = document.getElementById('doNotKnock_state');
309const doNotKnock_zip = document.getElementById('doNotKnock_zip');
310const data = localStorage.getItem("residentialtaxable");
311var taxable_data = JSON.parse(data);
312var select_streetnumber = "";
313if (txtStreetNumber != null) {
314    txtStreetNumber.addEventListener('change', (event) => {
315        select_streetnumber = event.target.value;
316        var search_result = taxable_data.filter(function (entry) {
317            return entry.Number === event.target.value;
318        });
319        if (search_result[0] != null) {
320            let ele = selStreetName;
321            removeOptions(selStreetName);
322            for (let i = 0; i < search_result.length; i++) {
323                ele.innerHTML = ele.innerHTML +
324                    '<option value="' + search_result[i]['Name'] + '">' + search_result[i]['Name'] + ' ' + search_result[i]['StreetSuffix'] + ' ' + search_result[i]['StreetDir'] + ' ' + search_result[i]['Apartment'] + '</option>';
325            }
326        }
327        var search_result_value = taxable_data.filter(function (entry) {
328            return entry.Name === selStreetName.value && entry.Number === select_streetnumber;
329        });
330        if (search_result_value[0] != null) {
331            doNotKnock_streetname.value = search_result_value[0].Name + ' ' + search_result_value[0].StreetSuffix + ' ' + search_result_value[0].StreetDir + ' ' + search_result_value[0].Apartment;
332            doNotKnock_suffix.value = search_result_value[0].StreetSuffix;
333            doNotKnock_streetdir.value = search_result_value[0].StreetDir;
334            doNotKnock_apartment.value = search_result_value[0].Apartment;
335            doNotKnock_city.value = search_result_value[0].City;
336            doNotKnock_state.value = search_result_value[0].State;
337            doNotKnock_zip.value = search_result_value[0].Zip;
338        }
339    })
340    if (selStreetName != null) {
341        selStreetName.addEventListener('change', (event) => {
342            var search_result = taxable_data.filter(function (entry) {
343                return entry.Name === event.target.value && entry.Number === select_streetnumber;
344            });
345            if (search_result[0] != null) {
346                doNotKnock_streetname.value = search_result[0].Name + ' ' + search_result[0].StreetSuffix + ' ' + search_result[0].StreetDir + ' ' + search_result[0].Apartment;
347                doNotKnock_suffix.value = search_result[0].StreetSuffix;
348                doNotKnock_streetdir.value = search_result[0].StreetDir;
349                doNotKnock_apartment.value = search_result[0].Apartment;
350                doNotKnock_city.value = search_result[0].City;
351                doNotKnock_state.value = search_result[0].State;
352                doNotKnock_zip.value = search_result[0].Zip;
353            }
354        })
355    }
356}
357function removeOptions(selectElement) {
358   var i, L = selectElement.options.length - 1;
359   for(i = L; i >= 0; i--) {
360      selectElement.remove(i);
361   }
362}
363
364
365// Search keywords log
366/*
367const quickSearchModalInput = document.getElementById('quickSearchModalInput');
368   if(quickSearchModalInput != null){
369  quickSearchModalInput.addEventListener('change', function () {
370      fetch('/?altTemplate=usersearchlog&searchkey='+ quickSearchModalInput.value, {
371        method: 'GET'
372    });
373  });
374   }
375 
376   const headerSearchInput = document.getElementById('headerSearchInput');
377   if(headerSearchInput != null){
378  headerSearchInput.addEventListener('change', function () {
379      fetch('/?altTemplate=usersearchlog&searchkey='+ headerSearchInput.value, {
380        method: 'GET'
381    });
382  });
383   }
384  
385  const searchInput = document.getElementById('searchInput');
386  if(searchInput != null){
387  searchInput.addEventListener('change', function () {
388      fetch('/?altTemplate=usersearchlog&searchkey='+ searchInput.value, {
389        method: 'GET'
390    });
391  });
392    }*/

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.