4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
17 window["undefined"] = window["undefined"];
21 * Roo core utilities and functions.
26 * Copies all the properties of config to obj.
27 * @param {Object} obj The receiver of the properties
28 * @param {Object} config The source of the properties
29 * @param {Object} defaults A different object that will also be applied for default values
30 * @return {Object} returns obj
35 Roo.apply = function(o, c, defaults){
37 // no "this" reference for friendly out of scope calls
38 Roo.apply(o, defaults);
40 if(o && c && typeof c == 'object'){
51 var ua = navigator.userAgent.toLowerCase();
53 var isStrict = document.compatMode == "CSS1Compat",
54 isOpera = ua.indexOf("opera") > -1,
55 isSafari = (/webkit|khtml/).test(ua),
56 isIE = ua.indexOf("msie") > -1,
57 isIE7 = ua.indexOf("msie 7") > -1,
58 isGecko = !isSafari && ua.indexOf("gecko") > -1,
59 isBorderBox = isIE && !isStrict,
60 isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
61 isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
62 isLinux = (ua.indexOf("linux") != -1),
63 isSecure = window.location.href.toLowerCase().indexOf("https") === 0;
65 // remove css image flicker
68 document.execCommand("BackgroundImageCache", false, true);
74 * True if the browser is in strict mode
79 * True if the page is running over SSL
84 * True when the document is fully initialized and ready for action
90 * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
93 enableGarbageCollector : true,
96 * True to automatically purge event listeners after uncaching an element (defaults to false).
97 * Note: this only happens if enableGarbageCollector is true.
100 enableListenerCollection:false,
103 * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
104 * the IE insecure content warning (defaults to javascript:false).
107 SSL_SECURE_URL : "javascript:false",
110 * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
111 * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
114 BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
116 emptyFn : function(){},
119 * Copies all the properties of config to obj if they don't already exist.
120 * @param {Object} obj The receiver of the properties
121 * @param {Object} config The source of the properties
122 * @return {Object} returns obj
124 applyIf : function(o, c){
127 if(typeof o[p] == "undefined"){ o[p] = c[p]; }
134 * Applies event listeners to elements by selectors when the document is ready.
135 * The event name is specified with an @ suffix.
138 // add a listener for click on all anchors in element with id foo
139 '#foo a@click' : function(e, t){
143 // add the same listener to multiple selectors (separated by comma BEFORE the @)
144 '#foo a, #bar span.some-class@mouseover' : function(){
149 * @param {Object} obj The list of behaviors to apply
151 addBehaviors : function(o){
153 Roo.onReady(function(){
158 var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
160 var parts = b.split('@');
161 if(parts[1]){ // for Object prototype breakers
164 cache[s] = Roo.select(s);
166 cache[s].on(parts[1], o[b]);
173 * Generates unique ids. If the element already has an id, it is unchanged
174 * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
175 * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
176 * @return {String} The generated Id.
178 id : function(el, prefix){
179 prefix = prefix || "roo-gen";
181 var id = prefix + (++idSeed);
182 return el ? (el.id ? el.id : (el.id = id)) : id;
187 * Extends one class with another class and optionally overrides members with the passed literal. This class
188 * also adds the function "override()" to the class that can be used to override
189 * members on an instance.
190 * @param {Object} subclass The class inheriting the functionality
191 * @param {Object} superclass The class being extended
192 * @param {Object} overrides (optional) A literal with members
197 var io = function(o){
202 return function(sb, sp, overrides){
203 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
206 sb = function(){sp.apply(this, arguments);};
208 var F = function(){}, sbp, spp = sp.prototype;
210 sbp = sb.prototype = new F();
214 if(spp.constructor == Object.prototype.constructor){
219 sb.override = function(o){
223 Roo.override(sb, overrides);
229 * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
231 Roo.override(MyClass, {
232 newMethod1: function(){
235 newMethod2: function(foo){
240 * @param {Object} origclass The class to override
241 * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
242 * containing one or more methods.
245 override : function(origclass, overrides){
247 var p = origclass.prototype;
248 for(var method in overrides){
249 p[method] = overrides[method];
254 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
256 Roo.namespace('Company', 'Company.data');
257 Company.Widget = function() { ... }
258 Company.data.CustomStore = function(config) { ... }
260 * @param {String} namespace1
261 * @param {String} namespace2
262 * @param {String} etc
265 namespace : function(){
266 var a=arguments, o=null, i, j, d, rt;
267 for (i=0; i<a.length; ++i) {
271 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
272 for (j=1; j<d.length; ++j) {
273 o[d[j]]=o[d[j]] || {};
279 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
281 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
282 Roo.factory(conf, Roo.data);
284 * @param {String} classname
285 * @param {String} namespace (optional)
289 factory : function(c, ns)
291 // no xtype, no ns or c.xns - or forced off by c.xns
292 if (!c.xtype || (!ns && !c.xns) || (c.xns === false)) { // not enough info...
295 ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
296 if (c.constructor == ns[c.xtype]) {// already created...
300 if (Roo.debug) console.log("Roo.Factory(" + c.xtype + ")");
301 var ret = new ns[c.xtype](c);
305 c.xns = false; // prevent recursion..
310 * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2". Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
314 urlEncode : function(o){
320 var ov = o[key], k = encodeURIComponent(key);
321 var type = typeof ov;
322 if(type == 'undefined'){
324 }else if(type != "function" && type != "object"){
325 buf.push(k, "=", encodeURIComponent(ov), "&");
326 }else if(ov instanceof Array){
328 for(var i = 0, len = ov.length; i < len; i++) {
329 buf.push(k, "=", encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
341 * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
342 * @param {String} string
343 * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
344 * @return {Object} A literal with members
346 urlDecode : function(string, overwrite){
347 if(!string || !string.length){
351 var pairs = string.split('&');
352 var pair, name, value;
353 for(var i = 0, len = pairs.length; i < len; i++){
354 pair = pairs[i].split('=');
355 name = decodeURIComponent(pair[0]);
356 value = decodeURIComponent(pair[1]);
357 if(overwrite !== true){
358 if(typeof obj[name] == "undefined"){
360 }else if(typeof obj[name] == "string"){
361 obj[name] = [obj[name]];
362 obj[name].push(value);
364 obj[name].push(value);
374 * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
375 * passed array is not really an array, your function is called once with it.
376 * The supplied function is called with (Object item, Number index, Array allItems).
377 * @param {Array/NodeList/Mixed} array
378 * @param {Function} fn
379 * @param {Object} scope
381 each : function(array, fn, scope){
382 if(typeof array.length == "undefined" || typeof array == "string"){
385 for(var i = 0, len = array.length; i < len; i++){
386 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
391 combine : function(){
392 var as = arguments, l = as.length, r = [];
393 for(var i = 0; i < l; i++){
395 if(a instanceof Array){
397 }else if(a.length !== undefined && !a.substr){
398 r = r.concat(Array.prototype.slice.call(a, 0));
407 * Escapes the passed string for use in a regular expression
408 * @param {String} str
411 escapeRe : function(s) {
412 return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
416 callback : function(cb, scope, args, delay){
417 if(typeof cb == "function"){
419 cb.defer(delay, scope, args || []);
421 cb.apply(scope, args || []);
427 * Return the dom node for the passed string (id), dom node, or Roo.Element
428 * @param {String/HTMLElement/Roo.Element} el
429 * @return HTMLElement
431 getDom : function(el){
435 return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
439 * Shorthand for {@link Roo.ComponentMgr#get}
441 * @return Roo.Component
443 getCmp : function(id){
444 return Roo.ComponentMgr.get(id);
447 num : function(v, defaultValue){
448 if(typeof v != 'number'){
454 destroy : function(){
455 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
459 as.removeAllListeners();
463 if(typeof as.purgeListeners == 'function'){
466 if(typeof as.destroy == 'function'){
473 // inpired by a similar function in mootools library
475 * Returns the type of object that is passed in. If the object passed in is null or undefined it
476 * return false otherwise it returns one of the following values:<ul>
477 * <li><b>string</b>: If the object passed is a string</li>
478 * <li><b>number</b>: If the object passed is a number</li>
479 * <li><b>boolean</b>: If the object passed is a boolean value</li>
480 * <li><b>function</b>: If the object passed is a function reference</li>
481 * <li><b>object</b>: If the object passed is an object</li>
482 * <li><b>array</b>: If the object passed is an array</li>
483 * <li><b>regexp</b>: If the object passed is a regular expression</li>
484 * <li><b>element</b>: If the object passed is a DOM Element</li>
485 * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
486 * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
487 * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
488 * @param {Mixed} object
492 if(o === undefined || o === null){
499 if(t == 'object' && o.nodeName) {
501 case 1: return 'element';
502 case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
505 if(t == 'object' || t == 'function') {
506 switch(o.constructor) {
507 case Array: return 'array';
508 case RegExp: return 'regexp';
510 if(typeof o.length == 'number' && typeof o.item == 'function') {
518 * Returns true if the passed value is null, undefined or an empty string (optional).
519 * @param {Mixed} value The value to test
520 * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
523 isEmpty : function(v, allowBlank){
524 return v === null || v === undefined || (!allowBlank ? v === '' : false);
538 isBorderBox : isBorderBox,
540 isWindows : isWindows,
547 * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
548 * you may want to set this to true.
551 useShims : ((isIE && !isIE7) || (isGecko && isMac))
557 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
558 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout", "Roo.app", "Roo.ux");
561 * Ext JS Library 1.1.1
562 * Copyright(c) 2006-2007, Ext JS, LLC.
564 * Originally Released Under LGPL - original licence link has changed is not relivant.
567 * <script type="text/javascript">
571 // wrappedn so fnCleanup is not in global scope...
573 function fnCleanUp() {
574 var p = Function.prototype;
575 delete p.createSequence;
577 delete p.createDelegate;
578 delete p.createCallback;
579 delete p.createInterceptor;
581 window.detachEvent("onunload", fnCleanUp);
583 window.attachEvent("onunload", fnCleanUp);
590 * These functions are available on every Function object (any JavaScript function).
592 Roo.apply(Function.prototype, {
594 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
595 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
596 * Will create a function that is bound to those 2 args.
597 * @return {Function} The new function
599 createCallback : function(/*args...*/){
600 // make args available, in function below
601 var args = arguments;
604 return method.apply(window, args);
609 * Creates a delegate (callback) that sets the scope to obj.
610 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
611 * Will create a function that is automatically scoped to this.
612 * @param {Object} obj (optional) The object for which the scope is set
613 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
614 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
615 * if a number the args are inserted at the specified position
616 * @return {Function} The new function
618 createDelegate : function(obj, args, appendArgs){
621 var callArgs = args || arguments;
622 if(appendArgs === true){
623 callArgs = Array.prototype.slice.call(arguments, 0);
624 callArgs = callArgs.concat(args);
625 }else if(typeof appendArgs == "number"){
626 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
627 var applyArgs = [appendArgs, 0].concat(args); // create method call params
628 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
630 return method.apply(obj || window, callArgs);
635 * Calls this function after the number of millseconds specified.
636 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
637 * @param {Object} obj (optional) The object for which the scope is set
638 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
639 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
640 * if a number the args are inserted at the specified position
641 * @return {Number} The timeout id that can be used with clearTimeout
643 defer : function(millis, obj, args, appendArgs){
644 var fn = this.createDelegate(obj, args, appendArgs);
646 return setTimeout(fn, millis);
652 * Create a combined function call sequence of the original function + the passed function.
653 * The resulting function returns the results of the original function.
654 * The passed fcn is called with the parameters of the original function
655 * @param {Function} fcn The function to sequence
656 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
657 * @return {Function} The new function
659 createSequence : function(fcn, scope){
660 if(typeof fcn != "function"){
665 var retval = method.apply(this || window, arguments);
666 fcn.apply(scope || this || window, arguments);
672 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
673 * The resulting function returns the results of the original function.
674 * The passed fcn is called with the parameters of the original function.
676 * @param {Function} fcn The function to call before the original
677 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
678 * @return {Function} The new function
680 createInterceptor : function(fcn, scope){
681 if(typeof fcn != "function"){
688 if(fcn.apply(scope || this || window, arguments) === false){
691 return method.apply(this || window, arguments);
697 * Ext JS Library 1.1.1
698 * Copyright(c) 2006-2007, Ext JS, LLC.
700 * Originally Released Under LGPL - original licence link has changed is not relivant.
703 * <script type="text/javascript">
706 Roo.applyIf(String, {
711 * Escapes the passed string for ' and \
712 * @param {String} string The string to escape
713 * @return {String} The escaped string
716 escape : function(string) {
717 return string.replace(/('|\\)/g, "\\$1");
721 * Pads the left side of a string with a specified character. This is especially useful
722 * for normalizing number and date strings. Example usage:
724 var s = String.leftPad('123', 5, '0');
725 // s now contains the string: '00123'
727 * @param {String} string The original string
728 * @param {Number} size The total length of the output string
729 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
730 * @return {String} The padded string
733 leftPad : function (val, size, ch) {
734 var result = new String(val);
735 if(ch === null || ch === undefined || ch === '') {
738 while (result.length < size) {
739 result = ch + result;
745 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
746 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
748 var cls = 'my-class', text = 'Some text';
749 var s = String.format('<div class="{0}">{1}</div>', cls, text);
750 // s now contains the string: '<div class="my-class">Some text</div>'
752 * @param {String} string The tokenized string to be formatted
753 * @param {String} value1 The value to replace token {0}
754 * @param {String} value2 Etc...
755 * @return {String} The formatted string
758 format : function(format){
759 var args = Array.prototype.slice.call(arguments, 1);
760 return format.replace(/\{(\d+)\}/g, function(m, i){
761 return Roo.util.Format.htmlEncode(args[i]);
767 * Utility function that allows you to easily switch a string between two alternating values. The passed value
768 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
769 * they are already different, the first value passed in is returned. Note that this method returns the new value
770 * but does not change the current string.
772 // alternate sort directions
773 sort = sort.toggle('ASC', 'DESC');
775 // instead of conditional logic:
776 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
778 * @param {String} value The value to compare to the current string
779 * @param {String} other The new value to use if the string already equals the first value passed in
780 * @return {String} The new value
783 String.prototype.toggle = function(value, other){
784 return this == value ? other : value;
787 * Ext JS Library 1.1.1
788 * Copyright(c) 2006-2007, Ext JS, LLC.
790 * Originally Released Under LGPL - original licence link has changed is not relivant.
793 * <script type="text/javascript">
799 Roo.applyIf(Number.prototype, {
801 * Checks whether or not the current number is within a desired range. If the number is already within the
802 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
803 * exceeded. Note that this method returns the constrained value but does not change the current number.
804 * @param {Number} min The minimum number in the range
805 * @param {Number} max The maximum number in the range
806 * @return {Number} The constrained value if outside the range, otherwise the current value
808 constrain : function(min, max){
809 return Math.min(Math.max(this, min), max);
813 * Ext JS Library 1.1.1
814 * Copyright(c) 2006-2007, Ext JS, LLC.
816 * Originally Released Under LGPL - original licence link has changed is not relivant.
819 * <script type="text/javascript">
824 Roo.applyIf(Array.prototype, {
826 * Checks whether or not the specified object exists in the array.
827 * @param {Object} o The object to check for
828 * @return {Number} The index of o in the array (or -1 if it is not found)
830 indexOf : function(o){
831 for (var i = 0, len = this.length; i < len; i++){
832 if(this[i] == o) return i;
838 * Removes the specified object from the array. If the object is not found nothing happens.
839 * @param {Object} o The object to remove
841 remove : function(o){
842 var index = this.indexOf(o);
844 this.splice(index, 1);
849 * Ext JS Library 1.1.1
850 * Copyright(c) 2006-2007, Ext JS, LLC.
852 * Originally Released Under LGPL - original licence link has changed is not relivant.
855 * <script type="text/javascript">
861 * The date parsing and format syntax is a subset of
862 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
863 * supported will provide results equivalent to their PHP versions.
865 * Following is the list of all currently supported formats:
868 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
870 Format Output Description
871 ------ ---------- --------------------------------------------------------------
872 d 10 Day of the month, 2 digits with leading zeros
873 D Wed A textual representation of a day, three letters
874 j 10 Day of the month without leading zeros
875 l Wednesday A full textual representation of the day of the week
876 S th English ordinal day of month suffix, 2 chars (use with j)
877 w 3 Numeric representation of the day of the week
878 z 9 The julian date, or day of the year (0-365)
879 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
880 F January A full textual representation of the month
881 m 01 Numeric representation of a month, with leading zeros
882 M Jan Month name abbreviation, three letters
883 n 1 Numeric representation of a month, without leading zeros
884 t 31 Number of days in the given month
885 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
886 Y 2007 A full numeric representation of a year, 4 digits
887 y 07 A two digit representation of a year
888 a pm Lowercase Ante meridiem and Post meridiem
889 A PM Uppercase Ante meridiem and Post meridiem
890 g 3 12-hour format of an hour without leading zeros
891 G 15 24-hour format of an hour without leading zeros
892 h 03 12-hour format of an hour with leading zeros
893 H 15 24-hour format of an hour with leading zeros
894 i 05 Minutes with leading zeros
895 s 01 Seconds, with leading zeros
896 O -0600 Difference to Greenwich time (GMT) in hours
897 T CST Timezone setting of the machine running the code
898 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
901 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
903 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
904 document.write(dt.format('Y-m-d')); //2007-01-10
905 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
906 document.write(dt.format('l, \\t\\he dS of F Y h:i:s A')); //Wednesday, the 10th of January 2007 03:05:01 PM
909 * Here are some standard date/time patterns that you might find helpful. They
910 * are not part of the source of Date.js, but to use them you can simply copy this
911 * block of code into any script that is included after Date.js and they will also become
912 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
915 ISO8601Long:"Y-m-d H:i:s",
916 ISO8601Short:"Y-m-d",
918 LongDate: "l, F d, Y",
919 FullDateTime: "l, F d, Y g:i:s A",
923 SortableDateTime: "Y-m-d\\TH:i:s",
924 UniversalSortableDateTime: "Y-m-d H:i:sO",
932 document.write(dt.format(Date.patterns.ShortDate));
937 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
938 * They generate precompiled functions from date formats instead of parsing and
939 * processing the pattern every time you format a date. These functions are available
940 * on every Date object (any javascript function).
942 * The original article and download are here:
943 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
950 Returns the number of milliseconds between this date and date
951 @param {Date} date (optional) Defaults to now
952 @return {Number} The diff in milliseconds
953 @member Date getElapsed
955 Date.prototype.getElapsed = function(date) {
956 return Math.abs((date || new Date()).getTime()-this.getTime());
958 // was in date file..
962 Date.parseFunctions = {count:0};
964 Date.parseRegexes = [];
966 Date.formatFunctions = {count:0};
969 Date.prototype.dateFormat = function(format) {
970 if (Date.formatFunctions[format] == null) {
971 Date.createNewFormat(format);
973 var func = Date.formatFunctions[format];
979 * Formats a date given the supplied format string
980 * @param {String} format The format string
981 * @return {String} The formatted date
984 Date.prototype.format = Date.prototype.dateFormat;
987 Date.createNewFormat = function(format) {
988 var funcName = "format" + Date.formatFunctions.count++;
989 Date.formatFunctions[format] = funcName;
990 var code = "Date.prototype." + funcName + " = function(){return ";
993 for (var i = 0; i < format.length; ++i) {
994 ch = format.charAt(i);
995 if (!special && ch == "\\") {
1000 code += "'" + String.escape(ch) + "' + ";
1003 code += Date.getFormatCode(ch);
1006 /** eval:var:zzzzzzzzzzzzz */
1007 eval(code.substring(0, code.length - 3) + ";}");
1011 Date.getFormatCode = function(character) {
1012 switch (character) {
1014 return "String.leftPad(this.getDate(), 2, '0') + ";
1016 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1018 return "this.getDate() + ";
1020 return "Date.dayNames[this.getDay()] + ";
1022 return "this.getSuffix() + ";
1024 return "this.getDay() + ";
1026 return "this.getDayOfYear() + ";
1028 return "this.getWeekOfYear() + ";
1030 return "Date.monthNames[this.getMonth()] + ";
1032 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1034 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1036 return "(this.getMonth() + 1) + ";
1038 return "this.getDaysInMonth() + ";
1040 return "(this.isLeapYear() ? 1 : 0) + ";
1042 return "this.getFullYear() + ";
1044 return "('' + this.getFullYear()).substring(2, 4) + ";
1046 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1048 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1050 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1052 return "this.getHours() + ";
1054 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1056 return "String.leftPad(this.getHours(), 2, '0') + ";
1058 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1060 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1062 return "this.getGMTOffset() + ";
1064 return "this.getTimezone() + ";
1066 return "(this.getTimezoneOffset() * -60) + ";
1068 return "'" + String.escape(character) + "' + ";
1073 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1074 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1075 * the date format that is not specified will default to the current date value for that part. Time parts can also
1076 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1077 * string or the parse operation will fail.
1080 //dt = Fri May 25 2007 (current date)
1081 var dt = new Date();
1083 //dt = Thu May 25 2006 (today's month/day in 2006)
1084 dt = Date.parseDate("2006", "Y");
1086 //dt = Sun Jan 15 2006 (all date parts specified)
1087 dt = Date.parseDate("2006-1-15", "Y-m-d");
1089 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1090 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1092 * @param {String} input The unparsed date as a string
1093 * @param {String} format The format the date is in
1094 * @return {Date} The parsed date
1097 Date.parseDate = function(input, format) {
1098 if (Date.parseFunctions[format] == null) {
1099 Date.createParser(format);
1101 var func = Date.parseFunctions[format];
1102 return Date[func](input);
1107 Date.createParser = function(format) {
1108 var funcName = "parse" + Date.parseFunctions.count++;
1109 var regexNum = Date.parseRegexes.length;
1110 var currentGroup = 1;
1111 Date.parseFunctions[format] = funcName;
1113 var code = "Date." + funcName + " = function(input){\n"
1114 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1115 + "var d = new Date();\n"
1116 + "y = d.getFullYear();\n"
1117 + "m = d.getMonth();\n"
1118 + "d = d.getDate();\n"
1119 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1120 + "if (results && results.length > 0) {";
1123 var special = false;
1125 for (var i = 0; i < format.length; ++i) {
1126 ch = format.charAt(i);
1127 if (!special && ch == "\\") {
1132 regex += String.escape(ch);
1135 var obj = Date.formatCodeToRegex(ch, currentGroup);
1136 currentGroup += obj.g;
1138 if (obj.g && obj.c) {
1144 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1145 + "{v = new Date(y, m, d, h, i, s);}\n"
1146 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1147 + "{v = new Date(y, m, d, h, i);}\n"
1148 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1149 + "{v = new Date(y, m, d, h);}\n"
1150 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1151 + "{v = new Date(y, m, d);}\n"
1152 + "else if (y >= 0 && m >= 0)\n"
1153 + "{v = new Date(y, m);}\n"
1154 + "else if (y >= 0)\n"
1155 + "{v = new Date(y);}\n"
1156 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1157 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1158 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1161 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1162 /** eval:var:zzzzzzzzzzzzz */
1167 Date.formatCodeToRegex = function(character, currentGroup) {
1168 switch (character) {
1172 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1175 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1176 s:"(\\d{1,2})"}; // day of month without leading zeroes
1179 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1180 s:"(\\d{2})"}; // day of month with leading zeroes
1184 s:"(?:" + Date.dayNames.join("|") + ")"};
1188 s:"(?:st|nd|rd|th)"};
1203 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1204 s:"(" + Date.monthNames.join("|") + ")"};
1207 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1208 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1211 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1212 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1215 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1216 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1227 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1231 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1232 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1236 c:"if (results[" + currentGroup + "] == 'am') {\n"
1237 + "if (h == 12) { h = 0; }\n"
1238 + "} else { if (h < 12) { h += 12; }}",
1242 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1243 + "if (h == 12) { h = 0; }\n"
1244 + "} else { if (h < 12) { h += 12; }}",
1249 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1250 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1254 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1255 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1258 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1262 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1267 "o = results[", currentGroup, "];\n",
1268 "var sn = o.substring(0,1);\n", // get + / - sign
1269 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1270 "var mn = o.substring(3,5) % 60;\n", // get minutes
1271 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1272 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1278 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1281 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1282 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1283 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1287 s:String.escape(character)};
1292 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1293 * @return {String} The abbreviated timezone name (e.g. 'CST')
1295 Date.prototype.getTimezone = function() {
1296 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1300 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1301 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1303 Date.prototype.getGMTOffset = function() {
1304 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1305 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1306 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1310 * Get the numeric day number of the year, adjusted for leap year.
1311 * @return {Number} 0 through 364 (365 in leap years)
1313 Date.prototype.getDayOfYear = function() {
1315 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1316 for (var i = 0; i < this.getMonth(); ++i) {
1317 num += Date.daysInMonth[i];
1319 return num + this.getDate() - 1;
1323 * Get the string representation of the numeric week number of the year
1324 * (equivalent to the format specifier 'W').
1325 * @return {String} '00' through '52'
1327 Date.prototype.getWeekOfYear = function() {
1328 // Skip to Thursday of this week
1329 var now = this.getDayOfYear() + (4 - this.getDay());
1330 // Find the first Thursday of the year
1331 var jan1 = new Date(this.getFullYear(), 0, 1);
1332 var then = (7 - jan1.getDay() + 4);
1333 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1337 * Whether or not the current date is in a leap year.
1338 * @return {Boolean} True if the current date is in a leap year, else false
1340 Date.prototype.isLeapYear = function() {
1341 var year = this.getFullYear();
1342 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1346 * Get the first day of the current month, adjusted for leap year. The returned value
1347 * is the numeric day index within the week (0-6) which can be used in conjunction with
1348 * the {@link #monthNames} array to retrieve the textual day name.
1351 var dt = new Date('1/10/2007');
1352 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1354 * @return {Number} The day number (0-6)
1356 Date.prototype.getFirstDayOfMonth = function() {
1357 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1358 return (day < 0) ? (day + 7) : day;
1362 * Get the last day of the current month, adjusted for leap year. The returned value
1363 * is the numeric day index within the week (0-6) which can be used in conjunction with
1364 * the {@link #monthNames} array to retrieve the textual day name.
1367 var dt = new Date('1/10/2007');
1368 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1370 * @return {Number} The day number (0-6)
1372 Date.prototype.getLastDayOfMonth = function() {
1373 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1374 return (day < 0) ? (day + 7) : day;
1379 * Get the first date of this date's month
1382 Date.prototype.getFirstDateOfMonth = function() {
1383 return new Date(this.getFullYear(), this.getMonth(), 1);
1387 * Get the last date of this date's month
1390 Date.prototype.getLastDateOfMonth = function() {
1391 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1394 * Get the number of days in the current month, adjusted for leap year.
1395 * @return {Number} The number of days in the month
1397 Date.prototype.getDaysInMonth = function() {
1398 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1399 return Date.daysInMonth[this.getMonth()];
1403 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1404 * @return {String} 'st, 'nd', 'rd' or 'th'
1406 Date.prototype.getSuffix = function() {
1407 switch (this.getDate()) {
1424 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1427 * An array of textual month names.
1428 * Override these values for international dates, for example...
1429 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1448 * An array of textual day names.
1449 * Override these values for international dates, for example...
1450 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1466 Date.monthNumbers = {
1481 * Creates and returns a new Date instance with the exact same date value as the called instance.
1482 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1483 * variable will also be changed. When the intention is to create a new variable that will not
1484 * modify the original instance, you should create a clone.
1486 * Example of correctly cloning a date:
1489 var orig = new Date('10/1/2006');
1492 document.write(orig); //returns 'Thu Oct 05 2006'!
1495 var orig = new Date('10/1/2006');
1496 var copy = orig.clone();
1498 document.write(orig); //returns 'Thu Oct 01 2006'
1500 * @return {Date} The new Date instance
1502 Date.prototype.clone = function() {
1503 return new Date(this.getTime());
1507 * Clears any time information from this date
1508 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1509 @return {Date} this or the clone
1511 Date.prototype.clearTime = function(clone){
1513 return this.clone().clearTime();
1518 this.setMilliseconds(0);
1523 // safari setMonth is broken
1525 Date.brokenSetMonth = Date.prototype.setMonth;
1526 Date.prototype.setMonth = function(num){
1528 var n = Math.ceil(-num);
1529 var back_year = Math.ceil(n/12);
1530 var month = (n % 12) ? 12 - n % 12 : 0 ;
1531 this.setFullYear(this.getFullYear() - back_year);
1532 return Date.brokenSetMonth.call(this, month);
1534 return Date.brokenSetMonth.apply(this, arguments);
1539 /** Date interval constant
1543 /** Date interval constant
1547 /** Date interval constant
1551 /** Date interval constant
1555 /** Date interval constant
1559 /** Date interval constant
1563 /** Date interval constant
1569 * Provides a convenient method of performing basic date arithmetic. This method
1570 * does not modify the Date instance being called - it creates and returns
1571 * a new Date instance containing the resulting date value.
1576 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1577 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1579 //Negative values will subtract correctly:
1580 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1581 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1583 //You can even chain several calls together in one line!
1584 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1585 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1588 * @param {String} interval A valid date interval enum value
1589 * @param {Number} value The amount to add to the current date
1590 * @return {Date} The new Date instance
1592 Date.prototype.add = function(interval, value){
1593 var d = this.clone();
1594 if (!interval || value === 0) return d;
1595 switch(interval.toLowerCase()){
1597 d.setMilliseconds(this.getMilliseconds() + value);
1600 d.setSeconds(this.getSeconds() + value);
1603 d.setMinutes(this.getMinutes() + value);
1606 d.setHours(this.getHours() + value);
1609 d.setDate(this.getDate() + value);
1612 var day = this.getDate();
1614 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1617 d.setMonth(this.getMonth() + value);
1620 d.setFullYear(this.getFullYear() + value);
1626 * Ext JS Library 1.1.1
1627 * Copyright(c) 2006-2007, Ext JS, LLC.
1629 * Originally Released Under LGPL - original licence link has changed is not relivant.
1632 * <script type="text/javascript">
1636 getViewWidth : function(full) {
1637 return full ? this.getDocumentWidth() : this.getViewportWidth();
1640 getViewHeight : function(full) {
1641 return full ? this.getDocumentHeight() : this.getViewportHeight();
1644 getDocumentHeight: function() {
1645 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1646 return Math.max(scrollHeight, this.getViewportHeight());
1649 getDocumentWidth: function() {
1650 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1651 return Math.max(scrollWidth, this.getViewportWidth());
1654 getViewportHeight: function() {
1655 var height = self.innerHeight;
1656 var mode = document.compatMode;
1658 if ((mode || Roo.isIE) && !Roo.isOpera) {
1659 height = (mode == "CSS1Compat") ?
1660 document.documentElement.clientHeight :
1661 document.body.clientHeight;
1667 getViewportWidth: function() {
1668 var width = self.innerWidth;
1669 var mode = document.compatMode;
1671 if (mode || Roo.isIE) {
1672 width = (mode == "CSS1Compat") ?
1673 document.documentElement.clientWidth :
1674 document.body.clientWidth;
1679 isAncestor : function(p, c) {
1686 if (p.contains && !Roo.isSafari) {
1687 return p.contains(c);
1688 } else if (p.compareDocumentPosition) {
1689 return !!(p.compareDocumentPosition(c) & 16);
1691 var parent = c.parentNode;
1696 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1699 parent = parent.parentNode;
1705 getRegion : function(el) {
1706 return Roo.lib.Region.getRegion(el);
1709 getY : function(el) {
1710 return this.getXY(el)[1];
1713 getX : function(el) {
1714 return this.getXY(el)[0];
1717 getXY : function(el) {
1718 var p, pe, b, scroll, bd = document.body;
1719 el = Roo.getDom(el);
1720 var fly = Roo.lib.AnimBase.fly;
1721 if (el.getBoundingClientRect) {
1722 b = el.getBoundingClientRect();
1723 scroll = fly(document).getScroll();
1724 return [b.left + scroll.left, b.top + scroll.top];
1730 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1737 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1744 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1745 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1752 if (p != el && pe.getStyle('overflow') != 'visible') {
1760 if (Roo.isSafari && hasAbsolute) {
1765 if (Roo.isGecko && !hasAbsolute) {
1767 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1768 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1772 while (p && p != bd) {
1773 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1785 setXY : function(el, xy) {
1786 el = Roo.fly(el, '_setXY');
1788 var pts = el.translatePoints(xy);
1789 if (xy[0] !== false) {
1790 el.dom.style.left = pts.left + "px";
1792 if (xy[1] !== false) {
1793 el.dom.style.top = pts.top + "px";
1797 setX : function(el, x) {
1798 this.setXY(el, [x, false]);
1801 setY : function(el, y) {
1802 this.setXY(el, [false, y]);
1806 * Portions of this file are based on pieces of Yahoo User Interface Library
1807 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1808 * YUI licensed under the BSD License:
1809 * http://developer.yahoo.net/yui/license.txt
1810 * <script type="text/javascript">
1814 Roo.lib.Event = function() {
1815 var loadComplete = false;
1817 var unloadListeners = [];
1819 var onAvailStack = [];
1821 var lastError = null;
1834 startInterval: function() {
1835 if (!this._interval) {
1837 var callback = function() {
1838 self._tryPreloadAttach();
1840 this._interval = setInterval(callback, this.POLL_INTERVAL);
1845 onAvailable: function(p_id, p_fn, p_obj, p_override) {
1846 onAvailStack.push({ id: p_id,
1849 override: p_override,
1850 checkReady: false });
1852 retryCount = this.POLL_RETRYS;
1853 this.startInterval();
1857 addListener: function(el, eventName, fn) {
1858 el = Roo.getDom(el);
1863 if ("unload" == eventName) {
1864 unloadListeners[unloadListeners.length] =
1865 [el, eventName, fn];
1869 var wrappedFn = function(e) {
1870 return fn(Roo.lib.Event.getEvent(e));
1873 var li = [el, eventName, fn, wrappedFn];
1875 var index = listeners.length;
1876 listeners[index] = li;
1878 this.doAdd(el, eventName, wrappedFn, false);
1884 removeListener: function(el, eventName, fn) {
1887 el = Roo.getDom(el);
1890 return this.purgeElement(el, false, eventName);
1894 if ("unload" == eventName) {
1896 for (i = 0,len = unloadListeners.length; i < len; i++) {
1897 var li = unloadListeners[i];
1900 li[1] == eventName &&
1902 unloadListeners.splice(i, 1);
1910 var cacheItem = null;
1913 var index = arguments[3];
1915 if ("undefined" == typeof index) {
1916 index = this._getCacheIndex(el, eventName, fn);
1920 cacheItem = listeners[index];
1923 if (!el || !cacheItem) {
1927 this.doRemove(el, eventName, cacheItem[this.WFN], false);
1929 delete listeners[index][this.WFN];
1930 delete listeners[index][this.FN];
1931 listeners.splice(index, 1);
1938 getTarget: function(ev, resolveTextNode) {
1939 ev = ev.browserEvent || ev;
1940 var t = ev.target || ev.srcElement;
1941 return this.resolveTextNode(t);
1945 resolveTextNode: function(node) {
1946 if (Roo.isSafari && node && 3 == node.nodeType) {
1947 return node.parentNode;
1954 getPageX: function(ev) {
1955 ev = ev.browserEvent || ev;
1957 if (!x && 0 !== x) {
1958 x = ev.clientX || 0;
1961 x += this.getScroll()[1];
1969 getPageY: function(ev) {
1970 ev = ev.browserEvent || ev;
1972 if (!y && 0 !== y) {
1973 y = ev.clientY || 0;
1976 y += this.getScroll()[0];
1985 getXY: function(ev) {
1986 ev = ev.browserEvent || ev;
1987 return [this.getPageX(ev), this.getPageY(ev)];
1991 getRelatedTarget: function(ev) {
1992 ev = ev.browserEvent || ev;
1993 var t = ev.relatedTarget;
1995 if (ev.type == "mouseout") {
1997 } else if (ev.type == "mouseover") {
2002 return this.resolveTextNode(t);
2006 getTime: function(ev) {
2007 ev = ev.browserEvent || ev;
2009 var t = new Date().getTime();
2013 this.lastError = ex;
2022 stopEvent: function(ev) {
2023 this.stopPropagation(ev);
2024 this.preventDefault(ev);
2028 stopPropagation: function(ev) {
2029 ev = ev.browserEvent || ev;
2030 if (ev.stopPropagation) {
2031 ev.stopPropagation();
2033 ev.cancelBubble = true;
2038 preventDefault: function(ev) {
2039 ev = ev.browserEvent || ev;
2040 if(ev.preventDefault) {
2041 ev.preventDefault();
2043 ev.returnValue = false;
2048 getEvent: function(e) {
2049 var ev = e || window.event;
2051 var c = this.getEvent.caller;
2053 ev = c.arguments[0];
2054 if (ev && Event == ev.constructor) {
2064 getCharCode: function(ev) {
2065 ev = ev.browserEvent || ev;
2066 return ev.charCode || ev.keyCode || 0;
2070 _getCacheIndex: function(el, eventName, fn) {
2071 for (var i = 0,len = listeners.length; i < len; ++i) {
2072 var li = listeners[i];
2074 li[this.FN] == fn &&
2075 li[this.EL] == el &&
2076 li[this.TYPE] == eventName) {
2088 getEl: function(id) {
2089 return document.getElementById(id);
2093 clearCache: function() {
2097 _load: function(e) {
2098 loadComplete = true;
2099 var EU = Roo.lib.Event;
2103 EU.doRemove(window, "load", EU._load);
2108 _tryPreloadAttach: function() {
2117 var tryAgain = !loadComplete;
2119 tryAgain = (retryCount > 0);
2124 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2125 var item = onAvailStack[i];
2127 var el = this.getEl(item.id);
2130 if (!item.checkReady ||
2133 (document && document.body)) {
2136 if (item.override) {
2137 if (item.override === true) {
2140 scope = item.override;
2143 item.fn.call(scope, item.obj);
2144 onAvailStack[i] = null;
2147 notAvail.push(item);
2152 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2156 this.startInterval();
2158 clearInterval(this._interval);
2159 this._interval = null;
2162 this.locked = false;
2169 purgeElement: function(el, recurse, eventName) {
2170 var elListeners = this.getListeners(el, eventName);
2172 for (var i = 0,len = elListeners.length; i < len; ++i) {
2173 var l = elListeners[i];
2174 this.removeListener(el, l.type, l.fn);
2178 if (recurse && el && el.childNodes) {
2179 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2180 this.purgeElement(el.childNodes[i], recurse, eventName);
2186 getListeners: function(el, eventName) {
2187 var results = [], searchLists;
2189 searchLists = [listeners, unloadListeners];
2190 } else if (eventName == "unload") {
2191 searchLists = [unloadListeners];
2193 searchLists = [listeners];
2196 for (var j = 0; j < searchLists.length; ++j) {
2197 var searchList = searchLists[j];
2198 if (searchList && searchList.length > 0) {
2199 for (var i = 0,len = searchList.length; i < len; ++i) {
2200 var l = searchList[i];
2201 if (l && l[this.EL] === el &&
2202 (!eventName || eventName === l[this.TYPE])) {
2207 adjust: l[this.ADJ_SCOPE],
2215 return (results.length) ? results : null;
2219 _unload: function(e) {
2221 var EU = Roo.lib.Event, i, j, l, len, index;
2223 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2224 l = unloadListeners[i];
2227 if (l[EU.ADJ_SCOPE]) {
2228 if (l[EU.ADJ_SCOPE] === true) {
2231 scope = l[EU.ADJ_SCOPE];
2234 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2235 unloadListeners[i] = null;
2241 unloadListeners = null;
2243 if (listeners && listeners.length > 0) {
2244 j = listeners.length;
2247 l = listeners[index];
2249 EU.removeListener(l[EU.EL], l[EU.TYPE],
2259 EU.doRemove(window, "unload", EU._unload);
2264 getScroll: function() {
2265 var dd = document.documentElement, db = document.body;
2266 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2267 return [dd.scrollTop, dd.scrollLeft];
2269 return [db.scrollTop, db.scrollLeft];
2276 doAdd: function () {
2277 if (window.addEventListener) {
2278 return function(el, eventName, fn, capture) {
2279 el.addEventListener(eventName, fn, (capture));
2281 } else if (window.attachEvent) {
2282 return function(el, eventName, fn, capture) {
2283 el.attachEvent("on" + eventName, fn);
2292 doRemove: function() {
2293 if (window.removeEventListener) {
2294 return function (el, eventName, fn, capture) {
2295 el.removeEventListener(eventName, fn, (capture));
2297 } else if (window.detachEvent) {
2298 return function (el, eventName, fn) {
2299 el.detachEvent("on" + eventName, fn);
2311 var E = Roo.lib.Event;
2312 E.on = E.addListener;
2313 E.un = E.removeListener;
2315 if (document && document.body) {
2318 E.doAdd(window, "load", E._load);
2320 E.doAdd(window, "unload", E._unload);
2321 E._tryPreloadAttach();
2325 * Portions of this file are based on pieces of Yahoo User Interface Library
2326 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2327 * YUI licensed under the BSD License:
2328 * http://developer.yahoo.net/yui/license.txt
2329 * <script type="text/javascript">
2336 request : function(method, uri, cb, data, options) {
2338 var hs = options.headers;
2341 if(hs.hasOwnProperty(h)){
2342 this.initHeader(h, hs[h], false);
2346 if(options.xmlData){
2347 this.initHeader('Content-Type', 'text/xml', false);
2349 data = options.xmlData;
2353 return this.asyncRequest(method, uri, cb, data);
2356 serializeForm : function(form) {
2357 if(typeof form == 'string') {
2358 form = (document.getElementById(form) || document.forms[form]);
2361 var el, name, val, disabled, data = '', hasSubmit = false;
2362 for (var i = 0; i < form.elements.length; i++) {
2363 el = form.elements[i];
2364 disabled = form.elements[i].disabled;
2365 name = form.elements[i].name;
2366 val = form.elements[i].value;
2368 if (!disabled && name){
2372 case 'select-multiple':
2373 for (var j = 0; j < el.options.length; j++) {
2374 if (el.options[j].selected) {
2376 data += encodeURIComponent(name) + '=' + encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2379 data += encodeURIComponent(name) + '=' + encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2387 data += encodeURIComponent(name) + '=' + encodeURIComponent(val) + '&';
2400 if(hasSubmit == false) {
2401 data += encodeURIComponent(name) + '=' + encodeURIComponent(val) + '&';
2406 data += encodeURIComponent(name) + '=' + encodeURIComponent(val) + '&';
2411 data = data.substr(0, data.length - 1);
2419 useDefaultHeader:true,
2421 defaultPostHeader:'application/x-www-form-urlencoded',
2423 useDefaultXhrHeader:true,
2425 defaultXhrHeader:'XMLHttpRequest',
2427 hasDefaultHeaders:true,
2439 setProgId:function(id)
2441 this.activeX.unshift(id);
2444 setDefaultPostHeader:function(b)
2446 this.useDefaultHeader = b;
2449 setDefaultXhrHeader:function(b)
2451 this.useDefaultXhrHeader = b;
2454 setPollingInterval:function(i)
2456 if (typeof i == 'number' && isFinite(i)) {
2457 this.pollInterval = i;
2461 createXhrObject:function(transactionId)
2467 http = new XMLHttpRequest();
2469 obj = { conn:http, tId:transactionId };
2473 for (var i = 0; i < this.activeX.length; ++i) {
2477 http = new ActiveXObject(this.activeX[i]);
2479 obj = { conn:http, tId:transactionId };
2492 getConnectionObject:function()
2495 var tId = this.transactionId;
2499 o = this.createXhrObject(tId);
2501 this.transactionId++;
2512 asyncRequest:function(method, uri, callback, postData)
2514 var o = this.getConnectionObject();
2520 o.conn.open(method, uri, true);
2522 if (this.useDefaultXhrHeader) {
2523 if (!this.defaultHeaders['X-Requested-With']) {
2524 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2528 if(postData && this.useDefaultHeader){
2529 this.initHeader('Content-Type', this.defaultPostHeader);
2532 if (this.hasDefaultHeaders || this.hasHeaders) {
2536 this.handleReadyState(o, callback);
2537 o.conn.send(postData || null);
2543 handleReadyState:function(o, callback)
2547 if (callback && callback.timeout) {
2548 this.timeout[o.tId] = window.setTimeout(function() {
2549 oConn.abort(o, callback, true);
2550 }, callback.timeout);
2553 this.poll[o.tId] = window.setInterval(
2555 if (o.conn && o.conn.readyState == 4) {
2556 window.clearInterval(oConn.poll[o.tId]);
2557 delete oConn.poll[o.tId];
2559 if(callback && callback.timeout) {
2560 window.clearTimeout(oConn.timeout[o.tId]);
2561 delete oConn.timeout[o.tId];
2564 oConn.handleTransactionResponse(o, callback);
2567 , this.pollInterval);
2570 handleTransactionResponse:function(o, callback, isAbort)
2574 this.releaseObject(o);
2578 var httpStatus, responseObject;
2582 if (o.conn.status !== undefined && o.conn.status != 0) {
2583 httpStatus = o.conn.status;
2595 if (httpStatus >= 200 && httpStatus < 300) {
2596 responseObject = this.createResponseObject(o, callback.argument);
2597 if (callback.success) {
2598 if (!callback.scope) {
2599 callback.success(responseObject);
2604 callback.success.apply(callback.scope, [responseObject]);
2609 switch (httpStatus) {
2617 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2618 if (callback.failure) {
2619 if (!callback.scope) {
2620 callback.failure(responseObject);
2623 callback.failure.apply(callback.scope, [responseObject]);
2628 responseObject = this.createResponseObject(o, callback.argument);
2629 if (callback.failure) {
2630 if (!callback.scope) {
2631 callback.failure(responseObject);
2634 callback.failure.apply(callback.scope, [responseObject]);
2640 this.releaseObject(o);
2641 responseObject = null;
2644 createResponseObject:function(o, callbackArg)
2651 var headerStr = o.conn.getAllResponseHeaders();
2652 var header = headerStr.split('\n');
2653 for (var i = 0; i < header.length; i++) {
2654 var delimitPos = header[i].indexOf(':');
2655 if (delimitPos != -1) {
2656 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2664 obj.status = o.conn.status;
2665 obj.statusText = o.conn.statusText;
2666 obj.getResponseHeader = headerObj;
2667 obj.getAllResponseHeaders = headerStr;
2668 obj.responseText = o.conn.responseText;
2669 obj.responseXML = o.conn.responseXML;
2671 if (typeof callbackArg !== undefined) {
2672 obj.argument = callbackArg;
2678 createExceptionObject:function(tId, callbackArg, isAbort)
2681 var COMM_ERROR = 'communication failure';
2682 var ABORT_CODE = -1;
2683 var ABORT_ERROR = 'transaction aborted';
2689 obj.status = ABORT_CODE;
2690 obj.statusText = ABORT_ERROR;
2693 obj.status = COMM_CODE;
2694 obj.statusText = COMM_ERROR;
2698 obj.argument = callbackArg;
2704 initHeader:function(label, value, isDefault)
2706 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2708 if (headerObj[label] === undefined) {
2709 headerObj[label] = value;
2714 headerObj[label] = value + "," + headerObj[label];
2718 this.hasDefaultHeaders = true;
2721 this.hasHeaders = true;
2726 setHeader:function(o)
2728 if (this.hasDefaultHeaders) {
2729 for (var prop in this.defaultHeaders) {
2730 if (this.defaultHeaders.hasOwnProperty(prop)) {
2731 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2736 if (this.hasHeaders) {
2737 for (var prop in this.headers) {
2738 if (this.headers.hasOwnProperty(prop)) {
2739 o.conn.setRequestHeader(prop, this.headers[prop]);
2743 this.hasHeaders = false;
2747 resetDefaultHeaders:function() {
2748 delete this.defaultHeaders;
2749 this.defaultHeaders = {};
2750 this.hasDefaultHeaders = false;
2753 abort:function(o, callback, isTimeout)
2755 if(this.isCallInProgress(o)) {
2757 window.clearInterval(this.poll[o.tId]);
2758 delete this.poll[o.tId];
2760 delete this.timeout[o.tId];
2763 this.handleTransactionResponse(o, callback, true);
2773 isCallInProgress:function(o)
2776 return o.conn.readyState != 4 && o.conn.readyState != 0;
2785 releaseObject:function(o)
2794 'MSXML2.XMLHTTP.3.0',
2802 * Portions of this file are based on pieces of Yahoo User Interface Library
2803 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2804 * YUI licensed under the BSD License:
2805 * http://developer.yahoo.net/yui/license.txt
2806 * <script type="text/javascript">
2810 Roo.lib.Region = function(t, r, b, l) {
2820 Roo.lib.Region.prototype = {
2821 contains : function(region) {
2822 return ( region.left >= this.left &&
2823 region.right <= this.right &&
2824 region.top >= this.top &&
2825 region.bottom <= this.bottom );
2829 getArea : function() {
2830 return ( (this.bottom - this.top) * (this.right - this.left) );
2833 intersect : function(region) {
2834 var t = Math.max(this.top, region.top);
2835 var r = Math.min(this.right, region.right);
2836 var b = Math.min(this.bottom, region.bottom);
2837 var l = Math.max(this.left, region.left);
2839 if (b >= t && r >= l) {
2840 return new Roo.lib.Region(t, r, b, l);
2845 union : function(region) {
2846 var t = Math.min(this.top, region.top);
2847 var r = Math.max(this.right, region.right);
2848 var b = Math.max(this.bottom, region.bottom);
2849 var l = Math.min(this.left, region.left);
2851 return new Roo.lib.Region(t, r, b, l);
2854 adjust : function(t, l, b, r) {
2863 Roo.lib.Region.getRegion = function(el) {
2864 var p = Roo.lib.Dom.getXY(el);
2867 var r = p[0] + el.offsetWidth;
2868 var b = p[1] + el.offsetHeight;
2871 return new Roo.lib.Region(t, r, b, l);
2874 * Portions of this file are based on pieces of Yahoo User Interface Library
2875 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2876 * YUI licensed under the BSD License:
2877 * http://developer.yahoo.net/yui/license.txt
2878 * <script type="text/javascript">
2881 //@@dep Roo.lib.Region
2884 Roo.lib.Point = function(x, y) {
2885 if (x instanceof Array) {
2889 this.x = this.right = this.left = this[0] = x;
2890 this.y = this.top = this.bottom = this[1] = y;
2893 Roo.lib.Point.prototype = new Roo.lib.Region();
2895 * Portions of this file are based on pieces of Yahoo User Interface Library
2896 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2897 * YUI licensed under the BSD License:
2898 * http://developer.yahoo.net/yui/license.txt
2899 * <script type="text/javascript">
2906 scroll : function(el, args, duration, easing, cb, scope) {
2907 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
2910 motion : function(el, args, duration, easing, cb, scope) {
2911 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
2914 color : function(el, args, duration, easing, cb, scope) {
2915 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
2918 run : function(el, args, duration, easing, cb, scope, type) {
2919 type = type || Roo.lib.AnimBase;
2920 if (typeof easing == "string") {
2921 easing = Roo.lib.Easing[easing];
2923 var anim = new type(el, args, duration, easing);
2924 anim.animateX(function() {
2925 Roo.callback(cb, scope);
2931 * Portions of this file are based on pieces of Yahoo User Interface Library
2932 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2933 * YUI licensed under the BSD License:
2934 * http://developer.yahoo.net/yui/license.txt
2935 * <script type="text/javascript">
2943 if (!libFlyweight) {
2944 libFlyweight = new Roo.Element.Flyweight();
2946 libFlyweight.dom = el;
2947 return libFlyweight;
2950 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
2954 Roo.lib.AnimBase = function(el, attributes, duration, method) {
2956 this.init(el, attributes, duration, method);
2960 Roo.lib.AnimBase.fly = fly;
2964 Roo.lib.AnimBase.prototype = {
2966 toString: function() {
2967 var el = this.getEl();
2968 var id = el.id || el.tagName;
2969 return ("Anim " + id);
2973 noNegatives: /width|height|opacity|padding/i,
2974 offsetAttribute: /^((width|height)|(top|left))$/,
2975 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
2976 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
2980 doMethod: function(attr, start, end) {
2981 return this.method(this.currentFrame, start, end - start, this.totalFrames);
2985 setAttribute: function(attr, val, unit) {
2986 if (this.patterns.noNegatives.test(attr)) {
2987 val = (val > 0) ? val : 0;
2990 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
2994 getAttribute: function(attr) {
2995 var el = this.getEl();
2996 var val = fly(el).getStyle(attr);
2998 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
2999 return parseFloat(val);
3002 var a = this.patterns.offsetAttribute.exec(attr) || [];
3003 var pos = !!( a[3] );
3004 var box = !!( a[2] );
3007 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3008 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3017 getDefaultUnit: function(attr) {
3018 if (this.patterns.defaultUnit.test(attr)) {
3025 animateX : function(callback, scope) {
3026 var f = function() {
3027 this.onComplete.removeListener(f);
3028 if (typeof callback == "function") {
3029 callback.call(scope || this, this);
3032 this.onComplete.addListener(f, this);
3037 setRuntimeAttribute: function(attr) {
3040 var attributes = this.attributes;
3042 this.runtimeAttributes[attr] = {};
3044 var isset = function(prop) {
3045 return (typeof prop !== 'undefined');
3048 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3052 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3055 if (isset(attributes[attr]['to'])) {
3056 end = attributes[attr]['to'];
3057 } else if (isset(attributes[attr]['by'])) {
3058 if (start.constructor == Array) {
3060 for (var i = 0, len = start.length; i < len; ++i) {
3061 end[i] = start[i] + attributes[attr]['by'][i];
3064 end = start + attributes[attr]['by'];
3068 this.runtimeAttributes[attr].start = start;
3069 this.runtimeAttributes[attr].end = end;
3072 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3076 init: function(el, attributes, duration, method) {
3078 var isAnimated = false;
3081 var startTime = null;
3084 var actualFrames = 0;
3087 el = Roo.getDom(el);
3090 this.attributes = attributes || {};
3093 this.duration = duration || 1;
3096 this.method = method || Roo.lib.Easing.easeNone;
3099 this.useSeconds = true;
3102 this.currentFrame = 0;
3105 this.totalFrames = Roo.lib.AnimMgr.fps;
3108 this.getEl = function() {
3113 this.isAnimated = function() {
3118 this.getStartTime = function() {
3122 this.runtimeAttributes = {};
3125 this.animate = function() {
3126 if (this.isAnimated()) {
3130 this.currentFrame = 0;
3132 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3134 Roo.lib.AnimMgr.registerElement(this);
3138 this.stop = function(finish) {
3140 this.currentFrame = this.totalFrames;
3141 this._onTween.fire();
3143 Roo.lib.AnimMgr.stop(this);
3146 var onStart = function() {
3147 this.onStart.fire();
3149 this.runtimeAttributes = {};
3150 for (var attr in this.attributes) {
3151 this.setRuntimeAttribute(attr);
3156 startTime = new Date();
3160 var onTween = function() {
3162 duration: new Date() - this.getStartTime(),
3163 currentFrame: this.currentFrame
3166 data.toString = function() {
3168 'duration: ' + data.duration +
3169 ', currentFrame: ' + data.currentFrame
3173 this.onTween.fire(data);
3175 var runtimeAttributes = this.runtimeAttributes;
3177 for (var attr in runtimeAttributes) {
3178 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3184 var onComplete = function() {
3185 var actual_duration = (new Date() - startTime) / 1000 ;
3188 duration: actual_duration,
3189 frames: actualFrames,
3190 fps: actualFrames / actual_duration
3193 data.toString = function() {
3195 'duration: ' + data.duration +
3196 ', frames: ' + data.frames +
3197 ', fps: ' + data.fps
3203 this.onComplete.fire(data);
3207 this._onStart = new Roo.util.Event(this);
3208 this.onStart = new Roo.util.Event(this);
3209 this.onTween = new Roo.util.Event(this);
3210 this._onTween = new Roo.util.Event(this);
3211 this.onComplete = new Roo.util.Event(this);
3212 this._onComplete = new Roo.util.Event(this);
3213 this._onStart.addListener(onStart);
3214 this._onTween.addListener(onTween);
3215 this._onComplete.addListener(onComplete);
3220 * Portions of this file are based on pieces of Yahoo User Interface Library
3221 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3222 * YUI licensed under the BSD License:
3223 * http://developer.yahoo.net/yui/license.txt
3224 * <script type="text/javascript">
3228 Roo.lib.AnimMgr = new function() {
3245 this.registerElement = function(tween) {
3246 queue[queue.length] = tween;
3248 tween._onStart.fire();
3253 this.unRegister = function(tween, index) {
3254 tween._onComplete.fire();
3255 index = index || getIndex(tween);
3257 queue.splice(index, 1);
3261 if (tweenCount <= 0) {
3267 this.start = function() {
3268 if (thread === null) {
3269 thread = setInterval(this.run, this.delay);
3274 this.stop = function(tween) {
3276 clearInterval(thread);
3278 for (var i = 0, len = queue.length; i < len; ++i) {
3279 if (queue[0].isAnimated()) {
3280 this.unRegister(queue[0], 0);
3289 this.unRegister(tween);
3294 this.run = function() {
3295 for (var i = 0, len = queue.length; i < len; ++i) {
3296 var tween = queue[i];
3297 if (!tween || !tween.isAnimated()) {
3301 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3303 tween.currentFrame += 1;
3305 if (tween.useSeconds) {
3306 correctFrame(tween);
3308 tween._onTween.fire();
3311 Roo.lib.AnimMgr.stop(tween, i);
3316 var getIndex = function(anim) {
3317 for (var i = 0, len = queue.length; i < len; ++i) {
3318 if (queue[i] == anim) {
3326 var correctFrame = function(tween) {
3327 var frames = tween.totalFrames;
3328 var frame = tween.currentFrame;
3329 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3330 var elapsed = (new Date() - tween.getStartTime());
3333 if (elapsed < tween.duration * 1000) {
3334 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3336 tweak = frames - (frame + 1);
3338 if (tweak > 0 && isFinite(tweak)) {
3339 if (tween.currentFrame + tweak >= frames) {
3340 tweak = frames - (frame + 1);
3343 tween.currentFrame += tweak;
3347 * Portions of this file are based on pieces of Yahoo User Interface Library
3348 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3349 * YUI licensed under the BSD License:
3350 * http://developer.yahoo.net/yui/license.txt
3351 * <script type="text/javascript">
3354 Roo.lib.Bezier = new function() {
3356 this.getPosition = function(points, t) {
3357 var n = points.length;
3360 for (var i = 0; i < n; ++i) {
3361 tmp[i] = [points[i][0], points[i][1]];
3364 for (var j = 1; j < n; ++j) {
3365 for (i = 0; i < n - j; ++i) {
3366 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3367 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3371 return [ tmp[0][0], tmp[0][1] ];
3375 * Portions of this file are based on pieces of Yahoo User Interface Library
3376 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3377 * YUI licensed under the BSD License:
3378 * http://developer.yahoo.net/yui/license.txt
3379 * <script type="text/javascript">
3384 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3385 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3388 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3390 var fly = Roo.lib.AnimBase.fly;
3392 var superclass = Y.ColorAnim.superclass;
3393 var proto = Y.ColorAnim.prototype;
3395 proto.toString = function() {
3396 var el = this.getEl();
3397 var id = el.id || el.tagName;
3398 return ("ColorAnim " + id);
3401 proto.patterns.color = /color$/i;
3402 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3403 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3404 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3405 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3408 proto.parseColor = function(s) {
3409 if (s.length == 3) {
3413 var c = this.patterns.hex.exec(s);
3414 if (c && c.length == 4) {
3415 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3418 c = this.patterns.rgb.exec(s);
3419 if (c && c.length == 4) {
3420 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3423 c = this.patterns.hex3.exec(s);
3424 if (c && c.length == 4) {
3425 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3430 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3431 proto.getAttribute = function(attr) {
3432 var el = this.getEl();
3433 if (this.patterns.color.test(attr)) {
3434 var val = fly(el).getStyle(attr);
3436 if (this.patterns.transparent.test(val)) {
3437 var parent = el.parentNode;
3438 val = fly(parent).getStyle(attr);
3440 while (parent && this.patterns.transparent.test(val)) {
3441 parent = parent.parentNode;
3442 val = fly(parent).getStyle(attr);
3443 if (parent.tagName.toUpperCase() == 'HTML') {
3449 val = superclass.getAttribute.call(this, attr);
3454 proto.getAttribute = function(attr) {
3455 var el = this.getEl();
3456 if (this.patterns.color.test(attr)) {
3457 var val = fly(el).getStyle(attr);
3459 if (this.patterns.transparent.test(val)) {
3460 var parent = el.parentNode;
3461 val = fly(parent).getStyle(attr);
3463 while (parent && this.patterns.transparent.test(val)) {
3464 parent = parent.parentNode;
3465 val = fly(parent).getStyle(attr);
3466 if (parent.tagName.toUpperCase() == 'HTML') {
3472 val = superclass.getAttribute.call(this, attr);
3478 proto.doMethod = function(attr, start, end) {
3481 if (this.patterns.color.test(attr)) {
3483 for (var i = 0, len = start.length; i < len; ++i) {
3484 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3487 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3490 val = superclass.doMethod.call(this, attr, start, end);
3496 proto.setRuntimeAttribute = function(attr) {
3497 superclass.setRuntimeAttribute.call(this, attr);
3499 if (this.patterns.color.test(attr)) {
3500 var attributes = this.attributes;
3501 var start = this.parseColor(this.runtimeAttributes[attr].start);
3502 var end = this.parseColor(this.runtimeAttributes[attr].end);
3504 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3505 end = this.parseColor(attributes[attr].by);
3507 for (var i = 0, len = start.length; i < len; ++i) {
3508 end[i] = start[i] + end[i];
3512 this.runtimeAttributes[attr].start = start;
3513 this.runtimeAttributes[attr].end = end;
3519 * Portions of this file are based on pieces of Yahoo User Interface Library
3520 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3521 * YUI licensed under the BSD License:
3522 * http://developer.yahoo.net/yui/license.txt
3523 * <script type="text/javascript">
3529 easeNone: function (t, b, c, d) {
3530 return c * t / d + b;
3534 easeIn: function (t, b, c, d) {
3535 return c * (t /= d) * t + b;
3539 easeOut: function (t, b, c, d) {
3540 return -c * (t /= d) * (t - 2) + b;
3544 easeBoth: function (t, b, c, d) {
3545 if ((t /= d / 2) < 1) {
3546 return c / 2 * t * t + b;
3549 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3553 easeInStrong: function (t, b, c, d) {
3554 return c * (t /= d) * t * t * t + b;
3558 easeOutStrong: function (t, b, c, d) {
3559 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3563 easeBothStrong: function (t, b, c, d) {
3564 if ((t /= d / 2) < 1) {
3565 return c / 2 * t * t * t * t + b;
3568 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3573 elasticIn: function (t, b, c, d, a, p) {
3577 if ((t /= d) == 1) {
3584 if (!a || a < Math.abs(c)) {
3589 var s = p / (2 * Math.PI) * Math.asin(c / a);
3592 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3596 elasticOut: function (t, b, c, d, a, p) {
3600 if ((t /= d) == 1) {
3607 if (!a || a < Math.abs(c)) {
3612 var s = p / (2 * Math.PI) * Math.asin(c / a);
3615 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3619 elasticBoth: function (t, b, c, d, a, p) {
3624 if ((t /= d / 2) == 2) {
3632 if (!a || a < Math.abs(c)) {
3637 var s = p / (2 * Math.PI) * Math.asin(c / a);
3641 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3642 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3644 return a * Math.pow(2, -10 * (t -= 1)) *
3645 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3650 backIn: function (t, b, c, d, s) {
3651 if (typeof s == 'undefined') {
3654 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3658 backOut: function (t, b, c, d, s) {
3659 if (typeof s == 'undefined') {
3662 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3666 backBoth: function (t, b, c, d, s) {
3667 if (typeof s == 'undefined') {
3671 if ((t /= d / 2 ) < 1) {
3672 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3674 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3678 bounceIn: function (t, b, c, d) {
3679 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3683 bounceOut: function (t, b, c, d) {
3684 if ((t /= d) < (1 / 2.75)) {
3685 return c * (7.5625 * t * t) + b;
3686 } else if (t < (2 / 2.75)) {
3687 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3688 } else if (t < (2.5 / 2.75)) {
3689 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3691 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3695 bounceBoth: function (t, b, c, d) {
3697 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3699 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3702 * Portions of this file are based on pieces of Yahoo User Interface Library
3703 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3704 * YUI licensed under the BSD License:
3705 * http://developer.yahoo.net/yui/license.txt
3706 * <script type="text/javascript">
3710 Roo.lib.Motion = function(el, attributes, duration, method) {
3712 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3716 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3720 var superclass = Y.Motion.superclass;
3721 var proto = Y.Motion.prototype;
3723 proto.toString = function() {
3724 var el = this.getEl();
3725 var id = el.id || el.tagName;
3726 return ("Motion " + id);
3729 proto.patterns.points = /^points$/i;
3731 proto.setAttribute = function(attr, val, unit) {
3732 if (this.patterns.points.test(attr)) {
3733 unit = unit || 'px';
3734 superclass.setAttribute.call(this, 'left', val[0], unit);
3735 superclass.setAttribute.call(this, 'top', val[1], unit);
3737 superclass.setAttribute.call(this, attr, val, unit);
3741 proto.getAttribute = function(attr) {
3742 if (this.patterns.points.test(attr)) {
3744 superclass.getAttribute.call(this, 'left'),
3745 superclass.getAttribute.call(this, 'top')
3748 val = superclass.getAttribute.call(this, attr);
3754 proto.doMethod = function(attr, start, end) {
3757 if (this.patterns.points.test(attr)) {
3758 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3759 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3761 val = superclass.doMethod.call(this, attr, start, end);
3766 proto.setRuntimeAttribute = function(attr) {
3767 if (this.patterns.points.test(attr)) {
3768 var el = this.getEl();
3769 var attributes = this.attributes;
3771 var control = attributes['points']['control'] || [];
3775 if (control.length > 0 && !(control[0] instanceof Array)) {
3776 control = [control];
3779 for (i = 0,len = control.length; i < len; ++i) {
3780 tmp[i] = control[i];
3785 Roo.fly(el).position();
3787 if (isset(attributes['points']['from'])) {
3788 Roo.lib.Dom.setXY(el, attributes['points']['from']);
3791 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3794 start = this.getAttribute('points');
3797 if (isset(attributes['points']['to'])) {
3798 end = translateValues.call(this, attributes['points']['to'], start);
3800 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3801 for (i = 0,len = control.length; i < len; ++i) {
3802 control[i] = translateValues.call(this, control[i], start);
3806 } else if (isset(attributes['points']['by'])) {
3807 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3809 for (i = 0,len = control.length; i < len; ++i) {
3810 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3814 this.runtimeAttributes[attr] = [start];
3816 if (control.length > 0) {
3817 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3820 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
3823 superclass.setRuntimeAttribute.call(this, attr);
3827 var translateValues = function(val, start) {
3828 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3829 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
3834 var isset = function(prop) {
3835 return (typeof prop !== 'undefined');
3839 * Portions of this file are based on pieces of Yahoo User Interface Library
3840 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3841 * YUI licensed under the BSD License:
3842 * http://developer.yahoo.net/yui/license.txt
3843 * <script type="text/javascript">
3847 Roo.lib.Scroll = function(el, attributes, duration, method) {
3849 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
3853 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
3857 var superclass = Y.Scroll.superclass;
3858 var proto = Y.Scroll.prototype;
3860 proto.toString = function() {
3861 var el = this.getEl();
3862 var id = el.id || el.tagName;
3863 return ("Scroll " + id);
3866 proto.doMethod = function(attr, start, end) {
3869 if (attr == 'scroll') {
3871 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
3872 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
3876 val = superclass.doMethod.call(this, attr, start, end);
3881 proto.getAttribute = function(attr) {
3883 var el = this.getEl();
3885 if (attr == 'scroll') {
3886 val = [ el.scrollLeft, el.scrollTop ];
3888 val = superclass.getAttribute.call(this, attr);
3894 proto.setAttribute = function(attr, val, unit) {
3895 var el = this.getEl();
3897 if (attr == 'scroll') {
3898 el.scrollLeft = val[0];
3899 el.scrollTop = val[1];
3901 superclass.setAttribute.call(this, attr, val, unit);
3907 * Ext JS Library 1.1.1
3908 * Copyright(c) 2006-2007, Ext JS, LLC.
3910 * Originally Released Under LGPL - original licence link has changed is not relivant.
3913 * <script type="text/javascript">
3918 * @class Roo.DomHelper
3919 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
3920 * For more information see <a href="http://www.jackslocum.com/yui/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
3923 Roo.DomHelper = function(){
3924 var tempTableEl = null;
3925 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
3926 var tableRe = /^table|tbody|tr|td$/i;
3928 // build as innerHTML where available
3930 var createHtml = function(o){
3931 if(typeof o == 'string'){
3940 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
3941 if(attr == "style"){
3943 if(typeof s == "function"){
3946 if(typeof s == "string"){
3947 b += ' style="' + s + '"';
3948 }else if(typeof s == "object"){
3951 if(typeof s[key] != "function"){
3952 b += key + ":" + s[key] + ";";
3959 b += ' class="' + o["cls"] + '"';
3960 }else if(attr == "htmlFor"){
3961 b += ' for="' + o["htmlFor"] + '"';
3963 b += " " + attr + '="' + o[attr] + '"';
3967 if(emptyTags.test(o.tag)){
3971 var cn = o.children || o.cn;
3973 //http://bugs.kde.org/show_bug.cgi?id=71506
3974 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
3975 for(var i = 0, len = cn.length; i < len; i++) {
3976 b += createHtml(cn[i], b);
3979 b += createHtml(cn, b);
3985 b += "</" + o.tag + ">";
3992 var createDom = function(o, parentNode){
3994 // defininition craeted..
3996 if (o.ns && o.ns != 'html') {
3998 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
3999 xmlns[o.ns] = o.xmlns;
4002 if (typeof(xmlns[o.ns]) == 'undefined') {
4003 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4009 if (typeof(o) == 'string') {
4010 return parentNode.appendChild(document.createTextNode(o));
4012 o.tag = o.tag || div;
4013 if (o.ns && Roo.isIE) {
4015 o.tag = o.ns + ':' + o.tag;
4018 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4019 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4022 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4023 attr == "style" || typeof o[attr] == "function") continue;
4025 if(attr=="cls" && Roo.isIE){
4026 el.className = o["cls"];
4028 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4029 else el[attr] = o[attr];
4032 Roo.DomHelper.applyStyles(el, o.style);
4033 var cn = o.children || o.cn;
4035 //http://bugs.kde.org/show_bug.cgi?id=71506
4036 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4037 for(var i = 0, len = cn.length; i < len; i++) {
4038 createDom(cn[i], el);
4045 el.innerHTML = o.html;
4048 parentNode.appendChild(el);
4053 var ieTable = function(depth, s, h, e){
4054 tempTableEl.innerHTML = [s, h, e].join('');
4055 var i = -1, el = tempTableEl;
4062 // kill repeat to save bytes
4066 tbe = '</tbody>'+te,
4072 * Nasty code for IE's broken table implementation
4074 var insertIntoTable = function(tag, where, el, html){
4076 tempTableEl = document.createElement('div');
4081 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4084 if(where == 'beforebegin'){
4088 before = el.nextSibling;
4091 node = ieTable(4, trs, html, tre);
4093 else if(tag == 'tr'){
4094 if(where == 'beforebegin'){
4097 node = ieTable(3, tbs, html, tbe);
4098 } else if(where == 'afterend'){
4099 before = el.nextSibling;
4101 node = ieTable(3, tbs, html, tbe);
4102 } else{ // INTO a TR
4103 if(where == 'afterbegin'){
4104 before = el.firstChild;
4106 node = ieTable(4, trs, html, tre);
4108 } else if(tag == 'tbody'){
4109 if(where == 'beforebegin'){
4112 node = ieTable(2, ts, html, te);
4113 } else if(where == 'afterend'){
4114 before = el.nextSibling;
4116 node = ieTable(2, ts, html, te);
4118 if(where == 'afterbegin'){
4119 before = el.firstChild;
4121 node = ieTable(3, tbs, html, tbe);
4124 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4127 if(where == 'afterbegin'){
4128 before = el.firstChild;
4130 node = ieTable(2, ts, html, te);
4132 el.insertBefore(node, before);
4137 /** True to force the use of DOM instead of html fragments @type Boolean */
4141 * Returns the markup for the passed Element(s) config
4142 * @param {Object} o The Dom object spec (and children)
4145 markup : function(o){
4146 return createHtml(o);
4150 * Applies a style specification to an element
4151 * @param {String/HTMLElement} el The element to apply styles to
4152 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4153 * a function which returns such a specification.
4155 applyStyles : function(el, styles){
4158 if(typeof styles == "string"){
4159 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4161 while ((matches = re.exec(styles)) != null){
4162 el.setStyle(matches[1], matches[2]);
4164 }else if (typeof styles == "object"){
4165 for (var style in styles){
4166 el.setStyle(style, styles[style]);
4168 }else if (typeof styles == "function"){
4169 Roo.DomHelper.applyStyles(el, styles.call());
4175 * Inserts an HTML fragment into the Dom
4176 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4177 * @param {HTMLElement} el The context element
4178 * @param {String} html The HTML fragmenet
4179 * @return {HTMLElement} The new node
4181 insertHtml : function(where, el, html){
4182 where = where.toLowerCase();
4183 if(el.insertAdjacentHTML){
4184 if(tableRe.test(el.tagName)){
4186 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4192 el.insertAdjacentHTML('BeforeBegin', html);
4193 return el.previousSibling;
4195 el.insertAdjacentHTML('AfterBegin', html);
4196 return el.firstChild;
4198 el.insertAdjacentHTML('BeforeEnd', html);
4199 return el.lastChild;
4201 el.insertAdjacentHTML('AfterEnd', html);
4202 return el.nextSibling;
4204 throw 'Illegal insertion point -> "' + where + '"';
4206 var range = el.ownerDocument.createRange();
4210 range.setStartBefore(el);
4211 frag = range.createContextualFragment(html);
4212 el.parentNode.insertBefore(frag, el);
4213 return el.previousSibling;
4216 range.setStartBefore(el.firstChild);
4217 frag = range.createContextualFragment(html);
4218 el.insertBefore(frag, el.firstChild);
4219 return el.firstChild;
4221 el.innerHTML = html;
4222 return el.firstChild;
4226 range.setStartAfter(el.lastChild);
4227 frag = range.createContextualFragment(html);
4228 el.appendChild(frag);
4229 return el.lastChild;
4231 el.innerHTML = html;
4232 return el.lastChild;
4235 range.setStartAfter(el);
4236 frag = range.createContextualFragment(html);
4237 el.parentNode.insertBefore(frag, el.nextSibling);
4238 return el.nextSibling;
4240 throw 'Illegal insertion point -> "' + where + '"';
4244 * Creates new Dom element(s) and inserts them before el
4245 * @param {String/HTMLElement/Element} el The context element
4246 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4247 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4248 * @return {HTMLElement/Roo.Element} The new node
4250 insertBefore : function(el, o, returnElement){
4251 return this.doInsert(el, o, returnElement, "beforeBegin");
4255 * Creates new Dom element(s) and inserts them after el
4256 * @param {String/HTMLElement/Element} el The context element
4257 * @param {Object} o The Dom object spec (and children)
4258 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4259 * @return {HTMLElement/Roo.Element} The new node
4261 insertAfter : function(el, o, returnElement){
4262 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4266 * Creates new Dom element(s) and inserts them as the first child of el
4267 * @param {String/HTMLElement/Element} el The context element
4268 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4269 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4270 * @return {HTMLElement/Roo.Element} The new node
4272 insertFirst : function(el, o, returnElement){
4273 return this.doInsert(el, o, returnElement, "afterBegin");
4277 doInsert : function(el, o, returnElement, pos, sibling){
4278 el = Roo.getDom(el);
4280 if(this.useDom || o.ns){
4281 newNode = createDom(o, null);
4282 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4284 var html = createHtml(o);
4285 newNode = this.insertHtml(pos, el, html);
4287 return returnElement ? Roo.get(newNode, true) : newNode;
4291 * Creates new Dom element(s) and appends them to el
4292 * @param {String/HTMLElement/Element} el The context element
4293 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4294 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4295 * @return {HTMLElement/Roo.Element} The new node
4297 append : function(el, o, returnElement){
4298 el = Roo.getDom(el);
4300 if(this.useDom || o.ns){
4301 newNode = createDom(o, null);
4302 el.appendChild(newNode);
4304 var html = createHtml(o);
4305 newNode = this.insertHtml("beforeEnd", el, html);
4307 return returnElement ? Roo.get(newNode, true) : newNode;
4311 * Creates new Dom element(s) and overwrites the contents of el with them
4312 * @param {String/HTMLElement/Element} el The context element
4313 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4314 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4315 * @return {HTMLElement/Roo.Element} The new node
4317 overwrite : function(el, o, returnElement){
4318 el = Roo.getDom(el);
4321 while (el.childNodes.length) {
4322 el.removeChild(el.firstChild);
4326 el.innerHTML = createHtml(o);
4329 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4333 * Creates a new Roo.DomHelper.Template from the Dom object spec
4334 * @param {Object} o The Dom object spec (and children)
4335 * @return {Roo.DomHelper.Template} The new template
4337 createTemplate : function(o){
4338 var html = createHtml(o);
4339 return new Roo.Template(html);
4345 * Ext JS Library 1.1.1
4346 * Copyright(c) 2006-2007, Ext JS, LLC.
4348 * Originally Released Under LGPL - original licence link has changed is not relivant.
4351 * <script type="text/javascript">
4355 * @class Roo.Template
4356 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4357 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4360 var t = new Roo.Template(
4361 '<div name="{id}">',
4362 '<span class="{cls}">{name:trim} {value:ellipsis(10)}</span>',
4365 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4367 * For more information see this blog post with examples: <a href="http://www.jackslocum.com/yui/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">DomHelper - Create Elements using DOM, HTML fragments and Templates</a>.
4369 * @param {String/Array} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4371 Roo.Template = function(html){
4372 if(html instanceof Array){
4373 html = html.join("");
4374 }else if(arguments.length > 1){
4375 html = Array.prototype.join.call(arguments, "");
4381 Roo.Template.prototype = {
4383 * Returns an HTML fragment of this template with the specified values applied.
4384 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4385 * @return {String} The HTML fragment
4387 applyTemplate : function(values){
4389 return this.compiled(values);
4391 var useF = this.disableFormats !== true;
4392 var fm = Roo.util.Format, tpl = this;
4393 var fn = function(m, name, format, args){
4395 if(format.substr(0, 5) == "this."){
4396 return tpl.call(format.substr(5), values[name], values);
4399 // quoted values are required for strings in compiled templates,
4400 // but for non compiled we need to strip them
4401 // quoted reversed for jsmin
4402 var re = /^\s*['"](.*)["']\s*$/;
4403 args = args.split(',');
4404 for(var i = 0, len = args.length; i < len; i++){
4405 args[i] = args[i].replace(re, "$1");
4407 args = [values[name]].concat(args);
4409 args = [values[name]];
4411 return fm[format].apply(fm, args);
4414 return values[name] !== undefined ? values[name] : "";
4417 return this.html.replace(this.re, fn);
4421 * Sets the HTML used as the template and optionally compiles it.
4422 * @param {String} html
4423 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4424 * @return {Roo.Template} this
4426 set : function(html, compile){
4428 this.compiled = null;
4436 * True to disable format functions (defaults to false)
4439 disableFormats : false,
4442 * The regular expression used to match template variables
4446 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4449 * Compiles the template into an internal function, eliminating the RegEx overhead.
4450 * @return {Roo.Template} this
4452 compile : function(){
4453 var fm = Roo.util.Format;
4454 var useF = this.disableFormats !== true;
4455 var sep = Roo.isGecko ? "+" : ",";
4456 var fn = function(m, name, format, args){
4458 args = args ? ',' + args : "";
4459 if(format.substr(0, 5) != "this."){
4460 format = "fm." + format + '(';
4462 format = 'this.call("'+ format.substr(5) + '", ';
4466 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4468 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4471 // branched to use + in gecko and [].join() in others
4473 body = "this.compiled = function(values){ return '" +
4474 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4477 body = ["this.compiled = function(values){ return ['"];
4478 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4479 body.push("'].join('');};");
4480 body = body.join('');
4490 // private function used to call members
4491 call : function(fnName, value, allValues){
4492 return this[fnName](value, allValues);
4496 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4497 * @param {String/HTMLElement/Roo.Element} el The context element
4498 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4499 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4500 * @return {HTMLElement/Roo.Element} The new node or Element
4502 insertFirst: function(el, values, returnElement){
4503 return this.doInsert('afterBegin', el, values, returnElement);
4507 * Applies the supplied values to the template and inserts the new node(s) before el.
4508 * @param {String/HTMLElement/Roo.Element} el The context element
4509 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4510 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4511 * @return {HTMLElement/Roo.Element} The new node or Element
4513 insertBefore: function(el, values, returnElement){
4514 return this.doInsert('beforeBegin', el, values, returnElement);
4518 * Applies the supplied values to the template and inserts the new node(s) after el.
4519 * @param {String/HTMLElement/Roo.Element} el The context element
4520 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4521 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4522 * @return {HTMLElement/Roo.Element} The new node or Element
4524 insertAfter : function(el, values, returnElement){
4525 return this.doInsert('afterEnd', el, values, returnElement);
4529 * Applies the supplied values to the template and appends the new node(s) to el.
4530 * @param {String/HTMLElement/Roo.Element} el The context element
4531 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4532 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4533 * @return {HTMLElement/Roo.Element} The new node or Element
4535 append : function(el, values, returnElement){
4536 return this.doInsert('beforeEnd', el, values, returnElement);
4539 doInsert : function(where, el, values, returnEl){
4540 el = Roo.getDom(el);
4541 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4542 return returnEl ? Roo.get(newNode, true) : newNode;
4546 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4547 * @param {String/HTMLElement/Roo.Element} el The context element
4548 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4549 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4550 * @return {HTMLElement/Roo.Element} The new node or Element
4552 overwrite : function(el, values, returnElement){
4553 el = Roo.getDom(el);
4554 el.innerHTML = this.applyTemplate(values);
4555 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4559 * Alias for {@link #applyTemplate}
4562 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4565 Roo.DomHelper.Template = Roo.Template;
4568 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4569 * @param {String/HTMLElement} el A DOM element or its id
4570 * @returns {Roo.Template} The created template
4573 Roo.Template.from = function(el){
4574 el = Roo.getDom(el);
4575 return new Roo.Template(el.value || el.innerHTML);
4578 * Ext JS Library 1.1.1
4579 * Copyright(c) 2006-2007, Ext JS, LLC.
4581 * Originally Released Under LGPL - original licence link has changed is not relivant.
4584 * <script type="text/javascript">
4589 * This is code is also distributed under MIT license for use
4590 * with jQuery and prototype JavaScript libraries.
4593 * @class Roo.DomQuery
4594 Provides high performance selector/xpath processing by compiling queries into reusable functions. New pseudo classes and matchers can be plugged. It works on HTML and XML documents (if a content node is passed in).
4596 DomQuery supports most of the <a href="http://www.w3.org/TR/2005/WD-css3-selectors-20051215/">CSS3 selectors spec</a>, along with some custom selectors and basic XPath.</p>
4599 All selectors, attribute filters and pseudos below can be combined infinitely in any order. For example "div.foo:nth-child(odd)[@foo=bar].bar:first" would be a perfectly valid selector. Node filters are processed in the order in which they appear, which allows you to optimize your queries for your document structure.
4601 <h4>Element Selectors:</h4>
4603 <li> <b>*</b> any element</li>
4604 <li> <b>E</b> an element with the tag E</li>
4605 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4606 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4607 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4608 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4610 <h4>Attribute Selectors:</h4>
4611 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4613 <li> <b>E[foo]</b> has an attribute "foo"</li>
4614 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4615 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4616 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4617 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4618 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4619 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4621 <h4>Pseudo Classes:</h4>
4623 <li> <b>E:first-child</b> E is the first child of its parent</li>
4624 <li> <b>E:last-child</b> E is the last child of its parent</li>
4625 <li> <b>E:nth-child(<i>n</i>)</b> E is the <i>n</i>th child of its parent (1 based as per the spec)</li>
4626 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4627 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4628 <li> <b>E:only-child</b> E is the only child of its parent</li>
4629 <li> <b>E:checked</b> E is an element that is has a checked attribute that is true (e.g. a radio or checkbox) </li>
4630 <li> <b>E:first</b> the first E in the resultset</li>
4631 <li> <b>E:last</b> the last E in the resultset</li>
4632 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4633 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4634 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4635 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4636 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4637 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4638 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4639 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4640 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4642 <h4>CSS Value Selectors:</h4>
4644 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4645 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4646 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4647 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4648 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4649 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4653 Roo.DomQuery = function(){
4654 var cache = {}, simpleCache = {}, valueCache = {};
4655 var nonSpace = /\S/;
4656 var trimRe = /^\s+|\s+$/g;
4657 var tplRe = /\{(\d+)\}/g;
4658 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4659 var tagTokenRe = /^(#)?([\w-\*]+)/;
4660 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4662 function child(p, index){
4664 var n = p.firstChild;
4666 if(n.nodeType == 1){
4677 while((n = n.nextSibling) && n.nodeType != 1);
4682 while((n = n.previousSibling) && n.nodeType != 1);
4686 function children(d){
4687 var n = d.firstChild, ni = -1;
4689 var nx = n.nextSibling;
4690 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4700 function byClassName(c, a, v){
4704 var r = [], ri = -1, cn;
4705 for(var i = 0, ci; ci = c[i]; i++){
4706 if((' '+ci.className+' ').indexOf(v) != -1){
4713 function attrValue(n, attr){
4714 if(!n.tagName && typeof n.length != "undefined"){
4723 if(attr == "class" || attr == "className"){
4726 return n.getAttribute(attr) || n[attr];
4730 function getNodes(ns, mode, tagName){
4731 var result = [], ri = -1, cs;
4735 tagName = tagName || "*";
4736 if(typeof ns.getElementsByTagName != "undefined"){
4740 for(var i = 0, ni; ni = ns[i]; i++){
4741 cs = ni.getElementsByTagName(tagName);
4742 for(var j = 0, ci; ci = cs[j]; j++){
4746 }else if(mode == "/" || mode == ">"){
4747 var utag = tagName.toUpperCase();
4748 for(var i = 0, ni, cn; ni = ns[i]; i++){
4749 cn = ni.children || ni.childNodes;
4750 for(var j = 0, cj; cj = cn[j]; j++){
4751 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
4756 }else if(mode == "+"){
4757 var utag = tagName.toUpperCase();
4758 for(var i = 0, n; n = ns[i]; i++){
4759 while((n = n.nextSibling) && n.nodeType != 1);
4760 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
4764 }else if(mode == "~"){
4765 for(var i = 0, n; n = ns[i]; i++){
4766 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
4775 function concat(a, b){
4779 for(var i = 0, l = b.length; i < l; i++){
4785 function byTag(cs, tagName){
4786 if(cs.tagName || cs == document){
4792 var r = [], ri = -1;
4793 tagName = tagName.toLowerCase();
4794 for(var i = 0, ci; ci = cs[i]; i++){
4795 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
4802 function byId(cs, attr, id){
4803 if(cs.tagName || cs == document){
4809 var r = [], ri = -1;
4810 for(var i = 0,ci; ci = cs[i]; i++){
4811 if(ci && ci.id == id){
4819 function byAttribute(cs, attr, value, op, custom){
4820 var r = [], ri = -1, st = custom=="{";
4821 var f = Roo.DomQuery.operators[op];
4822 for(var i = 0, ci; ci = cs[i]; i++){
4825 a = Roo.DomQuery.getStyle(ci, attr);
4827 else if(attr == "class" || attr == "className"){
4829 }else if(attr == "for"){
4831 }else if(attr == "href"){
4832 a = ci.getAttribute("href", 2);
4834 a = ci.getAttribute(attr);
4836 if((f && f(a, value)) || (!f && a)){
4843 function byPseudo(cs, name, value){
4844 return Roo.DomQuery.pseudos[name](cs, value);
4847 // This is for IE MSXML which does not support expandos.
4848 // IE runs the same speed using setAttribute, however FF slows way down
4849 // and Safari completely fails so they need to continue to use expandos.
4850 var isIE = window.ActiveXObject ? true : false;
4852 // this eval is stop the compressor from
4853 // renaming the variable to something shorter
4855 /** eval:var:batch */
4860 function nodupIEXml(cs){
4862 cs[0].setAttribute("_nodup", d);
4864 for(var i = 1, len = cs.length; i < len; i++){
4866 if(!c.getAttribute("_nodup") != d){
4867 c.setAttribute("_nodup", d);
4871 for(var i = 0, len = cs.length; i < len; i++){
4872 cs[i].removeAttribute("_nodup");
4881 var len = cs.length, c, i, r = cs, cj, ri = -1;
4882 if(!len || typeof cs.nodeType != "undefined" || len == 1){
4885 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
4886 return nodupIEXml(cs);
4890 for(i = 1; c = cs[i]; i++){
4895 for(var j = 0; j < i; j++){
4898 for(j = i+1; cj = cs[j]; j++){
4910 function quickDiffIEXml(c1, c2){
4912 for(var i = 0, len = c1.length; i < len; i++){
4913 c1[i].setAttribute("_qdiff", d);
4916 for(var i = 0, len = c2.length; i < len; i++){
4917 if(c2[i].getAttribute("_qdiff") != d){
4918 r[r.length] = c2[i];
4921 for(var i = 0, len = c1.length; i < len; i++){
4922 c1[i].removeAttribute("_qdiff");
4927 function quickDiff(c1, c2){
4928 var len1 = c1.length;
4932 if(isIE && c1[0].selectSingleNode){
4933 return quickDiffIEXml(c1, c2);
4936 for(var i = 0; i < len1; i++){
4940 for(var i = 0, len = c2.length; i < len; i++){
4941 if(c2[i]._qdiff != d){
4942 r[r.length] = c2[i];
4948 function quickId(ns, mode, root, id){
4950 var d = root.ownerDocument || root;
4951 return d.getElementById(id);
4953 ns = getNodes(ns, mode, "*");
4954 return byId(ns, null, id);
4958 getStyle : function(el, name){
4959 return Roo.fly(el).getStyle(name);
4962 * Compiles a selector/xpath query into a reusable function. The returned function
4963 * takes one parameter "root" (optional), which is the context node from where the query should start.
4964 * @param {String} selector The selector/xpath query
4965 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
4966 * @return {Function}
4968 compile : function(path, type){
4969 type = type || "select";
4971 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
4972 var q = path, mode, lq;
4973 var tk = Roo.DomQuery.matchers;
4974 var tklen = tk.length;
4977 // accept leading mode switch
4978 var lmode = q.match(modeRe);
4979 if(lmode && lmode[1]){
4980 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
4981 q = q.replace(lmode[1], "");
4983 // strip leading slashes
4984 while(path.substr(0, 1)=="/"){
4985 path = path.substr(1);
4988 while(q && lq != q){
4990 var tm = q.match(tagTokenRe);
4991 if(type == "select"){
4994 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
4996 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
4998 q = q.replace(tm[0], "");
4999 }else if(q.substr(0, 1) != '@'){
5000 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5005 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5007 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5009 q = q.replace(tm[0], "");
5012 while(!(mm = q.match(modeRe))){
5013 var matched = false;
5014 for(var j = 0; j < tklen; j++){
5016 var m = q.match(t.re);
5018 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5021 q = q.replace(m[0], "");
5026 // prevent infinite loop on bad selector
5028 throw 'Error parsing selector, parsing failed at "' + q + '"';
5032 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5033 q = q.replace(mm[1], "");
5036 fn[fn.length] = "return nodup(n);\n}";
5039 * list of variables that need from compression as they are used by eval.
5049 * eval:var:byClassName
5051 * eval:var:byAttribute
5052 * eval:var:attrValue
5060 * Selects a group of elements.
5061 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5062 * @param {Node} root (optional) The start of the query (defaults to document).
5065 select : function(path, root, type){
5066 if(!root || root == document){
5069 if(typeof root == "string"){
5070 root = document.getElementById(root);
5072 var paths = path.split(",");
5074 for(var i = 0, len = paths.length; i < len; i++){
5075 var p = paths[i].replace(trimRe, "");
5077 cache[p] = Roo.DomQuery.compile(p);
5079 throw p + " is not a valid selector";
5082 var result = cache[p](root);
5083 if(result && result != document){
5084 results = results.concat(result);
5087 if(paths.length > 1){
5088 return nodup(results);
5094 * Selects a single element.
5095 * @param {String} selector The selector/xpath query
5096 * @param {Node} root (optional) The start of the query (defaults to document).
5099 selectNode : function(path, root){
5100 return Roo.DomQuery.select(path, root)[0];
5104 * Selects the value of a node, optionally replacing null with the defaultValue.
5105 * @param {String} selector The selector/xpath query
5106 * @param {Node} root (optional) The start of the query (defaults to document).
5107 * @param {String} defaultValue
5109 selectValue : function(path, root, defaultValue){
5110 path = path.replace(trimRe, "");
5111 if(!valueCache[path]){
5112 valueCache[path] = Roo.DomQuery.compile(path, "select");
5114 var n = valueCache[path](root);
5115 n = n[0] ? n[0] : n;
5116 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5117 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5121 * Selects the value of a node, parsing integers and floats.
5122 * @param {String} selector The selector/xpath query
5123 * @param {Node} root (optional) The start of the query (defaults to document).
5124 * @param {Number} defaultValue
5127 selectNumber : function(path, root, defaultValue){
5128 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5129 return parseFloat(v);
5133 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5134 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5135 * @param {String} selector The simple selector to test
5138 is : function(el, ss){
5139 if(typeof el == "string"){
5140 el = document.getElementById(el);
5142 var isArray = (el instanceof Array);
5143 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5144 return isArray ? (result.length == el.length) : (result.length > 0);
5148 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5149 * @param {Array} el An array of elements to filter
5150 * @param {String} selector The simple selector to test
5151 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5152 * the selector instead of the ones that match
5155 filter : function(els, ss, nonMatches){
5156 ss = ss.replace(trimRe, "");
5157 if(!simpleCache[ss]){
5158 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5160 var result = simpleCache[ss](els);
5161 return nonMatches ? quickDiff(result, els) : result;
5165 * Collection of matching regular expressions and code snippets.
5169 select: 'n = byClassName(n, null, " {1} ");'
5171 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5172 select: 'n = byPseudo(n, "{1}", "{2}");'
5174 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5175 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5178 select: 'n = byId(n, null, "{1}");'
5181 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5186 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5187 * New operators can be added as long as the match the format <i>c</i>= where <i>c</i> is any character other than space, > <.
5190 "=" : function(a, v){
5193 "!=" : function(a, v){
5196 "^=" : function(a, v){
5197 return a && a.substr(0, v.length) == v;
5199 "$=" : function(a, v){
5200 return a && a.substr(a.length-v.length) == v;
5202 "*=" : function(a, v){
5203 return a && a.indexOf(v) !== -1;
5205 "%=" : function(a, v){
5206 return (a % v) == 0;
5208 "|=" : function(a, v){
5209 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5211 "~=" : function(a, v){
5212 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5217 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5218 * and the argument (if any) supplied in the selector.
5221 "first-child" : function(c){
5222 var r = [], ri = -1, n;
5223 for(var i = 0, ci; ci = n = c[i]; i++){
5224 while((n = n.previousSibling) && n.nodeType != 1);
5232 "last-child" : function(c){
5233 var r = [], ri = -1, n;
5234 for(var i = 0, ci; ci = n = c[i]; i++){
5235 while((n = n.nextSibling) && n.nodeType != 1);
5243 "nth-child" : function(c, a) {
5244 var r = [], ri = -1;
5245 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5246 var f = (m[1] || 1) - 0, l = m[2] - 0;
5247 for(var i = 0, n; n = c[i]; i++){
5248 var pn = n.parentNode;
5249 if (batch != pn._batch) {
5251 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5252 if(cn.nodeType == 1){
5259 if (l == 0 || n.nodeIndex == l){
5262 } else if ((n.nodeIndex + l) % f == 0){
5270 "only-child" : function(c){
5271 var r = [], ri = -1;;
5272 for(var i = 0, ci; ci = c[i]; i++){
5273 if(!prev(ci) && !next(ci)){
5280 "empty" : function(c){
5281 var r = [], ri = -1;
5282 for(var i = 0, ci; ci = c[i]; i++){
5283 var cns = ci.childNodes, j = 0, cn, empty = true;
5286 if(cn.nodeType == 1 || cn.nodeType == 3){
5298 "contains" : function(c, v){
5299 var r = [], ri = -1;
5300 for(var i = 0, ci; ci = c[i]; i++){
5301 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5308 "nodeValue" : function(c, v){
5309 var r = [], ri = -1;
5310 for(var i = 0, ci; ci = c[i]; i++){
5311 if(ci.firstChild && ci.firstChild.nodeValue == v){
5318 "checked" : function(c){
5319 var r = [], ri = -1;
5320 for(var i = 0, ci; ci = c[i]; i++){
5321 if(ci.checked == true){
5328 "not" : function(c, ss){
5329 return Roo.DomQuery.filter(c, ss, true);
5332 "odd" : function(c){
5333 return this["nth-child"](c, "odd");
5336 "even" : function(c){
5337 return this["nth-child"](c, "even");
5340 "nth" : function(c, a){
5341 return c[a-1] || [];
5344 "first" : function(c){
5348 "last" : function(c){
5349 return c[c.length-1] || [];
5352 "has" : function(c, ss){
5353 var s = Roo.DomQuery.select;
5354 var r = [], ri = -1;
5355 for(var i = 0, ci; ci = c[i]; i++){
5356 if(s(ss, ci).length > 0){
5363 "next" : function(c, ss){
5364 var is = Roo.DomQuery.is;
5365 var r = [], ri = -1;
5366 for(var i = 0, ci; ci = c[i]; i++){
5375 "prev" : function(c, ss){
5376 var is = Roo.DomQuery.is;
5377 var r = [], ri = -1;
5378 for(var i = 0, ci; ci = c[i]; i++){
5391 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5392 * @param {String} path The selector/xpath query
5393 * @param {Node} root (optional) The start of the query (defaults to document).
5398 Roo.query = Roo.DomQuery.select;
5401 * Ext JS Library 1.1.1
5402 * Copyright(c) 2006-2007, Ext JS, LLC.
5404 * Originally Released Under LGPL - original licence link has changed is not relivant.
5407 * <script type="text/javascript">
5411 * @class Roo.util.Observable
5412 * Base class that provides a common interface for publishing events. Subclasses are expected to
5413 * to have a property "events" with all the events defined.<br>
5416 Employee = function(name){
5423 Roo.extend(Employee, Roo.util.Observable);
5425 * @param {Object} config properties to use (incuding events / listeners)
5428 Roo.util.Observable = function(cfg){
5431 this.addEvents(cfg.events || {});
5433 delete cfg.events; // make sure
5436 Roo.apply(this, cfg);
5439 this.on(this.listeners);
5440 delete this.listeners;
5443 Roo.util.Observable.prototype = {
5445 * @cfg {Object} listeners list of events and functions to call for this object,
5449 'click' : function(e) {
5459 * Fires the specified event with the passed parameters (minus the event name).
5460 * @param {String} eventName
5461 * @param {Object...} args Variable number of parameters are passed to handlers
5462 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5464 fireEvent : function(){
5465 var ce = this.events[arguments[0].toLowerCase()];
5466 if(typeof ce == "object"){
5467 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5474 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5477 * Appends an event handler to this component
5478 * @param {String} eventName The type of event to listen for
5479 * @param {Function} handler The method the event invokes
5480 * @param {Object} scope (optional) The scope in which to execute the handler
5481 * function. The handler function's "this" context.
5482 * @param {Object} options (optional) An object containing handler configuration
5483 * properties. This may contain any of the following properties:<ul>
5484 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5485 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5486 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5487 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5488 * by the specified number of milliseconds. If the event fires again within that time, the original
5489 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5492 * <b>Combining Options</b><br>
5493 * Using the options argument, it is possible to combine different types of listeners:<br>
5495 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5497 el.on('click', this.onClick, this, {
5504 * <b>Attaching multiple handlers in 1 call</b><br>
5505 * The method also allows for a single argument to be passed which is a config object containing properties
5506 * which specify multiple handlers.
5515 fn: this.onMouseOver,
5519 fn: this.onMouseOut,
5525 * Or a shorthand syntax which passes the same scope object to all handlers:
5528 'click': this.onClick,
5529 'mouseover': this.onMouseOver,
5530 'mouseout': this.onMouseOut,
5535 addListener : function(eventName, fn, scope, o){
5536 if(typeof eventName == "object"){
5539 if(this.filterOptRe.test(e)){
5542 if(typeof o[e] == "function"){
5544 this.addListener(e, o[e], o.scope, o);
5546 // individual options
5547 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5552 o = (!o || typeof o == "boolean") ? {} : o;
5553 eventName = eventName.toLowerCase();
5554 var ce = this.events[eventName] || true;
5555 if(typeof ce == "boolean"){
5556 ce = new Roo.util.Event(this, eventName);
5557 this.events[eventName] = ce;
5559 ce.addListener(fn, scope, o);
5563 * Removes a listener
5564 * @param {String} eventName The type of event to listen for
5565 * @param {Function} handler The handler to remove
5566 * @param {Object} scope (optional) The scope (this object) for the handler
5568 removeListener : function(eventName, fn, scope){
5569 var ce = this.events[eventName.toLowerCase()];
5570 if(typeof ce == "object"){
5571 ce.removeListener(fn, scope);
5576 * Removes all listeners for this object
5578 purgeListeners : function(){
5579 for(var evt in this.events){
5580 if(typeof this.events[evt] == "object"){
5581 this.events[evt].clearListeners();
5586 relayEvents : function(o, events){
5587 var createHandler = function(ename){
5589 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5592 for(var i = 0, len = events.length; i < len; i++){
5593 var ename = events[i];
5594 if(!this.events[ename]){ this.events[ename] = true; };
5595 o.on(ename, createHandler(ename), this);
5600 * Used to define events on this Observable
5601 * @param {Object} object The object with the events defined
5603 addEvents : function(o){
5607 Roo.applyIf(this.events, o);
5611 * Checks to see if this object has any listeners for a specified event
5612 * @param {String} eventName The name of the event to check for
5613 * @return {Boolean} True if the event is being listened for, else false
5615 hasListener : function(eventName){
5616 var e = this.events[eventName];
5617 return typeof e == "object" && e.listeners.length > 0;
5621 * Appends an event handler to this element (shorthand for addListener)
5622 * @param {String} eventName The type of event to listen for
5623 * @param {Function} handler The method the event invokes
5624 * @param {Object} scope (optional) The scope in which to execute the handler
5625 * function. The handler function's "this" context.
5626 * @param {Object} options (optional)
5629 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5631 * Removes a listener (shorthand for removeListener)
5632 * @param {String} eventName The type of event to listen for
5633 * @param {Function} handler The handler to remove
5634 * @param {Object} scope (optional) The scope (this object) for the handler
5637 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5640 * Starts capture on the specified Observable. All events will be passed
5641 * to the supplied function with the event name + standard signature of the event
5642 * <b>before</b> the event is fired. If the supplied function returns false,
5643 * the event will not fire.
5644 * @param {Observable} o The Observable to capture
5645 * @param {Function} fn The function to call
5646 * @param {Object} scope (optional) The scope (this object) for the fn
5649 Roo.util.Observable.capture = function(o, fn, scope){
5650 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5654 * Removes <b>all</b> added captures from the Observable.
5655 * @param {Observable} o The Observable to release
5658 Roo.util.Observable.releaseCapture = function(o){
5659 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5664 var createBuffered = function(h, o, scope){
5665 var task = new Roo.util.DelayedTask();
5667 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5671 var createSingle = function(h, e, fn, scope){
5673 e.removeListener(fn, scope);
5674 return h.apply(scope, arguments);
5678 var createDelayed = function(h, o, scope){
5680 var args = Array.prototype.slice.call(arguments, 0);
5681 setTimeout(function(){
5682 h.apply(scope, args);
5687 Roo.util.Event = function(obj, name){
5690 this.listeners = [];
5693 Roo.util.Event.prototype = {
5694 addListener : function(fn, scope, options){
5695 var o = options || {};
5696 scope = scope || this.obj;
5697 if(!this.isListening(fn, scope)){
5698 var l = {fn: fn, scope: scope, options: o};
5701 h = createDelayed(h, o, scope);
5704 h = createSingle(h, this, fn, scope);
5707 h = createBuffered(h, o, scope);
5710 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5711 this.listeners.push(l);
5713 this.listeners = this.listeners.slice(0);
5714 this.listeners.push(l);
5719 findListener : function(fn, scope){
5720 scope = scope || this.obj;
5721 var ls = this.listeners;
5722 for(var i = 0, len = ls.length; i < len; i++){
5724 if(l.fn == fn && l.scope == scope){
5731 isListening : function(fn, scope){
5732 return this.findListener(fn, scope) != -1;
5735 removeListener : function(fn, scope){
5737 if((index = this.findListener(fn, scope)) != -1){
5739 this.listeners.splice(index, 1);
5741 this.listeners = this.listeners.slice(0);
5742 this.listeners.splice(index, 1);
5749 clearListeners : function(){
5750 this.listeners = [];
5754 var ls = this.listeners, scope, len = ls.length;
5757 var args = Array.prototype.slice.call(arguments, 0);
5758 for(var i = 0; i < len; i++){
5760 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
5761 this.firing = false;
5765 this.firing = false;
5772 * Ext JS Library 1.1.1
5773 * Copyright(c) 2006-2007, Ext JS, LLC.
5775 * Originally Released Under LGPL - original licence link has changed is not relivant.
5778 * <script type="text/javascript">
5782 * @class Roo.EventManager
5783 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
5784 * several useful events directly.
5785 * See {@link Roo.EventObject} for more details on normalized event objects.
5788 Roo.EventManager = function(){
5789 var docReadyEvent, docReadyProcId, docReadyState = false;
5790 var resizeEvent, resizeTask, textEvent, textSize;
5791 var E = Roo.lib.Event;
5792 var D = Roo.lib.Dom;
5795 var fireDocReady = function(){
5797 docReadyState = true;
5800 clearInterval(docReadyProcId);
5802 if(Roo.isGecko || Roo.isOpera) {
5803 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
5806 var defer = document.getElementById("ie-deferred-loader");
5808 defer.onreadystatechange = null;
5809 defer.parentNode.removeChild(defer);
5813 docReadyEvent.fire();
5814 docReadyEvent.clearListeners();
5819 var initDocReady = function(){
5820 docReadyEvent = new Roo.util.Event();
5821 if(Roo.isGecko || Roo.isOpera) {
5822 document.addEventListener("DOMContentLoaded", fireDocReady, false);
5824 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
5825 var defer = document.getElementById("ie-deferred-loader");
5826 defer.onreadystatechange = function(){
5827 if(this.readyState == "complete"){
5831 }else if(Roo.isSafari){
5832 docReadyProcId = setInterval(function(){
5833 var rs = document.readyState;
5834 if(rs == "complete") {
5839 // no matter what, make sure it fires on load
5840 E.on(window, "load", fireDocReady);
5843 var createBuffered = function(h, o){
5844 var task = new Roo.util.DelayedTask(h);
5846 // create new event object impl so new events don't wipe out properties
5847 e = new Roo.EventObjectImpl(e);
5848 task.delay(o.buffer, h, null, [e]);
5852 var createSingle = function(h, el, ename, fn){
5854 Roo.EventManager.removeListener(el, ename, fn);
5859 var createDelayed = function(h, o){
5861 // create new event object impl so new events don't wipe out properties
5862 e = new Roo.EventObjectImpl(e);
5863 setTimeout(function(){
5869 var listen = function(element, ename, opt, fn, scope){
5870 var o = (!opt || typeof opt == "boolean") ? {} : opt;
5871 fn = fn || o.fn; scope = scope || o.scope;
5872 var el = Roo.getDom(element);
5874 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
5876 var h = function(e){
5877 e = Roo.EventObject.setEvent(e);
5880 t = e.getTarget(o.delegate, el);
5887 if(o.stopEvent === true){
5890 if(o.preventDefault === true){
5893 if(o.stopPropagation === true){
5894 e.stopPropagation();
5897 if(o.normalized === false){
5901 fn.call(scope || el, e, t, o);
5904 h = createDelayed(h, o);
5907 h = createSingle(h, el, ename, fn);
5910 h = createBuffered(h, o);
5912 fn._handlers = fn._handlers || [];
5913 fn._handlers.push([Roo.id(el), ename, h]);
5916 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
5917 el.addEventListener("DOMMouseScroll", h, false);
5918 E.on(window, 'unload', function(){
5919 el.removeEventListener("DOMMouseScroll", h, false);
5922 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
5923 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
5928 var stopListening = function(el, ename, fn){
5929 var id = Roo.id(el), hds = fn._handlers, hd = fn;
5931 for(var i = 0, len = hds.length; i < len; i++){
5933 if(h[0] == id && h[1] == ename){
5940 E.un(el, ename, hd);
5941 el = Roo.getDom(el);
5942 if(ename == "mousewheel" && el.addEventListener){
5943 el.removeEventListener("DOMMouseScroll", hd, false);
5945 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
5946 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
5950 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
5957 * @scope Roo.EventManager
5962 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
5963 * object with a Roo.EventObject
5964 * @param {Function} fn The method the event invokes
5965 * @param {Object} scope An object that becomes the scope of the handler
5966 * @param {boolean} override If true, the obj passed in becomes
5967 * the execution scope of the listener
5968 * @return {Function} The wrapped function
5971 wrap : function(fn, scope, override){
5973 Roo.EventObject.setEvent(e);
5974 fn.call(override ? scope || window : window, Roo.EventObject, scope);
5979 * Appends an event handler to an element (shorthand for addListener)
5980 * @param {String/HTMLElement} element The html element or id to assign the
5981 * @param {String} eventName The type of event to listen for
5982 * @param {Function} handler The method the event invokes
5983 * @param {Object} scope (optional) The scope in which to execute the handler
5984 * function. The handler function's "this" context.
5985 * @param {Object} options (optional) An object containing handler configuration
5986 * properties. This may contain any of the following properties:<ul>
5987 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5988 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
5989 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
5990 * <li>preventDefault {Boolean} True to prevent the default action</li>
5991 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
5992 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
5993 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5994 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5995 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5996 * by the specified number of milliseconds. If the event fires again within that time, the original
5997 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6000 * <b>Combining Options</b><br>
6001 * Using the options argument, it is possible to combine different types of listeners:<br>
6003 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6005 el.on('click', this.onClick, this, {
6012 * <b>Attaching multiple handlers in 1 call</b><br>
6013 * The method also allows for a single argument to be passed which is a config object containing properties
6014 * which specify multiple handlers.
6024 fn: this.onMouseOver
6033 * Or a shorthand syntax:<br>
6036 'click' : this.onClick,
6037 'mouseover' : this.onMouseOver,
6038 'mouseout' : this.onMouseOut
6042 addListener : function(element, eventName, fn, scope, options){
6043 if(typeof eventName == "object"){
6049 if(typeof o[e] == "function"){
6051 listen(element, e, o, o[e], o.scope);
6053 // individual options
6054 listen(element, e, o[e]);
6059 return listen(element, eventName, options, fn, scope);
6063 * Removes an event handler
6065 * @param {String/HTMLElement} element The id or html element to remove the
6067 * @param {String} eventName The type of event
6068 * @param {Function} fn
6069 * @return {Boolean} True if a listener was actually removed
6071 removeListener : function(element, eventName, fn){
6072 return stopListening(element, eventName, fn);
6076 * Fires when the document is ready (before onload and before images are loaded). Can be
6077 * accessed shorthanded Roo.onReady().
6078 * @param {Function} fn The method the event invokes
6079 * @param {Object} scope An object that becomes the scope of the handler
6080 * @param {boolean} options
6082 onDocumentReady : function(fn, scope, options){
6083 if(docReadyState){ // if it already fired
6084 docReadyEvent.addListener(fn, scope, options);
6085 docReadyEvent.fire();
6086 docReadyEvent.clearListeners();
6092 docReadyEvent.addListener(fn, scope, options);
6096 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6097 * @param {Function} fn The method the event invokes
6098 * @param {Object} scope An object that becomes the scope of the handler
6099 * @param {boolean} options
6101 onWindowResize : function(fn, scope, options){
6103 resizeEvent = new Roo.util.Event();
6104 resizeTask = new Roo.util.DelayedTask(function(){
6105 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6107 E.on(window, "resize", function(){
6109 resizeTask.delay(50);
6111 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6115 resizeEvent.addListener(fn, scope, options);
6119 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6120 * @param {Function} fn The method the event invokes
6121 * @param {Object} scope An object that becomes the scope of the handler
6122 * @param {boolean} options
6124 onTextResize : function(fn, scope, options){
6126 textEvent = new Roo.util.Event();
6127 var textEl = new Roo.Element(document.createElement('div'));
6128 textEl.dom.className = 'x-text-resize';
6129 textEl.dom.innerHTML = 'X';
6130 textEl.appendTo(document.body);
6131 textSize = textEl.dom.offsetHeight;
6132 setInterval(function(){
6133 if(textEl.dom.offsetHeight != textSize){
6134 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6136 }, this.textResizeInterval);
6138 textEvent.addListener(fn, scope, options);
6142 * Removes the passed window resize listener.
6143 * @param {Function} fn The method the event invokes
6144 * @param {Object} scope The scope of handler
6146 removeResizeListener : function(fn, scope){
6148 resizeEvent.removeListener(fn, scope);
6153 fireResize : function(){
6155 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6159 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6163 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6165 textResizeInterval : 50
6170 * @scopeAlias pub=Roo.EventManager
6174 * Appends an event handler to an element (shorthand for addListener)
6175 * @param {String/HTMLElement} element The html element or id to assign the
6176 * @param {String} eventName The type of event to listen for
6177 * @param {Function} handler The method the event invokes
6178 * @param {Object} scope (optional) The scope in which to execute the handler
6179 * function. The handler function's "this" context.
6180 * @param {Object} options (optional) An object containing handler configuration
6181 * properties. This may contain any of the following properties:<ul>
6182 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6183 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6184 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6185 * <li>preventDefault {Boolean} True to prevent the default action</li>
6186 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6187 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6188 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6189 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6190 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6191 * by the specified number of milliseconds. If the event fires again within that time, the original
6192 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6195 * <b>Combining Options</b><br>
6196 * Using the options argument, it is possible to combine different types of listeners:<br>
6198 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6200 el.on('click', this.onClick, this, {
6207 * <b>Attaching multiple handlers in 1 call</b><br>
6208 * The method also allows for a single argument to be passed which is a config object containing properties
6209 * which specify multiple handlers.
6219 fn: this.onMouseOver
6228 * Or a shorthand syntax:<br>
6231 'click' : this.onClick,
6232 'mouseover' : this.onMouseOver,
6233 'mouseout' : this.onMouseOut
6237 pub.on = pub.addListener;
6238 pub.un = pub.removeListener;
6240 pub.stoppedMouseDownEvent = new Roo.util.Event();
6244 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6245 * @param {Function} fn The method the event invokes
6246 * @param {Object} scope An object that becomes the scope of the handler
6247 * @param {boolean} override If true, the obj passed in becomes
6248 * the execution scope of the listener
6252 Roo.onReady = Roo.EventManager.onDocumentReady;
6254 Roo.onReady(function(){
6255 var bd = Roo.get(document.body);
6260 : Roo.isGecko ? "roo-gecko"
6261 : Roo.isOpera ? "roo-opera"
6262 : Roo.isSafari ? "roo-safari" : ""];
6265 cls.push("roo-mac");
6268 cls.push("roo-linux");
6270 if(Roo.isBorderBox){
6271 cls.push('roo-border-box');
6273 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6274 var p = bd.dom.parentNode;
6276 p.className += ' roo-strict';
6279 bd.addClass(cls.join(' '));
6283 * @class Roo.EventObject
6284 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6285 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6288 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6290 var target = e.getTarget();
6293 var myDiv = Roo.get("myDiv");
6294 myDiv.on("click", handleClick);
6296 Roo.EventManager.on("myDiv", 'click', handleClick);
6297 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6301 Roo.EventObject = function(){
6303 var E = Roo.lib.Event;
6305 // safari keypress events for special keys return bad keycodes
6308 63235 : 39, // right
6311 63276 : 33, // page up
6312 63277 : 34, // page down
6313 63272 : 46, // delete
6318 // normalize button clicks
6319 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6320 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6322 Roo.EventObjectImpl = function(e){
6324 this.setEvent(e.browserEvent || e);
6327 Roo.EventObjectImpl.prototype = {
6329 * Used to fix doc tools.
6330 * @scope Roo.EventObject.prototype
6336 /** The normal browser event */
6337 browserEvent : null,
6338 /** The button pressed in a mouse event */
6340 /** True if the shift key was down during the event */
6342 /** True if the control key was down during the event */
6344 /** True if the alt key was down during the event */
6403 setEvent : function(e){
6404 if(e == this || (e && e.browserEvent)){ // already wrapped
6407 this.browserEvent = e;
6409 // normalize buttons
6410 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6411 if(e.type == 'click' && this.button == -1){
6415 this.shiftKey = e.shiftKey;
6416 // mac metaKey behaves like ctrlKey
6417 this.ctrlKey = e.ctrlKey || e.metaKey;
6418 this.altKey = e.altKey;
6419 // in getKey these will be normalized for the mac
6420 this.keyCode = e.keyCode;
6421 // keyup warnings on firefox.
6422 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6423 // cache the target for the delayed and or buffered events
6424 this.target = E.getTarget(e);
6426 this.xy = E.getXY(e);
6429 this.shiftKey = false;
6430 this.ctrlKey = false;
6431 this.altKey = false;
6441 * Stop the event (preventDefault and stopPropagation)
6443 stopEvent : function(){
6444 if(this.browserEvent){
6445 if(this.browserEvent.type == 'mousedown'){
6446 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6448 E.stopEvent(this.browserEvent);
6453 * Prevents the browsers default handling of the event.
6455 preventDefault : function(){
6456 if(this.browserEvent){
6457 E.preventDefault(this.browserEvent);
6462 isNavKeyPress : function(){
6463 var k = this.keyCode;
6464 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6465 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6468 isSpecialKey : function(){
6469 var k = this.keyCode;
6470 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6471 (k == 16) || (k == 17) ||
6472 (k >= 18 && k <= 20) ||
6473 (k >= 33 && k <= 35) ||
6474 (k >= 36 && k <= 39) ||
6475 (k >= 44 && k <= 45);
6478 * Cancels bubbling of the event.
6480 stopPropagation : function(){
6481 if(this.browserEvent){
6482 if(this.type == 'mousedown'){
6483 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6485 E.stopPropagation(this.browserEvent);
6490 * Gets the key code for the event.
6493 getCharCode : function(){
6494 return this.charCode || this.keyCode;
6498 * Returns a normalized keyCode for the event.
6499 * @return {Number} The key code
6501 getKey : function(){
6502 var k = this.keyCode || this.charCode;
6503 return Roo.isSafari ? (safariKeys[k] || k) : k;
6507 * Gets the x coordinate of the event.
6510 getPageX : function(){
6515 * Gets the y coordinate of the event.
6518 getPageY : function(){
6523 * Gets the time of the event.
6526 getTime : function(){
6527 if(this.browserEvent){
6528 return E.getTime(this.browserEvent);
6534 * Gets the page coordinates of the event.
6535 * @return {Array} The xy values like [x, y]
6542 * Gets the target for the event.
6543 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6544 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6545 search as a number or element (defaults to 10 || document.body)
6546 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6547 * @return {HTMLelement}
6549 getTarget : function(selector, maxDepth, returnEl){
6550 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6553 * Gets the related target.
6554 * @return {HTMLElement}
6556 getRelatedTarget : function(){
6557 if(this.browserEvent){
6558 return E.getRelatedTarget(this.browserEvent);
6564 * Normalizes mouse wheel delta across browsers
6565 * @return {Number} The delta
6567 getWheelDelta : function(){
6568 var e = this.browserEvent;
6570 if(e.wheelDelta){ /* IE/Opera. */
6571 delta = e.wheelDelta/120;
6572 }else if(e.detail){ /* Mozilla case. */
6573 delta = -e.detail/3;
6579 * Returns true if the control, meta, shift or alt key was pressed during this event.
6582 hasModifier : function(){
6583 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6587 * Returns true if the target of this event equals el or is a child of el
6588 * @param {String/HTMLElement/Element} el
6589 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6592 within : function(el, related){
6593 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6594 return t && Roo.fly(el).contains(t);
6597 getPoint : function(){
6598 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6602 return new Roo.EventObjectImpl();
6607 * Ext JS Library 1.1.1
6608 * Copyright(c) 2006-2007, Ext JS, LLC.
6610 * Originally Released Under LGPL - original licence link has changed is not relivant.
6613 * <script type="text/javascript">
6617 // was in Composite Element!??!?!
6620 var D = Roo.lib.Dom;
6621 var E = Roo.lib.Event;
6622 var A = Roo.lib.Anim;
6624 // local style camelizing for speed
6626 var camelRe = /(-[a-z])/gi;
6627 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6628 var view = document.defaultView;
6631 * @class Roo.Element
6632 * Represents an Element in the DOM.<br><br>
6635 var el = Roo.get("my-div");
6638 var el = getEl("my-div");
6640 // or with a DOM element
6641 var el = Roo.get(myDivElement);
6643 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6644 * each call instead of constructing a new one.<br><br>
6645 * <b>Animations</b><br />
6646 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6647 * should either be a boolean (true) or an object literal with animation options. The animation options are:
6649 Option Default Description
6650 --------- -------- ---------------------------------------------
6651 duration .35 The duration of the animation in seconds
6652 easing easeOut The YUI easing method
6653 callback none A function to execute when the anim completes
6654 scope this The scope (this) of the callback function
6656 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6657 * manipulate the animation. Here's an example:
6659 var el = Roo.get("my-div");
6664 // default animation
6665 el.setWidth(100, true);
6667 // animation with some options set
6674 // using the "anim" property to get the Anim object
6680 el.setWidth(100, opt);
6682 if(opt.anim.isAnimated()){
6686 * <b> Composite (Collections of) Elements</b><br />
6687 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6688 * @constructor Create a new Element directly.
6689 * @param {String/HTMLElement} element
6690 * @param {Boolean} forceNew (optional) By default the constructor checks to see if there is already an instance of this element in the cache and if there is it returns the same instance. This will skip that check (useful for extending this class).
6692 Roo.Element = function(element, forceNew){
6693 var dom = typeof element == "string" ?
6694 document.getElementById(element) : element;
6695 if(!dom){ // invalid id/element
6699 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6700 return Roo.Element.cache[id];
6710 * The DOM element ID
6713 this.id = id || Roo.id(dom);
6716 var El = Roo.Element;
6720 * The element's default display mode (defaults to "")
6723 originalDisplay : "",
6727 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6732 * Sets the element's visibility mode. When setVisible() is called it
6733 * will use this to determine whether to set the visibility or the display property.
6734 * @param visMode Element.VISIBILITY or Element.DISPLAY
6735 * @return {Roo.Element} this
6737 setVisibilityMode : function(visMode){
6738 this.visibilityMode = visMode;
6742 * Convenience method for setVisibilityMode(Element.DISPLAY)
6743 * @param {String} display (optional) What to set display to when visible
6744 * @return {Roo.Element} this
6746 enableDisplayMode : function(display){
6747 this.setVisibilityMode(El.DISPLAY);
6748 if(typeof display != "undefined") this.originalDisplay = display;
6753 * Looks at this node and then at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
6754 * @param {String} selector The simple selector to test
6755 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6756 search as a number or element (defaults to 10 || document.body)
6757 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6758 * @return {HTMLElement} The matching DOM node (or null if no match was found)
6760 findParent : function(simpleSelector, maxDepth, returnEl){
6761 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
6762 maxDepth = maxDepth || 50;
6763 if(typeof maxDepth != "number"){
6764 stopEl = Roo.getDom(maxDepth);
6767 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
6768 if(dq.is(p, simpleSelector)){
6769 return returnEl ? Roo.get(p) : p;
6779 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
6780 * @param {String} selector The simple selector to test
6781 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6782 search as a number or element (defaults to 10 || document.body)
6783 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6784 * @return {HTMLElement} The matching DOM node (or null if no match was found)
6786 findParentNode : function(simpleSelector, maxDepth, returnEl){
6787 var p = Roo.fly(this.dom.parentNode, '_internal');
6788 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
6792 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
6793 * This is a shortcut for findParentNode() that always returns an Roo.Element.
6794 * @param {String} selector The simple selector to test
6795 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6796 search as a number or element (defaults to 10 || document.body)
6797 * @return {Roo.Element} The matching DOM node (or null if no match was found)
6799 up : function(simpleSelector, maxDepth){
6800 return this.findParentNode(simpleSelector, maxDepth, true);
6806 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
6807 * @param {String} selector The simple selector to test
6808 * @return {Boolean} True if this element matches the selector, else false
6810 is : function(simpleSelector){
6811 return Roo.DomQuery.is(this.dom, simpleSelector);
6815 * Perform animation on this element.
6816 * @param {Object} args The YUI animation control args
6817 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
6818 * @param {Function} onComplete (optional) Function to call when animation completes
6819 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
6820 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
6821 * @return {Roo.Element} this
6823 animate : function(args, duration, onComplete, easing, animType){
6824 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
6829 * @private Internal animation call
6831 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
6832 animType = animType || 'run';
6834 var anim = Roo.lib.Anim[animType](
6836 (opt.duration || defaultDur) || .35,
6837 (opt.easing || defaultEase) || 'easeOut',
6839 Roo.callback(cb, this);
6840 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
6848 // private legacy anim prep
6849 preanim : function(a, i){
6850 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
6854 * Removes worthless text nodes
6855 * @param {Boolean} forceReclean (optional) By default the element
6856 * keeps track if it has been cleaned already so
6857 * you can call this over and over. However, if you update the element and
6858 * need to force a reclean, you can pass true.
6860 clean : function(forceReclean){
6861 if(this.isCleaned && forceReclean !== true){
6865 var d = this.dom, n = d.firstChild, ni = -1;
6867 var nx = n.nextSibling;
6868 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
6875 this.isCleaned = true;
6880 calcOffsetsTo : function(el){
6883 var restorePos = false;
6884 if(el.getStyle('position') == 'static'){
6885 el.position('relative');
6890 while(op && op != d && op.tagName != 'HTML'){
6893 op = op.offsetParent;
6896 el.position('static');
6902 * Scrolls this element into view within the passed container.
6903 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
6904 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
6905 * @return {Roo.Element} this
6907 scrollIntoView : function(container, hscroll){
6908 var c = Roo.getDom(container) || document.body;
6911 var o = this.calcOffsetsTo(c),
6914 b = t+el.offsetHeight,
6915 r = l+el.offsetWidth;
6917 var ch = c.clientHeight;
6918 var ct = parseInt(c.scrollTop, 10);
6919 var cl = parseInt(c.scrollLeft, 10);
6921 var cr = cl + c.clientWidth;
6929 if(hscroll !== false){
6933 c.scrollLeft = r-c.clientWidth;
6940 scrollChildIntoView : function(child, hscroll){
6941 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
6945 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
6946 * the new height may not be available immediately.
6947 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
6948 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
6949 * @param {Function} onComplete (optional) Function to call when animation completes
6950 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
6951 * @return {Roo.Element} this
6953 autoHeight : function(animate, duration, onComplete, easing){
6954 var oldHeight = this.getHeight();
6956 this.setHeight(1); // force clipping
6957 setTimeout(function(){
6958 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
6960 this.setHeight(height);
6962 if(typeof onComplete == "function"){
6966 this.setHeight(oldHeight); // restore original height
6967 this.setHeight(height, animate, duration, function(){
6969 if(typeof onComplete == "function") onComplete();
6970 }.createDelegate(this), easing);
6972 }.createDelegate(this), 0);
6977 * Returns true if this element is an ancestor of the passed element
6978 * @param {HTMLElement/String} el The element to check
6979 * @return {Boolean} True if this element is an ancestor of el, else false
6981 contains : function(el){
6982 if(!el){return false;}
6983 return D.isAncestor(this.dom, el.dom ? el.dom : el);
6987 * Checks whether the element is currently visible using both visibility and display properties.
6988 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
6989 * @return {Boolean} True if the element is currently visible, else false
6991 isVisible : function(deep) {
6992 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
6993 if(deep !== true || !vis){
6996 var p = this.dom.parentNode;
6997 while(p && p.tagName.toLowerCase() != "body"){
6998 if(!Roo.fly(p, '_isVisible').isVisible()){
7007 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7008 * @param {String} selector The CSS selector
7009 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7010 * @return {CompositeElement/CompositeElementLite} The composite element
7012 select : function(selector, unique){
7013 return El.select(selector, unique, this.dom);
7017 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7018 * @param {String} selector The CSS selector
7019 * @return {Array} An array of the matched nodes
7021 query : function(selector, unique){
7022 return Roo.DomQuery.select(selector, this.dom);
7026 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7027 * @param {String} selector The CSS selector
7028 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7029 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7031 child : function(selector, returnDom){
7032 var n = Roo.DomQuery.selectNode(selector, this.dom);
7033 return returnDom ? n : Roo.get(n);
7037 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7038 * @param {String} selector The CSS selector
7039 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7040 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7042 down : function(selector, returnDom){
7043 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7044 return returnDom ? n : Roo.get(n);
7048 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7049 * @param {String} group The group the DD object is member of
7050 * @param {Object} config The DD config object
7051 * @param {Object} overrides An object containing methods to override/implement on the DD object
7052 * @return {Roo.dd.DD} The DD object
7054 initDD : function(group, config, overrides){
7055 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7056 return Roo.apply(dd, overrides);
7060 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7061 * @param {String} group The group the DDProxy object is member of
7062 * @param {Object} config The DDProxy config object
7063 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7064 * @return {Roo.dd.DDProxy} The DDProxy object
7066 initDDProxy : function(group, config, overrides){
7067 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7068 return Roo.apply(dd, overrides);
7072 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7073 * @param {String} group The group the DDTarget object is member of
7074 * @param {Object} config The DDTarget config object
7075 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7076 * @return {Roo.dd.DDTarget} The DDTarget object
7078 initDDTarget : function(group, config, overrides){
7079 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7080 return Roo.apply(dd, overrides);
7084 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7085 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7086 * @param {Boolean} visible Whether the element is visible
7087 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7088 * @return {Roo.Element} this
7090 setVisible : function(visible, animate){
7092 if(this.visibilityMode == El.DISPLAY){
7093 this.setDisplayed(visible);
7096 this.dom.style.visibility = visible ? "visible" : "hidden";
7099 // closure for composites
7101 var visMode = this.visibilityMode;
7103 this.setOpacity(.01);
7104 this.setVisible(true);
7106 this.anim({opacity: { to: (visible?1:0) }},
7107 this.preanim(arguments, 1),
7108 null, .35, 'easeIn', function(){
7110 if(visMode == El.DISPLAY){
7111 dom.style.display = "none";
7113 dom.style.visibility = "hidden";
7115 Roo.get(dom).setOpacity(1);
7123 * Returns true if display is not "none"
7126 isDisplayed : function() {
7127 return this.getStyle("display") != "none";
7131 * Toggles the element's visibility or display, depending on visibility mode.
7132 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7133 * @return {Roo.Element} this
7135 toggle : function(animate){
7136 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7141 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7142 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7143 * @return {Roo.Element} this
7145 setDisplayed : function(value) {
7146 if(typeof value == "boolean"){
7147 value = value ? this.originalDisplay : "none";
7149 this.setStyle("display", value);
7154 * Tries to focus the element. Any exceptions are caught and ignored.
7155 * @return {Roo.Element} this
7157 focus : function() {
7165 * Tries to blur the element. Any exceptions are caught and ignored.
7166 * @return {Roo.Element} this
7176 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7177 * @param {String/Array} className The CSS class to add, or an array of classes
7178 * @return {Roo.Element} this
7180 addClass : function(className){
7181 if(className instanceof Array){
7182 for(var i = 0, len = className.length; i < len; i++) {
7183 this.addClass(className[i]);
7186 if(className && !this.hasClass(className)){
7187 this.dom.className = this.dom.className + " " + className;
7194 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7195 * @param {String/Array} className The CSS class to add, or an array of classes
7196 * @return {Roo.Element} this
7198 radioClass : function(className){
7199 var siblings = this.dom.parentNode.childNodes;
7200 for(var i = 0; i < siblings.length; i++) {
7201 var s = siblings[i];
7202 if(s.nodeType == 1){
7203 Roo.get(s).removeClass(className);
7206 this.addClass(className);
7211 * Removes one or more CSS classes from the element.
7212 * @param {String/Array} className The CSS class to remove, or an array of classes
7213 * @return {Roo.Element} this
7215 removeClass : function(className){
7216 if(!className || !this.dom.className){
7219 if(className instanceof Array){
7220 for(var i = 0, len = className.length; i < len; i++) {
7221 this.removeClass(className[i]);
7224 if(this.hasClass(className)){
7225 var re = this.classReCache[className];
7227 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7228 this.classReCache[className] = re;
7230 this.dom.className =
7231 this.dom.className.replace(re, " ");
7241 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7242 * @param {String} className The CSS class to toggle
7243 * @return {Roo.Element} this
7245 toggleClass : function(className){
7246 if(this.hasClass(className)){
7247 this.removeClass(className);
7249 this.addClass(className);
7255 * Checks if the specified CSS class exists on this element's DOM node.
7256 * @param {String} className The CSS class to check for
7257 * @return {Boolean} True if the class exists, else false
7259 hasClass : function(className){
7260 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7264 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7265 * @param {String} oldClassName The CSS class to replace
7266 * @param {String} newClassName The replacement CSS class
7267 * @return {Roo.Element} this
7269 replaceClass : function(oldClassName, newClassName){
7270 this.removeClass(oldClassName);
7271 this.addClass(newClassName);
7276 * Returns an object with properties matching the styles requested.
7277 * For example, el.getStyles('color', 'font-size', 'width') might return
7278 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7279 * @param {String} style1 A style name
7280 * @param {String} style2 A style name
7281 * @param {String} etc.
7282 * @return {Object} The style object
7284 getStyles : function(){
7285 var a = arguments, len = a.length, r = {};
7286 for(var i = 0; i < len; i++){
7287 r[a[i]] = this.getStyle(a[i]);
7293 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7294 * @param {String} property The style property whose value is returned.
7295 * @return {String} The current value of the style property for this element.
7297 getStyle : function(){
7298 return view && view.getComputedStyle ?
7300 var el = this.dom, v, cs, camel;
7301 if(prop == 'float'){
7304 if(el.style && (v = el.style[prop])){
7307 if(cs = view.getComputedStyle(el, "")){
7308 if(!(camel = propCache[prop])){
7309 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7316 var el = this.dom, v, cs, camel;
7317 if(prop == 'opacity'){
7318 if(typeof el.style.filter == 'string'){
7319 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7321 var fv = parseFloat(m[1]);
7323 return fv ? fv / 100 : 0;
7328 }else if(prop == 'float'){
7329 prop = "styleFloat";
7331 if(!(camel = propCache[prop])){
7332 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7334 if(v = el.style[camel]){
7337 if(cs = el.currentStyle){
7345 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7346 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7347 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7348 * @return {Roo.Element} this
7350 setStyle : function(prop, value){
7351 if(typeof prop == "string"){
7353 if(!(camel = propCache[prop])){
7354 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7356 if(camel == 'opacity') {
7357 this.setOpacity(value);
7359 this.dom.style[camel] = value;
7362 for(var style in prop){
7363 if(typeof prop[style] != "function"){
7364 this.setStyle(style, prop[style]);
7372 * More flexible version of {@link #setStyle} for setting style properties.
7373 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7374 * a function which returns such a specification.
7375 * @return {Roo.Element} this
7377 applyStyles : function(style){
7378 Roo.DomHelper.applyStyles(this.dom, style);
7383 * Gets the current X position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7384 * @return {Number} The X position of the element
7387 return D.getX(this.dom);
7391 * Gets the current Y position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7392 * @return {Number} The Y position of the element
7395 return D.getY(this.dom);
7399 * Gets the current position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7400 * @return {Array} The XY position of the element
7403 return D.getXY(this.dom);
7407 * Sets the X position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7408 * @param {Number} The X position of the element
7409 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7410 * @return {Roo.Element} this
7412 setX : function(x, animate){
7414 D.setX(this.dom, x);
7416 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7422 * Sets the Y position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7423 * @param {Number} The Y position of the element
7424 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7425 * @return {Roo.Element} this
7427 setY : function(y, animate){
7429 D.setY(this.dom, y);
7431 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7437 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7438 * @param {String} left The left CSS property value
7439 * @return {Roo.Element} this
7441 setLeft : function(left){
7442 this.setStyle("left", this.addUnits(left));
7447 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7448 * @param {String} top The top CSS property value
7449 * @return {Roo.Element} this
7451 setTop : function(top){
7452 this.setStyle("top", this.addUnits(top));
7457 * Sets the element's CSS right style.
7458 * @param {String} right The right CSS property value
7459 * @return {Roo.Element} this
7461 setRight : function(right){
7462 this.setStyle("right", this.addUnits(right));
7467 * Sets the element's CSS bottom style.
7468 * @param {String} bottom The bottom CSS property value
7469 * @return {Roo.Element} this
7471 setBottom : function(bottom){
7472 this.setStyle("bottom", this.addUnits(bottom));
7477 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7478 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7479 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7480 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7481 * @return {Roo.Element} this
7483 setXY : function(pos, animate){
7485 D.setXY(this.dom, pos);
7487 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7493 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7494 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7495 * @param {Number} x X value for new position (coordinates are page-based)
7496 * @param {Number} y Y value for new position (coordinates are page-based)
7497 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7498 * @return {Roo.Element} this
7500 setLocation : function(x, y, animate){
7501 this.setXY([x, y], this.preanim(arguments, 2));
7506 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7507 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7508 * @param {Number} x X value for new position (coordinates are page-based)
7509 * @param {Number} y Y value for new position (coordinates are page-based)
7510 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7511 * @return {Roo.Element} this
7513 moveTo : function(x, y, animate){
7514 this.setXY([x, y], this.preanim(arguments, 2));
7519 * Returns the region of the given element.
7520 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7521 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7523 getRegion : function(){
7524 return D.getRegion(this.dom);
7528 * Returns the offset height of the element
7529 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7530 * @return {Number} The element's height
7532 getHeight : function(contentHeight){
7533 var h = this.dom.offsetHeight || 0;
7534 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7538 * Returns the offset width of the element
7539 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7540 * @return {Number} The element's width
7542 getWidth : function(contentWidth){
7543 var w = this.dom.offsetWidth || 0;
7544 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7548 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7549 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7550 * if a height has not been set using CSS.
7553 getComputedHeight : function(){
7554 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7556 h = parseInt(this.getStyle('height'), 10) || 0;
7557 if(!this.isBorderBox()){
7558 h += this.getFrameWidth('tb');
7565 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7566 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7567 * if a width has not been set using CSS.
7570 getComputedWidth : function(){
7571 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7573 w = parseInt(this.getStyle('width'), 10) || 0;
7574 if(!this.isBorderBox()){
7575 w += this.getFrameWidth('lr');
7582 * Returns the size of the element.
7583 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7584 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7586 getSize : function(contentSize){
7587 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7591 * Returns the width and height of the viewport.
7592 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7594 getViewSize : function(){
7595 var d = this.dom, doc = document, aw = 0, ah = 0;
7596 if(d == doc || d == doc.body){
7597 return {width : D.getViewWidth(), height: D.getViewHeight()};
7600 width : d.clientWidth,
7601 height: d.clientHeight
7607 * Returns the value of the "value" attribute
7608 * @param {Boolean} asNumber true to parse the value as a number
7609 * @return {String/Number}
7611 getValue : function(asNumber){
7612 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7616 adjustWidth : function(width){
7617 if(typeof width == "number"){
7618 if(this.autoBoxAdjust && !this.isBorderBox()){
7619 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7629 adjustHeight : function(height){
7630 if(typeof height == "number"){
7631 if(this.autoBoxAdjust && !this.isBorderBox()){
7632 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7642 * Set the width of the element
7643 * @param {Number} width The new width
7644 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7645 * @return {Roo.Element} this
7647 setWidth : function(width, animate){
7648 width = this.adjustWidth(width);
7650 this.dom.style.width = this.addUnits(width);
7652 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7658 * Set the height of the element
7659 * @param {Number} height The new height
7660 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7661 * @return {Roo.Element} this
7663 setHeight : function(height, animate){
7664 height = this.adjustHeight(height);
7666 this.dom.style.height = this.addUnits(height);
7668 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7674 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7675 * @param {Number} width The new width
7676 * @param {Number} height The new height
7677 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7678 * @return {Roo.Element} this
7680 setSize : function(width, height, animate){
7681 if(typeof width == "object"){ // in case of object from getSize()
7682 height = width.height; width = width.width;
7684 width = this.adjustWidth(width); height = this.adjustHeight(height);
7686 this.dom.style.width = this.addUnits(width);
7687 this.dom.style.height = this.addUnits(height);
7689 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7695 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7696 * @param {Number} x X value for new position (coordinates are page-based)
7697 * @param {Number} y Y value for new position (coordinates are page-based)
7698 * @param {Number} width The new width
7699 * @param {Number} height The new height
7700 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7701 * @return {Roo.Element} this
7703 setBounds : function(x, y, width, height, animate){
7705 this.setSize(width, height);
7706 this.setLocation(x, y);
7708 width = this.adjustWidth(width); height = this.adjustHeight(height);
7709 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7710 this.preanim(arguments, 4), 'motion');
7716 * Sets the element's position and size the the specified region. If animation is true then width, height, x and y will be animated concurrently.
7717 * @param {Roo.lib.Region} region The region to fill
7718 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7719 * @return {Roo.Element} this
7721 setRegion : function(region, animate){
7722 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7727 * Appends an event handler
7729 * @param {String} eventName The type of event to append
7730 * @param {Function} fn The method the event invokes
7731 * @param {Object} scope (optional) The scope (this object) of the fn
7732 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
7734 addListener : function(eventName, fn, scope, options){
7735 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
7739 * Removes an event handler from this element
7740 * @param {String} eventName the type of event to remove
7741 * @param {Function} fn the method the event invokes
7742 * @return {Roo.Element} this
7744 removeListener : function(eventName, fn){
7745 Roo.EventManager.removeListener(this.dom, eventName, fn);
7750 * Removes all previous added listeners from this element
7751 * @return {Roo.Element} this
7753 removeAllListeners : function(){
7754 E.purgeElement(this.dom);
7758 relayEvent : function(eventName, observable){
7759 this.on(eventName, function(e){
7760 observable.fireEvent(eventName, e);
7765 * Set the opacity of the element
7766 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
7767 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7768 * @return {Roo.Element} this
7770 setOpacity : function(opacity, animate){
7772 var s = this.dom.style;
7775 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
7776 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
7778 s.opacity = opacity;
7781 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
7787 * Gets the left X coordinate
7788 * @param {Boolean} local True to get the local css position instead of page coordinate
7791 getLeft : function(local){
7795 return parseInt(this.getStyle("left"), 10) || 0;
7800 * Gets the right X coordinate of the element (element X position + element width)
7801 * @param {Boolean} local True to get the local css position instead of page coordinate
7804 getRight : function(local){
7806 return this.getX() + this.getWidth();
7808 return (this.getLeft(true) + this.getWidth()) || 0;
7813 * Gets the top Y coordinate
7814 * @param {Boolean} local True to get the local css position instead of page coordinate
7817 getTop : function(local) {
7821 return parseInt(this.getStyle("top"), 10) || 0;
7826 * Gets the bottom Y coordinate of the element (element Y position + element height)
7827 * @param {Boolean} local True to get the local css position instead of page coordinate
7830 getBottom : function(local){
7832 return this.getY() + this.getHeight();
7834 return (this.getTop(true) + this.getHeight()) || 0;
7839 * Initializes positioning on this element. If a desired position is not passed, it will make the
7840 * the element positioned relative IF it is not already positioned.
7841 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
7842 * @param {Number} zIndex (optional) The zIndex to apply
7843 * @param {Number} x (optional) Set the page X position
7844 * @param {Number} y (optional) Set the page Y position
7846 position : function(pos, zIndex, x, y){
7848 if(this.getStyle('position') == 'static'){
7849 this.setStyle('position', 'relative');
7852 this.setStyle("position", pos);
7855 this.setStyle("z-index", zIndex);
7857 if(x !== undefined && y !== undefined){
7859 }else if(x !== undefined){
7861 }else if(y !== undefined){
7867 * Clear positioning back to the default when the document was loaded
7868 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
7869 * @return {Roo.Element} this
7871 clearPositioning : function(value){
7879 "position" : "static"
7885 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
7886 * snapshot before performing an update and then restoring the element.
7889 getPositioning : function(){
7890 var l = this.getStyle("left");
7891 var t = this.getStyle("top");
7893 "position" : this.getStyle("position"),
7895 "right" : l ? "" : this.getStyle("right"),
7897 "bottom" : t ? "" : this.getStyle("bottom"),
7898 "z-index" : this.getStyle("z-index")
7903 * Gets the width of the border(s) for the specified side(s)
7904 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
7905 * passing lr would get the border (l)eft width + the border (r)ight width.
7906 * @return {Number} The width of the sides passed added together
7908 getBorderWidth : function(side){
7909 return this.addStyles(side, El.borders);
7913 * Gets the width of the padding(s) for the specified side(s)
7914 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
7915 * passing lr would get the padding (l)eft + the padding (r)ight.
7916 * @return {Number} The padding of the sides passed added together
7918 getPadding : function(side){
7919 return this.addStyles(side, El.paddings);
7923 * Set positioning with an object returned by getPositioning().
7924 * @param {Object} posCfg
7925 * @return {Roo.Element} this
7927 setPositioning : function(pc){
7928 this.applyStyles(pc);
7929 if(pc.right == "auto"){
7930 this.dom.style.right = "";
7932 if(pc.bottom == "auto"){
7933 this.dom.style.bottom = "";
7939 fixDisplay : function(){
7940 if(this.getStyle("display") == "none"){
7941 this.setStyle("visibility", "hidden");
7942 this.setStyle("display", this.originalDisplay); // first try reverting to default
7943 if(this.getStyle("display") == "none"){ // if that fails, default to block
7944 this.setStyle("display", "block");
7950 * Quick set left and top adding default units
7951 * @param {String} left The left CSS property value
7952 * @param {String} top The top CSS property value
7953 * @return {Roo.Element} this
7955 setLeftTop : function(left, top){
7956 this.dom.style.left = this.addUnits(left);
7957 this.dom.style.top = this.addUnits(top);
7962 * Move this element relative to its current position.
7963 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
7964 * @param {Number} distance How far to move the element in pixels
7965 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7966 * @return {Roo.Element} this
7968 move : function(direction, distance, animate){
7969 var xy = this.getXY();
7970 direction = direction.toLowerCase();
7974 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
7978 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
7983 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
7988 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
7995 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
7996 * @return {Roo.Element} this
7999 if(!this.isClipped){
8000 this.isClipped = true;
8001 this.originalClip = {
8002 "o": this.getStyle("overflow"),
8003 "x": this.getStyle("overflow-x"),
8004 "y": this.getStyle("overflow-y")
8006 this.setStyle("overflow", "hidden");
8007 this.setStyle("overflow-x", "hidden");
8008 this.setStyle("overflow-y", "hidden");
8014 * Return clipping (overflow) to original clipping before clip() was called
8015 * @return {Roo.Element} this
8017 unclip : function(){
8019 this.isClipped = false;
8020 var o = this.originalClip;
8021 if(o.o){this.setStyle("overflow", o.o);}
8022 if(o.x){this.setStyle("overflow-x", o.x);}
8023 if(o.y){this.setStyle("overflow-y", o.y);}
8030 * Gets the x,y coordinates specified by the anchor position on the element.
8031 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8032 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8033 * {width: (target width), height: (target height)} (defaults to the element's current size)
8034 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8035 * @return {Array} [x, y] An array containing the element's x and y coordinates
8037 getAnchorXY : function(anchor, local, s){
8038 //Passing a different size is useful for pre-calculating anchors,
8039 //especially for anchored animations that change the el size.
8041 var w, h, vp = false;
8044 if(d == document.body || d == document){
8046 w = D.getViewWidth(); h = D.getViewHeight();
8048 w = this.getWidth(); h = this.getHeight();
8051 w = s.width; h = s.height;
8053 var x = 0, y = 0, r = Math.round;
8054 switch((anchor || "tl").toLowerCase()){
8096 var sc = this.getScroll();
8097 return [x + sc.left, y + sc.top];
8099 //Add the element's offset xy
8100 var o = this.getXY();
8101 return [x+o[0], y+o[1]];
8105 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8106 * supported position values.
8107 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8108 * @param {String} position The position to align to.
8109 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8110 * @return {Array} [x, y]
8112 getAlignToXY : function(el, p, o){
8116 throw "Element.alignTo with an element that doesn't exist";
8118 var c = false; //constrain to viewport
8119 var p1 = "", p2 = "";
8126 }else if(p.indexOf("-") == -1){
8129 p = p.toLowerCase();
8130 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8132 throw "Element.alignTo with an invalid alignment " + p;
8134 p1 = m[1]; p2 = m[2]; c = !!m[3];
8136 //Subtract the aligned el's internal xy from the target's offset xy
8137 //plus custom offset to get the aligned el's new offset xy
8138 var a1 = this.getAnchorXY(p1, true);
8139 var a2 = el.getAnchorXY(p2, false);
8140 var x = a2[0] - a1[0] + o[0];
8141 var y = a2[1] - a1[1] + o[1];
8143 //constrain the aligned el to viewport if necessary
8144 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8145 // 5px of margin for ie
8146 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8148 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8149 //perpendicular to the vp border, allow the aligned el to slide on that border,
8150 //otherwise swap the aligned el to the opposite border of the target.
8151 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8152 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8153 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8154 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8157 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8158 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8160 if((x+w) > dw + scrollX){
8161 x = swapX ? r.left-w : dw+scrollX-w;
8164 x = swapX ? r.right : scrollX;
8166 if((y+h) > dh + scrollY){
8167 y = swapY ? r.top-h : dh+scrollY-h;
8170 y = swapY ? r.bottom : scrollY;
8177 getConstrainToXY : function(){
8178 var os = {top:0, left:0, bottom:0, right: 0};
8180 return function(el, local, offsets, proposedXY){
8182 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8184 var vw, vh, vx = 0, vy = 0;
8185 if(el.dom == document.body || el.dom == document){
8186 vw = Roo.lib.Dom.getViewWidth();
8187 vh = Roo.lib.Dom.getViewHeight();
8189 vw = el.dom.clientWidth;
8190 vh = el.dom.clientHeight;
8192 var vxy = el.getXY();
8198 var s = el.getScroll();
8200 vx += offsets.left + s.left;
8201 vy += offsets.top + s.top;
8203 vw -= offsets.right;
8204 vh -= offsets.bottom;
8209 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8210 var x = xy[0], y = xy[1];
8211 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8213 // only move it if it needs it
8216 // first validate right/bottom
8225 // then make sure top/left isn't negative
8234 return moved ? [x, y] : false;
8239 adjustForConstraints : function(xy, parent, offsets){
8240 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8244 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8245 * document it aligns it to the viewport.
8246 * The position parameter is optional, and can be specified in any one of the following formats:
8248 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8249 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8250 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8251 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8252 * <li><b>Two anchors</b>: If two values from the table below are passed separated by a dash, the first value is used as the
8253 * element's anchor point, and the second value is used as the target's anchor point.</li>
8255 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8256 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8257 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8258 * that specified in order to enforce the viewport constraints.
8259 * Following are all of the supported anchor positions:
8262 ----- -----------------------------
8263 tl The top left corner (default)
8264 t The center of the top edge
8265 tr The top right corner
8266 l The center of the left edge
8267 c In the center of the element
8268 r The center of the right edge
8269 bl The bottom left corner
8270 b The center of the bottom edge
8271 br The bottom right corner
8275 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8276 el.alignTo("other-el");
8278 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8279 el.alignTo("other-el", "tr?");
8281 // align the bottom right corner of el with the center left edge of other-el
8282 el.alignTo("other-el", "br-l?");
8284 // align the center of el with the bottom left corner of other-el and
8285 // adjust the x position by -6 pixels (and the y position by 0)
8286 el.alignTo("other-el", "c-bl", [-6, 0]);
8288 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8289 * @param {String} position The position to align to.
8290 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8291 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8292 * @return {Roo.Element} this
8294 alignTo : function(element, position, offsets, animate){
8295 var xy = this.getAlignToXY(element, position, offsets);
8296 this.setXY(xy, this.preanim(arguments, 3));
8301 * Anchors an element to another element and realigns it when the window is resized.
8302 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8303 * @param {String} position The position to align to.
8304 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8305 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8306 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8307 * is a number, it is used as the buffer delay (defaults to 50ms).
8308 * @param {Function} callback The function to call after the animation finishes
8309 * @return {Roo.Element} this
8311 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8312 var action = function(){
8313 this.alignTo(el, alignment, offsets, animate);
8314 Roo.callback(callback, this);
8316 Roo.EventManager.onWindowResize(action, this);
8317 var tm = typeof monitorScroll;
8318 if(tm != 'undefined'){
8319 Roo.EventManager.on(window, 'scroll', action, this,
8320 {buffer: tm == 'number' ? monitorScroll : 50});
8322 action.call(this); // align immediately
8326 * Clears any opacity settings from this element. Required in some cases for IE.
8327 * @return {Roo.Element} this
8329 clearOpacity : function(){
8330 if (window.ActiveXObject) {
8331 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8332 this.dom.style.filter = "";
8335 this.dom.style.opacity = "";
8336 this.dom.style["-moz-opacity"] = "";
8337 this.dom.style["-khtml-opacity"] = "";
8343 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8344 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8345 * @return {Roo.Element} this
8347 hide : function(animate){
8348 this.setVisible(false, this.preanim(arguments, 0));
8353 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8354 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8355 * @return {Roo.Element} this
8357 show : function(animate){
8358 this.setVisible(true, this.preanim(arguments, 0));
8363 * @private Test if size has a unit, otherwise appends the default
8365 addUnits : function(size){
8366 return Roo.Element.addUnits(size, this.defaultUnit);
8370 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8371 * @return {Roo.Element} this
8373 beginMeasure : function(){
8375 if(el.offsetWidth || el.offsetHeight){
8376 return this; // offsets work already
8379 var p = this.dom, b = document.body; // start with this element
8380 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8381 var pe = Roo.get(p);
8382 if(pe.getStyle('display') == 'none'){
8383 changed.push({el: p, visibility: pe.getStyle("visibility")});
8384 p.style.visibility = "hidden";
8385 p.style.display = "block";
8389 this._measureChanged = changed;
8395 * Restores displays to before beginMeasure was called
8396 * @return {Roo.Element} this
8398 endMeasure : function(){
8399 var changed = this._measureChanged;
8401 for(var i = 0, len = changed.length; i < len; i++) {
8403 r.el.style.visibility = r.visibility;
8404 r.el.style.display = "none";
8406 this._measureChanged = null;
8412 * Update the innerHTML of this element, optionally searching for and processing scripts
8413 * @param {String} html The new HTML
8414 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8415 * @param {Function} callback For async script loading you can be noticed when the update completes
8416 * @return {Roo.Element} this
8418 update : function(html, loadScripts, callback){
8419 if(typeof html == "undefined"){
8422 if(loadScripts !== true){
8423 this.dom.innerHTML = html;
8424 if(typeof callback == "function"){
8432 html += '<span id="' + id + '"></span>';
8434 E.onAvailable(id, function(){
8435 var hd = document.getElementsByTagName("head")[0];
8436 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8437 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8438 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8441 while(match = re.exec(html)){
8442 var attrs = match[1];
8443 var srcMatch = attrs ? attrs.match(srcRe) : false;
8444 if(srcMatch && srcMatch[2]){
8445 var s = document.createElement("script");
8446 s.src = srcMatch[2];
8447 var typeMatch = attrs.match(typeRe);
8448 if(typeMatch && typeMatch[2]){
8449 s.type = typeMatch[2];
8452 }else if(match[2] && match[2].length > 0){
8453 if(window.execScript) {
8454 window.execScript(match[2]);
8462 window.eval(match[2]);
8466 var el = document.getElementById(id);
8467 if(el){el.parentNode.removeChild(el);}
8468 if(typeof callback == "function"){
8472 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8477 * Direct access to the UpdateManager update() method (takes the same parameters).
8478 * @param {String/Function} url The url for this request or a function to call to get the url
8479 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "param1=1&param2=2" or an object {param1: 1, param2: 2}
8480 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8481 * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used url. If true, it will not store the url.
8482 * @return {Roo.Element} this
8485 var um = this.getUpdateManager();
8486 um.update.apply(um, arguments);
8491 * Gets this element's UpdateManager
8492 * @return {Roo.UpdateManager} The UpdateManager
8494 getUpdateManager : function(){
8495 if(!this.updateManager){
8496 this.updateManager = new Roo.UpdateManager(this);
8498 return this.updateManager;
8502 * Disables text selection for this element (normalized across browsers)
8503 * @return {Roo.Element} this
8505 unselectable : function(){
8506 this.dom.unselectable = "on";
8507 this.swallowEvent("selectstart", true);
8508 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8509 this.addClass("x-unselectable");
8514 * Calculates the x, y to center this element on the screen
8515 * @return {Array} The x, y values [x, y]
8517 getCenterXY : function(){
8518 return this.getAlignToXY(document, 'c-c');
8522 * Centers the Element in either the viewport, or another Element.
8523 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8525 center : function(centerIn){
8526 this.alignTo(centerIn || document, 'c-c');
8531 * Tests various css rules/browsers to determine if this element uses a border box
8534 isBorderBox : function(){
8535 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8539 * Return a box {x, y, width, height} that can be used to set another elements
8540 * size/location to match this element.
8541 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8542 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8543 * @return {Object} box An object in the format {x, y, width, height}
8545 getBox : function(contentBox, local){
8550 var left = parseInt(this.getStyle("left"), 10) || 0;
8551 var top = parseInt(this.getStyle("top"), 10) || 0;
8554 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8556 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8558 var l = this.getBorderWidth("l")+this.getPadding("l");
8559 var r = this.getBorderWidth("r")+this.getPadding("r");
8560 var t = this.getBorderWidth("t")+this.getPadding("t");
8561 var b = this.getBorderWidth("b")+this.getPadding("b");
8562 bx = {x: xy[0]+l, y: xy[1]+t, 0: xy[0]+l, 1: xy[1]+t, width: w-(l+r), height: h-(t+b)};
8564 bx.right = bx.x + bx.width;
8565 bx.bottom = bx.y + bx.height;
8570 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8571 for more information about the sides.
8572 * @param {String} sides
8575 getFrameWidth : function(sides, onlyContentBox){
8576 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8580 * Sets the element's box. Use getBox() on another element to get a box obj. If animate is true then width, height, x and y will be animated concurrently.
8581 * @param {Object} box The box to fill {x, y, width, height}
8582 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8583 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8584 * @return {Roo.Element} this
8586 setBox : function(box, adjust, animate){
8587 var w = box.width, h = box.height;
8588 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8589 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8590 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8592 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8597 * Forces the browser to repaint this element
8598 * @return {Roo.Element} this
8600 repaint : function(){
8602 this.addClass("x-repaint");
8603 setTimeout(function(){
8604 Roo.get(dom).removeClass("x-repaint");
8610 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8611 * then it returns the calculated width of the sides (see getPadding)
8612 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8613 * @return {Object/Number}
8615 getMargins : function(side){
8618 top: parseInt(this.getStyle("margin-top"), 10) || 0,
8619 left: parseInt(this.getStyle("margin-left"), 10) || 0,
8620 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8621 right: parseInt(this.getStyle("margin-right"), 10) || 0
8624 return this.addStyles(side, El.margins);
8629 addStyles : function(sides, styles){
8631 for(var i = 0, len = sides.length; i < len; i++){
8632 v = this.getStyle(styles[sides.charAt(i)]);
8634 w = parseInt(v, 10);
8642 * Creates a proxy element of this element
8643 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8644 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8645 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8646 * @return {Roo.Element} The new proxy element
8648 createProxy : function(config, renderTo, matchBox){
8650 renderTo = Roo.getDom(renderTo);
8652 renderTo = document.body;
8654 config = typeof config == "object" ?
8655 config : {tag : "div", cls: config};
8656 var proxy = Roo.DomHelper.append(renderTo, config, true);
8658 proxy.setBox(this.getBox());
8664 * Puts a mask over this element to disable user interaction. Requires core.css.
8665 * This method can only be applied to elements which accept child nodes.
8666 * @param {String} msg (optional) A message to display in the mask
8667 * @param {String} msgCls (optional) A css class to apply to the msg element
8668 * @return {Element} The mask element
8670 mask : function(msg, msgCls){
8671 if(this.getStyle("position") == "static"){
8672 this.setStyle("position", "relative");
8675 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8677 this.addClass("x-masked");
8678 this._mask.setDisplayed(true);
8679 if(typeof msg == 'string'){
8681 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8683 var mm = this._maskMsg;
8684 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8685 mm.dom.firstChild.innerHTML = msg;
8686 mm.setDisplayed(true);
8689 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8690 this._mask.setHeight(this.getHeight());
8696 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8697 * it is cached for reuse.
8699 unmask : function(removeEl){
8701 if(removeEl === true){
8702 this._mask.remove();
8705 this._maskMsg.remove();
8706 delete this._maskMsg;
8709 this._mask.setDisplayed(false);
8711 this._maskMsg.setDisplayed(false);
8715 this.removeClass("x-masked");
8719 * Returns true if this element is masked
8722 isMasked : function(){
8723 return this._mask && this._mask.isVisible();
8727 * Creates an iframe shim for this element to keep selects and other windowed objects from
8729 * @return {Roo.Element} The new shim element
8731 createShim : function(){
8732 var el = document.createElement('iframe');
8733 el.frameBorder = 'no';
8734 el.className = 'roo-shim';
8735 if(Roo.isIE && Roo.isSecure){
8736 el.src = Roo.SSL_SECURE_URL;
8738 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
8739 shim.autoBoxAdjust = false;
8744 * Removes this element from the DOM and deletes it from the cache
8746 remove : function(){
8747 if(this.dom.parentNode){
8748 this.dom.parentNode.removeChild(this.dom);
8750 delete El.cache[this.dom.id];
8754 * Sets up event handlers to add and remove a css class when the mouse is over this element
8755 * @param {String} className
8756 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
8757 * mouseout events for children elements
8758 * @return {Roo.Element} this
8760 addClassOnOver : function(className, preventFlicker){
8761 this.on("mouseover", function(){
8762 Roo.fly(this, '_internal').addClass(className);
8764 var removeFn = function(e){
8765 if(preventFlicker !== true || !e.within(this, true)){
8766 Roo.fly(this, '_internal').removeClass(className);
8769 this.on("mouseout", removeFn, this.dom);
8774 * Sets up event handlers to add and remove a css class when this element has the focus
8775 * @param {String} className
8776 * @return {Roo.Element} this
8778 addClassOnFocus : function(className){
8779 this.on("focus", function(){
8780 Roo.fly(this, '_internal').addClass(className);
8782 this.on("blur", function(){
8783 Roo.fly(this, '_internal').removeClass(className);
8788 * Sets up event handlers to add and remove a css class when the mouse is down and then up on this element (a click effect)
8789 * @param {String} className
8790 * @return {Roo.Element} this
8792 addClassOnClick : function(className){
8794 this.on("mousedown", function(){
8795 Roo.fly(dom, '_internal').addClass(className);
8796 var d = Roo.get(document);
8797 var fn = function(){
8798 Roo.fly(dom, '_internal').removeClass(className);
8799 d.removeListener("mouseup", fn);
8801 d.on("mouseup", fn);
8807 * Stops the specified event from bubbling and optionally prevents the default action
8808 * @param {String} eventName
8809 * @param {Boolean} preventDefault (optional) true to prevent the default action too
8810 * @return {Roo.Element} this
8812 swallowEvent : function(eventName, preventDefault){
8813 var fn = function(e){
8814 e.stopPropagation();
8819 if(eventName instanceof Array){
8820 for(var i = 0, len = eventName.length; i < len; i++){
8821 this.on(eventName[i], fn);
8825 this.on(eventName, fn);
8832 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
8835 * Sizes this element to its parent element's dimensions performing
8836 * neccessary box adjustments.
8837 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
8838 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
8839 * @return {Roo.Element} this
8841 fitToParent : function(monitorResize, targetParent) {
8842 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
8843 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
8844 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
8847 var p = Roo.get(targetParent || this.dom.parentNode);
8848 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
8849 if (monitorResize === true) {
8850 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
8851 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
8857 * Gets the next sibling, skipping text nodes
8858 * @return {HTMLElement} The next sibling or null
8860 getNextSibling : function(){
8861 var n = this.dom.nextSibling;
8862 while(n && n.nodeType != 1){
8869 * Gets the previous sibling, skipping text nodes
8870 * @return {HTMLElement} The previous sibling or null
8872 getPrevSibling : function(){
8873 var n = this.dom.previousSibling;
8874 while(n && n.nodeType != 1){
8875 n = n.previousSibling;
8882 * Appends the passed element(s) to this element
8883 * @param {String/HTMLElement/Array/Element/CompositeElement} el
8884 * @return {Roo.Element} this
8886 appendChild: function(el){
8893 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
8894 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
8895 * automatically generated with the specified attributes.
8896 * @param {HTMLElement} insertBefore (optional) a child element of this element
8897 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
8898 * @return {Roo.Element} The new child element
8900 createChild: function(config, insertBefore, returnDom){
8901 config = config || {tag:'div'};
8903 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
8905 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
8909 * Appends this element to the passed element
8910 * @param {String/HTMLElement/Element} el The new parent element
8911 * @return {Roo.Element} this
8913 appendTo: function(el){
8914 el = Roo.getDom(el);
8915 el.appendChild(this.dom);
8920 * Inserts this element before the passed element in the DOM
8921 * @param {String/HTMLElement/Element} el The element to insert before
8922 * @return {Roo.Element} this
8924 insertBefore: function(el){
8925 el = Roo.getDom(el);
8926 el.parentNode.insertBefore(this.dom, el);
8931 * Inserts this element after the passed element in the DOM
8932 * @param {String/HTMLElement/Element} el The element to insert after
8933 * @return {Roo.Element} this
8935 insertAfter: function(el){
8936 el = Roo.getDom(el);
8937 el.parentNode.insertBefore(this.dom, el.nextSibling);
8942 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
8943 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
8944 * @return {Roo.Element} The new child
8946 insertFirst: function(el, returnDom){
8948 if(typeof el == 'object' && !el.nodeType){ // dh config
8949 return this.createChild(el, this.dom.firstChild, returnDom);
8951 el = Roo.getDom(el);
8952 this.dom.insertBefore(el, this.dom.firstChild);
8953 return !returnDom ? Roo.get(el) : el;
8958 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
8959 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
8960 * @param {String} where (optional) 'before' or 'after' defaults to before
8961 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
8962 * @return {Roo.Element} the inserted Element
8964 insertSibling: function(el, where, returnDom){
8965 where = where ? where.toLowerCase() : 'before';
8967 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
8969 if(typeof el == 'object' && !el.nodeType){ // dh config
8970 if(where == 'after' && !this.dom.nextSibling){
8971 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
8973 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
8977 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
8978 where == 'before' ? this.dom : this.dom.nextSibling);
8987 * Creates and wraps this element with another element
8988 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
8989 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
8990 * @return {HTMLElement/Element} The newly created wrapper element
8992 wrap: function(config, returnDom){
8994 config = {tag: "div"};
8996 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
8997 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9002 * Replaces the passed element with this element
9003 * @param {String/HTMLElement/Element} el The element to replace
9004 * @return {Roo.Element} this
9006 replace: function(el){
9008 this.insertBefore(el);
9014 * Inserts an html fragment into this element
9015 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9016 * @param {String} html The HTML fragment
9017 * @param {Boolean} returnEl True to return an Roo.Element
9018 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9020 insertHtml : function(where, html, returnEl){
9021 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9022 return returnEl ? Roo.get(el) : el;
9026 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9027 * @param {Object} o The object with the attributes
9028 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9029 * @return {Roo.Element} this
9031 set : function(o, useSet){
9033 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9035 if(attr == "style" || typeof o[attr] == "function") continue;
9037 el.className = o["cls"];
9039 if(useSet) el.setAttribute(attr, o[attr]);
9040 else el[attr] = o[attr];
9044 Roo.DomHelper.applyStyles(el, o.style);
9050 * Convenience method for constructing a KeyMap
9051 * @param {Number/Array/Object/String} key Either a string with the keys to listen for, the numeric key code, array of key codes or an object with the following options:
9052 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9053 * @param {Function} fn The function to call
9054 * @param {Object} scope (optional) The scope of the function
9055 * @return {Roo.KeyMap} The KeyMap created
9057 addKeyListener : function(key, fn, scope){
9059 if(typeof key != "object" || key instanceof Array){
9075 return new Roo.KeyMap(this, config);
9079 * Creates a KeyMap for this element
9080 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9081 * @return {Roo.KeyMap} The KeyMap created
9083 addKeyMap : function(config){
9084 return new Roo.KeyMap(this, config);
9088 * Returns true if this element is scrollable.
9091 isScrollable : function(){
9093 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9097 * Scrolls this element the specified scroll point. It does NOT do bounds checking so if you scroll to a weird value it will try to do it. For auto bounds checking, use scroll().
9098 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9099 * @param {Number} value The new scroll value
9100 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9101 * @return {Element} this
9104 scrollTo : function(side, value, animate){
9105 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9107 this.dom[prop] = value;
9109 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9110 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9116 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9117 * within this element's scrollable range.
9118 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9119 * @param {Number} distance How far to scroll the element in pixels
9120 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9121 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9122 * was scrolled as far as it could go.
9124 scroll : function(direction, distance, animate){
9125 if(!this.isScrollable()){
9129 var l = el.scrollLeft, t = el.scrollTop;
9130 var w = el.scrollWidth, h = el.scrollHeight;
9131 var cw = el.clientWidth, ch = el.clientHeight;
9132 direction = direction.toLowerCase();
9133 var scrolled = false;
9134 var a = this.preanim(arguments, 2);
9139 var v = Math.min(l + distance, w-cw);
9140 this.scrollTo("left", v, a);
9147 var v = Math.max(l - distance, 0);
9148 this.scrollTo("left", v, a);
9156 var v = Math.max(t - distance, 0);
9157 this.scrollTo("top", v, a);
9165 var v = Math.min(t + distance, h-ch);
9166 this.scrollTo("top", v, a);
9175 * Translates the passed page coordinates into left/top css values for this element
9176 * @param {Number/Array} x The page x or an array containing [x, y]
9177 * @param {Number} y The page y
9178 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9180 translatePoints : function(x, y){
9181 if(typeof x == 'object' || x instanceof Array){
9184 var p = this.getStyle('position');
9185 var o = this.getXY();
9187 var l = parseInt(this.getStyle('left'), 10);
9188 var t = parseInt(this.getStyle('top'), 10);
9191 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9194 t = (p == "relative") ? 0 : this.dom.offsetTop;
9197 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9201 * Returns the current scroll position of the element.
9202 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9204 getScroll : function(){
9205 var d = this.dom, doc = document;
9206 if(d == doc || d == doc.body){
9207 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9208 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9209 return {left: l, top: t};
9211 return {left: d.scrollLeft, top: d.scrollTop};
9216 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9217 * are convert to standard 6 digit hex color.
9218 * @param {String} attr The css attribute
9219 * @param {String} defaultValue The default value to use when a valid color isn't found
9220 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9223 getColor : function(attr, defaultValue, prefix){
9224 var v = this.getStyle(attr);
9225 if(!v || v == "transparent" || v == "inherit") {
9226 return defaultValue;
9228 var color = typeof prefix == "undefined" ? "#" : prefix;
9229 if(v.substr(0, 4) == "rgb("){
9230 var rvs = v.slice(4, v.length -1).split(",");
9231 for(var i = 0; i < 3; i++){
9232 var h = parseInt(rvs[i]).toString(16);
9239 if(v.substr(0, 1) == "#"){
9241 for(var i = 1; i < 4; i++){
9242 var c = v.charAt(i);
9245 }else if(v.length == 7){
9246 color += v.substr(1);
9250 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9254 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9255 * gradient background, rounded corners and a 4-way shadow.
9256 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9257 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9258 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9259 * @return {Roo.Element} this
9261 boxWrap : function(cls){
9262 cls = cls || 'x-box';
9263 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9264 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9269 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9270 * @param {String} namespace The namespace in which to look for the attribute
9271 * @param {String} name The attribute name
9272 * @return {String} The attribute value
9274 getAttributeNS : Roo.isIE ? function(ns, name){
9276 var type = typeof d[ns+":"+name];
9277 if(type != 'undefined' && type != 'unknown'){
9278 return d[ns+":"+name];
9281 } : function(ns, name){
9283 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9287 var ep = El.prototype;
9290 * Appends an event handler (Shorthand for addListener)
9291 * @param {String} eventName The type of event to append
9292 * @param {Function} fn The method the event invokes
9293 * @param {Object} scope (optional) The scope (this object) of the fn
9294 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9297 ep.on = ep.addListener;
9299 ep.mon = ep.addListener;
9302 * Removes an event handler from this element (shorthand for removeListener)
9303 * @param {String} eventName the type of event to remove
9304 * @param {Function} fn the method the event invokes
9305 * @return {Roo.Element} this
9308 ep.un = ep.removeListener;
9311 * true to automatically adjust width and height settings for box-model issues (default to true)
9313 ep.autoBoxAdjust = true;
9316 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9319 El.addUnits = function(v, defaultUnit){
9320 if(v === "" || v == "auto"){
9323 if(v === undefined){
9326 if(typeof v == "number" || !El.unitPattern.test(v)){
9327 return v + (defaultUnit || 'px');
9332 // special markup used throughout Roo when box wrapping elements
9333 El.boxMarkup = '<div class="{0}-tl"><div class="{0}-tr"><div class="{0}-tc"></div></div></div><div class="{0}-ml"><div class="{0}-mr"><div class="{0}-mc"></div></div></div><div class="{0}-bl"><div class="{0}-br"><div class="{0}-bc"></div></div></div>';
9335 * Visibility mode constant - Use visibility to hide element
9341 * Visibility mode constant - Use display to hide element
9347 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9348 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9349 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9361 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9362 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9363 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9364 * @return {Element} The Element object
9367 El.get = function(el){
9369 if(!el){ return null; }
9370 if(typeof el == "string"){ // element id
9371 if(!(elm = document.getElementById(el))){
9374 if(ex = El.cache[el]){
9377 ex = El.cache[el] = new El(elm);
9380 }else if(el.tagName){ // dom element
9384 if(ex = El.cache[id]){
9387 ex = El.cache[id] = new El(el);
9390 }else if(el instanceof El){
9392 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9393 // catch case where it hasn't been appended
9394 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9397 }else if(el.isComposite){
9399 }else if(el instanceof Array){
9400 return El.select(el);
9401 }else if(el == document){
9402 // create a bogus element object representing the document object
9404 var f = function(){};
9405 f.prototype = El.prototype;
9407 docEl.dom = document;
9415 El.uncache = function(el){
9416 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9418 delete El.cache[a[i].id || a[i]];
9424 // Garbage collection - uncache elements/purge listeners on orphaned elements
9425 // so we don't hold a reference and cause the browser to retain them
9426 El.garbageCollect = function(){
9427 if(!Roo.enableGarbageCollector){
9428 clearInterval(El.collectorThread);
9431 for(var eid in El.cache){
9432 var el = El.cache[eid], d = el.dom;
9433 // -------------------------------------------------------
9434 // Determining what is garbage:
9435 // -------------------------------------------------------
9437 // dom node is null, definitely garbage
9438 // -------------------------------------------------------
9440 // no parentNode == direct orphan, definitely garbage
9441 // -------------------------------------------------------
9442 // !d.offsetParent && !document.getElementById(eid)
9443 // display none elements have no offsetParent so we will
9444 // also try to look it up by it's id. However, check
9445 // offsetParent first so we don't do unneeded lookups.
9446 // This enables collection of elements that are not orphans
9447 // directly, but somewhere up the line they have an orphan
9449 // -------------------------------------------------------
9450 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9451 delete El.cache[eid];
9452 if(d && Roo.enableListenerCollection){
9458 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9462 El.Flyweight = function(dom){
9465 El.Flyweight.prototype = El.prototype;
9467 El._flyweights = {};
9469 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9470 * the dom node can be overwritten by other code.
9471 * @param {String/HTMLElement} el The dom node or id
9472 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9473 * prevent conflicts (e.g. internally Roo uses "_internal")
9475 * @return {Element} The shared Element object
9477 El.fly = function(el, named){
9478 named = named || '_global';
9479 el = Roo.getDom(el);
9483 if(!El._flyweights[named]){
9484 El._flyweights[named] = new El.Flyweight();
9486 El._flyweights[named].dom = el;
9487 return El._flyweights[named];
9491 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9492 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9493 * Shorthand of {@link Roo.Element#get}
9494 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9495 * @return {Element} The Element object
9501 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9502 * the dom node can be overwritten by other code.
9503 * Shorthand of {@link Roo.Element#fly}
9504 * @param {String/HTMLElement} el The dom node or id
9505 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9506 * prevent conflicts (e.g. internally Roo uses "_internal")
9508 * @return {Element} The shared Element object
9514 // speedy lookup for elements never to box adjust
9515 var noBoxAdjust = Roo.isStrict ? {
9518 input:1, select:1, textarea:1
9520 if(Roo.isIE || Roo.isGecko){
9521 noBoxAdjust['button'] = 1;
9525 Roo.EventManager.on(window, 'unload', function(){
9527 delete El._flyweights;
9535 Roo.Element.selectorFunction = Roo.DomQuery.select;
9538 Roo.Element.select = function(selector, unique, root){
9540 if(typeof selector == "string"){
9541 els = Roo.Element.selectorFunction(selector, root);
9542 }else if(selector.length !== undefined){
9545 throw "Invalid selector";
9547 if(unique === true){
9548 return new Roo.CompositeElement(els);
9550 return new Roo.CompositeElementLite(els);
9554 * Selects elements based on the passed CSS selector to enable working on them as 1.
9555 * @param {String/Array} selector The CSS selector or an array of elements
9556 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9557 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9558 * @return {CompositeElementLite/CompositeElement}
9562 Roo.select = Roo.Element.select;
9579 * Ext JS Library 1.1.1
9580 * Copyright(c) 2006-2007, Ext JS, LLC.
9582 * Originally Released Under LGPL - original licence link has changed is not relivant.
9585 * <script type="text/javascript">
9590 //Notifies Element that fx methods are available
9591 Roo.enableFx = true;
9595 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
9596 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9597 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
9598 * Element effects to work.</p><br/>
9600 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9601 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9602 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9603 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
9604 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9605 * expected results and should be done with care.</p><br/>
9607 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9608 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
9611 ----- -----------------------------
9612 tl The top left corner
9613 t The center of the top edge
9614 tr The top right corner
9615 l The center of the left edge
9616 r The center of the right edge
9617 bl The bottom left corner
9618 b The center of the bottom edge
9619 br The bottom right corner
9621 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9622 * below are common options that can be passed to any Fx method.</b>
9623 * @cfg {Function} callback A function called when the effect is finished
9624 * @cfg {Object} scope The scope of the effect function
9625 * @cfg {String} easing A valid Easing value for the effect
9626 * @cfg {String} afterCls A css class to apply after the effect
9627 * @cfg {Number} duration The length of time (in seconds) that the effect should last
9628 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9629 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
9630 * effects that end with the element being visually hidden, ignored otherwise)
9631 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9632 * a function which returns such a specification that will be applied to the Element after the effect finishes
9633 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9634 * @cfg {Boolean} concurrent Whether to allow subsequently-queued effects to run at the same time as the current effect, or to ensure that they run in sequence
9635 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9639 * Slides the element into view. An anchor point can be optionally passed to set the point of
9640 * origin for the slide effect. This function automatically handles wrapping the element with
9641 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9644 // default: slide the element in from the top
9647 // custom: slide the element in from the right with a 2-second duration
9648 el.slideIn('r', { duration: 2 });
9650 // common config options shown with default values
9656 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9657 * @param {Object} options (optional) Object literal with any of the Fx config options
9658 * @return {Roo.Element} The Element
9660 slideIn : function(anchor, o){
9661 var el = this.getFxEl();
9664 el.queueFx(o, function(){
9666 anchor = anchor || "t";
9668 // fix display to visibility
9671 // restore values after effect
9672 var r = this.getFxRestore();
9673 var b = this.getBox();
9674 // fixed size for slide
9678 var wrap = this.fxWrap(r.pos, o, "hidden");
9680 var st = this.dom.style;
9681 st.visibility = "visible";
9682 st.position = "absolute";
9684 // clear out temp styles after slide and unwrap
9685 var after = function(){
9686 el.fxUnwrap(wrap, r.pos, o);
9688 st.height = r.height;
9691 // time to calc the positions
9692 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
9694 switch(anchor.toLowerCase()){
9696 wrap.setSize(b.width, 0);
9697 st.left = st.bottom = "0";
9701 wrap.setSize(0, b.height);
9702 st.right = st.top = "0";
9706 wrap.setSize(0, b.height);
9708 st.left = st.top = "0";
9709 a = {width: bw, points: pt};
9712 wrap.setSize(b.width, 0);
9713 wrap.setY(b.bottom);
9714 st.left = st.top = "0";
9715 a = {height: bh, points: pt};
9719 st.right = st.bottom = "0";
9720 a = {width: bw, height: bh};
9724 wrap.setY(b.y+b.height);
9725 st.right = st.top = "0";
9726 a = {width: bw, height: bh, points: pt};
9730 wrap.setXY([b.right, b.bottom]);
9731 st.left = st.top = "0";
9732 a = {width: bw, height: bh, points: pt};
9736 wrap.setX(b.x+b.width);
9737 st.left = st.bottom = "0";
9738 a = {width: bw, height: bh, points: pt};
9741 this.dom.style.visibility = "visible";
9744 arguments.callee.anim = wrap.fxanim(a,
9754 * Slides the element out of view. An anchor point can be optionally passed to set the end point
9755 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
9756 * 'hidden') but block elements will still take up space in the document. The element must be removed
9757 * from the DOM using the 'remove' config option if desired. This function automatically handles
9758 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9761 // default: slide the element out to the top
9764 // custom: slide the element out to the right with a 2-second duration
9765 el.slideOut('r', { duration: 2 });
9767 // common config options shown with default values
9775 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9776 * @param {Object} options (optional) Object literal with any of the Fx config options
9777 * @return {Roo.Element} The Element
9779 slideOut : function(anchor, o){
9780 var el = this.getFxEl();
9783 el.queueFx(o, function(){
9785 anchor = anchor || "t";
9787 // restore values after effect
9788 var r = this.getFxRestore();
9790 var b = this.getBox();
9791 // fixed size for slide
9795 var wrap = this.fxWrap(r.pos, o, "visible");
9797 var st = this.dom.style;
9798 st.visibility = "visible";
9799 st.position = "absolute";
9803 var after = function(){
9805 el.setDisplayed(false);
9810 el.fxUnwrap(wrap, r.pos, o);
9813 st.height = r.height;
9818 var a, zero = {to: 0};
9819 switch(anchor.toLowerCase()){
9821 st.left = st.bottom = "0";
9825 st.right = st.top = "0";
9829 st.left = st.top = "0";
9830 a = {width: zero, points: {to:[b.right, b.y]}};
9833 st.left = st.top = "0";
9834 a = {height: zero, points: {to:[b.x, b.bottom]}};
9837 st.right = st.bottom = "0";
9838 a = {width: zero, height: zero};
9841 st.right = st.top = "0";
9842 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
9845 st.left = st.top = "0";
9846 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
9849 st.left = st.bottom = "0";
9850 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
9854 arguments.callee.anim = wrap.fxanim(a,
9864 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
9865 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
9866 * The element must be removed from the DOM using the 'remove' config option if desired.
9872 // common config options shown with default values
9880 * @param {Object} options (optional) Object literal with any of the Fx config options
9881 * @return {Roo.Element} The Element
9884 var el = this.getFxEl();
9887 el.queueFx(o, function(){
9888 this.clearOpacity();
9891 // restore values after effect
9892 var r = this.getFxRestore();
9893 var st = this.dom.style;
9895 var after = function(){
9897 el.setDisplayed(false);
9904 el.setPositioning(r.pos);
9906 st.height = r.height;
9911 var width = this.getWidth();
9912 var height = this.getHeight();
9914 arguments.callee.anim = this.fxanim({
9915 width : {to: this.adjustWidth(width * 2)},
9916 height : {to: this.adjustHeight(height * 2)},
9917 points : {by: [-(width * .5), -(height * .5)]},
9919 fontSize: {to:200, unit: "%"}
9930 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
9931 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
9932 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
9938 // all config options shown with default values
9946 * @param {Object} options (optional) Object literal with any of the Fx config options
9947 * @return {Roo.Element} The Element
9949 switchOff : function(o){
9950 var el = this.getFxEl();
9953 el.queueFx(o, function(){
9954 this.clearOpacity();
9957 // restore values after effect
9958 var r = this.getFxRestore();
9959 var st = this.dom.style;
9961 var after = function(){
9963 el.setDisplayed(false);
9969 el.setPositioning(r.pos);
9971 st.height = r.height;
9976 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
9977 this.clearOpacity();
9981 points:{by:[0, this.getHeight() * .5]}
9982 }, o, 'motion', 0.3, 'easeIn', after);
9983 }).defer(100, this);
9990 * Highlights the Element by setting a color (applies to the background-color by default, but can be
9991 * changed using the "attr" config option) and then fading back to the original color. If no original
9992 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
9995 // default: highlight background to yellow
9998 // custom: highlight foreground text to blue for 2 seconds
9999 el.highlight("0000ff", { attr: 'color', duration: 2 });
10001 // common config options shown with default values
10002 el.highlight("ffff9c", {
10003 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10004 endColor: (current color) or "ffffff",
10009 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10010 * @param {Object} options (optional) Object literal with any of the Fx config options
10011 * @return {Roo.Element} The Element
10013 highlight : function(color, o){
10014 var el = this.getFxEl();
10017 el.queueFx(o, function(){
10018 color = color || "ffff9c";
10019 attr = o.attr || "backgroundColor";
10021 this.clearOpacity();
10024 var origColor = this.getColor(attr);
10025 var restoreColor = this.dom.style[attr];
10026 endColor = (o.endColor || origColor) || "ffffff";
10028 var after = function(){
10029 el.dom.style[attr] = restoreColor;
10034 a[attr] = {from: color, to: endColor};
10035 arguments.callee.anim = this.fxanim(a,
10045 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10048 // default: a single light blue ripple
10051 // custom: 3 red ripples lasting 3 seconds total
10052 el.frame("ff0000", 3, { duration: 3 });
10054 // common config options shown with default values
10055 el.frame("C3DAF9", 1, {
10056 duration: 1 //duration of entire animation (not each individual ripple)
10057 // Note: Easing is not configurable and will be ignored if included
10060 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10061 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10062 * @param {Object} options (optional) Object literal with any of the Fx config options
10063 * @return {Roo.Element} The Element
10065 frame : function(color, count, o){
10066 var el = this.getFxEl();
10069 el.queueFx(o, function(){
10070 color = color || "#C3DAF9";
10071 if(color.length == 6){
10072 color = "#" + color;
10074 count = count || 1;
10075 duration = o.duration || 1;
10078 var b = this.getBox();
10079 var animFn = function(){
10080 var proxy = this.createProxy({
10083 visbility:"hidden",
10084 position:"absolute",
10085 "z-index":"35000", // yee haw
10086 border:"0px solid " + color
10089 var scale = Roo.isBorderBox ? 2 : 1;
10091 top:{from:b.y, to:b.y - 20},
10092 left:{from:b.x, to:b.x - 20},
10093 borderWidth:{from:0, to:10},
10094 opacity:{from:1, to:0},
10095 height:{from:b.height, to:(b.height + (20*scale))},
10096 width:{from:b.width, to:(b.width + (20*scale))}
10097 }, duration, function(){
10101 animFn.defer((duration/2)*1000, this);
10112 * Creates a pause before any subsequent queued effects begin. If there are
10113 * no effects queued after the pause it will have no effect.
10118 * @param {Number} seconds The length of time to pause (in seconds)
10119 * @return {Roo.Element} The Element
10121 pause : function(seconds){
10122 var el = this.getFxEl();
10125 el.queueFx(o, function(){
10126 setTimeout(function(){
10128 }, seconds * 1000);
10134 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10135 * using the "endOpacity" config option.
10138 // default: fade in from opacity 0 to 100%
10141 // custom: fade in from opacity 0 to 75% over 2 seconds
10142 el.fadeIn({ endOpacity: .75, duration: 2});
10144 // common config options shown with default values
10146 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10151 * @param {Object} options (optional) Object literal with any of the Fx config options
10152 * @return {Roo.Element} The Element
10154 fadeIn : function(o){
10155 var el = this.getFxEl();
10157 el.queueFx(o, function(){
10158 this.setOpacity(0);
10160 this.dom.style.visibility = 'visible';
10161 var to = o.endOpacity || 1;
10162 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10163 o, null, .5, "easeOut", function(){
10165 this.clearOpacity();
10174 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10175 * using the "endOpacity" config option.
10178 // default: fade out from the element's current opacity to 0
10181 // custom: fade out from the element's current opacity to 25% over 2 seconds
10182 el.fadeOut({ endOpacity: .25, duration: 2});
10184 // common config options shown with default values
10186 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10193 * @param {Object} options (optional) Object literal with any of the Fx config options
10194 * @return {Roo.Element} The Element
10196 fadeOut : function(o){
10197 var el = this.getFxEl();
10199 el.queueFx(o, function(){
10200 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10201 o, null, .5, "easeOut", function(){
10202 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10203 this.dom.style.display = "none";
10205 this.dom.style.visibility = "hidden";
10207 this.clearOpacity();
10215 * Animates the transition of an element's dimensions from a starting height/width
10216 * to an ending height/width.
10219 // change height and width to 100x100 pixels
10220 el.scale(100, 100);
10222 // common config options shown with default values. The height and width will default to
10223 // the element's existing values if passed as null.
10226 [element's height], {
10231 * @param {Number} width The new width (pass undefined to keep the original width)
10232 * @param {Number} height The new height (pass undefined to keep the original height)
10233 * @param {Object} options (optional) Object literal with any of the Fx config options
10234 * @return {Roo.Element} The Element
10236 scale : function(w, h, o){
10237 this.shift(Roo.apply({}, o, {
10245 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10246 * Any of these properties not specified in the config object will not be changed. This effect
10247 * requires that at least one new dimension, position or opacity setting must be passed in on
10248 * the config object in order for the function to have any effect.
10251 // slide the element horizontally to x position 200 while changing the height and opacity
10252 el.shift({ x: 200, height: 50, opacity: .8 });
10254 // common config options shown with default values.
10256 width: [element's width],
10257 height: [element's height],
10258 x: [element's x position],
10259 y: [element's y position],
10260 opacity: [element's opacity],
10265 * @param {Object} options Object literal with any of the Fx config options
10266 * @return {Roo.Element} The Element
10268 shift : function(o){
10269 var el = this.getFxEl();
10271 el.queueFx(o, function(){
10272 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10273 if(w !== undefined){
10274 a.width = {to: this.adjustWidth(w)};
10276 if(h !== undefined){
10277 a.height = {to: this.adjustHeight(h)};
10279 if(x !== undefined || y !== undefined){
10281 x !== undefined ? x : this.getX(),
10282 y !== undefined ? y : this.getY()
10285 if(op !== undefined){
10286 a.opacity = {to: op};
10288 if(o.xy !== undefined){
10289 a.points = {to: o.xy};
10291 arguments.callee.anim = this.fxanim(a,
10292 o, 'motion', .35, "easeOut", function(){
10300 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10301 * ending point of the effect.
10304 // default: slide the element downward while fading out
10307 // custom: slide the element out to the right with a 2-second duration
10308 el.ghost('r', { duration: 2 });
10310 // common config options shown with default values
10318 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10319 * @param {Object} options (optional) Object literal with any of the Fx config options
10320 * @return {Roo.Element} The Element
10322 ghost : function(anchor, o){
10323 var el = this.getFxEl();
10326 el.queueFx(o, function(){
10327 anchor = anchor || "b";
10329 // restore values after effect
10330 var r = this.getFxRestore();
10331 var w = this.getWidth(),
10332 h = this.getHeight();
10334 var st = this.dom.style;
10336 var after = function(){
10338 el.setDisplayed(false);
10344 el.setPositioning(r.pos);
10345 st.width = r.width;
10346 st.height = r.height;
10351 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10352 switch(anchor.toLowerCase()){
10379 arguments.callee.anim = this.fxanim(a,
10389 * Ensures that all effects queued after syncFx is called on the element are
10390 * run concurrently. This is the opposite of {@link #sequenceFx}.
10391 * @return {Roo.Element} The Element
10393 syncFx : function(){
10394 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10403 * Ensures that all effects queued after sequenceFx is called on the element are
10404 * run in sequence. This is the opposite of {@link #syncFx}.
10405 * @return {Roo.Element} The Element
10407 sequenceFx : function(){
10408 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10410 concurrent : false,
10417 nextFx : function(){
10418 var ef = this.fxQueue[0];
10425 * Returns true if the element has any effects actively running or queued, else returns false.
10426 * @return {Boolean} True if element has active effects, else false
10428 hasActiveFx : function(){
10429 return this.fxQueue && this.fxQueue[0];
10433 * Stops any running effects and clears the element's internal effects queue if it contains
10434 * any additional effects that haven't started yet.
10435 * @return {Roo.Element} The Element
10437 stopFx : function(){
10438 if(this.hasActiveFx()){
10439 var cur = this.fxQueue[0];
10440 if(cur && cur.anim && cur.anim.isAnimated()){
10441 this.fxQueue = [cur]; // clear out others
10442 cur.anim.stop(true);
10449 beforeFx : function(o){
10450 if(this.hasActiveFx() && !o.concurrent){
10461 * Returns true if the element is currently blocking so that no other effect can be queued
10462 * until this effect is finished, else returns false if blocking is not set. This is commonly
10463 * used to ensure that an effect initiated by a user action runs to completion prior to the
10464 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10465 * @return {Boolean} True if blocking, else false
10467 hasFxBlock : function(){
10468 var q = this.fxQueue;
10469 return q && q[0] && q[0].block;
10473 queueFx : function(o, fn){
10477 if(!this.hasFxBlock()){
10478 Roo.applyIf(o, this.fxDefaults);
10480 var run = this.beforeFx(o);
10481 fn.block = o.block;
10482 this.fxQueue.push(fn);
10494 fxWrap : function(pos, o, vis){
10496 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10499 wrapXY = this.getXY();
10501 var div = document.createElement("div");
10502 div.style.visibility = vis;
10503 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10504 wrap.setPositioning(pos);
10505 if(wrap.getStyle("position") == "static"){
10506 wrap.position("relative");
10508 this.clearPositioning('auto');
10510 wrap.dom.appendChild(this.dom);
10512 wrap.setXY(wrapXY);
10519 fxUnwrap : function(wrap, pos, o){
10520 this.clearPositioning();
10521 this.setPositioning(pos);
10523 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10529 getFxRestore : function(){
10530 var st = this.dom.style;
10531 return {pos: this.getPositioning(), width: st.width, height : st.height};
10535 afterFx : function(o){
10537 this.applyStyles(o.afterStyle);
10540 this.addClass(o.afterCls);
10542 if(o.remove === true){
10545 Roo.callback(o.callback, o.scope, [this]);
10547 this.fxQueue.shift();
10553 getFxEl : function(){ // support for composite element fx
10554 return Roo.get(this.dom);
10558 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10559 animType = animType || 'run';
10561 var anim = Roo.lib.Anim[animType](
10563 (opt.duration || defaultDur) || .35,
10564 (opt.easing || defaultEase) || 'easeOut',
10566 Roo.callback(cb, this);
10575 // backwords compat
10576 Roo.Fx.resize = Roo.Fx.scale;
10578 //When included, Roo.Fx is automatically applied to Element so that all basic
10579 //effects are available directly via the Element API
10580 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10582 * Ext JS Library 1.1.1
10583 * Copyright(c) 2006-2007, Ext JS, LLC.
10585 * Originally Released Under LGPL - original licence link has changed is not relivant.
10588 * <script type="text/javascript">
10593 * @class Roo.CompositeElement
10594 * Standard composite class. Creates a Roo.Element for every element in the collection.
10596 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10597 * actions will be performed on all the elements in this collection.</b>
10599 * All methods return <i>this</i> and can be chained.
10601 var els = Roo.select("#some-el div.some-class", true);
10602 // or select directly from an existing element
10603 var el = Roo.get('some-el');
10604 el.select('div.some-class', true);
10606 els.setWidth(100); // all elements become 100 width
10607 els.hide(true); // all elements fade out and hide
10609 els.setWidth(100).hide(true);
10612 Roo.CompositeElement = function(els){
10613 this.elements = [];
10614 this.addElements(els);
10616 Roo.CompositeElement.prototype = {
10618 addElements : function(els){
10619 if(!els) return this;
10620 if(typeof els == "string"){
10621 els = Roo.Element.selectorFunction(els);
10623 var yels = this.elements;
10624 var index = yels.length-1;
10625 for(var i = 0, len = els.length; i < len; i++) {
10626 yels[++index] = Roo.get(els[i]);
10632 * Clears this composite and adds the elements returned by the passed selector.
10633 * @param {String/Array} els A string CSS selector, an array of elements or an element
10634 * @return {CompositeElement} this
10636 fill : function(els){
10637 this.elements = [];
10643 * Filters this composite to only elements that match the passed selector.
10644 * @param {String} selector A string CSS selector
10645 * @return {CompositeElement} this
10647 filter : function(selector){
10649 this.each(function(el){
10650 if(el.is(selector)){
10651 els[els.length] = el.dom;
10658 invoke : function(fn, args){
10659 var els = this.elements;
10660 for(var i = 0, len = els.length; i < len; i++) {
10661 Roo.Element.prototype[fn].apply(els[i], args);
10666 * Adds elements to this composite.
10667 * @param {String/Array} els A string CSS selector, an array of elements or an element
10668 * @return {CompositeElement} this
10670 add : function(els){
10671 if(typeof els == "string"){
10672 this.addElements(Roo.Element.selectorFunction(els));
10673 }else if(els.length !== undefined){
10674 this.addElements(els);
10676 this.addElements([els]);
10681 * Calls the passed function passing (el, this, index) for each element in this composite.
10682 * @param {Function} fn The function to call
10683 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10684 * @return {CompositeElement} this
10686 each : function(fn, scope){
10687 var els = this.elements;
10688 for(var i = 0, len = els.length; i < len; i++){
10689 if(fn.call(scope || els[i], els[i], this, i) === false) {
10697 * Returns the Element object at the specified index
10698 * @param {Number} index
10699 * @return {Roo.Element}
10701 item : function(index){
10702 return this.elements[index] || null;
10706 * Returns the first Element
10707 * @return {Roo.Element}
10709 first : function(){
10710 return this.item(0);
10714 * Returns the last Element
10715 * @return {Roo.Element}
10718 return this.item(this.elements.length-1);
10722 * Returns the number of elements in this composite
10725 getCount : function(){
10726 return this.elements.length;
10730 * Returns true if this composite contains the passed element
10733 contains : function(el){
10734 return this.indexOf(el) !== -1;
10738 * Returns true if this composite contains the passed element
10741 indexOf : function(el){
10742 return this.elements.indexOf(Roo.get(el));
10747 * Removes the specified element(s).
10748 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
10749 * or an array of any of those.
10750 * @param {Boolean} removeDom (optional) True to also remove the element from the document
10751 * @return {CompositeElement} this
10753 removeElement : function(el, removeDom){
10754 if(el instanceof Array){
10755 for(var i = 0, len = el.length; i < len; i++){
10756 this.removeElement(el[i]);
10760 var index = typeof el == 'number' ? el : this.indexOf(el);
10763 var d = this.elements[index];
10767 d.parentNode.removeChild(d);
10770 this.elements.splice(index, 1);
10776 * Replaces the specified element with the passed element.
10777 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
10779 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
10780 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
10781 * @return {CompositeElement} this
10783 replaceElement : function(el, replacement, domReplace){
10784 var index = typeof el == 'number' ? el : this.indexOf(el);
10787 this.elements[index].replaceWith(replacement);
10789 this.elements.splice(index, 1, Roo.get(replacement))
10796 * Removes all elements.
10798 clear : function(){
10799 this.elements = [];
10803 Roo.CompositeElement.createCall = function(proto, fnName){
10804 if(!proto[fnName]){
10805 proto[fnName] = function(){
10806 return this.invoke(fnName, arguments);
10810 for(var fnName in Roo.Element.prototype){
10811 if(typeof Roo.Element.prototype[fnName] == "function"){
10812 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
10818 * Ext JS Library 1.1.1
10819 * Copyright(c) 2006-2007, Ext JS, LLC.
10821 * Originally Released Under LGPL - original licence link has changed is not relivant.
10824 * <script type="text/javascript">
10828 * @class Roo.CompositeElementLite
10829 * @extends Roo.CompositeElement
10830 * Flyweight composite class. Reuses the same Roo.Element for element operations.
10832 var els = Roo.select("#some-el div.some-class");
10833 // or select directly from an existing element
10834 var el = Roo.get('some-el');
10835 el.select('div.some-class');
10837 els.setWidth(100); // all elements become 100 width
10838 els.hide(true); // all elements fade out and hide
10840 els.setWidth(100).hide(true);
10841 </code></pre><br><br>
10842 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10843 * actions will be performed on all the elements in this collection.</b>
10845 Roo.CompositeElementLite = function(els){
10846 Roo.CompositeElementLite.superclass.constructor.call(this, els);
10847 this.el = new Roo.Element.Flyweight();
10849 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
10850 addElements : function(els){
10852 if(els instanceof Array){
10853 this.elements = this.elements.concat(els);
10855 var yels = this.elements;
10856 var index = yels.length-1;
10857 for(var i = 0, len = els.length; i < len; i++) {
10858 yels[++index] = els[i];
10864 invoke : function(fn, args){
10865 var els = this.elements;
10867 for(var i = 0, len = els.length; i < len; i++) {
10869 Roo.Element.prototype[fn].apply(el, args);
10874 * Returns a flyweight Element of the dom element object at the specified index
10875 * @param {Number} index
10876 * @return {Roo.Element}
10878 item : function(index){
10879 if(!this.elements[index]){
10882 this.el.dom = this.elements[index];
10886 // fixes scope with flyweight
10887 addListener : function(eventName, handler, scope, opt){
10888 var els = this.elements;
10889 for(var i = 0, len = els.length; i < len; i++) {
10890 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
10896 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
10897 * passed is the flyweight (shared) Roo.Element instance, so if you require a
10898 * a reference to the dom node, use el.dom.</b>
10899 * @param {Function} fn The function to call
10900 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10901 * @return {CompositeElement} this
10903 each : function(fn, scope){
10904 var els = this.elements;
10906 for(var i = 0, len = els.length; i < len; i++){
10908 if(fn.call(scope || el, el, this, i) === false){
10915 indexOf : function(el){
10916 return this.elements.indexOf(Roo.getDom(el));
10919 replaceElement : function(el, replacement, domReplace){
10920 var index = typeof el == 'number' ? el : this.indexOf(el);
10922 replacement = Roo.getDom(replacement);
10924 var d = this.elements[index];
10925 d.parentNode.insertBefore(replacement, d);
10926 d.parentNode.removeChild(d);
10928 this.elements.splice(index, 1, replacement);
10933 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
10937 * Ext JS Library 1.1.1
10938 * Copyright(c) 2006-2007, Ext JS, LLC.
10940 * Originally Released Under LGPL - original licence link has changed is not relivant.
10943 * <script type="text/javascript">
10949 * @class Roo.data.Connection
10950 * @extends Roo.util.Observable
10951 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
10952 * either to a configured URL, or to a URL specified at request time.<br><br>
10954 * Requests made by this class are asynchronous, and will return immediately. No data from
10955 * the server will be available to the statement immediately following the {@link #request} call.
10956 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
10958 * Note: If you are doing a file upload, you will not get a normal response object sent back to
10959 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
10960 * The response object is created using the innerHTML of the IFRAME's document as the responseText
10961 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
10962 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
10963 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
10964 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
10965 * standard DOM methods.
10967 * @param {Object} config a configuration object.
10969 Roo.data.Connection = function(config){
10970 Roo.apply(this, config);
10973 * @event beforerequest
10974 * Fires before a network request is made to retrieve a data object.
10975 * @param {Connection} conn This Connection object.
10976 * @param {Object} options The options config object passed to the {@link #request} method.
10978 "beforerequest" : true,
10980 * @event requestcomplete
10981 * Fires if the request was successfully completed.
10982 * @param {Connection} conn This Connection object.
10983 * @param {Object} response The XHR object containing the response data.
10984 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
10985 * @param {Object} options The options config object passed to the {@link #request} method.
10987 "requestcomplete" : true,
10989 * @event requestexception
10990 * Fires if an error HTTP status was returned from the server.
10991 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
10992 * @param {Connection} conn This Connection object.
10993 * @param {Object} response The XHR object containing the response data.
10994 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
10995 * @param {Object} options The options config object passed to the {@link #request} method.
10997 "requestexception" : true
10999 Roo.data.Connection.superclass.constructor.call(this);
11002 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11004 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11007 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11008 * extra parameters to each request made by this object. (defaults to undefined)
11011 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11012 * to each request made by this object. (defaults to undefined)
11015 * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11018 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11022 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11028 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11031 disableCaching: true,
11034 * Sends an HTTP request to a remote server.
11035 * @param {Object} options An object which may contain the following properties:<ul>
11036 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11037 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11038 * request, a url encoded string or a function to call to get either.</li>
11039 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11040 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11041 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11042 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11043 * <li>options {Object} The parameter to the request call.</li>
11044 * <li>success {Boolean} True if the request succeeded.</li>
11045 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11047 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11048 * The callback is passed the following parameters:<ul>
11049 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11050 * <li>options {Object} The parameter to the request call.</li>
11052 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11053 * The callback is passed the following parameters:<ul>
11054 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11055 * <li>options {Object} The parameter to the request call.</li>
11057 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11058 * for the callback function. Defaults to the browser window.</li>
11059 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11060 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11061 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11062 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11063 * params for the post data. Any params will be appended to the URL.</li>
11064 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11066 * @return {Number} transactionId
11068 request : function(o){
11069 if(this.fireEvent("beforerequest", this, o) !== false){
11072 if(typeof p == "function"){
11073 p = p.call(o.scope||window, o);
11075 if(typeof p == "object"){
11076 p = Roo.urlEncode(o.params);
11078 if(this.extraParams){
11079 var extras = Roo.urlEncode(this.extraParams);
11080 p = p ? (p + '&' + extras) : extras;
11083 var url = o.url || this.url;
11084 if(typeof url == 'function'){
11085 url = url.call(o.scope||window, o);
11089 var form = Roo.getDom(o.form);
11090 url = url || form.action;
11092 var enctype = form.getAttribute("enctype");
11093 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11094 return this.doFormUpload(o, p, url);
11096 var f = Roo.lib.Ajax.serializeForm(form);
11097 p = p ? (p + '&' + f) : f;
11100 var hs = o.headers;
11101 if(this.defaultHeaders){
11102 hs = Roo.apply(hs || {}, this.defaultHeaders);
11109 success: this.handleResponse,
11110 failure: this.handleFailure,
11112 argument: {options: o},
11113 timeout : this.timeout
11116 var method = o.method||this.method||(p ? "POST" : "GET");
11118 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11119 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11122 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11126 }else if(this.autoAbort !== false){
11130 if((method == 'GET' && p) || o.xmlData){
11131 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11134 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11135 return this.transId;
11137 Roo.callback(o.callback, o.scope, [o, null, null]);
11143 * Determine whether this object has a request outstanding.
11144 * @param {Number} transactionId (Optional) defaults to the last transaction
11145 * @return {Boolean} True if there is an outstanding request.
11147 isLoading : function(transId){
11149 return Roo.lib.Ajax.isCallInProgress(transId);
11151 return this.transId ? true : false;
11156 * Aborts any outstanding request.
11157 * @param {Number} transactionId (Optional) defaults to the last transaction
11159 abort : function(transId){
11160 if(transId || this.isLoading()){
11161 Roo.lib.Ajax.abort(transId || this.transId);
11166 handleResponse : function(response){
11167 this.transId = false;
11168 var options = response.argument.options;
11169 response.argument = options ? options.argument : null;
11170 this.fireEvent("requestcomplete", this, response, options);
11171 Roo.callback(options.success, options.scope, [response, options]);
11172 Roo.callback(options.callback, options.scope, [options, true, response]);
11176 handleFailure : function(response, e){
11177 this.transId = false;
11178 var options = response.argument.options;
11179 response.argument = options ? options.argument : null;
11180 this.fireEvent("requestexception", this, response, options, e);
11181 Roo.callback(options.failure, options.scope, [response, options]);
11182 Roo.callback(options.callback, options.scope, [options, false, response]);
11186 doFormUpload : function(o, ps, url){
11188 var frame = document.createElement('iframe');
11191 frame.className = 'x-hidden';
11193 frame.src = Roo.SSL_SECURE_URL;
11195 document.body.appendChild(frame);
11198 document.frames[id].name = id;
11201 var form = Roo.getDom(o.form);
11203 form.method = 'POST';
11204 form.enctype = form.encoding = 'multipart/form-data';
11210 if(ps){ // add dynamic params
11212 ps = Roo.urlDecode(ps, false);
11214 if(ps.hasOwnProperty(k)){
11215 hd = document.createElement('input');
11216 hd.type = 'hidden';
11219 form.appendChild(hd);
11226 var r = { // bogus response object
11231 r.argument = o ? o.argument : null;
11236 doc = frame.contentWindow.document;
11238 doc = (frame.contentDocument || window.frames[id].document);
11240 if(doc && doc.body){
11241 r.responseText = doc.body.innerHTML;
11243 if(doc && doc.XMLDocument){
11244 r.responseXML = doc.XMLDocument;
11246 r.responseXML = doc;
11253 Roo.EventManager.removeListener(frame, 'load', cb, this);
11255 this.fireEvent("requestcomplete", this, r, o);
11256 Roo.callback(o.success, o.scope, [r, o]);
11257 Roo.callback(o.callback, o.scope, [o, true, r]);
11259 setTimeout(function(){document.body.removeChild(frame);}, 100);
11262 Roo.EventManager.on(frame, 'load', cb, this);
11265 if(hiddens){ // remove dynamic params
11266 for(var i = 0, len = hiddens.length; i < len; i++){
11267 form.removeChild(hiddens[i]);
11275 * @extends Roo.data.Connection
11276 * Global Ajax request class.
11280 Roo.Ajax = new Roo.data.Connection({
11283 * @cfg {String} url @hide
11286 * @cfg {Object} extraParams @hide
11289 * @cfg {Object} defaultHeaders @hide
11292 * @cfg {String} method (Optional) @hide
11295 * @cfg {Number} timeout (Optional) @hide
11298 * @cfg {Boolean} autoAbort (Optional) @hide
11302 * @cfg {Boolean} disableCaching (Optional) @hide
11306 * @property disableCaching
11307 * True to add a unique cache-buster param to GET requests. (defaults to true)
11312 * The default URL to be used for requests to the server. (defaults to undefined)
11316 * @property extraParams
11317 * An object containing properties which are used as
11318 * extra parameters to each request made by this object. (defaults to undefined)
11322 * @property defaultHeaders
11323 * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11328 * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11332 * @property timeout
11333 * The timeout in milliseconds to be used for requests. (defaults to 30000)
11338 * @property autoAbort
11339 * Whether a new request should abort any pending requests. (defaults to false)
11345 * Serialize the passed form into a url encoded string
11346 * @param {String/HTMLElement} form
11349 serializeForm : function(form){
11350 return Roo.lib.Ajax.serializeForm(form);
11354 * Ext JS Library 1.1.1
11355 * Copyright(c) 2006-2007, Ext JS, LLC.
11357 * Originally Released Under LGPL - original licence link has changed is not relivant.
11360 * <script type="text/javascript">
11365 * @extends Roo.data.Connection
11366 * Global Ajax request class.
11368 * @instanceOf Roo.data.Connection
11370 Roo.Ajax = new Roo.data.Connection({
11379 * @cfg {String} url @hide
11382 * @cfg {Object} extraParams @hide
11385 * @cfg {Object} defaultHeaders @hide
11388 * @cfg {String} method (Optional) @hide
11391 * @cfg {Number} timeout (Optional) @hide
11394 * @cfg {Boolean} autoAbort (Optional) @hide
11398 * @cfg {Boolean} disableCaching (Optional) @hide
11402 * @property disableCaching
11403 * True to add a unique cache-buster param to GET requests. (defaults to true)
11408 * The default URL to be used for requests to the server. (defaults to undefined)
11412 * @property extraParams
11413 * An object containing properties which are used as
11414 * extra parameters to each request made by this object. (defaults to undefined)
11418 * @property defaultHeaders
11419 * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11424 * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11428 * @property timeout
11429 * The timeout in milliseconds to be used for requests. (defaults to 30000)
11434 * @property autoAbort
11435 * Whether a new request should abort any pending requests. (defaults to false)
11441 * Serialize the passed form into a url encoded string
11442 * @param {String/HTMLElement} form
11445 serializeForm : function(form){
11446 return Roo.lib.Ajax.serializeForm(form);
11450 * Ext JS Library 1.1.1
11451 * Copyright(c) 2006-2007, Ext JS, LLC.
11453 * Originally Released Under LGPL - original licence link has changed is not relivant.
11456 * <script type="text/javascript">
11461 * @class Roo.UpdateManager
11462 * @extends Roo.util.Observable
11463 * Provides AJAX-style update for Element object.<br><br>
11466 * // Get it from a Roo.Element object
11467 * var el = Roo.get("foo");
11468 * var mgr = el.getUpdateManager();
11469 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11471 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11473 * // or directly (returns the same UpdateManager instance)
11474 * var mgr = new Roo.UpdateManager("myElementId");
11475 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11476 * mgr.on("update", myFcnNeedsToKnow);
11478 // short handed call directly from the element object
11479 Roo.get("foo").load({
11483 text: "Loading Foo..."
11487 * Create new UpdateManager directly.
11488 * @param {String/HTMLElement/Roo.Element} el The element to update
11489 * @param {Boolean} forceNew (optional) By default the constructor checks to see if the passed element already has an UpdateManager and if it does it returns the same instance. This will skip that check (useful for extending this class).
11491 Roo.UpdateManager = function(el, forceNew){
11493 if(!forceNew && el.updateManager){
11494 return el.updateManager;
11497 * The Element object
11498 * @type Roo.Element
11502 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11505 this.defaultUrl = null;
11509 * @event beforeupdate
11510 * Fired before an update is made, return false from your handler and the update is cancelled.
11511 * @param {Roo.Element} el
11512 * @param {String/Object/Function} url
11513 * @param {String/Object} params
11515 "beforeupdate": true,
11518 * Fired after successful update is made.
11519 * @param {Roo.Element} el
11520 * @param {Object} oResponseObject The response Object
11525 * Fired on update failure.
11526 * @param {Roo.Element} el
11527 * @param {Object} oResponseObject The response Object
11531 var d = Roo.UpdateManager.defaults;
11533 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11536 this.sslBlankUrl = d.sslBlankUrl;
11538 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11541 this.disableCaching = d.disableCaching;
11543 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11546 this.indicatorText = d.indicatorText;
11548 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11551 this.showLoadIndicator = d.showLoadIndicator;
11553 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11556 this.timeout = d.timeout;
11559 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11562 this.loadScripts = d.loadScripts;
11565 * Transaction object of current executing transaction
11567 this.transaction = null;
11572 this.autoRefreshProcId = null;
11574 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11577 this.refreshDelegate = this.refresh.createDelegate(this);
11579 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11582 this.updateDelegate = this.update.createDelegate(this);
11584 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11587 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11591 this.successDelegate = this.processSuccess.createDelegate(this);
11595 this.failureDelegate = this.processFailure.createDelegate(this);
11597 if(!this.renderer){
11599 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11601 this.renderer = new Roo.UpdateManager.BasicRenderer();
11604 Roo.UpdateManager.superclass.constructor.call(this);
11607 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11609 * Get the Element this UpdateManager is bound to
11610 * @return {Roo.Element} The element
11612 getEl : function(){
11616 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11617 * @param {Object/String/Function} url The url for this request or a function to call to get the url or a config object containing any of the following options:
11620 url: "your-url.php",<br/>
11621 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11622 callback: yourFunction,<br/>
11623 scope: yourObject, //(optional scope) <br/>
11624 discardUrl: false, <br/>
11625 nocache: false,<br/>
11626 text: "Loading...",<br/>
11628 scripts: false<br/>
11631 * The only required property is url. The optional properties nocache, text and scripts
11632 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11633 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "param1=1&param2=2" or an object {param1: 1, param2: 2}
11634 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11635 * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used url. If true, it will not store the url.
11637 update : function(url, params, callback, discardUrl){
11638 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11639 var method = this.method, cfg;
11640 if(typeof url == "object"){ // must be config object
11643 params = params || cfg.params;
11644 callback = callback || cfg.callback;
11645 discardUrl = discardUrl || cfg.discardUrl;
11646 if(callback && cfg.scope){
11647 callback = callback.createDelegate(cfg.scope);
11649 if(typeof cfg.method != "undefined"){method = cfg.method;};
11650 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11651 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11652 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11653 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11655 this.showLoading();
11657 this.defaultUrl = url;
11659 if(typeof url == "function"){
11660 url = url.call(this);
11663 method = method || (params ? "POST" : "GET");
11664 if(method == "GET"){
11665 url = this.prepareUrl(url);
11668 var o = Roo.apply(cfg ||{}, {
11671 success: this.successDelegate,
11672 failure: this.failureDelegate,
11673 callback: undefined,
11674 timeout: (this.timeout*1000),
11675 argument: {"url": url, "form": null, "callback": callback, "params": params}
11678 this.transaction = Roo.Ajax.request(o);
11683 * Performs an async form post, updating this element with the response. If the form has the attribute enctype="multipart/form-data", it assumes it's a file upload.
11684 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11685 * @param {String/HTMLElement} form The form Id or form element
11686 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11687 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11688 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11690 formUpdate : function(form, url, reset, callback){
11691 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11692 if(typeof url == "function"){
11693 url = url.call(this);
11695 form = Roo.getDom(form);
11696 this.transaction = Roo.Ajax.request({
11699 success: this.successDelegate,
11700 failure: this.failureDelegate,
11701 timeout: (this.timeout*1000),
11702 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11704 this.showLoading.defer(1, this);
11709 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11710 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11712 refresh : function(callback){
11713 if(this.defaultUrl == null){
11716 this.update(this.defaultUrl, null, callback, true);
11720 * Set this element to auto refresh.
11721 * @param {Number} interval How often to update (in seconds).
11722 * @param {String/Function} url (optional) The url for this request or a function to call to get the url (Defaults to the last used url)
11723 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "¶m1=1¶m2=2" or as an object {param1: 1, param2: 2}
11724 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11725 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11727 startAutoRefresh : function(interval, url, params, callback, refreshNow){
11729 this.update(url || this.defaultUrl, params, callback, true);
11731 if(this.autoRefreshProcId){
11732 clearInterval(this.autoRefreshProcId);
11734 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11738 * Stop auto refresh on this element.
11740 stopAutoRefresh : function(){
11741 if(this.autoRefreshProcId){
11742 clearInterval(this.autoRefreshProcId);
11743 delete this.autoRefreshProcId;
11747 isAutoRefreshing : function(){
11748 return this.autoRefreshProcId ? true : false;
11751 * Called to update the element to "Loading" state. Override to perform custom action.
11753 showLoading : function(){
11754 if(this.showLoadIndicator){
11755 this.el.update(this.indicatorText);
11760 * Adds unique parameter to query string if disableCaching = true
11763 prepareUrl : function(url){
11764 if(this.disableCaching){
11765 var append = "_dc=" + (new Date().getTime());
11766 if(url.indexOf("?") !== -1){
11767 url += "&" + append;
11769 url += "?" + append;
11778 processSuccess : function(response){
11779 this.transaction = null;
11780 if(response.argument.form && response.argument.reset){
11781 try{ // put in try/catch since some older FF releases had problems with this
11782 response.argument.form.reset();
11785 if(this.loadScripts){
11786 this.renderer.render(this.el, response, this,
11787 this.updateComplete.createDelegate(this, [response]));
11789 this.renderer.render(this.el, response, this);
11790 this.updateComplete(response);
11794 updateComplete : function(response){
11795 this.fireEvent("update", this.el, response);
11796 if(typeof response.argument.callback == "function"){
11797 response.argument.callback(this.el, true, response);
11804 processFailure : function(response){
11805 this.transaction = null;
11806 this.fireEvent("failure", this.el, response);
11807 if(typeof response.argument.callback == "function"){
11808 response.argument.callback(this.el, false, response);
11813 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
11814 * @param {Object} renderer The object implementing the render() method
11816 setRenderer : function(renderer){
11817 this.renderer = renderer;
11820 getRenderer : function(){
11821 return this.renderer;
11825 * Set the defaultUrl used for updates
11826 * @param {String/Function} defaultUrl The url or a function to call to get the url
11828 setDefaultUrl : function(defaultUrl){
11829 this.defaultUrl = defaultUrl;
11833 * Aborts the executing transaction
11835 abort : function(){
11836 if(this.transaction){
11837 Roo.Ajax.abort(this.transaction);
11842 * Returns true if an update is in progress
11843 * @return {Boolean}
11845 isUpdating : function(){
11846 if(this.transaction){
11847 return Roo.Ajax.isLoading(this.transaction);
11854 * @class Roo.UpdateManager.defaults
11855 * @static (not really - but it helps the doc tool)
11856 * The defaults collection enables customizing the default properties of UpdateManager
11858 Roo.UpdateManager.defaults = {
11860 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
11866 * True to process scripts by default (Defaults to false).
11869 loadScripts : false,
11872 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
11875 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
11877 * Whether to append unique parameter on get request to disable caching (Defaults to false).
11880 disableCaching : false,
11882 * Whether to show indicatorText when loading (Defaults to true).
11885 showLoadIndicator : true,
11887 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
11890 indicatorText : '<div class="loading-indicator">Loading...</div>'
11894 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
11896 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
11897 * @param {String/HTMLElement/Roo.Element} el The element to update
11898 * @param {String} url The url
11899 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
11900 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
11903 * @member Roo.UpdateManager
11905 Roo.UpdateManager.updateElement = function(el, url, params, options){
11906 var um = Roo.get(el, true).getUpdateManager();
11907 Roo.apply(um, options);
11908 um.update(url, params, options ? options.callback : null);
11910 // alias for backwards compat
11911 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
11913 * @class Roo.UpdateManager.BasicRenderer
11914 * Default Content renderer. Updates the elements innerHTML with the responseText.
11916 Roo.UpdateManager.BasicRenderer = function(){};
11918 Roo.UpdateManager.BasicRenderer.prototype = {
11920 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
11921 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
11922 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
11923 * @param {Roo.Element} el The element being rendered
11924 * @param {Object} response The YUI Connect response object
11925 * @param {UpdateManager} updateManager The calling update manager
11926 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
11928 render : function(el, response, updateManager, callback){
11929 el.update(response.responseText, updateManager.loadScripts, callback);
11934 * Ext JS Library 1.1.1
11935 * Copyright(c) 2006-2007, Ext JS, LLC.
11937 * Originally Released Under LGPL - original licence link has changed is not relivant.
11940 * <script type="text/javascript">
11944 * @class Roo.util.DelayedTask
11945 * Provides a convenient method of performing setTimeout where a new
11946 * timeout cancels the old timeout. An example would be performing validation on a keypress.
11947 * You can use this class to buffer
11948 * the keypress events for a certain number of milliseconds, and perform only if they stop
11949 * for that amount of time.
11950 * @constructor The parameters to this constructor serve as defaults and are not required.
11951 * @param {Function} fn (optional) The default function to timeout
11952 * @param {Object} scope (optional) The default scope of that timeout
11953 * @param {Array} args (optional) The default Array of arguments
11955 Roo.util.DelayedTask = function(fn, scope, args){
11956 var id = null, d, t;
11958 var call = function(){
11959 var now = new Date().getTime();
11963 fn.apply(scope, args || []);
11967 * Cancels any pending timeout and queues a new one
11968 * @param {Number} delay The milliseconds to delay
11969 * @param {Function} newFn (optional) Overrides function passed to constructor
11970 * @param {Object} newScope (optional) Overrides scope passed to constructor
11971 * @param {Array} newArgs (optional) Overrides args passed to constructor
11973 this.delay = function(delay, newFn, newScope, newArgs){
11974 if(id && delay != d){
11978 t = new Date().getTime();
11980 scope = newScope || scope;
11981 args = newArgs || args;
11983 id = setInterval(call, d);
11988 * Cancel the last queued timeout
11990 this.cancel = function(){
11998 * Ext JS Library 1.1.1
11999 * Copyright(c) 2006-2007, Ext JS, LLC.
12001 * Originally Released Under LGPL - original licence link has changed is not relivant.
12004 * <script type="text/javascript">
12008 Roo.util.TaskRunner = function(interval){
12009 interval = interval || 10;
12010 var tasks = [], removeQueue = [];
12012 var running = false;
12014 var stopThread = function(){
12020 var startThread = function(){
12023 id = setInterval(runTasks, interval);
12027 var removeTask = function(task){
12028 removeQueue.push(task);
12034 var runTasks = function(){
12035 if(removeQueue.length > 0){
12036 for(var i = 0, len = removeQueue.length; i < len; i++){
12037 tasks.remove(removeQueue[i]);
12040 if(tasks.length < 1){
12045 var now = new Date().getTime();
12046 for(var i = 0, len = tasks.length; i < len; ++i){
12048 var itime = now - t.taskRunTime;
12049 if(t.interval <= itime){
12050 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12051 t.taskRunTime = now;
12052 if(rt === false || t.taskRunCount === t.repeat){
12057 if(t.duration && t.duration <= (now - t.taskStartTime)){
12064 * Queues a new task.
12065 * @param {Object} task
12067 this.start = function(task){
12069 task.taskStartTime = new Date().getTime();
12070 task.taskRunTime = 0;
12071 task.taskRunCount = 0;
12076 this.stop = function(task){
12081 this.stopAll = function(){
12083 for(var i = 0, len = tasks.length; i < len; i++){
12084 if(tasks[i].onStop){
12093 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12095 * Ext JS Library 1.1.1
12096 * Copyright(c) 2006-2007, Ext JS, LLC.
12098 * Originally Released Under LGPL - original licence link has changed is not relivant.
12101 * <script type="text/javascript">
12106 * @class Roo.util.MixedCollection
12107 * @extends Roo.util.Observable
12108 * A Collection class that maintains both numeric indexes and keys and exposes events.
12110 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12111 * collection (defaults to false)
12112 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12113 * and return the key value for that item. This is used when available to look up the key on items that
12114 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12115 * equivalent to providing an implementation for the {@link #getKey} method.
12117 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12125 * Fires when the collection is cleared.
12130 * Fires when an item is added to the collection.
12131 * @param {Number} index The index at which the item was added.
12132 * @param {Object} o The item added.
12133 * @param {String} key The key associated with the added item.
12138 * Fires when an item is replaced in the collection.
12139 * @param {String} key he key associated with the new added.
12140 * @param {Object} old The item being replaced.
12141 * @param {Object} new The new item.
12146 * Fires when an item is removed from the collection.
12147 * @param {Object} o The item being removed.
12148 * @param {String} key (optional) The key associated with the removed item.
12153 this.allowFunctions = allowFunctions === true;
12155 this.getKey = keyFn;
12157 Roo.util.MixedCollection.superclass.constructor.call(this);
12160 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12161 allowFunctions : false,
12164 * Adds an item to the collection.
12165 * @param {String} key The key to associate with the item
12166 * @param {Object} o The item to add.
12167 * @return {Object} The item added.
12169 add : function(key, o){
12170 if(arguments.length == 1){
12172 key = this.getKey(o);
12174 if(typeof key == "undefined" || key === null){
12176 this.items.push(o);
12177 this.keys.push(null);
12179 var old = this.map[key];
12181 return this.replace(key, o);
12184 this.items.push(o);
12186 this.keys.push(key);
12188 this.fireEvent("add", this.length-1, o, key);
12193 * MixedCollection has a generic way to fetch keys if you implement getKey.
12196 var mc = new Roo.util.MixedCollection();
12197 mc.add(someEl.dom.id, someEl);
12198 mc.add(otherEl.dom.id, otherEl);
12202 var mc = new Roo.util.MixedCollection();
12203 mc.getKey = function(el){
12209 // or via the constructor
12210 var mc = new Roo.util.MixedCollection(false, function(el){
12216 * @param o {Object} The item for which to find the key.
12217 * @return {Object} The key for the passed item.
12219 getKey : function(o){
12224 * Replaces an item in the collection.
12225 * @param {String} key The key associated with the item to replace, or the item to replace.
12226 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12227 * @return {Object} The new item.
12229 replace : function(key, o){
12230 if(arguments.length == 1){
12232 key = this.getKey(o);
12234 var old = this.item(key);
12235 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12236 return this.add(key, o);
12238 var index = this.indexOfKey(key);
12239 this.items[index] = o;
12241 this.fireEvent("replace", key, old, o);
12246 * Adds all elements of an Array or an Object to the collection.
12247 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12248 * an Array of values, each of which are added to the collection.
12250 addAll : function(objs){
12251 if(arguments.length > 1 || objs instanceof Array){
12252 var args = arguments.length > 1 ? arguments : objs;
12253 for(var i = 0, len = args.length; i < len; i++){
12257 for(var key in objs){
12258 if(this.allowFunctions || typeof objs[key] != "function"){
12259 this.add(key, objs[key]);
12266 * Executes the specified function once for every item in the collection, passing each
12267 * item as the first and only parameter. returning false from the function will stop the iteration.
12268 * @param {Function} fn The function to execute for each item.
12269 * @param {Object} scope (optional) The scope in which to execute the function.
12271 each : function(fn, scope){
12272 var items = [].concat(this.items); // each safe for removal
12273 for(var i = 0, len = items.length; i < len; i++){
12274 if(fn.call(scope || items[i], items[i], i, len) === false){
12281 * Executes the specified function once for every key in the collection, passing each
12282 * key, and its associated item as the first two parameters.
12283 * @param {Function} fn The function to execute for each item.
12284 * @param {Object} scope (optional) The scope in which to execute the function.
12286 eachKey : function(fn, scope){
12287 for(var i = 0, len = this.keys.length; i < len; i++){
12288 fn.call(scope || window, this.keys[i], this.items[i], i, len);
12293 * Returns the first item in the collection which elicits a true return value from the
12294 * passed selection function.
12295 * @param {Function} fn The selection function to execute for each item.
12296 * @param {Object} scope (optional) The scope in which to execute the function.
12297 * @return {Object} The first item in the collection which returned true from the selection function.
12299 find : function(fn, scope){
12300 for(var i = 0, len = this.items.length; i < len; i++){
12301 if(fn.call(scope || window, this.items[i], this.keys[i])){
12302 return this.items[i];
12309 * Inserts an item at the specified index in the collection.
12310 * @param {Number} index The index to insert the item at.
12311 * @param {String} key The key to associate with the new item, or the item itself.
12312 * @param {Object} o (optional) If the second parameter was a key, the new item.
12313 * @return {Object} The item inserted.
12315 insert : function(index, key, o){
12316 if(arguments.length == 2){
12318 key = this.getKey(o);
12320 if(index >= this.length){
12321 return this.add(key, o);
12324 this.items.splice(index, 0, o);
12325 if(typeof key != "undefined" && key != null){
12328 this.keys.splice(index, 0, key);
12329 this.fireEvent("add", index, o, key);
12334 * Removed an item from the collection.
12335 * @param {Object} o The item to remove.
12336 * @return {Object} The item removed.
12338 remove : function(o){
12339 return this.removeAt(this.indexOf(o));
12343 * Remove an item from a specified index in the collection.
12344 * @param {Number} index The index within the collection of the item to remove.
12346 removeAt : function(index){
12347 if(index < this.length && index >= 0){
12349 var o = this.items[index];
12350 this.items.splice(index, 1);
12351 var key = this.keys[index];
12352 if(typeof key != "undefined"){
12353 delete this.map[key];
12355 this.keys.splice(index, 1);
12356 this.fireEvent("remove", o, key);
12361 * Removed an item associated with the passed key fom the collection.
12362 * @param {String} key The key of the item to remove.
12364 removeKey : function(key){
12365 return this.removeAt(this.indexOfKey(key));
12369 * Returns the number of items in the collection.
12370 * @return {Number} the number of items in the collection.
12372 getCount : function(){
12373 return this.length;
12377 * Returns index within the collection of the passed Object.
12378 * @param {Object} o The item to find the index of.
12379 * @return {Number} index of the item.
12381 indexOf : function(o){
12382 if(!this.items.indexOf){
12383 for(var i = 0, len = this.items.length; i < len; i++){
12384 if(this.items[i] == o) return i;
12388 return this.items.indexOf(o);
12393 * Returns index within the collection of the passed key.
12394 * @param {String} key The key to find the index of.
12395 * @return {Number} index of the key.
12397 indexOfKey : function(key){
12398 if(!this.keys.indexOf){
12399 for(var i = 0, len = this.keys.length; i < len; i++){
12400 if(this.keys[i] == key) return i;
12404 return this.keys.indexOf(key);
12409 * Returns the item associated with the passed key OR index. Key has priority over index.
12410 * @param {String/Number} key The key or index of the item.
12411 * @return {Object} The item associated with the passed key.
12413 item : function(key){
12414 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
12415 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
12419 * Returns the item at the specified index.
12420 * @param {Number} index The index of the item.
12423 itemAt : function(index){
12424 return this.items[index];
12428 * Returns the item associated with the passed key.
12429 * @param {String/Number} key The key of the item.
12430 * @return {Object} The item associated with the passed key.
12432 key : function(key){
12433 return this.map[key];
12437 * Returns true if the collection contains the passed Object as an item.
12438 * @param {Object} o The Object to look for in the collection.
12439 * @return {Boolean} True if the collection contains the Object as an item.
12441 contains : function(o){
12442 return this.indexOf(o) != -1;
12446 * Returns true if the collection contains the passed Object as a key.
12447 * @param {String} key The key to look for in the collection.
12448 * @return {Boolean} True if the collection contains the Object as a key.
12450 containsKey : function(key){
12451 return typeof this.map[key] != "undefined";
12455 * Removes all items from the collection.
12457 clear : function(){
12462 this.fireEvent("clear");
12466 * Returns the first item in the collection.
12467 * @return {Object} the first item in the collection..
12469 first : function(){
12470 return this.items[0];
12474 * Returns the last item in the collection.
12475 * @return {Object} the last item in the collection..
12478 return this.items[this.length-1];
12481 _sort : function(property, dir, fn){
12482 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
12483 fn = fn || function(a, b){
12486 var c = [], k = this.keys, items = this.items;
12487 for(var i = 0, len = items.length; i < len; i++){
12488 c[c.length] = {key: k[i], value: items[i], index: i};
12490 c.sort(function(a, b){
12491 var v = fn(a[property], b[property]) * dsc;
12493 v = (a.index < b.index ? -1 : 1);
12497 for(var i = 0, len = c.length; i < len; i++){
12498 items[i] = c[i].value;
12501 this.fireEvent("sort", this);
12505 * Sorts this collection with the passed comparison function
12506 * @param {String} direction (optional) "ASC" or "DESC"
12507 * @param {Function} fn (optional) comparison function
12509 sort : function(dir, fn){
12510 this._sort("value", dir, fn);
12514 * Sorts this collection by keys
12515 * @param {String} direction (optional) "ASC" or "DESC"
12516 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
12518 keySort : function(dir, fn){
12519 this._sort("key", dir, fn || function(a, b){
12520 return String(a).toUpperCase()-String(b).toUpperCase();
12525 * Returns a range of items in this collection
12526 * @param {Number} startIndex (optional) defaults to 0
12527 * @param {Number} endIndex (optional) default to the last item
12528 * @return {Array} An array of items
12530 getRange : function(start, end){
12531 var items = this.items;
12532 if(items.length < 1){
12535 start = start || 0;
12536 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
12539 for(var i = start; i <= end; i++) {
12540 r[r.length] = items[i];
12543 for(var i = start; i >= end; i--) {
12544 r[r.length] = items[i];
12551 * Filter the <i>objects</i> in this collection by a specific property.
12552 * Returns a new collection that has been filtered.
12553 * @param {String} property A property on your objects
12554 * @param {String/RegExp} value Either string that the property values
12555 * should start with or a RegExp to test against the property
12556 * @return {MixedCollection} The new filtered collection
12558 filter : function(property, value){
12559 if(!value.exec){ // not a regex
12560 value = String(value);
12561 if(value.length == 0){
12562 return this.clone();
12564 value = new RegExp("^" + Roo.escapeRe(value), "i");
12566 return this.filterBy(function(o){
12567 return o && value.test(o[property]);
12572 * Filter by a function. * Returns a new collection that has been filtered.
12573 * The passed function will be called with each
12574 * object in the collection. If the function returns true, the value is included
12575 * otherwise it is filtered.
12576 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
12577 * @param {Object} scope (optional) The scope of the function (defaults to this)
12578 * @return {MixedCollection} The new filtered collection
12580 filterBy : function(fn, scope){
12581 var r = new Roo.util.MixedCollection();
12582 r.getKey = this.getKey;
12583 var k = this.keys, it = this.items;
12584 for(var i = 0, len = it.length; i < len; i++){
12585 if(fn.call(scope||this, it[i], k[i])){
12586 r.add(k[i], it[i]);
12593 * Creates a duplicate of this collection
12594 * @return {MixedCollection}
12596 clone : function(){
12597 var r = new Roo.util.MixedCollection();
12598 var k = this.keys, it = this.items;
12599 for(var i = 0, len = it.length; i < len; i++){
12600 r.add(k[i], it[i]);
12602 r.getKey = this.getKey;
12607 * Returns the item associated with the passed key or index.
12609 * @param {String/Number} key The key or index of the item.
12610 * @return {Object} The item associated with the passed key.
12612 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
12614 * Ext JS Library 1.1.1
12615 * Copyright(c) 2006-2007, Ext JS, LLC.
12617 * Originally Released Under LGPL - original licence link has changed is not relivant.
12620 * <script type="text/javascript">
12623 * @class Roo.util.JSON
12624 * Modified version of Douglas Crockford"s json.js that doesn"t
12625 * mess with the Object prototype
12626 * http://www.json.org/js.html
12629 Roo.util.JSON = new (function(){
12630 var useHasOwn = {}.hasOwnProperty ? true : false;
12632 // crashes Safari in some instances
12633 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
12635 var pad = function(n) {
12636 return n < 10 ? "0" + n : n;
12649 var encodeString = function(s){
12650 if (/["\\\x00-\x1f]/.test(s)) {
12651 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
12656 c = b.charCodeAt();
12658 Math.floor(c / 16).toString(16) +
12659 (c % 16).toString(16);
12662 return '"' + s + '"';
12665 var encodeArray = function(o){
12666 var a = ["["], b, i, l = o.length, v;
12667 for (i = 0; i < l; i += 1) {
12669 switch (typeof v) {
12678 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
12686 var encodeDate = function(o){
12687 return '"' + o.getFullYear() + "-" +
12688 pad(o.getMonth() + 1) + "-" +
12689 pad(o.getDate()) + "T" +
12690 pad(o.getHours()) + ":" +
12691 pad(o.getMinutes()) + ":" +
12692 pad(o.getSeconds()) + '"';
12696 * Encodes an Object, Array or other value
12697 * @param {Mixed} o The variable to encode
12698 * @return {String} The JSON string
12700 this.encode = function(o){
12701 if(typeof o == "undefined" || o === null){
12703 }else if(o instanceof Array){
12704 return encodeArray(o);
12705 }else if(o instanceof Date){
12706 return encodeDate(o);
12707 }else if(typeof o == "string"){
12708 return encodeString(o);
12709 }else if(typeof o == "number"){
12710 return isFinite(o) ? String(o) : "null";
12711 }else if(typeof o == "boolean"){
12714 var a = ["{"], b, i, v;
12716 if(!useHasOwn || o.hasOwnProperty(i)) {
12718 switch (typeof v) {
12727 a.push(this.encode(i), ":",
12728 v === null ? "null" : this.encode(v));
12739 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
12740 * @param {String} json The JSON string
12741 * @return {Object} The resulting object
12743 this.decode = function(json){
12747 return eval("(" + json + ')');
12751 * Shorthand for {@link Roo.util.JSON#encode}
12752 * @member Roo encode
12754 Roo.encode = Roo.util.JSON.encode;
12756 * Shorthand for {@link Roo.util.JSON#decode}
12757 * @member Roo decode
12759 Roo.decode = Roo.util.JSON.decode;
12762 * Ext JS Library 1.1.1
12763 * Copyright(c) 2006-2007, Ext JS, LLC.
12765 * Originally Released Under LGPL - original licence link has changed is not relivant.
12768 * <script type="text/javascript">
12772 * @class Roo.util.Format
12773 * Reusable data formatting functions
12776 Roo.util.Format = function(){
12777 var trimRe = /^\s+|\s+$/g;
12780 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
12781 * @param {String} value The string to truncate
12782 * @param {Number} length The maximum length to allow before truncating
12783 * @return {String} The converted text
12785 ellipsis : function(value, len){
12786 if(value && value.length > len){
12787 return value.substr(0, len-3)+"...";
12793 * Checks a reference and converts it to empty string if it is undefined
12794 * @param {Mixed} value Reference to check
12795 * @return {Mixed} Empty string if converted, otherwise the original value
12797 undef : function(value){
12798 return typeof value != "undefined" ? value : "";
12802 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
12803 * @param {String} value The string to encode
12804 * @return {String} The encoded text
12806 htmlEncode : function(value){
12807 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
12811 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
12812 * @param {String} value The string to decode
12813 * @return {String} The decoded text
12815 htmlDecode : function(value){
12816 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
12820 * Trims any whitespace from either side of a string
12821 * @param {String} value The text to trim
12822 * @return {String} The trimmed text
12824 trim : function(value){
12825 return String(value).replace(trimRe, "");
12829 * Returns a substring from within an original string
12830 * @param {String} value The original text
12831 * @param {Number} start The start index of the substring
12832 * @param {Number} length The length of the substring
12833 * @return {String} The substring
12835 substr : function(value, start, length){
12836 return String(value).substr(start, length);
12840 * Converts a string to all lower case letters
12841 * @param {String} value The text to convert
12842 * @return {String} The converted text
12844 lowercase : function(value){
12845 return String(value).toLowerCase();
12849 * Converts a string to all upper case letters
12850 * @param {String} value The text to convert
12851 * @return {String} The converted text
12853 uppercase : function(value){
12854 return String(value).toUpperCase();
12858 * Converts the first character only of a string to upper case
12859 * @param {String} value The text to convert
12860 * @return {String} The converted text
12862 capitalize : function(value){
12863 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
12867 call : function(value, fn){
12868 if(arguments.length > 2){
12869 var args = Array.prototype.slice.call(arguments, 2);
12870 args.unshift(value);
12872 return /** eval:var:value */ eval(fn).apply(window, args);
12874 /** eval:var:value */
12875 return /** eval:var:value */ eval(fn).call(window, value);
12880 * Format a number as US currency
12881 * @param {Number/String} value The numeric value to format
12882 * @return {String} The formatted currency string
12884 usMoney : function(v){
12885 v = (Math.round((v-0)*100))/100;
12886 v = (v == Math.floor(v)) ? v + ".00" : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
12888 var ps = v.split('.');
12890 var sub = ps[1] ? '.'+ ps[1] : '.00';
12891 var r = /(\d+)(\d{3})/;
12892 while (r.test(whole)) {
12893 whole = whole.replace(r, '$1' + ',' + '$2');
12895 return "$" + whole + sub ;
12899 * Parse a value into a formatted date using the specified format pattern.
12900 * @param {Mixed} value The value to format
12901 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
12902 * @return {String} The formatted date string
12904 date : function(v, format){
12908 if(!(v instanceof Date)){
12909 v = new Date(Date.parse(v));
12911 return v.dateFormat(format || "m/d/Y");
12915 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
12916 * @param {String} format Any valid date format string
12917 * @return {Function} The date formatting function
12919 dateRenderer : function(format){
12920 return function(v){
12921 return Roo.util.Format.date(v, format);
12926 stripTagsRE : /<\/?[^>]+>/gi,
12929 * Strips all HTML tags
12930 * @param {Mixed} value The text from which to strip tags
12931 * @return {String} The stripped text
12933 stripTags : function(v){
12934 return !v ? v : String(v).replace(this.stripTagsRE, "");
12939 * Ext JS Library 1.1.1
12940 * Copyright(c) 2006-2007, Ext JS, LLC.
12942 * Originally Released Under LGPL - original licence link has changed is not relivant.
12945 * <script type="text/javascript">
12952 * @class Roo.MasterTemplate
12953 * @extends Roo.Template
12954 * Provides a template that can have child templates. The syntax is:
12956 var t = new Roo.MasterTemplate(
12957 '<select name="{name}">',
12958 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
12961 t.add('options', {value: 'foo', text: 'bar'});
12962 // or you can add multiple child elements in one shot
12963 t.addAll('options', [
12964 {value: 'foo', text: 'bar'},
12965 {value: 'foo2', text: 'bar2'},
12966 {value: 'foo3', text: 'bar3'}
12968 // then append, applying the master template values
12969 t.append('my-form', {name: 'my-select'});
12971 * A name attribute for the child template is not required if you have only one child
12972 * template or you want to refer to them by index.
12974 Roo.MasterTemplate = function(){
12975 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
12976 this.originalHtml = this.html;
12978 var m, re = this.subTemplateRe;
12981 while(m = re.exec(this.html)){
12982 var name = m[1], content = m[2];
12987 tpl : new Roo.Template(content)
12990 st[name] = st[subIndex];
12992 st[subIndex].tpl.compile();
12993 st[subIndex].tpl.call = this.call.createDelegate(this);
12996 this.subCount = subIndex;
12999 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13001 * The regular expression used to match sub templates
13005 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13008 * Applies the passed values to a child template.
13009 * @param {String/Number} name (optional) The name or index of the child template
13010 * @param {Array/Object} values The values to be applied to the template
13011 * @return {MasterTemplate} this
13013 add : function(name, values){
13014 if(arguments.length == 1){
13015 values = arguments[0];
13018 var s = this.subs[name];
13019 s.buffer[s.buffer.length] = s.tpl.apply(values);
13024 * Applies all the passed values to a child template.
13025 * @param {String/Number} name (optional) The name or index of the child template
13026 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13027 * @param {Boolean} reset (optional) True to reset the template first
13028 * @return {MasterTemplate} this
13030 fill : function(name, values, reset){
13032 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13040 for(var i = 0, len = values.length; i < len; i++){
13041 this.add(name, values[i]);
13047 * Resets the template for reuse
13048 * @return {MasterTemplate} this
13050 reset : function(){
13052 for(var i = 0; i < this.subCount; i++){
13058 applyTemplate : function(values){
13060 var replaceIndex = -1;
13061 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13062 return s[++replaceIndex].buffer.join("");
13064 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13067 apply : function(){
13068 return this.applyTemplate.apply(this, arguments);
13071 compile : function(){return this;}
13075 * Alias for fill().
13078 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13080 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13081 * var tpl = Roo.MasterTemplate.from('element-id');
13082 * @param {String/HTMLElement} el
13083 * @param {Object} config
13086 Roo.MasterTemplate.from = function(el, config){
13087 el = Roo.getDom(el);
13088 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13091 * Ext JS Library 1.1.1
13092 * Copyright(c) 2006-2007, Ext JS, LLC.
13094 * Originally Released Under LGPL - original licence link has changed is not relivant.
13097 * <script type="text/javascript">
13102 * @class Roo.util.CSS
13103 * Utility class for manipulating CSS rules
13106 Roo.util.CSS = function(){
13108 var doc = document;
13110 var camelRe = /(-[a-z])/gi;
13111 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13115 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13116 * tag and appended to the HEAD of the document.
13117 * @param {String} cssText The text containing the css rules
13118 * @param {String} id An id to add to the stylesheet for later removal
13119 * @return {StyleSheet}
13121 createStyleSheet : function(cssText, id){
13123 var head = doc.getElementsByTagName("head")[0];
13124 var rules = doc.createElement("style");
13125 rules.setAttribute("type", "text/css");
13127 rules.setAttribute("id", id);
13130 head.appendChild(rules);
13131 ss = rules.styleSheet;
13132 ss.cssText = cssText;
13135 rules.appendChild(doc.createTextNode(cssText));
13137 rules.cssText = cssText;
13139 head.appendChild(rules);
13140 ss = rules.styleSheet ? rules.styleSheet : (rules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13142 this.cacheStyleSheet(ss);
13147 * Removes a style or link tag by id
13148 * @param {String} id The id of the tag
13150 removeStyleSheet : function(id){
13151 var existing = doc.getElementById(id);
13153 existing.parentNode.removeChild(existing);
13158 * Dynamically swaps an existing stylesheet reference for a new one
13159 * @param {String} id The id of an existing link tag to remove
13160 * @param {String} url The href of the new stylesheet to include
13162 swapStyleSheet : function(id, url){
13163 this.removeStyleSheet(id);
13164 var ss = doc.createElement("link");
13165 ss.setAttribute("rel", "stylesheet");
13166 ss.setAttribute("type", "text/css");
13167 ss.setAttribute("id", id);
13168 ss.setAttribute("href", url);
13169 doc.getElementsByTagName("head")[0].appendChild(ss);
13173 * Refresh the rule cache if you have dynamically added stylesheets
13174 * @return {Object} An object (hash) of rules indexed by selector
13176 refreshCache : function(){
13177 return this.getRules(true);
13181 cacheStyleSheet : function(ss){
13185 try{// try catch for cross domain access issue
13186 var ssRules = ss.cssRules || ss.rules;
13187 for(var j = ssRules.length-1; j >= 0; --j){
13188 rules[ssRules[j].selectorText] = ssRules[j];
13194 * Gets all css rules for the document
13195 * @param {Boolean} refreshCache true to refresh the internal cache
13196 * @return {Object} An object (hash) of rules indexed by selector
13198 getRules : function(refreshCache){
13199 if(rules == null || refreshCache){
13201 var ds = doc.styleSheets;
13202 for(var i =0, len = ds.length; i < len; i++){
13204 this.cacheStyleSheet(ds[i]);
13212 * Gets an an individual CSS rule by selector(s)
13213 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13214 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13215 * @return {CSSRule} The CSS rule or null if one is not found
13217 getRule : function(selector, refreshCache){
13218 var rs = this.getRules(refreshCache);
13219 if(!(selector instanceof Array)){
13220 return rs[selector];
13222 for(var i = 0; i < selector.length; i++){
13223 if(rs[selector[i]]){
13224 return rs[selector[i]];
13232 * Updates a rule property
13233 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13234 * @param {String} property The css property
13235 * @param {String} value The new value for the property
13236 * @return {Boolean} true If a rule was found and updated
13238 updateRule : function(selector, property, value){
13239 if(!(selector instanceof Array)){
13240 var rule = this.getRule(selector);
13242 rule.style[property.replace(camelRe, camelFn)] = value;
13246 for(var i = 0; i < selector.length; i++){
13247 if(this.updateRule(selector[i], property, value)){
13257 * Ext JS Library 1.1.1
13258 * Copyright(c) 2006-2007, Ext JS, LLC.
13260 * Originally Released Under LGPL - original licence link has changed is not relivant.
13263 * <script type="text/javascript">
13269 * @class Roo.util.ClickRepeater
13270 * @extends Roo.util.Observable
13272 * A wrapper class which can be applied to any element. Fires a "click" event while the
13273 * mouse is pressed. The interval between firings may be specified in the config but
13274 * defaults to 10 milliseconds.
13276 * Optionally, a CSS class may be applied to the element during the time it is pressed.
13278 * @cfg {String/HTMLElement/Element} el The element to act as a button.
13279 * @cfg {Number} delay The initial delay before the repeating event begins firing.
13280 * Similar to an autorepeat key delay.
13281 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
13282 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
13283 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
13284 * "interval" and "delay" are ignored. "immediate" is honored.
13285 * @cfg {Boolean} preventDefault True to prevent the default click event
13286 * @cfg {Boolean} stopDefault True to stop the default click event
13289 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
13290 * 2007-02-02 jvs Renamed to ClickRepeater
13291 * 2007-02-03 jvs Modifications for FF Mac and Safari
13294 * @param {String/HTMLElement/Element} el The element to listen on
13295 * @param {Object} config
13297 Roo.util.ClickRepeater = function(el, config)
13299 this.el = Roo.get(el);
13300 this.el.unselectable();
13302 Roo.apply(this, config);
13307 * Fires when the mouse button is depressed.
13308 * @param {Roo.util.ClickRepeater} this
13310 "mousedown" : true,
13313 * Fires on a specified interval during the time the element is pressed.
13314 * @param {Roo.util.ClickRepeater} this
13319 * Fires when the mouse key is released.
13320 * @param {Roo.util.ClickRepeater} this
13325 this.el.on("mousedown", this.handleMouseDown, this);
13326 if(this.preventDefault || this.stopDefault){
13327 this.el.on("click", function(e){
13328 if(this.preventDefault){
13329 e.preventDefault();
13331 if(this.stopDefault){
13337 // allow inline handler
13339 this.on("click", this.handler, this.scope || this);
13342 Roo.util.ClickRepeater.superclass.constructor.call(this);
13345 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
13348 preventDefault : true,
13349 stopDefault : false,
13353 handleMouseDown : function(){
13354 clearTimeout(this.timer);
13356 if(this.pressClass){
13357 this.el.addClass(this.pressClass);
13359 this.mousedownTime = new Date();
13361 Roo.get(document).on("mouseup", this.handleMouseUp, this);
13362 this.el.on("mouseout", this.handleMouseOut, this);
13364 this.fireEvent("mousedown", this);
13365 this.fireEvent("click", this);
13367 this.timer = this.click.defer(this.delay || this.interval, this);
13371 click : function(){
13372 this.fireEvent("click", this);
13373 this.timer = this.click.defer(this.getInterval(), this);
13377 getInterval: function(){
13378 if(!this.accelerate){
13379 return this.interval;
13381 var pressTime = this.mousedownTime.getElapsed();
13382 if(pressTime < 500){
13384 }else if(pressTime < 1700){
13386 }else if(pressTime < 2600){
13388 }else if(pressTime < 3500){
13390 }else if(pressTime < 4400){
13392 }else if(pressTime < 5300){
13394 }else if(pressTime < 6200){
13402 handleMouseOut : function(){
13403 clearTimeout(this.timer);
13404 if(this.pressClass){
13405 this.el.removeClass(this.pressClass);
13407 this.el.on("mouseover", this.handleMouseReturn, this);
13411 handleMouseReturn : function(){
13412 this.el.un("mouseover", this.handleMouseReturn);
13413 if(this.pressClass){
13414 this.el.addClass(this.pressClass);
13420 handleMouseUp : function(){
13421 clearTimeout(this.timer);
13422 this.el.un("mouseover", this.handleMouseReturn);
13423 this.el.un("mouseout", this.handleMouseOut);
13424 Roo.get(document).un("mouseup", this.handleMouseUp);
13425 this.el.removeClass(this.pressClass);
13426 this.fireEvent("mouseup", this);
13430 * Ext JS Library 1.1.1
13431 * Copyright(c) 2006-2007, Ext JS, LLC.
13433 * Originally Released Under LGPL - original licence link has changed is not relivant.
13436 * <script type="text/javascript">
13441 * @class Roo.KeyNav
13442 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
13443 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
13444 * way to implement custom navigation schemes for any UI component.</p>
13445 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
13446 * pageUp, pageDown, del, home, end. Usage:</p>
13448 var nav = new Roo.KeyNav("my-element", {
13449 "left" : function(e){
13450 this.moveLeft(e.ctrlKey);
13452 "right" : function(e){
13453 this.moveRight(e.ctrlKey);
13455 "enter" : function(e){
13462 * @param {String/HTMLElement/Roo.Element} el The element to bind to
13463 * @param {Object} config The config
13465 Roo.KeyNav = function(el, config){
13466 this.el = Roo.get(el);
13467 Roo.apply(this, config);
13468 if(!this.disabled){
13469 this.disabled = true;
13474 Roo.KeyNav.prototype = {
13476 * @cfg {Boolean} disabled
13477 * True to disable this KeyNav instance (defaults to false)
13481 * @cfg {String} defaultEventAction
13482 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
13483 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
13484 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
13486 defaultEventAction: "stopEvent",
13488 * @cfg {Boolean} forceKeyDown
13489 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
13490 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
13491 * handle keydown instead of keypress.
13493 forceKeyDown : false,
13496 prepareEvent : function(e){
13497 var k = e.getKey();
13498 var h = this.keyToHandler[k];
13499 //if(h && this[h]){
13500 // e.stopPropagation();
13502 if(Roo.isSafari && h && k >= 37 && k <= 40){
13508 relay : function(e){
13509 var k = e.getKey();
13510 var h = this.keyToHandler[k];
13512 if(this.doRelay(e, this[h], h) !== true){
13513 e[this.defaultEventAction]();
13519 doRelay : function(e, h, hname){
13520 return h.call(this.scope || this, e);
13523 // possible handlers
13537 // quick lookup hash
13554 * Enable this KeyNav
13556 enable: function(){
13558 // ie won't do special keys on keypress, no one else will repeat keys with keydown
13559 // the EventObject will normalize Safari automatically
13560 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13561 this.el.on("keydown", this.relay, this);
13563 this.el.on("keydown", this.prepareEvent, this);
13564 this.el.on("keypress", this.relay, this);
13566 this.disabled = false;
13571 * Disable this KeyNav
13573 disable: function(){
13574 if(!this.disabled){
13575 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13576 this.el.un("keydown", this.relay);
13578 this.el.un("keydown", this.prepareEvent);
13579 this.el.un("keypress", this.relay);
13581 this.disabled = true;
13586 * Ext JS Library 1.1.1
13587 * Copyright(c) 2006-2007, Ext JS, LLC.
13589 * Originally Released Under LGPL - original licence link has changed is not relivant.
13592 * <script type="text/javascript">
13597 * @class Roo.KeyMap
13598 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
13599 * The constructor accepts the same config object as defined by {@link #addBinding}.
13600 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
13601 * combination it will call the function with this signature (if the match is a multi-key
13602 * combination the callback will still be called only once): (String key, Roo.EventObject e)
13603 * A KeyMap can also handle a string representation of keys.<br />
13606 // map one key by key code
13607 var map = new Roo.KeyMap("my-element", {
13608 key: 13, // or Roo.EventObject.ENTER
13613 // map multiple keys to one action by string
13614 var map = new Roo.KeyMap("my-element", {
13620 // map multiple keys to multiple actions by strings and array of codes
13621 var map = new Roo.KeyMap("my-element", [
13624 fn: function(){ alert("Return was pressed"); }
13627 fn: function(){ alert('a, b or c was pressed'); }
13632 fn: function(){ alert('Control + shift + tab was pressed.'); }
13636 * <b>Note: A KeyMap starts enabled</b>
13638 * @param {String/HTMLElement/Roo.Element} el The element to bind to
13639 * @param {Object} config The config (see {@link #addBinding})
13640 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
13642 Roo.KeyMap = function(el, config, eventName){
13643 this.el = Roo.get(el);
13644 this.eventName = eventName || "keydown";
13645 this.bindings = [];
13647 this.addBinding(config);
13652 Roo.KeyMap.prototype = {
13654 * True to stop the event from bubbling and prevent the default browser action if the
13655 * key was handled by the KeyMap (defaults to false)
13661 * Add a new binding to this KeyMap. The following config object properties are supported:
13663 Property Type Description
13664 ---------- --------------- ----------------------------------------------------------------------
13665 key String/Array A single keycode or an array of keycodes to handle
13666 shift Boolean True to handle key only when shift is pressed (defaults to false)
13667 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
13668 alt Boolean True to handle key only when alt is pressed (defaults to false)
13669 fn Function The function to call when KeyMap finds the expected key combination
13670 scope Object The scope of the callback function
13676 var map = new Roo.KeyMap(document, {
13677 key: Roo.EventObject.ENTER,
13682 //Add a new binding to the existing KeyMap later
13690 * @param {Object/Array} config A single KeyMap config or an array of configs
13692 addBinding : function(config){
13693 if(config instanceof Array){
13694 for(var i = 0, len = config.length; i < len; i++){
13695 this.addBinding(config[i]);
13699 var keyCode = config.key,
13700 shift = config.shift,
13701 ctrl = config.ctrl,
13704 scope = config.scope;
13705 if(typeof keyCode == "string"){
13707 var keyString = keyCode.toUpperCase();
13708 for(var j = 0, len = keyString.length; j < len; j++){
13709 ks.push(keyString.charCodeAt(j));
13713 var keyArray = keyCode instanceof Array;
13714 var handler = function(e){
13715 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
13716 var k = e.getKey();
13718 for(var i = 0, len = keyCode.length; i < len; i++){
13719 if(keyCode[i] == k){
13720 if(this.stopEvent){
13723 fn.call(scope || window, k, e);
13729 if(this.stopEvent){
13732 fn.call(scope || window, k, e);
13737 this.bindings.push(handler);
13741 * Shorthand for adding a single key listener
13742 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
13743 * following options:
13744 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
13745 * @param {Function} fn The function to call
13746 * @param {Object} scope (optional) The scope of the function
13748 on : function(key, fn, scope){
13749 var keyCode, shift, ctrl, alt;
13750 if(typeof key == "object" && !(key instanceof Array)){
13769 handleKeyDown : function(e){
13770 if(this.enabled){ //just in case
13771 var b = this.bindings;
13772 for(var i = 0, len = b.length; i < len; i++){
13773 b[i].call(this, e);
13779 * Returns true if this KeyMap is enabled
13780 * @return {Boolean}
13782 isEnabled : function(){
13783 return this.enabled;
13787 * Enables this KeyMap
13789 enable: function(){
13791 this.el.on(this.eventName, this.handleKeyDown, this);
13792 this.enabled = true;
13797 * Disable this KeyMap
13799 disable: function(){
13801 this.el.removeListener(this.eventName, this.handleKeyDown, this);
13802 this.enabled = false;
13807 * Ext JS Library 1.1.1
13808 * Copyright(c) 2006-2007, Ext JS, LLC.
13810 * Originally Released Under LGPL - original licence link has changed is not relivant.
13813 * <script type="text/javascript">
13818 * @class Roo.util.TextMetrics
13819 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
13820 * wide, in pixels, a given block of text will be.
13823 Roo.util.TextMetrics = function(){
13827 * Measures the size of the specified text
13828 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
13829 * that can affect the size of the rendered text
13830 * @param {String} text The text to measure
13831 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
13832 * in order to accurately measure the text height
13833 * @return {Object} An object containing the text's size {width: (width), height: (height)}
13835 measure : function(el, text, fixedWidth){
13837 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
13840 shared.setFixedWidth(fixedWidth || 'auto');
13841 return shared.getSize(text);
13845 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
13846 * the overhead of multiple calls to initialize the style properties on each measurement.
13847 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
13848 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
13849 * in order to accurately measure the text height
13850 * @return {Roo.util.TextMetrics.Instance} instance The new instance
13852 createInstance : function(el, fixedWidth){
13853 return Roo.util.TextMetrics.Instance(el, fixedWidth);
13858 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
13859 var ml = new Roo.Element(document.createElement('div'));
13860 document.body.appendChild(ml.dom);
13861 ml.position('absolute');
13862 ml.setLeftTop(-1000, -1000);
13866 ml.setWidth(fixedWidth);
13871 * Returns the size of the specified text based on the internal element's style and width properties
13872 * @param {String} text The text to measure
13873 * @return {Object} An object containing the text's size {width: (width), height: (height)}
13875 getSize : function(text){
13877 var s = ml.getSize();
13883 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
13884 * that can affect the size of the rendered text
13885 * @param {String/HTMLElement} el The element, dom node or id
13887 bind : function(el){
13889 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
13894 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
13895 * to set a fixed width in order to accurately measure the text height.
13896 * @param {Number} width The width to set on the element
13898 setFixedWidth : function(width){
13899 ml.setWidth(width);
13903 * Returns the measured width of the specified text
13904 * @param {String} text The text to measure
13905 * @return {Number} width The width in pixels
13907 getWidth : function(text){
13908 ml.dom.style.width = 'auto';
13909 return this.getSize(text).width;
13913 * Returns the measured height of the specified text. For multiline text, be sure to call
13914 * {@link #setFixedWidth} if necessary.
13915 * @param {String} text The text to measure
13916 * @return {Number} height The height in pixels
13918 getHeight : function(text){
13919 return this.getSize(text).height;
13923 instance.bind(bindTo);
13928 // backwards compat
13929 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
13931 * Ext JS Library 1.1.1
13932 * Copyright(c) 2006-2007, Ext JS, LLC.
13934 * Originally Released Under LGPL - original licence link has changed is not relivant.
13937 * <script type="text/javascript">
13941 * @class Roo.state.Provider
13942 * Abstract base class for state provider implementations. This class provides methods
13943 * for encoding and decoding <b>typed</b> variables including dates and defines the
13944 * Provider interface.
13946 Roo.state.Provider = function(){
13948 * @event statechange
13949 * Fires when a state change occurs.
13950 * @param {Provider} this This state provider
13951 * @param {String} key The state key which was changed
13952 * @param {String} value The encoded value for the state
13955 "statechange": true
13958 Roo.state.Provider.superclass.constructor.call(this);
13960 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
13962 * Returns the current value for a key
13963 * @param {String} name The key name
13964 * @param {Mixed} defaultValue A default value to return if the key's value is not found
13965 * @return {Mixed} The state data
13967 get : function(name, defaultValue){
13968 return typeof this.state[name] == "undefined" ?
13969 defaultValue : this.state[name];
13973 * Clears a value from the state
13974 * @param {String} name The key name
13976 clear : function(name){
13977 delete this.state[name];
13978 this.fireEvent("statechange", this, name, null);
13982 * Sets the value for a key
13983 * @param {String} name The key name
13984 * @param {Mixed} value The value to set
13986 set : function(name, value){
13987 this.state[name] = value;
13988 this.fireEvent("statechange", this, name, value);
13992 * Decodes a string previously encoded with {@link #encodeValue}.
13993 * @param {String} value The value to decode
13994 * @return {Mixed} The decoded value
13996 decodeValue : function(cookie){
13997 var re = /^(a|n|d|b|s|o)\:(.*)$/;
13998 var matches = re.exec(unescape(cookie));
13999 if(!matches || !matches[1]) return; // non state cookie
14000 var type = matches[1];
14001 var v = matches[2];
14004 return parseFloat(v);
14006 return new Date(Date.parse(v));
14011 var values = v.split("^");
14012 for(var i = 0, len = values.length; i < len; i++){
14013 all.push(this.decodeValue(values[i]));
14018 var values = v.split("^");
14019 for(var i = 0, len = values.length; i < len; i++){
14020 var kv = values[i].split("=");
14021 all[kv[0]] = this.decodeValue(kv[1]);
14030 * Encodes a value including type information. Decode with {@link #decodeValue}.
14031 * @param {Mixed} value The value to encode
14032 * @return {String} The encoded value
14034 encodeValue : function(v){
14036 if(typeof v == "number"){
14038 }else if(typeof v == "boolean"){
14039 enc = "b:" + (v ? "1" : "0");
14040 }else if(v instanceof Date){
14041 enc = "d:" + v.toGMTString();
14042 }else if(v instanceof Array){
14044 for(var i = 0, len = v.length; i < len; i++){
14045 flat += this.encodeValue(v[i]);
14046 if(i != len-1) flat += "^";
14049 }else if(typeof v == "object"){
14052 if(typeof v[key] != "function"){
14053 flat += key + "=" + this.encodeValue(v[key]) + "^";
14056 enc = "o:" + flat.substring(0, flat.length-1);
14060 return escape(enc);
14066 * Ext JS Library 1.1.1
14067 * Copyright(c) 2006-2007, Ext JS, LLC.
14069 * Originally Released Under LGPL - original licence link has changed is not relivant.
14072 * <script type="text/javascript">
14075 * @class Roo.state.Manager
14076 * This is the global state manager. By default all components that are "state aware" check this class
14077 * for state information if you don't pass them a custom state provider. In order for this class
14078 * to be useful, it must be initialized with a provider when your application initializes.
14080 // in your initialization function
14082 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14084 // supposed you have a {@link Roo.BorderLayout}
14085 var layout = new Roo.BorderLayout(...);
14086 layout.restoreState();
14087 // or a {Roo.BasicDialog}
14088 var dialog = new Roo.BasicDialog(...);
14089 dialog.restoreState();
14093 Roo.state.Manager = function(){
14094 var provider = new Roo.state.Provider();
14098 * Configures the default state provider for your application
14099 * @param {Provider} stateProvider The state provider to set
14101 setProvider : function(stateProvider){
14102 provider = stateProvider;
14106 * Returns the current value for a key
14107 * @param {String} name The key name
14108 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14109 * @return {Mixed} The state data
14111 get : function(key, defaultValue){
14112 return provider.get(key, defaultValue);
14116 * Sets the value for a key
14117 * @param {String} name The key name
14118 * @param {Mixed} value The state data
14120 set : function(key, value){
14121 provider.set(key, value);
14125 * Clears a value from the state
14126 * @param {String} name The key name
14128 clear : function(key){
14129 provider.clear(key);
14133 * Gets the currently configured state provider
14134 * @return {Provider} The state provider
14136 getProvider : function(){
14143 * Ext JS Library 1.1.1
14144 * Copyright(c) 2006-2007, Ext JS, LLC.
14146 * Originally Released Under LGPL - original licence link has changed is not relivant.
14149 * <script type="text/javascript">
14152 * @class Roo.state.CookieProvider
14153 * @extends Roo.state.Provider
14154 * The default Provider implementation which saves state via cookies.
14157 var cp = new Roo.state.CookieProvider({
14159 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14160 domain: "roojs.com"
14162 Roo.state.Manager.setProvider(cp);
14164 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14165 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14166 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
14167 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14168 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14169 * domain the page is running on including the 'www' like 'www.roojs.com')
14170 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14172 * Create a new CookieProvider
14173 * @param {Object} config The configuration object
14175 Roo.state.CookieProvider = function(config){
14176 Roo.state.CookieProvider.superclass.constructor.call(this);
14178 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14179 this.domain = null;
14180 this.secure = false;
14181 Roo.apply(this, config);
14182 this.state = this.readCookies();
14185 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14187 set : function(name, value){
14188 if(typeof value == "undefined" || value === null){
14192 this.setCookie(name, value);
14193 Roo.state.CookieProvider.superclass.set.call(this, name, value);
14197 clear : function(name){
14198 this.clearCookie(name);
14199 Roo.state.CookieProvider.superclass.clear.call(this, name);
14203 readCookies : function(){
14205 var c = document.cookie + ";";
14206 var re = /\s?(.*?)=(.*?);/g;
14208 while((matches = re.exec(c)) != null){
14209 var name = matches[1];
14210 var value = matches[2];
14211 if(name && name.substring(0,3) == "ys-"){
14212 cookies[name.substr(3)] = this.decodeValue(value);
14219 setCookie : function(name, value){
14220 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14221 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14222 ((this.path == null) ? "" : ("; path=" + this.path)) +
14223 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14224 ((this.secure == true) ? "; secure" : "");
14228 clearCookie : function(name){
14229 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14230 ((this.path == null) ? "" : ("; path=" + this.path)) +
14231 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14232 ((this.secure == true) ? "; secure" : "");
14236 * Ext JS Library 1.1.1
14237 * Copyright(c) 2006-2007, Ext JS, LLC.
14239 * Originally Released Under LGPL - original licence link has changed is not relivant.
14242 * <script type="text/javascript">
14248 * These classes are derivatives of the similarly named classes in the YUI Library.
14249 * The original license:
14250 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
14251 * Code licensed under the BSD License:
14252 * http://developer.yahoo.net/yui/license.txt
14257 var Event=Roo.EventManager;
14258 var Dom=Roo.lib.Dom;
14261 * @class Roo.dd.DragDrop
14262 * Defines the interface and base operation of items that that can be
14263 * dragged or can be drop targets. It was designed to be extended, overriding
14264 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
14265 * Up to three html elements can be associated with a DragDrop instance:
14267 * <li>linked element: the element that is passed into the constructor.
14268 * This is the element which defines the boundaries for interaction with
14269 * other DragDrop objects.</li>
14270 * <li>handle element(s): The drag operation only occurs if the element that
14271 * was clicked matches a handle element. By default this is the linked
14272 * element, but there are times that you will want only a portion of the
14273 * linked element to initiate the drag operation, and the setHandleElId()
14274 * method provides a way to define this.</li>
14275 * <li>drag element: this represents the element that would be moved along
14276 * with the cursor during a drag operation. By default, this is the linked
14277 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
14278 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
14281 * This class should not be instantiated until the onload event to ensure that
14282 * the associated elements are available.
14283 * The following would define a DragDrop obj that would interact with any
14284 * other DragDrop obj in the "group1" group:
14286 * dd = new Roo.dd.DragDrop("div1", "group1");
14288 * Since none of the event handlers have been implemented, nothing would
14289 * actually happen if you were to run the code above. Normally you would
14290 * override this class or one of the default implementations, but you can
14291 * also override the methods you want on an instance of the class...
14293 * dd.onDragDrop = function(e, id) {
14294 * alert("dd was dropped on " + id);
14298 * @param {String} id of the element that is linked to this instance
14299 * @param {String} sGroup the group of related DragDrop objects
14300 * @param {object} config an object containing configurable attributes
14301 * Valid properties for DragDrop:
14302 * padding, isTarget, maintainOffset, primaryButtonOnly
14304 Roo.dd.DragDrop = function(id, sGroup, config) {
14306 this.init(id, sGroup, config);
14310 Roo.dd.DragDrop.prototype = {
14313 * The id of the element associated with this object. This is what we
14314 * refer to as the "linked element" because the size and position of
14315 * this element is used to determine when the drag and drop objects have
14323 * Configuration attributes passed into the constructor
14330 * The id of the element that will be dragged. By default this is same
14331 * as the linked element , but could be changed to another element. Ex:
14333 * @property dragElId
14340 * the id of the element that initiates the drag operation. By default
14341 * this is the linked element, but could be changed to be a child of this
14342 * element. This lets us do things like only starting the drag when the
14343 * header element within the linked html element is clicked.
14344 * @property handleElId
14351 * An associative array of HTML tags that will be ignored if clicked.
14352 * @property invalidHandleTypes
14353 * @type {string: string}
14355 invalidHandleTypes: null,
14358 * An associative array of ids for elements that will be ignored if clicked
14359 * @property invalidHandleIds
14360 * @type {string: string}
14362 invalidHandleIds: null,
14365 * An indexted array of css class names for elements that will be ignored
14367 * @property invalidHandleClasses
14370 invalidHandleClasses: null,
14373 * The linked element's absolute X position at the time the drag was
14375 * @property startPageX
14382 * The linked element's absolute X position at the time the drag was
14384 * @property startPageY
14391 * The group defines a logical collection of DragDrop objects that are
14392 * related. Instances only get events when interacting with other
14393 * DragDrop object in the same group. This lets us define multiple
14394 * groups using a single DragDrop subclass if we want.
14396 * @type {string: string}
14401 * Individual drag/drop instances can be locked. This will prevent
14402 * onmousedown start drag.
14410 * Lock this instance
14413 lock: function() { this.locked = true; },
14416 * Unlock this instace
14419 unlock: function() { this.locked = false; },
14422 * By default, all insances can be a drop target. This can be disabled by
14423 * setting isTarget to false.
14430 * The padding configured for this drag and drop object for calculating
14431 * the drop zone intersection with this object.
14438 * Cached reference to the linked element
14439 * @property _domRef
14445 * Internal typeof flag
14446 * @property __ygDragDrop
14449 __ygDragDrop: true,
14452 * Set to true when horizontal contraints are applied
14453 * @property constrainX
14460 * Set to true when vertical contraints are applied
14461 * @property constrainY
14468 * The left constraint
14476 * The right constraint
14484 * The up constraint
14493 * The down constraint
14501 * Maintain offsets when we resetconstraints. Set to true when you want
14502 * the position of the element relative to its parent to stay the same
14503 * when the page changes
14505 * @property maintainOffset
14508 maintainOffset: false,
14511 * Array of pixel locations the element will snap to if we specified a
14512 * horizontal graduation/interval. This array is generated automatically
14513 * when you define a tick interval.
14520 * Array of pixel locations the element will snap to if we specified a
14521 * vertical graduation/interval. This array is generated automatically
14522 * when you define a tick interval.
14529 * By default the drag and drop instance will only respond to the primary
14530 * button click (left button for a right-handed mouse). Set to true to
14531 * allow drag and drop to start with any mouse click that is propogated
14533 * @property primaryButtonOnly
14536 primaryButtonOnly: true,
14539 * The availabe property is false until the linked dom element is accessible.
14540 * @property available
14546 * By default, drags can only be initiated if the mousedown occurs in the
14547 * region the linked element is. This is done in part to work around a
14548 * bug in some browsers that mis-report the mousedown if the previous
14549 * mouseup happened outside of the window. This property is set to true
14550 * if outer handles are defined.
14552 * @property hasOuterHandles
14556 hasOuterHandles: false,
14559 * Code that executes immediately before the startDrag event
14560 * @method b4StartDrag
14563 b4StartDrag: function(x, y) { },
14566 * Abstract method called after a drag/drop object is clicked
14567 * and the drag or mousedown time thresholds have beeen met.
14568 * @method startDrag
14569 * @param {int} X click location
14570 * @param {int} Y click location
14572 startDrag: function(x, y) { /* override this */ },
14575 * Code that executes immediately before the onDrag event
14579 b4Drag: function(e) { },
14582 * Abstract method called during the onMouseMove event while dragging an
14585 * @param {Event} e the mousemove event
14587 onDrag: function(e) { /* override this */ },
14590 * Abstract method called when this element fist begins hovering over
14591 * another DragDrop obj
14592 * @method onDragEnter
14593 * @param {Event} e the mousemove event
14594 * @param {String|DragDrop[]} id In POINT mode, the element
14595 * id this is hovering over. In INTERSECT mode, an array of one or more
14596 * dragdrop items being hovered over.
14598 onDragEnter: function(e, id) { /* override this */ },
14601 * Code that executes immediately before the onDragOver event
14602 * @method b4DragOver
14605 b4DragOver: function(e) { },
14608 * Abstract method called when this element is hovering over another
14610 * @method onDragOver
14611 * @param {Event} e the mousemove event
14612 * @param {String|DragDrop[]} id In POINT mode, the element
14613 * id this is hovering over. In INTERSECT mode, an array of dd items
14614 * being hovered over.
14616 onDragOver: function(e, id) { /* override this */ },
14619 * Code that executes immediately before the onDragOut event
14620 * @method b4DragOut
14623 b4DragOut: function(e) { },
14626 * Abstract method called when we are no longer hovering over an element
14627 * @method onDragOut
14628 * @param {Event} e the mousemove event
14629 * @param {String|DragDrop[]} id In POINT mode, the element
14630 * id this was hovering over. In INTERSECT mode, an array of dd items
14631 * that the mouse is no longer over.
14633 onDragOut: function(e, id) { /* override this */ },
14636 * Code that executes immediately before the onDragDrop event
14637 * @method b4DragDrop
14640 b4DragDrop: function(e) { },
14643 * Abstract method called when this item is dropped on another DragDrop
14645 * @method onDragDrop
14646 * @param {Event} e the mouseup event
14647 * @param {String|DragDrop[]} id In POINT mode, the element
14648 * id this was dropped on. In INTERSECT mode, an array of dd items this
14651 onDragDrop: function(e, id) { /* override this */ },
14654 * Abstract method called when this item is dropped on an area with no
14656 * @method onInvalidDrop
14657 * @param {Event} e the mouseup event
14659 onInvalidDrop: function(e) { /* override this */ },
14662 * Code that executes immediately before the endDrag event
14663 * @method b4EndDrag
14666 b4EndDrag: function(e) { },
14669 * Fired when we are done dragging the object
14671 * @param {Event} e the mouseup event
14673 endDrag: function(e) { /* override this */ },
14676 * Code executed immediately before the onMouseDown event
14677 * @method b4MouseDown
14678 * @param {Event} e the mousedown event
14681 b4MouseDown: function(e) { },
14684 * Event handler that fires when a drag/drop obj gets a mousedown
14685 * @method onMouseDown
14686 * @param {Event} e the mousedown event
14688 onMouseDown: function(e) { /* override this */ },
14691 * Event handler that fires when a drag/drop obj gets a mouseup
14692 * @method onMouseUp
14693 * @param {Event} e the mouseup event
14695 onMouseUp: function(e) { /* override this */ },
14698 * Override the onAvailable method to do what is needed after the initial
14699 * position was determined.
14700 * @method onAvailable
14702 onAvailable: function () {
14706 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
14709 defaultPadding : {left:0, right:0, top:0, bottom:0},
14712 * Initializes the drag drop object's constraints to restrict movement to a certain element.
14716 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
14717 { dragElId: "existingProxyDiv" });
14718 dd.startDrag = function(){
14719 this.constrainTo("parent-id");
14722 * Or you can initalize it using the {@link Roo.Element} object:
14724 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
14725 startDrag : function(){
14726 this.constrainTo("parent-id");
14730 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
14731 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
14732 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
14733 * an object containing the sides to pad. For example: {right:10, bottom:10}
14734 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
14736 constrainTo : function(constrainTo, pad, inContent){
14737 if(typeof pad == "number"){
14738 pad = {left: pad, right:pad, top:pad, bottom:pad};
14740 pad = pad || this.defaultPadding;
14741 var b = Roo.get(this.getEl()).getBox();
14742 var ce = Roo.get(constrainTo);
14743 var s = ce.getScroll();
14744 var c, cd = ce.dom;
14745 if(cd == document.body){
14746 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
14749 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
14753 var topSpace = b.y - c.y;
14754 var leftSpace = b.x - c.x;
14756 this.resetConstraints();
14757 this.setXConstraint(leftSpace - (pad.left||0), // left
14758 c.width - leftSpace - b.width - (pad.right||0) //right
14760 this.setYConstraint(topSpace - (pad.top||0), //top
14761 c.height - topSpace - b.height - (pad.bottom||0) //bottom
14766 * Returns a reference to the linked element
14768 * @return {HTMLElement} the html element
14770 getEl: function() {
14771 if (!this._domRef) {
14772 this._domRef = Roo.getDom(this.id);
14775 return this._domRef;
14779 * Returns a reference to the actual element to drag. By default this is
14780 * the same as the html element, but it can be assigned to another
14781 * element. An example of this can be found in Roo.dd.DDProxy
14782 * @method getDragEl
14783 * @return {HTMLElement} the html element
14785 getDragEl: function() {
14786 return Roo.getDom(this.dragElId);
14790 * Sets up the DragDrop object. Must be called in the constructor of any
14791 * Roo.dd.DragDrop subclass
14793 * @param id the id of the linked element
14794 * @param {String} sGroup the group of related items
14795 * @param {object} config configuration attributes
14797 init: function(id, sGroup, config) {
14798 this.initTarget(id, sGroup, config);
14799 Event.on(this.id, "mousedown", this.handleMouseDown, this);
14800 // Event.on(this.id, "selectstart", Event.preventDefault);
14804 * Initializes Targeting functionality only... the object does not
14805 * get a mousedown handler.
14806 * @method initTarget
14807 * @param id the id of the linked element
14808 * @param {String} sGroup the group of related items
14809 * @param {object} config configuration attributes
14811 initTarget: function(id, sGroup, config) {
14813 // configuration attributes
14814 this.config = config || {};
14816 // create a local reference to the drag and drop manager
14817 this.DDM = Roo.dd.DDM;
14818 // initialize the groups array
14821 // assume that we have an element reference instead of an id if the
14822 // parameter is not a string
14823 if (typeof id !== "string") {
14830 // add to an interaction group
14831 this.addToGroup((sGroup) ? sGroup : "default");
14833 // We don't want to register this as the handle with the manager
14834 // so we just set the id rather than calling the setter.
14835 this.handleElId = id;
14837 // the linked element is the element that gets dragged by default
14838 this.setDragElId(id);
14840 // by default, clicked anchors will not start drag operations.
14841 this.invalidHandleTypes = { A: "A" };
14842 this.invalidHandleIds = {};
14843 this.invalidHandleClasses = [];
14845 this.applyConfig();
14847 this.handleOnAvailable();
14851 * Applies the configuration parameters that were passed into the constructor.
14852 * This is supposed to happen at each level through the inheritance chain. So
14853 * a DDProxy implentation will execute apply config on DDProxy, DD, and
14854 * DragDrop in order to get all of the parameters that are available in
14856 * @method applyConfig
14858 applyConfig: function() {
14860 // configurable properties:
14861 // padding, isTarget, maintainOffset, primaryButtonOnly
14862 this.padding = this.config.padding || [0, 0, 0, 0];
14863 this.isTarget = (this.config.isTarget !== false);
14864 this.maintainOffset = (this.config.maintainOffset);
14865 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
14870 * Executed when the linked element is available
14871 * @method handleOnAvailable
14874 handleOnAvailable: function() {
14875 this.available = true;
14876 this.resetConstraints();
14877 this.onAvailable();
14881 * Configures the padding for the target zone in px. Effectively expands
14882 * (or reduces) the virtual object size for targeting calculations.
14883 * Supports css-style shorthand; if only one parameter is passed, all sides
14884 * will have that padding, and if only two are passed, the top and bottom
14885 * will have the first param, the left and right the second.
14886 * @method setPadding
14887 * @param {int} iTop Top pad
14888 * @param {int} iRight Right pad
14889 * @param {int} iBot Bot pad
14890 * @param {int} iLeft Left pad
14892 setPadding: function(iTop, iRight, iBot, iLeft) {
14893 // this.padding = [iLeft, iRight, iTop, iBot];
14894 if (!iRight && 0 !== iRight) {
14895 this.padding = [iTop, iTop, iTop, iTop];
14896 } else if (!iBot && 0 !== iBot) {
14897 this.padding = [iTop, iRight, iTop, iRight];
14899 this.padding = [iTop, iRight, iBot, iLeft];
14904 * Stores the initial placement of the linked element.
14905 * @method setInitialPosition
14906 * @param {int} diffX the X offset, default 0
14907 * @param {int} diffY the Y offset, default 0
14909 setInitPosition: function(diffX, diffY) {
14910 var el = this.getEl();
14912 if (!this.DDM.verifyEl(el)) {
14916 var dx = diffX || 0;
14917 var dy = diffY || 0;
14919 var p = Dom.getXY( el );
14921 this.initPageX = p[0] - dx;
14922 this.initPageY = p[1] - dy;
14924 this.lastPageX = p[0];
14925 this.lastPageY = p[1];
14928 this.setStartPosition(p);
14932 * Sets the start position of the element. This is set when the obj
14933 * is initialized, the reset when a drag is started.
14934 * @method setStartPosition
14935 * @param pos current position (from previous lookup)
14938 setStartPosition: function(pos) {
14939 var p = pos || Dom.getXY( this.getEl() );
14940 this.deltaSetXY = null;
14942 this.startPageX = p[0];
14943 this.startPageY = p[1];
14947 * Add this instance to a group of related drag/drop objects. All
14948 * instances belong to at least one group, and can belong to as many
14949 * groups as needed.
14950 * @method addToGroup
14951 * @param sGroup {string} the name of the group
14953 addToGroup: function(sGroup) {
14954 this.groups[sGroup] = true;
14955 this.DDM.regDragDrop(this, sGroup);
14959 * Remove's this instance from the supplied interaction group
14960 * @method removeFromGroup
14961 * @param {string} sGroup The group to drop
14963 removeFromGroup: function(sGroup) {
14964 if (this.groups[sGroup]) {
14965 delete this.groups[sGroup];
14968 this.DDM.removeDDFromGroup(this, sGroup);
14972 * Allows you to specify that an element other than the linked element
14973 * will be moved with the cursor during a drag
14974 * @method setDragElId
14975 * @param id {string} the id of the element that will be used to initiate the drag
14977 setDragElId: function(id) {
14978 this.dragElId = id;
14982 * Allows you to specify a child of the linked element that should be
14983 * used to initiate the drag operation. An example of this would be if
14984 * you have a content div with text and links. Clicking anywhere in the
14985 * content area would normally start the drag operation. Use this method
14986 * to specify that an element inside of the content div is the element
14987 * that starts the drag operation.
14988 * @method setHandleElId
14989 * @param id {string} the id of the element that will be used to
14990 * initiate the drag.
14992 setHandleElId: function(id) {
14993 if (typeof id !== "string") {
14996 this.handleElId = id;
14997 this.DDM.regHandle(this.id, id);
15001 * Allows you to set an element outside of the linked element as a drag
15003 * @method setOuterHandleElId
15004 * @param id the id of the element that will be used to initiate the drag
15006 setOuterHandleElId: function(id) {
15007 if (typeof id !== "string") {
15010 Event.on(id, "mousedown",
15011 this.handleMouseDown, this);
15012 this.setHandleElId(id);
15014 this.hasOuterHandles = true;
15018 * Remove all drag and drop hooks for this element
15021 unreg: function() {
15022 Event.un(this.id, "mousedown",
15023 this.handleMouseDown);
15024 this._domRef = null;
15025 this.DDM._remove(this);
15028 destroy : function(){
15033 * Returns true if this instance is locked, or the drag drop mgr is locked
15034 * (meaning that all drag/drop is disabled on the page.)
15036 * @return {boolean} true if this obj or all drag/drop is locked, else
15039 isLocked: function() {
15040 return (this.DDM.isLocked() || this.locked);
15044 * Fired when this object is clicked
15045 * @method handleMouseDown
15047 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
15050 handleMouseDown: function(e, oDD){
15051 if (this.primaryButtonOnly && e.button != 0) {
15055 if (this.isLocked()) {
15059 this.DDM.refreshCache(this.groups);
15061 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
15062 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
15064 if (this.clickValidator(e)) {
15066 // set the initial element position
15067 this.setStartPosition();
15070 this.b4MouseDown(e);
15071 this.onMouseDown(e);
15073 this.DDM.handleMouseDown(e, this);
15075 this.DDM.stopEvent(e);
15083 clickValidator: function(e) {
15084 var target = e.getTarget();
15085 return ( this.isValidHandleChild(target) &&
15086 (this.id == this.handleElId ||
15087 this.DDM.handleWasClicked(target, this.id)) );
15091 * Allows you to specify a tag name that should not start a drag operation
15092 * when clicked. This is designed to facilitate embedding links within a
15093 * drag handle that do something other than start the drag.
15094 * @method addInvalidHandleType
15095 * @param {string} tagName the type of element to exclude
15097 addInvalidHandleType: function(tagName) {
15098 var type = tagName.toUpperCase();
15099 this.invalidHandleTypes[type] = type;
15103 * Lets you to specify an element id for a child of a drag handle
15104 * that should not initiate a drag
15105 * @method addInvalidHandleId
15106 * @param {string} id the element id of the element you wish to ignore
15108 addInvalidHandleId: function(id) {
15109 if (typeof id !== "string") {
15112 this.invalidHandleIds[id] = id;
15116 * Lets you specify a css class of elements that will not initiate a drag
15117 * @method addInvalidHandleClass
15118 * @param {string} cssClass the class of the elements you wish to ignore
15120 addInvalidHandleClass: function(cssClass) {
15121 this.invalidHandleClasses.push(cssClass);
15125 * Unsets an excluded tag name set by addInvalidHandleType
15126 * @method removeInvalidHandleType
15127 * @param {string} tagName the type of element to unexclude
15129 removeInvalidHandleType: function(tagName) {
15130 var type = tagName.toUpperCase();
15131 // this.invalidHandleTypes[type] = null;
15132 delete this.invalidHandleTypes[type];
15136 * Unsets an invalid handle id
15137 * @method removeInvalidHandleId
15138 * @param {string} id the id of the element to re-enable
15140 removeInvalidHandleId: function(id) {
15141 if (typeof id !== "string") {
15144 delete this.invalidHandleIds[id];
15148 * Unsets an invalid css class
15149 * @method removeInvalidHandleClass
15150 * @param {string} cssClass the class of the element(s) you wish to
15153 removeInvalidHandleClass: function(cssClass) {
15154 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
15155 if (this.invalidHandleClasses[i] == cssClass) {
15156 delete this.invalidHandleClasses[i];
15162 * Checks the tag exclusion list to see if this click should be ignored
15163 * @method isValidHandleChild
15164 * @param {HTMLElement} node the HTMLElement to evaluate
15165 * @return {boolean} true if this is a valid tag type, false if not
15167 isValidHandleChild: function(node) {
15170 // var n = (node.nodeName == "#text") ? node.parentNode : node;
15173 nodeName = node.nodeName.toUpperCase();
15175 nodeName = node.nodeName;
15177 valid = valid && !this.invalidHandleTypes[nodeName];
15178 valid = valid && !this.invalidHandleIds[node.id];
15180 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
15181 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
15190 * Create the array of horizontal tick marks if an interval was specified
15191 * in setXConstraint().
15192 * @method setXTicks
15195 setXTicks: function(iStartX, iTickSize) {
15197 this.xTickSize = iTickSize;
15201 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
15203 this.xTicks[this.xTicks.length] = i;
15208 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
15210 this.xTicks[this.xTicks.length] = i;
15215 this.xTicks.sort(this.DDM.numericSort) ;
15219 * Create the array of vertical tick marks if an interval was specified in
15220 * setYConstraint().
15221 * @method setYTicks
15224 setYTicks: function(iStartY, iTickSize) {
15226 this.yTickSize = iTickSize;
15230 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
15232 this.yTicks[this.yTicks.length] = i;
15237 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
15239 this.yTicks[this.yTicks.length] = i;
15244 this.yTicks.sort(this.DDM.numericSort) ;
15248 * By default, the element can be dragged any place on the screen. Use
15249 * this method to limit the horizontal travel of the element. Pass in
15250 * 0,0 for the parameters if you want to lock the drag to the y axis.
15251 * @method setXConstraint
15252 * @param {int} iLeft the number of pixels the element can move to the left
15253 * @param {int} iRight the number of pixels the element can move to the
15255 * @param {int} iTickSize optional parameter for specifying that the
15257 * should move iTickSize pixels at a time.
15259 setXConstraint: function(iLeft, iRight, iTickSize) {
15260 this.leftConstraint = iLeft;
15261 this.rightConstraint = iRight;
15263 this.minX = this.initPageX - iLeft;
15264 this.maxX = this.initPageX + iRight;
15265 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
15267 this.constrainX = true;
15271 * Clears any constraints applied to this instance. Also clears ticks
15272 * since they can't exist independent of a constraint at this time.
15273 * @method clearConstraints
15275 clearConstraints: function() {
15276 this.constrainX = false;
15277 this.constrainY = false;
15282 * Clears any tick interval defined for this instance
15283 * @method clearTicks
15285 clearTicks: function() {
15286 this.xTicks = null;
15287 this.yTicks = null;
15288 this.xTickSize = 0;
15289 this.yTickSize = 0;
15293 * By default, the element can be dragged any place on the screen. Set
15294 * this to limit the vertical travel of the element. Pass in 0,0 for the
15295 * parameters if you want to lock the drag to the x axis.
15296 * @method setYConstraint
15297 * @param {int} iUp the number of pixels the element can move up
15298 * @param {int} iDown the number of pixels the element can move down
15299 * @param {int} iTickSize optional parameter for specifying that the
15300 * element should move iTickSize pixels at a time.
15302 setYConstraint: function(iUp, iDown, iTickSize) {
15303 this.topConstraint = iUp;
15304 this.bottomConstraint = iDown;
15306 this.minY = this.initPageY - iUp;
15307 this.maxY = this.initPageY + iDown;
15308 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
15310 this.constrainY = true;
15315 * resetConstraints must be called if you manually reposition a dd element.
15316 * @method resetConstraints
15317 * @param {boolean} maintainOffset
15319 resetConstraints: function() {
15322 // Maintain offsets if necessary
15323 if (this.initPageX || this.initPageX === 0) {
15324 // figure out how much this thing has moved
15325 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
15326 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
15328 this.setInitPosition(dx, dy);
15330 // This is the first time we have detected the element's position
15332 this.setInitPosition();
15335 if (this.constrainX) {
15336 this.setXConstraint( this.leftConstraint,
15337 this.rightConstraint,
15341 if (this.constrainY) {
15342 this.setYConstraint( this.topConstraint,
15343 this.bottomConstraint,
15349 * Normally the drag element is moved pixel by pixel, but we can specify
15350 * that it move a number of pixels at a time. This method resolves the
15351 * location when we have it set up like this.
15353 * @param {int} val where we want to place the object
15354 * @param {int[]} tickArray sorted array of valid points
15355 * @return {int} the closest tick
15358 getTick: function(val, tickArray) {
15361 // If tick interval is not defined, it is effectively 1 pixel,
15362 // so we return the value passed to us.
15364 } else if (tickArray[0] >= val) {
15365 // The value is lower than the first tick, so we return the first
15367 return tickArray[0];
15369 for (var i=0, len=tickArray.length; i<len; ++i) {
15371 if (tickArray[next] && tickArray[next] >= val) {
15372 var diff1 = val - tickArray[i];
15373 var diff2 = tickArray[next] - val;
15374 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
15378 // The value is larger than the last tick, so we return the last
15380 return tickArray[tickArray.length - 1];
15387 * @return {string} string representation of the dd obj
15389 toString: function() {
15390 return ("DragDrop " + this.id);
15398 * Ext JS Library 1.1.1
15399 * Copyright(c) 2006-2007, Ext JS, LLC.
15401 * Originally Released Under LGPL - original licence link has changed is not relivant.
15404 * <script type="text/javascript">
15409 * The drag and drop utility provides a framework for building drag and drop
15410 * applications. In addition to enabling drag and drop for specific elements,
15411 * the drag and drop elements are tracked by the manager class, and the
15412 * interactions between the various elements are tracked during the drag and
15413 * the implementing code is notified about these important moments.
15416 // Only load the library once. Rewriting the manager class would orphan
15417 // existing drag and drop instances.
15418 if (!Roo.dd.DragDropMgr) {
15421 * @class Roo.dd.DragDropMgr
15422 * DragDropMgr is a singleton that tracks the element interaction for
15423 * all DragDrop items in the window. Generally, you will not call
15424 * this class directly, but it does have helper methods that could
15425 * be useful in your DragDrop implementations.
15428 Roo.dd.DragDropMgr = function() {
15430 var Event = Roo.EventManager;
15435 * Two dimensional Array of registered DragDrop objects. The first
15436 * dimension is the DragDrop item group, the second the DragDrop
15439 * @type {string: string}
15446 * Array of element ids defined as drag handles. Used to determine
15447 * if the element that generated the mousedown event is actually the
15448 * handle and not the html element itself.
15449 * @property handleIds
15450 * @type {string: string}
15457 * the DragDrop object that is currently being dragged
15458 * @property dragCurrent
15466 * the DragDrop object(s) that are being hovered over
15467 * @property dragOvers
15475 * the X distance between the cursor and the object being dragged
15484 * the Y distance between the cursor and the object being dragged
15493 * Flag to determine if we should prevent the default behavior of the
15494 * events we define. By default this is true, but this can be set to
15495 * false if you need the default behavior (not recommended)
15496 * @property preventDefault
15500 preventDefault: true,
15503 * Flag to determine if we should stop the propagation of the events
15504 * we generate. This is true by default but you may want to set it to
15505 * false if the html element contains other features that require the
15507 * @property stopPropagation
15511 stopPropagation: true,
15514 * Internal flag that is set to true when drag and drop has been
15516 * @property initialized
15523 * All drag and drop can be disabled.
15531 * Called the first time an element is registered.
15537 this.initialized = true;
15541 * In point mode, drag and drop interaction is defined by the
15542 * location of the cursor during the drag/drop
15550 * In intersect mode, drag and drop interactio nis defined by the
15551 * overlap of two or more drag and drop objects.
15552 * @property INTERSECT
15559 * The current drag and drop mode. Default: POINT
15567 * Runs method on all drag and drop objects
15568 * @method _execOnAll
15572 _execOnAll: function(sMethod, args) {
15573 for (var i in this.ids) {
15574 for (var j in this.ids[i]) {
15575 var oDD = this.ids[i][j];
15576 if (! this.isTypeOfDD(oDD)) {
15579 oDD[sMethod].apply(oDD, args);
15585 * Drag and drop initialization. Sets up the global event handlers
15590 _onLoad: function() {
15595 Event.on(document, "mouseup", this.handleMouseUp, this, true);
15596 Event.on(document, "mousemove", this.handleMouseMove, this, true);
15597 Event.on(window, "unload", this._onUnload, this, true);
15598 Event.on(window, "resize", this._onResize, this, true);
15599 // Event.on(window, "mouseout", this._test);
15604 * Reset constraints on all drag and drop objs
15605 * @method _onResize
15609 _onResize: function(e) {
15610 this._execOnAll("resetConstraints", []);
15614 * Lock all drag and drop functionality
15618 lock: function() { this.locked = true; },
15621 * Unlock all drag and drop functionality
15625 unlock: function() { this.locked = false; },
15628 * Is drag and drop locked?
15630 * @return {boolean} True if drag and drop is locked, false otherwise.
15633 isLocked: function() { return this.locked; },
15636 * Location cache that is set for all drag drop objects when a drag is
15637 * initiated, cleared when the drag is finished.
15638 * @property locationCache
15645 * Set useCache to false if you want to force object the lookup of each
15646 * drag and drop linked element constantly during a drag.
15647 * @property useCache
15654 * The number of pixels that the mouse needs to move after the
15655 * mousedown before the drag is initiated. Default=3;
15656 * @property clickPixelThresh
15660 clickPixelThresh: 3,
15663 * The number of milliseconds after the mousedown event to initiate the
15664 * drag if we don't get a mouseup event. Default=1000
15665 * @property clickTimeThresh
15669 clickTimeThresh: 350,
15672 * Flag that indicates that either the drag pixel threshold or the
15673 * mousdown time threshold has been met
15674 * @property dragThreshMet
15679 dragThreshMet: false,
15682 * Timeout used for the click time threshold
15683 * @property clickTimeout
15688 clickTimeout: null,
15691 * The X position of the mousedown event stored for later use when a
15692 * drag threshold is met.
15701 * The Y position of the mousedown event stored for later use when a
15702 * drag threshold is met.
15711 * Each DragDrop instance must be registered with the DragDropMgr.
15712 * This is executed in DragDrop.init()
15713 * @method regDragDrop
15714 * @param {DragDrop} oDD the DragDrop object to register
15715 * @param {String} sGroup the name of the group this element belongs to
15718 regDragDrop: function(oDD, sGroup) {
15719 if (!this.initialized) { this.init(); }
15721 if (!this.ids[sGroup]) {
15722 this.ids[sGroup] = {};
15724 this.ids[sGroup][oDD.id] = oDD;
15728 * Removes the supplied dd instance from the supplied group. Executed
15729 * by DragDrop.removeFromGroup, so don't call this function directly.
15730 * @method removeDDFromGroup
15734 removeDDFromGroup: function(oDD, sGroup) {
15735 if (!this.ids[sGroup]) {
15736 this.ids[sGroup] = {};
15739 var obj = this.ids[sGroup];
15740 if (obj && obj[oDD.id]) {
15741 delete obj[oDD.id];
15746 * Unregisters a drag and drop item. This is executed in
15747 * DragDrop.unreg, use that method instead of calling this directly.
15752 _remove: function(oDD) {
15753 for (var g in oDD.groups) {
15754 if (g && this.ids[g][oDD.id]) {
15755 delete this.ids[g][oDD.id];
15758 delete this.handleIds[oDD.id];
15762 * Each DragDrop handle element must be registered. This is done
15763 * automatically when executing DragDrop.setHandleElId()
15764 * @method regHandle
15765 * @param {String} sDDId the DragDrop id this element is a handle for
15766 * @param {String} sHandleId the id of the element that is the drag
15770 regHandle: function(sDDId, sHandleId) {
15771 if (!this.handleIds[sDDId]) {
15772 this.handleIds[sDDId] = {};
15774 this.handleIds[sDDId][sHandleId] = sHandleId;
15778 * Utility function to determine if a given element has been
15779 * registered as a drag drop item.
15780 * @method isDragDrop
15781 * @param {String} id the element id to check
15782 * @return {boolean} true if this element is a DragDrop item,
15786 isDragDrop: function(id) {
15787 return ( this.getDDById(id) ) ? true : false;
15791 * Returns the drag and drop instances that are in all groups the
15792 * passed in instance belongs to.
15793 * @method getRelated
15794 * @param {DragDrop} p_oDD the obj to get related data for
15795 * @param {boolean} bTargetsOnly if true, only return targetable objs
15796 * @return {DragDrop[]} the related instances
15799 getRelated: function(p_oDD, bTargetsOnly) {
15801 for (var i in p_oDD.groups) {
15802 for (j in this.ids[i]) {
15803 var dd = this.ids[i][j];
15804 if (! this.isTypeOfDD(dd)) {
15807 if (!bTargetsOnly || dd.isTarget) {
15808 oDDs[oDDs.length] = dd;
15817 * Returns true if the specified dd target is a legal target for
15818 * the specifice drag obj
15819 * @method isLegalTarget
15820 * @param {DragDrop} the drag obj
15821 * @param {DragDrop} the target
15822 * @return {boolean} true if the target is a legal target for the
15826 isLegalTarget: function (oDD, oTargetDD) {
15827 var targets = this.getRelated(oDD, true);
15828 for (var i=0, len=targets.length;i<len;++i) {
15829 if (targets[i].id == oTargetDD.id) {
15838 * My goal is to be able to transparently determine if an object is
15839 * typeof DragDrop, and the exact subclass of DragDrop. typeof
15840 * returns "object", oDD.constructor.toString() always returns
15841 * "DragDrop" and not the name of the subclass. So for now it just
15842 * evaluates a well-known variable in DragDrop.
15843 * @method isTypeOfDD
15844 * @param {Object} the object to evaluate
15845 * @return {boolean} true if typeof oDD = DragDrop
15848 isTypeOfDD: function (oDD) {
15849 return (oDD && oDD.__ygDragDrop);
15853 * Utility function to determine if a given element has been
15854 * registered as a drag drop handle for the given Drag Drop object.
15856 * @param {String} id the element id to check
15857 * @return {boolean} true if this element is a DragDrop handle, false
15861 isHandle: function(sDDId, sHandleId) {
15862 return ( this.handleIds[sDDId] &&
15863 this.handleIds[sDDId][sHandleId] );
15867 * Returns the DragDrop instance for a given id
15868 * @method getDDById
15869 * @param {String} id the id of the DragDrop object
15870 * @return {DragDrop} the drag drop object, null if it is not found
15873 getDDById: function(id) {
15874 for (var i in this.ids) {
15875 if (this.ids[i][id]) {
15876 return this.ids[i][id];
15883 * Fired after a registered DragDrop object gets the mousedown event.
15884 * Sets up the events required to track the object being dragged
15885 * @method handleMouseDown
15886 * @param {Event} e the event
15887 * @param oDD the DragDrop object being dragged
15891 handleMouseDown: function(e, oDD) {
15893 Roo.QuickTips.disable();
15895 this.currentTarget = e.getTarget();
15897 this.dragCurrent = oDD;
15899 var el = oDD.getEl();
15901 // track start position
15902 this.startX = e.getPageX();
15903 this.startY = e.getPageY();
15905 this.deltaX = this.startX - el.offsetLeft;
15906 this.deltaY = this.startY - el.offsetTop;
15908 this.dragThreshMet = false;
15910 this.clickTimeout = setTimeout(
15912 var DDM = Roo.dd.DDM;
15913 DDM.startDrag(DDM.startX, DDM.startY);
15915 this.clickTimeThresh );
15919 * Fired when either the drag pixel threshol or the mousedown hold
15920 * time threshold has been met.
15921 * @method startDrag
15922 * @param x {int} the X position of the original mousedown
15923 * @param y {int} the Y position of the original mousedown
15926 startDrag: function(x, y) {
15927 clearTimeout(this.clickTimeout);
15928 if (this.dragCurrent) {
15929 this.dragCurrent.b4StartDrag(x, y);
15930 this.dragCurrent.startDrag(x, y);
15932 this.dragThreshMet = true;
15936 * Internal function to handle the mouseup event. Will be invoked
15937 * from the context of the document.
15938 * @method handleMouseUp
15939 * @param {Event} e the event
15943 handleMouseUp: function(e) {
15946 Roo.QuickTips.enable();
15948 if (! this.dragCurrent) {
15952 clearTimeout(this.clickTimeout);
15954 if (this.dragThreshMet) {
15955 this.fireEvents(e, true);
15965 * Utility to stop event propagation and event default, if these
15966 * features are turned on.
15967 * @method stopEvent
15968 * @param {Event} e the event as returned by this.getEvent()
15971 stopEvent: function(e){
15972 if(this.stopPropagation) {
15973 e.stopPropagation();
15976 if (this.preventDefault) {
15977 e.preventDefault();
15982 * Internal function to clean up event handlers after the drag
15983 * operation is complete
15985 * @param {Event} e the event
15989 stopDrag: function(e) {
15990 // Fire the drag end event for the item that was dragged
15991 if (this.dragCurrent) {
15992 if (this.dragThreshMet) {
15993 this.dragCurrent.b4EndDrag(e);
15994 this.dragCurrent.endDrag(e);
15997 this.dragCurrent.onMouseUp(e);
16000 this.dragCurrent = null;
16001 this.dragOvers = {};
16005 * Internal function to handle the mousemove event. Will be invoked
16006 * from the context of the html element.
16008 * @TODO figure out what we can do about mouse events lost when the
16009 * user drags objects beyond the window boundary. Currently we can
16010 * detect this in internet explorer by verifying that the mouse is
16011 * down during the mousemove event. Firefox doesn't give us the
16012 * button state on the mousemove event.
16013 * @method handleMouseMove
16014 * @param {Event} e the event
16018 handleMouseMove: function(e) {
16019 if (! this.dragCurrent) {
16023 // var button = e.which || e.button;
16025 // check for IE mouseup outside of page boundary
16026 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
16028 return this.handleMouseUp(e);
16031 if (!this.dragThreshMet) {
16032 var diffX = Math.abs(this.startX - e.getPageX());
16033 var diffY = Math.abs(this.startY - e.getPageY());
16034 if (diffX > this.clickPixelThresh ||
16035 diffY > this.clickPixelThresh) {
16036 this.startDrag(this.startX, this.startY);
16040 if (this.dragThreshMet) {
16041 this.dragCurrent.b4Drag(e);
16042 this.dragCurrent.onDrag(e);
16043 if(!this.dragCurrent.moveOnly){
16044 this.fireEvents(e, false);
16054 * Iterates over all of the DragDrop elements to find ones we are
16055 * hovering over or dropping on
16056 * @method fireEvents
16057 * @param {Event} e the event
16058 * @param {boolean} isDrop is this a drop op or a mouseover op?
16062 fireEvents: function(e, isDrop) {
16063 var dc = this.dragCurrent;
16065 // If the user did the mouse up outside of the window, we could
16066 // get here even though we have ended the drag.
16067 if (!dc || dc.isLocked()) {
16071 var pt = e.getPoint();
16073 // cache the previous dragOver array
16079 var enterEvts = [];
16081 // Check to see if the object(s) we were hovering over is no longer
16082 // being hovered over so we can fire the onDragOut event
16083 for (var i in this.dragOvers) {
16085 var ddo = this.dragOvers[i];
16087 if (! this.isTypeOfDD(ddo)) {
16091 if (! this.isOverTarget(pt, ddo, this.mode)) {
16092 outEvts.push( ddo );
16095 oldOvers[i] = true;
16096 delete this.dragOvers[i];
16099 for (var sGroup in dc.groups) {
16101 if ("string" != typeof sGroup) {
16105 for (i in this.ids[sGroup]) {
16106 var oDD = this.ids[sGroup][i];
16107 if (! this.isTypeOfDD(oDD)) {
16111 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
16112 if (this.isOverTarget(pt, oDD, this.mode)) {
16113 // look for drop interactions
16115 dropEvts.push( oDD );
16116 // look for drag enter and drag over interactions
16119 // initial drag over: dragEnter fires
16120 if (!oldOvers[oDD.id]) {
16121 enterEvts.push( oDD );
16122 // subsequent drag overs: dragOver fires
16124 overEvts.push( oDD );
16127 this.dragOvers[oDD.id] = oDD;
16135 if (outEvts.length) {
16136 dc.b4DragOut(e, outEvts);
16137 dc.onDragOut(e, outEvts);
16140 if (enterEvts.length) {
16141 dc.onDragEnter(e, enterEvts);
16144 if (overEvts.length) {
16145 dc.b4DragOver(e, overEvts);
16146 dc.onDragOver(e, overEvts);
16149 if (dropEvts.length) {
16150 dc.b4DragDrop(e, dropEvts);
16151 dc.onDragDrop(e, dropEvts);
16155 // fire dragout events
16157 for (i=0, len=outEvts.length; i<len; ++i) {
16158 dc.b4DragOut(e, outEvts[i].id);
16159 dc.onDragOut(e, outEvts[i].id);
16162 // fire enter events
16163 for (i=0,len=enterEvts.length; i<len; ++i) {
16164 // dc.b4DragEnter(e, oDD.id);
16165 dc.onDragEnter(e, enterEvts[i].id);
16168 // fire over events
16169 for (i=0,len=overEvts.length; i<len; ++i) {
16170 dc.b4DragOver(e, overEvts[i].id);
16171 dc.onDragOver(e, overEvts[i].id);
16174 // fire drop events
16175 for (i=0, len=dropEvts.length; i<len; ++i) {
16176 dc.b4DragDrop(e, dropEvts[i].id);
16177 dc.onDragDrop(e, dropEvts[i].id);
16182 // notify about a drop that did not find a target
16183 if (isDrop && !dropEvts.length) {
16184 dc.onInvalidDrop(e);
16190 * Helper function for getting the best match from the list of drag
16191 * and drop objects returned by the drag and drop events when we are
16192 * in INTERSECT mode. It returns either the first object that the
16193 * cursor is over, or the object that has the greatest overlap with
16194 * the dragged element.
16195 * @method getBestMatch
16196 * @param {DragDrop[]} dds The array of drag and drop objects
16198 * @return {DragDrop} The best single match
16201 getBestMatch: function(dds) {
16203 // Return null if the input is not what we expect
16204 //if (!dds || !dds.length || dds.length == 0) {
16206 // If there is only one item, it wins
16207 //} else if (dds.length == 1) {
16209 var len = dds.length;
16214 // Loop through the targeted items
16215 for (var i=0; i<len; ++i) {
16217 // If the cursor is over the object, it wins. If the
16218 // cursor is over multiple matches, the first one we come
16220 if (dd.cursorIsOver) {
16223 // Otherwise the object with the most overlap wins
16226 winner.overlap.getArea() < dd.overlap.getArea()) {
16237 * Refreshes the cache of the top-left and bottom-right points of the
16238 * drag and drop objects in the specified group(s). This is in the
16239 * format that is stored in the drag and drop instance, so typical
16242 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
16246 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
16248 * @TODO this really should be an indexed array. Alternatively this
16249 * method could accept both.
16250 * @method refreshCache
16251 * @param {Object} groups an associative array of groups to refresh
16254 refreshCache: function(groups) {
16255 for (var sGroup in groups) {
16256 if ("string" != typeof sGroup) {
16259 for (var i in this.ids[sGroup]) {
16260 var oDD = this.ids[sGroup][i];
16262 if (this.isTypeOfDD(oDD)) {
16263 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
16264 var loc = this.getLocation(oDD);
16266 this.locationCache[oDD.id] = loc;
16268 delete this.locationCache[oDD.id];
16269 // this will unregister the drag and drop object if
16270 // the element is not in a usable state
16279 * This checks to make sure an element exists and is in the DOM. The
16280 * main purpose is to handle cases where innerHTML is used to remove
16281 * drag and drop objects from the DOM. IE provides an 'unspecified
16282 * error' when trying to access the offsetParent of such an element
16284 * @param {HTMLElement} el the element to check
16285 * @return {boolean} true if the element looks usable
16288 verifyEl: function(el) {
16293 parent = el.offsetParent;
16296 parent = el.offsetParent;
16307 * Returns a Region object containing the drag and drop element's position
16308 * and size, including the padding configured for it
16309 * @method getLocation
16310 * @param {DragDrop} oDD the drag and drop object to get the
16312 * @return {Roo.lib.Region} a Region object representing the total area
16313 * the element occupies, including any padding
16314 * the instance is configured for.
16317 getLocation: function(oDD) {
16318 if (! this.isTypeOfDD(oDD)) {
16322 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
16325 pos= Roo.lib.Dom.getXY(el);
16333 x2 = x1 + el.offsetWidth;
16335 y2 = y1 + el.offsetHeight;
16337 t = y1 - oDD.padding[0];
16338 r = x2 + oDD.padding[1];
16339 b = y2 + oDD.padding[2];
16340 l = x1 - oDD.padding[3];
16342 return new Roo.lib.Region( t, r, b, l );
16346 * Checks the cursor location to see if it over the target
16347 * @method isOverTarget
16348 * @param {Roo.lib.Point} pt The point to evaluate
16349 * @param {DragDrop} oTarget the DragDrop object we are inspecting
16350 * @return {boolean} true if the mouse is over the target
16354 isOverTarget: function(pt, oTarget, intersect) {
16355 // use cache if available
16356 var loc = this.locationCache[oTarget.id];
16357 if (!loc || !this.useCache) {
16358 loc = this.getLocation(oTarget);
16359 this.locationCache[oTarget.id] = loc;
16367 oTarget.cursorIsOver = loc.contains( pt );
16369 // DragDrop is using this as a sanity check for the initial mousedown
16370 // in this case we are done. In POINT mode, if the drag obj has no
16371 // contraints, we are also done. Otherwise we need to evaluate the
16372 // location of the target as related to the actual location of the
16373 // dragged element.
16374 var dc = this.dragCurrent;
16375 if (!dc || !dc.getTargetCoord ||
16376 (!intersect && !dc.constrainX && !dc.constrainY)) {
16377 return oTarget.cursorIsOver;
16380 oTarget.overlap = null;
16382 // Get the current location of the drag element, this is the
16383 // location of the mouse event less the delta that represents
16384 // where the original mousedown happened on the element. We
16385 // need to consider constraints and ticks as well.
16386 var pos = dc.getTargetCoord(pt.x, pt.y);
16388 var el = dc.getDragEl();
16389 var curRegion = new Roo.lib.Region( pos.y,
16390 pos.x + el.offsetWidth,
16391 pos.y + el.offsetHeight,
16394 var overlap = curRegion.intersect(loc);
16397 oTarget.overlap = overlap;
16398 return (intersect) ? true : oTarget.cursorIsOver;
16405 * unload event handler
16406 * @method _onUnload
16410 _onUnload: function(e, me) {
16411 Roo.dd.DragDropMgr.unregAll();
16415 * Cleans up the drag and drop events and objects.
16420 unregAll: function() {
16422 if (this.dragCurrent) {
16424 this.dragCurrent = null;
16427 this._execOnAll("unreg", []);
16429 for (i in this.elementCache) {
16430 delete this.elementCache[i];
16433 this.elementCache = {};
16438 * A cache of DOM elements
16439 * @property elementCache
16446 * Get the wrapper for the DOM element specified
16447 * @method getElWrapper
16448 * @param {String} id the id of the element to get
16449 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
16451 * @deprecated This wrapper isn't that useful
16454 getElWrapper: function(id) {
16455 var oWrapper = this.elementCache[id];
16456 if (!oWrapper || !oWrapper.el) {
16457 oWrapper = this.elementCache[id] =
16458 new this.ElementWrapper(Roo.getDom(id));
16464 * Returns the actual DOM element
16465 * @method getElement
16466 * @param {String} id the id of the elment to get
16467 * @return {Object} The element
16468 * @deprecated use Roo.getDom instead
16471 getElement: function(id) {
16472 return Roo.getDom(id);
16476 * Returns the style property for the DOM element (i.e.,
16477 * document.getElById(id).style)
16479 * @param {String} id the id of the elment to get
16480 * @return {Object} The style property of the element
16481 * @deprecated use Roo.getDom instead
16484 getCss: function(id) {
16485 var el = Roo.getDom(id);
16486 return (el) ? el.style : null;
16490 * Inner class for cached elements
16491 * @class DragDropMgr.ElementWrapper
16496 ElementWrapper: function(el) {
16501 this.el = el || null;
16506 this.id = this.el && el.id;
16508 * A reference to the style property
16511 this.css = this.el && el.style;
16515 * Returns the X position of an html element
16517 * @param el the element for which to get the position
16518 * @return {int} the X coordinate
16520 * @deprecated use Roo.lib.Dom.getX instead
16523 getPosX: function(el) {
16524 return Roo.lib.Dom.getX(el);
16528 * Returns the Y position of an html element
16530 * @param el the element for which to get the position
16531 * @return {int} the Y coordinate
16532 * @deprecated use Roo.lib.Dom.getY instead
16535 getPosY: function(el) {
16536 return Roo.lib.Dom.getY(el);
16540 * Swap two nodes. In IE, we use the native method, for others we
16541 * emulate the IE behavior
16543 * @param n1 the first node to swap
16544 * @param n2 the other node to swap
16547 swapNode: function(n1, n2) {
16551 var p = n2.parentNode;
16552 var s = n2.nextSibling;
16555 p.insertBefore(n1, n2);
16556 } else if (n2 == n1.nextSibling) {
16557 p.insertBefore(n2, n1);
16559 n1.parentNode.replaceChild(n2, n1);
16560 p.insertBefore(n1, s);
16566 * Returns the current scroll position
16567 * @method getScroll
16571 getScroll: function () {
16572 var t, l, dde=document.documentElement, db=document.body;
16573 if (dde && (dde.scrollTop || dde.scrollLeft)) {
16575 l = dde.scrollLeft;
16582 return { top: t, left: l };
16586 * Returns the specified element style property
16588 * @param {HTMLElement} el the element
16589 * @param {string} styleProp the style property
16590 * @return {string} The value of the style property
16591 * @deprecated use Roo.lib.Dom.getStyle
16594 getStyle: function(el, styleProp) {
16595 return Roo.fly(el).getStyle(styleProp);
16599 * Gets the scrollTop
16600 * @method getScrollTop
16601 * @return {int} the document's scrollTop
16604 getScrollTop: function () { return this.getScroll().top; },
16607 * Gets the scrollLeft
16608 * @method getScrollLeft
16609 * @return {int} the document's scrollTop
16612 getScrollLeft: function () { return this.getScroll().left; },
16615 * Sets the x/y position of an element to the location of the
16618 * @param {HTMLElement} moveEl The element to move
16619 * @param {HTMLElement} targetEl The position reference element
16622 moveToEl: function (moveEl, targetEl) {
16623 var aCoord = Roo.lib.Dom.getXY(targetEl);
16624 Roo.lib.Dom.setXY(moveEl, aCoord);
16628 * Numeric array sort function
16629 * @method numericSort
16632 numericSort: function(a, b) { return (a - b); },
16636 * @property _timeoutCount
16643 * Trying to make the load order less important. Without this we get
16644 * an error if this file is loaded before the Event Utility.
16645 * @method _addListeners
16649 _addListeners: function() {
16650 var DDM = Roo.dd.DDM;
16651 if ( Roo.lib.Event && document ) {
16654 if (DDM._timeoutCount > 2000) {
16656 setTimeout(DDM._addListeners, 10);
16657 if (document && document.body) {
16658 DDM._timeoutCount += 1;
16665 * Recursively searches the immediate parent and all child nodes for
16666 * the handle element in order to determine wheter or not it was
16668 * @method handleWasClicked
16669 * @param node the html element to inspect
16672 handleWasClicked: function(node, id) {
16673 if (this.isHandle(id, node.id)) {
16676 // check to see if this is a text node child of the one we want
16677 var p = node.parentNode;
16680 if (this.isHandle(id, p.id)) {
16695 // shorter alias, save a few bytes
16696 Roo.dd.DDM = Roo.dd.DragDropMgr;
16697 Roo.dd.DDM._addListeners();
16701 * Ext JS Library 1.1.1
16702 * Copyright(c) 2006-2007, Ext JS, LLC.
16704 * Originally Released Under LGPL - original licence link has changed is not relivant.
16707 * <script type="text/javascript">
16712 * A DragDrop implementation where the linked element follows the
16713 * mouse cursor during a drag.
16714 * @extends Roo.dd.DragDrop
16716 * @param {String} id the id of the linked element
16717 * @param {String} sGroup the group of related DragDrop items
16718 * @param {object} config an object containing configurable attributes
16719 * Valid properties for DD:
16722 Roo.dd.DD = function(id, sGroup, config) {
16724 this.init(id, sGroup, config);
16728 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
16731 * When set to true, the utility automatically tries to scroll the browser
16732 * window wehn a drag and drop element is dragged near the viewport boundary.
16733 * Defaults to true.
16740 * Sets the pointer offset to the distance between the linked element's top
16741 * left corner and the location the element was clicked
16742 * @method autoOffset
16743 * @param {int} iPageX the X coordinate of the click
16744 * @param {int} iPageY the Y coordinate of the click
16746 autoOffset: function(iPageX, iPageY) {
16747 var x = iPageX - this.startPageX;
16748 var y = iPageY - this.startPageY;
16749 this.setDelta(x, y);
16753 * Sets the pointer offset. You can call this directly to force the
16754 * offset to be in a particular location (e.g., pass in 0,0 to set it
16755 * to the center of the object)
16757 * @param {int} iDeltaX the distance from the left
16758 * @param {int} iDeltaY the distance from the top
16760 setDelta: function(iDeltaX, iDeltaY) {
16761 this.deltaX = iDeltaX;
16762 this.deltaY = iDeltaY;
16766 * Sets the drag element to the location of the mousedown or click event,
16767 * maintaining the cursor location relative to the location on the element
16768 * that was clicked. Override this if you want to place the element in a
16769 * location other than where the cursor is.
16770 * @method setDragElPos
16771 * @param {int} iPageX the X coordinate of the mousedown or drag event
16772 * @param {int} iPageY the Y coordinate of the mousedown or drag event
16774 setDragElPos: function(iPageX, iPageY) {
16775 // the first time we do this, we are going to check to make sure
16776 // the element has css positioning
16778 var el = this.getDragEl();
16779 this.alignElWithMouse(el, iPageX, iPageY);
16783 * Sets the element to the location of the mousedown or click event,
16784 * maintaining the cursor location relative to the location on the element
16785 * that was clicked. Override this if you want to place the element in a
16786 * location other than where the cursor is.
16787 * @method alignElWithMouse
16788 * @param {HTMLElement} el the element to move
16789 * @param {int} iPageX the X coordinate of the mousedown or drag event
16790 * @param {int} iPageY the Y coordinate of the mousedown or drag event
16792 alignElWithMouse: function(el, iPageX, iPageY) {
16793 var oCoord = this.getTargetCoord(iPageX, iPageY);
16794 var fly = el.dom ? el : Roo.fly(el);
16795 if (!this.deltaSetXY) {
16796 var aCoord = [oCoord.x, oCoord.y];
16798 var newLeft = fly.getLeft(true);
16799 var newTop = fly.getTop(true);
16800 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
16802 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
16805 this.cachePosition(oCoord.x, oCoord.y);
16806 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
16811 * Saves the most recent position so that we can reset the constraints and
16812 * tick marks on-demand. We need to know this so that we can calculate the
16813 * number of pixels the element is offset from its original position.
16814 * @method cachePosition
16815 * @param iPageX the current x position (optional, this just makes it so we
16816 * don't have to look it up again)
16817 * @param iPageY the current y position (optional, this just makes it so we
16818 * don't have to look it up again)
16820 cachePosition: function(iPageX, iPageY) {
16822 this.lastPageX = iPageX;
16823 this.lastPageY = iPageY;
16825 var aCoord = Roo.lib.Dom.getXY(this.getEl());
16826 this.lastPageX = aCoord[0];
16827 this.lastPageY = aCoord[1];
16832 * Auto-scroll the window if the dragged object has been moved beyond the
16833 * visible window boundary.
16834 * @method autoScroll
16835 * @param {int} x the drag element's x position
16836 * @param {int} y the drag element's y position
16837 * @param {int} h the height of the drag element
16838 * @param {int} w the width of the drag element
16841 autoScroll: function(x, y, h, w) {
16844 // The client height
16845 var clientH = Roo.lib.Dom.getViewWidth();
16847 // The client width
16848 var clientW = Roo.lib.Dom.getViewHeight();
16850 // The amt scrolled down
16851 var st = this.DDM.getScrollTop();
16853 // The amt scrolled right
16854 var sl = this.DDM.getScrollLeft();
16856 // Location of the bottom of the element
16859 // Location of the right of the element
16862 // The distance from the cursor to the bottom of the visible area,
16863 // adjusted so that we don't scroll if the cursor is beyond the
16864 // element drag constraints
16865 var toBot = (clientH + st - y - this.deltaY);
16867 // The distance from the cursor to the right of the visible area
16868 var toRight = (clientW + sl - x - this.deltaX);
16871 // How close to the edge the cursor must be before we scroll
16872 // var thresh = (document.all) ? 100 : 40;
16875 // How many pixels to scroll per autoscroll op. This helps to reduce
16876 // clunky scrolling. IE is more sensitive about this ... it needs this
16877 // value to be higher.
16878 var scrAmt = (document.all) ? 80 : 30;
16880 // Scroll down if we are near the bottom of the visible page and the
16881 // obj extends below the crease
16882 if ( bot > clientH && toBot < thresh ) {
16883 window.scrollTo(sl, st + scrAmt);
16886 // Scroll up if the window is scrolled down and the top of the object
16887 // goes above the top border
16888 if ( y < st && st > 0 && y - st < thresh ) {
16889 window.scrollTo(sl, st - scrAmt);
16892 // Scroll right if the obj is beyond the right border and the cursor is
16893 // near the border.
16894 if ( right > clientW && toRight < thresh ) {
16895 window.scrollTo(sl + scrAmt, st);
16898 // Scroll left if the window has been scrolled to the right and the obj
16899 // extends past the left border
16900 if ( x < sl && sl > 0 && x - sl < thresh ) {
16901 window.scrollTo(sl - scrAmt, st);
16907 * Finds the location the element should be placed if we want to move
16908 * it to where the mouse location less the click offset would place us.
16909 * @method getTargetCoord
16910 * @param {int} iPageX the X coordinate of the click
16911 * @param {int} iPageY the Y coordinate of the click
16912 * @return an object that contains the coordinates (Object.x and Object.y)
16915 getTargetCoord: function(iPageX, iPageY) {
16918 var x = iPageX - this.deltaX;
16919 var y = iPageY - this.deltaY;
16921 if (this.constrainX) {
16922 if (x < this.minX) { x = this.minX; }
16923 if (x > this.maxX) { x = this.maxX; }
16926 if (this.constrainY) {
16927 if (y < this.minY) { y = this.minY; }
16928 if (y > this.maxY) { y = this.maxY; }
16931 x = this.getTick(x, this.xTicks);
16932 y = this.getTick(y, this.yTicks);
16939 * Sets up config options specific to this class. Overrides
16940 * Roo.dd.DragDrop, but all versions of this method through the
16941 * inheritance chain are called
16943 applyConfig: function() {
16944 Roo.dd.DD.superclass.applyConfig.call(this);
16945 this.scroll = (this.config.scroll !== false);
16949 * Event that fires prior to the onMouseDown event. Overrides
16952 b4MouseDown: function(e) {
16953 // this.resetConstraints();
16954 this.autoOffset(e.getPageX(),
16959 * Event that fires prior to the onDrag event. Overrides
16962 b4Drag: function(e) {
16963 this.setDragElPos(e.getPageX(),
16967 toString: function() {
16968 return ("DD " + this.id);
16971 //////////////////////////////////////////////////////////////////////////
16972 // Debugging ygDragDrop events that can be overridden
16973 //////////////////////////////////////////////////////////////////////////
16975 startDrag: function(x, y) {
16978 onDrag: function(e) {
16981 onDragEnter: function(e, id) {
16984 onDragOver: function(e, id) {
16987 onDragOut: function(e, id) {
16990 onDragDrop: function(e, id) {
16993 endDrag: function(e) {
17000 * Ext JS Library 1.1.1
17001 * Copyright(c) 2006-2007, Ext JS, LLC.
17003 * Originally Released Under LGPL - original licence link has changed is not relivant.
17006 * <script type="text/javascript">
17010 * @class Roo.dd.DDProxy
17011 * A DragDrop implementation that inserts an empty, bordered div into
17012 * the document that follows the cursor during drag operations. At the time of
17013 * the click, the frame div is resized to the dimensions of the linked html
17014 * element, and moved to the exact location of the linked element.
17016 * References to the "frame" element refer to the single proxy element that
17017 * was created to be dragged in place of all DDProxy elements on the
17020 * @extends Roo.dd.DD
17022 * @param {String} id the id of the linked html element
17023 * @param {String} sGroup the group of related DragDrop objects
17024 * @param {object} config an object containing configurable attributes
17025 * Valid properties for DDProxy in addition to those in DragDrop:
17026 * resizeFrame, centerFrame, dragElId
17028 Roo.dd.DDProxy = function(id, sGroup, config) {
17030 this.init(id, sGroup, config);
17036 * The default drag frame div id
17037 * @property Roo.dd.DDProxy.dragElId
17041 Roo.dd.DDProxy.dragElId = "ygddfdiv";
17043 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
17046 * By default we resize the drag frame to be the same size as the element
17047 * we want to drag (this is to get the frame effect). We can turn it off
17048 * if we want a different behavior.
17049 * @property resizeFrame
17055 * By default the frame is positioned exactly where the drag element is, so
17056 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
17057 * you do not have constraints on the obj is to have the drag frame centered
17058 * around the cursor. Set centerFrame to true for this effect.
17059 * @property centerFrame
17062 centerFrame: false,
17065 * Creates the proxy element if it does not yet exist
17066 * @method createFrame
17068 createFrame: function() {
17070 var body = document.body;
17072 if (!body || !body.firstChild) {
17073 setTimeout( function() { self.createFrame(); }, 50 );
17077 var div = this.getDragEl();
17080 div = document.createElement("div");
17081 div.id = this.dragElId;
17084 s.position = "absolute";
17085 s.visibility = "hidden";
17087 s.border = "2px solid #aaa";
17090 // appendChild can blow up IE if invoked prior to the window load event
17091 // while rendering a table. It is possible there are other scenarios
17092 // that would cause this to happen as well.
17093 body.insertBefore(div, body.firstChild);
17098 * Initialization for the drag frame element. Must be called in the
17099 * constructor of all subclasses
17100 * @method initFrame
17102 initFrame: function() {
17103 this.createFrame();
17106 applyConfig: function() {
17107 Roo.dd.DDProxy.superclass.applyConfig.call(this);
17109 this.resizeFrame = (this.config.resizeFrame !== false);
17110 this.centerFrame = (this.config.centerFrame);
17111 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
17115 * Resizes the drag frame to the dimensions of the clicked object, positions
17116 * it over the object, and finally displays it
17117 * @method showFrame
17118 * @param {int} iPageX X click position
17119 * @param {int} iPageY Y click position
17122 showFrame: function(iPageX, iPageY) {
17123 var el = this.getEl();
17124 var dragEl = this.getDragEl();
17125 var s = dragEl.style;
17127 this._resizeProxy();
17129 if (this.centerFrame) {
17130 this.setDelta( Math.round(parseInt(s.width, 10)/2),
17131 Math.round(parseInt(s.height, 10)/2) );
17134 this.setDragElPos(iPageX, iPageY);
17136 Roo.fly(dragEl).show();
17140 * The proxy is automatically resized to the dimensions of the linked
17141 * element when a drag is initiated, unless resizeFrame is set to false
17142 * @method _resizeProxy
17145 _resizeProxy: function() {
17146 if (this.resizeFrame) {
17147 var el = this.getEl();
17148 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
17152 // overrides Roo.dd.DragDrop
17153 b4MouseDown: function(e) {
17154 var x = e.getPageX();
17155 var y = e.getPageY();
17156 this.autoOffset(x, y);
17157 this.setDragElPos(x, y);
17160 // overrides Roo.dd.DragDrop
17161 b4StartDrag: function(x, y) {
17162 // show the drag frame
17163 this.showFrame(x, y);
17166 // overrides Roo.dd.DragDrop
17167 b4EndDrag: function(e) {
17168 Roo.fly(this.getDragEl()).hide();
17171 // overrides Roo.dd.DragDrop
17172 // By default we try to move the element to the last location of the frame.
17173 // This is so that the default behavior mirrors that of Roo.dd.DD.
17174 endDrag: function(e) {
17176 var lel = this.getEl();
17177 var del = this.getDragEl();
17179 // Show the drag frame briefly so we can get its position
17180 del.style.visibility = "";
17183 // Hide the linked element before the move to get around a Safari
17185 lel.style.visibility = "hidden";
17186 Roo.dd.DDM.moveToEl(lel, del);
17187 del.style.visibility = "hidden";
17188 lel.style.visibility = "";
17193 beforeMove : function(){
17197 afterDrag : function(){
17201 toString: function() {
17202 return ("DDProxy " + this.id);
17208 * Ext JS Library 1.1.1
17209 * Copyright(c) 2006-2007, Ext JS, LLC.
17211 * Originally Released Under LGPL - original licence link has changed is not relivant.
17214 * <script type="text/javascript">
17218 * @class Roo.dd.DDTarget
17219 * A DragDrop implementation that does not move, but can be a drop
17220 * target. You would get the same result by simply omitting implementation
17221 * for the event callbacks, but this way we reduce the processing cost of the
17222 * event listener and the callbacks.
17223 * @extends Roo.dd.DragDrop
17225 * @param {String} id the id of the element that is a drop target
17226 * @param {String} sGroup the group of related DragDrop objects
17227 * @param {object} config an object containing configurable attributes
17228 * Valid properties for DDTarget in addition to those in
17232 Roo.dd.DDTarget = function(id, sGroup, config) {
17234 this.initTarget(id, sGroup, config);
17238 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
17239 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
17240 toString: function() {
17241 return ("DDTarget " + this.id);
17246 * Ext JS Library 1.1.1
17247 * Copyright(c) 2006-2007, Ext JS, LLC.
17249 * Originally Released Under LGPL - original licence link has changed is not relivant.
17252 * <script type="text/javascript">
17257 * @class Roo.dd.ScrollManager
17258 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
17259 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
17262 Roo.dd.ScrollManager = function(){
17263 var ddm = Roo.dd.DragDropMgr;
17268 var onStop = function(e){
17273 var triggerRefresh = function(){
17274 if(ddm.dragCurrent){
17275 ddm.refreshCache(ddm.dragCurrent.groups);
17279 var doScroll = function(){
17280 if(ddm.dragCurrent){
17281 var dds = Roo.dd.ScrollManager;
17283 if(proc.el.scroll(proc.dir, dds.increment)){
17287 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
17292 var clearProc = function(){
17294 clearInterval(proc.id);
17301 var startProc = function(el, dir){
17305 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
17308 var onFire = function(e, isDrop){
17309 if(isDrop || !ddm.dragCurrent){ return; }
17310 var dds = Roo.dd.ScrollManager;
17311 if(!dragEl || dragEl != ddm.dragCurrent){
17312 dragEl = ddm.dragCurrent;
17313 // refresh regions on drag start
17314 dds.refreshCache();
17317 var xy = Roo.lib.Event.getXY(e);
17318 var pt = new Roo.lib.Point(xy[0], xy[1]);
17319 for(var id in els){
17320 var el = els[id], r = el._region;
17321 if(r && r.contains(pt) && el.isScrollable()){
17322 if(r.bottom - pt.y <= dds.thresh){
17324 startProc(el, "down");
17327 }else if(r.right - pt.x <= dds.thresh){
17329 startProc(el, "left");
17332 }else if(pt.y - r.top <= dds.thresh){
17334 startProc(el, "up");
17337 }else if(pt.x - r.left <= dds.thresh){
17339 startProc(el, "right");
17348 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
17349 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
17353 * Registers new overflow element(s) to auto scroll
17354 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
17356 register : function(el){
17357 if(el instanceof Array){
17358 for(var i = 0, len = el.length; i < len; i++) {
17359 this.register(el[i]);
17368 * Unregisters overflow element(s) so they are no longer scrolled
17369 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
17371 unregister : function(el){
17372 if(el instanceof Array){
17373 for(var i = 0, len = el.length; i < len; i++) {
17374 this.unregister(el[i]);
17383 * The number of pixels from the edge of a container the pointer needs to be to
17384 * trigger scrolling (defaults to 25)
17390 * The number of pixels to scroll in each scroll increment (defaults to 50)
17396 * The frequency of scrolls in milliseconds (defaults to 500)
17402 * True to animate the scroll (defaults to true)
17408 * The animation duration in seconds -
17409 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
17415 * Manually trigger a cache refresh.
17417 refreshCache : function(){
17418 for(var id in els){
17419 if(typeof els[id] == 'object'){ // for people extending the object prototype
17420 els[id]._region = els[id].getRegion();
17427 * Ext JS Library 1.1.1
17428 * Copyright(c) 2006-2007, Ext JS, LLC.
17430 * Originally Released Under LGPL - original licence link has changed is not relivant.
17433 * <script type="text/javascript">
17438 * @class Roo.dd.Registry
17439 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
17440 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
17443 Roo.dd.Registry = function(){
17446 var autoIdSeed = 0;
17448 var getId = function(el, autogen){
17449 if(typeof el == "string"){
17453 if(!id && autogen !== false){
17454 id = "roodd-" + (++autoIdSeed);
17462 * Register a drag drop element
17463 * @param {String|HTMLElement} element The id or DOM node to register
17464 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
17465 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
17466 * knows how to interpret, plus there are some specific properties known to the Registry that should be
17467 * populated in the data object (if applicable):
17469 Value Description<br />
17470 --------- ------------------------------------------<br />
17471 handles Array of DOM nodes that trigger dragging<br />
17472 for the element being registered<br />
17473 isHandle True if the element passed in triggers<br />
17474 dragging itself, else false
17477 register : function(el, data){
17479 if(typeof el == "string"){
17480 el = document.getElementById(el);
17483 elements[getId(el)] = data;
17484 if(data.isHandle !== false){
17485 handles[data.ddel.id] = data;
17488 var hs = data.handles;
17489 for(var i = 0, len = hs.length; i < len; i++){
17490 handles[getId(hs[i])] = data;
17496 * Unregister a drag drop element
17497 * @param {String|HTMLElement} element The id or DOM node to unregister
17499 unregister : function(el){
17500 var id = getId(el, false);
17501 var data = elements[id];
17503 delete elements[id];
17505 var hs = data.handles;
17506 for(var i = 0, len = hs.length; i < len; i++){
17507 delete handles[getId(hs[i], false)];
17514 * Returns the handle registered for a DOM Node by id
17515 * @param {String|HTMLElement} id The DOM node or id to look up
17516 * @return {Object} handle The custom handle data
17518 getHandle : function(id){
17519 if(typeof id != "string"){ // must be element?
17522 return handles[id];
17526 * Returns the handle that is registered for the DOM node that is the target of the event
17527 * @param {Event} e The event
17528 * @return {Object} handle The custom handle data
17530 getHandleFromEvent : function(e){
17531 var t = Roo.lib.Event.getTarget(e);
17532 return t ? handles[t.id] : null;
17536 * Returns a custom data object that is registered for a DOM node by id
17537 * @param {String|HTMLElement} id The DOM node or id to look up
17538 * @return {Object} data The custom data
17540 getTarget : function(id){
17541 if(typeof id != "string"){ // must be element?
17544 return elements[id];
17548 * Returns a custom data object that is registered for the DOM node that is the target of the event
17549 * @param {Event} e The event
17550 * @return {Object} data The custom data
17552 getTargetFromEvent : function(e){
17553 var t = Roo.lib.Event.getTarget(e);
17554 return t ? elements[t.id] || handles[t.id] : null;
17559 * Ext JS Library 1.1.1
17560 * Copyright(c) 2006-2007, Ext JS, LLC.
17562 * Originally Released Under LGPL - original licence link has changed is not relivant.
17565 * <script type="text/javascript">
17570 * @class Roo.dd.StatusProxy
17571 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
17572 * default drag proxy used by all Roo.dd components.
17574 * @param {Object} config
17576 Roo.dd.StatusProxy = function(config){
17577 Roo.apply(this, config);
17578 this.id = this.id || Roo.id();
17579 this.el = new Roo.Layer({
17581 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
17582 {tag: "div", cls: "x-dd-drop-icon"},
17583 {tag: "div", cls: "x-dd-drag-ghost"}
17586 shadow: !config || config.shadow !== false
17588 this.ghost = Roo.get(this.el.dom.childNodes[1]);
17589 this.dropStatus = this.dropNotAllowed;
17592 Roo.dd.StatusProxy.prototype = {
17594 * @cfg {String} dropAllowed
17595 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
17597 dropAllowed : "x-dd-drop-ok",
17599 * @cfg {String} dropNotAllowed
17600 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
17602 dropNotAllowed : "x-dd-drop-nodrop",
17605 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
17606 * over the current target element.
17607 * @param {String} cssClass The css class for the new drop status indicator image
17609 setStatus : function(cssClass){
17610 cssClass = cssClass || this.dropNotAllowed;
17611 if(this.dropStatus != cssClass){
17612 this.el.replaceClass(this.dropStatus, cssClass);
17613 this.dropStatus = cssClass;
17618 * Resets the status indicator to the default dropNotAllowed value
17619 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
17621 reset : function(clearGhost){
17622 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
17623 this.dropStatus = this.dropNotAllowed;
17625 this.ghost.update("");
17630 * Updates the contents of the ghost element
17631 * @param {String} html The html that will replace the current innerHTML of the ghost element
17633 update : function(html){
17634 if(typeof html == "string"){
17635 this.ghost.update(html);
17637 this.ghost.update("");
17638 html.style.margin = "0";
17639 this.ghost.dom.appendChild(html);
17641 // ensure float = none set?? cant remember why though.
17642 var el = this.ghost.dom.firstChild;
17644 Roo.fly(el).setStyle('float', 'none');
17649 * Returns the underlying proxy {@link Roo.Layer}
17650 * @return {Roo.Layer} el
17652 getEl : function(){
17657 * Returns the ghost element
17658 * @return {Roo.Element} el
17660 getGhost : function(){
17666 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
17668 hide : function(clear){
17676 * Stops the repair animation if it's currently running
17679 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
17685 * Displays this proxy
17692 * Force the Layer to sync its shadow and shim positions to the element
17699 * Causes the proxy to return to its position of origin via an animation. Should be called after an
17700 * invalid drop operation by the item being dragged.
17701 * @param {Array} xy The XY position of the element ([x, y])
17702 * @param {Function} callback The function to call after the repair is complete
17703 * @param {Object} scope The scope in which to execute the callback
17705 repair : function(xy, callback, scope){
17706 this.callback = callback;
17707 this.scope = scope;
17708 if(xy && this.animRepair !== false){
17709 this.el.addClass("x-dd-drag-repair");
17710 this.el.hideUnders(true);
17711 this.anim = this.el.shift({
17712 duration: this.repairDuration || .5,
17716 callback: this.afterRepair,
17720 this.afterRepair();
17725 afterRepair : function(){
17727 if(typeof this.callback == "function"){
17728 this.callback.call(this.scope || this);
17730 this.callback = null;
17735 * Ext JS Library 1.1.1
17736 * Copyright(c) 2006-2007, Ext JS, LLC.
17738 * Originally Released Under LGPL - original licence link has changed is not relivant.
17741 * <script type="text/javascript">
17745 * @class Roo.dd.DragSource
17746 * @extends Roo.dd.DDProxy
17747 * A simple class that provides the basic implementation needed to make any element draggable.
17749 * @param {String/HTMLElement/Element} el The container element
17750 * @param {Object} config
17752 Roo.dd.DragSource = function(el, config){
17753 this.el = Roo.get(el);
17754 this.dragData = {};
17756 Roo.apply(this, config);
17759 this.proxy = new Roo.dd.StatusProxy();
17762 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
17763 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
17765 this.dragging = false;
17768 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
17770 * @cfg {String} dropAllowed
17771 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
17773 dropAllowed : "x-dd-drop-ok",
17775 * @cfg {String} dropNotAllowed
17776 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
17778 dropNotAllowed : "x-dd-drop-nodrop",
17781 * Returns the data object associated with this drag source
17782 * @return {Object} data An object containing arbitrary data
17784 getDragData : function(e){
17785 return this.dragData;
17789 onDragEnter : function(e, id){
17790 var target = Roo.dd.DragDropMgr.getDDById(id);
17791 this.cachedTarget = target;
17792 if(this.beforeDragEnter(target, e, id) !== false){
17793 if(target.isNotifyTarget){
17794 var status = target.notifyEnter(this, e, this.dragData);
17795 this.proxy.setStatus(status);
17797 this.proxy.setStatus(this.dropAllowed);
17800 if(this.afterDragEnter){
17802 * An empty function by default, but provided so that you can perform a custom action
17803 * when the dragged item enters the drop target by providing an implementation.
17804 * @param {Roo.dd.DragDrop} target The drop target
17805 * @param {Event} e The event object
17806 * @param {String} id The id of the dragged element
17807 * @method afterDragEnter
17809 this.afterDragEnter(target, e, id);
17815 * An empty function by default, but provided so that you can perform a custom action
17816 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
17817 * @param {Roo.dd.DragDrop} target The drop target
17818 * @param {Event} e The event object
17819 * @param {String} id The id of the dragged element
17820 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
17822 beforeDragEnter : function(target, e, id){
17827 alignElWithMouse: function() {
17828 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
17833 onDragOver : function(e, id){
17834 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
17835 if(this.beforeDragOver(target, e, id) !== false){
17836 if(target.isNotifyTarget){
17837 var status = target.notifyOver(this, e, this.dragData);
17838 this.proxy.setStatus(status);
17841 if(this.afterDragOver){
17843 * An empty function by default, but provided so that you can perform a custom action
17844 * while the dragged item is over the drop target by providing an implementation.
17845 * @param {Roo.dd.DragDrop} target The drop target
17846 * @param {Event} e The event object
17847 * @param {String} id The id of the dragged element
17848 * @method afterDragOver
17850 this.afterDragOver(target, e, id);
17856 * An empty function by default, but provided so that you can perform a custom action
17857 * while the dragged item is over the drop target and optionally cancel the onDragOver.
17858 * @param {Roo.dd.DragDrop} target The drop target
17859 * @param {Event} e The event object
17860 * @param {String} id The id of the dragged element
17861 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
17863 beforeDragOver : function(target, e, id){
17868 onDragOut : function(e, id){
17869 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
17870 if(this.beforeDragOut(target, e, id) !== false){
17871 if(target.isNotifyTarget){
17872 target.notifyOut(this, e, this.dragData);
17874 this.proxy.reset();
17875 if(this.afterDragOut){
17877 * An empty function by default, but provided so that you can perform a custom action
17878 * after the dragged item is dragged out of the target without dropping.
17879 * @param {Roo.dd.DragDrop} target The drop target
17880 * @param {Event} e The event object
17881 * @param {String} id The id of the dragged element
17882 * @method afterDragOut
17884 this.afterDragOut(target, e, id);
17887 this.cachedTarget = null;
17891 * An empty function by default, but provided so that you can perform a custom action before the dragged
17892 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
17893 * @param {Roo.dd.DragDrop} target The drop target
17894 * @param {Event} e The event object
17895 * @param {String} id The id of the dragged element
17896 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
17898 beforeDragOut : function(target, e, id){
17903 onDragDrop : function(e, id){
17904 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
17905 if(this.beforeDragDrop(target, e, id) !== false){
17906 if(target.isNotifyTarget){
17907 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
17908 this.onValidDrop(target, e, id);
17910 this.onInvalidDrop(target, e, id);
17913 this.onValidDrop(target, e, id);
17916 if(this.afterDragDrop){
17918 * An empty function by default, but provided so that you can perform a custom action
17919 * after a valid drag drop has occurred by providing an implementation.
17920 * @param {Roo.dd.DragDrop} target The drop target
17921 * @param {Event} e The event object
17922 * @param {String} id The id of the dropped element
17923 * @method afterDragDrop
17925 this.afterDragDrop(target, e, id);
17928 delete this.cachedTarget;
17932 * An empty function by default, but provided so that you can perform a custom action before the dragged
17933 * item is dropped onto the target and optionally cancel the onDragDrop.
17934 * @param {Roo.dd.DragDrop} target The drop target
17935 * @param {Event} e The event object
17936 * @param {String} id The id of the dragged element
17937 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
17939 beforeDragDrop : function(target, e, id){
17944 onValidDrop : function(target, e, id){
17946 if(this.afterValidDrop){
17948 * An empty function by default, but provided so that you can perform a custom action
17949 * after a valid drop has occurred by providing an implementation.
17950 * @param {Object} target The target DD
17951 * @param {Event} e The event object
17952 * @param {String} id The id of the dropped element
17953 * @method afterInvalidDrop
17955 this.afterValidDrop(target, e, id);
17960 getRepairXY : function(e, data){
17961 return this.el.getXY();
17965 onInvalidDrop : function(target, e, id){
17966 this.beforeInvalidDrop(target, e, id);
17967 if(this.cachedTarget){
17968 if(this.cachedTarget.isNotifyTarget){
17969 this.cachedTarget.notifyOut(this, e, this.dragData);
17971 this.cacheTarget = null;
17973 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
17975 if(this.afterInvalidDrop){
17977 * An empty function by default, but provided so that you can perform a custom action
17978 * after an invalid drop has occurred by providing an implementation.
17979 * @param {Event} e The event object
17980 * @param {String} id The id of the dropped element
17981 * @method afterInvalidDrop
17983 this.afterInvalidDrop(e, id);
17988 afterRepair : function(){
17990 this.el.highlight(this.hlColor || "c3daf9");
17992 this.dragging = false;
17996 * An empty function by default, but provided so that you can perform a custom action after an invalid
17997 * drop has occurred.
17998 * @param {Roo.dd.DragDrop} target The drop target
17999 * @param {Event} e The event object
18000 * @param {String} id The id of the dragged element
18001 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
18003 beforeInvalidDrop : function(target, e, id){
18008 handleMouseDown : function(e){
18009 if(this.dragging) {
18012 var data = this.getDragData(e);
18013 if(data && this.onBeforeDrag(data, e) !== false){
18014 this.dragData = data;
18016 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
18021 * An empty function by default, but provided so that you can perform a custom action before the initial
18022 * drag event begins and optionally cancel it.
18023 * @param {Object} data An object containing arbitrary data to be shared with drop targets
18024 * @param {Event} e The event object
18025 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18027 onBeforeDrag : function(data, e){
18032 * An empty function by default, but provided so that you can perform a custom action once the initial
18033 * drag event has begun. The drag cannot be canceled from this function.
18034 * @param {Number} x The x position of the click on the dragged object
18035 * @param {Number} y The y position of the click on the dragged object
18037 onStartDrag : Roo.emptyFn,
18039 // private - YUI override
18040 startDrag : function(x, y){
18041 this.proxy.reset();
18042 this.dragging = true;
18043 this.proxy.update("");
18044 this.onInitDrag(x, y);
18049 onInitDrag : function(x, y){
18050 var clone = this.el.dom.cloneNode(true);
18051 clone.id = Roo.id(); // prevent duplicate ids
18052 this.proxy.update(clone);
18053 this.onStartDrag(x, y);
18058 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
18059 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
18061 getProxy : function(){
18066 * Hides the drag source's {@link Roo.dd.StatusProxy}
18068 hideProxy : function(){
18070 this.proxy.reset(true);
18071 this.dragging = false;
18075 triggerCacheRefresh : function(){
18076 Roo.dd.DDM.refreshCache(this.groups);
18079 // private - override to prevent hiding
18080 b4EndDrag: function(e) {
18083 // private - override to prevent moving
18084 endDrag : function(e){
18085 this.onEndDrag(this.dragData, e);
18089 onEndDrag : function(data, e){
18092 // private - pin to cursor
18093 autoOffset : function(x, y) {
18094 this.setDelta(-12, -20);
18098 * Ext JS Library 1.1.1
18099 * Copyright(c) 2006-2007, Ext JS, LLC.
18101 * Originally Released Under LGPL - original licence link has changed is not relivant.
18104 * <script type="text/javascript">
18109 * @class Roo.dd.DropTarget
18110 * @extends Roo.dd.DDTarget
18111 * A simple class that provides the basic implementation needed to make any element a drop target that can have
18112 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
18114 * @param {String/HTMLElement/Element} el The container element
18115 * @param {Object} config
18117 Roo.dd.DropTarget = function(el, config){
18118 this.el = Roo.get(el);
18120 Roo.apply(this, config);
18122 if(this.containerScroll){
18123 Roo.dd.ScrollManager.register(this.el);
18126 Roo.dd.DropTarget.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
18131 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
18133 * @cfg {String} overClass
18134 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
18137 * @cfg {String} dropAllowed
18138 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
18140 dropAllowed : "x-dd-drop-ok",
18142 * @cfg {String} dropNotAllowed
18143 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
18145 dropNotAllowed : "x-dd-drop-nodrop",
18151 isNotifyTarget : true,
18154 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
18155 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
18156 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
18157 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18158 * @param {Event} e The event
18159 * @param {Object} data An object containing arbitrary data supplied by the drag source
18160 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18161 * underlying {@link Roo.dd.StatusProxy} can be updated
18163 notifyEnter : function(dd, e, data){
18164 if(this.overClass){
18165 this.el.addClass(this.overClass);
18167 return this.dropAllowed;
18171 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
18172 * This method will be called on every mouse movement while the drag source is over the drop target.
18173 * This default implementation simply returns the dropAllowed config value.
18174 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18175 * @param {Event} e The event
18176 * @param {Object} data An object containing arbitrary data supplied by the drag source
18177 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18178 * underlying {@link Roo.dd.StatusProxy} can be updated
18180 notifyOver : function(dd, e, data){
18181 return this.dropAllowed;
18185 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
18186 * out of the target without dropping. This default implementation simply removes the CSS class specified by
18187 * overClass (if any) from the drop element.
18188 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18189 * @param {Event} e The event
18190 * @param {Object} data An object containing arbitrary data supplied by the drag source
18192 notifyOut : function(dd, e, data){
18193 if(this.overClass){
18194 this.el.removeClass(this.overClass);
18199 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
18200 * been dropped on it. This method has no default implementation and returns false, so you must provide an
18201 * implementation that does something to process the drop event and returns true so that the drag source's
18202 * repair action does not run.
18203 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18204 * @param {Event} e The event
18205 * @param {Object} data An object containing arbitrary data supplied by the drag source
18206 * @return {Boolean} True if the drop was valid, else false
18208 notifyDrop : function(dd, e, data){
18213 * Ext JS Library 1.1.1
18214 * Copyright(c) 2006-2007, Ext JS, LLC.
18216 * Originally Released Under LGPL - original licence link has changed is not relivant.
18219 * <script type="text/javascript">
18224 * @class Roo.dd.DragZone
18225 * @extends Roo.dd.DragSource
18226 * This class provides a container DD instance that proxies for multiple child node sources.<br />
18227 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
18229 * @param {String/HTMLElement/Element} el The container element
18230 * @param {Object} config
18232 Roo.dd.DragZone = function(el, config){
18233 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
18234 if(this.containerScroll){
18235 Roo.dd.ScrollManager.register(this.el);
18239 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
18241 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
18242 * for auto scrolling during drag operations.
18245 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
18246 * method after a failed drop (defaults to "c3daf9" - light blue)
18250 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
18251 * for a valid target to drag based on the mouse down. Override this method
18252 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
18253 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
18254 * @param {EventObject} e The mouse down event
18255 * @return {Object} The dragData
18257 getDragData : function(e){
18258 return Roo.dd.Registry.getHandleFromEvent(e);
18262 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
18263 * this.dragData.ddel
18264 * @param {Number} x The x position of the click on the dragged object
18265 * @param {Number} y The y position of the click on the dragged object
18266 * @return {Boolean} true to continue the drag, false to cancel
18268 onInitDrag : function(x, y){
18269 this.proxy.update(this.dragData.ddel.cloneNode(true));
18270 this.onStartDrag(x, y);
18275 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
18277 afterRepair : function(){
18279 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
18281 this.dragging = false;
18285 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
18286 * the XY of this.dragData.ddel
18287 * @param {EventObject} e The mouse up event
18288 * @return {Array} The xy location (e.g. [100, 200])
18290 getRepairXY : function(e){
18291 return Roo.Element.fly(this.dragData.ddel).getXY();
18295 * Ext JS Library 1.1.1
18296 * Copyright(c) 2006-2007, Ext JS, LLC.
18298 * Originally Released Under LGPL - original licence link has changed is not relivant.
18301 * <script type="text/javascript">
18304 * @class Roo.dd.DropZone
18305 * @extends Roo.dd.DropTarget
18306 * This class provides a container DD instance that proxies for multiple child node targets.<br />
18307 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
18309 * @param {String/HTMLElement/Element} el The container element
18310 * @param {Object} config
18312 Roo.dd.DropZone = function(el, config){
18313 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
18316 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
18318 * Returns a custom data object associated with the DOM node that is the target of the event. By default
18319 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
18320 * provide your own custom lookup.
18321 * @param {Event} e The event
18322 * @return {Object} data The custom data
18324 getTargetFromEvent : function(e){
18325 return Roo.dd.Registry.getTargetFromEvent(e);
18329 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
18330 * that it has registered. This method has no default implementation and should be overridden to provide
18331 * node-specific processing if necessary.
18332 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18333 * {@link #getTargetFromEvent} for this node)
18334 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18335 * @param {Event} e The event
18336 * @param {Object} data An object containing arbitrary data supplied by the drag source
18338 onNodeEnter : function(n, dd, e, data){
18343 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
18344 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
18345 * overridden to provide the proper feedback.
18346 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18347 * {@link #getTargetFromEvent} for this node)
18348 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18349 * @param {Event} e The event
18350 * @param {Object} data An object containing arbitrary data supplied by the drag source
18351 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18352 * underlying {@link Roo.dd.StatusProxy} can be updated
18354 onNodeOver : function(n, dd, e, data){
18355 return this.dropAllowed;
18359 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
18360 * the drop node without dropping. This method has no default implementation and should be overridden to provide
18361 * node-specific processing if necessary.
18362 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18363 * {@link #getTargetFromEvent} for this node)
18364 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18365 * @param {Event} e The event
18366 * @param {Object} data An object containing arbitrary data supplied by the drag source
18368 onNodeOut : function(n, dd, e, data){
18373 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
18374 * the drop node. The default implementation returns false, so it should be overridden to provide the
18375 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
18376 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18377 * {@link #getTargetFromEvent} for this node)
18378 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18379 * @param {Event} e The event
18380 * @param {Object} data An object containing arbitrary data supplied by the drag source
18381 * @return {Boolean} True if the drop was valid, else false
18383 onNodeDrop : function(n, dd, e, data){
18388 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
18389 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
18390 * it should be overridden to provide the proper feedback if necessary.
18391 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18392 * @param {Event} e The event
18393 * @param {Object} data An object containing arbitrary data supplied by the drag source
18394 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18395 * underlying {@link Roo.dd.StatusProxy} can be updated
18397 onContainerOver : function(dd, e, data){
18398 return this.dropNotAllowed;
18402 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
18403 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
18404 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
18405 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
18406 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18407 * @param {Event} e The event
18408 * @param {Object} data An object containing arbitrary data supplied by the drag source
18409 * @return {Boolean} True if the drop was valid, else false
18411 onContainerDrop : function(dd, e, data){
18416 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
18417 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
18418 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
18419 * you should override this method and provide a custom implementation.
18420 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18421 * @param {Event} e The event
18422 * @param {Object} data An object containing arbitrary data supplied by the drag source
18423 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18424 * underlying {@link Roo.dd.StatusProxy} can be updated
18426 notifyEnter : function(dd, e, data){
18427 return this.dropNotAllowed;
18431 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
18432 * This method will be called on every mouse movement while the drag source is over the drop zone.
18433 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
18434 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
18435 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
18436 * registered node, it will call {@link #onContainerOver}.
18437 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18438 * @param {Event} e The event
18439 * @param {Object} data An object containing arbitrary data supplied by the drag source
18440 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18441 * underlying {@link Roo.dd.StatusProxy} can be updated
18443 notifyOver : function(dd, e, data){
18444 var n = this.getTargetFromEvent(e);
18445 if(!n){ // not over valid drop target
18446 if(this.lastOverNode){
18447 this.onNodeOut(this.lastOverNode, dd, e, data);
18448 this.lastOverNode = null;
18450 return this.onContainerOver(dd, e, data);
18452 if(this.lastOverNode != n){
18453 if(this.lastOverNode){
18454 this.onNodeOut(this.lastOverNode, dd, e, data);
18456 this.onNodeEnter(n, dd, e, data);
18457 this.lastOverNode = n;
18459 return this.onNodeOver(n, dd, e, data);
18463 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
18464 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
18465 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
18466 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18467 * @param {Event} e The event
18468 * @param {Object} data An object containing arbitrary data supplied by the drag zone
18470 notifyOut : function(dd, e, data){
18471 if(this.lastOverNode){
18472 this.onNodeOut(this.lastOverNode, dd, e, data);
18473 this.lastOverNode = null;
18478 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
18479 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
18480 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
18481 * otherwise it will call {@link #onContainerDrop}.
18482 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18483 * @param {Event} e The event
18484 * @param {Object} data An object containing arbitrary data supplied by the drag source
18485 * @return {Boolean} True if the drop was valid, else false
18487 notifyDrop : function(dd, e, data){
18488 if(this.lastOverNode){
18489 this.onNodeOut(this.lastOverNode, dd, e, data);
18490 this.lastOverNode = null;
18492 var n = this.getTargetFromEvent(e);
18494 this.onNodeDrop(n, dd, e, data) :
18495 this.onContainerDrop(dd, e, data);
18499 triggerCacheRefresh : function(){
18500 Roo.dd.DDM.refreshCache(this.groups);
18504 * Ext JS Library 1.1.1
18505 * Copyright(c) 2006-2007, Ext JS, LLC.
18507 * Originally Released Under LGPL - original licence link has changed is not relivant.
18510 * <script type="text/javascript">
18515 * @class Roo.data.SortTypes
18517 * Defines the default sorting (casting?) comparison functions used when sorting data.
18519 Roo.data.SortTypes = {
18521 * Default sort that does nothing
18522 * @param {Mixed} s The value being converted
18523 * @return {Mixed} The comparison value
18525 none : function(s){
18530 * The regular expression used to strip tags
18534 stripTagsRE : /<\/?[^>]+>/gi,
18537 * Strips all HTML tags to sort on text only
18538 * @param {Mixed} s The value being converted
18539 * @return {String} The comparison value
18541 asText : function(s){
18542 return String(s).replace(this.stripTagsRE, "");
18546 * Strips all HTML tags to sort on text only - Case insensitive
18547 * @param {Mixed} s The value being converted
18548 * @return {String} The comparison value
18550 asUCText : function(s){
18551 return String(s).toUpperCase().replace(this.stripTagsRE, "");
18555 * Case insensitive string
18556 * @param {Mixed} s The value being converted
18557 * @return {String} The comparison value
18559 asUCString : function(s) {
18560 return String(s).toUpperCase();
18565 * @param {Mixed} s The value being converted
18566 * @return {Number} The comparison value
18568 asDate : function(s) {
18572 if(s instanceof Date){
18573 return s.getTime();
18575 return Date.parse(String(s));
18580 * @param {Mixed} s The value being converted
18581 * @return {Float} The comparison value
18583 asFloat : function(s) {
18584 var val = parseFloat(String(s).replace(/,/g, ""));
18585 if(isNaN(val)) val = 0;
18591 * @param {Mixed} s The value being converted
18592 * @return {Number} The comparison value
18594 asInt : function(s) {
18595 var val = parseInt(String(s).replace(/,/g, ""));
18596 if(isNaN(val)) val = 0;
18601 * Ext JS Library 1.1.1
18602 * Copyright(c) 2006-2007, Ext JS, LLC.
18604 * Originally Released Under LGPL - original licence link has changed is not relivant.
18607 * <script type="text/javascript">
18611 * @class Roo.data.Record
18612 * Instances of this class encapsulate both record <em>definition</em> information, and record
18613 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
18614 * to access Records cached in an {@link Roo.data.Store} object.<br>
18616 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
18617 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
18620 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
18622 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
18623 * {@link #create}. The parameters are the same.
18624 * @param {Array} data An associative Array of data values keyed by the field name.
18625 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
18626 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
18627 * not specified an integer id is generated.
18629 Roo.data.Record = function(data, id){
18630 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
18635 * Generate a constructor for a specific record layout.
18636 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
18637 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
18638 * Each field definition object may contain the following properties: <ul>
18639 * <li><b>name</b> : String<p style="margin-left:1em">The name by which the field is referenced within the Record. This is referenced by,
18640 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
18641 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
18642 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
18643 * is being used, then this is a string containing the javascript expression to reference the data relative to
18644 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
18645 * to the data item relative to the record element. If the mapping expression is the same as the field name,
18646 * this may be omitted.</p></li>
18647 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
18648 * <ul><li>auto (Default, implies no conversion)</li>
18653 * <li>date</li></ul></p></li>
18654 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
18655 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
18656 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
18657 * by the Reader into an object that will be stored in the Record. It is passed the
18658 * following parameters:<ul>
18659 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
18661 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
18663 * <br>usage:<br><pre><code>
18664 var TopicRecord = Roo.data.Record.create(
18665 {name: 'title', mapping: 'topic_title'},
18666 {name: 'author', mapping: 'username'},
18667 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
18668 {name: 'lastPost', mapping: 'post_time', type: 'date'},
18669 {name: 'lastPoster', mapping: 'user2'},
18670 {name: 'excerpt', mapping: 'post_text'}
18673 var myNewRecord = new TopicRecord({
18674 title: 'Do my job please',
18677 lastPost: new Date(),
18678 lastPoster: 'Animal',
18679 excerpt: 'No way dude!'
18681 myStore.add(myNewRecord);
18686 Roo.data.Record.create = function(o){
18687 var f = function(){
18688 f.superclass.constructor.apply(this, arguments);
18690 Roo.extend(f, Roo.data.Record);
18691 var p = f.prototype;
18692 p.fields = new Roo.util.MixedCollection(false, function(field){
18695 for(var i = 0, len = o.length; i < len; i++){
18696 p.fields.add(new Roo.data.Field(o[i]));
18698 f.getField = function(name){
18699 return p.fields.get(name);
18704 Roo.data.Record.AUTO_ID = 1000;
18705 Roo.data.Record.EDIT = 'edit';
18706 Roo.data.Record.REJECT = 'reject';
18707 Roo.data.Record.COMMIT = 'commit';
18709 Roo.data.Record.prototype = {
18711 * Readonly flag - true if this record has been modified.
18720 join : function(store){
18721 this.store = store;
18725 * Set the named field to the specified value.
18726 * @param {String} name The name of the field to set.
18727 * @param {Object} value The value to set the field to.
18729 set : function(name, value){
18730 if(this.data[name] == value){
18734 if(!this.modified){
18735 this.modified = {};
18737 if(typeof this.modified[name] == 'undefined'){
18738 this.modified[name] = this.data[name];
18740 this.data[name] = value;
18742 this.store.afterEdit(this);
18747 * Get the value of the named field.
18748 * @param {String} name The name of the field to get the value of.
18749 * @return {Object} The value of the field.
18751 get : function(name){
18752 return this.data[name];
18756 beginEdit : function(){
18757 this.editing = true;
18758 this.modified = {};
18762 cancelEdit : function(){
18763 this.editing = false;
18764 delete this.modified;
18768 endEdit : function(){
18769 this.editing = false;
18770 if(this.dirty && this.store){
18771 this.store.afterEdit(this);
18776 * Usually called by the {@link Roo.data.Store} which owns the Record.
18777 * Rejects all changes made to the Record since either creation, or the last commit operation.
18778 * Modified fields are reverted to their original values.
18780 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
18781 * of reject operations.
18783 reject : function(){
18784 var m = this.modified;
18786 if(typeof m[n] != "function"){
18787 this.data[n] = m[n];
18790 this.dirty = false;
18791 delete this.modified;
18792 this.editing = false;
18794 this.store.afterReject(this);
18799 * Usually called by the {@link Roo.data.Store} which owns the Record.
18800 * Commits all changes made to the Record since either creation, or the last commit operation.
18802 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
18803 * of commit operations.
18805 commit : function(){
18806 this.dirty = false;
18807 delete this.modified;
18808 this.editing = false;
18810 this.store.afterCommit(this);
18815 hasError : function(){
18816 return this.error != null;
18820 clearError : function(){
18825 * Creates a copy of this record.
18826 * @param {String} id (optional) A new record id if you don't want to use this record's id
18829 copy : function(newId) {
18830 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
18834 * Ext JS Library 1.1.1
18835 * Copyright(c) 2006-2007, Ext JS, LLC.
18837 * Originally Released Under LGPL - original licence link has changed is not relivant.
18840 * <script type="text/javascript">
18846 * @class Roo.data.Store
18847 * @extends Roo.util.Observable
18848 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
18849 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
18851 * A Store object uses an implementation of {@link Roo.data.DataProxy} to access a data object unless you call loadData() directly and pass in your data. The Store object
18852 * has no knowledge of the format of the data returned by the Proxy.<br>
18854 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
18855 * instances from the data object. These records are cached and made available through accessor functions.
18857 * Creates a new Store.
18858 * @param {Object} config A config object containing the objects needed for the Store to access data,
18859 * and read the data into Records.
18861 Roo.data.Store = function(config){
18862 this.data = new Roo.util.MixedCollection(false);
18863 this.data.getKey = function(o){
18866 this.baseParams = {};
18868 this.paramNames = {
18875 if(config && config.data){
18876 this.inlineData = config.data;
18877 delete config.data;
18880 Roo.apply(this, config);
18882 if(this.reader){ // reader passed
18883 this.reader = Roo.factory(this.reader, Roo.data);
18884 this.reader.xmodule = this.xmodule || false;
18885 if(!this.recordType){
18886 this.recordType = this.reader.recordType;
18888 if(this.reader.onMetaChange){
18889 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
18893 if(this.recordType){
18894 this.fields = this.recordType.prototype.fields;
18896 this.modified = [];
18900 * @event datachanged
18901 * Fires when the data cache has changed, and a widget which is using this Store
18902 * as a Record cache should refresh its view.
18903 * @param {Store} this
18905 datachanged : true,
18907 * @event metachange
18908 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
18909 * @param {Store} this
18910 * @param {Object} meta The JSON metadata
18915 * Fires when Records have been added to the Store
18916 * @param {Store} this
18917 * @param {Roo.data.Record[]} records The array of Records added
18918 * @param {Number} index The index at which the record(s) were added
18923 * Fires when a Record has been removed from the Store
18924 * @param {Store} this
18925 * @param {Roo.data.Record} record The Record that was removed
18926 * @param {Number} index The index at which the record was removed
18931 * Fires when a Record has been updated
18932 * @param {Store} this
18933 * @param {Roo.data.Record} record The Record that was updated
18934 * @param {String} operation The update operation being performed. Value may be one of:
18936 Roo.data.Record.EDIT
18937 Roo.data.Record.REJECT
18938 Roo.data.Record.COMMIT
18944 * Fires when the data cache has been cleared.
18945 * @param {Store} this
18949 * @event beforeload
18950 * Fires before a request is made for a new data object. If the beforeload handler returns false
18951 * the load action will be canceled.
18952 * @param {Store} this
18953 * @param {Object} options The loading options that were specified (see {@link #load} for details)
18958 * Fires after a new set of Records has been loaded.
18959 * @param {Store} this
18960 * @param {Roo.data.Record[]} records The Records that were loaded
18961 * @param {Object} options The loading options that were specified (see {@link #load} for details)
18965 * @event loadexception
18966 * Fires if an exception occurs in the Proxy during loading.
18967 * Called with the signature of the Proxy's "loadexception" event.
18968 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
18971 * @param {Object} return from JsonData.reader() - success, totalRecords, records
18972 * @param {Object} load options
18973 * @param {Object} jsonData from your request (normally this contains the Exception)
18975 loadexception : true
18979 this.proxy = Roo.factory(this.proxy, Roo.data);
18980 this.proxy.xmodule = this.xmodule || false;
18981 this.relayEvents(this.proxy, ["loadexception"]);
18983 this.sortToggle = {};
18985 Roo.data.Store.superclass.constructor.call(this);
18987 if(this.inlineData){
18988 this.loadData(this.inlineData);
18989 delete this.inlineData;
18992 Roo.extend(Roo.data.Store, Roo.util.Observable, {
18994 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
18995 * without a remote query - used by combo/forms at present.
18999 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
19002 * @cfg {Array} data Inline data to be loaded when the store is initialized.
19005 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
19006 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
19009 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
19010 * on any HTTP request
19013 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
19016 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
19017 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
19019 remoteSort : false,
19022 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
19023 * loaded or when a record is removed. (defaults to false).
19025 pruneModifiedRecords : false,
19028 lastOptions : null,
19031 * Add Records to the Store and fires the add event.
19032 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19034 add : function(records){
19035 records = [].concat(records);
19036 for(var i = 0, len = records.length; i < len; i++){
19037 records[i].join(this);
19039 var index = this.data.length;
19040 this.data.addAll(records);
19041 this.fireEvent("add", this, records, index);
19045 * Remove a Record from the Store and fires the remove event.
19046 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
19048 remove : function(record){
19049 var index = this.data.indexOf(record);
19050 this.data.removeAt(index);
19051 if(this.pruneModifiedRecords){
19052 this.modified.remove(record);
19054 this.fireEvent("remove", this, record, index);
19058 * Remove all Records from the Store and fires the clear event.
19060 removeAll : function(){
19062 if(this.pruneModifiedRecords){
19063 this.modified = [];
19065 this.fireEvent("clear", this);
19069 * Inserts Records to the Store at the given index and fires the add event.
19070 * @param {Number} index The start index at which to insert the passed Records.
19071 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19073 insert : function(index, records){
19074 records = [].concat(records);
19075 for(var i = 0, len = records.length; i < len; i++){
19076 this.data.insert(index, records[i]);
19077 records[i].join(this);
19079 this.fireEvent("add", this, records, index);
19083 * Get the index within the cache of the passed Record.
19084 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
19085 * @return {Number} The index of the passed Record. Returns -1 if not found.
19087 indexOf : function(record){
19088 return this.data.indexOf(record);
19092 * Get the index within the cache of the Record with the passed id.
19093 * @param {String} id The id of the Record to find.
19094 * @return {Number} The index of the Record. Returns -1 if not found.
19096 indexOfId : function(id){
19097 return this.data.indexOfKey(id);
19101 * Get the Record with the specified id.
19102 * @param {String} id The id of the Record to find.
19103 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
19105 getById : function(id){
19106 return this.data.key(id);
19110 * Get the Record at the specified index.
19111 * @param {Number} index The index of the Record to find.
19112 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
19114 getAt : function(index){
19115 return this.data.itemAt(index);
19119 * Returns a range of Records between specified indices.
19120 * @param {Number} startIndex (optional) The starting index (defaults to 0)
19121 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
19122 * @return {Roo.data.Record[]} An array of Records
19124 getRange : function(start, end){
19125 return this.data.getRange(start, end);
19129 storeOptions : function(o){
19130 o = Roo.apply({}, o);
19133 this.lastOptions = o;
19137 * Loads the Record cache from the configured Proxy using the configured Reader.
19139 * If using remote paging, then the first load call must specify the <em>start</em>
19140 * and <em>limit</em> properties in the options.params property to establish the initial
19141 * position within the dataset, and the number of Records to cache on each read from the Proxy.
19143 * <strong>It is important to note that for remote data sources, loading is asynchronous,
19144 * and this call will return before the new data has been loaded. Perform any post-processing
19145 * in a callback function, or in a "load" event handler.</strong>
19147 * @param {Object} options An object containing properties which control loading options:<ul>
19148 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
19149 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
19150 * passed the following arguments:<ul>
19151 * <li>r : Roo.data.Record[]</li>
19152 * <li>options: Options object from the load call</li>
19153 * <li>success: Boolean success indicator</li></ul></li>
19154 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
19155 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
19158 load : function(options){
19159 options = options || {};
19160 if(this.fireEvent("beforeload", this, options) !== false){
19161 this.storeOptions(options);
19162 var p = Roo.apply(options.params || {}, this.baseParams);
19163 if(this.sortInfo && this.remoteSort){
19164 var pn = this.paramNames;
19165 p[pn["sort"]] = this.sortInfo.field;
19166 p[pn["dir"]] = this.sortInfo.direction;
19168 this.proxy.load(p, this.reader, this.loadRecords, this, options);
19173 * Reloads the Record cache from the configured Proxy using the configured Reader and
19174 * the options from the last load operation performed.
19175 * @param {Object} options (optional) An object containing properties which may override the options
19176 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
19177 * the most recently used options are reused).
19179 reload : function(options){
19180 this.load(Roo.applyIf(options||{}, this.lastOptions));
19184 // Called as a callback by the Reader during a load operation.
19185 loadRecords : function(o, options, success){
19186 if(!o || success === false){
19187 if(success !== false){
19188 this.fireEvent("load", this, [], options);
19190 if(options.callback){
19191 options.callback.call(options.scope || this, [], options, false);
19195 // if data returned failure - throw an exception.
19196 if (o.success === false) {
19197 this.fireEvent("loadexception", this, o, options, this.reader.jsonData);
19200 var r = o.records, t = o.totalRecords || r.length;
19201 if(!options || options.add !== true){
19202 if(this.pruneModifiedRecords){
19203 this.modified = [];
19205 for(var i = 0, len = r.length; i < len; i++){
19209 this.data = this.snapshot;
19210 delete this.snapshot;
19213 this.data.addAll(r);
19214 this.totalLength = t;
19216 this.fireEvent("datachanged", this);
19218 this.totalLength = Math.max(t, this.data.length+r.length);
19221 this.fireEvent("load", this, r, options);
19222 if(options.callback){
19223 options.callback.call(options.scope || this, r, options, true);
19228 * Loads data from a passed data block. A Reader which understands the format of the data
19229 * must have been configured in the constructor.
19230 * @param {Object} data The data block from which to read the Records. The format of the data expected
19231 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
19232 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
19234 loadData : function(o, append){
19235 var r = this.reader.readRecords(o);
19236 this.loadRecords(r, {add: append}, true);
19240 * Gets the number of cached records.
19242 * <em>If using paging, this may not be the total size of the dataset. If the data object
19243 * used by the Reader contains the dataset size, then the getTotalCount() function returns
19244 * the data set size</em>
19246 getCount : function(){
19247 return this.data.length || 0;
19251 * Gets the total number of records in the dataset as returned by the server.
19253 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
19254 * the dataset size</em>
19256 getTotalCount : function(){
19257 return this.totalLength || 0;
19261 * Returns the sort state of the Store as an object with two properties:
19263 field {String} The name of the field by which the Records are sorted
19264 direction {String} The sort order, "ASC" or "DESC"
19267 getSortState : function(){
19268 return this.sortInfo;
19272 applySort : function(){
19273 if(this.sortInfo && !this.remoteSort){
19274 var s = this.sortInfo, f = s.field;
19275 var st = this.fields.get(f).sortType;
19276 var fn = function(r1, r2){
19277 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
19278 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
19280 this.data.sort(s.direction, fn);
19281 if(this.snapshot && this.snapshot != this.data){
19282 this.snapshot.sort(s.direction, fn);
19288 * Sets the default sort column and order to be used by the next load operation.
19289 * @param {String} fieldName The name of the field to sort by.
19290 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
19292 setDefaultSort : function(field, dir){
19293 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
19297 * Sort the Records.
19298 * If remote sorting is used, the sort is performed on the server, and the cache is
19299 * reloaded. If local sorting is used, the cache is sorted internally.
19300 * @param {String} fieldName The name of the field to sort by.
19301 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
19303 sort : function(fieldName, dir){
19304 var f = this.fields.get(fieldName);
19306 if(this.sortInfo && this.sortInfo.field == f.name){ // toggle sort dir
19307 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
19312 this.sortToggle[f.name] = dir;
19313 this.sortInfo = {field: f.name, direction: dir};
19314 if(!this.remoteSort){
19316 this.fireEvent("datachanged", this);
19318 this.load(this.lastOptions);
19323 * Calls the specified function for each of the Records in the cache.
19324 * @param {Function} fn The function to call. The Record is passed as the first parameter.
19325 * Returning <em>false</em> aborts and exits the iteration.
19326 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
19328 each : function(fn, scope){
19329 this.data.each(fn, scope);
19333 * Gets all records modified since the last commit. Modified records are persisted across load operations
19334 * (e.g., during paging).
19335 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
19337 getModifiedRecords : function(){
19338 return this.modified;
19342 createFilterFn : function(property, value, anyMatch){
19343 if(!value.exec){ // not a regex
19344 value = String(value);
19345 if(value.length == 0){
19348 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
19350 return function(r){
19351 return value.test(r.data[property]);
19356 * Sums the value of <i>property</i> for each record between start and end and returns the result.
19357 * @param {String} property A field on your records
19358 * @param {Number} start The record index to start at (defaults to 0)
19359 * @param {Number} end The last record index to include (defaults to length - 1)
19360 * @return {Number} The sum
19362 sum : function(property, start, end){
19363 var rs = this.data.items, v = 0;
19364 start = start || 0;
19365 end = (end || end === 0) ? end : rs.length-1;
19367 for(var i = start; i <= end; i++){
19368 v += (rs[i].data[property] || 0);
19374 * Filter the records by a specified property.
19375 * @param {String} field A field on your records
19376 * @param {String/RegExp} value Either a string that the field
19377 * should start with or a RegExp to test against the field
19378 * @param {Boolean} anyMatch True to match any part not just the beginning
19380 filter : function(property, value, anyMatch){
19381 var fn = this.createFilterFn(property, value, anyMatch);
19382 return fn ? this.filterBy(fn) : this.clearFilter();
19386 * Filter by a function. The specified function will be called with each
19387 * record in this data source. If the function returns true the record is included,
19388 * otherwise it is filtered.
19389 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
19390 * @param {Object} scope (optional) The scope of the function (defaults to this)
19392 filterBy : function(fn, scope){
19393 this.snapshot = this.snapshot || this.data;
19394 this.data = this.queryBy(fn, scope||this);
19395 this.fireEvent("datachanged", this);
19399 * Query the records by a specified property.
19400 * @param {String} field A field on your records
19401 * @param {String/RegExp} value Either a string that the field
19402 * should start with or a RegExp to test against the field
19403 * @param {Boolean} anyMatch True to match any part not just the beginning
19404 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
19406 query : function(property, value, anyMatch){
19407 var fn = this.createFilterFn(property, value, anyMatch);
19408 return fn ? this.queryBy(fn) : this.data.clone();
19412 * Query by a function. The specified function will be called with each
19413 * record in this data source. If the function returns true the record is included
19415 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
19416 * @param {Object} scope (optional) The scope of the function (defaults to this)
19417 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
19419 queryBy : function(fn, scope){
19420 var data = this.snapshot || this.data;
19421 return data.filterBy(fn, scope||this);
19425 * Collects unique values for a particular dataIndex from this store.
19426 * @param {String} dataIndex The property to collect
19427 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
19428 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
19429 * @return {Array} An array of the unique values
19431 collect : function(dataIndex, allowNull, bypassFilter){
19432 var d = (bypassFilter === true && this.snapshot) ?
19433 this.snapshot.items : this.data.items;
19434 var v, sv, r = [], l = {};
19435 for(var i = 0, len = d.length; i < len; i++){
19436 v = d[i].data[dataIndex];
19438 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
19447 * Revert to a view of the Record cache with no filtering applied.
19448 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
19450 clearFilter : function(suppressEvent){
19451 if(this.snapshot && this.snapshot != this.data){
19452 this.data = this.snapshot;
19453 delete this.snapshot;
19454 if(suppressEvent !== true){
19455 this.fireEvent("datachanged", this);
19461 afterEdit : function(record){
19462 if(this.modified.indexOf(record) == -1){
19463 this.modified.push(record);
19465 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
19469 afterReject : function(record){
19470 this.modified.remove(record);
19471 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
19475 afterCommit : function(record){
19476 this.modified.remove(record);
19477 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
19481 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
19482 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
19484 commitChanges : function(){
19485 var m = this.modified.slice(0);
19486 this.modified = [];
19487 for(var i = 0, len = m.length; i < len; i++){
19493 * Cancel outstanding changes on all changed records.
19495 rejectChanges : function(){
19496 var m = this.modified.slice(0);
19497 this.modified = [];
19498 for(var i = 0, len = m.length; i < len; i++){
19503 onMetaChange : function(meta, rtype, o){
19504 this.recordType = rtype;
19505 this.fields = rtype.prototype.fields;
19506 delete this.snapshot;
19507 this.sortInfo = meta.sortInfo;
19508 this.modified = [];
19509 this.fireEvent('metachange', this, this.reader.meta);
19513 * Ext JS Library 1.1.1
19514 * Copyright(c) 2006-2007, Ext JS, LLC.
19516 * Originally Released Under LGPL - original licence link has changed is not relivant.
19519 * <script type="text/javascript">
19523 * @class Roo.data.SimpleStore
19524 * @extends Roo.data.Store
19525 * Small helper class to make creating Stores from Array data easier.
19526 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
19527 * @cfg {Array} fields An array of field definition objects, or field name strings.
19528 * @cfg {Array} data The multi-dimensional array of data
19530 * @param {Object} config
19532 Roo.data.SimpleStore = function(config){
19533 Roo.data.SimpleStore.superclass.constructor.call(this, {
19535 reader: new Roo.data.ArrayReader({
19538 Roo.data.Record.create(config.fields)
19540 proxy : new Roo.data.MemoryProxy(config.data)
19544 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
19546 * Ext JS Library 1.1.1
19547 * Copyright(c) 2006-2007, Ext JS, LLC.
19549 * Originally Released Under LGPL - original licence link has changed is not relivant.
19552 * <script type="text/javascript">
19557 * @extends Roo.data.Store
19558 * @class Roo.data.JsonStore
19559 * Small helper class to make creating Stores for JSON data easier. <br/>
19561 var store = new Roo.data.JsonStore({
19562 url: 'get-images.php',
19564 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
19567 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
19568 * JsonReader and HttpProxy (unless inline data is provided).</b>
19569 * @cfg {Array} fields An array of field definition objects, or field name strings.
19571 * @param {Object} config
19573 Roo.data.JsonStore = function(c){
19574 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
19575 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
19576 reader: new Roo.data.JsonReader(c, c.fields)
19579 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
19581 * Ext JS Library 1.1.1
19582 * Copyright(c) 2006-2007, Ext JS, LLC.
19584 * Originally Released Under LGPL - original licence link has changed is not relivant.
19587 * <script type="text/javascript">
19591 Roo.data.Field = function(config){
19592 if(typeof config == "string"){
19593 config = {name: config};
19595 Roo.apply(this, config);
19598 this.type = "auto";
19601 var st = Roo.data.SortTypes;
19602 // named sortTypes are supported, here we look them up
19603 if(typeof this.sortType == "string"){
19604 this.sortType = st[this.sortType];
19607 // set default sortType for strings and dates
19608 if(!this.sortType){
19611 this.sortType = st.asUCString;
19614 this.sortType = st.asDate;
19617 this.sortType = st.none;
19622 var stripRe = /[\$,%]/g;
19624 // prebuilt conversion function for this field, instead of
19625 // switching every time we're reading a value
19627 var cv, dateFormat = this.dateFormat;
19632 cv = function(v){ return v; };
19635 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
19639 return v !== undefined && v !== null && v !== '' ?
19640 parseInt(String(v).replace(stripRe, ""), 10) : '';
19645 return v !== undefined && v !== null && v !== '' ?
19646 parseFloat(String(v).replace(stripRe, ""), 10) : '';
19651 cv = function(v){ return v === true || v === "true" || v == 1; };
19658 if(v instanceof Date){
19662 if(dateFormat == "timestamp"){
19663 return new Date(v*1000);
19665 return Date.parseDate(v, dateFormat);
19667 var parsed = Date.parse(v);
19668 return parsed ? new Date(parsed) : null;
19677 Roo.data.Field.prototype = {
19685 * Ext JS Library 1.1.1
19686 * Copyright(c) 2006-2007, Ext JS, LLC.
19688 * Originally Released Under LGPL - original licence link has changed is not relivant.
19691 * <script type="text/javascript">
19694 // Base class for reading structured data from a data source. This class is intended to be
19695 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
19698 * @class Roo.data.DataReader
19699 * Base class for reading structured data from a data source. This class is intended to be
19700 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
19703 Roo.data.DataReader = function(meta, recordType){
19707 this.recordType = recordType instanceof Array ?
19708 Roo.data.Record.create(recordType) : recordType;
19711 Roo.data.DataReader.prototype = {
19713 * Create an empty record
19714 * @param {Object} data (optional) - overlay some values
19715 * @return {Roo.data.Record} record created.
19717 newRow : function(d) {
19719 this.recordType.prototype.fields.each(function(c) {
19721 case 'int' : da[c.name] = 0; break;
19722 case 'date' : da[c.name] = new Date(); break;
19723 case 'float' : da[c.name] = 0.0; break;
19724 case 'boolean' : da[c.name] = false; break;
19725 default : da[c.name] = ""; break;
19729 return new this.recordType(Roo.apply(da, d));
19734 * Ext JS Library 1.1.1
19735 * Copyright(c) 2006-2007, Ext JS, LLC.
19737 * Originally Released Under LGPL - original licence link has changed is not relivant.
19740 * <script type="text/javascript">
19744 * @class Roo.data.DataProxy
19745 * @extends Roo.data.Observable
19746 * This class is an abstract base class for implementations which provide retrieval of
19747 * unformatted data objects.<br>
19749 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
19750 * (of the appropriate type which knows how to parse the data object) to provide a block of
19751 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
19753 * Custom implementations must implement the load method as described in
19754 * {@link Roo.data.HttpProxy#load}.
19756 Roo.data.DataProxy = function(){
19759 * @event beforeload
19760 * Fires before a network request is made to retrieve a data object.
19761 * @param {Object} This DataProxy object.
19762 * @param {Object} params The params parameter to the load function.
19767 * Fires before the load method's callback is called.
19768 * @param {Object} This DataProxy object.
19769 * @param {Object} o The data object.
19770 * @param {Object} arg The callback argument object passed to the load function.
19774 * @event loadexception
19775 * Fires if an Exception occurs during data retrieval.
19776 * @param {Object} This DataProxy object.
19777 * @param {Object} o The data object.
19778 * @param {Object} arg The callback argument object passed to the load function.
19779 * @param {Object} e The Exception.
19781 loadexception : true
19783 Roo.data.DataProxy.superclass.constructor.call(this);
19786 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
19789 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
19793 * Ext JS Library 1.1.1
19794 * Copyright(c) 2006-2007, Ext JS, LLC.
19796 * Originally Released Under LGPL - original licence link has changed is not relivant.
19799 * <script type="text/javascript">
19802 * @class Roo.data.MemoryProxy
19803 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
19804 * to the Reader when its load method is called.
19806 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
19808 Roo.data.MemoryProxy = function(data){
19812 Roo.data.MemoryProxy.superclass.constructor.call(this);
19816 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
19818 * Load data from the requested source (in this case an in-memory
19819 * data object passed to the constructor), read the data object into
19820 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
19821 * process that block using the passed callback.
19822 * @param {Object} params This parameter is not used by the MemoryProxy class.
19823 * @param {Roo.data.DataReader} reader The Reader object which converts the data
19824 * object into a block of Roo.data.Records.
19825 * @param {Function} callback The function into which to pass the block of Roo.data.records.
19826 * The function must be passed <ul>
19827 * <li>The Record block object</li>
19828 * <li>The "arg" argument from the load function</li>
19829 * <li>A boolean success indicator</li>
19831 * @param {Object} scope The scope in which to call the callback
19832 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
19834 load : function(params, reader, callback, scope, arg){
19835 params = params || {};
19838 result = reader.readRecords(this.data);
19840 this.fireEvent("loadexception", this, arg, null, e);
19841 callback.call(scope, null, arg, false);
19844 callback.call(scope, result, arg, true);
19848 update : function(params, records){
19853 * Ext JS Library 1.1.1
19854 * Copyright(c) 2006-2007, Ext JS, LLC.
19856 * Originally Released Under LGPL - original licence link has changed is not relivant.
19859 * <script type="text/javascript">
19862 * @class Roo.data.HttpProxy
19863 * @extends Roo.data.DataProxy
19864 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
19865 * configured to reference a certain URL.<br><br>
19867 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
19868 * from which the running page was served.<br><br>
19870 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
19872 * Be aware that to enable the browser to parse an XML document, the server must set
19873 * the Content-Type header in the HTTP response to "text/xml".
19875 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
19876 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
19877 * will be used to make the request.
19879 Roo.data.HttpProxy = function(conn){
19880 Roo.data.HttpProxy.superclass.constructor.call(this);
19881 // is conn a conn config or a real conn?
19883 this.useAjax = !conn || !conn.events;
19887 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
19888 // thse are take from connection...
19891 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
19894 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
19895 * extra parameters to each request made by this object. (defaults to undefined)
19898 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
19899 * to each request made by this object. (defaults to undefined)
19902 * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
19905 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
19908 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
19914 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
19918 * Return the {@link Roo.data.Connection} object being used by this Proxy.
19919 * @return {Connection} The Connection object. This object may be used to subscribe to events on
19920 * a finer-grained basis than the DataProxy events.
19922 getConnection : function(){
19923 return this.useAjax ? Roo.Ajax : this.conn;
19927 * Load data from the configured {@link Roo.data.Connection}, read the data object into
19928 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
19929 * process that block using the passed callback.
19930 * @param {Object} params An object containing properties which are to be used as HTTP parameters
19931 * for the request to the remote server.
19932 * @param {Roo.data.DataReader} reader The Reader object which converts the data
19933 * object into a block of Roo.data.Records.
19934 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
19935 * The function must be passed <ul>
19936 * <li>The Record block object</li>
19937 * <li>The "arg" argument from the load function</li>
19938 * <li>A boolean success indicator</li>
19940 * @param {Object} scope The scope in which to call the callback
19941 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
19943 load : function(params, reader, callback, scope, arg){
19944 if(this.fireEvent("beforeload", this, params) !== false){
19946 params : params || {},
19948 callback : callback,
19953 callback : this.loadResponse,
19957 Roo.applyIf(o, this.conn);
19958 if(this.activeRequest){
19959 Roo.Ajax.abort(this.activeRequest);
19961 this.activeRequest = Roo.Ajax.request(o);
19963 this.conn.request(o);
19966 callback.call(scope||this, null, arg, false);
19971 loadResponse : function(o, success, response){
19972 delete this.activeRequest;
19974 this.fireEvent("loadexception", this, o, response);
19975 o.request.callback.call(o.request.scope, null, o.request.arg, false);
19980 result = o.reader.read(response);
19982 this.fireEvent("loadexception", this, o, response, e);
19983 o.request.callback.call(o.request.scope, null, o.request.arg, false);
19987 this.fireEvent("load", this, o, o.request.arg);
19988 o.request.callback.call(o.request.scope, result, o.request.arg, true);
19992 update : function(dataSet){
19997 updateResponse : function(dataSet){
20002 * Ext JS Library 1.1.1
20003 * Copyright(c) 2006-2007, Ext JS, LLC.
20005 * Originally Released Under LGPL - original licence link has changed is not relivant.
20008 * <script type="text/javascript">
20012 * @class Roo.data.ScriptTagProxy
20013 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
20014 * other than the originating domain of the running page.<br><br>
20016 * <em>Note that if you are retrieving data from a page that is in a domain that is NOT the same as the originating domain
20017 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
20019 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
20020 * source code that is used as the source inside a <script> tag.<br><br>
20022 * In order for the browser to process the returned data, the server must wrap the data object
20023 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
20024 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
20025 * depending on whether the callback name was passed:
20028 boolean scriptTag = false;
20029 String cb = request.getParameter("callback");
20032 response.setContentType("text/javascript");
20034 response.setContentType("application/x-json");
20036 Writer out = response.getWriter();
20038 out.write(cb + "(");
20040 out.print(dataBlock.toJsonString());
20047 * @param {Object} config A configuration object.
20049 Roo.data.ScriptTagProxy = function(config){
20050 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
20051 Roo.apply(this, config);
20052 this.head = document.getElementsByTagName("head")[0];
20055 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
20057 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
20059 * @cfg {String} url The URL from which to request the data object.
20062 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
20066 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
20067 * the server the name of the callback function set up by the load call to process the returned data object.
20068 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
20069 * javascript output which calls this named function passing the data object as its only parameter.
20071 callbackParam : "callback",
20073 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
20074 * name to the request.
20079 * Load data from the configured URL, read the data object into
20080 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20081 * process that block using the passed callback.
20082 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20083 * for the request to the remote server.
20084 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20085 * object into a block of Roo.data.Records.
20086 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20087 * The function must be passed <ul>
20088 * <li>The Record block object</li>
20089 * <li>The "arg" argument from the load function</li>
20090 * <li>A boolean success indicator</li>
20092 * @param {Object} scope The scope in which to call the callback
20093 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20095 load : function(params, reader, callback, scope, arg){
20096 if(this.fireEvent("beforeload", this, params) !== false){
20098 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
20100 var url = this.url;
20101 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
20103 url += "&_dc=" + (new Date().getTime());
20105 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
20108 cb : "stcCallback"+transId,
20109 scriptId : "stcScript"+transId,
20113 callback : callback,
20119 window[trans.cb] = function(o){
20120 conn.handleResponse(o, trans);
20123 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
20125 if(this.autoAbort !== false){
20129 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
20131 var script = document.createElement("script");
20132 script.setAttribute("src", url);
20133 script.setAttribute("type", "text/javascript");
20134 script.setAttribute("id", trans.scriptId);
20135 this.head.appendChild(script);
20137 this.trans = trans;
20139 callback.call(scope||this, null, arg, false);
20144 isLoading : function(){
20145 return this.trans ? true : false;
20149 * Abort the current server request.
20151 abort : function(){
20152 if(this.isLoading()){
20153 this.destroyTrans(this.trans);
20158 destroyTrans : function(trans, isLoaded){
20159 this.head.removeChild(document.getElementById(trans.scriptId));
20160 clearTimeout(trans.timeoutId);
20162 window[trans.cb] = undefined;
20164 delete window[trans.cb];
20167 // if hasn't been loaded, wait for load to remove it to prevent script error
20168 window[trans.cb] = function(){
20169 window[trans.cb] = undefined;
20171 delete window[trans.cb];
20178 handleResponse : function(o, trans){
20179 this.trans = false;
20180 this.destroyTrans(trans, true);
20183 result = trans.reader.readRecords(o);
20185 this.fireEvent("loadexception", this, o, trans.arg, e);
20186 trans.callback.call(trans.scope||window, null, trans.arg, false);
20189 this.fireEvent("load", this, o, trans.arg);
20190 trans.callback.call(trans.scope||window, result, trans.arg, true);
20194 handleFailure : function(trans){
20195 this.trans = false;
20196 this.destroyTrans(trans, false);
20197 this.fireEvent("loadexception", this, null, trans.arg);
20198 trans.callback.call(trans.scope||window, null, trans.arg, false);
20202 * Ext JS Library 1.1.1
20203 * Copyright(c) 2006-2007, Ext JS, LLC.
20205 * Originally Released Under LGPL - original licence link has changed is not relivant.
20208 * <script type="text/javascript">
20212 * @class Roo.data.JsonReader
20213 * @extends Roo.data.DataReader
20214 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
20215 * based on mappings in a provided Roo.data.Record constructor.
20219 var RecordDef = Roo.data.Record.create([
20220 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
20221 {name: 'occupation'} // This field will use "occupation" as the mapping.
20223 var myReader = new Roo.data.JsonReader({
20224 totalProperty: "results", // The property which contains the total dataset size (optional)
20225 root: "rows", // The property which contains an Array of row objects
20226 id: "id" // The property within each row object that provides an ID for the record (optional)
20230 * This would consume a JSON file like this:
20232 { 'results': 2, 'rows': [
20233 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
20234 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
20237 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
20238 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
20239 * paged from the remote server.
20240 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
20241 * @cfg {String} root name of the property which contains the Array of row objects.
20242 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
20244 * Create a new JsonReader
20245 * @param {Object} meta Metadata configuration options
20246 * @param {Object} recordType Either an Array of field definition objects,
20247 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
20249 Roo.data.JsonReader = function(meta, recordType){
20252 // set some defaults:
20253 Roo.applyIf(meta, {
20254 totalProperty: 'total',
20255 successProperty : 'success',
20260 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
20262 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
20264 * This method is only used by a DataProxy which has retrieved data from a remote server.
20265 * @param {Object} response The XHR object which contains the JSON data in its responseText.
20266 * @return {Object} data A data block which is used by an Roo.data.Store object as
20267 * a cache of Roo.data.Records.
20269 read : function(response){
20270 var json = response.responseText;
20272 var o = eval("("+json+")");
20274 throw {message: "JsonReader.read: Json object not found"};
20279 this.meta = o.metaData;
20280 this.recordType = Roo.data.Record.create(o.metaData.fields);
20281 this.onMetaChange(this.meta, this.recordType, o);
20283 return this.readRecords(o);
20286 // private function a store will implement
20287 onMetaChange : function(meta, recordType, o){
20294 simpleAccess: function(obj, subsc) {
20301 getJsonAccessor: function(){
20303 return function(expr) {
20305 return(re.test(expr))
20306 ? new Function("obj", "return obj." + expr)
20311 return Roo.emptyFn;
20316 * Create a data block containing Roo.data.Records from an XML document.
20317 * @param {Object} o An object which contains an Array of row objects in the property specified
20318 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
20319 * which contains the total size of the dataset.
20320 * @return {Object} data A data block which is used by an Roo.data.Store object as
20321 * a cache of Roo.data.Records.
20323 readRecords : function(o){
20325 * After any data loads, the raw JSON data is available for further custom processing.
20329 var s = this.meta, Record = this.recordType,
20330 f = Record.prototype.fields, fi = f.items, fl = f.length;
20332 // Generate extraction functions for the totalProperty, the root, the id, and for each field
20334 if(s.totalProperty) {
20335 this.getTotal = this.getJsonAccessor(s.totalProperty);
20337 if(s.successProperty) {
20338 this.getSuccess = this.getJsonAccessor(s.successProperty);
20340 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
20342 var g = this.getJsonAccessor(s.id);
20343 this.getId = function(rec) {
20345 return (r === undefined || r === "") ? null : r;
20348 this.getId = function(){return null;};
20351 for(var i = 0; i < fl; i++){
20353 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
20354 this.ef[i] = this.getJsonAccessor(map);
20358 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
20359 if(s.totalProperty){
20360 var v = parseInt(this.getTotal(o), 10);
20365 if(s.successProperty){
20366 var v = this.getSuccess(o);
20367 if(v === false || v === 'false'){
20372 for(var i = 0; i < c; i++){
20375 var id = this.getId(n);
20376 for(var j = 0; j < fl; j++){
20378 var v = this.ef[j](n);
20379 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
20381 var record = new Record(values, id);
20383 records[i] = record;
20388 totalRecords : totalRecords
20393 * Ext JS Library 1.1.1
20394 * Copyright(c) 2006-2007, Ext JS, LLC.
20396 * Originally Released Under LGPL - original licence link has changed is not relivant.
20399 * <script type="text/javascript">
20403 * @class Roo.data.XmlReader
20404 * @extends Roo.data.DataReader
20405 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
20406 * based on mappings in a provided Roo.data.Record constructor.<br><br>
20408 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
20409 * header in the HTTP response must be set to "text/xml".</em>
20413 var RecordDef = Roo.data.Record.create([
20414 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
20415 {name: 'occupation'} // This field will use "occupation" as the mapping.
20417 var myReader = new Roo.data.XmlReader({
20418 totalRecords: "results", // The element which contains the total dataset size (optional)
20419 record: "row", // The repeated element which contains row information
20420 id: "id" // The element within the row that provides an ID for the record (optional)
20424 * This would consume an XML file like this:
20428 <results>2</results>
20431 <name>Bill</name>
20432 <occupation>Gardener</occupation>
20436 <name>Ben</name>
20437 <occupation>Horticulturalist</occupation>
20441 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
20442 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
20443 * paged from the remote server.
20444 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
20445 * @cfg {String} success The DomQuery path to the success attribute used by forms.
20446 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
20447 * a record identifier value.
20449 * Create a new XmlReader
20450 * @param {Object} meta Metadata configuration options
20451 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
20452 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
20453 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
20455 Roo.data.XmlReader = function(meta, recordType){
20457 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
20459 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
20461 * This method is only used by a DataProxy which has retrieved data from a remote server.
20462 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
20463 * to contain a method called 'responseXML' that returns an XML document object.
20464 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
20465 * a cache of Roo.data.Records.
20467 read : function(response){
20468 var doc = response.responseXML;
20470 throw {message: "XmlReader.read: XML Document not available"};
20472 return this.readRecords(doc);
20476 * Create a data block containing Roo.data.Records from an XML document.
20477 * @param {Object} doc A parsed XML document.
20478 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
20479 * a cache of Roo.data.Records.
20481 readRecords : function(doc){
20483 * After any data loads/reads, the raw XML Document is available for further custom processing.
20484 * @type XMLDocument
20486 this.xmlData = doc;
20487 var root = doc.documentElement || doc;
20488 var q = Roo.DomQuery;
20489 var recordType = this.recordType, fields = recordType.prototype.fields;
20490 var sid = this.meta.id;
20491 var totalRecords = 0, success = true;
20492 if(this.meta.totalRecords){
20493 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
20496 if(this.meta.success){
20497 var sv = q.selectValue(this.meta.success, root, true);
20498 success = sv !== false && sv !== 'false';
20501 var ns = q.select(this.meta.record, root);
20502 for(var i = 0, len = ns.length; i < len; i++) {
20505 var id = sid ? q.selectValue(sid, n) : undefined;
20506 for(var j = 0, jlen = fields.length; j < jlen; j++){
20507 var f = fields.items[j];
20508 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
20510 values[f.name] = v;
20512 var record = new recordType(values, id);
20514 records[records.length] = record;
20520 totalRecords : totalRecords || records.length
20525 * Ext JS Library 1.1.1
20526 * Copyright(c) 2006-2007, Ext JS, LLC.
20528 * Originally Released Under LGPL - original licence link has changed is not relivant.
20531 * <script type="text/javascript">
20535 * @class Roo.data.ArrayReader
20536 * @extends Roo.data.DataReader
20537 * Data reader class to create an Array of Roo.data.Record objects from an Array.
20538 * Each element of that Array represents a row of data fields. The
20539 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
20540 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
20544 var RecordDef = Roo.data.Record.create([
20545 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
20546 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
20548 var myReader = new Roo.data.ArrayReader({
20549 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
20553 * This would consume an Array like this:
20555 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
20557 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
20559 * Create a new JsonReader
20560 * @param {Object} meta Metadata configuration options.
20561 * @param {Object} recordType Either an Array of field definition objects
20562 * as specified to {@link Roo.data.Record#create},
20563 * or an {@link Roo.data.Record} object
20564 * created using {@link Roo.data.Record#create}.
20566 Roo.data.ArrayReader = function(meta, recordType){
20567 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
20570 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
20572 * Create a data block containing Roo.data.Records from an XML document.
20573 * @param {Object} o An Array of row objects which represents the dataset.
20574 * @return {Object} data A data block which is used by an Roo.data.Store object as
20575 * a cache of Roo.data.Records.
20577 readRecords : function(o){
20578 var sid = this.meta ? this.meta.id : null;
20579 var recordType = this.recordType, fields = recordType.prototype.fields;
20582 for(var i = 0; i < root.length; i++){
20585 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
20586 for(var j = 0, jlen = fields.length; j < jlen; j++){
20587 var f = fields.items[j];
20588 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
20589 var v = n[k] !== undefined ? n[k] : f.defaultValue;
20591 values[f.name] = v;
20593 var record = new recordType(values, id);
20595 records[records.length] = record;
20599 totalRecords : records.length
20604 * Ext JS Library 1.1.1
20605 * Copyright(c) 2006-2007, Ext JS, LLC.
20607 * Originally Released Under LGPL - original licence link has changed is not relivant.
20610 * <script type="text/javascript">
20615 * @class Roo.data.Tree
20616 * @extends Roo.util.Observable
20617 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
20618 * in the tree have most standard DOM functionality.
20620 * @param {Node} root (optional) The root node
20622 Roo.data.Tree = function(root){
20623 this.nodeHash = {};
20625 * The root node for this tree
20630 this.setRootNode(root);
20635 * Fires when a new child node is appended to a node in this tree.
20636 * @param {Tree} tree The owner tree
20637 * @param {Node} parent The parent node
20638 * @param {Node} node The newly appended node
20639 * @param {Number} index The index of the newly appended node
20644 * Fires when a child node is removed from a node in this tree.
20645 * @param {Tree} tree The owner tree
20646 * @param {Node} parent The parent node
20647 * @param {Node} node The child node removed
20652 * Fires when a node is moved to a new location in the tree
20653 * @param {Tree} tree The owner tree
20654 * @param {Node} node The node moved
20655 * @param {Node} oldParent The old parent of this node
20656 * @param {Node} newParent The new parent of this node
20657 * @param {Number} index The index it was moved to
20662 * Fires when a new child node is inserted in a node in this tree.
20663 * @param {Tree} tree The owner tree
20664 * @param {Node} parent The parent node
20665 * @param {Node} node The child node inserted
20666 * @param {Node} refNode The child node the node was inserted before
20670 * @event beforeappend
20671 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
20672 * @param {Tree} tree The owner tree
20673 * @param {Node} parent The parent node
20674 * @param {Node} node The child node to be appended
20676 "beforeappend" : true,
20678 * @event beforeremove
20679 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
20680 * @param {Tree} tree The owner tree
20681 * @param {Node} parent The parent node
20682 * @param {Node} node The child node to be removed
20684 "beforeremove" : true,
20686 * @event beforemove
20687 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
20688 * @param {Tree} tree The owner tree
20689 * @param {Node} node The node being moved
20690 * @param {Node} oldParent The parent of the node
20691 * @param {Node} newParent The new parent the node is moving to
20692 * @param {Number} index The index it is being moved to
20694 "beforemove" : true,
20696 * @event beforeinsert
20697 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
20698 * @param {Tree} tree The owner tree
20699 * @param {Node} parent The parent node
20700 * @param {Node} node The child node to be inserted
20701 * @param {Node} refNode The child node the node is being inserted before
20703 "beforeinsert" : true
20706 Roo.data.Tree.superclass.constructor.call(this);
20709 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
20710 pathSeparator: "/",
20712 proxyNodeEvent : function(){
20713 return this.fireEvent.apply(this, arguments);
20717 * Returns the root node for this tree.
20720 getRootNode : function(){
20725 * Sets the root node for this tree.
20726 * @param {Node} node
20729 setRootNode : function(node){
20731 node.ownerTree = this;
20732 node.isRoot = true;
20733 this.registerNode(node);
20738 * Gets a node in this tree by its id.
20739 * @param {String} id
20742 getNodeById : function(id){
20743 return this.nodeHash[id];
20746 registerNode : function(node){
20747 this.nodeHash[node.id] = node;
20750 unregisterNode : function(node){
20751 delete this.nodeHash[node.id];
20754 toString : function(){
20755 return "[Tree"+(this.id?" "+this.id:"")+"]";
20760 * @class Roo.data.Node
20761 * @extends Roo.util.Observable
20762 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
20763 * @cfg {String} id The id for this node. If one is not specified, one is generated.
20765 * @param {Object} attributes The attributes/config for the node
20767 Roo.data.Node = function(attributes){
20769 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
20772 this.attributes = attributes || {};
20773 this.leaf = this.attributes.leaf;
20775 * The node id. @type String
20777 this.id = this.attributes.id;
20779 this.id = Roo.id(null, "ynode-");
20780 this.attributes.id = this.id;
20783 * All child nodes of this node. @type Array
20785 this.childNodes = [];
20786 if(!this.childNodes.indexOf){ // indexOf is a must
20787 this.childNodes.indexOf = function(o){
20788 for(var i = 0, len = this.length; i < len; i++){
20789 if(this[i] == o) return i;
20795 * The parent node for this node. @type Node
20797 this.parentNode = null;
20799 * The first direct child node of this node, or null if this node has no child nodes. @type Node
20801 this.firstChild = null;
20803 * The last direct child node of this node, or null if this node has no child nodes. @type Node
20805 this.lastChild = null;
20807 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
20809 this.previousSibling = null;
20811 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
20813 this.nextSibling = null;
20818 * Fires when a new child node is appended
20819 * @param {Tree} tree The owner tree
20820 * @param {Node} this This node
20821 * @param {Node} node The newly appended node
20822 * @param {Number} index The index of the newly appended node
20827 * Fires when a child node is removed
20828 * @param {Tree} tree The owner tree
20829 * @param {Node} this This node
20830 * @param {Node} node The removed node
20835 * Fires when this node is moved to a new location in the tree
20836 * @param {Tree} tree The owner tree
20837 * @param {Node} this This node
20838 * @param {Node} oldParent The old parent of this node
20839 * @param {Node} newParent The new parent of this node
20840 * @param {Number} index The index it was moved to
20845 * Fires when a new child node is inserted.
20846 * @param {Tree} tree The owner tree
20847 * @param {Node} this This node
20848 * @param {Node} node The child node inserted
20849 * @param {Node} refNode The child node the node was inserted before
20853 * @event beforeappend
20854 * Fires before a new child is appended, return false to cancel the append.
20855 * @param {Tree} tree The owner tree
20856 * @param {Node} this This node
20857 * @param {Node} node The child node to be appended
20859 "beforeappend" : true,
20861 * @event beforeremove
20862 * Fires before a child is removed, return false to cancel the remove.
20863 * @param {Tree} tree The owner tree
20864 * @param {Node} this This node
20865 * @param {Node} node The child node to be removed
20867 "beforeremove" : true,
20869 * @event beforemove
20870 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
20871 * @param {Tree} tree The owner tree
20872 * @param {Node} this This node
20873 * @param {Node} oldParent The parent of this node
20874 * @param {Node} newParent The new parent this node is moving to
20875 * @param {Number} index The index it is being moved to
20877 "beforemove" : true,
20879 * @event beforeinsert
20880 * Fires before a new child is inserted, return false to cancel the insert.
20881 * @param {Tree} tree The owner tree
20882 * @param {Node} this This node
20883 * @param {Node} node The child node to be inserted
20884 * @param {Node} refNode The child node the node is being inserted before
20886 "beforeinsert" : true
20888 this.listeners = this.attributes.listeners;
20889 Roo.data.Node.superclass.constructor.call(this);
20892 Roo.extend(Roo.data.Node, Roo.util.Observable, {
20893 fireEvent : function(evtName){
20894 // first do standard event for this node
20895 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
20898 // then bubble it up to the tree if the event wasn't cancelled
20899 var ot = this.getOwnerTree();
20901 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
20909 * Returns true if this node is a leaf
20910 * @return {Boolean}
20912 isLeaf : function(){
20913 return this.leaf === true;
20917 setFirstChild : function(node){
20918 this.firstChild = node;
20922 setLastChild : function(node){
20923 this.lastChild = node;
20928 * Returns true if this node is the last child of its parent
20929 * @return {Boolean}
20931 isLast : function(){
20932 return (!this.parentNode ? true : this.parentNode.lastChild == this);
20936 * Returns true if this node is the first child of its parent
20937 * @return {Boolean}
20939 isFirst : function(){
20940 return (!this.parentNode ? true : this.parentNode.firstChild == this);
20943 hasChildNodes : function(){
20944 return !this.isLeaf() && this.childNodes.length > 0;
20948 * Insert node(s) as the last child node of this node.
20949 * @param {Node/Array} node The node or Array of nodes to append
20950 * @return {Node} The appended node if single append, or null if an array was passed
20952 appendChild : function(node){
20954 if(node instanceof Array){
20956 }else if(arguments.length > 1){
20959 // if passed an array or multiple args do them one by one
20961 for(var i = 0, len = multi.length; i < len; i++) {
20962 this.appendChild(multi[i]);
20965 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
20968 var index = this.childNodes.length;
20969 var oldParent = node.parentNode;
20970 // it's a move, make sure we move it cleanly
20972 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
20975 oldParent.removeChild(node);
20977 index = this.childNodes.length;
20979 this.setFirstChild(node);
20981 this.childNodes.push(node);
20982 node.parentNode = this;
20983 var ps = this.childNodes[index-1];
20985 node.previousSibling = ps;
20986 ps.nextSibling = node;
20988 node.previousSibling = null;
20990 node.nextSibling = null;
20991 this.setLastChild(node);
20992 node.setOwnerTree(this.getOwnerTree());
20993 this.fireEvent("append", this.ownerTree, this, node, index);
20995 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
21002 * Removes a child node from this node.
21003 * @param {Node} node The node to remove
21004 * @return {Node} The removed node
21006 removeChild : function(node){
21007 var index = this.childNodes.indexOf(node);
21011 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
21015 // remove it from childNodes collection
21016 this.childNodes.splice(index, 1);
21019 if(node.previousSibling){
21020 node.previousSibling.nextSibling = node.nextSibling;
21022 if(node.nextSibling){
21023 node.nextSibling.previousSibling = node.previousSibling;
21026 // update child refs
21027 if(this.firstChild == node){
21028 this.setFirstChild(node.nextSibling);
21030 if(this.lastChild == node){
21031 this.setLastChild(node.previousSibling);
21034 node.setOwnerTree(null);
21035 // clear any references from the node
21036 node.parentNode = null;
21037 node.previousSibling = null;
21038 node.nextSibling = null;
21039 this.fireEvent("remove", this.ownerTree, this, node);
21044 * Inserts the first node before the second node in this nodes childNodes collection.
21045 * @param {Node} node The node to insert
21046 * @param {Node} refNode The node to insert before (if null the node is appended)
21047 * @return {Node} The inserted node
21049 insertBefore : function(node, refNode){
21050 if(!refNode){ // like standard Dom, refNode can be null for append
21051 return this.appendChild(node);
21054 if(node == refNode){
21058 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
21061 var index = this.childNodes.indexOf(refNode);
21062 var oldParent = node.parentNode;
21063 var refIndex = index;
21065 // when moving internally, indexes will change after remove
21066 if(oldParent == this && this.childNodes.indexOf(node) < index){
21070 // it's a move, make sure we move it cleanly
21072 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
21075 oldParent.removeChild(node);
21078 this.setFirstChild(node);
21080 this.childNodes.splice(refIndex, 0, node);
21081 node.parentNode = this;
21082 var ps = this.childNodes[refIndex-1];
21084 node.previousSibling = ps;
21085 ps.nextSibling = node;
21087 node.previousSibling = null;
21089 node.nextSibling = refNode;
21090 refNode.previousSibling = node;
21091 node.setOwnerTree(this.getOwnerTree());
21092 this.fireEvent("insert", this.ownerTree, this, node, refNode);
21094 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
21100 * Returns the child node at the specified index.
21101 * @param {Number} index
21104 item : function(index){
21105 return this.childNodes[index];
21109 * Replaces one child node in this node with another.
21110 * @param {Node} newChild The replacement node
21111 * @param {Node} oldChild The node to replace
21112 * @return {Node} The replaced node
21114 replaceChild : function(newChild, oldChild){
21115 this.insertBefore(newChild, oldChild);
21116 this.removeChild(oldChild);
21121 * Returns the index of a child node
21122 * @param {Node} node
21123 * @return {Number} The index of the node or -1 if it was not found
21125 indexOf : function(child){
21126 return this.childNodes.indexOf(child);
21130 * Returns the tree this node is in.
21133 getOwnerTree : function(){
21134 // if it doesn't have one, look for one
21135 if(!this.ownerTree){
21139 this.ownerTree = p.ownerTree;
21145 return this.ownerTree;
21149 * Returns depth of this node (the root node has a depth of 0)
21152 getDepth : function(){
21155 while(p.parentNode){
21163 setOwnerTree : function(tree){
21164 // if it's move, we need to update everyone
21165 if(tree != this.ownerTree){
21166 if(this.ownerTree){
21167 this.ownerTree.unregisterNode(this);
21169 this.ownerTree = tree;
21170 var cs = this.childNodes;
21171 for(var i = 0, len = cs.length; i < len; i++) {
21172 cs[i].setOwnerTree(tree);
21175 tree.registerNode(this);
21181 * Returns the path for this node. The path can be used to expand or select this node programmatically.
21182 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
21183 * @return {String} The path
21185 getPath : function(attr){
21186 attr = attr || "id";
21187 var p = this.parentNode;
21188 var b = [this.attributes[attr]];
21190 b.unshift(p.attributes[attr]);
21193 var sep = this.getOwnerTree().pathSeparator;
21194 return sep + b.join(sep);
21198 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
21199 * function call will be the scope provided or the current node. The arguments to the function
21200 * will be the args provided or the current node. If the function returns false at any point,
21201 * the bubble is stopped.
21202 * @param {Function} fn The function to call
21203 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21204 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21206 bubble : function(fn, scope, args){
21209 if(fn.call(scope || p, args || p) === false){
21217 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
21218 * function call will be the scope provided or the current node. The arguments to the function
21219 * will be the args provided or the current node. If the function returns false at any point,
21220 * the cascade is stopped on that branch.
21221 * @param {Function} fn The function to call
21222 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21223 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21225 cascade : function(fn, scope, args){
21226 if(fn.call(scope || this, args || this) !== false){
21227 var cs = this.childNodes;
21228 for(var i = 0, len = cs.length; i < len; i++) {
21229 cs[i].cascade(fn, scope, args);
21235 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
21236 * function call will be the scope provided or the current node. The arguments to the function
21237 * will be the args provided or the current node. If the function returns false at any point,
21238 * the iteration stops.
21239 * @param {Function} fn The function to call
21240 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21241 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21243 eachChild : function(fn, scope, args){
21244 var cs = this.childNodes;
21245 for(var i = 0, len = cs.length; i < len; i++) {
21246 if(fn.call(scope || this, args || cs[i]) === false){
21253 * Finds the first child that has the attribute with the specified value.
21254 * @param {String} attribute The attribute name
21255 * @param {Mixed} value The value to search for
21256 * @return {Node} The found child or null if none was found
21258 findChild : function(attribute, value){
21259 var cs = this.childNodes;
21260 for(var i = 0, len = cs.length; i < len; i++) {
21261 if(cs[i].attributes[attribute] == value){
21269 * Finds the first child by a custom function. The child matches if the function passed
21271 * @param {Function} fn
21272 * @param {Object} scope (optional)
21273 * @return {Node} The found child or null if none was found
21275 findChildBy : function(fn, scope){
21276 var cs = this.childNodes;
21277 for(var i = 0, len = cs.length; i < len; i++) {
21278 if(fn.call(scope||cs[i], cs[i]) === true){
21286 * Sorts this nodes children using the supplied sort function
21287 * @param {Function} fn
21288 * @param {Object} scope (optional)
21290 sort : function(fn, scope){
21291 var cs = this.childNodes;
21292 var len = cs.length;
21294 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
21296 for(var i = 0; i < len; i++){
21298 n.previousSibling = cs[i-1];
21299 n.nextSibling = cs[i+1];
21301 this.setFirstChild(n);
21304 this.setLastChild(n);
21311 * Returns true if this node is an ancestor (at any point) of the passed node.
21312 * @param {Node} node
21313 * @return {Boolean}
21315 contains : function(node){
21316 return node.isAncestor(this);
21320 * Returns true if the passed node is an ancestor (at any point) of this node.
21321 * @param {Node} node
21322 * @return {Boolean}
21324 isAncestor : function(node){
21325 var p = this.parentNode;
21335 toString : function(){
21336 return "[Node"+(this.id?" "+this.id:"")+"]";