From f4135609d9219a5485ae4539efdf40a65a7ab3c8 Mon Sep 17 00:00:00 2001 From: Colin Rotherham Date: Thu, 20 Jul 2023 07:49:23 +0100 Subject: [PATCH] Follow GOV.UK Frontend coding standards for element checks --- src/javascripts/application.mjs | 16 ++++++--- src/javascripts/components/back-to-top.mjs | 7 ++++ src/javascripts/components/cookie-banner.mjs | 11 ++++++ src/javascripts/components/cookies-page.mjs | 37 +++++++++++++++----- src/javascripts/components/copy.mjs | 7 ++++ src/javascripts/components/example-page.mjs | 7 ++++ src/javascripts/components/example.mjs | 3 ++ src/javascripts/components/navigation.mjs | 3 ++ src/javascripts/components/options-table.mjs | 8 +++-- src/javascripts/components/search.mjs | 9 ++++- src/javascripts/components/tabs.mjs | 12 +++++++ 11 files changed, 104 insertions(+), 16 deletions(-) diff --git a/src/javascripts/application.mjs b/src/javascripts/application.mjs index 30123f33c3..8f67ca7903 100644 --- a/src/javascripts/application.mjs +++ b/src/javascripts/application.mjs @@ -17,7 +17,9 @@ initAll() // Initialise cookie banner const $cookieBanner = document.querySelector('[data-module="govuk-cookie-banner"]') -new CookieBanner($cookieBanner).init() +if ($cookieBanner) { + new CookieBanner($cookieBanner).init() +} // Initialise analytics if consent is given const userConsent = getConsentCookie() @@ -51,12 +53,18 @@ new Navigation().init() // Initialise search const $searchContainer = document.querySelector('[data-module="app-search"]') -new Search($searchContainer).init() +if ($searchContainer) { + new Search($searchContainer).init() +} // Initialise back to top const $backToTop = document.querySelector('[data-module="app-back-to-top"]') -new BackToTop($backToTop).init() +if ($backToTop) { + new BackToTop($backToTop).init() +} // Initialise cookie page const $cookiesPage = document.querySelector('[data-module="app-cookies-page"]') -new CookiesPage($cookiesPage).init() +if ($cookiesPage) { + new CookiesPage($cookiesPage).init() +} diff --git a/src/javascripts/components/back-to-top.mjs b/src/javascripts/components/back-to-top.mjs index 9937019de1..9416e34325 100644 --- a/src/javascripts/components/back-to-top.mjs +++ b/src/javascripts/components/back-to-top.mjs @@ -1,5 +1,12 @@ class BackToTop { + /** + * @param {Element} $module - HTML element + */ constructor ($module) { + if (!($module instanceof HTMLElement)) { + return this + } + this.$module = $module } diff --git a/src/javascripts/components/cookie-banner.mjs b/src/javascripts/components/cookie-banner.mjs index 6db1df563f..f3b88dee4b 100644 --- a/src/javascripts/components/cookie-banner.mjs +++ b/src/javascripts/components/cookie-banner.mjs @@ -8,11 +8,22 @@ const cookieConfirmationAcceptSelector = '.js-cookie-banner-confirmation-accept' const cookieConfirmationRejectSelector = '.js-cookie-banner-confirmation-reject' class CookieBanner { + /** + * @param {Element} $module - HTML element + */ constructor ($module) { + if (!($module instanceof HTMLElement)) { + return this + } + this.$module = $module } init () { + if (!this.$module) { + return + } + this.$cookieBanner = this.$module this.$acceptButton = this.$module.querySelector(cookieBannerAcceptSelector) this.$rejectButton = this.$module.querySelector(cookieBannerRejectSelector) diff --git a/src/javascripts/components/cookies-page.mjs b/src/javascripts/components/cookies-page.mjs index 14b8c72816..b20841ce39 100644 --- a/src/javascripts/components/cookies-page.mjs +++ b/src/javascripts/components/cookies-page.mjs @@ -1,28 +1,47 @@ import { getConsentCookie, setConsentCookie } from './cookie-functions.mjs' class CookiesPage { + /** + * @param {Element} $module - HTML element + */ constructor ($module) { - this.$module = $module + if (!($module instanceof HTMLElement)) { + return this + } + + const $cookieForm = $module.querySelector('.js-cookies-page-form') + if (!($cookieForm instanceof HTMLFormElement)) { + return this + } + + /** @satisfies {NodeListOf} */ + const $cookieFormFieldsets = $cookieForm.querySelectorAll('.js-cookies-page-form-fieldset') + const $cookieFormButton = $cookieForm.querySelector('.js-cookies-form-button') + + const $successNotification = $module.querySelector('.js-cookies-page-success') + if (!($successNotification instanceof HTMLElement)) { + return this + } + + this.$page = $module + this.$cookieForm = $cookieForm + this.$cookieFormFieldsets = $cookieFormFieldsets + this.$cookieFormButton = $cookieFormButton + this.$successNotification = $successNotification } init () { - this.$cookiePage = this.$module - - if (!this.$cookiePage) { + if (!this.$page || !this.$cookieForm) { return } - this.$cookieForm = this.$cookiePage.querySelector('.js-cookies-page-form') - this.$cookieFormFieldsets = this.$cookieForm.querySelectorAll('.js-cookies-page-form-fieldset') - this.$successNotification = this.$cookiePage.querySelector('.js-cookies-page-success') - this.$cookieFormFieldsets.forEach(($cookieFormFieldset) => { this.showUserPreference($cookieFormFieldset, getConsentCookie()) $cookieFormFieldset.removeAttribute('hidden') }) // Show submit button - this.$cookieForm.querySelector('.js-cookies-form-button').removeAttribute('hidden') + this.$cookieFormButton.removeAttribute('hidden') this.$cookieForm.addEventListener('submit', (event) => this.savePreferences(event)) } diff --git a/src/javascripts/components/copy.mjs b/src/javascripts/components/copy.mjs index 919bbec653..8f71af427f 100644 --- a/src/javascripts/components/copy.mjs +++ b/src/javascripts/components/copy.mjs @@ -1,7 +1,14 @@ import ClipboardJS from 'clipboard' class Copy { + /** + * @param {Element} $module - HTML element + */ constructor ($module) { + if (!($module instanceof HTMLElement)) { + return this + } + this.$module = $module } diff --git a/src/javascripts/components/example-page.mjs b/src/javascripts/components/example-page.mjs index 3b2a9f6170..323a14c509 100644 --- a/src/javascripts/components/example-page.mjs +++ b/src/javascripts/components/example-page.mjs @@ -1,5 +1,12 @@ class ExamplePage { + /** + * @param {Document} $module - HTML document + */ constructor ($module) { + if (!$module) { + return this + } + this.$module = $module } diff --git a/src/javascripts/components/example.mjs b/src/javascripts/components/example.mjs index dc57009979..509ecfab40 100644 --- a/src/javascripts/components/example.mjs +++ b/src/javascripts/components/example.mjs @@ -9,6 +9,9 @@ import iFrameResize from 'iframe-resizer/js/iframeResizer.js' * @param {Element} $module - HTML element to use for example */ class Example { + /** + * @param {Element} $module - HTML element + */ constructor ($module) { if (!($module instanceof HTMLIFrameElement)) { return diff --git a/src/javascripts/components/navigation.mjs b/src/javascripts/components/navigation.mjs index 8f76dfc2a7..4b19274c24 100644 --- a/src/javascripts/components/navigation.mjs +++ b/src/javascripts/components/navigation.mjs @@ -5,6 +5,9 @@ const subNavActiveClass = 'app-navigation__subnav--active' const subNavJSClass = '.js-app-navigation__subnav' class Navigation { + /** + * @param {Element} [$module] - HTML element + */ constructor ($module) { this.$module = $module || document diff --git a/src/javascripts/components/options-table.mjs b/src/javascripts/components/options-table.mjs index a54860ea54..3dfbec2f4a 100644 --- a/src/javascripts/components/options-table.mjs +++ b/src/javascripts/components/options-table.mjs @@ -18,7 +18,11 @@ class OptionsTable { if (exampleName) { const $tabLink = document.querySelector(`a[href="#${exampleName}-nunjucks"]`) - const $tabHeading = $tabLink ? $tabLink.parentElement : null + if (!($tabLink instanceof HTMLAnchorElement)) { + return + } + + const $tabHeading = $tabLink.parentElement const $optionsDetailsElement = document.getElementById(`options-${exampleName}-details`) if ($tabHeading && $optionsDetailsElement) { @@ -26,7 +30,7 @@ class OptionsTable { const $detailsSummary = $optionsDetailsElement.querySelector('.govuk-details__summary') const $detailsText = $optionsDetailsElement.querySelector('.govuk-details__text') - if ($detailsSummary && $detailsText) { + if ($detailsSummary && $detailsText instanceof HTMLElement) { $tabLink.setAttribute('aria-expanded', 'true') $tabHeading.className += ' app-tabs__item--current' $tabsElement.removeAttribute('hidden') diff --git a/src/javascripts/components/search.mjs b/src/javascripts/components/search.mjs index 6863b04d24..1ac203132d 100644 --- a/src/javascripts/components/search.mjs +++ b/src/javascripts/components/search.mjs @@ -14,7 +14,7 @@ let documentStore = null let statusMessage = null let searchQuery = '' -let searchCallback = function () {} +let searchCallback = function (searchResults) {} // Results that are rendered by the autocomplete let searchResults = [] @@ -32,7 +32,14 @@ const DEBOUNCE_TIME_TO_WAIT = function () { } class Search { + /** + * @param {Element} $module - HTML element + */ constructor ($module) { + if (!($module instanceof HTMLElement)) { + return this + } + this.$module = $module } diff --git a/src/javascripts/components/tabs.mjs b/src/javascripts/components/tabs.mjs index c1609cdedc..f454052460 100644 --- a/src/javascripts/components/tabs.mjs +++ b/src/javascripts/components/tabs.mjs @@ -10,7 +10,14 @@ */ class AppTabs { + /** + * @param {Element} $module - HTML element + */ constructor ($module) { + if (!($module instanceof HTMLElement)) { + return this + } + this.$module = $module this.$mobileTabs = this.$module.querySelectorAll('.js-tabs__heading a') this.$desktopTabs = this.$module.querySelectorAll('.js-tabs__item a') @@ -48,7 +55,12 @@ class AppTabs { */ onClick (event) { event.preventDefault() + const $currentTab = event.target + if (!($currentTab instanceof HTMLElement)) { + return + } + const panelId = $currentTab.getAttribute('aria-controls') const $panel = this.getPanel(panelId) const isTabAlreadyOpen = $currentTab.getAttribute('aria-expanded') === 'true'