From e68cd949b1cd1847b0e694203b3ee206d864caee Mon Sep 17 00:00:00 2001 From: Isabel Del Castillo Date: Wed, 27 Apr 2022 11:54:42 -0500 Subject: [PATCH 1/5] update timestamped example directory and references.csv --- tests/minimal-data-grid/data/references.csv | 2 +- .../2022-4-27_115334/css/dataGrids.css | 94 ++ .../2022-4-27_115334/css/layoutGrids.css | 185 ++++ .../2022-4-27_115334/css/menuButton.css | 36 + .../reference/2022-4-27_115334/dataGrids.html | 852 +++++++++++++++++ .../arrows-group-in-four-directions-2.png | Bin 0 -> 15495 bytes .../arrows-group-in-four-directions-3.png | Bin 0 -> 15664 bytes .../imgs/arrows-group-in-four-directions.png | Bin 0 -> 703 bytes .../2022-4-27_115334/imgs/black_keys.png | Bin 0 -> 8414 bytes .../reference/2022-4-27_115334/imgs/keys.png | Bin 0 -> 372 bytes .../2022-4-27_115334/imgs/pencil-icon.png | Bin 0 -> 5253 bytes .../reference/2022-4-27_115334/js/dataGrid.js | 874 ++++++++++++++++++ .../2022-4-27_115334/js/dataGrids.js | 50 + .../2022-4-27_115334/js/layoutGrids.js | 211 +++++ .../2022-4-27_115334/js/menuButton.js | 519 +++++++++++ 15 files changed, 2822 insertions(+), 1 deletion(-) create mode 100644 tests/minimal-data-grid/reference/2022-4-27_115334/css/dataGrids.css create mode 100644 tests/minimal-data-grid/reference/2022-4-27_115334/css/layoutGrids.css create mode 100644 tests/minimal-data-grid/reference/2022-4-27_115334/css/menuButton.css create mode 100644 tests/minimal-data-grid/reference/2022-4-27_115334/dataGrids.html create mode 100644 tests/minimal-data-grid/reference/2022-4-27_115334/imgs/arrows-group-in-four-directions-2.png create mode 100644 tests/minimal-data-grid/reference/2022-4-27_115334/imgs/arrows-group-in-four-directions-3.png create mode 100644 tests/minimal-data-grid/reference/2022-4-27_115334/imgs/arrows-group-in-four-directions.png create mode 100644 tests/minimal-data-grid/reference/2022-4-27_115334/imgs/black_keys.png create mode 100644 tests/minimal-data-grid/reference/2022-4-27_115334/imgs/keys.png create mode 100644 tests/minimal-data-grid/reference/2022-4-27_115334/imgs/pencil-icon.png create mode 100644 tests/minimal-data-grid/reference/2022-4-27_115334/js/dataGrid.js create mode 100644 tests/minimal-data-grid/reference/2022-4-27_115334/js/dataGrids.js create mode 100644 tests/minimal-data-grid/reference/2022-4-27_115334/js/layoutGrids.js create mode 100644 tests/minimal-data-grid/reference/2022-4-27_115334/js/menuButton.js diff --git a/tests/minimal-data-grid/data/references.csv b/tests/minimal-data-grid/data/references.csv index e33739ea8..6eb90c232 100644 --- a/tests/minimal-data-grid/data/references.csv +++ b/tests/minimal-data-grid/data/references.csv @@ -2,7 +2,7 @@ refId,value author,Isabel Del Castillo authorEmail,isa.delcastillo5@gmail.com title,Data Grid Example 1: Minimal Data Grid -reference,reference/2021-3-8_151542/dataGrids.html +reference,reference/2022-4-27_115334/dataGrids.html designPattern,https://w3c.github.io/aria-practices/#grid example,https://w3c.github.io/aria-practices/examples/grid/dataGrids.html grid,https://w3c.github.io/aria/#grid diff --git a/tests/minimal-data-grid/reference/2022-4-27_115334/css/dataGrids.css b/tests/minimal-data-grid/reference/2022-4-27_115334/css/dataGrids.css new file mode 100644 index 000000000..6955a5a4f --- /dev/null +++ b/tests/minimal-data-grid/reference/2022-4-27_115334/css/dataGrids.css @@ -0,0 +1,94 @@ +.annotate { + font-style: italic; + color: #366ed4; +} + +.hidden { + display: none !important; +} + +[role="button"] { + cursor: pointer; +} + +[aria-sort="ascending"] { + position: relative; +} + +[aria-sort="ascending"]::after { + content: " "; + border-bottom: 0.4em solid black; + border-left: 0.4em solid transparent; + border-right: 0.4em solid transparent; + position: absolute; + right: 1em; + top: 0.8em; +} + +[aria-sort="descending"] { + position: relative; +} + +[aria-sort="descending"]::after { + content: " "; + border-left: 0.4em solid transparent; + border-right: 0.4em solid transparent; + border-top: 0.4em solid black; + position: absolute; + right: 1em; + top: 0.8em; +} + +.edit-text-button { + color: #360; + display: block; + position: relative; +} + +.edit-text-button::after { + background-image: url("../imgs/pencil-icon.png"); + background-position: center; + background-repeat: no-repeat; + background-size: 44px; + content: " "; + height: 17px; + opacity: 0.6; + position: absolute; + right: -24px; + top: 0; + width: 20px; +} + +.edit-text-button:hover, +.edit-text-button:focus { + color: black; +} + +.edit-text-button:hover::after, +.edit-text-button:focus::after { + opacity: 1; +} + +[role="gridcell"]:focus, +[role="gridcell"] *:focus, +[role="grid"] [tabindex="0"]:focus { + outline: #005a9c; + outline-style: dotted; + outline-width: 3px; +} + +#arrow-keys-indicator { + bottom: 10px; + left: 0; + position: fixed; + height: 65px; + width: 85px; + background: url("../imgs/black_keys.png") no-repeat; + background-size: contain; +} + +@media screen and (max-width: 1000px) { + #arrow-keys-indicator { + display: none; + } +} diff --git a/tests/minimal-data-grid/reference/2022-4-27_115334/css/layoutGrids.css b/tests/minimal-data-grid/reference/2022-4-27_115334/css/layoutGrids.css new file mode 100644 index 000000000..bc1e411a1 --- /dev/null +++ b/tests/minimal-data-grid/reference/2022-4-27_115334/css/layoutGrids.css @@ -0,0 +1,185 @@ +.hidden { + display: none !important; +} + +#arrow-keys-indicator { + bottom: 10px; + left: 0; + position: fixed; + height: 65px; + width: 85px; + background: url("../imgs/black_keys.png") no-repeat; + background-size: contain; +} + +@media screen and (max-width: 1000px) { + #arrow-keys-indicator { + display: none; + } + + .indicator_description { + display: none; + } +} + +.accessible_elem { + clip: rect(1px 1px 1px 1px); + clip: rect(1px, 1px, 1px, 1px); + height: 1px; + overflow: hidden; + position: absolute; + white-space: nowrap; + width: 1px; +} + +.list-links { + font-size: 0; +} + +.list-link { + background: #eee; + border: 1px solid #bbb; + display: inline-block; + font-size: 14px; + height: 40px; + margin: 5px 0 0; + padding: 5px; + position: relative; + vertical-align: middle; + width: 120px; +} + +[role="gridcell"], +[role="gridcell"] [tabindex] { + display: inline-block; + position: relative; +} + +[role="gridcell"]:focus, +[role="gridcell"] *:focus { + outline: #005a9c; + outline-style: dotted; + outline-width: 3px; +} + +.grid-nux { + background: #eaf9ef; + position: absolute; + max-width: 500px; + border: 1px solid #bbb; + padding: 0 15px 20px; + margin-top: 20px; + box-shadow: 2px 2px 3px rgb(0 0 0 / 30%); +} + +.grid-nux::after, +.grid-nux::before { + bottom: 100%; + left: 20px; + border: solid transparent; + content: " "; + height: 0; + width: 0; + position: absolute; + pointer-events: none; +} + +.grid-nux::after { + border-color: rgb(136 183 213 / 0%); + border-bottom-color: #eaf9ef; + border-width: 10px; + margin-left: -10px; +} + +.grid-nux::before { + border-color: rgb(194 225 245 / 0%); + border-bottom-color: #bbb; + border-width: 11px; + margin-left: -11px; +} + +.grid-nux-header { + font-weight: bold; +} + +.indicator_graphic { + float: right; + margin-left: 10px; +} + +.close-nux-button { + color: #360; + cursor: default; + position: absolute; + right: 10px; + bottom: 10px; + text-decoration: underline; +} + +.recipient-list { + background: #eee; + border: 1px solid #ddd; + margin-bottom: 10px; + padding: 5px 15px; + position: relative; +} + +#send_to_label { + font-size: 14px; + font-weight: bold; + position: absolute; + top: 1.2em; +} + +.pill-list { + background: white; + border: 1px solid #ccc; + font-size: 0; + margin-bottom: 5px; + margin-left: 65px; + min-height: 31px; + padding: 0 5px 5px; +} + +.pill-item { + background: #eee; + border: 1px solid #3a69b6; + border-radius: 2px; + color: #3a69b6; + display: inline-block; + font-size: 14px; + margin: 5px 5px 0 0; + padding: 0.3em; +} + +.pill-name { + text-decoration: none; +} + +.pill-remove { + cursor: default; + margin-left: 10px; +} + +#recipient-form { + margin-left: 65px; +} + +#add-recipient-input { + font-size: 14px; +} + +.ex3_result_header { + margin: 0; + font-style: normal; + font-weight: bold; +} + +.ex3_result_indices { + margin-bottom: 40px; +} + +.ex3_pagination { + margin-top: 40px; + text-align: center; +} diff --git a/tests/minimal-data-grid/reference/2022-4-27_115334/css/menuButton.css b/tests/minimal-data-grid/reference/2022-4-27_115334/css/menuButton.css new file mode 100644 index 000000000..b880b7adc --- /dev/null +++ b/tests/minimal-data-grid/reference/2022-4-27_115334/css/menuButton.css @@ -0,0 +1,36 @@ +button { + cursor: pointer; + font-size: 110%; +} + +.menu-wrapper { + position: relative; +} + +ul[role="menu"] { + display: none; + position: absolute; + margin: 0; + padding: 0; + z-index: 1; +} + +ul[role="menu"] li { + list-style: none; +} + +[role="menu"] { + padding: 0; + width: 8em; + border: thin solid black; + background-color: #eee; +} + +[role="menuitem"] { + padding: 0.25em; +} + +[role="menuitem"]:focus, +[role="menuitem"]:hover { + background-color: #fff; +} diff --git a/tests/minimal-data-grid/reference/2022-4-27_115334/dataGrids.html b/tests/minimal-data-grid/reference/2022-4-27_115334/dataGrids.html new file mode 100644 index 000000000..a48e7e090 --- /dev/null +++ b/tests/minimal-data-grid/reference/2022-4-27_115334/dataGrids.html @@ -0,0 +1,852 @@ + + + + +Data Grid Examples | WAI-ARIA Authoring Practices 1.2 + + + + + + + + + + + + + + + + + + +
+

Data Grid Examples

+

+ Following are three example implementations of the + design pattern for grid + that demonstrate the keyboard interactions and ARIA features that enable accessible, interactive presentation + of tabular information. Each of the following three grids presents a set of financial + transactions. The first is a simple grid with minimum ARIA markup and keyboard support. The + second and third implementations add advanced features, such as content editing, sort, scroll, + and show/hide. +

+

Similar examples include:

+ +
+

Examples

+
+
+

Example 1: Minimal Data Grid

+
+ +
+

Transactions January 1 through January 6

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
DateTypeDescriptionAmountBalance
01-Jan-16Deposit + Cash Deposit + $1,000,000.00$1,000,000.00
02-Jan-16Debit + Down Town Grocery + $250.00$999,750.00
03-Jan-16Debit + Hot Coffee + $9.00$999,741.00
04-Jan-16Debit + The Filling Station + $88.00$999,653.00
05-Jan-16Debit + Tinker's Hardware + $3,421.00$996,232.00
06-Jan-16Debit + Cutey's Salon + $700.00$995,532.00
+
+ +

Notes

+
    +
  1. + Data cells can be focused using standard navigation keys, including directional arrows, Home, + End, Control + Home, and Control + End. +
  2. +
  3. + The Page Down and Page Up keys are not supported since such + scroll-like functions are not useful with so few rows. +
  4. +
  5. The links can be activated with the keyboard when focused.
  6. +
  7. + Since the header cells do not provide any functionality, they are not focusable. + Screen reader users are still aware of their presence because row and column headers are announced by screen readers during navigation. + And, they are also navigable when using a screen reader's reading or browsing mode. +
  8. +
+
+
+
+

Example 2: Sortable Data Grid With Editable Cells

+
+ +
+

Transactions January 1 through January 7

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Date + TypeDescriptionCategory + Amount + Balance
01-Jan-16Deposit +
+ Cash Deposit + +
+
$1,000,000.00$1,000,000.00
02-Jan-16Debit +
+ Down Town + Grocery + +
+
$250.00$999,750.00
03-Jan-16Debit +
+ Hot Coffee + +
+
$9.00$999,741.00
04-Jan-16Debit +
+ The Filling + Station + +
+
$88.00$999,653.00
05-Jan-16Debit +
+ Tinker's + Hardware + +
+
$3,421.00$996,232.00
06-Jan-16Debit +
+ Cutey's Salon + +
+
$700.00$995,532.00
07-Jan-16Debit +
+ My Chocolate + Shop + +
+
$41.00$995,491.00
+
+ +

Notes

+
    +
  1. The navigation keys and functions are the same as example 1 except that the column + headers are focusable because the date and amount columns provide sort functionality.
  2. +
  3. A description may be edited by activating the cell.
  4. +
  5. A category may be changed by using the category popup menu.
  6. +
+
+
+
+

Example 3: Scrollable Data Grid With Column Hiding

+
+ +
+

Transactions for January 1 through January 15

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
DateTypeDescriptionCategoryAmountBalance
01-Jan-16Deposit + Cash Deposit + Income$1,000,000.00$1,000,000.00
02-Jan-16Debit + Down Town Grocery + Groceries$250.00$999,750.00
03-Jan-16Debit + Hot Coffee + Dining Out$9.00$999,741.00
04-Jan-16Debit + The Filling Station + Auto$88.00$999,653.00
05-Jan-16Debit + Tinker's Hardware + Household$3,421.00$996,232.00
06-Jan-16Debit + Cutey's Salon + Beauty$700.00$995,532.00
07-Jan-16Debit + My Chocolate Shop + Dining Out$41.00$995,491.00
08-Jan-16Debit + Who's Cook'n + Dining Out$150.00$995,341.00
09-Jan-16Debit + Dmuddy Paws + Pet$100.00$995,241.00
10-Jan-16Debit + West End Bikes + Recreation$6,420.00$988,821.00
11-Jan-16Debit + Pay More Cars + Auto$431,323.00$557,498.00
12-Jan-16Debit + The Interior Shop + Household$142,334.00$415,164.00
13-Jan-16Debit + Adventure Guys + Recreation$88,424.00$326,740.00
14-Jan-16Debit + Hungry Folks Place + Dining Out$313.00$326,427.00
15-Jan-16Debit + Horse Play + Recreation$2,421.00$324,006.00
+
+ +

Notes

+
    +
  1. + In addition to the navigation keys supported in examples 1 and 2, Page Down and + Page Up scroll the grid. +
  2. +
  3. + As navigating up or down scrolls the visible set of rows, the aria-rowindex + value of the row containing the focus informs the screen reader of the number of that row + within the total set of rows. +
  4. +
  5. Activating the "Hide Type and Category" button hides the type and category columns.
  6. +
  7. + The aria-colindex value on a cell informs screen readers of the + position of that cell within the row. + When one or more columns are hidden, screen reader users can be aware of the hidden columns + because those column numbers are not present as users navigate across a row. +
  8. +
+
+
+ +
+

Keyboard Support

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
keyFunction
+ Right Arrow + +
    +
  • Moves focus one cell to the right.
  • +
  • If focus is on the right-most cell in the row, focus does not move.
  • +
+
+ Left Arrow + +
    +
  • Moves focus one cell to the left.
  • +
  • If focus is on the left-most cell in the row, focus does not move.
  • +
+
+ Down Arrow + +
    +
  • Moves focus one cell down.
  • +
  • If focus is on the bottom cell in the column, focus does not move.
  • +
+
+ Up Arrow + +
    +
  • Moves focus one cell Up.
  • +
  • If focus is on the top cell in the column, focus does not move.
  • +
+
+ Page Down + +
    +
  • In example 3, moves focus down five rows, scrolling so the bottom row in the + currently visible set of rows becomes the first visible row.
  • +
  • If focus is in the last row, focus does not move.
  • +
+
+ Page Up + +
    +
  • In example 3, moves focus up 5 rows, scrolling so the top row in the currently + visible set of rows becomes the last visible row.
  • +
  • If focus is in the first row of the grid, focus does not move.
  • +
+
+ Home + moves focus to the first cell in the row that contains focus.
+ End + moves focus to the last cell in the row that contains focus.
+ Control + Home + moves focus to the first cell in the first row.
+ Control + End + moves focus to the last cell in the last row.
+
+ +
+

Role, Property, State, and Tabindex Attributes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
RoleAttributeElementUsage
+ grid + + table + +
    +
  • Identifies the element that serves as the grid widget container.
  • +
  • + Because focus is managed using + roving tabindex + , the grid element is not focusable. +
  • +
  • + Since the grid role is applied to a table element, the row + , rowheader, colheader, and gridcell roles do + not need to be specified because they are implied by tr, th, + and td tags. +
  • +
+
+ aria-labelledby="ID_REF" + + table + Refers to the heading element that labels the grid.
+ aria-rowcount="16" + + table + +
    +
  • In example 3, specified because a total of 16 rows are available, but fewer + than 16 rows are visible.
  • +
  • + In this case, to demonstrate this feature, some rows are hidden using display:none, + which excludes them from the browser's accessibility tree. +
  • +
  • + a more common scenario for using aria-rowcount is when not all data is + loaded into the DOM at one time. +
  • +
+
+ aria-colcount="6" + + table + +
    +
  • In example 3, specified because a total of 6 columns are available, but when + columns are hidden, fewer than 6 columns are visible.
  • +
  • + Similar to how aria-rowcount overrides the browser calculation of the + total number of rows, the browser uses this value for the total number of columns so + it can report the correct number when columns are hidden. +
  • +
+
+ aria-rowindex="INDEX_VALUE" + + tr + +
    +
  • Used in example 3 because not all rows are present in the accessibility tree.
  • +
  • Overrides the browser calculation of the row number.
  • +
  • Has a value from 1 to 16.
  • +
  • Note that it is 1-based, not 0-based.
  • +
+
+ aria-sort="ascending" + + th + In example 2, applied when a column is sorted in ascending order.
+ aria-sort="descending" + + th + In example 2, applied when a column is sorted in descending order.
+ aria-sort="none" + + th + In example 2, applied when a column is sortable but not sorted.
+ aria-colindex="INDEX_VALUE" + + th and td + +
    +
  • Used in example 3 because when the column hiding feature is used, not all + columns are present in the accessibility tree.
  • +
  • Overrides the browser calculation of the column number.
  • +
  • Has a value from 1 to 6.
  • +
  • Note that it is 1-based, not 0-based.
  • +
+
+
+ + + +
+

Javascript and CSS Source Code

+ +
+ +
+

HTML Source Code

+

Example 1: Minimal Data Grid

+ +
+ + + +

Example 2: Sortable Data Grid With Editable Cells

+ +
+ + + +

Example 3: Scrollable Data Grid With Column Hiding

+ +
+ + + + +
+
+ + + diff --git a/tests/minimal-data-grid/reference/2022-4-27_115334/imgs/arrows-group-in-four-directions-2.png b/tests/minimal-data-grid/reference/2022-4-27_115334/imgs/arrows-group-in-four-directions-2.png new file mode 100644 index 0000000000000000000000000000000000000000..ca32c5f713bdc79b8ad943c0f344a33a5eb06e7e GIT binary patch literal 15495 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 RsFn-9Y(a&6U-7EV{{v=o z<1fFQXIhiT@eRtMQYy(iUWZGoB>i}OU3yN^4RJ$WKEq|-eQJ(M-2S@r*U^sa>8Fo! zd`XQ;s%dz9&w)q5#lfg0N+9S?=wrLK6%)QqRnd7W;rz=u*YL>x;)-6W=GFUNSbN=k zuxsg03D@SB;8H^`w$^R;ZcJkIHaBZv=czc-*sfD^<}kZ&&6U>n+?qSb#rbNUHcr>8 zd3#vgzvgS}^!Hs~|8s|n_~jJL)_)ERO4SnAh?11Vl2ohYqEsNoU}Ruuu4`bVYhV^) zWME}rVr6WiZD43+U?5bZcLPO3ZhlH;S|x4`$%@lbfEpx0HU#IVm6RtIr81P4m+NKb eWfvzW7NqLs7p2dBXCnnv#Ng@b=d#Wzp$PzZIsYdB literal 0 HcmV?d00001 diff --git a/tests/minimal-data-grid/reference/2022-4-27_115334/imgs/black_keys.png b/tests/minimal-data-grid/reference/2022-4-27_115334/imgs/black_keys.png new file mode 100644 index 0000000000000000000000000000000000000000..7d8c7b8ac9b171fd948f9b80e7c325c90bf7e6c6 GIT binary patch literal 8414 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 literal 0 HcmV?d00001 diff --git a/tests/minimal-data-grid/reference/2022-4-27_115334/imgs/keys.png b/tests/minimal-data-grid/reference/2022-4-27_115334/imgs/keys.png new file mode 100644 index 0000000000000000000000000000000000000000..01d47a0da08efd46bb0aa8f7abd8784448c0b181 GIT binary patch literal 372 zcmV-)0gL{LP)2_h&c;BRh$m*bV9@E3)pp z`|RA0k%-`8n1&pns@41E;Mxnps*Jn#CNOyS+sE&pqsQlZhF>2yuDyxLFbx3eM2Mi* z(*rYmbqc36tZq;W_LA{Zu#lrgth$y4fU^z==bh&}z0r<{mQphHMOcJ;#-OPiiP+4H zLs-4&$#S2)iE!TkgDC)1wUVDlw|^J&q?^!J3-y~mlR(}CEDvf4D Sg1}Dz0000BnXHKRIGvz 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 csdg}A&q;eS?T{=N{bA78Cy;x5#ioyc0S&R!= 0 && + col >= 0 && + this.grid && + this.grid.length && + row < this.grid.length && + col < this.grid[row].length + ); +}; + +/** + * @param row + * The index of the cell's row + * @param col + * The index of the cell's column + * @returns {boolean} + * Returns whether or not the cell has been hidden. + */ +aria.Grid.prototype.isHidden = function (row, col) { + var cell = this.gridNode + .querySelectorAll(aria.GridSelector.ROW) + [row].querySelectorAll(aria.GridSelector.CELL)[col]; + return aria.Utils.hasClass(cell, aria.CSSClass.HIDDEN); +}; + +/** + * @description + * Clean up grid events + */ +aria.Grid.prototype.clearEvents = function () { + this.gridNode.removeEventListener('keydown', this.checkFocusChange); + this.gridNode.removeEventListener('keydown', this.delegateButtonHandler); + this.gridNode.removeEventListener('click', this.focusClickedCell); + this.gridNode.removeEventListener('click', this.delegateButtonHandler); + + if (this.paginationEnabled) { + this.gridNode.removeEventListener('keydown', this.checkPageChange); + } + + if (this.shouldRestructure) { + window.removeEventListener('resize', this.checkRestructureGrid); + } + + this.grid[this.focusedRow][this.focusedCol].removeEventListener( + 'focus', + this.showKeysIndicator + ); + this.grid[this.focusedRow][this.focusedCol].removeEventListener( + 'blur', + this.hideKeysIndicator + ); +}; + +/** + * @description + * Register grid events + */ +aria.Grid.prototype.registerEvents = function () { + this.clearEvents(); + + this.gridNode.addEventListener('keydown', this.checkFocusChange); + this.gridNode.addEventListener('keydown', this.delegateButtonHandler); + this.gridNode.addEventListener('click', this.focusClickedCell); + this.gridNode.addEventListener('click', this.delegateButtonHandler); + + if (this.paginationEnabled) { + this.gridNode.addEventListener('keydown', this.checkPageChange); + } + + if (this.shouldRestructure) { + window.addEventListener('resize', this.checkRestructureGrid); + } +}; + +/** + * @description + * Focus on the cell in the specified row and column + * @param row + * The index of the cell's row + * @param col + * The index of the cell's column + */ +aria.Grid.prototype.focusCell = function (row, col) { + if (this.setFocusPointer(row, col)) { + this.grid[row][col].focus(); + } +}; + +aria.Grid.prototype.showKeysIndicator = function () { + if (this.keysIndicator) { + aria.Utils.removeClass(this.keysIndicator, 'hidden'); + } +}; + +aria.Grid.prototype.hideKeysIndicator = function () { + if ( + this.keysIndicator && + this.grid[this.focusedRow][this.focusedCol].tabIndex === 0 + ) { + aria.Utils.addClass(this.keysIndicator, 'hidden'); + } +}; + +/** + * @description + * Triggered on keydown. Checks if an arrow key was pressed, and (if possible) + * moves focus to the next valid cell in the direction of the arrow key. + * @param event + * Keydown event + */ +aria.Grid.prototype.checkFocusChange = function (event) { + if (!event || this.navigationDisabled) { + return; + } + + this.findFocusedItem(event.target); + + var key = event.which || event.keyCode; + var rowCaret = this.focusedRow; + var colCaret = this.focusedCol; + var nextCell; + + switch (key) { + case aria.KeyCode.UP: + nextCell = this.getNextVisibleCell(0, -1); + rowCaret = nextCell.row; + colCaret = nextCell.col; + break; + case aria.KeyCode.DOWN: + nextCell = this.getNextVisibleCell(0, 1); + rowCaret = nextCell.row; + colCaret = nextCell.col; + break; + case aria.KeyCode.LEFT: + nextCell = this.getNextVisibleCell(-1, 0); + rowCaret = nextCell.row; + colCaret = nextCell.col; + break; + case aria.KeyCode.RIGHT: + nextCell = this.getNextVisibleCell(1, 0); + rowCaret = nextCell.row; + colCaret = nextCell.col; + break; + case aria.KeyCode.HOME: + if (event.ctrlKey) { + rowCaret = 0; + } + colCaret = 0; + break; + case aria.KeyCode.END: + if (event.ctrlKey) { + rowCaret = this.grid.length - 1; + } + colCaret = this.grid[this.focusedRow].length - 1; + break; + default: + return; + } + + if (this.paginationEnabled) { + if (rowCaret < this.topIndex) { + this.showFromRow(rowCaret, true); + } + + if (rowCaret >= this.topIndex + this.perPage) { + this.showFromRow(rowCaret, false); + } + } + + this.focusCell(rowCaret, colCaret); + event.preventDefault(); +}; + +/** + * @description + * Reset focused row and col if it doesn't match focusedRow and focusedCol + * @param focusedTarget + * Element that is currently focused by browser + */ +aria.Grid.prototype.findFocusedItem = function (focusedTarget) { + var focusedCell = this.grid[this.focusedRow][this.focusedCol]; + + if (focusedCell === focusedTarget || focusedCell.contains(focusedTarget)) { + return; + } + + for (var i = 0; i < this.grid.length; i++) { + for (var j = 0; j < this.grid[i].length; j++) { + if ( + this.grid[i][j] === focusedTarget || + this.grid[i][j].contains(focusedTarget) + ) { + this.setFocusPointer(i, j); + return; + } + } + } +}; + +/** + * @description + * Triggered on click. Finds the cell that was clicked on and focuses on it. + * @param event + * Keydown event + */ +aria.Grid.prototype.focusClickedCell = function (event) { + var clickedGridCell = this.findClosest(event.target, '[tabindex]'); + + for (var row = 0; row < this.grid.length; row++) { + for (var col = 0; col < this.grid[row].length; col++) { + if (this.grid[row][col] === clickedGridCell) { + this.setFocusPointer(row, col); + + if (!aria.Utils.matches(clickedGridCell, 'button[aria-haspopup]')) { + // Don't focus if it's a menu button (focus should be set to menu) + this.focusCell(row, col); + } + + return; + } + } + } +}; + +/** + * @description + * Triggered on click. Checks if user clicked on a header with aria-sort. + * If so, it sorts the column based on the aria-sort attribute. + * @param event + * Keydown event + */ +aria.Grid.prototype.delegateButtonHandler = function (event) { + var key = event.which || event.keyCode; + var target = event.target; + var isClickEvent = event.type === 'click'; + + if (!target) { + return; + } + + if ( + target.parentNode && + target.parentNode.matches('th[aria-sort]') && + (isClickEvent || key === aria.KeyCode.SPACE || key === aria.KeyCode.RETURN) + ) { + event.preventDefault(); + this.handleSort(target.parentNode); + } + + if ( + aria.Utils.matches(target, '.editable-text, .edit-text-button') && + (isClickEvent || key === aria.KeyCode.RETURN) + ) { + event.preventDefault(); + this.toggleEditMode(this.findClosest(target, '.editable-text'), true, true); + } + + if ( + aria.Utils.matches(target, '.edit-text-input') && + (key === aria.KeyCode.RETURN || key === aria.KeyCode.ESC) + ) { + event.preventDefault(); + this.toggleEditMode( + this.findClosest(target, '.editable-text'), + false, + key === aria.KeyCode.RETURN + ); + } +}; + +/** + * @description + * Toggles the mode of an editable cell between displaying the edit button + * and displaying the editable input. + * @param editCell + * Cell to toggle + * @param toggleOn + * Whether to show or hide edit input + * @param updateText + * Whether or not to update the button text with the input text + */ +aria.Grid.prototype.toggleEditMode = function (editCell, toggleOn, updateText) { + var onClassName = toggleOn ? 'edit-text-input' : 'edit-text-button'; + var offClassName = toggleOn ? 'edit-text-button' : 'edit-text-input'; + var onNode = editCell.querySelector('.' + onClassName); + var offNode = editCell.querySelector('.' + offClassName); + + if (toggleOn) { + onNode.value = offNode.innerText; + } else if (updateText) { + onNode.innerText = offNode.value; + } + + aria.Utils.addClass(offNode, aria.CSSClass.HIDDEN); + aria.Utils.removeClass(onNode, aria.CSSClass.HIDDEN); + offNode.setAttribute('tabindex', -1); + onNode.setAttribute('tabindex', 0); + onNode.focus(); + this.grid[this.focusedRow][this.focusedCol] = onNode; + this.navigationDisabled = toggleOn; +}; + +/** + * @description + * Sorts the column below the header node, based on the aria-sort attribute. + * aria-sort="none" => aria-sort="ascending" + * aria-sort="ascending" => aria-sort="descending" + * All other headers with aria-sort are reset to "none" + * + * Note: This implementation assumes that there is no pagination on the grid. + * @param headerNode + * Header DOM node + */ +aria.Grid.prototype.handleSort = function (headerNode) { + var columnIndex = headerNode.cellIndex; + var sortType = headerNode.getAttribute('aria-sort'); + + if (sortType === aria.SortType.ASCENDING) { + sortType = aria.SortType.DESCENDING; + } else { + sortType = aria.SortType.ASCENDING; + } + + var comparator = function (row1, row2) { + var row1Text = row1.children[columnIndex].innerText; + var row2Text = row2.children[columnIndex].innerText; + var row1Value = parseInt(row1Text.replace(/[^0-9.]+/g, '')); + var row2Value = parseInt(row2Text.replace(/[^0-9.]+/g, '')); + + if (sortType === aria.SortType.ASCENDING) { + return row1Value - row2Value; + } else { + return row2Value - row1Value; + } + }; + + this.sortRows(comparator); + this.setupFocusGrid(); + + Array.prototype.forEach.call( + this.gridNode.querySelectorAll(aria.GridSelector.SORT_HEADER), + function (headerCell) { + headerCell.setAttribute('aria-sort', aria.SortType.NONE); + } + ); + + headerNode.setAttribute('aria-sort', sortType); +}; + +/** + * @description + * Sorts the grid's rows according to the specified compareFn + * @param compareFn + * Comparison function to sort the rows + */ +aria.Grid.prototype.sortRows = function (compareFn) { + var rows = this.gridNode.querySelectorAll(aria.GridSelector.ROW); + var rowWrapper = rows[0].parentNode; + var dataRows = Array.prototype.slice.call(rows, 1); + + dataRows.sort(compareFn); + + dataRows.forEach( + function (row) { + rowWrapper.appendChild(row); + }.bind(this) + ); +}; + +/** + * @description + * Adds aria-rowindex and aria-colindex to the cells in the grid + */ +aria.Grid.prototype.setupIndices = function () { + var rows = this.gridNode.querySelectorAll(aria.GridSelector.ROW); + + for (var row = 0; row < rows.length; row++) { + var cols = rows[row].querySelectorAll(aria.GridSelector.CELL); + rows[row].setAttribute('aria-rowindex', row + 1); + + for (var col = 0; col < cols.length; col++) { + cols[col].setAttribute('aria-colindex', col + 1); + } + } +}; + +/** + * @description + * Determines the per page attribute of the grid, and shows/hides rows + * accordingly. + */ +aria.Grid.prototype.setupPagination = function () { + this.onPaginationChange = this.onPaginationChange || function () {}; + this.perPage = parseInt(this.gridNode.getAttribute('data-per-page')); + this.showFromRow(0, true); +}; + +aria.Grid.prototype.setPaginationChangeHandler = function (onPaginationChange) { + this.onPaginationChange = onPaginationChange; +}; + +/** + * @description + * Check if page up or page down was pressed, and show the next page if so. + * @param event + * Keydown event + */ +aria.Grid.prototype.checkPageChange = function (event) { + if (!event) { + return; + } + + var key = event.which || event.keyCode; + + if (key === aria.KeyCode.PAGE_UP) { + event.preventDefault(); + this.movePageUp(); + } else if (key === aria.KeyCode.PAGE_DOWN) { + event.preventDefault(); + this.movePageDown(); + } +}; + +aria.Grid.prototype.movePageUp = function () { + var startIndex = Math.max(this.perPage - 1, this.topIndex - 1); + this.showFromRow(startIndex, false); + this.focusCell(startIndex, this.focusedCol); +}; + +aria.Grid.prototype.movePageDown = function () { + var startIndex = this.topIndex + this.perPage; + this.showFromRow(startIndex, true); + this.focusCell(startIndex, this.focusedCol); +}; + +/** + * @description + * Scroll the specified row into view in the specified direction + * @param startIndex + * Row index to use as the start index + * @param scrollDown + * Whether to scroll the new page above or below the row index + */ +aria.Grid.prototype.showFromRow = function (startIndex, scrollDown) { + var dataRows = this.gridNode.querySelectorAll(aria.GridSelector.SCROLL_ROW); + var reachedTop = false; + var firstIndex = -1; + var endIndex = -1; + + if (startIndex < 0 || startIndex >= dataRows.length) { + return; + } + + for (var i = 0; i < dataRows.length; i++) { + if ( + (scrollDown && i >= startIndex && i < startIndex + this.perPage) || + (!scrollDown && i <= startIndex && i > startIndex - this.perPage) + ) { + aria.Utils.removeClass(dataRows[i], aria.CSSClass.HIDDEN); + + if (!reachedTop) { + this.topIndex = i; + reachedTop = true; + } + + if (firstIndex < 0) { + firstIndex = i; + } + endIndex = i; + } else { + aria.Utils.addClass(dataRows[i], aria.CSSClass.HIDDEN); + } + } + this.onPaginationChange(firstIndex, endIndex); +}; + +/** + * @description + * Throttle restructuring to only happen every 300ms + */ +aria.Grid.prototype.checkRestructureGrid = function () { + if (this.waitingToRestructure) { + return; + } + + this.waitingToRestructure = true; + + setTimeout(this.restructureGrid, 300); +}; + +/** + * @description + * Restructure grid based on the size. + */ +aria.Grid.prototype.restructureGrid = function () { + this.waitingToRestructure = false; + + var gridWidth = this.gridNode.offsetWidth; + var cells = this.gridNode.querySelectorAll(aria.GridSelector.CELL); + var currentWidth = 0; + + var focusedElement = this.gridNode.querySelector(aria.GridSelector.TABBABLE); + var shouldRefocus = document.activeElement === focusedElement; + var focusedIndex = this.focusedRow * this.grid[0].length + this.focusedCol; + + var newRow = document.createElement('div'); + newRow.setAttribute('role', 'row'); + this.gridNode.innerHTML = ''; + this.gridNode.append(newRow); + + cells.forEach(function (cell) { + var cellWidth = cell.offsetWidth; + + if (currentWidth > 0 && currentWidth >= gridWidth - cellWidth) { + newRow = document.createElement('div'); + newRow.setAttribute('role', 'row'); + this.gridNode.append(newRow); + currentWidth = 0; + } + + newRow.append(cell); + currentWidth += cellWidth; + }); + + this.setupFocusGrid(); + + this.focusedRow = Math.floor(focusedIndex / this.grid[0].length); + this.focusedCol = focusedIndex % this.grid[0].length; + + if (shouldRefocus) { + this.focusCell(this.focusedRow, this.focusedCol); + } +}; + +/** + * @description + * Get next cell to the right or left (direction) of the focused + * cell. + * @param currRow + * Row index to start searching from + * @param currCol + * Column index to start searching from + * @param directionX + * X direction for where to check for cells. +1 to check to the right, -1 to + * check to the left + * @param directionY + * @returns {false | object} + * Indices of the next cell in the specified direction. Returns the focused + * cell if none are found. + */ +aria.Grid.prototype.getNextCell = function ( + currRow, + currCol, + directionX, + directionY +) { + var row = currRow + directionY; + var col = currCol + directionX; + var rowCount = this.grid.length; + var isLeftRight = directionX !== 0; + + if (!rowCount) { + return false; + } + + var colCount = this.grid[0].length; + + if (this.shouldWrapCols && isLeftRight) { + if (col < 0) { + col = colCount - 1; + row--; + } + + if (col >= colCount) { + col = 0; + row++; + } + } + + if (this.shouldWrapRows && !isLeftRight) { + if (row < 0) { + col--; + row = rowCount - 1; + if (this.grid[row] && col >= 0 && !this.grid[row][col]) { + // Sometimes the bottom row is not completely filled in. In this case, + // jump to the next filled in cell. + row--; + } + } else if (row >= rowCount || !this.grid[row][col]) { + row = 0; + col++; + } + } + + if (this.isValidCell(row, col)) { + return { + row: row, + col: col, + }; + } else if (this.isValidCell(currRow, currCol)) { + return { + row: currRow, + col: currCol, + }; + } else { + return false; + } +}; + +/** + * @param directionX + * @param directionY + * @description +Get next visible column to the right or left (direction) of the focused + * cell. + * @returns {false | object} + * Indices of the next visible cell in the specified direction. If no visible + * cells are found, returns false if the current cell is hidden and returns + * the current cell if it is not hidden. + */ +aria.Grid.prototype.getNextVisibleCell = function (directionX, directionY) { + var nextCell = this.getNextCell( + this.focusedRow, + this.focusedCol, + directionX, + directionY + ); + + if (!nextCell) { + return false; + } + + while (this.isHidden(nextCell.row, nextCell.col)) { + var currRow = nextCell.row; + var currCol = nextCell.col; + + nextCell = this.getNextCell(currRow, currCol, directionX, directionY); + + if (currRow === nextCell.row && currCol === nextCell.col) { + // There are no more cells to try if getNextCell returns the current cell + return false; + } + } + + return nextCell; +}; + +/** + * @description + * Show or hide the cells in the specified column + * @param columnIndex + * Index of the column to toggle + * @param isShown + * Whether or not to show the column + */ +aria.Grid.prototype.toggleColumn = function (columnIndex, isShown) { + var cellSelector = '[aria-colindex="' + columnIndex + '"]'; + var columnCells = this.gridNode.querySelectorAll(cellSelector); + + Array.prototype.forEach.call(columnCells, function (cell) { + if (isShown) { + aria.Utils.removeClass(cell, aria.CSSClass.HIDDEN); + } else { + aria.Utils.addClass(cell, aria.CSSClass.HIDDEN); + } + }); + + if (!isShown && this.focusedCol === columnIndex - 1) { + // If focus was set on the hidden column, shift focus to the right + var nextCell = this.getNextVisibleCell(1, 0); + if (nextCell) { + this.setFocusPointer(nextCell.row, nextCell.col); + } + } +}; + +/** + * @description + * Find the closest element matching the selector. Only checks parent and + * direct children. + * @param element + * Element to start searching from + * @param selector + * Index of the column to toggle + * @returns {object} matching element + */ +aria.Grid.prototype.findClosest = function (element, selector) { + if (aria.Utils.matches(element, selector)) { + return element; + } + + if (aria.Utils.matches(element.parentNode, selector)) { + return element.parentNode; + } + + return element.querySelector(selector); +}; diff --git a/tests/minimal-data-grid/reference/2022-4-27_115334/js/dataGrids.js b/tests/minimal-data-grid/reference/2022-4-27_115334/js/dataGrids.js new file mode 100644 index 000000000..238afe8c0 --- /dev/null +++ b/tests/minimal-data-grid/reference/2022-4-27_115334/js/dataGrids.js @@ -0,0 +1,50 @@ +/* + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + */ + +/* global aria */ + +'use strict'; + +/** + * ARIA Grid Examples + * + * @function onload + * @description Initialize the grid examples once the page has loaded + */ + +window.addEventListener('load', function () { + // Initialize Example 1 Grid (if it is present in the DOM) + var ex1GridElement = document.getElementById('ex1-grid'); + if (ex1GridElement) { + new aria.Grid(ex1GridElement); + } + + // Initialize Example 2 Grid (if it is present in the DOM) + var ex2GridElement = document.getElementById('ex2-grid'); + if (ex2GridElement) { + new aria.Grid(ex2GridElement); + } + + // Initialize Example 3 Grid (if it is present in the DOM) + var ex3GridElement = document.getElementById('ex3-grid'); + if (ex3GridElement) { + var ex3Grid = new aria.Grid(ex3GridElement); + var toggleButton = document.getElementById('toggle_column_btn'); + var toggledOn = true; + + toggleButton.addEventListener('click', function () { + toggledOn = !toggledOn; + + ex3Grid.toggleColumn(2, toggledOn); + ex3Grid.toggleColumn(4, toggledOn); + + if (toggledOn) { + toggleButton.innerText = 'Hide Type and Category'; + } else { + toggleButton.innerText = 'Show Type and Category'; + } + }); + } +}); diff --git a/tests/minimal-data-grid/reference/2022-4-27_115334/js/layoutGrids.js b/tests/minimal-data-grid/reference/2022-4-27_115334/js/layoutGrids.js new file mode 100644 index 000000000..0695b73a1 --- /dev/null +++ b/tests/minimal-data-grid/reference/2022-4-27_115334/js/layoutGrids.js @@ -0,0 +1,211 @@ +/* + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + */ + +'use strict'; + +var aria = aria || {}; + +/** + * ARIA Grid Examples + * + * @function onload + * @description Initialize the grid examples once the page has loaded + */ + +window.addEventListener('load', function () { + // Setup Example 1 + if (document.getElementById('ex1-grid')) { + new aria.Grid(document.getElementById('ex1-grid')); + + // Setup NUX; activates when the first grid cell is focused + var gridNUX = document.getElementById('grid-nux'); + var firstGridCell = document.querySelector('#ex1-grid [tabindex="0"]'); + var NUXCloseButton = document.getElementById('close-nux-button'); + var closeNUX = function () { + aria.Utils.addClass(gridNUX, 'hidden'); + firstGridCell.focus(); + }; + var setupInstructions = function () { + firstGridCell.removeEventListener('focus', setupInstructions); + aria.Utils.removeClass(gridNUX, 'hidden'); + + NUXCloseButton.addEventListener('click', closeNUX); + NUXCloseButton.addEventListener('keyup', function (event) { + if (event.which === aria.KeyCode.RETURN) { + closeNUX(); + } + }); + }; + firstGridCell.addEventListener('focus', setupInstructions); + } + + // Setup Example 2 + if (document.getElementById('ex2-grid')) { + var ex2Grid = new aria.Grid(document.getElementById('ex2-grid')); + + new PillList( + ex2Grid, + document.getElementById('add-recipient-input'), + document.getElementById('add-recipient-button'), + document.getElementById('form-action-text') + ); + } + + // Setup Example 3 + if (document.getElementById('ex3-grid')) { + var ex3Grid = new aria.Grid(document.getElementById('ex3-grid')); + var startIndexText = document.getElementById('ex3_start_index'); + var endIndexText = document.getElementById('ex3_end_index'); + var previousButton = document.getElementById('ex3_pageup_button'); + var nextButton = document.getElementById('ex3_pagedown_button'); + ex3Grid.setPaginationChangeHandler(function (startIndex, endIndex) { + startIndexText.innerText = startIndex + 1; + endIndexText.innerText = endIndex + 1; + if (startIndex <= 0) { + previousButton.setAttribute('disabled', 'true'); + } else { + previousButton.removeAttribute('disabled'); + } + if (endIndex >= 18) { + nextButton.setAttribute('disabled', 'true'); + } else { + nextButton.removeAttribute('disabled'); + } + }); + previousButton.addEventListener('click', ex3Grid.movePageUp.bind(ex3Grid)); + nextButton.addEventListener('click', ex3Grid.movePageDown.bind(ex3Grid)); + } +}); + +function PillList(grid, input, submitButton, formUpdateText) { + // Hardcoded to work for example 2 + this.pillIDs = { length: 2, 1: true, 2: true }; + this.nextPillID = 3; + this.grid = grid; + this.input = input; + this.submitButton = submitButton; + this.formUpdateText = formUpdateText; + + this.input.addEventListener('keydown', this.checkSubmitItem.bind(this)); + this.submitButton.addEventListener('click', this.submitItemForm.bind(this)); + this.grid.gridNode.addEventListener('click', this.checkRemovePill.bind(this)); + this.grid.gridNode.addEventListener( + 'keydown', + this.checkRemovePill.bind(this) + ); +} + +PillList.prototype.checkSubmitItem = function (event) { + var key = event.which || event.keyCode; + + if (key === aria.KeyCode.RETURN) { + this.submitItemForm(); + } +}; + +PillList.prototype.getRecipientsString = function () { + var recipientCount = this.pillIDs.length; + if (recipientCount === 1) { + return '1 recipient total.'; + } else { + return recipientCount + ' recipients total.'; + } +}; + +PillList.prototype.submitItemForm = function () { + var newItem = this.input.value; + this.addPillItem(newItem); + this.input.value = ''; + this.input.focus(); + this.formUpdateText.innerText = + newItem + ' added. ' + this.getRecipientsString(); +}; + +PillList.prototype.addPillItem = function (recipientName) { + var id = this.nextPillID; + + if (!recipientName) { + return; + } + + var newPillItem = document.createElement('div'); + newPillItem.setAttribute('role', 'row'); + newPillItem.setAttribute('data-id', 'id'); + newPillItem.className = 'pill-item'; + + newPillItem.innerHTML = + '' + + '' + + recipientName + + '' + + '' + + '' + + '' + + 'X' + + '' + + ''; + + this.grid.gridNode.append(newPillItem); + this.grid.setupFocusGrid(); + + if (this.grid.grid.length === 1) { + this.grid.focusedRow = undefined; + this.grid.focusedCol = undefined; + this.grid.setFocusPointer(0, 0); + } + + this.nextPillID++; + this.pillIDs[id] = true; + this.pillIDs.length++; +}; + +PillList.prototype.checkRemovePill = function (event) { + var pillItem, pillID, pillName; + var isClickEvent = event.type === 'click'; + var key = event.which || event.keyCode; + + if ( + !isClickEvent && + key !== aria.KeyCode.RETURN && + key !== aria.KeyCode.SPACE + ) { + return; + } + + if (event.target.className === 'pill-remove') { + pillItem = event.target.parentNode.parentNode; + pillID = pillItem.getAttribute('data-id'); + pillName = pillItem.querySelector('.pill-name').innerText; + } else { + return; + } + + delete this.pillIDs[pillID]; + this.pillIDs.length--; + this.formUpdateText.innerText = + pillName + ' removed. ' + this.getRecipientsString(); + + pillItem.remove(); + this.grid.setupFocusGrid(); + + if (this.grid.isValidCell(this.grid.focusedRow, this.grid.focusedCol)) { + // First, try to focus on the next pill + this.grid.focusCell(this.grid.focusedRow, this.grid.focusedCol); + } else if ( + this.grid.isValidCell(--this.grid.focusedRow, this.grid.focusedCol) + ) { + // If there is no next pill, try to focus on the previous pill + this.grid.focusCell(this.grid.focusedRow, this.grid.focusedCol); + } +}; diff --git a/tests/minimal-data-grid/reference/2022-4-27_115334/js/menuButton.js b/tests/minimal-data-grid/reference/2022-4-27_115334/js/menuButton.js new file mode 100644 index 000000000..e7813cd96 --- /dev/null +++ b/tests/minimal-data-grid/reference/2022-4-27_115334/js/menuButton.js @@ -0,0 +1,519 @@ +/* + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + */ + +'use strict'; + +/** + * ARIA Menu Button example + * + * @function onload + * @description after page has loaded initialize all menu buttons based on the selector "[aria-haspopup][aria-controls]" + */ + +window.addEventListener('load', function () { + var menuButtons = document.querySelectorAll('[aria-haspopup][aria-controls]'); + + [].forEach.call(menuButtons, function (menuButton) { + if ( + (menuButton && menuButton.tagName.toLowerCase() === 'button') || + menuButton.getAttribute('role').toLowerCase() === 'button' + ) { + var mb = new aria.widget.MenuButton(menuButton); + mb.initMenuButton(); + } + }); +}); + +/** + * @namespace aria + */ + +var aria = aria || {}; + +/* ---------------------------------------------------------------- */ +/* ARIA Utils Namespace */ +/* ---------------------------------------------------------------- */ + +/** + * @class Menu + * @memberof aria.Utils + * @description Computes absolute position of an element + */ + +aria.Utils = aria.Utils || {}; + +aria.Utils.findPos = function (element) { + var xPosition = 0; + var yPosition = 0; + + while (element) { + xPosition += element.offsetLeft - element.scrollLeft + element.clientLeft; + yPosition += element.offsetTop - element.scrollTop + element.clientTop; + element = element.offsetParent; + } + return { x: xPosition, y: yPosition }; +}; + +/* ---------------------------------------------------------------- */ +/* ARIA Widget Namespace */ +/* ---------------------------------------------------------------- */ + +aria.widget = aria.widget || {}; + +/* ---------------------------------------------------------------- */ +/* Menu Button Widget */ +/* ---------------------------------------------------------------- */ + +/** + * @class Menu + * @memberof aria.Widget + * @description Creates a Menu Button widget using ARIA + */ + +aria.widget.Menu = function (node, menuButton) { + this.keyCode = Object.freeze({ + TAB: 9, + RETURN: 13, + ESC: 27, + SPACE: 32, + PAGEUP: 33, + PAGEDOWN: 34, + END: 35, + HOME: 36, + LEFT: 37, + UP: 38, + RIGHT: 39, + DOWN: 40, + }); + + // Check fo DOM element node + if (typeof node !== 'object' || !node.getElementsByClassName) { + return false; + } + + this.menuNode = node; + node.tabIndex = -1; + + this.menuButton = menuButton; + + this.firstMenuItem = false; + this.lastMenuItem = false; +}; + +/** + * @function initMenuButton + * @memberof aria.widget.Menu + * @description Adds event handlers to button elements + */ + +aria.widget.Menu.prototype.initMenu = function () { + var self = this; + + var cn = this.menuNode.firstChild; + + while (cn) { + if (cn.nodeType === Node.ELEMENT_NODE) { + if (cn.getAttribute('role') === 'menuitem') { + cn.tabIndex = -1; + if (!this.firstMenuItem) { + this.firstMenuItem = cn; + } + this.lastMenuItem = cn; + + var eventKeyDown = function (event) { + self.eventKeyDown(event, self); + }; + cn.addEventListener('keydown', eventKeyDown); + + var eventMouseClick = function (event) { + self.eventMouseClick(event, self); + }; + cn.addEventListener('click', eventMouseClick); + + var eventBlur = function (event) { + self.eventBlur(event, self); + }; + cn.addEventListener('blur', eventBlur); + + var eventFocus = function (event) { + self.eventFocus(event, self); + }; + cn.addEventListener('focus', eventFocus); + } + } + cn = cn.nextSibling; + } +}; + +/** + * @function nextMenuItem + * @memberof aria.widget.Menu + * @description Moves focus to next menuItem + */ + +aria.widget.Menu.prototype.nextMenuItem = function (currentMenuItem) { + var mi = currentMenuItem.nextSibling; + + while (mi) { + if ( + mi.nodeType === Node.ELEMENT_NODE && + mi.getAttribute('role') === 'menuitem' + ) { + mi.focus(); + break; + } + mi = mi.nextSibling; + } + + if (!mi && this.firstMenuItem) { + this.firstMenuItem.focus(); + } +}; + +/** + * @function previousMenuItem + * @memberof aria.widget.Menu + * @description Moves focus to previous menuItem + */ + +aria.widget.Menu.prototype.previousMenuItem = function (currentMenuItem) { + var mi = currentMenuItem.previousSibling; + + while (mi) { + if ( + mi.nodeType === Node.ELEMENT_NODE && + mi.getAttribute('role') === 'menuitem' + ) { + mi.focus(); + break; + } + mi = mi.previousSibling; + } + + if (!mi && this.lastMenuItem) { + this.lastMenuItem.focus(); + } +}; + +/** + * @function eventKeyDown + * @memberof aria.widget.Menu + * @description Keydown event handler for Menu Object + * NOTE: The menu parameter is needed to provide a reference to the specific + * menu + */ + +aria.widget.Menu.prototype.eventKeyDown = function (event, menu) { + var ct = event.currentTarget; + var flag = false; + + switch (event.keyCode) { + case menu.keyCode.SPACE: + case menu.keyCode.RETURN: + menu.eventMouseClick(event, menu); + menu.menuButton.closeMenu(true); + flag = true; + break; + + case menu.keyCode.ESC: + menu.menuButton.closeMenu(true); + menu.menuButton.buttonNode.focus(); + flag = true; + break; + + case menu.keyCode.UP: + case menu.keyCode.LEFT: + menu.previousMenuItem(ct); + flag = true; + break; + + case menu.keyCode.DOWN: + case menu.keyCode.RIGHT: + menu.nextMenuItem(ct); + flag = true; + break; + + case menu.keyCode.TAB: + menu.menuButton.closeMenu(true, false); + break; + + default: + break; + } + + if (flag) { + event.stopPropagation(); + event.preventDefault(); + } +}; + +/** + * @function eventMouseClick + * @memberof aria.widget.Menu + * @description onclick event handler for Menu Object + * NOTE: The menu parameter is needed to provide a reference to the specific + * menu + */ + +aria.widget.Menu.prototype.eventMouseClick = function (event, menu) { + var clickedItemText = event.target.innerText; + this.menuButton.buttonNode.innerText = clickedItemText; + menu.menuButton.closeMenu(true); +}; + +/** + * @param event + * @param menu + * @function eventBlur + * @memberof aria.widget.Menu + * @description eventBlur event handler for Menu Object + * NOTE: The menu parameter is needed to provide a reference to the specific + * menu + */ +aria.widget.Menu.prototype.eventBlur = function (event, menu) { + menu.menuHasFocus = false; + setTimeout(function () { + if (!menu.menuHasFocus) { + menu.menuButton.closeMenu(false, false); + } + }, 200); +}; + +/** + * @param event + * @param menu + * @function eventFocus + * @memberof aria.widget.Menu + * @description eventFocus event handler for Menu Object + * NOTE: The menu parameter is needed to provide a reference to the specific + * menu + */ +aria.widget.Menu.prototype.eventFocus = function (event, menu) { + menu.menuHasFocus = true; +}; + +/* ---------------------------------------------------------------- */ +/* Menu Button Widget */ +/* ---------------------------------------------------------------- */ + +/** + * @class Menu Button + * @memberof aria.Widget + * @description Creates a Menu Button widget using ARIA + */ + +aria.widget.MenuButton = function (node) { + this.keyCode = Object.freeze({ + TAB: 9, + RETURN: 13, + ESC: 27, + SPACE: 32, + UP: 38, + DOWN: 40, + }); + + // Check fo DOM element node + if (typeof node !== 'object' || !node.getElementsByClassName) { + return false; + } + + this.done = true; + this.mouseInMouseButton = false; + this.menuHasFocus = false; + this.buttonNode = node; + this.isLink = false; + + if (node.tagName.toLowerCase() === 'a') { + var url = node.getAttribute('href'); + if (url && url.length && url.length > 0) { + this.isLink = true; + } + } +}; + +/** + * @function initMenuButton + * @memberof aria.widget.MenuButton + * @description Adds event handlers to button elements + */ + +aria.widget.MenuButton.prototype.initMenuButton = function () { + var id = this.buttonNode.getAttribute('aria-controls'); + + if (id) { + this.menuNode = document.getElementById(id); + + if (this.menuNode) { + this.menu = new aria.widget.Menu(this.menuNode, this); + this.menu.initMenu(); + this.menuShowing = false; + } + } + + this.closeMenu(false, false); + + var self = this; + + var eventKeyDown = function (event) { + self.eventKeyDown(event, self); + }; + this.buttonNode.addEventListener('keydown', eventKeyDown); + + var eventMouseClick = function (event) { + self.eventMouseClick(event, self); + }; + this.buttonNode.addEventListener('click', eventMouseClick); +}; + +/** + * @function openMenu + * @memberof aria.widget.MenuButton + * @description Opens the menu + */ + +aria.widget.MenuButton.prototype.openMenu = function () { + if (this.menuNode) { + this.menuNode.style.display = 'block'; + this.menuShowing = true; + } +}; + +/** + * @function closeMenu + * @memberof aria.widget.MenuButton + * @description Close the menu + */ + +aria.widget.MenuButton.prototype.closeMenu = function (force, focusMenuButton) { + if (typeof force !== 'boolean') { + force = false; + } + if (typeof focusMenuButton !== 'boolean') { + focusMenuButton = true; + } + + if ( + force || + (!this.mouseInMenuButton && + this.menuNode && + !this.menu.mouseInMenu && + !this.menu.menuHasFocus) + ) { + this.menuNode.style.display = 'none'; + if (focusMenuButton) { + this.buttonNode.focus(); + } + this.menuShowing = false; + } +}; + +/** + * @function toggleMenu + * @memberof aria.widget.MenuButton + * @description Close or open the menu depending on current state + */ + +aria.widget.MenuButton.prototype.toggleMenu = function () { + if (this.menuNode) { + if (this.menuNode.style.display === 'block') { + this.menuNode.style.display = 'none'; + } else { + this.menuNode.style.display = 'block'; + } + } +}; + +/** + * @function moveFocusToFirstMenuItem + * @memberof aria.widget.MenuButton + * @description Move keyboard focus to first menu item + */ + +aria.widget.MenuButton.prototype.moveFocusToFirstMenuItem = function () { + if (this.menu.firstMenuItem) { + this.openMenu(); + this.menu.firstMenuItem.focus(); + } +}; + +/** + * @function moveFocusToLastMenuItem + * @memberof aria.widget.MenuButton + * @description Move keyboard focus to last menu item + */ + +aria.widget.MenuButton.prototype.moveFocusToLastMenuItem = function () { + if (this.menu.lastMenuItem) { + this.openMenu(); + this.menu.lastMenuItem.focus(); + } +}; + +/** + * @function eventKeyDown + * @memberof aria.widget.MenuButton + * @description Keydown event handler for MenuButton Object + * NOTE: The menuButton parameter is needed to provide a reference to the specific + * menuButton + */ + +aria.widget.MenuButton.prototype.eventKeyDown = function (event, menuButton) { + var flag = false; + + switch (event.keyCode) { + case menuButton.keyCode.SPACE: + menuButton.moveFocusToFirstMenuItem(); + flag = true; + break; + + case menuButton.keyCode.RETURN: + menuButton.moveFocusToFirstMenuItem(); + flag = true; + break; + + case menuButton.keyCode.UP: + if (this.menuShowing) { + menuButton.moveFocusToLastMenuItem(); + flag = true; + } + break; + + case menuButton.keyCode.DOWN: + if (this.menuShowing) { + menuButton.moveFocusToFirstMenuItem(); + flag = true; + } + break; + + case menuButton.keyCode.TAB: + menuButton.closeMenu(true, false); + break; + + default: + break; + } + + if (flag) { + event.stopPropagation(); + event.preventDefault(); + } +}; + +/** + * @param event + * @param menuButton + * @function eventMouseClick + * @memberof aria.widget.MenuButton + * @description Click event handler for MenuButton Object + * NOTE: The menuButton parameter is needed to provide a reference to the specific + * menuButton + */ +aria.widget.MenuButton.prototype.eventMouseClick = function ( + event, + menuButton +) { + menuButton.moveFocusToFirstMenuItem(); +}; From c5def028133d1b1d4e75807fae96bec19a358c53 Mon Sep 17 00:00:00 2001 From: Isabel Del Castillo Date: Wed, 27 Apr 2022 12:02:13 -0500 Subject: [PATCH 2/5] Example: remove unneeded CSS/JS references and update page title --- .../2022-4-27_115334/css/layoutGrids.css | 185 ------- .../2022-4-27_115334/css/menuButton.css | 36 -- .../reference/2022-4-27_115334/dataGrids.html | 2 +- .../2022-4-27_115334/js/layoutGrids.js | 211 ------- .../2022-4-27_115334/js/menuButton.js | 519 ------------------ .../reference/2022-4-27_115334/js/utils.js | 131 +++++ 6 files changed, 132 insertions(+), 952 deletions(-) delete mode 100644 tests/minimal-data-grid/reference/2022-4-27_115334/css/layoutGrids.css delete mode 100644 tests/minimal-data-grid/reference/2022-4-27_115334/css/menuButton.css delete mode 100644 tests/minimal-data-grid/reference/2022-4-27_115334/js/layoutGrids.js delete mode 100644 tests/minimal-data-grid/reference/2022-4-27_115334/js/menuButton.js create mode 100644 tests/minimal-data-grid/reference/2022-4-27_115334/js/utils.js diff --git a/tests/minimal-data-grid/reference/2022-4-27_115334/css/layoutGrids.css b/tests/minimal-data-grid/reference/2022-4-27_115334/css/layoutGrids.css deleted file mode 100644 index bc1e411a1..000000000 --- a/tests/minimal-data-grid/reference/2022-4-27_115334/css/layoutGrids.css +++ /dev/null @@ -1,185 +0,0 @@ -.hidden { - display: none !important; -} - -#arrow-keys-indicator { - bottom: 10px; - left: 0; - position: fixed; - height: 65px; - width: 85px; - background: url("../imgs/black_keys.png") no-repeat; - background-size: contain; -} - -@media screen and (max-width: 1000px) { - #arrow-keys-indicator { - display: none; - } - - .indicator_description { - display: none; - } -} - -.accessible_elem { - clip: rect(1px 1px 1px 1px); - clip: rect(1px, 1px, 1px, 1px); - height: 1px; - overflow: hidden; - position: absolute; - white-space: nowrap; - width: 1px; -} - -.list-links { - font-size: 0; -} - -.list-link { - background: #eee; - border: 1px solid #bbb; - display: inline-block; - font-size: 14px; - height: 40px; - margin: 5px 0 0; - padding: 5px; - position: relative; - vertical-align: middle; - width: 120px; -} - -[role="gridcell"], -[role="gridcell"] [tabindex] { - display: inline-block; - position: relative; -} - -[role="gridcell"]:focus, -[role="gridcell"] *:focus { - outline: #005a9c; - outline-style: dotted; - outline-width: 3px; -} - -.grid-nux { - background: #eaf9ef; - position: absolute; - max-width: 500px; - border: 1px solid #bbb; - padding: 0 15px 20px; - margin-top: 20px; - box-shadow: 2px 2px 3px rgb(0 0 0 / 30%); -} - -.grid-nux::after, -.grid-nux::before { - bottom: 100%; - left: 20px; - border: solid transparent; - content: " "; - height: 0; - width: 0; - position: absolute; - pointer-events: none; -} - -.grid-nux::after { - border-color: rgb(136 183 213 / 0%); - border-bottom-color: #eaf9ef; - border-width: 10px; - margin-left: -10px; -} - -.grid-nux::before { - border-color: rgb(194 225 245 / 0%); - border-bottom-color: #bbb; - border-width: 11px; - margin-left: -11px; -} - -.grid-nux-header { - font-weight: bold; -} - -.indicator_graphic { - float: right; - margin-left: 10px; -} - -.close-nux-button { - color: #360; - cursor: default; - position: absolute; - right: 10px; - bottom: 10px; - text-decoration: underline; -} - -.recipient-list { - background: #eee; - border: 1px solid #ddd; - margin-bottom: 10px; - padding: 5px 15px; - position: relative; -} - -#send_to_label { - font-size: 14px; - font-weight: bold; - position: absolute; - top: 1.2em; -} - -.pill-list { - background: white; - border: 1px solid #ccc; - font-size: 0; - margin-bottom: 5px; - margin-left: 65px; - min-height: 31px; - padding: 0 5px 5px; -} - -.pill-item { - background: #eee; - border: 1px solid #3a69b6; - border-radius: 2px; - color: #3a69b6; - display: inline-block; - font-size: 14px; - margin: 5px 5px 0 0; - padding: 0.3em; -} - -.pill-name { - text-decoration: none; -} - -.pill-remove { - cursor: default; - margin-left: 10px; -} - -#recipient-form { - margin-left: 65px; -} - -#add-recipient-input { - font-size: 14px; -} - -.ex3_result_header { - margin: 0; - font-style: normal; - font-weight: bold; -} - -.ex3_result_indices { - margin-bottom: 40px; -} - -.ex3_pagination { - margin-top: 40px; - text-align: center; -} diff --git a/tests/minimal-data-grid/reference/2022-4-27_115334/css/menuButton.css b/tests/minimal-data-grid/reference/2022-4-27_115334/css/menuButton.css deleted file mode 100644 index b880b7adc..000000000 --- a/tests/minimal-data-grid/reference/2022-4-27_115334/css/menuButton.css +++ /dev/null @@ -1,36 +0,0 @@ -button { - cursor: pointer; - font-size: 110%; -} - -.menu-wrapper { - position: relative; -} - -ul[role="menu"] { - display: none; - position: absolute; - margin: 0; - padding: 0; - z-index: 1; -} - -ul[role="menu"] li { - list-style: none; -} - -[role="menu"] { - padding: 0; - width: 8em; - border: thin solid black; - background-color: #eee; -} - -[role="menuitem"] { - padding: 0.25em; -} - -[role="menuitem"]:focus, -[role="menuitem"]:hover { - background-color: #fff; -} diff --git a/tests/minimal-data-grid/reference/2022-4-27_115334/dataGrids.html b/tests/minimal-data-grid/reference/2022-4-27_115334/dataGrids.html index a48e7e090..7bb2ba279 100644 --- a/tests/minimal-data-grid/reference/2022-4-27_115334/dataGrids.html +++ b/tests/minimal-data-grid/reference/2022-4-27_115334/dataGrids.html @@ -2,7 +2,7 @@ -Data Grid Examples | WAI-ARIA Authoring Practices 1.2 +Data Grid Examples diff --git a/tests/minimal-data-grid/reference/2022-4-27_115334/js/layoutGrids.js b/tests/minimal-data-grid/reference/2022-4-27_115334/js/layoutGrids.js deleted file mode 100644 index 0695b73a1..000000000 --- a/tests/minimal-data-grid/reference/2022-4-27_115334/js/layoutGrids.js +++ /dev/null @@ -1,211 +0,0 @@ -/* - * This content is licensed according to the W3C Software License at - * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document - */ - -'use strict'; - -var aria = aria || {}; - -/** - * ARIA Grid Examples - * - * @function onload - * @description Initialize the grid examples once the page has loaded - */ - -window.addEventListener('load', function () { - // Setup Example 1 - if (document.getElementById('ex1-grid')) { - new aria.Grid(document.getElementById('ex1-grid')); - - // Setup NUX; activates when the first grid cell is focused - var gridNUX = document.getElementById('grid-nux'); - var firstGridCell = document.querySelector('#ex1-grid [tabindex="0"]'); - var NUXCloseButton = document.getElementById('close-nux-button'); - var closeNUX = function () { - aria.Utils.addClass(gridNUX, 'hidden'); - firstGridCell.focus(); - }; - var setupInstructions = function () { - firstGridCell.removeEventListener('focus', setupInstructions); - aria.Utils.removeClass(gridNUX, 'hidden'); - - NUXCloseButton.addEventListener('click', closeNUX); - NUXCloseButton.addEventListener('keyup', function (event) { - if (event.which === aria.KeyCode.RETURN) { - closeNUX(); - } - }); - }; - firstGridCell.addEventListener('focus', setupInstructions); - } - - // Setup Example 2 - if (document.getElementById('ex2-grid')) { - var ex2Grid = new aria.Grid(document.getElementById('ex2-grid')); - - new PillList( - ex2Grid, - document.getElementById('add-recipient-input'), - document.getElementById('add-recipient-button'), - document.getElementById('form-action-text') - ); - } - - // Setup Example 3 - if (document.getElementById('ex3-grid')) { - var ex3Grid = new aria.Grid(document.getElementById('ex3-grid')); - var startIndexText = document.getElementById('ex3_start_index'); - var endIndexText = document.getElementById('ex3_end_index'); - var previousButton = document.getElementById('ex3_pageup_button'); - var nextButton = document.getElementById('ex3_pagedown_button'); - ex3Grid.setPaginationChangeHandler(function (startIndex, endIndex) { - startIndexText.innerText = startIndex + 1; - endIndexText.innerText = endIndex + 1; - if (startIndex <= 0) { - previousButton.setAttribute('disabled', 'true'); - } else { - previousButton.removeAttribute('disabled'); - } - if (endIndex >= 18) { - nextButton.setAttribute('disabled', 'true'); - } else { - nextButton.removeAttribute('disabled'); - } - }); - previousButton.addEventListener('click', ex3Grid.movePageUp.bind(ex3Grid)); - nextButton.addEventListener('click', ex3Grid.movePageDown.bind(ex3Grid)); - } -}); - -function PillList(grid, input, submitButton, formUpdateText) { - // Hardcoded to work for example 2 - this.pillIDs = { length: 2, 1: true, 2: true }; - this.nextPillID = 3; - this.grid = grid; - this.input = input; - this.submitButton = submitButton; - this.formUpdateText = formUpdateText; - - this.input.addEventListener('keydown', this.checkSubmitItem.bind(this)); - this.submitButton.addEventListener('click', this.submitItemForm.bind(this)); - this.grid.gridNode.addEventListener('click', this.checkRemovePill.bind(this)); - this.grid.gridNode.addEventListener( - 'keydown', - this.checkRemovePill.bind(this) - ); -} - -PillList.prototype.checkSubmitItem = function (event) { - var key = event.which || event.keyCode; - - if (key === aria.KeyCode.RETURN) { - this.submitItemForm(); - } -}; - -PillList.prototype.getRecipientsString = function () { - var recipientCount = this.pillIDs.length; - if (recipientCount === 1) { - return '1 recipient total.'; - } else { - return recipientCount + ' recipients total.'; - } -}; - -PillList.prototype.submitItemForm = function () { - var newItem = this.input.value; - this.addPillItem(newItem); - this.input.value = ''; - this.input.focus(); - this.formUpdateText.innerText = - newItem + ' added. ' + this.getRecipientsString(); -}; - -PillList.prototype.addPillItem = function (recipientName) { - var id = this.nextPillID; - - if (!recipientName) { - return; - } - - var newPillItem = document.createElement('div'); - newPillItem.setAttribute('role', 'row'); - newPillItem.setAttribute('data-id', 'id'); - newPillItem.className = 'pill-item'; - - newPillItem.innerHTML = - '' + - '' + - recipientName + - '' + - '' + - '' + - '' + - 'X' + - '' + - ''; - - this.grid.gridNode.append(newPillItem); - this.grid.setupFocusGrid(); - - if (this.grid.grid.length === 1) { - this.grid.focusedRow = undefined; - this.grid.focusedCol = undefined; - this.grid.setFocusPointer(0, 0); - } - - this.nextPillID++; - this.pillIDs[id] = true; - this.pillIDs.length++; -}; - -PillList.prototype.checkRemovePill = function (event) { - var pillItem, pillID, pillName; - var isClickEvent = event.type === 'click'; - var key = event.which || event.keyCode; - - if ( - !isClickEvent && - key !== aria.KeyCode.RETURN && - key !== aria.KeyCode.SPACE - ) { - return; - } - - if (event.target.className === 'pill-remove') { - pillItem = event.target.parentNode.parentNode; - pillID = pillItem.getAttribute('data-id'); - pillName = pillItem.querySelector('.pill-name').innerText; - } else { - return; - } - - delete this.pillIDs[pillID]; - this.pillIDs.length--; - this.formUpdateText.innerText = - pillName + ' removed. ' + this.getRecipientsString(); - - pillItem.remove(); - this.grid.setupFocusGrid(); - - if (this.grid.isValidCell(this.grid.focusedRow, this.grid.focusedCol)) { - // First, try to focus on the next pill - this.grid.focusCell(this.grid.focusedRow, this.grid.focusedCol); - } else if ( - this.grid.isValidCell(--this.grid.focusedRow, this.grid.focusedCol) - ) { - // If there is no next pill, try to focus on the previous pill - this.grid.focusCell(this.grid.focusedRow, this.grid.focusedCol); - } -}; diff --git a/tests/minimal-data-grid/reference/2022-4-27_115334/js/menuButton.js b/tests/minimal-data-grid/reference/2022-4-27_115334/js/menuButton.js deleted file mode 100644 index e7813cd96..000000000 --- a/tests/minimal-data-grid/reference/2022-4-27_115334/js/menuButton.js +++ /dev/null @@ -1,519 +0,0 @@ -/* - * This content is licensed according to the W3C Software License at - * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document - * - */ - -'use strict'; - -/** - * ARIA Menu Button example - * - * @function onload - * @description after page has loaded initialize all menu buttons based on the selector "[aria-haspopup][aria-controls]" - */ - -window.addEventListener('load', function () { - var menuButtons = document.querySelectorAll('[aria-haspopup][aria-controls]'); - - [].forEach.call(menuButtons, function (menuButton) { - if ( - (menuButton && menuButton.tagName.toLowerCase() === 'button') || - menuButton.getAttribute('role').toLowerCase() === 'button' - ) { - var mb = new aria.widget.MenuButton(menuButton); - mb.initMenuButton(); - } - }); -}); - -/** - * @namespace aria - */ - -var aria = aria || {}; - -/* ---------------------------------------------------------------- */ -/* ARIA Utils Namespace */ -/* ---------------------------------------------------------------- */ - -/** - * @class Menu - * @memberof aria.Utils - * @description Computes absolute position of an element - */ - -aria.Utils = aria.Utils || {}; - -aria.Utils.findPos = function (element) { - var xPosition = 0; - var yPosition = 0; - - while (element) { - xPosition += element.offsetLeft - element.scrollLeft + element.clientLeft; - yPosition += element.offsetTop - element.scrollTop + element.clientTop; - element = element.offsetParent; - } - return { x: xPosition, y: yPosition }; -}; - -/* ---------------------------------------------------------------- */ -/* ARIA Widget Namespace */ -/* ---------------------------------------------------------------- */ - -aria.widget = aria.widget || {}; - -/* ---------------------------------------------------------------- */ -/* Menu Button Widget */ -/* ---------------------------------------------------------------- */ - -/** - * @class Menu - * @memberof aria.Widget - * @description Creates a Menu Button widget using ARIA - */ - -aria.widget.Menu = function (node, menuButton) { - this.keyCode = Object.freeze({ - TAB: 9, - RETURN: 13, - ESC: 27, - SPACE: 32, - PAGEUP: 33, - PAGEDOWN: 34, - END: 35, - HOME: 36, - LEFT: 37, - UP: 38, - RIGHT: 39, - DOWN: 40, - }); - - // Check fo DOM element node - if (typeof node !== 'object' || !node.getElementsByClassName) { - return false; - } - - this.menuNode = node; - node.tabIndex = -1; - - this.menuButton = menuButton; - - this.firstMenuItem = false; - this.lastMenuItem = false; -}; - -/** - * @function initMenuButton - * @memberof aria.widget.Menu - * @description Adds event handlers to button elements - */ - -aria.widget.Menu.prototype.initMenu = function () { - var self = this; - - var cn = this.menuNode.firstChild; - - while (cn) { - if (cn.nodeType === Node.ELEMENT_NODE) { - if (cn.getAttribute('role') === 'menuitem') { - cn.tabIndex = -1; - if (!this.firstMenuItem) { - this.firstMenuItem = cn; - } - this.lastMenuItem = cn; - - var eventKeyDown = function (event) { - self.eventKeyDown(event, self); - }; - cn.addEventListener('keydown', eventKeyDown); - - var eventMouseClick = function (event) { - self.eventMouseClick(event, self); - }; - cn.addEventListener('click', eventMouseClick); - - var eventBlur = function (event) { - self.eventBlur(event, self); - }; - cn.addEventListener('blur', eventBlur); - - var eventFocus = function (event) { - self.eventFocus(event, self); - }; - cn.addEventListener('focus', eventFocus); - } - } - cn = cn.nextSibling; - } -}; - -/** - * @function nextMenuItem - * @memberof aria.widget.Menu - * @description Moves focus to next menuItem - */ - -aria.widget.Menu.prototype.nextMenuItem = function (currentMenuItem) { - var mi = currentMenuItem.nextSibling; - - while (mi) { - if ( - mi.nodeType === Node.ELEMENT_NODE && - mi.getAttribute('role') === 'menuitem' - ) { - mi.focus(); - break; - } - mi = mi.nextSibling; - } - - if (!mi && this.firstMenuItem) { - this.firstMenuItem.focus(); - } -}; - -/** - * @function previousMenuItem - * @memberof aria.widget.Menu - * @description Moves focus to previous menuItem - */ - -aria.widget.Menu.prototype.previousMenuItem = function (currentMenuItem) { - var mi = currentMenuItem.previousSibling; - - while (mi) { - if ( - mi.nodeType === Node.ELEMENT_NODE && - mi.getAttribute('role') === 'menuitem' - ) { - mi.focus(); - break; - } - mi = mi.previousSibling; - } - - if (!mi && this.lastMenuItem) { - this.lastMenuItem.focus(); - } -}; - -/** - * @function eventKeyDown - * @memberof aria.widget.Menu - * @description Keydown event handler for Menu Object - * NOTE: The menu parameter is needed to provide a reference to the specific - * menu - */ - -aria.widget.Menu.prototype.eventKeyDown = function (event, menu) { - var ct = event.currentTarget; - var flag = false; - - switch (event.keyCode) { - case menu.keyCode.SPACE: - case menu.keyCode.RETURN: - menu.eventMouseClick(event, menu); - menu.menuButton.closeMenu(true); - flag = true; - break; - - case menu.keyCode.ESC: - menu.menuButton.closeMenu(true); - menu.menuButton.buttonNode.focus(); - flag = true; - break; - - case menu.keyCode.UP: - case menu.keyCode.LEFT: - menu.previousMenuItem(ct); - flag = true; - break; - - case menu.keyCode.DOWN: - case menu.keyCode.RIGHT: - menu.nextMenuItem(ct); - flag = true; - break; - - case menu.keyCode.TAB: - menu.menuButton.closeMenu(true, false); - break; - - default: - break; - } - - if (flag) { - event.stopPropagation(); - event.preventDefault(); - } -}; - -/** - * @function eventMouseClick - * @memberof aria.widget.Menu - * @description onclick event handler for Menu Object - * NOTE: The menu parameter is needed to provide a reference to the specific - * menu - */ - -aria.widget.Menu.prototype.eventMouseClick = function (event, menu) { - var clickedItemText = event.target.innerText; - this.menuButton.buttonNode.innerText = clickedItemText; - menu.menuButton.closeMenu(true); -}; - -/** - * @param event - * @param menu - * @function eventBlur - * @memberof aria.widget.Menu - * @description eventBlur event handler for Menu Object - * NOTE: The menu parameter is needed to provide a reference to the specific - * menu - */ -aria.widget.Menu.prototype.eventBlur = function (event, menu) { - menu.menuHasFocus = false; - setTimeout(function () { - if (!menu.menuHasFocus) { - menu.menuButton.closeMenu(false, false); - } - }, 200); -}; - -/** - * @param event - * @param menu - * @function eventFocus - * @memberof aria.widget.Menu - * @description eventFocus event handler for Menu Object - * NOTE: The menu parameter is needed to provide a reference to the specific - * menu - */ -aria.widget.Menu.prototype.eventFocus = function (event, menu) { - menu.menuHasFocus = true; -}; - -/* ---------------------------------------------------------------- */ -/* Menu Button Widget */ -/* ---------------------------------------------------------------- */ - -/** - * @class Menu Button - * @memberof aria.Widget - * @description Creates a Menu Button widget using ARIA - */ - -aria.widget.MenuButton = function (node) { - this.keyCode = Object.freeze({ - TAB: 9, - RETURN: 13, - ESC: 27, - SPACE: 32, - UP: 38, - DOWN: 40, - }); - - // Check fo DOM element node - if (typeof node !== 'object' || !node.getElementsByClassName) { - return false; - } - - this.done = true; - this.mouseInMouseButton = false; - this.menuHasFocus = false; - this.buttonNode = node; - this.isLink = false; - - if (node.tagName.toLowerCase() === 'a') { - var url = node.getAttribute('href'); - if (url && url.length && url.length > 0) { - this.isLink = true; - } - } -}; - -/** - * @function initMenuButton - * @memberof aria.widget.MenuButton - * @description Adds event handlers to button elements - */ - -aria.widget.MenuButton.prototype.initMenuButton = function () { - var id = this.buttonNode.getAttribute('aria-controls'); - - if (id) { - this.menuNode = document.getElementById(id); - - if (this.menuNode) { - this.menu = new aria.widget.Menu(this.menuNode, this); - this.menu.initMenu(); - this.menuShowing = false; - } - } - - this.closeMenu(false, false); - - var self = this; - - var eventKeyDown = function (event) { - self.eventKeyDown(event, self); - }; - this.buttonNode.addEventListener('keydown', eventKeyDown); - - var eventMouseClick = function (event) { - self.eventMouseClick(event, self); - }; - this.buttonNode.addEventListener('click', eventMouseClick); -}; - -/** - * @function openMenu - * @memberof aria.widget.MenuButton - * @description Opens the menu - */ - -aria.widget.MenuButton.prototype.openMenu = function () { - if (this.menuNode) { - this.menuNode.style.display = 'block'; - this.menuShowing = true; - } -}; - -/** - * @function closeMenu - * @memberof aria.widget.MenuButton - * @description Close the menu - */ - -aria.widget.MenuButton.prototype.closeMenu = function (force, focusMenuButton) { - if (typeof force !== 'boolean') { - force = false; - } - if (typeof focusMenuButton !== 'boolean') { - focusMenuButton = true; - } - - if ( - force || - (!this.mouseInMenuButton && - this.menuNode && - !this.menu.mouseInMenu && - !this.menu.menuHasFocus) - ) { - this.menuNode.style.display = 'none'; - if (focusMenuButton) { - this.buttonNode.focus(); - } - this.menuShowing = false; - } -}; - -/** - * @function toggleMenu - * @memberof aria.widget.MenuButton - * @description Close or open the menu depending on current state - */ - -aria.widget.MenuButton.prototype.toggleMenu = function () { - if (this.menuNode) { - if (this.menuNode.style.display === 'block') { - this.menuNode.style.display = 'none'; - } else { - this.menuNode.style.display = 'block'; - } - } -}; - -/** - * @function moveFocusToFirstMenuItem - * @memberof aria.widget.MenuButton - * @description Move keyboard focus to first menu item - */ - -aria.widget.MenuButton.prototype.moveFocusToFirstMenuItem = function () { - if (this.menu.firstMenuItem) { - this.openMenu(); - this.menu.firstMenuItem.focus(); - } -}; - -/** - * @function moveFocusToLastMenuItem - * @memberof aria.widget.MenuButton - * @description Move keyboard focus to last menu item - */ - -aria.widget.MenuButton.prototype.moveFocusToLastMenuItem = function () { - if (this.menu.lastMenuItem) { - this.openMenu(); - this.menu.lastMenuItem.focus(); - } -}; - -/** - * @function eventKeyDown - * @memberof aria.widget.MenuButton - * @description Keydown event handler for MenuButton Object - * NOTE: The menuButton parameter is needed to provide a reference to the specific - * menuButton - */ - -aria.widget.MenuButton.prototype.eventKeyDown = function (event, menuButton) { - var flag = false; - - switch (event.keyCode) { - case menuButton.keyCode.SPACE: - menuButton.moveFocusToFirstMenuItem(); - flag = true; - break; - - case menuButton.keyCode.RETURN: - menuButton.moveFocusToFirstMenuItem(); - flag = true; - break; - - case menuButton.keyCode.UP: - if (this.menuShowing) { - menuButton.moveFocusToLastMenuItem(); - flag = true; - } - break; - - case menuButton.keyCode.DOWN: - if (this.menuShowing) { - menuButton.moveFocusToFirstMenuItem(); - flag = true; - } - break; - - case menuButton.keyCode.TAB: - menuButton.closeMenu(true, false); - break; - - default: - break; - } - - if (flag) { - event.stopPropagation(); - event.preventDefault(); - } -}; - -/** - * @param event - * @param menuButton - * @function eventMouseClick - * @memberof aria.widget.MenuButton - * @description Click event handler for MenuButton Object - * NOTE: The menuButton parameter is needed to provide a reference to the specific - * menuButton - */ -aria.widget.MenuButton.prototype.eventMouseClick = function ( - event, - menuButton -) { - menuButton.moveFocusToFirstMenuItem(); -}; diff --git a/tests/minimal-data-grid/reference/2022-4-27_115334/js/utils.js b/tests/minimal-data-grid/reference/2022-4-27_115334/js/utils.js new file mode 100644 index 000000000..116414b8f --- /dev/null +++ b/tests/minimal-data-grid/reference/2022-4-27_115334/js/utils.js @@ -0,0 +1,131 @@ +'use strict'; +/** + * @namespace aria + */ + +var aria = aria || {}; + +/** + * @description + * Key code constants + */ +aria.KeyCode = { + BACKSPACE: 8, + TAB: 9, + RETURN: 13, + SHIFT: 16, + ESC: 27, + SPACE: 32, + PAGE_UP: 33, + PAGE_DOWN: 34, + END: 35, + HOME: 36, + LEFT: 37, + UP: 38, + RIGHT: 39, + DOWN: 40, + DELETE: 46, +}; + +aria.Utils = aria.Utils || {}; + +// Polyfill src https://developer.mozilla.org/en-US/docs/Web/API/Element/matches +aria.Utils.matches = function (element, selector) { + if (!Element.prototype.matches) { + Element.prototype.matches = + Element.prototype.matchesSelector || + Element.prototype.mozMatchesSelector || + Element.prototype.msMatchesSelector || + Element.prototype.oMatchesSelector || + Element.prototype.webkitMatchesSelector || + function (s) { + var matches = element.parentNode.querySelectorAll(s); + var i = matches.length; + while (--i >= 0 && matches.item(i) !== this) { + // empty + } + return i > -1; + }; + } + + return element.matches(selector); +}; + +aria.Utils.remove = function (item) { + if (item.remove && typeof item.remove === 'function') { + return item.remove(); + } + if ( + item.parentNode && + item.parentNode.removeChild && + typeof item.parentNode.removeChild === 'function' + ) { + return item.parentNode.removeChild(item); + } + return false; +}; + +aria.Utils.isFocusable = function (element) { + if (element.tabIndex < 0) { + return false; + } + + if (element.disabled) { + return false; + } + + switch (element.nodeName) { + case 'A': + return !!element.href && element.rel != 'ignore'; + case 'INPUT': + return element.type != 'hidden'; + case 'BUTTON': + case 'SELECT': + case 'TEXTAREA': + return true; + default: + return false; + } +}; + +aria.Utils.getAncestorBySelector = function (element, selector) { + if (!aria.Utils.matches(element, selector + ' ' + element.tagName)) { + // Element is not inside an element that matches selector + return null; + } + + // Move up the DOM tree until a parent matching the selector is found + var currentNode = element; + var ancestor = null; + while (ancestor === null) { + if (aria.Utils.matches(currentNode.parentNode, selector)) { + ancestor = currentNode.parentNode; + } else { + currentNode = currentNode.parentNode; + } + } + + return ancestor; +}; + +aria.Utils.hasClass = function (element, className) { + return new RegExp('(\\s|^)' + className + '(\\s|$)').test(element.className); +}; + +aria.Utils.addClass = function (element, className) { + if (!aria.Utils.hasClass(element, className)) { + element.className += ' ' + className; + } +}; + +aria.Utils.removeClass = function (element, className) { + var classRegex = new RegExp('(\\s|^)' + className + '(\\s|$)'); + element.className = element.className.replace(classRegex, ' ').trim(); +}; + +aria.Utils.bindMethods = function (object /* , ...methodNames */) { + var methodNames = Array.prototype.slice.call(arguments, 1); + methodNames.forEach(function (method) { + object[method] = object[method].bind(object); + }); +}; From 48ab58428db436eedd7e5b1449a49edde96f7bb5 Mon Sep 17 00:00:00 2001 From: Isabel Del Castillo Date: Wed, 27 Apr 2022 13:30:59 -0500 Subject: [PATCH 3/5] Example: remove unneeded CSS/JS references and update page title --- .../reference/2022-4-27_115334/dataGrids.html | 761 +----------------- .../arrows-group-in-four-directions-2.png | Bin 15495 -> 0 bytes .../arrows-group-in-four-directions-3.png | Bin 15664 -> 0 bytes .../imgs/arrows-group-in-four-directions.png | Bin 703 -> 0 bytes .../reference/2022-4-27_115334/imgs/keys.png | Bin 372 -> 0 bytes .../2022-4-27_115334/imgs/pencil-icon.png | Bin 5253 -> 0 bytes 6 files changed, 7 insertions(+), 754 deletions(-) delete mode 100644 tests/minimal-data-grid/reference/2022-4-27_115334/imgs/arrows-group-in-four-directions-2.png delete mode 100644 tests/minimal-data-grid/reference/2022-4-27_115334/imgs/arrows-group-in-four-directions-3.png delete mode 100644 tests/minimal-data-grid/reference/2022-4-27_115334/imgs/arrows-group-in-four-directions.png delete mode 100644 tests/minimal-data-grid/reference/2022-4-27_115334/imgs/keys.png delete mode 100644 tests/minimal-data-grid/reference/2022-4-27_115334/imgs/pencil-icon.png diff --git a/tests/minimal-data-grid/reference/2022-4-27_115334/dataGrids.html b/tests/minimal-data-grid/reference/2022-4-27_115334/dataGrids.html index 7bb2ba279..91c592fb8 100644 --- a/tests/minimal-data-grid/reference/2022-4-27_115334/dataGrids.html +++ b/tests/minimal-data-grid/reference/2022-4-27_115334/dataGrids.html @@ -4,46 +4,22 @@ Data Grid Examples - - - - - - - - - - + -

Data Grid Examples

- Following are three example implementations of the - design pattern for grid + Following is an example implementation of the + design pattern for grid that demonstrate the keyboard interactions and ARIA features that enable accessible, interactive presentation - of tabular information. Each of the following three grids presents a set of financial - transactions. The first is a simple grid with minimum ARIA markup and keyboard support. The - second and third implementations add advanced features, such as content editing, sort, scroll, - and show/hide. + of tabular information. The following grid presents a set of financial + transactions via a simple grid with minimum ARIA markup and keyboard support.

-

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.
  • -

Examples

@@ -53,6 +29,7 @@

Example 1: Minimal Data Grid

Transactions January 1 through January 6

+ Navigate forwards from here @@ -116,737 +93,13 @@

Transactions January 1 through January 6

Date $995,532.00
+ Navigate backwards from here
-

Notes

-
    -
  1. - Data cells can be focused using standard navigation keys, including directional arrows, Home, - End, Control + Home, and Control + End. -
  2. -
  3. - The Page Down and Page Up keys are not supported since such - scroll-like functions are not useful with so few rows. -
  4. -
  5. The links can be activated with the keyboard when focused.
  6. -
  7. - Since the header cells do not provide any functionality, they are not focusable. - Screen reader users are still aware of their presence because row and column headers are announced by screen readers during navigation. - And, they are also navigable when using a screen reader's reading or browsing mode. -
  8. -
-
-
-

Example 2: Sortable Data Grid With Editable Cells

-
- -
-

Transactions January 1 through January 7

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Date - TypeDescriptionCategory - Amount - Balance
01-Jan-16Deposit -
- Cash Deposit - -
-
$1,000,000.00$1,000,000.00
02-Jan-16Debit -
- Down Town - Grocery - -
-
$250.00$999,750.00
03-Jan-16Debit -
- Hot Coffee - -
-
$9.00$999,741.00
04-Jan-16Debit -
- The Filling - Station - -
-
$88.00$999,653.00
05-Jan-16Debit -
- Tinker's - Hardware - -
-
$3,421.00$996,232.00
06-Jan-16Debit -
- Cutey's Salon - -
-
$700.00$995,532.00
07-Jan-16Debit -
- My Chocolate - Shop - -
-
$41.00$995,491.00
-
- -

Notes

-
    -
  1. The navigation keys and functions are the same as example 1 except that the column - headers are focusable because the date and amount columns provide sort functionality.
  2. -
  3. A description may be edited by activating the cell.
  4. -
  5. A category may be changed by using the category popup menu.
  6. -
-
-
-
-

Example 3: Scrollable Data Grid With Column Hiding

-
- -
-

Transactions for January 1 through January 15

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
DateTypeDescriptionCategoryAmountBalance
01-Jan-16Deposit - Cash Deposit - Income$1,000,000.00$1,000,000.00
02-Jan-16Debit - Down Town Grocery - Groceries$250.00$999,750.00
03-Jan-16Debit - Hot Coffee - Dining Out$9.00$999,741.00
04-Jan-16Debit - The Filling Station - Auto$88.00$999,653.00
05-Jan-16Debit - Tinker's Hardware - Household$3,421.00$996,232.00
06-Jan-16Debit - Cutey's Salon - Beauty$700.00$995,532.00
07-Jan-16Debit - My Chocolate Shop - Dining Out$41.00$995,491.00
08-Jan-16Debit - Who's Cook'n - Dining Out$150.00$995,341.00
09-Jan-16Debit - Dmuddy Paws - Pet$100.00$995,241.00
10-Jan-16Debit - West End Bikes - Recreation$6,420.00$988,821.00
11-Jan-16Debit - Pay More Cars - Auto$431,323.00$557,498.00
12-Jan-16Debit - The Interior Shop - Household$142,334.00$415,164.00
13-Jan-16Debit - Adventure Guys - Recreation$88,424.00$326,740.00
14-Jan-16Debit - Hungry Folks Place - Dining Out$313.00$326,427.00
15-Jan-16Debit - Horse Play - Recreation$2,421.00$324,006.00
-
- -

Notes

-
    -
  1. - In addition to the navigation keys supported in examples 1 and 2, Page Down and - Page Up scroll the grid. -
  2. -
  3. - As navigating up or down scrolls the visible set of rows, the aria-rowindex - value of the row containing the focus informs the screen reader of the number of that row - within the total set of rows. -
  4. -
  5. Activating the "Hide Type and Category" button hides the type and category columns.
  6. -
  7. - The aria-colindex value on a cell informs screen readers of the - position of that cell within the row. - When one or more columns are hidden, screen reader users can be aware of the hidden columns - because those column numbers are not present as users navigate across a row. -
  8. -
-
-
- -
-

Keyboard Support

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
keyFunction
- Right Arrow - -
    -
  • Moves focus one cell to the right.
  • -
  • If focus is on the right-most cell in the row, focus does not move.
  • -
-
- Left Arrow - -
    -
  • Moves focus one cell to the left.
  • -
  • If focus is on the left-most cell in the row, focus does not move.
  • -
-
- Down Arrow - -
    -
  • Moves focus one cell down.
  • -
  • If focus is on the bottom cell in the column, focus does not move.
  • -
-
- Up Arrow - -
    -
  • Moves focus one cell Up.
  • -
  • If focus is on the top cell in the column, focus does not move.
  • -
-
- Page Down - -
    -
  • In example 3, moves focus down five rows, scrolling so the bottom row in the - currently visible set of rows becomes the first visible row.
  • -
  • If focus is in the last row, focus does not move.
  • -
-
- Page Up - -
    -
  • In example 3, moves focus up 5 rows, scrolling so the top row in the currently - visible set of rows becomes the last visible row.
  • -
  • If focus is in the first row of the grid, focus does not move.
  • -
-
- Home - moves focus to the first cell in the row that contains focus.
- End - moves focus to the last cell in the row that contains focus.
- Control + Home - moves focus to the first cell in the first row.
- Control + End - moves focus to the last cell in the last row.
-
- -
-

Role, Property, State, and Tabindex Attributes

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
RoleAttributeElementUsage
- grid - - table - -
    -
  • Identifies the element that serves as the grid widget container.
  • -
  • - Because focus is managed using - roving tabindex - , the grid element is not focusable. -
  • -
  • - Since the grid role is applied to a table element, the row - , rowheader, colheader, and gridcell roles do - not need to be specified because they are implied by tr, th, - and td tags. -
  • -
-
- aria-labelledby="ID_REF" - - table - Refers to the heading element that labels the grid.
- aria-rowcount="16" - - table - -
    -
  • In example 3, specified because a total of 16 rows are available, but fewer - than 16 rows are visible.
  • -
  • - In this case, to demonstrate this feature, some rows are hidden using display:none, - which excludes them from the browser's accessibility tree. -
  • -
  • - a more common scenario for using aria-rowcount is when not all data is - loaded into the DOM at one time. -
  • -
-
- aria-colcount="6" - - table - -
    -
  • In example 3, specified because a total of 6 columns are available, but when - columns are hidden, fewer than 6 columns are visible.
  • -
  • - Similar to how aria-rowcount overrides the browser calculation of the - total number of rows, the browser uses this value for the total number of columns so - it can report the correct number when columns are hidden. -
  • -
-
- aria-rowindex="INDEX_VALUE" - - tr - -
    -
  • Used in example 3 because not all rows are present in the accessibility tree.
  • -
  • Overrides the browser calculation of the row number.
  • -
  • Has a value from 1 to 16.
  • -
  • Note that it is 1-based, not 0-based.
  • -
-
- aria-sort="ascending" - - th - In example 2, applied when a column is sorted in ascending order.
- aria-sort="descending" - - th - In example 2, applied when a column is sorted in descending order.
- aria-sort="none" - - th - In example 2, applied when a column is sortable but not sorted.
- aria-colindex="INDEX_VALUE" - - th and td - -
    -
  • Used in example 3 because when the column hiding feature is used, not all - columns are present in the accessibility tree.
  • -
  • Overrides the browser calculation of the column number.
  • -
  • Has a value from 1 to 6.
  • -
  • Note that it is 1-based, not 0-based.
  • -
-
- -
-

Javascript and CSS Source Code

- -
- -
-

HTML Source Code

-

Example 1: Minimal Data Grid

- -
- - - -

Example 2: Sortable Data Grid With Editable Cells

- -
- - - -

Example 3: Scrollable Data Grid With Column Hiding

- -
- - - - -
- diff --git a/tests/minimal-data-grid/reference/2022-4-27_115334/imgs/arrows-group-in-four-directions-2.png b/tests/minimal-data-grid/reference/2022-4-27_115334/imgs/arrows-group-in-four-directions-2.png deleted file mode 100644 index ca32c5f713bdc79b8ad943c0f344a33a5eb06e7e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15495 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 RsFn-9Y(a&6U-7EV{{v=o z<1fFQXIhiT@eRtMQYy(iUWZGoB>i}OU3yN^4RJ$WKEq|-eQJ(M-2S@r*U^sa>8Fo! zd`XQ;s%dz9&w)q5#lfg0N+9S?=wrLK6%)QqRnd7W;rz=u*YL>x;)-6W=GFUNSbN=k zuxsg03D@SB;8H^`w$^R;ZcJkIHaBZv=czc-*sfD^<}kZ&&6U>n+?qSb#rbNUHcr>8 zd3#vgzvgS}^!Hs~|8s|n_~jJL)_)ERO4SnAh?11Vl2ohYqEsNoU}Ruuu4`bVYhV^) zWME}rVr6WiZD43+U?5bZcLPO3ZhlH;S|x4`$%@lbfEpx0HU#IVm6RtIr81P4m+NKb eWfvzW7NqLs7p2dBXCnnv#Ng@b=d#Wzp$PzZIsYdB diff --git a/tests/minimal-data-grid/reference/2022-4-27_115334/imgs/keys.png b/tests/minimal-data-grid/reference/2022-4-27_115334/imgs/keys.png deleted file mode 100644 index 01d47a0da08efd46bb0aa8f7abd8784448c0b181..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 372 zcmV-)0gL{LP)2_h&c;BRh$m*bV9@E3)pp z`|RA0k%-`8n1&pns@41E;Mxnps*Jn#CNOyS+sE&pqsQlZhF>2yuDyxLFbx3eM2Mi* z(*rYmbqc36tZq;W_LA{Zu#lrgth$y4fU^z==bh&}z0r<{mQphHMOcJ;#-OPiiP+4H zLs-4&$#S2)iE!TkgDC)1wUVDlw|^J&q?^!J3-y~mlR(}CEDvf4D Sg1}Dz0000BnXHKRIGvz zI&F|psj^VDEkuD}D5z8^4~-F6K`kn}Vg;!vDhLWH{ceEn?o6k%Q{CwwyUZ}>o-g0| zopXNYeBa4UW>DaV?@pOB1%jY=eOGcrAjndL{@YlCl|fhkEFiFIp9u9Dg-D&qS0a#i zv_gR3d}Vww5`yrfljAQSOCiWgBn^#FM+EqL3KcRkAKgPvlEndQ2wJ*4DUL6ULDV<_ zB9_X%@O`Jg$K#~YUiffE02~mOJ;5`&Ou^&KThuXL__3fO0)lWHg%ZIr$S_F=GhrN)N~Y4?+}+(>aWt3; zQ(zi}N+VI-J?S)07{-nN;ej`0w8%4r%NzFvG%vhFt&a1gP!bap$%%BbLMf(DSu7Tc zL8Fnt4w5QauI49^GH+QQ-lj9Id2%=IXD21RNq6HJifVrU#YEqQa~dEH@v9x0^SU#iCAN z{FW_^`%DSTLiEyS$!7 z!GhM+&zuL=a94#FYr@)pyzRHhXRR(|tst}FXmhLSN=3>LQ*}tywY1yxpuX{BOkb|o zkW;r;GkwS;q2+}_kh;%u7X-1j77)$^K^a&Gs>Qq&)gIh701Dz;n~~pCwV|7#(qJnH zg?dvJB#J_zd81Hotg39@DtY5|cw6L+*WqoE2TJ-@$(yLdpWKKr?%-65HupLE=1uzX zTr@4-zQCGjZsN29z1dZ5d{B+EKOeD4S=4n=Te0i8%(R-CTEBI6zr^IU%hu@rbSZS+ zBYkP(Ub(DpsdN8;<(&jtSD9A#(N_L(63)cdmIa3FKI5p8To_7Wb|HLgq&&yArJ0a& zf~RrWRot_9E;xY_f>CaKKAW&QBEHNwTXbiZa~!wI?bKl2yAl{$QuCqzrEc#f#`B z#EfLV?!-(H5oZ+48xbBS-hWW0v#rH!l5Lx=@-y|BaXOZeQIEK$IxILQbyyH#ojI0L z19_Gh;M~7eqg^f7;9!1c8kdzE9a@wkV8;*cRgm1oZh8LmCV!n`xsNy1@*=PO^fkeu zbx(!so%^?&ZmoE&5DVnlEZS)97(IVKMwlCt|K;wg#a*lU*2%GmrTTs3g1v!3$xc37 zIX45#K3o*LGJf+x1?wk$jxFnhPj&uJi()q%u4Ihvu9A#QJ5CD9cA%%x3SE2pjqQiD zep^SpwHBE9#!u|UbGJ{zW$XOUv(jUc%dwhE4{jJl)v|`2`bq=sZwo=0@A*VtuFTP& zFce_`wVbT-Wex2IoF|_b6K5y`aZ!1NC1(f+!-oxBJzAn5P&T?V#;#3Rk16OS_^sN= zN|7%!rtN*_rPCF5gKc!ZzeX39Nfav@ZmI@1RvXw}VJ2vJI^ruOihFim>>FBO0eJ2x zEUEDD3*Ibd4AtI4OLB}rbZO$ELT$t)D^K{xG1ieF=5Q zjLF$k{!^TZP8xOoB1=CL8QM*YAW<$%0(|C1zlR_`?Wgl|6~h(An>A{g1s^~LA8;1G zBdGa?7H(V@#nz_791UZJxP4tzfm1WpirXGn^!EUC0pb0KGM^5JWB8TNcK45v{Qe9vn}Cs2Rd7m zgGGE>DO<_Lf;c&B2jZJ+$|@f$jJ?G(byKemxPWL1oQR?{0&$7)v)tjC2q1CxUp4o( zn~7j+GHJkRp+As-Ngx5~_6U&auoaMKncs#ohB}V+XDVaKjz{pPCuFlyA^EzpJ1XNgLb2%>xot6G$t25zdIp3@nh?@x}jGflCQ~f%WK zbDLy!y$^lCK?Z|k$L4K}SC=kcz6;vWhCcgr{IpK}JjVsQ_AS;?|L;FtBhU#82Q&N^SiqAb8 z`Pf;1>DpC)%GT{d6Q^*mk2!;yjL5a56h(S!IJjY(UVc~TueGo%&9NfcDrZ}m|#Eaw6B5!Qi-Zy7aa(GR_ArgXA#sLS3FCjH7?tdcS2~E1>p^h+b0z9 z3sC|vOw;g8kaNMpX6lao8Ir1Q?fNXZ$QA+)UVx zTeIDtm#x|ZSZjfz@;+5rl4^3Q&Ud_iK;TEM(Zo-^HtXxgENn?b0EruU`I*t&3oT3T z&RV`X9Q8W~OfF?$L474H_soq{$Ksn;XCl4Elaqfg6IeeiR#lFAhMiQJ;~Th|wDWNB zLl1K+W<*+`)@!?1BH;4XsLC{0|1yN361F3Z7y0zyhLEvqrR6xs5zK_PF~6|Q-Tli` z<$#Yg2Qao-AGAD*%99>(l?fja|KX?8>yi^qcWW-T-MMaAi&Q??b&agAE$&`VF3bBlv_V_nu>C z$)1fiE1x8|b?LO(g6+>_mLP(uhQ7hnq(MWmhhMR(uWl>6r<`8HfDqLw3>b+`XVy0a z0))X555McxIlL*Q75D>T4K@9ag+z2V7i7RoJnW9^PdbQ?iKv5Jy$=`NcF4dE zrRu4AE9zm&WBH!C$YI@uY|;D!x2lg!uEktU1Gr5|=Ta+g7`lq|_9Ja~CPn-(K3oTG zJLoGq6XG%xZ%glCtk0dCoPkwiMLmPFdzjd{qy6ON;jP_SvX5GG%3Am1YcW59F8Lx} zl1msV93JAGXmnf*8nz$an)&Em(b^oXEjbDua2!#dl csdg}A&q;eS?T{=N{bA78Cy;x5#ioyc0S&R! Date: Wed, 27 Apr 2022 13:35:31 -0500 Subject: [PATCH 4/5] Remove previous APG example --- .../2021-3-8_151542/css/dataGrids.css | 80 -- .../reference/2021-3-8_151542/dataGrids.html | 105 -- .../dataGrids.setFocusAfterGrid.html | 128 --- .../dataGrids.setFocusBeforeGrid.html | 128 --- .../dataGrids.setFocusOnFifthDataCell.html | 129 --- .../dataGrids.setFocusOnFirstDataCell.html | 129 --- .../dataGrids.setFocusOnFirstLinkedCell.html | 129 --- .../dataGrids.setFocusOnFourthDataCell.html | 129 --- .../dataGrids.setFocusOnLastDataCell.html | 129 --- .../dataGrids.setFocusOnSecondDataCell.html | 129 --- .../dataGrids.setFocusOnSecondLinkedCell.html | 129 --- .../dataGrids.setFocusOnSixthDataCell.html | 129 --- .../2021-3-8_151542/imgs/black_keys.png | Bin 8414 -> 0 bytes .../reference/2021-3-8_151542/js/dataGrid.js | 902 ------------------ .../reference/2021-3-8_151542/js/dataGrids.js | 51 - .../reference/2021-3-8_151542/js/utils.js | 131 --- 16 files changed, 2557 deletions(-) delete mode 100644 tests/minimal-data-grid/reference/2021-3-8_151542/css/dataGrids.css delete mode 100644 tests/minimal-data-grid/reference/2021-3-8_151542/dataGrids.html delete mode 100644 tests/minimal-data-grid/reference/2021-3-8_151542/dataGrids.setFocusAfterGrid.html delete mode 100644 tests/minimal-data-grid/reference/2021-3-8_151542/dataGrids.setFocusBeforeGrid.html delete mode 100644 tests/minimal-data-grid/reference/2021-3-8_151542/dataGrids.setFocusOnFifthDataCell.html delete mode 100644 tests/minimal-data-grid/reference/2021-3-8_151542/dataGrids.setFocusOnFirstDataCell.html delete mode 100644 tests/minimal-data-grid/reference/2021-3-8_151542/dataGrids.setFocusOnFirstLinkedCell.html delete mode 100644 tests/minimal-data-grid/reference/2021-3-8_151542/dataGrids.setFocusOnFourthDataCell.html delete mode 100644 tests/minimal-data-grid/reference/2021-3-8_151542/dataGrids.setFocusOnLastDataCell.html delete mode 100644 tests/minimal-data-grid/reference/2021-3-8_151542/dataGrids.setFocusOnSecondDataCell.html delete mode 100644 tests/minimal-data-grid/reference/2021-3-8_151542/dataGrids.setFocusOnSecondLinkedCell.html delete mode 100644 tests/minimal-data-grid/reference/2021-3-8_151542/dataGrids.setFocusOnSixthDataCell.html delete mode 100644 tests/minimal-data-grid/reference/2021-3-8_151542/imgs/black_keys.png delete mode 100644 tests/minimal-data-grid/reference/2021-3-8_151542/js/dataGrid.js delete mode 100644 tests/minimal-data-grid/reference/2021-3-8_151542/js/dataGrids.js delete mode 100644 tests/minimal-data-grid/reference/2021-3-8_151542/js/utils.js diff --git a/tests/minimal-data-grid/reference/2021-3-8_151542/css/dataGrids.css b/tests/minimal-data-grid/reference/2021-3-8_151542/css/dataGrids.css deleted file mode 100644 index 49ef67dd4..000000000 --- a/tests/minimal-data-grid/reference/2021-3-8_151542/css/dataGrids.css +++ /dev/null @@ -1,80 +0,0 @@ -.annotate { - font-style: italic; - color: #366ed4; -} - -.hidden { - display: none !important; -} - -[role="button"] { - cursor: pointer; -} - -[aria-sort="ascending"] { - position: relative; -} - -[aria-sort="ascending"]::after { - content: " "; - border-bottom: 0.4em solid black; - border-left: 0.4em solid transparent; - border-right: 0.4em solid transparent; - position: absolute; - right: 1em; - top: 0.8em; -} - -[aria-sort="descending"] { - position: relative; -} - -[aria-sort="descending"]::after { - content: " "; - border-left: 0.4em solid transparent; - border-right: 0.4em solid transparent; - border-top: 0.4em solid black; - position: absolute; - right: 1em; - top: 0.8em; -} - -.edit-text-button { - color: #360; - display: block; - position: relative; -} - -.edit-text-button:hover, -.edit-text-button:focus { - color: black; -} - -.edit-text-button:hover::after, -.edit-text-button:focus::after { - opacity: 1; -} - -[role="gridcell"]:focus, -[role="gridcell"] *:focus, -[role="grid"] [tabindex="0"]:focus { - outline: #005a9c; - outline-style: dotted; - outline-width: 3px; -} - -#arrow-keys-indicator { - bottom: 10px; - left: 0; - position: fixed; - height: 65px; - width: 85px; - background: url("../imgs/black_keys.png") no-repeat; - background-size: contain; -} - -@media screen and (max-width: 1000px) { - #arrow-keys-indicator { - display: none; - } -} diff --git a/tests/minimal-data-grid/reference/2021-3-8_151542/dataGrids.html b/tests/minimal-data-grid/reference/2021-3-8_151542/dataGrids.html deleted file mode 100644 index b8ea71e73..000000000 --- a/tests/minimal-data-grid/reference/2021-3-8_151542/dataGrids.html +++ /dev/null @@ -1,105 +0,0 @@ - - - - -Data Grid Examples - - - - - - - - -
-

Data Grid Examples

-

- Following is an example implementation of the - design pattern for grid - that demonstrate the keyboard interactions and ARIA features that enable accessible, interactive presentation - of tabular information. The following grid presents a set of financial - transactions via a simple grid with minimum ARIA markup and keyboard support. -

-
-

Examples

-
-
-

Example 1: Minimal Data Grid

-
- -
-

Transactions January 1 through January 6

- Navigate forwards from here - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
DateTypeDescriptionAmountBalance
01-Jan-16Deposit - Cash Deposit - $1,000,000.00$1,000,000.00
02-Jan-16Debit - Down Town Grocery - $250.00$999,750.00
03-Jan-16Debit - Hot Coffee - $9.00$999,741.00
04-Jan-16Debit - The Filling Station - $88.00$999,653.00
05-Jan-16Debit - Tinker's Hardware - $3,421.00$996,232.00
06-Jan-16Debit - Cutey's Salon - $700.00$995,532.00
- Navigate backwards from here -
- -
-
- - -
- - diff --git a/tests/minimal-data-grid/reference/2021-3-8_151542/dataGrids.setFocusAfterGrid.html b/tests/minimal-data-grid/reference/2021-3-8_151542/dataGrids.setFocusAfterGrid.html deleted file mode 100644 index 32d4eb995..000000000 --- a/tests/minimal-data-grid/reference/2021-3-8_151542/dataGrids.setFocusAfterGrid.html +++ /dev/null @@ -1,128 +0,0 @@ - - - - -Data Grid Examples - - - - - - - - - - - -
-

Data Grid Examples

-

- Following is an example implementation of the - design pattern for grid - that demonstrate the keyboard interactions and ARIA features that enable accessible, interactive presentation - of tabular information. The following grid presents a set of financial - transactions via a simple grid with minimum ARIA markup and keyboard support. -

-
-

Examples

-
-
-

Example 1: Minimal Data Grid

-
- -
-

Transactions January 1 through January 6

- Navigate forwards from here - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
DateTypeDescriptionAmountBalance
01-Jan-16Deposit - Cash Deposit - $1,000,000.00$1,000,000.00
02-Jan-16Debit - Down Town Grocery - $250.00$999,750.00
03-Jan-16Debit - Hot Coffee - $9.00$999,741.00
04-Jan-16Debit - The Filling Station - $88.00$999,653.00
05-Jan-16Debit - Tinker's Hardware - $3,421.00$996,232.00
06-Jan-16Debit - Cutey's Salon - $700.00$995,532.00
- Navigate backwards from here -
- -
-
- - - - -
- -
-
- - diff --git a/tests/minimal-data-grid/reference/2021-3-8_151542/dataGrids.setFocusBeforeGrid.html b/tests/minimal-data-grid/reference/2021-3-8_151542/dataGrids.setFocusBeforeGrid.html deleted file mode 100644 index c9e7dbb5b..000000000 --- a/tests/minimal-data-grid/reference/2021-3-8_151542/dataGrids.setFocusBeforeGrid.html +++ /dev/null @@ -1,128 +0,0 @@ - - - - -Data Grid Examples - - - - - - - - - - - -
-

Data Grid Examples

-

- Following is an example implementation of the - design pattern for grid - that demonstrate the keyboard interactions and ARIA features that enable accessible, interactive presentation - of tabular information. The following grid presents a set of financial - transactions via a simple grid with minimum ARIA markup and keyboard support. -

-
-

Examples

-
-
-

Example 1: Minimal Data Grid

-
- -
-

Transactions January 1 through January 6

- Navigate forwards from here - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
DateTypeDescriptionAmountBalance
01-Jan-16Deposit - Cash Deposit - $1,000,000.00$1,000,000.00
02-Jan-16Debit - Down Town Grocery - $250.00$999,750.00
03-Jan-16Debit - Hot Coffee - $9.00$999,741.00
04-Jan-16Debit - The Filling Station - $88.00$999,653.00
05-Jan-16Debit - Tinker's Hardware - $3,421.00$996,232.00
06-Jan-16Debit - Cutey's Salon - $700.00$995,532.00
- Navigate backwards from here -
- -
-
- - - - -
- -
-
- - diff --git a/tests/minimal-data-grid/reference/2021-3-8_151542/dataGrids.setFocusOnFifthDataCell.html b/tests/minimal-data-grid/reference/2021-3-8_151542/dataGrids.setFocusOnFifthDataCell.html deleted file mode 100644 index 8b2f91142..000000000 --- a/tests/minimal-data-grid/reference/2021-3-8_151542/dataGrids.setFocusOnFifthDataCell.html +++ /dev/null @@ -1,129 +0,0 @@ - - - - -Data Grid Examples - - - - - - - - - - - -
-

Data Grid Examples

-

- Following is an example implementation of the - design pattern for grid - that demonstrate the keyboard interactions and ARIA features that enable accessible, interactive presentation - of tabular information. The following grid presents a set of financial - transactions via a simple grid with minimum ARIA markup and keyboard support. -

-
-

Examples

-
-
-

Example 1: Minimal Data Grid

-
- -
-

Transactions January 1 through January 6

- Navigate forwards from here - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
DateTypeDescriptionAmountBalance
01-Jan-16Deposit - Cash Deposit - $1,000,000.00$1,000,000.00
02-Jan-16Debit - Down Town Grocery - $250.00$999,750.00
03-Jan-16Debit - Hot Coffee - $9.00$999,741.00
04-Jan-16Debit - The Filling Station - $88.00$999,653.00
05-Jan-16Debit - Tinker's Hardware - $3,421.00$996,232.00
06-Jan-16Debit - Cutey's Salon - $700.00$995,532.00
- Navigate backwards from here -
- -
-
- - - - -
- -
-
- - diff --git a/tests/minimal-data-grid/reference/2021-3-8_151542/dataGrids.setFocusOnFirstDataCell.html b/tests/minimal-data-grid/reference/2021-3-8_151542/dataGrids.setFocusOnFirstDataCell.html deleted file mode 100644 index 3e0002ff5..000000000 --- a/tests/minimal-data-grid/reference/2021-3-8_151542/dataGrids.setFocusOnFirstDataCell.html +++ /dev/null @@ -1,129 +0,0 @@ - - - - -Data Grid Examples - - - - - - - - - - - -
-

Data Grid Examples

-

- Following is an example implementation of the - design pattern for grid - that demonstrate the keyboard interactions and ARIA features that enable accessible, interactive presentation - of tabular information. The following grid presents a set of financial - transactions via a simple grid with minimum ARIA markup and keyboard support. -

-
-

Examples

-
-
-

Example 1: Minimal Data Grid

-
- -
-

Transactions January 1 through January 6

- Navigate forwards from here - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
DateTypeDescriptionAmountBalance
01-Jan-16Deposit - Cash Deposit - $1,000,000.00$1,000,000.00
02-Jan-16Debit - Down Town Grocery - $250.00$999,750.00
03-Jan-16Debit - Hot Coffee - $9.00$999,741.00
04-Jan-16Debit - The Filling Station - $88.00$999,653.00
05-Jan-16Debit - Tinker's Hardware - $3,421.00$996,232.00
06-Jan-16Debit - Cutey's Salon - $700.00$995,532.00
- Navigate backwards from here -
- -
-
- - - - -
- -
-
- - diff --git a/tests/minimal-data-grid/reference/2021-3-8_151542/dataGrids.setFocusOnFirstLinkedCell.html b/tests/minimal-data-grid/reference/2021-3-8_151542/dataGrids.setFocusOnFirstLinkedCell.html deleted file mode 100644 index c9eb17d00..000000000 --- a/tests/minimal-data-grid/reference/2021-3-8_151542/dataGrids.setFocusOnFirstLinkedCell.html +++ /dev/null @@ -1,129 +0,0 @@ - - - - -Data Grid Examples - - - - - - - - - - - -
-

Data Grid Examples

-

- Following is an example implementation of the - design pattern for grid - that demonstrate the keyboard interactions and ARIA features that enable accessible, interactive presentation - of tabular information. The following grid presents a set of financial - transactions via a simple grid with minimum ARIA markup and keyboard support. -

-
-

Examples

-
-
-

Example 1: Minimal Data Grid

-
- -
-

Transactions January 1 through January 6

- Navigate forwards from here - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
DateTypeDescriptionAmountBalance
01-Jan-16Deposit - Cash Deposit - $1,000,000.00$1,000,000.00
02-Jan-16Debit - Down Town Grocery - $250.00$999,750.00
03-Jan-16Debit - Hot Coffee - $9.00$999,741.00
04-Jan-16Debit - The Filling Station - $88.00$999,653.00
05-Jan-16Debit - Tinker's Hardware - $3,421.00$996,232.00
06-Jan-16Debit - Cutey's Salon - $700.00$995,532.00
- Navigate backwards from here -
- -
-
- - - - -
- -
-
- - diff --git a/tests/minimal-data-grid/reference/2021-3-8_151542/dataGrids.setFocusOnFourthDataCell.html b/tests/minimal-data-grid/reference/2021-3-8_151542/dataGrids.setFocusOnFourthDataCell.html deleted file mode 100644 index b0d2ab7b9..000000000 --- a/tests/minimal-data-grid/reference/2021-3-8_151542/dataGrids.setFocusOnFourthDataCell.html +++ /dev/null @@ -1,129 +0,0 @@ - - - - -Data Grid Examples - - - - - - - - - - - -
-

Data Grid Examples

-

- Following is an example implementation of the - design pattern for grid - that demonstrate the keyboard interactions and ARIA features that enable accessible, interactive presentation - of tabular information. The following grid presents a set of financial - transactions via a simple grid with minimum ARIA markup and keyboard support. -

-
-

Examples

-
-
-

Example 1: Minimal Data Grid

-
- -
-

Transactions January 1 through January 6

- Navigate forwards from here - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
DateTypeDescriptionAmountBalance
01-Jan-16Deposit - Cash Deposit - $1,000,000.00$1,000,000.00
02-Jan-16Debit - Down Town Grocery - $250.00$999,750.00
03-Jan-16Debit - Hot Coffee - $9.00$999,741.00
04-Jan-16Debit - The Filling Station - $88.00$999,653.00
05-Jan-16Debit - Tinker's Hardware - $3,421.00$996,232.00
06-Jan-16Debit - Cutey's Salon - $700.00$995,532.00
- Navigate backwards from here -
- -
-
- - - - -
- -
-
- - diff --git a/tests/minimal-data-grid/reference/2021-3-8_151542/dataGrids.setFocusOnLastDataCell.html b/tests/minimal-data-grid/reference/2021-3-8_151542/dataGrids.setFocusOnLastDataCell.html deleted file mode 100644 index 440ac7ef4..000000000 --- a/tests/minimal-data-grid/reference/2021-3-8_151542/dataGrids.setFocusOnLastDataCell.html +++ /dev/null @@ -1,129 +0,0 @@ - - - - -Data Grid Examples - - - - - - - - - - - -
-

Data Grid Examples

-

- Following is an example implementation of the - design pattern for grid - that demonstrate the keyboard interactions and ARIA features that enable accessible, interactive presentation - of tabular information. The following grid presents a set of financial - transactions via a simple grid with minimum ARIA markup and keyboard support. -

-
-

Examples

-
-
-

Example 1: Minimal Data Grid

-
- -
-

Transactions January 1 through January 6

- Navigate forwards from here - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
DateTypeDescriptionAmountBalance
01-Jan-16Deposit - Cash Deposit - $1,000,000.00$1,000,000.00
02-Jan-16Debit - Down Town Grocery - $250.00$999,750.00
03-Jan-16Debit - Hot Coffee - $9.00$999,741.00
04-Jan-16Debit - The Filling Station - $88.00$999,653.00
05-Jan-16Debit - Tinker's Hardware - $3,421.00$996,232.00
06-Jan-16Debit - Cutey's Salon - $700.00$995,532.00
- Navigate backwards from here -
- -
-
- - - - -
- -
-
- - diff --git a/tests/minimal-data-grid/reference/2021-3-8_151542/dataGrids.setFocusOnSecondDataCell.html b/tests/minimal-data-grid/reference/2021-3-8_151542/dataGrids.setFocusOnSecondDataCell.html deleted file mode 100644 index be932a38b..000000000 --- a/tests/minimal-data-grid/reference/2021-3-8_151542/dataGrids.setFocusOnSecondDataCell.html +++ /dev/null @@ -1,129 +0,0 @@ - - - - -Data Grid Examples - - - - - - - - - - - -
-

Data Grid Examples

-

- Following is an example implementation of the - design pattern for grid - that demonstrate the keyboard interactions and ARIA features that enable accessible, interactive presentation - of tabular information. The following grid presents a set of financial - transactions via a simple grid with minimum ARIA markup and keyboard support. -

-
-

Examples

-
-
-

Example 1: Minimal Data Grid

-
- -
-

Transactions January 1 through January 6

- Navigate forwards from here - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
DateTypeDescriptionAmountBalance
01-Jan-16Deposit - Cash Deposit - $1,000,000.00$1,000,000.00
02-Jan-16Debit - Down Town Grocery - $250.00$999,750.00
03-Jan-16Debit - Hot Coffee - $9.00$999,741.00
04-Jan-16Debit - The Filling Station - $88.00$999,653.00
05-Jan-16Debit - Tinker's Hardware - $3,421.00$996,232.00
06-Jan-16Debit - Cutey's Salon - $700.00$995,532.00
- Navigate backwards from here -
- -
-
- - - - -
- -
-
- - diff --git a/tests/minimal-data-grid/reference/2021-3-8_151542/dataGrids.setFocusOnSecondLinkedCell.html b/tests/minimal-data-grid/reference/2021-3-8_151542/dataGrids.setFocusOnSecondLinkedCell.html deleted file mode 100644 index 40ab3a736..000000000 --- a/tests/minimal-data-grid/reference/2021-3-8_151542/dataGrids.setFocusOnSecondLinkedCell.html +++ /dev/null @@ -1,129 +0,0 @@ - - - - -Data Grid Examples - - - - - - - - - - - -
-

Data Grid Examples

-

- Following is an example implementation of the - design pattern for grid - that demonstrate the keyboard interactions and ARIA features that enable accessible, interactive presentation - of tabular information. The following grid presents a set of financial - transactions via a simple grid with minimum ARIA markup and keyboard support. -

-
-

Examples

-
-
-

Example 1: Minimal Data Grid

-
- -
-

Transactions January 1 through January 6

- Navigate forwards from here - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
DateTypeDescriptionAmountBalance
01-Jan-16Deposit - Cash Deposit - $1,000,000.00$1,000,000.00
02-Jan-16Debit - Down Town Grocery - $250.00$999,750.00
03-Jan-16Debit - Hot Coffee - $9.00$999,741.00
04-Jan-16Debit - The Filling Station - $88.00$999,653.00
05-Jan-16Debit - Tinker's Hardware - $3,421.00$996,232.00
06-Jan-16Debit - Cutey's Salon - $700.00$995,532.00
- Navigate backwards from here -
- -
-
- - - - -
- -
-
- - diff --git a/tests/minimal-data-grid/reference/2021-3-8_151542/dataGrids.setFocusOnSixthDataCell.html b/tests/minimal-data-grid/reference/2021-3-8_151542/dataGrids.setFocusOnSixthDataCell.html deleted file mode 100644 index 1a94d815e..000000000 --- a/tests/minimal-data-grid/reference/2021-3-8_151542/dataGrids.setFocusOnSixthDataCell.html +++ /dev/null @@ -1,129 +0,0 @@ - - - - -Data Grid Examples - - - - - - - - - - - -
-

Data Grid Examples

-

- Following is an example implementation of the - design pattern for grid - that demonstrate the keyboard interactions and ARIA features that enable accessible, interactive presentation - of tabular information. The following grid presents a set of financial - transactions via a simple grid with minimum ARIA markup and keyboard support. -

-
-

Examples

-
-
-

Example 1: Minimal Data Grid

-
- -
-

Transactions January 1 through January 6

- Navigate forwards from here - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
DateTypeDescriptionAmountBalance
01-Jan-16Deposit - Cash Deposit - $1,000,000.00$1,000,000.00
02-Jan-16Debit - Down Town Grocery - $250.00$999,750.00
03-Jan-16Debit - Hot Coffee - $9.00$999,741.00
04-Jan-16Debit - The Filling Station - $88.00$999,653.00
05-Jan-16Debit - Tinker's Hardware - $3,421.00$996,232.00
06-Jan-16Debit - Cutey's Salon - $700.00$995,532.00
- Navigate backwards from here -
- -
-
- - - - -
- -
-
- - diff --git a/tests/minimal-data-grid/reference/2021-3-8_151542/imgs/black_keys.png b/tests/minimal-data-grid/reference/2021-3-8_151542/imgs/black_keys.png deleted file mode 100644 index 7d8c7b8ac9b171fd948f9b80e7c325c90bf7e6c6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8414 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 diff --git a/tests/minimal-data-grid/reference/2021-3-8_151542/js/dataGrid.js b/tests/minimal-data-grid/reference/2021-3-8_151542/js/dataGrid.js deleted file mode 100644 index 44894e2ea..000000000 --- a/tests/minimal-data-grid/reference/2021-3-8_151542/js/dataGrid.js +++ /dev/null @@ -1,902 +0,0 @@ -/* - * This content is licensed according to the W3C Software License at - * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document - */ - -'use strict'; - -/** - * @namespace aria - */ -var aria = aria || {}; - -/** - * @description - * Values for aria-sort - */ -aria.SortType = { - ASCENDING: 'ascending', - DESCENDING: 'descending', - NONE: 'none', -}; - -/** - * @description - * DOM Selectors to find the grid components - */ -aria.GridSelector = { - ROW: 'tr, [role="row"]', - CELL: 'th, td, [role="gridcell"]', - SCROLL_ROW: 'tr:not([data-fixed]), [role="row"]', - SORT_HEADER: 'th[aria-sort]', - TABBABLE: '[tabindex="0"]', -}; - -/** - * @description - * CSS Class names - */ -aria.CSSClass = { - HIDDEN: 'hidden', -}; - -/** - * @class - * - * @description - * Grid object representing the state and interactions for a grid widget - * - * Assumptions: - * All focusable cells initially have tabindex="-1" - * Produces a fully filled in mxn grid (with no holes) - * - * @param gridNode - * The DOM node pointing to the grid - */ -aria.Grid = function (gridNode) { - this.navigationDisabled = false; - this.gridNode = gridNode; - this.paginationEnabled = this.gridNode.hasAttribute('data-per-page'); - this.shouldWrapCols = this.gridNode.hasAttribute('data-wrap-cols'); - this.shouldWrapRows = this.gridNode.hasAttribute('data-wrap-rows'); - this.shouldRestructure = this.gridNode.hasAttribute('data-restructure'); - this.topIndex = 0; - - this.keysIndicator = document.getElementById('arrow-keys-indicator'); - - aria.Utils.bindMethods( - this, - 'checkFocusChange', - 'checkPageChange', - 'checkRestructureGrid', - 'delegateButtonHandler', - 'focusClickedCell', - 'restructureGrid', - 'showKeysIndicator', - 'hideKeysIndicator' - ); - this.setupFocusGrid(); - this.setFocusPointer(0, 0); - - if (this.paginationEnabled) { - this.setupPagination(); - } else { - this.perPage = this.grid.length; - } - - this.registerEvents(); -}; - -/** - * @description - * Creates a 2D array of the focusable cells in the grid. - */ -aria.Grid.prototype.setupFocusGrid = function () { - this.grid = []; - - Array.prototype.forEach.call( - this.gridNode.querySelectorAll(aria.GridSelector.ROW), - function (row) { - var rowCells = []; - - Array.prototype.forEach.call( - row.querySelectorAll(aria.GridSelector.CELL), - function (cell) { - var focusableSelector = '[tabindex]'; - - if (aria.Utils.matches(cell, focusableSelector)) { - rowCells.push(cell); - } else { - var focusableCell = cell.querySelector(focusableSelector); - - if (focusableCell) { - rowCells.push(focusableCell); - } - } - }.bind(this) - ); - - if (rowCells.length) { - this.grid.push(rowCells); - } - }.bind(this) - ); - - if (this.paginationEnabled) { - this.setupIndices(); - } -}; - -/** - * @description - * If possible, set focus pointer to the cell with the specified coordinates - * - * @param row - * The index of the cell's row - * - * @param col - * The index of the cell's column - * - * @returns {boolean} - * Returns whether or not the focus could be set on the cell. - */ -aria.Grid.prototype.setFocusPointer = function (row, col) { - if (!this.isValidCell(row, col)) { - return false; - } - - if (this.isHidden(row, col)) { - return false; - } - - if (!isNaN(this.focusedRow) && !isNaN(this.focusedCol)) { - this.grid[this.focusedRow][this.focusedCol].setAttribute('tabindex', -1); - } - - this.grid[row][col].removeEventListener('focus', this.showKeysIndicator); - this.grid[row][col].removeEventListener('blur', this.hideKeysIndicator); - - // Disable navigation if focused on an input - this.navigationDisabled = aria.Utils.matches(this.grid[row][col], 'input'); - - this.grid[row][col].setAttribute('tabindex', 0); - this.focusedRow = row; - this.focusedCol = col; - - this.grid[row][col].addEventListener('focus', this.showKeysIndicator); - this.grid[row][col].addEventListener('blur', this.hideKeysIndicator); - - return true; -}; - -/** - * @param row - * The index of the cell's row - * - * @param col - * The index of the cell's column - * - * @returns {boolean} - * Returns whether or not the coordinates are within the grid's boundaries. - */ -aria.Grid.prototype.isValidCell = function (row, col) { - return ( - !isNaN(row) && - !isNaN(col) && - row >= 0 && - col >= 0 && - this.grid && - this.grid.length && - row < this.grid.length && - col < this.grid[row].length - ); -}; - -/** - * @param row - * The index of the cell's row - * - * @param col - * The index of the cell's column - * - * @returns {boolean} - * Returns whether or not the cell has been hidden. - */ -aria.Grid.prototype.isHidden = function (row, col) { - var cell = this.gridNode - .querySelectorAll(aria.GridSelector.ROW) - [row].querySelectorAll(aria.GridSelector.CELL)[col]; - return aria.Utils.hasClass(cell, aria.CSSClass.HIDDEN); -}; - -/** - * @description - * Clean up grid events - */ -aria.Grid.prototype.clearEvents = function () { - this.gridNode.removeEventListener('keydown', this.checkFocusChange); - this.gridNode.removeEventListener('keydown', this.delegateButtonHandler); - this.gridNode.removeEventListener('click', this.focusClickedCell); - this.gridNode.removeEventListener('click', this.delegateButtonHandler); - - if (this.paginationEnabled) { - this.gridNode.removeEventListener('keydown', this.checkPageChange); - } - - if (this.shouldRestructure) { - window.removeEventListener('resize', this.checkRestructureGrid); - } - - this.grid[this.focusedRow][this.focusedCol].removeEventListener( - 'focus', - this.showKeysIndicator - ); - this.grid[this.focusedRow][this.focusedCol].removeEventListener( - 'blur', - this.hideKeysIndicator - ); -}; - -/** - * @description - * Register grid events - */ -aria.Grid.prototype.registerEvents = function () { - this.clearEvents(); - - this.gridNode.addEventListener('keydown', this.checkFocusChange); - this.gridNode.addEventListener('keydown', this.delegateButtonHandler); - this.gridNode.addEventListener('click', this.focusClickedCell); - this.gridNode.addEventListener('click', this.delegateButtonHandler); - - if (this.paginationEnabled) { - this.gridNode.addEventListener('keydown', this.checkPageChange); - } - - if (this.shouldRestructure) { - window.addEventListener('resize', this.checkRestructureGrid); - } -}; - -/** - * @description - * Focus on the cell in the specified row and column - * - * @param row - * The index of the cell's row - * - * @param col - * The index of the cell's column - */ -aria.Grid.prototype.focusCell = function (row, col) { - if (this.setFocusPointer(row, col)) { - this.grid[row][col].focus(); - } -}; - -aria.Grid.prototype.showKeysIndicator = function () { - if (this.keysIndicator) { - aria.Utils.removeClass(this.keysIndicator, 'hidden'); - } -}; - -aria.Grid.prototype.hideKeysIndicator = function () { - if ( - this.keysIndicator && - this.grid[this.focusedRow][this.focusedCol].tabIndex === 0 - ) { - aria.Utils.addClass(this.keysIndicator, 'hidden'); - } -}; - -/** - * @description - * Triggered on keydown. Checks if an arrow key was pressed, and (if possible) - * moves focus to the next valid cell in the direction of the arrow key. - * - * @param event - * Keydown event - */ -aria.Grid.prototype.checkFocusChange = function (event) { - if (!event || this.navigationDisabled) { - return; - } - - this.findFocusedItem(event.target); - - var key = event.which || event.keyCode; - var rowCaret = this.focusedRow; - var colCaret = this.focusedCol; - var nextCell; - - switch (key) { - case aria.KeyCode.UP: - nextCell = this.getNextVisibleCell(0, -1); - rowCaret = nextCell.row; - colCaret = nextCell.col; - break; - case aria.KeyCode.DOWN: - nextCell = this.getNextVisibleCell(0, 1); - rowCaret = nextCell.row; - colCaret = nextCell.col; - break; - case aria.KeyCode.LEFT: - nextCell = this.getNextVisibleCell(-1, 0); - rowCaret = nextCell.row; - colCaret = nextCell.col; - break; - case aria.KeyCode.RIGHT: - nextCell = this.getNextVisibleCell(1, 0); - rowCaret = nextCell.row; - colCaret = nextCell.col; - break; - case aria.KeyCode.HOME: - if (event.ctrlKey) { - rowCaret = 0; - } - colCaret = 0; - break; - case aria.KeyCode.END: - if (event.ctrlKey) { - rowCaret = this.grid.length - 1; - } - colCaret = this.grid[this.focusedRow].length - 1; - break; - default: - return; - } - - if (this.paginationEnabled) { - if (rowCaret < this.topIndex) { - this.showFromRow(rowCaret, true); - } - - if (rowCaret >= this.topIndex + this.perPage) { - this.showFromRow(rowCaret, false); - } - } - - this.focusCell(rowCaret, colCaret); - event.preventDefault(); -}; - -/** - * @description - * Reset focused row and col if it doesn't match focusedRow and focusedCol - * - * @param focusedTarget - * Element that is currently focused by browser - */ -aria.Grid.prototype.findFocusedItem = function (focusedTarget) { - var focusedCell = this.grid[this.focusedRow][this.focusedCol]; - - if (focusedCell === focusedTarget || focusedCell.contains(focusedTarget)) { - return; - } - - for (var i = 0; i < this.grid.length; i++) { - for (var j = 0; j < this.grid[i].length; j++) { - if ( - this.grid[i][j] === focusedTarget || - this.grid[i][j].contains(focusedTarget) - ) { - this.setFocusPointer(i, j); - return; - } - } - } -}; - -/** - * @description - * Triggered on click. Finds the cell that was clicked on and focuses on it. - * - * @param event - * Keydown event - */ -aria.Grid.prototype.focusClickedCell = function (event) { - var clickedGridCell = this.findClosest(event.target, '[tabindex]'); - - for (var row = 0; row < this.grid.length; row++) { - for (var col = 0; col < this.grid[row].length; col++) { - if (this.grid[row][col] === clickedGridCell) { - this.setFocusPointer(row, col); - - if (!aria.Utils.matches(clickedGridCell, 'button[aria-haspopup]')) { - // Don't focus if it's a menu button (focus should be set to menu) - this.focusCell(row, col); - } - - return; - } - } - } -}; - -/** - * @description - * Triggered on click. Checks if user clicked on a header with aria-sort. - * If so, it sorts the column based on the aria-sort attribute. - * - * @param event - * Keydown event - */ -aria.Grid.prototype.delegateButtonHandler = function (event) { - var key = event.which || event.keyCode; - var target = event.target; - var isClickEvent = event.type === 'click'; - - if (!target) { - return; - } - - if ( - target.parentNode && - target.parentNode.matches('th[aria-sort]') && - (isClickEvent || key === aria.KeyCode.SPACE || key === aria.KeyCode.RETURN) - ) { - event.preventDefault(); - this.handleSort(target.parentNode); - } - - if ( - aria.Utils.matches(target, '.editable-text, .edit-text-button') && - (isClickEvent || key === aria.KeyCode.RETURN) - ) { - event.preventDefault(); - this.toggleEditMode(this.findClosest(target, '.editable-text'), true, true); - } - - if ( - aria.Utils.matches(target, '.edit-text-input') && - (key === aria.KeyCode.RETURN || key === aria.KeyCode.ESC) - ) { - event.preventDefault(); - this.toggleEditMode( - this.findClosest(target, '.editable-text'), - false, - key === aria.KeyCode.RETURN - ); - } -}; - -/** - * @description - * Toggles the mode of an editable cell between displaying the edit button - * and displaying the editable input. - * - * @param editCell - * Cell to toggle - * - * @param toggleOn - * Whether to show or hide edit input - * - * @param updateText - * Whether or not to update the button text with the input text - */ -aria.Grid.prototype.toggleEditMode = function (editCell, toggleOn, updateText) { - var onClassName = toggleOn ? 'edit-text-input' : 'edit-text-button'; - var offClassName = toggleOn ? 'edit-text-button' : 'edit-text-input'; - var onNode = editCell.querySelector('.' + onClassName); - var offNode = editCell.querySelector('.' + offClassName); - - if (toggleOn) { - onNode.value = offNode.innerText; - } else if (updateText) { - onNode.innerText = offNode.value; - } - - aria.Utils.addClass(offNode, aria.CSSClass.HIDDEN); - aria.Utils.removeClass(onNode, aria.CSSClass.HIDDEN); - offNode.setAttribute('tabindex', -1); - onNode.setAttribute('tabindex', 0); - onNode.focus(); - this.grid[this.focusedRow][this.focusedCol] = onNode; - this.navigationDisabled = toggleOn; -}; - -/** - * @description - * Sorts the column below the header node, based on the aria-sort attribute. - * aria-sort="none" => aria-sort="ascending" - * aria-sort="ascending" => aria-sort="descending" - * All other headers with aria-sort are reset to "none" - * - * Note: This implementation assumes that there is no pagination on the grid. - * - * @param headerNode - * Header DOM node - */ -aria.Grid.prototype.handleSort = function (headerNode) { - var columnIndex = headerNode.cellIndex; - var sortType = headerNode.getAttribute('aria-sort'); - - if (sortType === aria.SortType.ASCENDING) { - sortType = aria.SortType.DESCENDING; - } else { - sortType = aria.SortType.ASCENDING; - } - - var comparator = function (row1, row2) { - var row1Text = row1.children[columnIndex].innerText; - var row2Text = row2.children[columnIndex].innerText; - var row1Value = parseInt(row1Text.replace(/[^0-9.]+/g, '')); - var row2Value = parseInt(row2Text.replace(/[^0-9.]+/g, '')); - - if (sortType === aria.SortType.ASCENDING) { - return row1Value - row2Value; - } else { - return row2Value - row1Value; - } - }; - - this.sortRows(comparator); - this.setupFocusGrid(); - - Array.prototype.forEach.call( - this.gridNode.querySelectorAll(aria.GridSelector.SORT_HEADER), - function (headerCell) { - headerCell.setAttribute('aria-sort', aria.SortType.NONE); - } - ); - - headerNode.setAttribute('aria-sort', sortType); -}; - -/** - * @description - * Sorts the grid's rows according to the specified compareFn - * - * @param compareFn - * Comparison function to sort the rows - */ -aria.Grid.prototype.sortRows = function (compareFn) { - var rows = this.gridNode.querySelectorAll(aria.GridSelector.ROW); - var rowWrapper = rows[0].parentNode; - var dataRows = Array.prototype.slice.call(rows, 1); - - dataRows.sort(compareFn); - - dataRows.forEach( - function (row) { - rowWrapper.appendChild(row); - }.bind(this) - ); -}; - -/** - * @description - * Adds aria-rowindex and aria-colindex to the cells in the grid - */ -aria.Grid.prototype.setupIndices = function () { - var rows = this.gridNode.querySelectorAll(aria.GridSelector.ROW); - - for (var row = 0; row < rows.length; row++) { - var cols = rows[row].querySelectorAll(aria.GridSelector.CELL); - rows[row].setAttribute('aria-rowindex', row + 1); - - for (var col = 0; col < cols.length; col++) { - cols[col].setAttribute('aria-colindex', col + 1); - } - } -}; - -/** - * @description - * Determines the per page attribute of the grid, and shows/hides rows - * accordingly. - */ -aria.Grid.prototype.setupPagination = function () { - this.onPaginationChange = this.onPaginationChange || function () {}; - this.perPage = parseInt(this.gridNode.getAttribute('data-per-page')); - this.showFromRow(0, true); -}; - -aria.Grid.prototype.setPaginationChangeHandler = function (onPaginationChange) { - this.onPaginationChange = onPaginationChange; -}; - -/** - * @description - * Check if page up or page down was pressed, and show the next page if so. - * - * @param event - * Keydown event - */ -aria.Grid.prototype.checkPageChange = function (event) { - if (!event) { - return; - } - - var key = event.which || event.keyCode; - - if (key === aria.KeyCode.PAGE_UP) { - event.preventDefault(); - this.movePageUp(); - } else if (key === aria.KeyCode.PAGE_DOWN) { - event.preventDefault(); - this.movePageDown(); - } -}; - -aria.Grid.prototype.movePageUp = function () { - var startIndex = Math.max(this.perPage - 1, this.topIndex - 1); - this.showFromRow(startIndex, false); - this.focusCell(startIndex, this.focusedCol); -}; - -aria.Grid.prototype.movePageDown = function () { - var startIndex = this.topIndex + this.perPage; - this.showFromRow(startIndex, true); - this.focusCell(startIndex, this.focusedCol); -}; - -/** - * @description - * Scroll the specified row into view in the specified direction - * - * @param startIndex - * Row index to use as the start index - * - * @param scrollDown - * Whether to scroll the new page above or below the row index - */ -aria.Grid.prototype.showFromRow = function (startIndex, scrollDown) { - var dataRows = this.gridNode.querySelectorAll(aria.GridSelector.SCROLL_ROW); - var reachedTop = false; - var firstIndex = -1; - var endIndex = -1; - - if (startIndex < 0 || startIndex >= dataRows.length) { - return; - } - - for (var i = 0; i < dataRows.length; i++) { - if ( - (scrollDown && i >= startIndex && i < startIndex + this.perPage) || - (!scrollDown && i <= startIndex && i > startIndex - this.perPage) - ) { - aria.Utils.removeClass(dataRows[i], aria.CSSClass.HIDDEN); - - if (!reachedTop) { - this.topIndex = i; - reachedTop = true; - } - - if (firstIndex < 0) { - firstIndex = i; - } - endIndex = i; - } else { - aria.Utils.addClass(dataRows[i], aria.CSSClass.HIDDEN); - } - } - this.onPaginationChange(firstIndex, endIndex); -}; - -/** - * @description - * Throttle restructuring to only happen every 300ms - */ -aria.Grid.prototype.checkRestructureGrid = function () { - if (this.waitingToRestructure) { - return; - } - - this.waitingToRestructure = true; - - setTimeout(this.restructureGrid, 300); -}; - -/** - * @description - * Restructure grid based on the size. - */ -aria.Grid.prototype.restructureGrid = function () { - this.waitingToRestructure = false; - - var gridWidth = this.gridNode.offsetWidth; - var cells = this.gridNode.querySelectorAll(aria.GridSelector.CELL); - var currentWidth = 0; - - var focusedElement = this.gridNode.querySelector(aria.GridSelector.TABBABLE); - var shouldRefocus = document.activeElement === focusedElement; - var focusedIndex = this.focusedRow * this.grid[0].length + this.focusedCol; - - var newRow = document.createElement('div'); - newRow.setAttribute('role', 'row'); - this.gridNode.innerHTML = ''; - this.gridNode.append(newRow); - - cells.forEach(function (cell) { - var cellWidth = cell.offsetWidth; - - if (currentWidth > 0 && currentWidth >= gridWidth - cellWidth) { - newRow = document.createElement('div'); - newRow.setAttribute('role', 'row'); - this.gridNode.append(newRow); - currentWidth = 0; - } - - newRow.append(cell); - currentWidth += cellWidth; - }); - - this.setupFocusGrid(); - - this.focusedRow = Math.floor(focusedIndex / this.grid[0].length); - this.focusedCol = focusedIndex % this.grid[0].length; - - if (shouldRefocus) { - this.focusCell(this.focusedRow, this.focusedCol); - } -}; - -/** - * @description - * Get next cell to the right or left (direction) of the focused - * cell. - * @param currRow - * Row index to start searching from - * @param currCol - * Column index to start searching from - * @param directionX - * X direction for where to check for cells. +1 to check to the right, -1 to - * check to the left - * @param directionY - * @returns {false | object} - * Indices of the next cell in the specified direction. Returns the focused - * cell if none are found. - */ -aria.Grid.prototype.getNextCell = function ( - currRow, - currCol, - directionX, - directionY -) { - var row = currRow + directionY; - var col = currCol + directionX; - var rowCount = this.grid.length; - var isLeftRight = directionX !== 0; - - if (!rowCount) { - return false; - } - - var colCount = this.grid[0].length; - - if (this.shouldWrapCols && isLeftRight) { - if (col < 0) { - col = colCount - 1; - row--; - } - - if (col >= colCount) { - col = 0; - row++; - } - } - - if (this.shouldWrapRows && !isLeftRight) { - if (row < 0) { - col--; - row = rowCount - 1; - if (this.grid[row] && col >= 0 && !this.grid[row][col]) { - // Sometimes the bottom row is not completely filled in. In this case, - // jump to the next filled in cell. - row--; - } - } else if (row >= rowCount || !this.grid[row][col]) { - row = 0; - col++; - } - } - - if (this.isValidCell(row, col)) { - return { - row: row, - col: col, - }; - } else if (this.isValidCell(currRow, currCol)) { - return { - row: currRow, - col: currCol, - }; - } else { - return false; - } -}; - -/** - * @param directionX - * @param directionY - * @description -Get next visible column to the right or left (direction) of the focused - * cell. - * @returns {false | object} - * Indices of the next visible cell in the specified direction. If no visible - * cells are found, returns false if the current cell is hidden and returns - * the current cell if it is not hidden. - */ -aria.Grid.prototype.getNextVisibleCell = function (directionX, directionY) { - var nextCell = this.getNextCell( - this.focusedRow, - this.focusedCol, - directionX, - directionY - ); - - if (!nextCell) { - return false; - } - - while (this.isHidden(nextCell.row, nextCell.col)) { - var currRow = nextCell.row; - var currCol = nextCell.col; - - nextCell = this.getNextCell(currRow, currCol, directionX, directionY); - - if (currRow === nextCell.row && currCol === nextCell.col) { - // There are no more cells to try if getNextCell returns the current cell - return false; - } - } - - return nextCell; -}; - -/** - * @description - * Show or hide the cells in the specified column - * - * @param columnIndex - * Index of the column to toggle - * - * @param isShown - * Whether or not to show the column - */ -aria.Grid.prototype.toggleColumn = function (columnIndex, isShown) { - var cellSelector = '[aria-colindex="' + columnIndex + '"]'; - var columnCells = this.gridNode.querySelectorAll(cellSelector); - - Array.prototype.forEach.call(columnCells, function (cell) { - if (isShown) { - aria.Utils.removeClass(cell, aria.CSSClass.HIDDEN); - } else { - aria.Utils.addClass(cell, aria.CSSClass.HIDDEN); - } - }); - - if (!isShown && this.focusedCol === columnIndex - 1) { - // If focus was set on the hidden column, shift focus to the right - var nextCell = this.getNextVisibleCell(1, 0); - if (nextCell) { - this.setFocusPointer(nextCell.row, nextCell.col); - } - } -}; - -/** - * @description - * Find the closest element matching the selector. Only checks parent and - * direct children. - * - * @param element - * Element to start searching from - * - * @param selector - * Index of the column to toggle - * - * @returns {object} matching element - */ -aria.Grid.prototype.findClosest = function (element, selector) { - if (aria.Utils.matches(element, selector)) { - return element; - } - - if (aria.Utils.matches(element.parentNode, selector)) { - return element.parentNode; - } - - return element.querySelector(selector); -}; diff --git a/tests/minimal-data-grid/reference/2021-3-8_151542/js/dataGrids.js b/tests/minimal-data-grid/reference/2021-3-8_151542/js/dataGrids.js deleted file mode 100644 index f80997afc..000000000 --- a/tests/minimal-data-grid/reference/2021-3-8_151542/js/dataGrids.js +++ /dev/null @@ -1,51 +0,0 @@ -/* - * This content is licensed according to the W3C Software License at - * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document - */ - -/* global aria */ - -'use strict'; - -/** - * ARIA Grid Examples - * - * @function onload - * @description Initialize the grid examples once the page has loaded - */ - -window.addEventListener('load', function () { - // Initialize Example 1 Grid (if it is present in the DOM) - var ex1GridElement = document.getElementById('ex1-grid'); - if (ex1GridElement) { - var ex1Grid = new aria.Grid(ex1GridElement); - document.defaultView.ex1Grid = ex1Grid; - } - - // Initialize Example 2 Grid (if it is present in the DOM) - var ex2GridElement = document.getElementById('ex2-grid'); - if (ex2GridElement) { - new aria.Grid(ex2GridElement); - } - - // Initialize Example 3 Grid (if it is present in the DOM) - var ex3GridElement = document.getElementById('ex3-grid'); - if (ex3GridElement) { - var ex3Grid = new aria.Grid(ex3GridElement); - var toggleButton = document.getElementById('toggle_column_btn'); - var toggledOn = true; - - toggleButton.addEventListener('click', function () { - toggledOn = !toggledOn; - - ex3Grid.toggleColumn(2, toggledOn); - ex3Grid.toggleColumn(4, toggledOn); - - if (toggledOn) { - toggleButton.innerText = 'Hide Type and Category'; - } else { - toggleButton.innerText = 'Show Type and Category'; - } - }); - } -}); diff --git a/tests/minimal-data-grid/reference/2021-3-8_151542/js/utils.js b/tests/minimal-data-grid/reference/2021-3-8_151542/js/utils.js deleted file mode 100644 index 116414b8f..000000000 --- a/tests/minimal-data-grid/reference/2021-3-8_151542/js/utils.js +++ /dev/null @@ -1,131 +0,0 @@ -'use strict'; -/** - * @namespace aria - */ - -var aria = aria || {}; - -/** - * @description - * Key code constants - */ -aria.KeyCode = { - BACKSPACE: 8, - TAB: 9, - RETURN: 13, - SHIFT: 16, - ESC: 27, - SPACE: 32, - PAGE_UP: 33, - PAGE_DOWN: 34, - END: 35, - HOME: 36, - LEFT: 37, - UP: 38, - RIGHT: 39, - DOWN: 40, - DELETE: 46, -}; - -aria.Utils = aria.Utils || {}; - -// Polyfill src https://developer.mozilla.org/en-US/docs/Web/API/Element/matches -aria.Utils.matches = function (element, selector) { - if (!Element.prototype.matches) { - Element.prototype.matches = - Element.prototype.matchesSelector || - Element.prototype.mozMatchesSelector || - Element.prototype.msMatchesSelector || - Element.prototype.oMatchesSelector || - Element.prototype.webkitMatchesSelector || - function (s) { - var matches = element.parentNode.querySelectorAll(s); - var i = matches.length; - while (--i >= 0 && matches.item(i) !== this) { - // empty - } - return i > -1; - }; - } - - return element.matches(selector); -}; - -aria.Utils.remove = function (item) { - if (item.remove && typeof item.remove === 'function') { - return item.remove(); - } - if ( - item.parentNode && - item.parentNode.removeChild && - typeof item.parentNode.removeChild === 'function' - ) { - return item.parentNode.removeChild(item); - } - return false; -}; - -aria.Utils.isFocusable = function (element) { - if (element.tabIndex < 0) { - return false; - } - - if (element.disabled) { - return false; - } - - switch (element.nodeName) { - case 'A': - return !!element.href && element.rel != 'ignore'; - case 'INPUT': - return element.type != 'hidden'; - case 'BUTTON': - case 'SELECT': - case 'TEXTAREA': - return true; - default: - return false; - } -}; - -aria.Utils.getAncestorBySelector = function (element, selector) { - if (!aria.Utils.matches(element, selector + ' ' + element.tagName)) { - // Element is not inside an element that matches selector - return null; - } - - // Move up the DOM tree until a parent matching the selector is found - var currentNode = element; - var ancestor = null; - while (ancestor === null) { - if (aria.Utils.matches(currentNode.parentNode, selector)) { - ancestor = currentNode.parentNode; - } else { - currentNode = currentNode.parentNode; - } - } - - return ancestor; -}; - -aria.Utils.hasClass = function (element, className) { - return new RegExp('(\\s|^)' + className + '(\\s|$)').test(element.className); -}; - -aria.Utils.addClass = function (element, className) { - if (!aria.Utils.hasClass(element, className)) { - element.className += ' ' + className; - } -}; - -aria.Utils.removeClass = function (element, className) { - var classRegex = new RegExp('(\\s|^)' + className + '(\\s|$)'); - element.className = element.className.replace(classRegex, ' ').trim(); -}; - -aria.Utils.bindMethods = function (object /* , ...methodNames */) { - var methodNames = Array.prototype.slice.call(arguments, 1); - methodNames.forEach(function (method) { - object[method] = object[method].bind(object); - }); -}; From 5c6df5b92662e4ab8cc8fb8f2d0853c876e67924 Mon Sep 17 00:00:00 2001 From: IsaDC Date: Wed, 27 Apr 2022 18:37:12 +0000 Subject: [PATCH 5/5] Generate .html source files with scripts automatically --- .../dataGrids.setFocusAfterGrid.html | 128 +++++++++++++++++ .../dataGrids.setFocusBeforeGrid.html | 128 +++++++++++++++++ .../dataGrids.setFocusOnFifthDataCell.html | 129 ++++++++++++++++++ .../dataGrids.setFocusOnFirstDataCell.html | 129 ++++++++++++++++++ .../dataGrids.setFocusOnFirstLinkedCell.html | 129 ++++++++++++++++++ .../dataGrids.setFocusOnFourthDataCell.html | 129 ++++++++++++++++++ .../dataGrids.setFocusOnLastDataCell.html | 129 ++++++++++++++++++ .../dataGrids.setFocusOnSecondDataCell.html | 129 ++++++++++++++++++ .../dataGrids.setFocusOnSecondLinkedCell.html | 129 ++++++++++++++++++ .../dataGrids.setFocusOnSixthDataCell.html | 129 ++++++++++++++++++ 10 files changed, 1288 insertions(+) create mode 100644 tests/minimal-data-grid/reference/2022-4-27_115334/dataGrids.setFocusAfterGrid.html create mode 100644 tests/minimal-data-grid/reference/2022-4-27_115334/dataGrids.setFocusBeforeGrid.html create mode 100644 tests/minimal-data-grid/reference/2022-4-27_115334/dataGrids.setFocusOnFifthDataCell.html create mode 100644 tests/minimal-data-grid/reference/2022-4-27_115334/dataGrids.setFocusOnFirstDataCell.html create mode 100644 tests/minimal-data-grid/reference/2022-4-27_115334/dataGrids.setFocusOnFirstLinkedCell.html create mode 100644 tests/minimal-data-grid/reference/2022-4-27_115334/dataGrids.setFocusOnFourthDataCell.html create mode 100644 tests/minimal-data-grid/reference/2022-4-27_115334/dataGrids.setFocusOnLastDataCell.html create mode 100644 tests/minimal-data-grid/reference/2022-4-27_115334/dataGrids.setFocusOnSecondDataCell.html create mode 100644 tests/minimal-data-grid/reference/2022-4-27_115334/dataGrids.setFocusOnSecondLinkedCell.html create mode 100644 tests/minimal-data-grid/reference/2022-4-27_115334/dataGrids.setFocusOnSixthDataCell.html diff --git a/tests/minimal-data-grid/reference/2022-4-27_115334/dataGrids.setFocusAfterGrid.html b/tests/minimal-data-grid/reference/2022-4-27_115334/dataGrids.setFocusAfterGrid.html new file mode 100644 index 000000000..3b32f2684 --- /dev/null +++ b/tests/minimal-data-grid/reference/2022-4-27_115334/dataGrids.setFocusAfterGrid.html @@ -0,0 +1,128 @@ + + + + +Data Grid Examples + + + + + + + + + + + +
+

Data Grid Examples

+

+ Following is an example implementation of the + design pattern for grid + that demonstrate the keyboard interactions and ARIA features that enable accessible, interactive presentation + of tabular information. The following grid presents a set of financial + transactions via a simple grid with minimum ARIA markup and keyboard support. +

+
+

Examples

+
+
+

Example 1: Minimal Data Grid

+
+ +
+

Transactions January 1 through January 6

+ Navigate forwards from here + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
DateTypeDescriptionAmountBalance
01-Jan-16Deposit + Cash Deposit + $1,000,000.00$1,000,000.00
02-Jan-16Debit + Down Town Grocery + $250.00$999,750.00
03-Jan-16Debit + Hot Coffee + $9.00$999,741.00
04-Jan-16Debit + The Filling Station + $88.00$999,653.00
05-Jan-16Debit + Tinker's Hardware + $3,421.00$996,232.00
06-Jan-16Debit + Cutey's Salon + $700.00$995,532.00
+ Navigate backwards from here +
+ +
+
+ + + + +
+ +
+
+ + diff --git a/tests/minimal-data-grid/reference/2022-4-27_115334/dataGrids.setFocusBeforeGrid.html b/tests/minimal-data-grid/reference/2022-4-27_115334/dataGrids.setFocusBeforeGrid.html new file mode 100644 index 000000000..0a9cbb7d1 --- /dev/null +++ b/tests/minimal-data-grid/reference/2022-4-27_115334/dataGrids.setFocusBeforeGrid.html @@ -0,0 +1,128 @@ + + + + +Data Grid Examples + + + + + + + + + + + +
+

Data Grid Examples

+

+ Following is an example implementation of the + design pattern for grid + that demonstrate the keyboard interactions and ARIA features that enable accessible, interactive presentation + of tabular information. The following grid presents a set of financial + transactions via a simple grid with minimum ARIA markup and keyboard support. +

+
+

Examples

+
+
+

Example 1: Minimal Data Grid

+
+ +
+

Transactions January 1 through January 6

+ Navigate forwards from here + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
DateTypeDescriptionAmountBalance
01-Jan-16Deposit + Cash Deposit + $1,000,000.00$1,000,000.00
02-Jan-16Debit + Down Town Grocery + $250.00$999,750.00
03-Jan-16Debit + Hot Coffee + $9.00$999,741.00
04-Jan-16Debit + The Filling Station + $88.00$999,653.00
05-Jan-16Debit + Tinker's Hardware + $3,421.00$996,232.00
06-Jan-16Debit + Cutey's Salon + $700.00$995,532.00
+ Navigate backwards from here +
+ +
+
+ + + + +
+ +
+
+ + diff --git a/tests/minimal-data-grid/reference/2022-4-27_115334/dataGrids.setFocusOnFifthDataCell.html b/tests/minimal-data-grid/reference/2022-4-27_115334/dataGrids.setFocusOnFifthDataCell.html new file mode 100644 index 000000000..e23ae84a2 --- /dev/null +++ b/tests/minimal-data-grid/reference/2022-4-27_115334/dataGrids.setFocusOnFifthDataCell.html @@ -0,0 +1,129 @@ + + + + +Data Grid Examples + + + + + + + + + + + +
+

Data Grid Examples

+

+ Following is an example implementation of the + design pattern for grid + that demonstrate the keyboard interactions and ARIA features that enable accessible, interactive presentation + of tabular information. The following grid presents a set of financial + transactions via a simple grid with minimum ARIA markup and keyboard support. +

+
+

Examples

+
+
+

Example 1: Minimal Data Grid

+
+ +
+

Transactions January 1 through January 6

+ Navigate forwards from here + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
DateTypeDescriptionAmountBalance
01-Jan-16Deposit + Cash Deposit + $1,000,000.00$1,000,000.00
02-Jan-16Debit + Down Town Grocery + $250.00$999,750.00
03-Jan-16Debit + Hot Coffee + $9.00$999,741.00
04-Jan-16Debit + The Filling Station + $88.00$999,653.00
05-Jan-16Debit + Tinker's Hardware + $3,421.00$996,232.00
06-Jan-16Debit + Cutey's Salon + $700.00$995,532.00
+ Navigate backwards from here +
+ +
+
+ + + + +
+ +
+
+ + diff --git a/tests/minimal-data-grid/reference/2022-4-27_115334/dataGrids.setFocusOnFirstDataCell.html b/tests/minimal-data-grid/reference/2022-4-27_115334/dataGrids.setFocusOnFirstDataCell.html new file mode 100644 index 000000000..f855a2532 --- /dev/null +++ b/tests/minimal-data-grid/reference/2022-4-27_115334/dataGrids.setFocusOnFirstDataCell.html @@ -0,0 +1,129 @@ + + + + +Data Grid Examples + + + + + + + + + + + +
+

Data Grid Examples

+

+ Following is an example implementation of the + design pattern for grid + that demonstrate the keyboard interactions and ARIA features that enable accessible, interactive presentation + of tabular information. The following grid presents a set of financial + transactions via a simple grid with minimum ARIA markup and keyboard support. +

+
+

Examples

+
+
+

Example 1: Minimal Data Grid

+
+ +
+

Transactions January 1 through January 6

+ Navigate forwards from here + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
DateTypeDescriptionAmountBalance
01-Jan-16Deposit + Cash Deposit + $1,000,000.00$1,000,000.00
02-Jan-16Debit + Down Town Grocery + $250.00$999,750.00
03-Jan-16Debit + Hot Coffee + $9.00$999,741.00
04-Jan-16Debit + The Filling Station + $88.00$999,653.00
05-Jan-16Debit + Tinker's Hardware + $3,421.00$996,232.00
06-Jan-16Debit + Cutey's Salon + $700.00$995,532.00
+ Navigate backwards from here +
+ +
+
+ + + + +
+ +
+
+ + diff --git a/tests/minimal-data-grid/reference/2022-4-27_115334/dataGrids.setFocusOnFirstLinkedCell.html b/tests/minimal-data-grid/reference/2022-4-27_115334/dataGrids.setFocusOnFirstLinkedCell.html new file mode 100644 index 000000000..d3e831c64 --- /dev/null +++ b/tests/minimal-data-grid/reference/2022-4-27_115334/dataGrids.setFocusOnFirstLinkedCell.html @@ -0,0 +1,129 @@ + + + + +Data Grid Examples + + + + + + + + + + + +
+

Data Grid Examples

+

+ Following is an example implementation of the + design pattern for grid + that demonstrate the keyboard interactions and ARIA features that enable accessible, interactive presentation + of tabular information. The following grid presents a set of financial + transactions via a simple grid with minimum ARIA markup and keyboard support. +

+
+

Examples

+
+
+

Example 1: Minimal Data Grid

+
+ +
+

Transactions January 1 through January 6

+ Navigate forwards from here + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
DateTypeDescriptionAmountBalance
01-Jan-16Deposit + Cash Deposit + $1,000,000.00$1,000,000.00
02-Jan-16Debit + Down Town Grocery + $250.00$999,750.00
03-Jan-16Debit + Hot Coffee + $9.00$999,741.00
04-Jan-16Debit + The Filling Station + $88.00$999,653.00
05-Jan-16Debit + Tinker's Hardware + $3,421.00$996,232.00
06-Jan-16Debit + Cutey's Salon + $700.00$995,532.00
+ Navigate backwards from here +
+ +
+
+ + + + +
+ +
+
+ + diff --git a/tests/minimal-data-grid/reference/2022-4-27_115334/dataGrids.setFocusOnFourthDataCell.html b/tests/minimal-data-grid/reference/2022-4-27_115334/dataGrids.setFocusOnFourthDataCell.html new file mode 100644 index 000000000..9a0c559db --- /dev/null +++ b/tests/minimal-data-grid/reference/2022-4-27_115334/dataGrids.setFocusOnFourthDataCell.html @@ -0,0 +1,129 @@ + + + + +Data Grid Examples + + + + + + + + + + + +
+

Data Grid Examples

+

+ Following is an example implementation of the + design pattern for grid + that demonstrate the keyboard interactions and ARIA features that enable accessible, interactive presentation + of tabular information. The following grid presents a set of financial + transactions via a simple grid with minimum ARIA markup and keyboard support. +

+
+

Examples

+
+
+

Example 1: Minimal Data Grid

+
+ +
+

Transactions January 1 through January 6

+ Navigate forwards from here + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
DateTypeDescriptionAmountBalance
01-Jan-16Deposit + Cash Deposit + $1,000,000.00$1,000,000.00
02-Jan-16Debit + Down Town Grocery + $250.00$999,750.00
03-Jan-16Debit + Hot Coffee + $9.00$999,741.00
04-Jan-16Debit + The Filling Station + $88.00$999,653.00
05-Jan-16Debit + Tinker's Hardware + $3,421.00$996,232.00
06-Jan-16Debit + Cutey's Salon + $700.00$995,532.00
+ Navigate backwards from here +
+ +
+
+ + + + +
+ +
+
+ + diff --git a/tests/minimal-data-grid/reference/2022-4-27_115334/dataGrids.setFocusOnLastDataCell.html b/tests/minimal-data-grid/reference/2022-4-27_115334/dataGrids.setFocusOnLastDataCell.html new file mode 100644 index 000000000..4699595a5 --- /dev/null +++ b/tests/minimal-data-grid/reference/2022-4-27_115334/dataGrids.setFocusOnLastDataCell.html @@ -0,0 +1,129 @@ + + + + +Data Grid Examples + + + + + + + + + + + +
+

Data Grid Examples

+

+ Following is an example implementation of the + design pattern for grid + that demonstrate the keyboard interactions and ARIA features that enable accessible, interactive presentation + of tabular information. The following grid presents a set of financial + transactions via a simple grid with minimum ARIA markup and keyboard support. +

+
+

Examples

+
+
+

Example 1: Minimal Data Grid

+
+ +
+

Transactions January 1 through January 6

+ Navigate forwards from here + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
DateTypeDescriptionAmountBalance
01-Jan-16Deposit + Cash Deposit + $1,000,000.00$1,000,000.00
02-Jan-16Debit + Down Town Grocery + $250.00$999,750.00
03-Jan-16Debit + Hot Coffee + $9.00$999,741.00
04-Jan-16Debit + The Filling Station + $88.00$999,653.00
05-Jan-16Debit + Tinker's Hardware + $3,421.00$996,232.00
06-Jan-16Debit + Cutey's Salon + $700.00$995,532.00
+ Navigate backwards from here +
+ +
+
+ + + + +
+ +
+
+ + diff --git a/tests/minimal-data-grid/reference/2022-4-27_115334/dataGrids.setFocusOnSecondDataCell.html b/tests/minimal-data-grid/reference/2022-4-27_115334/dataGrids.setFocusOnSecondDataCell.html new file mode 100644 index 000000000..d2e9bfee7 --- /dev/null +++ b/tests/minimal-data-grid/reference/2022-4-27_115334/dataGrids.setFocusOnSecondDataCell.html @@ -0,0 +1,129 @@ + + + + +Data Grid Examples + + + + + + + + + + + +
+

Data Grid Examples

+

+ Following is an example implementation of the + design pattern for grid + that demonstrate the keyboard interactions and ARIA features that enable accessible, interactive presentation + of tabular information. The following grid presents a set of financial + transactions via a simple grid with minimum ARIA markup and keyboard support. +

+
+

Examples

+
+
+

Example 1: Minimal Data Grid

+
+ +
+

Transactions January 1 through January 6

+ Navigate forwards from here + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
DateTypeDescriptionAmountBalance
01-Jan-16Deposit + Cash Deposit + $1,000,000.00$1,000,000.00
02-Jan-16Debit + Down Town Grocery + $250.00$999,750.00
03-Jan-16Debit + Hot Coffee + $9.00$999,741.00
04-Jan-16Debit + The Filling Station + $88.00$999,653.00
05-Jan-16Debit + Tinker's Hardware + $3,421.00$996,232.00
06-Jan-16Debit + Cutey's Salon + $700.00$995,532.00
+ Navigate backwards from here +
+ +
+
+ + + + +
+ +
+
+ + diff --git a/tests/minimal-data-grid/reference/2022-4-27_115334/dataGrids.setFocusOnSecondLinkedCell.html b/tests/minimal-data-grid/reference/2022-4-27_115334/dataGrids.setFocusOnSecondLinkedCell.html new file mode 100644 index 000000000..3af2f1ec1 --- /dev/null +++ b/tests/minimal-data-grid/reference/2022-4-27_115334/dataGrids.setFocusOnSecondLinkedCell.html @@ -0,0 +1,129 @@ + + + + +Data Grid Examples + + + + + + + + + + + +
+

Data Grid Examples

+

+ Following is an example implementation of the + design pattern for grid + that demonstrate the keyboard interactions and ARIA features that enable accessible, interactive presentation + of tabular information. The following grid presents a set of financial + transactions via a simple grid with minimum ARIA markup and keyboard support. +

+
+

Examples

+
+
+

Example 1: Minimal Data Grid

+
+ +
+

Transactions January 1 through January 6

+ Navigate forwards from here + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
DateTypeDescriptionAmountBalance
01-Jan-16Deposit + Cash Deposit + $1,000,000.00$1,000,000.00
02-Jan-16Debit + Down Town Grocery + $250.00$999,750.00
03-Jan-16Debit + Hot Coffee + $9.00$999,741.00
04-Jan-16Debit + The Filling Station + $88.00$999,653.00
05-Jan-16Debit + Tinker's Hardware + $3,421.00$996,232.00
06-Jan-16Debit + Cutey's Salon + $700.00$995,532.00
+ Navigate backwards from here +
+ +
+
+ + + + +
+ +
+
+ + diff --git a/tests/minimal-data-grid/reference/2022-4-27_115334/dataGrids.setFocusOnSixthDataCell.html b/tests/minimal-data-grid/reference/2022-4-27_115334/dataGrids.setFocusOnSixthDataCell.html new file mode 100644 index 000000000..578c1a58a --- /dev/null +++ b/tests/minimal-data-grid/reference/2022-4-27_115334/dataGrids.setFocusOnSixthDataCell.html @@ -0,0 +1,129 @@ + + + + +Data Grid Examples + + + + + + + + + + + +
+

Data Grid Examples

+

+ Following is an example implementation of the + design pattern for grid + that demonstrate the keyboard interactions and ARIA features that enable accessible, interactive presentation + of tabular information. The following grid presents a set of financial + transactions via a simple grid with minimum ARIA markup and keyboard support. +

+
+

Examples

+
+
+

Example 1: Minimal Data Grid

+
+ +
+

Transactions January 1 through January 6

+ Navigate forwards from here + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
DateTypeDescriptionAmountBalance
01-Jan-16Deposit + Cash Deposit + $1,000,000.00$1,000,000.00
02-Jan-16Debit + Down Town Grocery + $250.00$999,750.00
03-Jan-16Debit + Hot Coffee + $9.00$999,741.00
04-Jan-16Debit + The Filling Station + $88.00$999,653.00
05-Jan-16Debit + Tinker's Hardware + $3,421.00$996,232.00
06-Jan-16Debit + Cutey's Salon + $700.00$995,532.00
+ Navigate backwards from here +
+ +
+
+ + + + +
+ +
+
+ +