Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
YUI.add('dom-base', function (Y, NAME) {
2
 
3
/**
4
* @for DOM
5
* @module dom
6
*/
7
var documentElement = Y.config.doc.documentElement,
8
    Y_DOM = Y.DOM,
9
    TAG_NAME = 'tagName',
10
    OWNER_DOCUMENT = 'ownerDocument',
11
    EMPTY_STRING = '',
12
    addFeature = Y.Features.add,
13
    testFeature = Y.Features.test;
14
 
15
Y.mix(Y_DOM, {
16
    /**
17
     * Returns the text content of the HTMLElement.
18
     * @method getText
19
     * @param {HTMLElement} element The html element.
20
     * @return {String} The text content of the element (includes text of any descending elements).
21
     */
22
    getText: (documentElement.textContent !== undefined) ?
23
        function(element) {
24
            var ret = '';
25
            if (element) {
26
                ret = element.textContent;
27
            }
28
            return ret || '';
29
        } : function(element) {
30
            var ret = '';
31
            if (element) {
32
                ret = element.innerText || element.nodeValue; // might be a textNode
33
            }
34
            return ret || '';
35
        },
36
 
37
    /**
38
     * Sets the text content of the HTMLElement.
39
     * @method setText
40
     * @param {HTMLElement} element The html element.
41
     * @param {String} content The content to add.
42
     */
43
    setText: (documentElement.textContent !== undefined) ?
44
        function(element, content) {
45
            if (element) {
46
                element.textContent = content;
47
            }
48
        } : function(element, content) {
49
            if ('innerText' in element) {
50
                element.innerText = content;
51
            } else if ('nodeValue' in element) {
52
                element.nodeValue = content;
53
            }
54
    },
55
 
56
    CUSTOM_ATTRIBUTES: (!documentElement.hasAttribute) ? { // IE < 8
57
        'for': 'htmlFor',
58
        'class': 'className'
59
    } : { // w3c
60
        'htmlFor': 'for',
61
        'className': 'class'
62
    },
63
 
64
    /**
65
     * Provides a normalized attribute interface.
66
     * @method setAttribute
67
     * @param {HTMLElement} el The target element for the attribute.
68
     * @param {String} attr The attribute to set.
69
     * @param {String} val The value of the attribute.
70
     */
71
    setAttribute: function(el, attr, val, ieAttr) {
72
        if (el && attr && el.setAttribute) {
73
            attr = Y_DOM.CUSTOM_ATTRIBUTES[attr] || attr;
74
            el.setAttribute(attr, val, ieAttr);
75
        }
76
    },
77
 
78
 
79
    /**
80
     * Provides a normalized attribute interface.
81
     * @method getAttribute
82
     * @param {HTMLElement} el The target element for the attribute.
83
     * @param {String} attr The attribute to get.
84
     * @return {String} The current value of the attribute.
85
     */
86
    getAttribute: function(el, attr, ieAttr) {
87
        ieAttr = (ieAttr !== undefined) ? ieAttr : 2;
88
        var ret = '';
89
        if (el && attr && el.getAttribute) {
90
            attr = Y_DOM.CUSTOM_ATTRIBUTES[attr] || attr;
91
            // BUTTON value issue for IE < 8
92
            ret = (el.tagName === "BUTTON" && attr === 'value') ? Y_DOM.getValue(el) : el.getAttribute(attr, ieAttr);
93
 
94
            if (ret === null) {
95
                ret = ''; // per DOM spec
96
            }
97
        }
98
        return ret;
99
    },
100
 
101
    VALUE_SETTERS: {},
102
 
103
    VALUE_GETTERS: {},
104
 
105
    getValue: function(node) {
106
        var ret = '', // TODO: return null?
107
            getter;
108
 
109
        if (node && node[TAG_NAME]) {
110
            getter = Y_DOM.VALUE_GETTERS[node[TAG_NAME].toLowerCase()];
111
 
112
            if (getter) {
113
                ret = getter(node);
114
            } else {
115
                ret = node.value;
116
            }
117
        }
118
 
119
        // workaround for IE8 JSON stringify bug
120
        // which converts empty string values to null
121
        if (ret === EMPTY_STRING) {
122
            ret = EMPTY_STRING; // for real
123
        }
124
 
125
        return (typeof ret === 'string') ? ret : '';
126
    },
127
 
128
    setValue: function(node, val) {
129
        var setter;
130
 
131
        if (node && node[TAG_NAME]) {
132
            setter = Y_DOM.VALUE_SETTERS[node[TAG_NAME].toLowerCase()];
133
            val = (val === null) ? '' : val;
134
            if (setter) {
135
                setter(node, val);
136
            } else {
137
                node.value = val;
138
            }
139
        }
140
    },
141
 
142
    creators: {}
143
});
144
 
145
addFeature('value-set', 'select', {
146
    test: function() {
147
        var node = Y.config.doc.createElement('select');
148
        node.innerHTML = '<option>1</option><option>2</option>';
149
        node.value = '2';
150
        return (node.value && node.value === '2');
151
    }
152
});
153
 
154
if (!testFeature('value-set', 'select')) {
155
    Y_DOM.VALUE_SETTERS.select = function(node, val) {
156
        for (var i = 0, options = node.getElementsByTagName('option'), option;
157
                option = options[i++];) {
158
            if (Y_DOM.getValue(option) === val) {
159
                option.selected = true;
160
                //Y_DOM.setAttribute(option, 'selected', 'selected');
161
                break;
162
            }
163
        }
164
    };
165
}
166
 
167
Y.mix(Y_DOM.VALUE_GETTERS, {
168
    button: function(node) {
169
        return (node.attributes && node.attributes.value) ? node.attributes.value.value : '';
170
    }
171
});
172
 
173
Y.mix(Y_DOM.VALUE_SETTERS, {
174
    // IE: node.value changes the button text, which should be handled via innerHTML
175
    button: function(node, val) {
176
        var attr = node.attributes.value;
177
        if (!attr) {
178
            attr = node[OWNER_DOCUMENT].createAttribute('value');
179
            node.setAttributeNode(attr);
180
        }
181
 
182
        attr.value = val;
183
    }
184
});
185
 
186
 
187
Y.mix(Y_DOM.VALUE_GETTERS, {
188
    option: function(node) {
189
        var attrs = node.attributes;
190
        return (attrs.value && attrs.value.specified) ? node.value : node.text;
191
    },
192
 
193
    select: function(node) {
194
        var val = node.value,
195
            options = node.options;
196
 
197
        if (options && options.length) {
198
            // TODO: implement multipe select
199
            if (node.multiple) {
200
            } else if (node.selectedIndex > -1) {
201
                val = Y_DOM.getValue(options[node.selectedIndex]);
202
            }
203
        }
204
 
205
        return val;
206
    }
207
});
208
var addClass, hasClass, removeClass;
209
 
210
Y.mix(Y.DOM, {
211
    /**
212
     * Determines whether a DOM element has the given className.
213
     * @method hasClass
214
     * @for DOM
215
     * @param {HTMLElement} element The DOM element.
216
     * @param {String} className the class name to search for
217
     * @return {Boolean} Whether or not the element has the given class.
218
     */
219
    hasClass: function(node, className) {
220
        var re = Y.DOM._getRegExp('(?:^|\\s+)' + className + '(?:\\s+|$)');
221
        return re.test(node.className);
222
    },
223
 
224
    /**
225
     * Adds a class name to a given DOM element.
226
     * @method addClass
227
     * @for DOM
228
     * @param {HTMLElement} element The DOM element.
229
     * @param {String} className the class name to add to the class attribute
230
     */
231
    addClass: function(node, className) {
232
        if (!Y.DOM.hasClass(node, className)) { // skip if already present
233
            node.className = Y.Lang.trim([node.className, className].join(' '));
234
        }
235
    },
236
 
237
    /**
238
     * Removes a class name from a given element.
239
     * @method removeClass
240
     * @for DOM
241
     * @param {HTMLElement} element The DOM element.
242
     * @param {String} className the class name to remove from the class attribute
243
     */
244
    removeClass: function(node, className) {
245
        if (className && hasClass(node, className)) {
246
            node.className = Y.Lang.trim(node.className.replace(Y.DOM._getRegExp('(?:^|\\s+)' +
247
                            className + '(?:\\s+|$)'), ' '));
248
 
249
            if ( hasClass(node, className) ) { // in case of multiple adjacent
250
                removeClass(node, className);
251
            }
252
        }
253
    },
254
 
255
    /**
256
     * Replace a class with another class for a given element.
257
     * If no oldClassName is present, the newClassName is simply added.
258
     * @method replaceClass
259
     * @for DOM
260
     * @param {HTMLElement} element The DOM element
261
     * @param {String} oldClassName the class name to be replaced
262
     * @param {String} newClassName the class name that will be replacing the old class name
263
     */
264
    replaceClass: function(node, oldC, newC) {
265
        removeClass(node, oldC); // remove first in case oldC === newC
266
        addClass(node, newC);
267
    },
268
 
269
    /**
270
     * If the className exists on the node it is removed, if it doesn't exist it is added.
271
     * @method toggleClass
272
     * @for DOM
273
     * @param {HTMLElement} element The DOM element
274
     * @param {String} className the class name to be toggled
275
     * @param {Boolean} addClass optional boolean to indicate whether class
276
     * should be added or removed regardless of current state
277
     */
278
    toggleClass: function(node, className, force) {
279
        var add = (force !== undefined) ? force :
280
                !(hasClass(node, className));
281
 
282
        if (add) {
283
            addClass(node, className);
284
        } else {
285
            removeClass(node, className);
286
        }
287
    }
288
});
289
 
290
hasClass = Y.DOM.hasClass;
291
removeClass = Y.DOM.removeClass;
292
addClass = Y.DOM.addClass;
293
 
294
var re_tag = /<([a-z]+)/i,
295
 
296
    Y_DOM = Y.DOM,
297
 
298
    addFeature = Y.Features.add,
299
    testFeature = Y.Features.test,
300
 
301
    creators = {},
302
 
303
    createFromDIV = function(html, tag) {
304
        var div = Y.config.doc.createElement('div'),
305
            ret = true;
306
 
307
        div.innerHTML = html;
308
        if (!div.firstChild || div.firstChild.tagName !== tag.toUpperCase()) {
309
            ret = false;
310
        }
311
 
312
        return ret;
313
    },
314
 
315
    re_tbody = /(?:\/(?:thead|tfoot|tbody|caption|col|colgroup)>)+\s*<tbody/,
316
 
317
    TABLE_OPEN = '<table>',
318
    TABLE_CLOSE = '</table>',
319
 
320
    selectedIndex;
321
 
322
Y.mix(Y.DOM, {
323
    _fragClones: {},
324
 
325
    _create: function(html, doc, tag) {
326
        tag = tag || 'div';
327
 
328
        var frag = Y_DOM._fragClones[tag];
329
        if (frag) {
330
            frag = frag.cloneNode(false);
331
        } else {
332
            frag = Y_DOM._fragClones[tag] = doc.createElement(tag);
333
        }
334
        frag.innerHTML = html;
335
        return frag;
336
    },
337
 
338
    _children: function(node, tag) {
339
            var i = 0,
340
            children = node.children,
341
            childNodes,
342
            hasComments,
343
            child;
344
 
345
        if (children && children.tags) { // use tags filter when possible
346
            if (tag) {
347
                children = node.children.tags(tag);
348
            } else { // IE leaks comments into children
349
                hasComments = children.tags('!').length;
350
            }
351
        }
352
 
353
        if (!children || (!children.tags && tag) || hasComments) {
354
            childNodes = children || node.childNodes;
355
            children = [];
356
            while ((child = childNodes[i++])) {
357
                if (child.nodeType === 1) {
358
                    if (!tag || tag === child.tagName) {
359
                        children.push(child);
360
                    }
361
                }
362
            }
363
        }
364
 
365
        return children || [];
366
    },
367
 
368
    /**
369
     * Creates a new dom node using the provided markup string.
370
     * @method create
371
     * @param {String} html The markup used to create the element
372
     * @param {HTMLDocument} doc An optional document context
373
     * @return {HTMLElement|DocumentFragment} returns a single HTMLElement
374
     * when creating one node, and a documentFragment when creating
375
     * multiple nodes.
376
     */
377
    create: function(html, doc) {
378
        if (typeof html === 'string') {
379
            html = Y.Lang.trim(html); // match IE which trims whitespace from innerHTML
380
 
381
        }
382
 
383
        doc = doc || Y.config.doc;
384
        var m = re_tag.exec(html),
385
            create = Y_DOM._create,
386
            custom = creators,
387
            ret = null,
388
            creator, tag, node, nodes;
389
 
390
        if (html != undefined) { // not undefined or null
391
            if (m && m[1]) {
392
                creator = custom[m[1].toLowerCase()];
393
                if (typeof creator === 'function') {
394
                    create = creator;
395
                } else {
396
                    tag = creator;
397
                }
398
            }
399
 
400
            node = create(html, doc, tag);
401
            nodes = node.childNodes;
402
 
403
            if (nodes.length === 1) { // return single node, breaking parentNode ref from "fragment"
404
                ret = node.removeChild(nodes[0]);
405
            } else if (nodes[0] && nodes[0].className === 'yui3-big-dummy') { // using dummy node to preserve some attributes (e.g. OPTION not selected)
406
                selectedIndex = node.selectedIndex;
407
 
408
                if (nodes.length === 2) {
409
                    ret = nodes[0].nextSibling;
410
                } else {
411
                    node.removeChild(nodes[0]);
412
                    ret = Y_DOM._nl2frag(nodes, doc);
413
                }
414
            } else { // return multiple nodes as a fragment
415
                 ret = Y_DOM._nl2frag(nodes, doc);
416
            }
417
 
418
        }
419
 
420
        return ret;
421
    },
422
 
423
    _nl2frag: function(nodes, doc) {
424
        var ret = null,
425
            i, len;
426
 
427
        if (nodes && (nodes.push || nodes.item) && nodes[0]) {
428
            doc = doc || nodes[0].ownerDocument;
429
            ret = doc.createDocumentFragment();
430
 
431
            if (nodes.item) { // convert live list to static array
432
                nodes = Y.Array(nodes, 0, true);
433
            }
434
 
435
            for (i = 0, len = nodes.length; i < len; i++) {
436
                ret.appendChild(nodes[i]);
437
            }
438
        } // else inline with log for minification
439
        return ret;
440
    },
441
 
442
    /**
443
     * Inserts content in a node at the given location
444
     * @method addHTML
445
     * @param {HTMLElement} node The node to insert into
446
     * @param {HTMLElement | Array | HTMLCollection} content The content to be inserted
447
     * @param {HTMLElement} where Where to insert the content
448
     * If no "where" is given, content is appended to the node
449
     * Possible values for "where"
450
     * <dl>
451
     * <dt>HTMLElement</dt>
452
     * <dd>The element to insert before</dd>
453
     * <dt>"replace"</dt>
454
     * <dd>Replaces the existing HTML</dd>
455
     * <dt>"before"</dt>
456
     * <dd>Inserts before the existing HTML</dd>
457
     * <dt>"before"</dt>
458
     * <dd>Inserts content before the node</dd>
459
     * <dt>"after"</dt>
460
     * <dd>Inserts content after the node</dd>
461
     * </dl>
462
     */
463
    addHTML: function(node, content, where) {
464
        var nodeParent = node.parentNode,
465
            i = 0,
466
            item,
467
            ret = content,
468
            newNode;
469
 
470
 
471
        if (content != undefined) { // not null or undefined (maybe 0)
472
            if (content.nodeType) { // DOM node, just add it
473
                newNode = content;
474
            } else if (typeof content == 'string' || typeof content == 'number') {
475
                ret = newNode = Y_DOM.create(content);
476
            } else if (content[0] && content[0].nodeType) { // array or collection
477
                newNode = Y.config.doc.createDocumentFragment();
478
                while ((item = content[i++])) {
479
                    newNode.appendChild(item); // append to fragment for insertion
480
                }
481
            }
482
        }
483
 
484
        if (where) {
485
            if (newNode && where.parentNode) { // insert regardless of relationship to node
486
                where.parentNode.insertBefore(newNode, where);
487
            } else {
488
                switch (where) {
489
                    case 'replace':
490
                        while (node.firstChild) {
491
                            node.removeChild(node.firstChild);
492
                        }
493
                        if (newNode) { // allow empty content to clear node
494
                            node.appendChild(newNode);
495
                        }
496
                        break;
497
                    case 'before':
498
                        if (newNode) {
499
                            nodeParent.insertBefore(newNode, node);
500
                        }
501
                        break;
502
                    case 'after':
503
                        if (newNode) {
504
                            if (node.nextSibling) { // IE errors if refNode is null
505
                                nodeParent.insertBefore(newNode, node.nextSibling);
506
                            } else {
507
                                nodeParent.appendChild(newNode);
508
                            }
509
                        }
510
                        break;
511
                    default:
512
                        if (newNode) {
513
                            node.appendChild(newNode);
514
                        }
515
                }
516
            }
517
        } else if (newNode) {
518
            node.appendChild(newNode);
519
        }
520
 
521
        // `select` elements are the only elements with `selectedIndex`.
522
        // Don't grab the dummy `option` element's `selectedIndex`.
523
        if (node.nodeName == "SELECT" && selectedIndex > 0) {
524
            node.selectedIndex = selectedIndex - 1;
525
        }
526
 
527
        return ret;
528
    },
529
 
530
    wrap: function(node, html) {
531
        var parent = (html && html.nodeType) ? html : Y.DOM.create(html),
532
            nodes = parent.getElementsByTagName('*');
533
 
534
        if (nodes.length) {
535
            parent = nodes[nodes.length - 1];
536
        }
537
 
538
        if (node.parentNode) {
539
            node.parentNode.replaceChild(parent, node);
540
        }
541
        parent.appendChild(node);
542
    },
543
 
544
    unwrap: function(node) {
545
        var parent = node.parentNode,
546
            lastChild = parent.lastChild,
547
            next = node,
548
            grandparent;
549
 
550
        if (parent) {
551
            grandparent = parent.parentNode;
552
            if (grandparent) {
553
                node = parent.firstChild;
554
                while (node !== lastChild) {
555
                    next = node.nextSibling;
556
                    grandparent.insertBefore(node, parent);
557
                    node = next;
558
                }
559
                grandparent.replaceChild(lastChild, parent);
560
            } else {
561
                parent.removeChild(node);
562
            }
563
        }
564
    }
565
});
566
 
567
addFeature('innerhtml', 'table', {
568
    test: function() {
569
        var node = Y.config.doc.createElement('table');
570
        try {
571
            node.innerHTML = '<tbody></tbody>';
572
        } catch(e) {
573
            return false;
574
        }
575
        return (node.firstChild && node.firstChild.nodeName === 'TBODY');
576
    }
577
});
578
 
579
addFeature('innerhtml-div', 'tr', {
580
    test: function() {
581
        return createFromDIV('<tr></tr>', 'tr');
582
    }
583
});
584
 
585
addFeature('innerhtml-div', 'script', {
586
    test: function() {
587
        return createFromDIV('<script></script>', 'script');
588
    }
589
});
590
 
591
if (!testFeature('innerhtml', 'table')) {
592
    // TODO: thead/tfoot with nested tbody
593
        // IE adds TBODY when creating TABLE elements (which may share this impl)
594
    creators.tbody = function(html, doc) {
595
        var frag = Y_DOM.create(TABLE_OPEN + html + TABLE_CLOSE, doc),
596
            tb = Y.DOM._children(frag, 'tbody')[0];
597
 
598
        if (frag.children.length > 1 && tb && !re_tbody.test(html)) {
599
            tb.parentNode.removeChild(tb); // strip extraneous tbody
600
        }
601
        return frag;
602
    };
603
}
604
 
605
if (!testFeature('innerhtml-div', 'script')) {
606
    creators.script = function(html, doc) {
607
        var frag = doc.createElement('div');
608
 
609
        frag.innerHTML = '-' + html;
610
        frag.removeChild(frag.firstChild);
611
        return frag;
612
    };
613
 
614
    creators.link = creators.style = creators.script;
615
}
616
 
617
if (!testFeature('innerhtml-div', 'tr')) {
618
    Y.mix(creators, {
619
        option: function(html, doc) {
620
            return Y_DOM.create('<select><option class="yui3-big-dummy" selected></option>' + html + '</select>', doc);
621
        },
622
 
623
        tr: function(html, doc) {
624
            return Y_DOM.create('<tbody>' + html + '</tbody>', doc);
625
        },
626
 
627
        td: function(html, doc) {
628
            return Y_DOM.create('<tr>' + html + '</tr>', doc);
629
        },
630
 
631
        col: function(html, doc) {
632
            return Y_DOM.create('<colgroup>' + html + '</colgroup>', doc);
633
        },
634
 
635
        tbody: 'table'
636
    });
637
 
638
    Y.mix(creators, {
639
        legend: 'fieldset',
640
        th: creators.td,
641
        thead: creators.tbody,
642
        tfoot: creators.tbody,
643
        caption: creators.tbody,
644
        colgroup: creators.tbody,
645
        optgroup: creators.option
646
    });
647
}
648
 
649
Y_DOM.creators = creators;
650
Y.mix(Y.DOM, {
651
    /**
652
     * Sets the width of the element to the given size, regardless
653
     * of box model, border, padding, etc.
654
     * @method setWidth
655
     * @param {HTMLElement} element The DOM element.
656
     * @param {String|Number} size The pixel height to size to
657
     */
658
 
659
    setWidth: function(node, size) {
660
        Y.DOM._setSize(node, 'width', size);
661
    },
662
 
663
    /**
664
     * Sets the height of the element to the given size, regardless
665
     * of box model, border, padding, etc.
666
     * @method setHeight
667
     * @param {HTMLElement} element The DOM element.
668
     * @param {String|Number} size The pixel height to size to
669
     */
670
 
671
    setHeight: function(node, size) {
672
        Y.DOM._setSize(node, 'height', size);
673
    },
674
 
675
    _setSize: function(node, prop, val) {
676
        val = (val > 0) ? val : 0;
677
        var size = 0;
678
 
679
        node.style[prop] = val + 'px';
680
        size = (prop === 'height') ? node.offsetHeight : node.offsetWidth;
681
 
682
        if (size > val) {
683
            val = val - (size - val);
684
 
685
            if (val < 0) {
686
                val = 0;
687
            }
688
 
689
            node.style[prop] = val + 'px';
690
        }
691
    }
692
});
693
 
694
 
695
}, '3.18.1', {"requires": ["dom-core"]});