diff --git a/css/jquery.uls.lcd.css b/css/jquery.uls.lcd.css
index 4b04e13..ca0ca00 100644
--- a/css/jquery.uls.lcd.css
+++ b/css/jquery.uls.lcd.css
@@ -138,3 +138,7 @@
bottom: 0;
left: 0;
}
+
+.language-option--highlighted {
+ background-color: #eaeff7;
+}
diff --git a/src/jquery.uls.languagefilter.js b/src/jquery.uls.languagefilter.js
index c87c680..c9d8005 100644
--- a/src/jquery.uls.languagefilter.js
+++ b/src/jquery.uls.languagefilter.js
@@ -115,6 +115,14 @@
this.options.onSelect( query, e );
}
+ break;
+ case 38: // arrow up
+ this.options.lcd.navigateUp();
+
+ break;
+ case 40: // arrow down
+ this.options.lcd.navigateDown();
+
break;
}
},
@@ -163,6 +171,10 @@
results = [],
query = ( this.$element.val() || '' ).trim().toLowerCase();
+ // Reset the keyboard navigation index inside LanguageCategoryDisplay (lcd)
+ // before re-rendering the language options
+ this.options.lcd.resetNavigationIndex();
+
if ( query === '' ) {
this.options.lcd.setGroupByRegionOverride( null );
this.resultHandler( query, languages );
diff --git a/src/jquery.uls.lcd.js b/src/jquery.uls.lcd.js
index 47f0820..a6ce325 100644
--- a/src/jquery.uls.lcd.js
+++ b/src/jquery.uls.lcd.js
@@ -59,6 +59,11 @@
this.$cachedQuicklist = null;
this.groupByRegionOverride = null;
+ // The index of the language option that is currently visited using arrow key navigation
+ // Can take values in the [0, languageOptionListItemsLength - 1] range for top to bottom navigation,
+ // or in the [-1, -languageOptionListItemsLength + 1] range for bottom to top navigation.
+ this.navigationIndex = null
+
this.render();
this.listen();
}
@@ -66,6 +71,74 @@
LanguageCategoryDisplay.prototype = {
constructor: LanguageCategoryDisplay,
+ /**
+ * Returns a jQuery object containing a collection of all the
+ * language option
elements
+ * @return {jQuery}
+ */
+ getLanguageOptionListItems() {
+ return this.$element.find( 'li[data-code]' );
+ },
+
+ /**
+ * Increases the keyboard navigation index by one and applies a specific
+ * class to the n-th language option element (where n = navigation index)
+ * Currently used as event handler for the arrow down 'keydown' event, inside
+ * LanguageFilter.
+ */
+ navigateDown: function () {
+ // We support navigation starting both from the top and the bottom of the language list.
+ // The navigation should stop when the last language option is already highlighted (for top to bottom navigation).
+ // For top to bottom navigation, that happens when navigation index is equal to languageOptionListItemsLength - 1.
+ // For bottom to top navigation, that happens when navigation index is equal to -1.
+ if ( this.navigationIndex === this.getLanguageOptionListItems().length - 1 || this.navigationIndex === -1 ) {
+ return;
+ }
+
+ if ( this.navigationIndex === null ) {
+ this.navigationIndex = 0
+ } else {
+ this.navigationIndex++;
+ }
+ this.highlightLanguageOption();
+ },
+
+ /**
+ * Decreases the keyboard navigation index by one and applies a specific
+ * class to the n-th language option element (where n = navigation index)
+ * Currently used as event handler for the arrow down 'keydown' event, inside
+ * LanguageFilter.
+ */
+ navigateUp: function () {
+ // We support navigation starting both from the top and the bottom of the language list.
+ // The navigation should stop when the first language option is already highlighted (for bottom to top navigation).
+ // For top to bottom navigation, that happens when navigation index is equal to 0.
+ // For bottom to top navigation, that happens when navigation index is equal to -languageOptionListItemsLength + 1.
+ if ( this.navigationIndex === 0 || this.navigationIndex === -this.getLanguageOptionListItems().length + 1 ) {
+ return;
+ }
+
+ this.navigationIndex--
+ this.highlightLanguageOption();
+ },
+
+ /**
+ * Adds a specific class ("language-option--highlighted") only to the n-th
+ * language option element (where n = navigation index)
+ */
+ highlightLanguageOption() {
+ this.getLanguageOptionListItems().removeClass( 'language-option--highlighted' );
+ this.getLanguageOptionListItems().eq( this.navigationIndex ).addClass( 'language-option--highlighted' );
+ },
+
+ /**
+ * Resets the navigation index to null.
+ * Currently used inside LanguageFilter search method, to reset the keyboard navigation
+ */
+ resetNavigationIndex: function () {
+ this.navigationIndex = null;
+ },
+
/**
* Adds language to the language list.
*