PageRenderTime 63ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/yuilib/3.9.1/build/tabview/tabview.js

https://bitbucket.org/kudutest/moodlegit
JavaScript | 418 lines | 298 code | 66 blank | 54 comment | 27 complexity | d1877fe2eb96431f08dd75e53e665c0f MD5 | raw file
  1. /* YUI 3.9.1 (build 5852) Copyright 2013 Yahoo! Inc. http://yuilibrary.com/license/ */
  2. YUI.add('tabview', function (Y, NAME) {
  3. /**
  4. * The TabView module
  5. *
  6. * @module tabview
  7. */
  8. var _queries = Y.TabviewBase._queries,
  9. _classNames = Y.TabviewBase._classNames,
  10. DOT = '.',
  11. /**
  12. * Provides a tabbed widget interface
  13. * @param config {Object} Object literal specifying tabview configuration properties.
  14. *
  15. * @class TabView
  16. * @constructor
  17. * @extends Widget
  18. * @uses WidgetParent
  19. */
  20. TabView = Y.Base.create('tabView', Y.Widget, [Y.WidgetParent], {
  21. _afterChildAdded: function() {
  22. this.get('contentBox').focusManager.refresh();
  23. },
  24. _defListNodeValueFn: function() {
  25. return Y.Node.create(TabView.LIST_TEMPLATE);
  26. },
  27. _defPanelNodeValueFn: function() {
  28. return Y.Node.create(TabView.PANEL_TEMPLATE);
  29. },
  30. _afterChildRemoved: function(e) { // update the selected tab when removed
  31. var i = e.index,
  32. selection = this.get('selection');
  33. if (!selection) { // select previous item if selection removed
  34. selection = this.item(i - 1) || this.item(0);
  35. if (selection) {
  36. selection.set('selected', 1);
  37. }
  38. }
  39. this.get('contentBox').focusManager.refresh();
  40. },
  41. _initAria: function() {
  42. var contentBox = this.get('contentBox'),
  43. tablist = contentBox.one(_queries.tabviewList);
  44. if (tablist) {
  45. tablist.setAttrs({
  46. //'aria-labelledby':
  47. role: 'tablist'
  48. });
  49. }
  50. },
  51. bindUI: function() {
  52. // Use the Node Focus Manager to add keyboard support:
  53. // Pressing the left and right arrow keys will move focus
  54. // among each of the tabs.
  55. this.get('contentBox').plug(Y.Plugin.NodeFocusManager, {
  56. descendants: DOT + _classNames.tabLabel,
  57. keys: { next: 'down:39', // Right arrow
  58. previous: 'down:37' }, // Left arrow
  59. circular: true
  60. });
  61. this.after('render', this._setDefSelection);
  62. this.after('addChild', this._afterChildAdded);
  63. this.after('removeChild', this._afterChildRemoved);
  64. },
  65. renderUI: function() {
  66. var contentBox = this.get('contentBox');
  67. this._renderListBox(contentBox);
  68. this._renderPanelBox(contentBox);
  69. this._childrenContainer = this.get('listNode');
  70. this._renderTabs(contentBox);
  71. },
  72. _setDefSelection: function() {
  73. // If no tab is selected, select the first tab.
  74. var selection = this.get('selection') || this.item(0);
  75. this.some(function(tab) {
  76. if (tab.get('selected')) {
  77. selection = tab;
  78. return true;
  79. }
  80. });
  81. if (selection) {
  82. // TODO: why both needed? (via widgetParent/Child)?
  83. this.set('selection', selection);
  84. selection.set('selected', 1);
  85. }
  86. },
  87. _renderListBox: function(contentBox) {
  88. var node = this.get('listNode');
  89. if (!node.inDoc()) {
  90. contentBox.append(node);
  91. }
  92. },
  93. _renderPanelBox: function(contentBox) {
  94. var node = this.get('panelNode');
  95. if (!node.inDoc()) {
  96. contentBox.append(node);
  97. }
  98. },
  99. _renderTabs: function(contentBox) {
  100. var tabs = contentBox.all(_queries.tab),
  101. panelNode = this.get('panelNode'),
  102. panels = (panelNode) ? this.get('panelNode').get('children') : null,
  103. tabview = this;
  104. if (tabs) { // add classNames and fill in Tab fields from markup when possible
  105. tabs.addClass(_classNames.tab);
  106. contentBox.all(_queries.tabLabel).addClass(_classNames.tabLabel);
  107. contentBox.all(_queries.tabPanel).addClass(_classNames.tabPanel);
  108. tabs.each(function(node, i) {
  109. var panelNode = (panels) ? panels.item(i) : null;
  110. tabview.add({
  111. boundingBox: node,
  112. contentBox: node.one(DOT + _classNames.tabLabel),
  113. panelNode: panelNode
  114. });
  115. });
  116. }
  117. }
  118. }, {
  119. LIST_TEMPLATE: '<ul class="' + _classNames.tabviewList + '"></ul>',
  120. PANEL_TEMPLATE: '<div class="' + _classNames.tabviewPanel + '"></div>',
  121. ATTRS: {
  122. defaultChildType: {
  123. value: 'Tab'
  124. },
  125. listNode: {
  126. setter: function(node) {
  127. node = Y.one(node);
  128. if (node) {
  129. node.addClass(_classNames.tabviewList);
  130. }
  131. return node;
  132. },
  133. valueFn: '_defListNodeValueFn'
  134. },
  135. panelNode: {
  136. setter: function(node) {
  137. node = Y.one(node);
  138. if (node) {
  139. node.addClass(_classNames.tabviewPanel);
  140. }
  141. return node;
  142. },
  143. valueFn: '_defPanelNodeValueFn'
  144. },
  145. tabIndex: {
  146. value: null
  147. //validator: '_validTabIndex'
  148. }
  149. },
  150. HTML_PARSER: {
  151. listNode: _queries.tabviewList,
  152. panelNode: _queries.tabviewPanel
  153. }
  154. });
  155. Y.TabView = TabView;
  156. var Lang = Y.Lang,
  157. _classNames = Y.TabviewBase._classNames;
  158. /**
  159. * Provides Tab instances for use with TabView
  160. * @param config {Object} Object literal specifying tabview configuration properties.
  161. *
  162. * @class Tab
  163. * @constructor
  164. * @extends Widget
  165. * @uses WidgetChild
  166. */
  167. Y.Tab = Y.Base.create('tab', Y.Widget, [Y.WidgetChild], {
  168. BOUNDING_TEMPLATE: '<li class="' + _classNames.tab + '"></li>',
  169. CONTENT_TEMPLATE: '<a class="' + _classNames.tabLabel + '"></a>',
  170. PANEL_TEMPLATE: '<div class="' + _classNames.tabPanel + '"></div>',
  171. _uiSetSelectedPanel: function(selected) {
  172. this.get('panelNode').toggleClass(_classNames.selectedPanel, selected);
  173. },
  174. _afterTabSelectedChange: function(event) {
  175. this._uiSetSelectedPanel(event.newVal);
  176. },
  177. _afterParentChange: function(e) {
  178. if (!e.newVal) {
  179. this._remove();
  180. } else {
  181. this._add();
  182. }
  183. },
  184. _initAria: function() {
  185. var anchor = this.get('contentBox'),
  186. id = anchor.get('id'),
  187. panel = this.get('panelNode');
  188. if (!id) {
  189. id = Y.guid();
  190. anchor.set('id', id);
  191. }
  192. // Apply the ARIA roles, states and properties to each tab
  193. anchor.set('role', 'tab');
  194. anchor.get('parentNode').set('role', 'presentation');
  195. // Apply the ARIA roles, states and properties to each panel
  196. panel.setAttrs({
  197. role: 'tabpanel',
  198. 'aria-labelledby': id
  199. });
  200. },
  201. syncUI: function() {
  202. this.set('label', this.get('label'));
  203. this.set('content', this.get('content'));
  204. this._uiSetSelectedPanel(this.get('selected'));
  205. },
  206. bindUI: function() {
  207. this.after('selectedChange', this._afterTabSelectedChange);
  208. this.after('parentChange', this._afterParentChange);
  209. },
  210. renderUI: function() {
  211. this._renderPanel();
  212. this._initAria();
  213. },
  214. _renderPanel: function() {
  215. this.get('parent').get('panelNode')
  216. .appendChild(this.get('panelNode'));
  217. },
  218. _add: function() {
  219. var parent = this.get('parent').get('contentBox'),
  220. list = parent.get('listNode'),
  221. panel = parent.get('panelNode');
  222. if (list) {
  223. list.appendChild(this.get('boundingBox'));
  224. }
  225. if (panel) {
  226. panel.appendChild(this.get('panelNode'));
  227. }
  228. },
  229. _remove: function() {
  230. this.get('boundingBox').remove();
  231. this.get('panelNode').remove();
  232. },
  233. _onActivate: function(e) {
  234. if (e.target === this) {
  235. // Prevent the browser from navigating to the URL specified by the
  236. // anchor's href attribute.
  237. e.domEvent.preventDefault();
  238. e.target.set('selected', 1);
  239. }
  240. },
  241. initializer: function() {
  242. this.publish(this.get('triggerEvent'), {
  243. defaultFn: this._onActivate
  244. });
  245. },
  246. _defLabelGetter: function() {
  247. return this.get('contentBox').getHTML();
  248. },
  249. _defLabelSetter: function(label) {
  250. var labelNode = this.get('contentBox');
  251. if (labelNode.getHTML() !== label) { // Avoid rewriting existing label.
  252. labelNode.setHTML(label);
  253. }
  254. return label;
  255. },
  256. _defContentSetter: function(content) {
  257. var panel = this.get('panelNode');
  258. if (panel.getHTML() !== content) { // Avoid rewriting existing content.
  259. panel.setHTML(content);
  260. }
  261. return content;
  262. },
  263. _defContentGetter: function() {
  264. return this.get('panelNode').getHTML();
  265. },
  266. // find panel by ID mapping from label href
  267. _defPanelNodeValueFn: function() {
  268. var href = this.get('contentBox').get('href') || '',
  269. parent = this.get('parent'),
  270. hashIndex = href.indexOf('#'),
  271. panel;
  272. href = href.substr(hashIndex);
  273. if (href.charAt(0) === '#') { // in-page nav, find by ID
  274. panel = Y.one(href);
  275. if (panel) {
  276. panel.addClass(_classNames.tabPanel);
  277. }
  278. }
  279. // use the one found by id, or else try matching indices
  280. if (!panel && parent) {
  281. panel = parent.get('panelNode')
  282. .get('children').item(this.get('index'));
  283. }
  284. if (!panel) { // create if none found
  285. panel = Y.Node.create(this.PANEL_TEMPLATE);
  286. }
  287. return panel;
  288. }
  289. }, {
  290. ATTRS: {
  291. /**
  292. * @attribute triggerEvent
  293. * @default "click"
  294. * @type String
  295. */
  296. triggerEvent: {
  297. value: 'click'
  298. },
  299. /**
  300. * @attribute label
  301. * @type HTML
  302. */
  303. label: {
  304. setter: '_defLabelSetter',
  305. getter: '_defLabelGetter'
  306. },
  307. /**
  308. * @attribute content
  309. * @type HTML
  310. */
  311. content: {
  312. setter: '_defContentSetter',
  313. getter: '_defContentGetter'
  314. },
  315. /**
  316. * @attribute panelNode
  317. * @type Y.Node
  318. */
  319. panelNode: {
  320. setter: function(node) {
  321. node = Y.one(node);
  322. if (node) {
  323. node.addClass(_classNames.tabPanel);
  324. }
  325. return node;
  326. },
  327. valueFn: '_defPanelNodeValueFn'
  328. },
  329. tabIndex: {
  330. value: null,
  331. validator: '_validTabIndex'
  332. }
  333. },
  334. HTML_PARSER: {
  335. selected: function() {
  336. var ret = (this.get('boundingBox').hasClass(_classNames.selectedTab)) ?
  337. 1 : 0;
  338. return ret;
  339. }
  340. }
  341. });
  342. }, '3.9.1', {
  343. "requires": [
  344. "widget",
  345. "widget-parent",
  346. "widget-child",
  347. "tabview-base",
  348. "node-pluginhost",
  349. "node-focusmanager"
  350. ],
  351. "skinnable": true
  352. });