📄 tabviewariaplugin.js
字号:
(function () { var Dom = YAHOO.util.Dom, Event = YAHOO.util.Event, UA = YAHOO.env.ua, Lang = YAHOO.lang, TabViewPrototype = YAHOO.widget.TabView.prototype, fnTabViewInitAttributes = TabViewPrototype.initAttributes, fnTabViewAddTab = TabViewPrototype.addTab, m_bUseARIA = (UA.gecko && UA.gecko >= 1.9) || (UA.ie && UA.ie >= 8), m_oTabListItems = {}, m_oTabIndexMap = {}, // Private constants for strings _A = "A", _ARIA_PREFIX = "aria-", _USE_ARIA = "usearia", _ELEMENT = "element", _ACTIVE_TAB = "activeTab", _ROLE = "role", _PRESENTATION = "presentation", _TAB = "tab", _HREF = "href", _CONTENT_EL = "contentEl", _TAB_PANEL = "tabpanel", _LABELLED_BY = "labelledby", _DESCRIBED_BY = "describedby", _ACTIVE_INDEX = "activeIndex", _TAB_LIST = "tablist", _KEY_PRESS = "keypress", _KEY_DOWN = "keydown", _ID = "id"; var setARIARole = function (element, role) { element.setAttribute(_ROLE, role); }; var setARIAProperty = function (element, property, value) { element.setAttribute((_ARIA_PREFIX + property), value); }; // Returns the <A> element representing each Tab in the TabView. var getTabAnchor = function (element) { var oTabAnchor; if (Dom.getAncestorByClassName(element, this.TAB_PARENT_CLASSNAME)) { if (element.nodeName.toUpperCase() === _A) { oTabAnchor = element; } else { oTabAnchor = Dom.getAncestorByTagName(element, _A); } } return oTabAnchor; }; var onKeyPress = function (event) { var oTabAnchor = getTabAnchor.call(this, Event.getTarget(event)), nCharCode = Event.getCharCode(event); if (oTabAnchor && (nCharCode === 13 || nCharCode === 32) && (oTabAnchor.parentNode !== this.get(_ACTIVE_TAB).get(_ELEMENT))) { this.set(_ACTIVE_INDEX, m_oTabIndexMap[this.get(_ID)][oTabAnchor.id]); } }; var onKeyDown = function (event) { var oCurrentTabAnchor = getTabAnchor.call(this, Event.getTarget(event)), aTabListItems = m_oTabListItems[this.get(_ID)], oCurrentTabLI, oNextTabLI, oNextTabAnchor, bArrowKeyPressed = false; if (oCurrentTabAnchor) { oCurrentTabLI = oCurrentTabAnchor.parentNode; switch (Event.getCharCode(event)) { case 37: // Left case 38: // Up oNextTabLI = Dom.getPreviousSibling(oCurrentTabLI); if (!oNextTabLI) { oNextTabLI = aTabListItems[aTabListItems.length-1]; } break; case 39: // Right case 40: // Down oNextTabLI = Dom.getNextSibling(oCurrentTabLI); if (!oNextTabLI) { oNextTabLI = aTabListItems[0]; } break; } if (oNextTabLI) { oNextTabAnchor = Dom.getFirstChild(oNextTabLI); oCurrentTabAnchor.tabIndex = -1; oNextTabAnchor.tabIndex = 0; oNextTabAnchor.focus(); } } }; Lang.augmentObject(TabViewPrototype, { addTab: function (tab, index) { fnTabViewAddTab.apply(this, arguments); var sID = this.get(_ID), aTabListItems = m_oTabListItems[sID], oTabEl, oTabAnchor, oTabContentEl, sTabId; if (this.get(_USE_ARIA)) { oTabEl = tab.get(_ELEMENT); oTabAnchor = Dom.getFirstChild(oTabEl); // Set the "tabIndex" attribute of each Tab's <A> element: The // "tabIndex" of the active Tab's <A> element is set to 0, the others to -1. // This improves the keyboard accessibility of the TabView by placing // only one Tab in the browser's tab index by default, allowing the user // to easily skip over the control when navigating the page with the tab key. oTabAnchor.tabIndex = (this.get(_ACTIVE_TAB) === tab) ? 0 : -1; // Create a map that links the ids of each Tab's <A> element to // the Tab's "index" attribute to make it possible to retrieve a Tab // instance reference by id. sTabId = oTabAnchor.id || Dom.generateId(oTabAnchor); m_oTabIndexMap[sID][sTabId] = this.getTabIndex(tab); // Need to set the "role" attribute of each Tab's <LI> element to // "presentation" so that Window-Eyes recognizes that each Tab belongs to // the same TabList. Without this, Window-Eyes will announce each Tab as // being "1 of 1" as opposed to "1 of 3," or "2 of 3". setARIARole(oTabEl, _PRESENTATION); setARIARole(oTabAnchor, _TAB); // JAWS announces the value of the "href" attribute of each Tab's <A> // element when it recieves focus. Ideally JAWS would allow the // applied "role" attribute of "tab" to take precedence over the default // role of the <A> element like NVDA and Window-Eyes do. It is // possible to fix this problem by removing the "href" attribute from // the <A>. oTabAnchor.removeAttribute(_HREF); oTabContentEl = tab.get(_CONTENT_EL); aTabListItems[aTabListItems.length] = oTabContentEl; setARIARole(oTabContentEl, _TAB_PANEL); // Set the "aria-labelledby" attribute for the TabPanel <LI> element to // the id of its corresponding Tab's <A> element. Doing so enables the // screen reader to announce the label of the Tab for each TabPanel when // the first element in a TabPanel receives focus, providing the user // with some context as to where they are. oTabContentEl.setAttribute(_LABELLED_BY, sTabId); } }, _setLabelledBy: function (id) { var oTabList = Dom.getFirstChild(this.get(_ELEMENT)); if (this.get(_USE_ARIA) && oTabList) { setARIAProperty(oTabList, _LABELLED_BY, id); } }, _setDescribedBy: function (id) { var oTabList = Dom.getFirstChild(this.get(_ELEMENT)); if (this.get(_USE_ARIA) && oTabList) { setARIAProperty(oTabList, _DESCRIBED_BY, id); } }, _setUseARIA: function (p_bUseARIA) { var oTabList, sID; if (p_bUseARIA) { sID = this.get(_ID); if (!sID) { this.set(_ID, Dom.generateId()); sID = this.get(_ID); } m_oTabListItems[sID] = []; m_oTabIndexMap[sID] = {}; oTabList = Dom.getFirstChild(this.get(_ELEMENT)); // Set the "role" attribute of the <UL> encapsulating the Tabs to "tablist" setARIARole(oTabList, _TAB_LIST); // Add a keypress listener that toggles the active Tab instance when the user // presses the Enter key. This is necessary because the removal of the "href" // attribute from each Tab's <A> element (for JAWS support) causes the // TabView's default Enter key support to stop working. Support for the Space // Bar is also added as an additional convience for the user. this.on(_KEY_PRESS, onKeyPress); // Keydown event listener for the TabView that provides support for // using the arrow keys to move focus between each Tab. this.on(_KEY_DOWN, onKeyDown); } }, initAttributes: function (p_oAttributes) { /** * @attribute usearia * @description Boolean indicating if use of the WAI-ARIA Roles and States should * be enabled. * @type Boolean * @default true for Firefox 3 and IE 8, false for all other browsers. */ this.setAttributeConfig(_USE_ARIA, { value: (p_oAttributes.usearia || m_bUseARIA), validator: Lang.isBoolean, writeOnce: true, method: this._setUseARIA }); /** * @attribute labelledby * @description String representing the id of the element that labels the TabView. * Maps directly to the <a href="http://www.w3.org/TR/wai-aria/#labelledby"> * <code>aria-labelledby</code></a> attribute. * @type String * @default null */ this.setAttributeConfig(_LABELLED_BY, { value: p_oAttributes.labelledby, validator: Lang.isString, method: this._setLabelledBy }); /** * @attribute describedby * @description String representing the id of the element that describes the TabView. * Maps directly to the <a href="http://www.w3.org/TR/wai-aria/#describedby"> * <code>aria-describedby</code></a> attribute. * @type String * @default null */ this.setAttributeConfig(_DESCRIBED_BY, { value: p_oAttributes.describedby, validator: Lang.isString, method: this._setDescribedBy }); fnTabViewInitAttributes.call(this, p_oAttributes); if (m_bUseARIA) { this.set(_USE_ARIA, true); } } }, "initAttributes", "_setUseARIA", "_setLabelledBy", "_setDescribedBy", "addTab");}());
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -