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">×</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.