Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
YUI.add('dom-core', function (Y, NAME) {
2
 
3
var NODE_TYPE = 'nodeType',
4
    OWNER_DOCUMENT = 'ownerDocument',
5
    DOCUMENT_ELEMENT = 'documentElement',
6
    DEFAULT_VIEW = 'defaultView',
7
    PARENT_WINDOW = 'parentWindow',
8
    TAG_NAME = 'tagName',
9
    PARENT_NODE = 'parentNode',
10
    PREVIOUS_SIBLING = 'previousSibling',
11
    NEXT_SIBLING = 'nextSibling',
12
    CONTAINS = 'contains',
13
    COMPARE_DOCUMENT_POSITION = 'compareDocumentPosition',
14
    EMPTY_ARRAY = [],
15
 
16
    // IE < 8 throws on node.contains(textNode)
17
    supportsContainsTextNode = (function() {
18
        var node = Y.config.doc.createElement('div'),
19
            textNode = node.appendChild(Y.config.doc.createTextNode('')),
20
            result = false;
21
 
22
        try {
23
            result = node.contains(textNode);
24
        } catch(e) {}
25
 
26
        return result;
27
    })(),
28
 
29
/**
30
 * The DOM utility provides a cross-browser abtraction layer
31
 * normalizing DOM tasks, and adds extra helper functionality
32
 * for other common tasks.
33
 * @module dom
34
 * @main dom
35
 * @submodule dom-base
36
 * @for DOM
37
 *
38
 */
39
 
40
/**
41
 * Provides DOM helper methods.
42
 * @class DOM
43
 *
44
 */
45
 
46
Y_DOM = {
47
    /**
48
     * Returns the HTMLElement with the given ID (Wrapper for document.getElementById).
49
     * @method byId
50
     * @param {String} id the id attribute
51
     * @param {Object} doc optional The document to search. Defaults to current document
52
     * @return {HTMLElement | null} The HTMLElement with the id, or null if none found.
53
     */
54
    byId: function(id, doc) {
55
        // handle dupe IDs and IE name collision
56
        return Y_DOM.allById(id, doc)[0] || null;
57
    },
58
 
59
    getId: function(node) {
60
        var id;
61
        // HTMLElement returned from FORM when INPUT name === "id"
62
        // IE < 8: HTMLCollection returned when INPUT id === "id"
63
        // via both getAttribute and form.id
64
        if (node.id && !node.id.tagName && !node.id.item) {
65
            id = node.id;
66
        } else if (node.attributes && node.attributes.id) {
67
            id = node.attributes.id.value;
68
        }
69
 
70
        return id;
71
    },
72
 
73
    setId: function(node, id) {
74
        if (node.setAttribute) {
75
            node.setAttribute('id', id);
76
        } else {
77
            node.id = id;
78
        }
79
    },
80
 
81
    /*
82
     * Finds the ancestor of the element.
83
     * @method ancestor
84
     * @param {HTMLElement} element The html element.
85
     * @param {Function} fn optional An optional boolean test to apply.
86
     * The optional function is passed the current DOM node being tested as its only argument.
87
     * If no function is given, the parentNode is returned.
88
     * @param {Boolean} testSelf optional Whether or not to include the element in the scan
89
     * @return {HTMLElement | null} The matching DOM node or null if none found.
90
     */
91
    ancestor: function(element, fn, testSelf, stopFn) {
92
        var ret = null;
93
        if (testSelf) {
94
            ret = (!fn || fn(element)) ? element : null;
95
 
96
        }
97
        return ret || Y_DOM.elementByAxis(element, PARENT_NODE, fn, null, stopFn);
98
    },
99
 
100
    /*
101
     * Finds the ancestors of the element.
102
     * @method ancestors
103
     * @param {HTMLElement} element The html element.
104
     * @param {Function} fn optional An optional boolean test to apply.
105
     * The optional function is passed the current DOM node being tested as its only argument.
106
     * If no function is given, all ancestors are returned.
107
     * @param {Boolean} testSelf optional Whether or not to include the element in the scan
108
     * @return {Array} An array containing all matching DOM nodes.
109
     */
110
    ancestors: function(element, fn, testSelf, stopFn) {
111
        var ancestor = element,
112
            ret = [];
113
 
114
        while ((ancestor = Y_DOM.ancestor(ancestor, fn, testSelf, stopFn))) {
115
            testSelf = false;
116
            if (ancestor) {
117
                ret.unshift(ancestor);
118
 
119
                if (stopFn && stopFn(ancestor)) {
120
                    return ret;
121
                }
122
            }
123
        }
124
 
125
        return ret;
126
    },
127
 
128
    /**
129
     * Searches the element by the given axis for the first matching element.
130
     * @method elementByAxis
131
     * @param {HTMLElement} element The html element.
132
     * @param {String} axis The axis to search (parentNode, nextSibling, previousSibling).
133
     * @param {Function} [fn] An optional boolean test to apply.
134
     * @param {Boolean} [all] Whether text nodes as well as element nodes should be returned, or
135
     * just element nodes will be returned(default)
136
     * The optional function is passed the current HTMLElement being tested as its only argument.
137
     * If no function is given, the first element is returned.
138
     * @return {HTMLElement | null} The matching element or null if none found.
139
     */
140
    elementByAxis: function(element, axis, fn, all, stopAt) {
141
        while (element && (element = element[axis])) { // NOTE: assignment
142
                if ( (all || element[TAG_NAME]) && (!fn || fn(element)) ) {
143
                    return element;
144
                }
145
 
146
                if (stopAt && stopAt(element)) {
147
                    return null;
148
                }
149
        }
150
        return null;
151
    },
152
 
153
    /**
154
     * Determines whether or not one HTMLElement is or contains another HTMLElement.
155
     * @method contains
156
     * @param {HTMLElement} element The containing html element.
157
     * @param {HTMLElement} needle The html element that may be contained.
158
     * @return {Boolean} Whether or not the element is or contains the needle.
159
     */
160
    contains: function(element, needle) {
161
        var ret = false;
162
 
163
        if ( !needle || !element || !needle[NODE_TYPE] || !element[NODE_TYPE]) {
164
            ret = false;
165
        } else if (element[CONTAINS] &&
166
                // IE < 8 throws on node.contains(textNode) so fall back to brute.
167
                // Falling back for other nodeTypes as well.
168
                (needle[NODE_TYPE] === 1 || supportsContainsTextNode)) {
169
                ret = element[CONTAINS](needle);
170
        } else if (element[COMPARE_DOCUMENT_POSITION]) {
171
            // Match contains behavior (node.contains(node) === true).
172
            // Needed for Firefox < 4.
173
            if (element === needle || !!(element[COMPARE_DOCUMENT_POSITION](needle) & 16)) {
174
                ret = true;
175
            }
176
        } else {
177
            ret = Y_DOM._bruteContains(element, needle);
178
        }
179
 
180
        return ret;
181
    },
182
 
183
    /**
184
     * Determines whether or not the HTMLElement is part of the document.
185
     * @method inDoc
186
     * @param {HTMLElement} element The containing html element.
187
     * @param {HTMLElement} doc optional The document to check.
188
     * @return {Boolean} Whether or not the element is attached to the document.
189
     */
190
    inDoc: function(element, doc) {
191
        var ret = false,
192
            rootNode;
193
 
194
        if (element && element.nodeType) {
195
            (doc) || (doc = element[OWNER_DOCUMENT]);
196
 
197
            rootNode = doc[DOCUMENT_ELEMENT];
198
 
199
            // contains only works with HTML_ELEMENT
200
            if (rootNode && rootNode.contains && element.tagName) {
201
                ret = rootNode.contains(element);
202
            } else {
203
                ret = Y_DOM.contains(rootNode, element);
204
            }
205
        }
206
 
207
        return ret;
208
 
209
    },
210
 
211
   allById: function(id, root) {
212
        root = root || Y.config.doc;
213
        var nodes = [],
214
            ret = [],
215
            i,
216
            node;
217
 
218
        if (root.querySelectorAll) {
219
            ret = root.querySelectorAll('[id="' + id + '"]');
220
        } else if (root.all) {
221
            nodes = root.all(id);
222
 
223
            if (nodes) {
224
                // root.all may return HTMLElement or HTMLCollection.
225
                // some elements are also HTMLCollection (FORM, SELECT).
226
                if (nodes.nodeName) {
227
                    if (nodes.id === id) { // avoid false positive on name
228
                        ret.push(nodes);
229
                        nodes = EMPTY_ARRAY; // done, no need to filter
230
                    } else { //  prep for filtering
231
                        nodes = [nodes];
232
                    }
233
                }
234
 
235
                if (nodes.length) {
236
                    // filter out matches on node.name
237
                    // and element.id as reference to element with id === 'id'
238
                    for (i = 0; node = nodes[i++];) {
239
                        if (node.id === id  ||
240
                                (node.attributes && node.attributes.id &&
241
                                node.attributes.id.value === id)) {
242
                            ret.push(node);
243
                        }
244
                    }
245
                }
246
            }
247
        } else {
248
            ret = [Y_DOM._getDoc(root).getElementById(id)];
249
        }
250
 
251
        return ret;
252
   },
253
 
254
 
255
    isWindow: function(obj) {
256
        return !!(obj && obj.scrollTo && obj.document);
257
    },
258
 
259
    _removeChildNodes: function(node) {
260
        while (node.firstChild) {
261
            node.removeChild(node.firstChild);
262
        }
263
    },
264
 
265
    siblings: function(node, fn) {
266
        var nodes = [],
267
            sibling = node;
268
 
269
        while ((sibling = sibling[PREVIOUS_SIBLING])) {
270
            if (sibling[TAG_NAME] && (!fn || fn(sibling))) {
271
                nodes.unshift(sibling);
272
            }
273
        }
274
 
275
        sibling = node;
276
        while ((sibling = sibling[NEXT_SIBLING])) {
277
            if (sibling[TAG_NAME] && (!fn || fn(sibling))) {
278
                nodes.push(sibling);
279
            }
280
        }
281
 
282
        return nodes;
283
    },
284
 
285
    /**
286
     * Brute force version of contains.
287
     * Used for browsers without contains support for non-HTMLElement Nodes (textNodes, etc).
288
     * @method _bruteContains
289
     * @private
290
     * @param {HTMLElement} element The containing html element.
291
     * @param {HTMLElement} needle The html element that may be contained.
292
     * @return {Boolean} Whether or not the element is or contains the needle.
293
     */
294
    _bruteContains: function(element, needle) {
295
        while (needle) {
296
            if (element === needle) {
297
                return true;
298
            }
299
            needle = needle.parentNode;
300
        }
301
        return false;
302
    },
303
 
304
// TODO: move to Lang?
305
    /**
306
     * Memoizes dynamic regular expressions to boost runtime performance.
307
     * @method _getRegExp
308
     * @private
309
     * @param {String} str The string to convert to a regular expression.
310
     * @param {String} flags optional An optinal string of flags.
311
     * @return {RegExp} An instance of RegExp
312
     */
313
    _getRegExp: function(str, flags) {
314
        flags = flags || '';
315
        Y_DOM._regexCache = Y_DOM._regexCache || {};
316
        if (!Y_DOM._regexCache[str + flags]) {
317
            Y_DOM._regexCache[str + flags] = new RegExp(str, flags);
318
        }
319
        return Y_DOM._regexCache[str + flags];
320
    },
321
 
322
// TODO: make getDoc/Win true privates?
323
    /**
324
     * returns the appropriate document.
325
     * @method _getDoc
326
     * @private
327
     * @param {HTMLElement} element optional Target element.
328
     * @return {Object} The document for the given element or the default document.
329
     */
330
    _getDoc: function(element) {
331
        var doc = Y.config.doc;
332
        if (element) {
333
            doc = (element[NODE_TYPE] === 9) ? element : // element === document
334
                element[OWNER_DOCUMENT] || // element === DOM node
335
                element.document || // element === window
336
                Y.config.doc; // default
337
        }
338
 
339
        return doc;
340
    },
341
 
342
    /**
343
     * returns the appropriate window.
344
     * @method _getWin
345
     * @private
346
     * @param {HTMLElement} element optional Target element.
347
     * @return {Object} The window for the given element or the default window.
348
     */
349
    _getWin: function(element) {
350
        var doc = Y_DOM._getDoc(element);
351
        return doc[DEFAULT_VIEW] || doc[PARENT_WINDOW] || Y.config.win;
352
    },
353
 
354
    _batch: function(nodes, fn, arg1, arg2, arg3, etc) {
355
        fn = (typeof fn === 'string') ? Y_DOM[fn] : fn;
356
        var result,
357
            i = 0,
358
            node,
359
            ret;
360
 
361
        if (fn && nodes) {
362
            while ((node = nodes[i++])) {
363
                result = result = fn.call(Y_DOM, node, arg1, arg2, arg3, etc);
364
                if (typeof result !== 'undefined') {
365
                    (ret) || (ret = []);
366
                    ret.push(result);
367
                }
368
            }
369
        }
370
 
371
        return (typeof ret !== 'undefined') ? ret : nodes;
372
    },
373
 
374
    generateID: function(el) {
375
        var id = el.id;
376
 
377
        if (!id) {
378
            id = Y.stamp(el);
379
            el.id = id;
380
        }
381
 
382
        return id;
383
    }
384
};
385
 
386
 
387
Y.DOM = Y_DOM;
388
 
389
 
390
}, '3.18.1', {"requires": ["oop", "features"]});