From ab999d490117ec0048efe07688db84acd5e14ca0 Mon Sep 17 00:00:00 2001 From: Nick Schonning Date: Thu, 1 Oct 2020 13:31:56 -0400 Subject: [PATCH] chore: Run fix for Prettier JS formatting --- examples/accordion/js/accordion.js | 245 +- examples/alert/js/alert.js | 30 +- examples/button/js/button.js | 34 +- examples/button/js/button_idl.js | 34 +- examples/carousel/js/carousel-prev-next.js | 259 ++- examples/carousel/js/carousel-tablist.js | 235 +- examples/checkbox/checkbox-1/js/checkbox.js | 46 +- .../checkbox/checkbox-2/js/checkboxMixed.js | 64 +- .../checkbox-2/js/controlledCheckbox.js | 38 +- examples/combobox/js/combobox-autocomplete.js | 240 +- examples/combobox/js/combobox-datepicker.js | 358 +-- examples/combobox/js/grid-combo-example.js | 15 +- examples/combobox/js/grid-combo.js | 67 +- examples/combobox/js/select-only.js | 149 +- examples/dialog-modal/js/alertdialog.js | 58 +- examples/dialog-modal/js/datepicker-dialog.js | 1596 ++++++------- examples/dialog-modal/js/dialog.js | 87 +- examples/disclosure/js/disclosureButton.js | 74 +- examples/disclosure/js/disclosureMenu.js | 94 +- examples/feed/js/feed.js | 14 +- examples/feed/js/feedDisplay.js | 127 +- examples/feed/js/main.js | 20 +- examples/grid/js/dataGrid.js | 185 +- examples/grid/js/dataGrids.js | 9 +- examples/grid/js/layoutGrids.js | 70 +- examples/grid/js/menuButton.js | 97 +- examples/js/app.js | 52 +- examples/js/examples.js | 151 +- examples/js/utils.js | 15 +- examples/landmarks/js/show.js | 10 +- examples/link/js/link.js | 13 +- examples/listbox/js/listbox-collapsible.js | 10 +- examples/listbox/js/listbox-rearrangeable.js | 50 +- examples/listbox/js/listbox-scrollable.js | 6 +- examples/listbox/js/listbox.js | 141 +- examples/listbox/js/toolbar.js | 11 +- examples/menu-button/js/MenuItemAction.js | 91 +- .../js/MenuItemActionActivedescendant.js | 48 +- examples/menu-button/js/MenuItemLinks.js | 95 +- examples/menu-button/js/Menubutton.js | 96 +- examples/menu-button/js/Menubutton2.js | 102 +- examples/menu-button/js/PopupMenuAction.js | 136 +- .../js/PopupMenuActionActivedescendant.js | 179 +- examples/menu-button/js/PopupMenuLinks.js | 123 +- examples/menubar/js/menubar-editor.js | 186 +- examples/menubar/js/menubar-navigation.js | 1249 +++++----- examples/menubar/js/style-manager.js | 32 +- examples/meter/js/meter.js | 17 +- examples/radio/js/radio-activedescendant.js | 48 +- examples/radio/js/radio.js | 38 +- examples/slider/js/multithumb-slider.js | 479 ++-- examples/slider/js/slider.js | 113 +- examples/slider/js/text-slider.js | 86 +- examples/slider/js/vertical-slider.js | 88 +- .../spinbutton/js/datepicker-spinbuttons.js | 116 +- examples/spinbutton/js/spinbutton-date.js | 98 +- examples/tabs/tabs-1/js/tabs.js | 59 +- examples/tabs/tabs-2/js/tabs.js | 55 +- examples/toolbar/js/FontMenu.js | 59 +- examples/toolbar/js/FontMenuButton.js | 26 +- examples/toolbar/js/FontMenuItem.js | 89 +- examples/toolbar/js/FormatToolbar.js | 124 +- examples/toolbar/js/FormatToolbarItem.js | 74 +- examples/toolbar/js/SpinButton.js | 61 +- examples/treegrid/js/treegrid-1.js | 150 +- examples/treeview/treeview-1/js/tree.js | 69 +- examples/treeview/treeview-1/js/treeitem.js | 73 +- .../treeview/treeview-1/js/treeitemClick.js | 18 +- examples/treeview/treeview-2/js/treeLinks.js | 75 +- .../treeview/treeview-2/js/treeitemLinks.js | 92 +- respec-config.js | 144 +- scripts/coverage-report.js | 380 ++- scripts/reference-tables.js | 129 +- test/index.js | 14 +- test/tests/accordion_accordion.js | 849 ++++--- test/tests/alert_alert.js | 38 +- test/tests/breadcrumb_index.js | 59 +- test/tests/button_button.js | 274 ++- test/tests/carousel_carousel-1-prev-next.js | 536 +++-- test/tests/carousel_carousel-2-tablist.js | 886 ++++--- test/tests/checkbox_checkbox-1.js | 257 ++- test/tests/checkbox_checkbox-2.js | 389 ++-- test/tests/combobox_autocomplete-both.js | 802 ++++--- test/tests/combobox_autocomplete-list.js | 770 +++--- test/tests/combobox_autocomplete-none.js | 748 +++--- test/tests/combobox_datepicker.js | 816 ++++--- test/tests/combobox_grid-combo.js | 768 +++--- test/tests/combobox_select-only.js | 1546 +++++++++---- test/tests/dialog-modal_datepicker.js | 1493 +++++++----- test/tests/dialog-modal_dialog.js | 574 +++-- test/tests/disclosure_faq.js | 234 +- test/tests/disclosure_img-long-description.js | 271 ++- test/tests/disclosure_navigation.js | 680 ++++-- test/tests/feed_feed.js | 306 ++- test/tests/grid_LayoutGrids.js | 1256 ++++++---- test/tests/grid_dataGrids.js | 1232 ++++++---- test/tests/link_link.js | 105 +- test/tests/listbox_collapsible.js | 591 +++-- test/tests/listbox_grouped.js | 516 +++-- test/tests/listbox_rearrangeable.js | 1229 ++++++---- test/tests/listbox_scrollable.js | 191 +- .../menu-button_actions-active-descendant.js | 369 ++- test/tests/menu-button_actions.js | 541 +++-- test/tests/menu-button_links.js | 509 ++-- test/tests/menubar_menubar-editor.js | 1571 ++++++++----- test/tests/menubar_menubar-navigation.js | 2056 ++++++++++------- test/tests/meter_meter.js | 145 +- test/tests/radio_radio-activedescendant.js | 418 ++-- test/tests/radio_radio.js | 454 ++-- test/tests/slider_multithumb.js | 1833 ++++++++------- test/tests/slider_slider-1.js | 1330 ++++++----- test/tests/slider_slider-2.js | 1210 ++++++---- test/tests/spinbutton_datepicker.js | 347 ++- test/tests/table_table.js | 92 +- test/tests/tabs_tabs-1.js | 560 +++-- test/tests/tabs_tabs-2.js | 495 ++-- test/tests/toolbar_toolbar.js | 107 +- test/tests/treegrid_treegrid-1.js | 955 ++++---- test/tests/treeview_treeview-1a.js | 865 ++++--- test/tests/treeview_treeview-1b.js | 953 ++++---- test/tests/treeview_treeview-2a.js | 932 ++++---- test/tests/treeview_treeview-2b.js | 1149 +++++---- test/util/assertAriaActivedescendant.js | 16 +- test/util/assertAriaControls.js | 23 +- test/util/assertAriaDescribedby.js | 48 +- test/util/assertAriaLabelExists.js | 20 +- test/util/assertAriaLabelledby.js | 27 +- test/util/assertAriaRoles.js | 20 +- .../assertAriaSelectedAndActivedescendant.js | 21 +- test/util/assertAttributeDNE.js | 26 +- test/util/assertAttributeValues.js | 15 +- test/util/assertHasFocus.js | 52 +- test/util/assertNoElements.js | 6 +- test/util/assertRovingTabindex.js | 17 +- test/util/assertTabOrder.js | 4 +- test/util/force-serial.js | 29 +- test/util/get-json.js | 52 +- test/util/queryElement.js | 2 +- test/util/queryElements.js | 2 +- test/util/report.js | 86 +- test/util/start-geckodriver.js | 23 +- 141 files changed, 26309 insertions(+), 18302 deletions(-) diff --git a/examples/accordion/js/accordion.js b/examples/accordion/js/accordion.js index 8d0b354ed0..e8b8531700 100644 --- a/examples/accordion/js/accordion.js +++ b/examples/accordion/js/accordion.js @@ -1,134 +1,143 @@ /* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -* -* Simple accordion pattern example -*/ + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * Simple accordion pattern example + */ 'use strict'; -Array.prototype.slice.call(document.querySelectorAll('.Accordion')).forEach(function (accordion) { - - // Allow for multiple accordion sections to be expanded at the same time - var allowMultiple = accordion.hasAttribute('data-allow-multiple'); - // Allow for each toggle to both open and close individually - var allowToggle = (allowMultiple) ? allowMultiple : accordion.hasAttribute('data-allow-toggle'); - - // Create the array of toggle elements for the accordion group - var triggers = Array.prototype.slice.call(accordion.querySelectorAll('.Accordion-trigger')); - var panels = Array.prototype.slice.call(accordion.querySelectorAll('.Accordion-panel')); - - - accordion.addEventListener('click', function (event) { - var target = event.target; - - if (target.classList.contains('Accordion-trigger')) { - // Check if the current toggle is expanded. - var isExpanded = target.getAttribute('aria-expanded') == 'true'; - var active = accordion.querySelector('[aria-expanded="true"]'); - - // without allowMultiple, close the open accordion - if (!allowMultiple && active && active !== target) { - // Set the expanded state on the triggering element - active.setAttribute('aria-expanded', 'false'); - // Hide the accordion sections, using aria-controls to specify the desired section - document.getElementById(active.getAttribute('aria-controls')).setAttribute('hidden', ''); - - // When toggling is not allowed, clean up disabled state - if (!allowToggle) { - active.removeAttribute('aria-disabled'); +Array.prototype.slice + .call(document.querySelectorAll('.Accordion')) + .forEach(function (accordion) { + // Allow for multiple accordion sections to be expanded at the same time + var allowMultiple = accordion.hasAttribute('data-allow-multiple'); + // Allow for each toggle to both open and close individually + var allowToggle = allowMultiple + ? allowMultiple + : accordion.hasAttribute('data-allow-toggle'); + + // Create the array of toggle elements for the accordion group + var triggers = Array.prototype.slice.call( + accordion.querySelectorAll('.Accordion-trigger') + ); + var panels = Array.prototype.slice.call( + accordion.querySelectorAll('.Accordion-panel') + ); + + accordion.addEventListener('click', function (event) { + var target = event.target; + + if (target.classList.contains('Accordion-trigger')) { + // Check if the current toggle is expanded. + var isExpanded = target.getAttribute('aria-expanded') == 'true'; + var active = accordion.querySelector('[aria-expanded="true"]'); + + // without allowMultiple, close the open accordion + if (!allowMultiple && active && active !== target) { + // Set the expanded state on the triggering element + active.setAttribute('aria-expanded', 'false'); + // Hide the accordion sections, using aria-controls to specify the desired section + document + .getElementById(active.getAttribute('aria-controls')) + .setAttribute('hidden', ''); + + // When toggling is not allowed, clean up disabled state + if (!allowToggle) { + active.removeAttribute('aria-disabled'); + } } - } - - if (!isExpanded) { - // Set the expanded state on the triggering element - target.setAttribute('aria-expanded', 'true'); - // Hide the accordion sections, using aria-controls to specify the desired section - document.getElementById(target.getAttribute('aria-controls')).removeAttribute('hidden'); - // If toggling is not allowed, set disabled state on trigger - if (!allowToggle) { - target.setAttribute('aria-disabled', 'true'); + if (!isExpanded) { + // Set the expanded state on the triggering element + target.setAttribute('aria-expanded', 'true'); + // Hide the accordion sections, using aria-controls to specify the desired section + document + .getElementById(target.getAttribute('aria-controls')) + .removeAttribute('hidden'); + + // If toggling is not allowed, set disabled state on trigger + if (!allowToggle) { + target.setAttribute('aria-disabled', 'true'); + } + } else if (allowToggle && isExpanded) { + // Set the expanded state on the triggering element + target.setAttribute('aria-expanded', 'false'); + // Hide the accordion sections, using aria-controls to specify the desired section + document + .getElementById(target.getAttribute('aria-controls')) + .setAttribute('hidden', ''); } - } - else if (allowToggle && isExpanded) { - // Set the expanded state on the triggering element - target.setAttribute('aria-expanded', 'false'); - // Hide the accordion sections, using aria-controls to specify the desired section - document.getElementById(target.getAttribute('aria-controls')).setAttribute('hidden', ''); - } - - event.preventDefault(); - } - }); - - // Bind keyboard behaviors on the main accordion container - accordion.addEventListener('keydown', function (event) { - var target = event.target; - var key = event.which.toString(); - - var isExpanded = target.getAttribute('aria-expanded') == 'true'; - var allowToggle = (allowMultiple) ? allowMultiple : accordion.hasAttribute('data-allow-toggle'); - - // 33 = Page Up, 34 = Page Down - var ctrlModifier = (event.ctrlKey && key.match(/33|34/)); - - // Is this coming from an accordion header? - if (target.classList.contains('Accordion-trigger')) { - // Up/ Down arrow and Control + Page Up/ Page Down keyboard operations - // 38 = Up, 40 = Down - if (key.match(/38|40/) || ctrlModifier) { - var index = triggers.indexOf(target); - var direction = (key.match(/34|40/)) ? 1 : -1; - var length = triggers.length; - var newIndex = (index + length + direction) % length; - - triggers[newIndex].focus(); event.preventDefault(); } - else if (key.match(/35|36/)) { - // 35 = End, 36 = Home keyboard operations - switch (key) { - // Go to first accordion - case '36': - triggers[0].focus(); - break; + }); + + // Bind keyboard behaviors on the main accordion container + accordion.addEventListener('keydown', function (event) { + var target = event.target; + var key = event.which.toString(); + + var isExpanded = target.getAttribute('aria-expanded') == 'true'; + var allowToggle = allowMultiple + ? allowMultiple + : accordion.hasAttribute('data-allow-toggle'); + + // 33 = Page Up, 34 = Page Down + var ctrlModifier = event.ctrlKey && key.match(/33|34/); + + // Is this coming from an accordion header? + if (target.classList.contains('Accordion-trigger')) { + // Up/ Down arrow and Control + Page Up/ Page Down keyboard operations + // 38 = Up, 40 = Down + if (key.match(/38|40/) || ctrlModifier) { + var index = triggers.indexOf(target); + var direction = key.match(/34|40/) ? 1 : -1; + var length = triggers.length; + var newIndex = (index + length + direction) % length; + + triggers[newIndex].focus(); + + event.preventDefault(); + } else if (key.match(/35|36/)) { + // 35 = End, 36 = Home keyboard operations + switch (key) { + // Go to first accordion + case '36': + triggers[0].focus(); + break; // Go to last accordion - case '35': - triggers[triggers.length - 1].focus(); - break; + case '35': + triggers[triggers.length - 1].focus(); + break; + } + event.preventDefault(); } - event.preventDefault(); - } - - } - }); - - // These are used to style the accordion when one of the buttons has focus - accordion.querySelectorAll('.Accordion-trigger').forEach(function (trigger) { - - trigger.addEventListener('focus', function (event) { - accordion.classList.add('focus'); - }); - - trigger.addEventListener('blur', function (event) { - accordion.classList.remove('focus'); }); - }); - - // Minor setup: will set disabled state, via aria-disabled, to an - // expanded/ active accordion which is not allowed to be toggled close - if (!allowToggle) { - // Get the first expanded/ active accordion - var expanded = accordion.querySelector('[aria-expanded="true"]'); - - // If an expanded/ active accordion is found, disable - if (expanded) { - expanded.setAttribute('aria-disabled', 'true'); + // These are used to style the accordion when one of the buttons has focus + accordion + .querySelectorAll('.Accordion-trigger') + .forEach(function (trigger) { + trigger.addEventListener('focus', function (event) { + accordion.classList.add('focus'); + }); + + trigger.addEventListener('blur', function (event) { + accordion.classList.remove('focus'); + }); + }); + + // Minor setup: will set disabled state, via aria-disabled, to an + // expanded/ active accordion which is not allowed to be toggled close + if (!allowToggle) { + // Get the first expanded/ active accordion + var expanded = accordion.querySelector('[aria-expanded="true"]'); + + // If an expanded/ active accordion is found, disable + if (expanded) { + expanded.setAttribute('aria-disabled', 'true'); + } } - } - -}); + }); diff --git a/examples/alert/js/alert.js b/examples/alert/js/alert.js index efc1d66be7..6bb39f055b 100644 --- a/examples/alert/js/alert.js +++ b/examples/alert/js/alert.js @@ -1,33 +1,29 @@ /* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -* -*/ + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + */ 'use strict'; window.addEventListener('load', function () { - var button = document.getElementById('alert-trigger'); button.addEventListener('click', addAlert); - }); /* -* @function addAlert -* -* @desc Adds an alert to the page -* -* @param {Object} event - Standard W3C event object -* -*/ - -function addAlert (event) { - + * @function addAlert + * + * @desc Adds an alert to the page + * + * @param {Object} event - Standard W3C event object + * + */ + +function addAlert(event) { var example = document.getElementById('example'); var template = document.getElementById('alert-template').innerHTML; example.innerHTML = template; - } diff --git a/examples/button/js/button.js b/examples/button/js/button.js index 3aabb28521..5af4207faa 100644 --- a/examples/button/js/button.js +++ b/examples/button/js/button.js @@ -1,16 +1,16 @@ /* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -* -* JS code for the button design pattern -*/ + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * JS code for the button design pattern + */ 'use strict'; var ICON_MUTE_URL = 'images/mute.svg#icon-mute'; var ICON_SOUND_URL = 'images/mute.svg#icon-sound'; -function init () { +function init() { var actionButton = document.getElementById('action'); actionButton.addEventListener('click', activateActionButton); actionButton.addEventListener('keydown', actionButtonKeydownHandler); @@ -27,7 +27,7 @@ function init () { * * @param {KeyboardEvent} event */ -function actionButtonKeydownHandler (event) { +function actionButtonKeydownHandler(event) { // The action button is activated by space on the keyup event, but the // default action for space is already triggered on keydown. It needs to be // prevented to stop scrolling the page before activating the button. @@ -46,14 +46,14 @@ function actionButtonKeydownHandler (event) { * * @param {KeyboardEvent} event */ -function actionButtonKeyupHandler (event) { +function actionButtonKeyupHandler(event) { if (event.keyCode === 32) { event.preventDefault(); activateActionButton(); } } -function activateActionButton () { +function activateActionButton() { window.print(); } @@ -63,7 +63,7 @@ function activateActionButton () { * * @param {MouseEvent} event */ -function toggleButtonClickHandler (event) { +function toggleButtonClickHandler(event) { if ( event.currentTarget.tagName === 'button' || event.currentTarget.getAttribute('role') === 'button' @@ -77,11 +77,10 @@ function toggleButtonClickHandler (event) { * * @param {KeyboardEvent} event */ -function toggleButtonKeydownHandler (event) { +function toggleButtonKeydownHandler(event) { if (event.keyCode === 32) { event.preventDefault(); - } - else if (event.keyCode === 13) { + } else if (event.keyCode === 13) { event.preventDefault(); toggleButtonState(event.currentTarget); } @@ -92,7 +91,7 @@ function toggleButtonKeydownHandler (event) { * * @param {KeyboardEvent} event */ -function toggleButtonKeyupHandler (event) { +function toggleButtonKeyupHandler(event) { if (event.keyCode === 32) { event.preventDefault(); toggleButtonState(event.currentTarget); @@ -104,13 +103,16 @@ function toggleButtonKeyupHandler (event) { * * @param {HTMLElement} button */ -function toggleButtonState (button) { +function toggleButtonState(button) { var isAriaPressed = button.getAttribute('aria-pressed') === 'true'; button.setAttribute('aria-pressed', isAriaPressed ? 'false' : 'true'); var icon = button.querySelector('use'); - icon.setAttribute('xlink:href', isAriaPressed ? ICON_SOUND_URL : ICON_MUTE_URL); + icon.setAttribute( + 'xlink:href', + isAriaPressed ? ICON_SOUND_URL : ICON_MUTE_URL + ); } window.onload = init; diff --git a/examples/button/js/button_idl.js b/examples/button/js/button_idl.js index 85a37ef8f6..c2fc4fd0df 100644 --- a/examples/button/js/button_idl.js +++ b/examples/button/js/button_idl.js @@ -1,16 +1,16 @@ /* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -* -* JS code for the button design pattern using the new ARIA 1.2 IDL for reflection. -*/ + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * JS code for the button design pattern using the new ARIA 1.2 IDL for reflection. + */ 'use strict'; var ICON_MUTE_URL = 'images/mute.svg#icon-mute'; var ICON_SOUND_URL = 'images/mute.svg#icon-sound'; -function init () { +function init() { var actionButton = document.getElementById('action'); // Set role in js instead of html actionButton.role = 'button'; @@ -32,7 +32,7 @@ function init () { * * @param {KeyboardEvent} event */ -function actionButtonKeydownHandler (event) { +function actionButtonKeydownHandler(event) { // The action button is activated by space on the keyup event, but the // default action for space is already triggered on keydown. It needs to be // prevented to stop scrolling the page before activating the button. @@ -51,14 +51,14 @@ function actionButtonKeydownHandler (event) { * * @param {KeyboardEvent} event */ -function actionButtonKeyupHandler (event) { +function actionButtonKeyupHandler(event) { if (event.keyCode === 32) { event.preventDefault(); activateActionButton(); } } -function activateActionButton () { +function activateActionButton() { window.print(); } @@ -68,7 +68,7 @@ function activateActionButton () { * * @param {MouseEvent} event */ -function toggleButtonClickHandler (event) { +function toggleButtonClickHandler(event) { if ( event.currentTarget.tagName === 'button' || event.currentTarget.role === 'button' // This code is equivalent to: event.currentTarget.getAttribute('role') === 'button' @@ -82,11 +82,10 @@ function toggleButtonClickHandler (event) { * * @param {KeyboardEvent} event */ -function toggleButtonKeydownHandler (event) { +function toggleButtonKeydownHandler(event) { if (event.keyCode === 32) { event.preventDefault(); - } - else if (event.keyCode === 13) { + } else if (event.keyCode === 13) { event.preventDefault(); toggleButtonState(event.currentTarget); } @@ -97,7 +96,7 @@ function toggleButtonKeydownHandler (event) { * * @param {KeyboardEvent} event */ -function toggleButtonKeyupHandler (event) { +function toggleButtonKeyupHandler(event) { if (event.keyCode === 32) { event.preventDefault(); toggleButtonState(event.currentTarget); @@ -109,7 +108,7 @@ function toggleButtonKeyupHandler (event) { * * @param {HTMLElement} button */ -function toggleButtonState (button) { +function toggleButtonState(button) { // The following line of code is equivalent to: var isAriaPressed = button.getAttribute('aria-pressed') === 'true'; var isAriaPressed = button.ariaPressed === 'true'; @@ -117,7 +116,10 @@ function toggleButtonState (button) { button.ariaPressed = isAriaPressed ? 'false' : 'true'; var icon = button.querySelector('use'); - icon.setAttribute('xlink:href', isAriaPressed ? ICON_SOUND_URL : ICON_MUTE_URL); + icon.setAttribute( + 'xlink:href', + isAriaPressed ? ICON_SOUND_URL : ICON_MUTE_URL + ); } window.onload = init; diff --git a/examples/carousel/js/carousel-prev-next.js b/examples/carousel/js/carousel-prev-next.js index 67090b2e98..8315aa9720 100644 --- a/examples/carousel/js/carousel-prev-next.js +++ b/examples/carousel/js/carousel-prev-next.js @@ -1,18 +1,21 @@ /* -* File: carousel-prev-next.js -* -* Desc: Carousel widget with Previous and Next Buttons that implements ARIA Authoring Practices -* -*/ + * File: carousel-prev-next.js + * + * Desc: Carousel widget with Previous and Next Buttons that implements ARIA Authoring Practices + * + */ 'use strict'; var CarouselPreviousNext = function (node, options) { // merge passed options with defaults - options = Object.assign({ moreaccessible: false, paused: false, norotate: false }, (options || {})); + options = Object.assign( + { moreaccessible: false, paused: false, norotate: false }, + options || {} + ); // a prefers-reduced-motion user setting must always override autoplay - var hasReducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)"); + var hasReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)'); if (hasReducedMotion.matches) { options.paused = true; } @@ -33,7 +36,7 @@ var CarouselPreviousNext = function (node, options) { /* State properties */ this.hasUserActivatedPlay = false; // set when the user activates the play/pause button - this.isAutoRotationDisabled = options.norotate // This property for disabling auto rotation + this.isAutoRotationDisabled = options.norotate; // This property for disabling auto rotation this.isPlayingEnabled = !options.paused; // This property is also set in updatePlaying method this.timeInterval = 5000; // length of slide rotation in ms this.currentIndex = 0; // index of current slide @@ -44,7 +47,10 @@ var CarouselPreviousNext = function (node, options) { var elem = document.querySelector('.carousel .controls button.rotation'); if (elem) { this.pausePlayButtonNode = elem; - this.pausePlayButtonNode.addEventListener('click', this.handlePausePlayButtonClick.bind(this)); + this.pausePlayButtonNode.addEventListener( + 'click', + this.handlePausePlayButtonClick.bind(this) + ); } // Previous Button @@ -52,9 +58,18 @@ var CarouselPreviousNext = function (node, options) { elem = document.querySelector('.carousel .controls button.previous'); if (elem) { this.previousButtonNode = elem; - this.previousButtonNode.addEventListener('click', this.handlePreviousButtonClick.bind(this)); - this.previousButtonNode.addEventListener('focus', this.handleFocusIn.bind(this)); - this.previousButtonNode.addEventListener('blur', this.handleFocusOut.bind(this)); + this.previousButtonNode.addEventListener( + 'click', + this.handlePreviousButtonClick.bind(this) + ); + this.previousButtonNode.addEventListener( + 'focus', + this.handleFocusIn.bind(this) + ); + this.previousButtonNode.addEventListener( + 'blur', + this.handleFocusOut.bind(this) + ); } // Next Button @@ -62,27 +77,44 @@ var CarouselPreviousNext = function (node, options) { elem = document.querySelector('.carousel .controls button.next'); if (elem) { this.nextButtonNode = elem; - this.nextButtonNode.addEventListener('click', this.handleNextButtonClick.bind(this)); - this.nextButtonNode.addEventListener('focus', this.handleFocusIn.bind(this)); - this.nextButtonNode.addEventListener('blur', this.handleFocusOut.bind(this)); + this.nextButtonNode.addEventListener( + 'click', + this.handleNextButtonClick.bind(this) + ); + this.nextButtonNode.addEventListener( + 'focus', + this.handleFocusIn.bind(this) + ); + this.nextButtonNode.addEventListener( + 'blur', + this.handleFocusOut.bind(this) + ); } // Carousel item events - for (var i = 0; i < this.carouselItemNodes.length; i++ ) { + for (var i = 0; i < this.carouselItemNodes.length; i++) { var caouselItemNode = this.carouselItemNodes[i]; // support stopping rotation when any element receives focus in the tabpanel caouselItemNode.addEventListener('focusin', this.handleFocusIn.bind(this)); - caouselItemNode.addEventListener('focusout', this.handleFocusOut.bind(this)); + caouselItemNode.addEventListener( + 'focusout', + this.handleFocusOut.bind(this) + ); var imageLinkNode = caouselItemNode.querySelector('.carousel-image a'); if (imageLinkNode) { - imageLinkNode.addEventListener('focus', this.handleImageLinkFocus.bind(this)); - imageLinkNode.addEventListener('blur', this.handleImageLinkBlur.bind(this)); + imageLinkNode.addEventListener( + 'focus', + this.handleImageLinkFocus.bind(this) + ); + imageLinkNode.addEventListener( + 'blur', + this.handleImageLinkBlur.bind(this) + ); } - } // Handle hover events @@ -95,38 +127,37 @@ var CarouselPreviousNext = function (node, options) { this.updatePlaying(!options.paused && !options.norotate); this.setAccessibleStyling(options.moreaccessible); this.rotateSlides(); -} +}; /* Public function to disable/enable rotation and if false, hide pause/play button*/ -CarouselPreviousNext.prototype.enableOrDisableAutoRotation = function(disable) { +CarouselPreviousNext.prototype.enableOrDisableAutoRotation = function ( + disable +) { this.isAutoRotationDisabled = disable; this.pausePlayButtonNode.hidden = disable; -} +}; /* Public function to update controls/caption styling */ -CarouselPreviousNext.prototype.setAccessibleStyling = function(accessible) { +CarouselPreviousNext.prototype.setAccessibleStyling = function (accessible) { if (accessible) { this.domNode.classList.add('carousel-moreaccessible'); - } - else { + } else { this.domNode.classList.remove('carousel-moreaccessible'); } -} +}; CarouselPreviousNext.prototype.showCarouselItem = function (index) { - this.currentIndex = index; - for(var i = 0; i < this.carouselItemNodes.length; i++) { + for (var i = 0; i < this.carouselItemNodes.length; i++) { var carouselItemNode = this.carouselItemNodes[i]; if (index === i) { carouselItemNode.classList.add('active'); - } - else { + } else { carouselItemNode.classList.remove('active'); } } -} +}; CarouselPreviousNext.prototype.previousCarouselItem = function () { var nextIndex = this.currentIndex - 1; @@ -134,7 +165,7 @@ CarouselPreviousNext.prototype.previousCarouselItem = function () { nextIndex = this.carouselItemNodes.length - 1; } this.showCarouselItem(nextIndex); -} +}; CarouselPreviousNext.prototype.nextCarouselItem = function () { var nextIndex = this.currentIndex + 1; @@ -142,20 +173,23 @@ CarouselPreviousNext.prototype.nextCarouselItem = function () { nextIndex = 0; } this.showCarouselItem(nextIndex); -} +}; CarouselPreviousNext.prototype.rotateSlides = function () { - if (!this.isAutoRotationDisabled ) { - if ((!this.hasFocus && - !this.hasHover && - this.isPlayingEnabled) || - this.hasUserActivatedPlay) { + if (!this.isAutoRotationDisabled) { + if ( + (!this.hasFocus && !this.hasHover && this.isPlayingEnabled) || + this.hasUserActivatedPlay + ) { this.nextCarouselItem(); } } - this.slideTimeout = setTimeout(this.rotateSlides.bind(this), this.timeInterval); -} + this.slideTimeout = setTimeout( + this.rotateSlides.bind(this), + this.timeInterval + ); +}; CarouselPreviousNext.prototype.updatePlaying = function (play) { this.isPlayingEnabled = play; @@ -165,122 +199,129 @@ CarouselPreviousNext.prototype.updatePlaying = function (play) { this.pausePlayButtonNode.classList.remove('play'); this.pausePlayButtonNode.classList.add('pause'); this.liveRegionNode.setAttribute('aria-live', 'off'); - } - else { + } else { this.pausePlayButtonNode.setAttribute('aria-label', this.playLabel); this.pausePlayButtonNode.classList.remove('pause'); this.pausePlayButtonNode.classList.add('play'); this.liveRegionNode.setAttribute('aria-live', 'polite'); } -} +}; - /* Event Handlers */ +/* Event Handlers */ CarouselPreviousNext.prototype.handleImageLinkFocus = function () { this.liveRegionNode.classList.add('focus'); -} +}; CarouselPreviousNext.prototype.handleImageLinkBlur = function () { this.liveRegionNode.classList.remove('focus'); -} +}; CarouselPreviousNext.prototype.handleMouseOver = function (event) { if (!this.pausePlayButtonNode.contains(event.target)) { this.hasHover = true; } -} +}; CarouselPreviousNext.prototype.handleMouseOut = function () { this.hasHover = false; -} +}; - /* EVENT HANDLERS */ +/* EVENT HANDLERS */ CarouselPreviousNext.prototype.handlePausePlayButtonClick = function () { this.hasUserActivatedPlay = !this.isPlayingEnabled; this.updatePlaying(!this.isPlayingEnabled); -} +}; CarouselPreviousNext.prototype.handlePreviousButtonClick = function () { this.previousCarouselItem(); -} +}; CarouselPreviousNext.prototype.handleNextButtonClick = function () { this.nextCarouselItem(); -} +}; - /* Event Handlers for carousel items*/ +/* Event Handlers for carousel items*/ CarouselPreviousNext.prototype.handleFocusIn = function () { this.liveRegionNode.setAttribute('aria-live', 'polite'); this.hasFocus = true; -} +}; CarouselPreviousNext.prototype.handleFocusOut = function () { if (this.isPlayingEnabled) { this.liveRegionNode.setAttribute('aria-live', 'off'); } this.hasFocus = false; -} +}; /* Initialize Carousel and options */ -window.addEventListener('load', function () { - var carouselEls = document.querySelectorAll('.carousel'); - var carousels = []; - - // set example behavior based on - // default setting of the checkboxes and the parameters in the URL - // update checkboxes based on any corresponding URL parameters - var checkboxes = document.querySelectorAll('.carousel-options input[type=checkbox]'); - var urlParams = new URLSearchParams(location.search); - var carouselOptions = {}; - - // initialize example features based on - // default setting of the checkboxes and the parameters in the URL - // update checkboxes based on any corresponding URL parameters - checkboxes.forEach(function(checkbox) { - var checked = checkbox.checked; - - if (urlParams.has(checkbox.value)) { - var urlParam = urlParams.get(checkbox.value); - if (typeof urlParam === 'string') { - checked = urlParam === 'true'; - checkbox.checked = checked; +window.addEventListener( + 'load', + function () { + var carouselEls = document.querySelectorAll('.carousel'); + var carousels = []; + + // set example behavior based on + // default setting of the checkboxes and the parameters in the URL + // update checkboxes based on any corresponding URL parameters + var checkboxes = document.querySelectorAll( + '.carousel-options input[type=checkbox]' + ); + var urlParams = new URLSearchParams(location.search); + var carouselOptions = {}; + + // initialize example features based on + // default setting of the checkboxes and the parameters in the URL + // update checkboxes based on any corresponding URL parameters + checkboxes.forEach(function (checkbox) { + var checked = checkbox.checked; + + if (urlParams.has(checkbox.value)) { + var urlParam = urlParams.get(checkbox.value); + if (typeof urlParam === 'string') { + checked = urlParam === 'true'; + checkbox.checked = checked; + } } - } - carouselOptions[checkbox.value] = checkbox.checked; - }); - - carouselEls.forEach(function (node) { - carousels.push(new CarouselPreviousNext(node, carouselOptions)); - }); - - // add change event to checkboxes - checkboxes.forEach(function(checkbox) { - var updateEvent; - switch(checkbox.value) { - case 'moreaccessible': - updateEvent = 'setAccessibleStyling'; - break; - case 'norotate': - updateEvent = 'enableOrDisableAutoRotation'; - break; - } - - // update the carousel behavior and URL when a checkbox state changes - checkbox.addEventListener('change', function(event) { - urlParams.set(event.target.value, event.target.checked + ''); - window.history.replaceState(null, '', window.location.pathname + '?' + urlParams); + carouselOptions[checkbox.value] = checkbox.checked; + }); - if (updateEvent) { - carousels.forEach(function (carousel) { - carousel[updateEvent](event.target.checked); - }); - } + carouselEls.forEach(function (node) { + carousels.push(new CarouselPreviousNext(node, carouselOptions)); }); - }); -}, false); + // add change event to checkboxes + checkboxes.forEach(function (checkbox) { + var updateEvent; + switch (checkbox.value) { + case 'moreaccessible': + updateEvent = 'setAccessibleStyling'; + break; + case 'norotate': + updateEvent = 'enableOrDisableAutoRotation'; + break; + } + // update the carousel behavior and URL when a checkbox state changes + checkbox.addEventListener('change', function (event) { + urlParams.set(event.target.value, event.target.checked + ''); + window.history.replaceState( + null, + '', + window.location.pathname + '?' + urlParams + ); + + if (updateEvent) { + carousels.forEach(function (carousel) { + carousel[updateEvent](event.target.checked); + }); + } + }); + }); + }, + false +); diff --git a/examples/carousel/js/carousel-tablist.js b/examples/carousel/js/carousel-tablist.js index b6ab7bdf49..70b8620c0d 100644 --- a/examples/carousel/js/carousel-tablist.js +++ b/examples/carousel/js/carousel-tablist.js @@ -1,9 +1,9 @@ /* -* File: carousel-tablist.js -* -* Desc: Carousel Tablist widget that implements ARIA Authoring Practices -* -*/ + * File: carousel-tablist.js + * + * Desc: Carousel Tablist widget that implements ARIA Authoring Practices + * + */ 'use strict'; @@ -12,10 +12,13 @@ var CarouselTablist = function (node, options) { // merge passed options with defaults - options = Object.assign({ moreaccessible: false, paused: false, norotate: false }, (options || {})); + options = Object.assign( + { moreaccessible: false, paused: false, norotate: false }, + options || {} + ); // a prefers-reduced-motion user setting must always override autoplay - var hasReducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)"); + var hasReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)'); if (hasReducedMotion.matches) { options.paused = true; } @@ -30,14 +33,16 @@ var CarouselTablist = function (node, options) { this.tabpanelNodes = []; this.liveRegionNode = node.querySelector('.carousel-items'); - this.pausePlayButtonNode = document.querySelector('.carousel-tablist .controls button.rotation'); + this.pausePlayButtonNode = document.querySelector( + '.carousel-tablist .controls button.rotation' + ); this.playLabel = 'Start automatic slide show'; this.pauseLabel = 'Stop automatic slide show'; /* State properties */ this.hasUserActivatedPlay = false; // set when the user activates the play/pause button - this.isAutoRotationDisabled = options.norotate // This property for disabling auto rotation + this.isAutoRotationDisabled = options.norotate; // This property for disabling auto rotation this.isPlayingEnabled = !options.paused; // This property is also set in updatePlaying method this.timeInterval = 5000; // length of slide rotation in ms this.currentIndex = 0; // index of current slide @@ -65,24 +70,35 @@ var CarouselTablist = function (node, options) { this.tabpanelNodes.push(tabpanelNode); // support stopping rotation when any element receives focus in the tabpanel - tabpanelNode.addEventListener('focusin', this.handleTabpanelFocusIn.bind(this)); - tabpanelNode.addEventListener('focusout', this.handleTabpanelFocusOut.bind(this)); + tabpanelNode.addEventListener( + 'focusin', + this.handleTabpanelFocusIn.bind(this) + ); + tabpanelNode.addEventListener( + 'focusout', + this.handleTabpanelFocusOut.bind(this) + ); var imageLink = tabpanelNode.querySelector('.carousel-image a'); if (imageLink) { - imageLink.addEventListener('focus', this.handleImageLinkFocus.bind(this)); + imageLink.addEventListener( + 'focus', + this.handleImageLinkFocus.bind(this) + ); imageLink.addEventListener('blur', this.handleImageLinkBlur.bind(this)); } - } - else { + } else { this.tabpanelNodes.push(null); } } // Pause Button if (this.pausePlayButtonNode) { - this.pausePlayButtonNode.addEventListener('click', this.handlePausePlayButtonClick.bind(this)); + this.pausePlayButtonNode.addEventListener( + 'click', + this.handlePausePlayButtonClick.bind(this) + ); } // Handle hover events @@ -95,23 +111,22 @@ var CarouselTablist = function (node, options) { this.updatePlaying(!options.paused && !options.norotate); this.setAccessibleStyling(options.moreaccessible); this.rotateSlides(); -} +}; /* Public function to disable/enable rotation and if false, hide pause/play button*/ -CarouselTablist.prototype.enableOrDisableAutoRotation = function(disable) { +CarouselTablist.prototype.enableOrDisableAutoRotation = function (disable) { this.isAutoRotationDisabled = disable; this.pausePlayButtonNode.hidden = disable; -} +}; /* Public function to update controls/caption styling */ -CarouselTablist.prototype.setAccessibleStyling = function(accessible) { +CarouselTablist.prototype.setAccessibleStyling = function (accessible) { if (accessible) { this.domNode.classList.add('carousel-tablist-moreaccessible'); - } - else { + } else { this.domNode.classList.remove('carousel-tablist-moreaccessible'); } -} +}; CarouselTablist.prototype.hideTabpanel = function (index) { var tabNode = this.tabNodes[index]; @@ -123,7 +138,7 @@ CarouselTablist.prototype.hideTabpanel = function (index) { if (panelNode) { panelNode.classList.remove('active'); } -} +}; CarouselTablist.prototype.showTabpanel = function (index, moveFocus) { var tabNode = this.tabNodes[index]; @@ -139,7 +154,7 @@ CarouselTablist.prototype.showTabpanel = function (index, moveFocus) { if (moveFocus) { tabNode.focus(); } -} +}; CarouselTablist.prototype.setSelectedTab = function (index, moveFocus) { if (index === this.currentIndex) { @@ -152,7 +167,7 @@ CarouselTablist.prototype.setSelectedTab = function (index, moveFocus) { } this.showTabpanel(index, moveFocus); -} +}; CarouselTablist.prototype.setSelectedToPreviousTab = function (moveFocus) { var nextIndex = this.currentIndex - 1; @@ -162,7 +177,7 @@ CarouselTablist.prototype.setSelectedToPreviousTab = function (moveFocus) { } this.setSelectedTab(nextIndex, moveFocus); -} +}; CarouselTablist.prototype.setSelectedToNextTab = function (moveFocus) { var nextIndex = this.currentIndex + 1; @@ -172,20 +187,23 @@ CarouselTablist.prototype.setSelectedToNextTab = function (moveFocus) { } this.setSelectedTab(nextIndex, moveFocus); -} +}; CarouselTablist.prototype.rotateSlides = function () { - if (!this.isAutoRotationDisabled ) { - if ((!this.hasFocus && - !this.hasHover && - this.isPlayingEnabled) || - this.hasUserActivatedPlay) { + if (!this.isAutoRotationDisabled) { + if ( + (!this.hasFocus && !this.hasHover && this.isPlayingEnabled) || + this.hasUserActivatedPlay + ) { this.setSelectedToNextTab(false); } } - this.slideTimeout = setTimeout(this.rotateSlides.bind(this), this.timeInterval); -} + this.slideTimeout = setTimeout( + this.rotateSlides.bind(this), + this.timeInterval + ); +}; CarouselTablist.prototype.updatePlaying = function (play) { this.isPlayingEnabled = play; @@ -195,49 +213,47 @@ CarouselTablist.prototype.updatePlaying = function (play) { this.pausePlayButtonNode.classList.remove('play'); this.pausePlayButtonNode.classList.add('pause'); this.liveRegionNode.setAttribute('aria-live', 'off'); - } - else { + } else { this.pausePlayButtonNode.setAttribute('aria-label', this.playLabel); this.pausePlayButtonNode.classList.remove('pause'); this.pausePlayButtonNode.classList.add('play'); this.liveRegionNode.setAttribute('aria-live', 'polite'); } -} +}; - /* Event Handlers */ +/* Event Handlers */ CarouselTablist.prototype.handleImageLinkFocus = function () { this.liveRegionNode.classList.add('focus'); -} +}; CarouselTablist.prototype.handleImageLinkBlur = function () { this.liveRegionNode.classList.remove('focus'); -} +}; CarouselTablist.prototype.handleMouseOver = function (event) { if (!this.pausePlayButtonNode.contains(event.target)) { this.hasHover = true; } -} +}; CarouselTablist.prototype.handleMouseOut = function () { this.hasHover = false; -} +}; - /* EVENT HANDLERS */ +/* EVENT HANDLERS */ CarouselTablist.prototype.handlePausePlayButtonClick = function () { this.hasUserActivatedPlay = !this.isPlayingEnabled; this.updatePlaying(!this.isPlayingEnabled); -} +}; - /* Event Handlers for Tabs*/ +/* Event Handlers for Tabs*/ CarouselTablist.prototype.handleTabKeydown = function (event) { var flag = false; switch (event.key) { - case 'ArrowRight': this.setSelectedToNextTab(true); flag = true; @@ -266,18 +282,18 @@ CarouselTablist.prototype.handleTabKeydown = function (event) { event.stopPropagation(); event.preventDefault(); } -} +}; CarouselTablist.prototype.handleTabClick = function (event) { var index = this.tabNodes.indexOf(event.currentTarget); this.setSelectedTab(index, true); -} +}; CarouselTablist.prototype.handleTabFocus = function () { this.tablistNode.classList.add('focus'); this.liveRegionNode.setAttribute('aria-live', 'polite'); this.hasFocus = true; -} +}; CarouselTablist.prototype.handleTabBlur = function () { this.tablistNode.classList.remove('focus'); @@ -286,75 +302,84 @@ CarouselTablist.prototype.handleTabBlur = function () { } this.hasFocus = false; -} +}; - /* Event Handlers for Tabpanels*/ +/* Event Handlers for Tabpanels*/ CarouselTablist.prototype.handleTabpanelFocusIn = function () { this.hasFocus = true; -} +}; CarouselTablist.prototype.handleTabpanelFocusOut = function () { this.hasFocus = false; -} +}; /* Iniitalize Carousel Tablists and options */ -window.addEventListener('load', function () { - var carouselEls = document.querySelectorAll('.carousel-tablist'); - var carousels = []; - - // set example behavior based on - // default setting of the checkboxes and the parameters in the URL - // update checkboxes based on any corresponding URL parameters - var checkboxes = document.querySelectorAll('.carousel-options input[type=checkbox]'); - var urlParams = new URLSearchParams(location.search); - var carouselOptions = {}; - - // initialize example features based on - // default setting of the checkboxes and the parameters in the URL - // update checkboxes based on any corresponding URL parameters - checkboxes.forEach(function(checkbox) { - var checked = checkbox.checked; - - if (urlParams.has(checkbox.value)) { - var urlParam = urlParams.get(checkbox.value); - if (typeof urlParam === 'string') { - checked = urlParam === 'true'; - checkbox.checked = checked; +window.addEventListener( + 'load', + function () { + var carouselEls = document.querySelectorAll('.carousel-tablist'); + var carousels = []; + + // set example behavior based on + // default setting of the checkboxes and the parameters in the URL + // update checkboxes based on any corresponding URL parameters + var checkboxes = document.querySelectorAll( + '.carousel-options input[type=checkbox]' + ); + var urlParams = new URLSearchParams(location.search); + var carouselOptions = {}; + + // initialize example features based on + // default setting of the checkboxes and the parameters in the URL + // update checkboxes based on any corresponding URL parameters + checkboxes.forEach(function (checkbox) { + var checked = checkbox.checked; + + if (urlParams.has(checkbox.value)) { + var urlParam = urlParams.get(checkbox.value); + if (typeof urlParam === 'string') { + checked = urlParam === 'true'; + checkbox.checked = checked; + } } - } - carouselOptions[checkbox.value] = checkbox.checked; - }); - - carouselEls.forEach(function (node) { - carousels.push(new CarouselTablist(node, carouselOptions)); - }); - - // add change event to checkboxes - checkboxes.forEach(function(checkbox) { - var updateEvent; - switch(checkbox.value) { - case 'moreaccessible': - updateEvent = 'setAccessibleStyling'; - break; - case 'norotate': - updateEvent = 'enableOrDisableAutoRotation'; - break; - } + carouselOptions[checkbox.value] = checkbox.checked; + }); - // update the carousel behavior and URL when a checkbox state changes - checkbox.addEventListener('change', function(event) { - urlParams.set(event.target.value, event.target.checked + ''); - window.history.replaceState(null, '', window.location.pathname + '?' + urlParams); + carouselEls.forEach(function (node) { + carousels.push(new CarouselTablist(node, carouselOptions)); + }); - if (updateEvent) { - carousels.forEach(function (carousel) { - carousel[updateEvent](event.target.checked); - }); + // add change event to checkboxes + checkboxes.forEach(function (checkbox) { + var updateEvent; + switch (checkbox.value) { + case 'moreaccessible': + updateEvent = 'setAccessibleStyling'; + break; + case 'norotate': + updateEvent = 'enableOrDisableAutoRotation'; + break; } - }); - }); -}, false); + // update the carousel behavior and URL when a checkbox state changes + checkbox.addEventListener('change', function (event) { + urlParams.set(event.target.value, event.target.checked + ''); + window.history.replaceState( + null, + '', + window.location.pathname + '?' + urlParams + ); + + if (updateEvent) { + carousels.forEach(function (carousel) { + carousel[updateEvent](event.target.checked); + }); + } + }); + }); + }, + false +); diff --git a/examples/checkbox/checkbox-1/js/checkbox.js b/examples/checkbox/checkbox-1/js/checkbox.js index ca5e7269c8..092727e974 100644 --- a/examples/checkbox/checkbox-1/js/checkbox.js +++ b/examples/checkbox/checkbox-1/js/checkbox.js @@ -1,28 +1,27 @@ /* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -* -* File: Checkbox.js -* -* Desc: Checkbox widget that implements ARIA Authoring Practices -* for a menu of links -* -*/ + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * File: Checkbox.js + * + * Desc: Checkbox widget that implements ARIA Authoring Practices + * for a menu of links + * + */ 'use strict'; /* -* @constructor Checkbox -* -* -*/ + * @constructor Checkbox + * + * + */ var Checkbox = function (domNode) { - this.domNode = domNode; this.keyCode = Object.freeze({ - 'RETURN': 13, - 'SPACE': 32 + RETURN: 13, + SPACE: 32, }); }; @@ -33,22 +32,18 @@ Checkbox.prototype.init = function () { this.domNode.setAttribute('aria-checked', 'false'); } - this.domNode.addEventListener('keydown', this.handleKeydown.bind(this)); - this.domNode.addEventListener('click', this.handleClick.bind(this)); - this.domNode.addEventListener('focus', this.handleFocus.bind(this)); - this.domNode.addEventListener('blur', this.handleBlur.bind(this)); - + this.domNode.addEventListener('keydown', this.handleKeydown.bind(this)); + this.domNode.addEventListener('click', this.handleClick.bind(this)); + this.domNode.addEventListener('focus', this.handleFocus.bind(this)); + this.domNode.addEventListener('blur', this.handleBlur.bind(this)); }; Checkbox.prototype.toggleCheckbox = function () { - if (this.domNode.getAttribute('aria-checked') === 'true') { this.domNode.setAttribute('aria-checked', 'false'); - } - else { + } else { this.domNode.setAttribute('aria-checked', 'true'); } - }; /* EVENT HANDLERS */ @@ -83,4 +78,3 @@ Checkbox.prototype.handleFocus = function (event) { Checkbox.prototype.handleBlur = function (event) { this.domNode.classList.remove('focus'); }; - diff --git a/examples/checkbox/checkbox-2/js/checkboxMixed.js b/examples/checkbox/checkbox-2/js/checkboxMixed.js index 752f37b32f..d2ca7f9a8f 100644 --- a/examples/checkbox/checkbox-2/js/checkboxMixed.js +++ b/examples/checkbox/checkbox-2/js/checkboxMixed.js @@ -1,29 +1,28 @@ /* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -* -* File: CheckboxMixed.js -* -* Desc: CheckboxMixed widget that implements ARIA Authoring Practices -* for a menu of links -*/ + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * File: CheckboxMixed.js + * + * Desc: CheckboxMixed widget that implements ARIA Authoring Practices + * for a menu of links + */ 'use strict'; /* -* @constructor CheckboxMixed -* -* -*/ + * @constructor CheckboxMixed + * + * + */ var CheckboxMixed = function (domNode) { - this.domNode = domNode; this.controlledCheckboxes = []; this.keyCode = Object.freeze({ - 'RETURN': 13, - 'SPACE': 32 + RETURN: 13, + SPACE: 32, }); }; @@ -39,17 +38,15 @@ CheckboxMixed.prototype.init = function () { this.controlledCheckboxes.push(ccb); } - this.domNode.addEventListener('keydown', this.handleKeydown.bind(this)); - this.domNode.addEventListener('click', this.handleClick.bind(this)); - this.domNode.addEventListener('focus', this.handleFocus.bind(this)); - this.domNode.addEventListener('blur', this.handleBlur.bind(this)); + this.domNode.addEventListener('keydown', this.handleKeydown.bind(this)); + this.domNode.addEventListener('click', this.handleClick.bind(this)); + this.domNode.addEventListener('focus', this.handleFocus.bind(this)); + this.domNode.addEventListener('blur', this.handleBlur.bind(this)); this.updateCheckboxMixed(); - }; CheckboxMixed.prototype.updateCheckboxMixed = function () { - var count = 0; for (var i = 0; i < this.controlledCheckboxes.length; i++) { @@ -60,12 +57,10 @@ CheckboxMixed.prototype.updateCheckboxMixed = function () { if (count === 0) { this.domNode.setAttribute('aria-checked', 'false'); - } - else { + } else { if (count === this.controlledCheckboxes.length) { this.domNode.setAttribute('aria-checked', 'true'); - } - else { + } else { this.domNode.setAttribute('aria-checked', 'mixed'); this.updateControlledStates(); } @@ -74,12 +69,13 @@ CheckboxMixed.prototype.updateCheckboxMixed = function () { CheckboxMixed.prototype.updateControlledStates = function () { for (var i = 0; i < this.controlledCheckboxes.length; i++) { - this.controlledCheckboxes[i].lastState = this.controlledCheckboxes[i].isChecked(); + this.controlledCheckboxes[i].lastState = this.controlledCheckboxes[ + i + ].isChecked(); } }; CheckboxMixed.prototype.anyLastChecked = function () { - var count = 0; for (var i = 0; i < this.controlledCheckboxes.length; i++) { @@ -89,36 +85,29 @@ CheckboxMixed.prototype.anyLastChecked = function () { } return count > 0; - }; CheckboxMixed.prototype.setControlledCheckboxes = function (value) { - for (var i = 0; i < this.controlledCheckboxes.length; i++) { this.controlledCheckboxes[i].setChecked(value); } this.updateCheckboxMixed(); - }; CheckboxMixed.prototype.toggleCheckboxMixed = function () { - var state = this.domNode.getAttribute('aria-checked'); if (state === 'false') { if (this.anyLastChecked()) { this.setControlledCheckboxes('last'); - } - else { + } else { this.setControlledCheckboxes('true'); } - } - else { + } else { if (state === 'mixed') { this.setControlledCheckboxes('true'); - } - else { + } else { this.setControlledCheckboxes('false'); } } @@ -158,4 +147,3 @@ CheckboxMixed.prototype.handleFocus = function (event) { CheckboxMixed.prototype.handleBlur = function (event) { this.domNode.classList.remove('focus'); }; - diff --git a/examples/checkbox/checkbox-2/js/controlledCheckbox.js b/examples/checkbox/checkbox-2/js/controlledCheckbox.js index 866ccbf3c5..b44c95eeba 100644 --- a/examples/checkbox/checkbox-2/js/controlledCheckbox.js +++ b/examples/checkbox/checkbox-2/js/controlledCheckbox.js @@ -1,39 +1,35 @@ /* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -* -* File: controlledCheckbox.js -* -* Desc: ControlledCheckbox widget that implements ARIA Authoring Practices -* for a mixed checkbox -*/ + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * File: controlledCheckbox.js + * + * Desc: ControlledCheckbox widget that implements ARIA Authoring Practices + * for a mixed checkbox + */ 'use strict'; /* -* @constructor ControlledCheckbox -* -* -*/ + * @constructor ControlledCheckbox + * + * + */ var ControlledCheckbox = function (domNode, controllerObj) { - this.domNode = domNode; this.controller = controllerObj; this.lastState = false; - }; ControlledCheckbox.prototype.init = function () { - this.lastState = this.isChecked(); console.log(this.lastState); this.domNode.addEventListener('change', this.handleChange.bind(this)); - this.domNode.addEventListener('keydown', this.handleKeyup.bind(this), true); - this.domNode.addEventListener('click', this.handleClick.bind(this), true); - + this.domNode.addEventListener('keydown', this.handleKeyup.bind(this), true); + this.domNode.addEventListener('click', this.handleClick.bind(this), true); }; ControlledCheckbox.prototype.isChecked = function () { @@ -49,7 +45,6 @@ ControlledCheckbox.prototype.isChecked = function () { ControlledCheckbox.prototype.setChecked = function (value) { // if standard input[type=checkbox] if (typeof this.domNode.checked === 'boolean') { - switch (value) { case 'true': this.domNode.checked = true; @@ -70,7 +65,6 @@ ControlledCheckbox.prototype.setChecked = function (value) { // If ARIA checkbox widget if (typeof this.domNode.getAttribute('aria-checked') === 'string') { - switch (value) { case 'true': case 'false': @@ -80,8 +74,7 @@ ControlledCheckbox.prototype.setChecked = function (value) { case 'last': if (this.lastState) { this.domNode.setAttribute('aria-checked', 'true'); - } - else { + } else { this.domNode.setAttribute('aria-checked', 'false'); } break; @@ -105,4 +98,3 @@ ControlledCheckbox.prototype.handleKeyup = function (event) { ControlledCheckbox.prototype.handleClick = function (event) { this.lastState = this.isChecked(); }; - diff --git a/examples/combobox/js/combobox-autocomplete.js b/examples/combobox/js/combobox-autocomplete.js index 20fe7fcb03..4e965fcf32 100644 --- a/examples/combobox/js/combobox-autocomplete.js +++ b/examples/combobox/js/combobox-autocomplete.js @@ -1,15 +1,14 @@ /* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -*/ + * 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 ComboboxAutocomplete = function (comboboxNode, buttonNode, listboxNode) { - this.comboboxNode = comboboxNode; - this.buttonNode = buttonNode; - this.listboxNode = listboxNode; + this.buttonNode = buttonNode; + this.listboxNode = listboxNode; this.comboboxHasVisualFocus = false; this.listboxHasVisualFocus = false; @@ -22,39 +21,58 @@ var ComboboxAutocomplete = function (comboboxNode, buttonNode, listboxNode) { this.allOptions = []; - this.option = null; - this.firstOption = null; - this.lastOption = null; + this.option = null; + this.firstOption = null; + this.lastOption = null; this.filteredOptions = []; - this.filter = ''; + this.filter = ''; }; ComboboxAutocomplete.prototype.init = function () { - var autocomplete = this.comboboxNode.getAttribute('aria-autocomplete'); if (typeof autocomplete === 'string') { autocomplete = autocomplete.toLowerCase(); - this.isNone = autocomplete === 'none'; - this.isList = autocomplete === 'list'; - this.isBoth = autocomplete === 'both'; - } - else { + this.isNone = autocomplete === 'none'; + this.isList = autocomplete === 'list'; + this.isBoth = autocomplete === 'both'; + } else { // default value of autocomplete this.isNone = true; } - this.comboboxNode.addEventListener('keydown', this.handleComboboxKeyDown.bind(this)); - this.comboboxNode.addEventListener('keyup', this.handleComboboxKeyUp.bind(this)); - this.comboboxNode.addEventListener('click', this.handleComboboxClick.bind(this)); - this.comboboxNode.addEventListener('focus', this.handleComboboxFocus.bind(this)); - this.comboboxNode.addEventListener('blur', this.handleComboboxBlur.bind(this)); + this.comboboxNode.addEventListener( + 'keydown', + this.handleComboboxKeyDown.bind(this) + ); + this.comboboxNode.addEventListener( + 'keyup', + this.handleComboboxKeyUp.bind(this) + ); + this.comboboxNode.addEventListener( + 'click', + this.handleComboboxClick.bind(this) + ); + this.comboboxNode.addEventListener( + 'focus', + this.handleComboboxFocus.bind(this) + ); + this.comboboxNode.addEventListener( + 'blur', + this.handleComboboxBlur.bind(this) + ); // initialize pop up menu - this.listboxNode.addEventListener('mouseover', this.handleListboxMouseover.bind(this)); - this.listboxNode.addEventListener('mouseout', this.handleListboxMouseout.bind(this)); + this.listboxNode.addEventListener( + 'mouseover', + this.handleListboxMouseover.bind(this) + ); + this.listboxNode.addEventListener( + 'mouseout', + this.handleListboxMouseout.bind(this) + ); // Traverse the element children of domNode: configure each with // option role behavior and store reference in.options array. @@ -64,10 +82,9 @@ ComboboxAutocomplete.prototype.init = function () { var node = nodes[i]; this.allOptions.push(node); - node.addEventListener('click', this.handleOptionClick.bind(this)); - node.addEventListener('mouseover', this.handleOptionMouseover.bind(this)); - node.addEventListener('mouseout', this.handleOptionMouseout.bind(this)); - + node.addEventListener('click', this.handleOptionClick.bind(this)); + node.addEventListener('mouseover', this.handleOptionMouseover.bind(this)); + node.addEventListener('mouseout', this.handleOptionMouseout.bind(this)); } this.filterOptions(); @@ -79,18 +96,16 @@ ComboboxAutocomplete.prototype.init = function () { if (button && button.tagName === 'BUTTON') { button.addEventListener('click', this.handleButtonClick.bind(this)); } - }; ComboboxAutocomplete.prototype.getLowercaseContent = function (node) { return node.textContent.toLowerCase(); -} +}; ComboboxAutocomplete.prototype.setActiveDescendant = function (option) { if (option && this.listboxHasVisualFocus) { this.comboboxNode.setAttribute('aria-activedescendant', option.id); - } - else { + } else { this.comboboxNode.setAttribute('aria-activedescendant', ''); } }; @@ -98,7 +113,7 @@ ComboboxAutocomplete.prototype.setActiveDescendant = function (option) { ComboboxAutocomplete.prototype.setValue = function (value) { this.filter = value; this.comboboxNode.value = this.filter; - this.comboboxNode.setSelectionRange(this.filter.length,this.filter.length); + this.comboboxNode.setSelectionRange(this.filter.length, this.filter.length); this.filterOptions(); }; @@ -113,12 +128,17 @@ ComboboxAutocomplete.prototype.setOption = function (option, flag) { this.setActiveDescendant(this.option); if (this.isBoth) { - this.comboboxNode.value = this.option.textContent; + this.comboboxNode.value = this.option.textContent; if (flag) { - this.comboboxNode.setSelectionRange(this.option.textContent.length,this.option.textContent.length); - } - else { - this.comboboxNode.setSelectionRange(this.filter.length,this.option.textContent.length); + this.comboboxNode.setSelectionRange( + this.option.textContent.length, + this.option.textContent.length + ); + } else { + this.comboboxNode.setSelectionRange( + this.filter.length, + this.option.textContent.length + ); } } } @@ -152,7 +172,6 @@ ComboboxAutocomplete.prototype.removeVisualFocusAll = function () { // ComboboxAutocomplete Events ComboboxAutocomplete.prototype.filterOptions = function () { - // do not filter any options if autocomplete is none if (this.isNone) { this.filter = ''; @@ -162,12 +181,15 @@ ComboboxAutocomplete.prototype.filterOptions = function () { var currentOption = this.option; var filter = this.filter.toLowerCase(); - this.filteredOptions = []; + this.filteredOptions = []; this.listboxNode.innerHTML = ''; for (var i = 0; i < this.allOptions.length; i++) { option = this.allOptions[i]; - if (filter.length === 0 || this.getLowercaseContent(option).indexOf(filter) === 0) { + if ( + filter.length === 0 || + this.getLowercaseContent(option).indexOf(filter) === 0 + ) { this.filteredOptions.push(option); this.listboxNode.appendChild(option); } @@ -177,38 +199,37 @@ ComboboxAutocomplete.prototype.filterOptions = function () { var numItems = this.filteredOptions.length; if (numItems > 0) { this.firstOption = this.filteredOptions[0]; - this.lastOption = this.filteredOptions[numItems - 1]; + this.lastOption = this.filteredOptions[numItems - 1]; if (currentOption && this.filteredOptions.indexOf(currentOption) >= 0) { option = currentOption; - } - else { + } else { option = this.firstOption; } - } - else { + } else { this.firstOption = null; option = null; - this.lastOption = null; + this.lastOption = null; } return option; }; ComboboxAutocomplete.prototype.setCurrentOptionStyle = function (option) { - for (var i = 0; i < this.filteredOptions.length; i++) { var opt = this.filteredOptions[i]; if (opt === option) { opt.setAttribute('aria-selected', 'true'); - if ((this.listboxNode.scrollTop + this.listboxNode.offsetHeight) < (opt.offsetTop + opt.offsetHeight)) { - this.listboxNode.scrollTop = opt.offsetTop + opt.offsetHeight - this.listboxNode.offsetHeight; - } - else if (this.listboxNode.scrollTop > (opt.offsetTop + 2)) { - this.listboxNode.scrollTop = opt.offsetTop; + if ( + this.listboxNode.scrollTop + this.listboxNode.offsetHeight < + opt.offsetTop + opt.offsetHeight + ) { + this.listboxNode.scrollTop = + opt.offsetTop + opt.offsetHeight - this.listboxNode.offsetHeight; + } else if (this.listboxNode.scrollTop > opt.offsetTop + 2) { + this.listboxNode.scrollTop = opt.offsetTop; } - } - else { + } else { opt.removeAttribute('aria-selected'); } } @@ -259,7 +280,12 @@ ComboboxAutocomplete.prototype.close = function (force) { force = false; } - if (force || (!this.comboboxHasVisualFocus && !this.listboxHasVisualFocus && !this.hasHover)) { + if ( + force || + (!this.comboboxHasVisualFocus && + !this.listboxHasVisualFocus && + !this.hasHover) + ) { this.setCurrentOptionStyle(false); this.listboxNode.style.display = 'none'; this.comboboxNode.setAttribute('aria-expanded', 'false'); @@ -273,15 +299,14 @@ ComboboxAutocomplete.prototype.close = function (force) { ComboboxAutocomplete.prototype.handleComboboxKeyDown = function (event) { var flag = false, char = event.key, - altKey = event.altKey; + altKey = event.altKey; if (event.ctrlKey || event.shiftKey) { return; } switch (event.key) { - - case "Enter": + case 'Enter': if (this.listboxHasVisualFocus) { this.setValue(this.option.textContent); } @@ -290,19 +315,20 @@ ComboboxAutocomplete.prototype.handleComboboxKeyDown = function (event) { flag = true; break; - case "Down": - case "ArrowDown": + case 'Down': + case 'ArrowDown': if (this.filteredOptions.length > 0) { if (altKey) { this.open(); - } - else { + } else { this.open(); - if (this.listboxHasVisualFocus || (this.isBoth && this.filteredOptions.length > 1)) { + if ( + this.listboxHasVisualFocus || + (this.isBoth && this.filteredOptions.length > 1) + ) { this.setOption(this.getNextOption(this.option), true); this.setVisualFocusListbox(); - } - else { + } else { this.setOption(this.firstOption, true); this.setVisualFocusListbox(); } @@ -311,14 +337,12 @@ ComboboxAutocomplete.prototype.handleComboboxKeyDown = function (event) { flag = true; break; - case "Up": - case "ArrowUp": - + case 'Up': + case 'ArrowUp': if (this.hasOptions()) { if (this.listboxHasVisualFocus) { this.setOption(this.getPreviousOption(this.option), true); - } - else { + } else { this.open(); if (!altKey) { this.setOption(this.lastOption, true); @@ -329,15 +353,14 @@ ComboboxAutocomplete.prototype.handleComboboxKeyDown = function (event) { flag = true; break; - case "Esc": - case "Escape": + case 'Esc': + case 'Escape': if (this.isOpen()) { this.close(true); this.filter = this.comboboxNode.value; this.filterOptions(); this.setVisualFocusCombobox(); - } - else { + } else { this.setValue(''); this.comboboxNode.value = ''; } @@ -345,7 +368,7 @@ ComboboxAutocomplete.prototype.handleComboboxKeyDown = function (event) { flag = true; break; - case "Tab": + case 'Tab': this.close(true); if (this.listboxHasVisualFocus) { if (this.option) { @@ -354,18 +377,17 @@ ComboboxAutocomplete.prototype.handleComboboxKeyDown = function (event) { } break; - case "Home": - this.comboboxNode.setSelectionRange(0,0); + case 'Home': + this.comboboxNode.setSelectionRange(0, 0); flag = true; break; - case "End": + case 'End': var length = this.comboboxNode.value.length; - this.comboboxNode.setSelectionRange(length,length); + this.comboboxNode.setSelectionRange(length, length); flag = true; break; - default: break; } @@ -374,12 +396,11 @@ ComboboxAutocomplete.prototype.handleComboboxKeyDown = function (event) { event.stopPropagation(); event.preventDefault(); } - }; ComboboxAutocomplete.prototype.isPrintableCharacter = function (str) { return str.length === 1 && str.match(/\S/); -} +}; ComboboxAutocomplete.prototype.handleComboboxKeyUp = function (event) { var flag = false, @@ -394,34 +415,32 @@ ComboboxAutocomplete.prototype.handleComboboxKeyUp = function (event) { if (this.comboboxNode.value.length < this.filter.length) { this.filter = this.comboboxNode.value; this.option = null; - this.filterOptions() + this.filterOptions(); } - if (event.key === "Escape" || event.key === "Esc") { + if (event.key === 'Escape' || event.key === 'Esc') { return; } switch (event.key) { - - case "Backspace": + case 'Backspace': this.setVisualFocusCombobox(); this.setCurrentOptionStyle(false); this.filter = this.comboboxNode.value; this.option = null; - this.filterOptions() + this.filterOptions(); flag = true; break; - case "Left": - case "ArrowLeft": - case "Right": - case "ArrowRight": - case "Home": - case "End": + case 'Left': + case 'ArrowLeft': + case 'Right': + case 'ArrowRight': + case 'Home': + case 'End': if (this.isBoth) { this.filter = this.comboboxNode.value; - } - else { + } else { this.option = null; this.setCurrentOptionStyle(false); } @@ -442,7 +461,11 @@ ComboboxAutocomplete.prototype.handleComboboxKeyUp = function (event) { this.open(); } - if (this.getLowercaseContent(option).indexOf(this.comboboxNode.value.toLowerCase()) === 0) { + if ( + this.getLowercaseContent(option).indexOf( + this.comboboxNode.value.toLowerCase() + ) === 0 + ) { this.option = option; if (this.isBoth || this.listboxHasVisualFocus) { this.setCurrentOptionStyle(option); @@ -450,19 +473,16 @@ ComboboxAutocomplete.prototype.handleComboboxKeyUp = function (event) { this.setOption(option); } } - } - else { + } else { this.option = null; this.setCurrentOptionStyle(false); } - } - else { + } else { this.close(); this.option = null; this.setActiveDescendant(false); } - } - else if (this.comboboxNode.value.length) { + } else if (this.comboboxNode.value.length) { this.open(); } } @@ -474,14 +494,12 @@ ComboboxAutocomplete.prototype.handleComboboxKeyUp = function (event) { event.stopPropagation(); event.preventDefault(); } - }; ComboboxAutocomplete.prototype.handleComboboxClick = function (event) { if (this.isOpen()) { this.close(true); - } - else { + } else { this.open(); } }; @@ -504,15 +522,13 @@ ComboboxAutocomplete.prototype.handleComboboxBlur = function (event) { ComboboxAutocomplete.prototype.handleButtonClick = function (event) { if (this.isOpen()) { this.close(true); - } - else { + } else { this.open(); } this.comboboxNode.focus(); this.setVisualFocusCombobox(); }; - /* Listbox Events */ ComboboxAutocomplete.prototype.handleListboxMouseover = function (event) { @@ -534,7 +550,6 @@ ComboboxAutocomplete.prototype.handleOptionClick = function (event) { ComboboxAutocomplete.prototype.handleOptionMouseover = function (event) { this.hasHover = true; this.open(); - }; ComboboxAutocomplete.prototype.handleOptionMouseout = function (event) { @@ -542,20 +557,17 @@ ComboboxAutocomplete.prototype.handleOptionMouseout = function (event) { setTimeout(this.close.bind(this, false), 300); }; - // Initialize comboboxes window.addEventListener('load', function () { - var comboboxes = document.querySelectorAll('.combobox-list'); for (var i = 0; i < comboboxes.length; i++) { var combobox = comboboxes[i]; var comboboxNode = combobox.querySelector('input'); - var buttonNode = combobox.querySelector('button'); - var listboxNode = combobox.querySelector('[role="listbox"]'); + var buttonNode = combobox.querySelector('button'); + var listboxNode = combobox.querySelector('[role="listbox"]'); var cba = new ComboboxAutocomplete(comboboxNode, buttonNode, listboxNode); cba.init(); } - }); diff --git a/examples/combobox/js/combobox-datepicker.js b/examples/combobox/js/combobox-datepicker.js index ab6cb9fade..c791141ea3 100644 --- a/examples/combobox/js/combobox-datepicker.js +++ b/examples/combobox/js/combobox-datepicker.js @@ -1,33 +1,48 @@ /* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -* -* File: ComboboxDatePicker.js -*/ + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * File: ComboboxDatePicker.js + */ 'use strict'; var ComboboxDatePicker = function (cdp) { this.buttonLabel = 'Date'; - this.monthLabels = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']; + this.monthLabels = [ + 'January', + 'February', + 'March', + 'April', + 'May', + 'June', + 'July', + 'August', + 'September', + 'October', + 'November', + 'December', + ]; this.messageCursorKeys = 'Cursor keys can navigate dates'; this.lastMessage = ''; - this.comboboxNode = cdp.querySelector('input[type="text"]'); - this.buttonNode = cdp.querySelector('.group button'); - this.dialogNode = cdp.querySelector('[role="dialog"]'); - this.messageNode = this.dialogNode.querySelector('.dialog-message'); + this.comboboxNode = cdp.querySelector('input[type="text"]'); + this.buttonNode = cdp.querySelector('.group button'); + this.dialogNode = cdp.querySelector('[role="dialog"]'); + this.messageNode = this.dialogNode.querySelector('.dialog-message'); this.monthYearNode = this.dialogNode.querySelector('.month-year'); - this.prevYearNode = this.dialogNode.querySelector('.prev-year'); + this.prevYearNode = this.dialogNode.querySelector('.prev-year'); this.prevMonthNode = this.dialogNode.querySelector('.prev-month'); this.nextMonthNode = this.dialogNode.querySelector('.next-month'); - this.nextYearNode = this.dialogNode.querySelector('.next-year'); + this.nextYearNode = this.dialogNode.querySelector('.next-year'); - this.okButtonNode = this.dialogNode.querySelector('button[value="ok"]'); - this.cancelButtonNode = this.dialogNode.querySelector('button[value="cancel"]'); + this.okButtonNode = this.dialogNode.querySelector('button[value="ok"]'); + this.cancelButtonNode = this.dialogNode.querySelector( + 'button[value="cancel"]' + ); this.tbodyNode = this.dialogNode.querySelector('table.dates tbody'); @@ -36,39 +51,86 @@ var ComboboxDatePicker = function (cdp) { this.days = []; this.focusDay = new Date(); - this.selectedDay = new Date(0,0,1); + this.selectedDay = new Date(0, 0, 1); this.isMouseDownOnBackground = false; - }; ComboboxDatePicker.prototype.init = function () { - - this.comboboxNode.addEventListener('keydown', this.handleComboboxKeyDown.bind(this)); - this.comboboxNode.addEventListener('click', this.handleComboboxClick.bind(this)); - this.comboboxNode.addEventListener('focus', this.handleComboboxFocus.bind(this)); - this.comboboxNode.addEventListener('blur', this.handleComboboxBlur.bind(this)); - - this.buttonNode.addEventListener('keydown', this.handleButtonKeyDown.bind(this)); - this.buttonNode.addEventListener('click', this.handleButtonClick.bind(this)); + this.comboboxNode.addEventListener( + 'keydown', + this.handleComboboxKeyDown.bind(this) + ); + this.comboboxNode.addEventListener( + 'click', + this.handleComboboxClick.bind(this) + ); + this.comboboxNode.addEventListener( + 'focus', + this.handleComboboxFocus.bind(this) + ); + this.comboboxNode.addEventListener( + 'blur', + this.handleComboboxBlur.bind(this) + ); + + this.buttonNode.addEventListener( + 'keydown', + this.handleButtonKeyDown.bind(this) + ); + this.buttonNode.addEventListener('click', this.handleButtonClick.bind(this)); this.okButtonNode.addEventListener('click', this.handleOkButton.bind(this)); this.okButtonNode.addEventListener('keydown', this.handleOkButton.bind(this)); - this.cancelButtonNode.addEventListener('click', this.handleCancelButton.bind(this)); - this.cancelButtonNode.addEventListener('keydown', this.handleCancelButton.bind(this)); - - this.prevMonthNode.addEventListener('click', this.handlePreviousMonthButton.bind(this)); - this.nextMonthNode.addEventListener('click', this.handleNextMonthButton.bind(this)); - this.prevYearNode.addEventListener('click', this.handlePreviousYearButton.bind(this)); - this.nextYearNode.addEventListener('click', this.handleNextYearButton.bind(this)); - - this.prevMonthNode.addEventListener('keydown', this.handlePreviousMonthButton.bind(this)); - this.nextMonthNode.addEventListener('keydown', this.handleNextMonthButton.bind(this)); - this.prevYearNode.addEventListener('keydown', this.handlePreviousYearButton.bind(this)); - this.nextYearNode.addEventListener('keydown', this.handleNextYearButton.bind(this)); - - document.body.addEventListener('mouseup', this.handleBackgroundMouseUp.bind(this), true); + this.cancelButtonNode.addEventListener( + 'click', + this.handleCancelButton.bind(this) + ); + this.cancelButtonNode.addEventListener( + 'keydown', + this.handleCancelButton.bind(this) + ); + + this.prevMonthNode.addEventListener( + 'click', + this.handlePreviousMonthButton.bind(this) + ); + this.nextMonthNode.addEventListener( + 'click', + this.handleNextMonthButton.bind(this) + ); + this.prevYearNode.addEventListener( + 'click', + this.handlePreviousYearButton.bind(this) + ); + this.nextYearNode.addEventListener( + 'click', + this.handleNextYearButton.bind(this) + ); + + this.prevMonthNode.addEventListener( + 'keydown', + this.handlePreviousMonthButton.bind(this) + ); + this.nextMonthNode.addEventListener( + 'keydown', + this.handleNextMonthButton.bind(this) + ); + this.prevYearNode.addEventListener( + 'keydown', + this.handlePreviousYearButton.bind(this) + ); + this.nextYearNode.addEventListener( + 'keydown', + this.handleNextYearButton.bind(this) + ); + + document.body.addEventListener( + 'mouseup', + this.handleBackgroundMouseUp.bind(this), + true + ); // Create Grid of Dates @@ -96,22 +158,26 @@ ComboboxDatePicker.prototype.init = function () { }; ComboboxDatePicker.prototype.isSameDay = function (day1, day2) { - return (day1.getFullYear() == day2.getFullYear()) && - (day1.getMonth() == day2.getMonth()) && - (day1.getDate() == day2.getDate()); + return ( + day1.getFullYear() == day2.getFullYear() && + day1.getMonth() == day2.getMonth() && + day1.getDate() == day2.getDate() + ); }; ComboboxDatePicker.prototype.isNotSameMonth = function (day1, day2) { - return (day1.getFullYear() != day2.getFullYear()) || - (day1.getMonth() != day2.getMonth()); + return ( + day1.getFullYear() != day2.getFullYear() || + day1.getMonth() != day2.getMonth() + ); }; ComboboxDatePicker.prototype.updateGrid = function () { - var i, flag; var fd = this.focusDay; - this.monthYearNode.innerHTML = this.monthLabels[fd.getMonth()] + ' ' + fd.getFullYear(); + this.monthYearNode.innerHTML = + this.monthLabels[fd.getMonth()] + ' ' + fd.getFullYear(); var firstDayOfMonth = new Date(fd.getFullYear(), fd.getMonth(), 1); var dayOfWeek = firstDayOfMonth.getDay(); @@ -129,8 +195,7 @@ ComboboxDatePicker.prototype.updateGrid = function () { if (i === 35) { if (flag) { this.lastRowNode.style.visibility = 'hidden'; - } - else { + } else { this.lastRowNode.style.visibility = 'visible'; } } @@ -138,7 +203,6 @@ ComboboxDatePicker.prototype.updateGrid = function () { }; ComboboxDatePicker.prototype.setFocusDay = function (flag) { - if (typeof flag !== 'boolean') { flag = true; } @@ -146,8 +210,7 @@ ComboboxDatePicker.prototype.setFocusDay = function (flag) { var fd = this.focusDay; var getDayFromDataDateAttribute = this.getDayFromDataDateAttribute; - function checkDay (domNode) { - + function checkDay(domNode) { var d = getDayFromDataDateAttribute(domNode); domNode.setAttribute('tabindex', '-1'); @@ -159,9 +222,7 @@ ComboboxDatePicker.prototype.setFocusDay = function (flag) { } } - this.days.forEach(checkDay.bind(this)); - }; ComboboxDatePicker.prototype.open = function () { @@ -186,7 +247,7 @@ ComboboxDatePicker.prototype.close = function (flag) { this.setMessage(''); this.dialogNode.style.display = 'none'; - this.comboboxNode.setAttribute('aria-expanded', 'false') + this.comboboxNode.setAttribute('aria-expanded', 'false'); this.buttonNode.classList.remove('open'); if (flag) { @@ -199,24 +260,22 @@ ComboboxDatePicker.prototype.handleOkButton = function (event) { switch (event.type) { case 'keydown': - switch (event.key) { - case "Tab": + case 'Tab': if (!event.shiftKey) { this.prevYearNode.focus(); flag = true; } break; - case "Esc": - case "Escape": + case 'Esc': + case 'Escape': this.close(); flag = true; break; default: break; - } break; @@ -241,18 +300,15 @@ ComboboxDatePicker.prototype.handleCancelButton = function (event) { switch (event.type) { case 'keydown': - switch (event.key) { - - case "Esc": - case "Escape": + case 'Esc': + case 'Escape': this.close(); flag = true; break; default: break; - } break; @@ -275,17 +331,15 @@ ComboboxDatePicker.prototype.handleNextYearButton = function (event) { var flag = false; switch (event.type) { - case 'keydown': - switch (event.key) { - case "Esc": - case "Escape": + case 'Esc': + case 'Escape': this.close(); flag = true; break; - case "Enter": + case 'Enter': this.moveToNextYear(); this.setFocusDay(false); flag = true; @@ -313,26 +367,23 @@ ComboboxDatePicker.prototype.handlePreviousYearButton = function (event) { var flag = false; switch (event.type) { - case 'keydown': - switch (event.key) { - - case "Enter": + case 'Enter': this.moveToPreviousYear(); this.setFocusDay(false); flag = true; break; - case "Tab": + case 'Tab': if (event.shiftKey) { this.okButtonNode.focus(); flag = true; } break; - case "Esc": - case "Escape": + case 'Esc': + case 'Escape': this.close(); flag = true; break; @@ -362,17 +413,15 @@ ComboboxDatePicker.prototype.handleNextMonthButton = function (event) { var flag = false; switch (event.type) { - case 'keydown': - switch (event.key) { - case "Esc": - case "Escape": + case 'Esc': + case 'Escape': this.close(); flag = true; break; - case "Enter": + case 'Enter': this.moveToNextMonth(); this.setFocusDay(false); flag = true; @@ -400,17 +449,15 @@ ComboboxDatePicker.prototype.handlePreviousMonthButton = function (event) { var flag = false; switch (event.type) { - case 'keydown': - switch (event.key) { - case "Esc": - case "Escape": + case 'Esc': + case 'Escape': this.close(); flag = true; break; - case "Enter": + case 'Enter': this.moveToPreviousMonth(); this.setFocusDay(false); flag = true; @@ -440,14 +487,15 @@ ComboboxDatePicker.prototype.moveFocusToDay = function (day) { this.focusDay = day; - if ((d.getMonth() != this.focusDay.getMonth()) || - (d.getYear() != this.focusDay.getYear())) { + if ( + d.getMonth() != this.focusDay.getMonth() || + d.getYear() != this.focusDay.getYear() + ) { this.updateGrid(); } this.setFocusDay(); }; - ComboboxDatePicker.prototype.moveToNextYear = function () { this.focusDay.setFullYear(this.focusDay.getFullYear() + 1); this.updateGrid(); @@ -512,11 +560,15 @@ ComboboxDatePicker.prototype.isDayDisabled = function (domNode) { ComboboxDatePicker.prototype.getDayFromDataDateAttribute = function (domNode) { var parts = domNode.getAttribute('data-date').split('-'); - return new Date(parts[0], parseInt(parts[1])-1, parts[2]); + return new Date(parts[0], parseInt(parts[1]) - 1, parts[2]); }; -ComboboxDatePicker.prototype.updateDate = function (domNode, disable, day, selected) { - +ComboboxDatePicker.prototype.updateDate = function ( + domNode, + disable, + day, + selected +) { var d = day.getDate().toString(); if (day.getDate() <= 9) { d = '0' + d; @@ -534,8 +586,7 @@ ComboboxDatePicker.prototype.updateDate = function (domNode, disable, day, selec if (disable) { domNode.classList.add('disabled'); domNode.innerHTML = ''; - } - else { + } else { domNode.classList.remove('disabled'); domNode.innerHTML = day.getDate(); if (selected) { @@ -543,44 +594,40 @@ ComboboxDatePicker.prototype.updateDate = function (domNode, disable, day, selec domNode.setAttribute('tabindex', '0'); } } - }; ComboboxDatePicker.prototype.updateSelected = function (domNode) { for (var i = 0; i < this.days.length; i++) { var day = this.days[i]; - if (day === domNode) { + if (day === domNode) { day.setAttribute('aria-selected', 'true'); - } - else { + } else { day.removeAttribute('aria-selected'); } } }; - ComboboxDatePicker.prototype.handleDayKeyDown = function (event) { var flag = false; switch (event.key) { - - case "Esc": - case "Escape": + case 'Esc': + case 'Escape': this.close(); break; - case " ": + case ' ': this.updateSelected(event.currentTarget); this.setComboboxDate(event.currentTarget); flag = true; break; - case "Enter": + case 'Enter': this.setComboboxDate(event.currentTarget); this.close(); break; - case "Tab": + case 'Tab': this.cancelButtonNode.focus(); if (event.shiftKey) { this.nextYearNode.focus(); @@ -589,58 +636,56 @@ ComboboxDatePicker.prototype.handleDayKeyDown = function (event) { flag = true; break; - case "Right": - case "ArrowRight": + case 'Right': + case 'ArrowRight': this.moveFocusToNextDay(); flag = true; break; - case "Left": - case "ArrowLeft": + case 'Left': + case 'ArrowLeft': this.moveFocusToPreviousDay(); flag = true; break; - case "Down": - case "ArrowDown": + case 'Down': + case 'ArrowDown': this.moveFocusToNextWeek(); flag = true; break; - case "Up": - case "ArrowUp": + case 'Up': + case 'ArrowUp': this.moveFocusToPreviousWeek(); flag = true; break; - case "PageUp": + case 'PageUp': if (event.shiftKey) { this.moveToPreviousYear(); - } - else { + } else { this.moveToPreviousMonth(); } this.setFocusDay(); flag = true; break; - case "PageDown": + case 'PageDown': if (event.shiftKey) { this.moveToNextYear(); - } - else { + } else { this.moveToNextMonth(); } this.setFocusDay(); flag = true; break; - case "Home": + case 'Home': this.moveFocusToFirstDayOfWeek(); flag = true; break; - case "End": + case 'End': this.moveFocusToLastDayOfWeek(); flag = true; break; @@ -653,7 +698,6 @@ ComboboxDatePicker.prototype.handleDayKeyDown = function (event) { }; ComboboxDatePicker.prototype.handleDayClick = function (event) { - if (!this.isDayDisabled(event.currentTarget)) { this.setComboboxDate(event.currentTarget); this.close(); @@ -661,7 +705,6 @@ ComboboxDatePicker.prototype.handleDayClick = function (event) { event.stopPropagation(); event.preventDefault(); - }; ComboboxDatePicker.prototype.handleDayFocus = function () { @@ -671,39 +714,40 @@ ComboboxDatePicker.prototype.handleDayFocus = function () { // Combobox methods ComboboxDatePicker.prototype.setComboboxDate = function (domNode) { - var d = this.focusDay; if (domNode) { d = this.getDayFromDataDateAttribute(domNode); } - this.comboboxNode.value = (d.getMonth() + 1) + '/' + d.getDate() + '/' + d.getFullYear(); - + this.comboboxNode.value = + d.getMonth() + 1 + '/' + d.getDate() + '/' + d.getFullYear(); }; ComboboxDatePicker.prototype.getDateFromCombobox = function () { - var parts = this.comboboxNode.value.split('/'); - if ((parts.length === 3) && - Number.isInteger(parseInt(parts[0])) && - Number.isInteger(parseInt(parts[1])) && - Number.isInteger(parseInt(parts[2]))) { - this.focusDay = new Date(parseInt(parts[2]), parseInt(parts[0]) - 1, parseInt(parts[1])); + if ( + parts.length === 3 && + Number.isInteger(parseInt(parts[0])) && + Number.isInteger(parseInt(parts[1])) && + Number.isInteger(parseInt(parts[2])) + ) { + this.focusDay = new Date( + parseInt(parts[2]), + parseInt(parts[0]) - 1, + parseInt(parts[1]) + ); this.selectedDay = new Date(this.focusDay); - } - else { + } else { // If not a valid date (MM/DD/YY) initialize with todays date this.focusDay = new Date(); - this.selectedDay = new Date(0,0,1); + this.selectedDay = new Date(0, 0, 1); } - }; ComboboxDatePicker.prototype.setMessage = function (str) { - - function setMessageDelayed () { + function setMessageDelayed() { this.messageNode.textContent = str; } @@ -716,38 +760,35 @@ ComboboxDatePicker.prototype.setMessage = function (str) { ComboboxDatePicker.prototype.handleComboboxKeyDown = function (event) { var flag = false, char = event.key, - altKey = event.altKey; + altKey = event.altKey; if (event.ctrlKey || event.shiftKey) { return; } switch (event.key) { - - case "Down": - case "ArrowDown": + case 'Down': + case 'ArrowDown': this.open(); this.setFocusDay(); flag = true; break; - case "Esc": - case "Escape": + case 'Esc': + case 'Escape': if (this.isOpen()) { this.close(false); - } - else { + } else { this.comboboxNode.value = ''; } this.option = null; flag = true; break; - case "Tab": + case 'Tab': this.close(false); break; - default: break; } @@ -756,14 +797,12 @@ ComboboxDatePicker.prototype.handleComboboxKeyDown = function (event) { event.stopPropagation(); event.preventDefault(); } - }; ComboboxDatePicker.prototype.handleComboboxClick = function (event) { if (this.isOpen()) { this.close(false); - } - else { + } else { this.open(); } @@ -780,8 +819,7 @@ ComboboxDatePicker.prototype.handleComboboxBlur = function (event) { }; ComboboxDatePicker.prototype.handleButtonKeyDown = function (event) { - - if (event.key === "Enter" || event.key === " ") { + if (event.key === 'Enter' || event.key === ' ') { this.open(); this.setFocusDay(); @@ -793,8 +831,7 @@ ComboboxDatePicker.prototype.handleButtonKeyDown = function (event) { ComboboxDatePicker.prototype.handleButtonClick = function (event) { if (this.isOpen()) { this.close(); - } - else { + } else { this.open(); this.setFocusDay(); } @@ -804,10 +841,11 @@ ComboboxDatePicker.prototype.handleButtonClick = function (event) { }; ComboboxDatePicker.prototype.handleBackgroundMouseUp = function (event) { - if (!this.comboboxNode.contains(event.target) && - !this.buttonNode.contains(event.target) && - !this.dialogNode.contains(event.target)) { - + if ( + !this.comboboxNode.contains(event.target) && + !this.buttonNode.contains(event.target) && + !this.dialogNode.contains(event.target) + ) { if (this.isOpen()) { this.close(false); event.stopPropagation(); @@ -818,13 +856,11 @@ ComboboxDatePicker.prototype.handleBackgroundMouseUp = function (event) { // Initialize menu button date picker -window.addEventListener('load' , function () { - +window.addEventListener('load', function () { var comboboxDatePickers = document.querySelectorAll('.combobox-datepicker'); comboboxDatePickers.forEach(function (dp) { var datePicker = new ComboboxDatePicker(dp); datePicker.init(); }); - }); diff --git a/examples/combobox/js/grid-combo-example.js b/examples/combobox/js/grid-combo-example.js index 24301ae8cd..b078ea3929 100644 --- a/examples/combobox/js/grid-combo-example.js +++ b/examples/combobox/js/grid-combo-example.js @@ -1,9 +1,9 @@ /* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -* -* ARIA Combobox Examples -*/ + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * ARIA Combobox Examples + */ 'use strict'; @@ -70,10 +70,10 @@ var FRUITS_AND_VEGGIES = [ ['Watercress', 'Vegetable'], ['Watermelon', 'Fruit'], ['Yam', 'Vegetable'], - ['Zucchini', 'Vegetable'] + ['Zucchini', 'Vegetable'], ]; -function searchVeggies (searchString) { +function searchVeggies(searchString) { var results = []; for (var i = 0; i < FRUITS_AND_VEGGIES.length; i++) { @@ -96,5 +96,4 @@ window.addEventListener('load', function () { document.getElementById('ex1-grid'), searchVeggies ); - }); diff --git a/examples/combobox/js/grid-combo.js b/examples/combobox/js/grid-combo.js index 74776fde34..78bc5c1078 100644 --- a/examples/combobox/js/grid-combo.js +++ b/examples/combobox/js/grid-combo.js @@ -1,7 +1,7 @@ /* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -*/ + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + */ 'use strict'; @@ -22,11 +22,7 @@ * The search function. The function accepts a search string and returns an * array of results. */ -aria.GridCombobox = function ( - input, - grid, - searchFn -) { +aria.GridCombobox = function (input, grid, searchFn) { this.input = input; this.grid = grid; this.searchFn = searchFn; @@ -78,7 +74,6 @@ aria.GridCombobox.prototype.handleInputKeyUp = function (evt) { } }; - aria.GridCombobox.prototype.handleInputKeyDown = function (evt) { var key = evt.which || evt.keyCode; var activeRowIndex = this.activeRowIndex; @@ -90,18 +85,17 @@ aria.GridCombobox.prototype.handleInputKeyDown = function (evt) { this.removeFocusCell(this.activeRowIndex, this.activeColIndex); this.activeRowIndex = -1; this.activeColIndex = 0; - this.input.setAttribute( - 'aria-activedescendant', - '' - ); - } - else { + this.input.setAttribute('aria-activedescendant', ''); + } else { if (!this.shown) { - setTimeout((function () { - // On Firefox, input does not get cleared here unless wrapped in - // a setTimeout - this.input.value = ''; - }).bind(this), 1); + setTimeout( + function () { + // On Firefox, input does not get cleared here unless wrapped in + // a setTimeout + this.input.value = ''; + }.bind(this), + 1 + ); } } if (this.shown) { @@ -132,8 +126,7 @@ aria.GridCombobox.prototype.handleInputKeyDown = function (evt) { if (activeColIndex <= 0) { activeColIndex = this.colsCount - 1; activeRowIndex = this.getRowIndex(key); - } - else { + } else { activeColIndex--; } if (this.gridFocused) { @@ -144,8 +137,7 @@ aria.GridCombobox.prototype.handleInputKeyDown = function (evt) { if (activeColIndex === -1 || activeColIndex >= this.colsCount - 1) { activeColIndex = 0; activeRowIndex = this.getRowIndex(key); - } - else { + } else { activeColIndex++; } if (this.gridFocused) { @@ -181,12 +173,8 @@ aria.GridCombobox.prototype.handleInputKeyDown = function (evt) { this.focusCell(activeRowIndex, activeColIndex); var selectedItem = this.getItemAt(activeRowIndex, this.selectionCol); selectedItem.setAttribute('aria-selected', 'true'); - } - else { - this.input.setAttribute( - 'aria-activedescendant', - '' - ); + } else { + this.input.setAttribute('aria-activedescendant', ''); } }; @@ -202,11 +190,9 @@ aria.GridCombobox.prototype.handleGridClick = function (evt) { var row; if (evt.target.getAttribute('role') === 'row') { row = evt.target; - } - else if (evt.target.getAttribute('role') === 'gridcell') { + } else if (evt.target.getAttribute('role') === 'gridcell') { row = evt.target.parentNode; - } - else { + } else { return; } @@ -256,8 +242,7 @@ aria.GridCombobox.prototype.getRowIndex = function (key) { case aria.KeyCode.LEFT: if (activeRowIndex <= 0) { activeRowIndex = this.rowsCount - 1; - } - else { + } else { activeRowIndex--; } break; @@ -265,8 +250,7 @@ aria.GridCombobox.prototype.getRowIndex = function (key) { case aria.KeyCode.RIGHT: if (activeRowIndex === -1 || activeRowIndex >= this.rowsCount - 1) { activeRowIndex = 0; - } - else { + } else { activeRowIndex++; } } @@ -274,12 +258,10 @@ aria.GridCombobox.prototype.getRowIndex = function (key) { return activeRowIndex; }; - aria.GridCombobox.prototype.getItemAt = function (rowIndex, colIndex) { return document.getElementById('result-item-' + rowIndex + 'x' + colIndex); }; - aria.GridCombobox.prototype.selectItem = function (item) { if (item) { this.input.value = item.innerText; @@ -297,10 +279,7 @@ aria.GridCombobox.prototype.hideResults = function () { this.input.setAttribute('aria-expanded', 'false'); this.rowsCount = 0; this.colsCount = 0; - this.input.setAttribute( - 'aria-activedescendant', - '' - ); + this.input.setAttribute('aria-activedescendant', ''); }; aria.GridCombobox.prototype.removeFocusCell = function (rowIndex, colIndex) { diff --git a/examples/combobox/js/select-only.js b/examples/combobox/js/select-only.js index 2c18abed80..f8441cfc51 100644 --- a/examples/combobox/js/select-only.js +++ b/examples/combobox/js/select-only.js @@ -1,7 +1,7 @@ /* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -*/ + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + */ 'use strict'; @@ -17,8 +17,8 @@ const SelectActions = { PageUp: 7, Previous: 8, Select: 9, - Type: 10 -} + Type: 10, +}; /* * Helper functions @@ -51,7 +51,11 @@ function getActionFromKey(event, menuOpen) { } // handle typing characters when open or closed - if (key === 'Backspace' || key === 'Clear' || (key.length === 1 && key !== ' ' && !altKey && !ctrlKey && !metaKey)) { + if ( + key === 'Backspace' || + key === 'Clear' || + (key.length === 1 && key !== ' ' && !altKey && !ctrlKey && !metaKey) + ) { return SelectActions.Type; } @@ -59,35 +63,32 @@ function getActionFromKey(event, menuOpen) { if (menuOpen) { if (key === 'ArrowUp' && altKey) { return SelectActions.CloseSelect; - } - else if (key === 'ArrowDown' && !altKey) { + } else if (key === 'ArrowDown' && !altKey) { return SelectActions.Next; - } - else if (key === 'ArrowUp') { + } else if (key === 'ArrowUp') { return SelectActions.Previous; - } - else if (key === 'PageUp') { + } else if (key === 'PageUp') { return SelectActions.PageUp; - } - else if (key === 'PageDown') { + } else if (key === 'PageDown') { return SelectActions.PageDown; - } - else if (key === 'Escape') { + } else if (key === 'Escape') { return SelectActions.Close; - } - else if (key === 'Enter' || key === ' ') { + } else if (key === 'Enter' || key === ' ') { return SelectActions.CloseSelect; } } } - + // return the index of an option from an array of options, based on a search string // if the filter is multiple iterations of the same letter (e.g "aaa"), then cycle through first-letter matches function getIndexByLetter(options, filter, startIndex = 0) { - const orderedOptions = [...options.slice(startIndex), ...options.slice(0, startIndex)]; + const orderedOptions = [ + ...options.slice(startIndex), + ...options.slice(0, startIndex), + ]; const firstMatch = filterOptions(orderedOptions, filter)[0]; const allSameLetter = (array) => array.every((letter) => letter === array[0]); - + // first check if there is an exact match for the typed string if (firstMatch) { return options.indexOf(firstMatch); @@ -104,12 +105,12 @@ function getIndexByLetter(options, filter, startIndex = 0) { return -1; } } - + // get an updated option index after performing an action function getUpdatedIndex(currentIndex, maxIndex, action) { const pageSize = 10; // used for pageup/pagedown - switch(action) { + switch (action) { case SelectActions.First: return 0; case SelectActions.Last: @@ -126,7 +127,7 @@ function getUpdatedIndex(currentIndex, maxIndex, action) { return currentIndex; } } - + // check if an element is currently scrollable function isScrollable(element) { return element && element.clientHeight < element.scrollHeight; @@ -139,12 +140,11 @@ function maintainScrollVisibility(activeElement, scrollParent) { const { offsetHeight: parentOffsetHeight, scrollTop } = scrollParent; const isAbove = offsetTop < scrollTop; - const isBelow = (offsetTop + offsetHeight) > (scrollTop + parentOffsetHeight); + const isBelow = offsetTop + offsetHeight > scrollTop + parentOffsetHeight; if (isAbove) { scrollParent.scrollTo(0, offsetTop); - } - else if (isBelow) { + } else if (isBelow) { scrollParent.scrollTo(0, offsetTop - parentOffsetHeight + offsetHeight); } } @@ -153,7 +153,7 @@ function maintainScrollVisibility(activeElement, scrollParent) { * Select Component * Accepts a combobox element and an array of string options */ -const Select = function(el, options = []) { +const Select = function (el, options = []) { // element refs this.el = el; this.comboEl = el.querySelector('[role=combobox]'); @@ -172,10 +172,10 @@ const Select = function(el, options = []) { // init if (el && this.comboEl && this.listboxEl) { this.init(); - } -} + } +}; -Select.prototype.init = function() { +Select.prototype.init = function () { // select first option by default this.comboEl.innerHTML = this.options[0]; @@ -189,13 +189,14 @@ Select.prototype.init = function() { const optionEl = this.createOption(option, index); this.listboxEl.appendChild(optionEl); }); -} +}; -Select.prototype.createOption = function(optionText, index) { +Select.prototype.createOption = function (optionText, index) { const optionEl = document.createElement('div'); optionEl.setAttribute('role', 'option'); optionEl.id = `${this.idBase}-${index}`; - optionEl.className = index === 0 ? 'combo-option option-current' : 'combo-option'; + optionEl.className = + index === 0 ? 'combo-option option-current' : 'combo-option'; optionEl.setAttribute('aria-selected', `${index === 0}`); optionEl.innerText = optionText; @@ -206,9 +207,9 @@ Select.prototype.createOption = function(optionText, index) { optionEl.addEventListener('mousedown', this.onOptionMouseDown.bind(this)); return optionEl; -} +}; -Select.prototype.getSearchString = function(char) { +Select.prototype.getSearchString = function (char) { // reset typing timeout and start new timeout // this allows us to make multiple-letter matches, like a native select if (typeof this.searchTimeout === 'number') { @@ -218,13 +219,13 @@ Select.prototype.getSearchString = function(char) { this.searchTimeout = window.setTimeout(() => { this.searchString = ''; }, 500); - + // add most recent letter to saved search string this.searchString += char; return this.searchString; -} +}; -Select.prototype.onComboBlur = function() { +Select.prototype.onComboBlur = function () { // do not do blur action if ignoreBlur flag has been set if (this.ignoreBlur) { this.ignoreBlur = false; @@ -236,33 +237,35 @@ Select.prototype.onComboBlur = function() { this.selectOption(this.activeIndex); this.updateMenuState(false, false); } -} +}; -Select.prototype.onComboClick = function() { +Select.prototype.onComboClick = function () { this.updateMenuState(!this.open, false); -} +}; -Select.prototype.onComboKeyDown = function(event) { +Select.prototype.onComboKeyDown = function (event) { const { key } = event; const max = this.options.length - 1; const action = getActionFromKey(event, this.open); - switch(action) { + switch (action) { case SelectActions.Last: case SelectActions.First: this.updateMenuState(true); - // intentional fallthrough + // intentional fallthrough case SelectActions.Next: case SelectActions.Previous: case SelectActions.PageUp: case SelectActions.PageDown: event.preventDefault(); - return this.onOptionChange(getUpdatedIndex(this.activeIndex, max, action)); + return this.onOptionChange( + getUpdatedIndex(this.activeIndex, max, action) + ); case SelectActions.CloseSelect: event.preventDefault(); this.selectOption(this.activeIndex); - // intentional fallthrough + // intentional fallthrough case SelectActions.Close: event.preventDefault(); return this.updateMenuState(false); @@ -272,15 +275,19 @@ Select.prototype.onComboKeyDown = function(event) { event.preventDefault(); return this.updateMenuState(true); } -} +}; -Select.prototype.onComboType = function(letter) { +Select.prototype.onComboType = function (letter) { // open the listbox if it is closed this.updateMenuState(true); // find the index of the first matching option const searchString = this.getSearchString(letter); - const searchIndex = getIndexByLetter(this.options, searchString, this.activeIndex + 1); + const searchIndex = getIndexByLetter( + this.options, + searchString, + this.activeIndex + 1 + ); // if a match was found, go to it if (searchIndex >= 0) { @@ -291,9 +298,9 @@ Select.prototype.onComboType = function(letter) { window.clearTimeout(this.searchTimeout); this.searchString = ''; } -} +}; -Select.prototype.onOptionChange = function(index) { +Select.prototype.onOptionChange = function (index) { // update state this.activeIndex = index; @@ -311,21 +318,21 @@ Select.prototype.onOptionChange = function(index) { if (isScrollable(this.listboxEl)) { maintainScrollVisibility(options[index], this.listboxEl); } -} +}; -Select.prototype.onOptionClick = function(index) { +Select.prototype.onOptionClick = function (index) { this.onOptionChange(index); this.selectOption(index); this.updateMenuState(false); -} +}; -Select.prototype.onOptionMouseDown = function() { +Select.prototype.onOptionMouseDown = function () { // Clicking an option will cause a blur event, // but we don't want to perform the default keyboard blur action this.ignoreBlur = true; -} +}; -Select.prototype.selectOption = function(index) { +Select.prototype.selectOption = function (index) { // update state this.activeIndex = index; @@ -339,9 +346,9 @@ Select.prototype.selectOption = function(index) { optionEl.setAttribute('aria-selected', 'false'); }); options[index].setAttribute('aria-selected', 'true'); -} +}; -Select.prototype.updateMenuState = function(open, callFocus = true) { +Select.prototype.updateMenuState = function (open, callFocus = true) { if (this.open === open) { return; } @@ -352,21 +359,35 @@ Select.prototype.updateMenuState = function(open, callFocus = true) { // update aria-expanded and styles this.comboEl.setAttribute('aria-expanded', `${open}`); open ? this.el.classList.add('open') : this.el.classList.remove('open'); - + // update activedescendant const activeID = open ? `${this.idBase}-${this.activeIndex}` : ''; this.comboEl.setAttribute('aria-activedescendant', activeID); // move focus back to the combobox, if needed callFocus && this.comboEl.focus(); -} +}; // init select window.addEventListener('load', function () { - const options = ['Choose a Fruit', 'Apple', 'Banana', 'Blueberry', 'Boysenberry', 'Cherry', 'Cranberry', 'Durian', 'Eggplant', 'Fig', 'Grape', 'Guava', 'Huckleberry']; + const options = [ + 'Choose a Fruit', + 'Apple', + 'Banana', + 'Blueberry', + 'Boysenberry', + 'Cherry', + 'Cranberry', + 'Durian', + 'Eggplant', + 'Fig', + 'Grape', + 'Guava', + 'Huckleberry', + ]; const selectEls = document.querySelectorAll('.js-select'); selectEls.forEach((el) => { new Select(el, options); }); -}); \ No newline at end of file +}); diff --git a/examples/dialog-modal/js/alertdialog.js b/examples/dialog-modal/js/alertdialog.js index 59683874b3..18b1ed8c02 100644 --- a/examples/dialog-modal/js/alertdialog.js +++ b/examples/dialog-modal/js/alertdialog.js @@ -17,11 +17,15 @@ aria.Utils.triggerAlert = function (alertEl, content) { try { alertEl.textContent = content || null; alertEl.classList.remove('hidden'); - alertEl.addEventListener('transitionend', function (e) { - if (!this.classList.contains('active')) { - this.classList.add('hidden'); - } - }, true); + alertEl.addEventListener( + 'transitionend', + function (e) { + if (!this.classList.contains('active')) { + this.classList.add('hidden'); + } + }, + true + ); setTimeout(function () { alertEl.classList.add('active'); }, 1); @@ -29,14 +33,13 @@ aria.Utils.triggerAlert = function (alertEl, content) { alertEl.classList.remove('active'); resolve(); }, 3000); - } - catch (err) { + } catch (err) { reject(err); } }); }; -aria.Notes = function Notes (notesId, saveId, discardId, localStorageKey) { +aria.Notes = function Notes(notesId, saveId, discardId, localStorageKey) { this.notesInput = document.getElementById(notesId); this.saveBtn = document.getElementById(saveId); this.discardBtn = document.getElementById(discardId); @@ -45,13 +48,15 @@ aria.Notes = function Notes (notesId, saveId, discardId, localStorageKey) { Object.defineProperty(this, 'controls', { get: function () { - return document.querySelectorAll('[aria-controls=' + this.notesInput.id + ']'); - } + return document.querySelectorAll( + '[aria-controls=' + this.notesInput.id + ']' + ); + }, }); Object.defineProperty(this, 'hasContent', { get: function () { return this.notesInput.value.length > 0; - } + }, }); Object.defineProperty(this, 'savedValue', { get: function () { @@ -59,12 +64,12 @@ aria.Notes = function Notes (notesId, saveId, discardId, localStorageKey) { }, set: function (val) { this.save(val); - } + }, }); Object.defineProperty(this, 'isCurrent', { get: function () { return this.notesInput.value === this.savedValue; - } + }, }); Object.defineProperty(this, 'oninput', { get: function () { @@ -75,7 +80,7 @@ aria.Notes = function Notes (notesId, saveId, discardId, localStorageKey) { throw new TypeError('oninput must be a function'); } this.notesInput.addEventListener('input', fn); - } + }, }); if (this.saveBtn && this.discardBtn) { @@ -87,7 +92,10 @@ aria.Notes.prototype.save = function (val) { if (this.alert && !this.isCurrent) { aria.Utils.triggerAlert(this.alert, 'Saved'); } - localStorage.setItem(this.localStorageKey, JSON.stringify(val || this.notesInput.value)); + localStorage.setItem( + this.localStorageKey, + JSON.stringify(val || this.notesInput.value) + ); aria.Utils.disableCtrl(this.saveBtn); }; @@ -114,8 +122,7 @@ aria.Notes.prototype.enableCtrls = function () { aria.Notes.prototype.toggleCtrls = function () { if (this.hasContent) { this.enableCtrls(); - } - else { + } else { this.disableCtrls(); } }; @@ -124,16 +131,15 @@ aria.Notes.prototype.toggleCurrent = function () { if (!this.isCurrent) { this.notesInput.classList.remove('can-save'); aria.Utils.enableCtrl(this.saveBtn); - } - else { + } else { this.notesInput.classList.add('can-save'); aria.Utils.disableCtrl(this.saveBtn); } }; aria.Notes.prototype.keydownHandler = function (e) { - var mod = (navigator.userAgent.includes('Mac')) ? e.metaKey : e.ctrlKey; - if (e.key === 's' & mod) { + var mod = navigator.userAgent.includes('Mac') ? e.metaKey : e.ctrlKey; + if ((e.key === 's') & mod) { e.preventDefault(); this.save(); } @@ -153,7 +159,7 @@ aria.Notes.prototype.init = function () { }; /** initialization */ -document.addEventListener('DOMContentLoaded', function initAlertDialog () { +document.addEventListener('DOMContentLoaded', function initAlertDialog() { var notes = new aria.Notes('notes', 'notes_save', 'notes_confirm'); notes.alert = document.getElementById('alert_toast'); @@ -163,7 +169,9 @@ document.addEventListener('DOMContentLoaded', function initAlertDialog () { }; window.openAlertDialog = function (dialogId, triggerBtn, focusFirst) { - var target = document.getElementById(triggerBtn.getAttribute('aria-controls')); + var target = document.getElementById( + triggerBtn.getAttribute('aria-controls') + ); var dialog = document.getElementById(dialogId); var desc = document.getElementById(dialog.getAttribute('aria-describedby')); var wordCount = document.getElementById('word_count'); @@ -173,8 +181,8 @@ document.addEventListener('DOMContentLoaded', function initAlertDialog () { desc.appendChild(wordCount); } var count = target.value.split(/\s/).length; - var frag = (count > 1) ? 'words' : 'word'; - wordCount.textContent = count + ' ' + frag + ' will be deleted.'; + var frag = count > 1 ? 'words' : 'word'; + wordCount.textContent = count + ' ' + frag + ' will be deleted.'; openDialog(dialogId, target, focusFirst); }; }); diff --git a/examples/dialog-modal/js/datepicker-dialog.js b/examples/dialog-modal/js/datepicker-dialog.js index 6040886c4d..8470f3e5e1 100644 --- a/examples/dialog-modal/js/datepicker-dialog.js +++ b/examples/dialog-modal/js/datepicker-dialog.js @@ -1,774 +1,822 @@ -/* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -* -* File: DatePickerDialog.js -*/ - -'use strict'; - -var DatePickerDialog = function (cdp) { - this.buttonLabelChoose = 'Choose Date'; - this.buttonLabelChange = 'Change Date'; - this.dayLabels = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']; - this.monthLabels = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']; - - this.messageCursorKeys = 'Cursor keys can navigate dates'; - this.lastMessage = ''; - - this.textboxNode = cdp.querySelector('input[type="text"'); - this.buttonNode = cdp.querySelector('.group button'); - this.dialogNode = cdp.querySelector('[role="dialog"]'); - this.messageNode = this.dialogNode.querySelector('.dialog-message'); - - this.monthYearNode = this.dialogNode.querySelector('.month-year'); - - this.prevYearNode = this.dialogNode.querySelector('.prev-year'); - this.prevMonthNode = this.dialogNode.querySelector('.prev-month'); - this.nextMonthNode = this.dialogNode.querySelector('.next-month'); - this.nextYearNode = this.dialogNode.querySelector('.next-year'); - - this.okButtonNode = this.dialogNode.querySelector('button[value="ok"]'); - this.cancelButtonNode = this.dialogNode.querySelector('button[value="cancel"]'); - - this.tbodyNode = this.dialogNode.querySelector('table.dates tbody'); - - this.lastRowNode = null; - - this.days = []; - - this.focusDay = new Date(); - this.selectedDay = new Date(0,0,1); - - this.isMouseDownOnBackground = false; - - this.init(); - -}; - -DatePickerDialog.prototype.init = function () { - - this.textboxNode.addEventListener('blur', this.setDateForButtonLabel.bind(this)); - - this.buttonNode.addEventListener('keydown', this.handleButtonKeydown.bind(this)); - this.buttonNode.addEventListener('click', this.handleButtonClick.bind(this)); - - this.okButtonNode.addEventListener('click', this.handleOkButton.bind(this)); - this.okButtonNode.addEventListener('keydown', this.handleOkButton.bind(this)); - - this.cancelButtonNode.addEventListener('click', this.handleCancelButton.bind(this)); - this.cancelButtonNode.addEventListener('keydown', this.handleCancelButton.bind(this)); - - this.prevMonthNode.addEventListener('click', this.handlePreviousMonthButton.bind(this)); - this.nextMonthNode.addEventListener('click', this.handleNextMonthButton.bind(this)); - this.prevYearNode.addEventListener('click', this.handlePreviousYearButton.bind(this)); - this.nextYearNode.addEventListener('click', this.handleNextYearButton.bind(this)); - - this.prevMonthNode.addEventListener('keydown', this.handlePreviousMonthButton.bind(this)); - this.nextMonthNode.addEventListener('keydown', this.handleNextMonthButton.bind(this)); - this.prevYearNode.addEventListener('keydown', this.handlePreviousYearButton.bind(this)); - this.nextYearNode.addEventListener('keydown', this.handleNextYearButton.bind(this)); - - document.body.addEventListener('mouseup', this.handleBackgroundMouseUp.bind(this), true); - - // Create Grid of Dates - - this.tbodyNode.innerHTML = ''; - for (var i = 0; i < 6; i++) { - var row = this.tbodyNode.insertRow(i); - this.lastRowNode = row; - for (var j = 0; j < 7; j++) { - var cell = document.createElement('td'); - - cell.tabIndex = -1; - cell.addEventListener('click', this.handleDayClick.bind(this)); - cell.addEventListener('keydown', this.handleDayKeyDown.bind(this)); - cell.addEventListener('focus', this.handleDayFocus.bind(this)); - - cell.textContent = '-1'; - - row.appendChild(cell); - this.days.push(cell); - } - } - - this.updateGrid(); - this.close(false); - this.setDateForButtonLabel(); -}; - -DatePickerDialog.prototype.isSameDay = function (day1, day2) { - return (day1.getFullYear() == day2.getFullYear()) && - (day1.getMonth() == day2.getMonth()) && - (day1.getDate() == day2.getDate()); -}; - -DatePickerDialog.prototype.isNotSameMonth = function (day1, day2) { - return (day1.getFullYear() != day2.getFullYear()) || - (day1.getMonth() != day2.getMonth()); -}; - -DatePickerDialog.prototype.updateGrid = function () { - - var flag; - var fd = this.focusDay; - - this.monthYearNode.textContent = this.monthLabels[fd.getMonth()] + ' ' + fd.getFullYear(); - - var firstDayOfMonth = new Date(fd.getFullYear(), fd.getMonth(), 1); - var dayOfWeek = firstDayOfMonth.getDay(); - - firstDayOfMonth.setDate(firstDayOfMonth.getDate() - dayOfWeek); - - var d = new Date(firstDayOfMonth); - - for (var i = 0; i < this.days.length; i++) { - flag = d.getMonth() != fd.getMonth(); - this.updateDate(this.days[i], flag, d, this.isSameDay(d, this.selectedDay)); - d.setDate(d.getDate() + 1); - - // Hide last row if all dates are disabled (e.g. in next month) - if (i === 35) { - if (flag) { - this.lastRowNode.style.visibility = 'hidden'; - } - else { - this.lastRowNode.style.visibility = 'visible'; - } - } - } -}; - -DatePickerDialog.prototype.updateDate = function (domNode, disable, day, selected) { - - var d = day.getDate().toString(); - if (day.getDate() <= 9) { - d = '0' + d; - } - - var m = day.getMonth() + 1; - if (day.getMonth() < 9) { - m = '0' + m; - } - - domNode.tabIndex = -1; - domNode.removeAttribute('aria-selected'); - domNode.setAttribute('data-date', day.getFullYear() + '-' + m + '-' + d); - - if (disable) { - domNode.classList.add('disabled'); - domNode.textContent = ''; - } - else { - domNode.classList.remove('disabled'); - domNode.textContent = day.getDate(); - if (selected) { - domNode.setAttribute('aria-selected', 'true'); - domNode.tabIndex = 0; - } - } -}; - -DatePickerDialog.prototype.moveFocusToDay = function (day) { - var d = this.focusDay; - - this.focusDay = day; - - if ((d.getMonth() != this.focusDay.getMonth()) || - (d.getYear() != this.focusDay.getYear())) { - this.updateGrid(); - } - this.setFocusDay(); -}; - -DatePickerDialog.prototype.setFocusDay = function (flag) { - - if (typeof flag !== 'boolean') { - flag = true; - } - - for (var i = 0; i < this.days.length; i++) { - var dayNode = this.days[i]; - var day = this.getDayFromDataDateAttribute(dayNode); - - dayNode.tabIndex = -1; - if (this.isSameDay(day, this.focusDay)) { - dayNode.tabIndex = 0; - if (flag) { - dayNode.focus(); - } - } - } -}; - -DatePickerDialog.prototype.open = function () { - this.dialogNode.style.display = 'block'; - this.dialogNode.style.zIndex = 2; - - this.getDateFromTextbox(); - this.updateGrid(); -}; - -DatePickerDialog.prototype.isOpen = function () { - return window.getComputedStyle(this.dialogNode).display !== 'none'; -}; - -DatePickerDialog.prototype.close = function (flag) { - if (typeof flag !== 'boolean') { - // Default is to move focus to combobox - flag = true; - } - - this.setMessage(''); - this.dialogNode.style.display = 'none'; - - if (flag) { - this.buttonNode.focus(); - } -}; - -DatePickerDialog.prototype.moveToNextYear = function () { - this.focusDay.setFullYear(this.focusDay.getFullYear() + 1); - this.updateGrid(); -}; - -DatePickerDialog.prototype.moveToPreviousYear = function () { - this.focusDay.setFullYear(this.focusDay.getFullYear() - 1); - this.updateGrid(); -}; - -DatePickerDialog.prototype.moveToNextMonth = function () { - this.focusDay.setMonth(this.focusDay.getMonth() + 1); - this.updateGrid(); -}; - -DatePickerDialog.prototype.moveToPreviousMonth = function () { - this.focusDay.setMonth(this.focusDay.getMonth() - 1); - this.updateGrid(); -}; - -DatePickerDialog.prototype.moveFocusToNextDay = function () { - var d = new Date(this.focusDay); - d.setDate(d.getDate() + 1); - this.moveFocusToDay(d); -}; - -DatePickerDialog.prototype.moveFocusToNextWeek = function () { - var d = new Date(this.focusDay); - d.setDate(d.getDate() + 7); - this.moveFocusToDay(d); -}; - -DatePickerDialog.prototype.moveFocusToPreviousDay = function () { - var d = new Date(this.focusDay); - d.setDate(d.getDate() - 1); - this.moveFocusToDay(d); -}; - -DatePickerDialog.prototype.moveFocusToPreviousWeek = function () { - var d = new Date(this.focusDay); - d.setDate(d.getDate() - 7); - this.moveFocusToDay(d); -}; - -DatePickerDialog.prototype.moveFocusToFirstDayOfWeek = function () { - var d = new Date(this.focusDay); - d.setDate(d.getDate() - d.getDay()); - this.moveFocusToDay(d); -}; - -DatePickerDialog.prototype.moveFocusToLastDayOfWeek = function () { - var d = new Date(this.focusDay); - d.setDate(d.getDate() + (6 - d.getDay())); - this.moveFocusToDay(d); -}; - -// Day methods - -DatePickerDialog.prototype.isDayDisabled = function (domNode) { - return domNode.classList.contains('disabled'); -}; - -DatePickerDialog.prototype.getDayFromDataDateAttribute = function (domNode) { - var parts = domNode.getAttribute('data-date').split('-'); - return new Date(parts[0], parseInt(parts[1])-1, parts[2]); -}; -// Textbox methods - -DatePickerDialog.prototype.setTextboxDate = function (domNode) { - - var d = this.focusDay; - - if (domNode) { - d = this.getDayFromDataDateAttribute(domNode); - // updated aria-selected - this.days.forEach(day => day === domNode ? day.setAttribute('aria-selected', 'true') : day.removeAttribute('aria-selected')); - } - - this.textboxNode.value = (d.getMonth() + 1) + '/' + d.getDate() + '/' + d.getFullYear(); - this.setDateForButtonLabel(); - -}; - -DatePickerDialog.prototype.getDateFromTextbox = function () { - - var parts = this.textboxNode.value.split('/'); - var month = parseInt(parts[0]); - var day = parseInt(parts[1]); - var year = parseInt(parts[2]); - - if ((parts.length === 3) && - Number.isInteger(month) && - Number.isInteger(day) && - Number.isInteger(year)) { - if (year < 100) { - year = 2000 + year; - } - this.focusDay = new Date(year, month-1, day); - this.selectedDay = new Date(this.focusDay); - } - else { - // If not a valid date (MM/DD/YY) initialize with todays date - this.focusDay = new Date(); - this.selectedDay = new Date(0,0,1); - } - -}; - -DatePickerDialog.prototype.setDateForButtonLabel = function () { - - var parts = this.textboxNode.value.split('/'); - - if ((parts.length === 3) && - Number.isInteger(parseInt(parts[0])) && - Number.isInteger(parseInt(parts[1])) && - Number.isInteger(parseInt(parts[2]))) { - var day = new Date(parseInt(parts[2]), parseInt(parts[0]) - 1, parseInt(parts[1])); - - var label = this.buttonLabelChange; - label += ', ' + this.dayLabels[day.getDay()]; - label += ' ' + this.monthLabels[day.getMonth()]; - label += ' ' + (day.getDate()); - label += ', ' + day.getFullYear(); - this.buttonNode.setAttribute('aria-label', label); - } - else { - // If not a valid date, initialize with "Choose Date" - this.buttonNode.setAttribute('aria-label', this.buttonLabelChoose); - } -}; - -DatePickerDialog.prototype.setMessage = function (str) { - - function setMessageDelayed () { - this.messageNode.textContent = str; - } - - if (str !== this.lastMessage) { - setTimeout(setMessageDelayed.bind(this), 200); - this.lastMessage = str; - } -}; - -// Event handlers - - -DatePickerDialog.prototype.handleOkButton = function (event) { - var flag = false; - - switch (event.type) { - case 'keydown': - - switch (event.key) { - case "Tab": - if (!event.shiftKey) { - this.prevYearNode.focus(); - flag = true; - } - break; - - case "Esc": - case "Escape": - this.close(); - flag = true; - break; - - default: - break; - - } - break; - - case 'click': - this.setTextboxDate(); - this.close(); - flag = true; - break; - - default: - break; - } - - if (flag) { - event.stopPropagation(); - event.preventDefault(); - } -}; - -DatePickerDialog.prototype.handleCancelButton = function (event) { - var flag = false; - - switch (event.type) { - case 'keydown': - - switch (event.key) { - - case "Esc": - case "Escape": - this.close(); - flag = true; - break; - - default: - break; - - } - break; - - case 'click': - this.close(); - flag = true; - break; - - default: - break; - } - - if (flag) { - event.stopPropagation(); - event.preventDefault(); - } -}; - -DatePickerDialog.prototype.handleNextYearButton = function (event) { - var flag = false; - - switch (event.type) { - - case 'keydown': - - switch (event.key) { - case "Esc": - case "Escape": - this.close(); - flag = true; - break; - - case "Enter": - this.moveToNextYear(); - this.setFocusDay(false); - flag = true; - break; - } - - break; - - case 'click': - this.moveToNextYear(); - this.setFocusDay(false); - break; - - default: - break; - } - - if (flag) { - event.stopPropagation(); - event.preventDefault(); - } -}; - -DatePickerDialog.prototype.handlePreviousYearButton = function (event) { - var flag = false; - - switch (event.type) { - - case 'keydown': - - switch (event.key) { - - case "Enter": - this.moveToPreviousYear(); - this.setFocusDay(false); - flag = true; - break; - - case "Tab": - if (event.shiftKey) { - this.okButtonNode.focus(); - flag = true; - } - break; - - case "Esc": - case "Escape": - this.close(); - flag = true; - break; - - default: - break; - } - - break; - - case 'click': - this.moveToPreviousYear(); - this.setFocusDay(false); - break; - - default: - break; - } - - if (flag) { - event.stopPropagation(); - event.preventDefault(); - } -}; - -DatePickerDialog.prototype.handleNextMonthButton = function (event) { - var flag = false; - - switch (event.type) { - - case 'keydown': - - switch (event.key) { - case "Esc": - case "Escape": - this.close(); - flag = true; - break; - - case "Enter": - this.moveToNextMonth(); - this.setFocusDay(false); - flag = true; - break; - } - - break; - - case 'click': - this.moveToNextMonth(); - this.setFocusDay(false); - break; - - default: - break; - } - - if (flag) { - event.stopPropagation(); - event.preventDefault(); - } -}; - -DatePickerDialog.prototype.handlePreviousMonthButton = function (event) { - var flag = false; - - switch (event.type) { - - case 'keydown': - - switch (event.key) { - case "Esc": - case "Escape": - this.close(); - flag = true; - break; - - case "Enter": - this.moveToPreviousMonth(); - this.setFocusDay(false); - flag = true; - break; - } - - break; - - case 'click': - this.moveToPreviousMonth(); - this.setFocusDay(false); - flag = true; - break; - - default: - break; - } - - if (flag) { - event.stopPropagation(); - event.preventDefault(); - } -}; - -DatePickerDialog.prototype.handleDayKeyDown = function (event) { - var flag = false; - - switch (event.key) { - - case "Esc": - case "Escape": - this.close(); - break; - - case " ": - this.setTextboxDate(event.currentTarget); - flag = true; - break; - - case "Enter": - this.setTextboxDate(event.currentTarget); - this.close(); - flag = true; - break; - - case "Tab": - this.cancelButtonNode.focus(); - if (event.shiftKey) { - this.nextYearNode.focus(); - } - this.setMessage(''); - flag = true; - break; - - case "Right": - case "ArrowRight": - this.moveFocusToNextDay(); - flag = true; - break; - - case "Left": - case "ArrowLeft": - this.moveFocusToPreviousDay(); - flag = true; - break; - - case "Down": - case "ArrowDown": - this.moveFocusToNextWeek(); - flag = true; - break; - - case "Up": - case "ArrowUp": - this.moveFocusToPreviousWeek(); - flag = true; - break; - - case "PageUp": - if (event.shiftKey) { - this.moveToPreviousYear(); - } - else { - this.moveToPreviousMonth(); - } - this.setFocusDay(); - flag = true; - break; - - case "PageDown": - if (event.shiftKey) { - this.moveToNextYear(); - } - else { - this.moveToNextMonth(); - } - this.setFocusDay(); - flag = true; - break; - - case "Home": - this.moveFocusToFirstDayOfWeek(); - flag = true; - break; - - case "End": - this.moveFocusToLastDayOfWeek(); - flag = true; - break; - } - - if (flag) { - event.stopPropagation(); - event.preventDefault(); - } -}; - -DatePickerDialog.prototype.handleDayClick = function (event) { - - if (!this.isDayDisabled(event.currentTarget)) { - this.setTextboxDate(event.currentTarget); - this.close(); - } - - event.stopPropagation(); - event.preventDefault(); - -}; - -DatePickerDialog.prototype.handleDayFocus = function () { - this.setMessage(this.messageCursorKeys); -}; - -DatePickerDialog.prototype.handleButtonKeydown = function (event) { - - if ((event.key === 'Enter') || - (event.key === ' ')) { - this.open(); - this.setFocusDay(); - - event.stopPropagation(); - event.preventDefault(); - } - -}; - -DatePickerDialog.prototype.handleButtonClick = function (event) { - if (this.isOpen()) { - this.close(); - } - else { - this.open(); - this.setFocusDay(); - } - - event.stopPropagation(); - event.preventDefault(); -}; - -DatePickerDialog.prototype.handleBackgroundMouseUp = function (event) { - if (!this.buttonNode.contains(event.target) && - !this.dialogNode.contains(event.target)) { - - if (this.isOpen()) { - this.close(false); - event.stopPropagation(); - event.preventDefault(); - } - } -}; - -// Initialize menu button date picker - -window.addEventListener('load' , function () { - - var datePickers = document.querySelectorAll('.datepicker'); - - datePickers.forEach(function (dp) { - new DatePickerDialog(dp); - }); - -}); +/* + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * File: DatePickerDialog.js + */ + +'use strict'; + +var DatePickerDialog = function (cdp) { + this.buttonLabelChoose = 'Choose Date'; + this.buttonLabelChange = 'Change Date'; + this.dayLabels = [ + 'Sunday', + 'Monday', + 'Tuesday', + 'Wednesday', + 'Thursday', + 'Friday', + 'Saturday', + ]; + this.monthLabels = [ + 'January', + 'February', + 'March', + 'April', + 'May', + 'June', + 'July', + 'August', + 'September', + 'October', + 'November', + 'December', + ]; + + this.messageCursorKeys = 'Cursor keys can navigate dates'; + this.lastMessage = ''; + + this.textboxNode = cdp.querySelector('input[type="text"'); + this.buttonNode = cdp.querySelector('.group button'); + this.dialogNode = cdp.querySelector('[role="dialog"]'); + this.messageNode = this.dialogNode.querySelector('.dialog-message'); + + this.monthYearNode = this.dialogNode.querySelector('.month-year'); + + this.prevYearNode = this.dialogNode.querySelector('.prev-year'); + this.prevMonthNode = this.dialogNode.querySelector('.prev-month'); + this.nextMonthNode = this.dialogNode.querySelector('.next-month'); + this.nextYearNode = this.dialogNode.querySelector('.next-year'); + + this.okButtonNode = this.dialogNode.querySelector('button[value="ok"]'); + this.cancelButtonNode = this.dialogNode.querySelector( + 'button[value="cancel"]' + ); + + this.tbodyNode = this.dialogNode.querySelector('table.dates tbody'); + + this.lastRowNode = null; + + this.days = []; + + this.focusDay = new Date(); + this.selectedDay = new Date(0, 0, 1); + + this.isMouseDownOnBackground = false; + + this.init(); +}; + +DatePickerDialog.prototype.init = function () { + this.textboxNode.addEventListener( + 'blur', + this.setDateForButtonLabel.bind(this) + ); + + this.buttonNode.addEventListener( + 'keydown', + this.handleButtonKeydown.bind(this) + ); + this.buttonNode.addEventListener('click', this.handleButtonClick.bind(this)); + + this.okButtonNode.addEventListener('click', this.handleOkButton.bind(this)); + this.okButtonNode.addEventListener('keydown', this.handleOkButton.bind(this)); + + this.cancelButtonNode.addEventListener( + 'click', + this.handleCancelButton.bind(this) + ); + this.cancelButtonNode.addEventListener( + 'keydown', + this.handleCancelButton.bind(this) + ); + + this.prevMonthNode.addEventListener( + 'click', + this.handlePreviousMonthButton.bind(this) + ); + this.nextMonthNode.addEventListener( + 'click', + this.handleNextMonthButton.bind(this) + ); + this.prevYearNode.addEventListener( + 'click', + this.handlePreviousYearButton.bind(this) + ); + this.nextYearNode.addEventListener( + 'click', + this.handleNextYearButton.bind(this) + ); + + this.prevMonthNode.addEventListener( + 'keydown', + this.handlePreviousMonthButton.bind(this) + ); + this.nextMonthNode.addEventListener( + 'keydown', + this.handleNextMonthButton.bind(this) + ); + this.prevYearNode.addEventListener( + 'keydown', + this.handlePreviousYearButton.bind(this) + ); + this.nextYearNode.addEventListener( + 'keydown', + this.handleNextYearButton.bind(this) + ); + + document.body.addEventListener( + 'mouseup', + this.handleBackgroundMouseUp.bind(this), + true + ); + + // Create Grid of Dates + + this.tbodyNode.innerHTML = ''; + for (var i = 0; i < 6; i++) { + var row = this.tbodyNode.insertRow(i); + this.lastRowNode = row; + for (var j = 0; j < 7; j++) { + var cell = document.createElement('td'); + + cell.tabIndex = -1; + cell.addEventListener('click', this.handleDayClick.bind(this)); + cell.addEventListener('keydown', this.handleDayKeyDown.bind(this)); + cell.addEventListener('focus', this.handleDayFocus.bind(this)); + + cell.textContent = '-1'; + + row.appendChild(cell); + this.days.push(cell); + } + } + + this.updateGrid(); + this.close(false); + this.setDateForButtonLabel(); +}; + +DatePickerDialog.prototype.isSameDay = function (day1, day2) { + return ( + day1.getFullYear() == day2.getFullYear() && + day1.getMonth() == day2.getMonth() && + day1.getDate() == day2.getDate() + ); +}; + +DatePickerDialog.prototype.isNotSameMonth = function (day1, day2) { + return ( + day1.getFullYear() != day2.getFullYear() || + day1.getMonth() != day2.getMonth() + ); +}; + +DatePickerDialog.prototype.updateGrid = function () { + var flag; + var fd = this.focusDay; + + this.monthYearNode.textContent = + this.monthLabels[fd.getMonth()] + ' ' + fd.getFullYear(); + + var firstDayOfMonth = new Date(fd.getFullYear(), fd.getMonth(), 1); + var dayOfWeek = firstDayOfMonth.getDay(); + + firstDayOfMonth.setDate(firstDayOfMonth.getDate() - dayOfWeek); + + var d = new Date(firstDayOfMonth); + + for (var i = 0; i < this.days.length; i++) { + flag = d.getMonth() != fd.getMonth(); + this.updateDate(this.days[i], flag, d, this.isSameDay(d, this.selectedDay)); + d.setDate(d.getDate() + 1); + + // Hide last row if all dates are disabled (e.g. in next month) + if (i === 35) { + if (flag) { + this.lastRowNode.style.visibility = 'hidden'; + } else { + this.lastRowNode.style.visibility = 'visible'; + } + } + } +}; + +DatePickerDialog.prototype.updateDate = function ( + domNode, + disable, + day, + selected +) { + var d = day.getDate().toString(); + if (day.getDate() <= 9) { + d = '0' + d; + } + + var m = day.getMonth() + 1; + if (day.getMonth() < 9) { + m = '0' + m; + } + + domNode.tabIndex = -1; + domNode.removeAttribute('aria-selected'); + domNode.setAttribute('data-date', day.getFullYear() + '-' + m + '-' + d); + + if (disable) { + domNode.classList.add('disabled'); + domNode.textContent = ''; + } else { + domNode.classList.remove('disabled'); + domNode.textContent = day.getDate(); + if (selected) { + domNode.setAttribute('aria-selected', 'true'); + domNode.tabIndex = 0; + } + } +}; + +DatePickerDialog.prototype.moveFocusToDay = function (day) { + var d = this.focusDay; + + this.focusDay = day; + + if ( + d.getMonth() != this.focusDay.getMonth() || + d.getYear() != this.focusDay.getYear() + ) { + this.updateGrid(); + } + this.setFocusDay(); +}; + +DatePickerDialog.prototype.setFocusDay = function (flag) { + if (typeof flag !== 'boolean') { + flag = true; + } + + for (var i = 0; i < this.days.length; i++) { + var dayNode = this.days[i]; + var day = this.getDayFromDataDateAttribute(dayNode); + + dayNode.tabIndex = -1; + if (this.isSameDay(day, this.focusDay)) { + dayNode.tabIndex = 0; + if (flag) { + dayNode.focus(); + } + } + } +}; + +DatePickerDialog.prototype.open = function () { + this.dialogNode.style.display = 'block'; + this.dialogNode.style.zIndex = 2; + + this.getDateFromTextbox(); + this.updateGrid(); +}; + +DatePickerDialog.prototype.isOpen = function () { + return window.getComputedStyle(this.dialogNode).display !== 'none'; +}; + +DatePickerDialog.prototype.close = function (flag) { + if (typeof flag !== 'boolean') { + // Default is to move focus to combobox + flag = true; + } + + this.setMessage(''); + this.dialogNode.style.display = 'none'; + + if (flag) { + this.buttonNode.focus(); + } +}; + +DatePickerDialog.prototype.moveToNextYear = function () { + this.focusDay.setFullYear(this.focusDay.getFullYear() + 1); + this.updateGrid(); +}; + +DatePickerDialog.prototype.moveToPreviousYear = function () { + this.focusDay.setFullYear(this.focusDay.getFullYear() - 1); + this.updateGrid(); +}; + +DatePickerDialog.prototype.moveToNextMonth = function () { + this.focusDay.setMonth(this.focusDay.getMonth() + 1); + this.updateGrid(); +}; + +DatePickerDialog.prototype.moveToPreviousMonth = function () { + this.focusDay.setMonth(this.focusDay.getMonth() - 1); + this.updateGrid(); +}; + +DatePickerDialog.prototype.moveFocusToNextDay = function () { + var d = new Date(this.focusDay); + d.setDate(d.getDate() + 1); + this.moveFocusToDay(d); +}; + +DatePickerDialog.prototype.moveFocusToNextWeek = function () { + var d = new Date(this.focusDay); + d.setDate(d.getDate() + 7); + this.moveFocusToDay(d); +}; + +DatePickerDialog.prototype.moveFocusToPreviousDay = function () { + var d = new Date(this.focusDay); + d.setDate(d.getDate() - 1); + this.moveFocusToDay(d); +}; + +DatePickerDialog.prototype.moveFocusToPreviousWeek = function () { + var d = new Date(this.focusDay); + d.setDate(d.getDate() - 7); + this.moveFocusToDay(d); +}; + +DatePickerDialog.prototype.moveFocusToFirstDayOfWeek = function () { + var d = new Date(this.focusDay); + d.setDate(d.getDate() - d.getDay()); + this.moveFocusToDay(d); +}; + +DatePickerDialog.prototype.moveFocusToLastDayOfWeek = function () { + var d = new Date(this.focusDay); + d.setDate(d.getDate() + (6 - d.getDay())); + this.moveFocusToDay(d); +}; + +// Day methods + +DatePickerDialog.prototype.isDayDisabled = function (domNode) { + return domNode.classList.contains('disabled'); +}; + +DatePickerDialog.prototype.getDayFromDataDateAttribute = function (domNode) { + var parts = domNode.getAttribute('data-date').split('-'); + return new Date(parts[0], parseInt(parts[1]) - 1, parts[2]); +}; +// Textbox methods + +DatePickerDialog.prototype.setTextboxDate = function (domNode) { + var d = this.focusDay; + + if (domNode) { + d = this.getDayFromDataDateAttribute(domNode); + // updated aria-selected + this.days.forEach((day) => + day === domNode + ? day.setAttribute('aria-selected', 'true') + : day.removeAttribute('aria-selected') + ); + } + + this.textboxNode.value = + d.getMonth() + 1 + '/' + d.getDate() + '/' + d.getFullYear(); + this.setDateForButtonLabel(); +}; + +DatePickerDialog.prototype.getDateFromTextbox = function () { + var parts = this.textboxNode.value.split('/'); + var month = parseInt(parts[0]); + var day = parseInt(parts[1]); + var year = parseInt(parts[2]); + + if ( + parts.length === 3 && + Number.isInteger(month) && + Number.isInteger(day) && + Number.isInteger(year) + ) { + if (year < 100) { + year = 2000 + year; + } + this.focusDay = new Date(year, month - 1, day); + this.selectedDay = new Date(this.focusDay); + } else { + // If not a valid date (MM/DD/YY) initialize with todays date + this.focusDay = new Date(); + this.selectedDay = new Date(0, 0, 1); + } +}; + +DatePickerDialog.prototype.setDateForButtonLabel = function () { + var parts = this.textboxNode.value.split('/'); + + if ( + parts.length === 3 && + Number.isInteger(parseInt(parts[0])) && + Number.isInteger(parseInt(parts[1])) && + Number.isInteger(parseInt(parts[2])) + ) { + var day = new Date( + parseInt(parts[2]), + parseInt(parts[0]) - 1, + parseInt(parts[1]) + ); + + var label = this.buttonLabelChange; + label += ', ' + this.dayLabels[day.getDay()]; + label += ' ' + this.monthLabels[day.getMonth()]; + label += ' ' + day.getDate(); + label += ', ' + day.getFullYear(); + this.buttonNode.setAttribute('aria-label', label); + } else { + // If not a valid date, initialize with "Choose Date" + this.buttonNode.setAttribute('aria-label', this.buttonLabelChoose); + } +}; + +DatePickerDialog.prototype.setMessage = function (str) { + function setMessageDelayed() { + this.messageNode.textContent = str; + } + + if (str !== this.lastMessage) { + setTimeout(setMessageDelayed.bind(this), 200); + this.lastMessage = str; + } +}; + +// Event handlers + +DatePickerDialog.prototype.handleOkButton = function (event) { + var flag = false; + + switch (event.type) { + case 'keydown': + switch (event.key) { + case 'Tab': + if (!event.shiftKey) { + this.prevYearNode.focus(); + flag = true; + } + break; + + case 'Esc': + case 'Escape': + this.close(); + flag = true; + break; + + default: + break; + } + break; + + case 'click': + this.setTextboxDate(); + this.close(); + flag = true; + break; + + default: + break; + } + + if (flag) { + event.stopPropagation(); + event.preventDefault(); + } +}; + +DatePickerDialog.prototype.handleCancelButton = function (event) { + var flag = false; + + switch (event.type) { + case 'keydown': + switch (event.key) { + case 'Esc': + case 'Escape': + this.close(); + flag = true; + break; + + default: + break; + } + break; + + case 'click': + this.close(); + flag = true; + break; + + default: + break; + } + + if (flag) { + event.stopPropagation(); + event.preventDefault(); + } +}; + +DatePickerDialog.prototype.handleNextYearButton = function (event) { + var flag = false; + + switch (event.type) { + case 'keydown': + switch (event.key) { + case 'Esc': + case 'Escape': + this.close(); + flag = true; + break; + + case 'Enter': + this.moveToNextYear(); + this.setFocusDay(false); + flag = true; + break; + } + + break; + + case 'click': + this.moveToNextYear(); + this.setFocusDay(false); + break; + + default: + break; + } + + if (flag) { + event.stopPropagation(); + event.preventDefault(); + } +}; + +DatePickerDialog.prototype.handlePreviousYearButton = function (event) { + var flag = false; + + switch (event.type) { + case 'keydown': + switch (event.key) { + case 'Enter': + this.moveToPreviousYear(); + this.setFocusDay(false); + flag = true; + break; + + case 'Tab': + if (event.shiftKey) { + this.okButtonNode.focus(); + flag = true; + } + break; + + case 'Esc': + case 'Escape': + this.close(); + flag = true; + break; + + default: + break; + } + + break; + + case 'click': + this.moveToPreviousYear(); + this.setFocusDay(false); + break; + + default: + break; + } + + if (flag) { + event.stopPropagation(); + event.preventDefault(); + } +}; + +DatePickerDialog.prototype.handleNextMonthButton = function (event) { + var flag = false; + + switch (event.type) { + case 'keydown': + switch (event.key) { + case 'Esc': + case 'Escape': + this.close(); + flag = true; + break; + + case 'Enter': + this.moveToNextMonth(); + this.setFocusDay(false); + flag = true; + break; + } + + break; + + case 'click': + this.moveToNextMonth(); + this.setFocusDay(false); + break; + + default: + break; + } + + if (flag) { + event.stopPropagation(); + event.preventDefault(); + } +}; + +DatePickerDialog.prototype.handlePreviousMonthButton = function (event) { + var flag = false; + + switch (event.type) { + case 'keydown': + switch (event.key) { + case 'Esc': + case 'Escape': + this.close(); + flag = true; + break; + + case 'Enter': + this.moveToPreviousMonth(); + this.setFocusDay(false); + flag = true; + break; + } + + break; + + case 'click': + this.moveToPreviousMonth(); + this.setFocusDay(false); + flag = true; + break; + + default: + break; + } + + if (flag) { + event.stopPropagation(); + event.preventDefault(); + } +}; + +DatePickerDialog.prototype.handleDayKeyDown = function (event) { + var flag = false; + + switch (event.key) { + case 'Esc': + case 'Escape': + this.close(); + break; + + case ' ': + this.setTextboxDate(event.currentTarget); + flag = true; + break; + + case 'Enter': + this.setTextboxDate(event.currentTarget); + this.close(); + flag = true; + break; + + case 'Tab': + this.cancelButtonNode.focus(); + if (event.shiftKey) { + this.nextYearNode.focus(); + } + this.setMessage(''); + flag = true; + break; + + case 'Right': + case 'ArrowRight': + this.moveFocusToNextDay(); + flag = true; + break; + + case 'Left': + case 'ArrowLeft': + this.moveFocusToPreviousDay(); + flag = true; + break; + + case 'Down': + case 'ArrowDown': + this.moveFocusToNextWeek(); + flag = true; + break; + + case 'Up': + case 'ArrowUp': + this.moveFocusToPreviousWeek(); + flag = true; + break; + + case 'PageUp': + if (event.shiftKey) { + this.moveToPreviousYear(); + } else { + this.moveToPreviousMonth(); + } + this.setFocusDay(); + flag = true; + break; + + case 'PageDown': + if (event.shiftKey) { + this.moveToNextYear(); + } else { + this.moveToNextMonth(); + } + this.setFocusDay(); + flag = true; + break; + + case 'Home': + this.moveFocusToFirstDayOfWeek(); + flag = true; + break; + + case 'End': + this.moveFocusToLastDayOfWeek(); + flag = true; + break; + } + + if (flag) { + event.stopPropagation(); + event.preventDefault(); + } +}; + +DatePickerDialog.prototype.handleDayClick = function (event) { + if (!this.isDayDisabled(event.currentTarget)) { + this.setTextboxDate(event.currentTarget); + this.close(); + } + + event.stopPropagation(); + event.preventDefault(); +}; + +DatePickerDialog.prototype.handleDayFocus = function () { + this.setMessage(this.messageCursorKeys); +}; + +DatePickerDialog.prototype.handleButtonKeydown = function (event) { + if (event.key === 'Enter' || event.key === ' ') { + this.open(); + this.setFocusDay(); + + event.stopPropagation(); + event.preventDefault(); + } +}; + +DatePickerDialog.prototype.handleButtonClick = function (event) { + if (this.isOpen()) { + this.close(); + } else { + this.open(); + this.setFocusDay(); + } + + event.stopPropagation(); + event.preventDefault(); +}; + +DatePickerDialog.prototype.handleBackgroundMouseUp = function (event) { + if ( + !this.buttonNode.contains(event.target) && + !this.dialogNode.contains(event.target) + ) { + if (this.isOpen()) { + this.close(false); + event.stopPropagation(); + event.preventDefault(); + } + } +}; + +// Initialize menu button date picker + +window.addEventListener('load', function () { + var datePickers = document.querySelectorAll('.datepicker'); + + datePickers.forEach(function (dp) { + new DatePickerDialog(dp); + }); +}); diff --git a/examples/dialog-modal/js/dialog.js b/examples/dialog-modal/js/dialog.js index 1dcd42a47b..0d2242e5eb 100644 --- a/examples/dialog-modal/js/dialog.js +++ b/examples/dialog-modal/js/dialog.js @@ -1,7 +1,7 @@ /* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -*/ + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + */ 'use strict'; @@ -29,8 +29,10 @@ aria.Utils = aria.Utils || {}; aria.Utils.focusFirstDescendant = function (element) { for (var i = 0; i < element.childNodes.length; i++) { var child = element.childNodes[i]; - if (aria.Utils.attemptFocus(child) || - aria.Utils.focusFirstDescendant(child)) { + if ( + aria.Utils.attemptFocus(child) || + aria.Utils.focusFirstDescendant(child) + ) { return true; } } @@ -47,8 +49,10 @@ aria.Utils = aria.Utils || {}; aria.Utils.focusLastDescendant = function (element) { for (var i = element.childNodes.length - 1; i >= 0; i--) { var child = element.childNodes[i]; - if (aria.Utils.attemptFocus(child) || - aria.Utils.focusLastDescendant(child)) { + if ( + aria.Utils.attemptFocus(child) || + aria.Utils.focusLastDescendant(child) + ) { return true; } } @@ -70,12 +74,11 @@ aria.Utils = aria.Utils || {}; aria.Utils.IgnoreUtilFocusChanges = true; try { element.focus(); - } - catch (e) { + } catch (e) { // continue regardless of error } aria.Utils.IgnoreUtilFocusChanges = false; - return (document.activeElement === element); + return document.activeElement === element; }; // end attemptFocus /* Modals can open modals. Keep track of them with this array. */ @@ -144,7 +147,8 @@ aria.Utils = aria.Utils || {}; }); if (!isDialog) { throw new Error( - 'Dialog() requires a DOM element with ARIA role of dialog or alertdialog.'); + 'Dialog() requires a DOM element with ARIA role of dialog or alertdialog.' + ); } // Wrap in an individual backdrop element if one doesn't exist @@ -153,11 +157,13 @@ aria.Utils = aria.Utils || {}; var backdropClass = 'dialog-backdrop'; if (this.dialogNode.parentNode.classList.contains(backdropClass)) { this.backdropNode = this.dialogNode.parentNode; - } - else { + } else { this.backdropNode = document.createElement('div'); this.backdropNode.className = backdropClass; - this.dialogNode.parentNode.insertBefore(this.backdropNode, this.dialogNode); + this.dialogNode.parentNode.insertBefore( + this.backdropNode, + this.dialogNode + ); this.backdropNode.appendChild(this.dialogNode); } this.backdropNode.classList.add('active'); @@ -167,22 +173,19 @@ aria.Utils = aria.Utils || {}; if (typeof focusAfterClosed === 'string') { this.focusAfterClosed = document.getElementById(focusAfterClosed); - } - else if (typeof focusAfterClosed === 'object') { + } else if (typeof focusAfterClosed === 'object') { this.focusAfterClosed = focusAfterClosed; - } - else { + } else { throw new Error( - 'the focusAfterClosed parameter is required for the aria.Dialog constructor.'); + 'the focusAfterClosed parameter is required for the aria.Dialog constructor.' + ); } if (typeof focusFirst === 'string') { this.focusFirst = document.getElementById(focusFirst); - } - else if (typeof focusFirst === 'object') { + } else if (typeof focusFirst === 'object') { this.focusFirst = focusFirst; - } - else { + } else { this.focusFirst = null; } @@ -190,12 +193,16 @@ aria.Utils = aria.Utils || {}; // While this dialog is open, we use these to make sure that focus never // leaves the document even if dialogNode is the first or last node. var preDiv = document.createElement('div'); - this.preNode = this.dialogNode.parentNode.insertBefore(preDiv, - this.dialogNode); + this.preNode = this.dialogNode.parentNode.insertBefore( + preDiv, + this.dialogNode + ); this.preNode.tabIndex = 0; var postDiv = document.createElement('div'); - this.postNode = this.dialogNode.parentNode.insertBefore(postDiv, - this.dialogNode.nextSibling); + this.postNode = this.dialogNode.parentNode.insertBefore( + postDiv, + this.dialogNode.nextSibling + ); this.postNode.tabIndex = 0; // If this modal is opening on top of one that is already open, @@ -211,8 +218,7 @@ aria.Utils = aria.Utils || {}; if (this.focusFirst) { this.focusFirst.focus(); - } - else { + } else { aria.Utils.focusFirstDescendant(this.dialogNode); } @@ -247,8 +253,7 @@ aria.Utils = aria.Utils || {}; // If a dialog was open underneath this one, restore its listeners. if (aria.OpenDialogList.length > 0) { aria.getCurrentDialog().addListeners(); - } - else { + } else { document.body.classList.remove(aria.Utils.dialogOpenClass); } }; // end close @@ -266,8 +271,11 @@ aria.Utils = aria.Utils || {}; * Optional ID or DOM node specifying where to place focus in the new dialog when it opens. * If not specified, the first focusable element will receive focus. */ - aria.Dialog.prototype.replace = function (newDialogId, newFocusAfterClosed, - newFocusFirst) { + aria.Dialog.prototype.replace = function ( + newDialogId, + newFocusAfterClosed, + newFocusFirst + ) { var closedDialog = aria.getCurrentDialog(); aria.OpenDialogList.pop(); this.removeListeners(); @@ -295,8 +303,7 @@ aria.Utils = aria.Utils || {}; var currentDialog = aria.getCurrentDialog(); if (currentDialog.dialogNode.contains(event.target)) { currentDialog.lastFocus = event.target; - } - else { + } else { aria.Utils.focusFirstDescendant(currentDialog.dialogNode); if (currentDialog.lastFocus == document.activeElement) { aria.Utils.focusLastDescendant(currentDialog.dialogNode); @@ -316,12 +323,14 @@ aria.Utils = aria.Utils || {}; } }; // end closeDialog - window.replaceDialog = function (newDialogId, newFocusAfterClosed, - newFocusFirst) { + window.replaceDialog = function ( + newDialogId, + newFocusAfterClosed, + newFocusFirst + ) { var topDialog = aria.getCurrentDialog(); if (topDialog.dialogNode.contains(document.activeElement)) { topDialog.replace(newDialogId, newFocusAfterClosed, newFocusFirst); } }; // end replaceDialog - -}()); +})(); diff --git a/examples/disclosure/js/disclosureButton.js b/examples/disclosure/js/disclosureButton.js index ab10bc986d..7cf26207f6 100644 --- a/examples/disclosure/js/disclosureButton.js +++ b/examples/disclosure/js/disclosureButton.js @@ -1,31 +1,29 @@ /* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -* -* File: ButtonExpand.js -* -* Desc: Checkbox widget that implements ARIA Authoring Practices -* for a menu of links -*/ + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * File: ButtonExpand.js + * + * Desc: Checkbox widget that implements ARIA Authoring Practices + * for a menu of links + */ 'use strict'; /* -* @constructor ButtonExpand -* -* -*/ + * @constructor ButtonExpand + * + * + */ var ButtonExpand = function (domNode) { - this.domNode = domNode; this.keyCode = Object.freeze({ - 'RETURN': 13 + RETURN: 13, }); }; ButtonExpand.prototype.init = function () { - this.controlledNode = false; var id = this.domNode.getAttribute('aria-controls'); @@ -37,52 +35,41 @@ ButtonExpand.prototype.init = function () { this.domNode.setAttribute('aria-expanded', 'false'); this.hideContent(); - this.domNode.addEventListener('keydown', this.handleKeydown.bind(this)); - this.domNode.addEventListener('click', this.handleClick.bind(this)); - this.domNode.addEventListener('focus', this.handleFocus.bind(this)); - this.domNode.addEventListener('blur', this.handleBlur.bind(this)); - + this.domNode.addEventListener('keydown', this.handleKeydown.bind(this)); + this.domNode.addEventListener('click', this.handleClick.bind(this)); + this.domNode.addEventListener('focus', this.handleFocus.bind(this)); + this.domNode.addEventListener('blur', this.handleBlur.bind(this)); }; ButtonExpand.prototype.showContent = function () { - if (this.controlledNode) { this.controlledNode.style.display = 'block'; } - }; ButtonExpand.prototype.hideContent = function () { - if (this.controlledNode) { this.controlledNode.style.display = 'none'; } - }; ButtonExpand.prototype.toggleExpand = function () { - if (this.domNode.getAttribute('aria-expanded') === 'true') { this.domNode.setAttribute('aria-expanded', 'false'); this.hideContent(); - } - else { + } else { this.domNode.setAttribute('aria-expanded', 'true'); this.showContent(); } - }; /* EVENT HANDLERS */ ButtonExpand.prototype.handleKeydown = function (event) { - console.log('[keydown]'); switch (event.keyCode) { - case this.keyCode.RETURN: - this.toggleExpand(); event.stopPropagation(); @@ -92,7 +79,6 @@ ButtonExpand.prototype.handleKeydown = function (event) { default: break; } - }; ButtonExpand.prototype.handleClick = function (event) { @@ -109,13 +95,17 @@ ButtonExpand.prototype.handleBlur = function (event) { /* Initialize Hide/Show Buttons */ -window.addEventListener('load', function (event) { - - var buttons = document.querySelectorAll('button[aria-expanded][aria-controls]'); - - for (var i = 0; i < buttons.length; i++) { - var be = new ButtonExpand(buttons[i]); - be.init(); - } - -}, false); +window.addEventListener( + 'load', + function (event) { + var buttons = document.querySelectorAll( + 'button[aria-expanded][aria-controls]' + ); + + for (var i = 0; i < buttons.length; i++) { + var be = new ButtonExpand(buttons[i]); + be.init(); + } + }, + false +); diff --git a/examples/disclosure/js/disclosureMenu.js b/examples/disclosure/js/disclosureMenu.js index 4eb39a84df..b70914a7d6 100644 --- a/examples/disclosure/js/disclosureMenu.js +++ b/examples/disclosure/js/disclosureMenu.js @@ -1,9 +1,9 @@ /* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -* -* Supplemental JS for the disclosure menu keyboard behavior -*/ + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * Supplemental JS for the disclosure menu keyboard behavior + */ 'use strict'; @@ -16,7 +16,9 @@ var DisclosureNav = function (domNode) { }; DisclosureNav.prototype.init = function () { - var buttons = this.rootNode.querySelectorAll('button[aria-expanded][aria-controls]'); + var buttons = this.rootNode.querySelectorAll( + 'button[aria-expanded][aria-controls]' + ); for (var i = 0; i < buttons.length; i++) { var button = buttons[i]; var menu = button.parentNode.querySelector('ul'); @@ -59,7 +61,11 @@ DisclosureNav.prototype.toggleExpand = function (index, expanded) { } }; -DisclosureNav.prototype.controlFocusByKey = function (keyboardEvent, nodeList, currentIndex) { +DisclosureNav.prototype.controlFocusByKey = function ( + keyboardEvent, + nodeList, + currentIndex +) { switch (keyboardEvent.key) { case 'ArrowUp': case 'ArrowLeft': @@ -105,7 +111,11 @@ DisclosureNav.prototype.handleButtonKeyDown = function (event) { } // move focus into the open menu if the current menu is open - else if (this.useArrowKeys && this.openIndex === targetButtonIndex && event.key === 'ArrowDown') { + else if ( + this.useArrowKeys && + this.openIndex === targetButtonIndex && + event.key === 'ArrowDown' + ) { event.preventDefault(); this.controlledNodes[this.openIndex].querySelector('a').focus(); } @@ -128,7 +138,9 @@ DisclosureNav.prototype.handleMenuKeyDown = function (event) { return; } - var menuLinks = Array.prototype.slice.call(this.controlledNodes[this.openIndex].querySelectorAll('a')); + var menuLinks = Array.prototype.slice.call( + this.controlledNodes[this.openIndex].querySelectorAll('a') + ); var currentIndex = menuLinks.indexOf(document.activeElement); // close on escape @@ -150,37 +162,41 @@ DisclosureNav.prototype.updateKeyControls = function (useArrowKeys) { /* Initialize Disclosure Menus */ -window.addEventListener('load', function (event) { - var menus = document.querySelectorAll('.disclosure-nav'); - var disclosureMenus = []; +window.addEventListener( + 'load', + function (event) { + var menus = document.querySelectorAll('.disclosure-nav'); + var disclosureMenus = []; - for (var i = 0; i < menus.length; i++) { - disclosureMenus[i] = new DisclosureNav(menus[i]); - disclosureMenus[i].init(); - } - - // listen to arrow key checkbox - var arrowKeySwitch = document.getElementById('arrow-behavior-switch'); - arrowKeySwitch.addEventListener('change', function (event) { - var checked = arrowKeySwitch.checked; - for (var i = 0; i < disclosureMenus.length; i++) { - disclosureMenus[i].updateKeyControls(checked); + for (var i = 0; i < menus.length; i++) { + disclosureMenus[i] = new DisclosureNav(menus[i]); + disclosureMenus[i].init(); } - }); - - // fake link behavior - var links = document.querySelectorAll('[href="#mythical-page-content"]'); - var examplePageHeading = document.getElementById('mythical-page-heading'); - for (var k = 0; k < links.length; k++) { - links[k].addEventListener('click', function (event) { - var pageTitle = event.target.innerText; - examplePageHeading.innerText = pageTitle; - - // handle aria-current - for (var n = 0; n < links.length; n++) { - links[n].removeAttribute('aria-current'); + + // listen to arrow key checkbox + var arrowKeySwitch = document.getElementById('arrow-behavior-switch'); + arrowKeySwitch.addEventListener('change', function (event) { + var checked = arrowKeySwitch.checked; + for (var i = 0; i < disclosureMenus.length; i++) { + disclosureMenus[i].updateKeyControls(checked); } - this.setAttribute('aria-current', 'page'); }); - } -}, false); + + // fake link behavior + var links = document.querySelectorAll('[href="#mythical-page-content"]'); + var examplePageHeading = document.getElementById('mythical-page-heading'); + for (var k = 0; k < links.length; k++) { + links[k].addEventListener('click', function (event) { + var pageTitle = event.target.innerText; + examplePageHeading.innerText = pageTitle; + + // handle aria-current + for (var n = 0; n < links.length; n++) { + links[n].removeAttribute('aria-current'); + } + this.setAttribute('aria-current', 'page'); + }); + } + }, + false +); diff --git a/examples/feed/js/feed.js b/examples/feed/js/feed.js index f4390fcb5d..6f84be649e 100644 --- a/examples/feed/js/feed.js +++ b/examples/feed/js/feed.js @@ -1,7 +1,7 @@ /* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -*/ + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + */ 'use strict'; @@ -40,10 +40,9 @@ aria.Feed.prototype.focusItem = function (item) { aria.Feed.prototype.mapKeyShortcut = function (event) { var key = event.which || event.keyCode; - var focusedArticle = - aria.Utils.matches(event.target, '[role="article"]') ? - event.target : - aria.Utils.getAncestorBySelector(event.target, '[role="article"]'); + var focusedArticle = aria.Utils.matches(event.target, '[role="article"]') + ? event.target + : aria.Utils.getAncestorBySelector(event.target, '[role="article"]'); if (!focusedArticle) { return; @@ -82,5 +81,4 @@ aria.Feed.prototype.mapKeyShortcut = function (event) { } break; } - }; diff --git a/examples/feed/js/feedDisplay.js b/examples/feed/js/feedDisplay.js index 654d777ff3..870563fea9 100644 --- a/examples/feed/js/feedDisplay.js +++ b/examples/feed/js/feedDisplay.js @@ -1,7 +1,7 @@ /* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -*/ + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + */ 'use strict'; @@ -12,13 +12,13 @@ var aria = aria || {}; aria.RestaurantData = [ { - name: 'Tito\'s Tacos', + name: "Tito's Tacos", rating: 5, type: 'Mexican, Tacos', street: '123 Blueberry Ln', citystate: 'San Dimas, CA', phone: '(111) 111-1111', - image: '' + image: '', }, { name: 'Sakura Sushi', @@ -27,7 +27,7 @@ aria.RestaurantData = [ street: '123 Blueberry Ln', citystate: 'Pomona, CA', phone: '(111) 111-1111', - image: '' + image: '', }, { name: 'Prime Steakhouse', @@ -36,7 +36,7 @@ aria.RestaurantData = [ street: '123 Blueberry Ln', citystate: 'Claremont, CA', phone: '(111) 111-1111', - image: '' + image: '', }, { name: 'The Pizza Factory', @@ -45,16 +45,16 @@ aria.RestaurantData = [ street: '123 Blueberry Ln', citystate: 'Pomona, CA', phone: '(111) 111-1111', - image: '' + image: '', }, { - name: 'Emperor\'s Mongolian', + name: "Emperor's Mongolian", rating: 5, type: 'Mongolian, Barbequeue, Buffets', street: '123 Blueberry Ln', citystate: 'La Verne, CA', phone: '(111) 111-1111', - image: '' + image: '', }, { name: 'Backyard Grill', @@ -63,7 +63,7 @@ aria.RestaurantData = [ street: '123 Blueberry Ln', citystate: 'San Dimas, CA', phone: '(111) 111-1111', - image: '' + image: '', }, { name: 'Taste Kitchen', @@ -72,7 +72,7 @@ aria.RestaurantData = [ street: '123 Blueberry Ln', citystate: 'Claremont, CA', phone: '(111) 111-1111', - image: '' + image: '', }, { name: 'Bon Appetit', @@ -81,16 +81,16 @@ aria.RestaurantData = [ street: '123 Blueberry Ln', citystate: 'La Verne, CA', phone: '(111) 111-1111', - image: '' + image: '', }, { - name: 'Sally\'s Sandwiches', + name: "Sally's Sandwiches", rating: 3, type: 'Sandwiches, American', street: '123 Blueberry Ln', citystate: 'San Dimas, CA', phone: '(111) 111-1111', - image: '' + image: '', }, { name: 'The HotPot Spot', @@ -99,8 +99,8 @@ aria.RestaurantData = [ street: '123 Blueberry Ln', citystate: 'Pomona, CA', phone: '(111) 111-1111', - image: '' - } + image: '', + }, ]; aria.FeedDisplay = function (feed, fetchData) { @@ -135,10 +135,14 @@ aria.FeedDisplay.prototype.loadData = function () { var loadingItems = []; - Array.prototype.forEach.call(feedData, function (itemData) { - var newFeedItem = this.renderItemData(itemData); - loadingItems.push(newFeedItem); - }, this); + Array.prototype.forEach.call( + feedData, + function (itemData) { + var newFeedItem = this.renderItemData(itemData); + loadingItems.push(newFeedItem); + }, + this + ); this.delayRender( loadingItems, @@ -165,9 +169,12 @@ aria.FeedDisplay.prototype.delayRender = function (items, onRenderDone) { feedItem.setAttribute('aria-setsize', this.feedItems.length); }, this); - setTimeout((function () { - this.delayRender(items, onRenderDone); - }).bind(this), this.loadingDelay); + setTimeout( + function () { + this.delayRender(items, onRenderDone); + }.bind(this), + this.loadingDelay + ); }; aria.FeedDisplay.prototype.renderItemData = function (itemData) { @@ -188,31 +195,42 @@ aria.FeedDisplay.prototype.renderItemData = function (itemData) { feedItem.setAttribute('aria-labelledby', restaurantID); if (itemData.image) { - itemContent += '
' + - itemData.image + - '
'; + itemContent += '
' + itemData.image + '
'; } - itemContent += '
' + - itemData.name + - '
'; + itemContent += + '
' + + itemData.name + + '
'; if (itemData.rating) { var ratingID = 'restaurant-rating-' + this.feedSize; - itemContent += '
' + - '' + - '
'; + itemContent += + '
' + + '' + + '
'; describedbyIDs.push(ratingID); } if (itemData.type) { var typeID = 'restaurant-type-' + this.feedSize; - itemContent += '
' + - itemData.type + - '
'; + itemContent += + '
' + + itemData.type + + '
'; describedbyIDs.push(typeID); } @@ -227,21 +245,18 @@ aria.FeedDisplay.prototype.renderItemData = function (itemData) { describedbyIDs.push(locationID); if (itemData.street) { - locationContent += '
' + - itemData.street + - '
'; + locationContent += + '
' + itemData.street + '
'; } if (itemData.citystate) { - locationContent += '
' + - itemData.citystate + - '
'; + locationContent += + '
' + itemData.citystate + '
'; } if (itemData.phone) { - locationContent += '
' + - itemData.phone + - '
'; + locationContent += + '
' + itemData.phone + '
'; } locationBlock.innerHTML = locationContent; @@ -251,7 +266,8 @@ aria.FeedDisplay.prototype.renderItemData = function (itemData) { var actions = document.createElement('div'); actions.className = 'restaurant-actions'; - actions.innerHTML = ''; + actions.innerHTML = + ''; feedItem.appendChild(actions); return feedItem; @@ -264,7 +280,7 @@ aria.FeedDisplay.prototype.setupEvents = function () { aria.FeedDisplay.prototype.handleScroll = function () { var now = Date.now(); - if ((this.lastChecked + 100 - now) < 0) { + if (this.lastChecked + 100 - now < 0) { this.checkLoadMore(); this.lastChecked = now; } @@ -276,13 +292,14 @@ aria.FeedDisplay.prototype.checkLoadMore = function () { } var lastFeedItem = this.feedItems[this.feedItems.length - 1]; - var scrollTop = window.pageYOffset || - document.documentElement.scrollTop || - document.body.scrollTop || - 0; + var scrollTop = + window.pageYOffset || + document.documentElement.scrollTop || + document.body.scrollTop || + 0; var scrollBottom = scrollTop + window.innerHeight; - if (scrollBottom >= (lastFeedItem.offsetTop - 300)) { + if (scrollBottom >= lastFeedItem.offsetTop - 300) { this.loadData(); } }; diff --git a/examples/feed/js/main.js b/examples/feed/js/main.js index 3cc5b7a412..3731fc2078 100644 --- a/examples/feed/js/main.js +++ b/examples/feed/js/main.js @@ -1,7 +1,7 @@ /* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -*/ + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + */ 'use strict'; @@ -13,17 +13,11 @@ window.addEventListener('load', function () { var feedNode = document.getElementById('restaurant-feed'); var delaySelect = document.getElementById('delay-time-select'); - var restaurantFeed = new aria.Feed( - feedNode, - delaySelect - ); + var restaurantFeed = new aria.Feed(feedNode, delaySelect); - var restaurantFeedDisplay = new aria.FeedDisplay( - restaurantFeed, - function () { - return aria.RestaurantData; - } - ); + var restaurantFeedDisplay = new aria.FeedDisplay(restaurantFeed, function () { + return aria.RestaurantData; + }); restaurantFeedDisplay.setDelay(delaySelect.value); delaySelect.addEventListener('change', function () { diff --git a/examples/grid/js/dataGrid.js b/examples/grid/js/dataGrid.js index 3887f2b0ce..c3e71d44af 100644 --- a/examples/grid/js/dataGrid.js +++ b/examples/grid/js/dataGrid.js @@ -1,7 +1,7 @@ /* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -*/ + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + */ 'use strict'; @@ -17,7 +17,7 @@ var aria = aria || {}; aria.SortType = { ASCENDING: 'ascending', DESCENDING: 'descending', - NONE: 'none' + NONE: 'none', }; /** @@ -29,7 +29,7 @@ aria.GridSelector = { CELL: 'th, td, [role="gridcell"]', SCROLL_ROW: 'tr:not([data-fixed]), [role="row"]', SORT_HEADER: 'th[aria-sort]', - TABBABLE: '[tabindex="0"]' + TABBABLE: '[tabindex="0"]', }; /** @@ -37,7 +37,7 @@ aria.GridSelector = { * CSS Class names */ aria.CSSClass = { - HIDDEN: 'hidden' + HIDDEN: 'hidden', }; /** @@ -64,17 +64,23 @@ aria.Grid = function (gridNode) { this.keysIndicator = document.getElementById('arrow-keys-indicator'); - aria.Utils.bindMethods(this, - 'checkFocusChange', 'checkPageChange', 'checkRestructureGrid', - 'delegateButtonHandler', 'focusClickedCell', 'restructureGrid', - 'showKeysIndicator', 'hideKeysIndicator'); + aria.Utils.bindMethods( + this, + 'checkFocusChange', + 'checkPageChange', + 'checkRestructureGrid', + 'delegateButtonHandler', + 'focusClickedCell', + 'restructureGrid', + 'showKeysIndicator', + 'hideKeysIndicator' + ); this.setupFocusGrid(); this.setFocusPointer(0, 0); if (this.paginationEnabled) { this.setupPagination(); - } - else { + } else { this.perPage = this.grid.length; } @@ -90,31 +96,30 @@ aria.Grid.prototype.setupFocusGrid = function () { Array.prototype.forEach.call( this.gridNode.querySelectorAll(aria.GridSelector.ROW), - (function (row) { + function (row) { var rowCells = []; Array.prototype.forEach.call( row.querySelectorAll(aria.GridSelector.CELL), - (function (cell) { + function (cell) { var focusableSelector = '[tabindex]'; if (aria.Utils.matches(cell, focusableSelector)) { rowCells.push(cell); - } - else { + } else { var focusableCell = cell.querySelector(focusableSelector); if (focusableCell) { rowCells.push(focusableCell); } } - }).bind(this) + }.bind(this) ); if (rowCells.length) { this.grid.push(rowCells); } - }).bind(this) + }.bind(this) ); if (this.paginationEnabled) { @@ -148,10 +153,8 @@ aria.Grid.prototype.setFocusPointer = function (row, col) { 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); + 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'); @@ -160,10 +163,8 @@ aria.Grid.prototype.setFocusPointer = function (row, col) { this.focusedRow = row; this.focusedCol = col; - this.grid[row][col] - .addEventListener('focus', this.showKeysIndicator); - this.grid[row][col] - .addEventListener('blur', this.hideKeysIndicator); + this.grid[row][col].addEventListener('focus', this.showKeysIndicator); + this.grid[row][col].addEventListener('blur', this.hideKeysIndicator); return true; }; @@ -202,8 +203,9 @@ aria.Grid.prototype.isValidCell = function (row, col) { * 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]; + var cell = this.gridNode + .querySelectorAll(aria.GridSelector.ROW) + [row].querySelectorAll(aria.GridSelector.CELL)[col]; return aria.Utils.hasClass(cell, aria.CSSClass.HIDDEN); }; @@ -225,10 +227,14 @@ aria.Grid.prototype.clearEvents = function () { 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); + this.grid[this.focusedRow][this.focusedCol].removeEventListener( + 'focus', + this.showKeysIndicator + ); + this.grid[this.focusedRow][this.focusedCol].removeEventListener( + 'blur', + this.hideKeysIndicator + ); }; /** @@ -275,8 +281,10 @@ aria.Grid.prototype.showKeysIndicator = function () { }; aria.Grid.prototype.hideKeysIndicator = function () { - if (this.keysIndicator && - this.grid[this.focusedRow][this.focusedCol].tabIndex === 0) { + if ( + this.keysIndicator && + this.grid[this.focusedRow][this.focusedCol].tabIndex === 0 + ) { aria.Utils.addClass(this.keysIndicator, 'hidden'); } }; @@ -362,15 +370,16 @@ aria.Grid.prototype.checkFocusChange = function (event) { aria.Grid.prototype.findFocusedItem = function (focusedTarget) { var focusedCell = this.grid[this.focusedRow][this.focusedCol]; - if (focusedCell === focusedTarget || - focusedCell.contains(focusedTarget)) { + 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)) { + if ( + this.grid[i][j] === focusedTarget || + this.grid[i][j].contains(focusedTarget) + ) { this.setFocusPointer(i, j); return; } @@ -415,7 +424,7 @@ aria.Grid.prototype.focusClickedCell = function (event) { aria.Grid.prototype.delegateButtonHandler = function (event) { var key = event.which || event.keyCode; var target = event.target; - var isClickEvent = (event.type === 'click'); + var isClickEvent = event.type === 'click'; if (!target) { return; @@ -424,11 +433,7 @@ aria.Grid.prototype.delegateButtonHandler = function (event) { if ( target.parentNode && target.parentNode.matches('th[aria-sort]') && - ( - isClickEvent || - key === aria.KeyCode.SPACE || - key === aria.KeyCode.RETURN - ) + (isClickEvent || key === aria.KeyCode.SPACE || key === aria.KeyCode.RETURN) ) { event.preventDefault(); this.handleSort(target.parentNode); @@ -436,25 +441,15 @@ aria.Grid.prototype.delegateButtonHandler = function (event) { if ( aria.Utils.matches(target, '.editable-text, .edit-text-button') && - ( - isClickEvent || - key === aria.KeyCode.RETURN - ) + (isClickEvent || key === aria.KeyCode.RETURN) ) { event.preventDefault(); - this.toggleEditMode( - this.findClosest(target, '.editable-text'), - true, - true - ); + 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 - ) + (key === aria.KeyCode.RETURN || key === aria.KeyCode.ESC) ) { event.preventDefault(); this.toggleEditMode( @@ -487,8 +482,7 @@ aria.Grid.prototype.toggleEditMode = function (editCell, toggleOn, updateText) { if (toggleOn) { onNode.value = offNode.innerText; - } - else if (updateText) { + } else if (updateText) { onNode.innerText = offNode.value; } @@ -519,8 +513,7 @@ aria.Grid.prototype.handleSort = function (headerNode) { if (sortType === aria.SortType.ASCENDING) { sortType = aria.SortType.DESCENDING; - } - else { + } else { sortType = aria.SortType.ASCENDING; } @@ -532,8 +525,7 @@ aria.Grid.prototype.handleSort = function (headerNode) { if (sortType === aria.SortType.ASCENDING) { return row1Value - row2Value; - } - else { + } else { return row2Value - row1Value; } }; @@ -565,9 +557,11 @@ aria.Grid.prototype.sortRows = function (compareFn) { dataRows.sort(compareFn); - dataRows.forEach((function (row) { - rowWrapper.appendChild(row); - }).bind(this)); + dataRows.forEach( + function (row) { + rowWrapper.appendChild(row); + }.bind(this) + ); }; /** @@ -584,7 +578,6 @@ aria.Grid.prototype.setupIndices = function () { for (var col = 0; col < cols.length; col++) { cols[col].setAttribute('aria-colindex', col + 1); } - } }; @@ -620,8 +613,7 @@ aria.Grid.prototype.checkPageChange = function (event) { if (key === aria.KeyCode.PAGE_UP) { event.preventDefault(); this.movePageUp(); - } - else if (key === aria.KeyCode.PAGE_DOWN) { + } else if (key === aria.KeyCode.PAGE_DOWN) { event.preventDefault(); this.movePageDown(); } @@ -650,8 +642,7 @@ aria.Grid.prototype.movePageDown = function () { * 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 dataRows = this.gridNode.querySelectorAll(aria.GridSelector.SCROLL_ROW); var reachedTop = false; var firstIndex = -1; var endIndex = -1; @@ -661,17 +652,9 @@ aria.Grid.prototype.showFromRow = function (startIndex, scrollDown) { } for (var i = 0; i < dataRows.length; i++) { - if ( - ( - scrollDown && - i >= startIndex && - i < startIndex + this.perPage) || - ( - !scrollDown && - i <= startIndex && - i > startIndex - this.perPage - ) + (scrollDown && i >= startIndex && i < startIndex + this.perPage) || + (!scrollDown && i <= startIndex && i > startIndex - this.perPage) ) { aria.Utils.removeClass(dataRows[i], aria.CSSClass.HIDDEN); @@ -684,8 +667,7 @@ aria.Grid.prototype.showFromRow = function (startIndex, scrollDown) { firstIndex = i; } endIndex = i; - } - else { + } else { aria.Utils.addClass(dataRows[i], aria.CSSClass.HIDDEN); } } @@ -718,8 +700,8 @@ aria.Grid.prototype.restructureGrid = function () { 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 shouldRefocus = document.activeElement === focusedElement; + var focusedIndex = this.focusedRow * this.grid[0].length + this.focusedCol; var newRow = document.createElement('div'); newRow.setAttribute('role', 'row'); @@ -729,7 +711,7 @@ aria.Grid.prototype.restructureGrid = function () { cells.forEach(function (cell, index) { var cellWidth = cell.offsetWidth; - if (currentWidth > 0 && currentWidth >= (gridWidth - cellWidth)) { + if (currentWidth > 0 && currentWidth >= gridWidth - cellWidth) { newRow = document.createElement('div'); newRow.setAttribute('role', 'row'); this.gridNode.append(newRow); @@ -807,8 +789,7 @@ aria.Grid.prototype.getNextCell = function ( // jump to the next filled in cell. row--; } - } - else if (row >= rowCount || !this.grid[row][col]) { + } else if (row >= rowCount || !this.grid[row][col]) { row = 0; col++; } @@ -817,16 +798,14 @@ aria.Grid.prototype.getNextCell = function ( if (this.isValidCell(row, col)) { return { row: row, - col: col + col: col, }; - } - else if (this.isValidCell(currRow, currCol)) { + } else if (this.isValidCell(currRow, currCol)) { return { row: currRow, - col: currCol + col: currCol, }; - } - else { + } else { return false; } }; @@ -889,19 +868,15 @@ 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); - } + 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 (!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) { diff --git a/examples/grid/js/dataGrids.js b/examples/grid/js/dataGrids.js index 0ee01253df..d2351c4d70 100644 --- a/examples/grid/js/dataGrids.js +++ b/examples/grid/js/dataGrids.js @@ -1,7 +1,7 @@ /* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -*/ + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + */ 'use strict'; @@ -31,8 +31,7 @@ window.addEventListener('load', function () { if (toggledOn) { toggleButton.innerText = 'Hide Type and Category'; - } - else { + } else { toggleButton.innerText = 'Show Type and Category'; } }); diff --git a/examples/grid/js/layoutGrids.js b/examples/grid/js/layoutGrids.js index b0e9b65fcc..3136ecdc83 100644 --- a/examples/grid/js/layoutGrids.js +++ b/examples/grid/js/layoutGrids.js @@ -1,7 +1,7 @@ /* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -*/ + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + */ 'use strict'; @@ -41,14 +41,12 @@ window.addEventListener('load', function () { endIndexText.innerText = endIndex + 1; if (startIndex <= 0) { previousButton.setAttribute('disabled', 'true'); - } - else { + } else { previousButton.removeAttribute('disabled'); } if (endIndex >= 18) { nextButton.setAttribute('disabled', 'true'); - } - else { + } else { nextButton.removeAttribute('disabled'); } }); @@ -77,9 +75,9 @@ window.addEventListener('load', function () { firstGridCell.addEventListener('focus', setupInstructions); }); -function PillList (grid, input, submitButton, formUpdateText) { +function PillList(grid, input, submitButton, formUpdateText) { // Hardcoded to work for example 2 - this.pillIDs = {length: 2, 1: true, 2: true}; + this.pillIDs = { length: 2, 1: true, 2: true }; this.nextPillID = 3; this.grid = grid; this.input = input; @@ -89,7 +87,10 @@ function PillList (grid, input, submitButton, 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)); + this.grid.gridNode.addEventListener( + 'keydown', + this.checkRemovePill.bind(this) + ); } PillList.prototype.checkSubmitItem = function (event) { @@ -104,8 +105,7 @@ PillList.prototype.getRecipientsString = function () { var recipientCount = this.pillIDs.length; if (recipientCount === 1) { return '1 recipient total.'; - } - else { + } else { return recipientCount + ' recipients total.'; } }; @@ -115,7 +115,8 @@ PillList.prototype.submitItemForm = function () { this.addPillItem(newItem); this.input.value = ''; this.input.focus(); - this.formUpdateText.innerText = newItem + ' added. ' + this.getRecipientsString(); + this.formUpdateText.innerText = + newItem + ' added. ' + this.getRecipientsString(); }; PillList.prototype.addPillItem = function (recipientName) { @@ -132,15 +133,23 @@ PillList.prototype.addPillItem = function (recipientName) { newPillItem.innerHTML = '' + - '' + - recipientName + - '' + + '' + + recipientName + + '' + '' + '' + - '' + - 'X' + - '' + + '' + + 'X' + + '' + ''; this.grid.gridNode.append(newPillItem); @@ -159,12 +168,14 @@ PillList.prototype.addPillItem = function (recipientName) { PillList.prototype.checkRemovePill = function (event) { var pillItem, pillID, pillName; - var isClickEvent = (event.type === 'click'); + var isClickEvent = event.type === 'click'; var key = event.which || event.keyCode; - if (!isClickEvent && - key !== aria.KeyCode.RETURN && - key !== aria.KeyCode.SPACE) { + if ( + !isClickEvent && + key !== aria.KeyCode.RETURN && + key !== aria.KeyCode.SPACE + ) { return; } @@ -172,14 +183,14 @@ PillList.prototype.checkRemovePill = function (event) { pillItem = event.target.parentNode.parentNode; pillID = pillItem.getAttribute('data-id'); pillName = pillItem.querySelector('.pill-name').innerText; - } - else { + } else { return; } delete this.pillIDs[pillID]; this.pillIDs.length--; - this.formUpdateText.innerText = pillName + ' removed. ' + this.getRecipientsString(); + this.formUpdateText.innerText = + pillName + ' removed. ' + this.getRecipientsString(); pillItem.remove(); this.grid.setupFocusGrid(); @@ -187,8 +198,9 @@ PillList.prototype.checkRemovePill = function (event) { 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)) { + } 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/examples/grid/js/menuButton.js b/examples/grid/js/menuButton.js index 0006b26b29..c3d5124c20 100644 --- a/examples/grid/js/menuButton.js +++ b/examples/grid/js/menuButton.js @@ -1,8 +1,8 @@ /* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -* -*/ + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + */ 'use strict'; @@ -13,13 +13,11 @@ */ window.addEventListener('load', function () { - var menuButtons = document.querySelectorAll('[aria-haspopup][aria-controls]'); [].forEach.call(menuButtons, function (menuButton) { if ( - menuButton && - menuButton.tagName.toLowerCase() === 'button' || + (menuButton && menuButton.tagName.toLowerCase() === 'button') || menuButton.getAttribute('role').toLowerCase() === 'button' ) { var mb = new aria.widget.MenuButton(menuButton); @@ -53,11 +51,11 @@ aria.Utils.findPos = function (element) { var yPosition = 0; while (element) { - xPosition += (element.offsetLeft - element.scrollLeft + element.clientLeft); - yPosition += (element.offsetTop - element.scrollTop + element.clientTop); + xPosition += element.offsetLeft - element.scrollLeft + element.clientLeft; + yPosition += element.offsetTop - element.scrollTop + element.clientTop; element = element.offsetParent; } - return {x: xPosition, y: yPosition}; + return { x: xPosition, y: yPosition }; }; /* ---------------------------------------------------------------- */ @@ -79,20 +77,19 @@ aria.widget = aria.widget || {}; */ 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 + 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 @@ -107,7 +104,6 @@ aria.widget.Menu = function (node, menuButton) { this.firstMenuItem = false; this.lastMenuItem = false; - }; /** @@ -119,7 +115,6 @@ aria.widget.Menu = function (node, menuButton) { */ aria.widget.Menu.prototype.initMenu = function () { - var self = this; var cn = this.menuNode.firstChild; @@ -152,7 +147,6 @@ aria.widget.Menu.prototype.initMenu = function () { self.eventFocus(event, self); }; cn.addEventListener('focus', eventFocus); - } } cn = cn.nextSibling; @@ -168,13 +162,12 @@ aria.widget.Menu.prototype.initMenu = function () { */ aria.widget.Menu.prototype.nextMenuItem = function (currentMenuItem) { - var mi = currentMenuItem.nextSibling; while (mi) { if ( - (mi.nodeType === Node.ELEMENT_NODE) && - (mi.getAttribute('role') === 'menuitem') + mi.nodeType === Node.ELEMENT_NODE && + mi.getAttribute('role') === 'menuitem' ) { mi.focus(); break; @@ -196,7 +189,6 @@ aria.widget.Menu.prototype.nextMenuItem = function (currentMenuItem) { */ aria.widget.Menu.prototype.previousMenuItem = function (currentMenuItem) { - var mi = currentMenuItem.previousSibling; while (mi) { @@ -226,12 +218,10 @@ aria.widget.Menu.prototype.previousMenuItem = function (currentMenuItem) { */ 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); @@ -269,7 +259,6 @@ aria.widget.Menu.prototype.eventKeyDown = function (event, menu) { event.stopPropagation(); event.preventDefault(); } - }; /** @@ -283,11 +272,9 @@ aria.widget.Menu.prototype.eventKeyDown = function (event, menu) { */ aria.widget.Menu.prototype.eventMouseClick = function (event, menu) { - var clickedItemText = event.target.innerText; this.menuButton.buttonNode.innerText = clickedItemText; menu.menuButton.closeMenu(true); - }; /** @@ -334,14 +321,13 @@ aria.widget.Menu.prototype.eventFocus = function (event, menu) { */ aria.widget.MenuButton = function (node) { - this.keyCode = Object.freeze({ - 'TAB': 9, - 'RETURN': 13, - 'ESC': 27, - 'SPACE': 32, - 'UP': 38, - 'DOWN': 40 + TAB: 9, + RETURN: 13, + ESC: 27, + SPACE: 32, + UP: 38, + DOWN: 40, }); // Check fo DOM element node @@ -357,11 +343,10 @@ aria.widget.MenuButton = function (node) { if (node.tagName.toLowerCase() === 'a') { var url = node.getAttribute('href'); - if (url && url.length && (url.length > 0)) { + if (url && url.length && url.length > 0) { this.isLink = true; } } - }; /** @@ -424,7 +409,6 @@ aria.widget.MenuButton.prototype.openMenu = function () { */ aria.widget.MenuButton.prototype.closeMenu = function (force, focusMenuButton) { - if (typeof force !== 'boolean') { force = false; } @@ -434,12 +418,10 @@ aria.widget.MenuButton.prototype.closeMenu = function (force, focusMenuButton) { if ( force || - ( - !this.mouseInMenuButton && + (!this.mouseInMenuButton && this.menuNode && !this.menu.mouseInMenu && - !this.menu.menuHasFocus - ) + !this.menu.menuHasFocus) ) { this.menuNode.style.display = 'none'; if (focusMenuButton) { @@ -458,16 +440,13 @@ aria.widget.MenuButton.prototype.closeMenu = function (force, focusMenuButton) { */ aria.widget.MenuButton.prototype.toggleMenu = function () { - if (this.menuNode) { if (this.menuNode.style.display === 'block') { this.menuNode.style.display = 'none'; - } - else { + } else { this.menuNode.style.display = 'block'; } } - }; /** @@ -479,12 +458,10 @@ aria.widget.MenuButton.prototype.toggleMenu = function () { */ aria.widget.MenuButton.prototype.moveFocusToFirstMenuItem = function () { - if (this.menu.firstMenuItem) { this.openMenu(); this.menu.firstMenuItem.focus(); } - }; /** @@ -496,12 +473,10 @@ aria.widget.MenuButton.prototype.moveFocusToFirstMenuItem = function () { */ aria.widget.MenuButton.prototype.moveFocusToLastMenuItem = function () { - if (this.menu.lastMenuItem) { this.openMenu(); this.menu.lastMenuItem.focus(); } - }; /** @@ -515,11 +490,9 @@ aria.widget.MenuButton.prototype.moveFocusToLastMenuItem = function () { */ aria.widget.MenuButton.prototype.eventKeyDown = function (event, menuButton) { - var flag = false; switch (event.keyCode) { - case menuButton.keyCode.SPACE: menuButton.moveFocusToFirstMenuItem(); flag = true; @@ -556,7 +529,6 @@ aria.widget.MenuButton.prototype.eventKeyDown = function (event, menuButton) { event.stopPropagation(); event.preventDefault(); } - }; /** @@ -568,6 +540,9 @@ aria.widget.MenuButton.prototype.eventKeyDown = function (event, menuButton) { * NOTE: The menuButton parameter is needed to provide a reference to the specific * menuButton */ -aria.widget.MenuButton.prototype.eventMouseClick = function (event, menuButton) { +aria.widget.MenuButton.prototype.eventMouseClick = function ( + event, + menuButton +) { menuButton.moveFocusToFirstMenuItem(); }; diff --git a/examples/js/app.js b/examples/js/app.js index 3ef86e6cd3..db66a66ebd 100644 --- a/examples/js/app.js +++ b/examples/js/app.js @@ -21,7 +21,9 @@ } // The #browser_and_AT_support link - var supportLink = document.querySelector('a[href$="#browser_and_AT_support"]'); + var supportLink = document.querySelector( + 'a[href$="#browser_and_AT_support"]' + ); if (!supportLink) { return; } @@ -30,32 +32,34 @@ var urlPrefix = supportLink.getAttribute('href').split('#')[0]; // Expected outcome '../js/app.js' OR '../../js/app.js' - var scriptSource = document.querySelector('[src$="app.js"]').getAttribute('src'); + var scriptSource = document + .querySelector('[src$="app.js"]') + .getAttribute('src'); // Replace 'app.js' part with 'notice.html' var fetchSource = scriptSource.replace('app.js', './notice.html'); //fetch('https://raw.githack.com/w3c/aria-practices/1228-support-notice/examples/js/notice.html') fetch(fetchSource) - .then(function(response) { - // Return notice.html as text - return response.text(); - }) - .then(function(html) { - // Parse response as text/html - var parser = new DOMParser(); - return parser.parseFromString(html, "text/html"); - }) - .then(function(doc) { - // Get the details element from the parsed response - var noticeElement = doc.querySelector('details'); - // Rewrite links with the right urlPrefix - var links = doc.querySelectorAll('a[href^="/#"]'); - for (var i = 0; i < links.length; ++i) { - links[i].pathname = urlPrefix; - } - // Insert the support notice before the page's h1 - var heading = document.querySelector('h1'); - heading.parentNode.insertBefore(noticeElement, heading.nextSibling); - }) + .then(function (response) { + // Return notice.html as text + return response.text(); + }) + .then(function (html) { + // Parse response as text/html + var parser = new DOMParser(); + return parser.parseFromString(html, 'text/html'); + }) + .then(function (doc) { + // Get the details element from the parsed response + var noticeElement = doc.querySelector('details'); + // Rewrite links with the right urlPrefix + var links = doc.querySelectorAll('a[href^="/#"]'); + for (var i = 0; i < links.length; ++i) { + links[i].pathname = urlPrefix; + } + // Insert the support notice before the page's h1 + var heading = document.querySelector('h1'); + heading.parentNode.insertBefore(noticeElement, heading.nextSibling); + }); } -}()); +})(); diff --git a/examples/js/examples.js b/examples/js/examples.js index 10aa54ba6f..95e86eb4f3 100644 --- a/examples/js/examples.js +++ b/examples/js/examples.js @@ -22,7 +22,22 @@ var DEFAULT_INDENT = '  '; // Void elements according to “HTML 5.3: The HTML Syntax”: // https://w3c.github.io/html/syntax.html#void-elements. -var VOID_ELEMENTS = ['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', 'track', 'wbr']; +var VOID_ELEMENTS = [ + 'area', + 'base', + 'br', + 'col', + 'embed', + 'hr', + 'img', + 'input', + 'link', + 'meta', + 'param', + 'source', + 'track', + 'wbr', +]; /** * Creates a slider widget using ARIA @@ -50,7 +65,12 @@ aria.widget.SourceCode = function () { * @method add * @memberof aria.widget.SourceCode */ -aria.widget.SourceCode.prototype.add = function (locationId, codeId, exampleHeaderId, cssJsFilesId) { +aria.widget.SourceCode.prototype.add = function ( + locationId, + codeId, + exampleHeaderId, + cssJsFilesId +) { this.location[this.location.length] = locationId; this.code[this.code.length] = codeId; this.exampleHeader[this.exampleHeader.length] = exampleHeaderId; @@ -78,7 +98,12 @@ aria.widget.SourceCode.prototype.make = function () { // Adds the "Open In CodePen" button by the example header if (this.exampleHeader[i]) { - addOpenInCodePenForm(i, this.exampleHeader[i], this.code[i], this.resources[i]); + addOpenInCodePenForm( + i, + this.exampleHeader[i], + this.code[i], + this.resources[i] + ); } } }; @@ -94,7 +119,12 @@ aria.widget.SourceCode.prototype.make = function () { * @method createCode * @memberof aria.widget.SourceCode */ -aria.widget.SourceCode.prototype.createCode = function (sourceCodeNode, node, indentLevel, skipFirst) { +aria.widget.SourceCode.prototype.createCode = function ( + sourceCodeNode, + node, + indentLevel, + skipFirst +) { if (!skipFirst) { var openTag = ''; var nodeNameStr = node.nodeName.toLowerCase(); @@ -109,9 +139,10 @@ aria.widget.SourceCode.prototype.createCode = function (sourceCodeNode, node, in } var attributeValue = sanitizeNodeValue(node.attributes[attrPos].value); - openTag += node.attributes[attrPos].nodeName + '="' + attributeValue + '"'; + openTag += + node.attributes[attrPos].nodeName + '="' + attributeValue + '"'; - if (wrapAttributes && (attrPos !== node.attributes.length - 1)) { + if (wrapAttributes && attrPos !== node.attributes.length - 1) { openTag += '
' + indentation(indentLevel); openTag += ' '.repeat(nodeNameStr.length + 2); } @@ -134,7 +165,10 @@ aria.widget.SourceCode.prototype.createCode = function (sourceCodeNode, node, in case Node.TEXT_NODE: if (hasText(childNode.nodeValue)) { var textNodeContent = sanitizeNodeValue(childNode.nodeValue).trim(); - textNodeContent = indentLines(textNodeContent, indentation(indentLevel)); + textNodeContent = indentLines( + textNodeContent, + indentation(indentLevel) + ); sourceCodeNode.innerHTML += '
' + textNodeContent; } @@ -144,7 +178,10 @@ aria.widget.SourceCode.prototype.createCode = function (sourceCodeNode, node, in if (hasText(childNode.nodeValue)) { var commentNodeContent = sanitizeNodeValue(childNode.nodeValue); commentNodeContent = '<!--' + commentNodeContent + '-->'; - commentNodeContent = indentLines(commentNodeContent, indentation(indentLevel)); + commentNodeContent = indentLines( + commentNodeContent, + indentation(indentLevel) + ); sourceCodeNode.innerHTML += '
' + commentNodeContent; } @@ -171,7 +208,7 @@ aria.widget.SourceCode.prototype.createCode = function (sourceCodeNode, node, in * @param {Number} indentLevel * @returns {String} */ -function indentation (indentLevel) { +function indentation(indentLevel) { return DEFAULT_INDENT.repeat(indentLevel); } @@ -193,7 +230,7 @@ function indentation (indentLevel) { * @param {String} nodeContent content of a node to test for whitespace characters * @returns {Boolean} */ -function hasText (nodeContent) { +function hasText(nodeContent) { if (typeof nodeContent !== 'string') { return false; } @@ -207,7 +244,7 @@ function hasText (nodeContent) { * @param {String} textContent * @returns {String} */ -function sanitizeNodeValue (textContent) { +function sanitizeNodeValue(textContent) { if (typeof textContent !== 'string') { return ''; } @@ -225,7 +262,7 @@ function sanitizeNodeValue (textContent) { * @param {String} textContent * @returns {String} */ -function stripIndentation (textContent) { +function stripIndentation(textContent) { var textIndentation = detectIndentation(textContent); if (textIndentation === 0) { @@ -273,7 +310,7 @@ function stripIndentation (textContent) { * @param {String} textContent * @returns {Number} The level of indentation */ -function detectIndentation (textContent) { +function detectIndentation(textContent) { // Case 1 if (!textContent.includes('\n')) { return 0; @@ -304,7 +341,7 @@ function detectIndentation (textContent) { * @param {String} indentation * @returns {String} */ -function indentLines (input, indentation) { +function indentLines(input, indentation) { var lines = input.split('\n'); lines = lines.map(function (line) { @@ -322,9 +359,14 @@ function indentLines (input, indentation) { * @param {String} exampleCodeId - the example html code * @param {String} exampleFilesId - the element containing all relevent CSS and JS file */ -function addOpenInCodePenForm (exampleIndex, exampleHeaderId, exampleCodeId, exampleFilesId) { +function addOpenInCodePenForm( + exampleIndex, + exampleHeaderId, + exampleCodeId, + exampleFilesId +) { var jsonInputId = 'codepen-data-ex-' + exampleIndex; - var buttonId = exampleCodeId + '-codepenbutton' + var buttonId = exampleCodeId + '-codepenbutton'; var form = document.createElement('form'); form.setAttribute('action', 'https://codepen.io/pen/define'); @@ -349,61 +391,62 @@ function addOpenInCodePenForm (exampleIndex, exampleHeaderId, exampleCodeId, exa var indentedExampleHtml = document.getElementById(exampleCodeId).innerHTML; indentedExampleHtml = indentedExampleHtml.replace(/^\n+/, ''); var indentation = indentedExampleHtml.match(/^\s+/)[0]; - var exampleHtml = indentedExampleHtml.replace(new RegExp('^' + indentation, 'gm'), ''); + var exampleHtml = indentedExampleHtml.replace( + new RegExp('^' + indentation, 'gm'), + '' + ); var postJson = { html: exampleHtml, css: '', js: '', - head: '' + head: '', }; var totalFetchedFiles = 0; var fileLinks = document.querySelectorAll('#' + exampleFilesId + ' a'); for (let fileLink of fileLinks) { - - var request = new XMLHttpRequest(); - - request.open('GET', fileLink.href, true); - request.onload = function() { - var href = this.responseURL; - if (this.status >= 200 && this.status < 400) { - if (href.indexOf('css') !== -1) { - postJson.css = postJson.css.concat(this.response); - } - if (href.indexOf('js') !== -1) { - postJson.js = postJson.js.concat(this.response); - } - totalFetchedFiles++; - } - else { - hideButton(buttonId, "Could not load resource: " + href); - } - }; - request.onerror = function() { - hideButton(buttonId, "Could not load resource: " + fileLink.href); - }; - request.send(); + var request = new XMLHttpRequest(); + + request.open('GET', fileLink.href, true); + request.onload = function () { + var href = this.responseURL; + if (this.status >= 200 && this.status < 400) { + if (href.indexOf('css') !== -1) { + postJson.css = postJson.css.concat(this.response); + } + if (href.indexOf('js') !== -1) { + postJson.js = postJson.js.concat(this.response); + } + totalFetchedFiles++; + } else { + hideButton(buttonId, 'Could not load resource: ' + href); + } + }; + request.onerror = function () { + hideButton(buttonId, 'Could not load resource: ' + fileLink.href); + }; + request.send(); } - var timerId = setInterval(() => { - console.log(totalFetchedFiles); - if (totalFetchedFiles === fileLinks.length) { - document.getElementById(jsonInputId).value = JSON.stringify(postJson); - clearInterval(timerId); - } - }, 500); + var timerId = setInterval(() => { + console.log(totalFetchedFiles); + if (totalFetchedFiles === fileLinks.length) { + document.getElementById(jsonInputId).value = JSON.stringify(postJson); + clearInterval(timerId); + } + }, 500); - setTimeout(() => { - clearInterval(timerId); - }, 10000); + setTimeout(() => { + clearInterval(timerId); + }, 10000); } function hideButton(buttonId, errorMsg) { - let button = document.querySelector(buttonId); - button.style.display = "none"; - console.log("Removing 'Open in Codepen button'. " + errorMsg); + let button = document.querySelector(buttonId); + button.style.display = 'none'; + console.log("Removing 'Open in Codepen button'. " + errorMsg); } var sourceCode = new aria.widget.SourceCode(); diff --git a/examples/js/utils.js b/examples/js/utils.js index 812d29cfd4..adb0e2b748 100644 --- a/examples/js/utils.js +++ b/examples/js/utils.js @@ -24,7 +24,7 @@ aria.KeyCode = { UP: 38, RIGHT: 39, DOWN: 40, - DELETE: 46 + DELETE: 46, }; aria.Utils = aria.Utils || {}; @@ -55,9 +55,11 @@ 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') { + if ( + item.parentNode && + item.parentNode.removeChild && + typeof item.parentNode.removeChild === 'function' + ) { return item.parentNode.removeChild(item); } return false; @@ -98,8 +100,7 @@ aria.Utils.getAncestorBySelector = function (element, selector) { while (ancestor === null) { if (aria.Utils.matches(currentNode.parentNode, selector)) { ancestor = currentNode.parentNode; - } - else { + } else { currentNode = currentNode.parentNode; } } @@ -108,7 +109,7 @@ aria.Utils.getAncestorBySelector = function (element, selector) { }; aria.Utils.hasClass = function (element, className) { - return (new RegExp('(\\s|^)' + className + '(\\s|$)')).test(element.className); + return new RegExp('(\\s|^)' + className + '(\\s|$)').test(element.className); }; aria.Utils.addClass = function (element, className) { diff --git a/examples/landmarks/js/show.js b/examples/landmarks/js/show.js index 71479746f6..042d41be93 100644 --- a/examples/landmarks/js/show.js +++ b/examples/landmarks/js/show.js @@ -17,28 +17,26 @@ 'use strict'; -function showLandmarks (event) { +function showLandmarks(event) { if (typeof window[initLandmarks] !== 'function') { window[initLandmarks] = initLandmarks(); } if (window[initLandmarks].run()) { event.target.innerHTML = 'Hide Landmarks'; - } - else { + } else { event.target.innerHTML = 'Show Landmarks'; } } -function showHeadings (event) { +function showHeadings(event) { if (typeof window[initHeadings] !== 'function') { window[initHeadings] = initHeadings(); } if (window[initHeadings].run()) { event.target.innerHTML = 'Hide Headings'; - } - else { + } else { event.target.innerHTML = 'Show Headings'; } } diff --git a/examples/link/js/link.js b/examples/link/js/link.js index 1bf9a14364..ecd1eba772 100644 --- a/examples/link/js/link.js +++ b/examples/link/js/link.js @@ -1,17 +1,14 @@ /* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -*/ + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + */ 'use strict'; -function goToLink (event, url) { +function goToLink(event, url) { var type = event.type; - if ( - (type === 'click') || - (type === 'keydown' && event.keyCode === 13) - ) { + if (type === 'click' || (type === 'keydown' && event.keyCode === 13)) { window.location.href = url; event.preventDefault(); diff --git a/examples/listbox/js/listbox-collapsible.js b/examples/listbox/js/listbox-collapsible.js index 8dc8750eb5..157f9fc10c 100644 --- a/examples/listbox/js/listbox-collapsible.js +++ b/examples/listbox/js/listbox-collapsible.js @@ -22,8 +22,14 @@ aria.ListboxButton = function (button, listbox) { aria.ListboxButton.prototype.registerEvents = function () { this.button.addEventListener('click', this.showListbox.bind(this)); this.button.addEventListener('keyup', this.checkShow.bind(this)); - this.listbox.listboxNode.addEventListener('blur', this.hideListbox.bind(this)); - this.listbox.listboxNode.addEventListener('keydown', this.checkHide.bind(this)); + this.listbox.listboxNode.addEventListener( + 'blur', + this.hideListbox.bind(this) + ); + this.listbox.listboxNode.addEventListener( + 'keydown', + this.checkHide.bind(this) + ); this.listbox.setHandleFocusChange(this.onFocusChange.bind(this)); }; diff --git a/examples/listbox/js/listbox-rearrangeable.js b/examples/listbox/js/listbox-rearrangeable.js index 74a62e9b46..d8b49aa855 100644 --- a/examples/listbox/js/listbox-rearrangeable.js +++ b/examples/listbox/js/listbox-rearrangeable.js @@ -1,7 +1,7 @@ /* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -*/ + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + */ 'use strict'; @@ -13,15 +13,22 @@ window.addEventListener('load', function () { var ex1 = document.getElementById('ex1'); - var ex1ImportantListbox = new aria.Listbox(document.getElementById('ss_imp_list')); - var ex1UnimportantListbox = new aria.Listbox(document.getElementById('ss_unimp_list')); + var ex1ImportantListbox = new aria.Listbox( + document.getElementById('ss_imp_list') + ); + var ex1UnimportantListbox = new aria.Listbox( + document.getElementById('ss_unimp_list') + ); new aria.Toolbar(ex1.querySelector('[role="toolbar"]')); ex1ImportantListbox.enableMoveUpDown( document.getElementById('ex1-up'), document.getElementById('ex1-down') ); - ex1ImportantListbox.setupMove(document.getElementById('ex1-delete'), ex1UnimportantListbox); + ex1ImportantListbox.setupMove( + document.getElementById('ex1-delete'), + ex1UnimportantListbox + ); ex1ImportantListbox.setHandleItemChange(function (event, items) { var updateText = ''; @@ -30,11 +37,15 @@ window.addEventListener('load', function () { updateText = 'Moved ' + items[0].innerText + ' to important features.'; break; case 'removed': - updateText = 'Moved ' + items[0].innerText + ' to unimportant features.'; + updateText = + 'Moved ' + items[0].innerText + ' to unimportant features.'; break; case 'moved_up': case 'moved_down': - var pos = Array.prototype.indexOf.call(this.listboxNode.children, items[0]); + var pos = Array.prototype.indexOf.call( + this.listboxNode.children, + items[0] + ); pos++; updateText = 'Moved to position ' + pos; break; @@ -45,13 +56,26 @@ window.addEventListener('load', function () { ex1LiveRegion.innerText = updateText; } }); - ex1UnimportantListbox.setupMove(document.getElementById('ex1-add'), ex1ImportantListbox); + ex1UnimportantListbox.setupMove( + document.getElementById('ex1-add'), + ex1ImportantListbox + ); - var ex2ImportantListbox = new aria.Listbox(document.getElementById('ms_imp_list')); - var ex2UnimportantListbox = new aria.Listbox(document.getElementById('ms_unimp_list')); + var ex2ImportantListbox = new aria.Listbox( + document.getElementById('ms_imp_list') + ); + var ex2UnimportantListbox = new aria.Listbox( + document.getElementById('ms_unimp_list') + ); - ex2ImportantListbox.setupMove(document.getElementById('ex2-add'), ex2UnimportantListbox); - ex2UnimportantListbox.setupMove(document.getElementById('ex2-delete'), ex2ImportantListbox); + ex2ImportantListbox.setupMove( + document.getElementById('ex2-add'), + ex2UnimportantListbox + ); + ex2UnimportantListbox.setupMove( + document.getElementById('ex2-delete'), + ex2ImportantListbox + ); ex2UnimportantListbox.setHandleItemChange(function (event, items) { var updateText = ''; var itemText = items.length === 1 ? '1 item' : items.length + ' items'; diff --git a/examples/listbox/js/listbox-scrollable.js b/examples/listbox/js/listbox-scrollable.js index 3479396146..fd7781e4b5 100644 --- a/examples/listbox/js/listbox-scrollable.js +++ b/examples/listbox/js/listbox-scrollable.js @@ -1,7 +1,7 @@ /* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -*/ + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + */ 'use strict'; diff --git a/examples/listbox/js/listbox.js b/examples/listbox/js/listbox.js index a7d9e89801..87c92b7b55 100644 --- a/examples/listbox/js/listbox.js +++ b/examples/listbox/js/listbox.js @@ -1,7 +1,7 @@ /* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -*/ + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + */ 'use strict'; @@ -21,7 +21,9 @@ var aria = aria || {}; */ aria.Listbox = function (listboxNode) { this.listboxNode = listboxNode; - this.activeDescendant = this.listboxNode.getAttribute('aria-activedescendant'); + this.activeDescendant = this.listboxNode.getAttribute( + 'aria-activedescendant' + ); this.multiselectable = this.listboxNode.hasAttribute('aria-multiselectable'); this.moveUpDownEnabled = false; this.siblingList = null; @@ -45,7 +47,10 @@ aria.Listbox.prototype.registerEvents = function () { this.listboxNode.addEventListener('click', this.checkClickItem.bind(this)); if (this.multiselectable) { - this.listboxNode.addEventListener('mousedown', this.checkMouseDown.bind(this)); + this.listboxNode.addEventListener( + 'mousedown', + this.checkMouseDown.bind(this) + ); } }; @@ -95,7 +100,8 @@ aria.Listbox.prototype.checkKeyPress = function (evt) { var key = evt.which || evt.keyCode; var lastActiveId = this.activeDescendant; var allOptions = this.listboxNode.querySelectorAll('[role="option"]'); - var currentItem = document.getElementById(this.activeDescendant) || allOptions[0]; + var currentItem = + document.getElementById(this.activeDescendant) || allOptions[0]; var nextItem = currentItem; if (!currentItem) { @@ -110,8 +116,7 @@ aria.Listbox.prototype.checkKeyPress = function (evt) { if (key === aria.KeyCode.PAGE_UP) { this.moveUpItems(); - } - else { + } else { this.moveDownItems(); } } @@ -119,7 +124,6 @@ aria.Listbox.prototype.checkKeyPress = function (evt) { break; case aria.KeyCode.UP: case aria.KeyCode.DOWN: - if (!this.activeDescendant) { // focus first option if no option was previously focused, and perform no other actions this.focusItem(currentItem); @@ -130,8 +134,7 @@ aria.Listbox.prototype.checkKeyPress = function (evt) { evt.preventDefault(); if (key === aria.KeyCode.UP) { this.moveUpItems(); - } - else { + } else { this.moveDownItems(); } return; @@ -139,8 +142,7 @@ aria.Listbox.prototype.checkKeyPress = function (evt) { if (key === aria.KeyCode.UP) { nextItem = this.findPreviousOption(currentItem); - } - else { + } else { nextItem = this.findNextOption(currentItem); } @@ -171,7 +173,7 @@ aria.Listbox.prototype.checkKeyPress = function (evt) { this.selectRange(this.startRangeIndex, allOptions.length - 1); } break; - case aria.KeyCode.SHIFT: + case aria.KeyCode.SHIFT: this.startRangeIndex = this.getElementIndex(currentItem, allOptions); break; case aria.KeyCode.SPACE: @@ -228,7 +230,7 @@ aria.Listbox.prototype.checkKeyPress = function (evt) { this.selectRange(0, allOptions.length - 1); break; } - // fall through + // fall through default: var itemToFocus = this.findItemToFocus(key); if (itemToFocus) { @@ -263,11 +265,7 @@ aria.Listbox.prototype.findItemToFocus = function (key) { itemList.length ); if (!nextMatch) { - nextMatch = this.findMatchInRange( - itemList, - 0, - searchIndex - ); + nextMatch = this.findMatchInRange(itemList, 0, searchIndex); } return nextMatch; }; @@ -282,7 +280,9 @@ aria.Listbox.prototype.getElementIndex = function (option, options) { /* Return the next listbox option, if it exists; otherwise, returns null */ aria.Listbox.prototype.findNextOption = function (currentOption) { - var allOptions = Array.prototype.slice.call(this.listboxNode.querySelectorAll('[role="option"]')); // get options array + var allOptions = Array.prototype.slice.call( + this.listboxNode.querySelectorAll('[role="option"]') + ); // get options array var currentOptionIndex = allOptions.indexOf(currentOption); var nextOption = null; @@ -295,7 +295,9 @@ aria.Listbox.prototype.findNextOption = function (currentOption) { /* Return the previous listbox option, if it exists; otherwise, returns null */ aria.Listbox.prototype.findPreviousOption = function (currentOption) { - var allOptions = Array.prototype.slice.call(this.listboxNode.querySelectorAll('[role="option"]')); // get options array + var allOptions = Array.prototype.slice.call( + this.listboxNode.querySelectorAll('[role="option"]') + ); // get options array var currentOptionIndex = allOptions.indexOf(currentOption); var previousOption = null; @@ -311,13 +313,20 @@ aria.Listbox.prototype.clearKeysSoFarAfterDelay = function () { clearTimeout(this.keyClear); this.keyClear = null; } - this.keyClear = setTimeout((function () { - this.keysSoFar = ''; - this.keyClear = null; - }).bind(this), 500); + this.keyClear = setTimeout( + function () { + this.keysSoFar = ''; + this.keyClear = null; + }.bind(this), + 500 + ); }; -aria.Listbox.prototype.findMatchInRange = function (list, startIndex, endIndex) { +aria.Listbox.prototype.findMatchInRange = function ( + list, + startIndex, + endIndex +) { // Find the first item starting with the keysSoFar substring, searching in // the specified range of items for (var n = startIndex; n < endIndex; n++) { @@ -354,7 +363,11 @@ aria.Listbox.prototype.checkClickItem = function (evt) { * Prevent text selection on shift + click for multiselect listboxes */ aria.Listbox.prototype.checkMouseDown = function (evt) { - if (this.multiselectable && evt.shiftKey && evt.target.getAttribute('role') === 'option') { + if ( + this.multiselectable && + evt.shiftKey && + evt.target.getAttribute('role') === 'option' + ) { evt.preventDefault(); } }; @@ -421,12 +434,12 @@ aria.Listbox.prototype.focusItem = function (element) { /** * Helper function to check if a number is within a range; no side effects. */ -aria.Listbox.prototype.checkInRange = function(index, start, end) { +aria.Listbox.prototype.checkInRange = function (index, start, end) { var rangeStart = start < end ? start : end; var rangeEnd = start < end ? end : start; return index >= rangeStart && index <= rangeEnd; -} +}; /** * Select a range of options @@ -434,8 +447,10 @@ aria.Listbox.prototype.checkInRange = function(index, start, end) { aria.Listbox.prototype.selectRange = function (start, end) { // get start/end indices var allOptions = this.listboxNode.querySelectorAll('[role="option"]'); - var startIndex = typeof start === 'number' ? start : this.getElementIndex(start, allOptions); - var endIndex = typeof end === 'number' ? end : this.getElementIndex(end, allOptions); + var startIndex = + typeof start === 'number' ? start : this.getElementIndex(start, allOptions); + var endIndex = + typeof end === 'number' ? end : this.getElementIndex(end, allOptions); for (var index = 0; index < allOptions.length; index++) { var selected = this.checkInRange(index, startIndex, endIndex); @@ -448,31 +463,34 @@ aria.Listbox.prototype.selectRange = function (start, end) { /** * Check for selected options and update moveButton, if applicable */ -aria.Listbox.prototype.updateMoveButton = function() { +aria.Listbox.prototype.updateMoveButton = function () { if (!this.moveButton) { return; } if (this.listboxNode.querySelector('[aria-selected="true"]')) { this.moveButton.setAttribute('aria-disabled', 'false'); - } - else { + } else { this.moveButton.setAttribute('aria-disabled', 'true'); } -} +}; /** * Check if the selected option is in view, and scroll if not */ aria.Listbox.prototype.updateScroll = function () { var selectedOption = document.getElementById(this.activeDescendant); - if (selectedOption && this.listboxNode.scrollHeight > this.listboxNode.clientHeight) { - var scrollBottom = this.listboxNode.clientHeight + this.listboxNode.scrollTop; + if ( + selectedOption && + this.listboxNode.scrollHeight > this.listboxNode.clientHeight + ) { + var scrollBottom = + this.listboxNode.clientHeight + this.listboxNode.scrollTop; var elementBottom = selectedOption.offsetTop + selectedOption.offsetHeight; if (elementBottom > scrollBottom) { - this.listboxNode.scrollTop = elementBottom - this.listboxNode.clientHeight; - } - else if (selectedOption.offsetTop < this.listboxNode.scrollTop) { + this.listboxNode.scrollTop = + elementBottom - this.listboxNode.clientHeight; + } else if (selectedOption.offsetTop < this.listboxNode.scrollTop) { this.listboxNode.scrollTop = selectedOption.offsetTop; } } @@ -498,8 +516,7 @@ aria.Listbox.prototype.checkUpDownButtons = function () { if (this.upButton) { if (activeElement.previousElementSibling) { this.upButton.setAttribute('aria-disabled', false); - } - else { + } else { this.upButton.setAttribute('aria-disabled', 'true'); } } @@ -507,8 +524,7 @@ aria.Listbox.prototype.checkUpDownButtons = function () { if (this.downButton) { if (activeElement.nextElementSibling) { this.downButton.setAttribute('aria-disabled', false); - } - else { + } else { this.downButton.setAttribute('aria-disabled', 'true'); } } @@ -526,11 +542,13 @@ aria.Listbox.prototype.addItems = function (items) { return false; } - items.forEach((function (item) { - this.defocusItem(item); - this.toggleSelectItem(item); - this.listboxNode.append(item); - }).bind(this)); + items.forEach( + function (item) { + this.defocusItem(item); + this.toggleSelectItem(item); + this.listboxNode.append(item); + }.bind(this) + ); if (!this.activeDescendant) { this.focusItem(items[0]); @@ -553,22 +571,23 @@ aria.Listbox.prototype.deleteItems = function () { if (this.multiselectable) { itemsToDelete = this.listboxNode.querySelectorAll('[aria-selected="true"]'); - } - else if (this.activeDescendant) { - itemsToDelete = [ document.getElementById(this.activeDescendant) ]; + } else if (this.activeDescendant) { + itemsToDelete = [document.getElementById(this.activeDescendant)]; } if (!itemsToDelete || !itemsToDelete.length) { return []; } - itemsToDelete.forEach((function (item) { - item.remove(); + itemsToDelete.forEach( + function (item) { + item.remove(); - if (item.id === this.activeDescendant) { - this.clearActiveDescendant(); - } - }).bind(this)); + if (item.id === this.activeDescendant) { + this.clearActiveDescendant(); + } + }.bind(this) + ); this.handleItemChange('removed', itemsToDelete); @@ -598,7 +617,7 @@ aria.Listbox.prototype.moveUpItems = function () { if (previousItem) { this.listboxNode.insertBefore(currentItem, previousItem); - this.handleItemChange('moved_up', [ currentItem ]); + this.handleItemChange('moved_up', [currentItem]); } this.checkUpDownButtons(); @@ -619,7 +638,7 @@ aria.Listbox.prototype.moveDownItems = function () { if (nextItem) { this.listboxNode.insertBefore(nextItem, currentItem); - this.handleItemChange('moved_down', [ currentItem ]); + this.handleItemChange('moved_down', [currentItem]); } this.checkUpDownButtons(); diff --git a/examples/listbox/js/toolbar.js b/examples/listbox/js/toolbar.js index 43155dea4f..9e90d9d789 100644 --- a/examples/listbox/js/toolbar.js +++ b/examples/listbox/js/toolbar.js @@ -1,7 +1,7 @@ /* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -*/ + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + */ 'use strict'; @@ -31,7 +31,10 @@ aria.Toolbar = function (toolbarNode) { * Register events for the toolbar interactions */ aria.Toolbar.prototype.registerEvents = function () { - this.toolbarNode.addEventListener('keydown', this.checkFocusChange.bind(this)); + this.toolbarNode.addEventListener( + 'keydown', + this.checkFocusChange.bind(this) + ); this.toolbarNode.addEventListener('click', this.checkClickItem.bind(this)); }; diff --git a/examples/menu-button/js/MenuItemAction.js b/examples/menu-button/js/MenuItemAction.js index 75422efb90..80af6074c5 100644 --- a/examples/menu-button/js/MenuItemAction.js +++ b/examples/menu-button/js/MenuItemAction.js @@ -1,47 +1,46 @@ /* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -* -* File: MenuItem.js -* -* Desc: Popup Menu Menuitem widget that implements ARIA Authoring Practices -*/ + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * File: MenuItem.js + * + * Desc: Popup Menu Menuitem widget that implements ARIA Authoring Practices + */ 'use strict'; /* -* @constructor MenuItem -* -* @desc -* Wrapper object for a simple menu item in a popup menu -* -* @param domNode -* The DOM element node that serves as the menu item container. -* The menuObj PopupMenu is responsible for checking that it has -* requisite metadata, e.g. role="menuitem". -* -* @param menuObj -* The object that is a wrapper for the PopupMenu DOM element that -* contains the menu item DOM element. See PopupMenuAction.js -*/ + * @constructor MenuItem + * + * @desc + * Wrapper object for a simple menu item in a popup menu + * + * @param domNode + * The DOM element node that serves as the menu item container. + * The menuObj PopupMenu is responsible for checking that it has + * requisite metadata, e.g. role="menuitem". + * + * @param menuObj + * The object that is a wrapper for the PopupMenu DOM element that + * contains the menu item DOM element. See PopupMenuAction.js + */ var PopupMenuItem = function (domNode, popupMenuObj) { - - this.domNode = domNode; + this.domNode = domNode; this.popupMenu = popupMenuObj; 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 + TAB: 9, + RETURN: 13, + ESC: 27, + SPACE: 32, + PAGEUP: 33, + PAGEDOWN: 34, + END: 35, + HOME: 36, + LEFT: 37, + UP: 38, + RIGHT: 39, + DOWN: 40, }); }; @@ -52,13 +51,12 @@ PopupMenuItem.prototype.init = function () { this.domNode.setAttribute('role', 'menuitem'); } - this.domNode.addEventListener('keydown', this.handleKeydown.bind(this)); - this.domNode.addEventListener('click', this.handleClick.bind(this)); - this.domNode.addEventListener('focus', this.handleFocus.bind(this)); - this.domNode.addEventListener('blur', this.handleBlur.bind(this)); - this.domNode.addEventListener('mouseover', this.handleMouseover.bind(this)); - this.domNode.addEventListener('mouseout', this.handleMouseout.bind(this)); - + this.domNode.addEventListener('keydown', this.handleKeydown.bind(this)); + this.domNode.addEventListener('click', this.handleClick.bind(this)); + this.domNode.addEventListener('focus', this.handleFocus.bind(this)); + this.domNode.addEventListener('blur', this.handleBlur.bind(this)); + this.domNode.addEventListener('mouseover', this.handleMouseover.bind(this)); + this.domNode.addEventListener('mouseout', this.handleMouseout.bind(this)); }; /* EVENT HANDLERS */ @@ -67,11 +65,11 @@ PopupMenuItem.prototype.handleKeydown = function (event) { var flag = false, char = event.key; - function isPrintableCharacter (str) { + function isPrintableCharacter(str) { return str.length === 1 && str.match(/\S/); } - if (event.ctrlKey || event.altKey || event.metaKey) { + if (event.ctrlKey || event.altKey || event.metaKey) { return; } @@ -79,9 +77,7 @@ PopupMenuItem.prototype.handleKeydown = function (event) { if (isPrintableCharacter(char)) { this.popupMenu.setFocusByFirstCharacter(this, char); } - } - else { - + } else { switch (event.keyCode) { case this.keyCode.SPACE: flag = true; @@ -159,7 +155,6 @@ PopupMenuItem.prototype.handleBlur = function (event) { PopupMenuItem.prototype.handleMouseover = function (event) { this.popupMenu.hasHover = true; this.popupMenu.open(); - }; PopupMenuItem.prototype.handleMouseout = function (event) { diff --git a/examples/menu-button/js/MenuItemActionActivedescendant.js b/examples/menu-button/js/MenuItemActionActivedescendant.js index 599f7551d5..72dce15880 100644 --- a/examples/menu-button/js/MenuItemActionActivedescendant.js +++ b/examples/menu-button/js/MenuItemActionActivedescendant.js @@ -1,29 +1,29 @@ /* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -* -* File: MenuItem.js -* -* Desc: Popup Menu Menuitem widget that implements ARIA Authoring Practices -*/ + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * File: MenuItem.js + * + * Desc: Popup Menu Menuitem widget that implements ARIA Authoring Practices + */ 'use strict'; /* -* @constructor MenuItem -* -* @desc -* Wrapper object for a simple menu item in a popup menu -* -* @param domNode -* The DOM element node that serves as the menu item container. -* The menuObj PopupMenu is responsible for checking that it has -* requisite metadata, e.g. role="menuitem". -* -* @param menuObj -* The object that is a wrapper for the PopupMenu DOM element that -* contains the menu item DOM element. See PopupMenuAction.js -*/ + * @constructor MenuItem + * + * @desc + * Wrapper object for a simple menu item in a popup menu + * + * @param domNode + * The DOM element node that serves as the menu item container. + * The menuObj PopupMenu is responsible for checking that it has + * requisite metadata, e.g. role="menuitem". + * + * @param menuObj + * The object that is a wrapper for the PopupMenu DOM element that + * contains the menu item DOM element. See PopupMenuAction.js + */ var MenuItem = function (domNode, menuObj) { this.domNode = domNode; this.menu = menuObj; @@ -36,9 +36,9 @@ MenuItem.prototype.init = function () { this.domNode.setAttribute('role', 'menuitem'); } - this.domNode.addEventListener('click', this.handleClick.bind(this)); - this.domNode.addEventListener('mouseover', this.handleMouseover.bind(this)); - this.domNode.addEventListener('mouseout', this.handleMouseout.bind(this)); + this.domNode.addEventListener('click', this.handleClick.bind(this)); + this.domNode.addEventListener('mouseover', this.handleMouseover.bind(this)); + this.domNode.addEventListener('mouseout', this.handleMouseout.bind(this)); }; /* EVENT HANDLERS */ diff --git a/examples/menu-button/js/MenuItemLinks.js b/examples/menu-button/js/MenuItemLinks.js index d307d68f8c..c16af95165 100644 --- a/examples/menu-button/js/MenuItemLinks.js +++ b/examples/menu-button/js/MenuItemLinks.js @@ -1,47 +1,46 @@ /* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -* -* File: MenuItemLinks.js -* -* Desc: Popup Menu Menuitem widget that implements ARIA Authoring Practices -*/ + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * File: MenuItemLinks.js + * + * Desc: Popup Menu Menuitem widget that implements ARIA Authoring Practices + */ 'use strict'; /* -* @constructor MenuItemLinks -* -* @desc -* Wrapper object for a simple menu item in a popup menu -* -* @param domNode -* The DOM element node that serves as the menu item container. -* The menuObj PopupMenu is responsible for checking that it has -* requisite metadata, e.g. role="menuitem". -* -* @param menuObj -* The object that is a wrapper for the PopupMenu DOM element that -* contains the menu item DOM element. See PopupMenu.js -*/ + * @constructor MenuItemLinks + * + * @desc + * Wrapper object for a simple menu item in a popup menu + * + * @param domNode + * The DOM element node that serves as the menu item container. + * The menuObj PopupMenu is responsible for checking that it has + * requisite metadata, e.g. role="menuitem". + * + * @param menuObj + * The object that is a wrapper for the PopupMenu DOM element that + * contains the menu item DOM element. See PopupMenu.js + */ var MenuItemLinks = function (domNode, menuObj) { - this.domNode = domNode; this.menu = menuObj; 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 + TAB: 9, + RETURN: 13, + ESC: 27, + SPACE: 32, + PAGEUP: 33, + PAGEDOWN: 34, + END: 35, + HOME: 36, + LEFT: 37, + UP: 38, + RIGHT: 39, + DOWN: 40, }); }; @@ -52,13 +51,12 @@ MenuItemLinks.prototype.init = function () { this.domNode.setAttribute('role', 'menuitem'); } - this.domNode.addEventListener('keydown', this.handleKeydown.bind(this)); - this.domNode.addEventListener('click', this.handleClick.bind(this)); - this.domNode.addEventListener('focus', this.handleFocus.bind(this)); - this.domNode.addEventListener('blur', this.handleBlur.bind(this)); - this.domNode.addEventListener('mouseover', this.handleMouseover.bind(this)); - this.domNode.addEventListener('mouseout', this.handleMouseout.bind(this)); - + this.domNode.addEventListener('keydown', this.handleKeydown.bind(this)); + this.domNode.addEventListener('click', this.handleClick.bind(this)); + this.domNode.addEventListener('focus', this.handleFocus.bind(this)); + this.domNode.addEventListener('blur', this.handleBlur.bind(this)); + this.domNode.addEventListener('mouseover', this.handleMouseover.bind(this)); + this.domNode.addEventListener('mouseout', this.handleMouseout.bind(this)); }; /* EVENT HANDLERS */ @@ -67,11 +65,17 @@ MenuItemLinks.prototype.handleKeydown = function (event) { var flag = false, char = event.key; - function isPrintableCharacter (str) { + function isPrintableCharacter(str) { return str.length === 1 && str.match(/\S/); } - if (event.ctrlKey || event.altKey || event.metaKey || (event.keyCode === this.keyCode.SPACE) || (event.keyCode === this.keyCode.RETURN)) { + if ( + event.ctrlKey || + event.altKey || + event.metaKey || + event.keyCode === this.keyCode.SPACE || + event.keyCode === this.keyCode.RETURN + ) { return; } @@ -85,10 +89,8 @@ MenuItemLinks.prototype.handleKeydown = function (event) { this.menu.setFocusToController(); this.menu.close(true); } - } - else { + } else { switch (event.keyCode) { - case this.keyCode.ESC: this.menu.setFocusToController(); this.menu.close(true); @@ -153,7 +155,6 @@ MenuItemLinks.prototype.handleBlur = function (event) { MenuItemLinks.prototype.handleMouseover = function (event) { this.menu.hasHover = true; this.menu.open(); - }; MenuItemLinks.prototype.handleMouseout = function (event) { diff --git a/examples/menu-button/js/Menubutton.js b/examples/menu-button/js/Menubutton.js index fed9daa1e1..3b39b933f9 100644 --- a/examples/menu-button/js/Menubutton.js +++ b/examples/menu-button/js/Menubutton.js @@ -1,62 +1,60 @@ /* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -* -* File: Menubutton.js -* -* Desc: Menubutton widget that implements ARIA Authoring Practices -*/ + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * File: Menubutton.js + * + * Desc: Menubutton widget that implements ARIA Authoring Practices + */ 'use strict'; /* -* @constructor MenuButton -* -* @desc -* Object that configures menu item elements by setting tabIndex -* and registering itself to handle pertinent events. -* -* While menuitem elements handle many keydown events, as well as -* focus and blur events, they do not maintain any state variables, -* delegating those responsibilities to its associated menu object. -* -* Consequently, it is only necessary to create one instance of -* MenubuttonItem from within the menu object; its configure method -* can then be called on each menuitem element. -* -* @param domNode -* The DOM element node that serves as the menu item container. -* The menuObj PopupMenu is responsible for checking that it has -* requisite metadata, e.g. role="menuitem". -* -* -*/ + * @constructor MenuButton + * + * @desc + * Object that configures menu item elements by setting tabIndex + * and registering itself to handle pertinent events. + * + * While menuitem elements handle many keydown events, as well as + * focus and blur events, they do not maintain any state variables, + * delegating those responsibilities to its associated menu object. + * + * Consequently, it is only necessary to create one instance of + * MenubuttonItem from within the menu object; its configure method + * can then be called on each menuitem element. + * + * @param domNode + * The DOM element node that serves as the menu item container. + * The menuObj PopupMenu is responsible for checking that it has + * requisite metadata, e.g. role="menuitem". + * + * + */ var Menubutton = function (domNode) { - - this.domNode = domNode; + this.domNode = domNode; this.popupMenu = false; this.hasFocus = false; this.hasHover = false; 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 + TAB: 9, + RETURN: 13, + ESC: 27, + SPACE: 32, + PAGEUP: 33, + PAGEDOWN: 34, + END: 35, + HOME: 36, + LEFT: 37, + UP: 38, + RIGHT: 39, + DOWN: 40, }); }; Menubutton.prototype.init = function () { - this.domNode.setAttribute('aria-haspopup', 'true'); this.domNode.addEventListener('keydown', this.handleKeydown.bind(this)); @@ -68,19 +66,19 @@ Menubutton.prototype.init = function () { // initialize pop up menus - var popupMenu = document.getElementById(this.domNode.getAttribute('aria-controls')); + var popupMenu = document.getElementById( + this.domNode.getAttribute('aria-controls') + ); if (popupMenu) { if (popupMenu.getAttribute('aria-activedescendant')) { this.popupMenu = new PopupMenuActionActivedescendant(popupMenu, this); this.popupMenu.init(); - } - else { + } else { this.popupMenu = new PopupMenuAction(popupMenu, this); this.popupMenu.init(); } } - }; Menubutton.prototype.handleKeydown = function (event) { @@ -118,8 +116,7 @@ Menubutton.prototype.handleKeydown = function (event) { Menubutton.prototype.handleClick = function (event) { if (this.domNode.getAttribute('aria-expanded') == 'true') { this.popupMenu.close(true); - } - else { + } else { this.popupMenu.open(); this.popupMenu.setFocusToFirstItem(); } @@ -132,7 +129,6 @@ Menubutton.prototype.handleFocus = function (event) { Menubutton.prototype.handleBlur = function (event) { this.popupMenu.hasFocus = false; setTimeout(this.popupMenu.close.bind(this.popupMenu, false), 300); - }; Menubutton.prototype.handleMouseover = function (event) { diff --git a/examples/menu-button/js/Menubutton2.js b/examples/menu-button/js/Menubutton2.js index 23dad838a4..5f7a082aad 100644 --- a/examples/menu-button/js/Menubutton2.js +++ b/examples/menu-button/js/Menubutton2.js @@ -1,79 +1,78 @@ /* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -* -* File: Menubutton.js -* -* Desc: Menubutton Menuitem widget that implements ARIA Authoring Practices -*/ + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * File: Menubutton.js + * + * Desc: Menubutton Menuitem widget that implements ARIA Authoring Practices + */ 'use strict'; /* -* @constructor MenubuttonItem -* -* @desc -* Object that configures menu item elements by setting tabIndex -* and registering itself to handle pertinent events. -* -* While menuitem elements handle many keydown events, as well as -* focus and blur events, they do not maintain any state variables, -* delegating those responsibilities to its associated menu object. -* -* Consequently, it is only necessary to create one instance of -* MenubuttonItem from within the menu object; its configure method -* can then be called on each menuitem element. -* -* @param domNode -* The DOM element node that serves as the menu item container. -* The menuObj PopupMenu is responsible for checking that it has -* requisite metadata, e.g. role="menuitem". -* -*/ + * @constructor MenubuttonItem + * + * @desc + * Object that configures menu item elements by setting tabIndex + * and registering itself to handle pertinent events. + * + * While menuitem elements handle many keydown events, as well as + * focus and blur events, they do not maintain any state variables, + * delegating those responsibilities to its associated menu object. + * + * Consequently, it is only necessary to create one instance of + * MenubuttonItem from within the menu object; its configure method + * can then be called on each menuitem element. + * + * @param domNode + * The DOM element node that serves as the menu item container. + * The menuObj PopupMenu is responsible for checking that it has + * requisite metadata, e.g. role="menuitem". + * + */ var Menubutton = function (domNode) { - - this.domNode = domNode; + this.domNode = domNode; this.popupMenu = false; this.hasFocus = false; this.hasHover = false; 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 + TAB: 9, + RETURN: 13, + ESC: 27, + SPACE: 32, + PAGEUP: 33, + PAGEDOWN: 34, + END: 35, + HOME: 36, + LEFT: 37, + UP: 38, + RIGHT: 39, + DOWN: 40, }); }; Menubutton.prototype.init = function () { - this.domNode.setAttribute('aria-haspopup', 'true'); - this.domNode.addEventListener('keydown', this.handleKeydown.bind(this)); - this.domNode.addEventListener('click', this.handleClick.bind(this)); - this.domNode.addEventListener('focus', this.handleFocus.bind(this)); - this.domNode.addEventListener('blur', this.handleBlur.bind(this)); - this.domNode.addEventListener('mouseover', this.handleMouseover.bind(this)); - this.domNode.addEventListener('mouseout', this.handleMouseout.bind(this)); + this.domNode.addEventListener('keydown', this.handleKeydown.bind(this)); + this.domNode.addEventListener('click', this.handleClick.bind(this)); + this.domNode.addEventListener('focus', this.handleFocus.bind(this)); + this.domNode.addEventListener('blur', this.handleBlur.bind(this)); + this.domNode.addEventListener('mouseover', this.handleMouseover.bind(this)); + this.domNode.addEventListener('mouseout', this.handleMouseout.bind(this)); // initialize pop up menus - var popupMenu = document.getElementById(this.domNode.getAttribute('aria-controls')); + var popupMenu = document.getElementById( + this.domNode.getAttribute('aria-controls') + ); if (popupMenu) { this.popupMenu = new PopupMenuLinks(popupMenu, this); this.popupMenu.init(); } - }; Menubutton.prototype.handleKeydown = function (event) { @@ -111,8 +110,7 @@ Menubutton.prototype.handleKeydown = function (event) { Menubutton.prototype.handleClick = function (event) { if (this.domNode.getAttribute('aria-expanded') == 'true') { this.popupMenu.close(true); - } - else { + } else { this.popupMenu.open(); this.popupMenu.setFocusToFirstItem(); } diff --git a/examples/menu-button/js/PopupMenuAction.js b/examples/menu-button/js/PopupMenuAction.js index 025d40c92d..b660e10ff8 100644 --- a/examples/menu-button/js/PopupMenuAction.js +++ b/examples/menu-button/js/PopupMenuAction.js @@ -1,37 +1,37 @@ /* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -* -* File: PopupMenuAction.js -* -* Desc: Popup menu widget that implements ARIA Authoring Practices -*/ + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * File: PopupMenuAction.js + * + * Desc: Popup menu widget that implements ARIA Authoring Practices + */ 'use strict'; /* -* @constructor PopupMenuAction -* -* @desc -* Wrapper object for a simple popup menu (without nested submenus) -* -* @param domNode -* The DOM element node that serves as the popup menu container. Each -* child element of domNode that represents a menuitem must have a -* 'role' attribute with value 'menuitem'. -* -* @param controllerObj -* The object that is a wrapper for the DOM element that controls the -* menu, e.g. a button element, with an 'aria-controls' attribute that -* references this menu's domNode. See MenuButton.js -* -* The controller object is expected to have the following properties: -* 1. domNode: The controller object's DOM element node, needed for -* retrieving positioning information. -* 2. hasHover: boolean that indicates whether the controller object's -* domNode has responded to a mouseover event with no subsequent -* mouseout event having occurred. -*/ + * @constructor PopupMenuAction + * + * @desc + * Wrapper object for a simple popup menu (without nested submenus) + * + * @param domNode + * The DOM element node that serves as the popup menu container. Each + * child element of domNode that represents a menuitem must have a + * 'role' attribute with value 'menuitem'. + * + * @param controllerObj + * The object that is a wrapper for the DOM element that controls the + * menu, e.g. a button element, with an 'aria-controls' attribute that + * references this menu's domNode. See MenuButton.js + * + * The controller object is expected to have the following properties: + * 1. domNode: The controller object's DOM element node, needed for + * retrieving positioning information. + * 2. hasHover: boolean that indicates whether the controller object's + * domNode has responded to a mouseover event with no subsequent + * mouseout event having occurred. + */ var PopupMenuAction = function (domNode, controllerObj) { var elementChildren, msgPrefix = 'PopupMenu constructor argument domNode '; @@ -51,7 +51,9 @@ var PopupMenuAction = function (domNode, controllerObj) { while (childElement) { var menuitem = childElement.firstElementChild; if (menuitem && menuitem === 'A') { - throw new Error(msgPrefix + 'Cannot have descendant elements are A elements.'); + throw new Error( + msgPrefix + 'Cannot have descendant elements are A elements.' + ); } childElement = childElement.nextElementSibling; } @@ -59,49 +61,61 @@ var PopupMenuAction = function (domNode, controllerObj) { this.domNode = domNode; this.controller = controllerObj; - this.menuitems = []; // see PopupMenu init method - this.firstChars = []; // see PopupMenu init method + this.menuitems = []; // see PopupMenu init method + this.firstChars = []; // see PopupMenu init method - this.firstItem = null; // see PopupMenu init method - this.lastItem = null; // see PopupMenu init method + this.firstItem = null; // see PopupMenu init method + this.lastItem = null; // see PopupMenu init method - this.hasFocus = false; // see MenuItem handleFocus, handleBlur - this.hasHover = false; // see PopupMenu handleMouseover, handleMouseout + this.hasFocus = false; // see MenuItem handleFocus, handleBlur + this.hasHover = false; // see PopupMenu handleMouseover, handleMouseout }; /* -* @method PopupMenuAction.prototype.init -* -* @desc -* Add domNode event listeners for mouseover and mouseout. Traverse -* domNode children to configure each menuitem and populate menuitems -* array. Initialize firstItem and lastItem properties. -*/ + * @method PopupMenuAction.prototype.init + * + * @desc + * Add domNode event listeners for mouseover and mouseout. Traverse + * domNode children to configure each menuitem and populate menuitems + * array. Initialize firstItem and lastItem properties. + */ PopupMenuAction.prototype.init = function () { - var childElement, menuElement, firstChildElement, menuItem, textContent, numItems, label; + var childElement, + menuElement, + firstChildElement, + menuItem, + textContent, + numItems, + label; // Configure the domNode itself this.domNode.tabIndex = -1; this.domNode.setAttribute('role', 'menu'); - if (!this.domNode.getAttribute('aria-labelledby') && !this.domNode.getAttribute('aria-label') && !this.domNode.getAttribute('title')) { + if ( + !this.domNode.getAttribute('aria-labelledby') && + !this.domNode.getAttribute('aria-label') && + !this.domNode.getAttribute('title') + ) { label = this.controller.domNode.innerHTML; this.domNode.setAttribute('aria-label', label); } this.domNode.addEventListener('mouseover', this.handleMouseover.bind(this)); - this.domNode.addEventListener('mouseout', this.handleMouseout.bind(this)); + this.domNode.addEventListener('mouseout', this.handleMouseout.bind(this)); // Traverse the element children of domNode: configure each with // menuitem role behavior and store reference in menuitems array. var menuElements = this.domNode.getElementsByTagName('LI'); for (var i = 0; i < menuElements.length; i++) { - menuElement = menuElements[i]; - if (!menuElement.firstElementChild && menuElement.getAttribute('role') != 'separator') { + if ( + !menuElement.firstElementChild && + menuElement.getAttribute('role') != 'separator' + ) { menuItem = new PopupMenuItem(menuElement, this); menuItem.init(); this.menuitems.push(menuItem); @@ -114,7 +128,7 @@ PopupMenuAction.prototype.init = function () { numItems = this.menuitems.length; if (numItems > 0) { this.firstItem = this.menuitems[0]; - this.lastItem = this.menuitems[numItems - 1]; + this.lastItem = this.menuitems[numItems - 1]; } }; @@ -138,12 +152,10 @@ PopupMenuAction.prototype.setFocusToController = function (command) { if (command === 'previous') { this.controller.menubutton.setFocusToPreviousItem(this.controller); - } - else { + } else { if (command === 'next') { this.controller.menubutton.setFocusToNextItem(this.controller); - } - else { + } else { this.controller.domNode.focus(); } } @@ -162,8 +174,7 @@ PopupMenuAction.prototype.setFocusToPreviousItem = function (currentItem) { if (currentItem === this.firstItem) { this.lastItem.domNode.focus(); - } - else { + } else { index = this.menuitems.indexOf(currentItem); this.menuitems[index - 1].domNode.focus(); } @@ -174,14 +185,16 @@ PopupMenuAction.prototype.setFocusToNextItem = function (currentItem) { if (currentItem === this.lastItem) { this.firstItem.domNode.focus(); - } - else { + } else { index = this.menuitems.indexOf(currentItem); this.menuitems[index + 1].domNode.focus(); } }; -PopupMenuAction.prototype.setFocusByFirstCharacter = function (currentItem, char) { +PopupMenuAction.prototype.setFocusByFirstCharacter = function ( + currentItem, + char +) { var start, index; char = char.toLowerCase(); @@ -224,7 +237,7 @@ PopupMenuAction.prototype.open = function () { // set CSS properties this.domNode.style.display = 'block'; this.domNode.style.position = 'absolute'; - this.domNode.style.top = rect.height + 'px'; + this.domNode.style.top = rect.height + 'px'; this.domNode.style.left = '0px'; // set aria-expanded attribute @@ -236,7 +249,10 @@ PopupMenuAction.prototype.close = function (force) { force = false; } - if (force || (!this.hasFocus && !this.hasHover && !this.controller.hasHover)) { + if ( + force || + (!this.hasFocus && !this.hasHover && !this.controller.hasHover) + ) { this.domNode.style.display = 'none'; this.controller.domNode.removeAttribute('aria-expanded'); } diff --git a/examples/menu-button/js/PopupMenuActionActivedescendant.js b/examples/menu-button/js/PopupMenuActionActivedescendant.js index eb07f59610..c31acbb9ce 100644 --- a/examples/menu-button/js/PopupMenuActionActivedescendant.js +++ b/examples/menu-button/js/PopupMenuActionActivedescendant.js @@ -1,37 +1,37 @@ /* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -* -* File: PopupMenuActionActivedescendant.js -* -* Desc: Popup menu widget that implements ARIA Authoring Practices -*/ + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * File: PopupMenuActionActivedescendant.js + * + * Desc: Popup menu widget that implements ARIA Authoring Practices + */ 'use strict'; /* -* @constructor PopupMenuActionActivedescendant -* -* @desc -* Wrapper object for a simple popup menu (without nested submenus) -* -* @param domNode -* The DOM element node that serves as the popup menu container. Each -* child element of domNode that represents a menuitem must have a -* 'role' attribute with value 'menuitem'. -* -* @param controllerObj -* The object that is a wrapper for the DOM element that controls the -* menu, e.g. a button element, with an 'aria-controls' attribute that -* references this menu's domNode. See MenuButton.js -* -* The controller object is expected to have the following properties: -* 1. domNode: The controller object's DOM element node, needed for -* retrieving positioning information. -* 2. hasHover: boolean that indicates whether the controller object's -* domNode has responded to a mouseover event with no subsequent -* mouseout event having occurred. -*/ + * @constructor PopupMenuActionActivedescendant + * + * @desc + * Wrapper object for a simple popup menu (without nested submenus) + * + * @param domNode + * The DOM element node that serves as the popup menu container. Each + * child element of domNode that represents a menuitem must have a + * 'role' attribute with value 'menuitem'. + * + * @param controllerObj + * The object that is a wrapper for the DOM element that controls the + * menu, e.g. a button element, with an 'aria-controls' attribute that + * references this menu's domNode. See MenuButton.js + * + * The controller object is expected to have the following properties: + * 1. domNode: The controller object's DOM element node, needed for + * retrieving positioning information. + * 2. hasHover: boolean that indicates whether the controller object's + * domNode has responded to a mouseover event with no subsequent + * mouseout event having occurred. + */ var PopupMenuActionActivedescendant = function (domNode, controllerObj) { var elementChildren, msgPrefix = 'PopupMenu constructor argument domNode '; @@ -51,7 +51,9 @@ var PopupMenuActionActivedescendant = function (domNode, controllerObj) { while (childElement) { var menuitem = childElement.firstElementChild; if (menuitem && menuitem === 'A') { - throw new Error(msgPrefix + 'Cannot have descendant elements are A elements.'); + throw new Error( + msgPrefix + 'Cannot have descendant elements are A elements.' + ); } childElement = childElement.nextElementSibling; } @@ -61,55 +63,63 @@ var PopupMenuActionActivedescendant = function (domNode, controllerObj) { this.domNode = domNode; this.controller = controllerObj; - this.menuitems = []; // see PopupMenu init method - this.firstChars = []; // see PopupMenu init method + this.menuitems = []; // see PopupMenu init method + this.firstChars = []; // see PopupMenu init method - this.firstItem = null; // see PopupMenu init method - this.lastItem = null; // see PopupMenu init method + this.firstItem = null; // see PopupMenu init method + this.lastItem = null; // see PopupMenu init method - this.hasFocus = false; // see MenuItem handleFocus, handleBlur - this.hasHover = false; // see PopupMenu handleMouseover, handleMouseout + this.hasFocus = false; // see MenuItem handleFocus, handleBlur + this.hasHover = false; // see PopupMenu handleMouseover, handleMouseout 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 + TAB: 9, + RETURN: 13, + ESC: 27, + SPACE: 32, + PAGEUP: 33, + PAGEDOWN: 34, + END: 35, + HOME: 36, + LEFT: 37, + UP: 38, + RIGHT: 39, + DOWN: 40, }); - }; /* -* @method PopupMenuActionActivedescendant.prototype.init -* -* @desc -* Add domNode event listeners for mouseover and mouseout. Traverse -* domNode children to configure each menuitem and populate menuitems -* array. Initialize firstItem and lastItem properties. -*/ + * @method PopupMenuActionActivedescendant.prototype.init + * + * @desc + * Add domNode event listeners for mouseover and mouseout. Traverse + * domNode children to configure each menuitem and populate menuitems + * array. Initialize firstItem and lastItem properties. + */ PopupMenuActionActivedescendant.prototype.init = function () { - var childElement, menuElement, firstChildElement, menuItem, textContent, label; + var childElement, + menuElement, + firstChildElement, + menuItem, + textContent, + label; // Configure the domNode itself this.domNode.tabIndex = 0; this.domNode.setAttribute('role', 'menu'); - if (!this.domNode.getAttribute('aria-labelledby') && !this.domNode.getAttribute('aria-label') && !this.domNode.getAttribute('title')) { + if ( + !this.domNode.getAttribute('aria-labelledby') && + !this.domNode.getAttribute('aria-label') && + !this.domNode.getAttribute('title') + ) { label = this.controller.domNode.innerHTML; this.domNode.setAttribute('aria-label', label); } - this.domNode.addEventListener('keydown', this.handleKeydown.bind(this)); + this.domNode.addEventListener('keydown', this.handleKeydown.bind(this)); this.domNode.addEventListener('mouseover', this.handleMouseover.bind(this)); - this.domNode.addEventListener('mouseout', this.handleMouseout.bind(this)); + this.domNode.addEventListener('mouseout', this.handleMouseout.bind(this)); this.domNode.addEventListener('blur', this.handleBlur.bind(this)); // Traverse the element children of domNode: configure each with @@ -117,9 +127,11 @@ PopupMenuActionActivedescendant.prototype.init = function () { var menuElements = this.domNode.getElementsByTagName('LI'); for (var i = 0; i < menuElements.length; i++) { - menuElement = menuElements[i]; - if (!menuElement.firstElementChild && menuElement.getAttribute('role') != 'separator') { + if ( + !menuElement.firstElementChild && + menuElement.getAttribute('role') != 'separator' + ) { menuItem = new MenuItem(menuElement, this); menuItem.init(); this.menuitems.push(menuItem); @@ -132,20 +144,19 @@ PopupMenuActionActivedescendant.prototype.init = function () { if (this.menuitems.length > 0) { this.firstItem = this.menuitems[0]; this.currentItem = this.firstItem; - this.lastItem = this.menuitems[this.menuitems.length - 1]; + this.lastItem = this.menuitems[this.menuitems.length - 1]; } - }; PopupMenuActionActivedescendant.prototype.handleKeydown = function (event) { var flag = false, char = event.key, clickEvent; - function isPrintableCharacter (str) { + function isPrintableCharacter(str) { return str.length === 1 && str.match(/\S/); } - if (event.ctrlKey || event.altKey || event.metaKey) { + if (event.ctrlKey || event.altKey || event.metaKey) { return; } @@ -153,10 +164,8 @@ PopupMenuActionActivedescendant.prototype.handleKeydown = function (event) { if (isPrintableCharacter(char)) { this.setFocusByFirstCharacter(char); } - } - else { + } else { switch (event.keyCode) { - case this.keyCode.SPACE: flag = true; break; @@ -166,12 +175,11 @@ PopupMenuActionActivedescendant.prototype.handleKeydown = function (event) { // and let the event handler handleClick do the housekeeping. try { clickEvent = new MouseEvent('click', { - 'view': window, - 'bubbles': true, - 'cancelable': true + view: window, + bubbles: true, + cancelable: true, }); - } - catch (err) { + } catch (err) { if (document.createEvent) { // DOM Level 3 for IE 9+ clickEvent = document.createEvent('MouseEvents'); @@ -268,8 +276,7 @@ PopupMenuActionActivedescendant.prototype.setFocusToPreviousItem = function () { if (this.currentItem === this.firstItem) { this.setFocusToLastItem(); - } - else { + } else { index = this.menuitems.indexOf(this.currentItem); this.setFocus(this.menuitems[index - 1]); } @@ -280,14 +287,15 @@ PopupMenuActionActivedescendant.prototype.setFocusToNextItem = function () { if (this.currentItem === this.lastItem) { this.setFocusToFirstItem(); - } - else { + } else { index = this.menuitems.indexOf(this.currentItem); this.setFocus(this.menuitems[index + 1]); } }; -PopupMenuActionActivedescendant.prototype.setFocusByFirstCharacter = function (char) { +PopupMenuActionActivedescendant.prototype.setFocusByFirstCharacter = function ( + char +) { var start, index; char = char.toLowerCase(); @@ -312,7 +320,10 @@ PopupMenuActionActivedescendant.prototype.setFocusByFirstCharacter = function (c } }; -PopupMenuActionActivedescendant.prototype.getIndexFirstChars = function (startIndex, char) { +PopupMenuActionActivedescendant.prototype.getIndexFirstChars = function ( + startIndex, + char +) { for (var i = startIndex; i < this.firstChars.length; i++) { if (char === this.firstChars[i]) { return i; @@ -324,7 +335,10 @@ PopupMenuActionActivedescendant.prototype.getIndexFirstChars = function (startIn PopupMenuActionActivedescendant.prototype.getCurrentItem = function () { var id = this.domNode.getAttribute('aria-activedescendant'); if (!id) { - this.domNode.setAttribute('aria-activedescendant', this.firstItem.domNode.id); + this.domNode.setAttribute( + 'aria-activedescendant', + this.firstItem.domNode.id + ); return this.firstItem; } for (var i = 0; i < this.menuitems.length; i++) { @@ -346,7 +360,7 @@ PopupMenuActionActivedescendant.prototype.open = function () { // set CSS properties this.domNode.style.display = 'block'; this.domNode.style.position = 'absolute'; - this.domNode.style.top = rect.height + 'px'; + this.domNode.style.top = rect.height + 'px'; this.domNode.style.left = '0px'; this.hasFocus = true; @@ -357,7 +371,6 @@ PopupMenuActionActivedescendant.prototype.open = function () { }; PopupMenuActionActivedescendant.prototype.close = function (force) { - if (typeof force !== 'boolean') { force = false; } diff --git a/examples/menu-button/js/PopupMenuLinks.js b/examples/menu-button/js/PopupMenuLinks.js index f8a5fb82d5..ca898dfd3c 100644 --- a/examples/menu-button/js/PopupMenuLinks.js +++ b/examples/menu-button/js/PopupMenuLinks.js @@ -1,37 +1,37 @@ /* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -* -* File: PopupMenuLinks.js -* -* Desc: Popup menu Links widget that implements ARIA Authoring Practices -*/ + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * File: PopupMenuLinks.js + * + * Desc: Popup menu Links widget that implements ARIA Authoring Practices + */ 'use strict'; /* -* @constructor PopupMenuLinks -* -* @desc -* Wrapper object for a simple popup menu (without nested submenus) -* -* @param domNode -* The DOM element node that serves as the popup menu container. Each -* child element of domNode that represents a menuitem must have a -* 'role' attribute with value 'menuitem'. -* -* @param controllerObj -* The object that is a wrapper for the DOM element that controls the -* menu, e.g. a button element, with an 'aria-controls' attribute that -* references this menu's domNode. See MenuButton.js -* -* The controller object is expected to have the following properties: -* 1. domNode: The controller object's DOM element node, needed for -* retrieving positioning information. -* 2. hasHover: boolean that indicates whether the controller object's -* domNode has responded to a mouseover event with no subsequent -* mouseout event having occurred. -*/ + * @constructor PopupMenuLinks + * + * @desc + * Wrapper object for a simple popup menu (without nested submenus) + * + * @param domNode + * The DOM element node that serves as the popup menu container. Each + * child element of domNode that represents a menuitem must have a + * 'role' attribute with value 'menuitem'. + * + * @param controllerObj + * The object that is a wrapper for the DOM element that controls the + * menu, e.g. a button element, with an 'aria-controls' attribute that + * references this menu's domNode. See MenuButton.js + * + * The controller object is expected to have the following properties: + * 1. domNode: The controller object's DOM element node, needed for + * retrieving positioning information. + * 2. hasHover: boolean that indicates whether the controller object's + * domNode has responded to a mouseover event with no subsequent + * mouseout event having occurred. + */ var PopupMenuLinks = function (domNode, controllerObj) { var elementChildren, msgPrefix = 'PopupMenuLinks constructor argument domNode '; @@ -51,7 +51,9 @@ var PopupMenuLinks = function (domNode, controllerObj) { while (childElement) { var menuitem = childElement.firstElementChild; if (menuitem && menuitem.tagName !== 'A') { - throw new Error(msgPrefix + 'has descendant elements that are not A elements.'); + throw new Error( + msgPrefix + 'has descendant elements that are not A elements.' + ); } childElement = childElement.nextElementSibling; } @@ -59,24 +61,24 @@ var PopupMenuLinks = function (domNode, controllerObj) { this.domNode = domNode; this.controller = controllerObj; - this.menuitems = []; // see PopupMenuLinks init method - this.firstChars = []; // see PopupMenuLinks init method + this.menuitems = []; // see PopupMenuLinks init method + this.firstChars = []; // see PopupMenuLinks init method - this.firstItem = null; // see PopupMenuLinks init method - this.lastItem = null; // see PopupMenuLinks init method + this.firstItem = null; // see PopupMenuLinks init method + this.lastItem = null; // see PopupMenuLinks init method - this.hasFocus = false; // see MenuItemLinks handleFocus, handleBlur - this.hasHover = false; // see PopupMenuLinks handleMouseover, handleMouseout + this.hasFocus = false; // see MenuItemLinks handleFocus, handleBlur + this.hasHover = false; // see PopupMenuLinks handleMouseover, handleMouseout }; /* -* @method PopupMenuLinks.prototype.init -* -* @desc -* Add domNode event listeners for mouseover and mouseout. Traverse -* domNode children to configure each menuitem and populate menuitems -* array. Initialize firstItem and lastItem properties. -*/ + * @method PopupMenuLinks.prototype.init + * + * @desc + * Add domNode event listeners for mouseover and mouseout. Traverse + * domNode children to configure each menuitem and populate menuitems + * array. Initialize firstItem and lastItem properties. + */ PopupMenuLinks.prototype.init = function () { var childElement, menuElement, menuItem, textContent, numItems, label; @@ -85,13 +87,17 @@ PopupMenuLinks.prototype.init = function () { this.domNode.setAttribute('role', 'menu'); - if (!this.domNode.getAttribute('aria-labelledby') && !this.domNode.getAttribute('aria-label') && !this.domNode.getAttribute('title')) { + if ( + !this.domNode.getAttribute('aria-labelledby') && + !this.domNode.getAttribute('aria-label') && + !this.domNode.getAttribute('title') + ) { label = this.controller.domNode.innerHTML; this.domNode.setAttribute('aria-label', label); } this.domNode.addEventListener('mouseover', this.handleMouseover.bind(this)); - this.domNode.addEventListener('mouseout', this.handleMouseout.bind(this)); + this.domNode.addEventListener('mouseout', this.handleMouseout.bind(this)); // Traverse the element children of domNode: configure each with // menuitem role behavior and store reference in menuitems array. @@ -114,7 +120,7 @@ PopupMenuLinks.prototype.init = function () { numItems = this.menuitems.length; if (numItems > 0) { this.firstItem = this.menuitems[0]; - this.lastItem = this.menuitems[numItems - 1]; + this.lastItem = this.menuitems[numItems - 1]; } }; @@ -138,12 +144,10 @@ PopupMenuLinks.prototype.setFocusToController = function (command) { if (command === 'previous') { this.controller.menubar.setFocusToPreviousItem(this.controller); - } - else { + } else { if (command === 'next') { this.controller.menubar.setFocusToNextItem(this.controller); - } - else { + } else { this.controller.domNode.focus(); } } @@ -162,8 +166,7 @@ PopupMenuLinks.prototype.setFocusToPreviousItem = function (currentItem) { if (currentItem === this.firstItem) { this.lastItem.domNode.focus(); - } - else { + } else { index = this.menuitems.indexOf(currentItem); this.menuitems[index - 1].domNode.focus(); } @@ -174,14 +177,16 @@ PopupMenuLinks.prototype.setFocusToNextItem = function (currentItem) { if (currentItem === this.lastItem) { this.firstItem.domNode.focus(); - } - else { + } else { index = this.menuitems.indexOf(currentItem); this.menuitems[index + 1].domNode.focus(); } }; -PopupMenuLinks.prototype.setFocusByFirstCharacter = function (currentItem, char) { +PopupMenuLinks.prototype.setFocusByFirstCharacter = function ( + currentItem, + char +) { var start, index; char = char.toLowerCase(); @@ -224,7 +229,7 @@ PopupMenuLinks.prototype.open = function () { // set CSS properties this.domNode.style.display = 'block'; this.domNode.style.position = 'absolute'; - this.domNode.style.top = rect.height + 'px'; + this.domNode.style.top = rect.height + 'px'; this.domNode.style.left = '0px'; // set aria-expanded attribute @@ -232,8 +237,10 @@ PopupMenuLinks.prototype.open = function () { }; PopupMenuLinks.prototype.close = function (force) { - - if (force || (!this.hasFocus && !this.hasHover && !this.controller.hasHover)) { + if ( + force || + (!this.hasFocus && !this.hasHover && !this.controller.hasHover) + ) { this.domNode.style.display = 'none'; this.controller.domNode.removeAttribute('aria-expanded'); } diff --git a/examples/menubar/js/menubar-editor.js b/examples/menubar/js/menubar-editor.js index 3f26973421..905b4ce87a 100644 --- a/examples/menubar/js/menubar-editor.js +++ b/examples/menubar/js/menubar-editor.js @@ -1,16 +1,15 @@ /* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -* -* File: menubar-editor.js -* -* Desc: Creates a menubar to control the styling of text in a textarea element -*/ + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * File: menubar-editor.js + * + * Desc: Creates a menubar to control the styling of text in a textarea element + */ 'use strict'; var MenubarEditor = function (domNode) { - this.domNode = domNode; this.menubarNode = domNode.querySelector('[role=menubar]'); this.textareaNode = domNode.querySelector('textarea'); @@ -25,14 +24,18 @@ var MenubarEditor = function (domNode) { this.firstMenuitem = {}; // see Menubar init method this.lastMenuitem = {}; // see Menubar init method - this.initMenu(this.menubarNode) + this.initMenu(this.menubarNode); this.domNode.addEventListener('focusin', this.handleFocusin.bind(this)); this.domNode.addEventListener('focusout', this.handleFocusout.bind(this)); - window.addEventListener('mousedown', this.handleBackgroundMousedown.bind(this), true); + window.addEventListener( + 'mousedown', + this.handleBackgroundMousedown.bind(this), + true + ); }; -MenubarEditor.prototype.getMenuitems = function(domNode) { +MenubarEditor.prototype.getMenuitems = function (domNode) { var nodes = []; var initMenu = this.initMenu.bind(this); @@ -102,7 +105,7 @@ MenubarEditor.prototype.initMenu = function (menu) { this.firstMenuitem[menuId] = null; this.lastMenuitem[menuId] = null; - for(i = 0; i < menuitems.length; i++) { + for (i = 0; i < menuitems.length; i++) { menuitem = menuitems[i]; role = menuitem.getAttribute('role'); @@ -117,23 +120,24 @@ MenubarEditor.prototype.initMenu = function (menu) { menuitem.addEventListener('keydown', this.handleKeydown.bind(this)); menuitem.addEventListener('click', this.handleMenuitemClick.bind(this)); - menuitem.addEventListener('mouseover', this.handleMenuitemMouseover.bind(this)); + menuitem.addEventListener( + 'mouseover', + this.handleMenuitemMouseover.bind(this) + ); - if( !this.firstMenuitem[menuId]) { + if (!this.firstMenuitem[menuId]) { if (this.hasPopup(menuitem)) { menuitem.tabIndex = 0; } this.firstMenuitem[menuId] = menuitem; } this.lastMenuitem[menuId] = menuitem; - } }; /* MenubarEditor FOCUS MANAGEMENT METHODS */ MenubarEditor.prototype.setFocusToMenuitem = function (menuId, newMenuitem) { - var isAnyPopupOpen = this.isAnyPopupOpen(); this.closePopupAll(newMenuitem); @@ -142,8 +146,7 @@ MenubarEditor.prototype.setFocusToMenuitem = function (menuId, newMenuitem) { if (isAnyPopupOpen) { this.openPopup(newMenuitem); } - } - else { + } else { var menu = this.getMenu(newMenuitem); var cmi = menu.previousElementSibling; if (!this.isOpen(cmi)) { @@ -153,7 +156,7 @@ MenubarEditor.prototype.setFocusToMenuitem = function (menuId, newMenuitem) { if (this.hasPopup(newMenuitem)) { if (this.menuitemGroups[menuId]) { - this.menuitemGroups[menuId].forEach(function(item) { + this.menuitemGroups[menuId].forEach(function (item) { item.tabIndex = -1; }); } @@ -161,7 +164,6 @@ MenubarEditor.prototype.setFocusToMenuitem = function (menuId, newMenuitem) { } newMenuitem.focus(); - }; MenubarEditor.prototype.setFocusToFirstMenuitem = function (menuId) { @@ -172,15 +174,17 @@ MenubarEditor.prototype.setFocusToLastMenuitem = function (menuId) { this.setFocusToMenuitem(menuId, this.lastMenuitem[menuId]); }; -MenubarEditor.prototype.setFocusToPreviousMenuitem = function (menuId, currentMenuitem) { +MenubarEditor.prototype.setFocusToPreviousMenuitem = function ( + menuId, + currentMenuitem +) { var newMenuitem, index; if (currentMenuitem === this.firstMenuitem[menuId]) { newMenuitem = this.lastMenuitem[menuId]; - } - else { + } else { index = this.menuitemGroups[menuId].indexOf(currentMenuitem); - newMenuitem = this.menuitemGroups[menuId][ index - 1 ]; + newMenuitem = this.menuitemGroups[menuId][index - 1]; } this.setFocusToMenuitem(menuId, newMenuitem); @@ -188,29 +192,35 @@ MenubarEditor.prototype.setFocusToPreviousMenuitem = function (menuId, currentMe return newMenuitem; }; -MenubarEditor.prototype.setFocusToNextMenuitem = function (menuId, currentMenuitem) { +MenubarEditor.prototype.setFocusToNextMenuitem = function ( + menuId, + currentMenuitem +) { var newMenuitem, index; if (currentMenuitem === this.lastMenuitem[menuId]) { newMenuitem = this.firstMenuitem[menuId]; - } - else { + } else { index = this.menuitemGroups[menuId].indexOf(currentMenuitem); - newMenuitem = this.menuitemGroups[menuId][ index + 1 ]; + newMenuitem = this.menuitemGroups[menuId][index + 1]; } this.setFocusToMenuitem(menuId, newMenuitem); return newMenuitem; }; -MenubarEditor.prototype.setFocusByFirstCharacter = function (menuId, currentMenuitem, char) { +MenubarEditor.prototype.setFocusByFirstCharacter = function ( + menuId, + currentMenuitem, + char +) { var start, index; char = char.toLowerCase(); // Get start index for search based on position of currentItem start = this.menuitemGroups[menuId].indexOf(currentMenuitem) + 1; - if (start >= this.menuitemGroups[menuId].length) { + if (start >= this.menuitemGroups[menuId].length) { start = 0; } @@ -230,7 +240,11 @@ MenubarEditor.prototype.setFocusByFirstCharacter = function (menuId, currentMenu // Utilities -MenubarEditor.prototype.getIndexFirstChars = function (menuId, startIndex, char) { +MenubarEditor.prototype.getIndexFirstChars = function ( + menuId, + startIndex, + char +) { for (var i = startIndex; i < this.firstChars[menuId].length; i++) { if (char === this.firstChars[menuId][i]) { return i; @@ -239,21 +253,19 @@ MenubarEditor.prototype.getIndexFirstChars = function (menuId, startIndex, char) return -1; }; -MenubarEditor.prototype.isPrintableCharacter = function(str) { - return str.length === 1 && str.match(/\S/); +MenubarEditor.prototype.isPrintableCharacter = function (str) { + return str.length === 1 && str.match(/\S/); }; -MenubarEditor.prototype.getIdFromAriaLabel = function(node) { - var id = node.getAttribute('aria-label') +MenubarEditor.prototype.getIdFromAriaLabel = function (node) { + var id = node.getAttribute('aria-label'); if (id) { id = id.trim().toLowerCase().replace(' ', '-').replace('/', '-'); } return id; }; - -MenubarEditor.prototype.getMenuOrientation = function(node) { - +MenubarEditor.prototype.getMenuOrientation = function (node) { var orientation = node.getAttribute('aria-orientation'); if (!orientation) { @@ -276,17 +288,13 @@ MenubarEditor.prototype.getMenuOrientation = function(node) { return orientation; }; -MenubarEditor.prototype.getDataOption = function(node) { - +MenubarEditor.prototype.getDataOption = function (node) { var option = false; var hasOption = node.hasAttribute('data-option'); var role = node.hasAttribute('role'); if (!hasOption) { - - while (node && !hasOption && - (role !== 'menu') && - (role !== 'menubar')) { + while (node && !hasOption && role !== 'menu' && role !== 'menubar') { node = node.parentNode; if (node) { role = node.getAttribute('role'); @@ -302,19 +310,16 @@ MenubarEditor.prototype.getDataOption = function(node) { return option; }; -MenubarEditor.prototype.getGroupId = function(node) { - +MenubarEditor.prototype.getGroupId = function (node) { var id = false; var role = node.getAttribute('role'); - while (node && (role !== 'group') && - (role !== 'menu') && - (role !== 'menubar')) { + while (node && role !== 'group' && role !== 'menu' && role !== 'menubar') { node = node.parentNode; if (node) { role = node.getAttribute('role'); } - } + } if (node) { id = role + '-' + this.getIdFromAriaLabel(node); @@ -323,12 +328,11 @@ MenubarEditor.prototype.getGroupId = function(node) { return id; }; -MenubarEditor.prototype.getMenuId = function(node) { - +MenubarEditor.prototype.getMenuId = function (node) { var id = false; var role = node.getAttribute('role'); - while (node && (role !== 'menu') && (role !== 'menubar')) { + while (node && role !== 'menu' && role !== 'menubar') { node = node.parentNode; if (node) { role = node.getAttribute('role'); @@ -342,14 +346,13 @@ MenubarEditor.prototype.getMenuId = function(node) { return id; }; -MenubarEditor.prototype.getMenu = function(menuitem) { - +MenubarEditor.prototype.getMenu = function (menuitem) { var id = false; var menu = menuitem; var role = menuitem.getAttribute('role'); - while (menu && (role !== 'menu') && (role !== 'menubar')) { - menu = menu.parentNode + while (menu && role !== 'menu' && role !== 'menubar') { + menu = menu.parentNode; if (menu) { role = menu.getAttribute('role'); } @@ -358,7 +361,7 @@ MenubarEditor.prototype.getMenu = function(menuitem) { return menu; }; -MenubarEditor.prototype.toggleCheckbox = function(menuitem) { +MenubarEditor.prototype.toggleCheckbox = function (menuitem) { if (menuitem.getAttribute('aria-checked') === 'true') { menuitem.setAttribute('aria-checked', 'false'); return false; @@ -367,18 +370,17 @@ MenubarEditor.prototype.toggleCheckbox = function(menuitem) { return true; }; -MenubarEditor.prototype.setRadioButton = function(menuitem) { +MenubarEditor.prototype.setRadioButton = function (menuitem) { var groupId = this.getGroupId(menuitem); var radiogroupItems = this.menuitemGroups[groupId]; - radiogroupItems.forEach( function (item) { - item.setAttribute('aria-checked', 'false') + radiogroupItems.forEach(function (item) { + item.setAttribute('aria-checked', 'false'); }); menuitem.setAttribute('aria-checked', 'true'); return menuitem.textContent; }; -MenubarEditor.prototype.updateFontSizeMenu = function(menuId) { - +MenubarEditor.prototype.updateFontSizeMenu = function (menuId) { var fontSizeMenuitems = this.menuitemGroups[menuId]; var currentValue = this.actionManager.getFontSize(); @@ -391,8 +393,7 @@ MenubarEditor.prototype.updateFontSizeMenu = function(menuId) { case 'font-smaller': if (currentValue === 'x-small') { mi.setAttribute('aria-disabled', 'true'); - } - else { + } else { mi.removeAttribute('aria-disabled'); } break; @@ -400,8 +401,7 @@ MenubarEditor.prototype.updateFontSizeMenu = function(menuId) { case 'font-larger': if (currentValue === 'x-large') { mi.setAttribute('aria-disabled', 'true'); - } - else { + } else { mi.removeAttribute('aria-disabled'); } break; @@ -409,17 +409,13 @@ MenubarEditor.prototype.updateFontSizeMenu = function(menuId) { default: if (currentValue === value) { mi.setAttribute('aria-checked', 'true'); - } - else { + } else { mi.setAttribute('aria-checked', 'false'); } break; - } } - - -} +}; // Popup menu methods @@ -433,7 +429,6 @@ MenubarEditor.prototype.isAnyPopupOpen = function () { }; MenubarEditor.prototype.openPopup = function (menuitem) { - // set aria-expanded attribute var popupMenu = menuitem.nextElementSibling; @@ -441,7 +436,7 @@ MenubarEditor.prototype.openPopup = function (menuitem) { // set CSS properties popupMenu.style.position = 'absolute'; - popupMenu.style.top = (rect.height - 3) + 'px'; + popupMenu.style.top = rect.height - 3 + 'px'; popupMenu.style.left = '0px'; popupMenu.style.zIndex = 100; popupMenu.style.display = 'block'; @@ -449,7 +444,6 @@ MenubarEditor.prototype.openPopup = function (menuitem) { menuitem.setAttribute('aria-expanded', 'true'); return this.getMenuId(popupMenu); - }; MenubarEditor.prototype.closePopup = function (menuitem) { @@ -460,10 +454,8 @@ MenubarEditor.prototype.closePopup = function (menuitem) { menuitem.setAttribute('aria-expanded', 'false'); menuitem.nextElementSibling.style.display = 'none'; menuitem.nextElementSibling.style.zIndex = 0; - } - } - else { + } else { menu = this.getMenu(menuitem); cmi = menu.previousElementSibling; cmi.setAttribute('aria-expanded', 'false'); @@ -533,14 +525,13 @@ MenubarEditor.prototype.handleKeydown = function (event) { switch (key) { case ' ': case 'Enter': - if (this.hasPopup(tgt)) { + if (this.hasPopup(tgt)) { popupMenuId = this.openPopup(tgt); this.setFocusToFirstMenuitem(popupMenuId); - } - else { + } else { role = tgt.getAttribute('role'); option = this.getDataOption(tgt); - switch(role) { + switch (role) { case 'menuitem': this.actionManager.setOption(option, tgt.textContent); break; @@ -565,15 +556,14 @@ MenubarEditor.prototype.handleKeydown = function (event) { this.closePopup(tgt); } flag = true; - break; + break; case 'ArrowDown': case 'Down': if (this.menuOrientation[menuId] === 'vertical') { this.setFocusToNextMenuitem(menuId, tgt); flag = true; - } - else { + } else { if (this.hasPopup(tgt)) { popupMenuId = this.openPopup(tgt); this.setFocusToFirstMenuitem(popupMenuId); @@ -584,8 +574,8 @@ MenubarEditor.prototype.handleKeydown = function (event) { case 'Esc': case 'Escape': - this.closePopup(tgt); - flag = true; + this.closePopup(tgt); + flag = true; break; case 'Left': @@ -593,8 +583,7 @@ MenubarEditor.prototype.handleKeydown = function (event) { if (this.menuOrientation[menuId] === 'horizontal') { this.setFocusToPreviousMenuitem(menuId, tgt); flag = true; - } - else { + } else { mi = this.closePopup(tgt); id = this.getMenuId(mi); mi = this.setFocusToPreviousMenuitem(id, mi); @@ -607,8 +596,7 @@ MenubarEditor.prototype.handleKeydown = function (event) { if (this.menuOrientation[menuId] === 'horizontal') { this.setFocusToNextMenuitem(menuId, tgt); flag = true; - } - else { + } else { mi = this.closePopup(tgt); id = this.getMenuId(mi); mi = this.setFocusToNextMenuitem(id, mi); @@ -621,8 +609,7 @@ MenubarEditor.prototype.handleKeydown = function (event) { if (this.menuOrientation[menuId] === 'vertical') { this.setFocusToPreviousMenuitem(menuId, tgt); flag = true; - } - else { + } else { if (this.hasPopup(tgt)) { popupMenuId = this.openPopup(tgt); this.setFocusToLastMenuitem(popupMenuId); @@ -668,16 +655,14 @@ MenubarEditor.prototype.handleMenuitemClick = function (event) { if (this.hasPopup(tgt)) { if (this.isOpen(tgt)) { this.closePopup(tgt); - } - else { + } else { var menuId = this.openPopup(tgt); this.setFocusToMenuitem(menuId, tgt); } - } - else { + } else { var role = tgt.getAttribute('role'); var option = this.getDataOption(tgt); - switch(role) { + switch (role) { case 'menuitem': this.actionManager.setOption(option, tgt.textContent); break; @@ -704,7 +689,6 @@ MenubarEditor.prototype.handleMenuitemClick = function (event) { event.stopPropagation(); event.preventDefault(); - }; MenubarEditor.prototype.handleMenuitemMouseover = function (event) { @@ -719,7 +703,7 @@ MenubarEditor.prototype.handleMenuitemMouseover = function (event) { window.addEventListener('load', function () { var menubarEditors = document.querySelectorAll('.menubar-editor'); - for(var i=0; i < menubarEditors.length; i++) { + for (var i = 0; i < menubarEditors.length; i++) { var menubarEditor = new MenubarEditor(menubarEditors[i]); } }); diff --git a/examples/menubar/js/menubar-navigation.js b/examples/menubar/js/menubar-navigation.js index 860943ec4f..af27ed0f38 100644 --- a/examples/menubar/js/menubar-navigation.js +++ b/examples/menubar/js/menubar-navigation.js @@ -1,619 +1,630 @@ -/* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -* -* File: menubar-navigation.js -* -* Desc: Creates a menubar of hierarchical set of links -*/ - -'use strict'; - -var MenubarNavigation = function (domNode) { - - this.domNode = domNode; - - - this.popups = []; - this.menuitemGroups = {}; - this.menuOrientation = {}; - this.isPopup = {}; - this.isPopout = {}; - this.openPopups = false; - - this.firstChars = {}; // see Menubar init method - this.firstMenuitem = {}; // see Menubar init method - this.lastMenuitem = {}; // see Menubar init method - - this.initMenu(domNode, 0); - - domNode.addEventListener('focusin', this.handleMenubarFocusin.bind(this)); - domNode.addEventListener('focusout', this.handleMenubarFocusout.bind(this)); - - window.addEventListener('mousedown', this.handleBackgroundMousedown.bind(this), true); -}; - -MenubarNavigation.prototype.getMenuitems = function(domNode, depth) { - var nodes = []; - - var initMenu = this.initMenu.bind(this); - var menuitemGroups = this.menuitemGroups; - var popups = this.popups; - - function findMenuitems(node) { - var role, flag; - - while (node) { - flag = true; - role = node.getAttribute('role'); - - if (role) { - role = role.trim().toLowerCase(); - } - - switch (role) { - case 'menu': - node.tabIndex = -1; - initMenu(node, depth + 1); - flag = false; - break; - - case 'menuitem': - if (node.getAttribute('aria-haspopup') === 'true') { - popups.push(node); - } - nodes.push(node); - break; - - default: - break; - } - - if (flag && node.firstElementChild && node.firstElementChild.tagName !== 'svg') { - findMenuitems(node.firstElementChild); - } - - node = node.nextElementSibling; - } - } - - findMenuitems(domNode.firstElementChild); - - return nodes; -}; - -MenubarNavigation.prototype.initMenu = function (menu, depth) { - var menuitems, menuitem, role, nextElement; - - var menuId = this.getMenuId(menu); - - menuitems = this.getMenuitems(menu, depth); - this.menuOrientation[menuId] = this.getMenuOrientation(menu); - - this.isPopup[menuId] = (menu.getAttribute('role') === 'menu') && (depth === 1); - this.isPopout[menuId] = (menu.getAttribute('role') === 'menu') && (depth > 1); - - this.menuitemGroups[menuId] = []; - this.firstChars[menuId] = []; - this.firstMenuitem[menuId] = null; - this.lastMenuitem[menuId] = null; - - for(var i = 0; i < menuitems.length; i++) { - menuitem = menuitems[i]; - role = menuitem.getAttribute('role'); - - if (role.indexOf('menuitem') < 0) { - continue; - } - - menuitem.tabIndex = -1; - this.menuitemGroups[menuId].push(menuitem); - this.firstChars[menuId].push(menuitem.textContent.trim().toLowerCase()[0]); - - menuitem.addEventListener('keydown', this.handleKeydown.bind(this)); - menuitem.addEventListener('click', this.handleMenuitemClick.bind(this)); - - menuitem.addEventListener('mouseover', this.handleMenuitemMouseover.bind(this)); - - if( !this.firstMenuitem[menuId]) { - if (this.hasPopup(menuitem)) { - menuitem.tabIndex = 0; - } - this.firstMenuitem[menuId] = menuitem; - } - this.lastMenuitem[menuId] = menuitem; - - } -}; - -MenubarNavigation.prototype.setFocusToMenuitem = function (menuId, newMenuitem) { - - this.closePopupAll(newMenuitem); - - if (this.menuitemGroups[menuId]) { - this.menuitemGroups[menuId].forEach(function(item) { - if (item === newMenuitem) { - item.tabIndex = 0; - newMenuitem.focus(); - } - else { - item.tabIndex = -1; - } - }); - } -}; - -MenubarNavigation.prototype.setFocusToFirstMenuitem = function (menuId, currentMenuitem) { - this.setFocusToMenuitem(menuId, this.firstMenuitem[menuId]); -}; - -MenubarNavigation.prototype.setFocusToLastMenuitem = function (menuId, currentMenuitem) { - this.setFocusToMenuitem(menuId, this.lastMenuitem[menuId]); -}; - -MenubarNavigation.prototype.setFocusToPreviousMenuitem = function (menuId, currentMenuitem) { - var newMenuitem, index; - - if (currentMenuitem === this.firstMenuitem[menuId]) { - newMenuitem = this.lastMenuitem[menuId]; - } - else { - index = this.menuitemGroups[menuId].indexOf(currentMenuitem); - newMenuitem = this.menuitemGroups[menuId][ index - 1 ]; - } - - this.setFocusToMenuitem(menuId, newMenuitem); - - return newMenuitem; -}; - -MenubarNavigation.prototype.setFocusToNextMenuitem = function (menuId, currentMenuitem) { - var newMenuitem, index; - - if (currentMenuitem === this.lastMenuitem[menuId]) { - newMenuitem = this.firstMenuitem[menuId]; - } - else { - index = this.menuitemGroups[menuId].indexOf(currentMenuitem); - newMenuitem = this.menuitemGroups[menuId][ index + 1 ]; - } - this.setFocusToMenuitem(menuId, newMenuitem); - - return newMenuitem; -}; - -MenubarNavigation.prototype.setFocusByFirstCharacter = function (menuId, currentMenuitem, char) { - var start, index; - - char = char.toLowerCase(); - - // Get start index for search based on position of currentItem - start = this.menuitemGroups[menuId].indexOf(currentMenuitem) + 1; - if (start >= this.menuitemGroups[menuId].length) { - start = 0; - } - - // Check remaining slots in the menu - index = this.getIndexFirstChars(menuId, start, char); - - // If not found in remaining slots, check from beginning - if (index === -1) { - index = this.getIndexFirstChars(menuId, 0, char); - } - - // If match was found... - if (index > -1) { - this.setFocusToMenuitem(menuId, this.menuitemGroups[menuId][index]); - } -}; - -// Utitlities - -MenubarNavigation.prototype.getIndexFirstChars = function (menuId, startIndex, char) { - for (var i = startIndex; i < this.firstChars[menuId].length; i++) { - if (char === this.firstChars[menuId][i]) { - return i; - } - } - return -1; -}; - -MenubarNavigation.prototype.isPrintableCharacter = function(str) { - return str.length === 1 && str.match(/\S/); -}; - -MenubarNavigation.prototype.getIdFromAriaLabel = function(node) { - var id = node.getAttribute('aria-label') - if (id) { - id = id.trim().toLowerCase().replace(' ', '-').replace('/', '-'); - } - return id; -}; - - -MenubarNavigation.prototype.getMenuOrientation = function(node) { - - var orientation = node.getAttribute('aria-orientation'); - - if (!orientation) { - var role = node.getAttribute('role'); - - switch (role) { - case 'menubar': - orientation = 'horizontal'; - break; - - case 'menu': - orientation = 'vertical'; - break; - - default: - break; - } - } - - return orientation; -}; - -MenubarNavigation.prototype.getMenuId = function(node) { - - var id = false; - var role = node.getAttribute('role'); - - while (node && (role !== 'menu') && (role !== 'menubar')) { - node = node.parentNode; - if (node) { - role = node.getAttribute('role'); - } - } - - if (node) { - id = role + '-' + this.getIdFromAriaLabel(node); - } - - return id; -}; - -MenubarNavigation.prototype.getMenu = function(menuitem) { - - var id = false; - var menu = menuitem; - var role = menuitem.getAttribute('role'); - - while (menu && (role !== 'menu') && (role !== 'menubar')) { - menu = menu.parentNode - if (menu) { - role = menu.getAttribute('role'); - } - } - - return menu; -}; - -// Popup menu methods - -MenubarNavigation.prototype.isAnyPopupOpen = function () { - for (var i = 0; i < this.popups.length; i++) { - if (this.popups[i].getAttribute('aria-expanded') === 'true') { - return true; - } - } - return false; -}; - -MenubarNavigation.prototype.openPopup = function (menuId, menuitem) { - - // set aria-expanded attribute - var popupMenu = menuitem.nextElementSibling; - - var rect = menuitem.getBoundingClientRect(); - - // Set CSS properties - if (this.isPopup[menuId]) { - popupMenu.parentNode.style.position = 'relative'; - popupMenu.style.display = 'block'; - popupMenu.style.position = 'absolute'; - popupMenu.style.left = (rect.width + 6) + 'px'; - popupMenu.style.top = '0px'; - popupMenu.style.zIndex = 100; - } - else { - popupMenu.style.display = 'block'; - popupMenu.style.position = 'absolute'; - popupMenu.style.left = '0px'; - popupMenu.style.top = (rect.height + 8)+ 'px'; - popupMenu.style.zIndex = 100; - } - - menuitem.setAttribute('aria-expanded', 'true'); - - return this.getMenuId(popupMenu); - -}; - -MenubarNavigation.prototype.closePopout = function (menuitem) { - var menu, - menuId = this.getMenuId(menuitem), - cmi = menuitem; - - while (this.isPopup[menuId] || this.isPopout[menuId]) { - menu = this.getMenu(cmi); - cmi = menu.previousElementSibling; - menuId = this.getMenuId(cmi); - cmi.setAttribute('aria-expanded', 'false'); - menu.style.display = 'none'; - } - cmi.focus(); - return cmi; -}; - -MenubarNavigation.prototype.closePopup = function (menuitem) { - var menu, - menuId = this.getMenuId(menuitem), - cmi = menuitem; - - if (this.isMenubar(menuId)) { - if (this.isOpen(menuitem)) { - menuitem.setAttribute('aria-expanded', 'false'); - menuitem.nextElementSibling.style.display = 'none'; - } - } - else { - menu = this.getMenu(menuitem); - cmi = menu.previousElementSibling; - cmi.setAttribute('aria-expanded', 'false'); - cmi.focus(); - menu.style.display = 'none'; - } - - return cmi; -}; - -MenubarNavigation.prototype.doesNotContain = function (popup, menuitem) { - if (menuitem) { - return !popup.nextElementSibling.contains(menuitem); - } - return true; -}; - -MenubarNavigation.prototype.closePopupAll = function (menuitem) { - if (typeof menuitem !== 'object') { - menuitem = false; - } - for (var i = 0; i < this.popups.length; i++) { - var popup = this.popups[i]; - if (this.doesNotContain(popup, menuitem) && this.isOpen(popup)) { - var cmi = popup.nextElementSibling; - if (cmi) { - popup.setAttribute('aria-expanded', 'false'); - cmi.style.display = 'none'; - } - } - } -}; - -MenubarNavigation.prototype.hasPopup = function (menuitem) { - return menuitem.getAttribute('aria-haspopup') === 'true'; -}; - -MenubarNavigation.prototype.isOpen = function (menuitem) { - return menuitem.getAttribute('aria-expanded') === 'true'; -}; - -MenubarNavigation.prototype.isMenubar = function (menuId) { - return !this.isPopup[menuId] && !this.isPopout[menuId]; -}; - -MenubarNavigation.prototype.isMenuHorizontal = function (menuitem) { - return this.menuOrientation[menuitem] === 'horizontal'; -}; - -MenubarNavigation.prototype.hasFocus = function () { - return this.domNode.classList.contains('focus'); -}; - -// Menu event handlers - -MenubarNavigation.prototype.handleMenubarFocusin = function (event) { - // if the menubar or any of its menus has focus, add styling hook for hover - this.domNode.classList.add('focus'); -}; - -MenubarNavigation.prototype.handleMenubarFocusout = function (event) { - // remove styling hook for hover on menubar item - this.domNode.classList.remove('focus'); -}; - -MenubarNavigation.prototype.handleKeydown = function (event) { - var tgt = event.currentTarget, - key = event.key, - flag = false, - menuId = this.getMenuId(tgt), - id, - popupMenuId, - mi, - role, - option, - value; - - var isAnyPopupOpen = this.isAnyPopupOpen(); - - switch (key) { - case ' ': - case 'Enter': - if (this.hasPopup(tgt)) { - this.openPopups = true; - popupMenuId = this.openPopup(menuId, tgt); - this.setFocusToFirstMenuitem(popupMenuId); - } - else { - if (tgt.href !== '#') { - this.closePopupAll(); - window.location.href=tgt.href; - } - } - flag = true; - break; - - case 'Esc': - case 'Escape': - this.openPopups = false; - this.closePopup(tgt); - flag = true; - break; - - case 'Up': - case 'ArrowUp': - if (this.isMenuHorizontal(menuId)) { - if (this.hasPopup(tgt)) { - this.openPopups = true; - popupMenuId = this.openPopup(menuId, tgt); - this.setFocusToLastMenuitem(popupMenuId); - } - } - else { - this.setFocusToPreviousMenuitem(menuId, tgt); - } - flag = true; - break; - - case 'ArrowDown': - case 'Down': - if (this.isMenuHorizontal(menuId)) { - if (this.hasPopup(tgt)) { - this.openPopups = true; - popupMenuId = this.openPopup(menuId, tgt); - this.setFocusToFirstMenuitem(popupMenuId); - } - } - else { - this.setFocusToNextMenuitem(menuId, tgt); - } - flag = true; - break; - - case 'Left': - case 'ArrowLeft': - if (this.isMenuHorizontal(menuId)) { - mi = this.setFocusToPreviousMenuitem(menuId, tgt); - if (isAnyPopupOpen) { - this.openPopup(menuId, mi); - } - } - else { - if (this.isPopout[menuId]) { - mi = this.closePopup(tgt); - id = this.getMenuId(mi); - mi = this.setFocusToMenuitem(id, mi); - } - else { - mi = this.closePopup(tgt); - id = this.getMenuId(mi); - mi = this.setFocusToPreviousMenuitem(id, mi); - this.openPopup(id, mi); - } - } - flag = true; - break; - - case 'Right': - case 'ArrowRight': - if (this.isMenuHorizontal(menuId)) { - mi = this.setFocusToNextMenuitem(menuId, tgt); - if (isAnyPopupOpen) { - this.openPopup(menuId, mi); - } - } - else { - if (this.hasPopup(tgt)) { - popupMenuId = this.openPopup(menuId, tgt); - this.setFocusToFirstMenuitem(popupMenuId); - } - else { - mi = this.closePopout(tgt); - id = this.getMenuId(mi); - mi = this.setFocusToNextMenuitem(id, mi); - this.openPopup(id, mi); - } - } - flag = true; - break; - - case 'Home': - case 'PageUp': - this.setFocusToFirstMenuitem(menuId, tgt); - flag = true; - break; - - case 'End': - case 'PageDown': - this.setFocusToLastMenuitem(menuId, tgt); - flag = true; - break; - - case 'Tab': - this.openPopups = false; - this.closePopup(tgt); - break; - - default: - if (this.isPrintableCharacter(key)) { - this.setFocusByFirstCharacter(menuId, tgt, key); - flag = true; - } - break; - } - - if (flag) { - event.stopPropagation(); - event.preventDefault(); - } -}; - -MenubarNavigation.prototype.handleMenuitemClick = function (event) { - var tgt = event.currentTarget; - var menuId = this.getMenuId(tgt); - - if (this.hasPopup(tgt)) { - if (this.isOpen(tgt)) { - this.closePopup(tgt); - } - else { - this.closePopupAll(tgt); - this.openPopup(menuId, tgt); - } - event.stopPropagation(); - event.preventDefault(); - } -}; - -MenubarNavigation.prototype.handleMenuitemMouseover = function (event) { - var tgt = event.currentTarget; - var menuId = this.getMenuId(tgt); - - if (this.hasFocus()) { - this.setFocusToMenuitem(menuId, tgt); - } - - if (this.isAnyPopupOpen() || this.hasFocus()) { - this.closePopupAll(tgt); - if (this.hasPopup(tgt)) { - this.openPopup(menuId, tgt); - } - } -}; - -MenubarNavigation.prototype.handleBackgroundMousedown = function (event) { - if (!this.domNode.contains(event.target)) { - this.closePopupAll(); - } -}; - -// Initialize menubar editor - -window.addEventListener('load', function () { - var menubarNavs = document.querySelectorAll('.menubar-navigation'); - for(var i=0; i < menubarNavs.length; i++) { - var menubarNav = new MenubarNavigation(menubarNavs[i]); - } -}); +/* + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * File: menubar-navigation.js + * + * Desc: Creates a menubar of hierarchical set of links + */ + +'use strict'; + +var MenubarNavigation = function (domNode) { + this.domNode = domNode; + + this.popups = []; + this.menuitemGroups = {}; + this.menuOrientation = {}; + this.isPopup = {}; + this.isPopout = {}; + this.openPopups = false; + + this.firstChars = {}; // see Menubar init method + this.firstMenuitem = {}; // see Menubar init method + this.lastMenuitem = {}; // see Menubar init method + + this.initMenu(domNode, 0); + + domNode.addEventListener('focusin', this.handleMenubarFocusin.bind(this)); + domNode.addEventListener('focusout', this.handleMenubarFocusout.bind(this)); + + window.addEventListener( + 'mousedown', + this.handleBackgroundMousedown.bind(this), + true + ); +}; + +MenubarNavigation.prototype.getMenuitems = function (domNode, depth) { + var nodes = []; + + var initMenu = this.initMenu.bind(this); + var menuitemGroups = this.menuitemGroups; + var popups = this.popups; + + function findMenuitems(node) { + var role, flag; + + while (node) { + flag = true; + role = node.getAttribute('role'); + + if (role) { + role = role.trim().toLowerCase(); + } + + switch (role) { + case 'menu': + node.tabIndex = -1; + initMenu(node, depth + 1); + flag = false; + break; + + case 'menuitem': + if (node.getAttribute('aria-haspopup') === 'true') { + popups.push(node); + } + nodes.push(node); + break; + + default: + break; + } + + if ( + flag && + node.firstElementChild && + node.firstElementChild.tagName !== 'svg' + ) { + findMenuitems(node.firstElementChild); + } + + node = node.nextElementSibling; + } + } + + findMenuitems(domNode.firstElementChild); + + return nodes; +}; + +MenubarNavigation.prototype.initMenu = function (menu, depth) { + var menuitems, menuitem, role, nextElement; + + var menuId = this.getMenuId(menu); + + menuitems = this.getMenuitems(menu, depth); + this.menuOrientation[menuId] = this.getMenuOrientation(menu); + + this.isPopup[menuId] = menu.getAttribute('role') === 'menu' && depth === 1; + this.isPopout[menuId] = menu.getAttribute('role') === 'menu' && depth > 1; + + this.menuitemGroups[menuId] = []; + this.firstChars[menuId] = []; + this.firstMenuitem[menuId] = null; + this.lastMenuitem[menuId] = null; + + for (var i = 0; i < menuitems.length; i++) { + menuitem = menuitems[i]; + role = menuitem.getAttribute('role'); + + if (role.indexOf('menuitem') < 0) { + continue; + } + + menuitem.tabIndex = -1; + this.menuitemGroups[menuId].push(menuitem); + this.firstChars[menuId].push(menuitem.textContent.trim().toLowerCase()[0]); + + menuitem.addEventListener('keydown', this.handleKeydown.bind(this)); + menuitem.addEventListener('click', this.handleMenuitemClick.bind(this)); + + menuitem.addEventListener( + 'mouseover', + this.handleMenuitemMouseover.bind(this) + ); + + if (!this.firstMenuitem[menuId]) { + if (this.hasPopup(menuitem)) { + menuitem.tabIndex = 0; + } + this.firstMenuitem[menuId] = menuitem; + } + this.lastMenuitem[menuId] = menuitem; + } +}; + +MenubarNavigation.prototype.setFocusToMenuitem = function ( + menuId, + newMenuitem +) { + this.closePopupAll(newMenuitem); + + if (this.menuitemGroups[menuId]) { + this.menuitemGroups[menuId].forEach(function (item) { + if (item === newMenuitem) { + item.tabIndex = 0; + newMenuitem.focus(); + } else { + item.tabIndex = -1; + } + }); + } +}; + +MenubarNavigation.prototype.setFocusToFirstMenuitem = function ( + menuId, + currentMenuitem +) { + this.setFocusToMenuitem(menuId, this.firstMenuitem[menuId]); +}; + +MenubarNavigation.prototype.setFocusToLastMenuitem = function ( + menuId, + currentMenuitem +) { + this.setFocusToMenuitem(menuId, this.lastMenuitem[menuId]); +}; + +MenubarNavigation.prototype.setFocusToPreviousMenuitem = function ( + menuId, + currentMenuitem +) { + var newMenuitem, index; + + if (currentMenuitem === this.firstMenuitem[menuId]) { + newMenuitem = this.lastMenuitem[menuId]; + } else { + index = this.menuitemGroups[menuId].indexOf(currentMenuitem); + newMenuitem = this.menuitemGroups[menuId][index - 1]; + } + + this.setFocusToMenuitem(menuId, newMenuitem); + + return newMenuitem; +}; + +MenubarNavigation.prototype.setFocusToNextMenuitem = function ( + menuId, + currentMenuitem +) { + var newMenuitem, index; + + if (currentMenuitem === this.lastMenuitem[menuId]) { + newMenuitem = this.firstMenuitem[menuId]; + } else { + index = this.menuitemGroups[menuId].indexOf(currentMenuitem); + newMenuitem = this.menuitemGroups[menuId][index + 1]; + } + this.setFocusToMenuitem(menuId, newMenuitem); + + return newMenuitem; +}; + +MenubarNavigation.prototype.setFocusByFirstCharacter = function ( + menuId, + currentMenuitem, + char +) { + var start, index; + + char = char.toLowerCase(); + + // Get start index for search based on position of currentItem + start = this.menuitemGroups[menuId].indexOf(currentMenuitem) + 1; + if (start >= this.menuitemGroups[menuId].length) { + start = 0; + } + + // Check remaining slots in the menu + index = this.getIndexFirstChars(menuId, start, char); + + // If not found in remaining slots, check from beginning + if (index === -1) { + index = this.getIndexFirstChars(menuId, 0, char); + } + + // If match was found... + if (index > -1) { + this.setFocusToMenuitem(menuId, this.menuitemGroups[menuId][index]); + } +}; + +// Utitlities + +MenubarNavigation.prototype.getIndexFirstChars = function ( + menuId, + startIndex, + char +) { + for (var i = startIndex; i < this.firstChars[menuId].length; i++) { + if (char === this.firstChars[menuId][i]) { + return i; + } + } + return -1; +}; + +MenubarNavigation.prototype.isPrintableCharacter = function (str) { + return str.length === 1 && str.match(/\S/); +}; + +MenubarNavigation.prototype.getIdFromAriaLabel = function (node) { + var id = node.getAttribute('aria-label'); + if (id) { + id = id.trim().toLowerCase().replace(' ', '-').replace('/', '-'); + } + return id; +}; + +MenubarNavigation.prototype.getMenuOrientation = function (node) { + var orientation = node.getAttribute('aria-orientation'); + + if (!orientation) { + var role = node.getAttribute('role'); + + switch (role) { + case 'menubar': + orientation = 'horizontal'; + break; + + case 'menu': + orientation = 'vertical'; + break; + + default: + break; + } + } + + return orientation; +}; + +MenubarNavigation.prototype.getMenuId = function (node) { + var id = false; + var role = node.getAttribute('role'); + + while (node && role !== 'menu' && role !== 'menubar') { + node = node.parentNode; + if (node) { + role = node.getAttribute('role'); + } + } + + if (node) { + id = role + '-' + this.getIdFromAriaLabel(node); + } + + return id; +}; + +MenubarNavigation.prototype.getMenu = function (menuitem) { + var id = false; + var menu = menuitem; + var role = menuitem.getAttribute('role'); + + while (menu && role !== 'menu' && role !== 'menubar') { + menu = menu.parentNode; + if (menu) { + role = menu.getAttribute('role'); + } + } + + return menu; +}; + +// Popup menu methods + +MenubarNavigation.prototype.isAnyPopupOpen = function () { + for (var i = 0; i < this.popups.length; i++) { + if (this.popups[i].getAttribute('aria-expanded') === 'true') { + return true; + } + } + return false; +}; + +MenubarNavigation.prototype.openPopup = function (menuId, menuitem) { + // set aria-expanded attribute + var popupMenu = menuitem.nextElementSibling; + + var rect = menuitem.getBoundingClientRect(); + + // Set CSS properties + if (this.isPopup[menuId]) { + popupMenu.parentNode.style.position = 'relative'; + popupMenu.style.display = 'block'; + popupMenu.style.position = 'absolute'; + popupMenu.style.left = rect.width + 6 + 'px'; + popupMenu.style.top = '0px'; + popupMenu.style.zIndex = 100; + } else { + popupMenu.style.display = 'block'; + popupMenu.style.position = 'absolute'; + popupMenu.style.left = '0px'; + popupMenu.style.top = rect.height + 8 + 'px'; + popupMenu.style.zIndex = 100; + } + + menuitem.setAttribute('aria-expanded', 'true'); + + return this.getMenuId(popupMenu); +}; + +MenubarNavigation.prototype.closePopout = function (menuitem) { + var menu, + menuId = this.getMenuId(menuitem), + cmi = menuitem; + + while (this.isPopup[menuId] || this.isPopout[menuId]) { + menu = this.getMenu(cmi); + cmi = menu.previousElementSibling; + menuId = this.getMenuId(cmi); + cmi.setAttribute('aria-expanded', 'false'); + menu.style.display = 'none'; + } + cmi.focus(); + return cmi; +}; + +MenubarNavigation.prototype.closePopup = function (menuitem) { + var menu, + menuId = this.getMenuId(menuitem), + cmi = menuitem; + + if (this.isMenubar(menuId)) { + if (this.isOpen(menuitem)) { + menuitem.setAttribute('aria-expanded', 'false'); + menuitem.nextElementSibling.style.display = 'none'; + } + } else { + menu = this.getMenu(menuitem); + cmi = menu.previousElementSibling; + cmi.setAttribute('aria-expanded', 'false'); + cmi.focus(); + menu.style.display = 'none'; + } + + return cmi; +}; + +MenubarNavigation.prototype.doesNotContain = function (popup, menuitem) { + if (menuitem) { + return !popup.nextElementSibling.contains(menuitem); + } + return true; +}; + +MenubarNavigation.prototype.closePopupAll = function (menuitem) { + if (typeof menuitem !== 'object') { + menuitem = false; + } + for (var i = 0; i < this.popups.length; i++) { + var popup = this.popups[i]; + if (this.doesNotContain(popup, menuitem) && this.isOpen(popup)) { + var cmi = popup.nextElementSibling; + if (cmi) { + popup.setAttribute('aria-expanded', 'false'); + cmi.style.display = 'none'; + } + } + } +}; + +MenubarNavigation.prototype.hasPopup = function (menuitem) { + return menuitem.getAttribute('aria-haspopup') === 'true'; +}; + +MenubarNavigation.prototype.isOpen = function (menuitem) { + return menuitem.getAttribute('aria-expanded') === 'true'; +}; + +MenubarNavigation.prototype.isMenubar = function (menuId) { + return !this.isPopup[menuId] && !this.isPopout[menuId]; +}; + +MenubarNavigation.prototype.isMenuHorizontal = function (menuitem) { + return this.menuOrientation[menuitem] === 'horizontal'; +}; + +MenubarNavigation.prototype.hasFocus = function () { + return this.domNode.classList.contains('focus'); +}; + +// Menu event handlers + +MenubarNavigation.prototype.handleMenubarFocusin = function (event) { + // if the menubar or any of its menus has focus, add styling hook for hover + this.domNode.classList.add('focus'); +}; + +MenubarNavigation.prototype.handleMenubarFocusout = function (event) { + // remove styling hook for hover on menubar item + this.domNode.classList.remove('focus'); +}; + +MenubarNavigation.prototype.handleKeydown = function (event) { + var tgt = event.currentTarget, + key = event.key, + flag = false, + menuId = this.getMenuId(tgt), + id, + popupMenuId, + mi, + role, + option, + value; + + var isAnyPopupOpen = this.isAnyPopupOpen(); + + switch (key) { + case ' ': + case 'Enter': + if (this.hasPopup(tgt)) { + this.openPopups = true; + popupMenuId = this.openPopup(menuId, tgt); + this.setFocusToFirstMenuitem(popupMenuId); + } else { + if (tgt.href !== '#') { + this.closePopupAll(); + window.location.href = tgt.href; + } + } + flag = true; + break; + + case 'Esc': + case 'Escape': + this.openPopups = false; + this.closePopup(tgt); + flag = true; + break; + + case 'Up': + case 'ArrowUp': + if (this.isMenuHorizontal(menuId)) { + if (this.hasPopup(tgt)) { + this.openPopups = true; + popupMenuId = this.openPopup(menuId, tgt); + this.setFocusToLastMenuitem(popupMenuId); + } + } else { + this.setFocusToPreviousMenuitem(menuId, tgt); + } + flag = true; + break; + + case 'ArrowDown': + case 'Down': + if (this.isMenuHorizontal(menuId)) { + if (this.hasPopup(tgt)) { + this.openPopups = true; + popupMenuId = this.openPopup(menuId, tgt); + this.setFocusToFirstMenuitem(popupMenuId); + } + } else { + this.setFocusToNextMenuitem(menuId, tgt); + } + flag = true; + break; + + case 'Left': + case 'ArrowLeft': + if (this.isMenuHorizontal(menuId)) { + mi = this.setFocusToPreviousMenuitem(menuId, tgt); + if (isAnyPopupOpen) { + this.openPopup(menuId, mi); + } + } else { + if (this.isPopout[menuId]) { + mi = this.closePopup(tgt); + id = this.getMenuId(mi); + mi = this.setFocusToMenuitem(id, mi); + } else { + mi = this.closePopup(tgt); + id = this.getMenuId(mi); + mi = this.setFocusToPreviousMenuitem(id, mi); + this.openPopup(id, mi); + } + } + flag = true; + break; + + case 'Right': + case 'ArrowRight': + if (this.isMenuHorizontal(menuId)) { + mi = this.setFocusToNextMenuitem(menuId, tgt); + if (isAnyPopupOpen) { + this.openPopup(menuId, mi); + } + } else { + if (this.hasPopup(tgt)) { + popupMenuId = this.openPopup(menuId, tgt); + this.setFocusToFirstMenuitem(popupMenuId); + } else { + mi = this.closePopout(tgt); + id = this.getMenuId(mi); + mi = this.setFocusToNextMenuitem(id, mi); + this.openPopup(id, mi); + } + } + flag = true; + break; + + case 'Home': + case 'PageUp': + this.setFocusToFirstMenuitem(menuId, tgt); + flag = true; + break; + + case 'End': + case 'PageDown': + this.setFocusToLastMenuitem(menuId, tgt); + flag = true; + break; + + case 'Tab': + this.openPopups = false; + this.closePopup(tgt); + break; + + default: + if (this.isPrintableCharacter(key)) { + this.setFocusByFirstCharacter(menuId, tgt, key); + flag = true; + } + break; + } + + if (flag) { + event.stopPropagation(); + event.preventDefault(); + } +}; + +MenubarNavigation.prototype.handleMenuitemClick = function (event) { + var tgt = event.currentTarget; + var menuId = this.getMenuId(tgt); + + if (this.hasPopup(tgt)) { + if (this.isOpen(tgt)) { + this.closePopup(tgt); + } else { + this.closePopupAll(tgt); + this.openPopup(menuId, tgt); + } + event.stopPropagation(); + event.preventDefault(); + } +}; + +MenubarNavigation.prototype.handleMenuitemMouseover = function (event) { + var tgt = event.currentTarget; + var menuId = this.getMenuId(tgt); + + if (this.hasFocus()) { + this.setFocusToMenuitem(menuId, tgt); + } + + if (this.isAnyPopupOpen() || this.hasFocus()) { + this.closePopupAll(tgt); + if (this.hasPopup(tgt)) { + this.openPopup(menuId, tgt); + } + } +}; + +MenubarNavigation.prototype.handleBackgroundMousedown = function (event) { + if (!this.domNode.contains(event.target)) { + this.closePopupAll(); + } +}; + +// Initialize menubar editor + +window.addEventListener('load', function () { + var menubarNavs = document.querySelectorAll('.menubar-navigation'); + for (var i = 0; i < menubarNavs.length; i++) { + var menubarNav = new MenubarNavigation(menubarNavs[i]); + } +}); diff --git a/examples/menubar/js/style-manager.js b/examples/menubar/js/style-manager.js index 36f6264a09..06e35d7c4b 100644 --- a/examples/menubar/js/style-manager.js +++ b/examples/menubar/js/style-manager.js @@ -1,11 +1,11 @@ /* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -* -* File: TextStyling.js -* -* Desc: Styling functions for changing the style of an item -*/ + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * File: TextStyling.js + * + * Desc: Styling functions for changing the style of an item + */ 'use strict'; @@ -36,27 +36,22 @@ StyleManager.prototype.setColor = function (value) { }; StyleManager.prototype.setBold = function (flag) { - if (flag) { this.node.style.fontWeight = 'bold'; - } - else { + } else { this.node.style.fontWeight = 'normal'; } }; StyleManager.prototype.setItalic = function (flag) { - if (flag) { this.node.style.fontStyle = 'italic'; - } - else { + } else { this.node.style.fontStyle = 'normal'; } }; StyleManager.prototype.fontSmaller = function () { - switch (this.fontSize) { case 'small': this.setFontSize('x-small'); @@ -76,12 +71,10 @@ StyleManager.prototype.fontSmaller = function () { default: break; - } // end switch }; StyleManager.prototype.fontLarger = function () { - switch (this.fontSize) { case 'x-small': this.setFontSize('small'); @@ -101,7 +94,6 @@ StyleManager.prototype.fontLarger = function () { default: break; - } // end switch }; @@ -118,14 +110,12 @@ StyleManager.prototype.getFontSize = function () { }; StyleManager.prototype.setOption = function (option, value) { - option = option.toLowerCase(); if (typeof value === 'string') { - value = value.toLowerCase(); + value = value.toLowerCase(); } switch (option) { - case 'font-bold': this.setBold(value); break; @@ -164,7 +154,5 @@ StyleManager.prototype.setOption = function (option, value) { default: break; - } // end switch - }; diff --git a/examples/meter/js/meter.js b/examples/meter/js/meter.js index a046ae8b3a..1eb084dfc1 100644 --- a/examples/meter/js/meter.js +++ b/examples/meter/js/meter.js @@ -14,11 +14,15 @@ var Meter = function (element) { // returns a number representing a percentage between 0 - 100 Meter.prototype._calculatePercentFill = function (min, max, value) { - if (typeof min !== 'number' || typeof max !== 'number' || typeof value !== 'number') { + if ( + typeof min !== 'number' || + typeof max !== 'number' || + typeof value !== 'number' + ) { return 0; } - return 100 * (value - min) / (max - min); + return (100 * (value - min)) / (max - min); }; // returns an hsl color string between red and green @@ -73,9 +77,9 @@ Meter.prototype.setValue = function (value) { window.addEventListener('load', function () { // helper function to randomize example meter value - function getRandomValue (min, max) { + function getRandomValue(min, max) { var range = max - min; - return Math.floor((Math.random() * range) + min); + return Math.floor(Math.random() * range + min); } // init meters @@ -88,7 +92,7 @@ window.addEventListener('load', function () { // randomly update meter values // returns an id for setInterval - function playMeters () { + function playMeters() { return window.setInterval(function () { meters.forEach(function (meter) { meter.setValue(Math.random() * 100); @@ -108,8 +112,7 @@ window.addEventListener('load', function () { updateInterval = playMeters(); playButton.classList.remove('paused'); playButton.innerHTML = 'Pause Updates'; - } - else { + } else { clearInterval(updateInterval); playButton.classList.add('paused'); playButton.innerHTML = 'Start Updates'; diff --git a/examples/radio/js/radio-activedescendant.js b/examples/radio/js/radio-activedescendant.js index 6b5ebd5d00..0ba8c997c9 100644 --- a/examples/radio/js/radio-activedescendant.js +++ b/examples/radio/js/radio-activedescendant.js @@ -1,22 +1,21 @@ /* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -* -* File: radio-activedescendant.js -* -* Desc: Radio group widget using aria-activedescendant that implements ARIA Authoring Practices -*/ + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * File: radio-activedescendant.js + * + * Desc: Radio group widget using aria-activedescendant that implements ARIA Authoring Practices + */ 'use strict'; var RadioGroupActiveDescendant = function (groupNode) { - this.groupNode = groupNode; this.radioButtons = []; - this.firstRadioButton = null; - this.lastRadioButton = null; + this.firstRadioButton = null; + this.lastRadioButton = null; this.groupNode.addEventListener('keydown', this.handleKeydown.bind(this)); this.groupNode.addEventListener('focus', this.handleFocus.bind(this)); @@ -41,7 +40,7 @@ var RadioGroupActiveDescendant = function (groupNode) { this.groupNode.tabIndex = 0; }; -RadioGroupActiveDescendant.prototype.setChecked = function (currentItem) { +RadioGroupActiveDescendant.prototype.setChecked = function (currentItem) { for (var i = 0; i < this.radioButtons.length; i++) { var rb = this.radioButtons[i]; rb.setAttribute('aria-checked', 'false'); @@ -53,25 +52,27 @@ RadioGroupActiveDescendant.prototype.setChecked = function (currentItem) { this.groupNode.focus(); }; -RadioGroupActiveDescendant.prototype.setCheckedToPreviousItem = function (currentItem) { +RadioGroupActiveDescendant.prototype.setCheckedToPreviousItem = function ( + currentItem +) { var index; if (currentItem === this.firstRadioButton) { this.setChecked(this.lastRadioButton); - } - else { + } else { index = this.radioButtons.indexOf(currentItem); this.setChecked(this.radioButtons[index - 1]); } }; -RadioGroupActiveDescendant.prototype.setCheckedToNextItem = function (currentItem) { +RadioGroupActiveDescendant.prototype.setCheckedToNextItem = function ( + currentItem +) { var index; if (currentItem === this.lastRadioButton) { this.setChecked(this.firstRadioButton); - } - else { + } else { index = this.radioButtons.indexOf(currentItem); this.setChecked(this.radioButtons[index + 1]); } @@ -80,7 +81,10 @@ RadioGroupActiveDescendant.prototype.setCheckedToNextItem = function (currentIte RadioGroupActiveDescendant.prototype.getCurrentRadioButton = function () { var id = this.groupNode.getAttribute('aria-activedescendant'); if (!id) { - this.groupNode.setAttribute('aria-activedescendant', this.firstRadioButton.id); + this.groupNode.setAttribute( + 'aria-activedescendant', + this.firstRadioButton.id + ); return this.firstRadioButton; } for (var i = 0; i < this.radioButtons.length; i++) { @@ -89,7 +93,10 @@ RadioGroupActiveDescendant.prototype.getCurrentRadioButton = function () { return rb; } } - this.groupNode.setAttribute('aria-activedescendant', this.firstRadioButton.id); + this.groupNode.setAttribute( + 'aria-activedescendant', + this.firstRadioButton.id + ); return this.firstRadioButton; }; @@ -146,12 +153,11 @@ RadioGroupActiveDescendant.prototype.handleBlur = function () { currentItem.classList.remove('focus'); }; - // Initialize radio button group using aria-activedescendant window.addEventListener('load', function () { var rgs = document.querySelectorAll('.radiogroup-activedescendant'); - for(var i=0; i < rgs.length; i++) { + for (var i = 0; i < rgs.length; i++) { new RadioGroupActiveDescendant(rgs[i]); } }); diff --git a/examples/radio/js/radio.js b/examples/radio/js/radio.js index b50b4480dd..ddf887df69 100644 --- a/examples/radio/js/radio.js +++ b/examples/radio/js/radio.js @@ -1,22 +1,21 @@ /* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -* -* File: radio.js -* -* Desc: Radio group widget that implements ARIA Authoring Practices -*/ + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * File: radio.js + * + * Desc: Radio group widget that implements ARIA Authoring Practices + */ 'use strict'; var RadioGroup = function (groupNode) { - this.groupNode = groupNode; this.radioButtons = []; - this.firstRadioButton = null; - this.lastRadioButton = null; + this.firstRadioButton = null; + this.lastRadioButton = null; var rbs = this.groupNode.querySelectorAll('[role=radio]'); @@ -26,10 +25,10 @@ var RadioGroup = function (groupNode) { rb.tabIndex = -1; rb.setAttribute('aria-checked', 'false'); - rb.addEventListener('keydown', this.handleKeydown.bind(this)); - rb.addEventListener('click', this.handleClick.bind(this)); - rb.addEventListener('focus', this.handleFocus.bind(this)); - rb.addEventListener('blur', this.handleBlur.bind(this)); + rb.addEventListener('keydown', this.handleKeydown.bind(this)); + rb.addEventListener('click', this.handleClick.bind(this)); + rb.addEventListener('focus', this.handleFocus.bind(this)); + rb.addEventListener('blur', this.handleBlur.bind(this)); this.radioButtons.push(rb); @@ -41,7 +40,7 @@ var RadioGroup = function (groupNode) { this.firstRadioButton.tabIndex = 0; }; -RadioGroup.prototype.setChecked = function (currentItem) { +RadioGroup.prototype.setChecked = function (currentItem) { for (var i = 0; i < this.radioButtons.length; i++) { var rb = this.radioButtons[i]; rb.setAttribute('aria-checked', 'false'); @@ -57,8 +56,7 @@ RadioGroup.prototype.setCheckedToPreviousItem = function (currentItem) { if (currentItem === this.firstRadioButton) { this.setChecked(this.lastRadioButton); - } - else { + } else { index = this.radioButtons.indexOf(currentItem); this.setChecked(this.radioButtons[index - 1]); } @@ -69,8 +67,7 @@ RadioGroup.prototype.setCheckedToNextItem = function (currentItem) { if (currentItem === this.lastRadioButton) { this.setChecked(this.firstRadioButton); - } - else { + } else { index = this.radioButtons.indexOf(currentItem); this.setChecked(this.radioButtons[index + 1]); } @@ -127,12 +124,11 @@ RadioGroup.prototype.handleBlur = function (event) { event.currentTarget.classList.remove('focus'); }; - // Initialize radio button group window.addEventListener('load', function () { var rgs = document.querySelectorAll('[role="radiogroup"]'); - for(var i=0; i < rgs.length; i++) { + for (var i = 0; i < rgs.length; i++) { new RadioGroup(rgs[i]); } }); diff --git a/examples/slider/js/multithumb-slider.js b/examples/slider/js/multithumb-slider.js index 6a19391e56..921d59084a 100644 --- a/examples/slider/js/multithumb-slider.js +++ b/examples/slider/js/multithumb-slider.js @@ -1,244 +1,235 @@ -/* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -* -* File: slider.js -* -* Desc: Slider widget that implements ARIA Authoring Practices -*/ - -'use strict'; - -// Create Slider that contains value, valuemin, valuemax, and valuenow -var Slider = function (domNode) { - - this.domNode = domNode; - this.railDomNode = domNode.parentNode; - - this.labelDomNode = false; - this.minDomNode = false; - this.maxDomNode = false; - - this.valueNow = 50; - - this.railMin = 0; - this.railMax = 100; - this.railWidth = 0; - this.railBorderWidth = 1; - - this.thumbWidth = 20; - this.thumbHeight = 24; - - this.keyCode = Object.freeze({ - 'left': 37, - 'up': 38, - 'right': 39, - 'down': 40, - 'pageUp': 33, - 'pageDown': 34, - 'end': 35, - 'home': 36 - }); -}; - -// Initialize slider -Slider.prototype.init = function () { - - if (this.domNode.previousElementSibling) { - this.minDomNode = this.domNode.previousElementSibling; - this.railMin = parseInt((this.minDomNode.getAttribute('aria-valuemin'))); - } - else { - this.railMin = parseInt((this.domNode.getAttribute('aria-valuemin'))); - } - - if (this.domNode.nextElementSibling) { - this.maxDomNode = this.domNode.nextElementSibling; - this.railMax = parseInt((this.maxDomNode.getAttribute('aria-valuemax'))); - } - - else { - this.railMax = parseInt((this.domNode.getAttribute('aria-valuemax'))); - } - - this.valueNow = parseInt((this.domNode.getAttribute('aria-valuenow'))); - - this.railWidth = parseInt(this.railDomNode.style.width.slice(0, -2)); - - if (this.domNode.classList.contains('min')) { - this.labelDomNode = this.domNode.parentElement.previousElementSibling; - } - - if (this.domNode.classList.contains('max')) { - this.labelDomNode = this.domNode.parentElement.nextElementSibling; - } - - if (this.domNode.tabIndex != 0) { - this.domNode.tabIndex = 0; - } - - this.domNode.addEventListener('keydown', this.handleKeyDown.bind(this)); - this.domNode.addEventListener('mousedown', this.handleMouseDown.bind(this)); - this.domNode.addEventListener('focus', this.handleFocus.bind(this)); - this.domNode.addEventListener('blur', this.handleBlur.bind(this)); - - this.moveSliderTo(this.valueNow); - -}; - -Slider.prototype.moveSliderTo = function (value) { - var valueMax = parseInt(this.domNode.getAttribute('aria-valuemax')); - var valueMin = parseInt(this.domNode.getAttribute('aria-valuemin')); - - if (value > valueMax) { - value = valueMax; - } - - if (value < valueMin) { - value = valueMin; - } - - this.valueNow = value; - this.dolValueNow = '$' + value; - - this.domNode.setAttribute('aria-valuenow', this.valueNow); - this.domNode.setAttribute('aria-valuetext', this.dolValueNow); - - if (this.minDomNode) { - this.minDomNode.setAttribute('aria-valuemax', this.valueNow); - } - - if (this.maxDomNode) { - this.maxDomNode.setAttribute('aria-valuemin', this.valueNow); - } - - var pos = Math.round(((this.valueNow - this.railMin) * (this.railWidth - 2 * (this.thumbWidth - this.railBorderWidth))) / (this.railMax - this.railMin)); - - if (this.minDomNode) { - this.domNode.style.left = (pos + this.thumbWidth - this.railBorderWidth) + 'px'; - } - else { - this.domNode.style.left = (pos - this.railBorderWidth) + 'px'; - } - - if (this.labelDomNode) { - this.labelDomNode.innerHTML = this.dolValueNow.toString(); - } -}; - -Slider.prototype.handleKeyDown = function (event) { - - var flag = false; - - switch (event.keyCode) { - case this.keyCode.left: - case this.keyCode.down: - this.moveSliderTo(this.valueNow - 1); - flag = true; - break; - - case this.keyCode.right: - case this.keyCode.up: - this.moveSliderTo(this.valueNow + 1); - flag = true; - break; - - case this.keyCode.pageDown: - this.moveSliderTo(this.valueNow - 10); - flag = true; - break; - - case this.keyCode.pageUp: - this.moveSliderTo(this.valueNow + 10); - flag = true; - break; - - case this.keyCode.home: - this.moveSliderTo(this.railMin); - flag = true; - break; - - case this.keyCode.end: - this.moveSliderTo(this.railMax); - flag = true; - break; - - default: - break; - } - - if (flag) { - event.preventDefault(); - event.stopPropagation(); - } - -}; - -Slider.prototype.handleFocus = function (event) { - this.domNode.classList.add('focus'); - this.railDomNode.classList.add('focus'); -}; - -Slider.prototype.handleBlur = function (event) { - this.domNode.classList.remove('focus'); - this.railDomNode.classList.remove('focus'); -}; - -Slider.prototype.handleMouseDown = function (event) { - - var self = this; - - var handleMouseMove = function (event) { - - var diffX = event.pageX - self.railDomNode.offsetLeft; - self.valueNow = self.railMin + parseInt(((self.railMax - self.railMin) * diffX) / self.railWidth); - self.moveSliderTo(self.valueNow); - - event.preventDefault(); - event.stopPropagation(); - }; - - var handleMouseUp = function (event) { - - document.removeEventListener('mousemove', handleMouseMove); - document.removeEventListener('mouseup', handleMouseUp); - - }; - - // bind a mousemove event handler to move pointer - document.addEventListener('mousemove', handleMouseMove); - - // bind a mouseup event handler to stop tracking mouse movements - document.addEventListener('mouseup', handleMouseUp); - - event.preventDefault(); - event.stopPropagation(); - - // Set focus to the clicked handle - this.domNode.focus(); - -}; - -// handleMouseMove has the same functionality as we need for handleMouseClick on the rail -// Slider.prototype.handleClick = function (event) { - -// var diffX = event.pageX - this.railDomNode.offsetLeft; -// this.valueNow = parseInt(((this.railMax - this.railMin) * diffX) / this.railWidth); -// this.moveSliderTo(this.valueNow); - -// event.preventDefault(); -// event.stopPropagation(); - -// }; - -// Initialise Sliders on the page -window.addEventListener('load', function () { - - var sliders = document.querySelectorAll('[role=slider]'); - - for (var i = 0; i < sliders.length; i++) { - var s = new Slider(sliders[i]); - s.init(); - } - -}); +/* + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * File: slider.js + * + * Desc: Slider widget that implements ARIA Authoring Practices + */ + +'use strict'; + +// Create Slider that contains value, valuemin, valuemax, and valuenow +var Slider = function (domNode) { + this.domNode = domNode; + this.railDomNode = domNode.parentNode; + + this.labelDomNode = false; + this.minDomNode = false; + this.maxDomNode = false; + + this.valueNow = 50; + + this.railMin = 0; + this.railMax = 100; + this.railWidth = 0; + this.railBorderWidth = 1; + + this.thumbWidth = 20; + this.thumbHeight = 24; + + this.keyCode = Object.freeze({ + left: 37, + up: 38, + right: 39, + down: 40, + pageUp: 33, + pageDown: 34, + end: 35, + home: 36, + }); +}; + +// Initialize slider +Slider.prototype.init = function () { + if (this.domNode.previousElementSibling) { + this.minDomNode = this.domNode.previousElementSibling; + this.railMin = parseInt(this.minDomNode.getAttribute('aria-valuemin')); + } else { + this.railMin = parseInt(this.domNode.getAttribute('aria-valuemin')); + } + + if (this.domNode.nextElementSibling) { + this.maxDomNode = this.domNode.nextElementSibling; + this.railMax = parseInt(this.maxDomNode.getAttribute('aria-valuemax')); + } else { + this.railMax = parseInt(this.domNode.getAttribute('aria-valuemax')); + } + + this.valueNow = parseInt(this.domNode.getAttribute('aria-valuenow')); + + this.railWidth = parseInt(this.railDomNode.style.width.slice(0, -2)); + + if (this.domNode.classList.contains('min')) { + this.labelDomNode = this.domNode.parentElement.previousElementSibling; + } + + if (this.domNode.classList.contains('max')) { + this.labelDomNode = this.domNode.parentElement.nextElementSibling; + } + + if (this.domNode.tabIndex != 0) { + this.domNode.tabIndex = 0; + } + + this.domNode.addEventListener('keydown', this.handleKeyDown.bind(this)); + this.domNode.addEventListener('mousedown', this.handleMouseDown.bind(this)); + this.domNode.addEventListener('focus', this.handleFocus.bind(this)); + this.domNode.addEventListener('blur', this.handleBlur.bind(this)); + + this.moveSliderTo(this.valueNow); +}; + +Slider.prototype.moveSliderTo = function (value) { + var valueMax = parseInt(this.domNode.getAttribute('aria-valuemax')); + var valueMin = parseInt(this.domNode.getAttribute('aria-valuemin')); + + if (value > valueMax) { + value = valueMax; + } + + if (value < valueMin) { + value = valueMin; + } + + this.valueNow = value; + this.dolValueNow = '$' + value; + + this.domNode.setAttribute('aria-valuenow', this.valueNow); + this.domNode.setAttribute('aria-valuetext', this.dolValueNow); + + if (this.minDomNode) { + this.minDomNode.setAttribute('aria-valuemax', this.valueNow); + } + + if (this.maxDomNode) { + this.maxDomNode.setAttribute('aria-valuemin', this.valueNow); + } + + var pos = Math.round( + ((this.valueNow - this.railMin) * + (this.railWidth - 2 * (this.thumbWidth - this.railBorderWidth))) / + (this.railMax - this.railMin) + ); + + if (this.minDomNode) { + this.domNode.style.left = + pos + this.thumbWidth - this.railBorderWidth + 'px'; + } else { + this.domNode.style.left = pos - this.railBorderWidth + 'px'; + } + + if (this.labelDomNode) { + this.labelDomNode.innerHTML = this.dolValueNow.toString(); + } +}; + +Slider.prototype.handleKeyDown = function (event) { + var flag = false; + + switch (event.keyCode) { + case this.keyCode.left: + case this.keyCode.down: + this.moveSliderTo(this.valueNow - 1); + flag = true; + break; + + case this.keyCode.right: + case this.keyCode.up: + this.moveSliderTo(this.valueNow + 1); + flag = true; + break; + + case this.keyCode.pageDown: + this.moveSliderTo(this.valueNow - 10); + flag = true; + break; + + case this.keyCode.pageUp: + this.moveSliderTo(this.valueNow + 10); + flag = true; + break; + + case this.keyCode.home: + this.moveSliderTo(this.railMin); + flag = true; + break; + + case this.keyCode.end: + this.moveSliderTo(this.railMax); + flag = true; + break; + + default: + break; + } + + if (flag) { + event.preventDefault(); + event.stopPropagation(); + } +}; + +Slider.prototype.handleFocus = function (event) { + this.domNode.classList.add('focus'); + this.railDomNode.classList.add('focus'); +}; + +Slider.prototype.handleBlur = function (event) { + this.domNode.classList.remove('focus'); + this.railDomNode.classList.remove('focus'); +}; + +Slider.prototype.handleMouseDown = function (event) { + var self = this; + + var handleMouseMove = function (event) { + var diffX = event.pageX - self.railDomNode.offsetLeft; + self.valueNow = + self.railMin + + parseInt(((self.railMax - self.railMin) * diffX) / self.railWidth); + self.moveSliderTo(self.valueNow); + + event.preventDefault(); + event.stopPropagation(); + }; + + var handleMouseUp = function (event) { + document.removeEventListener('mousemove', handleMouseMove); + document.removeEventListener('mouseup', handleMouseUp); + }; + + // bind a mousemove event handler to move pointer + document.addEventListener('mousemove', handleMouseMove); + + // bind a mouseup event handler to stop tracking mouse movements + document.addEventListener('mouseup', handleMouseUp); + + event.preventDefault(); + event.stopPropagation(); + + // Set focus to the clicked handle + this.domNode.focus(); +}; + +// handleMouseMove has the same functionality as we need for handleMouseClick on the rail +// Slider.prototype.handleClick = function (event) { + +// var diffX = event.pageX - this.railDomNode.offsetLeft; +// this.valueNow = parseInt(((this.railMax - this.railMin) * diffX) / this.railWidth); +// this.moveSliderTo(this.valueNow); + +// event.preventDefault(); +// event.stopPropagation(); + +// }; + +// Initialise Sliders on the page +window.addEventListener('load', function () { + var sliders = document.querySelectorAll('[role=slider]'); + + for (var i = 0; i < sliders.length; i++) { + var s = new Slider(sliders[i]); + s.init(); + } +}); diff --git a/examples/slider/js/slider.js b/examples/slider/js/slider.js index 4b0ee4a0b6..5d34977c86 100644 --- a/examples/slider/js/slider.js +++ b/examples/slider/js/slider.js @@ -1,17 +1,16 @@ /* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -* -* File: slider.js -* -* Desc: Slider widget that implements ARIA Authoring Practices -*/ + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * File: slider.js + * + * Desc: Slider widget that implements ARIA Authoring Practices + */ 'use strict'; // Create Slider that contains value, valuemin, valuemax, and valuenow -var Slider = function (domNode) { - +var Slider = function (domNode) { this.domNode = domNode; this.railDomNode = domNode.parentNode; @@ -23,32 +22,31 @@ var Slider = function (domNode) { this.railWidth = 0; - this.thumbWidth = 8; + this.thumbWidth = 8; this.thumbHeight = 28; this.keyCode = Object.freeze({ - 'left': 37, - 'up': 38, - 'right': 39, - 'down': 40, - 'pageUp': 33, - 'pageDown': 34, - 'end': 35, - 'home': 36 + left: 37, + up: 38, + right: 39, + down: 40, + pageUp: 33, + pageDown: 34, + end: 35, + home: 36, }); }; // Initialize slider Slider.prototype.init = function () { - if (this.domNode.getAttribute('aria-valuemin')) { - this.valueMin = parseInt((this.domNode.getAttribute('aria-valuemin'))); + this.valueMin = parseInt(this.domNode.getAttribute('aria-valuemin')); } if (this.domNode.getAttribute('aria-valuemax')) { - this.valueMax = parseInt((this.domNode.getAttribute('aria-valuemax'))); + this.valueMax = parseInt(this.domNode.getAttribute('aria-valuemax')); } if (this.domNode.getAttribute('aria-valuenow')) { - this.valueNow = parseInt((this.domNode.getAttribute('aria-valuenow'))); + this.valueNow = parseInt(this.domNode.getAttribute('aria-valuenow')); } this.railWidth = parseInt(this.railDomNode.style.width.slice(0, -2)); @@ -56,10 +54,10 @@ Slider.prototype.init = function () { this.valueDomNode = this.railDomNode.nextElementSibling; if (this.valueDomNode) { - this.valueDomNode.innerHTML = '0'; - this.valueDomNode.style.left = (this.railDomNode.offsetLeft + this.railWidth + 10) + 'px'; - this.valueDomNode.style.top = (this.railDomNode.offsetTop - 8) + 'px'; + this.valueDomNode.style.left = + this.railDomNode.offsetLeft + this.railWidth + 10 + 'px'; + this.valueDomNode.style.top = this.railDomNode.offsetTop - 8 + 'px'; } if (this.domNode.tabIndex != 0) { @@ -68,23 +66,21 @@ Slider.prototype.init = function () { this.domNode.style.width = this.thumbWidth + 'px'; this.domNode.style.height = this.thumbHeight + 'px'; - this.domNode.style.top = (this.thumbHeight / -2) + 'px'; + this.domNode.style.top = this.thumbHeight / -2 + 'px'; - this.domNode.addEventListener('keydown', this.handleKeyDown.bind(this)); + this.domNode.addEventListener('keydown', this.handleKeyDown.bind(this)); // add onmousedown, move, and onmouseup this.domNode.addEventListener('mousedown', this.handleMouseDown.bind(this)); - this.domNode.addEventListener('focus', this.handleFocus.bind(this)); - this.domNode.addEventListener('blur', this.handleBlur.bind(this)); + this.domNode.addEventListener('focus', this.handleFocus.bind(this)); + this.domNode.addEventListener('blur', this.handleBlur.bind(this)); this.railDomNode.addEventListener('click', this.handleClick.bind(this)); this.moveSliderTo(this.valueNow); - }; Slider.prototype.moveSliderTo = function (value) { - if (value > this.valueMax) { value = this.valueMax; } @@ -97,9 +93,11 @@ Slider.prototype.moveSliderTo = function (value) { this.domNode.setAttribute('aria-valuenow', this.valueNow); - var pos = Math.round( - (this.valueNow * this.railWidth) / (this.valueMax - this.valueMin) - ) - (this.thumbWidth / 2); + var pos = + Math.round( + (this.valueNow * this.railWidth) / (this.valueMax - this.valueMin) + ) - + this.thumbWidth / 2; this.domNode.style.left = pos + 'px'; @@ -108,11 +106,9 @@ Slider.prototype.moveSliderTo = function (value) { } updateColorBox(); - }; Slider.prototype.handleKeyDown = function (event) { - var flag = false; switch (event.keyCode) { @@ -156,7 +152,6 @@ Slider.prototype.handleKeyDown = function (event) { event.preventDefault(); event.stopPropagation(); } - }; Slider.prototype.handleFocus = function (event) { @@ -171,24 +166,22 @@ Slider.prototype.handleBlur = function (event) { // Initialise Sliders on the page window.addEventListener('load', function () { - var sliders = document.querySelectorAll('[role=slider]'); for (var i = 0; i < sliders.length; i++) { var s = new Slider(sliders[i]); s.init(); } - }); Slider.prototype.handleMouseDown = function (event) { - var self = this; var handleMouseMove = function (event) { - var diffX = event.pageX - self.railDomNode.offsetLeft; - self.valueNow = parseInt(((self.valueMax - self.valueMin) * diffX) / self.railWidth); + self.valueNow = parseInt( + ((self.valueMax - self.valueMin) * diffX) / self.railWidth + ); self.moveSliderTo(self.valueNow); event.preventDefault(); @@ -196,10 +189,8 @@ Slider.prototype.handleMouseDown = function (event) { }; var handleMouseUp = function (event) { - document.removeEventListener('mousemove', handleMouseMove); document.removeEventListener('mouseup', handleMouseUp); - }; // bind a mousemove event handler to move pointer @@ -213,19 +204,18 @@ Slider.prototype.handleMouseDown = function (event) { // Set focus to the clicked handle this.domNode.focus(); - }; // handleMouseMove has the same functionality as we need for handleMouseClick on the rail Slider.prototype.handleClick = function (event) { - var diffX = event.pageX - this.railDomNode.offsetLeft; - this.valueNow = parseInt(((this.valueMax - this.valueMin) * diffX) / this.railWidth); + this.valueNow = parseInt( + ((this.valueMax - this.valueMin) * diffX) / this.railWidth + ); this.moveSliderTo(this.valueNow); event.preventDefault(); event.stopPropagation(); - }; /* ---------------------------------------------------------------- */ @@ -233,11 +223,16 @@ Slider.prototype.handleClick = function (event) { /* ---------------------------------------------------------------- */ function updateColorBox() { - - function getColorHex () { - var r = parseInt(document.getElementById('idRedValue').getAttribute('aria-valuenow')).toString(16); - var g = parseInt(document.getElementById('idGreenValue').getAttribute('aria-valuenow')).toString(16); - var b = parseInt(document.getElementById('idBlueValue').getAttribute('aria-valuenow')).toString(16); + function getColorHex() { + var r = parseInt( + document.getElementById('idRedValue').getAttribute('aria-valuenow') + ).toString(16); + var g = parseInt( + document.getElementById('idGreenValue').getAttribute('aria-valuenow') + ).toString(16); + var b = parseInt( + document.getElementById('idBlueValue').getAttribute('aria-valuenow') + ).toString(16); if (r.length === 1) { r = '0' + r; @@ -252,10 +247,14 @@ function updateColorBox() { return '#' + r + g + b; } - function getColorRGB () { + function getColorRGB() { var r = document.getElementById('idRedValue').getAttribute('aria-valuenow'); - var g = document.getElementById('idGreenValue').getAttribute('aria-valuenow'); - var b = document.getElementById('idBlueValue').getAttribute('aria-valuenow'); + var g = document + .getElementById('idGreenValue') + .getAttribute('aria-valuenow'); + var b = document + .getElementById('idBlueValue') + .getAttribute('aria-valuenow'); return r + ', ' + g + ', ' + b; } @@ -263,7 +262,6 @@ function updateColorBox() { var node = document.getElementById('idColorBox'); if (node) { - var color = getColorHex(); node.style.backgroundColor = color; @@ -273,6 +271,5 @@ function updateColorBox() { node = document.getElementById('idColorValueRGB'); node.value = getColorRGB(); - } } diff --git a/examples/slider/js/text-slider.js b/examples/slider/js/text-slider.js index cd16a78380..dde4864fc9 100644 --- a/examples/slider/js/text-slider.js +++ b/examples/slider/js/text-slider.js @@ -1,18 +1,17 @@ /* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -* -* File: text-slider.js -* -* Desc: Text slider widget that implements ARIA Authoring Practices -*/ + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * File: text-slider.js + * + * Desc: Text slider widget that implements ARIA Authoring Practices + */ 'use strict'; // Create Text Slider that contains value, valuemin, valuemax, and valuenow -var TSlider = function (domNode) { - +var TSlider = function (domNode) { this.domNode = domNode; this.railDomNode = domNode.parentNode; @@ -31,30 +30,29 @@ var TSlider = function (domNode) { this.railWidth = 0; - this.thumbWidth = 8; + this.thumbWidth = 8; this.thumbHeight = 28; this.keyCode = Object.freeze({ - 'left': 37, - 'up': 38, - 'right': 39, - 'down': 40, - 'end': 35, - 'home': 36 + left: 37, + up: 38, + right: 39, + down: 40, + end: 35, + home: 36, }); }; // Initialize text slider TSlider.prototype.init = function () { - if (this.domNode.getAttribute('aria-valuemin')) { - this.valueMin = parseInt((this.domNode.getAttribute('aria-valuemin'))); + this.valueMin = parseInt(this.domNode.getAttribute('aria-valuemin')); } if (this.domNode.getAttribute('aria-valuemax')) { - this.valueMax = parseInt((this.domNode.getAttribute('aria-valuemax'))); + this.valueMax = parseInt(this.domNode.getAttribute('aria-valuemax')); } if (this.domNode.getAttribute('aria-valuenow')) { - this.valueNow = parseInt((this.domNode.getAttribute('aria-valuenow'))); + this.valueNow = parseInt(this.domNode.getAttribute('aria-valuenow')); } this.railWidth = parseInt(this.railDomNode.style.width.slice(0, -2)); @@ -65,33 +63,29 @@ TSlider.prototype.init = function () { this.domNode.style.width = this.thumbWidth + 'px'; this.domNode.style.height = this.thumbHeight + 'px'; - this.domNode.style.top = (this.thumbHeight / -2) + 'px'; + this.domNode.style.top = this.thumbHeight / -2 + 'px'; var pos = 0; var diff = this.railWidth / (this.valueNodes.length - 1); for (var i = 0; this.valueNodes[i]; i++) { - - this.valueNodes[i].style.left = ( - pos - (this.valueNodes[i].offsetWidth / 2) - ) + 'px'; + this.valueNodes[i].style.left = + pos - this.valueNodes[i].offsetWidth / 2 + 'px'; pos = pos + diff; } - this.domNode.addEventListener('keydown', this.handleKeyDown.bind(this)); + this.domNode.addEventListener('keydown', this.handleKeyDown.bind(this)); // add onmousedown, move, and onmouseup this.domNode.addEventListener('mousedown', this.handleMouseDown.bind(this)); - this.domNode.addEventListener('focus', this.handleFocus.bind(this)); - this.domNode.addEventListener('blur', this.handleBlur.bind(this)); + this.domNode.addEventListener('focus', this.handleFocus.bind(this)); + this.domNode.addEventListener('blur', this.handleBlur.bind(this)); this.railDomNode.addEventListener('click', this.handleClick.bind(this)); this.moveTSliderTo(this.valueNow); - }; TSlider.prototype.moveTSliderTo = function (value) { - if (value > this.valueMax) { value = this.valueMax; } @@ -105,16 +99,16 @@ TSlider.prototype.moveTSliderTo = function (value) { this.domNode.setAttribute('aria-valuenow', this.valueNow); this.domNode.setAttribute('aria-valuetext', this.values[this.valueNow]); - var pos = Math.round( - (this.valueNow * this.railWidth) / (this.valueMax - this.valueMin) - ) - (this.thumbWidth / 2); + var pos = + Math.round( + (this.valueNow * this.railWidth) / (this.valueMax - this.valueMin) + ) - + this.thumbWidth / 2; this.domNode.style.left = pos + 'px'; - }; TSlider.prototype.handleKeyDown = function (event) { - var flag = false; switch (event.keyCode) { @@ -147,7 +141,6 @@ TSlider.prototype.handleKeyDown = function (event) { event.preventDefault(); event.stopPropagation(); } - }; TSlider.prototype.handleFocus = function (event) { @@ -161,13 +154,13 @@ TSlider.prototype.handleBlur = function (event) { }; TSlider.prototype.handleMouseDown = function (event) { - var self = this; var handleMouseMove = function (event) { - var diffX = event.pageX - self.railDomNode.offsetLeft; - self.valueNow = parseInt(((self.valueMax - self.valueMin) * diffX) / self.railWidth); + self.valueNow = parseInt( + ((self.valueMax - self.valueMin) * diffX) / self.railWidth + ); self.moveTSliderTo(self.valueNow); event.preventDefault(); @@ -175,10 +168,8 @@ TSlider.prototype.handleMouseDown = function (event) { }; var handleMouseUp = function (event) { - document.removeEventListener('mousemove', handleMouseMove); document.removeEventListener('mouseup', handleMouseUp); - }; // bind a mousemove event handler to move pointer @@ -192,29 +183,28 @@ TSlider.prototype.handleMouseDown = function (event) { // Set focus to the clicked handle this.domNode.focus(); - }; // handleMouseMove has the same functionality as we need for handleMouseClick on the rail TSlider.prototype.handleClick = function (event) { - var diffX = event.pageX - this.railDomNode.offsetLeft; - this.valueNow = parseInt(((this.valueMax - this.valueMin) * diffX) / this.railWidth); + this.valueNow = parseInt( + ((this.valueMax - this.valueMin) * diffX) / this.railWidth + ); this.moveTSliderTo(this.valueNow); event.preventDefault(); event.stopPropagation(); - }; // Initialise TSliders on the page window.addEventListener('load', function () { - - var sliders = document.querySelectorAll('.aria-widget-text-slider [role=slider]'); + var sliders = document.querySelectorAll( + '.aria-widget-text-slider [role=slider]' + ); for (var i = 0; i < sliders.length; i++) { var s = new TSlider(sliders[i]); s.init(); } - }); diff --git a/examples/slider/js/vertical-slider.js b/examples/slider/js/vertical-slider.js index b6e3089306..046671a54a 100644 --- a/examples/slider/js/vertical-slider.js +++ b/examples/slider/js/vertical-slider.js @@ -1,17 +1,16 @@ /* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -* -* File: vertical-slider.js -* -* Desc: Vertical slider widget that implements ARIA Authoring Practices -*/ + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * File: vertical-slider.js + * + * Desc: Vertical slider widget that implements ARIA Authoring Practices + */ 'use strict'; // Create Vertical Slider that contains value, valuemin, valuemax, and valuenow -var VSlider = function (domNode) { - +var VSlider = function (domNode) { this.domNode = domNode; this.railDomNode = domNode.parentNode; @@ -23,34 +22,33 @@ var VSlider = function (domNode) { this.railHeight = 0; - this.thumbWidth = 28; + this.thumbWidth = 28; this.thumbHeight = 8; this.keyCode = Object.freeze({ - 'left': 37, - 'up': 38, - 'right': 39, - 'down': 40, - 'pageUp': 33, - 'pageDown': 34, - 'end': 35, - 'home': 36 + left: 37, + up: 38, + right: 39, + down: 40, + pageUp: 33, + pageDown: 34, + end: 35, + home: 36, }); }; // Initialize vertical slider VSlider.prototype.init = function () { - this.domNode.setAttribute('aria-orientation', 'vertical'); if (this.domNode.getAttribute('aria-valuemin')) { - this.valueMin = parseInt((this.domNode.getAttribute('aria-valuemin'))); + this.valueMin = parseInt(this.domNode.getAttribute('aria-valuemin')); } if (this.domNode.getAttribute('aria-valuemax')) { - this.valueMax = parseInt((this.domNode.getAttribute('aria-valuemax'))); + this.valueMax = parseInt(this.domNode.getAttribute('aria-valuemax')); } if (this.domNode.getAttribute('aria-valuenow')) { - this.valueNow = parseInt((this.domNode.getAttribute('aria-valuenow'))); + this.valueNow = parseInt(this.domNode.getAttribute('aria-valuenow')); } this.railHeight = parseInt(this.railDomNode.style.height.slice(0, -2)); @@ -67,23 +65,21 @@ VSlider.prototype.init = function () { this.domNode.style.width = this.thumbWidth + 'px'; this.domNode.style.height = this.thumbHeight + 'px'; - this.domNode.style.left = (this.thumbWidth / -2) + 'px'; + this.domNode.style.left = this.thumbWidth / -2 + 'px'; - this.domNode.addEventListener('keydown', this.handleKeyDown.bind(this)); + this.domNode.addEventListener('keydown', this.handleKeyDown.bind(this)); // add onmousedown, move, and onmouseup this.domNode.addEventListener('mousedown', this.handleMouseDown.bind(this)); - this.domNode.addEventListener('focus', this.handleFocus.bind(this)); - this.domNode.addEventListener('blur', this.handleBlur.bind(this)); + this.domNode.addEventListener('focus', this.handleFocus.bind(this)); + this.domNode.addEventListener('blur', this.handleBlur.bind(this)); this.railDomNode.addEventListener('click', this.handleClick.bind(this)); this.moveVSliderTo(this.valueNow); - }; VSlider.prototype.moveVSliderTo = function (value) { - if (value > this.valueMax) { value = this.valueMax; } @@ -97,23 +93,23 @@ VSlider.prototype.moveVSliderTo = function (value) { this.domNode.setAttribute('aria-valuenow', this.valueNow); this.domNode.setAttribute('aria-valuetext', this.valueNow + ' degrees'); - var pos = Math.round( - ((this.valueMax - this.valueNow) * this.railHeight - ) / (this.valueMax - this.valueMin) - ) - (this.thumbHeight / 2); + var pos = + Math.round( + ((this.valueMax - this.valueNow) * this.railHeight) / + (this.valueMax - this.valueMin) + ) - + this.thumbHeight / 2; this.domNode.style.top = pos + 'px'; if (this.valueDomNode) { this.valueDomNode.innerHTML = this.valueNow.toString(); - this.valueDomNode.style.left = (this.railDomNode.offsetWidth) / 2 - 2 + 'px'; + this.valueDomNode.style.left = this.railDomNode.offsetWidth / 2 - 2 + 'px'; console.log(this.valueDomNode.style.left); } - }; VSlider.prototype.handleKeyDown = function (event) { - var flag = false; switch (event.keyCode) { @@ -157,7 +153,6 @@ VSlider.prototype.handleKeyDown = function (event) { event.preventDefault(); event.stopPropagation(); } - }; VSlider.prototype.handleFocus = function (event) { @@ -171,13 +166,13 @@ VSlider.prototype.handleBlur = function (event) { }; VSlider.prototype.handleMouseDown = function (event) { - var self = this; var handleMouseMove = function (event) { - var diffY = event.pageY - self.railDomNode.offsetTop; - self.valueNow = self.valueMax - parseInt(((self.valueMax - self.valueMin) * diffY) / self.railHeight); + self.valueNow = + self.valueMax - + parseInt(((self.valueMax - self.valueMin) * diffY) / self.railHeight); self.moveVSliderTo(self.valueNow); event.preventDefault(); @@ -185,10 +180,8 @@ VSlider.prototype.handleMouseDown = function (event) { }; var handleMouseUp = function (event) { - document.removeEventListener('mousemove', handleMouseMove); document.removeEventListener('mouseup', handleMouseUp); - }; // bind a mousemove event handler to move pointer @@ -202,29 +195,28 @@ VSlider.prototype.handleMouseDown = function (event) { // Set focus to the clicked handle this.domNode.focus(); - }; // handleMouseMove has the same functionality as we need for handleMouseClick on the rail VSlider.prototype.handleClick = function (event) { - var diffY = event.pageY - this.railDomNode.offsetTop; - this.valueNow = this.valueMax - parseInt(((this.valueMax - this.valueMin) * diffY) / this.railHeight); + this.valueNow = + this.valueMax - + parseInt(((this.valueMax - this.valueMin) * diffY) / this.railHeight); this.moveVSliderTo(this.valueNow); event.preventDefault(); event.stopPropagation(); - }; // Initialise VSliders on the page window.addEventListener('load', function () { - - var sliders = document.querySelectorAll('.aria-widget-vertical-slider [role=slider]'); + var sliders = document.querySelectorAll( + '.aria-widget-vertical-slider [role=slider]' + ); for (var i = 0; i < sliders.length; i++) { var s = new VSlider(sliders[i]); s.init(); } - }); diff --git a/examples/spinbutton/js/datepicker-spinbuttons.js b/examples/spinbutton/js/datepicker-spinbuttons.js index c63290c767..033f928bd3 100644 --- a/examples/spinbutton/js/datepicker-spinbuttons.js +++ b/examples/spinbutton/js/datepicker-spinbuttons.js @@ -1,38 +1,101 @@ /* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -* -* File: datepicker-spinbuttons.js -*/ + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * File: datepicker-spinbuttons.js + */ 'use strict'; /* global SpinButtonDate */ -var DatePickerSpinButtons = function (domNode) { - +var DatePickerSpinButtons = function (domNode) { this.domNode = domNode; this.monthNode = domNode.querySelector('.spinbutton.month'); this.dayNode = domNode.querySelector('.spinbutton.day'); this.yearNode = domNode.querySelector('.spinbutton.year'); this.dateNode = domNode.querySelector('.date'); - this.valuesWeek = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']; - this.valuesDay = ['', 'first', 'second', 'third', 'fourth', 'fifth', 'sixth', 'seventh', 'eighth', 'ninth', 'tenth', 'eleventh', 'twelfth', 'thirteenth', 'fourteen', 'fifteenth', 'sixteenth', 'seveneenth', 'eighteenth', 'nineteenth', 'twentieth', 'twenty first', 'twenty second', 'twenty third', 'twenty fourth', 'twenty fifth', 'twenty sixth', 'twenty seventh', 'twenty eighth', 'twenty ninth', 'thirtieth', 'thirty first']; - this.valuesMonth = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']; - + this.valuesWeek = [ + 'Sunday', + 'Monday', + 'Tuesday', + 'Wednesday', + 'Thursday', + 'Friday', + 'Saturday', + ]; + this.valuesDay = [ + '', + 'first', + 'second', + 'third', + 'fourth', + 'fifth', + 'sixth', + 'seventh', + 'eighth', + 'ninth', + 'tenth', + 'eleventh', + 'twelfth', + 'thirteenth', + 'fourteen', + 'fifteenth', + 'sixteenth', + 'seveneenth', + 'eighteenth', + 'nineteenth', + 'twentieth', + 'twenty first', + 'twenty second', + 'twenty third', + 'twenty fourth', + 'twenty fifth', + 'twenty sixth', + 'twenty seventh', + 'twenty eighth', + 'twenty ninth', + 'thirtieth', + 'thirty first', + ]; + this.valuesMonth = [ + 'January', + 'February', + 'March', + 'April', + 'May', + 'June', + 'July', + 'August', + 'September', + 'October', + 'November', + 'December', + ]; }; // Initialize slider DatePickerSpinButtons.prototype.init = function () { - - this.spinbuttonDay = new SpinButtonDate(this.dayNode, null, this.updateDay.bind(this)); + this.spinbuttonDay = new SpinButtonDate( + this.dayNode, + null, + this.updateDay.bind(this) + ); this.spinbuttonDay.init(); - this.spinbuttonMonth = new SpinButtonDate(this.monthNode, this.valuesMonth, this.updateMonth.bind(this)); + this.spinbuttonMonth = new SpinButtonDate( + this.monthNode, + this.valuesMonth, + this.updateMonth.bind(this) + ); this.spinbuttonMonth.init(); - this.spinbuttonYear = new SpinButtonDate(this.yearNode, null, this.updateYear.bind(this)); + this.spinbuttonYear = new SpinButtonDate( + this.yearNode, + null, + this.updateYear.bind(this) + ); this.spinbuttonYear.init(); this.spinbuttonYear.noWrap(); @@ -95,7 +158,6 @@ DatePickerSpinButtons.prototype.updateNextDayMonthAndYear = function () { }; DatePickerSpinButtons.prototype.updateSpinButtons = function () { - this.daysInMonth = this.getDaysInMonth(this.year, this.month); this.spinbuttonDay.setValueMax(this.daysInMonth); if (this.day > this.daysInMonth) { @@ -116,22 +178,28 @@ DatePickerSpinButtons.prototype.updateSpinButtons = function () { this.spinbuttonMonth.setNextValue(this.nextMonth); this.spinbuttonYear.setNextValue(this.nextYear); - this.currentDate = new Date(this.year + '-' + (this.month + 1) + '-' + this.day); - - this.dateNode.innerHTML = 'current value is ' + this.valuesWeek[this.currentDate.getDay()] + ', ' + this.spinbuttonMonth.getValueText() + ' ' + this.spinbuttonDay.getValueText() + ', ' + this.spinbuttonYear.getValue(); - - + this.currentDate = new Date( + this.year + '-' + (this.month + 1) + '-' + this.day + ); + + this.dateNode.innerHTML = + 'current value is ' + + this.valuesWeek[this.currentDate.getDay()] + + ', ' + + this.spinbuttonMonth.getValueText() + + ' ' + + this.spinbuttonDay.getValueText() + + ', ' + + this.spinbuttonYear.getValue(); }; // Initialize menu button date picker -window.addEventListener('load' , function () { - +window.addEventListener('load', function () { var dpsbs = document.querySelectorAll('.datepicker-spinbuttons'); dpsbs.forEach(function (dpsb) { var datepicker = new DatePickerSpinButtons(dpsb); datepicker.init(); }); - }); diff --git a/examples/spinbutton/js/spinbutton-date.js b/examples/spinbutton/js/spinbutton-date.js index f4c48fc0a6..a99712ee85 100644 --- a/examples/spinbutton/js/spinbutton-date.js +++ b/examples/spinbutton/js/spinbutton-date.js @@ -1,14 +1,13 @@ /* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -* -* File: spinbutton-date.js -*/ + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * File: spinbutton-date.js + */ 'use strict'; -var SpinButtonDate = function (domNode, values, callback) { - +var SpinButtonDate = function (domNode, values, callback) { this.domNode = domNode; this.values = values; this.callback = callback; @@ -25,43 +24,49 @@ var SpinButtonDate = function (domNode, values, callback) { this.decreaseNode = domNode.querySelector('.decrease'); if (values) { - this.valueMin = 0; - this.valueMax = values.length - 1; + this.valueMin = 0; + this.valueMax = values.length - 1; if (initialValue) { - this.valueNow = values.indexOf(initialValue); + this.valueNow = values.indexOf(initialValue); this.valueText = initialValue; - } - else { - this.valueNow = values.length / 2; + } else { + this.valueNow = values.length / 2; this.valueText = values[this.valueNow]; } - } - else { - this.valueMin = parseInt(this.spinbuttonNode.getAttribute('aria-valuemin')); - this.valueMax = parseInt(this.spinbuttonNode.getAttribute('aria-valuemax')); - this.valueNow = parseInt(this.spinbuttonNode.getAttribute('aria-valuenow')); + } else { + this.valueMin = parseInt(this.spinbuttonNode.getAttribute('aria-valuemin')); + this.valueMax = parseInt(this.spinbuttonNode.getAttribute('aria-valuemax')); + this.valueNow = parseInt(this.spinbuttonNode.getAttribute('aria-valuenow')); this.valueText = this.spinbuttonNode.getAttribute('aria-valuenow'); } this.keyCode = Object.freeze({ - 'UP': 38, - 'DOWN': 40, - 'PAGEUP': 33, - 'PAGEDOWN': 34, - 'END': 35, - 'HOME': 36 + UP: 38, + DOWN: 40, + PAGEUP: 33, + PAGEDOWN: 34, + END: 35, + HOME: 36, }); }; // Initialize slider SpinButtonDate.prototype.init = function () { - - this.spinbuttonNode.addEventListener('keydown', this.handleKeyDown.bind(this)); - this.spinbuttonNode.addEventListener('focus', this.handleFocus.bind(this)); - this.spinbuttonNode.addEventListener('blur', this.handleBlur.bind(this)); - - this.increaseNode.addEventListener('click', this.handleIncreaseClick.bind(this)); - this.decreaseNode.addEventListener('click', this.handleDecreaseClick.bind(this)); + this.spinbuttonNode.addEventListener( + 'keydown', + this.handleKeyDown.bind(this) + ); + this.spinbuttonNode.addEventListener('focus', this.handleFocus.bind(this)); + this.spinbuttonNode.addEventListener('blur', this.handleBlur.bind(this)); + + this.increaseNode.addEventListener( + 'click', + this.handleIncreaseClick.bind(this) + ); + this.decreaseNode.addEventListener( + 'click', + this.handleDecreaseClick.bind(this) + ); }; SpinButtonDate.prototype.noWrap = function () { @@ -76,9 +81,7 @@ SpinButtonDate.prototype.getValueText = function () { return this.valueText; }; - SpinButtonDate.prototype.setValue = function (value, flag) { - if (typeof flag !== 'boolean') { flag = true; } @@ -86,8 +89,7 @@ SpinButtonDate.prototype.setValue = function (value, flag) { if (value > this.valueMax) { if (this.wrap) { value = this.valueMin; - } - else { + } else { value = this.valueMax; } } @@ -95,17 +97,15 @@ SpinButtonDate.prototype.setValue = function (value, flag) { if (value < this.valueMin) { if (this.wrap) { value = this.valueMax; - } - else { + } else { value = this.valueMin; } } - this.valueNow = value; + this.valueNow = value; if (this.values) { this.valueText = this.values[this.valueNow]; - } - else { + } else { if (typeof value === 'number') { this.valueText = parseInt(value); } @@ -119,10 +119,9 @@ SpinButtonDate.prototype.setValue = function (value, flag) { this.spinbuttonNode.innerHTML = this.valueText; - if (flag, this.callback) { + if ((flag, this.callback)) { this.callback(this.valueNow); } - }; SpinButtonDate.prototype.setValueText = function (value) { @@ -130,7 +129,6 @@ SpinButtonDate.prototype.setValueText = function (value) { this.spinbuttonNode.setAttribute('aria-valuetext', value); }; - SpinButtonDate.prototype.getValueMin = function () { return parseInt(this.spinbuttonNode.getAttribute('aria-valuemin')); }; @@ -144,9 +142,7 @@ SpinButtonDate.prototype.setValueMax = function (value) { this.valueMax = value; }; - SpinButtonDate.prototype.setPreviousValue = function (value) { - if (this.values) { value = this.values[value]; } @@ -154,8 +150,7 @@ SpinButtonDate.prototype.setPreviousValue = function (value) { if (typeof value === 'number') { if (value < this.valueMin) { value = ' '; - } - else { + } else { value = parseInt(value); } } @@ -171,8 +166,7 @@ SpinButtonDate.prototype.setNextValue = function (value) { if (typeof value === 'number') { if (value > this.valueMax) { value = ' '; - } - else { + } else { value = parseInt(value); } } @@ -181,7 +175,6 @@ SpinButtonDate.prototype.setNextValue = function (value) { }; SpinButtonDate.prototype.handleKeyDown = function (event) { - var flag = false; switch (event.keyCode) { @@ -223,7 +216,6 @@ SpinButtonDate.prototype.handleKeyDown = function (event) { event.preventDefault(); event.stopPropagation(); } - }; SpinButtonDate.prototype.handleFocus = function () { @@ -235,19 +227,15 @@ SpinButtonDate.prototype.handleBlur = function () { }; SpinButtonDate.prototype.handleIncreaseClick = function (event) { - this.setValue(this.valueNow + 1); event.preventDefault(); event.stopPropagation(); - }; SpinButtonDate.prototype.handleDecreaseClick = function (event) { - this.setValue(this.valueNow - 1); event.preventDefault(); event.stopPropagation(); - }; diff --git a/examples/tabs/tabs-1/js/tabs.js b/examples/tabs/tabs-1/js/tabs.js index c166e641fa..8b217bbbd3 100644 --- a/examples/tabs/tabs-1/js/tabs.js +++ b/examples/tabs/tabs-1/js/tabs.js @@ -1,7 +1,7 @@ /* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -*/ + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + */ 'use strict'; @@ -13,7 +13,7 @@ generateArrays(); - function generateArrays () { + function generateArrays() { tabs = document.querySelectorAll('[role="tab"]'); panels = document.querySelectorAll('[role="tabpanel"]'); } @@ -26,7 +26,7 @@ up: 38, right: 39, down: 40, - delete: 46 + delete: 46, }; // Add or substract depending on key pressed @@ -34,7 +34,7 @@ 37: -1, 38: -1, 39: 1, - 40: 1 + 40: 1, }; // Bind listeners @@ -42,7 +42,7 @@ addListeners(i); } - function addListeners (index) { + function addListeners(index) { tabs[index].addEventListener('click', clickEventListener); tabs[index].addEventListener('keydown', keydownEventListener); tabs[index].addEventListener('keyup', keyupEventListener); @@ -52,13 +52,13 @@ } // When a tab is clicked, activateTab is fired to activate it - function clickEventListener (event) { + function clickEventListener(event) { var tab = event.target; activateTab(tab, false); } // Handle keydown on tabs - function keydownEventListener (event) { + function keydownEventListener(event) { var key = event.keyCode; switch (key) { @@ -83,7 +83,7 @@ } // Handle keyup on tabs - function keyupEventListener (event) { + function keyupEventListener(event) { var key = event.keyCode; switch (key) { @@ -100,7 +100,7 @@ // When a tablist’s aria-orientation is set to vertical, // only up and down arrow should function. // In all other cases only left and right arrow function. - function determineOrientation (event) { + function determineOrientation(event) { var key = event.keyCode; var vertical = tablist.getAttribute('aria-orientation') == 'vertical'; var proceed = false; @@ -110,8 +110,7 @@ event.preventDefault(); proceed = true; } - } - else { + } else { if (key === keys.left || key === keys.right) { proceed = true; } @@ -124,7 +123,7 @@ // Either focus the next, previous, first, or last tab // depening on key pressed - function switchTabOnArrowPress (event) { + function switchTabOnArrowPress(event) { var pressed = event.keyCode; for (var x = 0; x < tabs.length; x++) { @@ -136,11 +135,9 @@ if (target.index !== undefined) { if (tabs[target.index + direction[pressed]]) { tabs[target.index + direction[pressed]].focus(); - } - else if (pressed === keys.left || pressed === keys.up) { + } else if (pressed === keys.left || pressed === keys.up) { focusLastTab(); - } - else if (pressed === keys.right || pressed == keys.down) { + } else if (pressed === keys.right || pressed == keys.down) { focusFirstTab(); } } @@ -148,7 +145,7 @@ } // Activates any given tab panel - function activateTab (tab, setFocus) { + function activateTab(tab, setFocus) { setFocus = setFocus || true; // Deactivate all other tabs deactivateTabs(); @@ -172,7 +169,7 @@ } // Deactivate all tabs and tab panels - function deactivateTabs () { + function deactivateTabs() { for (var t = 0; t < tabs.length; t++) { tabs[t].setAttribute('tabindex', '-1'); tabs[t].setAttribute('aria-selected', 'false'); @@ -185,17 +182,17 @@ } // Make a guess - function focusFirstTab () { + function focusFirstTab() { tabs[0].focus(); } // Make a guess - function focusLastTab () { + function focusLastTab() { tabs[tabs.length - 1].focus(); } // Detect if a tab is deletable - function determineDeletable (event) { + function determineDeletable(event) { var target = event.target; if (target.getAttribute('data-deletable') !== null) { @@ -208,15 +205,14 @@ // Activate the closest tab to the one that was just deleted if (target.index - 1 < 0) { activateTab(tabs[0]); - } - else { + } else { activateTab(tabs[target.index - 1]); } } } // Deletes a tab and its panel - function deleteTab (event) { + function deleteTab(event) { var target = event.target; var panel = document.getElementById(target.getAttribute('aria-controls')); @@ -226,7 +222,7 @@ // Determine whether there should be a delay // when user navigates with the arrow keys - function determineDelay () { + function determineDelay() { var hasDelay = tablist.hasAttribute('data-delay'); var delay = 0; @@ -234,8 +230,7 @@ var delayValue = tablist.getAttribute('data-delay'); if (delayValue) { delay = delayValue; - } - else { + } else { // If no value is specified, default to 300ms delay = 300; } @@ -245,18 +240,18 @@ } // - function focusEventHandler (event) { + function focusEventHandler(event) { var target = event.target; setTimeout(checkTabFocus, delay, target); } // Only activate tab on focus if it still has focus after the delay - function checkTabFocus (target) { + function checkTabFocus(target) { var focused = document.activeElement; if (target === focused) { activateTab(target, false); } } -}()); +})(); diff --git a/examples/tabs/tabs-2/js/tabs.js b/examples/tabs/tabs-2/js/tabs.js index 7c512d95c3..2b3eda488e 100644 --- a/examples/tabs/tabs-2/js/tabs.js +++ b/examples/tabs/tabs-2/js/tabs.js @@ -1,7 +1,7 @@ /* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -*/ + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + */ 'use strict'; @@ -12,7 +12,7 @@ generateArrays(); - function generateArrays () { + function generateArrays() { tabs = document.querySelectorAll('[role="tab"]'); panels = document.querySelectorAll('[role="tabpanel"]'); } @@ -27,7 +27,7 @@ down: 40, delete: 46, enter: 13, - space: 32 + space: 32, }; // Add or subtract depending on key pressed @@ -35,7 +35,7 @@ 37: -1, 38: -1, 39: 1, - 40: 1 + 40: 1, }; // Bind listeners @@ -43,7 +43,7 @@ addListeners(i); } - function addListeners (index) { + function addListeners(index) { tabs[index].addEventListener('click', clickEventListener); tabs[index].addEventListener('keydown', keydownEventListener); tabs[index].addEventListener('keyup', keyupEventListener); @@ -53,13 +53,13 @@ } // When a tab is clicked, activateTab is fired to activate it - function clickEventListener (event) { + function clickEventListener(event) { var tab = event.target; activateTab(tab, false); } // Handle keydown on tabs - function keydownEventListener (event) { + function keydownEventListener(event) { var key = event.keyCode; switch (key) { @@ -84,7 +84,7 @@ } // Handle keyup on tabs - function keyupEventListener (event) { + function keyupEventListener(event) { var key = event.keyCode; switch (key) { @@ -105,7 +105,7 @@ // When a tablist’s aria-orientation is set to vertical, // only up and down arrow should function. // In all other cases only left and right arrow function. - function determineOrientation (event) { + function determineOrientation(event) { var key = event.keyCode; var vertical = tablist.getAttribute('aria-orientation') == 'vertical'; var proceed = false; @@ -115,8 +115,7 @@ event.preventDefault(); proceed = true; } - } - else { + } else { if (key === keys.left || key === keys.right) { proceed = true; } @@ -129,7 +128,7 @@ // Either focus the next, previous, first, or last tab // depending on key pressed - function switchTabOnArrowPress (event) { + function switchTabOnArrowPress(event) { var pressed = event.keyCode; if (direction[pressed]) { @@ -137,11 +136,9 @@ if (target.index !== undefined) { if (tabs[target.index + direction[pressed]]) { tabs[target.index + direction[pressed]].focus(); - } - else if (pressed === keys.left || pressed === keys.up) { + } else if (pressed === keys.left || pressed === keys.up) { focusLastTab(); - } - else if (pressed === keys.right || pressed == keys.down) { + } else if (pressed === keys.right || pressed == keys.down) { focusFirstTab(); } } @@ -149,7 +146,7 @@ } // Activates any given tab panel - function activateTab (tab, setFocus) { + function activateTab(tab, setFocus) { setFocus = setFocus || true; // Deactivate all other tabs deactivateTabs(); @@ -173,7 +170,7 @@ } // Deactivate all tabs and tab panels - function deactivateTabs () { + function deactivateTabs() { for (var t = 0; t < tabs.length; t++) { tabs[t].setAttribute('tabindex', '-1'); tabs[t].setAttribute('aria-selected', 'false'); @@ -185,17 +182,17 @@ } // Make a guess - function focusFirstTab () { + function focusFirstTab() { tabs[0].focus(); } // Make a guess - function focusLastTab () { + function focusLastTab() { tabs[tabs.length - 1].focus(); } // Detect if a tab is deletable - function determineDeletable (event) { + function determineDeletable(event) { var target = event.target; if (target.getAttribute('data-deletable') !== null) { @@ -208,15 +205,14 @@ // Activate the closest tab to the one that was just deleted if (target.index - 1 < 0) { activateTab(tabs[0]); - } - else { + } else { activateTab(tabs[target.index - 1]); } } } // Deletes a tab and its panel - function deleteTab (event) { + function deleteTab(event) { var target = event.target; var panel = document.getElementById(target.getAttribute('aria-controls')); @@ -226,7 +222,7 @@ // Determine whether there should be a delay // when user navigates with the arrow keys - function determineDelay () { + function determineDelay() { var hasDelay = tablist.hasAttribute('data-delay'); var delay = 0; @@ -234,8 +230,7 @@ var delayValue = tablist.getAttribute('data-delay'); if (delayValue) { delay = delayValue; - } - else { + } else { // If no value is specified, default to 300ms delay = 300; } @@ -243,4 +238,4 @@ return delay; } -}()); +})(); diff --git a/examples/toolbar/js/FontMenu.js b/examples/toolbar/js/FontMenu.js index 993d9b778d..75485ae17c 100644 --- a/examples/toolbar/js/FontMenu.js +++ b/examples/toolbar/js/FontMenu.js @@ -1,9 +1,9 @@ /* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -* -* File: FontMenu.js -*/ + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * File: FontMenu.js + */ 'use strict'; @@ -28,7 +28,9 @@ var FontMenu = function (domNode, controllerObj) { var menuitem = childElement.firstElementChild; if (menuitem && menuitem === 'A') { - throw new Error(msgPrefix + 'Cannot have descendant elements are A elements.'); + throw new Error( + msgPrefix + 'Cannot have descendant elements are A elements.' + ); } childElement = childElement.nextElementSibling; } @@ -36,24 +38,24 @@ var FontMenu = function (domNode, controllerObj) { this.domNode = domNode; this.controller = controllerObj; - this.menuitems = []; // See PopupMenu init method - this.firstChars = []; // See PopupMenu init method + this.menuitems = []; // See PopupMenu init method + this.firstChars = []; // See PopupMenu init method - this.firstItem = null; // See PopupMenu init method - this.lastItem = null; // See PopupMenu init method + this.firstItem = null; // See PopupMenu init method + this.lastItem = null; // See PopupMenu init method - this.hasFocus = false; // See MenuItem handleFocus, handleBlur - this.hasHover = false; // See PopupMenu handleMouseover, handleMouseout + this.hasFocus = false; // See MenuItem handleFocus, handleBlur + this.hasHover = false; // See PopupMenu handleMouseover, handleMouseout }; /* -* @method FontMenu.prototype.init -* -* @desc -* Add domNode event listeners for mouseover and mouseout. Traverse -* domNode children to configure each menuitem and populate menuitems -* array. Initialize firstItem and lastItem properties. -*/ + * @method FontMenu.prototype.init + * + * @desc + * Add domNode event listeners for mouseover and mouseout. Traverse + * domNode children to configure each menuitem and populate menuitems + * array. Initialize firstItem and lastItem properties. + */ FontMenu.prototype.init = function () { var menuitemElements, menuitemElement, menuItem, textContent, numItems; @@ -104,12 +106,10 @@ FontMenu.prototype.setFocusToController = function (command) { if (command === 'previous') { this.controller.toolbar.setFocusToPrevious(this.controller.toolbarItem); - } - else { + } else { if (command === 'next') { this.controller.toolbar.setFocusToNext(this.controller.toolbarItem); - } - else { + } else { this.controller.domNode.focus(); } } @@ -136,8 +136,7 @@ FontMenu.prototype.setFocusToPreviousItem = function (currentItem) { if (currentItem === this.firstItem) { this.lastItem.domNode.focus(); - } - else { + } else { index = this.menuitems.indexOf(currentItem); this.menuitems[index - 1].domNode.focus(); } @@ -148,8 +147,7 @@ FontMenu.prototype.setFocusToNextItem = function (currentItem) { if (currentItem === this.lastItem) { this.firstItem.domNode.focus(); - } - else { + } else { index = this.menuitems.indexOf(currentItem); this.menuitems[index + 1].domNode.focus(); } @@ -225,7 +223,7 @@ FontMenu.prototype.open = function () { // Set CSS properties this.domNode.style.display = 'block'; this.domNode.style.position = 'absolute'; - this.domNode.style.top = (rect.height - 1) + 'px'; + this.domNode.style.top = rect.height - 1 + 'px'; this.domNode.style.left = '0px'; this.domNode.style.zIndex = 100; @@ -238,7 +236,10 @@ FontMenu.prototype.close = function (force) { force = false; } - if (force || (!this.hasFocus && !this.hasHover && !this.controller.hasHover)) { + if ( + force || + (!this.hasFocus && !this.hasHover && !this.controller.hasHover) + ) { this.domNode.style.display = 'none'; this.controller.domNode.removeAttribute('aria-expanded'); } diff --git a/examples/toolbar/js/FontMenuButton.js b/examples/toolbar/js/FontMenuButton.js index 15ffb2ca6a..30d0d9b431 100644 --- a/examples/toolbar/js/FontMenuButton.js +++ b/examples/toolbar/js/FontMenuButton.js @@ -1,9 +1,9 @@ /* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -* -* File: FontMenuButton.js -*/ + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * File: FontMenuButton.js + */ 'use strict'; @@ -17,12 +17,12 @@ function FontMenuButton(node, toolbar, toolbarItem) { this.value = ''; this.keyCode = Object.freeze({ - 'TAB': 9, - 'ENTER': 13, - 'ESC': 27, - 'SPACE': 32, - 'UP': 38, - 'DOWN': 40 + TAB: 9, + ENTER: 13, + ESC: 27, + SPACE: 32, + UP: 38, + DOWN: 40, }); } @@ -68,8 +68,7 @@ FontMenuButton.prototype.handleKeyDown = function (event) { FontMenuButton.prototype.handleClick = function (event, menuButton) { if (this.fontMenu.isOpen()) { this.fontMenu.close(); - } - else { + } else { this.fontMenu.open(); } }; @@ -81,4 +80,3 @@ FontMenuButton.prototype.setFontFamily = function (font) { this.domNode.setAttribute('aria-label', 'Font: ' + font); this.toolbar.activateItem(this); }; - diff --git a/examples/toolbar/js/FontMenuItem.js b/examples/toolbar/js/FontMenuItem.js index 74e7e749e4..5fbd8ee4f9 100644 --- a/examples/toolbar/js/FontMenuItem.js +++ b/examples/toolbar/js/FontMenuItem.js @@ -1,46 +1,45 @@ /* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -* -* File: FontMenuItem.js -*/ + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * File: FontMenuItem.js + */ 'use strict'; /* -* @constructor MenuItem -* -* @desc -* Wrapper object for a simple menu item in a popup menu -* -* @param domNode -* The DOM element node that serves as the menu item container. -* The menuObj PopupMenu is responsible for checking that it has -* requisite metadata, e.g. role="menuitem". -* -* @param menuObj -* The object that is a wrapper for the PopupMenu DOM element that -* contains the menu item DOM element. See PopupMenuAction.js -*/ + * @constructor MenuItem + * + * @desc + * Wrapper object for a simple menu item in a popup menu + * + * @param domNode + * The DOM element node that serves as the menu item container. + * The menuObj PopupMenu is responsible for checking that it has + * requisite metadata, e.g. role="menuitem". + * + * @param menuObj + * The object that is a wrapper for the PopupMenu DOM element that + * contains the menu item DOM element. See PopupMenuAction.js + */ var FontMenuItem = function (domNode, fontMenu) { - - this.domNode = domNode; + this.domNode = domNode; this.fontMenu = fontMenu; - this.font = ''; + this.font = ''; this.keyCode = Object.freeze({ - 'TAB': 9, - 'ENTER': 13, - 'ESC': 27, - 'SPACE': 32, - 'PAGEUP': 33, - 'PAGEDOWN': 34, - 'END': 35, - 'HOME': 36, - 'LEFT': 37, - 'UP': 38, - 'RIGHT': 39, - 'DOWN': 40 + TAB: 9, + ENTER: 13, + ESC: 27, + SPACE: 32, + PAGEUP: 33, + PAGEDOWN: 34, + END: 35, + HOME: 36, + LEFT: 37, + UP: 38, + RIGHT: 39, + DOWN: 40, }); }; @@ -53,13 +52,12 @@ FontMenuItem.prototype.init = function () { this.font = this.domNode.textContent.trim().toLowerCase(); - this.domNode.addEventListener('keydown', this.handleKeydown.bind(this)); - this.domNode.addEventListener('click', this.handleClick.bind(this)); - this.domNode.addEventListener('focus', this.handleFocus.bind(this)); - this.domNode.addEventListener('blur', this.handleBlur.bind(this)); - this.domNode.addEventListener('mouseover', this.handleMouseover.bind(this)); - this.domNode.addEventListener('mouseout', this.handleMouseout.bind(this)); - + this.domNode.addEventListener('keydown', this.handleKeydown.bind(this)); + this.domNode.addEventListener('click', this.handleClick.bind(this)); + this.domNode.addEventListener('focus', this.handleFocus.bind(this)); + this.domNode.addEventListener('blur', this.handleBlur.bind(this)); + this.domNode.addEventListener('mouseover', this.handleMouseover.bind(this)); + this.domNode.addEventListener('mouseout', this.handleMouseout.bind(this)); }; /* EVENT HANDLERS */ @@ -70,11 +68,11 @@ FontMenuItem.prototype.handleKeydown = function (event) { char = event.key, clickEvent; - function isPrintableCharacter (str) { + function isPrintableCharacter(str) { return str.length === 1 && str.match(/\S/); } - if (event.ctrlKey || event.altKey || event.metaKey) { + if (event.ctrlKey || event.altKey || event.metaKey) { return; } @@ -82,9 +80,7 @@ FontMenuItem.prototype.handleKeydown = function (event) { if (isPrintableCharacter(char)) { this.fontMenu.setFocusByFirstCharacter(this, char); } - } - else { - + } else { switch (event.keyCode) { case this.keyCode.SPACE: case this.keyCode.ENTER: @@ -164,7 +160,6 @@ FontMenuItem.prototype.handleBlur = function (event) { FontMenuItem.prototype.handleMouseover = function (event) { this.fontMenu.hasHover = true; this.fontMenu.open(); - }; FontMenuItem.prototype.handleMouseout = function (event) { diff --git a/examples/toolbar/js/FormatToolbar.js b/examples/toolbar/js/FormatToolbar.js index d9517f7c43..4b40996ee2 100644 --- a/examples/toolbar/js/FormatToolbar.js +++ b/examples/toolbar/js/FormatToolbar.js @@ -1,9 +1,9 @@ /* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -* -* File: FormatToolbar.js -*/ + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * File: FormatToolbar.js + */ 'use strict'; @@ -35,29 +35,29 @@ function FormatToolbar(domNode) { this.selected = null; this.nightModeCheck = null; - } FormatToolbar.prototype.init = function () { var i, items, toolbarItem, menuButton; - this.textarea = document.getElementById(this.domNode.getAttribute('aria-controls')); - this.textarea.style.width = (this.domNode.getBoundingClientRect().width - 12) + 'px'; + this.textarea = document.getElementById( + this.domNode.getAttribute('aria-controls') + ); + this.textarea.style.width = + this.domNode.getBoundingClientRect().width - 12 + 'px'; this.textarea.addEventListener('mouseup', this.selectTextContent.bind(this)); this.textarea.addEventListener('keyup', this.selectTextContent.bind(this)); this.selected = this.textarea.selectText; - this.copyButton = this.domNode.querySelector('.copy'); - this.cutButton = this.domNode.querySelector('.cut'); + this.copyButton = this.domNode.querySelector('.copy'); + this.cutButton = this.domNode.querySelector('.cut'); this.pasteButton = this.domNode.querySelector('.paste'); this.nightModeCheck = this.domNode.querySelector('.nightmode'); - items = this.domNode.querySelectorAll('.item'); - + items = this.domNode.querySelectorAll('.item'); for (i = 0; i < items.length; i++) { - toolbarItem = new FormatToolbarItem(items[i], this); toolbarItem.init(); @@ -79,26 +79,33 @@ FormatToolbar.prototype.init = function () { var s = new SpinButton(spinButtons[i], this); s.init(); } - }; FormatToolbar.prototype.selectTextContent = function () { this.start = this.textarea.selectionStart; this.end = this.textarea.selectionEnd; this.selected = this.textarea.value.substring(this.start, this.end); - this.updateDisable(this.copyButton, this.cutButton, this.pasteButton, this.selected); - + this.updateDisable( + this.copyButton, + this.cutButton, + this.pasteButton, + this.selected + ); }; -FormatToolbar.prototype.updateDisable = function (copyButton, cutButton, pasteButton, selectedContent) { +FormatToolbar.prototype.updateDisable = function ( + copyButton, + cutButton, + pasteButton, + selectedContent +) { var start = this.textarea.selectionStart; var end = this.textarea.selectionEnd; if (start !== end) { copyButton.setAttribute('aria-disabled', false); - cutButton.setAttribute('aria-disabled', false); - } - else { + cutButton.setAttribute('aria-disabled', false); + } else { copyButton.setAttribute('aria-disabled', true); - cutButton.setAttribute('aria-disabled', true); + cutButton.setAttribute('aria-disabled', true); } if (this.ourClipboard.length > 0) { pasteButton.setAttribute('aria-disabled', false); @@ -106,7 +113,7 @@ FormatToolbar.prototype.updateDisable = function (copyButton, cutButton, pasteBu }; FormatToolbar.prototype.selectText = function (start, end, textarea) { - if (typeof textarea.selectionStart !== "undefined") { + if (typeof textarea.selectionStart !== 'undefined') { textarea.focus(); textarea.selectionStart = start; textarea.selectionEnd = end; @@ -119,8 +126,12 @@ FormatToolbar.prototype.copyTextContent = function (toolbarItem) { } this.selectText(this.start, this.end, this.textarea); this.ourClipboard = this.selected; - this.updateDisable(this.copyButton, this.cutButton, this.pasteButton, this.selected); - + this.updateDisable( + this.copyButton, + this.cutButton, + this.pasteButton, + this.selected + ); }; FormatToolbar.prototype.cutTextContent = function (toolbarItem) { @@ -129,9 +140,14 @@ FormatToolbar.prototype.cutTextContent = function (toolbarItem) { } this.copyTextContent(toolbarItem); var str = this.textarea.value; - this.textarea.value = str.replace(str.substring(this.start, this.end),''); + this.textarea.value = str.replace(str.substring(this.start, this.end), ''); this.selected = ''; - this.updateDisable(this.copyButton, this.cutButton, this.pasteButton, this.selected); + this.updateDisable( + this.copyButton, + this.cutButton, + this.pasteButton, + this.selected + ); }; FormatToolbar.prototype.pasteTextContent = function () { @@ -139,18 +155,24 @@ FormatToolbar.prototype.pasteTextContent = function () { return; } var str = this.textarea.value; - this.textarea.value = str.slice(0,this.textarea.selectionStart) + this.ourClipboard + str.slice(this.textarea.selectionEnd); + this.textarea.value = + str.slice(0, this.textarea.selectionStart) + + this.ourClipboard + + str.slice(this.textarea.selectionEnd); this.textarea.focus(); - this.updateDisable(this.copyButton, this.cutButton, this.pasteButton, this.selected); + this.updateDisable( + this.copyButton, + this.cutButton, + this.pasteButton, + this.selected + ); }; - FormatToolbar.prototype.toggleBold = function (toolbarItem) { if (toolbarItem.isPressed()) { this.textarea.style.fontWeight = 'normal'; toolbarItem.resetPressed(); - } - else { + } else { this.textarea.style.fontWeight = 'bold'; toolbarItem.setPressed(); } @@ -160,8 +182,7 @@ FormatToolbar.prototype.toggleUnderline = function (toolbarItem) { if (toolbarItem.isPressed()) { this.textarea.style.textDecoration = 'none'; toolbarItem.resetPressed(); - } - else { + } else { this.textarea.style.textDecoration = 'underline'; toolbarItem.setPressed(); } @@ -171,8 +192,7 @@ FormatToolbar.prototype.toggleItalic = function (toolbarItem) { if (toolbarItem.isPressed()) { this.textarea.style.fontStyle = 'normal'; toolbarItem.resetPressed(); - } - else { + } else { this.textarea.style.fontStyle = 'italic'; toolbarItem.setPressed(); } @@ -186,18 +206,14 @@ FormatToolbar.prototype.toggleNightMode = function (toolbarItem) { if (this.nightModeCheck.checked) { this.textarea.style.color = '#eee'; this.textarea.style.background = 'black'; - } - else { + } else { this.textarea.style.color = 'black'; this.textarea.style.background = 'white'; } }; FormatToolbar.prototype.redirectLink = function (toolbarItem) { - window.open( - toolbarItem.domNode.href, - '_blank' - ); + window.open(toolbarItem.domNode.href, '_blank'); }; FormatToolbar.prototype.setAlignment = function (toolbarItem) { @@ -269,7 +285,6 @@ FormatToolbar.prototype.activateItem = function (toolbarItem) { break; default: break; - } }; @@ -294,8 +309,7 @@ FormatToolbar.prototype.setFocusToNext = function (currentItem) { if (currentItem === this.lastItem) { newItem = this.firstItem; - } - else { + } else { index = this.toolbarItems.indexOf(currentItem); newItem = this.toolbarItems[index + 1]; } @@ -307,8 +321,7 @@ FormatToolbar.prototype.setFocusToPrevious = function (currentItem) { if (currentItem === this.firstItem) { newItem = this.lastItem; - } - else { + } else { index = this.toolbarItems.indexOf(currentItem); newItem = this.toolbarItems[index - 1]; } @@ -325,20 +338,21 @@ FormatToolbar.prototype.setFocusToLast = function (currentItem) { FormatToolbar.prototype.hidePopupLabels = function () { var tps = this.domNode.querySelectorAll('button .popup-label'); - tps.forEach(function (tp) {tp.classList.remove('show');}); + tps.forEach(function (tp) { + tp.classList.remove('show'); + }); }; - // Initialize toolbars /* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -* -* ARIA Toolbar Examples -* @function onload -* @desc Initialize the toolbar example once the page has loaded -*/ + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * ARIA Toolbar Examples + * @function onload + * @desc Initialize the toolbar example once the page has loaded + */ window.addEventListener('load', function () { var toolbars = document.querySelectorAll('[role="toolbar"].format'); diff --git a/examples/toolbar/js/FormatToolbarItem.js b/examples/toolbar/js/FormatToolbarItem.js index d889974095..d50d32709d 100644 --- a/examples/toolbar/js/FormatToolbarItem.js +++ b/examples/toolbar/js/FormatToolbarItem.js @@ -1,9 +1,9 @@ /* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -* -* File: FontToolbarItem.js -*/ + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * File: FontToolbarItem.js + */ 'use strict'; @@ -16,20 +16,19 @@ function FormatToolbarItem(domNode, toolbar) { this.hasHover = false; this.popupLabelDelay = 800; - this.keyCode = Object.freeze({ - 'TAB': 9, - 'ENTER': 13, - 'ESC': 27, - 'SPACE': 32, - 'PAGEUP': 33, - 'PAGEDOWN': 34, - 'END': 35, - 'HOME': 36, - 'LEFT': 37, - 'UP': 38, - 'RIGHT': 39, - 'DOWN': 40 + TAB: 9, + ENTER: 13, + ESC: 27, + SPACE: 32, + PAGEUP: 33, + PAGEDOWN: 34, + END: 35, + HOME: 36, + LEFT: 37, + UP: 38, + RIGHT: 39, + DOWN: 40, }); } @@ -41,8 +40,10 @@ FormatToolbarItem.prototype.init = function () { this.domNode.addEventListener('mouseover', this.handleMouseOver.bind(this)); this.domNode.addEventListener('mouseleave', this.handleMouseLeave.bind(this)); - document.body.addEventListener('keydown', this.handleHideAllPopupLabels.bind(this)); - + document.body.addEventListener( + 'keydown', + this.handleHideAllPopupLabels.bind(this) + ); if (this.domNode.classList.contains('bold')) { this.buttonAction = 'bold'; @@ -97,13 +98,13 @@ FormatToolbarItem.prototype.init = function () { if (this.popupLabelNode) { var width = 8 * this.popupLabelNode.textContent.length; this.popupLabelNode.style.width = width + 'px'; - this.popupLabelNode.style.left = -1 * ((width - this.domNode.offsetWidth) / 2) - 5 + 'px'; + this.popupLabelNode.style.left = + -1 * ((width - this.domNode.offsetWidth) / 2) - 5 + 'px'; } - }; FormatToolbarItem.prototype.isPressed = function () { - return this.domNode.getAttribute('aria-pressed') === 'true'; + return this.domNode.getAttribute('aria-pressed') === 'true'; }; FormatToolbarItem.prototype.setPressed = function () { @@ -114,11 +115,9 @@ FormatToolbarItem.prototype.resetPressed = function () { this.domNode.setAttribute('aria-pressed', 'false'); }; - FormatToolbarItem.prototype.setChecked = function () { this.domNode.setAttribute('aria-checked', 'true'); this.domNode.checked = true; - }; FormatToolbarItem.prototype.resetChecked = function () { @@ -147,13 +146,10 @@ FormatToolbarItem.prototype.hidePopupLabel = function () { } }; - // Events FormatToolbarItem.prototype.handleHideAllPopupLabels = function (event) { - switch (event.keyCode) { - case this.keyCode.ESC: this.toolbar.hidePopupLabels(); break; @@ -161,11 +157,8 @@ FormatToolbarItem.prototype.handleHideAllPopupLabels = function (event) { default: break; } - - }; - FormatToolbarItem.prototype.handleBlur = function (event) { this.toolbar.domNode.classList.remove('focus'); @@ -198,13 +191,14 @@ FormatToolbarItem.prototype.handleKeyDown = function (event) { var flag = false; switch (event.keyCode) { - case this.keyCode.ENTER: case this.keyCode.SPACE: - if ((this.buttonAction !== '') && - (this.buttonAction !== 'bold') && - (this.buttonAction !== 'italic') && - (this.buttonAction !== 'underline')) { + if ( + this.buttonAction !== '' && + this.buttonAction !== 'bold' && + this.buttonAction !== 'italic' && + this.buttonAction !== 'underline' + ) { this.toolbar.activateItem(this); if (this.buttonAction !== 'nightmode') { flag = true; @@ -236,8 +230,7 @@ FormatToolbarItem.prototype.handleKeyDown = function (event) { if (this.buttonAction === 'align') { if (this.domNode.classList.contains('align-left')) { this.toolbar.setFocusToLastAlignItem(); - } - else { + } else { this.toolbar.setFocusToPrevious(this); } flag = true; @@ -247,8 +240,7 @@ FormatToolbarItem.prototype.handleKeyDown = function (event) { if (this.buttonAction === 'align') { if (this.domNode.classList.contains('align-right')) { this.toolbar.setFocusToFirstAlignItem(); - } - else { + } else { this.toolbar.setFocusToNext(this); } flag = true; @@ -262,11 +254,9 @@ FormatToolbarItem.prototype.handleKeyDown = function (event) { event.stopPropagation(); event.preventDefault(); } - }; FormatToolbarItem.prototype.handleClick = function (e) { - if (this.buttonAction == 'link') { return; } diff --git a/examples/toolbar/js/SpinButton.js b/examples/toolbar/js/SpinButton.js index 15b8105792..3fb5570d37 100644 --- a/examples/toolbar/js/SpinButton.js +++ b/examples/toolbar/js/SpinButton.js @@ -1,15 +1,14 @@ /* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -* -* File: SpinButton.js -*/ + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * File: SpinButton.js + */ 'use strict'; // Create SpinButton that contains value, valuemin, valuemax, and valuenow -var SpinButton = function (domNode, toolbar) { - +var SpinButton = function (domNode, toolbar) { this.domNode = domNode; this.toolbar = toolbar; @@ -17,47 +16,50 @@ var SpinButton = function (domNode, toolbar) { this.increaseDomNode = domNode.querySelector('.increase'); this.decreaseDomNode = domNode.querySelector('.decrease'); - this.valueMin = 8; - this.valueMax = 40; - this.valueNow = 12; + this.valueMin = 8; + this.valueMax = 40; + this.valueNow = 12; this.valueText = this.valueNow + ' Point'; this.keyCode = Object.freeze({ - 'UP': 38, - 'DOWN': 40, - 'PAGEUP': 33, - 'PAGEDOWN': 34, - 'END': 35, - 'HOME': 36 + UP: 38, + DOWN: 40, + PAGEUP: 33, + PAGEDOWN: 34, + END: 35, + HOME: 36, }); }; // Initialize slider SpinButton.prototype.init = function () { - if (this.domNode.getAttribute('aria-valuemin')) { - this.valueMin = parseInt((this.domNode.getAttribute('aria-valuemin'))); + this.valueMin = parseInt(this.domNode.getAttribute('aria-valuemin')); } if (this.domNode.getAttribute('aria-valuemax')) { - this.valueMax = parseInt((this.domNode.getAttribute('aria-valuemax'))); + this.valueMax = parseInt(this.domNode.getAttribute('aria-valuemax')); } if (this.domNode.getAttribute('aria-valuenow')) { - this.valueNow = parseInt((this.domNode.getAttribute('aria-valuenow'))); + this.valueNow = parseInt(this.domNode.getAttribute('aria-valuenow')); } this.setValue(this.valueNow); - this.domNode.addEventListener('keydown', this.handleKeyDown.bind(this)); - - this.increaseDomNode.addEventListener('click', this.handleIncreaseClick.bind(this)); - this.decreaseDomNode.addEventListener('click', this.handleDecreaseClick.bind(this)); + this.domNode.addEventListener('keydown', this.handleKeyDown.bind(this)); + this.increaseDomNode.addEventListener( + 'click', + this.handleIncreaseClick.bind(this) + ); + this.decreaseDomNode.addEventListener( + 'click', + this.handleDecreaseClick.bind(this) + ); }; SpinButton.prototype.setValue = function (value) { - if (value > this.valueMax) { value = this.valueMax; } @@ -66,7 +68,7 @@ SpinButton.prototype.setValue = function (value) { value = this.valueMin; } - this.valueNow = value; + this.valueNow = value; this.valueText = value + ' Point'; this.domNode.setAttribute('aria-valuenow', this.valueNow); @@ -77,11 +79,9 @@ SpinButton.prototype.setValue = function (value) { } this.toolbar.changeFontSize(value); - }; SpinButton.prototype.handleKeyDown = function (event) { - var flag = false; switch (event.keyCode) { @@ -123,23 +123,18 @@ SpinButton.prototype.handleKeyDown = function (event) { event.preventDefault(); event.stopPropagation(); } - }; SpinButton.prototype.handleIncreaseClick = function (event) { - this.setValue(this.valueNow + 1); event.preventDefault(); event.stopPropagation(); - }; SpinButton.prototype.handleDecreaseClick = function (event) { - this.setValue(this.valueNow - 1); event.preventDefault(); event.stopPropagation(); - }; diff --git a/examples/treegrid/js/treegrid-1.js b/examples/treegrid/js/treegrid-1.js index 2c14a10dc5..d7234f4803 100644 --- a/examples/treegrid/js/treegrid-1.js +++ b/examples/treegrid/js/treegrid-1.js @@ -1,7 +1,7 @@ 'use strict'; /* exported TreeGrid */ -function TreeGrid (treegridElem, doAllowRowFocus, doStartRowFocus) { - function initAttributes () { +function TreeGrid(treegridElem, doAllowRowFocus, doStartRowFocus) { + function initAttributes() { // Make sure focusable elements are not in the tab order // They will be added back in for the active row setTabIndexOfFocusableElems(treegridElem, -1); @@ -16,8 +16,7 @@ function TreeGrid (treegridElem, doAllowRowFocus, doStartRowFocus) { while (index--) { if (doAllowRowFocus) { rows[index].tabIndex = index === startRowIndex ? 0 : -1; - } - else { + } else { setTabIndexForCellsInRow(rows[index], -1); moveAriaExpandedToFirstCell(rows[index]); } @@ -32,12 +31,12 @@ function TreeGrid (treegridElem, doAllowRowFocus, doStartRowFocus) { setTabIndexForCell(firstCell); } - function setTabIndexForCell (cell, tabIndex) { + function setTabIndexForCell(cell, tabIndex) { var focusable = getFocusableElems(cell)[0] || cell; focusable.tabIndex = tabIndex; } - function setTabIndexForCellsInRow (row, tabIndex) { + function setTabIndexForCellsInRow(row, tabIndex) { var cells = getNavigableCols(row); var cellIndex = cells.length; while (cellIndex--) { @@ -45,12 +44,12 @@ function TreeGrid (treegridElem, doAllowRowFocus, doStartRowFocus) { } } - function getAllRows () { + function getAllRows() { var nodeList = treegridElem.querySelectorAll('tbody > tr'); return Array.prototype.slice.call(nodeList); } - function getFocusableElems (root) { + function getFocusableElems(root) { // textarea not supported as a cell widget as it's multiple lines // and needs up/down keys // These should all be descendants of a cell @@ -58,7 +57,7 @@ function TreeGrid (treegridElem, doAllowRowFocus, doStartRowFocus) { return Array.prototype.slice.call(nodeList); } - function setTabIndexOfFocusableElems (root, tabIndex) { + function setTabIndexOfFocusableElems(root, tabIndex) { var focusableElems = getFocusableElems(root); var index = focusableElems.length; while (index--) { @@ -66,30 +65,32 @@ function TreeGrid (treegridElem, doAllowRowFocus, doStartRowFocus) { } } - function getAllNavigableRows () { - var nodeList = treegridElem.querySelectorAll('tbody > tr:not([class~="hidden"])'); + function getAllNavigableRows() { + var nodeList = treegridElem.querySelectorAll( + 'tbody > tr:not([class~="hidden"])' + ); // Convert to array so that we can use array methods on it return Array.prototype.slice.call(nodeList); } - function getNavigableCols (currentRow) { + function getNavigableCols(currentRow) { var nodeList = currentRow.getElementsByTagName('td'); return Array.prototype.slice.call(nodeList); } - function restrictIndex (index, numItems) { + function restrictIndex(index, numItems) { if (index < 0) { return 0; } return index >= numItems ? index - 1 : index; } - function focus (elem) { + function focus(elem) { elem.tabIndex = 0; // Ensure focusable elem.focus(); } - function focusCell (cell) { + function focusCell(cell) { // Check for focusable child such as link or textbox // and use that if available var focusableChildren = getFocusableElems(cell); @@ -98,18 +99,22 @@ function TreeGrid (treegridElem, doAllowRowFocus, doStartRowFocus) { // Restore tabIndex to what it should be when focus switches from // one treegrid item to another - function onFocusIn (event) { + function onFocusIn(event) { var newTreeGridFocus = - event.target !== window && treegridElem.contains(event.target) && - event.target; + event.target !== window && + treegridElem.contains(event.target) && + event.target; // The last row we considered focused var oldCurrentRow = enableTabbingInActiveRowDescendants.tabbingRow; if (oldCurrentRow) { enableTabbingInActiveRowDescendants(false, oldCurrentRow); } - if (doAllowRowFocus && onFocusIn.prevTreeGridFocus && - onFocusIn.prevTreeGridFocus.localName === 'td') { + if ( + doAllowRowFocus && + onFocusIn.prevTreeGridFocus && + onFocusIn.prevTreeGridFocus.localName === 'td' + ) { // Was focused on td, remove tabIndex so that it's not focused on click onFocusIn.prevTreeGridFocus.removeAttribute('tabindex'); } @@ -135,13 +140,12 @@ function TreeGrid (treegridElem, doAllowRowFocus, doStartRowFocus) { } // Set whether interactive elements within a row are tabbable - function enableTabbingInActiveRowDescendants (isTabbingOn, row) { + function enableTabbingInActiveRowDescendants(isTabbingOn, row) { if (row) { setTabIndexOfFocusableElems(row, isTabbingOn ? 0 : -1); if (isTabbingOn) { enableTabbingInActiveRowDescendants.tabbingRow = row; - } - else { + } else { if (enableTabbingInActiveRowDescendants.tabbingRow === row) { enableTabbingInActiveRowDescendants.tabbingRow = null; } @@ -151,11 +155,11 @@ function TreeGrid (treegridElem, doAllowRowFocus, doStartRowFocus) { // The row with focus is the row that either has focus or an element // inside of it has focus - function getRowWithFocus () { + function getRowWithFocus() { return getContainingRow(document.activeElement); } - function getContainingRow (start) { + function getContainingRow(start) { var possibleRow = start; if (treegridElem.contains(possibleRow)) { while (possibleRow !== treegridElem) { @@ -167,17 +171,17 @@ function TreeGrid (treegridElem, doAllowRowFocus, doStartRowFocus) { } } - function isRowFocused () { + function isRowFocused() { return getRowWithFocus() === document.activeElement; } // Note: contenteditable not currently supported - function isEditableFocused () { + function isEditableFocused() { var focusedElem = document.activeElement; return focusedElem.localName === 'input'; } - function getColWithFocus (currentRow) { + function getColWithFocus(currentRow) { if (currentRow) { var possibleCol = document.activeElement; if (currentRow.contains(possibleCol)) { @@ -191,17 +195,17 @@ function TreeGrid (treegridElem, doAllowRowFocus, doStartRowFocus) { } } - function getLevel (row) { + function getLevel(row) { return row && parseInt(row.getAttribute('aria-level')); } // Move backwards (direction = -1) or forwards (direction = 1) // If we also need to move down/up a level, requireLevelChange = true // When - function moveByRow (direction, requireLevelChange) { + function moveByRow(direction, requireLevelChange) { var currentRow = getRowWithFocus(); - var requiredLevel = requireLevelChange && currentRow && - getLevel(currentRow) + direction; + var requiredLevel = + requireLevelChange && currentRow && getLevel(currentRow) + direction; var rows = getAllNavigableRows(); var numRows = rows.length; var rowIndex = currentRow ? rows.indexOf(currentRow) : -1; @@ -215,15 +219,14 @@ function TreeGrid (treegridElem, doAllowRowFocus, doStartRowFocus) { return; // Failed to find required level, return without focus change } rowIndex = restrictIndex(rowIndex + direction, numRows); - } - while (requiredLevel && requiredLevel !== getLevel(rows[rowIndex])); + } while (requiredLevel && requiredLevel !== getLevel(rows[rowIndex])); if (!focusSameColInDifferentRow(currentRow, rows[rowIndex])) { focus(rows[rowIndex]); } } - function focusSameColInDifferentRow (fromRow, toRow) { + function focusSameColInDifferentRow(fromRow, toRow) { var currentCol = getColWithFocus(fromRow); if (!currentCol) { return; @@ -242,7 +245,7 @@ function TreeGrid (treegridElem, doAllowRowFocus, doStartRowFocus) { return true; } - function moveToExtreme (direction) { + function moveToExtreme(direction) { var currentRow = getRowWithFocus(); if (!currentRow) { return; @@ -250,14 +253,13 @@ function TreeGrid (treegridElem, doAllowRowFocus, doStartRowFocus) { var currentCol = getColWithFocus(currentRow); if (currentCol) { moveToExtremeCol(direction, currentRow); - } - else { + } else { // Move to first/last row moveToExtremeRow(direction); } } - function moveByCol (direction) { + function moveByCol(direction) { var currentRow = getRowWithFocus(); if (!currentRow) { return; @@ -267,8 +269,8 @@ function TreeGrid (treegridElem, doAllowRowFocus, doStartRowFocus) { var currentCol = getColWithFocus(currentRow); var currentColIndex = cols.indexOf(currentCol); // First right arrow moves to first column - var newColIndex = (currentCol || direction < 0) ? currentColIndex + - direction : 0; + var newColIndex = + currentCol || direction < 0 ? currentColIndex + direction : 0; // Moving past beginning focuses row if (doAllowRowFocus && newColIndex < 0) { focus(currentRow); @@ -278,14 +280,14 @@ function TreeGrid (treegridElem, doAllowRowFocus, doStartRowFocus) { focusCell(cols[newColIndex]); } - function moveToExtremeCol (direction, currentRow) { + function moveToExtremeCol(direction, currentRow) { // Move to first/last col var cols = getNavigableCols(currentRow); var desiredColIndex = direction < 0 ? 0 : cols.length - 1; focusCell(cols[desiredColIndex]); } - function moveToExtremeRow (direction) { + function moveToExtremeRow(direction) { var rows = getAllNavigableRows(); var newRow = rows[direction > 0 ? rows.length - 1 : 0]; if (!focusSameColInDifferentRow(getRowWithFocus(), newRow)) { @@ -293,7 +295,7 @@ function TreeGrid (treegridElem, doAllowRowFocus, doStartRowFocus) { } } - function doPrimaryAction () { + function doPrimaryAction() { var currentRow = getRowWithFocus(); if (!currentRow) { return; @@ -301,8 +303,12 @@ function TreeGrid (treegridElem, doAllowRowFocus, doStartRowFocus) { // If row has focus, open message if (currentRow === document.activeElement) { - alert('Message from ' + currentRow.children[2].innerText + ':\n\n' + - currentRow.children[1].innerText); + alert( + 'Message from ' + + currentRow.children[2].innerText + + ':\n\n' + + currentRow.children[1].innerText + ); return; } @@ -310,7 +316,7 @@ function TreeGrid (treegridElem, doAllowRowFocus, doStartRowFocus) { toggleExpanded(currentRow); } - function toggleExpanded (row) { + function toggleExpanded(row) { var cols = getNavigableCols(row); var currentCol = getColWithFocus(row); if (currentCol === cols[0] && isExpandable(row)) { @@ -318,7 +324,7 @@ function TreeGrid (treegridElem, doAllowRowFocus, doStartRowFocus) { } } - function changeExpanded (doExpand, row) { + function changeExpanded(doExpand, row) { var currentRow = row || getRowWithFocus(); if (!currentRow) { return; @@ -339,16 +345,14 @@ function TreeGrid (treegridElem, doAllowRowFocus, doStartRowFocus) { // Only expand the next level if this level is expanded // and previous level is expanded doExpandLevel[rowLevel + 1] = - doExpandLevel[rowLevel] && - isExpanded(nextRow); + doExpandLevel[rowLevel] && isExpanded(nextRow); var willHideRow = !doExpandLevel[rowLevel]; var isRowHidden = nextRow.classList.contains('hidden'); if (willHideRow !== isRowHidden) { if (willHideRow) { nextRow.classList.add('hidden'); - } - else { + } else { nextRow.classList.remove('hidden'); } didChange = true; @@ -363,7 +367,7 @@ function TreeGrid (treegridElem, doAllowRowFocus, doStartRowFocus) { // Mirror aria-expanded from the row to the first cell in that row // (TBD is this a good idea? How else will screen reader user hear // that the cell represents the opportunity to collapse/expand rows?) - function moveAriaExpandedToFirstCell (row) { + function moveAriaExpandedToFirstCell(row) { var expandedValue = row.getAttribute('aria-expanded'); var firstCell = getNavigableCols(row)[0]; if (expandedValue) { @@ -372,26 +376,26 @@ function TreeGrid (treegridElem, doAllowRowFocus, doStartRowFocus) { } } - function getAriaExpandedElem (row) { + function getAriaExpandedElem(row) { return doAllowRowFocus ? row : getNavigableCols(row)[0]; } - function setAriaExpanded (row, doExpand) { + function setAriaExpanded(row, doExpand) { var elem = getAriaExpandedElem(row); elem.setAttribute('aria-expanded', doExpand); } - function isExpandable (row) { + function isExpandable(row) { var elem = getAriaExpandedElem(row); return elem.hasAttribute('aria-expanded'); } - function isExpanded (row) { + function isExpanded(row) { var elem = getAriaExpandedElem(row); return elem.getAttribute('aria-expanded') === 'true'; } - function onKeyDown (event) { + function onKeyDown(event) { var ENTER = 13; var UP = 38; var DOWN = 40; @@ -402,15 +406,14 @@ function TreeGrid (treegridElem, doAllowRowFocus, doStartRowFocus) { var CTRL_HOME = -HOME; var CTRL_END = -END; - var numModifiersPressed = event.ctrlKey + event.altKey + event.shiftKey + - event.metaKey; + var numModifiersPressed = + event.ctrlKey + event.altKey + event.shiftKey + event.metaKey; var key = event.keyCode; if (numModifiersPressed === 1 && event.ctrlKey) { key = -key; // Treat as negative key value when ctrl pressed - } - else if (numModifiersPressed) { + } else if (numModifiersPressed) { return; } @@ -423,18 +426,17 @@ function TreeGrid (treegridElem, doAllowRowFocus, doStartRowFocus) { break; case LEFT: if (isEditableFocused()) { - return; // Leave key for editable area + return; // Leave key for editable area } if (isRowFocused()) { changeExpanded(false) || moveByRow(-1, true); - } - else { + } else { moveByCol(-1); } break; case RIGHT: if (isEditableFocused()) { - return; // Leave key for editable area + return; // Leave key for editable area } // If row: try to expand @@ -448,7 +450,7 @@ function TreeGrid (treegridElem, doAllowRowFocus, doStartRowFocus) { break; case HOME: if (isEditableFocused()) { - return; // Leave key for editable area + return; // Leave key for editable area } moveToExtreme(-1); break; @@ -457,7 +459,7 @@ function TreeGrid (treegridElem, doAllowRowFocus, doStartRowFocus) { break; case END: if (isEditableFocused()) { - return; // Leave key for editable area + return; // Leave key for editable area } moveToExtreme(1); break; @@ -475,7 +477,7 @@ function TreeGrid (treegridElem, doAllowRowFocus, doStartRowFocus) { // Toggle row expansion if the click is over the expando triangle // Since the triangle is a pseudo element we can't bind an event listener // to it. Another option is to have an actual element with role="presentation" - function onClick (event) { + function onClick(event) { var target = event.target; if (target.localName !== 'td') { return; @@ -498,7 +500,7 @@ function TreeGrid (treegridElem, doAllowRowFocus, doStartRowFocus) { } // Double click on row toggles expansion - function onDoubleClick (event) { + function onDoubleClick(event) { var row = getContainingRow(event.target); if (row) { if (isExpandable(row)) { @@ -513,7 +515,9 @@ function TreeGrid (treegridElem, doAllowRowFocus, doStartRowFocus) { treegridElem.addEventListener('click', onClick); treegridElem.addEventListener('dblclick', onDoubleClick); // Polyfill for focusin necessary for Firefox < 52 - window.addEventListener(window.onfocusin ? 'focusin' : 'focus', - onFocusIn, true); + window.addEventListener( + window.onfocusin ? 'focusin' : 'focus', + onFocusIn, + true + ); } - diff --git a/examples/treeview/treeview-1/js/tree.js b/examples/treeview/treeview-1/js/tree.js index 426d82a4fb..e55e824188 100644 --- a/examples/treeview/treeview-1/js/tree.js +++ b/examples/treeview/treeview-1/js/tree.js @@ -1,12 +1,12 @@ /* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -* -* File: Tree.js -* -* Desc: Tree widget that implements ARIA Authoring Practices -* for a tree being used as a file viewer -*/ + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * File: Tree.js + * + * Desc: Tree widget that implements ARIA Authoring Practices + * for a tree being used as a file viewer + */ 'use strict'; @@ -17,26 +17,24 @@ */ window.addEventListener('load', function () { - var trees = document.querySelectorAll('[role="tree"]'); for (var i = 0; i < trees.length; i++) { var t = new Tree(trees[i]); t.init(); } - }); /* -* @constructor -* -* @desc -* Tree item object for representing the state and user interactions for a -* tree widget -* -* @param node -* An element with the role=tree attribute -*/ + * @constructor + * + * @desc + * Tree item object for representing the state and user interactions for a + * tree widget + * + * @param node + * An element with the role=tree attribute + */ var Tree = function (node) { // Check whether node is a DOM element @@ -51,18 +49,14 @@ var Tree = function (node) { this.firstTreeitem = null; this.lastTreeitem = null; - }; Tree.prototype.init = function () { - - function findTreeitems (node, tree, group) { - + function findTreeitems(node, tree, group) { var elem = node.firstElementChild; var ti = group; while (elem) { - if (elem.tagName.toLowerCase() === 'li') { ti = new Treeitem(elem, tree, group); ti.init(); @@ -88,30 +82,25 @@ Tree.prototype.init = function () { this.updateVisibleTreeitems(); this.firstTreeitem.domNode.tabIndex = 0; - }; Tree.prototype.setFocusToItem = function (treeitem) { - for (var i = 0; i < this.treeitems.length; i++) { var ti = this.treeitems[i]; if (ti === treeitem) { ti.domNode.tabIndex = 0; ti.domNode.focus(); - } - else { + } else { ti.domNode.tabIndex = -1; } } - }; Tree.prototype.setFocusToNextItem = function (currentItem) { - var nextItem = false; - for (var i = (this.treeitems.length - 1); i >= 0; i--) { + for (var i = this.treeitems.length - 1; i >= 0; i--) { var ti = this.treeitems[i]; if (ti === currentItem) { break; @@ -124,11 +113,9 @@ Tree.prototype.setFocusToNextItem = function (currentItem) { if (nextItem) { this.setFocusToItem(nextItem); } - }; Tree.prototype.setFocusToPreviousItem = function (currentItem) { - var prevItem = false; for (var i = 0; i < this.treeitems.length; i++) { @@ -147,7 +134,6 @@ Tree.prototype.setFocusToPreviousItem = function (currentItem) { }; Tree.prototype.setFocusToParentItem = function (currentItem) { - if (currentItem.groupTreeitem) { this.setFocusToItem(currentItem.groupTreeitem); } @@ -162,33 +148,28 @@ Tree.prototype.setFocusToLastItem = function () { }; Tree.prototype.expandTreeitem = function (currentItem) { - if (currentItem.isExpandable) { currentItem.domNode.setAttribute('aria-expanded', true); this.updateVisibleTreeitems(); } - }; Tree.prototype.expandAllSiblingItems = function (currentItem) { for (var i = 0; i < this.treeitems.length; i++) { var ti = this.treeitems[i]; - if ((ti.groupTreeitem === currentItem.groupTreeitem) && ti.isExpandable) { + if (ti.groupTreeitem === currentItem.groupTreeitem && ti.isExpandable) { this.expandTreeitem(ti); } } - }; Tree.prototype.collapseTreeitem = function (currentItem) { - var groupTreeitem = false; if (currentItem.isExpanded()) { groupTreeitem = currentItem; - } - else { + } else { groupTreeitem = currentItem.groupTreeitem; } @@ -197,11 +178,9 @@ Tree.prototype.collapseTreeitem = function (currentItem) { this.updateVisibleTreeitems(); this.setFocusToItem(groupTreeitem); } - }; Tree.prototype.updateVisibleTreeitems = function () { - this.firstTreeitem = this.treeitems[0]; for (var i = 0; i < this.treeitems.length; i++) { @@ -211,8 +190,7 @@ Tree.prototype.updateVisibleTreeitems = function () { ti.isVisible = true; - while (parent && (parent !== this.domNode)) { - + while (parent && parent !== this.domNode) { if (parent.getAttribute('aria-expanded') == 'false') { ti.isVisible = false; } @@ -223,7 +201,6 @@ Tree.prototype.updateVisibleTreeitems = function () { this.lastTreeitem = ti; } } - }; Tree.prototype.setFocusByFirstCharacter = function (currentItem, char) { diff --git a/examples/treeview/treeview-1/js/treeitem.js b/examples/treeview/treeview-1/js/treeitem.js index bf2e1a152b..84d31d3b74 100644 --- a/examples/treeview/treeview-1/js/treeitem.js +++ b/examples/treeview/treeview-1/js/treeitem.js @@ -1,28 +1,27 @@ /* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -* -* File: Treeitem.js -* -* Desc: Treeitem widget that implements ARIA Authoring Practices -* for a tree being used as a file viewer -*/ + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * File: Treeitem.js + * + * Desc: Treeitem widget that implements ARIA Authoring Practices + * for a tree being used as a file viewer + */ 'use strict'; /* -* @constructor -* -* @desc -* Treeitem object for representing the state and user interactions for a -* treeItem widget -* -* @param node -* An element with the role=tree attribute -*/ + * @constructor + * + * @desc + * Treeitem object for representing the state and user interactions for a + * treeItem widget + * + * @param node + * An element with the role=tree attribute + */ var Treeitem = function (node, treeObj, group) { - // Check whether node is a DOM element if (typeof node !== 'object') { return; @@ -49,7 +48,6 @@ var Treeitem = function (node, treeObj, group) { var elem = node.firstElementChild; while (elem) { - if (elem.tagName.toLowerCase() == 'ul') { elem.setAttribute('role', 'group'); this.isExpandable = true; @@ -69,7 +67,7 @@ var Treeitem = function (node, treeObj, group) { LEFT: 37, UP: 38, RIGHT: 39, - DOWN: 40 + DOWN: 40, }); }; @@ -92,34 +90,30 @@ Treeitem.prototype.init = function () { }; Treeitem.prototype.isExpanded = function () { - if (this.isExpandable) { return this.domNode.getAttribute('aria-expanded') === 'true'; } return false; - }; /* EVENT HANDLERS */ Treeitem.prototype.handleKeydown = function (event) { - var tgt = event.currentTarget, flag = false, char = event.key, clickEvent; - function isPrintableCharacter (str) { + function isPrintableCharacter(str) { return str.length === 1 && str.match(/\S/); } - function printableCharacter (item) { + function printableCharacter(item) { if (char == '*') { item.tree.expandAllSiblingItems(item); flag = true; - } - else { + } else { if (isPrintableCharacter(char)) { item.tree.setFocusByFirstCharacter(item, char); flag = true; @@ -135,8 +129,7 @@ Treeitem.prototype.handleKeydown = function (event) { if (isPrintableCharacter(char)) { printableCharacter(this); } - } - else { + } else { switch (event.keyCode) { case this.keyCode.SPACE: case this.keyCode.RETURN: @@ -144,12 +137,11 @@ Treeitem.prototype.handleKeydown = function (event) { // and let the event handler handleClick do the housekeeping. try { clickEvent = new MouseEvent('click', { - 'view': window, - 'bubbles': true, - 'cancelable': true + view: window, + bubbles: true, + cancelable: true, }); - } - catch (err) { + } catch (err) { if (document.createEvent) { // DOM Level 3 for IE 9+ clickEvent = document.createEvent('MouseEvents'); @@ -174,8 +166,7 @@ Treeitem.prototype.handleKeydown = function (event) { if (this.isExpandable) { if (this.isExpanded()) { this.tree.setFocusToNextItem(this); - } - else { + } else { this.tree.expandTreeitem(this); } } @@ -186,8 +177,7 @@ Treeitem.prototype.handleKeydown = function (event) { if (this.isExpandable && this.isExpanded()) { this.tree.collapseTreeitem(this); flag = true; - } - else { + } else { if (this.inGroup) { this.tree.setFocusToParentItem(this); flag = true; @@ -211,7 +201,6 @@ Treeitem.prototype.handleKeydown = function (event) { } break; } - } if (flag) { @@ -224,13 +213,11 @@ Treeitem.prototype.handleClick = function (event) { if (this.isExpandable) { if (this.isExpanded()) { this.tree.collapseTreeitem(this); - } - else { + } else { this.tree.expandTreeitem(this); } event.stopPropagation(); - } - else { + } else { this.tree.setFocusToItem(this); } }; diff --git a/examples/treeview/treeview-1/js/treeitemClick.js b/examples/treeview/treeview-1/js/treeitemClick.js index b967753c63..f2a0d922f8 100644 --- a/examples/treeview/treeview-1/js/treeitemClick.js +++ b/examples/treeview/treeview-1/js/treeitemClick.js @@ -1,11 +1,11 @@ /* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -* -* File: Treeitem.js -* -* Desc: Setup click events for Tree widget examples -*/ + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * File: Treeitem.js + * + * Desc: Setup click events for Tree widget examples + */ 'use strict'; @@ -16,11 +16,9 @@ */ window.addEventListener('load', function () { - var treeitems = document.querySelectorAll('[role="treeitem"]'); for (var i = 0; i < treeitems.length; i++) { - treeitems[i].addEventListener('click', function (event) { var treeitem = event.currentTarget; var label = treeitem.getAttribute('aria-label'); @@ -34,7 +32,5 @@ window.addEventListener('load', function () { event.stopPropagation(); event.preventDefault(); }); - } - }); diff --git a/examples/treeview/treeview-2/js/treeLinks.js b/examples/treeview/treeview-2/js/treeLinks.js index 49c15d9262..04aac8e40d 100644 --- a/examples/treeview/treeview-2/js/treeLinks.js +++ b/examples/treeview/treeview-2/js/treeLinks.js @@ -1,12 +1,12 @@ /* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -* -* File: TreeLinks.js -* -* Desc: Tree widget that implements ARIA Authoring Practices -* for a tree being used as a file viewer -*/ + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * File: TreeLinks.js + * + * Desc: Tree widget that implements ARIA Authoring Practices + * for a tree being used as a file viewer + */ 'use strict'; @@ -17,26 +17,24 @@ */ window.addEventListener('load', function () { - var trees = document.querySelectorAll('[role="tree"]'); for (var i = 0; i < trees.length; i++) { var t = new TreeLinks(trees[i]); t.init(); } - }); /* -* @constructor -* -* @desc -* Tree item object for representing the state and user interactions for a -* tree widget -* -* @param node -* An element with the role=tree attribute -*/ + * @constructor + * + * @desc + * Tree item object for representing the state and user interactions for a + * tree widget + * + * @param node + * An element with the role=tree attribute + */ var TreeLinks = function (node) { // Check whether node is a DOM element @@ -51,19 +49,19 @@ var TreeLinks = function (node) { this.firstTreeitem = null; this.lastTreeitem = null; - }; TreeLinks.prototype.init = function () { - - function findTreeitems (node, tree, group) { - + function findTreeitems(node, tree, group) { var elem = node.firstElementChild; var ti = group; while (elem) { - - if ((elem.tagName.toLowerCase() === 'li' && elem.firstElementChild.tagName.toLowerCase() === 'span') || elem.tagName.toLowerCase() === 'a') { + if ( + (elem.tagName.toLowerCase() === 'li' && + elem.firstElementChild.tagName.toLowerCase() === 'span') || + elem.tagName.toLowerCase() === 'a' + ) { ti = new TreeitemLink(elem, tree, group); ti.init(); tree.treeitems.push(ti); @@ -88,30 +86,25 @@ TreeLinks.prototype.init = function () { this.updateVisibleTreeitems(); this.firstTreeitem.domNode.tabIndex = 0; - }; TreeLinks.prototype.setFocusToItem = function (treeitem) { - for (var i = 0; i < this.treeitems.length; i++) { var ti = this.treeitems[i]; if (ti === treeitem) { ti.domNode.tabIndex = 0; ti.domNode.focus(); - } - else { + } else { ti.domNode.tabIndex = -1; } } - }; TreeLinks.prototype.setFocusToNextItem = function (currentItem) { - var nextItem = false; - for (var i = (this.treeitems.length - 1); i >= 0; i--) { + for (var i = this.treeitems.length - 1; i >= 0; i--) { var ti = this.treeitems[i]; if (ti === currentItem) { break; @@ -124,11 +117,9 @@ TreeLinks.prototype.setFocusToNextItem = function (currentItem) { if (nextItem) { this.setFocusToItem(nextItem); } - }; TreeLinks.prototype.setFocusToPreviousItem = function (currentItem) { - var prevItem = false; for (var i = 0; i < this.treeitems.length; i++) { @@ -147,7 +138,6 @@ TreeLinks.prototype.setFocusToPreviousItem = function (currentItem) { }; TreeLinks.prototype.setFocusToParentItem = function (currentItem) { - if (currentItem.groupTreeitem) { this.setFocusToItem(currentItem.groupTreeitem); } @@ -162,33 +152,28 @@ TreeLinks.prototype.setFocusToLastItem = function () { }; TreeLinks.prototype.expandTreeitem = function (currentItem) { - if (currentItem.isExpandable) { currentItem.domNode.setAttribute('aria-expanded', true); this.updateVisibleTreeitems(); } - }; TreeLinks.prototype.expandAllSiblingItems = function (currentItem) { for (var i = 0; i < this.treeitems.length; i++) { var ti = this.treeitems[i]; - if ((ti.groupTreeitem === currentItem.groupTreeitem) && ti.isExpandable) { + if (ti.groupTreeitem === currentItem.groupTreeitem && ti.isExpandable) { this.expandTreeitem(ti); } } - }; TreeLinks.prototype.collapseTreeitem = function (currentItem) { - var groupTreeitem = false; if (currentItem.isExpanded()) { groupTreeitem = currentItem; - } - else { + } else { groupTreeitem = currentItem.groupTreeitem; } @@ -197,11 +182,9 @@ TreeLinks.prototype.collapseTreeitem = function (currentItem) { this.updateVisibleTreeitems(); this.setFocusToItem(groupTreeitem); } - }; TreeLinks.prototype.updateVisibleTreeitems = function () { - this.firstTreeitem = this.treeitems[0]; for (var i = 0; i < this.treeitems.length; i++) { @@ -211,8 +194,7 @@ TreeLinks.prototype.updateVisibleTreeitems = function () { ti.isVisible = true; - while (parent && (parent !== this.domNode)) { - + while (parent && parent !== this.domNode) { if (parent.getAttribute('aria-expanded') == 'false') { ti.isVisible = false; } @@ -223,7 +205,6 @@ TreeLinks.prototype.updateVisibleTreeitems = function () { this.lastTreeitem = ti; } } - }; TreeLinks.prototype.setFocusByFirstCharacter = function (currentItem, char) { diff --git a/examples/treeview/treeview-2/js/treeitemLinks.js b/examples/treeview/treeview-2/js/treeitemLinks.js index 4a8ea7bc77..674f0adcd1 100644 --- a/examples/treeview/treeview-2/js/treeitemLinks.js +++ b/examples/treeview/treeview-2/js/treeitemLinks.js @@ -1,28 +1,27 @@ /* -* This content is licensed according to the W3C Software License at -* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document -* -* File: TreeitemLink.js -* -* Desc: Treeitem widget that implements ARIA Authoring Practices -* for a tree being used as a file viewer -*/ + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * File: TreeitemLink.js + * + * Desc: Treeitem widget that implements ARIA Authoring Practices + * for a tree being used as a file viewer + */ 'use strict'; /* -* @constructor -* -* @desc -* Treeitem object for representing the state and user interactions for a -* treeItem widget -* -* @param node -* An element with the role=tree attribute -*/ + * @constructor + * + * @desc + * Treeitem object for representing the state and user interactions for a + * treeItem widget + * + * @param node + * An element with the role=tree attribute + */ var TreeitemLink = function (node, treeObj, group) { - // Check whether node is a DOM element if (typeof node !== 'object') { return; @@ -50,7 +49,6 @@ var TreeitemLink = function (node, treeObj, group) { var elem = node.firstElementChild; while (elem) { - if (elem.tagName.toLowerCase() == 'ul') { elem.setAttribute('role', 'group'); this.isExpandable = true; @@ -70,7 +68,7 @@ var TreeitemLink = function (node, treeObj, group) { LEFT: 37, UP: 38, RIGHT: 39, - DOWN: 40 + DOWN: 40, }); }; @@ -87,23 +85,26 @@ TreeitemLink.prototype.init = function () { this.domNode.addEventListener('blur', this.handleBlur.bind(this)); if (this.isExpandable) { - this.domNode.firstElementChild.addEventListener('mouseover', this.handleMouseOver.bind(this)); - this.domNode.firstElementChild.addEventListener('mouseout', this.handleMouseOut.bind(this)); - } - else { + this.domNode.firstElementChild.addEventListener( + 'mouseover', + this.handleMouseOver.bind(this) + ); + this.domNode.firstElementChild.addEventListener( + 'mouseout', + this.handleMouseOut.bind(this) + ); + } else { this.domNode.addEventListener('mouseover', this.handleMouseOver.bind(this)); this.domNode.addEventListener('mouseout', this.handleMouseOut.bind(this)); } }; TreeitemLink.prototype.isExpanded = function () { - if (this.isExpandable) { return this.domNode.getAttribute('aria-expanded') === 'true'; } return false; - }; /* EVENT HANDLERS */ @@ -114,16 +115,15 @@ TreeitemLink.prototype.handleKeydown = function (event) { char = event.key, clickEvent; - function isPrintableCharacter (str) { + function isPrintableCharacter(str) { return str.length === 1 && str.match(/\S/); } - function printableCharacter (item) { + function printableCharacter(item) { if (char == '*') { item.tree.expandAllSiblingItems(item); flag = true; - } - else { + } else { if (isPrintableCharacter(char)) { item.tree.setFocusByFirstCharacter(item, char); flag = true; @@ -138,30 +138,29 @@ TreeitemLink.prototype.handleKeydown = function (event) { } if (event.shift) { - if (event.keyCode == this.keyCode.SPACE || event.keyCode == this.keyCode.RETURN) { + if ( + event.keyCode == this.keyCode.SPACE || + event.keyCode == this.keyCode.RETURN + ) { event.stopPropagation(); this.stopDefaultClick = true; - } - else { + } else { if (isPrintableCharacter(char)) { printableCharacter(this); } } - } - else { + } else { switch (event.keyCode) { case this.keyCode.SPACE: case this.keyCode.RETURN: if (this.isExpandable) { if (this.isExpanded()) { this.tree.collapseTreeitem(this); - } - else { + } else { this.tree.expandTreeitem(this); } flag = true; - } - else { + } else { event.stopPropagation(); this.stopDefaultClick = true; } @@ -181,8 +180,7 @@ TreeitemLink.prototype.handleKeydown = function (event) { if (this.isExpandable) { if (this.isExpanded()) { this.tree.setFocusToNextItem(this); - } - else { + } else { this.tree.expandTreeitem(this); } } @@ -193,8 +191,7 @@ TreeitemLink.prototype.handleKeydown = function (event) { if (this.isExpandable && this.isExpanded()) { this.tree.collapseTreeitem(this); flag = true; - } - else { + } else { if (this.inGroup) { this.tree.setFocusToParentItem(this); flag = true; @@ -227,17 +224,18 @@ TreeitemLink.prototype.handleKeydown = function (event) { }; TreeitemLink.prototype.handleClick = function (event) { - // only process click events that directly happened on this treeitem - if (event.target !== this.domNode && event.target !== this.domNode.firstElementChild) { + if ( + event.target !== this.domNode && + event.target !== this.domNode.firstElementChild + ) { return; } if (this.isExpandable) { if (this.isExpanded()) { this.tree.collapseTreeitem(this); - } - else { + } else { this.tree.expandTreeitem(this); } event.stopPropagation(); diff --git a/respec-config.js b/respec-config.js index 8298dff3fc..72255ba293 100644 --- a/respec-config.js +++ b/respec-config.js @@ -24,62 +24,72 @@ var respecConfig = { // previousDiffURI: "", // Github repo - github: "w3c/aria-practices", + github: 'w3c/aria-practices', // If this is a LCWD, uncomment and set the end of its review period // lcEnd: "2012-02-21", // Editors, add as many as you like. // “name” is the only required field. - editors: [{ - name: 'Matt King', - mailto: 'mck@fb.com', - company: 'Facebook', - companyURI: 'https://www.facebook.com/', - w3cid: 44582 - }, { - name: 'JaEun Jemma Ku', - mailto: 'jku@illinois.edu', - company: 'University of Illinois', - companyURI: 'https://illinois.edu/', - w3cid: 74097 - }, { - name: 'James Nurthen', - mailto: 'nurthen@adobe.com', - company: 'Adobe', - companyURI: 'https://www.adobe.com/', - w3cid: 37155 - }, { - name: 'Zoë Bijl', - company: 'Invited Expert', - w3cid: 74040 - }, { - name: 'Michael Cooper', - url: 'https://www.w3.org/People/cooper/', - mailto: 'cooper@w3.org', - company: 'W3C', - companyURI: 'https://www.w3.org/', - w3cid: 34017 - }], - formerEditors: [{ - name: 'Joseph Scheuhammer', - company: 'Inclusive Design Research Centre, OCAD University', - companyURI: 'https://idrc.ocad.ca/', - w3cid: 42279, - retiredDate: '2014-10-01' - }, { - name: 'Lisa Pappas', - company: 'SAS', - companyURI: 'https://www.sas.com/', - w3cid: 41725, - retiredDate: '2009-10-01' - }, { - name: 'Rich Schwerdtfeger', - company: 'IBM Corporation', - companyURI: 'https://ibm.com/', - w3cid: 2460, - retiredDate: '2014-10-01' - }], + editors: [ + { + name: 'Matt King', + mailto: 'mck@fb.com', + company: 'Facebook', + companyURI: 'https://www.facebook.com/', + w3cid: 44582, + }, + { + name: 'JaEun Jemma Ku', + mailto: 'jku@illinois.edu', + company: 'University of Illinois', + companyURI: 'https://illinois.edu/', + w3cid: 74097, + }, + { + name: 'James Nurthen', + mailto: 'nurthen@adobe.com', + company: 'Adobe', + companyURI: 'https://www.adobe.com/', + w3cid: 37155, + }, + { + name: 'Zoë Bijl', + company: 'Invited Expert', + w3cid: 74040, + }, + { + name: 'Michael Cooper', + url: 'https://www.w3.org/People/cooper/', + mailto: 'cooper@w3.org', + company: 'W3C', + companyURI: 'https://www.w3.org/', + w3cid: 34017, + }, + ], + formerEditors: [ + { + name: 'Joseph Scheuhammer', + company: 'Inclusive Design Research Centre, OCAD University', + companyURI: 'https://idrc.ocad.ca/', + w3cid: 42279, + retiredDate: '2014-10-01', + }, + { + name: 'Lisa Pappas', + company: 'SAS', + companyURI: 'https://www.sas.com/', + w3cid: 41725, + retiredDate: '2009-10-01', + }, + { + name: 'Rich Schwerdtfeger', + company: 'IBM Corporation', + companyURI: 'https://ibm.com/', + w3cid: 2460, + retiredDate: '2014-10-01', + }, + ], // Authors, add as many as you like. // This is optional, uncomment if you have authors as well as editors. @@ -96,28 +106,28 @@ var respecConfig = { // Spec URLs ariaSpecURLs: { - 'ED': 'https://w3c.github.io/aria/', - 'FPWD': 'https://www.w3.org/TR/wai-aria-1.2/', - 'WD': 'https://www.w3.org/TR/wai-aria-1.2/', - 'REC': 'https://www.w3.org/TR/wai-aria/' + ED: 'https://w3c.github.io/aria/', + FPWD: 'https://www.w3.org/TR/wai-aria-1.2/', + WD: 'https://www.w3.org/TR/wai-aria-1.2/', + REC: 'https://www.w3.org/TR/wai-aria/', }, accNameURLs: { - 'ED': 'https://w3c.github.io/accname/', - 'WD': 'https://www.w3.org/TR/accname-1.2/', - 'FPWD': 'https://www.w3.org/TR/accname-1.2/', - 'REC': 'https://www.w3.org/TR/accname/' + ED: 'https://w3c.github.io/accname/', + WD: 'https://www.w3.org/TR/accname-1.2/', + FPWD: 'https://www.w3.org/TR/accname-1.2/', + REC: 'https://www.w3.org/TR/accname/', }, coreMappingURLs: { - 'ED': 'https://w3c.github.io/core-aam/', - 'WD': 'https://www.w3.org/TR/core-aam-1.2/', - 'FPWD': 'https://www.w3.org/TR/core-aam-1.2/', - 'REC': 'https://www.w3.org/TR/core-aam/' + ED: 'https://w3c.github.io/core-aam/', + WD: 'https://www.w3.org/TR/core-aam-1.2/', + FPWD: 'https://www.w3.org/TR/core-aam-1.2/', + REC: 'https://www.w3.org/TR/core-aam/', }, htmlMappingURLs: { - 'ED': 'https://w3c.github.io/html-aam/', - 'WD': 'https://www.w3.org/TR/html-aam-1.0/', - 'FPWD': 'https://www.w3.org/TR/html-aam-1.0/', - 'REC': 'https://www.w3.org/TR/html-aam-1.0/' + ED: 'https://w3c.github.io/html-aam/', + WD: 'https://www.w3.org/TR/html-aam-1.0/', + FPWD: 'https://www.w3.org/TR/html-aam-1.0/', + REC: 'https://www.w3.org/TR/html-aam-1.0/', }, // alternateFormats: [ @@ -154,5 +164,5 @@ var respecConfig = { // If in doubt ask your friendly neighbourhood Team Contact. wgPatentURI: 'https://www.w3.org/2004/01/pp-impl/83726/status', maxTocLevel: 4, - preProcess: [ linkCrossReferences ] + preProcess: [linkCrossReferences], }; diff --git a/scripts/coverage-report.js b/scripts/coverage-report.js index 15d534a366..af07bc1c9b 100644 --- a/scripts/coverage-report.js +++ b/scripts/coverage-report.js @@ -16,9 +16,18 @@ const cheerio = require('cheerio'); const exampleFilePath = path.join(__dirname, '..', 'coverage', 'index.html'); const exampleTemplatePath = path.join(__dirname, 'coverage-report.template'); -const csvRoleFilePath = path.join(__dirname, '..', 'coverage', 'role-coverage.csv'); -const csvPropFilePath = path.join(__dirname, '..', 'coverage', 'prop-coverage.csv'); - +const csvRoleFilePath = path.join( + __dirname, + '..', + 'coverage', + 'role-coverage.csv' +); +const csvPropFilePath = path.join( + __dirname, + '..', + 'coverage', + 'prop-coverage.csv' +); let output = fs.readFileSync(exampleTemplatePath, function (err) { console.log('Error reading aria index:', err); @@ -26,7 +35,6 @@ let output = fs.readFileSync(exampleTemplatePath, function (err) { const $ = cheerio.load(output); - const ariaRoles = [ 'alert', 'alertdialog', @@ -96,7 +104,7 @@ const ariaRoles = [ 'tooltip', 'tree', 'treegrid', - 'treeitem' + 'treeitem', ]; const ariaPropertiesAndStates = [ @@ -147,20 +155,28 @@ const ariaPropertiesAndStates = [ 'aria-valuemax', 'aria-valuemin', 'aria-valuenow', - 'aria-valuetext' + 'aria-valuetext', ]; let indexOfRolesInExamples = {}; -ariaRoles.forEach(function(role) { indexOfRolesInExamples[role] = []}); +ariaRoles.forEach(function (role) { + indexOfRolesInExamples[role] = []; +}); let indexOfRolesInGuidance = {}; -ariaRoles.forEach(function(role) { indexOfRolesInGuidance[role] = []}); +ariaRoles.forEach(function (role) { + indexOfRolesInGuidance[role] = []; +}); let indexOfPropertiesAndStatesInExamples = {}; -ariaPropertiesAndStates.forEach(function(prop) { indexOfPropertiesAndStatesInExamples[prop] = []}); +ariaPropertiesAndStates.forEach(function (prop) { + indexOfPropertiesAndStatesInExamples[prop] = []; +}); let indexOfPropertiesAndStatesInGuidance = {}; -ariaPropertiesAndStates.forEach(function(prop) { indexOfPropertiesAndStatesInGuidance[prop] = []}); +ariaPropertiesAndStates.forEach(function (prop) { + indexOfPropertiesAndStatesInGuidance[prop] = []; +}); console.log('Generating index...'); @@ -194,9 +210,11 @@ function getRolesFromExample(data) { let code = data.substring(indexStart + 6, indexEnd).trim(); for (let i = 0; i < ariaRoles.length; i++) { - if ((getColumn(data, indexStart) === 1) && - (code == ariaRoles[i]) && - (roles.indexOf(ariaRoles[i]) < 0)) { + if ( + getColumn(data, indexStart) === 1 && + code == ariaRoles[i] && + roles.indexOf(ariaRoles[i]) < 0 + ) { roles.push(ariaRoles[i]); } } @@ -221,9 +239,11 @@ function getPropertiesAndStatesFromExample(data) { let code = data.substring(indexStart + 6, indexEnd); for (let i = 0; i < ariaPropertiesAndStates.length; i++) { - if ((getColumn(data, indexStart) === 2) && - (code.indexOf(ariaPropertiesAndStates[i]) >= 0) && - (propertiesAndStates.indexOf(ariaPropertiesAndStates[i]) < 0)) { + if ( + getColumn(data, indexStart) === 2 && + code.indexOf(ariaPropertiesAndStates[i]) >= 0 && + propertiesAndStates.indexOf(ariaPropertiesAndStates[i]) < 0 + ) { propertiesAndStates.push(ariaPropertiesAndStates[i]); } } @@ -271,7 +291,7 @@ function addExampleToPropertiesAndStates(props, example) { function addLandmarkRole(landmark, hasLabel, title, ref) { let example = { title: title, - ref: ref + ref: ref, }; addExampleToRoles(landmark, example); @@ -281,24 +301,33 @@ function addLandmarkRole(landmark, hasLabel, title, ref) { } // Index roles, properties and states used in examples -glob.sync('examples/!(landmarks)/**/!(index).html', {cwd: path.join(__dirname, '..'), nodir: true}).forEach(function (file) { - let data = fs.readFileSync(file, 'utf8'); - let ref = file.replace('examples/', '../examples/'); - let title = data.substring(data.indexOf('') + 7, data.indexOf('')) - .split('|')[0] - .replace('Examples', '') - .replace('Example of', '') - .replace('Example', '') - .trim(); - - let example = { - title: title, - ref: ref - }; - - addExampleToRoles(getRolesFromExample(data), example); - addExampleToPropertiesAndStates(getPropertiesAndStatesFromExample(data), example); -}); +glob + .sync('examples/!(landmarks)/**/!(index).html', { + cwd: path.join(__dirname, '..'), + nodir: true, + }) + .forEach(function (file) { + let data = fs.readFileSync(file, 'utf8'); + let ref = file.replace('examples/', '../examples/'); + let title = data + .substring(data.indexOf('') + 7, data.indexOf('')) + .split('|')[0] + .replace('Examples', '') + .replace('Example of', '') + .replace('Example', '') + .trim(); + + let example = { + title: title, + ref: ref, + }; + + addExampleToRoles(getRolesFromExample(data), example); + addExampleToPropertiesAndStates( + getPropertiesAndStatesFromExample(data), + example + ); + }); // Index roles, properties and states used in guidance @@ -315,7 +344,6 @@ function getClosestId(data, index) { } function addGuidanceToRole(role, url, label, id) { - let r = {}; r.title = label; r.ref = url + '#' + id; @@ -338,11 +366,10 @@ function addGuidanceToPropertyOrState(prop, url, label, id) { } function getHeaderContent(data, index) { - let content = ''; let indexStart = data.indexOf('>', index); - let indexEnd = data.indexOf(' 1 && indexEnd > 1) { content = data.substring(indexStart + 1, indexEnd).trim(); @@ -354,40 +381,41 @@ function getHeaderContent(data, index) { return content; } - function getRolesPropertiesAndStatesFromHeaders(data, url) { - function getRolesPropertiesAndStatesFromHeader(level) { - let indexStart = data.indexOf('', 0); - let indexEnd = data.indexOf('', indexStart); + let indexEnd = data.indexOf('', indexStart); while (indexStart > 1 && indexEnd > 1) { let content = getHeaderContent(data, indexStart); let contentItems = content.toLowerCase().split(' '); - ariaRoles.forEach(function(role) { + ariaRoles.forEach(function (role) { if (contentItems.indexOf(role) >= 0) { console.log('h' + level + ': ' + role + ', ' + content); addGuidanceToRole(role, url, content, getClosestId(data, indexStart)); } }); - ariaPropertiesAndStates.forEach(function(prop) { + ariaPropertiesAndStates.forEach(function (prop) { if (contentItems.indexOf(prop) >= 0) { console.log('h' + level + ': ' + prop + ', ' + content); - addGuidanceToPropertyOrState(prop, url, content , getClosestId(data, indexStart)); + addGuidanceToPropertyOrState( + prop, + url, + content, + getClosestId(data, indexStart) + ); } }); indexStart = data.indexOf('', indexEnd); if (indexStart > 0) { - indexEnd = data.indexOf('', indexStart); + indexEnd = data.indexOf('', indexStart); } } - } getRolesPropertiesAndStatesFromHeader(2); @@ -395,27 +423,31 @@ function getRolesPropertiesAndStatesFromHeaders(data, url) { getRolesPropertiesAndStatesFromHeader(4); getRolesPropertiesAndStatesFromHeader(5); getRolesPropertiesAndStatesFromHeader(6); - } - function getRolesFromDataAttributesOnHeaders(data, url) { - let indexStart = data.indexOf('data-aria-roles="', 0); let indexEnd = data.indexOf('"', indexStart + 17); while (indexStart > 1 && indexEnd > 1) { - let content = getHeaderContent(data, indexStart); - let roles = data.substring(indexStart + 17, indexEnd).trim().toLowerCase(); + let roles = data + .substring(indexStart + 17, indexEnd) + .trim() + .toLowerCase(); roles = roles.split(' '); - ariaRoles.forEach(function(role) { + ariaRoles.forEach(function (role) { if (roles.indexOf(role) >= 0) { console.log('data: ' + role + ', ' + content); - addGuidanceToRole(role, url, content+ ' (D)', getClosestId(data, indexStart)); + addGuidanceToRole( + role, + url, + content + ' (D)', + getClosestId(data, indexStart) + ); } }); @@ -425,26 +457,31 @@ function getRolesFromDataAttributesOnHeaders(data, url) { indexEnd = data.indexOf('"', indexStart + 17); } } - } function getPropertiesAndStatesFromDataAttributesOnHeaders(data, url) { - let indexStart = data.indexOf('data-aria-props="', 0); let indexEnd = data.indexOf('"', indexStart + 17); while (indexStart > 1 && indexEnd > 1) { - let content = getHeaderContent(data, indexStart); - let props = data.substring(indexStart + 17, indexEnd).trim().toLowerCase(); + let props = data + .substring(indexStart + 17, indexEnd) + .trim() + .toLowerCase(); props = props.split(' '); - ariaPropertiesAndStates.forEach(function(prop) { + ariaPropertiesAndStates.forEach(function (prop) { if (props.indexOf(prop) >= 0) { console.log('data: ' + prop + ', ' + content); - addGuidanceToPropertyOrState(prop, url, content+ ' (D)', getClosestId(data, indexStart)); + addGuidanceToPropertyOrState( + prop, + url, + content + ' (D)', + getClosestId(data, indexStart) + ); } }); @@ -454,7 +491,6 @@ function getPropertiesAndStatesFromDataAttributesOnHeaders(data, url) { indexEnd = data.indexOf('"', indexStart + 17); } } - } function getRolesPropertiesAndStatesFromGuidance(data, url) { getRolesPropertiesAndStatesFromHeaders(data, url); @@ -462,35 +498,107 @@ function getRolesPropertiesAndStatesFromGuidance(data, url) { getPropertiesAndStatesFromDataAttributesOnHeaders(data, url); } -let data = fs.readFileSync(path.join(__dirname, '../aria-practices.html'), 'utf8'); +let data = fs.readFileSync( + path.join(__dirname, '../aria-practices.html'), + 'utf8' +); getRolesPropertiesAndStatesFromGuidance(data, '../aria-practices.html'); - // Add landmark examples, since they are a different format -addLandmarkRole(['banner'], false, 'Banner Landmark', '../examples/landmarks/banner.html'); -addGuidanceToRole('banner', '../aria-practices.html', 'Banner', 'aria_lh_banner'); - -addLandmarkRole(['complementary'], true, 'Complementary Landmark', '../examples/landmarks/complementary.html'); -addGuidanceToRole('complementary', '../aria-practices.html', 'Complementary', 'aria_lh_complemtary'); - -addLandmarkRole(['contentinfo'], false, 'Contentinfo Landmark', '../examples/landmarks/contentinfo.html'); -addGuidanceToRole('contentinfo', '../aria-practices.html', 'Contentinfo', 'aria_lh_contentinfo'); - -addLandmarkRole(['form'], true, 'Form Landmark', '../examples/landmarks/form.html'); +addLandmarkRole( + ['banner'], + false, + 'Banner Landmark', + '../examples/landmarks/banner.html' +); +addGuidanceToRole( + 'banner', + '../aria-practices.html', + 'Banner', + 'aria_lh_banner' +); + +addLandmarkRole( + ['complementary'], + true, + 'Complementary Landmark', + '../examples/landmarks/complementary.html' +); +addGuidanceToRole( + 'complementary', + '../aria-practices.html', + 'Complementary', + 'aria_lh_complemtary' +); + +addLandmarkRole( + ['contentinfo'], + false, + 'Contentinfo Landmark', + '../examples/landmarks/contentinfo.html' +); +addGuidanceToRole( + 'contentinfo', + '../aria-practices.html', + 'Contentinfo', + 'aria_lh_contentinfo' +); + +addLandmarkRole( + ['form'], + true, + 'Form Landmark', + '../examples/landmarks/form.html' +); addGuidanceToRole('form', '../aria-practices.html', 'Form', 'aria_lh_form'); -addLandmarkRole(['main'], true, 'Main Landmark', '../examples/landmarks/main.html'); +addLandmarkRole( + ['main'], + true, + 'Main Landmark', + '../examples/landmarks/main.html' +); addGuidanceToRole('main', '../aria-practices.html', 'Main', 'aria_lh_main'); -addLandmarkRole(['navigation'], true, 'Navigation Landmark', '../examples/landmarks/navigation.html'); -addGuidanceToRole('navigation', '../aria-practices.html', 'Navigation', 'aria_lh_navigation'); - -addLandmarkRole(['region'], true, 'Region Landmark', '../examples/landmarks/region.html'); -addGuidanceToRole('region', '../aria-practices.html', 'Region', 'aria_lh_region'); - -addLandmarkRole(['search'], true, 'Search Landmark', '../examples/landmarks/search.html'); -addGuidanceToRole('search', '../aria-practices.html', 'Search', 'aria_lh_search'); +addLandmarkRole( + ['navigation'], + true, + 'Navigation Landmark', + '../examples/landmarks/navigation.html' +); +addGuidanceToRole( + 'navigation', + '../aria-practices.html', + 'Navigation', + 'aria_lh_navigation' +); + +addLandmarkRole( + ['region'], + true, + 'Region Landmark', + '../examples/landmarks/region.html' +); +addGuidanceToRole( + 'region', + '../aria-practices.html', + 'Region', + 'aria_lh_region' +); + +addLandmarkRole( + ['search'], + true, + 'Search Landmark', + '../examples/landmarks/search.html' +); +addGuidanceToRole( + 'search', + '../aria-practices.html', + 'Search', + 'aria_lh_search' +); function getListItem(item) { return ` @@ -502,10 +610,9 @@ function getListHTML(list) { if (list.length === 1) { html = `${list[0].title}\n`; - } - else { + } else { if (list.length > 1) { - html = `