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