From 40da1afaa7b552de5a610149905a5d803994fdf4 Mon Sep 17 00:00:00 2001
From: alflennik
Date: Tue, 31 Jan 2023 15:20:16 -0500
Subject: [PATCH 1/7] Fix iframe height
---
ARIA/apg/patterns/button/examples/button.md | 11 +++++++++++
ARIA/apg/shared/js/app.js | 15 +++++++++++++++
_external/aria-practices | 2 +-
scripts/pre-build/library/transformAsset.js | 4 ++--
4 files changed, 29 insertions(+), 3 deletions(-)
diff --git a/ARIA/apg/patterns/button/examples/button.md b/ARIA/apg/patterns/button/examples/button.md
index c4e1dba00..f828eaf3d 100644
--- a/ARIA/apg/patterns/button/examples/button.md
+++ b/ARIA/apg/patterns/button/examples/button.md
@@ -263,6 +263,17 @@ if (enableSidebar) document.body.classList.add('has-sidebar');
sourceCode.make();
+
+
+
diff --git a/ARIA/apg/shared/js/app.js b/ARIA/apg/shared/js/app.js
index 19205fe00..138bf2cce 100644
--- a/ARIA/apg/shared/js/app.js
+++ b/ARIA/apg/shared/js/app.js
@@ -12,6 +12,10 @@
// Rewrite links so they point to the proper spec document
// window.addEventListener('DOMContentLoaded', resolveSpecLinks, false);// Line edited by pre-build script
+ // Support levels iframes should not show scrollbars, so a message with the
+ // correct height will be posted from the iframe.
+ window.addEventListener('message', fixIframeHeight);
+
async function addExampleUsageWarning() {
// Determine we are on an example page
if (!document.location.href.match(/examples\/[^/]+\.html/)) return;
@@ -43,4 +47,15 @@
const fixSpecLink = specLinks({ specStatus: 'ED' });
document.querySelectorAll('a[href]').forEach(fixSpecLink);
}
+
+ function fixIframeHeight(event) {
+ const data = event.data;
+ if (!data.iframe || !data.height || isNaN(data.height)) {
+ return;
+ }
+ const iframe = document.querySelector(`.${data.iframe}`);
+ if (!iframe) return;
+ const magicNumberAdjustment = 5;
+ iframe.style.height = `${data.height + magicNumberAdjustment}px`;
+ }
})();
diff --git a/_external/aria-practices b/_external/aria-practices
index ae779f32c..906272650 160000
--- a/_external/aria-practices
+++ b/_external/aria-practices
@@ -1 +1 @@
-Subproject commit ae779f32cd76d562fbb17c2ebc892835b6e07a5d
+Subproject commit 906272650145d666561c2c899ee735aa37e3a50b
diff --git a/scripts/pre-build/library/transformAsset.js b/scripts/pre-build/library/transformAsset.js
index db6667271..296f038fa 100644
--- a/scripts/pre-build/library/transformAsset.js
+++ b/scripts/pre-build/library/transformAsset.js
@@ -4,12 +4,12 @@ const transformAsset = async (sourcePath, sourceContents) => {
.replace(
"window.addEventListener('DOMContentLoaded', addExampleUsageWarning, false);",
"// window.addEventListener('DOMContentLoaded', addExampleUsageWarning, false);" +
- "// Line edited by pre-build script"
+ " // Line edited by pre-build script"
)
.replace(
"window.addEventListener('DOMContentLoaded', resolveSpecLinks, false);",
"// window.addEventListener('DOMContentLoaded', resolveSpecLinks, false);" +
- "// Line edited by pre-build script"
+ " // Line edited by pre-build script"
);
}
if (sourcePath.endsWith("content/shared/js/skipto.js")) {
From dcf09ab0a58851c5f53508d6f521d536599fb1a8 Mon Sep 17 00:00:00 2001
From: alflennik
Date: Thu, 2 Mar 2023 13:52:54 -0500
Subject: [PATCH 2/7] Merge main
---
ARIA/apg/index/index.md | 26 +++++++++----------
.../patterns/accordion/examples/accordion.md | 2 +-
ARIA/apg/patterns/alert/examples/alert.md | 2 +-
.../alertdialog/examples/alertdialog.md | 2 +-
.../breadcrumb/examples/breadcrumb.md | 2 +-
ARIA/apg/patterns/button/examples/button.md | 11 ++++----
.../patterns/button/examples/button_idl.md | 2 +-
.../carousel/examples/carousel-1-prev-next.md | 2 +-
.../carousel/examples/carousel-2-tablist.md | 2 +-
.../checkbox/examples/checkbox-mixed.md | 2 +-
.../patterns/checkbox/examples/checkbox.md | 2 +-
.../examples/combobox-autocomplete-both.md | 2 +-
.../examples/combobox-autocomplete-list.md | 2 +-
.../examples/combobox-autocomplete-none.md | 2 +-
.../combobox/examples/combobox-datepicker.md | 2 +-
.../combobox/examples/combobox-select-only.md | 2 +-
.../patterns/combobox/examples/grid-combo.md | 2 +-
.../examples/datepicker-dialog.md | 2 +-
.../patterns/dialog-modal/examples/dialog.md | 2 +-
.../disclosure/examples/disclosure-faq.md | 2 +-
.../examples/disclosure-image-description.md | 2 +-
.../examples/disclosure-navigation-hybrid.md | 2 +-
.../examples/disclosure-navigation.md | 2 +-
ARIA/apg/patterns/feed/examples/feed.md | 8 +++---
.../{feed-display.html => feedDisplay.html} | 2 +-
.../{layout-grids.md => LayoutGrids.md} | 14 +++++-----
...anced-data-grid.md => advancedDataGrid.md} | 12 ++++-----
.../examples/{data-grids.md => dataGrids.md} | 12 ++++-----
ARIA/apg/patterns/grid/grid-pattern.md | 6 ++---
ARIA/apg/patterns/link/examples/link.md | 2 +-
.../listbox/examples/listbox-collapsible.md | 2 +-
.../listbox/examples/listbox-grouped.md | 2 +-
.../listbox/examples/listbox-rearrangeable.md | 2 +-
.../listbox/examples/listbox-scrollable.md | 2 +-
.../menu-button-actions-active-descendant.md | 2 +-
.../examples/menu-button-actions.md | 2 +-
.../menu-button/examples/menu-button-links.md | 2 +-
.../menubar/examples/menubar-editor.md | 2 +-
.../menubar/examples/menubar-navigation.md | 2 +-
ARIA/apg/patterns/meter/examples/meter.md | 2 +-
.../radio/examples/radio-activedescendant.md | 2 +-
.../patterns/radio/examples/radio-rating.md | 2 +-
ARIA/apg/patterns/radio/examples/radio.md | 2 +-
.../examples/slider-multithumb.md | 2 +-
.../slider/examples/slider-color-viewer.md | 2 +-
.../patterns/slider/examples/slider-rating.md | 2 +-
.../patterns/slider/examples/slider-seek.md | 2 +-
.../slider/examples/slider-temperature.md | 2 +-
.../examples/datepicker-spinbuttons.md | 2 +-
.../patterns/switch/examples/switch-button.md | 2 +-
.../switch/examples/switch-checkbox.md | 2 +-
ARIA/apg/patterns/switch/examples/switch.md | 2 +-
.../patterns/table/examples/sortable-table.md | 4 +--
ARIA/apg/patterns/table/examples/table.md | 4 +--
.../patterns/tabs/examples/tabs-automatic.md | 2 +-
.../apg/patterns/tabs/examples/tabs-manual.md | 2 +-
ARIA/apg/patterns/toolbar/examples/toolbar.md | 2 +-
.../patterns/treegrid/examples/treegrid-1.md | 4 +--
.../patterns/treeview/examples/treeview-1a.md | 2 +-
.../patterns/treeview/examples/treeview-1b.md | 2 +-
.../treeview/examples/treeview-navigation.md | 2 +-
.../slider/examples/css/slider-seek.css | 2 +-
.../examples/css/slider-temperature.css | 2 +-
.../wai-aria-practices/shared/js/app.js | 6 ++---
.../pre-build/library/determineContentType.js | 1 -
65 files changed, 107 insertions(+), 107 deletions(-)
rename ARIA/apg/patterns/feed/examples/{feed-display.html => feedDisplay.html} (97%)
rename ARIA/apg/patterns/grid/examples/{layout-grids.md => LayoutGrids.md} (98%)
rename ARIA/apg/patterns/grid/examples/{advanced-data-grid.md => advancedDataGrid.md} (91%)
rename ARIA/apg/patterns/grid/examples/{data-grids.md => dataGrids.md} (98%)
diff --git a/ARIA/apg/index/index.md b/ARIA/apg/index/index.md
index d0f4ba9d0..2a5d60013 100644
--- a/ARIA/apg/index/index.md
+++ b/ARIA/apg/index/index.md
@@ -184,8 +184,8 @@ if (enableSidebar) document.body.classList.add('has-sidebar');
Date Picker Combobox (HC)
Editable Combobox with Grid Popup
Date Picker Dialog (HC)
- Data Grid
- Layout Grid
+ Data Grid
+ Layout Grid
@@ -194,7 +194,7 @@ if (enableSidebar) document.body.classList.add('has-sidebar');
|
@@ -369,7 +369,7 @@ if (enableSidebar) document.body.classList.add('has-sidebar');
@@ -549,11 +549,11 @@ if (enableSidebar) document.body.classList.add('has-sidebar');
|
aria-colcount |
- Data Grid |
+ Data Grid |
aria-colindex |
- Data Grid |
+ Data Grid |
aria-controls |
@@ -720,8 +720,8 @@ if (enableSidebar) document.body.classList.add('has-sidebar');
Date Picker Dialog (HC)
Modal Dialog
Feed
- Data Grid
- Layout Grid
+ Data Grid
+ Layout Grid
(Deprecated) Collapsible Dropdown Listbox
Listbox with Grouped Options
Listboxes with Rearrangeable Options
@@ -831,8 +831,8 @@ if (enableSidebar) document.body.classList.add('has-sidebar');
aria-rowcount |
|
@@ -840,8 +840,8 @@ if (enableSidebar) document.body.classList.add('has-sidebar');
aria-rowindex |
|
@@ -882,7 +882,7 @@ if (enableSidebar) document.body.classList.add('has-sidebar');
aria-sort |
|
diff --git a/ARIA/apg/patterns/accordion/examples/accordion.md b/ARIA/apg/patterns/accordion/examples/accordion.md
index 309d48a2c..8793917e3 100644
--- a/ARIA/apg/patterns/accordion/examples/accordion.md
+++ b/ARIA/apg/patterns/accordion/examples/accordion.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/accordion/examples/accordion/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/alert/examples/alert.md b/ARIA/apg/patterns/alert/examples/alert.md
index 8a45cb3a1..5823a3dcd 100644
--- a/ARIA/apg/patterns/alert/examples/alert.md
+++ b/ARIA/apg/patterns/alert/examples/alert.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/alert/examples/alert/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/alertdialog/examples/alertdialog.md b/ARIA/apg/patterns/alertdialog/examples/alertdialog.md
index 60626f932..6573dbd84 100644
--- a/ARIA/apg/patterns/alertdialog/examples/alertdialog.md
+++ b/ARIA/apg/patterns/alertdialog/examples/alertdialog.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/alertdialog/examples/alertdialog/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/breadcrumb/examples/breadcrumb.md b/ARIA/apg/patterns/breadcrumb/examples/breadcrumb.md
index 67a386029..68909ed33 100644
--- a/ARIA/apg/patterns/breadcrumb/examples/breadcrumb.md
+++ b/ARIA/apg/patterns/breadcrumb/examples/breadcrumb.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/breadcrumb/examples/breadcrumb/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/button/examples/button.md b/ARIA/apg/patterns/button/examples/button.md
index 786eccf60..af4447c78 100644
--- a/ARIA/apg/patterns/button/examples/button.md
+++ b/ARIA/apg/patterns/button/examples/button.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/button/examples/button/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
@@ -267,11 +267,12 @@ if (enableSidebar) document.body.classList.add('has-sidebar');
+
+ Assistive Technology Support
+
-
@@ -259,7 +259,7 @@ if (enableSidebar) document.body.classList.add('has-sidebar');
Javascript and CSS Source Code
- The following Javascript and CSS is used by the feed-display.html page:
+ The following Javascript and CSS is used by the feedDisplay.html page:
Similar examples include:
- - Data Grid Examples: Three example implementations of grid that include features relevant to presenting tabular information, such as content editing, sort, and column hiding.
- - Advanced Data Grid Example: Example of a grid with behaviors and features similar to a typical spreadsheet, including cell and row selection.
+ - Data Grid Examples: Three example implementations of grid that include features relevant to presenting tabular information, such as content editing, sort, and column hiding.
+ - Advanced Data Grid Example: Example of a grid with behaviors and features similar to a typical spreadsheet, including cell and row selection.
@@ -438,7 +438,7 @@ if (enableSidebar) document.body.classList.add('has-sidebar');
Whether focus can wrap from the last column to the first column in the next row or from the first column to the last column in the previous row when Right Arrow and Left Arrow are pressed:
This wrapping is expected in all grids except for those presenting tabular, i.e., spreadsheet-like, data.
- The data grid examples demonstrate grids where focus movement does not wrap at the ends of rows.
+ The data grid examples demonstrate grids where focus movement does not wrap at the ends of rows.
Whether focus can wrap to the first row in the next column or the last row in the previous column when Down Arrow and Up Arrow are pressed:
diff --git a/ARIA/apg/patterns/grid/examples/advanced-data-grid.md b/ARIA/apg/patterns/grid/examples/advancedDataGrid.md
similarity index 91%
rename from ARIA/apg/patterns/grid/examples/advanced-data-grid.md
rename to ARIA/apg/patterns/grid/examples/advancedDataGrid.md
index 8451bd503..ea4f56334 100644
--- a/ARIA/apg/patterns/grid/examples/advanced-data-grid.md
+++ b/ARIA/apg/patterns/grid/examples/advancedDataGrid.md
@@ -1,18 +1,18 @@
---
# This file was generated by scripts/pre-build/library/formatForJekyll.js
title: "Advanced Data Grid"
-ref: /ARIA/apg/patterns/grid/examples/advanced-data-grid/
+ref: /ARIA/apg/patterns/grid/examples/advancedDataGrid/
github:
repository: w3c/aria-practices
branch: main
- path: content/patterns/grid/examples/advanced-data-grid.html
+ path: content/patterns/grid/examples/advancedDataGrid.html
feedbackmail: public-aria-practices@w3.org
-permalink: /ARIA/apg/patterns/grid/examples/advanced-data-grid/
+permalink: /ARIA/apg/patterns/grid/examples/advancedDataGrid/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
@@ -116,8 +116,8 @@ if (enableSidebar) document.body.classList.add('has-sidebar');
Similar examples include:
- - Data Grid Examples: Three example implementations of grid that include features relevant to presenting tabular information, such as content editing, sort, and column hiding.
- - Layout Grid Examples: Three example implementations of grids that are used to lay out widgets, including a collection of navigation links, a message recipients list, and a set of search results.
+ - Data Grid Examples: Three example implementations of grid that include features relevant to presenting tabular information, such as content editing, sort, and column hiding.
+ - Layout Grid Examples: Three example implementations of grids that are used to lay out widgets, including a collection of navigation links, a message recipients list, and a set of search results.
diff --git a/ARIA/apg/patterns/grid/examples/data-grids.md b/ARIA/apg/patterns/grid/examples/dataGrids.md
similarity index 98%
rename from ARIA/apg/patterns/grid/examples/data-grids.md
rename to ARIA/apg/patterns/grid/examples/dataGrids.md
index 023077c79..558c156b3 100644
--- a/ARIA/apg/patterns/grid/examples/data-grids.md
+++ b/ARIA/apg/patterns/grid/examples/dataGrids.md
@@ -1,18 +1,18 @@
---
# This file was generated by scripts/pre-build/library/formatForJekyll.js
title: "Data Grid Examples"
-ref: /ARIA/apg/patterns/grid/examples/data-grids/
+ref: /ARIA/apg/patterns/grid/examples/dataGrids/
github:
repository: w3c/aria-practices
branch: main
- path: content/patterns/grid/examples/data-grids.html
+ path: content/patterns/grid/examples/dataGrids.html
feedbackmail: public-aria-practices@w3.org
-permalink: /ARIA/apg/patterns/grid/examples/data-grids/
+permalink: /ARIA/apg/patterns/grid/examples/dataGrids/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
@@ -115,8 +115,8 @@ if (enableSidebar) document.body.classList.add('has-sidebar');
Similar examples include:
- - Layout Grid Examples: Three example implementations of grids that are used to lay out widgets, including a collection of navigation links, a message recipients list, and a set of search results.
- - Advanced Data Grid Example: Example of a grid with behaviors and features similar to a typical spreadsheet, including cell and row selection.
+ - Layout Grid Examples: Three example implementations of grids that are used to lay out widgets, including a collection of navigation links, a message recipients list, and a set of search results.
+ - Advanced Data Grid Example: Example of a grid with behaviors and features similar to a typical spreadsheet, including cell and row selection.
diff --git a/ARIA/apg/patterns/grid/grid-pattern.md b/ARIA/apg/patterns/grid/grid-pattern.md
index 401d8fe27..02eac03b5 100644
--- a/ARIA/apg/patterns/grid/grid-pattern.md
+++ b/ARIA/apg/patterns/grid/grid-pattern.md
@@ -100,9 +100,9 @@ if (enableSidebar) document.body.classList.add('has-sidebar');
>
Examples
- - Layout Grid Examples: Three example implementations of grids that are used to lay out widgets, including a collection of navigation links, a message recipients list, and a set of search results.
- - Data Grid Examples: Three example implementations of grid that include features relevant to presenting tabular information, such as content editing, sort, and column hiding.
- - Advanced Data Grid Example: Example of a grid with behaviors and features similar to a typical spreadsheet, including cell and row selection.
+ - Layout Grid Examples: Three example implementations of grids that are used to lay out widgets, including a collection of navigation links, a message recipients list, and a set of search results.
+ - Data Grid Examples: Three example implementations of grid that include features relevant to presenting tabular information, such as content editing, sort, and column hiding.
+ - Advanced Data Grid Example: Example of a grid with behaviors and features similar to a typical spreadsheet, including cell and row selection.
diff --git a/ARIA/apg/patterns/link/examples/link.md b/ARIA/apg/patterns/link/examples/link.md
index 2676547e2..9896a476d 100644
--- a/ARIA/apg/patterns/link/examples/link.md
+++ b/ARIA/apg/patterns/link/examples/link.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/link/examples/link/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/listbox/examples/listbox-collapsible.md b/ARIA/apg/patterns/listbox/examples/listbox-collapsible.md
index fa47f4f27..bfb978f7f 100644
--- a/ARIA/apg/patterns/listbox/examples/listbox-collapsible.md
+++ b/ARIA/apg/patterns/listbox/examples/listbox-collapsible.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/listbox/examples/listbox-collapsible/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/listbox/examples/listbox-grouped.md b/ARIA/apg/patterns/listbox/examples/listbox-grouped.md
index e1794cb5c..67d19e400 100644
--- a/ARIA/apg/patterns/listbox/examples/listbox-grouped.md
+++ b/ARIA/apg/patterns/listbox/examples/listbox-grouped.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/listbox/examples/listbox-grouped/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/listbox/examples/listbox-rearrangeable.md b/ARIA/apg/patterns/listbox/examples/listbox-rearrangeable.md
index 619ec79a0..24ae5a861 100644
--- a/ARIA/apg/patterns/listbox/examples/listbox-rearrangeable.md
+++ b/ARIA/apg/patterns/listbox/examples/listbox-rearrangeable.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/listbox/examples/listbox-rearrangeable/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/listbox/examples/listbox-scrollable.md b/ARIA/apg/patterns/listbox/examples/listbox-scrollable.md
index 61af80a54..98f49ea31 100644
--- a/ARIA/apg/patterns/listbox/examples/listbox-scrollable.md
+++ b/ARIA/apg/patterns/listbox/examples/listbox-scrollable.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/listbox/examples/listbox-scrollable/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/menu-button/examples/menu-button-actions-active-descendant.md b/ARIA/apg/patterns/menu-button/examples/menu-button-actions-active-descendant.md
index 8a4a1dfc1..6aea92a81 100644
--- a/ARIA/apg/patterns/menu-button/examples/menu-button-actions-active-descendant.md
+++ b/ARIA/apg/patterns/menu-button/examples/menu-button-actions-active-descendant.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/menu-button/examples/menu-button-actions-active-de
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/menu-button/examples/menu-button-actions.md b/ARIA/apg/patterns/menu-button/examples/menu-button-actions.md
index 48b024362..7094e00e4 100644
--- a/ARIA/apg/patterns/menu-button/examples/menu-button-actions.md
+++ b/ARIA/apg/patterns/menu-button/examples/menu-button-actions.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/menu-button/examples/menu-button-actions/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/menu-button/examples/menu-button-links.md b/ARIA/apg/patterns/menu-button/examples/menu-button-links.md
index dd081cc3b..dafc4318d 100644
--- a/ARIA/apg/patterns/menu-button/examples/menu-button-links.md
+++ b/ARIA/apg/patterns/menu-button/examples/menu-button-links.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/menu-button/examples/menu-button-links/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/menubar/examples/menubar-editor.md b/ARIA/apg/patterns/menubar/examples/menubar-editor.md
index c5bbed4e6..a6793785a 100644
--- a/ARIA/apg/patterns/menubar/examples/menubar-editor.md
+++ b/ARIA/apg/patterns/menubar/examples/menubar-editor.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/menubar/examples/menubar-editor/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/menubar/examples/menubar-navigation.md b/ARIA/apg/patterns/menubar/examples/menubar-navigation.md
index 0dc3e429d..adceb6c9e 100644
--- a/ARIA/apg/patterns/menubar/examples/menubar-navigation.md
+++ b/ARIA/apg/patterns/menubar/examples/menubar-navigation.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/menubar/examples/menubar-navigation/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/meter/examples/meter.md b/ARIA/apg/patterns/meter/examples/meter.md
index b536cc035..6a9054b36 100644
--- a/ARIA/apg/patterns/meter/examples/meter.md
+++ b/ARIA/apg/patterns/meter/examples/meter.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/meter/examples/meter/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/radio/examples/radio-activedescendant.md b/ARIA/apg/patterns/radio/examples/radio-activedescendant.md
index e01791e17..38c898b0c 100644
--- a/ARIA/apg/patterns/radio/examples/radio-activedescendant.md
+++ b/ARIA/apg/patterns/radio/examples/radio-activedescendant.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/radio/examples/radio-activedescendant/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/radio/examples/radio-rating.md b/ARIA/apg/patterns/radio/examples/radio-rating.md
index 7101a2f9e..ffb639b72 100644
--- a/ARIA/apg/patterns/radio/examples/radio-rating.md
+++ b/ARIA/apg/patterns/radio/examples/radio-rating.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/radio/examples/radio-rating/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/radio/examples/radio.md b/ARIA/apg/patterns/radio/examples/radio.md
index f33453ddc..53c64be0f 100644
--- a/ARIA/apg/patterns/radio/examples/radio.md
+++ b/ARIA/apg/patterns/radio/examples/radio.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/radio/examples/radio/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/slider-multithumb/examples/slider-multithumb.md b/ARIA/apg/patterns/slider-multithumb/examples/slider-multithumb.md
index 8871211b9..1def1b69d 100644
--- a/ARIA/apg/patterns/slider-multithumb/examples/slider-multithumb.md
+++ b/ARIA/apg/patterns/slider-multithumb/examples/slider-multithumb.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/slider-multithumb/examples/slider-multithumb/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/slider/examples/slider-color-viewer.md b/ARIA/apg/patterns/slider/examples/slider-color-viewer.md
index 77dadfcc6..a3f13308e 100644
--- a/ARIA/apg/patterns/slider/examples/slider-color-viewer.md
+++ b/ARIA/apg/patterns/slider/examples/slider-color-viewer.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/slider/examples/slider-color-viewer/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/slider/examples/slider-rating.md b/ARIA/apg/patterns/slider/examples/slider-rating.md
index 2b562fb8f..0bb31f06a 100644
--- a/ARIA/apg/patterns/slider/examples/slider-rating.md
+++ b/ARIA/apg/patterns/slider/examples/slider-rating.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/slider/examples/slider-rating/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/slider/examples/slider-seek.md b/ARIA/apg/patterns/slider/examples/slider-seek.md
index 22ec32ea5..772a33ba6 100644
--- a/ARIA/apg/patterns/slider/examples/slider-seek.md
+++ b/ARIA/apg/patterns/slider/examples/slider-seek.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/slider/examples/slider-seek/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/slider/examples/slider-temperature.md b/ARIA/apg/patterns/slider/examples/slider-temperature.md
index c904c8d6d..bdc85ef8d 100644
--- a/ARIA/apg/patterns/slider/examples/slider-temperature.md
+++ b/ARIA/apg/patterns/slider/examples/slider-temperature.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/slider/examples/slider-temperature/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/spinbutton/examples/datepicker-spinbuttons.md b/ARIA/apg/patterns/spinbutton/examples/datepicker-spinbuttons.md
index 51772ede1..b87fbe20a 100644
--- a/ARIA/apg/patterns/spinbutton/examples/datepicker-spinbuttons.md
+++ b/ARIA/apg/patterns/spinbutton/examples/datepicker-spinbuttons.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/spinbutton/examples/datepicker-spinbuttons/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/switch/examples/switch-button.md b/ARIA/apg/patterns/switch/examples/switch-button.md
index 85e856eaf..4b3f1b70b 100644
--- a/ARIA/apg/patterns/switch/examples/switch-button.md
+++ b/ARIA/apg/patterns/switch/examples/switch-button.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/switch/examples/switch-button/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/switch/examples/switch-checkbox.md b/ARIA/apg/patterns/switch/examples/switch-checkbox.md
index 562de3912..15ead1b92 100644
--- a/ARIA/apg/patterns/switch/examples/switch-checkbox.md
+++ b/ARIA/apg/patterns/switch/examples/switch-checkbox.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/switch/examples/switch-checkbox/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/switch/examples/switch.md b/ARIA/apg/patterns/switch/examples/switch.md
index 653df9132..0ad92abe4 100644
--- a/ARIA/apg/patterns/switch/examples/switch.md
+++ b/ARIA/apg/patterns/switch/examples/switch.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/switch/examples/switch/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/table/examples/sortable-table.md b/ARIA/apg/patterns/table/examples/sortable-table.md
index 399453bf3..496c971a8 100644
--- a/ARIA/apg/patterns/table/examples/sortable-table.md
+++ b/ARIA/apg/patterns/table/examples/sortable-table.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/table/examples/sortable-table/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
@@ -108,7 +108,7 @@ if (enableSidebar) document.body.classList.add('has-sidebar');
Similar examples include:
- - Data Grid Examples: Three example implementations of grid that include features relevant to presenting tabular information, such as content editing, sort, and column hiding.
+ - Data Grid Examples: Three example implementations of grid that include features relevant to presenting tabular information, such as content editing, sort, and column hiding.
- Table Example: ARIA table made using HTML
div
and span
elements.
diff --git a/ARIA/apg/patterns/table/examples/table.md b/ARIA/apg/patterns/table/examples/table.md
index 7f559e1df..1a2ba7db8 100644
--- a/ARIA/apg/patterns/table/examples/table.md
+++ b/ARIA/apg/patterns/table/examples/table.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/table/examples/table/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
@@ -106,7 +106,7 @@ if (enableSidebar) document.body.classList.add('has-sidebar');
Similar examples include:
- Sortable Table Example: Basic HTML table that illustrates implementation of
aria-sort
in the headers of sortable columns.
- - Data Grid Examples: Three example implementations of grid that include features relevant to presenting tabular information, such as content editing, sort, and column hiding.
+ - Data Grid Examples: Three example implementations of grid that include features relevant to presenting tabular information, such as content editing, sort, and column hiding.
diff --git a/ARIA/apg/patterns/tabs/examples/tabs-automatic.md b/ARIA/apg/patterns/tabs/examples/tabs-automatic.md
index a1a23f5a3..3f53acb4a 100644
--- a/ARIA/apg/patterns/tabs/examples/tabs-automatic.md
+++ b/ARIA/apg/patterns/tabs/examples/tabs-automatic.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/tabs/examples/tabs-automatic/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/tabs/examples/tabs-manual.md b/ARIA/apg/patterns/tabs/examples/tabs-manual.md
index 09cd85d98..cdebe2bdc 100644
--- a/ARIA/apg/patterns/tabs/examples/tabs-manual.md
+++ b/ARIA/apg/patterns/tabs/examples/tabs-manual.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/tabs/examples/tabs-manual/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/toolbar/examples/toolbar.md b/ARIA/apg/patterns/toolbar/examples/toolbar.md
index 31ce6f8cc..8448d2428 100644
--- a/ARIA/apg/patterns/toolbar/examples/toolbar.md
+++ b/ARIA/apg/patterns/toolbar/examples/toolbar.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/toolbar/examples/toolbar/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/treegrid/examples/treegrid-1.md b/ARIA/apg/patterns/treegrid/examples/treegrid-1.md
index 02fe3f5c3..530585e37 100644
--- a/ARIA/apg/patterns/treegrid/examples/treegrid-1.md
+++ b/ARIA/apg/patterns/treegrid/examples/treegrid-1.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/treegrid/examples/treegrid-1/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
@@ -127,7 +127,7 @@ if (enableSidebar) document.body.classList.add('has-sidebar');
The following example demonstrates how the Treegrid Pattern can be used to make an interactive tree that enables users to both navigate the hierarchical structure of email conversations and also navigate elements that describe each email, such as subject and sender.
Similar examples include:
- - Data Grid Examples: Three example implementations of grid that include features relevant to presenting tabular information, such as content editing, sort, and column hiding.
+ - Data Grid Examples: Three example implementations of grid that include features relevant to presenting tabular information, such as content editing, sort, and column hiding.
- File Directory Treeview using computed properties
- File Directory Treeview using declared properties
- Navigation Treeview Example
diff --git a/ARIA/apg/patterns/treeview/examples/treeview-1a.md b/ARIA/apg/patterns/treeview/examples/treeview-1a.md
index c0abdb493..e4b877bc6 100644
--- a/ARIA/apg/patterns/treeview/examples/treeview-1a.md
+++ b/ARIA/apg/patterns/treeview/examples/treeview-1a.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/treeview/examples/treeview-1a/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/treeview/examples/treeview-1b.md b/ARIA/apg/patterns/treeview/examples/treeview-1b.md
index 44486450e..b628ceed9 100644
--- a/ARIA/apg/patterns/treeview/examples/treeview-1b.md
+++ b/ARIA/apg/patterns/treeview/examples/treeview-1b.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/treeview/examples/treeview-1b/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/treeview/examples/treeview-navigation.md b/ARIA/apg/patterns/treeview/examples/treeview-navigation.md
index 286c968ba..3a1ecf706 100644
--- a/ARIA/apg/patterns/treeview/examples/treeview-navigation.md
+++ b/ARIA/apg/patterns/treeview/examples/treeview-navigation.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/treeview/examples/treeview-navigation/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/content-assets/wai-aria-practices/patterns/slider/examples/css/slider-seek.css b/content-assets/wai-aria-practices/patterns/slider/examples/css/slider-seek.css
index a3a65c68c..1e9a82190 100644
--- a/content-assets/wai-aria-practices/patterns/slider/examples/css/slider-seek.css
+++ b/content-assets/wai-aria-practices/patterns/slider/examples/css/slider-seek.css
@@ -37,7 +37,7 @@
stroke: currentcolor;
stroke-width: 2px;
fill: currentcolor;
- fill-opacity: 0.25;
+ fill-opacity: 25%;
}
.slider-seek .thumb {
diff --git a/content-assets/wai-aria-practices/patterns/slider/examples/css/slider-temperature.css b/content-assets/wai-aria-practices/patterns/slider/examples/css/slider-temperature.css
index 4163851b0..05b9e289e 100644
--- a/content-assets/wai-aria-practices/patterns/slider/examples/css/slider-temperature.css
+++ b/content-assets/wai-aria-practices/patterns/slider/examples/css/slider-temperature.css
@@ -54,7 +54,7 @@
stroke: currentcolor;
stroke-width: 2px;
fill: currentcolor;
- fill-opacity: 0.25;
+ fill-opacity: 25%;
}
.slider-temperature .thumb,
diff --git a/content-assets/wai-aria-practices/shared/js/app.js b/content-assets/wai-aria-practices/shared/js/app.js
index 138bf2cce..293dc04e9 100644
--- a/content-assets/wai-aria-practices/shared/js/app.js
+++ b/content-assets/wai-aria-practices/shared/js/app.js
@@ -7,10 +7,10 @@
hljs.initHighlightingOnLoad();
// Add usage warning to all examples
- // window.addEventListener('DOMContentLoaded', addExampleUsageWarning, false);// Line edited by pre-build script
+ // window.addEventListener('DOMContentLoaded', addExampleUsageWarning, false); // Line edited by pre-build script
// Rewrite links so they point to the proper spec document
- // window.addEventListener('DOMContentLoaded', resolveSpecLinks, false);// Line edited by pre-build script
+ // window.addEventListener('DOMContentLoaded', resolveSpecLinks, false); // Line edited by pre-build script
// Support levels iframes should not show scrollbars, so a message with the
// correct height will be posted from the iframe.
@@ -55,7 +55,7 @@
}
const iframe = document.querySelector(`.${data.iframe}`);
if (!iframe) return;
- const magicNumberAdjustment = 5;
+ const magicNumberAdjustment = 35;
iframe.style.height = `${data.height + magicNumberAdjustment}px`;
}
})();
diff --git a/scripts/pre-build/library/determineContentType.js b/scripts/pre-build/library/determineContentType.js
index 08b14b84e..66aca6466 100644
--- a/scripts/pre-build/library/determineContentType.js
+++ b/scripts/pre-build/library/determineContentType.js
@@ -17,7 +17,6 @@ const determineContentType = (sourcePath) => {
}
if (
sourcePath.endsWith("feed/examples/feed-display.html") ||
- sourcePath.endsWith("feed/examples/feedDisplay.html") || // To be removed
sourcePath.match(/content\/patterns\/landmarks\/examples\/.+\.html/) ||
sourcePath.endsWith("toolbar/examples/help.html") ||
sourcePath.endsWith("shared/templates/example-usage-warning.html")
From fdf07522ac188610616952d4cec0ef1dae460e5b Mon Sep 17 00:00:00 2001
From: alflennik
Date: Thu, 9 Mar 2023 12:11:06 -0500
Subject: [PATCH 3/7] Temporarily use sandbox to host the embed
---
ARIA/apg/index/index.md | 26 +++++++++----------
ARIA/apg/patterns/button/examples/button.md | 11 +++++---
.../{feedDisplay.html => feed-display.html} | 2 +-
ARIA/apg/patterns/feed/examples/feed.md | 8 +++---
...ancedDataGrid.md => advanced-data-grid.md} | 12 ++++-----
.../examples/{dataGrids.md => data-grids.md} | 12 ++++-----
.../{LayoutGrids.md => layout-grids.md} | 14 +++++-----
ARIA/apg/patterns/grid/grid-pattern.md | 6 ++---
.../patterns/table/examples/sortable-table.md | 4 +--
ARIA/apg/patterns/table/examples/table.md | 4 +--
.../patterns/treegrid/examples/treegrid-1.md | 4 +--
_external/aria-practices | 2 +-
.../slider/examples/css/slider-seek.css | 2 +-
.../examples/css/slider-temperature.css | 2 +-
14 files changed, 57 insertions(+), 52 deletions(-)
rename ARIA/apg/patterns/feed/examples/{feedDisplay.html => feed-display.html} (97%)
rename ARIA/apg/patterns/grid/examples/{advancedDataGrid.md => advanced-data-grid.md} (91%)
rename ARIA/apg/patterns/grid/examples/{dataGrids.md => data-grids.md} (98%)
rename ARIA/apg/patterns/grid/examples/{LayoutGrids.md => layout-grids.md} (98%)
diff --git a/ARIA/apg/index/index.md b/ARIA/apg/index/index.md
index 2a5d60013..d0f4ba9d0 100644
--- a/ARIA/apg/index/index.md
+++ b/ARIA/apg/index/index.md
@@ -184,8 +184,8 @@ if (enableSidebar) document.body.classList.add('has-sidebar');
- Date Picker Combobox (HC)
- Editable Combobox with Grid Popup
- Date Picker Dialog (HC)
- - Data Grid
- - Layout Grid
+ - Data Grid
+ - Layout Grid
@@ -194,7 +194,7 @@ if (enableSidebar) document.body.classList.add('has-sidebar');
|
@@ -369,7 +369,7 @@ if (enableSidebar) document.body.classList.add('has-sidebar');
@@ -549,11 +549,11 @@ if (enableSidebar) document.body.classList.add('has-sidebar');
|
aria-colcount |
- Data Grid |
+ Data Grid |
aria-colindex |
- Data Grid |
+ Data Grid |
aria-controls |
@@ -720,8 +720,8 @@ if (enableSidebar) document.body.classList.add('has-sidebar');
Date Picker Dialog (HC)
Modal Dialog
Feed
- Data Grid
- Layout Grid
+ Data Grid
+ Layout Grid
(Deprecated) Collapsible Dropdown Listbox
Listbox with Grouped Options
Listboxes with Rearrangeable Options
@@ -831,8 +831,8 @@ if (enableSidebar) document.body.classList.add('has-sidebar');
aria-rowcount |
|
@@ -840,8 +840,8 @@ if (enableSidebar) document.body.classList.add('has-sidebar');
aria-rowindex |
|
@@ -882,7 +882,7 @@ if (enableSidebar) document.body.classList.add('has-sidebar');
aria-sort |
|
diff --git a/ARIA/apg/patterns/button/examples/button.md b/ARIA/apg/patterns/button/examples/button.md
index af4447c78..0c8bf7387 100644
--- a/ARIA/apg/patterns/button/examples/button.md
+++ b/ARIA/apg/patterns/button/examples/button.md
@@ -269,10 +269,15 @@ if (enableSidebar) document.body.classList.add('has-sidebar');
Assistive Technology Support
-
+
-
@@ -259,7 +259,7 @@ if (enableSidebar) document.body.classList.add('has-sidebar');
Javascript and CSS Source Code
- The following Javascript and CSS is used by the feedDisplay.html page:
+ The following Javascript and CSS is used by the feed-display.html page:
- feedDisplay.css
- Javascript: feed.js, feedDisplay.js, main.js, utils.js
@@ -268,7 +268,7 @@ if (enableSidebar) document.body.classList.add('has-sidebar');
diff --git a/ARIA/apg/patterns/grid/examples/advancedDataGrid.md b/ARIA/apg/patterns/grid/examples/advanced-data-grid.md
similarity index 91%
rename from ARIA/apg/patterns/grid/examples/advancedDataGrid.md
rename to ARIA/apg/patterns/grid/examples/advanced-data-grid.md
index ea4f56334..8451bd503 100644
--- a/ARIA/apg/patterns/grid/examples/advancedDataGrid.md
+++ b/ARIA/apg/patterns/grid/examples/advanced-data-grid.md
@@ -1,18 +1,18 @@
---
# This file was generated by scripts/pre-build/library/formatForJekyll.js
title: "Advanced Data Grid"
-ref: /ARIA/apg/patterns/grid/examples/advancedDataGrid/
+ref: /ARIA/apg/patterns/grid/examples/advanced-data-grid/
github:
repository: w3c/aria-practices
branch: main
- path: content/patterns/grid/examples/advancedDataGrid.html
+ path: content/patterns/grid/examples/advanced-data-grid.html
feedbackmail: public-aria-practices@w3.org
-permalink: /ARIA/apg/patterns/grid/examples/advancedDataGrid/
+permalink: /ARIA/apg/patterns/grid/examples/advanced-data-grid/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
@@ -116,8 +116,8 @@ if (enableSidebar) document.body.classList.add('has-sidebar');
Similar examples include:
- - Data Grid Examples: Three example implementations of grid that include features relevant to presenting tabular information, such as content editing, sort, and column hiding.
- - Layout Grid Examples: Three example implementations of grids that are used to lay out widgets, including a collection of navigation links, a message recipients list, and a set of search results.
+ - Data Grid Examples: Three example implementations of grid that include features relevant to presenting tabular information, such as content editing, sort, and column hiding.
+ - Layout Grid Examples: Three example implementations of grids that are used to lay out widgets, including a collection of navigation links, a message recipients list, and a set of search results.
diff --git a/ARIA/apg/patterns/grid/examples/dataGrids.md b/ARIA/apg/patterns/grid/examples/data-grids.md
similarity index 98%
rename from ARIA/apg/patterns/grid/examples/dataGrids.md
rename to ARIA/apg/patterns/grid/examples/data-grids.md
index 558c156b3..023077c79 100644
--- a/ARIA/apg/patterns/grid/examples/dataGrids.md
+++ b/ARIA/apg/patterns/grid/examples/data-grids.md
@@ -1,18 +1,18 @@
---
# This file was generated by scripts/pre-build/library/formatForJekyll.js
title: "Data Grid Examples"
-ref: /ARIA/apg/patterns/grid/examples/dataGrids/
+ref: /ARIA/apg/patterns/grid/examples/data-grids/
github:
repository: w3c/aria-practices
branch: main
- path: content/patterns/grid/examples/dataGrids.html
+ path: content/patterns/grid/examples/data-grids.html
feedbackmail: public-aria-practices@w3.org
-permalink: /ARIA/apg/patterns/grid/examples/dataGrids/
+permalink: /ARIA/apg/patterns/grid/examples/data-grids/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
@@ -115,8 +115,8 @@ if (enableSidebar) document.body.classList.add('has-sidebar');
Similar examples include:
- - Layout Grid Examples: Three example implementations of grids that are used to lay out widgets, including a collection of navigation links, a message recipients list, and a set of search results.
- - Advanced Data Grid Example: Example of a grid with behaviors and features similar to a typical spreadsheet, including cell and row selection.
+ - Layout Grid Examples: Three example implementations of grids that are used to lay out widgets, including a collection of navigation links, a message recipients list, and a set of search results.
+ - Advanced Data Grid Example: Example of a grid with behaviors and features similar to a typical spreadsheet, including cell and row selection.
diff --git a/ARIA/apg/patterns/grid/examples/LayoutGrids.md b/ARIA/apg/patterns/grid/examples/layout-grids.md
similarity index 98%
rename from ARIA/apg/patterns/grid/examples/LayoutGrids.md
rename to ARIA/apg/patterns/grid/examples/layout-grids.md
index 1dcde1d51..3fadff550 100644
--- a/ARIA/apg/patterns/grid/examples/LayoutGrids.md
+++ b/ARIA/apg/patterns/grid/examples/layout-grids.md
@@ -1,18 +1,18 @@
---
# This file was generated by scripts/pre-build/library/formatForJekyll.js
title: "Layout Grid Examples"
-ref: /ARIA/apg/patterns/grid/examples/LayoutGrids/
+ref: /ARIA/apg/patterns/grid/examples/layout-grids/
github:
repository: w3c/aria-practices
branch: main
- path: content/patterns/grid/examples/LayoutGrids.html
+ path: content/patterns/grid/examples/layout-grids.html
feedbackmail: public-aria-practices@w3.org
-permalink: /ARIA/apg/patterns/grid/examples/LayoutGrids/
+permalink: /ARIA/apg/patterns/grid/examples/layout-grids/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
@@ -120,8 +120,8 @@ if (enableSidebar) document.body.classList.add('has-sidebar');
Similar examples include:
- - Data Grid Examples: Three example implementations of grid that include features relevant to presenting tabular information, such as content editing, sort, and column hiding.
- - Advanced Data Grid Example: Example of a grid with behaviors and features similar to a typical spreadsheet, including cell and row selection.
+ - Data Grid Examples: Three example implementations of grid that include features relevant to presenting tabular information, such as content editing, sort, and column hiding.
+ - Advanced Data Grid Example: Example of a grid with behaviors and features similar to a typical spreadsheet, including cell and row selection.
@@ -438,7 +438,7 @@ if (enableSidebar) document.body.classList.add('has-sidebar');
Whether focus can wrap from the last column to the first column in the next row or from the first column to the last column in the previous row when Right Arrow and Left Arrow are pressed:
This wrapping is expected in all grids except for those presenting tabular, i.e., spreadsheet-like, data.
- The data grid examples demonstrate grids where focus movement does not wrap at the ends of rows.
+ The data grid examples demonstrate grids where focus movement does not wrap at the ends of rows.
Whether focus can wrap to the first row in the next column or the last row in the previous column when Down Arrow and Up Arrow are pressed:
diff --git a/ARIA/apg/patterns/grid/grid-pattern.md b/ARIA/apg/patterns/grid/grid-pattern.md
index 02eac03b5..401d8fe27 100644
--- a/ARIA/apg/patterns/grid/grid-pattern.md
+++ b/ARIA/apg/patterns/grid/grid-pattern.md
@@ -100,9 +100,9 @@ if (enableSidebar) document.body.classList.add('has-sidebar');
>
Examples
- - Layout Grid Examples: Three example implementations of grids that are used to lay out widgets, including a collection of navigation links, a message recipients list, and a set of search results.
- - Data Grid Examples: Three example implementations of grid that include features relevant to presenting tabular information, such as content editing, sort, and column hiding.
- - Advanced Data Grid Example: Example of a grid with behaviors and features similar to a typical spreadsheet, including cell and row selection.
+ - Layout Grid Examples: Three example implementations of grids that are used to lay out widgets, including a collection of navigation links, a message recipients list, and a set of search results.
+ - Data Grid Examples: Three example implementations of grid that include features relevant to presenting tabular information, such as content editing, sort, and column hiding.
+ - Advanced Data Grid Example: Example of a grid with behaviors and features similar to a typical spreadsheet, including cell and row selection.
diff --git a/ARIA/apg/patterns/table/examples/sortable-table.md b/ARIA/apg/patterns/table/examples/sortable-table.md
index 496c971a8..399453bf3 100644
--- a/ARIA/apg/patterns/table/examples/sortable-table.md
+++ b/ARIA/apg/patterns/table/examples/sortable-table.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/table/examples/sortable-table/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
@@ -108,7 +108,7 @@ if (enableSidebar) document.body.classList.add('has-sidebar');
Similar examples include:
- - Data Grid Examples: Three example implementations of grid that include features relevant to presenting tabular information, such as content editing, sort, and column hiding.
+ - Data Grid Examples: Three example implementations of grid that include features relevant to presenting tabular information, such as content editing, sort, and column hiding.
- Table Example: ARIA table made using HTML
div
and span
elements.
diff --git a/ARIA/apg/patterns/table/examples/table.md b/ARIA/apg/patterns/table/examples/table.md
index 1a2ba7db8..7f559e1df 100644
--- a/ARIA/apg/patterns/table/examples/table.md
+++ b/ARIA/apg/patterns/table/examples/table.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/table/examples/table/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
@@ -106,7 +106,7 @@ if (enableSidebar) document.body.classList.add('has-sidebar');
Similar examples include:
- Sortable Table Example: Basic HTML table that illustrates implementation of
aria-sort
in the headers of sortable columns.
- - Data Grid Examples: Three example implementations of grid that include features relevant to presenting tabular information, such as content editing, sort, and column hiding.
+ - Data Grid Examples: Three example implementations of grid that include features relevant to presenting tabular information, such as content editing, sort, and column hiding.
diff --git a/ARIA/apg/patterns/treegrid/examples/treegrid-1.md b/ARIA/apg/patterns/treegrid/examples/treegrid-1.md
index 530585e37..02fe3f5c3 100644
--- a/ARIA/apg/patterns/treegrid/examples/treegrid-1.md
+++ b/ARIA/apg/patterns/treegrid/examples/treegrid-1.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/treegrid/examples/treegrid-1/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
@@ -127,7 +127,7 @@ if (enableSidebar) document.body.classList.add('has-sidebar');
The following example demonstrates how the Treegrid Pattern can be used to make an interactive tree that enables users to both navigate the hierarchical structure of email conversations and also navigate elements that describe each email, such as subject and sender.
Similar examples include:
- - Data Grid Examples: Three example implementations of grid that include features relevant to presenting tabular information, such as content editing, sort, and column hiding.
+ - Data Grid Examples: Three example implementations of grid that include features relevant to presenting tabular information, such as content editing, sort, and column hiding.
- File Directory Treeview using computed properties
- File Directory Treeview using declared properties
- Navigation Treeview Example
diff --git a/_external/aria-practices b/_external/aria-practices
index a35e8e0e6..b8ba19874 160000
--- a/_external/aria-practices
+++ b/_external/aria-practices
@@ -1 +1 @@
-Subproject commit a35e8e0e64ffdba86055590f0e8fdf16cc707fbc
+Subproject commit b8ba1987471671e4adaeb60aab7f2f7f2e41e836
diff --git a/content-assets/wai-aria-practices/patterns/slider/examples/css/slider-seek.css b/content-assets/wai-aria-practices/patterns/slider/examples/css/slider-seek.css
index 1e9a82190..a3a65c68c 100644
--- a/content-assets/wai-aria-practices/patterns/slider/examples/css/slider-seek.css
+++ b/content-assets/wai-aria-practices/patterns/slider/examples/css/slider-seek.css
@@ -37,7 +37,7 @@
stroke: currentcolor;
stroke-width: 2px;
fill: currentcolor;
- fill-opacity: 25%;
+ fill-opacity: 0.25;
}
.slider-seek .thumb {
diff --git a/content-assets/wai-aria-practices/patterns/slider/examples/css/slider-temperature.css b/content-assets/wai-aria-practices/patterns/slider/examples/css/slider-temperature.css
index 05b9e289e..4163851b0 100644
--- a/content-assets/wai-aria-practices/patterns/slider/examples/css/slider-temperature.css
+++ b/content-assets/wai-aria-practices/patterns/slider/examples/css/slider-temperature.css
@@ -54,7 +54,7 @@
stroke: currentcolor;
stroke-width: 2px;
fill: currentcolor;
- fill-opacity: 25%;
+ fill-opacity: 0.25;
}
.slider-temperature .thumb,
From 93b3a773e526d7f2d556f1ef77256ec1ab032f17 Mon Sep 17 00:00:00 2001
From: alflennik
Date: Mon, 13 Mar 2023 14:18:25 -0400
Subject: [PATCH 4/7] Include recent aria-practices changes
---
.../patterns/accordion/examples/accordion.md | 2 +-
ARIA/apg/patterns/alert/examples/alert.md | 2 +-
.../alertdialog/examples/alertdialog.md | 2 +-
.../breadcrumb/examples/breadcrumb.md | 2 +-
ARIA/apg/patterns/button/examples/button.md | 10 +-
.../patterns/button/examples/button_idl.md | 2 +-
.../carousel/examples/carousel-1-prev-next.md | 2 +-
.../carousel/examples/carousel-2-tablist.md | 2 +-
.../checkbox/examples/checkbox-mixed.md | 2 +-
.../patterns/checkbox/examples/checkbox.md | 2 +-
.../examples/combobox-autocomplete-both.md | 2 +-
.../examples/combobox-autocomplete-list.md | 2 +-
.../examples/combobox-autocomplete-none.md | 2 +-
.../combobox/examples/combobox-datepicker.md | 2 +-
.../combobox/examples/combobox-select-only.md | 2 +-
.../patterns/combobox/examples/grid-combo.md | 2 +-
.../examples/datepicker-dialog.md | 2 +-
.../patterns/dialog-modal/examples/dialog.md | 2 +-
.../disclosure/examples/disclosure-faq.md | 2 +-
.../examples/disclosure-image-description.md | 2 +-
.../examples/disclosure-navigation-hybrid.md | 2 +-
.../examples/disclosure-navigation.md | 2 +-
ARIA/apg/patterns/feed/examples/feed.md | 2 +-
.../grid/examples/advanced-data-grid.md | 2 +-
ARIA/apg/patterns/grid/examples/data-grids.md | 2 +-
.../patterns/grid/examples/layout-grids.md | 2 +-
ARIA/apg/patterns/link/examples/link.md | 2 +-
.../listbox/examples/listbox-collapsible.md | 2 +-
.../listbox/examples/listbox-grouped.md | 2 +-
.../listbox/examples/listbox-rearrangeable.md | 2 +-
.../listbox/examples/listbox-scrollable.md | 2 +-
.../menu-button-actions-active-descendant.md | 2 +-
.../examples/menu-button-actions.md | 2 +-
.../menu-button/examples/menu-button-links.md | 2 +-
.../menubar/examples/menubar-editor.md | 2 +-
.../menubar/examples/menubar-navigation.md | 2 +-
ARIA/apg/patterns/meter/examples/meter.md | 2 +-
.../radio/examples/radio-activedescendant.md | 2 +-
.../patterns/radio/examples/radio-rating.md | 2 +-
ARIA/apg/patterns/radio/examples/radio.md | 2 +-
.../examples/slider-multithumb.md | 2 +-
.../slider/examples/slider-color-viewer.md | 2 +-
.../patterns/slider/examples/slider-rating.md | 2 +-
.../patterns/slider/examples/slider-seek.md | 2 +-
.../slider/examples/slider-temperature.md | 2 +-
.../examples/datepicker-spinbuttons.md | 2 +-
.../patterns/switch/examples/switch-button.md | 2 +-
.../switch/examples/switch-checkbox.md | 2 +-
ARIA/apg/patterns/switch/examples/switch.md | 2 +-
.../patterns/table/examples/sortable-table.md | 2 +-
ARIA/apg/patterns/table/examples/table.md | 2 +-
.../patterns/tabs/examples/tabs-automatic.md | 2 +-
.../apg/patterns/tabs/examples/tabs-manual.md | 2 +-
ARIA/apg/patterns/toolbar/examples/toolbar.md | 2 +-
.../patterns/treegrid/examples/treegrid-1.md | 2 +-
.../patterns/treeview/examples/treeview-1a.md | 2 +-
.../patterns/treeview/examples/treeview-1b.md | 2 +-
.../treeview/examples/treeview-navigation.md | 2 +-
.../wai-aria-practices/shared/js/skipto.js | 4122 ++++++-----------
59 files changed, 1572 insertions(+), 2674 deletions(-)
diff --git a/ARIA/apg/patterns/accordion/examples/accordion.md b/ARIA/apg/patterns/accordion/examples/accordion.md
index d7abd6a5d..8793917e3 100644
--- a/ARIA/apg/patterns/accordion/examples/accordion.md
+++ b/ARIA/apg/patterns/accordion/examples/accordion.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/accordion/examples/accordion/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/alert/examples/alert.md b/ARIA/apg/patterns/alert/examples/alert.md
index abeb28eef..5823a3dcd 100644
--- a/ARIA/apg/patterns/alert/examples/alert.md
+++ b/ARIA/apg/patterns/alert/examples/alert.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/alert/examples/alert/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/alertdialog/examples/alertdialog.md b/ARIA/apg/patterns/alertdialog/examples/alertdialog.md
index 54233dcd2..6573dbd84 100644
--- a/ARIA/apg/patterns/alertdialog/examples/alertdialog.md
+++ b/ARIA/apg/patterns/alertdialog/examples/alertdialog.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/alertdialog/examples/alertdialog/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/breadcrumb/examples/breadcrumb.md b/ARIA/apg/patterns/breadcrumb/examples/breadcrumb.md
index 64cf173b0..68909ed33 100644
--- a/ARIA/apg/patterns/breadcrumb/examples/breadcrumb.md
+++ b/ARIA/apg/patterns/breadcrumb/examples/breadcrumb.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/breadcrumb/examples/breadcrumb/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/button/examples/button.md b/ARIA/apg/patterns/button/examples/button.md
index 3705d6392..cd80c155d 100644
--- a/ARIA/apg/patterns/button/examples/button.md
+++ b/ARIA/apg/patterns/button/examples/button.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/button/examples/button/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
@@ -269,16 +269,18 @@ if (enableSidebar) document.body.classList.add('has-sidebar');
Assistive Technology Support
+ Command Button
+ Toggle Button
diff --git a/ARIA/apg/patterns/button/examples/button_idl.md b/ARIA/apg/patterns/button/examples/button_idl.md
index d25578b1a..d3851bc43 100644
--- a/ARIA/apg/patterns/button/examples/button_idl.md
+++ b/ARIA/apg/patterns/button/examples/button_idl.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/button/examples/button_idl/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/carousel/examples/carousel-1-prev-next.md b/ARIA/apg/patterns/carousel/examples/carousel-1-prev-next.md
index e610f9aef..9ba432f2b 100644
--- a/ARIA/apg/patterns/carousel/examples/carousel-1-prev-next.md
+++ b/ARIA/apg/patterns/carousel/examples/carousel-1-prev-next.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/carousel/examples/carousel-1-prev-next/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/carousel/examples/carousel-2-tablist.md b/ARIA/apg/patterns/carousel/examples/carousel-2-tablist.md
index 33b858cf4..4045f5b06 100644
--- a/ARIA/apg/patterns/carousel/examples/carousel-2-tablist.md
+++ b/ARIA/apg/patterns/carousel/examples/carousel-2-tablist.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/carousel/examples/carousel-2-tablist/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/checkbox/examples/checkbox-mixed.md b/ARIA/apg/patterns/checkbox/examples/checkbox-mixed.md
index be5674a07..e866f84fc 100644
--- a/ARIA/apg/patterns/checkbox/examples/checkbox-mixed.md
+++ b/ARIA/apg/patterns/checkbox/examples/checkbox-mixed.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/checkbox/examples/checkbox-mixed/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/checkbox/examples/checkbox.md b/ARIA/apg/patterns/checkbox/examples/checkbox.md
index 4dc3dac8b..b03bbbfef 100644
--- a/ARIA/apg/patterns/checkbox/examples/checkbox.md
+++ b/ARIA/apg/patterns/checkbox/examples/checkbox.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/checkbox/examples/checkbox/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/combobox/examples/combobox-autocomplete-both.md b/ARIA/apg/patterns/combobox/examples/combobox-autocomplete-both.md
index 89b466778..84f3aaf85 100644
--- a/ARIA/apg/patterns/combobox/examples/combobox-autocomplete-both.md
+++ b/ARIA/apg/patterns/combobox/examples/combobox-autocomplete-both.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/combobox/examples/combobox-autocomplete-both/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/combobox/examples/combobox-autocomplete-list.md b/ARIA/apg/patterns/combobox/examples/combobox-autocomplete-list.md
index e3e6c36cc..807e120af 100644
--- a/ARIA/apg/patterns/combobox/examples/combobox-autocomplete-list.md
+++ b/ARIA/apg/patterns/combobox/examples/combobox-autocomplete-list.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/combobox/examples/combobox-autocomplete-list/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/combobox/examples/combobox-autocomplete-none.md b/ARIA/apg/patterns/combobox/examples/combobox-autocomplete-none.md
index 7de55b893..6953616ea 100644
--- a/ARIA/apg/patterns/combobox/examples/combobox-autocomplete-none.md
+++ b/ARIA/apg/patterns/combobox/examples/combobox-autocomplete-none.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/combobox/examples/combobox-autocomplete-none/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/combobox/examples/combobox-datepicker.md b/ARIA/apg/patterns/combobox/examples/combobox-datepicker.md
index 28345d5a6..39e5751b4 100644
--- a/ARIA/apg/patterns/combobox/examples/combobox-datepicker.md
+++ b/ARIA/apg/patterns/combobox/examples/combobox-datepicker.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/combobox/examples/combobox-datepicker/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/combobox/examples/combobox-select-only.md b/ARIA/apg/patterns/combobox/examples/combobox-select-only.md
index 4b180dc0c..bf09304f6 100644
--- a/ARIA/apg/patterns/combobox/examples/combobox-select-only.md
+++ b/ARIA/apg/patterns/combobox/examples/combobox-select-only.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/combobox/examples/combobox-select-only/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/combobox/examples/grid-combo.md b/ARIA/apg/patterns/combobox/examples/grid-combo.md
index b328e55ce..3197d1dc8 100644
--- a/ARIA/apg/patterns/combobox/examples/grid-combo.md
+++ b/ARIA/apg/patterns/combobox/examples/grid-combo.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/combobox/examples/grid-combo/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/dialog-modal/examples/datepicker-dialog.md b/ARIA/apg/patterns/dialog-modal/examples/datepicker-dialog.md
index 0f965a338..5ded31b28 100644
--- a/ARIA/apg/patterns/dialog-modal/examples/datepicker-dialog.md
+++ b/ARIA/apg/patterns/dialog-modal/examples/datepicker-dialog.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/dialog-modal/examples/datepicker-dialog/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/dialog-modal/examples/dialog.md b/ARIA/apg/patterns/dialog-modal/examples/dialog.md
index d69834c69..269f092e9 100644
--- a/ARIA/apg/patterns/dialog-modal/examples/dialog.md
+++ b/ARIA/apg/patterns/dialog-modal/examples/dialog.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/dialog-modal/examples/dialog/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/disclosure/examples/disclosure-faq.md b/ARIA/apg/patterns/disclosure/examples/disclosure-faq.md
index 944460a81..458c7f1cb 100644
--- a/ARIA/apg/patterns/disclosure/examples/disclosure-faq.md
+++ b/ARIA/apg/patterns/disclosure/examples/disclosure-faq.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/disclosure/examples/disclosure-faq/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/disclosure/examples/disclosure-image-description.md b/ARIA/apg/patterns/disclosure/examples/disclosure-image-description.md
index 7cf01f451..37aaab746 100644
--- a/ARIA/apg/patterns/disclosure/examples/disclosure-image-description.md
+++ b/ARIA/apg/patterns/disclosure/examples/disclosure-image-description.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/disclosure/examples/disclosure-image-description/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/disclosure/examples/disclosure-navigation-hybrid.md b/ARIA/apg/patterns/disclosure/examples/disclosure-navigation-hybrid.md
index 7e253aa75..bd76011bc 100644
--- a/ARIA/apg/patterns/disclosure/examples/disclosure-navigation-hybrid.md
+++ b/ARIA/apg/patterns/disclosure/examples/disclosure-navigation-hybrid.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/disclosure/examples/disclosure-navigation-hybrid/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/disclosure/examples/disclosure-navigation.md b/ARIA/apg/patterns/disclosure/examples/disclosure-navigation.md
index 817fb04cd..d81d338c3 100644
--- a/ARIA/apg/patterns/disclosure/examples/disclosure-navigation.md
+++ b/ARIA/apg/patterns/disclosure/examples/disclosure-navigation.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/disclosure/examples/disclosure-navigation/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/feed/examples/feed.md b/ARIA/apg/patterns/feed/examples/feed.md
index f62d47c26..efa1dfdfe 100644
--- a/ARIA/apg/patterns/feed/examples/feed.md
+++ b/ARIA/apg/patterns/feed/examples/feed.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/feed/examples/feed/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/grid/examples/advanced-data-grid.md b/ARIA/apg/patterns/grid/examples/advanced-data-grid.md
index ef13aecdd..8451bd503 100644
--- a/ARIA/apg/patterns/grid/examples/advanced-data-grid.md
+++ b/ARIA/apg/patterns/grid/examples/advanced-data-grid.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/grid/examples/advanced-data-grid/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/grid/examples/data-grids.md b/ARIA/apg/patterns/grid/examples/data-grids.md
index 5fdb99a8b..023077c79 100644
--- a/ARIA/apg/patterns/grid/examples/data-grids.md
+++ b/ARIA/apg/patterns/grid/examples/data-grids.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/grid/examples/data-grids/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/grid/examples/layout-grids.md b/ARIA/apg/patterns/grid/examples/layout-grids.md
index f63717d2f..3fadff550 100644
--- a/ARIA/apg/patterns/grid/examples/layout-grids.md
+++ b/ARIA/apg/patterns/grid/examples/layout-grids.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/grid/examples/layout-grids/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/link/examples/link.md b/ARIA/apg/patterns/link/examples/link.md
index d874ce5ad..9896a476d 100644
--- a/ARIA/apg/patterns/link/examples/link.md
+++ b/ARIA/apg/patterns/link/examples/link.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/link/examples/link/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/listbox/examples/listbox-collapsible.md b/ARIA/apg/patterns/listbox/examples/listbox-collapsible.md
index 67d71e4bd..bfb978f7f 100644
--- a/ARIA/apg/patterns/listbox/examples/listbox-collapsible.md
+++ b/ARIA/apg/patterns/listbox/examples/listbox-collapsible.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/listbox/examples/listbox-collapsible/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/listbox/examples/listbox-grouped.md b/ARIA/apg/patterns/listbox/examples/listbox-grouped.md
index 4098ab753..67d19e400 100644
--- a/ARIA/apg/patterns/listbox/examples/listbox-grouped.md
+++ b/ARIA/apg/patterns/listbox/examples/listbox-grouped.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/listbox/examples/listbox-grouped/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/listbox/examples/listbox-rearrangeable.md b/ARIA/apg/patterns/listbox/examples/listbox-rearrangeable.md
index 89a18fde9..24ae5a861 100644
--- a/ARIA/apg/patterns/listbox/examples/listbox-rearrangeable.md
+++ b/ARIA/apg/patterns/listbox/examples/listbox-rearrangeable.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/listbox/examples/listbox-rearrangeable/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/listbox/examples/listbox-scrollable.md b/ARIA/apg/patterns/listbox/examples/listbox-scrollable.md
index ca28f56cf..98f49ea31 100644
--- a/ARIA/apg/patterns/listbox/examples/listbox-scrollable.md
+++ b/ARIA/apg/patterns/listbox/examples/listbox-scrollable.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/listbox/examples/listbox-scrollable/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/menu-button/examples/menu-button-actions-active-descendant.md b/ARIA/apg/patterns/menu-button/examples/menu-button-actions-active-descendant.md
index fa094a860..6aea92a81 100644
--- a/ARIA/apg/patterns/menu-button/examples/menu-button-actions-active-descendant.md
+++ b/ARIA/apg/patterns/menu-button/examples/menu-button-actions-active-descendant.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/menu-button/examples/menu-button-actions-active-de
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/menu-button/examples/menu-button-actions.md b/ARIA/apg/patterns/menu-button/examples/menu-button-actions.md
index 6ea099231..7094e00e4 100644
--- a/ARIA/apg/patterns/menu-button/examples/menu-button-actions.md
+++ b/ARIA/apg/patterns/menu-button/examples/menu-button-actions.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/menu-button/examples/menu-button-actions/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/menu-button/examples/menu-button-links.md b/ARIA/apg/patterns/menu-button/examples/menu-button-links.md
index 18d57dffc..dafc4318d 100644
--- a/ARIA/apg/patterns/menu-button/examples/menu-button-links.md
+++ b/ARIA/apg/patterns/menu-button/examples/menu-button-links.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/menu-button/examples/menu-button-links/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/menubar/examples/menubar-editor.md b/ARIA/apg/patterns/menubar/examples/menubar-editor.md
index 9aaa01002..a6793785a 100644
--- a/ARIA/apg/patterns/menubar/examples/menubar-editor.md
+++ b/ARIA/apg/patterns/menubar/examples/menubar-editor.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/menubar/examples/menubar-editor/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/menubar/examples/menubar-navigation.md b/ARIA/apg/patterns/menubar/examples/menubar-navigation.md
index c02a0431c..adceb6c9e 100644
--- a/ARIA/apg/patterns/menubar/examples/menubar-navigation.md
+++ b/ARIA/apg/patterns/menubar/examples/menubar-navigation.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/menubar/examples/menubar-navigation/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/meter/examples/meter.md b/ARIA/apg/patterns/meter/examples/meter.md
index ddb0d470c..6a9054b36 100644
--- a/ARIA/apg/patterns/meter/examples/meter.md
+++ b/ARIA/apg/patterns/meter/examples/meter.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/meter/examples/meter/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/radio/examples/radio-activedescendant.md b/ARIA/apg/patterns/radio/examples/radio-activedescendant.md
index 45601e4de..38c898b0c 100644
--- a/ARIA/apg/patterns/radio/examples/radio-activedescendant.md
+++ b/ARIA/apg/patterns/radio/examples/radio-activedescendant.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/radio/examples/radio-activedescendant/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/radio/examples/radio-rating.md b/ARIA/apg/patterns/radio/examples/radio-rating.md
index 3a7996d96..ffb639b72 100644
--- a/ARIA/apg/patterns/radio/examples/radio-rating.md
+++ b/ARIA/apg/patterns/radio/examples/radio-rating.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/radio/examples/radio-rating/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/radio/examples/radio.md b/ARIA/apg/patterns/radio/examples/radio.md
index 2da009cd1..53c64be0f 100644
--- a/ARIA/apg/patterns/radio/examples/radio.md
+++ b/ARIA/apg/patterns/radio/examples/radio.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/radio/examples/radio/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/slider-multithumb/examples/slider-multithumb.md b/ARIA/apg/patterns/slider-multithumb/examples/slider-multithumb.md
index fb2b22a69..1def1b69d 100644
--- a/ARIA/apg/patterns/slider-multithumb/examples/slider-multithumb.md
+++ b/ARIA/apg/patterns/slider-multithumb/examples/slider-multithumb.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/slider-multithumb/examples/slider-multithumb/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/slider/examples/slider-color-viewer.md b/ARIA/apg/patterns/slider/examples/slider-color-viewer.md
index 8905e39e6..a3f13308e 100644
--- a/ARIA/apg/patterns/slider/examples/slider-color-viewer.md
+++ b/ARIA/apg/patterns/slider/examples/slider-color-viewer.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/slider/examples/slider-color-viewer/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/slider/examples/slider-rating.md b/ARIA/apg/patterns/slider/examples/slider-rating.md
index b5770fc2e..0bb31f06a 100644
--- a/ARIA/apg/patterns/slider/examples/slider-rating.md
+++ b/ARIA/apg/patterns/slider/examples/slider-rating.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/slider/examples/slider-rating/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/slider/examples/slider-seek.md b/ARIA/apg/patterns/slider/examples/slider-seek.md
index 5929e034d..772a33ba6 100644
--- a/ARIA/apg/patterns/slider/examples/slider-seek.md
+++ b/ARIA/apg/patterns/slider/examples/slider-seek.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/slider/examples/slider-seek/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/slider/examples/slider-temperature.md b/ARIA/apg/patterns/slider/examples/slider-temperature.md
index fc278096f..bdc85ef8d 100644
--- a/ARIA/apg/patterns/slider/examples/slider-temperature.md
+++ b/ARIA/apg/patterns/slider/examples/slider-temperature.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/slider/examples/slider-temperature/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/spinbutton/examples/datepicker-spinbuttons.md b/ARIA/apg/patterns/spinbutton/examples/datepicker-spinbuttons.md
index f91773efa..b87fbe20a 100644
--- a/ARIA/apg/patterns/spinbutton/examples/datepicker-spinbuttons.md
+++ b/ARIA/apg/patterns/spinbutton/examples/datepicker-spinbuttons.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/spinbutton/examples/datepicker-spinbuttons/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/switch/examples/switch-button.md b/ARIA/apg/patterns/switch/examples/switch-button.md
index f173c00e9..4b3f1b70b 100644
--- a/ARIA/apg/patterns/switch/examples/switch-button.md
+++ b/ARIA/apg/patterns/switch/examples/switch-button.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/switch/examples/switch-button/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/switch/examples/switch-checkbox.md b/ARIA/apg/patterns/switch/examples/switch-checkbox.md
index e1a403060..15ead1b92 100644
--- a/ARIA/apg/patterns/switch/examples/switch-checkbox.md
+++ b/ARIA/apg/patterns/switch/examples/switch-checkbox.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/switch/examples/switch-checkbox/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/switch/examples/switch.md b/ARIA/apg/patterns/switch/examples/switch.md
index f3657c714..0ad92abe4 100644
--- a/ARIA/apg/patterns/switch/examples/switch.md
+++ b/ARIA/apg/patterns/switch/examples/switch.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/switch/examples/switch/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/table/examples/sortable-table.md b/ARIA/apg/patterns/table/examples/sortable-table.md
index 3e15c5cc3..399453bf3 100644
--- a/ARIA/apg/patterns/table/examples/sortable-table.md
+++ b/ARIA/apg/patterns/table/examples/sortable-table.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/table/examples/sortable-table/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/table/examples/table.md b/ARIA/apg/patterns/table/examples/table.md
index c72c38973..7f559e1df 100644
--- a/ARIA/apg/patterns/table/examples/table.md
+++ b/ARIA/apg/patterns/table/examples/table.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/table/examples/table/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/tabs/examples/tabs-automatic.md b/ARIA/apg/patterns/tabs/examples/tabs-automatic.md
index 08cd38602..3f53acb4a 100644
--- a/ARIA/apg/patterns/tabs/examples/tabs-automatic.md
+++ b/ARIA/apg/patterns/tabs/examples/tabs-automatic.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/tabs/examples/tabs-automatic/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/tabs/examples/tabs-manual.md b/ARIA/apg/patterns/tabs/examples/tabs-manual.md
index 6df53d4ba..cdebe2bdc 100644
--- a/ARIA/apg/patterns/tabs/examples/tabs-manual.md
+++ b/ARIA/apg/patterns/tabs/examples/tabs-manual.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/tabs/examples/tabs-manual/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/toolbar/examples/toolbar.md b/ARIA/apg/patterns/toolbar/examples/toolbar.md
index ec3525821..8448d2428 100644
--- a/ARIA/apg/patterns/toolbar/examples/toolbar.md
+++ b/ARIA/apg/patterns/toolbar/examples/toolbar.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/toolbar/examples/toolbar/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/treegrid/examples/treegrid-1.md b/ARIA/apg/patterns/treegrid/examples/treegrid-1.md
index d2e2d405f..02fe3f5c3 100644
--- a/ARIA/apg/patterns/treegrid/examples/treegrid-1.md
+++ b/ARIA/apg/patterns/treegrid/examples/treegrid-1.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/treegrid/examples/treegrid-1/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/treeview/examples/treeview-1a.md b/ARIA/apg/patterns/treeview/examples/treeview-1a.md
index 2395c3e44..e4b877bc6 100644
--- a/ARIA/apg/patterns/treeview/examples/treeview-1a.md
+++ b/ARIA/apg/patterns/treeview/examples/treeview-1a.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/treeview/examples/treeview-1a/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/treeview/examples/treeview-1b.md b/ARIA/apg/patterns/treeview/examples/treeview-1b.md
index 050c974cc..b628ceed9 100644
--- a/ARIA/apg/patterns/treeview/examples/treeview-1b.md
+++ b/ARIA/apg/patterns/treeview/examples/treeview-1b.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/treeview/examples/treeview-1b/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/ARIA/apg/patterns/treeview/examples/treeview-navigation.md b/ARIA/apg/patterns/treeview/examples/treeview-navigation.md
index 4381e3753..3a1ecf706 100644
--- a/ARIA/apg/patterns/treeview/examples/treeview-navigation.md
+++ b/ARIA/apg/patterns/treeview/examples/treeview-navigation.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/treeview/examples/treeview-navigation/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
diff --git a/content-assets/wai-aria-practices/shared/js/skipto.js b/content-assets/wai-aria-practices/shared/js/skipto.js
index 71c3f9892..ef9c4a866 100644
--- a/content-assets/wai-aria-practices/shared/js/skipto.js
+++ b/content-assets/wai-aria-practices/shared/js/skipto.js
@@ -1,2346 +1,1250 @@
+/*! skipto - v4.2.0 - 2022-06-16
+ * https://github.com/paypal/skipto
+ * Copyright (c) 2022 Jon Gunderson; Licensed BSD
+ * Copyright (c) 2021 PayPal Accessibility Team and University of Illinois; Licensed BSD */
+/*@cc_on @*/
+/*@if (@_jscript_version >= es6) @*/
/* ========================================================================
- * Version: 5.1.3
- * Copyright (c) 2022, 2023 Jon Gunderson; Licensed BSD
- * Copyright (c) 2021 PayPal Accessibility Team and University of Illinois; Licensed BSD
+ * Copyright (c) <2022> (ver 4.2) Jon Gunderson
+ * Copyright (c) <2021> PayPal and University of Illinois
* All rights reserved.
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
- * Neither the name of PayPal or any of its subsidiaries or affiliates, nor the name of the University of Illinois, nor the names of any other contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+ * Neither the name of PayPal or any of its subsidiaries or affiliates, nor the name of the University of Illinois, nor the names of any other contributors contributors may be used to endorse or promote products derived from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Documentation: https://skipto-landmarks-headings.github.io/page-script-5
- * Code: https://github.com/skipto-landmarks-headings/page-script-5
- * Report Issues: https://github.com/skipto-landmarks-headings/page-script-5/issues
* ======================================================================== */
(function () {
'use strict';
+ const SkipTo = {
+ skipToId: 'id-skip-to-js-50',
+ skipToMenuId: 'id-skip-to-menu-50',
+ domNode: null,
+ buttonNode: null,
+ menuNode: null,
+ menuitemNodes: [],
+ firstMenuitem: false,
+ lastMenuitem: false,
+ firstChars: [],
+ headingLevels: [],
+ skipToIdIndex: 1,
+ showAllLandmarksSelector:
+ 'main, [role=main], [role=search], nav, [role=navigation], section[aria-label], section[aria-labelledby], section[title], [role=region][aria-label], [role=region][aria-labelledby], [role=region][title], form[aria-label], form[aria-labelledby], aside, [role=complementary], body > header, [role=banner], body > footer, [role=contentinfo]',
+ showAllHeadingsSelector: 'h1, h2, h3, h4, h5, h6',
+ // Default configuration values
+ config: {
+ // Feature switches
+ enableActions: false,
+ enableMofN: true,
+ enableHeadingLevelShortcuts: true,
+
+ // Customization of button and menu
+ altShortcut: '0', // default shortcut key is the number zero
+ optionShortcut: 'ยบ', // default shortcut key character associated with option+0 on mac
+ attachElement: 'body',
+ displayOption: 'popup', // Line edited by pre-build script
+ // container element, use containerClass for custom styling
+ containerElement: 'div',
+ containerRole: '',
+ customClass: '',
+
+ // Button labels and messages
+ buttonLabel: 'Skip To Content',
+ altLabel: 'Alt',
+ optionLabel: 'Option',
+ buttonShortcut: ' ($modifier+$key)',
+ altButtonAriaLabel: 'Skip To Content, shortcut Alt plus $key',
+ optionButtonAriaLabel: 'Skip To Content, shortcut Option plus $key',
+
+ // Menu labels and messages
+ menuLabel: 'Landmarks and Headings',
+ landmarkGroupLabel: 'Landmarks',
+ headingGroupLabel: 'Headings',
+ mofnGroupLabel: ' ($m of $n)',
+ headingLevelLabel: 'Heading level',
+ mainLabel: 'main',
+ searchLabel: 'search',
+ navLabel: 'navigation',
+ regionLabel: 'region',
+ asideLabel: 'complementary',
+ footerLabel: 'contentinfo',
+ headerLabel: 'banner',
+ formLabel: 'form',
+ msgNoLandmarksFound: 'No landmarks found',
+ msgNoHeadingsFound: 'No headings found',
+
+ // Action labels and messages
+ actionGroupLabel: 'Actions',
+ actionShowHeadingsHelp:
+ 'Toggles between showing "All" and "Selected" Headings.',
+ actionShowSelectedHeadingsLabel: 'Show Selected Headings ($num)',
+ actionShowAllHeadingsLabel: 'Show All Headings ($num)',
+ actionShowLandmarksHelp:
+ 'Toggles between showing "All" and "Selected" Landmarks.',
+ actionShowSelectedLandmarksLabel: 'Show Selected Landmarks ($num)',
+ actionShowAllLandmarksLabel: 'Show All Landmarks ($num)',
+
+ actionShowSelectedHeadingsAriaLabel: 'Show $num selected headings',
+ actionShowAllHeadingsAriaLabel: 'Show all $num headings',
+ actionShowSelectedLandmarksAriaLabel: 'Show $num selected landmarks',
+ actionShowAllLandmarksAriaLabel: 'Show all $num landmarks',
+
+ // Selectors for landmark and headings sections
+ landmarks:
+ 'main, [role="main"], [role="search"], nav, [role="navigation"], aside, [role="complementary"]',
+ headings: 'main h1, [role="main"] h1, main h2, [role="main"] h2',
+
+ // Custom CSS position and colors
+ colorTheme: '',
+ fontFamily: '',
+ fontSize: '',
+ positionLeft: '',
+ menuTextColor: '',
+ menuBackgroundColor: '',
+ menuitemFocusTextColor: '',
+ menuitemFocusBackgroundColor: '',
+ focusBorderColor: '',
+ buttonTextColor: '',
+ buttonBackgroundColor: '',
+ },
+ colorThemes: {
+ default: {
+ fontFamily:
+ 'Noto Sans, Trebuchet MS, Helvetica Neue, Arial, sans-serif',
+ fontSize: '14px',
+ positionLeft: 'unset',
+ menuTextColor: '#000',
+ menuBackgroundColor: '#def',
+ menuitemFocusTextColor: '#fff',
+ menuitemFocusBackgroundColor: '#005a9c',
+ focusBorderColor: '#005a9c',
+ buttonTextColor: '#005a9c',
+ buttonBackgroundColor: '#ddd',
+ },
+ },
+ defaultCSS:
+ '.skip-to.popup{position:absolute;top:-30em;left:0}.skip-to,.skip-to.popup.focus{position:absolute;top:0;left:$positionLeft;font-family:$fontFamily;font-size:$fontSize}.skip-to.fixed{position:fixed}.skip-to button{position:relative;margin:0;padding:6px 8px 6px 8px;border-width:0 1px 1px 1px;border-style:solid;border-radius:0 0 6px 6px;border-color:$buttonBackgroundColor;color:$menuTextColor;background-color:$buttonBackgroundColor;z-index:100000!important;font-family:$fontFamily;font-size:$fontSize}.skip-to [role=menu]{position:absolute;min-width:17em;display:none;margin:0;padding:.25rem;background-color:$menuBackgroundColor;border-width:2px;border-style:solid;border-color:$focusBorderColor;border-radius:5px;z-index:100000!important;overflow-x:hidden}.skip-to [role=group]{display:grid;grid-auto-rows:min-content;grid-row-gap:1px}.skip-to [role=separator]:first-child{border-radius:5px 5px 0 0}.skip-to [role=menuitem]{padding:3px;width:auto;border-width:0;border-style:solid;color:$menuTextColor;background-color:$menuBackgroundColor;z-index:100000!important;display:grid;overflow-y:clip;grid-template-columns:repeat(6,1.2rem) 1fr;grid-column-gap:2px;font-size:1em}.skip-to [role=menuitem] .label,.skip-to [role=menuitem] .level{font-size:100%;font-weight:400;color:$menuTextColor;display:inline-block;background-color:$menuBackgroundColor;line-height:inherit;display:inline-block}.skip-to [role=menuitem] .level{text-align:right;padding-right:4px}.skip-to [role=menuitem] .label{text-align:left;margin:0;padding:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.skip-to [role=menuitem] .label:first-letter,.skip-to [role=menuitem] .level:first-letter{text-decoration:underline;text-transform:uppercase}.skip-to [role=menuitem].skip-to-h1 .level{grid-column:1}.skip-to [role=menuitem].skip-to-h2 .level{grid-column:2}.skip-to [role=menuitem].skip-to-h3 .level{grid-column:3}.skip-to [role=menuitem].skip-to-h4 .level{grid-column:4}.skip-to [role=menuitem].skip-to-h5 .level{grid-column:5}.skip-to [role=menuitem].skip-to-h6 .level{grid-column:8}.skip-to [role=menuitem].skip-to-h1 .label{grid-column:2/8}.skip-to [role=menuitem].skip-to-h2 .label{grid-column:3/8}.skip-to [role=menuitem].skip-to-h3 .label{grid-column:4/8}.skip-to [role=menuitem].skip-to-h4 .label{grid-column:5/8}.skip-to [role=menuitem].skip-to-h5 .label{grid-column:6/8}.skip-to [role=menuitem].skip-to-h6 .label{grid-column:7/8}.skip-to [role=menuitem].skip-to-h1.no-level .label{grid-column:1/8}.skip-to [role=menuitem].skip-to-h2.no-level .label{grid-column:2/8}.skip-to [role=menuitem].skip-to-h3.no-level .label{grid-column:3/8}.skip-to [role=menuitem].skip-to-h4.no-level .label{grid-column:4/8}.skip-to [role=menuitem].skip-to-h5.no-level .label{grid-column:5/8}.skip-to [role=menuitem].skip-to-h6.no-level .label{grid-column:6/8}.skip-to [role=menuitem].skip-to-nesting-level-1 .nesting{grid-column:1}.skip-to [role=menuitem].skip-to-nesting-level-2 .nesting{grid-column:2}.skip-to [role=menuitem].skip-to-nesting-level-3 .nesting{grid-column:3}.skip-to [role=menuitem].skip-to-nesting-level-0 .label{grid-column:1/8}.skip-to [role=menuitem].skip-to-nesting-level-1 .label{grid-column:2/8}.skip-to [role=menuitem].skip-to-nesting-level-2 .label{grid-column:3/8}.skip-to [role=menuitem].skip-to-nesting-level-3 .label{grid-column:4/8}.skip-to [role=menuitem].action .label,.skip-to [role=menuitem].no-items .label{grid-column:1/8}.skip-to [role=separator]{margin:1px 0 1px 0;padding:3px;display:block;width:auto;font-weight:700;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:$menuTextColor;background-color:$menuBackgroundColor;color:$menuTextColor;z-index:100000!important}.skip-to [role=separator] .mofn{font-weight:400;font-size:85%}.skip-to [role=separator]:first-child{border-radius:5px 5px 0 0}.skip-to [role=menuitem].last{border-radius:0 0 5px 5px}.skip-to.focus{display:block}.skip-to button:focus,.skip-to button:hover{background-color:$menuBackgroundColor;color:$menuTextColor;outline:0}.skip-to button:focus{padding:6px 7px 5px 7px;border-width:0 2px 2px 2px;border-color:$focusBorderColor}.skip-to [role=menuitem]:focus{padding:1px;border-width:2px;border-style:solid;border-color:$focusBorderColor;background-color:$menuitemFocusBackgroundColor;color:$menuitemFocusTextColor;outline:0}.skip-to [role=menuitem]:focus .label,.skip-to [role=menuitem]:focus .level{background-color:$menuitemFocusBackgroundColor;color:$menuitemFocusTextColor}',
+
+ //
+ // Functions related to configuring the features
+ // of skipTo
+ //
+ isNotEmptyString: function (str) {
+ return (
+ typeof str === 'string' && str.length && str.trim() && str !== ' '
+ );
+ },
+ isEmptyString: function (str) {
+ return typeof str !== 'string' || (str.length === 0 && !str.trim());
+ },
+ init: function (config) {
+ let node;
+ let buttonVisibleLabel;
+ let buttonAriaLabel;
+
+ // Check if skipto is already loaded
+
+ if (document.querySelector('style#' + this.skipToId)) {
+ return;
+ }
- /*
- * debug.js
- *
- * Usage
- * import DebugLogging from './debug.js';
- * const debug = new DebugLogging('myLabel', true); // e.g. 'myModule'
- * ...
- * if (debug.flag) debug.log('myMessage');
- *
- * Notes
- * new DebugLogging() - calling the constructor with no arguments results
- * in debug.flag set to false and debug.label set to 'debug';
- * constructor accepts 0, 1 or 2 arguments in any order
- * @param flag [optional] {boolean} - sets debug.flag
- * @param label [optional] {string} - sets debug.label
- * Properties
- * debug.flag {boolean} allows you to switch debug logging on or off;
- * default value is false
- * debug.label {string} rendered as a prefix to each log message;
- * default value is 'debug'
- * Methods
- * debug.log calls console.log with label prefix and message
- * @param message {object} - console.log calls toString()
- * @param spaceAbove [optional] {boolean}
- *
- * debug.tag outputs tagName and textContent of DOM element
- * @param node {DOM node reference} - usually an HTMLElement
- * @param spaceAbove [optional] {boolean}
- *
- * debug.separator outputs only debug.label and a series of hyphens
- * @param spaceAbove [optional] {boolean}
- */
-
- class DebugLogging {
- constructor (...args) {
- // Default values for cases where fewer than two arguments are provided
- this._flag = false;
- this._label = 'debug';
-
- // The constructor may be called with zero, one or two arguments. If two
- // arguments, they can be in any order: one is assumed to be the boolean
- // value for '_flag' and the other one the string value for '_label'.
- for (const [index, arg] of args.entries()) {
- if (index < 2) {
- switch (typeof arg) {
- case 'boolean':
- this._flag = arg;
- break;
- case 'string':
- this._label = arg;
- break;
- }
+ let attachElement = document.body;
+ if (config) {
+ this.setUpConfig(config);
+ }
+ if (typeof this.config.attachElement === 'string') {
+ node = document.querySelector(this.config.attachElement);
+ if (node && node.nodeType === Node.ELEMENT_NODE) {
+ attachElement = node;
}
}
- }
-
- get flag () { return this._flag; }
-
- set flag (value) {
- if (typeof value === 'boolean') {
- this._flag = value;
- }
- }
-
- get label () { return this._label; }
-
- set label (value) {
- if (typeof value === 'string') {
- this._label = value;
- }
- }
-
- log (message, spaceAbove) {
- const newline = spaceAbove ? '\n' : '';
- console.log(`${newline}[${this._label}] ${message}`);
- }
-
- tag (node, spaceAbove) {
- if (node && node.tagName) {
- const text = node.textContent.trim().replace(/\s+/g, ' ');
- this.log(`[${node.tagName}]: ${text.substring(0, 40)}`, spaceAbove);
- }
- }
-
- separator (spaceAbove) {
- this.log('-----------------------------', spaceAbove);
- }
-
- }
-
- /* style.js */
-
- /* Constants */
- const debug$5 = new DebugLogging('style', false);
- debug$5.flag = false;
-
- const styleTemplate = document.createElement('template');
- styleTemplate.innerHTML = `
-
-`;
-
- /*
- * @function getTheme
- *
- * @desc Returns
- *
- * @param {Object} colorThemes - Javascript object with keyed color themes
- * @param {String} colorTheme - A string identifying a color theme
- *
- * @returns {Object} see @desc
- */
- function getTheme(colorThemes, colorTheme) {
- if (typeof colorThemes[colorTheme] === 'object') {
- return colorThemes[colorTheme];
- }
- // if no theme defined, use urlSelectors
- let hostnameMatch = '';
- let pathnameMatch = '';
- let hostandpathnameMatch = '';
-
- const locationURL = new URL(location.href);
- const hostname = locationURL.hostname;
- const pathname = location.pathname;
-
- for (let item in colorThemes) {
- const hostnameSelector = colorThemes[item].hostnameSelector;
- const pathnameSelector = colorThemes[item].pathnameSelector;
- let hostnameFlag = false;
- let pathnameFlag = false;
-
-
- if (hostnameSelector) {
- if (hostname.indexOf(hostnameSelector) >= 0) {
- if (!hostnameMatch ||
- (colorThemes[hostnameMatch].hostnameSelector.length < hostnameSelector.length)) {
- hostnameMatch = item;
- hostnameFlag = true;
- pathnameMatch = '';
- }
- else {
- // if the same hostname is used in another theme, set the hostnameFlas in case the pathname
- // matches
- if (colorThemes[hostnameMatch].hostnameSelector.length === hostnameSelector.length) {
- hostnameFlag = true;
- }
+ this.addCSSColors();
+ this.renderStyleElement(this.defaultCSS);
+ var elem = this.config.containerElement.toLowerCase().trim();
+ if (!this.isNotEmptyString(elem)) {
+ elem = 'div';
+ }
+ this.domNode = document.createElement(elem);
+ this.domNode.classList.add('skip-to');
+ if (this.isNotEmptyString(this.config.customClass)) {
+ this.domNode.classList.add(this.config.customClass);
+ }
+ if (this.isNotEmptyString(this.config.containerRole)) {
+ this.domNode.setAttribute('role', this.config.containerRole);
+ }
+ var displayOption = this.config.displayOption;
+ if (typeof displayOption === 'string') {
+ displayOption = displayOption.trim().toLowerCase();
+ if (displayOption.length) {
+ switch (this.config.displayOption) {
+ case 'fixed':
+ this.domNode.classList.add('fixed');
+ break;
+ case 'onfocus': // Legacy option
+ case 'popup':
+ this.domNode.classList.add('popup');
+ break;
+ default:
+ break;
}
}
}
- if (pathnameSelector) {
- if (pathname.indexOf(pathnameSelector) >= 0) {
- if (!pathnameMatch ||
- (colorThemes[pathnameMatch].pathnameSelector.length < pathnameSelector.length)) {
- pathnameMatch = item;
- pathnameFlag = true;
- }
- }
+ // Place skip to at the beginning of the document
+ if (attachElement.firstElementChild) {
+ attachElement.insertBefore(
+ this.domNode,
+ attachElement.firstElementChild
+ );
+ } else {
+ attachElement.appendChild(this.domNode);
}
- if (hostnameFlag && pathnameFlag) {
- hostandpathnameMatch = item;
+ // Menu button
+ [buttonVisibleLabel, buttonAriaLabel] = this.getBrowserSpecificShortcut();
+
+ this.buttonNode = document.createElement('button');
+ this.buttonNode.textContent = buttonVisibleLabel;
+ this.buttonNode.setAttribute('aria-label', buttonAriaLabel);
+ this.buttonNode.setAttribute('aria-haspopup', 'true');
+ this.buttonNode.setAttribute('aria-expanded', 'false');
+ this.buttonNode.setAttribute('aria-controls', this.skipToMenuId);
+
+ this.buttonNode.addEventListener(
+ 'keydown',
+ this.handleButtonKeydown.bind(this)
+ );
+ this.buttonNode.addEventListener(
+ 'click',
+ this.handleButtonClick.bind(this)
+ );
+
+ this.domNode.appendChild(this.buttonNode);
+
+ this.menuNode = document.createElement('div');
+ this.menuNode.setAttribute('role', 'menu');
+ this.menuNode.setAttribute('aria-busy', 'true');
+ this.menuNode.setAttribute('id', this.skipToMenuId);
+
+ this.domNode.appendChild(this.menuNode);
+ this.domNode.addEventListener('focusin', this.handleFocusin.bind(this));
+ this.domNode.addEventListener('focusout', this.handleFocusout.bind(this));
+ window.addEventListener(
+ 'pointerdown',
+ this.handleBackgroundPointerdown.bind(this),
+ true
+ );
+
+ if (this.usesAltKey || this.usesOptionKey) {
+ document.addEventListener(
+ 'keydown',
+ this.handleDocumentKeydown.bind(this)
+ );
}
- }
+ },
- if (hostandpathnameMatch) {
- return colorThemes[hostandpathnameMatch];
- }
- else {
- if (hostnameMatch) {
- return colorThemes[hostnameMatch];
- } else {
- if (pathnameMatch) {
- return colorThemes[pathnameMatch];
- }
+ updateStyle: function (stylePlaceholder, value, defaultValue) {
+ if (typeof value !== 'string' || value.length === 0) {
+ value = defaultValue;
}
- }
-
- // if no other theme is found use default theme
- return colorThemes['default'];
- }
-
- /*
- * @function updateStyle
- *
- * @desc
- *
- * @param
- *
- * @returns
- */
- function updateStyle(stylePlaceholder, configValue, themeValue, defaultValue) {
- let value = defaultValue;
- if (typeof configValue === 'string' && configValue) {
- value = configValue;
- } else {
- if (typeof themeValue === 'string' && themeValue) {
- value = themeValue;
- }
- }
-
- let cssContent = styleTemplate.innerHTML;
- let index1 = cssContent.indexOf(stylePlaceholder);
- let index2 = index1 + stylePlaceholder.length;
- while (index1 >= 0 && index2 < cssContent.length) {
- cssContent = cssContent.substring(0, index1) + value + cssContent.substring(index2);
- index1 = cssContent.indexOf(stylePlaceholder, index2);
- index2 = index1 + stylePlaceholder.length;
- }
- styleTemplate.innerHTML = cssContent;
- }
-
- /*
- * @function addCSSColors
- *
- * @desc Updates the styling information in the attached
- * stylesheet to use the configured or default colors
- *
- * @param {Object} colorThemes - Object with theme information
- * @param {Object} config - Configuration information object
- */
- function addCSSColors (colorThemes, config) {
- const theme = getTheme(colorThemes, config.colorTheme);
- const defaultTheme = getTheme(colorThemes, 'default');
-
- // Check for display option in theme
- if ((typeof theme.displayOption === 'string') &&
- ('fixed popup static'.indexOf(theme.displayOption.toLowerCase())>= 0)) {
- config.displayOption = theme.displayOption;
- }
-
- updateStyle('$fontFamily', config.fontFamily, theme.fontFamily, defaultTheme.fontFamily);
- updateStyle('$fontSize', config.fontSize, theme.fontSize, defaultTheme.fontSize);
-
- updateStyle('$positionLeft', config.positionLeft, theme.positionLeft, defaultTheme.positionLeft);
- updateStyle('$mediaBreakPoint', config.mediaBreakPoint, theme.mediaBreakPoint, defaultTheme.mediaBreakPoint);
-
- updateStyle('$menuTextColor', config.menuTextColor, theme.menuTextColor, defaultTheme.menuTextColor);
- updateStyle('$menuBackgroundColor', config.menuBackgroundColor, theme.menuBackgroundColor, defaultTheme.menuBackgroundColor);
-
- updateStyle('$menuitemFocusTextColor', config.menuitemFocusTextColor, theme.menuitemFocusTextColor, defaultTheme.menuitemFocusTextColor);
- updateStyle('$menuitemFocusBackgroundColor', config.menuitemFocusBackgroundColor, theme.menuitemFocusBackgroundColor, defaultTheme.menuitemFocusBackgroundColor);
-
- updateStyle('$focusBorderColor', config.focusBorderColor, theme.focusBorderColor, defaultTheme.focusBorderColor);
-
- updateStyle('$buttonTextColor', config.buttonTextColor, theme.buttonTextColor, defaultTheme.buttonTextColor);
- updateStyle('$buttonBackgroundColor', config.buttonBackgroundColor, theme.buttonBackgroundColor, defaultTheme.buttonBackgroundColor);
-
- updateStyle('$zIndex', config.zIndex, theme.zIndex, defaultTheme.zIndex);
-
- }
-
- /*
- * @function enderStyleElement
- *
- * @desc Updates the style sheet template and then attaches it to the document
- *
- * @param {Object} colorThemes - Object with theme information
- * @param {Object} config - Configuration information object
- * @param {String} skipYToStyleId - Id used for the skipto container element
- */
- function renderStyleElement (colorThemes, config, skipToId) {
- styleTemplate.innerHTML = styleTemplate.innerHTML.replaceAll('$skipToId', '#' + skipToId);
- addCSSColors(colorThemes, config);
- const styleNode = styleTemplate.content.cloneNode(true);
- const headNode = document.getElementsByTagName('head')[0];
- headNode.appendChild(styleNode);
- }
-
- /* utils.js */
-
- /* Constants */
- const debug$4 = new DebugLogging('Utils', false);
- debug$4.flag = false;
-
-
- /*
- * @function getAttributeValue
- *
- * @desc Return attribute value if present on element,
- * otherwise return empty string.
- *
- * @returns {String} see @desc
- */
- function getAttributeValue (element, attribute) {
- let value = element.getAttribute(attribute);
- return (value === null) ? '' : normalize(value);
- }
-
- /*
- * @function normalize
- *
- * @desc Trim leading and trailing whitespace and condense all
- * internal sequences of whitespace to a single space. Adapted from
- * Mozilla documentation on String.prototype.trim polyfill. Handles
- * BOM and NBSP characters.
- *
- * @return {String} see @desc
- */
- function normalize (s) {
- let rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;
- return s.replace(rtrim, '').replace(/\s+/g, ' ');
- }
-
- /**
- * @fuction isNotEmptyString
- *
- * @desc Returns true if the string has content, otherwise false
- *
- * @param {Boolean} see @desc
- */
- function isNotEmptyString (str) {
- return (typeof str === 'string') && str.length && str.trim() && str !== " ";
- }
-
- /**
- * @fuction isVisible
- *
- * @desc Returns true if the element is visible in the graphical rendering
- *
- * @param {node} elem - DOM element node of a labelable element
- */
- function isVisible (element) {
-
- function isDisplayNone(el) {
- if (!el || (el.nodeType !== Node.ELEMENT_NODE)) {
- return false;
- }
-
- if (el.hasAttribute('hidden')) {
- return true;
- }
-
- const style = window.getComputedStyle(el, null);
- const display = style.getPropertyValue("display");
- if (display === 'none') {
- return true;
- }
-
- // check ancestors for display none
- if (el.parentNode) {
- return isDisplayNone(el.parentNode);
- }
-
- return false;
- }
-
- const computedStyle = window.getComputedStyle(element);
- let visibility = computedStyle.getPropertyValue('visibility');
- if ((visibility === 'hidden') || (visibility === 'collapse')) {
- return false;
- }
-
- return !isDisplayNone(element);
- }
-
- /*
- * namefrom.js
- */
-
- /* constants */
-
- const debug$3 = new DebugLogging('nameFrom', false);
- debug$3.flag = false;
-
- //
- // LOW-LEVEL HELPER FUNCTIONS (NOT EXPORTED)
-
- /*
- * @function isDisplayNone
- *
- * @desc Returns true if the element or parent element has set the CSS
- * display property to none or has the hidden attribute,
- * otherwise false
- *
- * @param {Object} node - a DOM node
- *
- * @returns {Boolean} see @desc
- */
-
- function isDisplayNone (node) {
-
- if (!node) {
- return false;
- }
-
- if (node.nodeType === Node.TEXT_NODE) {
- node = node.parentNode;
- }
-
- if (node.nodeType === Node.ELEMENT_NODE) {
-
- if (node.hasAttribute('hidden')) {
- return true;
- }
-
- // aria-hidden attribute with the value "true" is an same as
- // setting the hidden attribute for name calcuation
- if (node.hasAttribute('aria-hidden')) {
- if (node.getAttribute('aria-hidden').toLowerCase() === 'true') {
- return true;
- }
+ let index1 = this.defaultCSS.indexOf(stylePlaceholder);
+ let index2 = index1 + stylePlaceholder.length;
+ while (index1 >= 0 && index2 < this.defaultCSS.length) {
+ this.defaultCSS =
+ this.defaultCSS.substring(0, index1) +
+ value +
+ this.defaultCSS.substring(index2);
+ index1 = this.defaultCSS.indexOf(stylePlaceholder, index2);
+ index2 = index1 + stylePlaceholder.length;
}
-
- const style = window.getComputedStyle(node, null);
-
- const display = style.getPropertyValue("display");
-
- if (display) {
- return display === 'none';
- }
- }
- return false;
- }
-
- /*
- * @function isVisibilityHidden
- *
- * @desc Returns true if the node (or it's parrent) has the CSS visibility
- * property set to "hidden" or "collapse", otherwise false
- *
- * @param {Object} node - DOM node
- *
- * @return see @desc
- */
-
- function isVisibilityHidden(node) {
-
- if (!node) {
- return false;
- }
-
- if (node.nodeType === Node.TEXT_NODE) {
- node = node.parentNode;
- }
-
- if (node.nodeType === Node.ELEMENT_NODE) {
- const style = window.getComputedStyle(node, null);
-
- const visibility = style.getPropertyValue("visibility");
- if (visibility) {
- return (visibility === 'hidden') || (visibility === 'collapse');
- }
- }
- return false;
- }
-
- /*
- * @function isAriaHiddenFalse
- *
- * @desc Returns true if the node has the aria-hidden property set to
- * "false", otherwise false.
- * NOTE: This function is important in the accessible namce
- * calculation, since content hidden with a CSS technique
- * can be included in the accessible name calculation when
- * aria-hidden is set to false
- *
- * @param {Object} node - DOM node
- *
- * @return see @desc
- */
-
- function isAriaHIddenFalse(node) {
-
- if (!node) {
- return false;
- }
-
- if (node.nodeType === Node.TEXT_NODE) {
- node = node.parentNode;
- }
-
- if (node.nodeType === Node.ELEMENT_NODE) {
- return (node.hasAttribute('aria-hidden') &&
- (node.getAttribute('aria-hidden').toLowerCase() === 'false'));
- }
-
- return false;
- }
-
- /*
- * @function includeContentInName
- *
- * @desc Checks the CSS display and hidden properties, and
- * the aria-hidden property to see if the content
- * should be included in the accessible name
- * calculation. Returns true if it should be
- * included, otherwise false
- *
- * @param {Object} node - DOM node
- *
- * @return see @desc
- */
-
- function includeContentInName(node) {
- const flag = isAriaHIddenFalse(node) ||
- (!isVisibilityHidden(node) &&
- !isDisplayNone(node));
- return flag;
- }
-
- /*
- * @function getNodeContents
- *
- * @desc Recursively process element and text nodes by aggregating
- * their text values for an ARIA accessible name or description
- * calculation.
- *
- * NOTE: This includes special handling of elements with 'alt'
- * text and embedded controls.
- *
- * @param {Object} node - A DOM node
- *
- * @return {String} The text content for an accessible name or description
- */
- function getNodeContents (node) {
- let contents = '';
- let nc;
- let arr = [];
-
- switch (node.nodeType) {
- case Node.ELEMENT_NODE:
- // If aria-label is present, node recursion stops and
- // aria-label value is returned
- if (node.hasAttribute('aria-label')) {
- if (includeContentInName(node)) {
- contents = node.getAttribute('aria-label');
- }
+ },
+ addCSSColors: function () {
+ let theme = this.colorThemes['default'];
+ if (typeof this.colorThemes[this.config.colorTheme] === 'object') {
+ theme = this.colorThemes[this.config.colorTheme];
+ }
+ this.updateStyle('$fontFamily', this.config.fontFamily, theme.fontFamily);
+ this.updateStyle('$fontSize', this.config.fontSize, theme.fontSize);
+
+ this.updateStyle(
+ '$positionLeft',
+ this.config.positionLeft,
+ theme.positionLeft
+ );
+
+ this.updateStyle(
+ '$menuTextColor',
+ this.config.menuTextColor,
+ theme.menuTextColor
+ );
+ this.updateStyle(
+ '$menuBackgroundColor',
+ this.config.menuBackgroundColor,
+ theme.menuBackgroundColor
+ );
+
+ this.updateStyle(
+ '$menuitemFocusTextColor',
+ this.config.menuitemFocusTextColor,
+ theme.menuitemFocusTextColor
+ );
+ this.updateStyle(
+ '$menuitemFocusBackgroundColor',
+ this.config.menuitemFocusBackgroundColor,
+ theme.menuitemFocusBackgroundColor
+ );
+
+ this.updateStyle(
+ '$focusBorderColor',
+ this.config.focusBorderColor,
+ theme.focusBorderColor
+ );
+
+ this.updateStyle(
+ '$buttonTextColor',
+ this.config.buttonTextColor,
+ theme.buttonTextColor
+ );
+ this.updateStyle(
+ '$buttonBackgroundColor',
+ this.config.buttonBackgroundColor,
+ theme.buttonBackgroundColor
+ );
+ },
+
+ getBrowserSpecificShortcut: function () {
+ const platform = navigator.platform.toLowerCase();
+ const userAgent = navigator.userAgent.toLowerCase();
+
+ const hasWin = platform.indexOf('win') >= 0;
+ const hasMac = platform.indexOf('mac') >= 0;
+ const hasLinux =
+ platform.indexOf('linux') >= 0 || platform.indexOf('bsd') >= 0;
+ const hasAndroid = userAgent.indexOf('android') >= 0;
+
+ this.usesAltKey = hasWin || (hasLinux && !hasAndroid);
+ this.usesOptionKey = hasMac;
+
+ let label = this.config.buttonLabel;
+ let ariaLabel = this.config.buttonLabel;
+ let buttonShortcut;
+
+ // Check to make sure a shortcut key is defined
+ if (this.config.altShortcut && this.config.optionShortcut) {
+ if (this.usesAltKey || this.usesOptionKey) {
+ buttonShortcut = this.config.buttonShortcut.replace(
+ '$key',
+ this.config.altShortcut
+ );
}
- else {
- if (node instanceof HTMLSlotElement) {
- // if no slotted elements, check for default slotted content
- const assignedNodes = node.assignedNodes().length ? node.assignedNodes() : node.assignedNodes({ flatten: true });
- assignedNodes.forEach( assignedNode => {
- nc = getNodeContents(assignedNode);
- if (nc.length) arr.push(nc);
- });
- contents = (arr.length) ? arr.join(' ') : '';
- } else {
- if (couldHaveAltText(node) && includeContentInName(node)) {
- contents = getAttributeValue(node, 'alt');
- }
- else {
- if (node.hasChildNodes()) {
- let children = Array.from(node.childNodes);
- children.forEach( child => {
- nc = getNodeContents(child);
- if (nc.length) arr.push(nc);
- });
- contents = (arr.length) ? arr.join(' ') : '';
- }
- }
- // For all branches of the ELEMENT_NODE case...
- }
+ if (this.usesAltKey) {
+ buttonShortcut = buttonShortcut.replace(
+ '$modifier',
+ this.config.altLabel
+ );
+ label = label + buttonShortcut;
+ ariaLabel = this.config.altButtonAriaLabel.replace(
+ '$key',
+ this.config.altShortcut
+ );
}
- contents = addCssGeneratedContent(node, contents);
- break;
- case Node.TEXT_NODE:
- if (includeContentInName(node)) {
- contents = normalize(node.textContent);
+ if (this.usesOptionKey) {
+ buttonShortcut = buttonShortcut.replace(
+ '$modifier',
+ this.config.optionLabel
+ );
+ label = label + buttonShortcut;
+ ariaLabel = this.config.optionButtonAriaLabel.replace(
+ '$key',
+ this.config.altShortcut
+ );
}
- break;
- }
-
- return contents;
- }
-
- /*
- * @function couldHaveAltText
- *
- * @desc Based on HTML5 specification, returns true if
- * the element could have an 'alt' attribute,
- * otherwise false.
- *
- * @param {Object} element - DOM eleemnt node
- *
- * @return {Boolean} see @desc
- */
- function couldHaveAltText (element) {
- let tagName = element.tagName.toLowerCase();
-
- switch (tagName) {
- case 'img':
- case 'area':
- return true;
- case 'input':
- return (element.type && element.type === 'image');
- }
-
- return false;
- }
-
- /*
- * @function addCssGeneratedContent
- *
- * @desc Adds CSS-generated content for pseudo-elements
- * :before and :after. According to the CSS spec, test that content
- * value is other than the default computed value of 'none'.
- *
- * Note: Even if an author specifies content: 'none', because browsers
- * add the double-quote character to the beginning and end of
- * computed string values, the result cannot and will not be
- * equal to 'none'.
- *
- * @param {Object} element - DOM node element
- * @param {String} contents - Text content for DOM node
- *
- * @returns {String} see @desc
- *
- */
- function addCssGeneratedContent (element, contents) {
-
- let result = contents,
- prefix = getComputedStyle(element, ':before').content,
- suffix = getComputedStyle(element, ':after').content;
-
- if (prefix !== 'none') {
- result = prefix.replaceAll('"', '') + result;
- }
- if (suffix !== 'none') {
- result = result + suffix.replaceAll('"', '');
- }
-
- return result;
- }
-
- /* accName.js */
-
- /* Constants */
- const debug$2 = new DebugLogging('accName', false);
- debug$2.flag = false;
-
- /**
- * @fuction getAccessibleName
- *
- * @desc Returns the accessible name for an heading or landamrk
- *
- * @paramn {Object} dom - Document of the current element
- * @param {node} element - DOM element node for either a heading or
- * landmark
- * @param {Boolean} fromContent - if true will compute name from content
- *
- * @return {String} The accessible name for the landmark or heading element
- */
-
- function getAccessibleName (doc, element, fromContent=false) {
- let accName = '';
-
- accName = nameFromAttributeIdRefs(doc, element, 'aria-labelledby');
-
- if (accName === '' && element.hasAttribute('aria-label')) {
- accName = element.getAttribute('aria-label').trim();
- }
-
- if (accName === '' && fromContent) {
- accName = getNodeContents(element);
- }
-
- if (accName === '' && element.title.trim() !== '') {
- accName = element.title.trim();
- }
-
- return accName;
- }
-
- /*
- * @function nameFromAttributeIdRefs
- *
- * @desc Get the value of attrName on element (a space-
- * separated list of IDREFs), visit each referenced element in the order it
- * appears in the list and obtain its accessible name (skipping recursive
- * aria-labelledby or aria-describedby calculations), and return an object
- * with name property set to a string that is a space-separated concatena-
- * tion of those results if any, otherwise return empty string.
- *
- * @param {Object} doc - Browser document object
- * @param {Object} element - DOM element node
- * @param {String} attribute - Attribute name (e.g. "aria-labelledby", "aria-describedby",
- * or "aria-errormessage")
- *
- * @returns {String} see @desc
- */
- function nameFromAttributeIdRefs (doc, element, attribute) {
- const value = getAttributeValue(element, attribute);
- const arr = [];
-
- if (value.length) {
- const idRefs = value.split(' ');
-
- for (let i = 0; i < idRefs.length; i++) {
- const refElement = doc.getElementById(idRefs[i]);
- if (refElement) {
- const accName = getNodeContents(refElement);
- if (accName && accName.length) arr.push(accName);
+ }
+ return [label, ariaLabel];
+ },
+ setUpConfig: function (appConfig) {
+ let localConfig = this.config,
+ name,
+ appConfigSettings =
+ typeof appConfig.settings !== 'undefined'
+ ? appConfig.settings.skipTo
+ : {};
+ for (name in appConfigSettings) {
+ //overwrite values of our local config, based on the external config
+ if (
+ typeof localConfig[name] !== 'undefined' &&
+ ((typeof appConfigSettings[name] === 'string' &&
+ appConfigSettings[name].length > 0) ||
+ typeof appConfigSettings[name] === 'boolean')
+ ) {
+ localConfig[name] = appConfigSettings[name];
+ } else {
+ throw new Error(
+ '** SkipTo Problem with user configuration option "' + name + '".'
+ );
}
}
- }
-
- if (arr.length) {
- return arr.join(' ');
- }
-
- return '';
- }
-
- /* landmarksHeadings.js */
-
- /* Constants */
- const debug$1 = new DebugLogging('landmarksHeadings', false);
- debug$1.flag = false;
-
- const skipableElements = [
- 'base',
- 'content',
- 'frame',
- 'iframe',
- 'input[type=hidden]',
- 'link',
- 'meta',
- 'noscript',
- 'script',
- 'style',
- 'template',
- 'shadow',
- 'title'
- ];
-
- const allowedLandmarkSelectors = [
- 'banner',
- 'complementary',
- 'contentinfo',
- 'form',
- 'main',
- 'navigation',
- 'region',
- 'search'
- ];
-
- const higherLevelElements = [
- 'article',
- 'aside',
- 'footer',
- 'header',
- 'main',
- 'nav',
- 'region',
- 'section'
- ];
-
-
- let idIndex = 0;
-
- /*
- * @function getSkipToIdIndex
- *
- * @desc Returns the current skipto index used for generating
- * id for target elements
- *
- * @returns {Number} see @desc
- */
- function getSkipToIdIndex () {
- return idIndex;
- }
-
- /*
- * @function incSkipToIdIndex
- *
- * @desc Adds one to the skipto index
- */
- function incSkipToIdIndex () {
- idIndex += 1;
- }
-
- /*
- * @function isSkipableElement
- *
- * @desc Returns true if the element is skipable, otherwise false
- *
- * @param {Object} element - DOM element node
- *
- * @returns {Boolean} see @desc
- */
- function isSkipableElement(element) {
- const tagName = element.tagName.toLowerCase();
- const type = element.hasAttribute('type') ? element.getAttribute('type') : '';
- const elemSelector = (tagName === 'input') && type.length ?
- `${tagName}[type=${type}]` :
- tagName;
- return skipableElements.includes(elemSelector);
- }
-
- /*
- * @function isCustomElement
- *
- * @desc Reuturns true if the element is a custom element, otherwise
- * false
- *
- * @param {Object} element - DOM element node
- *
- * @returns {Boolean} see @desc
- */
- function isCustomElement(element) {
- return element.tagName.indexOf('-') >= 0;
- }
-
- /*
- * @function sSlotElement
- *
- * @desc Reuturns true if the element is a slot element, otherwise
- * false
- *
- * @param {Object} element - DOM element node
- *
- * @returns {Boolean} see @desc
- */
- function isSlotElement(node) {
- return (node instanceof HTMLSlotElement);
- }
-
- /**
- * @function isTopLevel
- *
- * @desc Tests the node to see if it is in the content of any other
- * elements with default landmark roles or is the descendant
- * of an element with a defined landmark role
- *
- * @param {Object} node - Element node from a berowser DOM
- *
- * @reutrn {Boolean} Returns true if top level landmark, otherwise false
- */
-
- function isTopLevel (node) {
- node = node && node.parentNode;
- while (node && (node.nodeType === Node.ELEMENT_NODE)) {
- const tagName = node.tagName.toLowerCase();
- let role = node.getAttribute('role');
- if (role) {
- role = role.toLowerCase();
- }
-
- if (higherLevelElements.includes(tagName) ||
- allowedLandmarkSelectors.includes(role)) {
- return false;
- }
- node = node.parentNode;
- }
- return true;
- }
-
- /*
- * @function checkForLandmark
- *
- * @desc Re=trns the lamdnark name if a landmark, otherwise an
- * empty string
- *
- * @param {Object} element - DOM element node
- *
- * @returns {String} see @desc
- */
- function checkForLandmark (element) {
- if (element.hasAttribute('role')) {
- const role = element.getAttribute('role').toLowerCase();
- if (allowedLandmarkSelectors.indexOf(role) >= 0) {
- return role;
- }
- } else {
- const tagName = element.tagName.toLowerCase();
+ },
+ renderStyleElement: function (cssString) {
+ const styleNode = document.createElement('style');
+ const headNode = document.getElementsByTagName('head')[0];
+ const css = document.createTextNode(cssString);
+
+ styleNode.setAttribute('type', 'text/css');
+ // ID is used to test whether skipto is already loaded
+ styleNode.id = this.skipToId;
+ styleNode.appendChild(css);
+ headNode.appendChild(styleNode);
+ },
+
+ //
+ // Functions related to creating and populating the
+ // the popup menu
+ //
+
+ getFirstChar: function (menuitem) {
+ const label = menuitem.querySelector('.label');
+ if (label && this.isNotEmptyString(label.textContent)) {
+ return label.textContent.trim()[0].toLowerCase();
+ }
+ return '';
+ },
- switch (tagName) {
- case 'aside':
- return 'complementary';
+ getHeadingLevelFromAttribute: function (menuitem) {
+ if (menuitem.hasAttribute('data-level')) {
+ return menuitem.getAttribute('data-level');
+ }
+ return '';
+ },
+
+ updateKeyboardShortCuts: function () {
+ let mi;
+ this.firstChars = [];
+ this.headingLevels = [];
+
+ for (let i = 0; i < this.menuitemNodes.length; i += 1) {
+ mi = this.menuitemNodes[i];
+ this.firstChars.push(this.getFirstChar(mi));
+ this.headingLevels.push(this.getHeadingLevelFromAttribute(mi));
+ }
+ },
- case 'main':
- return 'main';
+ updateMenuitems: function () {
+ let menuitemNodes = this.menuNode.querySelectorAll('[role=menuitem');
- case 'nav':
- return 'navigation';
+ this.menuitemNodes = [];
+ for (let i = 0; i < menuitemNodes.length; i += 1) {
+ this.menuitemNodes.push(menuitemNodes[i]);
+ }
- case 'header':
- if (isTopLevel(element)) {
- return 'banner';
- }
- break;
+ this.firstMenuitem = this.menuitemNodes[0];
+ this.lastMenuitem = this.menuitemNodes[this.menuitemNodes.length - 1];
+ this.lastMenuitem.classList.add('last');
+ this.updateKeyboardShortCuts();
+ },
- case 'footer':
- if (isTopLevel(element)) {
- return 'contentinfo';
- }
- break;
+ renderMenuitemToGroup: function (groupNode, mi) {
+ let tagNode, tagNodeChild, labelNode, nestingNode;
- case 'section':
- // Sections need an accessible name for be considered a "region" landmark
- if (element.hasAttribute('aria-label') || element.hasAttribute('aria-labelledby')) {
- return 'region';
- }
- break;
+ let menuitemNode = document.createElement('div');
+ menuitemNode.setAttribute('role', 'menuitem');
+ menuitemNode.classList.add(mi.class);
+ if (this.isNotEmptyString(mi.tagName)) {
+ menuitemNode.classList.add('skip-to-' + mi.tagName.toLowerCase());
}
- }
- return '';
- }
-
-
- /**
- * @function queryDOMForSkipToId
- *
- * @desc Returns DOM node associated with the id, if id not found returns null
- *
- * @param {String} targetId - dom node element to attach button and menu
- *
- * @returns (Object) @desc
- */
- function queryDOMForSkipToId (targetId) {
- function transverseDOMForSkipToId(startingNode) {
- var targetNode = null;
- for (let node = startingNode.firstChild; node !== null; node = node.nextSibling ) {
- if (node.nodeType === Node.ELEMENT_NODE) {
- if (node.getAttribute('data-skip-to-id') === targetId) {
- return node;
- }
- if (!isSkipableElement(node)) {
- // check for slotted content
- if (isSlotElement(node)) {
- // if no slotted elements, check for default slotted content
- const assignedNodes = node.assignedNodes().length ?
- node.assignedNodes() :
- node.assignedNodes({ flatten: true });
- for (let i = 0; i < assignedNodes.length; i += 1) {
- const assignedNode = assignedNodes[i];
- if (assignedNode.nodeType === Node.ELEMENT_NODE) {
- if (assignedNode.getAttribute('data-skip-to-id') === targetId) {
- return assignedNode;
- }
- targetNode = transverseDOMForSkipToId(assignedNode);
- if (targetNode) {
- return targetNode;
- }
- }
- }
- } else {
- // check for custom elements
- if (isCustomElement(node)) {
- if (node.shadowRoot) {
- targetNode = transverseDOMForSkipToId(node.shadowRoot);
- if (targetNode) {
- return targetNode;
- }
- }
- } else {
- targetNode = transverseDOMForSkipToId(node);
- if (targetNode) {
- return targetNode;
- }
- }
- }
- }
- } // end if
- } // end for
- return false;
- } // end function
- return transverseDOMForSkipToId(document.body);
- }
-
- /**
- * @function findVisibleElement
- *
- * @desc Returns the first isible decsendant DOM node that matches a set of element tag names
- *
- * @param {node} startingNode - dom node to start search for element
- * @param {Array} tagNames - Array of tag names
- *
- * @returns (node} Returns first descendmt element, if not found returns false
- */
- function findVisibleElement (startingNode, tagNames) {
-
- function transverseDOMForVisibleElement(startingNode, targetTagName) {
- var targetNode = null;
- for (let node = startingNode.firstChild; node !== null; node = node.nextSibling ) {
- if (node.nodeType === Node.ELEMENT_NODE) {
- if (!isSkipableElement(node)) {
- // check for slotted content
- if (isSlotElement(node)) {
- // if no slotted elements, check for default slotted content
- const assignedNodes = node.assignedNodes().length ?
- node.assignedNodes() :
- node.assignedNodes({ flatten: true });
- for (let i = 0; i < assignedNodes.length; i += 1) {
- const assignedNode = assignedNodes[i];
- if (assignedNode.nodeType === Node.ELEMENT_NODE) {
- const tagName = assignedNode.tagName.toLowerCase();
- if (tagName === targetTagName){
- if (isVisible(assignedNode)) {
- return assignedNode;
- }
- }
- targetNode = transverseDOMForVisibleElement(assignedNode, targetTagName);
- if (targetNode) {
- return targetNode;
- }
- }
- }
- } else {
- // check for custom elements
- if (isCustomElement(node)) {
- if (node.shadowRoot) {
- targetNode = transverseDOMForVisibleElement(node.shadowRoot, targetTagName);
- if (targetNode) {
- return targetNode;
- }
- }
- } else {
- const tagName = node.tagName.toLowerCase();
- if (tagName === targetTagName){
- if (isVisible(node)) {
- return node;
- }
- }
- targetNode = transverseDOMForVisibleElement(node, targetTagName);
- if (targetNode) {
- return targetNode;
- }
- }
- }
- }
- } // end if
- } // end for
- return false;
- } // end function
- let targetNode = false;
-
- // Go through the tag names one at a time
- for (let i = 0; i < tagNames.length; i += 1) {
- targetNode = transverseDOMForVisibleElement(startingNode, tagNames[i]);
- if (targetNode) {
- break;
- }
- }
- return targetNode ? targetNode : startingNode;
- }
-
- /*
- * @function skipToElement
- *
- * @desc Moves focus to the element identified by the memu item
- *
- * @param {Object} menutim - DOM element in the menu identifying the target element.
- */
- function skipToElement(menuitem) {
-
- let focusNode = false;
- let scrollNode = false;
- let elem;
-
- const searchSelectors = ['input', 'button', 'a'];
- const navigationSelectors = ['a', 'input', 'button'];
- const landmarkSelectors = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'section', 'article', 'p', 'li', 'a'];
-
- const isLandmark = menuitem.classList.contains('landmark');
- const isSearch = menuitem.classList.contains('skip-to-search');
- const isNav = menuitem.classList.contains('skip-to-nav');
-
- elem = queryDOMForSkipToId(menuitem.getAttribute('data-id'));
-
- if (elem) {
- if (isSearch) {
- focusNode = findVisibleElement(elem, searchSelectors);
- }
- if (isNav) {
- focusNode = findVisibleElement(elem, navigationSelectors);
- }
- if (focusNode && isVisible(focusNode)) {
- if (focusNode.tabIndex >= 0) {
- focusNode.focus();
- } else {
- focusNode.tabIndex = 0;
- focusNode.focus();
- focusNode.tabIndex = -1;
- }
- focusNode.scrollIntoView({block: 'center'});
+ menuitemNode.setAttribute('data-id', mi.dataId);
+ menuitemNode.tabIndex = -1;
+ if (this.isNotEmptyString(mi.ariaLabel)) {
+ menuitemNode.setAttribute('aria-label', mi.ariaLabel);
}
- else {
- if (isLandmark) {
- scrollNode = findVisibleElement(elem, landmarkSelectors);
- if (scrollNode) {
- elem = scrollNode;
- }
- }
- if (elem.tabIndex >= 0) {
- elem.focus();
- } else {
- elem.tabIndex = 0;
- elem.focus();
- elem.tabIndex = -1;
- }
- elem.scrollIntoView({block: 'center'});
- }
- }
- }
-
- /*
- * @function getHeadingTargets
- *
- * @desc Returns an array of heading tag names to include in menu
- * NOTE: It uses "includes" method to maximimze compatibility with
- * previous versions of SkipTo which used CSS selectors for
- * identifying targets.
- *
- * @param {String} targets - A space with the heading tags to inclucde
- *
- * @returns {Array} Array of heading element tag names to include in menu
- */
- function getHeadingTargets(targets) {
- let targetHeadings = [];
- ['h1','h2','h3','h4','h5','h6'].forEach( h => {
- if (targets.includes(h)) {
- targetHeadings.push(h);
- }
- });
- return targetHeadings;
- }
-
- /*
- * @function isMain
- *
- * @desc Returns true if the element is a main landamrk
- *
- * @param {Object} element - DOM element node
- *
- * @returns {Boolean} see @desc
- */
- function isMain (element) {
- const tagName = element.tagName.toLowerCase();
- const role = element.hasAttribute('role') ? element.getAttribute('role').toLowerCase() : '';
- return (tagName === 'main') || (role === 'main');
- }
-
- /*
- * @function queryDOMForLandmarksAndHeadings
- *
- * @desc Recursive function to return two arrays, one an array of the DOM element nodes for
- * landmarks and the other an array of DOM element ndoes for headings
- *
- * @param {Array} landamrkTargets - An array of strings representing landmark regions
- * @param {Array} headingTargets - An array of strings representing headings
- *
- * @returns {Array} @see @desc
- */
- function queryDOMForLandmarksAndHeadings (landmarkTargets, headingTargets) {
- let headingInfo = [];
- let landmarkInfo = [];
- let targetLandmarks = getLandmarkTargets(landmarkTargets.toLowerCase());
- let targetHeadings = getHeadingTargets(headingTargets.toLowerCase());
- let onlyInMain = headingTargets.includes('main');
-
- function transverseDOM(startingNode, doc, parentDoc=null, inMain = false) {
- for (let node = startingNode.firstChild; node !== null; node = node.nextSibling ) {
- if (node.nodeType === Node.ELEMENT_NODE) {
- const tagName = node.tagName.toLowerCase();
- if (targetLandmarks.indexOf(checkForLandmark(node)) >= 0) {
- landmarkInfo.push({ node: node, name: getAccessibleName(doc, node)});
- }
- if (targetHeadings.indexOf(tagName) >= 0) {
- if (!onlyInMain || inMain) {
- headingInfo.push({ node: node, name: getAccessibleName(doc, node, true)});
- }
- }
- if (isMain(node)) {
- inMain = true;
- }
-
- if (!isSkipableElement(node)) {
- // check for slotted content
- if (isSlotElement(node)) {
- // if no slotted elements, check for default slotted content
- const slotContent = node.assignedNodes().length > 0;
- const assignedNodes = slotContent ?
- node.assignedNodes() :
- node.assignedNodes({ flatten: true });
- const nameDoc = slotContent ?
- parentDoc :
- doc;
- for (let i = 0; i < assignedNodes.length; i += 1) {
- const assignedNode = assignedNodes[i];
- if (assignedNode.nodeType === Node.ELEMENT_NODE) {
- const tagName = assignedNodes[i].tagName.toLowerCase();
- if (targetLandmarks.indexOf(checkForLandmark(assignedNode)) >= 0) {
- landmarkInfo.push({ node: assignedNode, name: getAccessibleName(nameDoc, assignedNode)});
- }
-
- if (targetHeadings.indexOf(tagName) >= 0) {
- if (!onlyInMain || inMain) {
- headingInfo.push({ node: assignedNode, name: getAccessibleName(nameDoc, assignedNode, true)});
- }
- }
- if (slotContent) {
- transverseDOM(assignedNode, parentDoc, null, inMain);
- } else {
- transverseDOM(assignedNode, doc, parentDoc, inMain);
- }
- }
- }
- } else {
- // check for custom elements
- if (isCustomElement(node)) {
- if (node.shadowRoot) {
- transverseDOM(node.shadowRoot, node.shadowRoot, doc, inMain);
- }
- } else {
- transverseDOM(node, doc, parentDoc, inMain);
- }
- }
- }
- } // end if
- } // end for
- } // end function
-
- transverseDOM(document.body, document);
-
- // If no elements found when onlyInMain is set, try
- // to find any headings
- if ((headingInfo.length === 0) && onlyInMain) {
- onlyInMain = false;
- transverseDOM(document.body, document);
- }
-
- return [landmarkInfo, headingInfo];
- }
-
- /*
- * @function getLandmarksAndHeadings
- *
- * @desc Returns two arrays of of DOM node elements with, one for landmark regions
- * the other for headings with additional information needed to create
- * menuitems
- *
- * @param {Object} config - Object with configuration information
- *
- * @return see @desc
- */
-
- function getLandmarksAndHeadings (config) {
-
- let landmarkTargets = config.landmarks;
- if (typeof landmarkTargets !== 'string') {
- landmarkTargets = 'main search navigation';
- }
-
- let headingTargets = config.headings;
- // If targets undefined, use default settings
- if (typeof headingTargets !== 'string') {
- headingTargets = 'h1 h2';
- }
-
- const [landmarks, headings] = queryDOMForLandmarksAndHeadings(landmarkTargets, headingTargets);
-
- return [getLandmarks(config, landmarks), getHeadings(config, headings)];
- }
-
- /*
- * @function getHeadings
- *
- * @desc Returns an array of heading menu elements
- *
- * @param {Object} config - Object with configuration information
- * @param {Object} headings - Array of dome node elements that are headings
- *
- * @returns see @desc
- */
- function getHeadings (config, headings) {
- let dataId, level;
- let headingElementsArr = [];
-
- for (let i = 0, len = headings.length; i < len; i += 1) {
- let heading = headings[i];
- let role = heading.node.getAttribute('role');
- if ((typeof role === 'string') && (role === 'presentation')) continue;
- if (isVisible(heading.node) && isNotEmptyString(heading.node.innerHTML)) {
- if (heading.node.hasAttribute('data-skip-to-id')) {
- dataId = heading.node.getAttribute('data-skip-to-id');
- } else {
- dataId = getSkipToIdIndex();
- heading.node.setAttribute('data-skip-to-id', dataId);
- }
- level = heading.node.tagName.substring(1);
- const headingItem = {};
- headingItem.dataId = dataId.toString();
- headingItem.class = 'heading';
- headingItem.name = heading.name;
- headingItem.ariaLabel = headingItem.name + ', ';
- headingItem.ariaLabel += config.headingLevelLabel + ' ' + level;
- headingItem.tagName = heading.node.tagName.toLowerCase();
- headingItem.role = 'heading';
- headingItem.level = level;
- headingElementsArr.push(headingItem);
- incSkipToIdIndex();
- }
- }
- return headingElementsArr;
- }
-
- /*
- * @function getLocalizedLandmarkName
- *
- * @desc Localizes a landmark name and adds accessible name if defined
- *
- * @param {Object} config - Object with configuration information
- * @param {String} tagName - String with landamrk and/or tag names
- * @param {String} AccName - Accessible name for therlandmark, maybe an empty string
- *
- * @returns {String} A localized string for a landmark name
- */
- function getLocalizedLandmarkName (config, tagName, accName) {
- let n;
- switch (tagName) {
- case 'aside':
- n = config.asideLabel;
- break;
- case 'footer':
- n = config.footerLabel;
- break;
- case 'form':
- n = config.formLabel;
- break;
- case 'header':
- n = config.headerLabel;
- break;
- case 'main':
- n = config.mainLabel;
- break;
- case 'nav':
- n = config.navLabel;
- break;
- case 'section':
- case 'region':
- n = config.regionLabel;
- break;
- case 'search':
- n = config.searchLabel;
- break;
- // When an ID is used as a selector, assume for main content
- default:
- n = tagName;
- break;
- }
- if (isNotEmptyString(accName)) {
- n += ': ' + accName;
- }
- return n;
- }
-
- /*
- * @function getLandmarkTargets
- *
- * @desc Analyzes a configuration string for landamrk and tag names
- * NOTE: This function is included to maximize compatibility
- * with confiuguration strings that use CSS selectors
- * in previous versions of SkipTo
- *
- * @param {String} targets - String with landamrk and/or tag names
- *
- * @returns {Array} A normailized array of landmark names based on target configuration
- */
- function getLandmarkTargets (targets) {
- let targetLandmarks = [];
- targets = targets.toLowerCase();
- if (targets.includes('main')) {
- targetLandmarks.push('main');
- }
- if (targets.includes('search')) {
- targetLandmarks.push('search');
- }
- if (targets.includes('nav')) {
- targetLandmarks.push('navigation');
- }
- if (targets.includes('complementary') ||
- targets.includes('aside')) {
- targetLandmarks.push('complementary');
- }
- if (targets.includes('banner') ||
- targets.includes('header')) {
- targetLandmarks.push('banner');
- }
- if (targets.includes('contentinfo') ||
- targets.includes('footer')) {
- targetLandmarks.push('contentinfo');
- }
- if (targets.includes('region') ||
- targets.includes('section')) {
- targetLandmarks.push('region');
- }
- return targetLandmarks;
- }
-
-
- /*
- * @function getLandmarks
- *
- * @desc Returns an array of objects with information to build the
- * the landmarks menu, ordering in the array by the type of landmark
- * region
- *
- * @param {Object} config - Object with configuration information
- * @param {Array} landmarks - Array of objects containing the DOM node and
- * accessible name for landmarks
- *
- * @returns {Array} see @desc
- */
- function getLandmarks(config, landmarks) {
- let mainElements = [];
- let searchElements = [];
- let navElements = [];
- let asideElements = [];
- let footerElements = [];
- let regionElements = [];
- let otherElements = [];
- let dataId = '';
- for (let i = 0, len = landmarks.length; i < len; i += 1) {
- let landmark = landmarks[i];
- if (landmark.node.id === 'id-skip-to') {
- continue;
- }
- let role = landmark.node.getAttribute('role');
- let tagName = landmark.node.tagName.toLowerCase();
- if ((typeof role === 'string') && (role === 'presentation')) continue;
- if (isVisible(landmark.node)) {
- if (!role) role = tagName;
- // normalize tagNames
- switch (role) {
- case 'banner':
- tagName = 'header';
- break;
- case 'complementary':
- tagName = 'aside';
- break;
- case 'contentinfo':
- tagName = 'footer';
- break;
- case 'form':
- tagName = 'form';
- break;
- case 'main':
- tagName = 'main';
- break;
- case 'navigation':
- tagName = 'nav';
- break;
- case 'region':
- tagName = 'section';
- break;
- case 'search':
- tagName = 'search';
- break;
- }
- // if using ID for selectQuery give tagName as main
- if (['aside', 'footer', 'form', 'header', 'main', 'nav', 'section', 'search'].indexOf(tagName) < 0) {
- tagName = 'main';
- }
- if (landmark.node.hasAttribute('aria-roledescription')) {
- tagName = landmark.node.getAttribute('aria-roledescription').trim().replace(' ', '-');
- }
- if (landmark.node.hasAttribute('data-skip-to-id')) {
- dataId = landmark.node.getAttribute('data-skip-to-id');
+ // add event handlers
+ menuitemNode.addEventListener(
+ 'keydown',
+ this.handleMenuitemKeydown.bind(this)
+ );
+ menuitemNode.addEventListener(
+ 'click',
+ this.handleMenuitemClick.bind(this)
+ );
+ menuitemNode.addEventListener(
+ 'pointerenter',
+ this.handleMenuitemPointerenter.bind(this)
+ );
+
+ groupNode.appendChild(menuitemNode);
+
+ // add heading level and label
+ if (mi.class.includes('heading')) {
+ if (this.config.enableHeadingLevelShortcuts) {
+ tagNode = document.createElement('span');
+ tagNodeChild = document.createElement('span');
+ tagNodeChild.appendChild(document.createTextNode(mi.level));
+ tagNode.append(tagNodeChild);
+ tagNode.appendChild(document.createTextNode(')'));
+ tagNode.classList.add('level');
+ menuitemNode.append(tagNode);
} else {
- dataId = getSkipToIdIndex();
- landmark.node.setAttribute('data-skip-to-id', dataId);
+ menuitemNode.classList.add('no-level');
}
- const landmarkItem = {};
- landmarkItem.dataId = dataId.toString();
- landmarkItem.class = 'landmark';
- landmarkItem.hasName = landmark.name.length > 0;
- landmarkItem.name = getLocalizedLandmarkName(config, tagName, landmark.name);
- landmarkItem.tagName = tagName;
- landmarkItem.nestingLevel = 0;
- incSkipToIdIndex();
-
- // For sorting landmarks into groups
- switch (tagName) {
- case 'main':
- mainElements.push(landmarkItem);
- break;
- case 'search':
- searchElements.push(landmarkItem);
- break;
- case 'nav':
- navElements.push(landmarkItem);
- break;
- case 'aside':
- asideElements.push(landmarkItem);
- break;
- case 'footer':
- footerElements.push(landmarkItem);
- break;
- case 'section':
- // Regions must have accessible name to be included
- if (landmarkItem.hasName) {
- regionElements.push(landmarkItem);
- }
- break;
- default:
- otherElements.push(landmarkItem);
- break;
+ menuitemNode.setAttribute('data-level', mi.level);
+ if (this.isNotEmptyString(mi.tagName)) {
+ menuitemNode.classList.add('skip-to-' + mi.tagName);
}
}
- }
- return [].concat(mainElements, searchElements, navElements, asideElements, regionElements, footerElements, otherElements);
- }
-
- /* skiptoMenuButton.js */
-
- /* Constants */
- const debug = new DebugLogging('SkipToButton', false);
- debug.flag = false;
-
- /**
- * @class SkiptoMenuButton
- *
- * @desc Constructor for creating a button to open a menu of headings and landmarks on
- * a web page
- *
- * @param {Object} attachNode - DOM eleemnt node to attach button and menu container element
- *
- * @returns {Object} DOM element node that is the contatiner for the button and the menu
- */
- class SkiptoMenuButton {
-
- constructor (attachNode, config, id) {
- this.config = config;
-
- this.containerNode = document.createElement(config.containerElement);
- if (config.containerElement === 'nav') {
- this.containerNode.setAttribute('aria-label', config.buttonLabel);
- }
- this.containerNode.id = id;
+ // add nesting level for landmarks
+ if (mi.class.includes('landmark')) {
+ menuitemNode.setAttribute('data-nesting', mi.nestingLevel);
+ menuitemNode.classList.add('skip-to-nesting-level-' + mi.nestingLevel);
- if (isNotEmptyString(config.customClass)) {
- this.containerNode.classList.add(config.customClass);
+ if (mi.nestingLevel > 0 && mi.nestingLevel > this.lastNestingLevel) {
+ nestingNode = document.createElement('span');
+ nestingNode.classList.add('nesting');
+ menuitemNode.append(nestingNode);
}
+ this.lastNestingLevel = mi.nestingLevel;
+ }
- let displayOption = config.displayOption;
- if (typeof displayOption === 'string') {
- displayOption = displayOption.trim().toLowerCase();
- if (displayOption.length) {
- switch (config.displayOption) {
- case 'fixed':
- this.containerNode.classList.add('fixed');
- break;
- case 'onfocus': // Legacy option
- case 'popup':
- this.containerNode.classList.add('popup');
- break;
- }
- }
- }
+ labelNode = document.createElement('span');
+ labelNode.appendChild(document.createTextNode(mi.name));
+ labelNode.classList.add('label');
+ menuitemNode.append(labelNode);
- // Create button
-
- const [buttonVisibleLabel, buttonAriaLabel] = this.getBrowserSpecificShortcut(config);
-
- this.buttonNode = document.createElement('button');
- this.buttonNode.setAttribute('aria-label', buttonAriaLabel);
- this.buttonNode.addEventListener('keydown', this.handleButtonKeydown.bind(this));
- this.buttonNode.addEventListener('click', this.handleButtonClick.bind(this));
- this.containerNode.appendChild(this.buttonNode);
-
- this.buttonTextNode = document.createElement('span');
- this.buttonTextNode.classList.add('text');
- this.buttonTextNode.textContent = buttonVisibleLabel;
- this.buttonNode.appendChild(this.buttonTextNode);
-
- const imageNode = document.createElement('img');
- imageNode.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAALEwAACxMBAJqcGAAAAVlpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDUuNC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFkb2JlLmNvbS90aWZmLzEuMC8iPgogICAgICAgICA8dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk9yaWVudGF0aW9uPgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4KTMInWQAABP5JREFUWAm9V11MXEUUnjN7KbuwKD/L8qOp2kpbWCSFpkZN2qIxjQYWaC2JD/4kxsTE1MQHeedBY6K+mPSpJsakhcSgFaQk+qCh1DZRQmioSypVa0q1IKC1bFlw753jN5e9txfobmkBJ1nm3DPnb87fHEhkWGWVBx9QYqFCkSxk4nuFYMpA7jkilkIsMHNCGnI8m9VPl8/3/e0hcMEVAosjTc+wsl5iomcFc75LuTYA4ug7IajDZ+Qfnxw5dsMR5xoQqm0qF/OqgwXXO4cbscOQCwb5npuI9Yxq+bYBJTUHwqaZHMSNN99USjNE4jQoxuD5KeBnBSm+eZ4BYglWsQkhCzKLLWB6DHC1wwEj4j6DaiZHei8ZGmklkx+CwFZOgqalT772+qG67vb2duUwrXUPVzfVKMv6GMbsQm4ETVO8D5mHqHxXNLSQUFcFC23MdSmz9k3Fus+tVeGt+IsjrUFWc2MwokyfS5lTZiQTYndKuY5H33LlYCplv+Xmyq0Ep8PRvI+nYl0TzjngeKiqoQP63lrEzT9sIK5hIFKLhh1I76HKxjal5t4Tc17s6mEtNlQVbZse7f3A5SJx0dWn+D5DsbwmhBvqCpcQQDDb+ChuKmTrauvfy61h4qAhz0x70JJ8PYpUm5aZFaBvRElN9KGiyga2f1UN46W1rcUe+g0BkdwSiWiH1f4TqmocAGKP1oYqGPEZfGDyfN+vG6J9mVDbgNKqaMRkHkQTCtjnTBa8960U8hRyZAxljT4g44IsN1uWyVn6SRJ0dEP4xOzh5rqJTOXsZnf4kcbHlcUn0DhKl0pb2xc8mkC8R5nk11lCdE6M9sa8El0DNFLXqVCJN+GJF3GFbV7CdYK1Z45RoTw8febLWS1ziQFeJeHqlq2CrZ2WEBUkuBBt+p5M9F5eJDgJKfwot3xcBnJoB7yAB3JxoRUPEwX26r6Q1gCHeD32+yOthfNi/mVc4m0ke44tk+jIzOjJN/4XA5xLhKuj+y3FvTBkE7ww5zMKwrYBoUj0VSAr/RR450qs6y+HYSN2tOJuJHpzygtPG7oRmUl1FAhaEAndtN51FBdVNp5A/PGU3uXCs5uKtfseoCq+R14sGsBUbiAmuuxsT6Ahl3tV+SR1YAIY8eLuDObZzf6CGT1MOIsFwcOL7QTtwm/PA87h8j2nuKgvPnv97HL8ar+DlkoMDR1NZqLPaED8z+mz8FBtJgGZzvQIVV7d/OAfP/aMp6PLaABmtxdMqbakY749nuOZlGt+tzncXtjGUBiWItNNCko9RildJlvHWd19CJDbK0NAnOsMJKiIpJFNcmLBGUiY6rz3DIZDTyAJC7y4O4F1Ev52rhsDz5L1qPNFQl0lPRwc+XTwCgqjDD3bkpKfnBrtO+0QredeHGnZycocQB/IQ+EnA5RT6uvv7+dAeHsRFO0BUj/kB3NLtsfmpsbG1lN5KNIYFUp9DuW2R0lS50Ssu9NuQBjNc/5N8BBKDq9WahFdRhccQBx/JhbX8MDNI6SLHcShSbdjggFtALEuwA9zJu2DYrfJ4fBSdl7W7t9/+GLGfYz0LGguzH2GPr03ndz1wEP5KZKB551x3TXAEV5UGW0h4lfwOO3HdbMd/Fp2/fLBu1/B7Z9Mx072emWtMMA5rK9vNy5MDW8zhbUVLsxDqebil5be4VvcETQ9ExL9g3/rf3lqh/9iV1cXZpuV6z8QFu9El3GwrAAAAABJRU5ErkJggg==";
- imageNode.setAttribute('alt', '');
- this.buttonNode.appendChild(imageNode);
-
- // Create menu container
-
- this.menuNode = document.createElement('div');
- this.menuNode.id = 'id-skip-to-menu';
- this.menuNode.setAttribute('role', 'menu');
- this.menuNode.setAttribute('aria-label', config.menuLabel);
- this.menuNode.setAttribute('aria-busy', 'true');
- this.containerNode.appendChild(this.menuNode);
-
- const landmarkGroupLabelNode = document.createElement('div');
- landmarkGroupLabelNode.id = 'id-skip-to-menu-landmark-group-label';
- landmarkGroupLabelNode.setAttribute('role', 'separator');
- landmarkGroupLabelNode.textContent = this.config.landmarkGroupLabel;
- this.menuNode.appendChild(landmarkGroupLabelNode);
-
- this.landmarkGroupNode = document.createElement('div');
- this.landmarkGroupNode.setAttribute('role', 'group');
- this.landmarkGroupNode.setAttribute('aria-labelledby', landmarkGroupLabelNode.id);
- this.landmarkGroupNode.id = '#id-skip-to-menu-landmark-group';
- this.menuNode.appendChild(this.landmarkGroupNode);
-
- const headingGroupLabelNode = document.createElement('div');
- headingGroupLabelNode.id = 'id-skip-to-menu-heading-group-label';
- headingGroupLabelNode.setAttribute('role', 'separator');
- headingGroupLabelNode.textContent = this.config.headingGroupLabel;
- this.menuNode.appendChild(headingGroupLabelNode);
-
- this.headingGroupNode = document.createElement('div');
- this.headingGroupNode.setAttribute('role', 'group');
- this.headingGroupNode.setAttribute('aria-labelledby', headingGroupLabelNode.id);
- this.headingGroupNode.id = '#id-skip-to-menu-heading-group';
- this.menuNode.appendChild(this.headingGroupNode);
-
- this.containerNode.addEventListener('focusin', this.handleFocusin.bind(this));
- this.containerNode.addEventListener('focusout', this.handleFocusout.bind(this));
- window.addEventListener('pointerdown', this.handleBackgroundPointerdown.bind(this), true);
+ return menuitemNode;
+ },
- if (this.usesAltKey || this.usesOptionKey) {
- document.addEventListener(
- 'keydown',
- this.handleDocumentKeydown.bind(this)
- );
- }
+ renderGroupLabel: function (groupLabelId, title, m, n) {
+ let titleNode, mofnNode, s;
+ let groupLabelNode = document.getElementById(groupLabelId);
- attachNode.insertBefore(this.containerNode, attachNode.firstElementChild);
-
- return this.containerNode;
-
- }
-
- /*
- * @method getBrowserSpecificShortcut
- *
- * @desc Identifies the operating system and updates labels for
- * shortcut key to use either the "alt" or the "option"
- * label
- *
- * @param {Object} - SkipTp configure object
- *
- * @return {Array} - An array of two strings used for the button label
- */
- getBrowserSpecificShortcut (config) {
- const platform = navigator.platform.toLowerCase();
- const userAgent = navigator.userAgent.toLowerCase();
-
- const hasWin = platform.indexOf('win') >= 0;
- const hasMac = platform.indexOf('mac') >= 0;
- const hasLinux = platform.indexOf('linux') >= 0 || platform.indexOf('bsd') >= 0;
- const hasAndroid = userAgent.indexOf('android') >= 0;
-
- this.usesAltKey = hasWin || (hasLinux && !hasAndroid);
- this.usesOptionKey = hasMac;
-
- let label = config.buttonLabel;
- let ariaLabel = config.buttonLabel;
- let buttonShortcut;
-
- // Check to make sure a shortcut key is defined
- if (config.altShortcut && config.optionShortcut) {
- if (this.usesAltKey || this.usesOptionKey) {
- buttonShortcut = config.buttonShortcut.replace(
- '$key',
- config.altShortcut
- );
- }
- if (this.usesAltKey) {
- buttonShortcut = buttonShortcut.replace(
- '$modifier',
- config.altLabel
- );
- label = label + buttonShortcut;
- ariaLabel = config.altButtonAriaLabel.replace('$key', config.altShortcut);
- }
+ titleNode = groupLabelNode.querySelector('.title');
+ mofnNode = groupLabelNode.querySelector('.mofn');
- if (this.usesOptionKey) {
- buttonShortcut = buttonShortcut.replace(
- '$modifier',
- config.optionLabel
- );
- label = label + buttonShortcut;
- ariaLabel = config.optionButtonAriaLabel.replace('$key', config.altShortcut);
- }
- }
- return [label, ariaLabel];
- }
-
- /*
- * @method getFirstChar
- *
- * @desc Gets the first character in a menuitem to use as a shortcut key
- *
- * @param {Object} menuitem - DOM element node
- *
- * @returns {String} see @desc
- */
- getFirstChar(menuitem) {
- const label = menuitem.querySelector('.label');
- if (label && isNotEmptyString(label.textContent)) {
- return label.textContent.trim()[0].toLowerCase();
- }
- return '';
- }
-
- /*
- * @method getHeadingLevelFromAttribute
- *
- * @desc Returns the the heading level of the menu item
- *
- * @param {Object} menuitem - DOM element node
- *
- * @returns {String} see @desc
- */
- getHeadingLevelFromAttribute(menuitem) {
- if (menuitem.hasAttribute('data-level')) {
- return menuitem.getAttribute('data-level');
+ titleNode.textContent = title;
+
+ if (this.config.enableActions && this.config.enableMofN) {
+ if (typeof m === 'number' && typeof n === 'number') {
+ s = this.config.mofnGroupLabel;
+ s = s.replace('$m', m);
+ s = s.replace('$n', n);
+ mofnNode.textContent = s;
}
- return '';
- }
-
- /*
- * @method updateKeyboardShortCuts
- *
- * @desc Updates the keyboard short cuts for the curent menu items
- */
- updateKeyboardShortCuts () {
- let mi;
- this.firstChars = [];
- this.headingLevels = [];
-
- for(let i = 0; i < this.menuitemNodes.length; i += 1) {
- mi = this.menuitemNodes[i];
- this.firstChars.push(this.getFirstChar(mi));
- this.headingLevels.push(this.getHeadingLevelFromAttribute(mi));
+ }
+ },
+
+ renderMenuitemGroup: function (groupId, title) {
+ let labelNode, groupNode, spanNode;
+ let menuNode = this.menuNode;
+ if (this.isNotEmptyString(title)) {
+ labelNode = document.createElement('div');
+ labelNode.id = groupId + '-label';
+ labelNode.setAttribute('role', 'separator');
+ menuNode.appendChild(labelNode);
+
+ spanNode = document.createElement('span');
+ spanNode.classList.add('title');
+ spanNode.textContent = title;
+ labelNode.append(spanNode);
+
+ spanNode = document.createElement('span');
+ spanNode.classList.add('mofn');
+ labelNode.append(spanNode);
+
+ groupNode = document.createElement('div');
+ groupNode.setAttribute('role', 'group');
+ groupNode.setAttribute('aria-labelledby', labelNode.id);
+ groupNode.id = groupId;
+ menuNode.appendChild(groupNode);
+ menuNode = groupNode;
+ }
+ return groupNode;
+ },
+
+ removeMenuitemGroup: function (groupId) {
+ let node = document.getElementById(groupId);
+ this.menuNode.removeChild(node);
+ node = document.getElementById(groupId + '-label');
+ this.menuNode.removeChild(node);
+ },
+
+ renderMenuitemsToGroup: function (groupNode, menuitems, msgNoItemsFound) {
+ groupNode.innerHTML = '';
+ this.lastNestingLevel = 0;
+
+ if (menuitems.length === 0) {
+ const item = {};
+ item.name = msgNoItemsFound;
+ item.tagName = '';
+ item.class = 'no-items';
+ item.dataId = '';
+ this.renderMenuitemToGroup(groupNode, item);
+ } else {
+ for (var i = 0; i < menuitems.length; i += 1) {
+ this.renderMenuitemToGroup(groupNode, menuitems[i]);
}
}
+ },
- /*
- * @method updateMenuitems
- *
- * @desc Updates the menu information with the current manu items
- * used for menu navgation commands
- */
- updateMenuitems () {
- let menuitemNodes = this.menuNode.querySelectorAll('[role=menuitem');
+ getShowMoreHeadingsSelector: function (option) {
+ if (option === 'all') {
+ return this.showAllHeadingsSelector;
+ }
+ return this.config.headings;
+ },
- this.menuitemNodes = [];
- for(let i = 0; i < menuitemNodes.length; i += 1) {
- this.menuitemNodes.push(menuitemNodes[i]);
- }
+ getShowMoreHeadingsLabel: function (option, n) {
+ let label = this.config.actionShowSelectedHeadingsLabel;
+ if (option === 'all') {
+ label = this.config.actionShowAllHeadingsLabel;
+ }
+ return label.replace('$num', n);
+ },
- this.firstMenuitem = this.menuitemNodes[0];
- this.lastMenuitem = this.menuitemNodes[this.menuitemNodes.length-1];
- this.lastMenuitem.classList.add('last');
- this.updateKeyboardShortCuts();
- }
-
- /*
- * @method renderMenuitemToGroup
- *
- * @desc Renders a menuitem using an information object about the menuitem
- *
- * @param {Object} groupNode - DOM element node for the menu group
- * @param {Object} mi - object with menuitem information
- */
- renderMenuitemToGroup (groupNode, mi) {
- let tagNode, tagNodeChild, labelNode, nestingNode;
-
- let menuitemNode = document.createElement('div');
- menuitemNode.setAttribute('role', 'menuitem');
- menuitemNode.classList.add(mi.class);
- if (isNotEmptyString(mi.tagName)) {
- menuitemNode.classList.add('skip-to-' + mi.tagName.toLowerCase());
- }
- menuitemNode.setAttribute('data-id', mi.dataId);
- menuitemNode.tabIndex = -1;
- if (isNotEmptyString(mi.ariaLabel)) {
- menuitemNode.setAttribute('aria-label', mi.ariaLabel);
- }
+ getShowMoreHeadingsAriaLabel: function (option, n) {
+ let label = this.config.actionShowSelectedHeadingsAriaLabel;
- // add event handlers
- menuitemNode.addEventListener('keydown', this.handleMenuitemKeydown.bind(this));
- menuitemNode.addEventListener('click', this.handleMenuitemClick.bind(this));
- menuitemNode.addEventListener('pointerenter', this.handleMenuitemPointerenter.bind(this));
-
- groupNode.appendChild(menuitemNode);
-
- // add heading level and label
- if (mi.class.includes('heading')) {
- if (this.config.enableHeadingLevelShortcuts) {
- tagNode = document.createElement('span');
- tagNodeChild = document.createElement('span');
- tagNodeChild.appendChild(document.createTextNode(mi.level));
- tagNode.append(tagNodeChild);
- tagNode.appendChild(document.createTextNode(')'));
- tagNode.classList.add('level');
- menuitemNode.append(tagNode);
- } else {
- menuitemNode.classList.add('no-level');
- }
- menuitemNode.setAttribute('data-level', mi.level);
- if (isNotEmptyString(mi.tagName)) {
- menuitemNode.classList.add('skip-to-' + mi.tagName);
- }
- }
+ if (option === 'all') {
+ label = this.config.actionShowAllHeadingsAriaLabel;
+ }
- // add nesting level for landmarks
- if (mi.class.includes('landmark')) {
- menuitemNode.setAttribute('data-nesting', mi.nestingLevel);
- menuitemNode.classList.add('skip-to-nesting-level-' + mi.nestingLevel);
+ return label.replace('$num', n);
+ },
- if (mi.nestingLevel > 0 && (mi.nestingLevel > this.lastNestingLevel)) {
- nestingNode = document.createElement('span');
- nestingNode.classList.add('nesting');
- menuitemNode.append(nestingNode);
- }
- this.lastNestingLevel = mi.nestingLevel;
- }
+ renderActionMoreHeadings: function (groupNode) {
+ let item, menuitemNode;
+ let option = 'all';
- labelNode = document.createElement('span');
- labelNode.appendChild(document.createTextNode(mi.name));
- labelNode.classList.add('label');
- menuitemNode.append(labelNode);
-
- return menuitemNode;
- }
-
- /*
- * @method renderMenuitemsToGroup
- *
- * @desc Renders either the landmark region or headings menu group
- *
- * @param {Object} groupNode - DOM element node for the menu group
- * @param {Array} menuitems - Array of objects with menu item information
- * @param {String} msgNoItesmFound - Message to render if there are no menu items
- */
- renderMenuitemsToGroup(groupNode, menuitems, msgNoItemsFound) {
- groupNode.innerHTML = '';
- this.lastNestingLevel = 0;
-
- if (menuitems.length === 0) {
- const item = {};
- item.name = msgNoItemsFound;
- item.tagName = '';
- item.class = 'no-items';
- item.dataId = '';
- this.renderMenuitemToGroup(groupNode, item);
- }
- else {
- for (let i = 0; i < menuitems.length; i += 1) {
- this.renderMenuitemToGroup(groupNode, menuitems[i]);
- }
- }
+ let selectedHeadingsLen = this.getHeadings(
+ this.getShowMoreHeadingsSelector('selected')
+ ).length;
+ let allHeadingsLen = this.getHeadings(
+ this.getShowMoreHeadingsSelector('all')
+ ).length;
+ let noAction = selectedHeadingsLen === allHeadingsLen;
+ let headingsLen = allHeadingsLen;
+
+ if (option !== 'all') {
+ headingsLen = selectedHeadingsLen;
}
- /*
- * @method renderMenu
- *
- * @desc
- */
- renderMenu() {
- // remove landmark menu items
- while (this.landmarkGroupNode.lastElementChild) {
- this.landmarkGroupNode.removeChild(this.landmarkGroupNode.lastElementChild);
- }
- // remove heading menu items
- while (this.headingGroupNode.lastElementChild) {
- this.headingGroupNode.removeChild(this.headingGroupNode.lastElementChild);
- }
+ if (!noAction) {
+ item = {};
+ item.tagName = '';
+ item.role = 'menuitem';
+ item.class = 'action';
+ item.dataId = 'skip-to-more-headings';
+ item.name = this.getShowMoreHeadingsLabel(option, headingsLen);
+ item.ariaLabel = this.getShowMoreHeadingsAriaLabel(option, headingsLen);
+
+ menuitemNode = this.renderMenuitemToGroup(groupNode, item);
+ menuitemNode.setAttribute('data-show-heading-option', option);
+ menuitemNode.title = this.config.actionShowHeadingsHelp;
+ }
+ return noAction;
+ },
+
+ updateHeadingGroupMenuitems: function (option) {
+ let headings, headingsLen, labelNode, groupNode;
+
+ const selectedHeadings = this.getHeadings(
+ this.getShowMoreHeadingsSelector('selected')
+ );
+ const selectedHeadingsLen = selectedHeadings.length;
+ const allHeadings = this.getHeadings(
+ this.getShowMoreHeadingsSelector('all')
+ );
+ const allHeadingsLen = allHeadings.length;
+
+ // Update list of headings
+ if (option === 'all') {
+ headings = allHeadings;
+ } else {
+ headings = selectedHeadings;
+ }
- // Create landmarks group
- const [landmarkElements, headingElements] = getLandmarksAndHeadings(this.config);
- this.renderMenuitemsToGroup(this.landmarkGroupNode, landmarkElements, this.config.msgNoLandmarksFound);
- this.renderMenuitemsToGroup(this.headingGroupNode, headingElements, this.config.msgNoHeadingsFound);
-
- // Update list of menuitems
- this.updateMenuitems();
- }
-
- //
- // Menu scripting helper functions and event handlers
- //
-
- /*
- * @method setFocusToMenuitem
- *
- * @desc Moves focus to menu item
- *
- * @param {Object} menuItem - DOM element node used as a menu item
- */
- setFocusToMenuitem(menuitem) {
- if (menuitem) {
- menuitem.focus();
- }
+ this.renderGroupLabel(
+ 'id-skip-to-group-headings-label',
+ this.config.headingGroupLabel,
+ headings.length,
+ allHeadings.length
+ );
+
+ groupNode = document.getElementById('id-skip-to-group-headings');
+ this.renderMenuitemsToGroup(
+ groupNode,
+ headings,
+ this.config.msgNoHeadingsFound
+ );
+ this.updateMenuitems();
+
+ // Move focus to first heading menuitem
+ if (groupNode.firstElementChild) {
+ groupNode.firstElementChild.focus();
}
- /*
- * @method setFocusToFirstMenuitem
- *
- * @desc Moves focus to first menu item
- */
- setFocusToFirstMenuitem() {
- this.setFocusToMenuitem(this.firstMenuitem);
- }
-
- /*
- * @method setFocusToLastMenuitem
- *
- * @desc Moves focus to last menu item
- */
- setFocusToLastMenuitem() {
- this.setFocusToMenuitem(this.lastMenuitem);
- }
-
- /*
- * @method setFocusToPreviousMenuitem
- *
- * @desc Moves focus to previous menu item
- *
- * @param {Object} menuItem - DOM element node
- */
- setFocusToPreviousMenuitem(menuitem) {
- let newMenuitem, index;
- if (menuitem === this.firstMenuitem) {
- newMenuitem = this.lastMenuitem;
- } else {
- index = this.menuitemNodes.indexOf(menuitem);
- newMenuitem = this.menuitemNodes[index - 1];
- }
- this.setFocusToMenuitem(newMenuitem);
- return newMenuitem;
- }
-
- /*
- * @method setFocusToNextMenuitem
- *
- * @desc Moves focus to next menu item
- *
- * @param {Object} menuItem - DOM element node
- */
- setFocusToNextMenuitem(menuitem) {
- let newMenuitem, index;
- if (menuitem === this.lastMenuitem) {
- newMenuitem = this.firstMenuitem;
- } else {
- index = this.menuitemNodes.indexOf(menuitem);
- newMenuitem = this.menuitemNodes[index + 1];
- }
- this.setFocusToMenuitem(newMenuitem);
- return newMenuitem;
- }
-
- /*
- * @method setFocusByFirstCharacter
- *
- * @desc Moves focus to next menu item based on shortcut key
- *
- * @param {Object} menuItem - Starting DOM element node
- * @param {String} char - Shortcut key to identify the
- * next menu item
- */
- setFocusByFirstCharacter(menuitem, char) {
- let start, index;
- if (char.length > 1) {
- return;
- }
- char = char.toLowerCase();
+ // Update heading action menuitem
+ if (option === 'all') {
+ option = 'selected';
+ headingsLen = selectedHeadingsLen;
+ } else {
+ option = 'all';
+ headingsLen = allHeadingsLen;
+ }
- // Get start index for search based on position of currentItem
- start = this.menuitemNodes.indexOf(menuitem) + 1;
- if (start >= this.menuitemNodes.length) {
- start = 0;
- }
+ const menuitemNode = this.menuNode.querySelector(
+ '[data-id=skip-to-more-headings]'
+ );
+ menuitemNode.setAttribute('data-show-heading-option', option);
+ menuitemNode.setAttribute(
+ 'aria-label',
+ this.getShowMoreHeadingsAriaLabel(option, headingsLen)
+ );
+
+ labelNode = menuitemNode.querySelector('span.label');
+ labelNode.textContent = this.getShowMoreHeadingsLabel(
+ option,
+ headingsLen
+ );
+ },
+
+ getShowMoreLandmarksSelector: function (option) {
+ if (option === 'all') {
+ return this.showAllLandmarksSelector;
+ }
+ return this.config.landmarks;
+ },
- // Check remaining items in the menu
- index = this.firstChars.indexOf(char, start);
+ getShowMoreLandmarksLabel: function (option, n) {
+ let label = this.config.actionShowSelectedLandmarksLabel;
- // If not found in remaining items, check headings
- if (index === -1) {
- index = this.headingLevels.indexOf(char, start);
- }
+ if (option === 'all') {
+ label = this.config.actionShowAllLandmarksLabel;
+ }
+ return label.replace('$num', n);
+ },
- // If not found in remaining items, check from beginning
- if (index === -1) {
- index = this.firstChars.indexOf(char, 0);
- }
+ getShowMoreLandmarksAriaLabel: function (option, n) {
+ let label = this.config.actionShowSelectedLandmarksAriaLabel;
- // If not found in remaining items, check headings from beginning
- if (index === -1) {
- index = this.headingLevels.indexOf(char, 0);
- }
+ if (option === 'all') {
+ label = this.config.actionShowAllLandmarksAriaLabel;
+ }
+
+ return label.replace('$num', n);
+ },
+
+ renderActionMoreLandmarks: function (groupNode) {
+ let item, menuitemNode;
+ let option = 'all';
+
+ const selectedLandmarksLen = this.getLandmarks(
+ this.getShowMoreLandmarksSelector('selected')
+ ).length;
+ const allLandmarksLen = this.getLandmarks(
+ this.getShowMoreLandmarksSelector('all')
+ ).length;
+ const noAction = selectedLandmarksLen === allLandmarksLen;
+ let landmarksLen = allLandmarksLen;
+
+ if (option !== 'all') {
+ landmarksLen = selectedLandmarksLen;
+ }
+
+ if (!noAction) {
+ item = {};
+ item.tagName = '';
+ item.role = 'menuitem';
+ item.class = 'action';
+ item.dataId = 'skip-to-more-landmarks';
+ item.name = this.getShowMoreLandmarksLabel(option, landmarksLen);
+ item.ariaLabel = this.getShowMoreLandmarksAriaLabel(
+ option,
+ landmarksLen
+ );
+
+ menuitemNode = this.renderMenuitemToGroup(groupNode, item);
+
+ menuitemNode.setAttribute('data-show-landmark-option', option);
+ menuitemNode.title = this.config.actionShowLandmarksHelp;
+ }
+ return noAction;
+ },
+
+ updateLandmarksGroupMenuitems: function (option) {
+ let landmarks, landmarksLen, labelNode, groupNode;
+
+ const selectedLandmarks = this.getLandmarks(
+ this.getShowMoreLandmarksSelector('selected')
+ );
+ const selectedLandmarksLen = selectedLandmarks.length;
+ const allLandmarks = this.getLandmarks(
+ this.getShowMoreLandmarksSelector('all'),
+ true
+ );
+ const allLandmarksLen = allLandmarks.length;
+
+ // Update landmark menu items
+ if (option === 'all') {
+ landmarks = allLandmarks;
+ } else {
+ landmarks = selectedLandmarks;
+ }
- // If match was found...
- if (index > -1) {
- this.setFocusToMenuitem(this.menuitemNodes[index]);
+ this.renderGroupLabel(
+ 'id-skip-to-group-landmarks-label',
+ this.config.landmarkGroupLabel,
+ landmarks.length,
+ allLandmarks.length
+ );
+
+ groupNode = document.getElementById('id-skip-to-group-landmarks');
+ this.renderMenuitemsToGroup(
+ groupNode,
+ landmarks,
+ this.config.msgNoLandmarksFound
+ );
+ this.updateMenuitems();
+
+ // Move focus to first landmark menuitem
+ if (groupNode.firstElementChild) {
+ groupNode.firstElementChild.focus();
+ }
+
+ // Update landmark action menuitem
+ if (option === 'all') {
+ option = 'selected';
+ landmarksLen = selectedLandmarksLen;
+ } else {
+ option = 'all';
+ landmarksLen = allLandmarksLen;
+ }
+
+ const menuitemNode = this.menuNode.querySelector(
+ '[data-id=skip-to-more-landmarks]'
+ );
+ menuitemNode.setAttribute('data-show-landmark-option', option);
+ menuitemNode.setAttribute(
+ 'aria-label',
+ this.getShowMoreLandmarksAriaLabel(option, landmarksLen)
+ );
+
+ labelNode = menuitemNode.querySelector('span.label');
+ labelNode.textContent = this.getShowMoreLandmarksLabel(
+ option,
+ landmarksLen
+ );
+ },
+
+ renderMenu: function () {
+ let groupNode,
+ selectedLandmarks,
+ allLandmarks,
+ landmarkElements,
+ selectedHeadings,
+ allHeadings,
+ headingElements,
+ selector,
+ option,
+ hasNoAction1,
+ hasNoAction2;
+ // remove current menu items from menu
+ while (this.menuNode.lastElementChild) {
+ this.menuNode.removeChild(this.menuNode.lastElementChild);
+ }
+
+ option = 'selected';
+ // Create landmarks group
+ selector = this.getShowMoreLandmarksSelector('all');
+ allLandmarks = this.getLandmarks(selector, true);
+ selector = this.getShowMoreLandmarksSelector('selected');
+ selectedLandmarks = this.getLandmarks(selector);
+ landmarkElements = selectedLandmarks;
+
+ if (option === 'all') {
+ landmarkElements = allLandmarks;
+ }
+
+ groupNode = this.renderMenuitemGroup(
+ 'id-skip-to-group-landmarks',
+ this.config.landmarkGroupLabel
+ );
+ this.renderMenuitemsToGroup(
+ groupNode,
+ landmarkElements,
+ this.config.msgNoLandmarksFound
+ );
+ this.renderGroupLabel(
+ 'id-skip-to-group-landmarks-label',
+ this.config.landmarkGroupLabel,
+ landmarkElements.length,
+ allLandmarks.length
+ );
+
+ // Create headings group
+ selector = this.getShowMoreHeadingsSelector('all');
+ allHeadings = this.getHeadings(selector);
+ selector = this.getShowMoreHeadingsSelector('selected');
+ selectedHeadings = this.getHeadings(selector);
+ headingElements = selectedHeadings;
+
+ if (option === 'all') {
+ headingElements = allHeadings;
+ }
+
+ groupNode = this.renderMenuitemGroup(
+ 'id-skip-to-group-headings',
+ this.config.headingGroupLabel
+ );
+ this.renderMenuitemsToGroup(
+ groupNode,
+ headingElements,
+ this.config.msgNoHeadingsFound
+ );
+ this.renderGroupLabel(
+ 'id-skip-to-group-headings-label',
+ this.config.headingGroupLabel,
+ headingElements.length,
+ allHeadings.length
+ );
+
+ // Create actions, if enabled
+ if (this.config.enableActions) {
+ groupNode = this.renderMenuitemGroup(
+ 'id-skip-to-group-actions',
+ this.config.actionGroupLabel
+ );
+ hasNoAction1 = this.renderActionMoreLandmarks(groupNode);
+ hasNoAction2 = this.renderActionMoreHeadings(groupNode);
+ // Remove action label if no actions are available
+ if (hasNoAction1 && hasNoAction2) {
+ this.removeMenuitemGroup('id-skip-to-group-actions');
}
}
- /*
- * @method getIndexFirstChars
- *
- * @desc
- *
- * @returns {Number}
- */
- getIndexFirstChars(startIndex, char) {
- for (let i = startIndex; i < this.firstChars.length; i += 1) {
- if (char === this.firstChars[i]) {
- return i;
- }
+ // Update list of menuitems
+ this.updateMenuitems();
+ },
+
+ //
+ // Menu scripting event functions and utilities
+ //
+
+ setFocusToMenuitem: function (menuitem) {
+ if (menuitem) {
+ menuitem.focus();
+ }
+ },
+
+ setFocusToFirstMenuitem: function () {
+ this.setFocusToMenuitem(this.firstMenuitem);
+ },
+
+ setFocusToLastMenuitem: function () {
+ this.setFocusToMenuitem(this.lastMenuitem);
+ },
+
+ setFocusToPreviousMenuitem: function (menuitem) {
+ let newMenuitem, index;
+ if (menuitem === this.firstMenuitem) {
+ newMenuitem = this.lastMenuitem;
+ } else {
+ index = this.menuitemNodes.indexOf(menuitem);
+ newMenuitem = this.menuitemNodes[index - 1];
+ }
+ this.setFocusToMenuitem(newMenuitem);
+ return newMenuitem;
+ },
+
+ setFocusToNextMenuitem: function (menuitem) {
+ let newMenuitem, index;
+ if (menuitem === this.lastMenuitem) {
+ newMenuitem = this.firstMenuitem;
+ } else {
+ index = this.menuitemNodes.indexOf(menuitem);
+ newMenuitem = this.menuitemNodes[index + 1];
+ }
+ this.setFocusToMenuitem(newMenuitem);
+ return newMenuitem;
+ },
+
+ setFocusByFirstCharacter: function (menuitem, char) {
+ let start, index;
+ if (char.length > 1) {
+ return;
+ }
+ char = char.toLowerCase();
+
+ // Get start index for search based on position of currentItem
+ start = this.menuitemNodes.indexOf(menuitem) + 1;
+ if (start >= this.menuitemNodes.length) {
+ start = 0;
+ }
+
+ // Check remaining items in the menu
+ index = this.firstChars.indexOf(char, start);
+
+ // If not found in remaining items, check headings
+ if (index === -1) {
+ index = this.headingLevels.indexOf(char, start);
+ }
+
+ // If not found in remaining items, check from beginning
+ if (index === -1) {
+ index = this.firstChars.indexOf(char, 0);
+ }
+
+ // If not found in remaining items, check headings from beginning
+ if (index === -1) {
+ index = this.headingLevels.indexOf(char, 0);
+ }
+
+ // If match was found...
+ if (index > -1) {
+ this.setFocusToMenuitem(this.menuitemNodes[index]);
+ }
+ },
+
+ // Utilities
+ getIndexFirstChars: function (startIndex, char) {
+ for (let i = startIndex; i < this.firstChars.length; i += 1) {
+ if (char === this.firstChars[i]) {
+ return i;
}
- return -1;
- }
-
- /*
- * @method openPopup
- *
- * @desc Opens the memu of landmark regions and headings
- */
- openPopup() {
- this.menuNode.setAttribute('aria-busy', 'true');
- const h = (80 * window.innerHeight) / 100;
- this.menuNode.style.maxHeight = h + 'px';
- this.renderMenu();
- this.menuNode.style.display = 'block';
- const buttonRect = this.buttonNode.getBoundingClientRect();
- const menuRect = this.menuNode.getBoundingClientRect();
- const diff = window.innerWidth - buttonRect.left - menuRect.width - 8;
- if (diff < 0) {
- if (buttonRect.left + diff < 0) {
- this.menuNode.style.left = (8 - buttonRect.left) + 'px';
- } else {
- this.menuNode.style.left = diff + 'px';
+ }
+ return -1;
+ },
+ // Popup menu methods
+ openPopup: function () {
+ this.menuNode.setAttribute('aria-busy', 'true');
+ const h = (80 * window.innerHeight) / 100;
+ this.menuNode.style.maxHeight = h + 'px';
+ this.renderMenu();
+ this.menuNode.style.display = 'block';
+ this.menuNode.removeAttribute('aria-busy');
+ this.buttonNode.setAttribute('aria-expanded', 'true');
+ },
+
+ closePopup: function () {
+ if (this.isOpen()) {
+ this.buttonNode.setAttribute('aria-expanded', 'false');
+ this.menuNode.style.display = 'none';
+ }
+ },
+ isOpen: function () {
+ return this.buttonNode.getAttribute('aria-expanded') === 'true';
+ },
+ // Menu event handlers
+ handleFocusin: function () {
+ this.domNode.classList.add('focus');
+ },
+ handleFocusout: function () {
+ this.domNode.classList.remove('focus');
+ },
+ handleButtonKeydown: function (event) {
+ let key = event.key,
+ flag = false;
+ switch (key) {
+ case ' ':
+ case 'Enter':
+ case 'ArrowDown':
+ case 'Down':
+ this.openPopup();
+ this.setFocusToFirstMenuitem();
+ flag = true;
+ break;
+ case 'Esc':
+ case 'Escape':
+ this.closePopup();
+ this.buttonNode.focus();
+ flag = true;
+ break;
+ case 'Up':
+ case 'ArrowUp':
+ this.openPopup();
+ this.setFocusToLastMenuitem();
+ flag = true;
+ break;
+ default:
+ break;
+ }
+ if (flag) {
+ event.stopPropagation();
+ event.preventDefault();
+ }
+ },
+ handleButtonClick: function (event) {
+ if (this.isOpen()) {
+ this.closePopup();
+ this.buttonNode.focus();
+ } else {
+ this.openPopup();
+ this.setFocusToFirstMenuitem();
+ }
+ event.stopPropagation();
+ event.preventDefault();
+ },
+ handleDocumentKeydown: function (event) {
+ let key = event.key,
+ flag = false;
+
+ let altPressed =
+ this.usesAltKey &&
+ event.altKey &&
+ !event.ctrlKey &&
+ !event.shiftKey &&
+ !event.metaKey;
+
+ let optionPressed =
+ this.usesOptionKey &&
+ event.altKey &&
+ !event.ctrlKey &&
+ !event.shiftKey &&
+ !event.metaKey;
+
+ if (
+ (optionPressed && this.config.optionShortcut === key) ||
+ (altPressed && this.config.altShortcut === key)
+ ) {
+ this.openPopup();
+ this.setFocusToFirstMenuitem();
+ flag = true;
+ }
+ if (flag) {
+ event.stopPropagation();
+ event.preventDefault();
+ }
+ },
+ skipToElement: function (menuitem) {
+ const isVisible = this.isVisible;
+ let focusNode = false;
+ let scrollNode = false;
+ let elem;
+
+ function findVisibleElement(e, selectors) {
+ if (e) {
+ for (let j = 0; j < selectors.length; j += 1) {
+ const elems = e.querySelectorAll(selectors[j]);
+ for (let i = 0; i < elems.length; i += 1) {
+ if (isVisible(elems[i])) {
+ return elems[i];
+ }
+ }
}
}
- this.menuNode.removeAttribute('aria-busy');
- this.buttonNode.setAttribute('aria-expanded', 'true');
+ return e;
}
- /*
- * @method closePopup
- *
- * @desc Closes the memu of landmark regions and headings
- */
- closePopup() {
- if (this.isOpen()) {
- this.buttonNode.setAttribute('aria-expanded', 'false');
- this.menuNode.style.display = 'none';
+ const searchSelectors = [
+ 'input',
+ 'button',
+ 'input[type=button]',
+ 'input[type=submit]',
+ 'a',
+ ];
+ const navigationSelectors = [
+ 'a',
+ 'input',
+ 'button',
+ 'input[type=button]',
+ 'input[type=submit]',
+ ];
+ const landmarkSelectors = [
+ 'h1',
+ 'h2',
+ 'h3',
+ 'h4',
+ 'h5',
+ 'h6',
+ 'section',
+ 'article',
+ 'p',
+ 'li',
+ 'a',
+ ];
+
+ const isLandmark = menuitem.classList.contains('landmark');
+ const isSearch = menuitem.classList.contains('skip-to-search');
+ const isNav = menuitem.classList.contains('skip-to-nav');
+
+ elem = document.querySelector(
+ '[data-skip-to-id="' + menuitem.getAttribute('data-id') + '"]'
+ );
+
+ if (elem) {
+ if (isSearch) {
+ focusNode = findVisibleElement(elem, searchSelectors);
+ }
+ if (isNav) {
+ focusNode = findVisibleElement(elem, navigationSelectors);
+ }
+ if (focusNode && this.isVisible(focusNode)) {
+ focusNode.focus();
+ focusNode.scrollIntoView({ block: 'nearest' });
+ } else {
+ if (isLandmark) {
+ scrollNode = findVisibleElement(elem, landmarkSelectors);
+ if (scrollNode) {
+ elem = scrollNode;
+ }
+ }
+ elem.tabIndex = -1;
+ elem.focus();
+ elem.scrollIntoView({ block: 'center' });
}
}
+ },
+ handleMenuitemAction: function (tgt) {
+ let option;
+ switch (tgt.getAttribute('data-id')) {
+ case '':
+ // this means there were no headings or landmarks in the list
+ break;
- /*
- * @method isOpen
- *
- * @desc Returns true if menu is open, otherwise false
- *
- * @returns {Boolean} see @desc
- */
- isOpen() {
- return this.buttonNode.getAttribute('aria-expanded') === 'true';
- }
+ case 'skip-to-more-headings':
+ option = tgt.getAttribute('data-show-heading-option');
+ this.updateHeadingGroupMenuitems(option);
+ break;
- // Menu event handlers
+ case 'skip-to-more-landmarks':
+ option = tgt.getAttribute('data-show-landmark-option');
+ this.updateLandmarksGroupMenuitems(option);
+ break;
- handleFocusin() {
- this.containerNode.classList.add('focus');
+ default:
+ this.closePopup();
+ this.skipToElement(tgt);
+ break;
}
-
- handleFocusout() {
- this.containerNode.classList.remove('focus');
+ },
+ handleMenuitemKeydown: function (event) {
+ let tgt = event.currentTarget,
+ key = event.key,
+ flag = false;
+
+ function isPrintableCharacter(str) {
+ return str.length === 1 && str.match(/\S/);
}
-
- handleButtonKeydown(event) {
- let key = event.key,
- flag = false;
+ if (event.ctrlKey || event.altKey || event.metaKey) {
+ return;
+ }
+ if (event.shiftKey) {
+ if (isPrintableCharacter(key)) {
+ this.setFocusByFirstCharacter(tgt, key);
+ flag = true;
+ }
+ if (event.key === 'Tab') {
+ this.buttonNode.focus();
+ this.closePopup();
+ flag = true;
+ }
+ } else {
switch (key) {
- case ' ':
case 'Enter':
- case 'ArrowDown':
- case 'Down':
- this.openPopup();
- this.setFocusToFirstMenuitem();
+ case ' ':
+ this.handleMenuitemAction(tgt);
flag = true;
break;
case 'Esc':
@@ -2351,399 +1255,391 @@ $skipToId [role="menuitem"]:focus .label {
break;
case 'Up':
case 'ArrowUp':
- this.openPopup();
+ this.setFocusToPreviousMenuitem(tgt);
+ flag = true;
+ break;
+ case 'ArrowDown':
+ case 'Down':
+ this.setFocusToNextMenuitem(tgt);
+ flag = true;
+ break;
+ case 'Home':
+ case 'PageUp':
+ this.setFocusToFirstMenuitem();
+ flag = true;
+ break;
+ case 'End':
+ case 'PageDown':
this.setFocusToLastMenuitem();
flag = true;
break;
- }
- if (flag) {
- event.stopPropagation();
- event.preventDefault();
+ case 'Tab':
+ this.closePopup();
+ break;
+ default:
+ if (isPrintableCharacter(key)) {
+ this.setFocusByFirstCharacter(tgt, key);
+ flag = true;
+ }
+ break;
}
}
-
- handleButtonClick(event) {
+ if (flag) {
+ event.stopPropagation();
+ event.preventDefault();
+ }
+ },
+ handleMenuitemClick: function (event) {
+ this.handleMenuitemAction(event.currentTarget);
+ event.stopPropagation();
+ event.preventDefault();
+ },
+ handleMenuitemPointerenter: function (event) {
+ let tgt = event.currentTarget;
+ tgt.focus();
+ },
+ handleBackgroundPointerdown: function (event) {
+ if (!this.domNode.contains(event.target)) {
if (this.isOpen()) {
this.closePopup();
this.buttonNode.focus();
- } else {
- this.openPopup();
- this.setFocusToFirstMenuitem();
}
- event.stopPropagation();
- event.preventDefault();
}
-
- handleDocumentKeydown (event) {
- let key = event.key,
- flag = false;
-
- let altPressed =
- this.usesAltKey &&
- event.altKey &&
- !event.ctrlKey &&
- !event.shiftKey &&
- !event.metaKey;
-
- let optionPressed =
- this.usesOptionKey &&
- event.altKey &&
- !event.ctrlKey &&
- !event.shiftKey &&
- !event.metaKey;
-
- if (
- (optionPressed && this.config.optionShortcut === key) ||
- (altPressed && this.config.altShortcut === key)
- ) {
- this.openPopup();
- this.setFocusToFirstMenuitem();
- flag = true;
+ },
+ // methods to extract landmarks, headings and ids
+ normalizeName: function (name) {
+ if (typeof name === 'string')
+ return name.replace(/\w\S*/g, function (txt) {
+ return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
+ });
+ return '';
+ },
+ getTextContent: function (elem) {
+ function getText(e, strings) {
+ // If text node get the text and return
+ if (e.nodeType === Node.TEXT_NODE) {
+ strings.push(e.data);
+ } else {
+ // if an element for through all the children elements looking for text
+ if (e.nodeType === Node.ELEMENT_NODE) {
+ // check to see if IMG or AREA element and to use ALT content if defined
+ let tagName = e.tagName.toLowerCase();
+ if (tagName === 'img' || tagName === 'area') {
+ if (e.alt) {
+ strings.push(e.alt);
+ }
+ } else {
+ let c = e.firstChild;
+ while (c) {
+ getText(c, strings);
+ c = c.nextSibling;
+ } // end loop
+ }
+ }
}
- if (flag) {
- event.stopPropagation();
- event.preventDefault();
+ } // end function getStrings
+ // Create return object
+ let str = 'Test',
+ strings = [];
+ getText(elem, strings);
+ if (strings.length) str = strings.join(' ');
+ return str;
+ },
+ getAccessibleName: function (elem) {
+ let labelledbyIds = elem.getAttribute('aria-labelledby'),
+ label = elem.getAttribute('aria-label'),
+ title = elem.getAttribute('title'),
+ name = '';
+ if (labelledbyIds && labelledbyIds.length) {
+ let str,
+ strings = [],
+ ids = labelledbyIds.split(' ');
+ if (!ids.length) ids = [labelledbyIds];
+ for (let i = 0, l = ids.length; i < l; i += 1) {
+ let e = document.getElementById(ids[i]);
+ if (e) str = this.getTextContent(e);
+ if (str && str.length) strings.push(str);
+ }
+ name = strings.join(' ');
+ } else {
+ if (this.isNotEmptyString(label)) {
+ name = label;
+ } else {
+ if (this.isNotEmptyString(title)) {
+ name = title;
+ }
}
}
-
- handleMenuitemAction(tgt) {
- switch (tgt.getAttribute('data-id')) {
- case '':
- // this means there were no headings or landmarks in the list
- break;
-
- default:
- this.closePopup();
- skipToElement(tgt);
- break;
+ return name;
+ },
+ isVisible: function (element) {
+ function isVisibleRec(el) {
+ if (el.parentNode.nodeType !== 1 || el.parentNode.tagName === 'BODY') {
+ return true;
}
+ const computedStyle = window.getComputedStyle(el);
+ const display = computedStyle.getPropertyValue('display');
+ const visibility = computedStyle.getPropertyValue('visibility');
+ const hidden = el.getAttribute('hidden');
+ if (display === 'none' || visibility === 'hidden' || hidden !== null) {
+ return false;
+ }
+ const isVis = isVisibleRec(el.parentNode);
+ return isVis;
}
- handleMenuitemKeydown(event) {
- let tgt = event.currentTarget,
- key = event.key,
- flag = false;
-
- function isPrintableCharacter(str) {
- return str.length === 1 && str.match(/\S/);
- }
- if (event.ctrlKey || event.altKey || event.metaKey) {
- return;
+ return isVisibleRec(element);
+ },
+ getHeadings: function (targets) {
+ let dataId, level;
+ if (typeof targets !== 'string') {
+ targets = this.config.headings;
+ }
+ let headingElementsArr = [];
+ if (typeof targets !== 'string' || targets.length === 0) return;
+ const headings = document.querySelectorAll(targets);
+ for (let i = 0, len = headings.length; i < len; i += 1) {
+ let heading = headings[i];
+ let role = heading.getAttribute('role');
+ if (typeof role === 'string' && role === 'presentation') continue;
+ if (
+ this.isVisible(heading) &&
+ this.isNotEmptyString(heading.innerHTML)
+ ) {
+ if (heading.hasAttribute('data-skip-to-id')) {
+ dataId = heading.getAttribute('data-skip-to-id');
+ } else {
+ heading.setAttribute('data-skip-to-id', this.skipToIdIndex);
+ dataId = this.skipToIdIndex;
+ }
+ level = heading.tagName.substring(1);
+ const headingItem = {};
+ headingItem.dataId = dataId.toString();
+ headingItem.class = 'heading';
+ headingItem.name = this.getTextContent(heading);
+ headingItem.ariaLabel = headingItem.name + ', ';
+ headingItem.ariaLabel += this.config.headingLevelLabel + ' ' + level;
+ headingItem.tagName = heading.tagName.toLowerCase();
+ headingItem.role = 'heading';
+ headingItem.level = level;
+ headingElementsArr.push(headingItem);
+ this.skipToIdIndex += 1;
}
- if (event.shiftKey) {
- if (isPrintableCharacter(key)) {
- this.setFocusByFirstCharacter(tgt, key);
- flag = true;
+ }
+ return headingElementsArr;
+ },
+ getLocalizedLandmarkName: function (tagName, name) {
+ let n;
+ switch (tagName) {
+ case 'aside':
+ n = this.config.asideLabel;
+ break;
+ case 'footer':
+ n = this.config.footerLabel;
+ break;
+ case 'form':
+ n = this.config.formLabel;
+ break;
+ case 'header':
+ n = this.config.headerLabel;
+ break;
+ case 'main':
+ n = this.config.mainLabel;
+ break;
+ case 'nav':
+ n = this.config.navLabel;
+ break;
+ case 'section':
+ case 'region':
+ n = this.config.regionLabel;
+ break;
+ case 'search':
+ n = this.config.searchLabel;
+ break;
+ // When an ID is used as a selector, assume for main content
+ default:
+ n = tagName;
+ break;
+ }
+ if (this.isNotEmptyString(name)) {
+ n += ': ' + name;
+ }
+ return n;
+ },
+ getNestingLevel: function (landmark, landmarks) {
+ let nestingLevel = 0;
+ let parentNode = landmark.parentNode;
+ while (parentNode) {
+ for (let i = 0; i < landmarks.length; i += 1) {
+ if (landmarks[i] === parentNode) {
+ nestingLevel += 1;
+ // no more than 3 levels of nesting supported
+ if (nestingLevel === 3) {
+ return 3;
+ }
+ continue;
}
- if (event.key === 'Tab') {
- this.buttonNode.focus();
- this.closePopup();
- flag = true;
+ }
+ parentNode = parentNode.parentNode;
+ }
+ return nestingLevel;
+ },
+ getLandmarks: function (targets, allFlag) {
+ if (typeof allFlag !== 'boolean') {
+ allFlag = false;
+ }
+ if (typeof targets !== 'string') {
+ targets = this.config.landmarks;
+ }
+ let landmarks = document.querySelectorAll(targets);
+ let mainElements = [];
+ let searchElements = [];
+ let navElements = [];
+ let asideElements = [];
+ let footerElements = [];
+ let regionElements = [];
+ let otherElements = [];
+ let allLandmarks = [];
+ let dataId = '';
+ for (let i = 0, len = landmarks.length; i < len; i += 1) {
+ let landmark = landmarks[i];
+ // if skipto is a landmark don't include it in the list
+ if (landmark === this.domNode) {
+ continue;
+ }
+ let role = landmark.getAttribute('role');
+ let tagName = landmark.tagName.toLowerCase();
+ if (typeof role === 'string' && role === 'presentation') continue;
+ if (this.isVisible(landmark)) {
+ if (!role) role = tagName;
+ let name = this.getAccessibleName(landmark);
+ if (typeof name !== 'string') {
+ name = '';
}
- } else {
- switch (key) {
- case 'Enter':
- case ' ':
- this.handleMenuitemAction(tgt);
- flag = true;
+ // normalize tagNames
+ switch (role) {
+ case 'banner':
+ tagName = 'header';
break;
- case 'Esc':
- case 'Escape':
- this.closePopup();
- this.buttonNode.focus();
- flag = true;
+ case 'complementary':
+ tagName = 'aside';
break;
- case 'Up':
- case 'ArrowUp':
- this.setFocusToPreviousMenuitem(tgt);
- flag = true;
+ case 'contentinfo':
+ tagName = 'footer';
break;
- case 'ArrowDown':
- case 'Down':
- this.setFocusToNextMenuitem(tgt);
- flag = true;
+ case 'form':
+ tagName = 'form';
break;
- case 'Home':
- case 'PageUp':
- this.setFocusToFirstMenuitem();
- flag = true;
+ case 'main':
+ tagName = 'main';
break;
- case 'End':
- case 'PageDown':
- this.setFocusToLastMenuitem();
- flag = true;
+ case 'navigation':
+ tagName = 'nav';
+ break;
+ case 'region':
+ tagName = 'section';
break;
- case 'Tab':
- this.closePopup();
+ case 'search':
+ tagName = 'search';
break;
default:
- if (isPrintableCharacter(key)) {
- this.setFocusByFirstCharacter(tgt, key);
- flag = true;
- }
break;
}
- }
- if (flag) {
- event.stopPropagation();
- event.preventDefault();
- }
- }
-
- handleMenuitemClick(event) {
- this.handleMenuitemAction(event.currentTarget);
- event.stopPropagation();
- event.preventDefault();
- }
-
- handleMenuitemPointerenter(event) {
- let tgt = event.currentTarget;
- tgt.focus();
- }
-
- handleBackgroundPointerdown(event) {
- if (!this.containerNode.contains(event.target)) {
- if (this.isOpen()) {
- this.closePopup();
- this.buttonNode.focus();
+ // if using ID for selectQuery give tagName as main
+ if (
+ [
+ 'aside',
+ 'footer',
+ 'form',
+ 'header',
+ 'main',
+ 'nav',
+ 'section',
+ 'search',
+ ].indexOf(tagName) < 0
+ ) {
+ tagName = 'main';
}
- }
- }
- }
-
- (function() {
-
- const SkipTo = {
- skipToId: 'id-skip-to',
- domNode: null,
- buttonNode: null,
- menuNode: null,
- menuitemNodes: [],
- firstMenuitem: false,
- lastMenuitem: false,
- firstChars: [],
- headingLevels: [],
- skipToIdIndex: 1,
- // Default configuration values
- config: {
- // Feature switches
- enableHeadingLevelShortcuts: true,
-
- // Customization of button and menu
- altShortcut: '0', // default shortcut key is the number zero
- optionShortcut: 'ยบ', // default shortcut key character associated with option+0 on mac
- attachElement: 'body',
- displayOption: 'popup', // Line edited by pre-build script, fixed
- // container element, use containerClass for custom styling
- containerElement: 'div',
- containerRole: '',
- customClass: '',
-
- // Button labels and messages
- buttonLabel: 'Skip To Content',
- altLabel: 'Alt',
- optionLabel: 'Option',
- buttonShortcut: ' ($modifier+$key)',
- altButtonAriaLabel: 'Skip To Content, shortcut Alt plus $key',
- optionButtonAriaLabel: 'Skip To Content, shortcut Option plus $key',
-
- // Menu labels and messages
- menuLabel: 'Landmarks and Headings',
- landmarkGroupLabel: 'Landmark Regions',
- headingGroupLabel: 'Headings',
- headingLevelLabel: 'Heading level',
- mainLabel: 'main',
- searchLabel: 'search',
- navLabel: 'navigation',
- regionLabel: 'region',
- asideLabel: 'complementary',
- footerLabel: 'contentinfo',
- headerLabel: 'banner',
- formLabel: 'form',
- msgNoLandmarksFound: 'No landmarks found',
- msgNoHeadingsFound: 'No headings found',
-
- // Selectors for landmark and headings sections
- landmarks: 'main search navigation complementary',
- headings: 'main h1 h2',
-
- // Place holders for configuration
- colorTheme: 'aria',
- fontFamily: '',
- fontSize: '',
- positionLeft: '',
- mediaBreakPoint: '',
- menuTextColor: '',
- menuBackgroundColor: '',
- menuitemFocusTextColor: '',
- menuitemFocusBackgroundColor: '',
- focusBorderColor: '',
- buttonTextColor: '',
- buttonBackgroundColor: '',
- zIndex: '',
- },
- colorThemes: {
- 'default': {
- fontFamily: 'inherit',
- fontSize: 'inherit',
- positionLeft: '46%',
- mediaBreakPoint: '540',
- menuTextColor: '#1a1a1a',
- menuBackgroundColor: '#dcdcdc',
- menuitemFocusTextColor: '#eeeeee',
- menuitemFocusBackgroundColor: '#1a1a1a',
- focusBorderColor: '#1a1a1a',
- buttonTextColor: '#1a1a1a',
- buttonBackgroundColor: '#eeeeee',
- zIndex: '100000',
- },
- 'aria': {
- hostnameSelector: 'w3.org',
- pathnameSelector: 'ARIA/apg',
- fontFamily: 'sans-serif',
- fontSize: '10pt',
- positionLeft: '7%',
- menuTextColor: '#000',
- menuBackgroundColor: '#def',
- menuitemFocusTextColor: '#fff',
- menuitemFocusBackgroundColor: '#005a9c',
- focusBorderColor: '#005a9c',
- buttonTextColor: '#005a9c',
- buttonBackgroundColor: '#ddd',
- },
- 'illinois': {
- hostnameSelector: 'illinois.edu',
- menuTextColor: '#00132c',
- menuBackgroundColor: '#cad9ef',
- menuitemFocusTextColor: '#eeeeee',
- menuitemFocusBackgroundColor: '#00132c',
- focusBorderColor: '#ff552e',
- buttonTextColor: '#444444',
- buttonBackgroundColor: '#dddede',
- },
- 'skipto': {
- hostnameSelector: 'skipto-landmarks-headings.github.io',
- fontSize: '14px',
- menuTextColor: '#00132c',
- menuBackgroundColor: '#cad9ef',
- menuitemFocusTextColor: '#eeeeee',
- menuitemFocusBackgroundColor: '#00132c',
- focusBorderColor: '#ff552e',
- buttonTextColor: '#444444',
- buttonBackgroundColor: '#dddede',
- },
- 'uic': {
- hostnameSelector: 'uic.edu',
- menuTextColor: '#001e62',
- menuBackgroundColor: '#f8f8f8',
- menuitemFocusTextColor: '#ffffff',
- menuitemFocusBackgroundColor: '#001e62',
- focusBorderColor: '#d50032',
- buttonTextColor: '#ffffff',
- buttonBackgroundColor: '#001e62',
- },
- 'uillinois': {
- hostnameSelector: 'uillinois.edu',
- menuTextColor: '#001e62',
- menuBackgroundColor: '#e8e9ea',
- menuitemFocusTextColor: '#f8f8f8',
- menuitemFocusBackgroundColor: '#13294b',
- focusBorderColor: '#dd3403',
- buttonTextColor: '#e8e9ea',
- buttonBackgroundColor: '#13294b',
- },
- 'uis': {
- hostnameSelector: 'uis.edu',
- menuTextColor: '#036',
- menuBackgroundColor: '#fff',
- menuitemFocusTextColor: '#fff',
- menuitemFocusBackgroundColor: '#036',
- focusBorderColor: '#dd3444',
- buttonTextColor: '#fff',
- buttonBackgroundColor: '#036',
- }
- },
-
- /*
- * @method init
- *
- * @desc Initializes the skipto button and menu with default and user
- * defined options
- *
- * @param {object} config - Reference to configuration object
- * can be undefined
- */
- init: function(config) {
- let node;
-
- // Check if skipto is already loaded
- if (document.querySelector('style#' + this.skipToId)) {
- return;
- }
-
- let attachElement = document.body;
- if (config) {
- this.setupConfig(config);
- }
- if (typeof this.config.attachElement === 'string') {
- node = document.querySelector(this.config.attachElement);
- if (node && node.nodeType === Node.ELEMENT_NODE) {
- attachElement = node;
+ if (landmark.hasAttribute('aria-roledescription')) {
+ tagName = landmark
+ .getAttribute('aria-roledescription')
+ .trim()
+ .replace(' ', '-');
}
- }
- // Add skipto style sheet to document
- renderStyleElement(this.colorThemes, this.config, this.skipToId);
-
- new SkiptoMenuButton(attachElement, this.config, this.skipToId);
- },
-
- /*
- * @method setupConfig
- *
- * @desc Get configuration information from user configuration to change
- * default settings
- *
- * @param {object} appConfig - Javascript object with configuration information
- */
- setupConfig: function(appConfig) {
- let appConfigSettings;
- // Support version 4.1 configuration object structure
- // If found use it
- if ((typeof appConfig.settings === 'object') &&
- (typeof appConfig.settings.skipTo === 'object')) {
- appConfigSettings = appConfig.settings.skipTo;
- }
- else {
- // Version 5.0 removes the requirement for the "settings" and "skipto" properties
- // to reduce the complexity of configuring skipto
- if ((typeof appConfig === 'undefined') ||
- (typeof appConfig !== 'object')) {
- appConfigSettings = {};
+ if (landmark.hasAttribute('data-skip-to-id')) {
+ dataId = landmark.getAttribute('data-skip-to-id');
+ } else {
+ landmark.setAttribute('data-skip-to-id', this.skipToIdIndex);
+ dataId = this.skipToIdIndex;
}
- else {
- appConfigSettings = appConfig;
+ const landmarkItem = {};
+ landmarkItem.dataId = dataId.toString();
+ landmarkItem.class = 'landmark';
+ landmarkItem.hasName = name.length > 0;
+ landmarkItem.name = this.getLocalizedLandmarkName(tagName, name);
+ landmarkItem.tagName = tagName;
+ landmarkItem.nestingLevel = 0;
+ if (allFlag) {
+ landmarkItem.nestingLevel = this.getNestingLevel(
+ landmark,
+ landmarks
+ );
}
- }
+ this.skipToIdIndex += 1;
+ allLandmarks.push(landmarkItem);
- for (const name in appConfigSettings) {
- //overwrite values of our local config, based on the external config
- if ((typeof this.config[name] !== 'undefined') &&
- ((typeof appConfigSettings[name] === 'string') &&
- (appConfigSettings[name].length > 0 ) ||
- typeof appConfigSettings[name] === 'boolean')
- ) {
- this.config[name] = appConfigSettings[name];
- } else {
- console.warn('[SkipTo]: Unsuported or deprecated configuration option "' + name + '".');
+ // For sorting landmarks into groups
+ switch (tagName) {
+ case 'main':
+ mainElements.push(landmarkItem);
+ break;
+ case 'search':
+ searchElements.push(landmarkItem);
+ break;
+ case 'nav':
+ navElements.push(landmarkItem);
+ break;
+ case 'aside':
+ asideElements.push(landmarkItem);
+ break;
+ case 'footer':
+ footerElements.push(landmarkItem);
+ break;
+ case 'section':
+ // Regions must have accessible name to be included
+ if (landmarkItem.hasName) {
+ regionElements.push(landmarkItem);
+ }
+ break;
+ default:
+ otherElements.push(landmarkItem);
+ break;
}
}
}
- };
-
- // Initialize skipto menu button with onload event
- window.addEventListener('load', function() {
- SkipTo.init(window.SkipToConfig);
- });
- })();
-
+ if (allFlag) {
+ return allLandmarks;
+ }
+ return [].concat(
+ mainElements,
+ searchElements,
+ navElements,
+ asideElements,
+ regionElements,
+ footerElements,
+ otherElements
+ );
+ },
+ };
+ // Initialize skipto menu button with onload event
+ window.addEventListener('load', function () {
+ SkipTo.init(
+ window.SkipToConfig ||
+ (typeof window.Joomla === 'object' &&
+ typeof window.Joomla.getOptions === 'function'
+ ? window.Joomla.getOptions('skipto-settings', {})
+ : {})
+ );
+ });
})();
+/*@end @*/
From 332973044d77e9382af5a9799d3c720c7b12b552 Mon Sep 17 00:00:00 2001
From: alflennik
Date: Mon, 13 Mar 2023 14:23:47 -0400
Subject: [PATCH 5/7] Remove unneeded iframe magic number adjustment
---
_external/aria-practices | 2 +-
content-assets/wai-aria-practices/shared/js/app.js | 5 +++--
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/_external/aria-practices b/_external/aria-practices
index 8776df8f6..a74962f1f 160000
--- a/_external/aria-practices
+++ b/_external/aria-practices
@@ -1 +1 @@
-Subproject commit 8776df8f6cadfd9b4a5e718b67fb2afc285f8ffb
+Subproject commit a74962f1f829537c93de996b5d9b0ba2660cd95a
diff --git a/content-assets/wai-aria-practices/shared/js/app.js b/content-assets/wai-aria-practices/shared/js/app.js
index 293dc04e9..812016054 100644
--- a/content-assets/wai-aria-practices/shared/js/app.js
+++ b/content-assets/wai-aria-practices/shared/js/app.js
@@ -55,7 +55,8 @@
}
const iframe = document.querySelector(`.${data.iframe}`);
if (!iframe) return;
- const magicNumberAdjustment = 35;
- iframe.style.height = `${data.height + magicNumberAdjustment}px`;
+ // const magicNumberAdjustment = 35;
+ // iframe.style.height = `${data.height + magicNumberAdjustment}px`;
+ iframe.style.height = data.height + 'px';
}
})();
From 90b4bee12c53e4a26e1c25290d09e0cba9a20be0 Mon Sep 17 00:00:00 2001
From: alflennik
Date: Mon, 27 Mar 2023 17:39:22 -0400
Subject: [PATCH 6/7] Update support tables to use production url
---
ARIA/apg/patterns/button/examples/button.md | 6 +++---
_external/aria-practices | 2 +-
content-assets/wai-aria-practices/shared/js/app.js | 2 --
3 files changed, 4 insertions(+), 6 deletions(-)
diff --git a/ARIA/apg/patterns/button/examples/button.md b/ARIA/apg/patterns/button/examples/button.md
index cd80c155d..55095cc3f 100644
--- a/ARIA/apg/patterns/button/examples/button.md
+++ b/ARIA/apg/patterns/button/examples/button.md
@@ -12,7 +12,7 @@ permalink: /ARIA/apg/patterns/button/examples/button/
sidebar: true
-footer: " "
+footer: " "
# Context here: https://github.com/w3c/wai-aria-practices/issues/31
type_of_guidance: APG
@@ -271,7 +271,7 @@ if (enableSidebar) document.body.classList.add('has-sidebar');
Assistive Technology Support
Command Button