From 720ac53e7e5352990ba5f9ba7de932a4e4fa5568 Mon Sep 17 00:00:00 2001
From: James Jacobs <jamesjacobs1@mac.com>
Date: Mon, 7 Sep 2020 08:26:10 +0100
Subject: [PATCH 01/15] Fix broken lexicon page

---
 views/lexicon/tabs/buttons_labels.html.twig | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/views/lexicon/tabs/buttons_labels.html.twig b/views/lexicon/tabs/buttons_labels.html.twig
index 8c2012b977..4c30ff4b11 100644
--- a/views/lexicon/tabs/buttons_labels.html.twig
+++ b/views/lexicon/tabs/buttons_labels.html.twig
@@ -699,7 +699,8 @@
             	})
 
             }}
-        </p>
+        </div>
+    </p>
 
     <h2 class="heading">All the things!</h2>
     <p>

From 961c75938d72f1665b38021558d67424d008e8e8 Mon Sep 17 00:00:00 2001
From: James Jacobs <jamesjacobs1@mac.com>
Date: Mon, 7 Sep 2020 08:27:11 +0100
Subject: [PATCH 02/15] Fix nav focus issue

---
 js/NavMainComponent.js               | 94 ++++++++++++++++++++++------
 tests/js/web/NavMainComponentTest.js | 42 +++++++++++++
 2 files changed, 116 insertions(+), 20 deletions(-)

diff --git a/js/NavMainComponent.js b/js/NavMainComponent.js
index f389c776dc..32edee1fbe 100644
--- a/js/NavMainComponent.js
+++ b/js/NavMainComponent.js
@@ -10,6 +10,8 @@ function NavMainComponent ($html, rootWindow, focusManagementService) {
 };
 
 NavMainComponent.MISSING_ATTR_ERROR = 'A nav link must have a href or data-target attribute';
+NavMainComponent.CLOSE_WITH_ESCAPE = "CLOSE_WITH_ESCAPE";
+NavMainComponent.CLOSE_WITH_CLICK = "CLOSE_WITH_CLICK";
 
 /**
  * Initialise
@@ -27,7 +29,6 @@ NavMainComponent.prototype.init = function () {
 
     component.$body = this.$html.find('body');
     component.$navMain = this.$html.find('.nav-main');
-    component.$contentMain = this.$html.find('.content-main');
     component.$brandingLink = this.$html.find('.jadu-branding');
     component.$navPrimary = this.$html.find('.nav-primary');
     component.$navSecondary = this.$html.find('.nav-secondary');
@@ -82,9 +83,11 @@ NavMainComponent.prototype.init = function () {
         }
     });
 
-    // Close navs on main content click
-    component.$contentMain.on('click', function () {
-        component.closeNavs($(this));
+    // Close navs when element outside of nav is clicked
+    component.$body.find('.toolbar, .content-main, .footer').on('click', function () {
+        if (component.isNavOpen()) {
+            component.closeNavs($(this));
+        }
     });
 
     // Open secondary nav on primary nav item click
@@ -126,11 +129,11 @@ NavMainComponent.prototype.init = function () {
     this.$html.on('keydown', function (event) {
         if (event.keyCode === 27) {
             if (component.$navQuaternary.hasClass('is-open')) {
-                component.closeQuaternaryNav();
+                component.closeQuaternaryNav({ type: NavMainComponent.CLOSE_WITH_ESCAPE });
             } else if (component.$navTertiary.hasClass('is-open')) {
                 component.closeTertiaryNav();
             } else if (component.$navSecondary.hasClass('is-open')) {
-                component.closeSecondaryNav();
+                component.closeSecondaryNav({ type: NavMainComponent.CLOSE_WITH_ESCAPE });
             } else if (isMobile && component.$body.hasClass('open-nav')) {
                 component.showMobileNav(false)
             }
@@ -138,6 +141,27 @@ NavMainComponent.prototype.init = function () {
     });
 }
 
+/**
+ * Check if any navs are open
+ * @returns {boolean}
+ */
+NavMainComponent.prototype.isNavOpen = function () {
+    var component = this,
+        isMobile = !component.window.matchMedia('(min-width: 992px)').matches;
+
+    if (component.$navQuaternary.hasClass('is-open')) {
+        return true;
+    } else if (component.$navTertiary.hasClass('is-open')) {
+        return true;
+    } else if (component.$navSecondary.hasClass('is-open')) {
+        return true;
+    } else if (isMobile && component.$body.hasClass('open-nav')) {
+        return true;
+    } else {
+        return false;
+    }
+}
+
 /**
  * Unto the tabindex if the main nav is in responsive mode
  * This maintains the tab order to ensure WCAG compliance
@@ -157,7 +181,7 @@ NavMainComponent.prototype.manageTabIndexes = function () {
 
 /**
  * Open secondary navigation, close all other navs and highlight primary nav item parent
- * @param {jQuery} $linkClicked - the element clicked to open secondary nav
+ * @param {jQuery} $triggeringElement - the element clicked to open secondary nav
  * @param {Event} event - click event for the primary nav link
  */
 NavMainComponent.prototype.openSecondaryNav = function ($triggeringElement, event) {
@@ -235,7 +259,7 @@ NavMainComponent.prototype.closeNavs = function ($linkClicked) {
         $linkParent = $linkClicked.closest('.nav-flyout');
 
     if ($linkParent.hasClass('nav-secondary')) {
-        component.closeSecondaryNav();
+        component.closeSecondaryNav({ type: NavMainComponent.CLOSE_WITH_CLICK, trigger: $linkClicked });
     }
 
     else if ($linkParent.hasClass('nav-tertiary')) {
@@ -243,20 +267,22 @@ NavMainComponent.prototype.closeNavs = function ($linkClicked) {
     }
 
     else if ($linkParent.hasClass('nav-quaternary')) {
-        component.closeQuaternaryNav();
+        component.closeQuaternaryNav({ type: NavMainComponent.CLOSE_WITH_CLICK, trigger: $linkClicked });
     }
 
+    // like a body click or something outside of navs
     else {
-        component.closeSecondaryNav();
+        component.closeSecondaryNav({ type: NavMainComponent.CLOSE_WITH_CLICK, trigger: $linkClicked });
         component.closeTertiaryNav();
-        component.closeQuaternaryNav();
+        component.closeQuaternaryNav({ type: NavMainComponent.CLOSE_WITH_CLICK, trigger: $linkClicked });
     }
 }
 
 /**
  * Close secondary navigation
+ * @param {Object} [action]
  */
-NavMainComponent.prototype.closeSecondaryNav = function () {
+NavMainComponent.prototype.closeSecondaryNav = function (action) {
     var component = this;
 
     component.$navMain.removeClass('is-open');
@@ -266,8 +292,23 @@ NavMainComponent.prototype.closeSecondaryNav = function () {
     component.$navMain.find('.nav-item.is-active').removeClass('is-active');
     component.$navSecondary.find('.nav-list').removeClass('is-active');
 
-    if (component.focusManagementService.hasStoredElement()) {
-        component.focusManagementService.returnFocusToElement();
+    if (action === undefined) {
+        return;
+    }
+
+    switch (action.type) {
+        case NavMainComponent.CLOSE_WITH_ESCAPE:
+            if (component.focusManagementService.hasStoredElement()) {
+                component.focusManagementService.returnFocusToElement();
+            }
+            break;
+        case NavMainComponent.CLOSE_WITH_CLICK:
+            if (action.trigger.parents('.nav-secondary').length > 0) {
+                if (component.focusManagementService.hasStoredElement()) {
+                    component.focusManagementService.returnFocusToElement();
+                }
+            }
+            break;
     }
 }
 
@@ -288,22 +329,35 @@ NavMainComponent.prototype.closeTertiaryNav = function () {
 
 /**
  * Close quaternary navigation
+ * @param {Object} [action]
  */
-NavMainComponent.prototype.closeQuaternaryNav = function () {
+NavMainComponent.prototype.closeQuaternaryNav = function (action) {
     var component = this;
 
     component.$navQuaternary.removeClass('is-open');
     component.$navQuaternary.find('.nav-list.is-active').removeClass('is-active');
+    component.$navTertiary.find('[aria-expanded=true]').attr('aria-expanded', 'false');
 
-    if (component.focusManagementService.hasStoredElement()) {
-        component.focusManagementService.returnFocusToElement();
+    if (action === undefined) {
+        return;
     }
 
-    // Reset aria-expanded on tertiary link
-    component.$navTertiary.find('[aria-expanded=true]').attr('aria-expanded', 'false');
+    switch (action.type) {
+        case NavMainComponent.CLOSE_WITH_ESCAPE:
+            if (component.focusManagementService.hasStoredElement()) {
+                component.focusManagementService.returnFocusToElement();
+            }
+            break;
+        case NavMainComponent.CLOSE_WITH_CLICK:
+            if (action.trigger.parents('.nav-quaternary').length > 0) {
+                if (component.focusManagementService.hasStoredElement()) {
+                    component.focusManagementService.returnFocusToElement();
+                }
+            }
+            break;
+    }
 }
 
-
 /**
  * Toggle mobile navigation
  */
diff --git a/tests/js/web/NavMainComponentTest.js b/tests/js/web/NavMainComponentTest.js
index 480df96aac..4da483183f 100644
--- a/tests/js/web/NavMainComponentTest.js
+++ b/tests/js/web/NavMainComponentTest.js
@@ -871,4 +871,46 @@ describe('NavMainComponent', function () {
             expect(this.$body.hasClass('open-nav')).to.be.false;
         });
     });
+
+    describe('isNavOpen()', function () {
+        it('should return true if quaternary nav is open', function () {
+            this.navMainComponent.init();
+
+            this.$html.find('.nav-quaternary').addClass('is-open');
+
+            expect(this.navMainComponent.isNavOpen()).to.be.true;
+        });
+
+        it('should return true if tertiary nav is open', function () {
+            this.navMainComponent.init();
+
+            this.$html.find('.nav-tertiary').addClass('is-open');
+
+            expect(this.navMainComponent.isNavOpen()).to.be.true;
+        });
+
+        it('should return true if secondary nav is open', function () {
+            this.navMainComponent.init();
+
+            this.$html.find('.nav-secondary').addClass('is-open');
+
+            expect(this.navMainComponent.isNavOpen()).to.be.true;
+        });
+
+        it('should return true if mobile nav is open', function () {
+            this.window.matchMedia.returns({matches: false});
+            this.navMainComponent.init();
+            this.clickEvent = $.Event('click');
+
+            this.$mobileMenuButton.trigger(this.clickEvent);
+
+            expect(this.navMainComponent.isNavOpen()).to.be.true;
+        });
+
+        it('should return false if all navs are closed', function () {
+            this.navMainComponent.init();
+
+            expect(this.navMainComponent.isNavOpen()).to.be.false;
+        });
+    });
 });

From d6ed3d2dc6b9cbb78d7bb6d5068af347dd29d499 Mon Sep 17 00:00:00 2001
From: James Jacobs <jamesjacobs1@mac.com>
Date: Mon, 7 Sep 2020 08:27:37 +0100
Subject: [PATCH 03/15] Fix disapearing help button issue

---
 js/HelpTextComponent.js               |  8 ++---
 stylesheets/_component.tab-help.scss  | 26 +-------------
 tests/js/web/HelpTextComponentTest.js | 51 +++++++++++++--------------
 3 files changed, 30 insertions(+), 55 deletions(-)

diff --git a/js/HelpTextComponent.js b/js/HelpTextComponent.js
index 08a5075474..63b98309f3 100644
--- a/js/HelpTextComponent.js
+++ b/js/HelpTextComponent.js
@@ -87,11 +87,11 @@ HelpTextComponent.prototype.updateHelpSidebar = function () {
     var component = this,
         $activeTabContainer = component.$html.find('.tab__pane.is-active .tab__container'),
         activeTabSideBarContentHtml = component.$html.find('.tab__pane.is-active .tab__sidebar').html(),
-        $mobileToggleHelpButton = $('<button class="show-page-help js-show-page-help"><i class="icon-question-sign" aria-hidden="true"></i><span class="hide">Show on-page help</span></button>'),
-        $mobileToggleContainer = component.$html.find('.toolbar'),
+        $mobileToggleHelpButton = $('<button type="button" class="btn show-page-help js-show-page-help">Show Page Help</button>'),
+        $mobileToggleContainer = component.$html.find('.tab__pane.is-active .tab__content'),
         $tabHelp = component.$html.find('.tab-help'),
         isMobile,
-        mobileCloseHelpButton = '<button class="close-page-help js-close-page-help"><i class="icon-remove-sign" aria-hidden="true"></i><span class="hide">Close on-page help</span></button>';
+        mobileCloseHelpButton = '<button type="button" class="close-page-help js-close-page-help"><i class="icon-remove-sign" aria-hidden="true"></i><span class="hide">Close on-page help</span></button>';
 
     // Check if active tab has help text
     if (activeTabSideBarContentHtml && activeTabSideBarContentHtml.length > 0) {
@@ -111,7 +111,7 @@ HelpTextComponent.prototype.updateHelpSidebar = function () {
 
         // If mobile help button doesn't already exist add it if help text exists
         if (!$mobileToggleContainer.find('.js-show-page-help').length) {
-            $mobileToggleHelpButton.appendTo($mobileToggleContainer);
+            $mobileToggleHelpButton.prependTo($mobileToggleContainer);
         }
 
         // Add class used for setting desktop column widths
diff --git a/stylesheets/_component.tab-help.scss b/stylesheets/_component.tab-help.scss
index 06b365b12e..355fe269c7 100644
--- a/stylesheets/_component.tab-help.scss
+++ b/stylesheets/_component.tab-help.scss
@@ -62,35 +62,11 @@ $nav-color-dark:  darken(color(jadu-blue, dark), 5%) !default;
 }
 
 .show-page-help {
-    background-color: transparent;
-    border: 0;
-    color: color(gray, dark);
-    display: inline-block;
-    font-size: 28px;
-    line-height: normal;
-    margin-top: -45px;
-    padding: 0;
-    position: absolute;
-    text-decoration: none;
-    transition: all 100ms ease-in;
-    right: 20px;
+    margin-bottom: $margin-large-vertical;
 
     @include respond-min($screen-desktop) {
         display: none;
     }
-
-    &:hover,
-    &.is-open {
-        color: $nav-color-dark;
-    }
-
-    &:active {
-        color: darken($nav-color-dark, 10%);
-    }
-
-    &:focus {
-        @include pulsar-button-focused;
-    }
 }
 
 .close-page-help {
diff --git a/tests/js/web/HelpTextComponentTest.js b/tests/js/web/HelpTextComponentTest.js
index 682a347fa2..33089186a1 100644
--- a/tests/js/web/HelpTextComponentTest.js
+++ b/tests/js/web/HelpTextComponentTest.js
@@ -14,7 +14,6 @@ describe('HelpTextComponent', function() {
         this.$document = $('<div></div>').appendTo(this.$window);
         this.$html = $('<html></html>').appendTo(this.$document);
         this.$body = $('<body></body>').appendTo(this.$html);
-        this.$toolbar = $('<div class="toolbar"></div>').appendTo(this.$body);
         this.$tabHelpContainer = $('<div class="tab-help-container"></div>').appendTo(this.$body);
         this.$tabHelp = $('<div class="tab-help"></div>').appendTo(this.$tabHelpContainer);
         this.$contentMain = $('<div class="content-main"></div>').appendTo(this.$body);
@@ -46,15 +45,15 @@ describe('HelpTextComponent', function() {
         });
 
         it('should copy the active tabs sidebar contents to the tab-help container', function() {
-            expect(this.$tabHelp.html()).to.equal('<button class="close-page-help js-close-page-help" tabindex="-1"><i class="icon-remove-sign" aria-hidden="true"></i><span class="hide">Close on-page help</span></button>Some help text <a href="#" tabindex="-1">link</a>');
+            expect(this.$tabHelp.html()).to.equal('<button type="button" class="close-page-help js-close-page-help" tabindex="-1"><i class="icon-remove-sign" aria-hidden="true"></i><span class="hide">Close on-page help</span></button>Some help text <a href="#" tabindex="-1">link</a>');
         });
 
         it('should add the help-close button to the tab-help container', function() {
             expect(this.$tabHelp.find('.js-close-page-help').length).to.equal(1);
         });
 
-        it('should add the help toggle button to the toolbar', function() {
-            expect(this.$toolbar.find('.js-show-page-help').length).to.equal(1);
+        it('should add the help toggle button to .tab__content', function() {
+            expect(this.$tabContent.find('.js-show-page-help').length).to.equal(1);
         });
 
         it('should add tabindex="-1" to all links and buttons', function () {
@@ -73,45 +72,45 @@ describe('HelpTextComponent', function() {
         });
 
         it('should prevent the default behaviour', function () {
-            this.$toolbar.find('.js-show-page-help').trigger(this.clickEvent);
+            this.$tabContent.find('.js-show-page-help').trigger(this.clickEvent);
 
             expect(this.clickEvent.isDefaultPrevented()).to.be.true;
         });
 
         it('should stop propagation of the click event', function () {
-            this.$toolbar.find('.js-show-page-help').trigger(this.clickEvent);
+            this.$tabContent.find('.js-show-page-help').trigger(this.clickEvent);
 
             expect(this.clickEvent.isPropagationStopped()).to.be.true;
         });
 
         it('should open the side menu', function () {
-            this.$toolbar.find('.js-show-page-help').trigger(this.clickEvent);
+            this.$tabContent.find('.js-show-page-help').trigger(this.clickEvent);
 
             expect(this.$html.hasClass('open-help')).to.be.true;
         });
 
         it('should add the is-open class to the button ', function () {
-            this.$toolbar.find('.js-show-page-help').trigger(this.clickEvent);
+            this.$tabContent.find('.js-show-page-help').trigger(this.clickEvent);
 
-            expect(this.$toolbar.find('.js-show-page-help').hasClass('is-open')).to.be.true;
+            expect(this.$tabContent.find('.js-show-page-help').hasClass('is-open')).to.be.true;
         });
 
         it('should remove the aria-hidden attribute from the tab-help-container', function () {
-            this.$toolbar.find('.js-show-page-help').trigger(this.clickEvent);
+            this.$tabContent.find('.js-show-page-help').trigger(this.clickEvent);
 
             expect(this.$tabHelpContainer.attr('aria-hidden')).to.be.undefined;
         });
 
         it('move focus to the close button', function () {
             sinon.spy(this.helpTextComponent, 'toggleHelpSidebar');
-            this.$toolbar.find('.js-show-page-help').trigger(this.clickEvent);
+            this.$tabContent.find('.js-show-page-help').trigger(this.clickEvent);
             this.$tabHelpContainer.trigger('transitionend');
 
             expect(this.helpTextComponent.toggleHelpSidebar).to.have.been.called;
         });
 
         it('should remove tabindex="-1" from all links and buttons', function () {
-            this.$toolbar.find('.js-show-page-help').trigger(this.clickEvent);
+            this.$tabContent.find('.js-show-page-help').trigger(this.clickEvent);
 
             expect(this.$tabHelp.find('a').attr('tabindex')).to.be.undefined;
         });
@@ -125,43 +124,43 @@ describe('HelpTextComponent', function() {
             this.helpTextComponent.updateHelpSidebar();
             this.clickEvent = $.Event('click');
             this.$html.addClass('open-help');
-            this.$toolbar.find('.js-show-page-help').addClass('is-open');
+            this.$tabContent.find('.js-show-page-help').addClass('is-open');
         });
 
         it('should close the side menu', function () {
-            this.$toolbar.find('.js-show-page-help').trigger(this.clickEvent);
+            this.$tabContent.find('.js-show-page-help').trigger(this.clickEvent);
 
             expect(this.$html.hasClass('open-help')).to.be.false;
         });
 
         it('should remove the is-open class from the help button', function () {
-            this.$toolbar.find('.js-show-page-help').trigger(this.clickEvent);
+            this.$tabContent.find('.js-show-page-help').trigger(this.clickEvent);
 
-            expect(this.$toolbar.find('.js-show-page-help').hasClass('is-open')).to.be.false;
+            expect(this.$tabContent.find('.js-show-page-help').hasClass('is-open')).to.be.false;
         });
 
         it('should add the hide class to the tab-help-container', function () {
-            this.$toolbar.find('.js-show-page-help').trigger(this.clickEvent);
+            this.$tabContent.find('.js-show-page-help').trigger(this.clickEvent);
             this.$tabHelpContainer.trigger('transitionend');
             expect(this.$tabHelpContainer.hasClass('hide')).to.be.true;
         });
 
         it('should add aria-hidden attribute to the tab-help-container', function () {
-            this.$toolbar.find('.js-show-page-help').trigger(this.clickEvent);
+            this.$tabContent.find('.js-show-page-help').trigger(this.clickEvent);
             this.$tabHelpContainer.trigger('transitionend');
             expect(this.$tabHelpContainer.attr('aria-hidden')).to.equal('true');
         });
 
         it('should add the hide class to the tab-help-container if lt-ie10', function () {
             this.$html.addClass('lt-ie10');
-            this.$toolbar.find('.js-show-page-help').trigger(this.clickEvent);
+            this.$tabContent.find('.js-show-page-help').trigger(this.clickEvent);
 
             expect(this.$tabHelpContainer.hasClass('hide')).to.be.true;
         });
 
         it('should add aria-hidden attribute to the tab-help-container', function () {
             this.$html.addClass('lt-ie10');
-            this.$toolbar.find('.js-show-page-help').trigger(this.clickEvent);
+            this.$tabContent.find('.js-show-page-help').trigger(this.clickEvent);
 
             expect(this.$tabHelpContainer.attr('aria-hidden')).to.equal('true');
         });
@@ -187,7 +186,7 @@ describe('HelpTextComponent', function() {
         });
 
         it('should stop propagation of the click event', function () {
-            this.$toolbar.find('.js-show-page-help').trigger(this.clickEvent);
+            this.$tabContent.find('.js-show-page-help').trigger(this.clickEvent);
 
             expect(this.clickEvent.isPropagationStopped()).to.be.true;
         });
@@ -201,11 +200,11 @@ describe('HelpTextComponent', function() {
         });
 
         it('should remove the is-open class from the help button', function () {
-            this.$toolbar.find('.js-show-page-help').addClass('is-open');
+            this.$tabContent.find('.js-show-page-help').addClass('is-open');
 
             this.$tabHelp.find('.js-close-page-help').trigger(this.clickEvent);
 
-            expect(this.$toolbar.find('.js-show-page-help').hasClass('is-open')).to.be.false;
+            expect(this.$tabContent.find('.js-show-page-help').hasClass('is-open')).to.be.false;
         });
 
         it('should add the hide class from the tab-help-container', function () {
@@ -253,7 +252,7 @@ describe('HelpTextComponent', function() {
             this.helpTextComponent.updateHelpSidebar();
             this.clickEvent = $.Event('click');
             this.$html.addClass('open-help');
-            this.$toolbar.find('.js-show-page-help').addClass('is-open');
+            this.$tabContent.find('.js-show-page-help').addClass('is-open');
         });
 
         it('should close the help side bar', function () {
@@ -265,7 +264,7 @@ describe('HelpTextComponent', function() {
         it('should remove the is-open class from the mobile help button', function () {
             this.$tabContentLink.trigger(this.clickEvent);
 
-            expect(this.$toolbar.find('.js-show-page-help').hasClass('is-open')).to.be.false;
+            expect(this.$tabContent.find('.js-show-page-help').hasClass('is-open')).to.be.false;
         });
 
         it('should add the hide class from the tab-help-container', function () {
@@ -298,7 +297,7 @@ describe('HelpTextComponent', function() {
         });
 
         it('should copy the active tabs sidebar contents to the tab-help container', function() {
-            expect(this.$tabHelp.html()).to.equal('<button class="close-page-help js-close-page-help" tabindex="-1"><i class="icon-remove-sign" aria-hidden="true"></i><span class="hide">Close on-page help</span></button>Some help text <a href="#" tabindex="-1">link</a>');
+            expect(this.$tabHelp.html()).to.equal('<button type="button" class="close-page-help js-close-page-help" tabindex="-1"><i class="icon-remove-sign" aria-hidden="true"></i><span class="hide">Close on-page help</span></button>Some help text <a href="#" tabindex="-1">link</a>');
         });
 
         it('should add the help-close button to the tab-help container', function() {

From b718ed3685dce406930d4638cdbc8d89527fa825 Mon Sep 17 00:00:00 2001
From: James Jacobs <jamesjacobs1@mac.com>
Date: Mon, 7 Sep 2020 08:27:56 +0100
Subject: [PATCH 04/15] Fix issue where flash appeared over dropdowns

---
 stylesheets/_config.variables.scss | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/stylesheets/_config.variables.scss b/stylesheets/_config.variables.scss
index 7dc355e427..fc86580693 100644
--- a/stylesheets/_config.variables.scss
+++ b/stylesheets/_config.variables.scss
@@ -220,8 +220,8 @@ $zindex-tour:                         1000 !default;
 $zindex-footer:                       1020 !default;
 $zindex-tooltip:                      1055 !default;
 $zindex-sticky:                       1060 !default;
-$zindex-dropdown:                     1060 !default;
-$zindex-flash:                        1065 !default;
+$zindex-flash:                        1064 !default;
+$zindex-dropdown:                     1065 !default;
 $zindex-nav-secondary:                1070 !default;
 $zindex-nav:                          1080 !default;
 $zindex-popover:                      1090 !default;

From 48edf1cdea2f2aa01b9943d9532fd53fb34db02d Mon Sep 17 00:00:00 2001
From: James Jacobs <jamesjacobs1@mac.com>
Date: Mon, 7 Sep 2020 08:28:10 +0100
Subject: [PATCH 05/15] Make search 100% width on mobile

---
 stylesheets/_component.search.scss | 1 -
 1 file changed, 1 deletion(-)

diff --git a/stylesheets/_component.search.scss b/stylesheets/_component.search.scss
index e531dc00cb..837cb89d08 100644
--- a/stylesheets/_component.search.scss
+++ b/stylesheets/_component.search.scss
@@ -6,7 +6,6 @@
     flex-grow: 1;
     height: 32px;
     margin-bottom: 10px;
-    margin-right: 5px;
     position: relative;
 
     @include respond-min($screen-tablet) {

From c71ee42f23fdc3cd5b93a7a8d0e10eb53870257c Mon Sep 17 00:00:00 2001
From: James Jacobs <jamesjacobs1@mac.com>
Date: Mon, 7 Sep 2020 08:28:29 +0100
Subject: [PATCH 06/15] Fix dropdown divider styles

---
 stylesheets/_component.dropdowns.scss | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/stylesheets/_component.dropdowns.scss b/stylesheets/_component.dropdowns.scss
index 97ce0d5257..81aea7d1f3 100644
--- a/stylesheets/_component.dropdowns.scss
+++ b/stylesheets/_component.dropdowns.scss
@@ -53,12 +53,13 @@
 
   // Dividers (basically an hr) within the dropdown
   .divider {
+    background-color: $dropdown-divider-bg;
     display: block;
     height: 1px;
     margin: ($line-height-base / 4) 0;
     min-width: 160px;
     overflow: hidden;
-    background-color: $dropdown-divider-bg;
+    padding: 0;
   }
 
   > li {

From 9f7466d44cf23ae7726197967fe4f2befda4bd06 Mon Sep 17 00:00:00 2001
From: James Jacobs <jamesjacobs1@mac.com>
Date: Mon, 7 Sep 2020 10:56:55 +0100
Subject: [PATCH 07/15] Fix IE11 flexbox issue causing layout to shift under
 main nav

---
 stylesheets/_component.toolbar.scss | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/stylesheets/_component.toolbar.scss b/stylesheets/_component.toolbar.scss
index 0beed5a047..4f3bc63ff6 100644
--- a/stylesheets/_component.toolbar.scss
+++ b/stylesheets/_component.toolbar.scss
@@ -5,6 +5,10 @@
     flex-wrap: wrap;
     justify-content: space-between;
     padding: 12px 20px 0;
+
+    .main-title {
+        flex: 1 1 100%;
+    }
 }
 
 .toolbar-actions {

From e47c27f94b38a0b2a80b32f6af06a345528f8bf3 Mon Sep 17 00:00:00 2001
From: James Jacobs <jamesjacobs1@mac.com>
Date: Mon, 7 Sep 2020 11:40:35 +0100
Subject: [PATCH 08/15] Move skip link to landmark to prevent a11y tool
 failures

---
 views/pulsar/layouts/base.html.twig | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/views/pulsar/layouts/base.html.twig b/views/pulsar/layouts/base.html.twig
index c321aef088..9347845dbe 100644
--- a/views/pulsar/layouts/base.html.twig
+++ b/views/pulsar/layouts/base.html.twig
@@ -53,7 +53,9 @@
     {% block pageStyle %}{% endblock %}
 </head>
 <body class="language-html">
-    <a class="skip-link" href="#skip-target" tabindex="1">Skip to main content</a>
+    <div role="complementary" aria-label="skip to main content">
+        <a class="skip-link" href="#skip-target" tabindex="1">Skip to main content</a>
+    </div>
 
 {% block body %}
     <div class="container" id="top">

From 45382e56a6513f4766d85ed8fe60e75083fa87d6 Mon Sep 17 00:00:00 2001
From: James Jacobs <jamesjacobs1@mac.com>
Date: Mon, 7 Sep 2020 11:42:59 +0100
Subject: [PATCH 09/15] Remove aria-label from logo link to stop a11y tool
 failure on link text not matching label

---
 views/pulsar/v2/helpers/nav.html.twig | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/views/pulsar/v2/helpers/nav.html.twig b/views/pulsar/v2/helpers/nav.html.twig
index b3451d1615..b2b51956ff 100644
--- a/views/pulsar/v2/helpers/nav.html.twig
+++ b/views/pulsar/v2/helpers/nav.html.twig
@@ -5,7 +5,7 @@
 
 <nav role="navigation" class="nav-main" aria-label="primary" id="aria-main-nav">
     <div class="nav-primary t-nav-primary">
-        <a href="{{ options.brand_link|default('#') }}" class="jadu-branding" aria-label="Home">
+        <a href="{{ options.brand_link|default('#') }}" class="jadu-branding">
             <span class="jadu-logomark"><span class="hide">Return to home</span></span>
             <span class="jadu-wordmark">Jadu</span>
         </a>
@@ -131,11 +131,11 @@
             )
         }}
     >
-        <{{ attributes(options|only('aria-label href data-toggle data-target'), { 'tag': tag }) }} 
-            
-            class="nav-link t-nav-link" 
-            {% if options.class is defined and 'is-active' in options.class %} aria-current="page" {% endif %} 
-            {% if options.href starts with '#' or tag == 'button' %} aria-haspopup="true" aria-expanded="false" 
+        <{{ attributes(options|only('aria-label href data-toggle data-target'), { 'tag': tag }) }}
+
+            class="nav-link t-nav-link"
+            {% if options.class is defined and 'is-active' in options.class %} aria-current="page" {% endif %}
+            {% if options.href starts with '#' or tag == 'button' %} aria-haspopup="true" aria-expanded="false"
                 {% if aria_controls is not null %}aria-controls="{{ aria_controls }}"{% endif %}
             {% endif %}
         >

From 8382c2ee3eb7dd4d17c62315cc6b446fc78562fd Mon Sep 17 00:00:00 2001
From: James Jacobs <jamesjacobs1@mac.com>
Date: Thu, 17 Sep 2020 11:18:37 +0100
Subject: [PATCH 10/15] Removed old CXM specific styles from piano sass partial

---
 stylesheets/_component.piano.scss | 77 -------------------------------
 1 file changed, 77 deletions(-)

diff --git a/stylesheets/_component.piano.scss b/stylesheets/_component.piano.scss
index f4f72e0a71..1e1a1ed935 100644
--- a/stylesheets/_component.piano.scss
+++ b/stylesheets/_component.piano.scss
@@ -139,25 +139,6 @@ $piano-bg: #fafafa;
         list-style: none;
     }
 
-    .history {
-        background-color: color(new);
-        border-bottom: 1px solid color(border);
-        border-top: 1px solid color(border);
-        color: #989699;
-        cursor: pointer;
-        display: block;
-        margin: 1em 0;
-        position: relative;
-        text-align: center;
-
-        span {
-            background-color: color(new);
-            padding: 0 20px;
-            position: relative;
-            z-index: 1;
-        }
-    }
-
     h4 {
         font-size: $font-size-base;
 
@@ -221,56 +202,10 @@ $piano-bg: #fafafa;
     display: block;
 }
 
-.message-old.message--open {
-    border-bottom: 3px double $gray;
-}
-
 .message {
     overflow: hidden;
     padding: 1em $gutter-width 0;
 
-    &.message--open {
-        .message-body {
-            height: auto;
-        }
-    }
-
-    &.message--closed {
-        color: lighten($text-color, 2%);
-        padding: 10px;
-
-        .message-body {
-            border-top: 1px dashed color(border);
-            margin-top: .5em;
-        }
-
-        .message-body {
-            > * {
-                display: none;
-            }
-        }
-
-        &:hover {
-            cursor: pointer;
-        }
-
-        &:nth-of-type(odd) {
-            background-color: lighten($gray, 17%);
-
-            &:hover {
-                background-color: lighten($gray, 16%);
-            }
-        }
-
-        &:nth-of-type(even) {
-            background-color: lighten($gray, 15%);
-
-            &:hover {
-                background-color: lighten($gray, 14%);
-            }
-        }
-    }
-
     .preview > p {
         display: inline;
     }
@@ -329,15 +264,3 @@ $piano-bg: #fafafa;
 .setting__actions {
     padding: 10px;
 }
-
-.piano-wrapper {
-
-    .tab__content {
-        display: table;
-    }
-
-    .tabs__content {
-        display: table;
-        width: 100%;
-    }
-}

From fe8f66500eb6c42ad2572987ffb57733d15509aa Mon Sep 17 00:00:00 2001
From: James Jacobs <jamesjacobs1@mac.com>
Date: Thu, 24 Sep 2020 08:31:28 +0100
Subject: [PATCH 11/15] Fix focus styles of dropdown danger link

---
 stylesheets/_component.dropdowns.scss | 1 +
 1 file changed, 1 insertion(+)

diff --git a/stylesheets/_component.dropdowns.scss b/stylesheets/_component.dropdowns.scss
index 81aea7d1f3..cff0396cef 100644
--- a/stylesheets/_component.dropdowns.scss
+++ b/stylesheets/_component.dropdowns.scss
@@ -313,6 +313,7 @@
 
     &:focus {
       @include pulsar-dropdown-item-focused;
+      background-color: color(background, focus) !important;
       color: color(black) !important;
     }
 

From 455cf0346785fae7fe4f96d4dc3335498fcec1a0 Mon Sep 17 00:00:00 2001
From: James Jacobs <jamesjacobs1@mac.com>
Date: Mon, 9 Nov 2020 12:22:26 +0000
Subject: [PATCH 12/15] Added extra condition to deal with edge case modals
 with none of the standard buttons

---
 js/Modals/ModalFocusService.js               |  9 ++++++---
 tests/js/web/Modals/ModalFocusServiceTest.js | 14 ++++++++++++++
 2 files changed, 20 insertions(+), 3 deletions(-)

diff --git a/js/Modals/ModalFocusService.js b/js/Modals/ModalFocusService.js
index c561d43b82..3e6f44f83f 100644
--- a/js/Modals/ModalFocusService.js
+++ b/js/Modals/ModalFocusService.js
@@ -19,15 +19,18 @@ class ModalFocusService {
         /**
          * Manage focus
          * If modal has focusable elements in body, focus the first
-         * if not, focus the X close button
-         * if for some reason it doesn't have that, focus the cancel button in footer
+         * If not, focus the X close button
+         * If for some reason it doesn't have that, focus the cancel button in footer
+         * As a last resort, search for anything to focus
          */
         if ($modalBodyFocusableElements.length) {
             $modalBodyFocusableElements.first().trigger('focus');
         } else if ($modalCloseButton.length) {
             $modalCloseButton.trigger('focus');
-        } else {
+        } else if ($modalFooterCancelButton.length) {
             $modalFooterCancelButton.trigger('focus');
+        } else {
+            $modalFocusableElements.first().trigger('focus');
         }
 
         /**
diff --git a/tests/js/web/Modals/ModalFocusServiceTest.js b/tests/js/web/Modals/ModalFocusServiceTest.js
index ff2f589892..3ea6acc1d0 100644
--- a/tests/js/web/Modals/ModalFocusServiceTest.js
+++ b/tests/js/web/Modals/ModalFocusServiceTest.js
@@ -11,6 +11,7 @@ describe('ModalFocusService', () => {
     let $closeButton;
     let $inputButton;
     let $cancelButton;
+    let $submitButton;
     let keyDownEvent;
     let service;
 
@@ -61,6 +62,7 @@ describe('ModalFocusService', () => {
 
         $closeButton = $modal.find('.close');
         $inputButton = $modal.find('.input4');
+        $submitButton = $modal.find('.input7');
         $cancelButton = $modal.find('.input8');
         keyDownEvent = $.Event('keydown');
 
@@ -102,6 +104,18 @@ describe('ModalFocusService', () => {
             });
         });
 
+        describe('When there are no focusable elements, no close X button and no footer button with data-dismiss="modal"', () => {
+            it('should focus the first interactive element in the modal', () => {
+                $body.find('.modal__body').empty();
+                $body.find('.modal__header .close').remove();
+                $body.find('.modal__footer [data-dismiss="modal"]').remove();
+
+                service.trapFocus($modal, $body);
+
+                expect($submitButton.is(':focus')).to.be.true;
+            });
+        });
+
         describe('when tab is pressed', () => {
             it('should focus the first element, when the last element was previously focused', () => {
                 service.trapFocus($modal, $body);

From 694d7af5d4a7ca307365f7e350c0dea516896223 Mon Sep 17 00:00:00 2001
From: James Jacobs <jamesjacobs1@mac.com>
Date: Mon, 9 Nov 2020 12:23:21 +0000
Subject: [PATCH 13/15] Tooltip v2 slight refactor to add methods useful for
 ajax content

---
 js/Tooltips/TooltipListener.js               | 64 +++++++++++++++++---
 tests/js/web/Tooltips/TooltipListenerTest.js | 53 +++++++++++++++-
 2 files changed, 106 insertions(+), 11 deletions(-)

diff --git a/js/Tooltips/TooltipListener.js b/js/Tooltips/TooltipListener.js
index 60d32d03e7..e773d7aaaa 100644
--- a/js/Tooltips/TooltipListener.js
+++ b/js/Tooltips/TooltipListener.js
@@ -8,7 +8,7 @@ class TooltipListener {
     /**
      * Tooltip listener
      * @constructor
-     * @param {jQuery} $html - jQuery wrapper of the html node
+     * @param {jQuery} $html - jQuery wrapper of the container node
      * @param {tippy} TippyJS lib
      * @param {hideAll} Tippy hideAll method
      */
@@ -16,14 +16,8 @@ class TooltipListener {
         this.$html = $html;
         this.tippy = tippy;
         this.hideAll = hideAll
-    }
-
-    /**
-     * Initialise
-     */
-    init () {
-        this.tippy('[data-tippy-content]', {
-
+        this.tippys = [];
+        this.tippyConfig = {
             // Default to not allowing html inside of tooltip
             allowHTML: false,
 
@@ -47,7 +41,14 @@ class TooltipListener {
             onMount: this.onMount,
             onHide: this.onHide,
             onHidden: this.onHidden
-        });
+        };
+    }
+
+    /**
+     * Initialise
+     */
+    init () {
+        this.tippys = this.tippy('[data-tippy-content]', this.tippyConfig);
 
         // Close ESC button
         this.$html.on('keydown', (event) => {
@@ -57,6 +58,49 @@ class TooltipListener {
         });
     }
 
+    /**
+     * Listen for new elements with tippys, ignore if already instantiated, create tooltip if not
+     * @param {jQuery} $html - jQuery wrapper of the container node
+     */
+    listen ($html) {
+        // Only create new tippys
+        $html.find('[data-tippy-content]').each((index, element) => {
+            if (this.isInstantiated(element)) {
+                return;
+            }
+
+            this.tippys.push(this.tippy(element, this.tippyConfig));
+        });
+    }
+
+    /**
+     * Check if element is instantiated
+     * @param {Element} element - element to check for tippy instance
+     */
+    isInstantiated(element) {
+        for (const tippy of this.tippys) {
+            if (tippy.reference === element) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+
+    /**
+     * Get tippy instance of element
+     * @returns {(object|null)} tippy object relating to an element or null
+     */
+    getInstance(element) {
+        for (const tippy of this.tippys) {
+            if (tippy.reference === element) {
+                return tippy;
+            }
+        }
+
+        return null;
+    }
+
     onCreate (instance) {
         // Remove unnecessary aria-expanded attribute (added by the interactive option - needed for content hover)
         $(instance.reference).removeAttr('aria-expanded');
diff --git a/tests/js/web/Tooltips/TooltipListenerTest.js b/tests/js/web/Tooltips/TooltipListenerTest.js
index 57350c1adc..0e3af7ecb9 100644
--- a/tests/js/web/Tooltips/TooltipListenerTest.js
+++ b/tests/js/web/Tooltips/TooltipListenerTest.js
@@ -26,7 +26,6 @@ describe('TooltipListener', () => {
     });
 
     describe('init()', () => {
-
         beforeEach(() => {
             tooltipListener.init();
         });
@@ -35,6 +34,10 @@ describe('TooltipListener', () => {
             expect(tippyStub).to.have.been.called;
         });
 
+        it('should call tippy on an elements with data-tippy-content using the listener config', () => {
+            expect(tippyStub).to.have.been.calledWith('[data-tippy-content]', tooltipListener.tippyConfig);
+        });
+
         describe('When the ESC key is pressed', () => {
             beforeEach(() => {
                 keyDownEvent.keyCode = 27;
@@ -47,6 +50,54 @@ describe('TooltipListener', () => {
         });
     });
 
+    describe('listen()', () => {
+        it('should create a new tippy, if element was not already a tippy instance', () => {
+            tippyStub.returns([]);
+            tooltipListener.init();
+
+            tippyStub.returns('tippy');
+            tooltipListener.listen($html);
+
+            expect(tooltipListener.tippys[0]).to.equal('tippy');
+
+            expect(tippyStub).to.have.been.calledWith('[data-tippy-content]', tooltipListener.tippyConfig);
+        });
+
+        it('should not push a new tippy instance, if element is already a tippy instance', () => {
+            const existingTippyElement = $button[0];
+            const existingTippyElementObject = { reference: existingTippyElement };
+
+            tippyStub.returns([existingTippyElementObject]);
+            tooltipListener.init();
+            tooltipListener.listen($html);
+
+            expect(tooltipListener.tippys).to.have.length(1);
+        });
+    });
+
+    describe('getInstance()', () => {
+        it('should return the tippy instance for an element, if one exists', () => {
+            const existingTippyElement = $button[0];
+            const existingTippyElementObject = { reference: existingTippyElement };
+
+            tippyStub.returns([existingTippyElementObject]);
+            tooltipListener.init();
+
+            expect(tooltipListener.getInstance($button[0])).to.equal(existingTippyElementObject)
+        });
+
+        it('should return null, if no tippy instance for an element exists', () => {
+            const existingTippyElement = $button[0];
+            const existingTippyElementObject = { reference: existingTippyElement };
+
+            tippyStub.returns([existingTippyElementObject]);
+            tooltipListener.init();
+
+            expect(tooltipListener.getInstance('something')).to.be.null;
+        });
+
+    });
+
     describe('onCreate()', () => {
         it('should remove the added aria-expanded attribute', () => {
             let instance = {'reference': $body.find('#button-1')[0]};

From f04af4baa8c63dc2043a95181d21ac4302ab1211 Mon Sep 17 00:00:00 2001
From: James Jacobs <jamesjacobs1@mac.com>
Date: Fri, 13 Nov 2020 15:56:39 +0000
Subject: [PATCH 14/15] =?UTF-8?q?House=20keeping=20=F0=9F=A7=B9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 js/Tooltips/TooltipListener.js        | 1 -
 views/pulsar/v2/helpers/nav.html.twig | 1 -
 2 files changed, 2 deletions(-)

diff --git a/js/Tooltips/TooltipListener.js b/js/Tooltips/TooltipListener.js
index e773d7aaaa..f0e8cb8352 100644
--- a/js/Tooltips/TooltipListener.js
+++ b/js/Tooltips/TooltipListener.js
@@ -86,7 +86,6 @@ class TooltipListener {
         return false;
     }
 
-
     /**
      * Get tippy instance of element
      * @returns {(object|null)} tippy object relating to an element or null
diff --git a/views/pulsar/v2/helpers/nav.html.twig b/views/pulsar/v2/helpers/nav.html.twig
index b2b51956ff..02008ff41d 100644
--- a/views/pulsar/v2/helpers/nav.html.twig
+++ b/views/pulsar/v2/helpers/nav.html.twig
@@ -132,7 +132,6 @@
         }}
     >
         <{{ attributes(options|only('aria-label href data-toggle data-target'), { 'tag': tag }) }}
-
             class="nav-link t-nav-link"
             {% if options.class is defined and 'is-active' in options.class %} aria-current="page" {% endif %}
             {% if options.href starts with '#' or tag == 'button' %} aria-haspopup="true" aria-expanded="false"

From 92ebe74d3150a2512fe258d2c20f9b1630bcbe34 Mon Sep 17 00:00:00 2001
From: James Jacobs <jamesjacobs1@mac.com>
Date: Mon, 16 Nov 2020 13:31:05 +0000
Subject: [PATCH 15/15] reversed nav close logic

---
 js/NavMainComponent.js | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/js/NavMainComponent.js b/js/NavMainComponent.js
index 32edee1fbe..a0c9fb4997 100644
--- a/js/NavMainComponent.js
+++ b/js/NavMainComponent.js
@@ -149,13 +149,13 @@ NavMainComponent.prototype.isNavOpen = function () {
     var component = this,
         isMobile = !component.window.matchMedia('(min-width: 992px)').matches;
 
-    if (component.$navQuaternary.hasClass('is-open')) {
-        return true;
-    } else if (component.$navTertiary.hasClass('is-open')) {
+    if (isMobile && component.$body.hasClass('open-nav')) {
         return true;
     } else if (component.$navSecondary.hasClass('is-open')) {
         return true;
-    } else if (isMobile && component.$body.hasClass('open-nav')) {
+    } else if (component.$navTertiary.hasClass('is-open')) {
+        return true;
+    } else if (component.$navQuaternary.hasClass('is-open')) {
         return true;
     } else {
         return false;