PageRenderTime 26ms CodeModel.GetById 36ms RepoModel.GetById 0ms app.codeStats 0ms

/src/switchable/tabs/aria.js

https://github.com/timeflows/kissy
JavaScript | 235 lines | 144 code | 37 blank | 54 comment | 32 complexity | 176c033e6ddb404b6d3bfb355bc68183 MD5 | raw file
  1. /**
  2. * Tabs aria support
  3. * @creator yiminghe@gmail.com
  4. */
  5. KISSY.add('switchable/tabs/aria', function(S, DOM, Event, Switchable, Aria, Tabs) {
  6. var KEY_PAGEUP = 33;
  7. var KEY_PAGEDOWN = 34;
  8. var KEY_END = 35;
  9. var KEY_HOME = 36;
  10. var KEY_LEFT = 37;
  11. var KEY_UP = 38;
  12. var KEY_RIGHT = 39;
  13. var KEY_DOWN = 40;
  14. var KEY_TAB = 9;
  15. // var KEY_SPACE = 32;
  16. // var KEY_BACKSPACE = 8;
  17. // var KEY_DELETE = 46;
  18. // var KEY_ENTER = 13;
  19. // var KEY_INSERT = 45;
  20. // var KEY_ESCAPE = 27;
  21. S.mix(Tabs.Config, {
  22. aria:true
  23. });
  24. Tabs.Plugins.push({
  25. name:"aria",
  26. init:function(self) {
  27. if (!self.config.aria) return;
  28. var triggers = self.triggers,
  29. activeIndex = self.activeIndex,
  30. panels = self.panels;
  31. var container = self.container;
  32. if (self.nav) {
  33. DOM.attr(self.nav, "role", "tablist");
  34. }
  35. var i = 0;
  36. S.each(triggers, function(trigger) {
  37. trigger.setAttribute("role", "tab");
  38. setTabIndex(trigger, activeIndex == i ? "0" : "-1");
  39. if (!trigger.id) {
  40. trigger.id = S.guid("ks-switchable");
  41. }
  42. i++;
  43. });
  44. i = 0;
  45. S.each(panels, function(panel) {
  46. var t = triggers[i];
  47. panel.setAttribute("role", "tabpanel");
  48. panel.setAttribute("aria-hidden", activeIndex == i ? "false" : "true");
  49. panel.setAttribute("aria-labelledby", t.id);
  50. i++;
  51. });
  52. self.on("switch", _tabSwitch, self);
  53. Event.on(container, "keydown", _tabKeydown, self);
  54. /**
  55. * prevent firefox native tab switch
  56. */
  57. Event.on(container, "keypress", _tabKeypress, self);
  58. }
  59. });
  60. var setTabIndex = Aria.setTabIndex;
  61. function _currentTabFromEvent(t) {
  62. var triggers = this.triggers,
  63. trigger;
  64. S.each(triggers, function(ct) {
  65. if (ct == t || DOM.contains(ct, t)) {
  66. trigger = ct;
  67. }
  68. });
  69. return trigger;
  70. }
  71. function _tabKeypress(e) {
  72. switch (e.keyCode) {
  73. case KEY_PAGEUP:
  74. case KEY_PAGEDOWN:
  75. if (e.ctrlKey && !e.altKey && !e.shiftKey) {
  76. e.halt();
  77. } // endif
  78. break;
  79. case KEY_TAB:
  80. if (e.ctrlKey && !e.altKey) {
  81. e.halt();
  82. } // endif
  83. break;
  84. }
  85. }
  86. var getDomEvent = Switchable.getDomEvent;
  87. /**
  88. * Keyboard commands for the Tab Panel
  89. * @param e
  90. */
  91. function _tabKeydown(e) {
  92. var t = e.target,self = this;
  93. var triggers = self.triggers;
  94. // Save information about a modifier key being pressed
  95. // May want to ignore keyboard events that include modifier keys
  96. var no_modifier_pressed_flag = !e.ctrlKey && !e.shiftKey && !e.altKey;
  97. var control_modifier_pressed_flag = e.ctrlKey && !e.shiftKey && !e.altKey;
  98. switch (e.keyCode) {
  99. case KEY_LEFT:
  100. case KEY_UP:
  101. if (_currentTabFromEvent.call(self, t)
  102. // 争渡读屏器阻止了上下左右键
  103. //&& no_modifier_pressed_flag
  104. ) {
  105. self.prev(getDomEvent(e));
  106. e.halt();
  107. } // endif
  108. break;
  109. case KEY_RIGHT:
  110. case KEY_DOWN:
  111. if (_currentTabFromEvent.call(self, t)
  112. //&& no_modifier_pressed_flag
  113. ) {
  114. self.next(getDomEvent(e));
  115. e.halt();
  116. } // endif
  117. break;
  118. case KEY_PAGEDOWN:
  119. if (control_modifier_pressed_flag) {
  120. e.halt();
  121. self.next(getDomEvent(e));
  122. }
  123. break;
  124. case KEY_PAGEUP:
  125. if (control_modifier_pressed_flag) {
  126. e.halt();
  127. self.prev(getDomEvent(e));
  128. }
  129. break;
  130. // case KEY_HOME:
  131. // if (no_modifier_pressed_flag) {
  132. // self.switchTo(0, undefined, getDomEvent(e));
  133. // e.halt();
  134. // }
  135. // break;
  136. // case KEY_END:
  137. // if (no_modifier_pressed_flag) {
  138. // self.switchTo(triggers.length - 1, undefined, getDomEvent(e));
  139. // e.halt();
  140. // }
  141. //
  142. // break;
  143. case KEY_TAB:
  144. if (e.ctrlKey && !e.altKey) {
  145. e.halt();
  146. if (e.shiftKey)
  147. self.prev(getDomEvent(e));
  148. else
  149. self.next(getDomEvent(e));
  150. }
  151. break;
  152. }
  153. }
  154. function _tabSwitch(ev) {
  155. var domEvent = !!(ev.originalEvent.target || ev.originalEvent.srcElement);
  156. var self = this;
  157. // 上一个激活 tab
  158. var lastActiveIndex = self.completedIndex;
  159. // 当前激活 tab
  160. var activeIndex = ev.currentIndex;
  161. if (lastActiveIndex == activeIndex) return;
  162. var lastTrigger = self.triggers[lastActiveIndex];
  163. var trigger = self.triggers[activeIndex];
  164. var lastPanel = self.panels[lastActiveIndex];
  165. var panel = self.panels[activeIndex];
  166. if (lastTrigger) {
  167. setTabIndex(lastTrigger, "-1");
  168. }
  169. setTabIndex(trigger, "0");
  170. // move focus to current trigger if invoked by dom event
  171. if (domEvent) {
  172. trigger.focus();
  173. }
  174. if (lastPanel) {
  175. lastPanel.setAttribute("aria-hidden", "true");
  176. }
  177. panel.setAttribute("aria-hidden", "false");
  178. }
  179. },
  180. {
  181. requires:["dom","event","../base","../aria","./base"]
  182. });
  183. /**
  184. * 2011-05-08 承玉:add support for aria & keydown
  185. * <h2>键盘快捷键</h2>
  186. <ul class="list">
  187. <li>左/上键:当焦点在标签时转到上一个标签
  188. <li>右/下键:当焦点在标签时转到下一个标签
  189. <li>Home: 当焦点在标签时转到第一个标签 -- 去除
  190. 输入框内 home 跳到输入框第一个字符前面 ,
  191. end 跳到输入框最后一个字符后面 ,
  192. 不应该拦截
  193. <li>End: 当焦点在标签时转到最后一个标签 -- 去除
  194. <li>Control + PgUp and Control + Shift + Tab: 当然焦点在容器内时转到当前标签上一个标签
  195. <li>Control + PgDn and Control + Tab: 当然焦点在容器内时转到当前标签下一个标签
  196. </ul>
  197. */