Project

General

Profile

1
/*
2
Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3
Code licensed under the BSD License:
4
http://developer.yahoo.net/yui/license.txt
5
version: 2.4.1
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
 * @method namespace
92
 * @static
93
 * @param  {String*} arguments 1-n namespaces to create 
94
 * @return {Object}  A reference to the last namespace object created
95
 */
96
YAHOO.namespace = function() {
97
    var a=arguments, o=null, i, j, d;
98
    for (i=0; i<a.length; i=i+1) {
99
        d=a[i].split(".");
100
        o=YAHOO;
101

    
102
        // YAHOO is implied, so it is ignored if it is included
103
        for (j=(d[0] == "YAHOO") ? 1 : 0; j<d.length; j=j+1) {
104
            o[d[j]]=o[d[j]] || {};
105
            o=o[d[j]];
106
        }
107
    }
108

    
109
    return o;
110
};
111

    
112
/**
113
 * Uses YAHOO.widget.Logger to output a log message, if the widget is
114
 * available.
115
 *
116
 * @method log
117
 * @static
118
 * @param  {String}  msg  The message to log.
119
 * @param  {String}  cat  The log category for the message.  Default
120
 *                        categories are "info", "warn", "error", time".
121
 *                        Custom categories can be used as well. (opt)
122
 * @param  {String}  src  The source of the the message (opt)
123
 * @return {Boolean}      True if the log operation was successful.
124
 */
125
YAHOO.log = function(msg, cat, src) {
126
    var l=YAHOO.widget.Logger;
127
    if(l && l.log) {
128
        return l.log(msg, cat, src);
129
    } else {
130
        return false;
131
    }
132
};
133

    
134
/**
135
 * Registers a module with the YAHOO object
136
 * @method register
137
 * @static
138
 * @param {String}   name    the name of the module (event, slider, etc)
139
 * @param {Function} mainClass a reference to class in the module.  This
140
 *                             class will be tagged with the version info
141
 *                             so that it will be possible to identify the
142
 *                             version that is in use when multiple versions
143
 *                             have loaded
144
 * @param {Object}   data      metadata object for the module.  Currently it
145
 *                             is expected to contain a "version" property
146
 *                             and a "build" property at minimum.
147
 */
148
YAHOO.register = function(name, mainClass, data) {
149
    var mods = YAHOO.env.modules;
150
    if (!mods[name]) {
151
        mods[name] = { versions:[], builds:[] };
152
    }
153
    var m=mods[name],v=data.version,b=data.build,ls=YAHOO.env.listeners;
154
    m.name = name;
155
    m.version = v;
156
    m.build = b;
157
    m.versions.push(v);
158
    m.builds.push(b);
159
    m.mainClass = mainClass;
160
    // fire the module load listeners
161
    for (var i=0;i<ls.length;i=i+1) {
162
        ls[i](m);
163
    }
164
    // label the main class
165
    if (mainClass) {
166
        mainClass.VERSION = v;
167
        mainClass.BUILD = b;
168
    } else {
169
        YAHOO.log("mainClass is undefined for module " + name, "warn");
170
    }
171
};
172

    
173
/**
174
 * YAHOO.env is used to keep track of what is known about the YUI library and
175
 * the browsing environment
176
 * @class YAHOO.env
177
 * @static
178
 */
179
YAHOO.env = YAHOO.env || {
180

    
181
    /**
182
     * Keeps the version info for all YUI modules that have reported themselves
183
     * @property modules
184
     * @type Object[]
185
     */
186
    modules: [],
187
    
188
    /**
189
     * List of functions that should be executed every time a YUI module
190
     * reports itself.
191
     * @property listeners
192
     * @type Function[]
193
     */
194
    listeners: []
195
};
196

    
197
/**
198
 * Returns the version data for the specified module:
199
 *      <dl>
200
 *      <dt>name:</dt>      <dd>The name of the module</dd>
201
 *      <dt>version:</dt>   <dd>The version in use</dd>
202
 *      <dt>build:</dt>     <dd>The build number in use</dd>
203
 *      <dt>versions:</dt>  <dd>All versions that were registered</dd>
204
 *      <dt>builds:</dt>    <dd>All builds that were registered.</dd>
205
 *      <dt>mainClass:</dt> <dd>An object that was was stamped with the
206
 *                 current version and build. If 
207
 *                 mainClass.VERSION != version or mainClass.BUILD != build,
208
 *                 multiple versions of pieces of the library have been
209
 *                 loaded, potentially causing issues.</dd>
210
 *       </dl>
211
 *
212
 * @method getVersion
213
 * @static
214
 * @param {String}  name the name of the module (event, slider, etc)
215
 * @return {Object} The version info
216
 */
217
YAHOO.env.getVersion = function(name) {
218
    return YAHOO.env.modules[name] || null;
219
};
220

    
221
/**
222
 * Do not fork for a browser if it can be avoided.  Use feature detection when
223
 * you can.  Use the user agent as a last resort.  YAHOO.env.ua stores a version
224
 * number for the browser engine, 0 otherwise.  This value may or may not map
225
 * to the version number of the browser using the engine.  The value is 
226
 * presented as a float so that it can easily be used for boolean evaluation 
227
 * as well as for looking for a particular range of versions.  Because of this, 
228
 * some of the granularity of the version info may be lost (e.g., Gecko 1.8.0.9 
229
 * reports 1.8).
230
 * @class YAHOO.env.ua
231
 * @static
232
 */
233
YAHOO.env.ua = function() {
234
    var o={
235

    
236
        /**
237
         * Internet Explorer version number or 0.  Example: 6
238
         * @property ie
239
         * @type float
240
         */
241
        ie:0,
242

    
243
        /**
244
         * Opera version number or 0.  Example: 9.2
245
         * @property opera
246
         * @type float
247
         */
248
        opera:0,
249

    
250
        /**
251
         * Gecko engine revision number.  Will evaluate to 1 if Gecko 
252
         * is detected but the revision could not be found. Other browsers
253
         * will be 0.  Example: 1.8
254
         * <pre>
255
         * Firefox 1.0.0.4: 1.7.8   <-- Reports 1.7
256
         * Firefox 1.5.0.9: 1.8.0.9 <-- Reports 1.8
257
         * Firefox 2.0.0.3: 1.8.1.3 <-- Reports 1.8
258
         * Firefox 3 alpha: 1.9a4   <-- Reports 1.9
259
         * </pre>
260
         * @property gecko
261
         * @type float
262
         */
263
        gecko:0,
264

    
265
        /**
266
         * AppleWebKit version.  KHTML browsers that are not WebKit browsers 
267
         * will evaluate to 1, other browsers 0.  Example: 418.9.1
268
         * <pre>
269
         * Safari 1.3.2 (312.6): 312.8.1 <-- Reports 312.8 -- currently the 
270
         *                                   latest available for Mac OSX 10.3.
271
         * Safari 2.0.2:         416     <-- hasOwnProperty introduced
272
         * Safari 2.0.4:         418     <-- preventDefault fixed
273
         * Safari 2.0.4 (419.3): 418.9.1 <-- One version of Safari may run
274
         *                                   different versions of webkit
275
         * Safari 2.0.4 (419.3): 419     <-- Current Safari release
276
         * Webkit 212 nightly:   522+    <-- Safari 3.0 (with native SVG) should
277
         *                                   be higher than this
278
         *                                   
279
         * </pre>
280
         * http://developer.apple.com/internet/safari/uamatrix.html
281
         * @property webkit
282
         * @type float
283
         */
284
        webkit:0,
285

    
286
        /**
287
         * The mobile property will be set to a string containing any relevant
288
         * user agent information when a modern mobile browser is detected.
289
         * Currently limited to Safari on the iPhone/iPod Touch, Nokia N-series
290
         * devices with the WebKit-based browser, and Opera Mini.  
291
         * @property mobile 
292
         * @type string
293
         */
294
        mobile: null 
295
    };
296

    
297
    var ua=navigator.userAgent, m;
298

    
299
    // Modern KHTML browsers should qualify as Safari X-Grade
300
    if ((/KHTML/).test(ua)) {
301
        o.webkit=1;
302
    }
303
    // Modern WebKit browsers are at least X-Grade
304
    m=ua.match(/AppleWebKit\/([^\s]*)/);
305
    if (m&&m[1]) {
306
        o.webkit=parseFloat(m[1]);
307

    
308
        // Mobile browser check
309
        if (/ Mobile\//.test(ua)) {
310
            o.mobile = "Apple"; // iPhone or iPod Touch
311
        } else {
312
            m=ua.match(/NokiaN[^\/]*/);
313
            if (m) {
314
                o.mobile = m[0]; // Nokia N-series, ex: NokiaN95
315
            }
316
        }
317

    
318
    }
319

    
320
    if (!o.webkit) { // not webkit
321
        // @todo check Opera/8.01 (J2ME/MIDP; Opera Mini/2.0.4509/1316; fi; U; ssr)
322
        m=ua.match(/Opera[\s\/]([^\s]*)/);
323
        if (m&&m[1]) {
324
            o.opera=parseFloat(m[1]);
325
            m=ua.match(/Opera Mini[^;]*/);
326
            if (m) {
327
                o.mobile = m[0]; // ex: Opera Mini/2.0.4509/1316
328
            }
329
        } else { // not opera or webkit
330
            m=ua.match(/MSIE\s([^;]*)/);
331
            if (m&&m[1]) {
332
                o.ie=parseFloat(m[1]);
333
            } else { // not opera, webkit, or ie
334
                m=ua.match(/Gecko\/([^\s]*)/);
335
                if (m) {
336
                    o.gecko=1; // Gecko detected, look for revision
337
                    m=ua.match(/rv:([^\s\)]*)/);
338
                    if (m&&m[1]) {
339
                        o.gecko=parseFloat(m[1]);
340
                    }
341
                }
342
            }
343
        }
344
    }
345
    
346
    return o;
347
}();
348

    
349
/*
350
 * Initializes the global by creating the default namespaces and applying
351
 * any new configuration information that is detected.  This is the setup
352
 * for env.
353
 * @method init
354
 * @static
355
 * @private
356
 */
357
(function() {
358
    YAHOO.namespace("util", "widget", "example");
359
    if ("undefined" !== typeof YAHOO_config) {
360
        var l=YAHOO_config.listener,ls=YAHOO.env.listeners,unique=true,i;
361
        if (l) {
362
            // if YAHOO is loaded multiple times we need to check to see if
363
            // this is a new config object.  If it is, add the new component
364
            // load listener to the stack
365
            for (i=0;i<ls.length;i=i+1) {
366
                if (ls[i]==l) {
367
                    unique=false;
368
                    break;
369
                }
370
            }
371
            if (unique) {
372
                ls.push(l);
373
            }
374
        }
375
    }
376
})();
377
/**
378
 * Provides the language utilites and extensions used by the library
379
 * @class YAHOO.lang
380
 */
381
YAHOO.lang = YAHOO.lang || {
382
    /**
383
     * Determines whether or not the provided object is an array.
384
     * Testing typeof/instanceof/constructor of arrays across frame 
385
     * boundaries isn't possible in Safari unless you have a reference
386
     * to the other frame to test against its Array prototype.  To
387
     * handle this case, we test well-known array properties instead.
388
     * properties.
389
     * @method isArray
390
     * @param {any} o The object being testing
391
     * @return Boolean
392
     */
393
    isArray: function(o) { 
394

    
395
        if (o) {
396
           var l = YAHOO.lang;
397
           return l.isNumber(o.length) && l.isFunction(o.splice);
398
        }
399
        return false;
400
    },
401

    
402
    /**
403
     * Determines whether or not the provided object is a boolean
404
     * @method isBoolean
405
     * @param {any} o The object being testing
406
     * @return Boolean
407
     */
408
    isBoolean: function(o) {
409
        return typeof o === 'boolean';
410
    },
411
    
412
    /**
413
     * Determines whether or not the provided object is a function
414
     * @method isFunction
415
     * @param {any} o The object being testing
416
     * @return Boolean
417
     */
418
    isFunction: function(o) {
419
        return typeof o === 'function';
420
    },
421
        
422
    /**
423
     * Determines whether or not the provided object is null
424
     * @method isNull
425
     * @param {any} o The object being testing
426
     * @return Boolean
427
     */
428
    isNull: function(o) {
429
        return o === null;
430
    },
431
        
432
    /**
433
     * Determines whether or not the provided object is a legal number
434
     * @method isNumber
435
     * @param {any} o The object being testing
436
     * @return Boolean
437
     */
438
    isNumber: function(o) {
439
        return typeof o === 'number' && isFinite(o);
440
    },
441
      
442
    /**
443
     * Determines whether or not the provided object is of type object
444
     * or function
445
     * @method isObject
446
     * @param {any} o The object being testing
447
     * @return Boolean
448
     */  
449
    isObject: function(o) {
450
return (o && (typeof o === 'object' || YAHOO.lang.isFunction(o))) || false;
451
    },
452
        
453
    /**
454
     * Determines whether or not the provided object is a string
455
     * @method isString
456
     * @param {any} o The object being testing
457
     * @return Boolean
458
     */
459
    isString: function(o) {
460
        return typeof o === 'string';
461
    },
462
        
463
    /**
464
     * Determines whether or not the provided object is undefined
465
     * @method isUndefined
466
     * @param {any} o The object being testing
467
     * @return Boolean
468
     */
469
    isUndefined: function(o) {
470
        return typeof o === 'undefined';
471
    },
472
    
473
    /**
474
     * Determines whether or not the property was added
475
     * to the object instance.  Returns false if the property is not present
476
     * in the object, or was inherited from the prototype.
477
     * This abstraction is provided to enable hasOwnProperty for Safari 1.3.x.
478
     * There is a discrepancy between YAHOO.lang.hasOwnProperty and
479
     * Object.prototype.hasOwnProperty when the property is a primitive added to
480
     * both the instance AND prototype with the same value:
481
     * <pre>
482
     * var A = function() {};
483
     * A.prototype.foo = 'foo';
484
     * var a = new A();
485
     * a.foo = 'foo';
486
     * alert(a.hasOwnProperty('foo')); // true
487
     * alert(YAHOO.lang.hasOwnProperty(a, 'foo')); // false when using fallback
488
     * </pre>
489
     * @method hasOwnProperty
490
     * @param {any} o The object being testing
491
     * @return Boolean
492
     */
493
    hasOwnProperty: function(o, prop) {
494
        if (Object.prototype.hasOwnProperty) {
495
            return o.hasOwnProperty(prop);
496
        }
497
        
498
        return !YAHOO.lang.isUndefined(o[prop]) && 
499
                o.constructor.prototype[prop] !== o[prop];
500
    },
501
 
502
    /**
503
     * IE will not enumerate native functions in a derived object even if the
504
     * function was overridden.  This is a workaround for specific functions 
505
     * we care about on the Object prototype. 
506
     * @property _IEEnumFix
507
     * @param {Function} r  the object to receive the augmentation
508
     * @param {Function} s  the object that supplies the properties to augment
509
     * @static
510
     * @private
511
     */
512
    _IEEnumFix: function(r, s) {
513
        if (YAHOO.env.ua.ie) {
514
            var add=["toString", "valueOf"], i;
515
            for (i=0;i<add.length;i=i+1) {
516
                var fname=add[i],f=s[fname];
517
                if (YAHOO.lang.isFunction(f) && f!=Object.prototype[fname]) {
518
                    r[fname]=f;
519
                }
520
            }
521
        }
522
    },
523
       
524
    /**
525
     * Utility to set up the prototype, constructor and superclass properties to
526
     * support an inheritance strategy that can chain constructors and methods.
527
     * Static members will not be inherited.
528
     *
529
     * @method extend
530
     * @static
531
     * @param {Function} subc   the object to modify
532
     * @param {Function} superc the object to inherit
533
     * @param {Object} overrides  additional properties/methods to add to the
534
     *                              subclass prototype.  These will override the
535
     *                              matching items obtained from the superclass 
536
     *                              if present.
537
     */
538
    extend: function(subc, superc, overrides) {
539
        if (!superc||!subc) {
540
            throw new Error("YAHOO.lang.extend failed, please check that " +
541
                            "all dependencies are included.");
542
        }
543
        var F = function() {};
544
        F.prototype=superc.prototype;
545
        subc.prototype=new F();
546
        subc.prototype.constructor=subc;
547
        subc.superclass=superc.prototype;
548
        if (superc.prototype.constructor == Object.prototype.constructor) {
549
            superc.prototype.constructor=superc;
550
        }
551
    
552
        if (overrides) {
553
            for (var i in overrides) {
554
                subc.prototype[i]=overrides[i];
555
            }
556

    
557
            YAHOO.lang._IEEnumFix(subc.prototype, overrides);
558
        }
559
    },
560
   
561
    /**
562
     * Applies all properties in the supplier to the receiver if the
563
     * receiver does not have these properties yet.  Optionally, one or 
564
     * more methods/properties can be specified (as additional 
565
     * parameters).  This option will overwrite the property if receiver 
566
     * has it already.  If true is passed as the third parameter, all 
567
     * properties will be applied and _will_ overwrite properties in 
568
     * the receiver.
569
     *
570
     * @method augmentObject
571
     * @static
572
     * @since 2.3.0
573
     * @param {Function} r  the object to receive the augmentation
574
     * @param {Function} s  the object that supplies the properties to augment
575
     * @param {String*|boolean}  arguments zero or more properties methods 
576
     *        to augment the receiver with.  If none specified, everything
577
     *        in the supplier will be used unless it would
578
     *        overwrite an existing property in the receiver. If true
579
     *        is specified as the third parameter, all properties will
580
     *        be applied and will overwrite an existing property in
581
     *        the receiver
582
     */
583
    augmentObject: function(r, s) {
584
        if (!s||!r) {
585
            throw new Error("Absorb failed, verify dependencies.");
586
        }
587
        var a=arguments, i, p, override=a[2];
588
        if (override && override!==true) { // only absorb the specified properties
589
            for (i=2; i<a.length; i=i+1) {
590
                r[a[i]] = s[a[i]];
591
            }
592
        } else { // take everything, overwriting only if the third parameter is true
593
            for (p in s) { 
594
                if (override || !r[p]) {
595
                    r[p] = s[p];
596
                }
597
            }
598
            
599
            YAHOO.lang._IEEnumFix(r, s);
600
        }
601
    },
602
 
603
    /**
604
     * Same as YAHOO.lang.augmentObject, except it only applies prototype properties
605
     * @see YAHOO.lang.augmentObject
606
     * @method augmentProto
607
     * @static
608
     * @param {Function} r  the object to receive the augmentation
609
     * @param {Function} s  the object that supplies the properties to augment
610
     * @param {String*|boolean}  arguments zero or more properties methods 
611
     *        to augment the receiver with.  If none specified, everything 
612
     *        in the supplier will be used unless it would overwrite an existing 
613
     *        property in the receiver.  if true is specified as the third 
614
     *        parameter, all properties will be applied and will overwrite an 
615
     *        existing property in the receiver
616
     */
617
    augmentProto: function(r, s) {
618
        if (!s||!r) {
619
            throw new Error("Augment failed, verify dependencies.");
620
        }
621
        //var a=[].concat(arguments);
622
        var a=[r.prototype,s.prototype];
623
        for (var i=2;i<arguments.length;i=i+1) {
624
            a.push(arguments[i]);
625
        }
626
        YAHOO.lang.augmentObject.apply(this, a);
627
    },
628

    
629
      
630
    /**
631
     * Returns a simple string representation of the object or array.
632
     * Other types of objects will be returned unprocessed.  Arrays
633
     * are expected to be indexed.  Use object notation for
634
     * associative arrays.
635
     * @method dump
636
     * @since 2.3.0
637
     * @param o {Object} The object to dump
638
     * @param d {int} How deep to recurse child objects, default 3
639
     * @return {String} the dump result
640
     */
641
    dump: function(o, d) {
642
        var l=YAHOO.lang,i,len,s=[],OBJ="{...}",FUN="f(){...}",
643
            COMMA=', ', ARROW=' => ';
644

    
645
        // Cast non-objects to string
646
        // Skip dates because the std toString is what we want
647
        // Skip HTMLElement-like objects because trying to dump 
648
        // an element will cause an unhandled exception in FF 2.x
649
        if (!l.isObject(o)) {
650
            return o + "";
651
        } else if (o instanceof Date || ("nodeType" in o && "tagName" in o)) {
652
            return o;
653
        } else if  (l.isFunction(o)) {
654
            return FUN;
655
        }
656

    
657
        // dig into child objects the depth specifed. Default 3
658
        d = (l.isNumber(d)) ? d : 3;
659

    
660
        // arrays [1, 2, 3]
661
        if (l.isArray(o)) {
662
            s.push("[");
663
            for (i=0,len=o.length;i<len;i=i+1) {
664
                if (l.isObject(o[i])) {
665
                    s.push((d > 0) ? l.dump(o[i], d-1) : OBJ);
666
                } else {
667
                    s.push(o[i]);
668
                }
669
                s.push(COMMA);
670
            }
671
            if (s.length > 1) {
672
                s.pop();
673
            }
674
            s.push("]");
675
        // objects {k1 => v1, k2 => v2}
676
        } else {
677
            s.push("{");
678
            for (i in o) {
679
                if (l.hasOwnProperty(o, i)) {
680
                    s.push(i + ARROW);
681
                    if (l.isObject(o[i])) {
682
                        s.push((d > 0) ? l.dump(o[i], d-1) : OBJ);
683
                    } else {
684
                        s.push(o[i]);
685
                    }
686
                    s.push(COMMA);
687
                }
688
            }
689
            if (s.length > 1) {
690
                s.pop();
691
            }
692
            s.push("}");
693
        }
694

    
695
        return s.join("");
696
    },
697

    
698
    /**
699
     * Does variable substitution on a string. It scans through the string 
700
     * looking for expressions enclosed in { } braces. If an expression 
701
     * is found, it is used a key on the object.  If there is a space in
702
     * the key, the first word is used for the key and the rest is provided
703
     * to an optional function to be used to programatically determine the
704
     * value (the extra information might be used for this decision). If 
705
     * the value for the key in the object, or what is returned from the
706
     * function has a string value, number value, or object value, it is 
707
     * substituted for the bracket expression and it repeats.  If this
708
     * value is an object, it uses the Object's toString() if this has
709
     * been overridden, otherwise it does a shallow dump of the key/value
710
     * pairs.
711
     * @method substitute
712
     * @since 2.3.0
713
     * @param s {String} The string that will be modified.
714
     * @param o {Object} An object containing the replacement values
715
     * @param f {Function} An optional function that can be used to
716
     *                     process each match.  It receives the key,
717
     *                     value, and any extra metadata included with
718
     *                     the key inside of the braces.
719
     * @return {String} the substituted string
720
     */
721
    substitute: function (s, o, f) {
722
        var i, j, k, key, v, meta, l=YAHOO.lang, saved=[], token, 
723
            DUMP='dump', SPACE=' ', LBRACE='{', RBRACE='}';
724

    
725

    
726
        for (;;) {
727
            i = s.lastIndexOf(LBRACE);
728
            if (i < 0) {
729
                break;
730
            }
731
            j = s.indexOf(RBRACE, i);
732
            if (i + 1 >= j) {
733
                break;
734
            }
735

    
736
            //Extract key and meta info 
737
            token = s.substring(i + 1, j);
738
            key = token;
739
            meta = null;
740
            k = key.indexOf(SPACE);
741
            if (k > -1) {
742
                meta = key.substring(k + 1);
743
                key = key.substring(0, k);
744
            }
745

    
746
            // lookup the value
747
            v = o[key];
748

    
749
            // if a substitution function was provided, execute it
750
            if (f) {
751
                v = f(key, v, meta);
752
            }
753

    
754
            if (l.isObject(v)) {
755
                if (l.isArray(v)) {
756
                    v = l.dump(v, parseInt(meta, 10));
757
                } else {
758
                    meta = meta || "";
759

    
760
                    // look for the keyword 'dump', if found force obj dump
761
                    var dump = meta.indexOf(DUMP);
762
                    if (dump > -1) {
763
                        meta = meta.substring(4);
764
                    }
765

    
766
                    // use the toString if it is not the Object toString 
767
                    // and the 'dump' meta info was not found
768
                    if (v.toString===Object.prototype.toString||dump>-1) {
769
                        v = l.dump(v, parseInt(meta, 10));
770
                    } else {
771
                        v = v.toString();
772
                    }
773
                }
774
            } else if (!l.isString(v) && !l.isNumber(v)) {
775
                // This {block} has no replace string. Save it for later.
776
                v = "~-" + saved.length + "-~";
777
                saved[saved.length] = token;
778

    
779
                // break;
780
            }
781

    
782
            s = s.substring(0, i) + v + s.substring(j + 1);
783

    
784

    
785
        }
786

    
787
        // restore saved {block}s
788
        for (i=saved.length-1; i>=0; i=i-1) {
789
            s = s.replace(new RegExp("~-" + i + "-~"), "{"  + saved[i] + "}", "g");
790
        }
791

    
792
        return s;
793
    },
794

    
795

    
796
    /**
797
     * Returns a string without any leading or trailing whitespace.  If 
798
     * the input is not a string, the input will be returned untouched.
799
     * @method trim
800
     * @since 2.3.0
801
     * @param s {string} the string to trim
802
     * @return {string} the trimmed string
803
     */
804
    trim: function(s){
805
        try {
806
            return s.replace(/^\s+|\s+$/g, "");
807
        } catch(e) {
808
            return s;
809
        }
810
    },
811

    
812
    /**
813
     * Returns a new object containing all of the properties of
814
     * all the supplied objects.  The properties from later objects
815
     * will overwrite those in earlier objects.
816
     * @method merge
817
     * @since 2.3.0
818
     * @param arguments {Object*} the objects to merge
819
     * @return the new merged object
820
     */
821
    merge: function() {
822
        var o={}, a=arguments;
823
        for (var i=0, l=a.length; i<l; i=i+1) {
824
            YAHOO.lang.augmentObject(o, a[i], true);
825
        }
826
        return o;
827
    },
828

    
829
    /**
830
     * Executes the supplied function in the scope of the supplied 
831
     * object 'when' milliseconds later.  Executes the function a 
832
     * single time unless periodic is set to true.
833
     * @method later
834
     * @since 2.4.0
835
     * @param when {int} the number of milliseconds to wait until the fn 
836
     * is executed
837
     * @param o the scope object
838
     * @param fn {Function|String} the function to execute or the name of 
839
     * the method in the 'o' object to execute
840
     * @param data [Array] data that is provided to the function.  This accepts
841
     * either a single item or an array.  If an array is provided, the
842
     * function is executed with one parameter for each array item.  If
843
     * you need to pass a single array parameter, it needs to be wrapped in
844
     * an array [myarray]
845
     * @param periodic {boolean} if true, executes continuously at supplied 
846
     * interval until canceled
847
     * @return a timer object. Call the cancel() method on this object to 
848
     * stop the timer.
849
     */
850
    later: function(when, o, fn, data, periodic) {
851
        when = when || 0; 
852
        o = o || {};
853
        var m=fn, d=data, f, r;
854

    
855
        if (YAHOO.lang.isString(fn)) {
856
            m = o[fn];
857
        }
858

    
859
        if (!m) {
860
            throw new TypeError("method undefined");
861
        }
862

    
863
        if (!YAHOO.lang.isArray(d)) {
864
            d = [data];
865
        }
866

    
867
        f = function() {
868
            m.apply(o, d);
869
        };
870

    
871
        r = (periodic) ? setInterval(f, when) : setTimeout(f, when);
872

    
873
        return {
874
            interval: periodic,
875
            cancel: function() {
876
                if (this.interval) {
877
                    clearInterval(r);
878
                } else {
879
                    clearTimeout(r);
880
                }
881
            }
882
        };
883
    },
884

    
885
    /**
886
     * A convenience method for detecting a legitimate non-null value.
887
     * Returns false for null/undefined/NaN, true for other values, 
888
     * including 0/false/''
889
     * @method isValue
890
     * @since 2.3.0
891
     * @param o {any} the item to test
892
     * @return {boolean} true if it is not null/undefined/NaN || false
893
     */
894
    isValue: function(o) {
895
        // return (o || o === false || o === 0 || o === ''); // Infinity fails
896
        var l = YAHOO.lang;
897
return (l.isObject(o) || l.isString(o) || l.isNumber(o) || l.isBoolean(o));
898
    }
899

    
900
};
901

    
902
/*
903
 * An alias for <a href="YAHOO.lang.html">YAHOO.lang</a>
904
 * @class YAHOO.util.Lang
905
 */
906
YAHOO.util.Lang = YAHOO.lang;
907
 
908
/**
909
 * Same as YAHOO.lang.augmentObject, except it only applies prototype 
910
 * properties.  This is an alias for augmentProto.
911
 * @see YAHOO.lang.augmentObject
912
 * @method augment
913
 * @static
914
 * @param {Function} r  the object to receive the augmentation
915
 * @param {Function} s  the object that supplies the properties to augment
916
 * @param {String*|boolean}  arguments zero or more properties methods to 
917
 *        augment the receiver with.  If none specified, everything
918
 *        in the supplier will be used unless it would
919
 *        overwrite an existing property in the receiver.  if true
920
 *        is specified as the third parameter, all properties will
921
 *        be applied and will overwrite an existing property in
922
 *        the receiver
923
 */
924
YAHOO.lang.augment = YAHOO.lang.augmentProto;
925

    
926
/**
927
 * An alias for <a href="YAHOO.lang.html#augment">YAHOO.lang.augment</a>
928
 * @for YAHOO
929
 * @method augment
930
 * @static
931
 * @param {Function} r  the object to receive the augmentation
932
 * @param {Function} s  the object that supplies the properties to augment
933
 * @param {String*}  arguments zero or more properties methods to 
934
 *        augment the receiver with.  If none specified, everything
935
 *        in the supplier will be used unless it would
936
 *        overwrite an existing property in the receiver
937
 */
938
YAHOO.augment = YAHOO.lang.augmentProto;
939
       
940
/**
941
 * An alias for <a href="YAHOO.lang.html#extend">YAHOO.lang.extend</a>
942
 * @method extend
943
 * @static
944
 * @param {Function} subc   the object to modify
945
 * @param {Function} superc the object to inherit
946
 * @param {Object} overrides  additional properties/methods to add to the
947
 *        subclass prototype.  These will override the
948
 *        matching items obtained from the superclass if present.
949
 */
950
YAHOO.extend = YAHOO.lang.extend;
951

    
952
YAHOO.register("yahoo", YAHOO, {version: "2.4.1", build: "742"});
(2-2/4)