Skip to content

Commit

Permalink
Draft example API of how we could initialise components
Browse files Browse the repository at this point in the history
First things first, this code has not even been run, it's only a draft of an API I think could be nice for initialising components, accounting for the nuances found in the different components of the Design System.

- Some components run on a specific element, some not. So the API need to allow both.
- When initialised on a specific element, the module name could be a static property of the component, however, it's probably useful to let it be set explicitely
- Further selection, like finding the  for the Copy, should probably be part of the component's responsibility, rather than the initialisation code
- Similarly, if a component needs to be initialised only once, this could be part of the component's responsibility, rather thatn the initialisation loop.

TypeScript might get in the way of having something so dynamic. Especially, I'm not 100% sure how we can note that a function accepts a 'class' as parameter. Seems it's a bit tricky based on this: microsoft/TypeScript#17572
  • Loading branch information
romaricpascal committed Apr 23, 2024
1 parent 46604e7 commit 346885e
Showing 1 changed file with 72 additions and 45 deletions.
117 changes: 72 additions & 45 deletions src/javascripts/application.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -20,58 +20,85 @@ import AppTabs from './components/tabs.mjs'
// Initialise GOV.UK Frontend
initAll()

// Initialise cookie banner
const $cookieBanner = document.querySelector(
'[data-module="govuk-cookie-banner"]'
)
if ($cookieBanner) {
new CookieBanner($cookieBanner)
}
initModules([
[CookieBanner, 'govuk-cookie-banner'], // Why is this not 'app-cookie-banner' ?
[Analytics, hasUserConsentedToAnalytics],
[Example, 'app-example-frame'], // Why do we not match the module name ?
[AppTabs, 'app-tabs'],
OptionsTable,
[Copy, 'app-copy', {selector: 'pre'}], // Should probably be the responsibility of the Copy module to lookup the `<pre>`
Navigation,
[Search, 'app-search', {single: true}], // Could error if there's more than one
[BackToTop, 'app-back-to-top', {single: true}],
[CookiesPage, 'app-cookies-page', {single: true}]
])

// Initialise analytics if consent is given
const userConsent = getConsentCookie()
if (userConsent && isValidConsentCookie(userConsent) && userConsent.analytics) {
Analytics()
/**
* Checks if user has consented to run analytics
*
* @returns {boolean}
*/
function hasUserConsentedToAnalytics() {
const userConsent = getConsentCookie();
return (
userConsent && isValidConsentCookie(userConsent) && userConsent.analytics
)
}

// Initialise example frames
const $examples = document.querySelectorAll('[data-module="app-example-frame"]')
$examples.forEach(($example) => {
new Example($example)
})

// Initialise tabs
const $tabs = document.querySelectorAll('[data-module="app-tabs"]')
$tabs.forEach(($tabs) => {
new AppTabs($tabs)
})

// Do this after initialising tabs
new OptionsTable()
/**
* Initialises the given list of modules, according to the provided options
*
* @param {Array<ModulesToInitialise>} modulesToInitialise
*/
function initModules(modulesToInitialise) {
for(const moduleToInitialise of modulesToInitialise) {
if (Array.isArray(moduleToInitialise)) {
initModule(...moduleToInitialise)
} else {
initModules(moduleToInitialise)
}
}
}

// Add copy to clipboard to code blocks inside tab containers
const $codeBlocks = document.querySelectorAll('[data-module="app-copy"] pre')
$codeBlocks.forEach(($codeBlock) => {
new Copy($codeBlock)
})

// Initialise mobile navigation
new Navigation(document)

// Initialise search
const $searchContainer = document.querySelector('[data-module="app-search"]')
if ($searchContainer) {
new Search($searchContainer)
}
/**
*
* @param {Function} ModuleClass
* @param {string} moduleName
* @param {{single?: boolean, selector?: string}} options
*/
function initModule(ModuleClass, moduleName, options) {
if (!moduleName) {
runInitialisation(ModuleClass);
}

// Initialise back to top
const $backToTop = document.querySelector('[data-module="app-back-to-top"]')
if ($backToTop) {
new BackToTop($backToTop)
const elements = document.querySelectorAll(`[data-module=${moduleName}]`);
for(const element of elements) {
if (options.selector) {
runInitialisation(ModuleClass, element.querySelector(options.selector));
} else {
runInitialisation(ModuleClass, element)
}
}
}

// Initialise cookie page
const $cookiesPage = document.querySelector('[data-module="app-cookies-page"]')
if ($cookiesPage) {
new CookiesPage($cookiesPage)
/**
* Initialises the given Module, passing it the given `element`
* if provided, logging errors if they happen
*
* @param {Function} ModuleClass
* @param {Element} [element]
* @returns {object} The initialised instance of the module
*/
function runInitialisation(ModuleClass, element) {
try {
if (element) {
return new ModuleClass(element)
} else {
return new ModuleClass()
}
} catch (error) {
console.error(error);
}
}

0 comments on commit 346885e

Please sign in to comment.