Upgrade to ExtJS 3.1.1 - Released 02/08/2010
[extjs.git] / docs / source / Ext-more.html
1 <html>\r
2 <head>\r
3   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />    \r
4   <title>The source code</title>\r
5     <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />\r
6     <script type="text/javascript" src="../resources/prettify/prettify.js"></script>\r
7 </head>\r
8 <body  onload="prettyPrint();">\r
9     <pre class="prettyprint lang-js"><div id="cls-Ext"></div>/**
10  * @class Ext
11  */
12
13 Ext.ns("Ext.grid", "Ext.list", "Ext.dd", "Ext.tree", "Ext.form", "Ext.menu",
14        "Ext.state", "Ext.layout", "Ext.app", "Ext.ux", "Ext.chart", "Ext.direct");
15     <div id="prop-Ext-ux"></div>/**
16      * Namespace alloted for extensions to the framework.
17      * @property ux
18      * @type Object
19      */
20
21 Ext.apply(Ext, function(){
22     var E = Ext, 
23         idSeed = 0,
24         scrollWidth = null;
25
26     return {
27         <div id="prop-Ext-emptyFn"></div>/**
28         * A reusable empty function
29         * @property
30         * @type Function
31         */
32         emptyFn : function(){},
33
34         <div id="prop-Ext-BLANK_IMAGE_URL"></div>/**
35          * URL to a 1x1 transparent gif image used by Ext to create inline icons with CSS background images. 
36          * In older versions of IE, this defaults to "http://extjs.com/s.gif" and you should change this to a URL on your server.
37          * For other browsers it uses an inline data URL.
38          * @type String
39          */
40         BLANK_IMAGE_URL : Ext.isIE6 || Ext.isIE7 || Ext.isAir ?
41                             'http:/' + '/extjs.com/s.gif' :
42                             'data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==',
43
44         extendX : function(supr, fn){
45             return Ext.extend(supr, fn(supr.prototype));
46         },
47
48         <div id="method-Ext-getDoc"></div>/**
49          * Returns the current HTML document object as an {@link Ext.Element}.
50          * @return Ext.Element The document
51          */
52         getDoc : function(){
53             return Ext.get(document);
54         },
55
56         <div id="method-Ext-num"></div>/**
57          * Utility method for validating that a value is numeric, returning the specified default value if it is not.
58          * @param {Mixed} value Should be a number, but any type will be handled appropriately
59          * @param {Number} defaultValue The value to return if the original value is non-numeric
60          * @return {Number} Value, if numeric, else defaultValue
61          */
62         num : function(v, defaultValue){
63             v = Number(Ext.isEmpty(v) || Ext.isArray(v) || Ext.isBoolean(v) || (Ext.isString(v) && v.trim().length == 0) ? NaN : v);
64             return isNaN(v) ? defaultValue : v;
65         },
66
67         <div id="method-Ext-value"></div>/**
68          * <p>Utility method for returning a default value if the passed value is empty.</p>
69          * <p>The value is deemed to be empty if it is<div class="mdetail-params"><ul>
70          * <li>null</li>
71          * <li>undefined</li>
72          * <li>an empty array</li>
73          * <li>a zero length string (Unless the <tt>allowBlank</tt> parameter is <tt>true</tt>)</li>
74          * </ul></div>
75          * @param {Mixed} value The value to test
76          * @param {Mixed} defaultValue The value to return if the original value is empty
77          * @param {Boolean} allowBlank (optional) true to allow zero length strings to qualify as non-empty (defaults to false)
78          * @return {Mixed} value, if non-empty, else defaultValue
79          */
80         value : function(v, defaultValue, allowBlank){
81             return Ext.isEmpty(v, allowBlank) ? defaultValue : v;
82         },
83
84         <div id="method-Ext-escapeRe"></div>/**
85          * Escapes the passed string for use in a regular expression
86          * @param {String} str
87          * @return {String}
88          */
89         escapeRe : function(s) {
90             return s.replace(/([-.*+?^${}()|[\]\/\\])/g, "\\$1");
91         },
92
93         sequence : function(o, name, fn, scope){
94             o[name] = o[name].createSequence(fn, scope);
95         },
96
97         <div id="method-Ext-addBehaviors"></div>/**
98          * Applies event listeners to elements by selectors when the document is ready.
99          * The event name is specified with an <tt>&#64;</tt> suffix.
100          * <pre><code>
101 Ext.addBehaviors({
102     // add a listener for click on all anchors in element with id foo
103     '#foo a&#64;click' : function(e, t){
104         // do something
105     },
106     
107     // add the same listener to multiple selectors (separated by comma BEFORE the &#64;)
108     '#foo a, #bar span.some-class&#64;mouseover' : function(){
109         // do something
110     }
111 });
112          * </code></pre> 
113          * @param {Object} obj The list of behaviors to apply
114          */
115         addBehaviors : function(o){
116             if(!Ext.isReady){
117                 Ext.onReady(function(){
118                     Ext.addBehaviors(o);
119                 });
120             } else {
121                 var cache = {}, // simple cache for applying multiple behaviors to same selector does query multiple times
122                     parts,
123                     b,
124                     s;
125                 for (b in o) {
126                     if ((parts = b.split('@'))[1]) { // for Object prototype breakers
127                         s = parts[0];
128                         if(!cache[s]){
129                             cache[s] = Ext.select(s);
130                         }
131                         cache[s].on(parts[1], o[b]);
132                     }
133                 }
134                 cache = null;
135             }
136         },
137         
138         <div id="method-Ext-getScrollBarWidth"></div>/**
139          * Utility method for getting the width of the browser scrollbar. This can differ depending on
140          * operating system settings, such as the theme or font size.
141          * @param {Boolean} force (optional) true to force a recalculation of the value.
142          * @return {Number} The width of the scrollbar.
143          */
144         getScrollBarWidth: function(force){
145             if(!Ext.isReady){
146                 return 0;
147             }
148             
149             if(force === true || scrollWidth === null){
150                     // Append our div, do our calculation and then remove it
151                 var div = Ext.getBody().createChild('<div class="x-hide-offsets" style="width:100px;height:50px;overflow:hidden;"><div style="height:200px;"></div></div>'),
152                     child = div.child('div', true);
153                 var w1 = child.offsetWidth;
154                 div.setStyle('overflow', (Ext.isWebKit || Ext.isGecko) ? 'auto' : 'scroll');
155                 var w2 = child.offsetWidth;
156                 div.remove();
157                 // Need to add 2 to ensure we leave enough space
158                 scrollWidth = w1 - w2 + 2;
159             }
160             return scrollWidth;
161         },
162
163
164         // deprecated
165         combine : function(){
166             var as = arguments, l = as.length, r = [];
167             for(var i = 0; i < l; i++){
168                 var a = as[i];
169                 if(Ext.isArray(a)){
170                     r = r.concat(a);
171                 }else if(a.length !== undefined && !a.substr){
172                     r = r.concat(Array.prototype.slice.call(a, 0));
173                 }else{
174                     r.push(a);
175                 }
176             }
177             return r;
178         },
179
180         <div id="method-Ext-copyTo"></div>/**
181          * Copies a set of named properties fom the source object to the destination object.
182          * <p>example:<pre><code>
183 ImageComponent = Ext.extend(Ext.BoxComponent, {
184     initComponent: function() {
185         this.autoEl = { tag: 'img' };
186         MyComponent.superclass.initComponent.apply(this, arguments);
187         this.initialBox = Ext.copyTo({}, this.initialConfig, 'x,y,width,height');
188     }
189 });
190          * </code></pre> 
191          * @param {Object} The destination object.
192          * @param {Object} The source object.
193          * @param {Array/String} Either an Array of property names, or a comma-delimited list
194          * of property names to copy.
195          * @return {Object} The modified object.
196         */
197         copyTo : function(dest, source, names){
198             if(Ext.isString(names)){
199                 names = names.split(/[,;\s]/);
200             }
201             Ext.each(names, function(name){
202                 if(source.hasOwnProperty(name)){
203                     dest[name] = source[name];
204                 }
205             }, this);
206             return dest;
207         },
208
209         <div id="method-Ext-destroy"></div>/**
210          * Attempts to destroy any objects passed to it by removing all event listeners, removing them from the
211          * DOM (if applicable) and calling their destroy functions (if available).  This method is primarily
212          * intended for arguments of type {@link Ext.Element} and {@link Ext.Component}, but any subclass of
213          * {@link Ext.util.Observable} can be passed in.  Any number of elements and/or components can be
214          * passed into this function in a single call as separate arguments.
215          * @param {Mixed} arg1 An {@link Ext.Element}, {@link Ext.Component}, or an Array of either of these to destroy
216          * @param {Mixed} arg2 (optional)
217          * @param {Mixed} etc... (optional)
218          */
219         destroy : function(){
220             Ext.each(arguments, function(arg){
221                 if(arg){
222                     if(Ext.isArray(arg)){
223                         this.destroy.apply(this, arg);
224                     }else if(Ext.isFunction(arg.destroy)){
225                         arg.destroy();
226                     }else if(arg.dom){
227                         arg.remove();
228                     }    
229                 }
230             }, this);
231         },
232
233         <div id="method-Ext-destroyMembers"></div>/**
234          * Attempts to destroy and then remove a set of named properties of the passed object.
235          * @param {Object} o The object (most likely a Component) who's properties you wish to destroy.
236          * @param {Mixed} arg1 The name of the property to destroy and remove from the object.
237          * @param {Mixed} etc... More property names to destroy and remove.
238          */
239         destroyMembers : function(o, arg1, arg2, etc){
240             for(var i = 1, a = arguments, len = a.length; i < len; i++) {
241                 Ext.destroy(o[a[i]]);
242                 delete o[a[i]];
243             }
244         },
245
246         <div id="method-Ext-clean"></div>/**
247          * Creates a copy of the passed Array with falsy values removed.
248          * @param {Array/NodeList} arr The Array from which to remove falsy values.
249          * @return {Array} The new, compressed Array.
250          */
251         clean : function(arr){
252             var ret = [];
253             Ext.each(arr, function(v){
254                 if(!!v){
255                     ret.push(v);
256                 }
257             });
258             return ret;
259         },
260
261         <div id="method-Ext-unique"></div>/**
262          * Creates a copy of the passed Array, filtered to contain only unique values.
263          * @param {Array} arr The Array to filter
264          * @return {Array} The new Array containing unique values.
265          */
266         unique : function(arr){
267             var ret = [],
268                 collect = {};
269
270             Ext.each(arr, function(v) {
271                 if(!collect[v]){
272                     ret.push(v);
273                 }
274                 collect[v] = true;
275             });
276             return ret;
277         },
278
279         <div id="method-Ext-flatten"></div>/**
280          * Recursively flattens into 1-d Array. Injects Arrays inline.
281          * @param {Array} arr The array to flatten
282          * @return {Array} The new, flattened array.
283          */
284         flatten : function(arr){
285             var worker = [];
286             function rFlatten(a) {
287                 Ext.each(a, function(v) {
288                     if(Ext.isArray(v)){
289                         rFlatten(v);
290                     }else{
291                         worker.push(v);
292                     }
293                 });
294                 return worker;
295             }
296             return rFlatten(arr);
297         },
298
299         <div id="method-Ext-min"></div>/**
300          * Returns the minimum value in the Array.
301          * @param {Array|NodeList} arr The Array from which to select the minimum value.
302          * @param {Function} comp (optional) a function to perform the comparision which determines minimization.
303          *                   If omitted the "<" operator will be used. Note: gt = 1; eq = 0; lt = -1
304          * @return {Object} The minimum value in the Array.
305          */
306         min : function(arr, comp){
307             var ret = arr[0];
308             comp = comp || function(a,b){ return a < b ? -1 : 1; };
309             Ext.each(arr, function(v) {
310                 ret = comp(ret, v) == -1 ? ret : v;
311             });
312             return ret;
313         },
314
315         <div id="method-Ext-max"></div>/**
316          * Returns the maximum value in the Array
317          * @param {Array|NodeList} arr The Array from which to select the maximum value.
318          * @param {Function} comp (optional) a function to perform the comparision which determines maximization.
319          *                   If omitted the ">" operator will be used. Note: gt = 1; eq = 0; lt = -1
320          * @return {Object} The maximum value in the Array.
321          */
322         max : function(arr, comp){
323             var ret = arr[0];
324             comp = comp || function(a,b){ return a > b ? 1 : -1; };
325             Ext.each(arr, function(v) {
326                 ret = comp(ret, v) == 1 ? ret : v;
327             });
328             return ret;
329         },
330
331         <div id="method-Ext-mean"></div>/**
332          * Calculates the mean of the Array
333          * @param {Array} arr The Array to calculate the mean value of.
334          * @return {Number} The mean.
335          */
336         mean : function(arr){
337            return arr.length > 0 ? Ext.sum(arr) / arr.length : undefined;
338         },
339
340         <div id="method-Ext-sum"></div>/**
341          * Calculates the sum of the Array
342          * @param {Array} arr The Array to calculate the sum value of.
343          * @return {Number} The sum.
344          */
345         sum : function(arr){
346            var ret = 0;
347            Ext.each(arr, function(v) {
348                ret += v;
349            });
350            return ret;
351         },
352
353         <div id="method-Ext-partition"></div>/**
354          * Partitions the set into two sets: a true set and a false set.
355          * Example: 
356          * Example2: 
357          * <pre><code>
358 // Example 1:
359 Ext.partition([true, false, true, true, false]); // [[true, true, true], [false, false]]
360
361 // Example 2:
362 Ext.partition(
363     Ext.query("p"),
364     function(val){
365         return val.className == "class1"
366     }
367 );
368 // true are those paragraph elements with a className of "class1",
369 // false set are those that do not have that className.
370          * </code></pre>
371          * @param {Array|NodeList} arr The array to partition
372          * @param {Function} truth (optional) a function to determine truth.  If this is omitted the element
373          *                   itself must be able to be evaluated for its truthfulness.
374          * @return {Array} [true<Array>,false<Array>]
375          */
376         partition : function(arr, truth){
377             var ret = [[],[]];
378             Ext.each(arr, function(v, i, a) {
379                 ret[ (truth && truth(v, i, a)) || (!truth && v) ? 0 : 1].push(v);
380             });
381             return ret;
382         },
383
384         <div id="method-Ext-invoke"></div>/**
385          * Invokes a method on each item in an Array.
386          * <pre><code>
387 // Example:
388 Ext.invoke(Ext.query("p"), "getAttribute", "id");
389 // [el1.getAttribute("id"), el2.getAttribute("id"), ..., elN.getAttribute("id")]
390          * </code></pre>
391          * @param {Array|NodeList} arr The Array of items to invoke the method on.
392          * @param {String} methodName The method name to invoke.
393          * @param {Anything} ... Arguments to send into the method invocation.
394          * @return {Array} The results of invoking the method on each item in the array.
395          */
396         invoke : function(arr, methodName){
397             var ret = [],
398                 args = Array.prototype.slice.call(arguments, 2);
399             Ext.each(arr, function(v,i) {
400                 if (v && Ext.isFunction(v[methodName])) {
401                     ret.push(v[methodName].apply(v, args));
402                 } else {
403                     ret.push(undefined);
404                 }
405             });
406             return ret;
407         },
408
409         <div id="method-Ext-pluck"></div>/**
410          * Plucks the value of a property from each item in the Array
411          * <pre><code>
412 // Example:
413 Ext.pluck(Ext.query("p"), "className"); // [el1.className, el2.className, ..., elN.className]
414          * </code></pre>
415          * @param {Array|NodeList} arr The Array of items to pluck the value from.
416          * @param {String} prop The property name to pluck from each element.
417          * @return {Array} The value from each item in the Array.
418          */
419         pluck : function(arr, prop){
420             var ret = [];
421             Ext.each(arr, function(v) {
422                 ret.push( v[prop] );
423             });
424             return ret;
425         },
426
427         <div id="method-Ext-zip"></div>/**
428          * <p>Zips N sets together.</p>
429          * <pre><code>
430 // Example 1:
431 Ext.zip([1,2,3],[4,5,6]); // [[1,4],[2,5],[3,6]]
432 // Example 2:
433 Ext.zip(
434     [ "+", "-", "+"],
435     [  12,  10,  22],
436     [  43,  15,  96],
437     function(a, b, c){
438         return "$" + a + "" + b + "." + c
439     }
440 ); // ["$+12.43", "$-10.15", "$+22.96"]
441          * </code></pre>
442          * @param {Arrays|NodeLists} arr This argument may be repeated. Array(s) to contribute values.
443          * @param {Function} zipper (optional) The last item in the argument list. This will drive how the items are zipped together.
444          * @return {Array} The zipped set.
445          */
446         zip : function(){
447             var parts = Ext.partition(arguments, function( val ){ return !Ext.isFunction(val); }),
448                 arrs = parts[0],
449                 fn = parts[1][0],
450                 len = Ext.max(Ext.pluck(arrs, "length")),
451                 ret = [];
452
453             for (var i = 0; i < len; i++) {
454                 ret[i] = [];
455                 if(fn){
456                     ret[i] = fn.apply(fn, Ext.pluck(arrs, i));
457                 }else{
458                     for (var j = 0, aLen = arrs.length; j < aLen; j++){
459                         ret[i].push( arrs[j][i] );
460                     }
461                 }
462             }
463             return ret;
464         },
465
466         <div id="method-Ext-getCmp"></div>/**
467          * This is shorthand reference to {@link Ext.ComponentMgr#get}.
468          * Looks up an existing {@link Ext.Component Component} by {@link Ext.Component#id id}
469          * @param {String} id The component {@link Ext.Component#id id}
470          * @return Ext.Component The Component, <tt>undefined</tt> if not found, or <tt>null</tt> if a
471          * Class was found.
472         */
473         getCmp : function(id){
474             return Ext.ComponentMgr.get(id);
475         },
476
477         <div id="prop-Ext-useShims"></div>/**
478          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
479          * you may want to set this to true.
480          * @type Boolean
481          */
482         useShims: E.isIE6 || (E.isMac && E.isGecko2),
483
484         // inpired by a similar function in mootools library
485         <div id="method-Ext-type"></div>/**
486          * Returns the type of object that is passed in. If the object passed in is null or undefined it
487          * return false otherwise it returns one of the following values:<div class="mdetail-params"><ul>
488          * <li><b>string</b>: If the object passed is a string</li>
489          * <li><b>number</b>: If the object passed is a number</li>
490          * <li><b>boolean</b>: If the object passed is a boolean value</li>
491          * <li><b>date</b>: If the object passed is a Date object</li>
492          * <li><b>function</b>: If the object passed is a function reference</li>
493          * <li><b>object</b>: If the object passed is an object</li>
494          * <li><b>array</b>: If the object passed is an array</li>
495          * <li><b>regexp</b>: If the object passed is a regular expression</li>
496          * <li><b>element</b>: If the object passed is a DOM Element</li>
497          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
498          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
499          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
500          * </ul></div>
501          * @param {Mixed} object
502          * @return {String}
503          */
504         type : function(o){
505             if(o === undefined || o === null){
506                 return false;
507             }
508             if(o.htmlElement){
509                 return 'element';
510             }
511             var t = typeof o;
512             if(t == 'object' && o.nodeName) {
513                 switch(o.nodeType) {
514                     case 1: return 'element';
515                     case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
516                 }
517             }
518             if(t == 'object' || t == 'function') {
519                 switch(o.constructor) {
520                     case Array: return 'array';
521                     case RegExp: return 'regexp';
522                     case Date: return 'date';
523                 }
524                 if(Ext.isNumber(o.length) && Ext.isFunction(o.item)) {
525                     return 'nodelist';
526                 }
527             }
528             return t;
529         },
530
531         intercept : function(o, name, fn, scope){
532             o[name] = o[name].createInterceptor(fn, scope);
533         },
534
535         // internal
536         callback : function(cb, scope, args, delay){
537             if(Ext.isFunction(cb)){
538                 if(delay){
539                     cb.defer(delay, scope, args || []);
540                 }else{
541                     cb.apply(scope, args || []);
542                 }
543             }
544         }
545     };
546 }());
547
548 <div id="cls-Function"></div>/**
549  * @class Function
550  * These functions are available on every Function object (any JavaScript function).
551  */
552 Ext.apply(Function.prototype, {
553     <div id="method-Function-createSequence"></div>/**
554      * Create a combined function call sequence of the original function + the passed function.
555      * The resulting function returns the results of the original function.
556      * The passed fcn is called with the parameters of the original function. Example usage:
557      * <pre><code>
558 var sayHi = function(name){
559     alert('Hi, ' + name);
560 }
561
562 sayHi('Fred'); // alerts "Hi, Fred"
563
564 var sayGoodbye = sayHi.createSequence(function(name){
565     alert('Bye, ' + name);
566 });
567
568 sayGoodbye('Fred'); // both alerts show
569 </code></pre>
570      * @param {Function} fcn The function to sequence
571      * @param {Object} scope (optional) The scope (<code><b>this</b></code> reference) in which the passed function is executed.
572      * <b>If omitted, defaults to the scope in which the original function is called or the browser window.</b>
573      * @return {Function} The new function
574      */
575     createSequence : function(fcn, scope){
576         var method = this;
577         return !Ext.isFunction(fcn) ?
578                 this :
579                 function(){
580                     var retval = method.apply(this || window, arguments);
581                     fcn.apply(scope || this || window, arguments);
582                     return retval;
583                 };
584     }
585 });
586
587
588 <div id="cls-String"></div>/**
589  * @class String
590  * These functions are available as static methods on the JavaScript String object.
591  */
592 Ext.applyIf(String, {
593
594     <div id="method-String-escape"></div>/**
595      * Escapes the passed string for ' and \
596      * @param {String} string The string to escape
597      * @return {String} The escaped string
598      * @static
599      */
600     escape : function(string) {
601         return string.replace(/('|\\)/g, "\\$1");
602     },
603
604     <div id="method-String-leftPad"></div>/**
605      * Pads the left side of a string with a specified character.  This is especially useful
606      * for normalizing number and date strings.  Example usage:
607      * <pre><code>
608 var s = String.leftPad('123', 5, '0');
609 // s now contains the string: '00123'
610      * </code></pre>
611      * @param {String} string The original string
612      * @param {Number} size The total length of the output string
613      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
614      * @return {String} The padded string
615      * @static
616      */
617     leftPad : function (val, size, ch) {
618         var result = String(val);
619         if(!ch) {
620             ch = " ";
621         }
622         while (result.length < size) {
623             result = ch + result;
624         }
625         return result;
626     }
627 });
628
629 <div id="method-String-toggle"></div>/**
630  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
631  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
632  * they are already different, the first value passed in is returned.  Note that this method returns the new value
633  * but does not change the current string.
634  * <pre><code>
635 // alternate sort directions
636 sort = sort.toggle('ASC', 'DESC');
637
638 // instead of conditional logic:
639 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
640 </code></pre>
641  * @param {String} value The value to compare to the current string
642  * @param {String} other The new value to use if the string already equals the first value passed in
643  * @return {String} The new value
644  */
645 String.prototype.toggle = function(value, other){
646     return this == value ? other : value;
647 };
648
649 <div id="method-String-trim"></div>/**
650  * Trims whitespace from either end of a string, leaving spaces within the string intact.  Example:
651  * <pre><code>
652 var s = '  foo bar  ';
653 alert('-' + s + '-');         //alerts "- foo bar -"
654 alert('-' + s.trim() + '-');  //alerts "-foo bar-"
655 </code></pre>
656  * @return {String} The trimmed string
657  */
658 String.prototype.trim = function(){
659     var re = /^\s+|\s+$/g;
660     return function(){ return this.replace(re, ""); };
661 }();
662
663 // here to prevent dependency on Date.js
664 <div id="method-Date-getElapsed"></div>/**
665  Returns the number of milliseconds between this date and date
666  @param {Date} date (optional) Defaults to now
667  @return {Number} The diff in milliseconds
668  @member Date getElapsed
669  */
670 Date.prototype.getElapsed = function(date) {
671     return Math.abs((date || new Date()).getTime()-this.getTime());
672 };
673
674
675 <div id="cls-Number"></div>/**
676  * @class Number
677  */
678 Ext.applyIf(Number.prototype, {
679     <div id="method-Number-constrain"></div>/**
680      * Checks whether or not the current number is within a desired range.  If the number is already within the
681      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
682      * exceeded.  Note that this method returns the constrained value but does not change the current number.
683      * @param {Number} min The minimum number in the range
684      * @param {Number} max The maximum number in the range
685      * @return {Number} The constrained value if outside the range, otherwise the current value
686      */
687     constrain : function(min, max){
688         return Math.min(Math.max(this, min), max);
689     }
690 });
691 </pre>    \r
692 </body>\r
693 </html>