geico-design-kit 7.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

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 };