Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

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