]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - include/javascript/yui/build/yahoo/yahoo.js
Release 6.2.0beta4
[Github/sugarcrm.git] / include / javascript / yui / build / yahoo / yahoo.js
1 /*
2 Copyright (c) 2009, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.net/yui/license.txt
5 version: 2.8.0r4
6 */
7 /**
8  * The YAHOO object is the single global object used by YUI Library.  It
9  * contains utility function for setting up namespaces, inheritance, and
10  * logging.  YAHOO.util, YAHOO.widget, and YAHOO.example are namespaces
11  * created automatically for and used by the library.
12  * @module yahoo
13  * @title  YAHOO Global
14  */
15
16 /**
17  * YAHOO_config is not included as part of the library.  Instead it is an 
18  * object that can be defined by the implementer immediately before 
19  * including the YUI library.  The properties included in this object
20  * will be used to configure global properties needed as soon as the 
21  * library begins to load.
22  * @class YAHOO_config
23  * @static
24  */
25
26 /**
27  * A reference to a function that will be executed every time a YAHOO module
28  * is loaded.  As parameter, this function will receive the version
29  * information for the module. See <a href="YAHOO.env.html#getVersion">
30  * YAHOO.env.getVersion</a> for the description of the version data structure.
31  * @property listener
32  * @type Function
33  * @static
34  * @default undefined
35  */
36
37 /**
38  * Set to true if the library will be dynamically loaded after window.onload.
39  * Defaults to false 
40  * @property injecting
41  * @type boolean
42  * @static
43  * @default undefined
44  */
45
46 /**
47  * Instructs the yuiloader component to dynamically load yui components and
48  * their dependencies.  See the yuiloader documentation for more information
49  * about dynamic loading
50  * @property load
51  * @static
52  * @default undefined
53  * @see yuiloader
54  */
55
56 /**
57  * Forces the use of the supplied locale where applicable in the library
58  * @property locale
59  * @type string
60  * @static
61  * @default undefined
62  */
63
64 if (typeof YAHOO == "undefined" || !YAHOO) {
65     /**
66      * The YAHOO global namespace object.  If YAHOO is already defined, the
67      * existing YAHOO object will not be overwritten so that defined
68      * namespaces are preserved.
69      * @class YAHOO
70      * @static
71      */
72     var YAHOO = {};
73 }
74
75 /**
76  * Returns the namespace specified and creates it if it doesn't exist
77  * <pre>
78  * YAHOO.namespace("property.package");
79  * YAHOO.namespace("YAHOO.property.package");
80  * </pre>
81  * Either of the above would create YAHOO.property, then
82  * YAHOO.property.package
83  *
84  * Be careful when naming packages. Reserved words may work in some browsers
85  * and not others. For instance, the following will fail in Safari:
86  * <pre>
87  * YAHOO.namespace("really.long.nested.namespace");
88  * </pre>
89  * This fails because "long" is a future reserved word in ECMAScript
90  *
91  * For implementation code that uses YUI, do not create your components
92  * in the namespaces defined by YUI (
93  * <code>YAHOO.util</code>, 
94  * <code>YAHOO.widget</code>, 
95  * <code>YAHOO.lang</code>, 
96  * <code>YAHOO.tool</code>, 
97  * <code>YAHOO.example</code>, 
98  * <code>YAHOO.env</code>) -- create your own namespace (e.g., 'companyname').
99  *
100  * @method namespace
101  * @static
102  * @param  {String*} arguments 1-n namespaces to create 
103  * @return {Object}  A reference to the last namespace object created
104  */
105 YAHOO.namespace = function() {
106     var a=arguments, o=null, i, j, d;
107     for (i=0; i<a.length; i=i+1) {
108         d=(""+a[i]).split(".");
109         o=YAHOO;
110
111         // YAHOO is implied, so it is ignored if it is included
112         for (j=(d[0] == "YAHOO") ? 1 : 0; j<d.length; j=j+1) {
113             o[d[j]]=o[d[j]] || {};
114             o=o[d[j]];
115         }
116     }
117
118     return o;
119 };
120
121 /**
122  * Uses YAHOO.widget.Logger to output a log message, if the widget is
123  * available.
124  *
125  * @method log
126  * @static
127  * @param  {String}  msg  The message to log.
128  * @param  {String}  cat  The log category for the message.  Default
129  *                        categories are "info", "warn", "error", time".
130  *                        Custom categories can be used as well. (opt)
131  * @param  {String}  src  The source of the the message (opt)
132  * @return {Boolean}      True if the log operation was successful.
133  */
134 YAHOO.log = function(msg, cat, src) {
135     var l=YAHOO.widget.Logger;
136     if(l && l.log) {
137         return l.log(msg, cat, src);
138     } else {
139         return false;
140     }
141 };
142
143 /**
144  * Registers a module with the YAHOO object
145  * @method register
146  * @static
147  * @param {String}   name    the name of the module (event, slider, etc)
148  * @param {Function} mainClass a reference to class in the module.  This
149  *                             class will be tagged with the version info
150  *                             so that it will be possible to identify the
151  *                             version that is in use when multiple versions
152  *                             have loaded
153  * @param {Object}   data      metadata object for the module.  Currently it
154  *                             is expected to contain a "version" property
155  *                             and a "build" property at minimum.
156  */
157 YAHOO.register = function(name, mainClass, data) {
158     var mods = YAHOO.env.modules, m, v, b, ls, i;
159
160     if (!mods[name]) {
161         mods[name] = { 
162             versions:[], 
163             builds:[] 
164         };
165     }
166
167     m  = mods[name];
168     v  = data.version;
169     b  = data.build;
170     ls = YAHOO.env.listeners;
171
172     m.name = name;
173     m.version = v;
174     m.build = b;
175     m.versions.push(v);
176     m.builds.push(b);
177     m.mainClass = mainClass;
178
179     // fire the module load listeners
180     for (i=0;i<ls.length;i=i+1) {
181         ls[i](m);
182     }
183     // label the main class
184     if (mainClass) {
185         mainClass.VERSION = v;
186         mainClass.BUILD = b;
187     } else {
188         YAHOO.log("mainClass is undefined for module " + name, "warn");
189     }
190 };
191
192 /**
193  * YAHOO.env is used to keep track of what is known about the YUI library and
194  * the browsing environment
195  * @class YAHOO.env
196  * @static
197  */
198 YAHOO.env = YAHOO.env || {
199
200     /**
201      * Keeps the version info for all YUI modules that have reported themselves
202      * @property modules
203      * @type Object[]
204      */
205     modules: [],
206     
207     /**
208      * List of functions that should be executed every time a YUI module
209      * reports itself.
210      * @property listeners
211      * @type Function[]
212      */
213     listeners: []
214 };
215
216 /**
217  * Returns the version data for the specified module:
218  *      <dl>
219  *      <dt>name:</dt>      <dd>The name of the module</dd>
220  *      <dt>version:</dt>   <dd>The version in use</dd>
221  *      <dt>build:</dt>     <dd>The build number in use</dd>
222  *      <dt>versions:</dt>  <dd>All versions that were registered</dd>
223  *      <dt>builds:</dt>    <dd>All builds that were registered.</dd>
224  *      <dt>mainClass:</dt> <dd>An object that was was stamped with the
225  *                 current version and build. If 
226  *                 mainClass.VERSION != version or mainClass.BUILD != build,
227  *                 multiple versions of pieces of the library have been
228  *                 loaded, potentially causing issues.</dd>
229  *       </dl>
230  *
231  * @method getVersion
232  * @static
233  * @param {String}  name the name of the module (event, slider, etc)
234  * @return {Object} The version info
235  */
236 YAHOO.env.getVersion = function(name) {
237     return YAHOO.env.modules[name] || null;
238 };
239
240 /**
241  * Do not fork for a browser if it can be avoided.  Use feature detection when
242  * you can.  Use the user agent as a last resort.  YAHOO.env.ua stores a version
243  * number for the browser engine, 0 otherwise.  This value may or may not map
244  * to the version number of the browser using the engine.  The value is 
245  * presented as a float so that it can easily be used for boolean evaluation 
246  * as well as for looking for a particular range of versions.  Because of this, 
247  * some of the granularity of the version info may be lost (e.g., Gecko 1.8.0.9 
248  * reports 1.8).
249  * @class YAHOO.env.ua
250  * @static
251  */
252 YAHOO.env.ua = function() {
253
254         var numberfy = function(s) {
255             var c = 0;
256             return parseFloat(s.replace(/\./g, function() {
257                 return (c++ == 1) ? '' : '.';
258             }));
259         },
260
261         nav = navigator,
262
263         o = {
264
265         /**
266          * Internet Explorer version number or 0.  Example: 6
267          * @property ie
268          * @type float
269          */
270         ie: 0,
271
272         /**
273          * Opera version number or 0.  Example: 9.2
274          * @property opera
275          * @type float
276          */
277         opera: 0,
278
279         /**
280          * Gecko engine revision number.  Will evaluate to 1 if Gecko 
281          * is detected but the revision could not be found. Other browsers
282          * will be 0.  Example: 1.8
283          * <pre>
284          * Firefox 1.0.0.4: 1.7.8   <-- Reports 1.7
285          * Firefox 1.5.0.9: 1.8.0.9 <-- Reports 1.8
286          * Firefox 2.0.0.3: 1.8.1.3 <-- Reports 1.8
287          * Firefox 3 alpha: 1.9a4   <-- Reports 1.9
288          * </pre>
289          * @property gecko
290          * @type float
291          */
292         gecko: 0,
293
294         /**
295          * AppleWebKit version.  KHTML browsers that are not WebKit browsers 
296          * will evaluate to 1, other browsers 0.  Example: 418.9.1
297          * <pre>
298          * Safari 1.3.2 (312.6): 312.8.1 <-- Reports 312.8 -- currently the 
299          *                                   latest available for Mac OSX 10.3.
300          * Safari 2.0.2:         416     <-- hasOwnProperty introduced
301          * Safari 2.0.4:         418     <-- preventDefault fixed
302          * Safari 2.0.4 (419.3): 418.9.1 <-- One version of Safari may run
303          *                                   different versions of webkit
304          * Safari 2.0.4 (419.3): 419     <-- Tiger installations that have been
305          *                                   updated, but not updated
306          *                                   to the latest patch.
307          * Webkit 212 nightly:   522+    <-- Safari 3.0 precursor (with native SVG
308          *                                   and many major issues fixed).  
309          * 3.x yahoo.com, flickr:422     <-- Safari 3.x hacks the user agent
310          *                                   string when hitting yahoo.com and 
311          *                                   flickr.com.
312          * Safari 3.0.4 (523.12):523.12  <-- First Tiger release - automatic update
313          *                                   from 2.x via the 10.4.11 OS patch
314          * Webkit nightly 1/2008:525+    <-- Supports DOMContentLoaded event.
315          *                                   yahoo.com user agent hack removed.
316          *                                   
317          * </pre>
318          * http://developer.apple.com/internet/safari/uamatrix.html
319          * @property webkit
320          * @type float
321          */
322         webkit: 0,
323
324         /**
325          * The mobile property will be set to a string containing any relevant
326          * user agent information when a modern mobile browser is detected.
327          * Currently limited to Safari on the iPhone/iPod Touch, Nokia N-series
328          * devices with the WebKit-based browser, and Opera Mini.  
329          * @property mobile 
330          * @type string
331          */
332         mobile: null,
333
334         /**
335          * Adobe AIR version number or 0.  Only populated if webkit is detected.
336          * Example: 1.0
337          * @property air
338          * @type float
339          */
340         air: 0,
341
342         /**
343          * Google Caja version number or 0.
344          * @property caja
345          * @type float
346          */
347         caja: nav.cajaVersion,
348
349         /**
350          * Set to true if the page appears to be in SSL
351          * @property secure
352          * @type boolean
353          * @static
354          */
355         secure: false,
356
357         /**
358          * The operating system.  Currently only detecting windows or macintosh
359          * @property os
360          * @type string
361          * @static
362          */
363         os: null
364
365     },
366
367     ua = navigator && navigator.userAgent, 
368     
369     loc = window && window.location,
370
371     href = loc && loc.href,
372     
373     m;
374
375     o.secure = href && (href.toLowerCase().indexOf("https") === 0);
376
377     if (ua) {
378
379         if ((/windows|win32/i).test(ua)) {
380             o.os = 'windows';
381         } else if ((/macintosh/i).test(ua)) {
382             o.os = 'macintosh';
383         }
384     
385         // Modern KHTML browsers should qualify as Safari X-Grade
386         if ((/KHTML/).test(ua)) {
387             o.webkit=1;
388         }
389
390         // Modern WebKit browsers are at least X-Grade
391         m=ua.match(/AppleWebKit\/([^\s]*)/);
392         if (m&&m[1]) {
393             o.webkit=numberfy(m[1]);
394
395             // Mobile browser check
396             if (/ Mobile\//.test(ua)) {
397                 o.mobile = "Apple"; // iPhone or iPod Touch
398             } else {
399                 m=ua.match(/NokiaN[^\/]*/);
400                 if (m) {
401                     o.mobile = m[0]; // Nokia N-series, ex: NokiaN95
402                 }
403             }
404
405             m=ua.match(/AdobeAIR\/([^\s]*)/);
406             if (m) {
407                 o.air = m[0]; // Adobe AIR 1.0 or better
408             }
409
410         }
411
412         if (!o.webkit) { // not webkit
413             // @todo check Opera/8.01 (J2ME/MIDP; Opera Mini/2.0.4509/1316; fi; U; ssr)
414             m=ua.match(/Opera[\s\/]([^\s]*)/);
415             if (m&&m[1]) {
416                 o.opera=numberfy(m[1]);
417                 m=ua.match(/Opera Mini[^;]*/);
418                 if (m) {
419                     o.mobile = m[0]; // ex: Opera Mini/2.0.4509/1316
420                 }
421             } else { // not opera or webkit
422                 m=ua.match(/MSIE\s([^;]*)/);
423                 if (m&&m[1]) {
424                     o.ie=numberfy(m[1]);
425                 } else { // not opera, webkit, or ie
426                     m=ua.match(/Gecko\/([^\s]*)/);
427                     if (m) {
428                         o.gecko=1; // Gecko detected, look for revision
429                         m=ua.match(/rv:([^\s\)]*)/);
430                         if (m&&m[1]) {
431                             o.gecko=numberfy(m[1]);
432                         }
433                     }
434                 }
435             }
436         }
437     }
438
439     return o;
440 }();
441
442 /*
443  * Initializes the global by creating the default namespaces and applying
444  * any new configuration information that is detected.  This is the setup
445  * for env.
446  * @method init
447  * @static
448  * @private
449  */
450 (function() {
451     YAHOO.namespace("util", "widget", "example");
452     /*global YAHOO_config*/
453     if ("undefined" !== typeof YAHOO_config) {
454         var l=YAHOO_config.listener, ls=YAHOO.env.listeners,unique=true, i;
455         if (l) {
456             // if YAHOO is loaded multiple times we need to check to see if
457             // this is a new config object.  If it is, add the new component
458             // load listener to the stack
459             for (i=0; i<ls.length; i++) {
460                 if (ls[i] == l) {
461                     unique = false;
462                     break;
463                 }
464             }
465
466             if (unique) {
467                 ls.push(l);
468             }
469         }
470     }
471 })();
472 /**
473  * Provides the language utilites and extensions used by the library
474  * @class YAHOO.lang
475  */
476 YAHOO.lang = YAHOO.lang || {};
477
478 (function() {
479
480
481 var L = YAHOO.lang,
482
483     OP = Object.prototype,
484     ARRAY_TOSTRING = '[object Array]',
485     FUNCTION_TOSTRING = '[object Function]',
486     OBJECT_TOSTRING = '[object Object]',
487     NOTHING = [],
488
489     // ADD = ["toString", "valueOf", "hasOwnProperty"],
490     ADD = ["toString", "valueOf"],
491
492     OB = {
493
494     /**
495      * Determines wheather or not the provided object is an array.
496      * @method isArray
497      * @param {any} o The object being testing
498      * @return {boolean} the result
499      */
500     isArray: function(o) { 
501         return OP.toString.apply(o) === ARRAY_TOSTRING;
502     },
503
504     /**
505      * Determines whether or not the provided object is a boolean
506      * @method isBoolean
507      * @param {any} o The object being testing
508      * @return {boolean} the result
509      */
510     isBoolean: function(o) {
511         return typeof o === 'boolean';
512     },
513     
514     /**
515      * Determines whether or not the provided object is a function.
516      * Note: Internet Explorer thinks certain functions are objects:
517      *
518      * var obj = document.createElement("object");
519      * YAHOO.lang.isFunction(obj.getAttribute) // reports false in IE
520      *
521      * var input = document.createElement("input"); // append to body
522      * YAHOO.lang.isFunction(input.focus) // reports false in IE
523      *
524      * You will have to implement additional tests if these functions
525      * matter to you.
526      *
527      * @method isFunction
528      * @param {any} o The object being testing
529      * @return {boolean} the result
530      */
531     isFunction: function(o) {
532         return (typeof o === 'function') || OP.toString.apply(o) === FUNCTION_TOSTRING;
533     },
534         
535     /**
536      * Determines whether or not the provided object is null
537      * @method isNull
538      * @param {any} o The object being testing
539      * @return {boolean} the result
540      */
541     isNull: function(o) {
542         return o === null;
543     },
544         
545     /**
546      * Determines whether or not the provided object is a legal number
547      * @method isNumber
548      * @param {any} o The object being testing
549      * @return {boolean} the result
550      */
551     isNumber: function(o) {
552         return typeof o === 'number' && isFinite(o);
553     },
554       
555     /**
556      * Determines whether or not the provided object is of type object
557      * or function
558      * @method isObject
559      * @param {any} o The object being testing
560      * @return {boolean} the result
561      */  
562     isObject: function(o) {
563 return (o && (typeof o === 'object' || L.isFunction(o))) || false;
564     },
565         
566     /**
567      * Determines whether or not the provided object is a string
568      * @method isString
569      * @param {any} o The object being testing
570      * @return {boolean} the result
571      */
572     isString: function(o) {
573         return typeof o === 'string';
574     },
575         
576     /**
577      * Determines whether or not the provided object is undefined
578      * @method isUndefined
579      * @param {any} o The object being testing
580      * @return {boolean} the result
581      */
582     isUndefined: function(o) {
583         return typeof o === 'undefined';
584     },
585     
586  
587     /**
588      * IE will not enumerate native functions in a derived object even if the
589      * function was overridden.  This is a workaround for specific functions 
590      * we care about on the Object prototype. 
591      * @property _IEEnumFix
592      * @param {Function} r  the object to receive the augmentation
593      * @param {Function} s  the object that supplies the properties to augment
594      * @static
595      * @private
596      */
597     _IEEnumFix: (YAHOO.env.ua.ie) ? function(r, s) {
598             var i, fname, f;
599             for (i=0;i<ADD.length;i=i+1) {
600
601                 fname = ADD[i];
602                 f = s[fname];
603
604                 if (L.isFunction(f) && f!=OP[fname]) {
605                     r[fname]=f;
606                 }
607             }
608     } : function(){},
609        
610     /**
611      * Utility to set up the prototype, constructor and superclass properties to
612      * support an inheritance strategy that can chain constructors and methods.
613      * Static members will not be inherited.
614      *
615      * @method extend
616      * @static
617      * @param {Function} subc   the object to modify
618      * @param {Function} superc the object to inherit
619      * @param {Object} overrides  additional properties/methods to add to the
620      *                              subclass prototype.  These will override the
621      *                              matching items obtained from the superclass 
622      *                              if present.
623      */
624     extend: function(subc, superc, overrides) {
625         if (!superc||!subc) {
626             throw new Error("extend failed, please check that " +
627                             "all dependencies are included.");
628         }
629         var F = function() {}, i;
630         F.prototype=superc.prototype;
631         subc.prototype=new F();
632         subc.prototype.constructor=subc;
633         subc.superclass=superc.prototype;
634         if (superc.prototype.constructor == OP.constructor) {
635             superc.prototype.constructor=superc;
636         }
637     
638         if (overrides) {
639             for (i in overrides) {
640                 if (L.hasOwnProperty(overrides, i)) {
641                     subc.prototype[i]=overrides[i];
642                 }
643             }
644
645             L._IEEnumFix(subc.prototype, overrides);
646         }
647     },
648    
649     /**
650      * Applies all properties in the supplier to the receiver if the
651      * receiver does not have these properties yet.  Optionally, one or 
652      * more methods/properties can be specified (as additional 
653      * parameters).  This option will overwrite the property if receiver 
654      * has it already.  If true is passed as the third parameter, all 
655      * properties will be applied and _will_ overwrite properties in 
656      * the receiver.
657      *
658      * @method augmentObject
659      * @static
660      * @since 2.3.0
661      * @param {Function} r  the object to receive the augmentation
662      * @param {Function} s  the object that supplies the properties to augment
663      * @param {String*|boolean}  arguments zero or more properties methods 
664      *        to augment the receiver with.  If none specified, everything
665      *        in the supplier will be used unless it would
666      *        overwrite an existing property in the receiver. If true
667      *        is specified as the third parameter, all properties will
668      *        be applied and will overwrite an existing property in
669      *        the receiver
670      */
671     augmentObject: function(r, s) {
672         if (!s||!r) {
673             throw new Error("Absorb failed, verify dependencies.");
674         }
675         var a=arguments, i, p, overrideList=a[2];
676         if (overrideList && overrideList!==true) { // only absorb the specified properties
677             for (i=2; i<a.length; i=i+1) {
678                 r[a[i]] = s[a[i]];
679             }
680         } else { // take everything, overwriting only if the third parameter is true
681             for (p in s) { 
682                 if (overrideList || !(p in r)) {
683                     r[p] = s[p];
684                 }
685             }
686             
687             L._IEEnumFix(r, s);
688         }
689     },
690  
691     /**
692      * Same as YAHOO.lang.augmentObject, except it only applies prototype properties
693      * @see YAHOO.lang.augmentObject
694      * @method augmentProto
695      * @static
696      * @param {Function} r  the object to receive the augmentation
697      * @param {Function} s  the object that supplies the properties to augment
698      * @param {String*|boolean}  arguments zero or more properties methods 
699      *        to augment the receiver with.  If none specified, everything 
700      *        in the supplier will be used unless it would overwrite an existing 
701      *        property in the receiver.  if true is specified as the third 
702      *        parameter, all properties will be applied and will overwrite an 
703      *        existing property in the receiver
704      */
705     augmentProto: function(r, s) {
706         if (!s||!r) {
707             throw new Error("Augment failed, verify dependencies.");
708         }
709         //var a=[].concat(arguments);
710         var a=[r.prototype,s.prototype], i;
711         for (i=2;i<arguments.length;i=i+1) {
712             a.push(arguments[i]);
713         }
714         L.augmentObject.apply(this, a);
715     },
716
717       
718     /**
719      * Returns a simple string representation of the object or array.
720      * Other types of objects will be returned unprocessed.  Arrays
721      * are expected to be indexed.  Use object notation for
722      * associative arrays.
723      * @method dump
724      * @since 2.3.0
725      * @param o {Object} The object to dump
726      * @param d {int} How deep to recurse child objects, default 3
727      * @return {String} the dump result
728      */
729     dump: function(o, d) {
730         var i,len,s=[],OBJ="{...}",FUN="f(){...}",
731             COMMA=', ', ARROW=' => ';
732
733         // Cast non-objects to string
734         // Skip dates because the std toString is what we want
735         // Skip HTMLElement-like objects because trying to dump 
736         // an element will cause an unhandled exception in FF 2.x
737         if (!L.isObject(o)) {
738             return o + "";
739         } else if (o instanceof Date || ("nodeType" in o && "tagName" in o)) {
740             return o;
741         } else if  (L.isFunction(o)) {
742             return FUN;
743         }
744
745         // dig into child objects the depth specifed. Default 3
746         d = (L.isNumber(d)) ? d : 3;
747
748         // arrays [1, 2, 3]
749         if (L.isArray(o)) {
750             s.push("[");
751             for (i=0,len=o.length;i<len;i=i+1) {
752                 if (L.isObject(o[i])) {
753                     s.push((d > 0) ? L.dump(o[i], d-1) : OBJ);
754                 } else {
755                     s.push(o[i]);
756                 }
757                 s.push(COMMA);
758             }
759             if (s.length > 1) {
760                 s.pop();
761             }
762             s.push("]");
763         // objects {k1 => v1, k2 => v2}
764         } else {
765             s.push("{");
766             for (i in o) {
767                 if (L.hasOwnProperty(o, i)) {
768                     s.push(i + ARROW);
769                     if (L.isObject(o[i])) {
770                         s.push((d > 0) ? L.dump(o[i], d-1) : OBJ);
771                     } else {
772                         s.push(o[i]);
773                     }
774                     s.push(COMMA);
775                 }
776             }
777             if (s.length > 1) {
778                 s.pop();
779             }
780             s.push("}");
781         }
782
783         return s.join("");
784     },
785
786     /**
787      * Does variable substitution on a string. It scans through the string 
788      * looking for expressions enclosed in { } braces. If an expression 
789      * is found, it is used a key on the object.  If there is a space in
790      * the key, the first word is used for the key and the rest is provided
791      * to an optional function to be used to programatically determine the
792      * value (the extra information might be used for this decision). If 
793      * the value for the key in the object, or what is returned from the
794      * function has a string value, number value, or object value, it is 
795      * substituted for the bracket expression and it repeats.  If this
796      * value is an object, it uses the Object's toString() if this has
797      * been overridden, otherwise it does a shallow dump of the key/value
798      * pairs.
799      * @method substitute
800      * @since 2.3.0
801      * @param s {String} The string that will be modified.
802      * @param o {Object} An object containing the replacement values
803      * @param f {Function} An optional function that can be used to
804      *                     process each match.  It receives the key,
805      *                     value, and any extra metadata included with
806      *                     the key inside of the braces.
807      * @return {String} the substituted string
808      */
809     substitute: function (s, o, f) {
810         var i, j, k, key, v, meta, saved=[], token, 
811             DUMP='dump', SPACE=' ', LBRACE='{', RBRACE='}',
812             dump, objstr;
813
814
815         for (;;) {
816             i = s.lastIndexOf(LBRACE);
817             if (i < 0) {
818                 break;
819             }
820             j = s.indexOf(RBRACE, i);
821             if (i + 1 >= j) {
822                 break;
823             }
824
825             //Extract key and meta info 
826             token = s.substring(i + 1, j);
827             key = token;
828             meta = null;
829             k = key.indexOf(SPACE);
830             if (k > -1) {
831                 meta = key.substring(k + 1);
832                 key = key.substring(0, k);
833             }
834
835             // lookup the value
836             v = o[key];
837
838             // if a substitution function was provided, execute it
839             if (f) {
840                 v = f(key, v, meta);
841             }
842
843             if (L.isObject(v)) {
844                 if (L.isArray(v)) {
845                     v = L.dump(v, parseInt(meta, 10));
846                 } else {
847                     meta = meta || "";
848
849                     // look for the keyword 'dump', if found force obj dump
850                     dump = meta.indexOf(DUMP);
851                     if (dump > -1) {
852                         meta = meta.substring(4);
853                     }
854
855                     objstr = v.toString();
856
857                     // use the toString if it is not the Object toString 
858                     // and the 'dump' meta info was not found
859                     if (objstr === OBJECT_TOSTRING || dump > -1) {
860                         v = L.dump(v, parseInt(meta, 10));
861                     } else {
862                         v = objstr;
863                     }
864                 }
865             } else if (!L.isString(v) && !L.isNumber(v)) {
866                 // This {block} has no replace string. Save it for later.
867                 v = "~-" + saved.length + "-~";
868                 saved[saved.length] = token;
869
870                 // break;
871             }
872
873             s = s.substring(0, i) + v + s.substring(j + 1);
874
875
876         }
877
878         // restore saved {block}s
879         for (i=saved.length-1; i>=0; i=i-1) {
880             s = s.replace(new RegExp("~-" + i + "-~"), "{"  + saved[i] + "}", "g");
881         }
882
883         return s;
884     },
885
886
887     /**
888      * Returns a string without any leading or trailing whitespace.  If 
889      * the input is not a string, the input will be returned untouched.
890      * @method trim
891      * @since 2.3.0
892      * @param s {string} the string to trim
893      * @return {string} the trimmed string
894      */
895     trim: function(s){
896         try {
897             return s.replace(/^\s+|\s+$/g, "");
898         } catch(e) {
899             return s;
900         }
901     },
902
903     /**
904      * Returns a new object containing all of the properties of
905      * all the supplied objects.  The properties from later objects
906      * will overwrite those in earlier objects.
907      * @method merge
908      * @since 2.3.0
909      * @param arguments {Object*} the objects to merge
910      * @return the new merged object
911      */
912     merge: function() {
913         var o={}, a=arguments, l=a.length, i;
914         for (i=0; i<l; i=i+1) {
915             L.augmentObject(o, a[i], true);
916         }
917         return o;
918     },
919
920     /**
921      * Executes the supplied function in the context of the supplied 
922      * object 'when' milliseconds later.  Executes the function a 
923      * single time unless periodic is set to true.
924      * @method later
925      * @since 2.4.0
926      * @param when {int} the number of milliseconds to wait until the fn 
927      * is executed
928      * @param o the context object
929      * @param fn {Function|String} the function to execute or the name of 
930      * the method in the 'o' object to execute
931      * @param data [Array] data that is provided to the function.  This accepts
932      * either a single item or an array.  If an array is provided, the
933      * function is executed with one parameter for each array item.  If
934      * you need to pass a single array parameter, it needs to be wrapped in
935      * an array [myarray]
936      * @param periodic {boolean} if true, executes continuously at supplied 
937      * interval until canceled
938      * @return a timer object. Call the cancel() method on this object to 
939      * stop the timer.
940      */
941     later: function(when, o, fn, data, periodic) {
942         when = when || 0; 
943         o = o || {};
944         var m=fn, d=data, f, r;
945
946         if (L.isString(fn)) {
947             m = o[fn];
948         }
949
950         if (!m) {
951             throw new TypeError("method undefined");
952         }
953
954         if (d && !L.isArray(d)) {
955             d = [data];
956         }
957
958         f = function() {
959             m.apply(o, d || NOTHING);
960         };
961
962         r = (periodic) ? setInterval(f, when) : setTimeout(f, when);
963
964         return {
965             interval: periodic,
966             cancel: function() {
967                 if (this.interval) {
968                     clearInterval(r);
969                 } else {
970                     clearTimeout(r);
971                 }
972             }
973         };
974     },
975     
976     /**
977      * A convenience method for detecting a legitimate non-null value.
978      * Returns false for null/undefined/NaN, true for other values, 
979      * including 0/false/''
980      * @method isValue
981      * @since 2.3.0
982      * @param o {any} the item to test
983      * @return {boolean} true if it is not null/undefined/NaN || false
984      */
985     isValue: function(o) {
986         // return (o || o === false || o === 0 || o === ''); // Infinity fails
987 return (L.isObject(o) || L.isString(o) || L.isNumber(o) || L.isBoolean(o));
988     }
989
990 };
991
992 /**
993  * Determines whether or not the property was added
994  * to the object instance.  Returns false if the property is not present
995  * in the object, or was inherited from the prototype.
996  * This abstraction is provided to enable hasOwnProperty for Safari 1.3.x.
997  * There is a discrepancy between YAHOO.lang.hasOwnProperty and
998  * Object.prototype.hasOwnProperty when the property is a primitive added to
999  * both the instance AND prototype with the same value:
1000  * <pre>
1001  * var A = function() {};
1002  * A.prototype.foo = 'foo';
1003  * var a = new A();
1004  * a.foo = 'foo';
1005  * alert(a.hasOwnProperty('foo')); // true
1006  * alert(YAHOO.lang.hasOwnProperty(a, 'foo')); // false when using fallback
1007  * </pre>
1008  * @method hasOwnProperty
1009  * @param {any} o The object being testing
1010  * @param prop {string} the name of the property to test
1011  * @return {boolean} the result
1012  */
1013 L.hasOwnProperty = (OP.hasOwnProperty) ?
1014     function(o, prop) {
1015         return o && o.hasOwnProperty(prop);
1016     } : function(o, prop) {
1017         return !L.isUndefined(o[prop]) && 
1018                 o.constructor.prototype[prop] !== o[prop];
1019     };
1020
1021 // new lang wins
1022 OB.augmentObject(L, OB, true);
1023
1024 /*
1025  * An alias for <a href="YAHOO.lang.html">YAHOO.lang</a>
1026  * @class YAHOO.util.Lang
1027  */
1028 YAHOO.util.Lang = L;
1029  
1030 /**
1031  * Same as YAHOO.lang.augmentObject, except it only applies prototype 
1032  * properties.  This is an alias for augmentProto.
1033  * @see YAHOO.lang.augmentObject
1034  * @method augment
1035  * @static
1036  * @param {Function} r  the object to receive the augmentation
1037  * @param {Function} s  the object that supplies the properties to augment
1038  * @param {String*|boolean}  arguments zero or more properties methods to 
1039  *        augment the receiver with.  If none specified, everything
1040  *        in the supplier will be used unless it would
1041  *        overwrite an existing property in the receiver.  if true
1042  *        is specified as the third parameter, all properties will
1043  *        be applied and will overwrite an existing property in
1044  *        the receiver
1045  */
1046 L.augment = L.augmentProto;
1047
1048 /**
1049  * An alias for <a href="YAHOO.lang.html#augment">YAHOO.lang.augment</a>
1050  * @for YAHOO
1051  * @method augment
1052  * @static
1053  * @param {Function} r  the object to receive the augmentation
1054  * @param {Function} s  the object that supplies the properties to augment
1055  * @param {String*}  arguments zero or more properties methods to 
1056  *        augment the receiver with.  If none specified, everything
1057  *        in the supplier will be used unless it would
1058  *        overwrite an existing property in the receiver
1059  */
1060 YAHOO.augment = L.augmentProto;
1061        
1062 /**
1063  * An alias for <a href="YAHOO.lang.html#extend">YAHOO.lang.extend</a>
1064  * @method extend
1065  * @static
1066  * @param {Function} subc   the object to modify
1067  * @param {Function} superc the object to inherit
1068  * @param {Object} overrides  additional properties/methods to add to the
1069  *        subclass prototype.  These will override the
1070  *        matching items obtained from the superclass if present.
1071  */
1072 YAHOO.extend = L.extend;
1073
1074 })();
1075 YAHOO.register("yahoo", YAHOO, {version: "2.8.0r4", build: "2449"});