PageRenderTime 27ms CodeModel.GetById 2ms app.highlight 17ms RepoModel.GetById 1ms app.codeStats 0ms

/src/main/resources/org/apache/struts2/static/get/get.js

http://struts2yuiplugin.googlecode.com/
JavaScript | 724 lines | 270 code | 76 blank | 378 comment | 66 complexity | 158b905b602116717045dcc20682ec8c MD5 | raw file
  1/*
  2Copyright (c) 2009, Yahoo! Inc. All rights reserved.
  3Code licensed under the BSD License:
  4http://developer.yahoo.net/yui/license.txt
  5version: 2.7.0
  6*/
  7/**
  8 * Provides a mechanism to fetch remote resources and
  9 * insert them into a document
 10 * @module get
 11 * @requires yahoo
 12 */
 13
 14/**
 15 * Fetches and inserts one or more script or link nodes into the document 
 16 * @namespace YAHOO.util
 17 * @class YAHOO.util.Get
 18 */
 19YAHOO.util.Get = function() {
 20
 21    /**
 22     * hash of queues to manage multiple requests
 23     * @property queues
 24     * @private
 25     */
 26    var queues={}, 
 27        
 28    /**
 29     * queue index used to generate transaction ids
 30     * @property qidx
 31     * @type int
 32     * @private
 33     */
 34        qidx=0, 
 35        
 36    /**
 37     * node index used to generate unique node ids
 38     * @property nidx
 39     * @type int
 40     * @private
 41     */
 42        nidx=0, 
 43
 44        // ridx=0,
 45
 46        // sandboxFrame=null,
 47
 48    /**
 49     * interal property used to prevent multiple simultaneous purge 
 50     * processes
 51     * @property purging
 52     * @type boolean
 53     * @private
 54     */
 55        purging=false,
 56
 57        ua=YAHOO.env.ua, 
 58        
 59        lang=YAHOO.lang;
 60    
 61    /** 
 62     * Generates an HTML element, this is not appended to a document
 63     * @method _node
 64     * @param type {string} the type of element
 65     * @param attr {string} the attributes
 66     * @param win {Window} optional window to create the element in
 67     * @return {HTMLElement} the generated node
 68     * @private
 69     */
 70    var _node = function(type, attr, win) {
 71        var w = win || window, d=w.document, n=d.createElement(type);
 72
 73        for (var i in attr) {
 74            if (attr[i] && YAHOO.lang.hasOwnProperty(attr, i)) {
 75                n.setAttribute(i, attr[i]);
 76            }
 77        }
 78
 79        return n;
 80    };
 81
 82    /**
 83     * Generates a link node
 84     * @method _linkNode
 85     * @param url {string} the url for the css file
 86     * @param win {Window} optional window to create the node in
 87     * @return {HTMLElement} the generated node
 88     * @private
 89     */
 90    var _linkNode = function(url, win, charset) {
 91        var c = charset || "utf-8";
 92        return _node("link", {
 93                "id":      "yui__dyn_" + (nidx++),
 94                "type":    "text/css",
 95                "charset": c,
 96                "rel":     "stylesheet",
 97                "href":    url
 98            }, win);
 99    };
100
101    /**
102     * Generates a script node
103     * @method _scriptNode
104     * @param url {string} the url for the script file
105     * @param win {Window} optional window to create the node in
106     * @return {HTMLElement} the generated node
107     * @private
108     */
109    var _scriptNode = function(url, win, charset) {
110        var c = charset || "utf-8";
111        return _node("script", {
112                "id":      "yui__dyn_" + (nidx++),
113                "type":    "text/javascript",
114                "charset": c,
115                "src":     url
116            }, win);
117    };
118
119    /**
120     * Returns the data payload for callback functions
121     * @method _returnData
122     * @private
123     */
124    var _returnData = function(q, msg) {
125        return {
126                tId: q.tId,
127                win: q.win,
128                data: q.data,
129                nodes: q.nodes,
130                msg: msg,
131                purge: function() {
132                    _purge(this.tId);
133                }
134            };
135    };
136
137    var _get = function(nId, tId) {
138        var q = queues[tId],
139            n = (lang.isString(nId)) ? q.win.document.getElementById(nId) : nId;
140        if (!n) {
141            _fail(tId, "target node not found: " + nId);
142        }
143
144        return n;
145    };
146
147    /*
148     * The request failed, execute fail handler with whatever
149     * was accomplished.  There isn't a failure case at the
150     * moment unless you count aborted transactions
151     * @method _fail
152     * @param id {string} the id of the request
153     * @private
154     */
155    var _fail = function(id, msg) {
156        var q = queues[id];
157        // execute failure callback
158        if (q.onFailure) {
159            var sc=q.scope || q.win;
160            q.onFailure.call(sc, _returnData(q, msg));
161        }
162    };
163
164    /**
165     * The request is complete, so executing the requester's callback
166     * @method _finish
167     * @param id {string} the id of the request
168     * @private
169     */
170    var _finish = function(id) {
171        var q = queues[id];
172        q.finished = true;
173
174        if (q.aborted) {
175            var msg = "transaction " + id + " was aborted";
176            _fail(id, msg);
177            return;
178        }
179
180        // execute success callback
181        if (q.onSuccess) {
182            var sc=q.scope || q.win;
183            q.onSuccess.call(sc, _returnData(q));
184        }
185    };
186
187    /**
188     * Timeout detected
189     * @method _timeout
190     * @param id {string} the id of the request
191     * @private
192     */
193    var _timeout = function(id) {
194        var q = queues[id];
195        if (q.onTimeout) {
196            var sc=q.scope || q;
197            q.onTimeout.call(sc, _returnData(q));
198        }
199    };
200
201    /**
202     * Loads the next item for a given request
203     * @method _next
204     * @param id {string} the id of the request
205     * @param loaded {string} the url that was just loaded, if any
206     * @private
207     */
208    var _next = function(id, loaded) {
209        var q = queues[id];
210
211        if (q.timer) {
212            // Y.log('cancel timer');
213            q.timer.cancel();
214        }
215
216        if (q.aborted) {
217            var msg = "transaction " + id + " was aborted";
218            _fail(id, msg);
219            return;
220        }
221
222        if (loaded) {
223            q.url.shift(); 
224            if (q.varName) {
225                q.varName.shift(); 
226            }
227        } else {
228            // This is the first pass: make sure the url is an array
229            q.url = (lang.isString(q.url)) ? [q.url] : q.url;
230            if (q.varName) {
231                q.varName = (lang.isString(q.varName)) ? [q.varName] : q.varName;
232            }
233        }
234
235        var w=q.win, d=w.document, h=d.getElementsByTagName("head")[0], n;
236
237        if (q.url.length === 0) {
238            // Safari 2.x workaround - There is no way to know when 
239            // a script is ready in versions of Safari prior to 3.x.
240            // Adding an extra node reduces the problem, but doesn't
241            // eliminate it completely because the browser executes
242            // them asynchronously. 
243            if (q.type === "script" && ua.webkit && ua.webkit < 420 && 
244                    !q.finalpass && !q.varName) {
245                // Add another script node.  This does not guarantee that the
246                // scripts will execute in order, but it does appear to fix the
247                // problem on fast connections more effectively than using an
248                // arbitrary timeout.  It is possible that the browser does
249                // block subsequent script execution in this case for a limited
250                // time.
251                var extra = _scriptNode(null, q.win, q.charset);
252                extra.innerHTML='YAHOO.util.Get._finalize("' + id + '");';
253                q.nodes.push(extra); h.appendChild(extra);
254
255            } else {
256                _finish(id);
257            }
258
259            return;
260        } 
261
262
263        var url = q.url[0];
264
265        // if the url is undefined, this is probably a trailing comma problem in IE
266        if (!url) {
267            q.url.shift(); 
268            return _next(id);
269        }
270
271
272        if (q.timeout) {
273            // Y.log('create timer');
274            q.timer = lang.later(q.timeout, q, _timeout, id);
275        }
276
277        if (q.type === "script") {
278            n = _scriptNode(url, w, q.charset);
279        } else {
280            n = _linkNode(url, w, q.charset);
281        }
282
283        // track this node's load progress
284        _track(q.type, n, id, url, w, q.url.length);
285
286        // add the node to the queue so we can return it to the user supplied callback
287        q.nodes.push(n);
288
289        // add it to the head or insert it before 'insertBefore'
290        if (q.insertBefore) {
291            var s = _get(q.insertBefore, id);
292            if (s) {
293                s.parentNode.insertBefore(n, s);
294            }
295        } else {
296            h.appendChild(n);
297        }
298        
299
300        // FireFox does not support the onload event for link nodes, so there is
301        // no way to make the css requests synchronous. This means that the css 
302        // rules in multiple files could be applied out of order in this browser
303        // if a later request returns before an earlier one.  Safari too.
304        if ((ua.webkit || ua.gecko) && q.type === "css") {
305            _next(id, url);
306        }
307    };
308
309    /**
310     * Removes processed queues and corresponding nodes
311     * @method _autoPurge
312     * @private
313     */
314    var _autoPurge = function() {
315
316        if (purging) {
317            return;
318        }
319
320        purging = true;
321        for (var i in queues) {
322            var q = queues[i];
323            if (q.autopurge && q.finished) {
324                _purge(q.tId);
325                delete queues[i];
326            }
327        }
328
329        purging = false;
330    };
331
332    /**
333     * Removes the nodes for the specified queue
334     * @method _purge
335     * @private
336     */
337    var _purge = function(tId) {
338        var q=queues[tId];
339        if (q) {
340            var n=q.nodes, l=n.length, d=q.win.document, 
341                h=d.getElementsByTagName("head")[0];
342
343            if (q.insertBefore) {
344                var s = _get(q.insertBefore, tId);
345                if (s) {
346                    h = s.parentNode;
347                }
348            }
349
350            for (var i=0; i<l; i=i+1) {
351                h.removeChild(n[i]);
352            }
353
354            q.nodes = [];
355        }
356    };
357
358    /**
359     * Saves the state for the request and begins loading
360     * the requested urls
361     * @method queue
362     * @param type {string} the type of node to insert
363     * @param url {string} the url to load
364     * @param opts the hash of options for this request
365     * @private
366     */
367    var _queue = function(type, url, opts) {
368
369        var id = "q" + (qidx++);
370        opts = opts || {};
371
372        if (qidx % YAHOO.util.Get.PURGE_THRESH === 0) {
373            _autoPurge();
374        }
375
376        queues[id] = lang.merge(opts, {
377            tId: id,
378            type: type,
379            url: url,
380            finished: false,
381            aborted: false,
382            nodes: []
383        });
384
385        var q = queues[id];
386        q.win = q.win || window;
387        q.scope = q.scope || q.win;
388        q.autopurge = ("autopurge" in q) ? q.autopurge : 
389                      (type === "script") ? true : false;
390
391        lang.later(0, q, _next, id);
392
393        return {
394            tId: id
395        };
396    };
397
398    /**
399     * Detects when a node has been loaded.  In the case of
400     * script nodes, this does not guarantee that contained
401     * script is ready to use.
402     * @method _track
403     * @param type {string} the type of node to track
404     * @param n {HTMLElement} the node to track
405     * @param id {string} the id of the request
406     * @param url {string} the url that is being loaded
407     * @param win {Window} the targeted window
408     * @param qlength the number of remaining items in the queue,
409     * including this one
410     * @param trackfn {Function} function to execute when finished
411     * the default is _next
412     * @private
413     */
414    var _track = function(type, n, id, url, win, qlength, trackfn) {
415        var f = trackfn || _next;
416
417        // IE supports the readystatechange event for script and css nodes
418        if (ua.ie) {
419            n.onreadystatechange = function() {
420                var rs = this.readyState;
421                if ("loaded" === rs || "complete" === rs) {
422                    n.onreadystatechange = null;
423                    f(id, url);
424                }
425            };
426
427        // webkit prior to 3.x is problemmatic
428        } else if (ua.webkit) {
429
430            if (type === "script") {
431
432                // Safari 3.x supports the load event for script nodes (DOM2)
433                if (ua.webkit >= 420) {
434
435                    n.addEventListener("load", function() {
436                        f(id, url);
437                    });
438
439                // Nothing can be done with Safari < 3.x except to pause and hope
440                // for the best, particularly after last script is inserted. The
441                // scripts will always execute in the order they arrive, not
442                // necessarily the order in which they were inserted.  To support
443                // script nodes with complete reliability in these browsers, script
444                // nodes either need to invoke a function in the window once they
445                // are loaded or the implementer needs to provide a well-known
446                // property that the utility can poll for.
447                } else {
448                    // Poll for the existence of the named variable, if it
449                    // was supplied.
450                    var q = queues[id];
451                    if (q.varName) {
452                        var freq=YAHOO.util.Get.POLL_FREQ;
453                        q.maxattempts = YAHOO.util.Get.TIMEOUT/freq;
454                        q.attempts = 0;
455                        q._cache = q.varName[0].split(".");
456                        q.timer = lang.later(freq, q, function(o) {
457                            var a=this._cache, l=a.length, w=this.win, i;
458                            for (i=0; i<l; i=i+1) {
459                                w = w[a[i]];
460                                if (!w) {
461                                    // if we have exausted our attempts, give up
462                                    this.attempts++;
463                                    if (this.attempts++ > this.maxattempts) {
464                                        var msg = "Over retry limit, giving up";
465                                        q.timer.cancel();
466                                        _fail(id, msg);
467                                    } else {
468                                    }
469                                    return;
470                                }
471                            }
472                            
473
474                            q.timer.cancel();
475                            f(id, url);
476
477                        }, null, true);
478                    } else {
479                        lang.later(YAHOO.util.Get.POLL_FREQ, null, f, [id, url]);
480                    }
481                }
482            } 
483
484        // FireFox and Opera support onload (but not DOM2 in FF) handlers for
485        // script nodes.  Opera, but not FF, supports the onload event for link
486        // nodes.
487        } else { 
488            n.onload = function() {
489                f(id, url);
490            };
491        }
492    };
493
494    return {
495
496        /**
497         * The default poll freqency in ms, when needed
498         * @property POLL_FREQ
499         * @static
500         * @type int
501         * @default 10
502         */
503        POLL_FREQ: 10,
504
505        /**
506         * The number of request required before an automatic purge.
507         * property PURGE_THRESH
508         * @static
509         * @type int
510         * @default 20
511         */
512        PURGE_THRESH: 20,
513
514        /**
515         * The length time to poll for varName when loading a script in
516         * Safari 2.x before the transaction fails.
517         * property TIMEOUT
518         * @static
519         * @type int
520         * @default 2000
521         */
522        TIMEOUT: 2000,
523        
524        /**
525         * Called by the the helper for detecting script load in Safari
526         * @method _finalize
527         * @param id {string} the transaction id
528         * @private
529         */
530        _finalize: function(id) {
531            lang.later(0, null, _finish, id);
532        },
533
534        /**
535         * Abort a transaction
536         * @method abort
537         * @param {string|object} either the tId or the object returned from
538         * script() or css()
539         */
540        abort: function(o) {
541            var id = (lang.isString(o)) ? o : o.tId;
542            var q = queues[id];
543            if (q) {
544                q.aborted = true;
545            }
546        }, 
547
548        /**
549         * Fetches and inserts one or more script nodes into the head
550         * of the current document or the document in a specified window.
551         *
552         * @method script
553         * @static
554         * @param url {string|string[]} the url or urls to the script(s)
555         * @param opts {object} Options: 
556         * <dl>
557         * <dt>onSuccess</dt>
558         * <dd>
559         * callback to execute when the script(s) are finished loading
560         * The callback receives an object back with the following
561         * data:
562         * <dl>
563         * <dt>win</dt>
564         * <dd>the window the script(s) were inserted into</dd>
565         * <dt>data</dt>
566         * <dd>the data object passed in when the request was made</dd>
567         * <dt>nodes</dt>
568         * <dd>An array containing references to the nodes that were
569         * inserted</dd>
570         * <dt>purge</dt>
571         * <dd>A function that, when executed, will remove the nodes
572         * that were inserted</dd>
573         * <dt>
574         * </dl>
575         * </dd>
576         * <dt>onFailure</dt>
577         * <dd>
578         * callback to execute when the script load operation fails
579         * The callback receives an object back with the following
580         * data:
581         * <dl>
582         * <dt>win</dt>
583         * <dd>the window the script(s) were inserted into</dd>
584         * <dt>data</dt>
585         * <dd>the data object passed in when the request was made</dd>
586         * <dt>nodes</dt>
587         * <dd>An array containing references to the nodes that were
588         * inserted successfully</dd>
589         * <dt>purge</dt>
590         * <dd>A function that, when executed, will remove any nodes
591         * that were inserted</dd>
592         * <dt>
593         * </dl>
594         * </dd>
595         * <dt>onTimeout</dt>
596         * <dd>
597         * callback to execute when a timeout occurs.
598         * The callback receives an object back with the following
599         * data:
600         * <dl>
601         * <dt>win</dt>
602         * <dd>the window the script(s) were inserted into</dd>
603         * <dt>data</dt>
604         * <dd>the data object passed in when the request was made</dd>
605         * <dt>nodes</dt>
606         * <dd>An array containing references to the nodes that were
607         * inserted</dd>
608         * <dt>purge</dt>
609         * <dd>A function that, when executed, will remove the nodes
610         * that were inserted</dd>
611         * <dt>
612         * </dl>
613         * </dd>
614         * <dt>scope</dt>
615         * <dd>the execution context for the callbacks</dd>
616         * <dt>win</dt>
617         * <dd>a window other than the one the utility occupies</dd>
618         * <dt>autopurge</dt>
619         * <dd>
620         * setting to true will let the utilities cleanup routine purge 
621         * the script once loaded
622         * </dd>
623         * <dt>data</dt>
624         * <dd>
625         * data that is supplied to the callback when the script(s) are
626         * loaded.
627         * </dd>
628         * <dt>varName</dt>
629         * <dd>
630         * variable that should be available when a script is finished
631         * loading.  Used to help Safari 2.x and below with script load 
632         * detection.  The type of this property should match what was
633         * passed into the url parameter: if loading a single url, a
634         * string can be supplied.  If loading multiple scripts, you
635         * must supply an array that contains the variable name for
636         * each script.
637         * </dd>
638         * <dt>insertBefore</dt>
639         * <dd>node or node id that will become the new node's nextSibling</dd>
640         * </dl>
641         * <dt>charset</dt>
642         * <dd>Node charset, default utf-8</dd>
643         * <dt>timeout</dt>
644         * <dd>Number of milliseconds to wait before aborting and firing the timeout event</dd>
645         * <pre>
646         * // assumes yahoo, dom, and event are already on the page
647         * &nbsp;&nbsp;YAHOO.util.Get.script(
648         * &nbsp;&nbsp;["http://yui.yahooapis.com/2.3.1/build/dragdrop/dragdrop-min.js",
649         * &nbsp;&nbsp;&nbsp;"http://yui.yahooapis.com/2.3.1/build/animation/animation-min.js"], &#123;
650         * &nbsp;&nbsp;&nbsp;&nbsp;onSuccess: function(o) &#123;
651         * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;new YAHOO.util.DDProxy("dd1"); // also new o.reference("dd1"); would work
652         * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.log("won't cause error because YAHOO is the scope");
653         * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.log(o.nodes.length === 2) // true
654         * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// o.purge(); // optionally remove the script nodes immediately
655         * &nbsp;&nbsp;&nbsp;&nbsp;&#125;,
656         * &nbsp;&nbsp;&nbsp;&nbsp;onFailure: function(o) &#123;
657         * &nbsp;&nbsp;&nbsp;&nbsp;&#125;,
658         * &nbsp;&nbsp;&nbsp;&nbsp;data: "foo",
659         * &nbsp;&nbsp;&nbsp;&nbsp;timeout: 10000, // 10 second timeout
660         * &nbsp;&nbsp;&nbsp;&nbsp;scope: YAHOO,
661         * &nbsp;&nbsp;&nbsp;&nbsp;// win: otherframe // target another window/frame
662         * &nbsp;&nbsp;&nbsp;&nbsp;autopurge: true // allow the utility to choose when to remove the nodes
663         * &nbsp;&nbsp;&#125;);
664         * </pre>
665         * @return {tId: string} an object containing info about the transaction
666         */
667        script: function(url, opts) { return _queue("script", url, opts); },
668
669        /**
670         * Fetches and inserts one or more css link nodes into the 
671         * head of the current document or the document in a specified
672         * window.
673         * @method css
674         * @static
675         * @param url {string} the url or urls to the css file(s)
676         * @param opts Options: 
677         * <dl>
678         * <dt>onSuccess</dt>
679         * <dd>
680         * callback to execute when the css file(s) are finished loading
681         * The callback receives an object back with the following
682         * data:
683         * <dl>win</dl>
684         * <dd>the window the link nodes(s) were inserted into</dd>
685         * <dt>data</dt>
686         * <dd>the data object passed in when the request was made</dd>
687         * <dt>nodes</dt>
688         * <dd>An array containing references to the nodes that were
689         * inserted</dd>
690         * <dt>purge</dt>
691         * <dd>A function that, when executed, will remove the nodes
692         * that were inserted</dd>
693         * <dt>
694         * </dl>
695         * </dd>
696         * <dt>scope</dt>
697         * <dd>the execution context for the callbacks</dd>
698         * <dt>win</dt>
699         * <dd>a window other than the one the utility occupies</dd>
700         * <dt>data</dt>
701         * <dd>
702         * data that is supplied to the callbacks when the nodes(s) are
703         * loaded.
704         * </dd>
705         * <dt>insertBefore</dt>
706         * <dd>node or node id that will become the new node's nextSibling</dd>
707         * <dt>charset</dt>
708         * <dd>Node charset, default utf-8</dd>
709         * </dl>
710         * <pre>
711         *      YAHOO.util.Get.css("http://yui.yahooapis.com/2.3.1/build/menu/assets/skins/sam/menu.css");
712         * </pre>
713         * <pre>
714         *      YAHOO.util.Get.css(["http://yui.yahooapis.com/2.3.1/build/menu/assets/skins/sam/menu.css",
715         * </pre>
716         * @return {tId: string} an object containing info about the transaction
717         */
718        css: function(url, opts) {
719            return _queue("css", url, opts); 
720        }
721    };
722}();
723
724YAHOO.register("get", YAHOO.util.Get, {version: "2.7.0", build: "1799"});