geico-design-kit 7.0.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of geico-design-kit might be problematic. Click here for more details.

Files changed (107) hide show
  1. package/.babelrc +5 -0
  2. package/LICENSE +0 -0
  3. package/dist/analytics.js +119 -0
  4. package/dist/appState.js +56 -0
  5. package/dist/baseComponent.js +110 -0
  6. package/dist/components/Accordion.js +312 -0
  7. package/dist/components/AddressAutoComplete.js +220 -0
  8. package/dist/components/Alert.js +145 -0
  9. package/dist/components/BackgroundPattern.js +99 -0
  10. package/dist/components/BackgroundPatternPortfolio.js +242 -0
  11. package/dist/components/ButtonSwitch.js +236 -0
  12. package/dist/components/CardSelections.js +230 -0
  13. package/dist/components/CommonQuestionsSquares.js +169 -0
  14. package/dist/components/Confirmation.js +156 -0
  15. package/dist/components/ConsolidatedSummary.js +489 -0
  16. package/dist/components/CoverageGraph.js +201 -0
  17. package/dist/components/CreditCard.js +591 -0
  18. package/dist/components/CurrencyInput.js +302 -0
  19. package/dist/components/DatePicker.js +468 -0
  20. package/dist/components/DockedMessage.js +146 -0
  21. package/dist/components/DotNavigation.js +200 -0
  22. package/dist/components/EditComponent.js +128 -0
  23. package/dist/components/EditableTable.js +113 -0
  24. package/dist/components/InPageNavigation.js +360 -0
  25. package/dist/components/Loader.js +232 -0
  26. package/dist/components/MakePayment.js +361 -0
  27. package/dist/components/Modal.js +254 -0
  28. package/dist/components/MoreInfoButton.js +227 -0
  29. package/dist/components/MultipleSelectBox.js +217 -0
  30. package/dist/components/NavigationalBox.js +161 -0
  31. package/dist/components/Navigator.js +294 -0
  32. package/dist/components/PasswordMeter.js +201 -0
  33. package/dist/components/PayPlans.js +534 -0
  34. package/dist/components/SegmentedControl.js +327 -0
  35. package/dist/components/SortableTable.js +166 -0
  36. package/dist/components/Tabs.js +1 -0
  37. package/dist/components/TextAreaCountdown.js +219 -0
  38. package/dist/components/Timeline.js +498 -0
  39. package/dist/components/TimelineFilter.js +492 -0
  40. package/dist/components/ToTopArrow.js +153 -0
  41. package/dist/components/Tooltip.js +329 -0
  42. package/dist/components/Upsell.js +168 -0
  43. package/dist/components/VIN.js +271 -0
  44. package/dist/components/ValidateForm.js +938 -0
  45. package/dist/components/ViewMoreLess.js +191 -0
  46. package/dist/components/ZipCode.js +191 -0
  47. package/dist/components/portfolio.js +99 -0
  48. package/dist/geico-design-kit.js +141 -0
  49. package/dist/global/components.js +98 -0
  50. package/dist/global/footer.js +26 -0
  51. package/dist/global/nav.js +1257 -0
  52. package/dist/services/CharacterTypeService.js +106 -0
  53. package/dist/services/UserAgentService.js +73 -0
  54. package/dist/utils.js +79 -0
  55. package/package.json +32 -0
  56. package/src/analytics.js +82 -0
  57. package/src/appState.js +56 -0
  58. package/src/baseComponent.js +156 -0
  59. package/src/components/Accordion.js +336 -0
  60. package/src/components/AddressAutoComplete.js +236 -0
  61. package/src/components/Alert.js +135 -0
  62. package/src/components/BackgroundPattern.js +96 -0
  63. package/src/components/BackgroundPatternPortfolio.js +284 -0
  64. package/src/components/ButtonSwitch.js +241 -0
  65. package/src/components/CardSelections.js +240 -0
  66. package/src/components/CommonQuestionsSquares.js +179 -0
  67. package/src/components/Confirmation.js +160 -0
  68. package/src/components/ConsolidatedSummary.js +505 -0
  69. package/src/components/CoverageGraph.js +203 -0
  70. package/src/components/CreditCard.js +595 -0
  71. package/src/components/CurrencyInput.js +321 -0
  72. package/src/components/DatePicker.js +487 -0
  73. package/src/components/DockedMessage.js +142 -0
  74. package/src/components/DotNavigation.js +206 -0
  75. package/src/components/EditComponent.js +130 -0
  76. package/src/components/EditableTable.js +106 -0
  77. package/src/components/InPageNavigation.js +391 -0
  78. package/src/components/Loader.js +272 -0
  79. package/src/components/MakePayment.js +397 -0
  80. package/src/components/Modal.js +279 -0
  81. package/src/components/MoreInfoButton.js +243 -0
  82. package/src/components/MultipleSelectBox.js +211 -0
  83. package/src/components/NavigationalBox.js +163 -0
  84. package/src/components/Navigator.js +338 -0
  85. package/src/components/PasswordMeter.js +209 -0
  86. package/src/components/PayPlans.js +604 -0
  87. package/src/components/SegmentedControl.js +365 -0
  88. package/src/components/SortableTable.js +176 -0
  89. package/src/components/Tabs.js +0 -0
  90. package/src/components/TextAreaCountdown.js +231 -0
  91. package/src/components/Timeline.js +532 -0
  92. package/src/components/TimelineFilter.js +533 -0
  93. package/src/components/ToTopArrow.js +153 -0
  94. package/src/components/Tooltip.js +344 -0
  95. package/src/components/Upsell.js +196 -0
  96. package/src/components/VIN.js +289 -0
  97. package/src/components/ValidateForm.js +1030 -0
  98. package/src/components/ViewMoreLess.js +193 -0
  99. package/src/components/ZipCode.js +193 -0
  100. package/src/components/portfolio.js +106 -0
  101. package/src/geico-design-kit.js +144 -0
  102. package/src/global/components.js +92 -0
  103. package/src/global/footer.js +25 -0
  104. package/src/global/nav.js +1457 -0
  105. package/src/services/CharacterTypeService.js +107 -0
  106. package/src/services/UserAgentService.js +59 -0
  107. package/src/utils.js +82 -0
@@ -0,0 +1,1457 @@
1
+ import * as utils from '../utils';
2
+ import appState from '../appState';
3
+
4
+ //Global nav vars
5
+ let body,
6
+ header,
7
+ headerAnchors,
8
+ nav,
9
+ navBackground,
10
+ actionableIcons,
11
+ submenuWrapper,
12
+ panelTriggers,
13
+ headerLinks,
14
+ currentlyOpenPanel,
15
+ currentlyOpenSubPanel,
16
+ panels,
17
+ panelUL,
18
+ panelIsOpen = false,
19
+ hover_timer,
20
+ panel_timer,
21
+ open_timer,
22
+ svgAnim_timer,
23
+ currentNavState,
24
+ mainListItems,
25
+ mainListItemsAnchor,
26
+ mainListItemsAnchorMobile,
27
+ mainListItemsAnchorRightMobile,
28
+ mobilenavaccordionHeadlines,
29
+ secondaryListItemsAnchorMobile,
30
+ svgToAnim,
31
+ subpanelName,
32
+ hamburgerIcons,
33
+ dashOffsetEnd = 180,//svg animation settings
34
+ dashArrayComplete = 183,//svg animation settings
35
+ tickSpeed = 3.5,//svg animation settings
36
+ tickSpeedMobile = 5,//svg animation settings
37
+ tick = 0;//svg animation settings
38
+ var isHovering = false;
39
+ var isTouch = false;
40
+
41
+
42
+ function init(config) {
43
+
44
+ if(!config || config.generateMobileNavHtml) {
45
+ generateMobileMenuElements(config);
46
+ /*
47
+ * At this point the mobile nav has been generated so we
48
+ * can initialize the view-more-less components for the first menu tier.
49
+ * */
50
+ var mobileNav = new GDK.Accordion({
51
+ "content" : "#mobile-nav",
52
+ "forceOpenSingleAccordionElement" : true
53
+ });
54
+ }
55
+
56
+
57
+ console.log('Initialized Navigation');
58
+
59
+ findDomElements();
60
+
61
+ if (appState.mode === "mobile") {
62
+ body.style.overflowX = "hidden";
63
+ }
64
+
65
+ //add the navigation background
66
+ nav.insertAdjacentHTML('afterBegin', '<div id="nav-background"></div>');
67
+ navBackground = document.getElementById('nav-background');
68
+
69
+ addSVGs();
70
+ addHamburgerMarkup();
71
+
72
+ if (appState.mode === "desktop") {
73
+ currentNavState = "desktop";
74
+
75
+ if (appState.isTouchDevice) {
76
+ initDesktopTouchEvents();
77
+ } else {
78
+ initDesktopEvents();
79
+ }
80
+
81
+ } else {
82
+ currentNavState = "mobile";
83
+
84
+ if (appState.isTouchDevice) {
85
+ initMobileTouchEvents();
86
+ } else {
87
+ initMobileEvents();
88
+ }
89
+
90
+ }
91
+
92
+ if(document.querySelector('.skip-to-content')&&(!document.body.classList.contains('with-unsupported-browser')||!document.querySelector('.unsupported-browser'))){
93
+ document.querySelector('.skip-to-content').addEventListener('blur', function(){document.querySelector('#primary-header').style.top = '0';});
94
+ document.querySelector('.skip-to-content').addEventListener('focus', function(){document.querySelector('#primary-header').style.top = '2rem';});
95
+ }
96
+
97
+ Array.prototype.forEach.call(headerAnchors, function (el, i) {
98
+ el.setAttribute('aria-expanded', 'false');
99
+ });
100
+
101
+ window.addEventListener('resize', handleResize);
102
+ handleResize();
103
+
104
+
105
+ //for IE
106
+ Array.prototype.forEach.call(mainListItemsAnchor, function (el, i) {
107
+ el.addEventListener('pointerdown', function(e){
108
+ if(e.pointerType=='touch' && el.parentNode.querySelector('.geico-nav-menu-secondary-wrapper')){
109
+ e.preventDefault();
110
+ }
111
+ });
112
+ });
113
+
114
+ //for IE, Chrome, FF - affects all browsers
115
+ document.querySelector('#primary-header').addEventListener('mouseover', function(){
116
+ if(isHovering === false){
117
+ isHovering = true;
118
+ isTouch = false;
119
+
120
+ appState.isTouchDevice = false;
121
+
122
+ removeNavEvents();
123
+ if (appState.mode === "desktop") {
124
+ currentNavState = "desktop";
125
+
126
+ if (appState.isTouchDevice) {
127
+ initDesktopTouchEvents();
128
+ } else {
129
+ initDesktopEvents();
130
+ }
131
+
132
+ } else {
133
+ currentNavState = "mobile";
134
+
135
+ if (appState.isTouchDevice) {
136
+ initMobileTouchEvents();
137
+ } else {
138
+ initMobileEvents();
139
+ }
140
+
141
+ }
142
+ }
143
+ });
144
+
145
+
146
+ }
147
+
148
+ function closeAccordionsMobileNav() {
149
+ let openAccordians = document.querySelector('#mobile-nav').querySelectorAll(".accordion > li.open");
150
+ Array.prototype.forEach.call(openAccordians, (el, i)=>{
151
+ el.classList.remove("open");
152
+ let contentContainer = el.querySelector(".accordion-content-container");
153
+ contentContainer.style.display="none";
154
+ });
155
+
156
+ }
157
+
158
+ /**
159
+ * findDomElements()
160
+ * Finds all Dom elements needed to run the navigation functionality
161
+ */
162
+ function findDomElements() {
163
+ body = document.getElementsByTagName('body')[0];
164
+ header = document.getElementById('primary-header');
165
+ nav = document.getElementById('primary-navigation');
166
+
167
+ //find all header anchors
168
+ headerAnchors = header.querySelectorAll('a');
169
+
170
+ //finds any dom elements that have a data attribute of side-panel.
171
+ //Any header element that opens a panel should have this data attribute, so we know which panel to open
172
+ panelTriggers = header.querySelectorAll('[data-side-panel-trigger]');
173
+ headerLinks = header.querySelectorAll('a');
174
+ panels = nav.querySelectorAll('.panel-wrapper');
175
+
176
+ //find all the submenus
177
+ submenuWrapper = nav.querySelectorAll('.geico-nav-menu-secondary-wrapper');
178
+
179
+ //find all hamburger icons
180
+ hamburgerIcons = header.querySelectorAll('.hamburger-menu');
181
+
182
+ //find all the actionable-icons
183
+ actionableIcons = nav.querySelectorAll('a .geico-icon--actionable');
184
+
185
+ Array.prototype.forEach.call(actionableIcons, function (el, i) {
186
+ el.style.width = "60px";
187
+ el.style.height = "60px";
188
+ el.style.lineHeight = "60px";
189
+ el.style.fontSize = "30px";
190
+ });
191
+
192
+
193
+ //find all first level li's for mobile
194
+ mainListItems = nav.querySelectorAll('.panel-wrapper > ul > li');
195
+ mainListItemsAnchor = nav.querySelectorAll('.panel-wrapper > ul > li > a');
196
+ mainListItemsAnchorMobile = nav.querySelectorAll('.panel-wrapper > #mobile-nav > li > .accordion-content-container > div > ul > li > a');
197
+ mainListItemsAnchorRightMobile = nav.querySelectorAll('.panel-wrapper.right > ul > li > a');
198
+ mobilenavaccordionHeadlines = nav.querySelectorAll('.panel-wrapper > #mobile-nav > li > .accordion-headline');
199
+ secondaryListItemsAnchorMobile = nav.querySelectorAll('.panel-wrapper > #mobile-nav .geico-nav-menu-secondary-wrapper > ul > li > a');
200
+
201
+
202
+ panelUL = nav.querySelectorAll('.panel-wrapper > ul');
203
+
204
+
205
+ }
206
+
207
+ /**
208
+ * Svetoslav Kostadinov
209
+ * 07.Jan.2106
210
+ *
211
+ * Generate mobile navigation markup.
212
+ */
213
+ function generateMobileMenuElements(config) {
214
+
215
+ let navContainer = document.querySelectorAll('#primary-navigation')[0];
216
+ /* Delete any existing Mobile Nav */
217
+ if(navContainer.querySelector('[data-side-panel="mobile-menu"]') !== null) {
218
+ navContainer.removeChild(navContainer.querySelector('[data-side-panel="mobile-menu"]'));
219
+ }
220
+ let mobileNavDiv = navContainer.cloneNode(true);
221
+
222
+ // Create the mobile menu element
223
+ let navMobilePanelWrapper = document.createElement('div');
224
+ navMobilePanelWrapper.className = 'panel-wrapper';
225
+ navMobilePanelWrapper.setAttribute('data-side-panel', 'mobile-menu');
226
+
227
+ // Generate the mobile nav shell
228
+ let mobileNavigation = document.createElement('ul');
229
+ mobileNavigation.setAttribute('id', 'mobile-nav');
230
+ mobileNavigation.setAttribute('class', 'accordion');
231
+
232
+ // generate the search form section
233
+ if(config && config.mobileSearchForm) {
234
+ let searchForm = document.createElement('form');
235
+ searchForm.setAttribute('method', config.mobileSearchForm.method);
236
+ searchForm.setAttribute('action', config.mobileSearchForm.action);
237
+ searchForm.setAttribute('class', 'search-box');
238
+
239
+ let searchInputField = document.createElement('input');
240
+ searchInputField.setAttribute('type', 'text');
241
+ searchInputField.setAttribute('class', 'search-input');
242
+ searchInputField.setAttribute('placeholder', config.mobileSearchForm.placeholder);
243
+ searchInputField.setAttribute('name', config.mobileSearchForm.name);
244
+ searchInputField.setAttribute('aria-label', config.mobileSearchForm.ariaLabel);
245
+
246
+ let searchSubmitButton = document.createElement('button');
247
+ searchSubmitButton.setAttribute('type', 'submit');
248
+ searchSubmitButton.setAttribute('class', 'icon-search small');
249
+
250
+ // assemble the search form
251
+ searchForm.appendChild(searchInputField);
252
+ searchForm.appendChild(searchSubmitButton);
253
+
254
+ let searchResultField = document.createElement('ul');
255
+ searchResultField.setAttribute('class', 'dropdown-list');
256
+ searchResultField.setAttribute('style', 'display: none');
257
+
258
+ // Add the search form to the Mobile Nav before the Tier One Elements Loop
259
+ navMobilePanelWrapper.appendChild(searchForm);
260
+ navMobilePanelWrapper.appendChild(searchResultField);
261
+ }
262
+
263
+ let mobileHeader = document.querySelector('#primary-header').cloneNode(true);
264
+ let primaryHeaderLeftAnchors = mobileHeader.querySelectorAll('#header-left-links .desktop-links a');
265
+ let nonMenuAnchorUL = document.createElement('UL');
266
+ Array.prototype.forEach.call(primaryHeaderLeftAnchors, function(el, i){
267
+ if(!el.getAttribute('data-side-panel-trigger')){
268
+ let justAnchorLI = document.createElement('LI');
269
+ let anchorTextNode = document.createTextNode(el.innerHTML);
270
+ el.innerHTML = "";
271
+ let justAnchorSpan = document.createElement('SPAN');
272
+ justAnchorSpan.classList.add('geico-nav-menu-item');
273
+ justAnchorSpan.appendChild(anchorTextNode);
274
+ el.appendChild(justAnchorSpan);
275
+ justAnchorLI.appendChild(el);
276
+ nonMenuAnchorUL.appendChild(justAnchorLI);
277
+ }
278
+ });
279
+
280
+
281
+
282
+ // generate nav tier 1 elements
283
+ // pull nav elements from the desktop main menu.
284
+ let navElementsArray = mobileNavDiv.querySelectorAll('.panel-wrapper');
285
+ // Loop through and generate the mobile menu structure.
286
+ Array.prototype.forEach.call(navElementsArray, function(element, i){
287
+ if(element.className.indexOf("no-mobile") === -1) {
288
+ let tierOneElement = document.createElement('li');
289
+
290
+ // Element Headline and Label
291
+ let tierOneHeadline = document.createElement('div');
292
+ tierOneHeadline.setAttribute('class', 'accordion-headline');
293
+ tierOneHeadline.setAttribute('tabindex', '0');
294
+ let tierOneHeadlineH3 = document.createElement('h3');
295
+ tierOneHeadlineH3.innerHTML = element.getAttribute('data-side-panel').capitalizeFirstLetter();
296
+ tierOneHeadline.appendChild(tierOneHeadlineH3);
297
+
298
+ //element content container
299
+ let tierOneContentContainer = document.createElement('div');
300
+ tierOneContentContainer.setAttribute('class', 'accordion-content-container');
301
+
302
+ let tierOneContent = document.createElement('div');
303
+ tierOneContent.setAttribute('class', 'accordion-content');
304
+ tierOneContent.setAttribute('data-side-panel', 'mobile-menu');
305
+
306
+ let tierOneContentUl = document.createElement('ul');
307
+ // fill the ul with tier 2 and 3 elements.
308
+ Array.prototype.forEach.call(element.querySelectorAll('ul>li[data-name]'), function(el, i){
309
+
310
+ let classNames = el.className;
311
+ let classArray = classNames.split(' ');
312
+
313
+ el.className = classArray.join(' ');
314
+ tierOneContentUl.appendChild(el);
315
+ });
316
+
317
+ // assemble the navigation
318
+ tierOneContent.appendChild(tierOneContentUl);
319
+ tierOneContentContainer.appendChild(tierOneContent);
320
+ tierOneElement.appendChild(tierOneHeadline);
321
+ tierOneElement.appendChild(tierOneContentContainer);
322
+ mobileNavigation.appendChild(tierOneElement);
323
+ }
324
+ });
325
+
326
+ navMobilePanelWrapper.appendChild(mobileNavigation);
327
+ navMobilePanelWrapper.appendChild(nonMenuAnchorUL);
328
+
329
+ navContainer.appendChild(navMobilePanelWrapper);
330
+
331
+ }
332
+
333
+ /**
334
+ * Svetoslav Kostadinov
335
+ * 07.Jan.2016
336
+ *
337
+ * @returns {string}
338
+ */
339
+ String.prototype.capitalizeFirstLetter = function() {
340
+ return this.charAt(0).toUpperCase() + this.slice(1);
341
+ };
342
+
343
+
344
+ /**
345
+ * initDesktopEvents()
346
+ * Initialize all desktop events
347
+ */
348
+ function initDesktopEvents() {
349
+ console.log("initDesktopEvents");
350
+
351
+ document.addEventListener('keyup', function(e){
352
+ if(document.getElementById('wrapper').contains(e.target)){
353
+ if(e.which == '9' || e.keyCode == '9'){
354
+ if (panelIsOpen) {
355
+ closePanel(currentlyOpenPanel);
356
+ }
357
+ }
358
+ }
359
+ });
360
+
361
+ Array.prototype.forEach.call(panelTriggers, function (el, i) {
362
+ el.addEventListener('click', menuEnter);
363
+ el.addEventListener('keydown', menuEnter);
364
+ });
365
+
366
+ Array.prototype.forEach.call(headerLinks, function (el, i) {
367
+ el.addEventListener('mouseenter', displayHoverStyle);
368
+ el.addEventListener('mouseleave', removeHoverStyle);
369
+ });
370
+
371
+ //keyboard navigation events on header anchors
372
+ Array.prototype.forEach.call(headerAnchors, function (el, i) {
373
+ addKeyboardFocus(el);
374
+ el.addEventListener('focus', focusPanel);
375
+ });
376
+
377
+ Array.prototype.forEach.call(mainListItems, function (el, i) {
378
+ el.addEventListener('click', closeAllPanels);
379
+ el.addEventListener('mouseenter', openSubMenu);
380
+ el.addEventListener('focus', openSubMenu, true);
381
+ });
382
+
383
+ //for each submenu wrapper listen for its mouse over
384
+ //so we know when to close the menu when you roll off the submenu
385
+ Array.prototype.forEach.call(submenuWrapper, function (el, i) {
386
+ el.addEventListener('mouseover', submenuWrapperHover);
387
+ });
388
+
389
+ //for each panel listen for its mouse leave so we know when to close the menu
390
+ Array.prototype.forEach.call(panels, function (el, i) {
391
+ el.addEventListener('mouseenter', function(){let dataside = el.getAttribute('data-side-panel');
392
+ Array.prototype.forEach.call(headerAnchors, (el, i) => {
393
+ if (el.getAttribute('data-side-panel-trigger') != dataside) {
394
+ el.classList.add("not-open");
395
+ }
396
+ });
397
+ });
398
+ let firstFocusableInPanel = nav.querySelectorAll('.first-focusable');
399
+ Array.prototype.forEach.call(firstFocusableInPanel, function(el, i){
400
+ el.addEventListener('keydown', keyPressSearchBackward);
401
+ });
402
+ if(document.querySelector('.search input')){
403
+ document.querySelector('.search input').addEventListener('keydown', keyPressSearchBackward);
404
+ }
405
+
406
+ if(!el.classList.contains('search')){
407
+ if (el.querySelector('ul') && el.firstElementChild.nodeName == 'UL' && el.querySelector('ul').firstElementChild && el.querySelector('ul').lastElementChild) {
408
+ el.querySelector('ul').firstElementChild.querySelector('a').addEventListener('keydown', keyPressFirstBackwards);
409
+ if (el.querySelector('ul').lastElementChild.querySelector('.geico-nav-menu-secondary-wrapper')) {
410
+ el.querySelector('ul').lastElementChild.querySelector('.geico-nav-menu-secondary-wrapper').querySelector('ul').lastElementChild.querySelector('a').addEventListener('keydown', keyPressNextTab);
411
+ } else {
412
+ el.querySelector('ul').lastElementChild.querySelector('a').addEventListener('keydown', keyPressNextTab);
413
+ }
414
+ } else {
415
+ if (el.lastElementChild.querySelector('ul') && el.lastElementChild.querySelector('ul').lastElementChild) {
416
+ el.lastElementChild.querySelector('ul').lastElementChild.querySelector('a').addEventListener('keydown', keyPressNextTab);
417
+ }
418
+ }
419
+ }
420
+
421
+ navBackground.addEventListener('click', closeAllPanels);
422
+ });
423
+
424
+ }
425
+
426
+ function removeHoverStyle(){
427
+ Array.prototype.forEach.call(headerAnchors, (el, i) => {
428
+ if (el != this) {
429
+ el.classList.remove("not-open");
430
+ }
431
+ });
432
+ }
433
+
434
+ function displayHoverStyle(){
435
+ Array.prototype.forEach.call(headerAnchors, (el, i) => {
436
+ if (el != this) {
437
+ el.classList.add("not-open");
438
+ }
439
+ });
440
+ }
441
+
442
+
443
+ function keyPressSearchBackward(e){
444
+ if(e.shiftKey && e.keyCode == 9){
445
+ e.preventDefault();
446
+
447
+ let parentPanel = e.target.parentNode.parentNode;
448
+ //to be refined for an easier way to implement this logic
449
+ if(!parentPanel.getAttribute('data-side-panel')){
450
+ parentPanel = parentPanel.parentNode;
451
+ if(!parentPanel.getAttribute('data-side-panel')){
452
+ parentPanel = parentPanel.parentNode;
453
+ if(!parentPanel.getAttribute('data-side-panel')){
454
+ parentPanel = parentPanel.parentNode;
455
+ }
456
+ }
457
+ }
458
+ header.querySelector('[data-side-panel-trigger="' + parentPanel.getAttribute('data-side-panel') + '"]').focus();
459
+ if (appState.mode === "desktop") {
460
+ Array.prototype.forEach.call(headerAnchors, function (el, i) {
461
+ el.removeAttribute('tabindex');
462
+ });
463
+ }
464
+ }
465
+ }
466
+
467
+ function keyPressNextTab(e){
468
+ if(e.shiftKey){
469
+ return;
470
+ }
471
+ else if(e.which == 9 || e.keyCode == 9){
472
+ console.log('tab only');
473
+ console.log(e.target);
474
+ let parentPanel = findUpParent(e.target, 'data-side-panel');
475
+ //let parentPanel = e.target.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode;
476
+ //console.log(header.querySelector('[data-side-panel-trigger="' + parentPanel.getAttribute('data-side-panel') + '"]').parentNode);
477
+ header.querySelector('[data-side-panel-trigger="' + parentPanel.getAttribute('data-side-panel') + '"]').parentNode.querySelector('a').focus();
478
+ }
479
+ }
480
+
481
+ function keyPressFirstBackwards(e){
482
+ //header.querySelector('[data-side-panel-trigger="versions"]').focus();
483
+ if(e.shiftKey && e.keyCode == 9){
484
+ e.preventDefault();
485
+ let parentPanel = e.target.parentNode.parentNode.parentNode;
486
+ if(appState.mode == 'desktop'){
487
+ header.querySelector('[data-side-panel-trigger="' + parentPanel.getAttribute('data-side-panel') + '"]').focus();
488
+ }
489
+ else if(appState.mode == 'mobile'){
490
+ header.querySelector('.mobile-links [data-side-panel-trigger="' + parentPanel.getAttribute('data-side-panel') + '"]').focus();
491
+ }
492
+ console.log(parentPanel);
493
+ console.log(header.querySelector('[data-side-panel-trigger="' + parentPanel.getAttribute('data-side-panel') + '"]'));
494
+ }
495
+ }
496
+
497
+ function findUpParent(el, attribute) {
498
+ while (el.parentNode) {
499
+ el = el.parentNode;
500
+ if (el.getAttribute(attribute))
501
+ return el;
502
+ }
503
+ return null;
504
+ }
505
+
506
+ /**
507
+ * initDesktopTouchEvents()
508
+ * Initialize all desktop touch events
509
+ */
510
+ function initDesktopTouchEvents() {
511
+ console.log("initDesktopTouchEvents");
512
+
513
+ //All panel triggers should have a click event that open or closes a panel
514
+ Array.prototype.forEach.call(panelTriggers, function (el, i) {
515
+ el.addEventListener('touchend', menuEnter);
516
+ el.addEventListener('click', function(e){
517
+ if(el.getAttribute('data-side-panel-trigger')!==''){
518
+ e.preventDefault();
519
+ }
520
+ });
521
+ });
522
+
523
+
524
+ Array.prototype.forEach.call(mainListItemsAnchor, function (el, i) {
525
+ el.addEventListener('click', openSubMenu);
526
+ });
527
+
528
+ //for each submenu wrapper listen for its mouse over
529
+ //so we know when to close the menu when you roll off the submenu
530
+ Array.prototype.forEach.call(submenuWrapper, function (el, i) {
531
+ el.addEventListener('touchend', submenuWrapperHover);
532
+ });
533
+
534
+ navBackground.addEventListener('touchend', closeAllPanels);
535
+
536
+ }
537
+
538
+
539
+ /**
540
+ * initMobileEvents()
541
+ * Initialize all mobile events
542
+ */
543
+ function initMobileEvents() {
544
+ let isClick = false;
545
+
546
+
547
+ document.addEventListener('keyup', function(e){
548
+ if(document.getElementById('wrapper').contains(e.target)){
549
+ if(e.which == '9' || e.keyCode == '9'){
550
+ if (panelIsOpen) {
551
+ closePanel(currentlyOpenPanel);
552
+ header.querySelector('.mobile-links [data-side-panel-trigger="' + currentlyOpenPanel.getAttribute('data-side-panel') + '"]').focus();
553
+ }
554
+ }
555
+ }
556
+ });
557
+
558
+ //All panel triggers should have a click event that open or closes a panel
559
+ Array.prototype.forEach.call(panelTriggers, function (el, i) {
560
+ el.addEventListener('click', menuEnter);
561
+ el.addEventListener('keypress', menuEnter);
562
+ });
563
+
564
+ Array.prototype.forEach.call(headerAnchors, function (el, i) {
565
+ addKeyboardFocus(el);
566
+ });
567
+
568
+ //close mobile panel when focusing on geico logo
569
+ document.querySelector('#header-middle-links a').addEventListener('focus', function () {
570
+ Array.prototype.forEach.call(panels, function (panel, i) {
571
+ if (panel.classList.contains('open')) {
572
+ closePanel(panel);
573
+ }
574
+ });
575
+ });
576
+
577
+ Array.prototype.forEach.call(mainListItemsAnchorMobile, function (el, i) {
578
+ addKeyboardFocus(el);
579
+
580
+ el.addEventListener('mousedown', function(){
581
+ isClick = true;
582
+ });
583
+
584
+ el.addEventListener('click', openMobileSubMenu);
585
+
586
+ el.addEventListener('focus', function (e) {
587
+ let submenu = el.parentNode.getElementsByClassName('geico-nav-menu-secondary-wrapper');
588
+
589
+ if (!isClick && submenu.length > 0) {
590
+ openMobileSubMenu.bind(this)(e);
591
+ } else {
592
+ if (currentlyOpenSubPanel) {
593
+ //closeMobileSubMenu(currentlyOpenSubPanel); do not need, duplicate
594
+ }
595
+ }
596
+
597
+ //reset flag
598
+ isClick = false;
599
+
600
+ let parentAccordion = findClosestParent(el, 'accordion-content-container');
601
+ let accordionHeadline = parentAccordion.parentNode.querySelector('.accordion-headline');
602
+
603
+ if(!parentAccordion.parentNode.classList.contains('open')){
604
+ accordionHeadline.click();
605
+ }
606
+ });
607
+
608
+ Array.prototype.forEach.call(secondaryListItemsAnchorMobile, function (el, i) {
609
+ addKeyboardFocus(el);
610
+
611
+ el.addEventListener('focus', function (e) {
612
+ //var parentLI = el.closest('.accordion-content > ul > li');
613
+ var parentLI = findUpParent(el, 'data-name');
614
+ var submenu = parentLI.querySelector('.geico-nav-menu-secondary-wrapper');
615
+
616
+ if(!parentLI.classList.contains('open')){
617
+ openMobileSubMenu.bind(submenu)(e);
618
+ }
619
+
620
+ var parentAccordion = findClosestParent(el, 'accordion-content-container');
621
+ var accordionHeadline = parentAccordion.parentNode.querySelector('.accordion-headline');
622
+
623
+ if(!parentAccordion.parentNode.classList.contains('open')){
624
+ accordionHeadline.click();
625
+ }
626
+ });
627
+
628
+ el.addEventListener('click', closeAllPanels);
629
+
630
+ });
631
+ });
632
+
633
+ navBackground.addEventListener('click', closeAllPanels);
634
+
635
+ Array.prototype.forEach.call(mobilenavaccordionHeadlines, function (el, i) {
636
+ addKeyboardFocus(el);
637
+ el.addEventListener('click', closeSubMenufromHeadline);
638
+ });
639
+
640
+ Array.prototype.forEach.call(headerAnchors, function(el, i){
641
+ el.setAttribute('tabindex', '-1');
642
+ if(el.parentNode.parentNode.classList.contains('mobile-links')||el.parentNode.parentNode.classList.contains('right-mobile-links')||el.classList.contains('icon-geico')){
643
+ el.removeAttribute('tabindex');
644
+ }
645
+ });
646
+
647
+ Array.prototype.forEach.call(mainListItemsAnchorRightMobile, function(el, i){
648
+ el.addEventListener('focus', function(){
649
+ addKeyboardFocus(el);
650
+ });
651
+ });
652
+
653
+ }
654
+
655
+ /**
656
+ * initMobileTouchEvents()
657
+ * Initialize mobile touch events
658
+ */
659
+ function initMobileTouchEvents() {
660
+
661
+ //All panel triggers should have a click event that open or closes a panel
662
+ Array.prototype.forEach.call(panelTriggers, function (el, i) {
663
+ el.addEventListener('touchend', menuEnter);
664
+ });
665
+
666
+ Array.prototype.forEach.call(mainListItemsAnchorMobile, function (el, i) {
667
+ el.addEventListener('click', openMobileSubMenu);
668
+ });
669
+
670
+ navBackground.addEventListener('touchend', closeAllPanels);
671
+
672
+ Array.prototype.forEach.call(mobilenavaccordionHeadlines, function (el, i) {
673
+ el.addEventListener('touchend', closeSubMenufromHeadline);
674
+ });
675
+
676
+ }
677
+
678
+ function closeSubMenufromHeadline(){
679
+ if (currentlyOpenSubPanel) {
680
+ closeMobileSubMenu(currentlyOpenSubPanel);
681
+ //console.log(subWrapper.getBoundingClientRect().top);
682
+
683
+ }
684
+ }
685
+
686
+
687
+ /**
688
+ * removeNavEvents()
689
+ * Remove all navigation events
690
+ */
691
+
692
+ function removeNavEvents() {
693
+
694
+ Array.prototype.forEach.call(panelTriggers, function (el, i) {
695
+ el.removeEventListener('touchstart', menuEnter);
696
+ el.removeEventListener('click', menuEnter);
697
+ el.removeEventListener('mouseenter', menuEnter);
698
+ el.removeEventListener('mouseleave', menuLeave);
699
+ el.removeEventListener('keypress', menuEnter);
700
+ el.removeEventListener('touchend', menuEnter);
701
+ });
702
+
703
+ Array.prototype.forEach.call(headerAnchors, function (el, i) {
704
+ el.removeEventListener('keypress', menuEnter);
705
+ el.removeEventListener('focus', focusPanel);
706
+ });
707
+
708
+ Array.prototype.forEach.call(mainListItems, function (el, i) {
709
+ el.removeEventListener('click', closeAllPanels);
710
+ el.removeEventListener('mouseenter', openSubMenu);
711
+ el.removeEventListener('focus', openSubMenu, true);
712
+ });
713
+
714
+ Array.prototype.forEach.call(mainListItemsAnchor, function (el, i) {
715
+ el.removeEventListener('click', openMobileSubMenu);
716
+ el.removeEventListener('touchstart', openSubMenu);
717
+ el.removeEventListener('mouseenter', openSubMenu);
718
+ });
719
+
720
+ Array.prototype.forEach.call(submenuWrapper, function (el, i) {
721
+ el.removeEventListener('touchstart', submenuWrapperHover);
722
+ el.removeEventListener('mouseover', submenuWrapperHover);
723
+ });
724
+
725
+ Array.prototype.forEach.call(panels, function (el, i) {
726
+ el.removeEventListener('mouseleave', panelLeave);
727
+ });
728
+
729
+ navBackground.removeEventListener('touchstart', closeAllPanels);
730
+ navBackground.removeEventListener('click', closeAllPanels);
731
+
732
+ removeTabIndexes();
733
+ }
734
+
735
+ function focusPanel(){
736
+ Array.prototype.forEach.call(panels, function (panel, i) {
737
+ if(panel.classList.contains('open')){
738
+ closePanel(panel);
739
+ }
740
+ });
741
+ }
742
+
743
+ /**
744
+ * removeTabIndexes()
745
+ * remove all tabindexes from nav elements
746
+ */
747
+ function removeTabIndexes() {
748
+ let headerLinks = header.querySelectorAll('a');
749
+
750
+ Array.prototype.forEach.call(headerLinks, function (headerLink) {
751
+ headerLink.removeAttribute('tabindex');
752
+ });
753
+
754
+ let panelElements = nav.querySelectorAll('*');
755
+
756
+ Array.prototype.forEach.call(panelElements, function (panelElement) {
757
+ if(panelElement.classList&&!panelElement.classList.contains('accordion-headline'))
758
+ panelElement.removeAttribute('tabindex');
759
+ });
760
+ }
761
+
762
+ /**
763
+ * addKeyboardFocus()
764
+ * add/remove focus class to keyboard focused and blurred elements
765
+ */
766
+ function addKeyboardFocus(element){
767
+ let isClick = false;
768
+
769
+ element.addEventListener('mousedown', function () {
770
+ isClick = true;
771
+ });
772
+
773
+ element.addEventListener('focus', function (e) {
774
+ if(!isClick){
775
+ element.classList.add('keyboard-focus');
776
+ }
777
+
778
+ //reset flag
779
+ isClick = false;
780
+ });
781
+
782
+ element.addEventListener('blur', function () {
783
+ element.classList.remove('keyboard-focus');
784
+ });
785
+ }
786
+
787
+ /**
788
+ * findClosestParent()
789
+ * finds closest parent element by class
790
+ */
791
+ function findClosestParent(element, parentClass) {
792
+ while ((element = element.parentElement) && !element.classList.contains(parentClass));
793
+ return element;
794
+ }
795
+
796
+ /**
797
+ * menuEnter()
798
+ * Gets called whenever your mouse enters a trigger link
799
+ */
800
+
801
+ function menuEnter(e) {
802
+ //for keyboard navigation: if anything other than "enter" key is pressed do not continue
803
+ if((e.type == 'keydown' || e.type == 'keypress') && ((e.keyCode || e.which) != 13)){
804
+ return;
805
+ }else if(e.type == 'keydown' || e.type == 'keypress' || e.type == 'click'){
806
+ if(appState.mode === "desktop") {
807
+ Array.prototype.forEach.call(headerAnchors, function (el, i) {
808
+ el.setAttribute('tabindex', '-1');
809
+ });
810
+ }
811
+ Array.prototype.forEach.call(submenuWrapper, function (el, i) {
812
+ el.removeEventListener('mouseover', submenuWrapperHover);
813
+ });
814
+ }else if(e.type == 'mouseenter'){
815
+ removeNavEvents();
816
+ if (appState.isTouchDevice) {
817
+ initDesktopTouchEvents();
818
+ } else {
819
+ initDesktopEvents();
820
+ }
821
+ if(appState.mode == "desktop"){
822
+ if (panelIsOpen&&e.target.classList.contains('open')) {
823
+ e.preventDefault();
824
+ return;
825
+ }
826
+ }
827
+ }else if(e.type == 'click'){
828
+ if(appState.mode == "desktop"){
829
+ if (panelIsOpen) {
830
+ e.preventDefault();
831
+ return;
832
+ }
833
+ }
834
+ }
835
+
836
+ e.preventDefault();
837
+ let panelToFind;
838
+
839
+ //get the name of the panel to find which is stored in the data attribute of the trigger
840
+ if (e.target.nodeName === "A") {
841
+ panelToFind = e.target.getAttribute('data-side-panel-trigger');
842
+ } else {
843
+ panelToFind = utils.getParentByTagName(e.target, "A").getAttribute('data-side-panel-trigger');
844
+ }
845
+
846
+ if (appState.mode === "mobile" && utils.hasClass(this, 'open')) {
847
+
848
+ //if our mode is mobile and the panel is already open just close it
849
+ Array.prototype.forEach.call(panels, function (el, i) {
850
+
851
+ if (el.getAttribute('data-side-panel') === panelToFind) {
852
+ closePanel(el);
853
+ }
854
+
855
+
856
+ });
857
+
858
+
859
+ } else {
860
+ if(this.classList.contains('open')){
861
+ closePanel(currentlyOpenPanel);
862
+ return;
863
+ }
864
+
865
+ //if there is a current panel open then close it before opening the new one
866
+ if (panelIsOpen) {
867
+ closePanel(currentlyOpenPanel);
868
+ }
869
+
870
+ //add and open class the the a tag
871
+ this.classList.add('open');
872
+ this.setAttribute('aria-expanded', 'true');
873
+
874
+ //for each panel find the one that was triggered
875
+ Array.prototype.forEach.call(panels, function (el, i) {
876
+
877
+ if (el.getAttribute('data-side-panel') === panelToFind) {
878
+
879
+ openPanel(el);
880
+ if(appState.mode == 'desktop' && !appState.isTouchDevice)
881
+ el.style.display = "block";
882
+ let allAinPanel = el.querySelectorAll('a');
883
+ Array.prototype.forEach.call(allAinPanel, function(el, i){
884
+ el.removeAttribute('tabindex');
885
+ });
886
+ let allULinPanel = el.querySelectorAll('ul');
887
+ if(el.querySelector('.geico-nav-menu-secondary-wrapper')){
888
+ let allSecondaryUL = el.querySelectorAll('.geico-nav-menu-secondary-wrapper > ul');
889
+ Array.prototype.forEach.call(allSecondaryUL, function(el, i){
890
+ el.removeAttribute('tabindex');
891
+ });
892
+ Array.prototype.forEach.call(allULinPanel, function(el, i){
893
+ el.setAttribute('tabindex', '-1');
894
+ let allSVGinUL = el.querySelectorAll('svg');
895
+ Array.prototype.forEach.call(allSVGinUL, function(el, i){
896
+ el.setAttribute('focusable', 'false');
897
+ });
898
+ });
899
+ }
900
+
901
+
902
+ }else{
903
+ if(appState.mode == 'desktop' && !appState.isTouchDevice)
904
+ el.style.display = "none";
905
+ let allAinPanel = el.querySelectorAll('a');
906
+ Array.prototype.forEach.call(allAinPanel, function(el, i){
907
+ el.setAttribute('tabindex', '-1');
908
+ });
909
+ let allULinPanel = el.querySelectorAll('ul');
910
+
911
+ if(el.querySelector('.geico-nav-menu-secondary-wrapper')){
912
+ let allSecondaryUL = el.querySelectorAll('.geico-nav-menu-secondary-wrapper > ul');
913
+ Array.prototype.forEach.call(allSecondaryUL, function(el, i){
914
+ el.setAttribute('tabindex', '-1');
915
+ });
916
+ }
917
+ Array.prototype.forEach.call(allULinPanel, function(el, i){
918
+ el.setAttribute('tabindex', '-1');
919
+ });
920
+ }
921
+ });
922
+
923
+ //add a class to every panel trigger you did not roll over
924
+ Array.prototype.forEach.call(panelTriggers, (el, i) => {
925
+
926
+ if (el != this) {
927
+ el.classList.add("not-open");
928
+ el.setAttribute('aria-expanded', 'false');
929
+ }
930
+ });
931
+
932
+ }
933
+
934
+ }
935
+
936
+ /**
937
+ * menuEnter()
938
+ * Gets called whenever your mouse leaves a trigger link
939
+ */
940
+ function menuLeave(e) {
941
+ //When your mouse leaves the trigger detect if its over the open panel
942
+ //If its not over the open panel then close the panel
943
+ if (currentlyOpenPanel) {
944
+ if (!currentlyOpenPanel.contains(e.relatedTarget)) {
945
+ closePanel(currentlyOpenPanel);
946
+ }
947
+ }
948
+
949
+ }
950
+
951
+ function scrollTo(element, to, duration) {
952
+ if (duration <= 0) return;
953
+ var difference = to - element.scrollTop;
954
+ var perTick = difference / duration * 10;
955
+
956
+ setTimeout(function() {
957
+ element.scrollTop = element.scrollTop + perTick;
958
+ if (element.scrollTop === to) return;
959
+ scrollTo(element, to, duration - 10);
960
+ }, 10);
961
+ }
962
+
963
+ /**
964
+ * panelLeave()
965
+ * Gets fired when your mouse leaves a panel
966
+ */
967
+ function panelLeave() {
968
+ //only close the panel if there is not a sub panel open
969
+ if (currentlyOpenSubPanel || currentlyOpenPanel) {
970
+ if(!currentlyOpenPanel.contains(document.activeElement)){
971
+ closePanel(currentlyOpenPanel);
972
+ }
973
+ }
974
+ }
975
+
976
+
977
+ /**
978
+ * openPanel()
979
+ * Opens a panel by adding the necessary open a classes
980
+ */
981
+ function openPanel(el) {
982
+
983
+ //if there is a panel close timer than cancel it because we just opened up another panel
984
+ if (panel_timer) {
985
+ clearTimeout(panel_timer);
986
+ nav.style.display = "block";
987
+ }
988
+
989
+ nav.style.display = "block";
990
+
991
+
992
+ if (appState.mode === "mobile") {
993
+ document.querySelector('body').style.overflowY = "hidden";
994
+ document.querySelector('body').style.position = "fixed";
995
+
996
+ header.querySelector('#header-middle-links a').setAttribute('tabindex', '-1');
997
+
998
+ if(el.getAttribute('data-side-panel')=='mobile-menu'){
999
+ let allHeaderRight = header.querySelectorAll('#header-right-links .mobile-links a');
1000
+ Array.prototype.forEach.call(allHeaderRight, function(el, i){
1001
+ el.setAttribute('tabindex', '-1');
1002
+ });
1003
+ }else if(el.classList.contains('right')){
1004
+ header.querySelector('#header-middle-links a').removeAttribute('tabindex');
1005
+ }
1006
+
1007
+ }
1008
+
1009
+ clearTimeout(open_timer);
1010
+
1011
+ open_timer = setTimeout(()=> {
1012
+
1013
+ nav.classList.add('open');
1014
+ if(el.getAttribute('data-side-panel')=='mobile-menu'){
1015
+ header.classList.add('open');
1016
+ }
1017
+ el.classList.add('open');
1018
+ if(appState.mode === 'mobile'&&!appState.isTouchDevice){
1019
+ Array.prototype.forEach.call(panels, function(el, i){
1020
+ if(!el.classList.contains('open')){
1021
+ el.style.display = "none";
1022
+ }
1023
+ });
1024
+ }
1025
+
1026
+ //store the open panel
1027
+ currentlyOpenPanel = el;
1028
+ panelIsOpen = true;
1029
+
1030
+ }, 50);
1031
+
1032
+ }
1033
+
1034
+ /**
1035
+ * closePanel()
1036
+ * Closes a panel by removing the necessary open a classes
1037
+ */
1038
+ function closePanel(el, e) {
1039
+
1040
+ if (appState.mode === "mobile") {
1041
+ document.querySelector('body').style.overflowY = "visible";
1042
+ document.querySelector('body').style.position = "relative";
1043
+
1044
+ closeAccordionsMobileNav();
1045
+
1046
+ header.querySelector('#header-middle-links a').removeAttribute('tabindex');
1047
+
1048
+ }
1049
+ if(appState.mode === 'mobile'){
1050
+ Array.prototype.forEach.call(panels, function(el, i){
1051
+
1052
+ el.removeAttribute('style');
1053
+
1054
+ });
1055
+ }
1056
+ nav.classList.remove('open');
1057
+ header.classList.remove('open');
1058
+ el.classList.remove('open');
1059
+ panelIsOpen = false;
1060
+ subpanelName = null;
1061
+
1062
+ Array.prototype.forEach.call(panelTriggers, function (el, i) {
1063
+ el.classList.remove('open');
1064
+ el.classList.remove('not-open');
1065
+ el.setAttribute('aria-expanded', 'false');
1066
+ });
1067
+
1068
+
1069
+ //if a sub menu is open then close that
1070
+ if (currentlyOpenSubPanel) {
1071
+ currentlyOpenSubPanel.classList.remove("open");
1072
+ currentlyOpenSubPanel = null;
1073
+ }
1074
+
1075
+
1076
+ panel_timer = setTimeout(()=> {
1077
+
1078
+
1079
+ Array.prototype.forEach.call(mainListItems, function (el, i) {
1080
+ el.classList.remove("open");
1081
+ });
1082
+
1083
+ if (appState.mode === "mobile") {
1084
+ Array.prototype.forEach.call(submenuWrapper, function (el, i) {
1085
+ el.style.maxHeight = "0px";
1086
+ });
1087
+ }
1088
+
1089
+ nav.style.display = "none";
1090
+ panel_timer = null;
1091
+
1092
+
1093
+ }, 500);
1094
+
1095
+
1096
+ removeTabIndexes();
1097
+ //no animation for kit purpose because too jagged
1098
+ }
1099
+
1100
+ /**
1101
+ * submenuWrapperHover()
1102
+ * Detects if you have rolled over the submenuWrapper
1103
+ * so we know when to close the menu when you roll off the submenu
1104
+ */
1105
+ function submenuWrapperHover(e) {
1106
+ if (currentlyOpenPanel) {
1107
+ //NodeList of items that the mouse is currently over in document order.
1108
+ //The last element in the NodeList is the most specific, each preceding
1109
+ //one should be a parent, grandparent, and so on.
1110
+ let nodes = document.querySelectorAll(":hover");
1111
+
1112
+ //if the target node is a div an the last hovered node is the wrapper
1113
+ //we know we are off the submenu so close menues
1114
+ if (e.target.nodeName == "DIV" && e.target == nodes[nodes.length - 1]) {
1115
+ closePanel(currentlyOpenPanel);
1116
+ }
1117
+ }
1118
+ }
1119
+
1120
+ /**
1121
+ * openSubMenu()
1122
+ * Opens the submenu when you click on its parent li
1123
+ * This is used when on a touch device
1124
+ */
1125
+ function openSubMenu(e) {
1126
+ Array.prototype.forEach.call(headerAnchors, function (el, i) {
1127
+ el.removeAttribute('tabindex');
1128
+ });
1129
+ //dont open a subpanel if the parent is not open
1130
+ if (!panelIsOpen) {
1131
+ return;
1132
+ }
1133
+
1134
+ clearTimeout(hover_timer);
1135
+ let p;
1136
+ let hoverDelay;
1137
+ if (appState.isTouchDevice) {
1138
+ p = this.parentNode;
1139
+ hoverDelay = 0;
1140
+ } else {
1141
+ p = this;
1142
+ hoverDelay = 150;
1143
+ }
1144
+
1145
+ let subWrapper = p.querySelector(".geico-nav-menu-secondary-wrapper");
1146
+
1147
+
1148
+ if (subWrapper) {
1149
+ e.preventDefault();
1150
+ }
1151
+ hover_timer = setTimeout(()=> {
1152
+
1153
+ if (!utils.hasClass(p, 'open')) {
1154
+ //animate the svg
1155
+ if(p.querySelector("svg")) {
1156
+ svgToAnim = p.querySelector("svg");
1157
+ svgAnim();
1158
+ }
1159
+ }
1160
+
1161
+ //if a sub menu is open then close that
1162
+ if (currentlyOpenSubPanel) {
1163
+ currentlyOpenSubPanel.classList.remove("open");
1164
+ currentlyOpenSubPanel = null;
1165
+ }
1166
+
1167
+ currentlyOpenSubPanel = p;
1168
+
1169
+ if (!appState.isTouchDevice) {
1170
+ p.classList.toggle('open'); //this FF
1171
+ }
1172
+
1173
+ if (subWrapper) {
1174
+
1175
+ if (appState.isTouchDevice) {
1176
+ p.classList.toggle('open');
1177
+ }
1178
+ }
1179
+
1180
+
1181
+ }, hoverDelay);
1182
+
1183
+ }
1184
+
1185
+
1186
+ /**
1187
+ * closeMobileSubMenu()
1188
+ * Opens the submenu when you click on its parent li
1189
+ */
1190
+ function closeMobileSubMenu(el) {
1191
+ el.classList.remove('open');
1192
+ let subWrapper = el.querySelector(".geico-nav-menu-secondary-wrapper");
1193
+ subWrapper.style.maxHeight = "0px";
1194
+ currentlyOpenSubPanel = null;
1195
+ subpanelName = null;
1196
+
1197
+ }
1198
+
1199
+
1200
+ /**
1201
+ * openMobileSubMenu()
1202
+ * Opens the submenu when you click on its parent li
1203
+ */
1204
+ function openMobileSubMenu(e) {
1205
+
1206
+ //console.log("openMobileSubMenu");
1207
+
1208
+ //this is the list item that was clicked
1209
+ let p = this.parentNode;
1210
+ let subWrapper = p.querySelector(".geico-nav-menu-secondary-wrapper");
1211
+ let clickedSubpanelName = p.getAttribute('data-name');
1212
+ let shouldOpenSubPanel = false;
1213
+ let subMenuOpened = false;
1214
+ //console.log(subWrapper.parentNode.querySelector('a').querySelector('span').getBoundingClientRect().top);
1215
+
1216
+
1217
+ if (subWrapper) {
1218
+ //if there is a submenu then prevent default
1219
+ e.preventDefault();
1220
+
1221
+ if (subpanelName !== clickedSubpanelName) {
1222
+ shouldOpenSubPanel = true;
1223
+ }
1224
+
1225
+ ///close any open submenus
1226
+ if (currentlyOpenSubPanel) {
1227
+ subMenuOpened = true;
1228
+ closeMobileSubMenu(currentlyOpenSubPanel);
1229
+ }
1230
+
1231
+ //if the submenu you are trying to open up is not already open then open the submenu
1232
+ if (shouldOpenSubPanel) {
1233
+
1234
+ //store the open panel and its name
1235
+ currentlyOpenSubPanel = p;
1236
+ subpanelName = this.parentNode.getAttribute('data-name');
1237
+
1238
+
1239
+ if (!utils.hasClass(p, 'open')) {
1240
+ //animate the svg
1241
+ svgToAnim = p.querySelector("svg");
1242
+ svgAnim();
1243
+ }
1244
+
1245
+ p.classList.toggle('open');
1246
+ let accordionContainer = searchParentByClassName(this, "accordion-content-container");
1247
+
1248
+ let subWrapperUl = subWrapper.querySelector("ul");
1249
+ if (window.getComputedStyle(subWrapper).maxHeight == "0px") {
1250
+
1251
+ subWrapper.style.maxHeight = outerHeight(subWrapperUl) + "px";
1252
+ accordionContainer.style.maxHeight = accordionContainer.offsetHeight + outerHeight(subWrapperUl) + "px";
1253
+
1254
+ //if there are no other submenus opened, scroll the current submenu being opened to the top of the page
1255
+ if (subMenuOpened === false) {
1256
+ let aboveNavOffset = 0;
1257
+ let aboveNavElements = document.getElementsByClassName('above-nav');
1258
+
1259
+ Array.prototype.forEach.call(aboveNavElements, function (el, i) {
1260
+ aboveNavOffset += el.offsetHeight;
1261
+ });
1262
+
1263
+ let mobileMenu = document.querySelector('[data-side-panel="mobile-menu"]');
1264
+ let offset = p.getBoundingClientRect().top + mobileMenu.scrollTop - aboveNavOffset;
1265
+
1266
+ setTimeout(()=>{
1267
+ scrollTo(mobileMenu, offset, 200);
1268
+ }, 296);
1269
+ }
1270
+
1271
+ } else {
1272
+ accordionContainer.style.maxHeight = accordionContainer.offsetHeight - outerHeight(subWrapperUl) + "px";
1273
+ subWrapper.style.maxHeight = "0px";
1274
+ }
1275
+ }
1276
+ } else {
1277
+ closePanel(currentlyOpenPanel);
1278
+ }
1279
+ }
1280
+
1281
+
1282
+ /**
1283
+ * Svetoslav Kostadinov
1284
+ * 06.Jan.2016
1285
+ * Recursive Search of a Parent element by a search Criteria
1286
+ *
1287
+ * @param sPoint // starting point
1288
+ * @param criteria // search criteria
1289
+ * @returns {*}
1290
+ */
1291
+ function searchParentByClassName(sPoint, criteria){
1292
+ if(typeof sPoint === "undefined") {
1293
+ return null;
1294
+ }
1295
+ else if(sPoint.className.indexOf(criteria) === -1) {
1296
+ let element = searchParentByClassName(sPoint.parentNode, criteria);
1297
+ if (element !== null)
1298
+ return element;
1299
+ }
1300
+ else {
1301
+ return sPoint;
1302
+ }
1303
+ }
1304
+
1305
+ /**
1306
+ * addSVGs()
1307
+ * Adds the border SVGs to all first level nav items
1308
+ */
1309
+ function addSVGs() {
1310
+
1311
+ //All panel triggers should have a click event that open or closes a panel
1312
+ Array.prototype.forEach.call(actionableIcons, function (el, i) {
1313
+ el.insertAdjacentHTML('beforebegin', `<svg width="60" height="60" version="1.1" xmlns="http://www.w3.org/2000/svg" style="width: 60px; height: 60px;"><circle cx="30" cy='30' r="29" /></svg>`);
1314
+ });
1315
+
1316
+ Array.prototype.forEach.call(actionableIcons, function (el, i) {
1317
+ el.style.width = "60px";
1318
+ el.style.height = "60px";
1319
+ el.style.lineHeight = "60px";
1320
+ el.style.fontSize = "30px";
1321
+ });
1322
+
1323
+ }
1324
+
1325
+
1326
+ /**
1327
+ * addSVGs()
1328
+ * Adds additional markup to every hamburger item
1329
+ */
1330
+ function addHamburgerMarkup() {
1331
+
1332
+ //All panel triggers should have a click event that open or closes a panel
1333
+ Array.prototype.forEach.call(hamburgerIcons, function (el, i) {
1334
+ el.insertAdjacentHTML('beforeend', `<div class="hamburger"><span></span><span></span><span></span><span></span></div>`);
1335
+ });
1336
+
1337
+ }
1338
+
1339
+
1340
+ /**
1341
+ * handleResize()
1342
+ * listen for window resize so we can detect the mode
1343
+ */
1344
+ function handleResize() {
1345
+ if (appState.mode === "desktop" && currentNavState === "mobile") {
1346
+ //clear some styling
1347
+ Array.prototype.forEach.call(submenuWrapper, function (el, i) {
1348
+ el.removeAttribute('style');
1349
+ });
1350
+ Array.prototype.forEach.call(panels, function(el, i){
1351
+ if(!el.classList.contains('open')){
1352
+ el.removeAttribute('style');
1353
+ }
1354
+ });
1355
+ removeNavEvents();
1356
+ currentNavState = "desktop";
1357
+ if (currentlyOpenPanel) {
1358
+ closePanel(currentlyOpenPanel);
1359
+ }
1360
+ if (appState.isTouchDevice) {
1361
+ initDesktopTouchEvents();
1362
+ } else {
1363
+ initDesktopEvents();
1364
+ }
1365
+ //document.querySelector('body').style.overflowY = "visible";
1366
+ //document.querySelector('body').style.position = "relative";
1367
+ //body.style.overflowX = "visible";
1368
+ body.removeAttribute('style');
1369
+
1370
+ } else if (appState.mode === "mobile" && currentNavState === "desktop") {
1371
+ removeNavEvents();
1372
+ currentNavState = "mobile";
1373
+ if (currentlyOpenPanel) {
1374
+ closePanel(currentlyOpenPanel);
1375
+ }
1376
+ if (appState.isTouchDevice) {
1377
+ initMobileTouchEvents();
1378
+ } else {
1379
+ initMobileEvents();
1380
+ }
1381
+ }
1382
+ }
1383
+
1384
+
1385
+ /**
1386
+ * closeAllPanels()
1387
+ * this force closes all menus, good for single page apps thats need to close the menu
1388
+ */
1389
+ function closeAllPanels() {
1390
+
1391
+ if (currentlyOpenPanel) {
1392
+ closePanel(currentlyOpenPanel);
1393
+ removeHoverStyle();
1394
+ }
1395
+ }
1396
+
1397
+
1398
+ /**
1399
+ * outerHeight()
1400
+ * used to get the height of an element that is the same across all browsers
1401
+ *
1402
+ * @param {Object} node DOM node
1403
+ * @return {number}
1404
+ */
1405
+ function outerHeight(el) {
1406
+ let height = el.offsetHeight;
1407
+ let style = getComputedStyle(el);
1408
+
1409
+ height += parseInt(style.marginTop) + parseInt(style.marginBottom);
1410
+ return height;
1411
+ }
1412
+
1413
+
1414
+ /**
1415
+ * svgAnim()
1416
+ * animates the svg around the icon
1417
+ */
1418
+ function svgAnim() {
1419
+
1420
+ if (appState.mode === "desktop") {
1421
+ tick += tickSpeed;
1422
+ } else {
1423
+ tick += tickSpeedMobile;
1424
+ }
1425
+
1426
+
1427
+ let t = tick / 100;
1428
+ let offsetStrokeDasharray = easeInQuad(t, 0, dashArrayComplete, 1);
1429
+ svgToAnim.style.strokeDasharray = `${offsetStrokeDasharray} , ${dashArrayComplete}`;
1430
+
1431
+ if (tick < 100) {
1432
+ requestAnimationFrame(svgAnim.bind(this));
1433
+ } else {
1434
+ tick = 0;
1435
+ }
1436
+
1437
+ }
1438
+
1439
+
1440
+ /**
1441
+ * easeInQuad()
1442
+ * Quadratic easing
1443
+ */
1444
+ function easeInQuad(t, b, c, d) {
1445
+ var ts = (t /= d) * t;
1446
+ return b + c * (ts);
1447
+ }
1448
+ /**
1449
+ * easeInCubic()
1450
+ * Cubic easing
1451
+ */
1452
+ function easeInCubic(t, b, c, d) {
1453
+ var ts = (t /= d) * t * t;
1454
+ return b + c * (ts);
1455
+ }
1456
+
1457
+ export { init, closeAllPanels };