123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180 |
- /*
- * This content is licensed according to the W3C Software License at
- * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
- */
- var Menubar = function (domNode) {
- var elementChildren,
- msgPrefix = 'Menubar constructor argument menubarNode ';
- // Check whether menubarNode is a DOM element
- if (!domNode instanceof Element) {
- throw new TypeError(msgPrefix + 'is not a DOM Element.');
- }
- // Check whether menubarNode has descendant elements
- if (domNode.childElementCount === 0) {
- throw new Error(msgPrefix + 'has no element children.');
- }
- // Check whether menubarNode has A elements
- e = domNode.firstElementChild;
- while (e) {
- var menubarItem = e.firstElementChild;
- if (e && menubarItem && menubarItem.tagName !== 'A') {
- throw new Error(msgPrefix + 'has child elements are not A elements.');
- }
- e = e.nextElementSibling;
- }
- this.isMenubar = true;
- this.domNode = domNode;
- this.menubarItems = []; // See Menubar init method
- this.firstChars = []; // See Menubar init method
- this.firstItem = null; // See Menubar init method
- this.lastItem = null; // See Menubar init method
- this.hasFocus = false; // See MenubarItem handleFocus, handleBlur
- this.hasHover = false; // See Menubar handleMouseover, handleMouseout
- };
- /*
- * @method Menubar.prototype.init
- *
- * @desc
- * Adds ARIA role to the menubar node
- * Traverse menubar children for A elements to configure each A element as a ARIA menuitem
- * and populate menuitems array. Initialize firstItem and lastItem properties.
- */
- Menubar.prototype.init = function () {
- var menubarItem, childElement, menuElement, textContent, numItems;
- // Traverse the element children of menubarNode: configure each with
- // menuitem role behavior and store reference in menuitems array.
- elem = this.domNode.firstElementChild;
- while (elem) {
- var menuElement = elem.firstElementChild;
- if (elem && menuElement && menuElement.tagName === 'A') {
- menubarItem = new MenubarItem(menuElement, this);
- menubarItem.init();
- this.menubarItems.push(menubarItem);
- textContent = menuElement.textContent.trim();
- this.firstChars.push(textContent.substring(0, 1).toLowerCase());
- }
- elem = elem.nextElementSibling;
- }
- // Use populated menuitems array to initialize firstItem and lastItem.
- numItems = this.menubarItems.length;
- if (numItems > 0) {
- this.firstItem = this.menubarItems[ 0 ];
- this.lastItem = this.menubarItems[ numItems - 1 ];
- }
- this.firstItem.domNode.tabIndex = 0;
- };
- /* FOCUS MANAGEMENT METHODS */
- Menubar.prototype.setFocusToItem = function (newItem) {
- var flag = false;
- for (var i = 0; i < this.menubarItems.length; i++) {
- var mbi = this.menubarItems[i];
- if (mbi.domNode.tabIndex == 0) {
- flag = mbi.domNode.getAttribute('aria-expanded') === 'true';
- }
- mbi.domNode.tabIndex = -1;
- if (mbi.popupMenu) {
- mbi.popupMenu.close();
- }
- }
- newItem.domNode.focus();
- newItem.domNode.tabIndex = 0;
- if (flag && newItem.popupMenu) {
- newItem.popupMenu.open();
- }
- };
- Menubar.prototype.setFocusToFirstItem = function (flag) {
- this.setFocusToItem(this.firstItem);
- };
- Menubar.prototype.setFocusToLastItem = function (flag) {
- this.setFocusToItem(this.lastItem);
- };
- Menubar.prototype.setFocusToPreviousItem = function (currentItem) {
- var index;
- if (currentItem === this.firstItem) {
- newItem = this.lastItem;
- }
- else {
- index = this.menubarItems.indexOf(currentItem);
- newItem = this.menubarItems[ index - 1 ];
- }
- this.setFocusToItem(newItem);
- };
- Menubar.prototype.setFocusToNextItem = function (currentItem) {
- var index;
- if (currentItem === this.lastItem) {
- newItem = this.firstItem;
- }
- else {
- index = this.menubarItems.indexOf(currentItem);
- newItem = this.menubarItems[ index + 1 ];
- }
- this.setFocusToItem(newItem);
- };
- Menubar.prototype.setFocusByFirstCharacter = function (currentItem, char) {
- var start, index, char = char.toLowerCase();
- var flag = currentItem.domNode.getAttribute('aria-expanded') === 'true';
- // Get start index for search based on position of currentItem
- start = this.menubarItems.indexOf(currentItem) + 1;
- if (start === this.menubarItems.length) {
- start = 0;
- }
- // Check remaining slots in the menu
- index = this.getIndexFirstChars(start, char);
- // If not found in remaining slots, check from beginning
- if (index === -1) {
- index = this.getIndexFirstChars(0, char);
- }
- // If match was found...
- if (index > -1) {
- this.setFocusToItem(this.menubarItems[ index ]);
- }
- };
- Menubar.prototype.getIndexFirstChars = function (startIndex, char) {
- for (var i = startIndex; i < this.firstChars.length; i++) {
- if (char === this.firstChars[ i ]) {
- return i;
- }
- }
- return -1;
- };
|