diff --git a/content/patterns/accordion/accordion-pattern.html b/content/patterns/accordion/accordion-pattern.html index 5e53b1158a..9704964d03 100644 --- a/content/patterns/accordion/accordion-pattern.html +++ b/content/patterns/accordion/accordion-pattern.html @@ -11,6 +11,7 @@ +
diff --git a/content/patterns/alert/alert-pattern.html b/content/patterns/alert/alert-pattern.html index 125e2e017d..883b9d2b53 100644 --- a/content/patterns/alert/alert-pattern.html +++ b/content/patterns/alert/alert-pattern.html @@ -11,6 +11,7 @@ +
diff --git a/content/patterns/alertdialog/alertdialog-pattern.html b/content/patterns/alertdialog/alertdialog-pattern.html index 0cfa66ee6e..f81bb1b2cd 100644 --- a/content/patterns/alertdialog/alertdialog-pattern.html +++ b/content/patterns/alertdialog/alertdialog-pattern.html @@ -11,6 +11,7 @@ +
diff --git a/content/patterns/breadcrumb/breadcrumb-pattern.html b/content/patterns/breadcrumb/breadcrumb-pattern.html index 3cb30aa572..3558a3b9cb 100644 --- a/content/patterns/breadcrumb/breadcrumb-pattern.html +++ b/content/patterns/breadcrumb/breadcrumb-pattern.html @@ -11,6 +11,7 @@ +
diff --git a/content/patterns/button/button-pattern.html b/content/patterns/button/button-pattern.html index 380085ce81..d91bb47130 100644 --- a/content/patterns/button/button-pattern.html +++ b/content/patterns/button/button-pattern.html @@ -11,6 +11,7 @@ +
diff --git a/content/patterns/carousel/carousel-pattern.html b/content/patterns/carousel/carousel-pattern.html index a9c17cb2f4..c4e7078b37 100644 --- a/content/patterns/carousel/carousel-pattern.html +++ b/content/patterns/carousel/carousel-pattern.html @@ -11,6 +11,7 @@ +
diff --git a/content/patterns/checkbox/checkbox-pattern.html b/content/patterns/checkbox/checkbox-pattern.html index f8477d0fb7..faef05602d 100644 --- a/content/patterns/checkbox/checkbox-pattern.html +++ b/content/patterns/checkbox/checkbox-pattern.html @@ -11,6 +11,7 @@ +
diff --git a/content/patterns/combobox/combobox-pattern.html b/content/patterns/combobox/combobox-pattern.html index ec5e2d4bab..80bcb7dd57 100644 --- a/content/patterns/combobox/combobox-pattern.html +++ b/content/patterns/combobox/combobox-pattern.html @@ -11,6 +11,7 @@ +
diff --git a/content/patterns/dialog-modal/dialog-modal-pattern.html b/content/patterns/dialog-modal/dialog-modal-pattern.html index ba37954138..09d8181eec 100644 --- a/content/patterns/dialog-modal/dialog-modal-pattern.html +++ b/content/patterns/dialog-modal/dialog-modal-pattern.html @@ -11,6 +11,7 @@ +
diff --git a/content/patterns/disclosure/disclosure-pattern.html b/content/patterns/disclosure/disclosure-pattern.html index b30eb449f1..b553e9c58f 100644 --- a/content/patterns/disclosure/disclosure-pattern.html +++ b/content/patterns/disclosure/disclosure-pattern.html @@ -11,6 +11,7 @@ +
diff --git a/content/patterns/feed/feed-pattern.html b/content/patterns/feed/feed-pattern.html index b4bcc0d1d1..9e9edd9b72 100644 --- a/content/patterns/feed/feed-pattern.html +++ b/content/patterns/feed/feed-pattern.html @@ -11,6 +11,7 @@ +
diff --git a/content/patterns/grid/grid-pattern.html b/content/patterns/grid/grid-pattern.html index eec44961f9..ba34e00bba 100644 --- a/content/patterns/grid/grid-pattern.html +++ b/content/patterns/grid/grid-pattern.html @@ -11,6 +11,7 @@ +
diff --git a/content/patterns/landmarks/landmarks-pattern.html b/content/patterns/landmarks/landmarks-pattern.html index c020b5ca08..c262af86c7 100644 --- a/content/patterns/landmarks/landmarks-pattern.html +++ b/content/patterns/landmarks/landmarks-pattern.html @@ -11,6 +11,7 @@ +
diff --git a/content/patterns/link/link-pattern.html b/content/patterns/link/link-pattern.html index 21d92f9e89..dcbec34763 100644 --- a/content/patterns/link/link-pattern.html +++ b/content/patterns/link/link-pattern.html @@ -11,6 +11,7 @@ +
diff --git a/content/patterns/listbox/listbox-pattern.html b/content/patterns/listbox/listbox-pattern.html index f17aab71bf..99a7798713 100644 --- a/content/patterns/listbox/listbox-pattern.html +++ b/content/patterns/listbox/listbox-pattern.html @@ -11,6 +11,7 @@ +
diff --git a/content/patterns/menu-button/menu-button-pattern.html b/content/patterns/menu-button/menu-button-pattern.html index de0e4b42b0..84f47e1be5 100644 --- a/content/patterns/menu-button/menu-button-pattern.html +++ b/content/patterns/menu-button/menu-button-pattern.html @@ -11,6 +11,7 @@ +
diff --git a/content/patterns/menubar/menu-and-menubar-pattern.html b/content/patterns/menubar/menu-and-menubar-pattern.html index c8af7ff04c..a5eebc5f5c 100644 --- a/content/patterns/menubar/menu-and-menubar-pattern.html +++ b/content/patterns/menubar/menu-and-menubar-pattern.html @@ -11,6 +11,7 @@ +
diff --git a/content/patterns/meter/meter-pattern.html b/content/patterns/meter/meter-pattern.html index 6830ff3434..91781b3225 100644 --- a/content/patterns/meter/meter-pattern.html +++ b/content/patterns/meter/meter-pattern.html @@ -11,6 +11,7 @@ +
diff --git a/content/patterns/patterns.html b/content/patterns/patterns.html index 88689af939..fae5214867 100644 --- a/content/patterns/patterns.html +++ b/content/patterns/patterns.html @@ -13,6 +13,7 @@ +

Patterns

diff --git a/content/patterns/radio/radio-group-pattern.html b/content/patterns/radio/radio-group-pattern.html index bb451c98e1..d1ac151271 100644 --- a/content/patterns/radio/radio-group-pattern.html +++ b/content/patterns/radio/radio-group-pattern.html @@ -11,6 +11,7 @@ +
diff --git a/content/patterns/slider-multithumb/slider-multithumb-pattern.html b/content/patterns/slider-multithumb/slider-multithumb-pattern.html index 070f8b6f5b..72a653efa5 100644 --- a/content/patterns/slider-multithumb/slider-multithumb-pattern.html +++ b/content/patterns/slider-multithumb/slider-multithumb-pattern.html @@ -11,6 +11,7 @@ +
diff --git a/content/patterns/slider/slider-pattern.html b/content/patterns/slider/slider-pattern.html index e57ccfea49..e59a8dbcc0 100644 --- a/content/patterns/slider/slider-pattern.html +++ b/content/patterns/slider/slider-pattern.html @@ -11,6 +11,7 @@ +
diff --git a/content/patterns/spinbutton/spinbutton-pattern.html b/content/patterns/spinbutton/spinbutton-pattern.html index 58f1f3e052..047219cd4a 100644 --- a/content/patterns/spinbutton/spinbutton-pattern.html +++ b/content/patterns/spinbutton/spinbutton-pattern.html @@ -11,6 +11,7 @@ +
diff --git a/content/patterns/switch/switch-pattern.html b/content/patterns/switch/switch-pattern.html index 96c291f78f..0f88576bcc 100644 --- a/content/patterns/switch/switch-pattern.html +++ b/content/patterns/switch/switch-pattern.html @@ -11,6 +11,7 @@ +
diff --git a/content/patterns/table/table-pattern.html b/content/patterns/table/table-pattern.html index 9902055d57..35fe48c18a 100644 --- a/content/patterns/table/table-pattern.html +++ b/content/patterns/table/table-pattern.html @@ -11,6 +11,7 @@ +
diff --git a/content/patterns/tabs/tabs-pattern.html b/content/patterns/tabs/tabs-pattern.html index c32132b334..56222ff2a0 100644 --- a/content/patterns/tabs/tabs-pattern.html +++ b/content/patterns/tabs/tabs-pattern.html @@ -11,6 +11,7 @@ +
diff --git a/content/patterns/toolbar/toolbar-pattern.html b/content/patterns/toolbar/toolbar-pattern.html index 97b8bd832d..81c0d1d789 100644 --- a/content/patterns/toolbar/toolbar-pattern.html +++ b/content/patterns/toolbar/toolbar-pattern.html @@ -11,6 +11,7 @@ +
diff --git a/content/patterns/tooltip/tooltip-pattern.html b/content/patterns/tooltip/tooltip-pattern.html index e89c741093..547184a0e3 100644 --- a/content/patterns/tooltip/tooltip-pattern.html +++ b/content/patterns/tooltip/tooltip-pattern.html @@ -11,6 +11,7 @@ +
diff --git a/content/patterns/treegrid/treegrid-pattern.html b/content/patterns/treegrid/treegrid-pattern.html index 0b438b68e7..ed2a96f905 100644 --- a/content/patterns/treegrid/treegrid-pattern.html +++ b/content/patterns/treegrid/treegrid-pattern.html @@ -11,6 +11,7 @@ +
diff --git a/content/patterns/treeview/treeview-pattern.html b/content/patterns/treeview/treeview-pattern.html index 8eaff4c7e1..223e56bc7e 100644 --- a/content/patterns/treeview/treeview-pattern.html +++ b/content/patterns/treeview/treeview-pattern.html @@ -11,6 +11,7 @@ +
diff --git a/content/patterns/windowsplitter/windowsplitter-pattern.html b/content/patterns/windowsplitter/windowsplitter-pattern.html index 8d78e89e6d..5ada78bcd6 100644 --- a/content/patterns/windowsplitter/windowsplitter-pattern.html +++ b/content/patterns/windowsplitter/windowsplitter-pattern.html @@ -11,6 +11,7 @@ +
diff --git a/content/practices/practices.html b/content/practices/practices.html index 3f31e1ce80..560b56d89c 100644 --- a/content/practices/practices.html +++ b/content/practices/practices.html @@ -12,6 +12,7 @@ +

Practices

diff --git a/content/shared/js/read-this-first.js b/content/shared/js/read-this-first.js new file mode 100644 index 0000000000..ac4dfa0887 --- /dev/null +++ b/content/shared/js/read-this-first.js @@ -0,0 +1,151 @@ +'use strict'; + +/** + * Inserts the "Read This First" banner from /content/shared/templates/read-this-first.html into + * pages after the h1 element when the DOM is loaded. The banner is configured using data + * attributes on the script element. + * + * USAGE: + * Add this script to your HTML page with the appropriate data attributes: + * + * + * + * CONFIGURATION OPTIONS: + * - showImage: boolean (default: true) - Controls whether the illustration image is displayed + * + * BEHAVIOR: + * - Banner is inserted after the h1 element when DOM is loaded + * - If template file can't be fetched (e.g., CORS issues with file:// protocol), uses fallback + * - Paths are automatically adjusted based on script location + * - Image can be conditionally removed based on showImage setting + */ +(function () { + const defaultConfig = { + showImage: true, + }; + + // NOTE: If /content/shared/templates/read-this-first.html is ever changed, update this fallback banner to match + // MUST HAVE `div class="read-this-first"` + const fallbackBanner = ` +
+
+ Illustration of a brown-skinned woman with a slight smile gesturing towards the right with her hand +

Read This First

+

+ No ARIA is better than Bad ARIA. Before using any ARIA, read this to understand why. +

+
+
+ `; + + function getScriptBasePath() { + const scriptElement = document.querySelector( + 'script[src*="read-this-first.js"]' + ); + if (!scriptElement) return '../../'; + + const scriptSrc = scriptElement.getAttribute('src'); + // Extract the directory path from the script src + // e.g., "../../shared/js/read-this-first.js" gives "../../" + const match = scriptSrc.match(/^(.*\/)shared\/js\/read-this-first\.js$/); + return match ? match[1] : '../../'; + } + + function parseConfigFromDataAttribute() { + const config = { ...defaultConfig }; + const configElem = document.querySelector('[data-read-this-first]'); + + if (configElem) { + const dataValue = configElem.getAttribute('data-read-this-first'); + if (dataValue) { + const values = dataValue.split(';'); + values.forEach((v) => { + let [prop, value] = v.split(':'); + if (prop) { + prop = prop.trim(); + } + if (value) { + value = value.trim(); + } + if (prop && value) { + // Convert string values to appropriate types + if (value === 'true' || value === 'false') { + config[prop] = value === 'true'; + } else { + config[prop] = value; + } + } + }); + } + } + + return config; + } + + function removeImageIfNeeded(bannerElement, config) { + if (!config.showImage) { + const img = bannerElement.querySelector('img'); + if (img) img.remove(); + } + } + + async function insertBanner(config) { + // Get the first found h1 element on page + const h1 = document.querySelector('h1'); + if (!h1) return; + + // Get the base path for relative URLs + const basePath = getScriptBasePath(); + + try { + // Fetch the banner HTML from the template file (will fail with file:// protocol) + const response = await fetch( + `${basePath}shared/templates/read-this-first.html` + ); + const html = await response.text(); + + const parser = new DOMParser(); + const doc = parser.parseFromString(html, 'text/html'); + // Get the read-this-first div + const bannerDiv = doc.querySelector('.read-this-first'); + + if (!bannerDiv) return; + + const bannerElement = bannerDiv.cloneNode(true); + removeImageIfNeeded(bannerElement, config); + + // Insert the banner after h1 + h1.parentNode.insertBefore(bannerElement, h1.nextSibling); + } catch (error) { + // Fallback to static banner if fetch fails (CORS will fail with file:// protocol) + const tempBannerDiv = document.createElement('div'); + // Adjust paths in the fallback banner based on script location + tempBannerDiv.innerHTML = fallbackBanner + .replace(/src="\.\.\/\.\.\//g, `src="${basePath}`) + .replace(/href="\.\.\/\.\.\//g, `href="${basePath}`); + + const fallbackBannerElement = tempBannerDiv.firstElementChild; + removeImageIfNeeded(fallbackBannerElement, config); + + // Insert the banner after h1 + h1.parentNode.insertBefore(fallbackBannerElement, h1.nextSibling); + } + } + + async function init() { + const config = parseConfigFromDataAttribute(); + await insertBanner(config); + } + + if (document.readyState === 'loading') { + // Initialize on DOMContentLoaded + document.addEventListener('DOMContentLoaded', init); + } else { + // DOM is already loaded + init(); + } +})(); diff --git a/content/shared/templates/read-this-first.html b/content/shared/templates/read-this-first.html index 348700ae25..7879da749e 100644 --- a/content/shared/templates/read-this-first.html +++ b/content/shared/templates/read-this-first.html @@ -3,6 +3,7 @@ Read This First (Template) +