PageSourceSearch

https://www.hennepinattorney.org/assets/js/main.js?v=2.43

js hennepinattorney.org collected 2026-10-02 04:29:57 UTC 71,221 bytes, 1,684 lines download raw bytes

1(function ($, hco) {
2
3    $(document).ready(function () {
4
5        hco.DesktopSize = 950;
6
7        hco.UberBg.init();
8        hco.SlideOutNav.init();
9        hco.Tabble.init();
10        hco.HorizontalTabbedModal.init();
11        hco.SearchPop.init();
12        hco.DrawerOpener.init();
13        hco.SimpleSlideShow.init();
14        hco.AutoReplace.init();
15        hco.BtnScrollTop.init();
16        hco.StickyNav.init();
17        hco.SmoothScroll.init();
18
19
20
21        //Causes IE8 to redraw all :before and :after psedo elements. 
22        //Fixes font icon size glitch.
23        if ($(".lt-ie9").length > 0) {
24            var head = document.getElementsByTagName('head')[0],
25                style = document.createElement('style');
26            style.type = 'text/css';
27            style.styleSheet.cssText = ':before,:after{content:none !important';
28            head.appendChild(style);
29            setTimeout(function () {
30                head.removeChild(style);
31            }, 0);
32        }
33    });
34
35    //redirect covid hash link
36    if (window.location.href.indexOf('#closures-disruptions') > -1) {
37        window.location.assign('https://www.hennepin.us/covid-19')
38    }
39
40    // Change site title and home link for sheriff's site
41    var docUrl = document.URL;
42    if (docUrl.indexOf("sheriff") != -1) {
43        $('.site-title a').html("Hennepin County Sheriff's Office");
44    }
45
46    // if there is no home page slider content, remove overlay 
47    var sliderOverlay = $('.overlay-slider > .content-wrapper > .overlay-slider__slide');
48    function removeOverlay() {
49        if ($(sliderOverlay).length == 0) {
50            $('.overlay-slider').hide();
51        };
52    }
53    removeOverlay();
54
55
56    //mobile - if no sub-nav, make main nav the link
57    $(document).ready(function () {
58        function modifyNav() {
59            $('.popout-nav').find('.nav-stack').each(function () {
60                if ($(this).find('ul').length == 0) {
61                    //$(this).parent().hide();
62                    $(this).parent().parent().find('a').hide();
63                    $(this).parent().show().removeClass('sub-nav').addClass('sub-nav__none');
64                    $(this).prev().find('a').show();
65                }
66            });
67            if (jQuery('.popout-nav .drawer > li.current').length) {
68                $('.popout-nav').prepend('<a class="skip-to-link" href="#skip-secondary-nav">Skip secondary nav</a>').append('<span id="skip-secondary-nav" class="sr-only" tabindex="-1"></span>');
69            }
70            var isMobile = window.matchMedia('(max-width: ' + hco.DesktopSize + 'px)').matches;
71            if (isMobile) {
72                // console.log($('#skip-main-nav').length);
73                $('.page').eq(0).before($('#skip-main-nav'));
74            }
75        }
76        modifyNav();
77    });
78
79    // set min-height so module grid is at least same height at vertical tabs
80    $(document).ready(function () {
81        var $window = $(window);
82
83        function checkWidth() {
84            var windowsize = $window.width();
85            if (windowsize > 950) {
86                $('.tabbed--vertical').each(function () {
87                    var verticalNav = $(this).find('nav.tabbed__nav').height();
88                    $(this).find('.module-grid').css('min-height', verticalNav);
89                });
90            }
91            else {
92                $('.tabbed--vertical').each(function () {
93                    $(this).find('.module-grid').css('min-height', '0');
94                });
95            }
96        }
97        checkWidth();
98        $(window).resize(checkWidth);
99    });
100
101    // Accordion for Police Legal Resources legal terms list
102    $(".show-more-link a").on("click", function () {
103        var $link = $(this);
104        var $content = $link.parent().prev("div.azContent");
105        var linkText = $link.text();
106
107        $content.toggleClass("expand");
108        $link.toggleClass("show-less");
109        $link.text(getShowLinkText(linkText));
110
111        return false;
112    });
113
114    function getShowLinkText(currentText) {
115        var newText = '';
116        if (currentText.toUpperCase() === "SHOW MORE") {
117            newText = "Show less";
118        } else {
119            newText = "Show more";
120        }
121        return newText;
122    }
123
124    //Set focus for GovDelivery field
125    var emailInput = $('.subscribe-email-field');
126    var defaultFocus = false;
127    var hasFocus = defaultFocus;
128
129    emailInput.focus(function () {
130        hasFocus = true;
131
132        return hasFocus;
133    });
134
135    emailInput.blur(function () {
136        hasFocus = false;
137        return hasFocus;
138    });
139
140    //Validate GovDelivery email submission
141    $(document).ready(function () {
142        if (!$('#subscribe-success').is(':visible')) {
143            $('#subscribe-submit').click(function () {
144                var sEmail = $('#email').val();
145                if ($.trim(sEmail).length == 0) {
146                    $('#subscribe-invalid-email').show();
147                    $(".subscribe-email-field").focus();
148                    return false;
149                }
150                if (validateEmail(sEmail)) {
151                    $('#subscribe-success').show();
152                    $('#GD-snippet-form').hide();
153                    $('#subscribe-invalid-email').hide();
154                    $('#subscription-description').hide();
155                }
156                else {
157                    $('#subscribe-invalid-email').show();
158                    $(".subscribe-email-field").focus();
159                    return false;
160                }
161            });
162        }
163    });
164    $(document).ready(function () {
165        $('li.pub_date:contains("6/19/2020 01:38")').parent().parent().parent().remove();
166        $('li.pub_date:contains("6/19/2020 10:52")').parent().parent().parent().remove();
167        $('li.pub_date:contains("6/19/2020 10:37")').parent().parent().parent().remove();
168    });
169    function validateEmail(sEmail) {
170        var filter = /^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$/;
171        if (filter.test(sEmail)) {
172            return true;
173        }
174        else {
175            return false;
176        }
177    }
178
179
180    /* ---------------------------------------------------------------------
181    DrawerOpener
182    Author: Nick Charbonneau
183    Generic class toggler intended for opening hidden drawer content 
184    Note: Trigger must be the direct descendant of the single drawer container
185    
186    .drawer (outer wrapper)
187        <article> (single drawer container, will have open class added here)
188            a.drawer__handle (trigger)
189            div.drawer__inner (generic container for layout, unimportant to this script)
190                -content-
191        </article>
192        <article> 
193            a.drawer__handle 
194            div.drawer__inner
195                -content-
196        </article>
197    
198    ------------------------------------------------------------------------ */
199    hco.DrawerOpener = {
200        $options: {
201            parentClass: 'drawer',
202            triggerClass: 'drawer__handle',
203            singleFlag: 'drawer--single',
204            hasOpenFlag: 'drawer--has-open',
205            collapserClass: 'drawer__closer',
206            openerClass: 'drawer__opener',
207            togglerClass: 'drawer__toggler',
208            activeClass: 'open'
209        },
210        updateTogglerText: function (parent) {
211            var self = this;
212            var $parent = parent;
213            var $articles = $parent.find('article');
214            var $toggler = $parent.find('.' + self.$options.togglerClass);
215            var text = ($articles.hasClass(self.$options.activeClass)) ? 'Close all' : 'Open all';
216            var ariaLabel = ($articles.hasClass(self.$options.activeClass)) ? 'close all drawers' : 'open all drawers';
217            $toggler.text(text);
218            $toggler.attr("aria-label", ariaLabel);
219        },
220        init: function (opt) {
221            var self = this;
222            self.$options = $.extend(self.$options, opt);
223            if ($('.' + self.$options.parentClass).length > 0) {
224                var targets = $('.' + self.$options.parentClass).find($('.' + self.$options.triggerClass));
225                var isMobile = navigator.userAgent.match(/(iPhone|iPod|iPad|Android|BlackBerry)/);
226
227                //catches url #id on page load
228                if (window.location.hash && !/\/search/i.test(location.pathname)) {
229                    var _hashLoc = $(decodeURI(window.location.hash));
230                    if (_hashLoc.length) {
231                        if (_hashLoc.parent().hasClass(self.$options.parentClass)) {
232                            _hashLoc.addClass(self.$options.activeClass)
233                                .find('.' + self.$options.triggerClass + ' a')
234                                .attr('aria-expanded', 'true');
235                        } else {
236                            var padding = Number(_hashLoc.css('padding-top').replace(/[^-\d\.]/g, ''));
237                            var oTop = Number(_hashLoc.offset().top);
238                            var _targetOffset = padding + oTop;
239                            // console.log(padding, oTop, _targetOffset);
240                            window.scrollTo(0, _targetOffset);
241
242                            /**********************************
243                            * This is a janky fix to account for
244                            * the scrollTop position of the _hashLoc
245                            * variable changing. I've spend too much
246                            * time trying to figure out why it's
247                            * changing and I need to move on. 750ms 
248                            * seems to be enough time to consistantly
249                            * account for the change in value. 
250                            * Sorry for the hacky solution. 
251                            ***********************************/
252                           
253                            // recalculate scrollTo position
254                            setTimeout(function() {
255                                padding = Number(_hashLoc.css('padding-top').replace(/[^-\d\.]/g, ''));
256                                oTop = Number(_hashLoc.offset().top);
257                                _targetOffset = padding + oTop;
258                                // console.log(padding, oTop, _targetOffset);
259                                // window.scrollTo(0, _targetOffset);
260                                $('html, body').animate({
261                                    scrollTop: _targetOffset
262                                }, 500);
263                            }, 750);
264
265                        }
266                    }
267                }
268
269                //catches links on the same page.
270                $('a[href*=#]')
271                    .not(targets)
272                    .not('.skip-to-link')
273                    .not('[role="tab"]')
274                    .click(function (_evt) {
275                        var _self = $(this);
276                        if (_self.attr('href').length < 2) { return; }//check for empty links
277                        if (_self.parents('.page-nav').length > 0) { return; }//check for nav item
278                        var _internalTarget = $(_self.attr('href'));
279                        var _path = window.location.pathname; //Catch self reference links
280                        if (_internalTarget.length < 1 && _self.attr('href').split('#')[0] == _path.match(_self.attr('href').split('#')[0])[0]) { //Catch self reference links
281                            _internalTarget = $('#' + _self.attr('href').split('#')[1]);
282                        }
283                        if (_internalTarget.length < 1) { return; }//catch all for bad destinations
284                        _evt.preventDefault();
285
286                        $('html, body').animate({
287                            scrollTop: _internalTarget.offset().top
288                        }, 800);
289                        _internalTarget.addClass(self.$options.activeClass);
290                        document.location.hash = _self.attr('href').split('#')[1];
291                    });
292                //main bind
293                $.each(targets, function (i, v) {
294                    var $this = $(v);
295                    if (!isMobile && $this.parents('.main-nav').length > 0) {
296                        // self.hoverBind($this);
297                        self.clickBind($this);
298                    } else {
299                        self.bind($this);
300                        // set aria-expanded=true if drawer loads with activeClass
301                        if ($this.parent().hasClass(self.$options.activeClass)) {
302                            $this.find('a').attr('aria-expanded', 'true');
303                        }
304                    }
305                });
306                $(document).on('click', function(e) {
307                    if ($(e.target).closest('.main-nav .page-nav').length) return;
308                    $('.main-nav .' + self.$options.parentClass + ' .' + self.$options.activeClass).removeClass(self.$options.activeClass);
309                    $('.main-nav').removeClass(self.$options.hasOpenFlag);
310                });
311                //Collapse all link
312                var $toggler = $('.' + self.$options.togglerClass);
313                // set initial collapse text
314                for (var i = 0; i < $('.' + self.$options.parentClass).length; i++) {
315                    var $drawer = $($('.' + self.$options.parentClass)[i]);
316                    if ($drawer.length !== 1 || $drawer.find('span[role="alert"]').length !== 1) continue;
317                    var statusID = 'drawerStatus-' + i;
318                    $drawer.find('span[role="alert"]').attr('id', statusID);
319                    $drawer.find('.' + self.$options.togglerClass).attr('aria-describedby', statusID);
320                    self.updateTogglerText($drawer);
321                }
322                $toggler.on("click", function (evt) {
323                    evt.preventDefault();
324                    var $this = $(this);
325                    var $parent = $this.closest('.' + self.$options.parentClass);
326                    var openDrawers = $parent.find(' article.' + self.$options.activeClass).length;
327                    var $articles = $parent.find('article');
328                    var $drawerStatus = $('#' + $this.attr('aria-describedby'));
329                    // if the any of the drawers are open     
330                    if (openDrawers) {
331                        $articles.removeClass(self.$options.activeClass)
332                            .find('.' + self.$options.triggerClass + ' a')
333                            .attr('aria-expanded', 'false');
334                        if ($drawerStatus.length) $drawerStatus.text('All information collapsed');
335                    } else {
336                        $articles.addClass(self.$options.activeClass)
337                            .find('.' + self.$options.triggerClass + ' a')
338                            .attr('aria-expanded', 'true');
339                        if ($drawerStatus.length) $drawerStatus.text('All information expanded');
340                    }
341                    self.updateTogglerText($parent);
342                    setTimeout(function () {
343                        if ($drawerStatus.length) $drawerStatus.text('');
344                    }, 1000);
345
346                });
347
348            };
349        },
350        bind: function ($caller) {
351            var self = this;
352
353            $caller.on("click.DrawerOpener.hco", function (e) {
354                if ($caller.parent().hasClass(self.$options.activeClass) && $(this).parents('.' + self.$options.singleFlag).length > 0) {
355                    $(this).parents('.' + self.$options.singleFlag).find('.' + self.$options.triggerClass).parent().removeClass(self.$options.activeClass);
356                    openCheck();
357
358                    e.preventDefault();
359                    return;
360                }
361                //If Single flag
362                $(this).parents('.' + self.$options.singleFlag).find('.' + self.$options.triggerClass).parent().removeClass(self.$options.activeClass);
363
364                if ($(this).parent().hasClass(self.$options.activeClass)) {
365                    $(this).parent()
366                        .removeClass(self.$options.activeClass)
367                        .find('.' + self.$options.triggerClass + ' a')
368                        .attr('aria-expanded', 'false');
369                } else {
370                    $(this).parent()
371                        .addClass(self.$options.activeClass)
372                        .find('.' + self.$options.triggerClass + ' a')
373                        .attr('aria-expanded', 'true');
374                }
375
376                openCheck();
377                self.updateTogglerText($(this).closest('.' + self.$options.parentClass));
378
379                e.preventDefault();
380
381
382            });
383            function openCheck() {
384                if ($caller.parents('.main-nav').find('.open').length > 0) {
385                    $caller.parents('.main-nav').addClass(self.$options.hasOpenFlag);
386                } else {
387                    $caller.parents('.main-nav').removeClass(self.$options.hasOpenFlag);
388                }
389            }
390        },
391        hoverBind: function ($caller) {
392            var self = this;
393            $caller.mouseenter(
394                function () {
395                    $caller.parent().parent().children().removeClass(self.$options.activeClass);
396                    $caller.parents('.main-nav').removeClass(self.$options.hasOpenFlag);
397                    //disable top sub-nav hover if no items
398                    var subnavlength = $caller.parent().find('.nav-stack > ul').length;
399                    if (subnavlength > 0) {
400                        $caller.parent().addClass(self.$options.activeClass);
401                        $caller.parents('.main-nav').addClass(self.$options.hasOpenFlag);
402                    }
403
404                    $caller.parent().children('.sub-nav').mouseleave(function () {
405                        $caller.parent().removeClass(self.$options.activeClass);
406                        $caller.parents('.main-nav').removeClass(self.$options.hasOpenFlag);
407                    })
408
409                }
410            );
411            $('.main-nav .page-nav').mouseleave(function () {
412                $caller.parent().parent().children().removeClass(self.$options.activeClass);
413                $caller.parents('.main-nav').removeClass(self.$options.hasOpenFlag)
414            });
415
416        },
417        clickBind: function ($caller) {
418            var $subNav = $caller.parent().find('.nav-stack > ul');
419            if (!$subNav.length) return;
420
421            var self = this;
422            if ($caller.attr('href')) {
423                $subNav.last().append('<li class="exploreLink"><a href="' + $caller.attr('href') + '">Explore topic</a></li>');
424            }
425            $caller
426                .wrapInner('<div class="main-nav-label" />')
427                .addClass('has-sub-nav')
428                .attr('role', 'button')
429                .attr('aria-expanded', 'false')
430                .click(function (e) {
431                    e.preventDefault();
432                    if ($caller.parent().hasClass(self.$options.activeClass)) {
433                        // close that nav item
434                        $caller.attr('aria-expanded', 'false').parent().removeClass(self.$options.activeClass);
435                        $caller.parents('.main-nav').removeClass(self.$options.hasOpenFlag);
436                    } else {
437                        // open that nav item
438                        $caller.parent().siblings().removeClass(self.$options.activeClass).find('.has-sub-nav.' + self.$options.triggerClass).attr('aria-expanded', 'false');
439                        $caller.attr('aria-expanded', 'true').parent().addClass(self.$options.activeClass);
440                        $caller.parents('.main-nav').addClass(self.$options.hasOpenFlag);
441                    }
442
443                });
444
445        }
446    };
447
448
449
450    /* ---------------------------------------------------------------------
451    SlideOutNav
452    Author: Nick Charbonneau
453    Replicates slide over nav interaction common in native mobile apps.
454    Note:Uses the href on the trigger to find the target nav container by name attr.
455    ------------------------------------------------------------------------ */
456
457    hco.SlideOutNav = {
458        $options: {
459            staticNavClass: 'main-nav',
460            parentClass: 'popout-nav',
461            triggerClass: 'popout-nav--trigger',
462            activeClass: 'popout-nav--open',
463            pageWrapper: 'page-wrapper',
464         
464   pageHeader: 'site-header'
465        },
466        init: function (opt) {
467            var self = this;
468            self.$options = $.extend(self.$options, opt);
469            if ($('.' + self.$options.staticNavClass).length > 0) {
470                var navTrigger = $('.' + self.$options.triggerClass),
471                    navOrg = $('[name*="' + navTrigger.attr('href').replace('#', '') + '"]');
472
473                // self.modLocInDOM(navOrg, 'body');
474                //self.modLocInDOM(navOrg, '.page-wrapper');
475                navOrg.clone().insertAfter('.site-header').removeClass().addClass(this.$options.parentClass);
476                var navRoot = $('.' + self.$options.parentClass);
477                self.bind(navTrigger, navRoot);
478
479                // prevent multiple IDs from being copied into the side nav
480                if (navRoot.find('#skip-main-nav').length) navRoot.find('#skip-main-nav').remove();
481
482            };
483        },
484        bind: function ($navTrigger, $navRoot) {
485            var self = this;
486            $navTrigger.on("click.SlideOutNav", function () {
487                self.showHideNav(self, $navRoot);
488            });
489        },
490        showHideNav: function (self, $navRoot) {
491            var initialTop = $(window).scrollTop();
492            if ($navRoot.hasClass(self.$options.activeClass)) {
493                movePage(- $navRoot.width());
494                $(window).off("scroll.SlideOutNav");
495                $('.' + self.$options.triggerClass).removeClass(self.$options.activeClass);
496            } else {
497                var curTop = null,
498                    newTop = null,
499                    lastPos = 0;
500
501                $navRoot.on("click.SlideOutNav", 'a', function () {
502                    if (!$(this).hasClass('drawer__handle')) {
503                        movePage(- $navRoot.width());
504                        $('.' + self.$options.triggerClass).removeClass(self.$options.activeClass);
505                    }
506                });
507
508                //Position navRoot to the static bar
509                $navRoot
510                    .css(
511                        'top', initialTop + 'px'
512                    )
513                    .addClass(self.$options.activeClass);
514
515                $('.site-search--trigger').hide();
516
517                //Scroll Loop
518                $(window).on("scroll.SlideOutNav", function (e) {
519                    curTop = $(window).scrollTop();
520
521                    if (curTop < parseInt($navRoot.css('top'), 10) && curTop < newTop && $navRoot.hasClass(self.$options.activeClass)) { //scroll up
522                        //lock to top of screen
523                        $navRoot.css(
524                            'top', curTop + 'px'
525                        );
526                    }
527                    /*
528                    if (curTop > (parseInt($navRoot.css('top'), 10) + $navRoot.height()) && $navRoot.hasClass(self.$options.activeClass)) {
529                        $navRoot.css({
530                            left: - $navRoot.width()
531                        }).removeClass(self.$options.activeClass);
532                        $('.site-search--trigger').show();
533                        $('.' + self.$options.triggerClass).removeClass(self.$options.activeClass);
534
535                    }
536                    */
537
538                    newTop = curTop;
539                });
540                movePage(0);
541            }
542
543            function movePage(offset) {
544                //Close the Search bar it it's open.
545                if ($('.' + self.$options.pageHeader).hasClass('site-search--active')) {
546                    $('.site-search--trigger').trigger("click.SearchPop");
547                }
548                $('.' + self.$options.triggerClass).addClass(self.$options.activeClass);
549                $('.' + self.$options.parentClass).animate({
550                    left: offset
551                }, self.$options.animateTime, function () {
552                    if (offset != 0) { //if closing the nav, remove open class
553                        $navRoot.removeClass(self.$options.activeClass);
554                        $('.site-search--trigger').show();
555                    }
556                });
557
558            }
559
560        },
561        modLocInDOM: function ($targ, dest) {
562
563            $targ.clone().appendTo(dest).removeClass().addClass(this.$options.parentClass);
564            return $targ;
565        }
566    };
567
568    /* ---------------------------------------------------------------------
569    Tabble
570    Author: Nick Charbonneau
571    Uses the href on tab links to open the correct tab page by name. 
572    -This leaves a fallback for screen readers.
573    
574    Note: Pretty well abstracted, just watch out for 2 identical href's/name attr's
575        on the same page. Also, the tabbed nav and pages must be the descendants of
576        the tabbed container. 
577    ------------------------------------------------------------------------ */
578
579    hco.Tabble = {
580        $options: {
581            parentClass: 'tabbed',
582            pageClass: 'tabbed__page',
583            tabContainer: 'tabbed__nav',
584            menuActive: 'tabbed__nav--active',
585            activeClass: 'tabbed--active',
586            inactiveClass: 'tabbed--inactive',
587            verticalNav: 'tabbed--vertical'
588        },
589        init: function (opt) {
590            var self = this;
591            self.$options = $.extend(self.$options, opt);
592            var $parent = $('.' + self.$options.parentClass);
593            if ($parent.length < 1) return;
594            var isMobile = window.matchMedia('(max-width: ' + hco.DesktopSize + 'px)').matches;
595            $parent.each(function (i, v) {
596                var $this = $(v);
597                var orientation = ($this.is('.' + self.$options.verticalNav) || isMobile) ? 'vertical' : 'horizontal';
598                $this.find('.' + self.$options.tabContainer + ' > ul').attr({
599                    'role': 'tablist',
600                    'aria-orientation': orientation
601                }).find('> li').attr({
602                    'role': 'presentation'
603                });
604                self.bind($this);
605            });
606            // set initial a11y attributes
607            $parent.find('.' + self.$options.tabContainer + ' a').each(function(i, e) {
608                var $this = $(e);
609                var tabindex = $this.is('.' + self.$options.activeClass) ? '0' : '-1';
610                var selected = $this.is('.' + self.$options.activeClass) ? 'true' : 'false';
611                var control = 'tab' + i;
612                var name = $this.attr('href') ? $this.attr('href').replace('#', '') : control;
613      
614                $this.attr({
615                    'tabindex': tabindex,
616                    'aria-selected': selected,
617                    'aria-controls': control,
618                    'role': 'tab'
619                })
620                .closest('.' + self.$options.parentClass)
621                .find('.tabbed__page[name="' + name + '"]')
622                .attr({
623                    'id': control,
624                    'role': 'tabpanel'
625                });
626            });
627            
628            
629        },
630        bind: function ($parent) {
631            var self = this;
632            var isMobile = window.matchMedia('(max-width: ' + hco.DesktopSize + 'px)').matches;
633            // For easy reference
634            var keys = {
635                end: 35,
636                home: 36,
637                left: 37,
638                up: 38,
639                right: 39,
640                down: 40
641            };
642            var $tabs = $parent.find('.' + self.$options.tabContainer + ' a');
643            var $tabLength = $tabs.length;
644            $parent.find('.' + self.$options.tabContainer)
645                .on("click.Tabble", "a", function (e) {
646                    e.preventDefault();
647                    var $this = $(this);
648                    var isActive = $this.closest('.' + self.$options.tabContainer).is('.' + self.$options.menuActive);
649
650                    if (!isMobile || isActive) {
651                        //make all inactive
652                        self.toggleActive($parent.find($('.' + self.$options.pageClass)));
653                        self.toggleActive($parent.find('.' + self.$options.tabContainer + ' a'));
654                        //make one active
655                        self.toggleActive($this.closest('.' + self.$options.parentClass).find('#' + $this.attr('aria-controls')));
656                        self.toggleActive($this);
657
658                        $this.closest('.' + self.$options.tabContainer).removeClass(self.$options.menuActive);
659                        
660                    } else {
661                        $this.closest('.' + self.$options.tabContainer).addClass(self.$options.menuActive);
662                    }
663                })
664                .on("keydown", function (e) {
665                    var key = e.which;
666                    var $this = $(this);
667                    var currIndex = $this.find(':focus').parent().index();
668                    var newActiveTab = false;
669                    var isVertical = $this.find('[aria-orientation]').attr('aria-orientation') === 'vertical';
670                    switch (key) {                         
671                        case keys.end:
672                            e.preventDefault();
673                            newActiveTab = $tabs[$tabLength - 1];
674                            break;
675                        case keys.home:
676                            e.preventDefault();
677                            newActiveTab = $tabs[0];
678                            break;
679                        case keys.left:
680                            e.preventDefault();
681                            newActiveTab = (currIndex === 0) ? $tabs[$tabLength - 1] : $tabs[currIndex - 1];
682                            break;
683                        case keys.right:
684                            e.preventDefault();
685                            newActiveTab = ((currIndex + 1) < $tabLength) ? $tabs[currIndex + 1] : $tabs[0];
686                            break;
687                        case keys.up:
688                            if (!isVertical) break;
689                            e.preventDefault();
690                            newActiveTab = (currIndex === 0) ? $tabs[$tabLength - 1] : $tabs[currIndex - 1];
691                            break;
692                        case keys.down:
693                            if (!isVertical) break;
694                            e.preventDefault();
695                            newActiveTab = ((currIndex + 1) < $tabLength) ? $tabs[currIndex + 1] : $tabs[0];
696                            break;
697                    };
698                    if (newActiveTab) {
699                        var $newActiveTab = $(newActiveTab);
700                        //make all inactive
701                        self.toggleActive($parent.find($('.' + self.$options.pageClass)));
702                        self.toggleActive($parent.find('.' + self.$options.tabContainer + ' a'));
703                        //make one active
704                        self.toggleActive($newActiveTab.closest('.' + self.$options.parentClass).find('#' + $newActiveTab.attr('aria-controls')));
705                        self.toggleActive($newActiveTab);
706                    }
707                });
708        },
709        toggleActive: function ($elem) {
710            var self = this;
711            if ($elem.hasClass(self.$options.activeClass)) {
712                $elem
713                    .removeClass(self.$options.activeClass)
714                    .addClass(self.$options.inactiveClass);
715
716                if ($elem.is('a')) {
717                    $elem.attr({
718                        'tabindex': '-1',
719                        'aria-selected': 'false'
720                    });
721                }
722
723            } else {
724                $elem
725                    .removeClass(self.$options.inactiveClass)
726                    .addClass(self.$options.activeClass);
727
728                if ($elem.is('a')) {
729                    $elem.attr({
730                        'tabindex': '0',
731                        'aria-selected': 'true'
732                    }).focus();
733                }
734                
735            }
736            return this;
737        }
738    };
739
740    /* ---------------------------------------------------------------------
741    HorizontalTabbedModal
742    Author: Nick Charbonneau
743    Addon to Tabble. Handles modal window behavior for horizontal tab instances.
744    ------------------------------------------------------------------------ */
745
746    hco.HorizontalTabbedModal = {
747        $options: {
748            parentClass: 'tabbed--horizontal',
749            pageClass: 'tabbed__page',
750            triggerClass: 'btn-modal',
751            activeClass: 'active-modal',
752            closeBtn: 'btn-close-modal',
753            windowClass: 'modal'
754        },
755        init: function (opt) {
756            var self = this;
757            self.$options = $.extend(self.$options, opt);
758            if ($('.' + self.$options.parentClass).length > 0) {
759                self.bind($('.' + self.$options.parentClass));
760            }
761        },
762        bind: function ($wrapper) {
763            var self = this;
764            $wrapper.find('.' + self.$options.triggerClass)
765                .on("click.HorizontalTabbedModal", function (e) {
766                    console.log('click.HorizontalTabbedModal', this);
767                    var $elem = $(this);
768                    $.get($elem.attr('href'), function (data) {
769                        $elem.closest('.' + self.$options.pageClass)
770                            .append(data)
771                            .addClass(self.$options.activeClass)
772                            .on("click.HorizontalTabbedModal", '.' + self.$options.closeBtn, function (q) {
773                                q.preventDefault();
774                                $elem.closest('.' + self.$options.pageClass)
775                                    .removeClass(self.$options.activeClass)
776                                    .find('.' + self.$options.windowClass)
777                                    .remove();
778                            });
779                    });
780                    e.preventDefault();
781                });
782        }
783    };
784
785
786
787
788    /* ---------------------------------------------------------------------
789    SearchPop
790    Author: Nick Charbonneau
791    Open the Search dialog
792    -toggles an active class on the site header
793    ------------------------------------------------------------------------ */
794
795    hco.SearchPop = {
796        $options: {
797            parentClass: 'site-search',
798            triggerClass: 'site-search--trigger',
799            siteHeader: 'site-header',
800            activeClass: 'site-search--active'
801
802        },
803        init: function (opt) {
804            var self = this;
805            self.$options = $.extend(self.$options, opt);
806            if ($('.' + self.$options.parentClass).length > 0) {
807                $('.' + self.$options.triggerClass).on("click.SearchPop", function (e) {
808                    $('.' + self.$options.siteHeader).toggleClass(self.$options.activeClass);
809                    e.preventDefault();
810                });
811            }
812        }
813
814    };
815
816
817
818
819    /* ---------------------------------------------------------------------
820    UberBg
821    Author: Nick Charbonneau
822    Tracks the page scroll and adjusts the background image.
823    ------------------------------------------------------------------------ */
824
825    hco.UberBg = {
826        $options: {
827            pageClass: 'page',
828            bgContainer: 'uber-background',
829            offsetPageSwap: 1.5
830        },
831        $pages: [],
832        $bgs: '',
833        $breakpoints: [],
834        $currentPage: 0,
835        init: function (opt) {
836            var self = this;
837            self.$options = $.extend(self.$options, opt);
838            if ($('.' + self.$options.pageClass).length > 0) {
839                var _$pages = $('.' + self.$options.pageClass);
840                self.$bgs = $('.' + self.$options.bgContainer).children();
841
842                self.buildPageRefs(_$pages, self.$bgs);
843                self.sizePages();
844                self.bind();
845
846                //fade in the first image
847                if (window.location.hash) {
848                    $.each(self.$pages, function (k, v) {
849                        if (window.location.hash == '#' + v.page.attr('id')) {
850                            self.$pages[k].background.fadeIn();
851                        }
852                    });
853
854                } else {
855                    self.$pages[0].background.fadeIn();
856                }
857            }
858        },
859        bind: function () {
860            var self = this;
861            $(window)
862                .scroll(callSwap(30))
863                .on('resize.UberBg', function (e) {
864                    self.sizePages();
865                });
866
867            function callSwap(ms) {
868                var timer, lastCall = 0;
869                return function () {
870                    var now = new Date().getTime(),
871                        diff = now - lastCall;
872                    if (diff >= ms) {
873                        lastCall = now;
874                        self.swapBackground();
875                    }
876                };
877            }
878        },
879        buildPageRefs: function (_$pages, _$bgs) {
880            //[$pages] = {page: $(page), background: $(bg img)}
881            //background will be null if page doesn't have image flag
882            var self = this,
883                _assoBg = null,
884                _j = 0;
885            for (var i = 0; i < _$pages.length; i++) {
886                _assoBg = _$bgs[_j];
887                _j++;
888                self.$pages.push({
889                    page: $(_$pages[i]),
890                    background: $(_assoBg)
891                });
892            }
893        },
894        // sizePages: function(){
895        //     var self = this;
896        //     $.each(self.$pages,function(k,v){
897        //         v.page
898        //             .css({ //If first page, don't put padding on top
899        //                 'padding-top': ((k == 0)? 0 : (($(window).height() /3) )),
900        //                 'min-height': ($(window).height() / self.$options.offsetPageSwap)+60
901
902        //   });
903        //     });
904        // },
905        sizePages: function () {
906            var self = this;
907
908            var $window = $(window);
909
910            function uberCheckWidth() {
911                var uberWindowSize = $window.width();
912                if (uberWindowSize > 950) {
913
914                    $.each(self.$pages, function (k, v) {
915                        v.page
916                            .css({ //If first page, don't put padding on top
917                                'padding-top': ((k == 0) ? 0 : (($window.height() / 3))),
918                                'min-height': ($window.height() / self.$options.offsetPageSwap) + 60
919                            });
920                    });
921                    
922                } else {
923                    $.each(self.$pages, function (k, v) {
924                        v.page
925                            .css({ //If first page, don't put padding on top
926                                'padding-top': ((k == 0) ? 0 : '25px'),
927                                'min-height': ($window.height() / self.$options.offsetPageSwap) + 60
928
929                            });
930                    });
931                }
932            }
933            uberCheckWidth();
934            $window.resize(uberCheckWidth);
935        },
936        swapBackground: function () {
937            var self = this,
938                _swapArry = _buildSwapPoints(),
939                _tempPoint = self.$currentPage,
940                _$w = $(window);
941            self.$breakpoints = _swapArry;
942
943            for (var k = 0; k < _swapArry.length; k++) {
944                var _nextPoint = ((typeof _swapArry[k + 1] === "undefined") ? $(document).height() : _swapArry[k + 1]);
945                if (_$w.scrollTop() >= _swapArry[k] && _$w.scrollTop() < _nextPoint) {
946                    _tempPoint = k;
947                }
948            }
949            if (_tempPoint != self.$currentPage) {
950                _swapImg(_tempPoint);
951                self.followSideNav(_tempPoint);
952                self.$currentPage = _tempPoint;
953
954                //Kind of blunt, but hide the reminder after scrolling a bit.
955                $('.scroll-reminder').fadeOut();
956            }
957
958            function _swapImg(_tempPoint) {
959                self.$pages[self.$currentPage].background.finish().fadeOut();
960                self.$pages[_tempPoint].background.finish().fadeIn();
961            }
962
963            function _buildSwapPoints() {
964                //console.log("buildSwapPoints() each fn");
965                var _pairs = [];
966                var _temp = 0;
967                var _swapPoint = 0;
968                $.each(self.$pages, function (k, v) {
969                    _swapPoint = v.page.offset().top - (v.page.height() / (self.$options.offsetPageSwap * 4));
970                    /*console.info("-------------" + v.page.offset().top);
971                    console.info("v.page.height = " + v.page.height());
972                    console.info("options.offsetPageSwap * 4 = " + (self.$options.offsetPageSwap * 4));
973                    console.info("_swapPoint = " + (v.page.offset().top - ( v.page.height() / (self.$options.offsetPageSwap * 4))));
974                    console.info("_temp= " + _temp + ":: _swapPoint= " + _swapPoint)
975                    console.log("buildSwapPoints() each fn");*/
976                    if (_swapPoint < _temp) {
977
978                        _swapPoint += 400;
979                    }
980                    if ((_swapPoint - _temp) > 100 && (_swapPoint - _temp) < 450) {
981                        // console.log('true');
982                        _swapPoint += 150;
983                    }
984                    //console.info("post-calc _swapPoint = " + _swapPoint);
985                    _temp = _swapPoint;
986                    //console.info("temp=swappoint = " + _swapPoint);
987                    _pairs.push(_swapPoint);
988
989                });
990                return _pairs;
991
992
993            }
994        },
995        followSideNav: function (_index) {
996            var $nav = $('.popout-nav li.current');
997            $nav.find('.sub-nav li').removeClass('active');
998            $nav.find('.sub-nav li:not(.nav-stack)').eq(_index).addClass('active');
999        }
1000    };
1001
1002
1003    /* ---------------------------------------------------------------------
1004    SimpleSlideShow
1005    Author: Nick Charbonneau
1006    Loops through a set of slides with the ability to navigate.
1007    ------------------------------------------------------------------------ */
1008
1009    hco.SimpleSlideShow = {
1010        $options: {
1011            parentClass: 'overlay-slider',
1012            activeClass: 'active'
1013        },
1014        init: function (opt) {
1015            var self = this;
1016            self.$options = $.extend(self.$options, opt);
1017            if ($('.' + self.$options.parentClass).length > 0) {
1018                self.bind($('.' + self.$options.parentClass));
1019            }
1020        },
1021        bind: function ($parent) {
1022            var self = this,
1023                $slides = $('.overlay-slider__slide'),
1024                currentSlide = 0;
1025
1026            $('.overlay-slider__prev').on("click", function (q) {
1027                prevSlide();
1028                $slides.stop();
1029                q.preventDefault();
1030            });
1031
1032            $('.overlay-slider__next').on("click", function (w) {
1033                nextSlide();
1034                $slides.stop();
1035                w.preventDefault();
1036            });
1037
1038            $('.overlay-slider__nav').on("click", 'a', function (e) {
1039                showSlide($(e.currentTarget).data().target);
1040                $slides.stop();
1041                e.preventDefault();
1042            });
1043
1044            setInterval(nextSlide, 5000);
1045
1046            function showSlide(targ) {
1047                if (currentSlide > $slides.length - 1) {
1048                    currentSlide = 0;
1049                    targ = 0;
1050                }
1051                if (currentSlide < 0) {
1052                    currentSlide = $slides.length - 1;
1053                    targ = $slides.length - 1;
1054                }
1055                $slides.fadeOut().removeClass('active').delay(400)
1056                    .eq(targ).fadeIn().addClass('active');
1057
1058                $('.overlay-slider__nav a')
1059                    .removeClass('active')
1060                    .removeAttr('aria-current')
1061                    .eq(targ)
1062                        .addClass('active')
1063                        .attr('aria-current', 'true');
1064
1065                currentSlide = targ;
1066            }
1067            function nextSlide() {
1068                currentSlide++;
1069                showSlide(currentSlide);
1070            }
1071            function prevSlide() {
1072                currentSlide--;
1073                showSlide(currentSlide);
1074            }
1075        }
1076    };
1077
1078    /* ---------------------------------------------------------------------
1079    AutoReplace
1080    Author: Merne William
1081    Mimics HTML5 placeholder behavior
1082    
1083    Additionally, adds and removes 'placeholder-text' class, used as a styling
1084    hook for when placeholder text is visible or not visible
1085    
1086    Additionally, prevents forms from being
1087    submitted if the default text remains in input field - which we may 
1088    or may not want to leave in place, depending on usage in site
1089    ------------------------------------------------------------------------ */
1090    hco.AutoReplace = {
1091        $fields: undefined,
1092
1093        init: function () {
1094            var $fields = $('[placeholder]');
1095
1096            // Let Placeholder be default if supported.
1097            if (this.placeholderIsSupported) {
1098                return false;
1099            }
1100
1101            if ($fields.length !== 0) {
1102                var self = this;
1103                self.$fields = $fields.addClass('placeholder-text');
1104                self.bind();
1105            }
1106        },
1107
1108        bind: function () {
1109            var self = this;
1110
1111            self.$fields.each(
1112                function () {
1113                    var $this = $(this);
1114                    var defaultText = $this.attr('placeholder');
1115                    $this.attr('placeholder', '').val(defaultText);
1116                    $this.focus(
1117                        function () {
1118                            if ($this.val() === defaultText) {
1119                                $this.val('').removeClass('placeholder-text');
1120                            }
1121                        }
1122                    );
1123
1124                    $this.blur(
1125                        function () {
1126                            if ($this.val() === '') {
1127                                $this.val(defaultText).addClass('placeholder-text');
1128                            }
1129                        }
1130                    );
1131
1132                    $this.parents('form').submit(
1133                        function () {
1134                            if ($this.is('.required') && $this.val() === '') {
1135                                return false;
1136                            } else {
1137                                $this.val('');
1138                            }
1139                        }
1140                    );
1141                }
1142            );
1143        },
1144        placeholderIsSupported: function () {
1145            var test = document.createElement('input');
1146            return ('placeholder' in test);
1147        }
1148    };
1149
1150    /* ---------------------------------------------------------------------
1151    BtnScrollTop
1152    Author: Nick Charbonneau
1153    Makes the 'top' button work. 
1154    ------------------------------------------------------------------------ */
1155
1156    hco.BtnScrollTop = {
1157        init: function () {
1158            var self = this;
1159            $elem = $(".top-reminder");
1160            if ($elem.length > 0) {
1161                self.bind($elem);
1162            }
1163        },
1164        bind: function ($elem) {
1165            var self = this,
1166                _lastScroll = 0,
1167                $_w = $(window);
1168
1169            $_w.scroll(function () {
1170                if ($_w.scrollTop() < _lastScroll) {
1171                    self.showBtn($elem);
1172                } else {
1173                    self.hideBtn($elem);
1174                }
1175                _lastScroll = $(window).scrollTop();
1176            });
1177
1178            $elem.click(function () {
1179                $("html, body").animate({ scrollTop: 0 }, "slow");
1180                return false;
1181            });
1182
1183        },
1184        showBtn: function ($elem) {
1185            if (!$elem.hasClass("active")) {
1186                $elem.stop().show().animate({ "bottom": "0px" })
1187                    .addClass("active");
1188            }
1189        },
1190        hideBtn: function ($elem) {
1191            if ($elem.hasClass("active")) {
1192                $elem.stop().hide().animate({ "bottom": "-45px" })
1193                    .removeClass("active");
1194            }
1195        }
1196    };
1197
1198    /* ---------------------------------------------------------------------
1199    StickyNav
1200    Author: Nick Charbonneau
1201    ------------------------------------------------------------------------ */
1202    hco.StickyNav = {
1203        $options: {
1204            $sidebar: $('<div id="side-nav"></div>'),
1205            $siteFooter: $('.site-footer'),
1206            $siteHeader: $('.site-header'),
1207            fixedSpacing: 50,
1208            currentlyFixed: false,
1209            fixedBottom: false
1210        },
1211        init: function () {
1212            var self = this;
1213            var isMobile = window.matchMedia('(max-width: ' + hco.DesktopSize + 'px)').matches;
1214            // do not bind to mobile
1215            if (isMobile) return;
1216            // add new side nav element
1217            self.$options.$siteHeader.after(self.$options.$sidebar);  
1218            // add sidebar elements to new side nav element
1219            self.$options.$sidebar.prepend($('.site-search'));
1220            if ($('.tert-lvl-sidebar').length) self.$options.$sidebar.append($('.tert-lvl-sidebar'));
1221            self.$options.$sidebar.wrap('<aside></aside>');
1222            // add .popout-nav when it becomes available
1223            self.wait4popoutNav();
1224            
1225            // bind scroll event
1226            $(window).on("scroll", function () {
1227                self.bind();
1228            });
1229
1230
1231
1232        },
1233        bind: function () {
1234
1235            var self = this;
1236            var footerTop = self.$options.$siteFooter.offset().top;
1237            var sideNavHeight = self.$options.$sidebar.outerHeight();
1238            var headerHeight = self.$options.$siteHeader.outerHeight();
1239            var sy = window.scrollY;
1240
1241
1242            if ( footerTop - sideNavHeight - sy - self.$options.fixedSpacing <= self.$options.fixedSpacing ) {
1243                // bottom
1244                self.$options.currentlyFixed = false;
1245                if (self.$options.fixedBottom) return;
1246                self.$options.fixedBottom = true;
1247                self.$options.$sidebar.addClass('bottom');
1248
1249            } else if ( sy <= headerHeight + self.$options.fixedSpacing ) {
1250
1251                // middle
1252                self.$options.currentlyFixed = false;
1253                self.$options.fixedBottom = false;
1254                self.$options.$sidebar.removeClass('fixed');
1255
1256            } else {
1257
1258                // top
1259                self.$options.fixedBottom = false;
1260                if (self.$options.currentlyFixed) return;
1261                self.$options.currentlyFixed = true;
1262                self.$options.$sidebar.removeClass('bottom').addClass('fixed');
1263
1264            }
1265
1266            
1267        },
1268        wait4popoutNav: function() {
1269            var self = this;
1270            var popoutnavFound = false;
1271            var int = setInterval(function() {
1272                if ($('.popout-nav').length < 1) return;
1273                clearInterval(int);
1274                popoutnavFound = true;
1275                self.$options.$sidebar.append($('.popout-nav'));
1276            }, 100);
1277            // clear interval after 5 seconds
1278            setTimeout(function() {
1279                if (!popoutnavFound) clearInterval(int);
1280            }, 5e3);
1281        }
1282
1283    };
1284
1285
1286    /* ---------------------------------------------------------------------
1287    Smooth Scroll
1288    Author: Nick Charbonneau
1289    ------------------------------------------------------------------------ */
1290    /*
1291    hco.SmoothScroll = {
1292        init: function() {  
1293            var self = this;
1294            $('.sub-nav > li.nav-stack').on("click", "a", function(e){  
1295                e.preventDefault();
1296                var targ = $(e.target).attr('href'),
1297                    topPad = parseInt( $(targ).css('padding-top'), 10 );
1298                if($(e.target).parents('.popout-nav').length > 0){
1299                    topPad = topPad +180;
1300                }
1301                if($(targ).length > 0){
1302                    $('html, body').animate({
1303                        scrollTop: $(targ).offset().top + (topPad/1.5) - 60
1304                    }, 800,"swing",function(){
1305                        //document.location.hash = targ;
1306                        var docHash = '#' + targ;
1307                        history.pushState(null, null, targ);
1308                    });
1309                }
1310            });        
1311        }
1312    }*/
1313
1314    hco.SmoothScroll = {
1315        init: function () {
1316            var self = this;
1317            $('.sub-nav').on("click", "a", function (e) {
1318                var targ = $(e.target).attr('href');
1319                if (!/^#/.test(targ)) return;
1320                // only if it's an anchor link
1321                var topPad = parseInt($(targ).css('padding-top'), 10);
1322                if ($(e.target).parents('.popout-nav').length > 0) {
1323                    topPad = topPad + 180;
1324                }
1325                if ($(targ).length > 0) {
1326                    $('html, body').animate({
1327                        scrollTop: $(targ).offset().top + (topPad / 1.5) - 60
1328                    }, 800);
1329                    document.location.hash = targ;
1330                    e.preventDefault();
1331                }
1332            });
1333        }
1334    }
1335
1336
1337
1338
1339
1340    // Qualtrics Purchasing trigger
1341    $(function () {
1342
1343        // Check page before proceeding
1344        // !important not to include the trailing backslash in the pathname
1345        var pages = [
1346            '/business/work-with-henn-co/contracting-with-hennepin-county',
1347            '/residents/property/assessment',
1348            '/assessment',
1349            '/business/property/property-tax-benefit-programs',
1350            '/residents/property/homestead-and-related-programs',
1351            '/homestead'
1352        ];
1353        if (pages.indexOf(location.pathname.replace(/\/$/, '')) < 0) return;
1354
1355        // Apply modal markup to DOM
1356        $('body').append('<div id="modal" tabindex="-1" aria-hidden="true" role="dialog"><button type="button" class="btn-close" aria-label="Close">&times;</button><iframe id="qQuestionnaire" src="" title="Feedback and Help Form"></div>');
1357        $('body').append('<div id="modalBG"></div>');
1358
1359        // Set variables
1360        var $modal = $('#modal');
1361        var $modalClose = $modal.find('.btn-close');
1362        var $modalBG = $('#modalBG');
1363        var currentPagePath = window.location.pathname;
1364        var firstOpen = true;
1365
1366
1367        // set a different button text assessor pages
1368        if (currentPagePath == '/residents/property/assessment'
1369            || currentPagePath == '/assessment'
1370            || currentPagePath == '/business/property/property-tax-benefit-programs'
1371            || currentPagePath == '/residents/property/homestead-and-related-programs'
1372            || currentPagePath == '/homestead'
1373        ) {
1374            var triggerHTML = '<div class="contactBlock"><button type="button" id="qualtricsTrigger" aria-controls="modal">Contact the assessor</button></div>';
1375        } else {
1376            var triggerHTML = '<div class="contactBlock"><button type="button" id="qualtricsTrigger" aria-controls="modal">Have a question or feedback?</button></div>';
1377        }
1378
1379
1380        function openModal() {
1381            // set a different button target for assessor pages
1382            if (currentPagePath == '/residents/property/assessment'
1383                || currentPagePath == '/assessment'
1384                || currentPagePath == '/business/property/property-tax-benefit-programs'
1385                || currentPagePath == '/residents/property/homestead-and-related-programs'
1386                || currentPagePath == '/homestead'
1387            ) {
1388                var src = "https://hennepinco.az1.qualtrics.com/jfe/form/SV_3JjSRWL9Sjq3sA6";
1389            } else {
1390                var src = "https://hennepinco.az1.qualtrics.com/jfe/form/SV_cT5r5sFTkOQyzsx";
1391            }
1392            
1393            
1394            if (firstOpen) $('#qQuestionnaire').attr('src', src);
1395            firstOpen = false;
1396            $modal
1397                .css('top', 'calc(10% + ' + $(window).scrollTop() + 'px)')
1398                .css('height', '75%')
1399                .show()
1400                .attr('aria-hidden', 'false')
1401                .focus();
1402            $modalBG.show();
1403        }
1404        function closeModal() {
1405            $modal.hide().attr('aria-hidden', 'true');
1406            $modalBG.hide();
1407            $('#qualtricsTrigger').focus();
1408        }
1409
1410        // close modal events
1411        $modal.find('.btn-close').on('click', function () {
1412            closeModal();
1413        });
1414        $modalBG.on('click', function () {
1415            closeModal();
1416        });
1417        $(document).on('keyup', function (e) {
1418            if (!$modal.is(':visible')) return;
1419            if (e.which !== 27) return;
1420            closeModal();
1421        });
1422        // modal focus trap
1423        $modal.append('<div class="tabTrap2 sr-only" tabindex="-1"></div>');
1424        $modal.append('<div class="tabTrap sr-only" tabindex="0"></div>');
1425        $modal.find('.tabTrap').on('focus', function () {
1426            $modal.find('.btn-close').focus();
1427        });
1428        $modalClose.on('focus', function () {
1429            var $this = $(this);
1430            $this.on('keydown', function (e) {
1431                if (!e.shiftKey || e.keyCode !== 9) return;
1432                e.preventDefault();
1433                $modal.find('.tabTrap2').focus();
1434            });
1435            $this.on('blur', function() {
1436                $this.off('keydown');
1437            });
1438        });
1439
1440        // get messages from iframe (ie. content height and esc keypress)
1441        window.addEventListener('message', function (e) {
1442            if (!/https:\/\/hennepinco.az1.qualtrics.com/.test(e.origin)) return;
1443            if (e.data === 'closeModal') {
1444                closeModal();
1445            } else {
1446                $modal.css('height', e.data + 41 + 'px');
1447            }
1448        });
1449
1450        // Apply the modal trigger
1451        if ($('aside.street-address').length) {
1452            $('aside.street-address').append(triggerHTML);
1453        } else {
1454            $('.aside-content__main').after('<aside class="street-address">' + triggerHTML + '</aside>');
1455        }
1456        $('#qualtricsTrigger').on('click', function (e) {
1457            openModal();
1458        });
1459
1460    });
1461
1462    // Force focus change on skip to links
1463    $(function () {
1464        $('.skip-to-link').on('click', function (e) {
1465            if (!window.matchMedia('(max-width: ' + hco.DesktopSize + 'px)').matches) e.preventDefault();
1466            var $target = $($(this).attr('href'));
1467            if ($target.length < 1) return;
1468            // check to make sure the target is focusable
1469            if (!$target.is('[tabindex]')) $target.attr('tabindex', '-1');
1470            $target.focus();
1471        });
1472    });
1473
1474    // Hennepin.us Commissioner govDelivery Archive Widgets
1475    $(function () {
1476        /*
1477            Jeffrey Lunde       (1st-district): MNHENNE_532
1478            Irene Fernando      (2nd-district): MNHENNE_95
1479            Marion Greene       (3rd-district): MNHENNE_243
1480            Angela Conley       (4th-district): MNHENNE_96
1481            Debbie Goettel      (5th-district): MNHENNE_642
1482            Chris LaTondresse   (6th-district): MNHENNE_82
1483            Kevin Anderson      (7th-district): MNHENNE_531
1484        */
1485        if (!/hennepin\.us/i.test(location.hostname)) return;
1486        var pathSplit = location.pathname.replace(/\/$/, '').split('/');
1487        var district = pathSplit[pathSplit.length - 1];
1488        var $container = $('#newsletterArchive');
1489        var newsletterID;
1490
1491        if (/\/your-government\/leadership\/\d\D\D-district/.test(location.pathname)) {
1492            newsletterID = {
1493                '1st-district': '532',
1494                '2nd-district': '95',
1495                '3rd-district': '243',
1496                '4th-district': '96',
1497                '5th-district': '642',
1498                '6th-district': '82',
1499                '7th-district': '531'
1500            };
1501        } else {
1502            newsletterID = {
1503                'lunde': '532',
1504                'fernando': '95',
1505                'greene': '243',
1506                'conley': '96',
1507                'goettel': '642',
1508                'latondresse': '82',
1509                'anderson': '531'
1510            };
1511        }
1512        
1513        if ($container.length && newsletterID[district]) $container.html('<script id="govd_widget_js_mnhenne_mnhenne_widget_' + newsletterID[district] + '" src="https://content.govdelivery.com/accounts/MNHENNE/widgets/MNHENNE_WIDGET_' + newsletterID[district] + '.js"></script><style>#newsletterArchive .gdw_content{overflow:initial;}#newsletterArchive .gdw_buttons{display:none;}#newsletterArchive .gdw_widget form{padding:0 0 19px 0;}</style>');
1514
1515    });
1516
1517    // Hennepin.us employee sample page govDelivery Archive Widget
1518    $(function () {
1519        if (!/hennepin\.us\/employees\/sample\-page/i.test(location.href)) return;
1520        var $container = $('#newsletterArchive');
1521        if ($container.length) $container.html('<script id="govd_widget_js_mnhenne_mnhenne_widget_243" src="https://content.govdelivery.com/accounts/MNHENNE/widgets/MNHENNE_WIDGET_243.js"></script><style>#newsletterArchive .gdw_content{overflow:initial;}#newsletterArchive .gdw_buttons, #newsletterArchive .gdw_subscribe{display:none;}</style>');
1522    });
1523
1524    /* CUSTOM GOV DELIVERY SIGNUP WIDGET
1525    ***********************************/
1526    $(function () {
1527        var $gdWidgets = $('.gdWidget');
1528        // add form html for each widget instance
1529        for (var i = 0; i < $gdWidgets.length; i++) {
1530            var $this = $($gdWidgets[i]);
1531            var topicID = $this.attr('data-topicID');
1532            var copy = $this.attr('data-copy') ? '<p>' + $this.attr('data-copy') + '</p>' : '';
1533            var position = $this.attr('data-position') ? $this.attr('data-position').toLowerCase() : '';
1534            var $drawerContainer = $('section.page > .content-wrapper > .drawer');
1535            // topicID is required
1536            if (!topicID) continue;
1537            // place the container in the proper position (if not set, it will remain inline)
1538            if (position === "bottom" && $drawerContainer.length) {
1539                $this.insertAfter($drawerContainer.eq(0));
1540            } else if (position === "top" && $drawerContainer.length) {
1541                $this.insertBefore($drawerContainer.eq(0));
1542            }
1543
1544            $this.empty().append('\
1545                <div class="gdForm">\
1546                    <div class="gdHeading">Get email updates</div>'
1547                + copy +
1548                '<form action="#" novalidate>\
1549                        <label for="email' + i + '">Email address</label>\
1550                        <div class="form-group">\
1551                            <input class="form-control" id="email' + i + '" name="email" type="email" aria-describedby="email' + i + 'Feedback">\
1552                            <button class="btn btn-lg btn-primary" type="submit">Submit</button>\
1553                        </div>\
1554                        <div data-for="email' + i + '" id="email' + i + 'Feedback" class="label-secondary invalid-feedback" style="display:none">\
1555                            Please enter a valid email address.\
1556                        </div>\
1557                    </form>\
1558                    <div class="form-status" aria-live="assertive"></div>\
1559                    <div class="subscription-preferences">\
1560                        <p><a href="https://public.govdelivery.com/accounts/MNHENNE/subscriber/edit?preferences=true#tab1">Update your subscriber preferences</a></p>\
1561                    </div>\
1562                </div>\
1563            ');
1564
1565        }
1566        // gov delivery callback
1567        window.gdEmailSignup = function (result) {
1568            // console.log(result);
1569            var $this = $('.gdWidget[data-topicID="' + result.topic_id + '"]');
1570            if (!$this.length) return;
1571            if (result.errors) {
1572                $this.find('.form-status').html('<strong>' + result.message + '</strong>');
1573            } else {
1574                $this.find('form').hide();
1575                $this.find('.form-status').html('<strong>Thank you for signing up! You will start receiving updates soon.</strong>');
1576            }
1577        }
1578        // validation check
1579        var validate = {
1580            email: function (email, $selector) {
1581                if (/^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$/.test(email)) {
1582                    $selector.removeClass('is-invalid');
1583                    $selector.attr('aria-invalid', 'false');
1584                    $('#' + $selector.attr('aria-describedby')).hide();
1585                    return true;
1586                } else {
1587                    $selector.addClass('is-invalid');
1588                    $selector.attr('aria-invalid', 'true');
1589                    $('#' + $selector.attr('aria-describedby')).show();
1590                    return false;
1591                }
1592            }
1593        };
1594        // form submit function
1595        $('.gdWidget form').on('submit', function (e) {
1596            e.preventDefault();
1597            var $this = $(this);
1598            var $gdWidget = $this.closest('.gdWidget');
1599            var topicID = $gdWidget.attr('data-topicID');
1600            var $email = $this.find('input[type="email"]');
1601            var email = $email.val();
1602            if (validate.email(email, $email)) {
1603                var data = {
1604                    t: topicID,
1605                    e: email,
1606                    c: 'gdEmailSignup',
1607                    k: 'kFJxoD7KW3viXaRypqo8KNJjw5Dgsbt0IEswaLn38kBWps4HlG9PdJEAhsEpoClcz5Y7fQhRCGRuMLZYPcswaA'
1608                }
1609                $.ajax({
1610                    url: 'https://api.govdelivery.com/api/add_script_subscription',
1611                    dataType: 'jsonp',
1612                    data: data,
1613                    jsonp: 'c'
1614                });
1615            } else {
1616                $email.focus();
1617            }
1618        });
1619        // validate invalid field on keyup
1620        $(document).on('keyup', '.is-invalid', function () {
1621            if (!$(this).is('[type="email"]')) return;
1622            var $email = $(this);
1623            var email = $email.val();
1624            validate.email(email, $email);
1625        });
1626        // invalid text label
1627        $('.label-secondary').on('click', function () {
1628            var id = $(this).attr('data-for');
1629            if (!id || !$('#' + id).length) return;
1630            $('#' + id).focus();
1631        });
1632    });
1633
1634    // lvl3 related pages quick fix - temporary fix 05/2021
1635    $(function () {
1636        if ($('.popout-nav + .tert-lvl-sidebar').length < 1) return;
1637
1638        var $relatedNav = $('.tert-lvl-sidebar');
1639        function checkRelatedNav() {
1640            var isMobile = window.matchMedia('(max-width: ' + hco.DesktopSize + 'px)').matches;
1641            if (isMobile) {
1642                $relatedNav.insertAfter('.page-wrapper > section.page');
1643            } else {
1644                $relatedNav.insertAfter('.page-wrapper > .popout-nav');
1645            }
1646        }
1647        // resize throttling (example is a 100ms throttle delay)
1648        var throttleResize;
1649        $(window).on('resize orientationchange', function () {
1650            clearTimeout(throttleResize);
1651            throttleResize = setTimeout(function () {
1652                checkRelatedNav();
1653            }, 100);
1654        });
1655        // initial check
1656        checkRelatedNav();
1657    });
1658
1659    // resize fix for hennepinattorney.org
1660    // this prevents the mobile menu from showing up over the page in white when you resize down from desktop to mobile width
1661    var cachedWidth = $( window ).width();
1662    
1663    var isMobileBeforeResize = window.matchMedia('(max-width: 950px)').matches;
1664
1665    // resize fix for hennepinattorney.org
1666    // this prevents the mobile menu from showing up over the page in white when you resize down from desktop to mobile width
1667    var isMobileBeforeResize = window.matchMedia('(max-width: 950px)').matches;
1668
1669    $( window ).on( "resize", function() {
1670        var isMobileAfterResize = window.matchMedia('(max-width: 950px)').matches;
1671                
1672        if ( isMobileBeforeResize !== isMobileAfterResize ) {         
1673            location.reload();
1674        }
1675    });
1676
1677})(jQuery, window.hco = window.hco || {});
1678
1679//Height fix for Affordable connectivity widget (hennepin.us/projects-initiatives/affordable-connectivity-program)
1680$( document ).ready(function() {
1681    if ($('.acp-widget-css').length > 0) {
1682        $('.acp-widget-css').css('height','700px');
1683    }
1684});

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.