From f9f019967f670bf600d09561fb0238f563748b59 Mon Sep 17 00:00:00 2001
From: Jon Gunderson
Date: Thu, 21 Nov 2019 16:49:57 -0700
Subject: [PATCH 01/42] updated combox code to use single prototype
---
.../combobox/combobox-autocomplete-both.html | 17 +-
examples/combobox/css/combobox.css | 31 +-
examples/combobox/js/combobox-autocomplete.js | 542 ++++++++++++++++++
examples/combobox/js/combobox-list.js | 2 +-
4 files changed, 583 insertions(+), 9 deletions(-)
create mode 100644 examples/combobox/js/combobox-autocomplete.js
diff --git a/examples/combobox/combobox-autocomplete-both.html b/examples/combobox/combobox-autocomplete-both.html
index 0a4b273c2..668e72d06 100644
--- a/examples/combobox/combobox-autocomplete-both.html
+++ b/examples/combobox/combobox-autocomplete-both.html
@@ -13,9 +13,7 @@
-
-
-
+
@@ -54,7 +52,18 @@ Example
Alabama
diff --git a/examples/combobox/css/combobox.css b/examples/combobox/css/combobox.css
index d437c332a..f430472ae 100644
--- a/examples/combobox/css/combobox.css
+++ b/examples/combobox/css/combobox.css
@@ -33,11 +33,31 @@
font-size: 70%;
}
+.combobox .group button .down {
+ display: block;
+}
+
+.combobox .group button .up {
+ display: none;
+}
+
+.combobox .group button.open .down {
+ display: none;
+}
+
+.combobox .group button.open .up {
+ display: block;
+}
+
.combobox .group.focus {
outline: 2px solid black;
outline-offset: 1px;
}
+.combobox .group.focus input {
+ background-color: #DEF;
+}
+
ul[role="listbox"] {
margin: 0;
padding: 0;
@@ -58,18 +78,21 @@ ul[role="listbox"] {
}
ul[role="listbox"] li[role="option"] {
- border-top: 1px solid transparent;
- border-bottom: 1px solid transparent;
display: block;
+ padding-left: 2px;
+ padding-top: 2px;
+ padding-bottom: 2px;
margin: 0;
- padding: 0.1em 0.3em;
}
/* focus and hover styling */
[role="listbox"].focus [role="option"][aria-selected="true"] {
background-color: #DEF;
- border-color: #8CCBF2;
+ padding-top: 0;
+ padding-bottom: 0;
+ border-top: 2px solid #8CCBF2;
+ border-bottom: 2px solid #8CCBF2;
}
@media (forced-colors: active), (-ms-high-contrast: active) {
diff --git a/examples/combobox/js/combobox-autocomplete.js b/examples/combobox/js/combobox-autocomplete.js
new file mode 100644
index 000000000..33b52b1f9
--- /dev/null
+++ b/examples/combobox/js/combobox-autocomplete.js
@@ -0,0 +1,542 @@
+/*
+* This content is licensed according to the W3C Software License at
+* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+*/
+var ComboboxAutocomplete = function (comboboxNode, buttonNode, listboxNode) {
+
+ this.comboboxNode = comboboxNode;
+ this.buttonNode = buttonNode;
+ this.listboxNode = listboxNode;
+
+ this.comboboxHasFocus = false;
+ this.listboxHasFocus = false;
+
+ this.hasHover = false;
+
+ this.isNone = false;
+ this.isList = false;
+ this.isBoth = false;
+
+ this.allOptions = [];
+
+ this.option = null;
+ this.firstOption = null;
+ this.lastOption = null;
+
+ this.filteredOptions = [];
+ this.filter = '';
+
+ this.firstChars = [];
+
+ this.keyCode = Object.freeze({
+ 'BACKSPACE': 8,
+ 'TAB': 9,
+ 'RETURN': 13,
+ 'ESC': 27,
+ 'SPACE': 32,
+ 'PAGEUP': 33,
+ 'PAGEDOWN': 34,
+ 'END': 35,
+ 'HOME': 36,
+ 'LEFT': 37,
+ 'UP': 38,
+ 'RIGHT': 39,
+ 'DOWN': 40
+ });
+};
+
+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 {
+ // 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));
+
+ // initialize pop up menu
+
+ 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.
+ var nodes = this.listboxNode.getElementsByTagName('LI');
+
+ for (var i = 0; i < nodes.length; i++) {
+ var node = nodes[i];
+ this.allOptions.push(node);
+
+ node.textComparison = node.textContent.toLowerCase();
+
+ node.addEventListener('click', this.handleOptionClick.bind(this));
+ node.addEventListener('mouseover', this.handleOptionMouseover.bind(this));
+ node.addEventListener('mouseout', this.handleOptionMouseout.bind(this));
+
+ }
+
+ this.filterOptions('');
+
+ // Open Button
+
+ var button = this.comboboxNode.nextElementSibling;
+
+ if (button && button.tagName === 'BUTTON') {
+ button.addEventListener('click', this.handleButtonClick.bind(this));
+ }
+
+};
+
+ComboboxAutocomplete.prototype.setActiveDescendant = function (option) {
+ if (option && this.listboxHasFocus) {
+ this.comboboxNode.setAttribute('aria-activedescendant', option.id);
+ }
+ else {
+ this.comboboxNode.setAttribute('aria-activedescendant', '');
+ }
+};
+
+ComboboxAutocomplete.prototype.setValue = function (value) {
+ this.filter = value;
+ this.comboboxNode.value = this.filter;
+ this.comboboxNode.setSelectionRange(this.filter.length,this.filter.length);
+ if (this.isList || this.isBoth) {
+ this.filterOptions(this.filter, this.option);
+ }
+};
+
+ComboboxAutocomplete.prototype.setOption = function (option, flag) {
+ if (typeof flag !== 'boolean') {
+ flag = false;
+ }
+
+ if (option) {
+ this.option = option;
+ this.setCurrentOptionStyle(this.option);
+ this.setActiveDescendant(this.option);
+
+ if (this.isBoth) {
+ 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);
+ }
+ }
+ }
+};
+
+ComboboxAutocomplete.prototype.setVisualFocusCombobox = function () {
+ this.listboxNode.classList.remove('focus');
+ this.comboboxNode.parentNode.classList.add('focus'); // set the focus class to the parent for easier styling
+ this.comboboxHasFocus = true;
+ this.listboxHasFocus = false;
+ this.setActiveDescendant(false);
+};
+
+ComboboxAutocomplete.prototype.setVisualFocusListbox = function () {
+ this.comboboxNode.parentNode.classList.remove('focus');
+ this.comboboxHasFocus = false;
+ this.listboxHasFocus = true;
+ this.listboxNode.classList.add('focus');
+ this.setActiveDescendant(this.option);
+};
+
+ComboboxAutocomplete.prototype.removeVisualFocusAll = function () {
+ this.comboboxNode.parentNode.classList.remove('focus');
+ this.comboboxHasFocus = false;
+ this.listboxHasFocus = false;
+ this.listboxNode.classList.remove('focus');
+ this.option = false;
+ this.setActiveDescendant(false);
+};
+
+// ComboboxAutocomplete Events
+
+ComboboxAutocomplete.prototype.filterOptions = function (filter, currentOption) {
+
+ if (typeof filter !== 'string') {
+ filter = '';
+ }
+
+ filter = filter.toLowerCase();
+
+ this.filteredOptions = [];
+ this.firstChars = [];
+ this.listboxNode.innerHTML = '';
+
+ for (var i = 0; i < this.allOptions.length; i++) {
+ var option = this.allOptions[i];
+ if (filter.length === 0 || option.textComparison.indexOf(filter) === 0) {
+ this.filteredOptions.push(option);
+ var textContent = option.textContent.trim();
+ this.firstChars.push(textContent.substring(0, 1).toLowerCase());
+ this.listboxNode.appendChild(option);
+ }
+ }
+
+ // Use populated options array to initialize firstOption and lastOption.
+ var numItems = this.filteredOptions.length;
+ if (numItems > 0) {
+ this.firstOption = this.filteredOptions[0];
+ this.lastOption = this.filteredOptions[numItems - 1];
+
+ if (currentOption && this.filteredOptions.indexOf(currentOption) >= 0) {
+ option = currentOption;
+ }
+ else {
+ option = this.firstOption;
+ }
+ }
+ else {
+ this.firstOption = false;
+ option = false;
+ this.lastOption = false;
+ }
+
+ 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');
+ this.listboxNode.scrollTop = opt.offsetTop;
+ }
+ else {
+ opt.removeAttribute('aria-selected');
+ }
+ }
+};
+
+ComboboxAutocomplete.prototype.getPreviousOption = function (currentOption) {
+ var index;
+
+ if (currentOption !== this.firstOption) {
+ index = this.filteredOptions.indexOf(currentOption);
+ return this.filteredOptions[index - 1];
+ }
+ return this.lastOption;
+};
+
+ComboboxAutocomplete.prototype.getNextOption = function (currentOption) {
+ var index;
+
+ if (currentOption !== this.lastOption) {
+ index = this.filteredOptions.indexOf(currentOption);
+ return this.filteredOptions[index + 1];
+ }
+ return this.firstOption;
+};
+
+/* MENU DISPLAY METHODS */
+
+ComboboxAutocomplete.prototype.doesOptionHaveFocus = function () {
+ return this.combobocNode.getAttribute('aria-activedescendant') !== '';
+};
+
+ComboboxAutocomplete.prototype.isOpen = function () {
+ return this.listboxNode.style.display === 'block';
+};
+
+ComboboxAutocomplete.prototype.isClosed = function () {
+ return this.listboxNode.style.display !== 'block';
+};
+
+ComboboxAutocomplete.prototype.hasOptions = function () {
+ return this.filteredOptions.length;
+};
+
+ComboboxAutocomplete.prototype.open = function () {
+ this.listboxNode.style.display = 'block';
+ this.comboboxNode.setAttribute('aria-expanded', 'true');
+ this.buttonNode.classList.add('open');
+};
+
+ComboboxAutocomplete.prototype.close = function (force) {
+ if (typeof force !== 'boolean') {
+ force = false;
+ }
+
+ if (force || (!this.comboboxHasFocus && !this.listboxHasFocus && !this.hasHover)) {
+ this.setCurrentOptionStyle(false);
+ this.listboxNode.style.display = 'none';
+ this.comboboxNode.setAttribute('aria-expanded', 'false');
+ this.buttonNode.classList.remove('open');
+ this.setActiveDescendant(false);
+ }
+};
+
+/* combobox Events */
+
+ComboboxAutocomplete.prototype.handleComboboxKeyDown = function (event) {
+ var flag = false,
+ char = event.key,
+ altKey = event.altKey;
+
+ if (event.ctrlKey || event.shiftKey) {
+ return;
+ }
+
+ switch (event.keyCode) {
+
+ case this.keyCode.RETURN:
+ if ((this.listboxHasFocus || this.isBoth) && this.option) {
+ this.setValue(this.option.textContent);
+ }
+ this.close(true);
+ flag = true;
+ break;
+
+ case this.keyCode.DOWN:
+ if (this.filteredOptions.length > 0) {
+ if (this.listboxHasFocus || (this.isBoth && this.option)) {
+ this.setOption(this.getNextOption(this.option), true);
+ }
+ else {
+ this.open();
+ if (!altKey) {
+ this.setOption(this.firstOption, true);
+ }
+ }
+ this.setVisualFocusListbox();
+ }
+ flag = true;
+ break;
+
+ case this.keyCode.UP:
+
+ if (this.hasOptions()) {
+ if (this.listboxHasFocus || (this.isBoth && this.option)) {
+ this.setOption(this.getPreviousOption(this.option), true);
+ }
+ else {
+ this.open();
+ if (!altKey) {
+ this.setOption(this.lastOption, true);
+ }
+ }
+ this.setVisualFocusListbox();
+ }
+ flag = true;
+ break;
+
+ case this.keyCode.ESC:
+ this.close(true);
+ this.setVisualFocusCombobox();
+ this.option = false;
+ flag = true;
+ break;
+
+ case this.keyCode.TAB:
+ this.close(true);
+ if (this.listboxHasFocus) {
+ if (this.option) {
+ this.setValue(this.option.textContent);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (flag) {
+ event.stopPropagation();
+ event.preventDefault();
+ }
+
+};
+
+ComboboxAutocomplete.prototype.handleComboboxKeyUp = function (event) {
+ var flag = false,
+ option = false,
+ char = event.key;
+
+ function isPrintableCharacter (str) {
+ return str.length === 1 && str.match(/\S/);
+ }
+
+ if (isPrintableCharacter(char)) {
+ this.filter += char;
+ }
+
+ // this is for the case when a selection in the textbox has been deleted
+ if (this.comboboxNode.value.length < this.filter.length) {
+ this.filter = this.comboboxNode.value;
+ this.option = false;
+ }
+
+ if (event.keyCode === this.keyCode.ESC) {
+ return;
+ }
+
+ switch (event.keyCode) {
+
+ case this.keyCode.BACKSPACE:
+ this.setValue(this.comboboxNode.value);
+ this.setVisualFocusCombobox();
+ this.setCurrentOptionStyle(false);
+ this.option = false;
+ flag = true;
+ break;
+
+ case this.keyCode.LEFT:
+ case this.keyCode.RIGHT:
+ case this.keyCode.HOME:
+ case this.keyCode.END:
+ if (this.isBoth) {
+ this.filter = this.comboboxNode.value;
+ }
+ else {
+ this.option = false;
+ this.setCurrentOptionStyle(false);
+ }
+
+ this.setVisualFocusCombobox();
+ flag = true;
+ break;
+
+ default:
+ if (isPrintableCharacter(char)) {
+ this.setVisualFocusCombobox();
+ this.setCurrentOptionStyle(false);
+ flag = true;
+
+ if (this.isList || this.isBoth) {
+ option = this.filterOptions(this.filter, this.option);
+ if (option) {
+ if (this.isClosed() && this.comboboxNode.value.length) {
+ this.open();
+ }
+
+ if (option.textComparison.indexOf(this.comboboxNode.value.toLowerCase()) === 0) {
+ this.option = option;
+ if (this.isBoth || this.listboxHasFocus) {
+ this.setCurrentOptionStyle(option);
+ if (this.isBoth && isPrintableCharacter(char)) {
+ this.setOption(option);
+ }
+ }
+ }
+ else {
+ this.option = false;
+ this.setCurrentOptionStyle(false);
+ }
+ }
+ else {
+ this.close();
+ this.option = false;
+ this.setActiveDescendant(false);
+ }
+ }
+ else if (this.comboboxNode.value.length) {
+ this.open();
+ }
+ }
+
+ break;
+ }
+
+ if (flag) {
+ event.stopPropagation();
+ event.preventDefault();
+ }
+
+};
+
+ComboboxAutocomplete.prototype.handleComboboxClick = function (event) {
+ if (this.isOpen()) {
+ this.close(true);
+ }
+ else {
+ this.open();
+ }
+};
+
+ComboboxAutocomplete.prototype.handleComboboxFocus = function (event) {
+ this.setVisualFocusCombobox();
+ this.option = false;
+ this.setCurrentOptionStyle(null);
+};
+
+ComboboxAutocomplete.prototype.handleComboboxBlur = function (event) {
+ this.comboboxHasFocus = false;
+ this.setCurrentOptionStyle(null);
+ this.removeVisualFocusAll();
+ setTimeout(this.close.bind(this, false), 300);
+};
+
+ComboboxAutocomplete.prototype.handleButtonClick = function (event) {
+ if (this.isOpen()) {
+ this.close(true);
+ }
+ else {
+ this.open();
+ }
+ this.comboboxNode.focus();
+ this.setVisualFocusCombobox();
+};
+
+
+/* Listbox Events */
+
+ComboboxAutocomplete.prototype.handleListboxMouseover = function (event) {
+ this.hasHover = true;
+};
+
+ComboboxAutocomplete.prototype.handleListboxMouseout = function (event) {
+ this.hasHover = false;
+ setTimeout(this.close.bind(this, false), 300);
+};
+
+// Listbox Option Events
+
+ComboboxAutocomplete.prototype.handleOptionClick = function (event) {
+ this.setOption(event.target);
+ this.close(true);
+};
+
+ComboboxAutocomplete.prototype.handleOptionMouseover = function (event) {
+ this.hasHover = true;
+ this.open();
+
+};
+
+ComboboxAutocomplete.prototype.handleOptionMouseout = function (event) {
+ this.hasHover = false;
+ 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 cba = new ComboboxAutocomplete(comboboxNode, buttonNode, listboxNode);
+ cba.init();
+ }
+
+});
diff --git a/examples/combobox/js/combobox-list.js b/examples/combobox/js/combobox-list.js
index d5bd49a47..798761ded 100644
--- a/examples/combobox/js/combobox-list.js
+++ b/examples/combobox/js/combobox-list.js
@@ -282,7 +282,7 @@ ComboboxList.prototype.handleKeyup = function (event) {
if (this.listbox.isClosed() && this.domNode.value.length) {
this.listbox.open();
}
-
+
if (option.textComparison.indexOf(this.domNode.value.toLowerCase()) === 0) {
this.option = option;
if (this.isBoth || this.listbox.hasFocus) {
From 3663deaa720c5a3369e7a25f9e37169fa986a6e3 Mon Sep 17 00:00:00 2001
From: Jon Gunderson
Date: Thu, 21 Nov 2019 19:13:14 -0700
Subject: [PATCH 02/42] updated escape key behavior
---
.../combobox/combobox-autocomplete-both.html | 24 +++--------
.../combobox/combobox-autocomplete-list.html | 40 +++++++++---------
.../combobox/combobox-autocomplete-none.html | 42 +++++++++----------
...combobox.css => combobox-autocomplete.css} | 6 ++-
examples/combobox/js/combobox-autocomplete.js | 13 +++---
5 files changed, 56 insertions(+), 69 deletions(-)
rename examples/combobox/css/{combobox.css => combobox-autocomplete.css} (96%)
diff --git a/examples/combobox/combobox-autocomplete-both.html b/examples/combobox/combobox-autocomplete-both.html
index 668e72d06..533131802 100644
--- a/examples/combobox/combobox-autocomplete-both.html
+++ b/examples/combobox/combobox-autocomplete-both.html
@@ -12,7 +12,7 @@
-
+
@@ -53,12 +53,12 @@ Example
-
+
-
+
@@ -177,8 +177,8 @@ Textbox
Escape
- Clears the textbox.
If the listbox is displayed, closes it.
+ If the listbox is not displayed, clears the textbox.
@@ -419,23 +419,11 @@ Javascript and CSS Source Code
diff --git a/examples/combobox/combobox-autocomplete-list.html b/examples/combobox/combobox-autocomplete-list.html
index ed807f249..026970d34 100644
--- a/examples/combobox/combobox-autocomplete-list.html
+++ b/examples/combobox/combobox-autocomplete-list.html
@@ -12,10 +12,9 @@
-
-
-
-
+
+
+
@@ -54,7 +53,18 @@ Example
Alabama
@@ -163,9 +173,9 @@ Textbox
Escape
- Clears the textbox.
If the listbox is displayed, closes it.
-
+ If the listbox is not displayed, clears the textbox.
+
@@ -405,23 +415,11 @@ Javascript and CSS Source Code
diff --git a/examples/combobox/combobox-autocomplete-none.html b/examples/combobox/combobox-autocomplete-none.html
index 05ad2d7d9..cb72c8141 100644
--- a/examples/combobox/combobox-autocomplete-none.html
+++ b/examples/combobox/combobox-autocomplete-none.html
@@ -12,10 +12,8 @@
-
-
-
-
+
+
@@ -55,7 +53,18 @@ Example
aria-autocomplete="none"
aria-expanded="false"
aria-controls="cb1-listbox">
- ▼
+
+
+
+
+
+
+
+
+
+
+
+
weather
@@ -158,10 +167,9 @@ Listbox Popup
Escape
- Clears the textbox.
- Closes the listbox.
- Sets visual focus on the textbox.
-
+ If the listbox is displayed, closes it.
+ If the listbox is not displayed, clears the textbox.
+
@@ -355,23 +363,11 @@ Javascript and CSS Source Code
diff --git a/examples/combobox/css/combobox.css b/examples/combobox/css/combobox-autocomplete.css
similarity index 96%
rename from examples/combobox/css/combobox.css
rename to examples/combobox/css/combobox-autocomplete.css
index f430472ae..1461118ca 100644
--- a/examples/combobox/css/combobox.css
+++ b/examples/combobox/css/combobox-autocomplete.css
@@ -30,7 +30,11 @@
width: 1.25rem;
border-left: none;
outline: none;
- font-size: 70%;
+ position: relative;
+}
+
+.combobox .group button .arrow {
+ top:;
}
.combobox .group button .down {
diff --git a/examples/combobox/js/combobox-autocomplete.js b/examples/combobox/js/combobox-autocomplete.js
index 33b52b1f9..ed0fdbd73 100644
--- a/examples/combobox/js/combobox-autocomplete.js
+++ b/examples/combobox/js/combobox-autocomplete.js
@@ -26,8 +26,6 @@ var ComboboxAutocomplete = function (comboboxNode, buttonNode, listboxNode) {
this.filteredOptions = [];
this.filter = '';
- this.firstChars = [];
-
this.keyCode = Object.freeze({
'BACKSPACE': 8,
'TAB': 9,
@@ -175,7 +173,6 @@ ComboboxAutocomplete.prototype.filterOptions = function (filter, currentOption)
filter = filter.toLowerCase();
this.filteredOptions = [];
- this.firstChars = [];
this.listboxNode.innerHTML = '';
for (var i = 0; i < this.allOptions.length; i++) {
@@ -183,7 +180,6 @@ ComboboxAutocomplete.prototype.filterOptions = function (filter, currentOption)
if (filter.length === 0 || option.textComparison.indexOf(filter) === 0) {
this.filteredOptions.push(option);
var textContent = option.textContent.trim();
- this.firstChars.push(textContent.substring(0, 1).toLowerCase());
this.listboxNode.appendChild(option);
}
}
@@ -337,8 +333,13 @@ ComboboxAutocomplete.prototype.handleComboboxKeyDown = function (event) {
break;
case this.keyCode.ESC:
- this.close(true);
- this.setVisualFocusCombobox();
+ if (this.isOpen()) {
+ this.close(true);
+ this.setVisualFocusCombobox();
+ }
+ else {
+ this.setValue('');
+ }
this.option = false;
flag = true;
break;
From db05fa516ddabd3458b43541a3f2ce1e3ee6d4e8 Mon Sep 17 00:00:00 2001
From: Jon Gunderson
Date: Thu, 21 Nov 2019 19:19:04 -0700
Subject: [PATCH 03/42] removed unused files
---
examples/combobox/js/combobox-list.js | 403 --------------------------
examples/combobox/js/listbox.js | 225 --------------
examples/combobox/js/listboxOption.js | 42 ---
3 files changed, 670 deletions(-)
delete mode 100644 examples/combobox/js/combobox-list.js
delete mode 100644 examples/combobox/js/listbox.js
delete mode 100644 examples/combobox/js/listboxOption.js
diff --git a/examples/combobox/js/combobox-list.js b/examples/combobox/js/combobox-list.js
deleted file mode 100644
index 798761ded..000000000
--- a/examples/combobox/js/combobox-list.js
+++ /dev/null
@@ -1,403 +0,0 @@
-/*
-* This content is licensed according to the W3C Software License at
-* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
-*/
-var ComboboxList = function (domNode) {
-
- this.domNode = domNode;
- this.listbox = false;
- this.option = false;
-
- this.hasFocus = false;
- this.hasHover = false;
- this.filter = '';
- this.isNone = false;
- this.isList = false;
- this.isBoth = false;
-
- this.keyCode = Object.freeze({
- 'BACKSPACE': 8,
- 'TAB': 9,
- 'RETURN': 13,
- 'ESC': 27,
- 'SPACE': 32,
- 'PAGEUP': 33,
- 'PAGEDOWN': 34,
- 'END': 35,
- 'HOME': 36,
- 'LEFT': 37,
- 'UP': 38,
- 'RIGHT': 39,
- 'DOWN': 40
- });
-};
-
-ComboboxList.prototype.init = function () {
-
- this.domNode.setAttribute('aria-haspopup', 'true');
-
- var autocomplete = this.domNode.getAttribute('aria-autocomplete');
-
- if (typeof autocomplete === 'string') {
- autocomplete = autocomplete.toLowerCase();
- this.isNone = autocomplete === 'none';
- this.isList = autocomplete === 'list';
- this.isBoth = autocomplete === 'both';
- }
- else {
- // default value of autocomplete
- this.isNone = true;
- }
-
- this.domNode.addEventListener('keydown', this.handleKeydown.bind(this));
- this.domNode.addEventListener('keyup', this.handleKeyup.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));
-
- // initialize pop up menus
-
- var listbox = document.getElementById(this.domNode.getAttribute('aria-controls'));
-
- if (listbox) {
- this.listbox = new Listbox(listbox, this);
- this.listbox.init();
- }
-
- // Open Button
-
- var button = this.domNode.nextElementSibling;
-
- if (button && button.tagName === 'BUTTON') {
- button.addEventListener('click', this.handleButtonClick.bind(this));
- }
-
-};
-
-ComboboxList.prototype.setActiveDescendant = function (option) {
- if (option && this.listbox.hasFocus) {
- this.domNode.setAttribute('aria-activedescendant', option.domNode.id);
- }
- else {
- this.domNode.setAttribute('aria-activedescendant', '');
- }
-};
-
-ComboboxList.prototype.setValue = function (value) {
- this.filter = value;
- this.domNode.value = this.filter;
- this.domNode.setSelectionRange(this.filter.length,this.filter.length);
- if (this.isList || this.isBoth) {
- this.listbox.filterOptions(this.filter, this.option);
- }
-};
-
-ComboboxList.prototype.setOption = function (option, flag) {
- if (typeof flag !== 'boolean') {
- flag = false;
- }
-
- if (option) {
- this.option = option;
- this.listbox.setCurrentOptionStyle(this.option);
- this.setActiveDescendant(this.option);
-
- if (this.isBoth) {
- this.domNode.value = this.option.textContent;
- if (flag) {
- this.domNode.setSelectionRange(this.option.textContent.length,this.option.textContent.length);
- }
- else {
- this.domNode.setSelectionRange(this.filter.length,this.option.textContent.length);
- }
- }
- }
-};
-
-ComboboxList.prototype.setVisualFocusTextbox = function () {
- this.listbox.domNode.classList.remove('focus');
- this.listbox.hasFocus = false;
- this.domNode.parentNode.classList.add('focus'); // set the focus class to the parent for easier styling
- this.hasFocus = true;
- this.setActiveDescendant(false);
-};
-
-ComboboxList.prototype.setVisualFocusListbox = function () {
- this.domNode.parentNode.classList.remove('focus');
- this.hasFocus = false;
- this.listbox.domNode.classList.add('focus');
- this.listbox.hasFocus = true;
- this.setActiveDescendant(this.option);
-};
-
-ComboboxList.prototype.removeVisualFocusAll = function () {
- this.domNode.parentNode.classList.remove('focus');
- this.hasFocus = false;
- this.listbox.domNode.classList.remove('focus');
- this.listbox.hasFocus = true;
- this.option = false;
- this.setActiveDescendant(false);
-};
-
-/* Event Handlers */
-
-ComboboxList.prototype.handleKeydown = function (event) {
- var tgt = event.currentTarget,
- flag = false,
- char = event.key,
- shiftKey = event.shiftKey,
- ctrlKey = event.ctrlKey,
- altKey = event.altKey;
-
- switch (event.keyCode) {
-
- case this.keyCode.RETURN:
- if ((this.listbox.hasFocus || this.isBoth) && this.option) {
- this.setValue(this.option.textContent);
- }
- this.listbox.close(true);
- flag = true;
- break;
-
- case this.keyCode.DOWN:
-
- if (this.listbox.hasOptions()) {
- if (this.listbox.hasFocus || (this.isBoth && this.option)) {
- this.setOption(this.listbox.getNextItem(this.option), true);
- }
- else {
- this.listbox.open();
- if (!altKey) {
- this.setOption(this.listbox.getFirstItem(), true);
- }
- }
- this.setVisualFocusListbox();
- }
- flag = true;
- break;
-
- case this.keyCode.UP:
-
- if (this.listbox.hasOptions()) {
- if (this.listbox.hasFocus || (this.isBoth && this.option)) {
- this.setOption(this.listbox.getPreviousItem(this.option), true);
- }
- else {
- this.listbox.open();
- if (!altKey) {
- this.setOption(this.listbox.getLastItem(), true);
- }
- }
- this.setVisualFocusListbox();
- }
- flag = true;
- break;
-
- case this.keyCode.ESC:
- this.listbox.close(true);
- this.setVisualFocusTextbox();
- this.setValue('');
- this.option = false;
- flag = true;
- break;
-
- case this.keyCode.TAB:
- this.listbox.close(true);
- if (this.listbox.hasFocus) {
- if (this.option) {
- this.setValue(this.option.textContent);
- }
- }
- break;
-
- default:
- break;
- }
-
- if (flag) {
- event.stopPropagation();
- event.preventDefault();
- }
-
-};
-
-ComboboxList.prototype.handleKeyup = function (event) {
- var flag = false,
- option = false,
- char = event.key;
-
- function isPrintableCharacter (str) {
- return str.length === 1 && str.match(/\S/);
- }
-
- if (isPrintableCharacter(char)) {
- this.filter += char;
- }
-
- // this is for the case when a selection in the textbox has been deleted
- if (this.domNode.value.length < this.filter.length) {
- this.filter = this.domNode.value;
- this.option = false;
- }
-
- if (event.keyCode === this.keyCode.ESC) {
- return;
- }
-
- switch (event.keyCode) {
-
- case this.keyCode.BACKSPACE:
- this.setValue(this.domNode.value);
- this.setVisualFocusTextbox();
- this.listbox.setCurrentOptionStyle(false);
- this.option = false;
- flag = true;
- break;
-
- case this.keyCode.LEFT:
- case this.keyCode.RIGHT:
- case this.keyCode.HOME:
- case this.keyCode.END:
- if (this.isBoth) {
- this.filter = this.domNode.value;
- }
- else {
- this.option = false;
- this.listbox.setCurrentOptionStyle(false);
- }
-
- this.setVisualFocusTextbox();
- flag = true;
- break;
-
- default:
- if (isPrintableCharacter(char)) {
- this.setVisualFocusTextbox();
- this.listbox.setCurrentOptionStyle(false);
- flag = true;
-
- if (this.isList || this.isBoth) {
- option = this.listbox.filterOptions(this.filter, this.option);
- if (option) {
- if (this.listbox.isClosed() && this.domNode.value.length) {
- this.listbox.open();
- }
-
- if (option.textComparison.indexOf(this.domNode.value.toLowerCase()) === 0) {
- this.option = option;
- if (this.isBoth || this.listbox.hasFocus) {
- this.listbox.setCurrentOptionStyle(option);
- if (this.isBoth && isPrintableCharacter(char)) {
- this.setOption(option);
- }
- }
- }
- else {
- this.option = false;
- this.listbox.setCurrentOptionStyle(false);
- }
- }
- else {
- this.listbox.close();
- this.option = false;
- this.setActiveDescendant(false);
- }
- }
- else if (this.domNode.value.length) {
- this.listbox.open();
- }
- }
-
- break;
- }
-
- // if (event.keyCode !== this.keyCode.RETURN) {
-
- // if (this.isList || this.isBoth) {
- // option = this.listbox.filterOptions(this.filter, this.option);
- // if (option) {
- // if (this.listbox.isClosed() && this.domNode.value.length) {
- // this.listbox.open();
- // }
-
- // if (option.textComparison.indexOf(this.domNode.value.toLowerCase()) === 0) {
- // this.option = option;
- // if (this.isBoth || this.listbox.hasFocus) {
- // this.listbox.setCurrentOptionStyle(option);
- // if (this.isBoth && isPrintableCharacter(char)) {
- // this.setOption(option);
- // }
- // }
- // }
- // else {
- // this.option = false;
- // this.listbox.setCurrentOptionStyle(false);
- // }
- // }
- // else {
- // this.listbox.close();
- // this.option = false;
- // this.setActiveDescendant(false);
- // }
- // }
- // else if (this.domNode.value.length) {
- // this.listbox.open();
- // }
-
- // }
-
-
- if (flag) {
- event.stopPropagation();
- event.preventDefault();
- }
-
-};
-
-ComboboxList.prototype.handleClick = function (event) {
- if (this.listbox.isOpen()) {
- this.listbox.close(true);
- }
- else {
- this.listbox.open();
- }
-};
-
-ComboboxList.prototype.handleFocus = function (event) {
- this.setVisualFocusTextbox();
- this.option = false;
- this.listbox.setCurrentOptionStyle(null);
-};
-
-ComboboxList.prototype.handleBlur = function (event) {
- this.listbox.hasFocus = false;
- this.listbox.setCurrentOptionStyle(null);
- this.removeVisualFocusAll();
- setTimeout(this.listbox.close.bind(this.listbox, false), 300);
-
-};
-
-ComboboxList.prototype.handleButtonClick = function (event) {
- if (this.listbox.isOpen()) {
- this.listbox.close(true);
- }
- else {
- this.listbox.open();
- }
- this.domNode.focus();
- this.setVisualFocusTextbox();
-};
-
-
-// Initialize comboboxes
-
-window.addEventListener('load', function () {
-
- var comboboxes = document.querySelectorAll('.combobox-list [role="combobox"]');
-
- for (var i = 0; i < comboboxes.length; i++) {
- var combobox = new ComboboxList(comboboxes[i]);
- combobox.init();
- }
-
-});
diff --git a/examples/combobox/js/listbox.js b/examples/combobox/js/listbox.js
deleted file mode 100644
index fe9f7f55c..000000000
--- a/examples/combobox/js/listbox.js
+++ /dev/null
@@ -1,225 +0,0 @@
-/*
-* This content is licensed according to the W3C Software License at
-* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
-*/
-var Listbox = function (domNode, comboboxObj) {
- var elementChildren,
- msgPrefix = 'Listbox constructor argument domNode ';
-
- // Check whether domNode is a DOM element
- if (!(domNode instanceof Element)) {
- throw new TypeError(msgPrefix + 'is not a DOM Element.');
- }
-
- // Check whether domNode has child elements
- if (domNode.childElementCount === 0) {
- throw new Error(msgPrefix + 'has no element children.');
- }
-
- // Check whether domNode child elements are A elements
- var childElement = domNode.firstElementChild;
- while (childElement) {
- var option = childElement.firstElementChild;
- childElement = childElement.nextElementSibling;
- }
-
- this.domNode = domNode;
- this.combobox = comboboxObj;
-
- this.allOptions = [];
-
- this.options = []; // see PopupMenu init method
-
- this.firstOption = null; // see PopupMenu init method
- this.lastOption = null; // see PopupMenu init method
-
- this.hasFocus = false; // see MenuItem handleFocus, handleBlur
- this.hasHover = false; // see PopupMenu handleMouseover, handleMouseout
-};
-
-/*
-* @method Listbox.prototype.init
-*
-* @desc
-* Add domNode event listeners for mouseover and mouseout. Traverse
-* domNode children to configure each option and populate.options
-* array. Initialize firstOption and lastOption properties.
-*/
-Listbox.prototype.init = function () {
- var childElement, optionElement, optionElements, firstChildElement, option, textContent, numItems;
-
- // Configure the domNode itself
- this.domNode.tabIndex = -1;
-
- this.domNode.setAttribute('role', 'listbox');
-
- this.domNode.addEventListener('mouseover', this.handleMouseover.bind(this));
- this.domNode.addEventListener('mouseout', this.handleMouseout.bind(this));
-
- // Traverse the element children of domNode: configure each with
- // option role behavior and store reference in.options array.
- optionElements = this.domNode.getElementsByTagName('LI');
-
- for (var i = 0; i < optionElements.length; i++) {
-
- optionElement = optionElements[i];
-
- if (!optionElement.firstElementChild && optionElement.getAttribute('role') != 'separator') {
- option = new ListboxOption(optionElement, this);
- option.init();
- this.allOptions.push(option);
- }
- }
-
- this.filterOptions('');
-
-};
-
-Listbox.prototype.filterOptions = function (filter, currentOption) {
-
- if (typeof filter !== 'string') {
- filter = '';
- }
-
- var i,
- option,
- textContent,
- numItems;
-
- filter = filter.toLowerCase();
-
- this.options = [];
- this.firstChars = [];
- this.domNode.innerHTML = '';
-
- for (i = 0; i < this.allOptions.length; i++) {
- option = this.allOptions[i];
- if (filter.length === 0 || option.textComparison.indexOf(filter) === 0) {
- this.options.push(option);
- textContent = option.textContent.trim();
- this.firstChars.push(textContent.substring(0, 1).toLowerCase());
- this.domNode.appendChild(option.domNode);
- }
- }
-
- // Use populated.options array to initialize firstOption and lastOption.
- numItems = this.options.length;
- if (numItems > 0) {
- this.firstOption = this.options[0];
- this.lastOption = this.options[numItems - 1];
-
- if (currentOption && this.options.indexOf(currentOption) >= 0) {
- option = currentOption;
- }
- else {
- option = this.firstOption;
- }
- }
- else {
- this.firstOption = false;
- option = false;
- this.lastOption = false;
- }
-
- return option;
-};
-
-Listbox.prototype.setCurrentOptionStyle = function (option) {
-
- for (var i = 0; i < this.options.length; i++) {
- var opt = this.options[i];
- if (opt === option) {
- opt.domNode.setAttribute('aria-selected', 'true');
- this.domNode.scrollTop = opt.domNode.offsetTop;
- }
- else {
- opt.domNode.removeAttribute('aria-selected');
- }
- }
-};
-
-Listbox.prototype.setOption = function (option) {
- if (option) {
- this.combobox.setOption(option);
- this.combobox.setValue(option.textContent);
- }
-};
-
-/* EVENT HANDLERS */
-
-Listbox.prototype.handleMouseover = function (event) {
- this.hasHover = true;
-};
-
-Listbox.prototype.handleMouseout = function (event) {
- this.hasHover = false;
- setTimeout(this.close.bind(this, false), 300);
-};
-
-/* FOCUS MANAGEMENT METHODS */
-
-
-Listbox.prototype.getFirstItem = function () {
- return this.firstOption;
-};
-
-Listbox.prototype.getLastItem = function () {
- return this.lastOption;
-};
-
-Listbox.prototype.getPreviousItem = function (currentOption) {
- var index;
-
- if (currentOption !== this.firstOption) {
- index = this.options.indexOf(currentOption);
- return this.options[index - 1];
- }
- return this.lastOption;
-};
-
-Listbox.prototype.getNextItem = function (currentOption) {
- var index;
-
- if (currentOption !== this.lastOption) {
- index = this.options.indexOf(currentOption);
- return this.options[index + 1];
- }
- return this.firstOption;
-};
-
-/* MENU DISPLAY METHODS */
-
-Listbox.prototype.isOpen = function () {
- return this.domNode.style.display === 'block';
-};
-
-Listbox.prototype.isClosed = function () {
- return this.domNode.style.display !== 'block';
-};
-
-Listbox.prototype.hasOptions = function () {
- return this.options.length;
-};
-
-Listbox.prototype.open = function () {
- // set CSS properties
- this.domNode.style.display = 'block';
-
- // set aria-expanded attribute
- this.combobox.domNode.setAttribute('aria-expanded', 'true');
-};
-
-Listbox.prototype.close = function (force) {
- if (typeof force !== 'boolean') {
- force = false;
- }
-
- if (force || (!this.hasFocus && !this.hasHover && !this.combobox.hasHover)) {
- this.setCurrentOptionStyle(false);
- this.domNode.style.display = 'none';
- this.combobox.domNode.setAttribute('aria-expanded', 'false');
- this.combobox.setActiveDescendant(false);
- }
-};
-
-
diff --git a/examples/combobox/js/listboxOption.js b/examples/combobox/js/listboxOption.js
deleted file mode 100644
index 0707760d0..000000000
--- a/examples/combobox/js/listboxOption.js
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
-* This content is licensed according to the W3C Software License at
-* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
-*/
-var ListboxOption = function (domNode, listboxObj) {
-
- this.domNode = domNode;
- this.listbox = listboxObj;
- this.textContent = domNode.textContent;
- this.textComparison = domNode.textContent.toLowerCase();
-
-};
-
-ListboxOption.prototype.init = function () {
-
- if (!this.domNode.getAttribute('role')) {
- this.domNode.setAttribute('role', 'option');
- }
-
- 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 */
-
-ListboxOption.prototype.handleClick = function (event) {
- this.listbox.setOption(this);
- this.listbox.close(true);
-};
-
-ListboxOption.prototype.handleMouseover = function (event) {
- this.listbox.hasHover = true;
- this.listbox.open();
-
-};
-
-ListboxOption.prototype.handleMouseout = function (event) {
- this.listbox.hasHover = false;
- setTimeout(this.listbox.close.bind(this.listbox, false), 300);
-};
From 7937a0381cc928d0ce447129acfc50f7e2e5ad1f Mon Sep 17 00:00:00 2001
From: Jon Gunderson
Date: Thu, 21 Nov 2019 19:54:51 -0700
Subject: [PATCH 04/42] fixing regression issues for escape key
---
examples/combobox/js/combobox-autocomplete.js | 14 +++++++++++++-
test/tests/combobox_autocomplete-both.js | 4 ++--
test/tests/combobox_autocomplete-list.js | 4 ++--
3 files changed, 17 insertions(+), 5 deletions(-)
diff --git a/examples/combobox/js/combobox-autocomplete.js b/examples/combobox/js/combobox-autocomplete.js
index ed0fdbd73..f2c75f89f 100644
--- a/examples/combobox/js/combobox-autocomplete.js
+++ b/examples/combobox/js/combobox-autocomplete.js
@@ -339,6 +339,7 @@ ComboboxAutocomplete.prototype.handleComboboxKeyDown = function (event) {
}
else {
this.setValue('');
+ this.comboboxNode.value = '';
}
this.option = false;
flag = true;
@@ -353,6 +354,18 @@ ComboboxAutocomplete.prototype.handleComboboxKeyDown = function (event) {
}
break;
+ case this.keyCode.HOME:
+ this.comboboxNode.setSelectionRange(0,0);
+ flag = true;
+ break;
+
+ case this.keyCode.END:
+ var length = this.comboboxNode.value.length;
+ this.comboboxNode.setSelectionRange(length,length);
+ flag = true;
+ break;
+
+
default:
break;
}
@@ -408,7 +421,6 @@ ComboboxAutocomplete.prototype.handleComboboxKeyUp = function (event) {
this.option = false;
this.setCurrentOptionStyle(false);
}
-
this.setVisualFocusCombobox();
flag = true;
break;
diff --git a/test/tests/combobox_autocomplete-both.js b/test/tests/combobox_autocomplete-both.js
index 879c30389..a6a8e0f79 100644
--- a/test/tests/combobox_autocomplete-both.js
+++ b/test/tests/combobox_autocomplete-both.js
@@ -354,7 +354,7 @@ ariaTest('Test escape key press with focus on textbox',
await t.context.session
.findElement(By.css(ex.textboxSelector))
.getAttribute('value'),
- '',
+ 'Alabama',
'In key press "ESCAPE" should result in first option in textbox'
);
@@ -378,7 +378,7 @@ ariaTest('Test escape key press with focus on textbox',
await t.context.session
.findElement(By.css(ex.textboxSelector))
.getAttribute('value'),
- '',
+ 'Alaska',
'In listbox key press "ESCAPE" should result in first option in textbox'
);
diff --git a/test/tests/combobox_autocomplete-list.js b/test/tests/combobox_autocomplete-list.js
index 63e3631c5..597a17d82 100644
--- a/test/tests/combobox_autocomplete-list.js
+++ b/test/tests/combobox_autocomplete-list.js
@@ -352,7 +352,7 @@ ariaTest('Test escape key press with focus on textbox',
await t.context.session
.findElement(By.css(ex.textboxSelector))
- .sendKeys('a', Key.ESCAPE);
+ .sendKeys('a', Key.ESCAPE, Key.ESCAPE);
// Confirm the listbox is closed and the textboxed is cleared
@@ -385,7 +385,7 @@ ariaTest('Test escape key press with focus on textbox',
await t.context.session
.findElement(By.css(ex.textboxSelector))
.getAttribute('value'),
- '',
+ 'a',
'In listbox key press "ESCAPE" should result in first option in textbox'
);
From d9464c8c95fc9964df392cb81d41fa6c9cbd212b Mon Sep 17 00:00:00 2001
From: Jon Gunderson
Date: Thu, 21 Nov 2019 20:34:51 -0700
Subject: [PATCH 05/42] updated tests for single and double escape key tests
---
test/tests/combobox_autocomplete-both.js | 25 +++++++++++++++++++++++-
test/tests/combobox_autocomplete-list.js | 25 +++++++++++++++++++++++-
test/tests/combobox_autocomplete-none.js | 24 +++++++++++++++++++++++
3 files changed, 72 insertions(+), 2 deletions(-)
diff --git a/test/tests/combobox_autocomplete-both.js b/test/tests/combobox_autocomplete-both.js
index a6a8e0f79..bb40e8b4d 100644
--- a/test/tests/combobox_autocomplete-both.js
+++ b/test/tests/combobox_autocomplete-both.js
@@ -337,7 +337,7 @@ ariaTest('Test enter key press with focus on listbox',
});
-ariaTest('Test escape key press with focus on textbox',
+ariaTest('Test single escape key press with focus on textbox',
exampleFile, 'textbox-key-escape', async (t) => {
t.plan(2);
@@ -360,6 +360,29 @@ ariaTest('Test escape key press with focus on textbox',
});
+ariaTest('Test double escape key press with focus on textbox',
+ exampleFile, 'textbox-key-escape', async (t) => {
+ t.plan(2);
+
+ // Send key "a", then key ESCAPE to the textbox
+
+ await t.context.session
+ .findElement(By.css(ex.textboxSelector))
+ .sendKeys('a', Key.ESCAPE, Key.ESCAPE);
+
+ // Confirm the listbox is closed and the textboxed is clearedx
+
+ await assertAttributeValues(t, ex.textboxSelector, 'aria-expanded', 'false');
+ t.is(
+ await t.context.session
+ .findElement(By.css(ex.textboxSelector))
+ .getAttribute('value'),
+ '',
+ 'In key press "ESCAPE" should result in first option in textbox'
+ );
+
+ });
+
ariaTest('Test escape key press with focus on textbox',
exampleFile, 'listbox-key-escape', async (t) => {
t.plan(2);
diff --git a/test/tests/combobox_autocomplete-list.js b/test/tests/combobox_autocomplete-list.js
index 597a17d82..b2cbf5d46 100644
--- a/test/tests/combobox_autocomplete-list.js
+++ b/test/tests/combobox_autocomplete-list.js
@@ -344,7 +344,30 @@ ariaTest('Test enter key press with focus on listbox',
});
-ariaTest('Test escape key press with focus on textbox',
+ariaTest('Test single escape key press with focus on textbox',
+ exampleFile, 'textbox-key-escape', async (t) => {
+ t.plan(2);
+
+ // Send key "a", then key ESCAPE to the textbox
+
+ await t.context.session
+ .findElement(By.css(ex.textboxSelector))
+ .sendKeys('a', Key.ESCAPE);
+
+ // Confirm the listbox is closed and the textboxed is cleared
+
+ await assertAttributeValues(t, ex.textboxSelector, 'aria-expanded', 'false');
+ t.is(
+ await t.context.session
+ .findElement(By.css(ex.textboxSelector))
+ .getAttribute('value'),
+ 'a',
+ 'In key press "ESCAPE" should result in first option in textbox'
+ );
+
+ });
+
+ariaTest('Test double escape key press with focus on textbox',
exampleFile, 'textbox-key-escape', async (t) => {
t.plan(2);
diff --git a/test/tests/combobox_autocomplete-none.js b/test/tests/combobox_autocomplete-none.js
index 0119089cf..45df191db 100644
--- a/test/tests/combobox_autocomplete-none.js
+++ b/test/tests/combobox_autocomplete-none.js
@@ -356,6 +356,30 @@ ariaTest('Test escape key press with focus on textbox',
// Confirm the listbox is closed and the textboxed is cleared
+ await assertAttributeValues(t, ex.textboxSelector, 'aria-expanded', 'false');
+ t.is(
+ await t.context.session
+ .findElement(By.css(ex.textboxSelector))
+ .getAttribute('value'),
+ 'a',
+ 'In listbox key press "ESCAPE" should result in first option in textbox'
+ );
+
+ });
+
+ariaTest('Test double escape key press with focus on textbox',
+ exampleFile, 'listbox-key-escape', async (t) => {
+ t.plan(2);
+
+ // Send key "a" then key "ARROW_DOWN to put the focus on the listbox,
+ // then key ESCAPE to the textbox
+
+ await t.context.session
+ .findElement(By.css(ex.textboxSelector))
+ .sendKeys('a', Key.ARROW_DOWN, Key.ESCAPE, Key.ESCAPE);
+
+ // Confirm the listbox is closed and the textboxed is cleared
+
await assertAttributeValues(t, ex.textboxSelector, 'aria-expanded', 'false');
t.is(
await t.context.session
From 903f6d3cd68f9694f07b44adadeb3cc55d4ee94b Mon Sep 17 00:00:00 2001
From: Jon
Date: Fri, 29 Nov 2019 07:47:07 -0600
Subject: [PATCH 06/42] fixed focus bug on enter and removed use of keycode
property
---
examples/combobox/js/combobox-autocomplete.js | 52 ++++++++-----------
1 file changed, 21 insertions(+), 31 deletions(-)
diff --git a/examples/combobox/js/combobox-autocomplete.js b/examples/combobox/js/combobox-autocomplete.js
index f2c75f89f..eb2c443f1 100644
--- a/examples/combobox/js/combobox-autocomplete.js
+++ b/examples/combobox/js/combobox-autocomplete.js
@@ -25,22 +25,6 @@ var ComboboxAutocomplete = function (comboboxNode, buttonNode, listboxNode) {
this.filteredOptions = [];
this.filter = '';
-
- this.keyCode = Object.freeze({
- 'BACKSPACE': 8,
- 'TAB': 9,
- 'RETURN': 13,
- 'ESC': 27,
- 'SPACE': 32,
- 'PAGEUP': 33,
- 'PAGEDOWN': 34,
- 'END': 35,
- 'HOME': 36,
- 'LEFT': 37,
- 'UP': 38,
- 'RIGHT': 39,
- 'DOWN': 40
- });
};
ComboboxAutocomplete.prototype.init = function () {
@@ -289,17 +273,19 @@ ComboboxAutocomplete.prototype.handleComboboxKeyDown = function (event) {
return;
}
- switch (event.keyCode) {
+ switch (event.key) {
- case this.keyCode.RETURN:
+ case "Enter":
if ((this.listboxHasFocus || this.isBoth) && this.option) {
this.setValue(this.option.textContent);
}
this.close(true);
+ this.setVisualFocusCombobox();
flag = true;
break;
- case this.keyCode.DOWN:
+ case "Down":
+ case "ArrowDown":
if (this.filteredOptions.length > 0) {
if (this.listboxHasFocus || (this.isBoth && this.option)) {
this.setOption(this.getNextOption(this.option), true);
@@ -315,7 +301,8 @@ ComboboxAutocomplete.prototype.handleComboboxKeyDown = function (event) {
flag = true;
break;
- case this.keyCode.UP:
+ case "Up":
+ case "ArrowUp":
if (this.hasOptions()) {
if (this.listboxHasFocus || (this.isBoth && this.option)) {
@@ -332,7 +319,8 @@ ComboboxAutocomplete.prototype.handleComboboxKeyDown = function (event) {
flag = true;
break;
- case this.keyCode.ESC:
+ case "Esc":
+ case "Escape":
if (this.isOpen()) {
this.close(true);
this.setVisualFocusCombobox();
@@ -345,7 +333,7 @@ ComboboxAutocomplete.prototype.handleComboboxKeyDown = function (event) {
flag = true;
break;
- case this.keyCode.TAB:
+ case "Tab":
this.close(true);
if (this.listboxHasFocus) {
if (this.option) {
@@ -354,12 +342,12 @@ ComboboxAutocomplete.prototype.handleComboboxKeyDown = function (event) {
}
break;
- case this.keyCode.HOME:
+ case "Home":
this.comboboxNode.setSelectionRange(0,0);
flag = true;
break;
- case this.keyCode.END:
+ case "End":
var length = this.comboboxNode.value.length;
this.comboboxNode.setSelectionRange(length,length);
flag = true;
@@ -396,13 +384,13 @@ ComboboxAutocomplete.prototype.handleComboboxKeyUp = function (event) {
this.option = false;
}
- if (event.keyCode === this.keyCode.ESC) {
+ if (event.key === "Escape" || event.key === "Esc") {
return;
}
- switch (event.keyCode) {
+ switch (event.key) {
- case this.keyCode.BACKSPACE:
+ case "Backspace":
this.setValue(this.comboboxNode.value);
this.setVisualFocusCombobox();
this.setCurrentOptionStyle(false);
@@ -410,10 +398,12 @@ ComboboxAutocomplete.prototype.handleComboboxKeyUp = function (event) {
flag = true;
break;
- case this.keyCode.LEFT:
- case this.keyCode.RIGHT:
- case this.keyCode.HOME:
- case this.keyCode.END:
+ case "Left":
+ case "ArrowLeft":
+ case "Right":
+ case "ArrowRight":
+ case "Home":
+ case "End":
if (this.isBoth) {
this.filter = this.comboboxNode.value;
}
From 60e8955a2c3ffe28fe0ff7c7e5bdf8197cca1f14 Mon Sep 17 00:00:00 2001
From: Jon
Date: Mon, 2 Dec 2019 15:16:50 -0600
Subject: [PATCH 07/42] fixed bug in opening list and improved property names
for visual focus flags
---
examples/combobox/js/combobox-autocomplete.js | 34 +++++++++----------
1 file changed, 17 insertions(+), 17 deletions(-)
diff --git a/examples/combobox/js/combobox-autocomplete.js b/examples/combobox/js/combobox-autocomplete.js
index eb2c443f1..069b2a553 100644
--- a/examples/combobox/js/combobox-autocomplete.js
+++ b/examples/combobox/js/combobox-autocomplete.js
@@ -8,8 +8,8 @@ var ComboboxAutocomplete = function (comboboxNode, buttonNode, listboxNode) {
this.buttonNode = buttonNode;
this.listboxNode = listboxNode;
- this.comboboxHasFocus = false;
- this.listboxHasFocus = false;
+ this.comboboxHasVisualFocus = false;
+ this.listboxHasVisualFocus = false;
this.hasHover = false;
@@ -82,7 +82,7 @@ ComboboxAutocomplete.prototype.init = function () {
};
ComboboxAutocomplete.prototype.setActiveDescendant = function (option) {
- if (option && this.listboxHasFocus) {
+ if (option && this.listboxHasVisualFocus) {
this.comboboxNode.setAttribute('aria-activedescendant', option.id);
}
else {
@@ -124,23 +124,23 @@ ComboboxAutocomplete.prototype.setOption = function (option, flag) {
ComboboxAutocomplete.prototype.setVisualFocusCombobox = function () {
this.listboxNode.classList.remove('focus');
this.comboboxNode.parentNode.classList.add('focus'); // set the focus class to the parent for easier styling
- this.comboboxHasFocus = true;
- this.listboxHasFocus = false;
+ this.comboboxHasVisualFocus = true;
+ this.listboxHasVisualFocus = false;
this.setActiveDescendant(false);
};
ComboboxAutocomplete.prototype.setVisualFocusListbox = function () {
this.comboboxNode.parentNode.classList.remove('focus');
- this.comboboxHasFocus = false;
- this.listboxHasFocus = true;
+ this.comboboxHasVisualFocus = false;
+ this.listboxHasVisualFocus = true;
this.listboxNode.classList.add('focus');
this.setActiveDescendant(this.option);
};
ComboboxAutocomplete.prototype.removeVisualFocusAll = function () {
this.comboboxNode.parentNode.classList.remove('focus');
- this.comboboxHasFocus = false;
- this.listboxHasFocus = false;
+ this.comboboxHasVisualFocus = false;
+ this.listboxHasVisualFocus = false;
this.listboxNode.classList.remove('focus');
this.option = false;
this.setActiveDescendant(false);
@@ -253,7 +253,7 @@ ComboboxAutocomplete.prototype.close = function (force) {
force = false;
}
- if (force || (!this.comboboxHasFocus && !this.listboxHasFocus && !this.hasHover)) {
+ if (force || (!this.comboboxHasVisualFocus && !this.listboxHasVisualFocus && !this.hasHover)) {
this.setCurrentOptionStyle(false);
this.listboxNode.style.display = 'none';
this.comboboxNode.setAttribute('aria-expanded', 'false');
@@ -276,10 +276,10 @@ ComboboxAutocomplete.prototype.handleComboboxKeyDown = function (event) {
switch (event.key) {
case "Enter":
- if ((this.listboxHasFocus || this.isBoth) && this.option) {
+ if (this.listboxHasVisualFocus) {
this.setValue(this.option.textContent);
+ this.close(true);
}
- this.close(true);
this.setVisualFocusCombobox();
flag = true;
break;
@@ -287,7 +287,7 @@ ComboboxAutocomplete.prototype.handleComboboxKeyDown = function (event) {
case "Down":
case "ArrowDown":
if (this.filteredOptions.length > 0) {
- if (this.listboxHasFocus || (this.isBoth && this.option)) {
+ if (this.listboxHasVisualFocus) {
this.setOption(this.getNextOption(this.option), true);
}
else {
@@ -305,7 +305,7 @@ ComboboxAutocomplete.prototype.handleComboboxKeyDown = function (event) {
case "ArrowUp":
if (this.hasOptions()) {
- if (this.listboxHasFocus || (this.isBoth && this.option)) {
+ if (this.listboxHasVisualFocus) {
this.setOption(this.getPreviousOption(this.option), true);
}
else {
@@ -335,7 +335,7 @@ ComboboxAutocomplete.prototype.handleComboboxKeyDown = function (event) {
case "Tab":
this.close(true);
- if (this.listboxHasFocus) {
+ if (this.listboxHasVisualFocus) {
if (this.option) {
this.setValue(this.option.textContent);
}
@@ -430,7 +430,7 @@ ComboboxAutocomplete.prototype.handleComboboxKeyUp = function (event) {
if (option.textComparison.indexOf(this.comboboxNode.value.toLowerCase()) === 0) {
this.option = option;
- if (this.isBoth || this.listboxHasFocus) {
+ if (this.isBoth || this.listboxHasVisualFocus) {
this.setCurrentOptionStyle(option);
if (this.isBoth && isPrintableCharacter(char)) {
this.setOption(option);
@@ -479,7 +479,7 @@ ComboboxAutocomplete.prototype.handleComboboxFocus = function (event) {
};
ComboboxAutocomplete.prototype.handleComboboxBlur = function (event) {
- this.comboboxHasFocus = false;
+ this.comboboxHasVisualFocus = false;
this.setCurrentOptionStyle(null);
this.removeVisualFocusAll();
setTimeout(this.close.bind(this, false), 300);
From 2468850333c65ca8733d250fc8bd388364dda370 Mon Sep 17 00:00:00 2001
From: Jon
Date: Mon, 2 Dec 2019 15:24:58 -0600
Subject: [PATCH 08/42] fixed bug in opening list with alt key pressed
---
examples/combobox/js/combobox-autocomplete.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/examples/combobox/js/combobox-autocomplete.js b/examples/combobox/js/combobox-autocomplete.js
index 069b2a553..2bc911750 100644
--- a/examples/combobox/js/combobox-autocomplete.js
+++ b/examples/combobox/js/combobox-autocomplete.js
@@ -294,9 +294,9 @@ ComboboxAutocomplete.prototype.handleComboboxKeyDown = function (event) {
this.open();
if (!altKey) {
this.setOption(this.firstOption, true);
+ this.setVisualFocusListbox();
}
}
- this.setVisualFocusListbox();
}
flag = true;
break;
@@ -312,9 +312,9 @@ ComboboxAutocomplete.prototype.handleComboboxKeyDown = function (event) {
this.open();
if (!altKey) {
this.setOption(this.lastOption, true);
+ this.setVisualFocusListbox();
}
}
- this.setVisualFocusListbox();
}
flag = true;
break;
From 98b0967d38528662cac2ffa0649b2d8082ab9a14 Mon Sep 17 00:00:00 2001
From: Jon
Date: Mon, 2 Dec 2019 15:54:35 -0600
Subject: [PATCH 09/42] fixed bug with enter key not updating aria-expanded
---
examples/combobox/js/combobox-autocomplete.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/examples/combobox/js/combobox-autocomplete.js b/examples/combobox/js/combobox-autocomplete.js
index 2bc911750..a840d2a7b 100644
--- a/examples/combobox/js/combobox-autocomplete.js
+++ b/examples/combobox/js/combobox-autocomplete.js
@@ -278,8 +278,8 @@ ComboboxAutocomplete.prototype.handleComboboxKeyDown = function (event) {
case "Enter":
if (this.listboxHasVisualFocus) {
this.setValue(this.option.textContent);
- this.close(true);
}
+ this.close(true);
this.setVisualFocusCombobox();
flag = true;
break;
From 52356756eebedf87676e750d0145726ee74ceaa8 Mon Sep 17 00:00:00 2001
From: Jon Gunderson
Date: Tue, 3 Dec 2019 14:00:19 -0600
Subject: [PATCH 10/42] fixed bugs in down arrow
---
examples/combobox/js/combobox-autocomplete.js | 10 +++++---
test/tests/combobox_autocomplete-both.js | 25 ++++++++++---------
2 files changed, 20 insertions(+), 15 deletions(-)
diff --git a/examples/combobox/js/combobox-autocomplete.js b/examples/combobox/js/combobox-autocomplete.js
index a840d2a7b..b49973e67 100644
--- a/examples/combobox/js/combobox-autocomplete.js
+++ b/examples/combobox/js/combobox-autocomplete.js
@@ -287,12 +287,16 @@ ComboboxAutocomplete.prototype.handleComboboxKeyDown = function (event) {
case "Down":
case "ArrowDown":
if (this.filteredOptions.length > 0) {
- if (this.listboxHasVisualFocus) {
- this.setOption(this.getNextOption(this.option), true);
+ if (altKey) {
+ this.open();
}
else {
this.open();
- if (!altKey) {
+ if (this.listboxHasVisualFocus || (this.isBoth && this.filteredOptions.length > 1)) {
+ this.setOption(this.getNextOption(this.option), true);
+ this.setVisualFocusListbox();
+ }
+ else {
this.setOption(this.firstOption, true);
this.setVisualFocusListbox();
}
diff --git a/test/tests/combobox_autocomplete-both.js b/test/tests/combobox_autocomplete-both.js
index bb40e8b4d..1b089d474 100644
--- a/test/tests/combobox_autocomplete-both.js
+++ b/test/tests/combobox_autocomplete-both.js
@@ -14,7 +14,8 @@ const ex = {
listboxSelector: '#ex1 [role="listbox"]',
optionsSelector: '#ex1 [role="option"]',
numAOptions: 5,
- numCharFirstAOption: 6
+ numCharFirstAOption: 7,
+ secondAOption: 'Alaska'
};
@@ -148,7 +149,6 @@ ariaTest('"aria-selected" attribute on options element', exampleFile, 'option-ar
await assertAttributeValues(t, ex.optionsSelector + ':nth-of-type(1)', 'aria-selected', 'true');
});
-
// Keys
ariaTest('Test down key press with focus on textbox',
@@ -175,6 +175,7 @@ ariaTest('Test down key press with focus on textbox',
});
+
ariaTest('Test down key press with focus on list',
exampleFile, 'listbox-key-down-arrow', async (t) => {
@@ -310,7 +311,7 @@ ariaTest('Test enter key press with focus on listbox',
.findElement(By.css(ex.textboxSelector))
.sendKeys('a', Key.ARROW_DOWN);
- // Get the value of the second option in the listbox
+ // Get the value of the first option in the listbox
const secondOption = await(await t.context.session.findElements(By.css(ex.optionsSelector)))[1]
.getText();
@@ -337,6 +338,7 @@ ariaTest('Test enter key press with focus on listbox',
});
+
ariaTest('Test single escape key press with focus on textbox',
exampleFile, 'textbox-key-escape', async (t) => {
t.plan(2);
@@ -401,8 +403,8 @@ ariaTest('Test escape key press with focus on textbox',
await t.context.session
.findElement(By.css(ex.textboxSelector))
.getAttribute('value'),
- 'Alaska',
- 'In listbox key press "ESCAPE" should result in first option in textbox'
+ ex.secondAOption,
+ 'In listbox key press "ESCAPE" should result in second option in textbox'
);
});
@@ -419,8 +421,8 @@ ariaTest('left arrow from focus on list puts focus on listbox and moves cursor r
await textbox.sendKeys(Key.ARROW_LEFT);
t.true(
- await confirmCursorIndex(t, ex.textboxSelector, ex.numCharFirstAOption - 1),
- 'Cursor should be at index ' + (ex.numCharFirstAOption - 1) + ' after one ARROW_LEFT key'
+ await confirmCursorIndex(t, ex.textboxSelector, ex.secondAOption.length - 1),
+ 'Cursor should be at index ' + (ex.secondAOption.length - 1) + ' after one ARROW_LEFT key'
);
t.is(
@@ -443,8 +445,8 @@ ariaTest('Right arrow from focus on list puts focus on listbox',
await textbox.sendKeys(Key.ARROW_RIGHT);
t.true(
- await confirmCursorIndex(t, ex.textboxSelector, ex.numCharFirstAOption),
- 'Cursor should be at index ' + ex.numCharFirstAOption + ' after one ARROW_RIGHT key'
+ await confirmCursorIndex(t, ex.textboxSelector, ex.secondAOption.length),
+ 'Cursor should be at index ' + ex.secondAOption.length + ' after one ARROW_RIGHT key'
);
t.is(
@@ -489,8 +491,8 @@ ariaTest('End from focus on list puts focus on listbox',
await textbox.sendKeys(Key.END);
t.true(
- await confirmCursorIndex(t, ex.textboxSelector, ex.numCharFirstAOption),
- 'Cursor should be at index ' + ex.numCharFirstAOption + ' after one ARROW_END key'
+ await confirmCursorIndex(t, ex.textboxSelector, ex.secondAOption.length),
+ 'Cursor should be at index ' + ex.secondAOption.length + ' after one ARROW_END key'
);
t.is(
@@ -534,4 +536,3 @@ ariaTest.failing('Expected behavior for all other standard single line editing k
t.plan(1);
t.fail();
});
-
From 245d30e20f8b524ab38fdc9b8947285b857eebf3 Mon Sep 17 00:00:00 2001
From: Jon Gunderson
Date: Tue, 3 Dec 2019 14:31:37 -0600
Subject: [PATCH 11/42] added documentation and tests for ALT Down Arrow
feature
---
.../combobox/combobox-autocomplete-both.html | 6 ++++++
.../combobox/combobox-autocomplete-list.html | 6 ++++++
.../combobox/combobox-autocomplete-none.html | 6 ++++++
test/tests/combobox_autocomplete-both.js | 19 +++++++++++++++++++
test/tests/combobox_autocomplete-list.js | 18 ++++++++++++++++++
test/tests/combobox_autocomplete-none.js | 19 +++++++++++++++++++
6 files changed, 74 insertions(+)
diff --git a/examples/combobox/combobox-autocomplete-both.html b/examples/combobox/combobox-autocomplete-both.html
index 533131802..a94a93b90 100644
--- a/examples/combobox/combobox-autocomplete-both.html
+++ b/examples/combobox/combobox-autocomplete-both.html
@@ -154,6 +154,12 @@ Textbox
+
+ Alt + Down Arrow
+
+ Opens the listbox but no option is selected and visual focus and DOM focus stays on the textbox.
+
+
Up Arrow
diff --git a/examples/combobox/combobox-autocomplete-list.html b/examples/combobox/combobox-autocomplete-list.html
index 026970d34..6e4358105 100644
--- a/examples/combobox/combobox-autocomplete-list.html
+++ b/examples/combobox/combobox-autocomplete-list.html
@@ -155,6 +155,12 @@ Textbox
+
+ Alt + Down Arrow
+
+ Opens the listbox but no option is selected and visual focus and DOM focus stays on the textbox.
+
+
Up Arrow
diff --git a/examples/combobox/combobox-autocomplete-none.html b/examples/combobox/combobox-autocomplete-none.html
index cb72c8141..326a6245c 100644
--- a/examples/combobox/combobox-autocomplete-none.html
+++ b/examples/combobox/combobox-autocomplete-none.html
@@ -109,6 +109,12 @@ Textbox
+
+ Alt + Down Arrow
+
+ Opens the listbox but no option is selected and visual focus and DOM focus stays on the textbox.
+
+
Up Arrow
diff --git a/test/tests/combobox_autocomplete-both.js b/test/tests/combobox_autocomplete-both.js
index 1b089d474..1839c6d3b 100644
--- a/test/tests/combobox_autocomplete-both.js
+++ b/test/tests/combobox_autocomplete-both.js
@@ -151,6 +151,25 @@ ariaTest('"aria-selected" attribute on options element', exampleFile, 'option-ar
// Keys
+ariaTest('Test alt + down key press with focus on textbox',
+ exampleFile, 'textbox-key-alt-down-arrow', async (t) => {
+
+ t.plan(1);
+
+ // Send ARROW_DOWN to the textbox
+ await t.context.session
+ .findElement(By.css(ex.textboxSelector))
+ .sendKeys(Key.ALT, Key.ARROW_DOWN);
+
+ // Check that the listbox is displayed
+ t.true(
+ await t.context.session.findElement(By.css(ex.listboxSelector)).isDisplayed(),
+ 'In example the list box should display after ALT + ARROW_DOWN keypress'
+ );
+
+ });
+
+
ariaTest('Test down key press with focus on textbox',
exampleFile, 'textbox-key-down-arrow', async (t) => {
diff --git a/test/tests/combobox_autocomplete-list.js b/test/tests/combobox_autocomplete-list.js
index b2cbf5d46..403643f0d 100644
--- a/test/tests/combobox_autocomplete-list.js
+++ b/test/tests/combobox_autocomplete-list.js
@@ -157,6 +157,24 @@ ariaTest('"aria-selected" attribute on options element', exampleFile, 'option-ar
// Keys
+ariaTest('Test alt + down key press with focus on textbox',
+ exampleFile, 'textbox-key-alt-down-arrow', async (t) => {
+
+ t.plan(1);
+
+ // Send ARROW_DOWN to the textbox
+ await t.context.session
+ .findElement(By.css(ex.textboxSelector))
+ .sendKeys(Key.ALT, Key.ARROW_DOWN);
+
+ // Check that the listbox is displayed
+ t.true(
+ await t.context.session.findElement(By.css(ex.listboxSelector)).isDisplayed(),
+ 'In example the list box should display after ALT + ARROW_DOWN keypress'
+ );
+
+ });
+
ariaTest('Test down key press with focus on textbox',
exampleFile, 'textbox-key-down-arrow', async (t) => {
diff --git a/test/tests/combobox_autocomplete-none.js b/test/tests/combobox_autocomplete-none.js
index 45df191db..7f6e3fbca 100644
--- a/test/tests/combobox_autocomplete-none.js
+++ b/test/tests/combobox_autocomplete-none.js
@@ -157,6 +157,25 @@ ariaTest('"aria-selected" attribute on options element', exampleFile, 'option-ar
// Keys
+ariaTest('Test alt + down key press with focus on textbox',
+ exampleFile, 'textbox-key-alt-down-arrow', async (t) => {
+
+ t.plan(1);
+
+ // Send ARROW_DOWN to the textbox
+ await t.context.session
+ .findElement(By.css(ex.textboxSelector))
+ .sendKeys(Key.ALT, Key.ARROW_DOWN);
+
+ // Check that the listbox is displayed
+ t.true(
+ await t.context.session.findElement(By.css(ex.listboxSelector)).isDisplayed(),
+ 'In example the list box should display after ALT + ARROW_DOWN keypress'
+ );
+
+ });
+
+
ariaTest('Test down key press with focus on textbox',
exampleFile, 'textbox-key-down-arrow', async (t) => {
From 565a0c1361376b4814806817f02bf994804073ba Mon Sep 17 00:00:00 2001
From: Jon Gunderson
Date: Wed, 4 Dec 2019 10:23:39 -0600
Subject: [PATCH 12/42] fixed some styling bugs
---
.../combobox/combobox-autocomplete-both.html | 4 ++--
.../combobox/css/combobox-autocomplete.css | 8 ++------
examples/combobox/js/combobox-autocomplete.js | 19 ++++++++++---------
3 files changed, 14 insertions(+), 17 deletions(-)
diff --git a/examples/combobox/combobox-autocomplete-both.html b/examples/combobox/combobox-autocomplete-both.html
index a94a93b90..0e54fe671 100644
--- a/examples/combobox/combobox-autocomplete-both.html
+++ b/examples/combobox/combobox-autocomplete-both.html
@@ -55,12 +55,12 @@ Example
-
+
-
+
diff --git a/examples/combobox/css/combobox-autocomplete.css b/examples/combobox/css/combobox-autocomplete.css
index 1461118ca..78d79cad7 100644
--- a/examples/combobox/css/combobox-autocomplete.css
+++ b/examples/combobox/css/combobox-autocomplete.css
@@ -16,6 +16,7 @@
margin: 0;
vertical-align: bottom;
border: 1px solid gray;
+ position: relative;
}
.combobox .group input {
@@ -30,11 +31,6 @@
width: 1.25rem;
border-left: none;
outline: none;
- position: relative;
-}
-
-.combobox .group button .arrow {
- top:;
}
.combobox .group button .down {
@@ -50,7 +46,7 @@
}
.combobox .group button.open .up {
- display: block;
+ display: inline-block;
}
.combobox .group.focus {
diff --git a/examples/combobox/js/combobox-autocomplete.js b/examples/combobox/js/combobox-autocomplete.js
index b49973e67..86dca9b64 100644
--- a/examples/combobox/js/combobox-autocomplete.js
+++ b/examples/combobox/js/combobox-autocomplete.js
@@ -69,7 +69,7 @@ ComboboxAutocomplete.prototype.init = function () {
}
- this.filterOptions('');
+ this.filterOptions();
// Open Button
@@ -95,7 +95,7 @@ ComboboxAutocomplete.prototype.setValue = function (value) {
this.comboboxNode.value = this.filter;
this.comboboxNode.setSelectionRange(this.filter.length,this.filter.length);
if (this.isList || this.isBoth) {
- this.filterOptions(this.filter, this.option);
+ this.filterOptions();
}
};
@@ -148,13 +148,10 @@ ComboboxAutocomplete.prototype.removeVisualFocusAll = function () {
// ComboboxAutocomplete Events
-ComboboxAutocomplete.prototype.filterOptions = function (filter, currentOption) {
+ComboboxAutocomplete.prototype.filterOptions = function () {
- if (typeof filter !== 'string') {
- filter = '';
- }
-
- filter = filter.toLowerCase();
+ var currentOption = this.option;
+ var filter = this.filter.toLowerCase();
this.filteredOptions = [];
this.listboxNode.innerHTML = '';
@@ -327,6 +324,8 @@ ComboboxAutocomplete.prototype.handleComboboxKeyDown = function (event) {
case "Escape":
if (this.isOpen()) {
this.close(true);
+ this.filter = this.comboboxNode.value;
+ this.filterOptions();
this.setVisualFocusCombobox();
}
else {
@@ -426,7 +425,7 @@ ComboboxAutocomplete.prototype.handleComboboxKeyUp = function (event) {
flag = true;
if (this.isList || this.isBoth) {
- option = this.filterOptions(this.filter, this.option);
+ option = this.filterOptions();
if (option) {
if (this.isClosed() && this.comboboxNode.value.length) {
this.open();
@@ -477,6 +476,8 @@ ComboboxAutocomplete.prototype.handleComboboxClick = function (event) {
};
ComboboxAutocomplete.prototype.handleComboboxFocus = function (event) {
+ this.filter = this.comboboxNode.value;
+ this.filterOptions();
this.setVisualFocusCombobox();
this.option = false;
this.setCurrentOptionStyle(null);
From 98f6d55117540936f3a5ae5c57852350be2e0ea7 Mon Sep 17 00:00:00 2001
From: Jon Gunderson
Date: Wed, 4 Dec 2019 10:40:22 -0600
Subject: [PATCH 13/42] using only one SVG image to show listbox state
---
.../combobox/combobox-autocomplete-both.html | 7 +------
.../combobox/combobox-autocomplete-list.html | 9 ++-------
.../combobox/combobox-autocomplete-none.html | 9 ++-------
examples/combobox/css/combobox-autocomplete.css | 16 ++--------------
4 files changed, 7 insertions(+), 34 deletions(-)
diff --git a/examples/combobox/combobox-autocomplete-both.html b/examples/combobox/combobox-autocomplete-both.html
index 0e54fe671..5fea8780e 100644
--- a/examples/combobox/combobox-autocomplete-both.html
+++ b/examples/combobox/combobox-autocomplete-both.html
@@ -53,12 +53,7 @@ Example
-
-
-
-
-
-
+
diff --git a/examples/combobox/combobox-autocomplete-list.html b/examples/combobox/combobox-autocomplete-list.html
index 6e4358105..a7cbb1df8 100644
--- a/examples/combobox/combobox-autocomplete-list.html
+++ b/examples/combobox/combobox-autocomplete-list.html
@@ -54,14 +54,9 @@ Example
-
+
-
-
-
-
-
-
+
diff --git a/examples/combobox/combobox-autocomplete-none.html b/examples/combobox/combobox-autocomplete-none.html
index 326a6245c..ababcb908 100644
--- a/examples/combobox/combobox-autocomplete-none.html
+++ b/examples/combobox/combobox-autocomplete-none.html
@@ -54,14 +54,9 @@ Example
aria-expanded="false"
aria-controls="cb1-listbox">
-
+
-
-
-
-
-
-
+
diff --git a/examples/combobox/css/combobox-autocomplete.css b/examples/combobox/css/combobox-autocomplete.css
index 78d79cad7..cbd6958fd 100644
--- a/examples/combobox/css/combobox-autocomplete.css
+++ b/examples/combobox/css/combobox-autocomplete.css
@@ -33,20 +33,8 @@
outline: none;
}
-.combobox .group button .down {
- display: block;
-}
-
-.combobox .group button .up {
- display: none;
-}
-
-.combobox .group button.open .down {
- display: none;
-}
-
-.combobox .group button.open .up {
- display: inline-block;
+.combobox .group button.open svg {
+ transform: rotate(180deg);
}
.combobox .group.focus {
From 4b8524fd9829975074897259f5b50c73a76a6cc1 Mon Sep 17 00:00:00 2001
From: Jon Gunderson
Date: Wed, 4 Dec 2019 10:47:41 -0600
Subject: [PATCH 14/42] updated CSS for styling listbox focus
---
examples/combobox/css/combobox-autocomplete.css | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/examples/combobox/css/combobox-autocomplete.css b/examples/combobox/css/combobox-autocomplete.css
index cbd6958fd..65054b840 100644
--- a/examples/combobox/css/combobox-autocomplete.css
+++ b/examples/combobox/css/combobox-autocomplete.css
@@ -67,9 +67,9 @@ ul[role="listbox"] {
ul[role="listbox"] li[role="option"] {
display: block;
- padding-left: 2px;
- padding-top: 2px;
- padding-bottom: 2px;
+ padding-left: 0.3em;
+ padding-top: 0.2em;
+ padding-bottom: 0.2em;
margin: 0;
}
@@ -79,8 +79,8 @@ ul[role="listbox"] li[role="option"] {
background-color: #DEF;
padding-top: 0;
padding-bottom: 0;
- border-top: 2px solid #8CCBF2;
- border-bottom: 2px solid #8CCBF2;
+ border-top: 0.2em solid #8CCBF2;
+ border-bottom: 0.2em solid #8CCBF2;
}
@media (forced-colors: active), (-ms-high-contrast: active) {
From 2abf21c8beb6a245a88be856b12c26f97091bf95 Mon Sep 17 00:00:00 2001
From: Jon Gunderson
Date: Wed, 4 Dec 2019 11:24:06 -0600
Subject: [PATCH 15/42] fixed scrolling issue in listbox
---
examples/combobox/css/combobox-autocomplete.css | 2 +-
examples/combobox/js/combobox-autocomplete.js | 7 ++++++-
2 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/examples/combobox/css/combobox-autocomplete.css b/examples/combobox/css/combobox-autocomplete.css
index 65054b840..2b8ddbead 100644
--- a/examples/combobox/css/combobox-autocomplete.css
+++ b/examples/combobox/css/combobox-autocomplete.css
@@ -58,7 +58,7 @@ ul[role="listbox"] {
box-sizing: border-box;
border: 1px gray solid;
border-top: none;
- max-height: 12em;
+ max-height: 11.4em;
width: 12rem;
overflow: scroll;
overflow-x: hidden;
diff --git a/examples/combobox/js/combobox-autocomplete.js b/examples/combobox/js/combobox-autocomplete.js
index 86dca9b64..aec4ae616 100644
--- a/examples/combobox/js/combobox-autocomplete.js
+++ b/examples/combobox/js/combobox-autocomplete.js
@@ -193,7 +193,12 @@ ComboboxAutocomplete.prototype.setCurrentOptionStyle = function (option) {
var opt = this.filteredOptions[i];
if (opt === option) {
opt.setAttribute('aria-selected', 'true');
- this.listboxNode.scrollTop = opt.offsetTop;
+ while ((this.listboxNode.scrollTop + this.listboxNode.offsetHeight) < (opt.offsetTop + opt.offsetHeight)) {
+ this.listboxNode.scrollTop = this.listboxNode.scrollTop + opt.offsetHeight;
+ }
+ while (this.listboxNode.scrollTop > (opt.offsetTop + 2)) {
+ this.listboxNode.scrollTop = this.listboxNode.scrollTop - opt.offsetHeight;
+ }
}
else {
opt.removeAttribute('aria-selected');
From 670bb244a1b7e7803192e8d0daebe0881eb420d9 Mon Sep 17 00:00:00 2001
From: Jon Gunderson
Date: Thu, 5 Dec 2019 14:20:59 -0600
Subject: [PATCH 16/42] adjusted position of svg image button
---
.../combobox/combobox-autocomplete-both.html | 4 ++--
.../combobox/combobox-autocomplete-list.html | 4 ++--
.../combobox/combobox-autocomplete-none.html | 4 ++--
examples/combobox/css/combobox-autocomplete.css | 16 ++++++++++++++--
4 files changed, 20 insertions(+), 8 deletions(-)
diff --git a/examples/combobox/combobox-autocomplete-both.html b/examples/combobox/combobox-autocomplete-both.html
index 5fea8780e..bca79e82e 100644
--- a/examples/combobox/combobox-autocomplete-both.html
+++ b/examples/combobox/combobox-autocomplete-both.html
@@ -54,8 +54,8 @@ Example
aria-expanded="false" aria-controls="lb1">
-
-
+
+
diff --git a/examples/combobox/combobox-autocomplete-list.html b/examples/combobox/combobox-autocomplete-list.html
index a7cbb1df8..0089a51a8 100644
--- a/examples/combobox/combobox-autocomplete-list.html
+++ b/examples/combobox/combobox-autocomplete-list.html
@@ -55,8 +55,8 @@ Example
aria-expanded="false" aria-controls="cb1-listbox">
-
-
+
+
diff --git a/examples/combobox/combobox-autocomplete-none.html b/examples/combobox/combobox-autocomplete-none.html
index ababcb908..44cbf7187 100644
--- a/examples/combobox/combobox-autocomplete-none.html
+++ b/examples/combobox/combobox-autocomplete-none.html
@@ -55,8 +55,8 @@ Example
aria-controls="cb1-listbox">
-
-
+
+
diff --git a/examples/combobox/css/combobox-autocomplete.css b/examples/combobox/css/combobox-autocomplete.css
index 2b8ddbead..3627964fd 100644
--- a/examples/combobox/css/combobox-autocomplete.css
+++ b/examples/combobox/css/combobox-autocomplete.css
@@ -34,7 +34,7 @@
}
.combobox .group button.open svg {
- transform: rotate(180deg);
+ transform: rotate(180deg) translate(0, -1px);
}
.combobox .group.focus {
@@ -42,10 +42,22 @@
outline-offset: 1px;
}
-.combobox .group.focus input {
+.combobox .group.focus input,
+.combobox .group.focus button {
background-color: #DEF;
}
+.combobox .group svg polygon {
+ fill: gray;
+ stroke: gray;
+}
+
+.combobox button.open svg polygon,
+.combobox .group.focus svg polygon {
+ fill: black;
+ stroke: black;
+}
+
ul[role="listbox"] {
margin: 0;
padding: 0;
From 6a418160cfabec06cc4587d8da8c2293aa63b829 Mon Sep 17 00:00:00 2001
From: Jon
Date: Tue, 21 Jan 2020 14:28:14 -0600
Subject: [PATCH 17/42] fixed onlcik bug not selecting options for list and
none options
---
examples/combobox/js/combobox-autocomplete.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/examples/combobox/js/combobox-autocomplete.js b/examples/combobox/js/combobox-autocomplete.js
index aec4ae616..a1757a854 100644
--- a/examples/combobox/js/combobox-autocomplete.js
+++ b/examples/combobox/js/combobox-autocomplete.js
@@ -108,9 +108,9 @@ ComboboxAutocomplete.prototype.setOption = function (option, flag) {
this.option = option;
this.setCurrentOptionStyle(this.option);
this.setActiveDescendant(this.option);
+ this.comboboxNode.value = this.option.textContent;
if (this.isBoth) {
- this.comboboxNode.value = this.option.textContent;
if (flag) {
this.comboboxNode.setSelectionRange(this.option.textContent.length,this.option.textContent.length);
}
From faedb8c0677236fb517a43a2f9c9637e16c34b3f Mon Sep 17 00:00:00 2001
From: Jon
Date: Wed, 22 Jan 2020 10:06:16 -0600
Subject: [PATCH 18/42] updated combobox test for autocomplete, list and none
---
test/tests/combobox_autocomplete-both.js | 8 ++++----
test/tests/combobox_autocomplete-list.js | 8 ++++----
test/tests/combobox_autocomplete-none.js | 8 ++++----
3 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/test/tests/combobox_autocomplete-both.js b/test/tests/combobox_autocomplete-both.js
index 1839c6d3b..2966f3a90 100644
--- a/test/tests/combobox_autocomplete-both.js
+++ b/test/tests/combobox_autocomplete-both.js
@@ -362,13 +362,13 @@ ariaTest('Test single escape key press with focus on textbox',
exampleFile, 'textbox-key-escape', async (t) => {
t.plan(2);
- // Send key "a", then key ESCAPE to the textbox
+ // Send key "a", then key ESCAPE once to the textbox
await t.context.session
.findElement(By.css(ex.textboxSelector))
.sendKeys('a', Key.ESCAPE);
- // Confirm the listbox is closed and the textboxed is clearedx
+ // Confirm the listbox is closed and the textbox is not cleared
await assertAttributeValues(t, ex.textboxSelector, 'aria-expanded', 'false');
t.is(
@@ -385,13 +385,13 @@ ariaTest('Test double escape key press with focus on textbox',
exampleFile, 'textbox-key-escape', async (t) => {
t.plan(2);
- // Send key "a", then key ESCAPE to the textbox
+ // Send key "a", then key ESCAPE twice to the textbox
await t.context.session
.findElement(By.css(ex.textboxSelector))
.sendKeys('a', Key.ESCAPE, Key.ESCAPE);
- // Confirm the listbox is closed and the textboxed is clearedx
+ // Confirm the listbox is closed and the textbox is cleared
await assertAttributeValues(t, ex.textboxSelector, 'aria-expanded', 'false');
t.is(
diff --git a/test/tests/combobox_autocomplete-list.js b/test/tests/combobox_autocomplete-list.js
index 403643f0d..464e47e81 100644
--- a/test/tests/combobox_autocomplete-list.js
+++ b/test/tests/combobox_autocomplete-list.js
@@ -366,13 +366,13 @@ ariaTest('Test single escape key press with focus on textbox',
exampleFile, 'textbox-key-escape', async (t) => {
t.plan(2);
- // Send key "a", then key ESCAPE to the textbox
+ // Send key "a", then key ESCAPE once to the textbox
await t.context.session
.findElement(By.css(ex.textboxSelector))
.sendKeys('a', Key.ESCAPE);
- // Confirm the listbox is closed and the textboxed is cleared
+ // Confirm the listbox is closed and the textbox is not cleared
await assertAttributeValues(t, ex.textboxSelector, 'aria-expanded', 'false');
t.is(
@@ -389,13 +389,13 @@ ariaTest('Test double escape key press with focus on textbox',
exampleFile, 'textbox-key-escape', async (t) => {
t.plan(2);
- // Send key "a", then key ESCAPE to the textbox
+ // Send key "a", then key ESCAPE twice to the textbox
await t.context.session
.findElement(By.css(ex.textboxSelector))
.sendKeys('a', Key.ESCAPE, Key.ESCAPE);
- // Confirm the listbox is closed and the textboxed is cleared
+ // Confirm the listbox is closed and the textbox is cleared
await assertAttributeValues(t, ex.textboxSelector, 'aria-expanded', 'false');
t.is(
diff --git a/test/tests/combobox_autocomplete-none.js b/test/tests/combobox_autocomplete-none.js
index 7f6e3fbca..f112ebac1 100644
--- a/test/tests/combobox_autocomplete-none.js
+++ b/test/tests/combobox_autocomplete-none.js
@@ -367,13 +367,13 @@ ariaTest('Test escape key press with focus on textbox',
t.plan(2);
// Send key "a" then key "ARROW_DOWN to put the focus on the listbox,
- // then key ESCAPE to the textbox
+ // then key ESCAPE once to the textbox
await t.context.session
.findElement(By.css(ex.textboxSelector))
.sendKeys('a', Key.ARROW_DOWN, Key.ESCAPE);
- // Confirm the listbox is closed and the textboxed is cleared
+ // Confirm the listbox is closed and the textbox is not cleared
await assertAttributeValues(t, ex.textboxSelector, 'aria-expanded', 'false');
t.is(
@@ -391,13 +391,13 @@ ariaTest('Test double escape key press with focus on textbox',
t.plan(2);
// Send key "a" then key "ARROW_DOWN to put the focus on the listbox,
- // then key ESCAPE to the textbox
+ // then key ESCAPE twice to the textbox
await t.context.session
.findElement(By.css(ex.textboxSelector))
.sendKeys('a', Key.ARROW_DOWN, Key.ESCAPE, Key.ESCAPE);
- // Confirm the listbox is closed and the textboxed is cleared
+ // Confirm the listbox is closed and the textbox is cleared
await assertAttributeValues(t, ex.textboxSelector, 'aria-expanded', 'false');
t.is(
From 11bdddd4964f7c21d1a57d5ab9eadefc6594e659 Mon Sep 17 00:00:00 2001
From: Jon
Date: Wed, 22 Jan 2020 10:38:22 -0600
Subject: [PATCH 19/42] fixed bug with onclick behavior and documented option
filtering as users type
---
examples/combobox/combobox-autocomplete-both.html | 1 +
examples/combobox/combobox-autocomplete-list.html | 1 +
examples/combobox/combobox-autocomplete-none.html | 1 +
examples/combobox/js/combobox-autocomplete.js | 4 ++--
4 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/examples/combobox/combobox-autocomplete-both.html b/examples/combobox/combobox-autocomplete-both.html
index bca79e82e..0c620f1b8 100644
--- a/examples/combobox/combobox-autocomplete-both.html
+++ b/examples/combobox/combobox-autocomplete-both.html
@@ -271,6 +271,7 @@ Listbox Popup
Moves visual focus to the textbox.
Types the character in the textbox.
+ Filters options based on matching letters in the textbox.
diff --git a/examples/combobox/combobox-autocomplete-list.html b/examples/combobox/combobox-autocomplete-list.html
index 0089a51a8..8bdd2eee6 100644
--- a/examples/combobox/combobox-autocomplete-list.html
+++ b/examples/combobox/combobox-autocomplete-list.html
@@ -267,6 +267,7 @@ Listbox Popup
Moves visual focus to the textbox.
Types the character in the textbox.
+ Filters options based on matching letters in the textbox.
diff --git a/examples/combobox/combobox-autocomplete-none.html b/examples/combobox/combobox-autocomplete-none.html
index 44cbf7187..eca11fed3 100644
--- a/examples/combobox/combobox-autocomplete-none.html
+++ b/examples/combobox/combobox-autocomplete-none.html
@@ -215,6 +215,7 @@ Listbox Popup
Moves visual focus to the textbox.
Types the character in the textbox.
+ Filters options based on matching letters in the textbox.
diff --git a/examples/combobox/js/combobox-autocomplete.js b/examples/combobox/js/combobox-autocomplete.js
index a1757a854..aa937868d 100644
--- a/examples/combobox/js/combobox-autocomplete.js
+++ b/examples/combobox/js/combobox-autocomplete.js
@@ -108,9 +108,9 @@ ComboboxAutocomplete.prototype.setOption = function (option, flag) {
this.option = option;
this.setCurrentOptionStyle(this.option);
this.setActiveDescendant(this.option);
- this.comboboxNode.value = this.option.textContent;
if (this.isBoth) {
+ this.comboboxNode.value = this.option.textContent;
if (flag) {
this.comboboxNode.setSelectionRange(this.option.textContent.length,this.option.textContent.length);
}
@@ -521,7 +521,7 @@ ComboboxAutocomplete.prototype.handleListboxMouseout = function (event) {
// Listbox Option Events
ComboboxAutocomplete.prototype.handleOptionClick = function (event) {
- this.setOption(event.target);
+ this.comboboxNode.value = event.target.textContent;
this.close(true);
};
From 0d352f4c52fa71bf9faf183fecc0243069a88ed1 Mon Sep 17 00:00:00 2001
From: Jon
Date: Wed, 22 Jan 2020 11:04:07 -0600
Subject: [PATCH 20/42] updated documentation abou filtering of options
---
examples/combobox/combobox-autocomplete-both.html | 2 +-
examples/combobox/combobox-autocomplete-list.html | 2 +-
examples/combobox/combobox-autocomplete-none.html | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/examples/combobox/combobox-autocomplete-both.html b/examples/combobox/combobox-autocomplete-both.html
index 0c620f1b8..f7a81f8d5 100644
--- a/examples/combobox/combobox-autocomplete-both.html
+++ b/examples/combobox/combobox-autocomplete-both.html
@@ -271,7 +271,7 @@ Listbox Popup
Moves visual focus to the textbox.
Types the character in the textbox.
- Filters options based on matching letters in the textbox.
+ Options in the listbox are filtered based on character in the textbox.
diff --git a/examples/combobox/combobox-autocomplete-list.html b/examples/combobox/combobox-autocomplete-list.html
index 8bdd2eee6..e375a74af 100644
--- a/examples/combobox/combobox-autocomplete-list.html
+++ b/examples/combobox/combobox-autocomplete-list.html
@@ -267,7 +267,7 @@ Listbox Popup
Moves visual focus to the textbox.
Types the character in the textbox.
- Filters options based on matching letters in the textbox.
+ Options in the listbox are filtered based on character in the textbox.
diff --git a/examples/combobox/combobox-autocomplete-none.html b/examples/combobox/combobox-autocomplete-none.html
index eca11fed3..51afb1939 100644
--- a/examples/combobox/combobox-autocomplete-none.html
+++ b/examples/combobox/combobox-autocomplete-none.html
@@ -215,7 +215,7 @@ Listbox Popup
Moves visual focus to the textbox.
Types the character in the textbox.
- Filters options based on matching letters in the textbox.
+ Options in the listbox are not filtered based on the characters in the textbox.
From 8f303a1f9a64d69555f25f19e3f4e82d984ddfc5 Mon Sep 17 00:00:00 2001
From: Carolyn MacLeod
Date: Wed, 22 Jan 2020 12:53:58 -0500
Subject: [PATCH 21/42] Typo: character -> characters
---
examples/combobox/combobox-autocomplete-both.html | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/examples/combobox/combobox-autocomplete-both.html b/examples/combobox/combobox-autocomplete-both.html
index f7a81f8d5..7a13536e8 100644
--- a/examples/combobox/combobox-autocomplete-both.html
+++ b/examples/combobox/combobox-autocomplete-both.html
@@ -271,7 +271,7 @@ Listbox Popup
Moves visual focus to the textbox.
Types the character in the textbox.
- Options in the listbox are filtered based on character in the textbox.
+ Options in the listbox are filtered based on characters in the textbox.
From 22575ec85985f42035a8b4b48f70c24d9af497d9 Mon Sep 17 00:00:00 2001
From: Carolyn MacLeod
Date: Wed, 22 Jan 2020 12:54:36 -0500
Subject: [PATCH 22/42] Typo: character -> characters
---
examples/combobox/combobox-autocomplete-list.html | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/examples/combobox/combobox-autocomplete-list.html b/examples/combobox/combobox-autocomplete-list.html
index e375a74af..08718a97b 100644
--- a/examples/combobox/combobox-autocomplete-list.html
+++ b/examples/combobox/combobox-autocomplete-list.html
@@ -267,7 +267,7 @@ Listbox Popup
Moves visual focus to the textbox.
Types the character in the textbox.
- Options in the listbox are filtered based on character in the textbox.
+ Options in the listbox are filtered based on characters in the textbox.
From 710f769553cb71d4962f6a078aa9f4e894097181 Mon Sep 17 00:00:00 2001
From: Jon
Date: Wed, 22 Jan 2020 13:14:49 -0600
Subject: [PATCH 23/42] fixed option filter bug with autocomplete=none
---
examples/combobox/js/combobox-autocomplete.js | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/examples/combobox/js/combobox-autocomplete.js b/examples/combobox/js/combobox-autocomplete.js
index aa937868d..b964d1bb2 100644
--- a/examples/combobox/js/combobox-autocomplete.js
+++ b/examples/combobox/js/combobox-autocomplete.js
@@ -94,9 +94,7 @@ ComboboxAutocomplete.prototype.setValue = function (value) {
this.filter = value;
this.comboboxNode.value = this.filter;
this.comboboxNode.setSelectionRange(this.filter.length,this.filter.length);
- if (this.isList || this.isBoth) {
- this.filterOptions();
- }
+ this.filterOptions();
};
ComboboxAutocomplete.prototype.setOption = function (option, flag) {
@@ -150,6 +148,11 @@ ComboboxAutocomplete.prototype.removeVisualFocusAll = function () {
ComboboxAutocomplete.prototype.filterOptions = function () {
+ // do not filter any options if autocomplete is none
+ if (this.isNone) {
+ this.filter = '';
+ }
+
var currentOption = this.option;
var filter = this.filter.toLowerCase();
From ad47b9d84cdea58fa9441dd77c1ac02216361a8b Mon Sep 17 00:00:00 2001
From: Jon
Date: Thu, 23 Jan 2020 09:30:31 -0600
Subject: [PATCH 24/42] improved description of when listbox opens
---
examples/combobox/combobox-autocomplete-none.html | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/examples/combobox/combobox-autocomplete-none.html b/examples/combobox/combobox-autocomplete-none.html
index 51afb1939..d81ea5271 100644
--- a/examples/combobox/combobox-autocomplete-none.html
+++ b/examples/combobox/combobox-autocomplete-none.html
@@ -32,7 +32,7 @@ Editable Combobox without Autocomplete Example
The design pattern describes four types of autocomplete behavior.
This example illustrates the autocomplete behavior known as no autocomplete .
The terms that appear in the listbox popup are not related to the string that is present in the textbox.
- In this implementation, The listbox popup is not automatically triggered; it is displayed only when the user opens it.
+ In this implementation, The listbox popup is not automatically triggered when the textbox receives focus; the list is opened when the user types a character into the textbox or through an explicit open command.
Similar examples include: