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 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);
1106 Date.createParser = function(format) {
1107 var funcName = "parse" + Date.parseFunctions.count++;
1108 var regexNum = Date.parseRegexes.length;
1109 var currentGroup = 1;
1110 Date.parseFunctions[format] = funcName;
1112 var code = "Date." + funcName + " = function(input){\n"
1113 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1114 + "var d = new Date();\n"
1115 + "y = d.getFullYear();\n"
1116 + "m = d.getMonth();\n"
1117 + "d = d.getDate();\n"
1118 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1119 + "if (results && results.length > 0) {";
1122 var special = false;
1124 for (var i = 0; i < format.length; ++i) {
1125 ch = format.charAt(i);
1126 if (!special && ch == "\\") {
1131 regex += String.escape(ch);
1134 var obj = Date.formatCodeToRegex(ch, currentGroup);
1135 currentGroup += obj.g;
1137 if (obj.g && obj.c) {
1143 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1144 + "{v = new Date(y, m, d, h, i, s);}\n"
1145 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1146 + "{v = new Date(y, m, d, h, i);}\n"
1147 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1148 + "{v = new Date(y, m, d, h);}\n"
1149 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1150 + "{v = new Date(y, m, d);}\n"
1151 + "else if (y >= 0 && m >= 0)\n"
1152 + "{v = new Date(y, m);}\n"
1153 + "else if (y >= 0)\n"
1154 + "{v = new Date(y);}\n"
1155 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1156 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1157 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1160 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1161 /** eval:var:zzzzzzzzzzzzz */
1166 Date.formatCodeToRegex = function(character, currentGroup) {
1167 switch (character) {
1171 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1174 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1175 s:"(\\d{1,2})"}; // day of month without leading zeroes
1178 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1179 s:"(\\d{2})"}; // day of month with leading zeroes
1183 s:"(?:" + Date.dayNames.join("|") + ")"};
1187 s:"(?:st|nd|rd|th)"};
1202 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1203 s:"(" + Date.monthNames.join("|") + ")"};
1206 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1207 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1210 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1211 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1214 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1215 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1226 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1230 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1231 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1235 c:"if (results[" + currentGroup + "] == 'am') {\n"
1236 + "if (h == 12) { h = 0; }\n"
1237 + "} else { if (h < 12) { h += 12; }}",
1241 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1242 + "if (h == 12) { h = 0; }\n"
1243 + "} else { if (h < 12) { h += 12; }}",
1248 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1249 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1253 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1254 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1257 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1261 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1266 "o = results[", currentGroup, "];\n",
1267 "var sn = o.substring(0,1);\n", // get + / - sign
1268 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1269 "var mn = o.substring(3,5) % 60;\n", // get minutes
1270 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1271 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1277 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1280 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1281 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1282 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1286 s:String.escape(character)};
1291 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1292 * @return {String} The abbreviated timezone name (e.g. 'CST')
1294 Date.prototype.getTimezone = function() {
1295 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1299 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1300 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1302 Date.prototype.getGMTOffset = function() {
1303 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1304 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1305 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1309 * Get the numeric day number of the year, adjusted for leap year.
1310 * @return {Number} 0 through 364 (365 in leap years)
1312 Date.prototype.getDayOfYear = function() {
1314 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1315 for (var i = 0; i < this.getMonth(); ++i) {
1316 num += Date.daysInMonth[i];
1318 return num + this.getDate() - 1;
1322 * Get the string representation of the numeric week number of the year
1323 * (equivalent to the format specifier 'W').
1324 * @return {String} '00' through '52'
1326 Date.prototype.getWeekOfYear = function() {
1327 // Skip to Thursday of this week
1328 var now = this.getDayOfYear() + (4 - this.getDay());
1329 // Find the first Thursday of the year
1330 var jan1 = new Date(this.getFullYear(), 0, 1);
1331 var then = (7 - jan1.getDay() + 4);
1332 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1336 * Whether or not the current date is in a leap year.
1337 * @return {Boolean} True if the current date is in a leap year, else false
1339 Date.prototype.isLeapYear = function() {
1340 var year = this.getFullYear();
1341 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1345 * Get the first day of the current month, adjusted for leap year. The returned value
1346 * is the numeric day index within the week (0-6) which can be used in conjunction with
1347 * the {@link #monthNames} array to retrieve the textual day name.
1350 var dt = new Date('1/10/2007');
1351 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1353 * @return {Number} The day number (0-6)
1355 Date.prototype.getFirstDayOfMonth = function() {
1356 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1357 return (day < 0) ? (day + 7) : day;
1361 * Get the last day of the current month, adjusted for leap year. The returned value
1362 * is the numeric day index within the week (0-6) which can be used in conjunction with
1363 * the {@link #monthNames} array to retrieve the textual day name.
1366 var dt = new Date('1/10/2007');
1367 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1369 * @return {Number} The day number (0-6)
1371 Date.prototype.getLastDayOfMonth = function() {
1372 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1373 return (day < 0) ? (day + 7) : day;
1378 * Get the first date of this date's month
1381 Date.prototype.getFirstDateOfMonth = function() {
1382 return new Date(this.getFullYear(), this.getMonth(), 1);
1386 * Get the last date of this date's month
1389 Date.prototype.getLastDateOfMonth = function() {
1390 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1393 * Get the number of days in the current month, adjusted for leap year.
1394 * @return {Number} The number of days in the month
1396 Date.prototype.getDaysInMonth = function() {
1397 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1398 return Date.daysInMonth[this.getMonth()];
1402 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1403 * @return {String} 'st, 'nd', 'rd' or 'th'
1405 Date.prototype.getSuffix = function() {
1406 switch (this.getDate()) {
1423 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1426 * An array of textual month names.
1427 * Override these values for international dates, for example...
1428 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1447 * An array of textual day names.
1448 * Override these values for international dates, for example...
1449 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1465 Date.monthNumbers = {
1480 * Creates and returns a new Date instance with the exact same date value as the called instance.
1481 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1482 * variable will also be changed. When the intention is to create a new variable that will not
1483 * modify the original instance, you should create a clone.
1485 * Example of correctly cloning a date:
1488 var orig = new Date('10/1/2006');
1491 document.write(orig); //returns 'Thu Oct 05 2006'!
1494 var orig = new Date('10/1/2006');
1495 var copy = orig.clone();
1497 document.write(orig); //returns 'Thu Oct 01 2006'
1499 * @return {Date} The new Date instance
1501 Date.prototype.clone = function() {
1502 return new Date(this.getTime());
1506 * Clears any time information from this date
1507 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1508 @return {Date} this or the clone
1510 Date.prototype.clearTime = function(clone){
1512 return this.clone().clearTime();
1517 this.setMilliseconds(0);
1522 // safari setMonth is broken
1524 Date.brokenSetMonth = Date.prototype.setMonth;
1525 Date.prototype.setMonth = function(num){
1527 var n = Math.ceil(-num);
1528 var back_year = Math.ceil(n/12);
1529 var month = (n % 12) ? 12 - n % 12 : 0 ;
1530 this.setFullYear(this.getFullYear() - back_year);
1531 return Date.brokenSetMonth.call(this, month);
1533 return Date.brokenSetMonth.apply(this, arguments);
1538 /** Date interval constant
1542 /** Date interval constant
1546 /** Date interval constant
1550 /** Date interval constant
1554 /** Date interval constant
1558 /** Date interval constant
1562 /** Date interval constant
1568 * Provides a convenient method of performing basic date arithmetic. This method
1569 * does not modify the Date instance being called - it creates and returns
1570 * a new Date instance containing the resulting date value.
1575 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1576 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1578 //Negative values will subtract correctly:
1579 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1580 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1582 //You can even chain several calls together in one line!
1583 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1584 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1587 * @param {String} interval A valid date interval enum value
1588 * @param {Number} value The amount to add to the current date
1589 * @return {Date} The new Date instance
1591 Date.prototype.add = function(interval, value){
1592 var d = this.clone();
1593 if (!interval || value === 0) return d;
1594 switch(interval.toLowerCase()){
1596 d.setMilliseconds(this.getMilliseconds() + value);
1599 d.setSeconds(this.getSeconds() + value);
1602 d.setMinutes(this.getMinutes() + value);
1605 d.setHours(this.getHours() + value);
1608 d.setDate(this.getDate() + value);
1611 var day = this.getDate();
1613 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1616 d.setMonth(this.getMonth() + value);
1619 d.setFullYear(this.getFullYear() + value);
1625 * Ext JS Library 1.1.1
1626 * Copyright(c) 2006-2007, Ext JS, LLC.
1628 * Originally Released Under LGPL - original licence link has changed is not relivant.
1631 * <script type="text/javascript">
1635 getViewWidth : function(full) {
1636 return full ? this.getDocumentWidth() : this.getViewportWidth();
1639 getViewHeight : function(full) {
1640 return full ? this.getDocumentHeight() : this.getViewportHeight();
1643 getDocumentHeight: function() {
1644 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1645 return Math.max(scrollHeight, this.getViewportHeight());
1648 getDocumentWidth: function() {
1649 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1650 return Math.max(scrollWidth, this.getViewportWidth());
1653 getViewportHeight: function() {
1654 var height = self.innerHeight;
1655 var mode = document.compatMode;
1657 if ((mode || Roo.isIE) && !Roo.isOpera) {
1658 height = (mode == "CSS1Compat") ?
1659 document.documentElement.clientHeight :
1660 document.body.clientHeight;
1666 getViewportWidth: function() {
1667 var width = self.innerWidth;
1668 var mode = document.compatMode;
1670 if (mode || Roo.isIE) {
1671 width = (mode == "CSS1Compat") ?
1672 document.documentElement.clientWidth :
1673 document.body.clientWidth;
1678 isAncestor : function(p, c) {
1685 if (p.contains && !Roo.isSafari) {
1686 return p.contains(c);
1687 } else if (p.compareDocumentPosition) {
1688 return !!(p.compareDocumentPosition(c) & 16);
1690 var parent = c.parentNode;
1695 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1698 parent = parent.parentNode;
1704 getRegion : function(el) {
1705 return Roo.lib.Region.getRegion(el);
1708 getY : function(el) {
1709 return this.getXY(el)[1];
1712 getX : function(el) {
1713 return this.getXY(el)[0];
1716 getXY : function(el) {
1717 var p, pe, b, scroll, bd = document.body;
1718 el = Roo.getDom(el);
1719 var fly = Roo.lib.AnimBase.fly;
1720 if (el.getBoundingClientRect) {
1721 b = el.getBoundingClientRect();
1722 scroll = fly(document).getScroll();
1723 return [b.left + scroll.left, b.top + scroll.top];
1729 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1736 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1743 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1744 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1751 if (p != el && pe.getStyle('overflow') != 'visible') {
1759 if (Roo.isSafari && hasAbsolute) {
1764 if (Roo.isGecko && !hasAbsolute) {
1766 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1767 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1771 while (p && p != bd) {
1772 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1784 setXY : function(el, xy) {
1785 el = Roo.fly(el, '_setXY');
1787 var pts = el.translatePoints(xy);
1788 if (xy[0] !== false) {
1789 el.dom.style.left = pts.left + "px";
1791 if (xy[1] !== false) {
1792 el.dom.style.top = pts.top + "px";
1796 setX : function(el, x) {
1797 this.setXY(el, [x, false]);
1800 setY : function(el, y) {
1801 this.setXY(el, [false, y]);
1805 * Portions of this file are based on pieces of Yahoo User Interface Library
1806 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1807 * YUI licensed under the BSD License:
1808 * http://developer.yahoo.net/yui/license.txt
1809 * <script type="text/javascript">
1813 Roo.lib.Event = function() {
1814 var loadComplete = false;
1816 var unloadListeners = [];
1818 var onAvailStack = [];
1820 var lastError = null;
1833 startInterval: function() {
1834 if (!this._interval) {
1836 var callback = function() {
1837 self._tryPreloadAttach();
1839 this._interval = setInterval(callback, this.POLL_INTERVAL);
1844 onAvailable: function(p_id, p_fn, p_obj, p_override) {
1845 onAvailStack.push({ id: p_id,
1848 override: p_override,
1849 checkReady: false });
1851 retryCount = this.POLL_RETRYS;
1852 this.startInterval();
1856 addListener: function(el, eventName, fn) {
1857 el = Roo.getDom(el);
1862 if ("unload" == eventName) {
1863 unloadListeners[unloadListeners.length] =
1864 [el, eventName, fn];
1868 var wrappedFn = function(e) {
1869 return fn(Roo.lib.Event.getEvent(e));
1872 var li = [el, eventName, fn, wrappedFn];
1874 var index = listeners.length;
1875 listeners[index] = li;
1877 this.doAdd(el, eventName, wrappedFn, false);
1883 removeListener: function(el, eventName, fn) {
1886 el = Roo.getDom(el);
1889 return this.purgeElement(el, false, eventName);
1893 if ("unload" == eventName) {
1895 for (i = 0,len = unloadListeners.length; i < len; i++) {
1896 var li = unloadListeners[i];
1899 li[1] == eventName &&
1901 unloadListeners.splice(i, 1);
1909 var cacheItem = null;
1912 var index = arguments[3];
1914 if ("undefined" == typeof index) {
1915 index = this._getCacheIndex(el, eventName, fn);
1919 cacheItem = listeners[index];
1922 if (!el || !cacheItem) {
1926 this.doRemove(el, eventName, cacheItem[this.WFN], false);
1928 delete listeners[index][this.WFN];
1929 delete listeners[index][this.FN];
1930 listeners.splice(index, 1);
1937 getTarget: function(ev, resolveTextNode) {
1938 ev = ev.browserEvent || ev;
1939 var t = ev.target || ev.srcElement;
1940 return this.resolveTextNode(t);
1944 resolveTextNode: function(node) {
1945 if (Roo.isSafari && node && 3 == node.nodeType) {
1946 return node.parentNode;
1953 getPageX: function(ev) {
1954 ev = ev.browserEvent || ev;
1956 if (!x && 0 !== x) {
1957 x = ev.clientX || 0;
1960 x += this.getScroll()[1];
1968 getPageY: function(ev) {
1969 ev = ev.browserEvent || ev;
1971 if (!y && 0 !== y) {
1972 y = ev.clientY || 0;
1975 y += this.getScroll()[0];
1984 getXY: function(ev) {
1985 ev = ev.browserEvent || ev;
1986 return [this.getPageX(ev), this.getPageY(ev)];
1990 getRelatedTarget: function(ev) {
1991 ev = ev.browserEvent || ev;
1992 var t = ev.relatedTarget;
1994 if (ev.type == "mouseout") {
1996 } else if (ev.type == "mouseover") {
2001 return this.resolveTextNode(t);
2005 getTime: function(ev) {
2006 ev = ev.browserEvent || ev;
2008 var t = new Date().getTime();
2012 this.lastError = ex;
2021 stopEvent: function(ev) {
2022 this.stopPropagation(ev);
2023 this.preventDefault(ev);
2027 stopPropagation: function(ev) {
2028 ev = ev.browserEvent || ev;
2029 if (ev.stopPropagation) {
2030 ev.stopPropagation();
2032 ev.cancelBubble = true;
2037 preventDefault: function(ev) {
2038 ev = ev.browserEvent || ev;
2039 if(ev.preventDefault) {
2040 ev.preventDefault();
2042 ev.returnValue = false;
2047 getEvent: function(e) {
2048 var ev = e || window.event;
2050 var c = this.getEvent.caller;
2052 ev = c.arguments[0];
2053 if (ev && Event == ev.constructor) {
2063 getCharCode: function(ev) {
2064 ev = ev.browserEvent || ev;
2065 return ev.charCode || ev.keyCode || 0;
2069 _getCacheIndex: function(el, eventName, fn) {
2070 for (var i = 0,len = listeners.length; i < len; ++i) {
2071 var li = listeners[i];
2073 li[this.FN] == fn &&
2074 li[this.EL] == el &&
2075 li[this.TYPE] == eventName) {
2087 getEl: function(id) {
2088 return document.getElementById(id);
2092 clearCache: function() {
2096 _load: function(e) {
2097 loadComplete = true;
2098 var EU = Roo.lib.Event;
2102 EU.doRemove(window, "load", EU._load);
2107 _tryPreloadAttach: function() {
2116 var tryAgain = !loadComplete;
2118 tryAgain = (retryCount > 0);
2123 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2124 var item = onAvailStack[i];
2126 var el = this.getEl(item.id);
2129 if (!item.checkReady ||
2132 (document && document.body)) {
2135 if (item.override) {
2136 if (item.override === true) {
2139 scope = item.override;
2142 item.fn.call(scope, item.obj);
2143 onAvailStack[i] = null;
2146 notAvail.push(item);
2151 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2155 this.startInterval();
2157 clearInterval(this._interval);
2158 this._interval = null;
2161 this.locked = false;
2168 purgeElement: function(el, recurse, eventName) {
2169 var elListeners = this.getListeners(el, eventName);
2171 for (var i = 0,len = elListeners.length; i < len; ++i) {
2172 var l = elListeners[i];
2173 this.removeListener(el, l.type, l.fn);
2177 if (recurse && el && el.childNodes) {
2178 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2179 this.purgeElement(el.childNodes[i], recurse, eventName);
2185 getListeners: function(el, eventName) {
2186 var results = [], searchLists;
2188 searchLists = [listeners, unloadListeners];
2189 } else if (eventName == "unload") {
2190 searchLists = [unloadListeners];
2192 searchLists = [listeners];
2195 for (var j = 0; j < searchLists.length; ++j) {
2196 var searchList = searchLists[j];
2197 if (searchList && searchList.length > 0) {
2198 for (var i = 0,len = searchList.length; i < len; ++i) {
2199 var l = searchList[i];
2200 if (l && l[this.EL] === el &&
2201 (!eventName || eventName === l[this.TYPE])) {
2206 adjust: l[this.ADJ_SCOPE],
2214 return (results.length) ? results : null;
2218 _unload: function(e) {
2220 var EU = Roo.lib.Event, i, j, l, len, index;
2222 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2223 l = unloadListeners[i];
2226 if (l[EU.ADJ_SCOPE]) {
2227 if (l[EU.ADJ_SCOPE] === true) {
2230 scope = l[EU.ADJ_SCOPE];
2233 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2234 unloadListeners[i] = null;
2240 unloadListeners = null;
2242 if (listeners && listeners.length > 0) {
2243 j = listeners.length;
2246 l = listeners[index];
2248 EU.removeListener(l[EU.EL], l[EU.TYPE],
2258 EU.doRemove(window, "unload", EU._unload);
2263 getScroll: function() {
2264 var dd = document.documentElement, db = document.body;
2265 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2266 return [dd.scrollTop, dd.scrollLeft];
2268 return [db.scrollTop, db.scrollLeft];
2275 doAdd: function () {
2276 if (window.addEventListener) {
2277 return function(el, eventName, fn, capture) {
2278 el.addEventListener(eventName, fn, (capture));
2280 } else if (window.attachEvent) {
2281 return function(el, eventName, fn, capture) {
2282 el.attachEvent("on" + eventName, fn);
2291 doRemove: function() {
2292 if (window.removeEventListener) {
2293 return function (el, eventName, fn, capture) {
2294 el.removeEventListener(eventName, fn, (capture));
2296 } else if (window.detachEvent) {
2297 return function (el, eventName, fn) {
2298 el.detachEvent("on" + eventName, fn);
2310 var E = Roo.lib.Event;
2311 E.on = E.addListener;
2312 E.un = E.removeListener;
2314 if (document && document.body) {
2317 E.doAdd(window, "load", E._load);
2319 E.doAdd(window, "unload", E._unload);
2320 E._tryPreloadAttach();
2324 * Portions of this file are based on pieces of Yahoo User Interface Library
2325 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2326 * YUI licensed under the BSD License:
2327 * http://developer.yahoo.net/yui/license.txt
2328 * <script type="text/javascript">
2335 request : function(method, uri, cb, data, options) {
2337 var hs = options.headers;
2340 if(hs.hasOwnProperty(h)){
2341 this.initHeader(h, hs[h], false);
2345 if(options.xmlData){
2346 this.initHeader('Content-Type', 'text/xml', false);
2348 data = options.xmlData;
2352 return this.asyncRequest(method, uri, cb, data);
2355 serializeForm : function(form) {
2356 if(typeof form == 'string') {
2357 form = (document.getElementById(form) || document.forms[form]);
2360 var el, name, val, disabled, data = '', hasSubmit = false;
2361 for (var i = 0; i < form.elements.length; i++) {
2362 el = form.elements[i];
2363 disabled = form.elements[i].disabled;
2364 name = form.elements[i].name;
2365 val = form.elements[i].value;
2367 if (!disabled && name){
2371 case 'select-multiple':
2372 for (var j = 0; j < el.options.length; j++) {
2373 if (el.options[j].selected) {
2375 data += encodeURIComponent(name) + '=' + encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2378 data += encodeURIComponent(name) + '=' + encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2386 data += encodeURIComponent(name) + '=' + encodeURIComponent(val) + '&';
2399 if(hasSubmit == false) {
2400 data += encodeURIComponent(name) + '=' + encodeURIComponent(val) + '&';
2405 data += encodeURIComponent(name) + '=' + encodeURIComponent(val) + '&';
2410 data = data.substr(0, data.length - 1);
2418 useDefaultHeader:true,
2420 defaultPostHeader:'application/x-www-form-urlencoded',
2422 useDefaultXhrHeader:true,
2424 defaultXhrHeader:'XMLHttpRequest',
2426 hasDefaultHeaders:true,
2438 setProgId:function(id)
2440 this.activeX.unshift(id);
2443 setDefaultPostHeader:function(b)
2445 this.useDefaultHeader = b;
2448 setDefaultXhrHeader:function(b)
2450 this.useDefaultXhrHeader = b;
2453 setPollingInterval:function(i)
2455 if (typeof i == 'number' && isFinite(i)) {
2456 this.pollInterval = i;
2460 createXhrObject:function(transactionId)
2466 http = new XMLHttpRequest();
2468 obj = { conn:http, tId:transactionId };
2472 for (var i = 0; i < this.activeX.length; ++i) {
2476 http = new ActiveXObject(this.activeX[i]);
2478 obj = { conn:http, tId:transactionId };
2491 getConnectionObject:function()
2494 var tId = this.transactionId;
2498 o = this.createXhrObject(tId);
2500 this.transactionId++;
2511 asyncRequest:function(method, uri, callback, postData)
2513 var o = this.getConnectionObject();
2519 o.conn.open(method, uri, true);
2521 if (this.useDefaultXhrHeader) {
2522 if (!this.defaultHeaders['X-Requested-With']) {
2523 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2527 if(postData && this.useDefaultHeader){
2528 this.initHeader('Content-Type', this.defaultPostHeader);
2531 if (this.hasDefaultHeaders || this.hasHeaders) {
2535 this.handleReadyState(o, callback);
2536 o.conn.send(postData || null);
2542 handleReadyState:function(o, callback)
2546 if (callback && callback.timeout) {
2547 this.timeout[o.tId] = window.setTimeout(function() {
2548 oConn.abort(o, callback, true);
2549 }, callback.timeout);
2552 this.poll[o.tId] = window.setInterval(
2554 if (o.conn && o.conn.readyState == 4) {
2555 window.clearInterval(oConn.poll[o.tId]);
2556 delete oConn.poll[o.tId];
2558 if(callback && callback.timeout) {
2559 window.clearTimeout(oConn.timeout[o.tId]);
2560 delete oConn.timeout[o.tId];
2563 oConn.handleTransactionResponse(o, callback);
2566 , this.pollInterval);
2569 handleTransactionResponse:function(o, callback, isAbort)
2573 this.releaseObject(o);
2577 var httpStatus, responseObject;
2581 if (o.conn.status !== undefined && o.conn.status != 0) {
2582 httpStatus = o.conn.status;
2594 if (httpStatus >= 200 && httpStatus < 300) {
2595 responseObject = this.createResponseObject(o, callback.argument);
2596 if (callback.success) {
2597 if (!callback.scope) {
2598 callback.success(responseObject);
2603 callback.success.apply(callback.scope, [responseObject]);
2608 switch (httpStatus) {
2616 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2617 if (callback.failure) {
2618 if (!callback.scope) {
2619 callback.failure(responseObject);
2622 callback.failure.apply(callback.scope, [responseObject]);
2627 responseObject = this.createResponseObject(o, callback.argument);
2628 if (callback.failure) {
2629 if (!callback.scope) {
2630 callback.failure(responseObject);
2633 callback.failure.apply(callback.scope, [responseObject]);
2639 this.releaseObject(o);
2640 responseObject = null;
2643 createResponseObject:function(o, callbackArg)
2650 var headerStr = o.conn.getAllResponseHeaders();
2651 var header = headerStr.split('\n');
2652 for (var i = 0; i < header.length; i++) {
2653 var delimitPos = header[i].indexOf(':');
2654 if (delimitPos != -1) {
2655 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2663 obj.status = o.conn.status;
2664 obj.statusText = o.conn.statusText;
2665 obj.getResponseHeader = headerObj;
2666 obj.getAllResponseHeaders = headerStr;
2667 obj.responseText = o.conn.responseText;
2668 obj.responseXML = o.conn.responseXML;
2670 if (typeof callbackArg !== undefined) {
2671 obj.argument = callbackArg;
2677 createExceptionObject:function(tId, callbackArg, isAbort)
2680 var COMM_ERROR = 'communication failure';
2681 var ABORT_CODE = -1;
2682 var ABORT_ERROR = 'transaction aborted';
2688 obj.status = ABORT_CODE;
2689 obj.statusText = ABORT_ERROR;
2692 obj.status = COMM_CODE;
2693 obj.statusText = COMM_ERROR;
2697 obj.argument = callbackArg;
2703 initHeader:function(label, value, isDefault)
2705 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2707 if (headerObj[label] === undefined) {
2708 headerObj[label] = value;
2713 headerObj[label] = value + "," + headerObj[label];
2717 this.hasDefaultHeaders = true;
2720 this.hasHeaders = true;
2725 setHeader:function(o)
2727 if (this.hasDefaultHeaders) {
2728 for (var prop in this.defaultHeaders) {
2729 if (this.defaultHeaders.hasOwnProperty(prop)) {
2730 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2735 if (this.hasHeaders) {
2736 for (var prop in this.headers) {
2737 if (this.headers.hasOwnProperty(prop)) {
2738 o.conn.setRequestHeader(prop, this.headers[prop]);
2742 this.hasHeaders = false;
2746 resetDefaultHeaders:function() {
2747 delete this.defaultHeaders;
2748 this.defaultHeaders = {};
2749 this.hasDefaultHeaders = false;
2752 abort:function(o, callback, isTimeout)
2754 if(this.isCallInProgress(o)) {
2756 window.clearInterval(this.poll[o.tId]);
2757 delete this.poll[o.tId];
2759 delete this.timeout[o.tId];
2762 this.handleTransactionResponse(o, callback, true);
2772 isCallInProgress:function(o)
2775 return o.conn.readyState != 4 && o.conn.readyState != 0;
2784 releaseObject:function(o)
2793 'MSXML2.XMLHTTP.3.0',
2801 * Portions of this file are based on pieces of Yahoo User Interface Library
2802 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2803 * YUI licensed under the BSD License:
2804 * http://developer.yahoo.net/yui/license.txt
2805 * <script type="text/javascript">
2809 Roo.lib.Region = function(t, r, b, l) {
2819 Roo.lib.Region.prototype = {
2820 contains : function(region) {
2821 return ( region.left >= this.left &&
2822 region.right <= this.right &&
2823 region.top >= this.top &&
2824 region.bottom <= this.bottom );
2828 getArea : function() {
2829 return ( (this.bottom - this.top) * (this.right - this.left) );
2832 intersect : function(region) {
2833 var t = Math.max(this.top, region.top);
2834 var r = Math.min(this.right, region.right);
2835 var b = Math.min(this.bottom, region.bottom);
2836 var l = Math.max(this.left, region.left);
2838 if (b >= t && r >= l) {
2839 return new Roo.lib.Region(t, r, b, l);
2844 union : function(region) {
2845 var t = Math.min(this.top, region.top);
2846 var r = Math.max(this.right, region.right);
2847 var b = Math.max(this.bottom, region.bottom);
2848 var l = Math.min(this.left, region.left);
2850 return new Roo.lib.Region(t, r, b, l);
2853 adjust : function(t, l, b, r) {
2862 Roo.lib.Region.getRegion = function(el) {
2863 var p = Roo.lib.Dom.getXY(el);
2866 var r = p[0] + el.offsetWidth;
2867 var b = p[1] + el.offsetHeight;
2870 return new Roo.lib.Region(t, r, b, l);
2873 * Portions of this file are based on pieces of Yahoo User Interface Library
2874 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2875 * YUI licensed under the BSD License:
2876 * http://developer.yahoo.net/yui/license.txt
2877 * <script type="text/javascript">
2880 //@@dep Roo.lib.Region
2883 Roo.lib.Point = function(x, y) {
2884 if (x instanceof Array) {
2888 this.x = this.right = this.left = this[0] = x;
2889 this.y = this.top = this.bottom = this[1] = y;
2892 Roo.lib.Point.prototype = new Roo.lib.Region();
2894 * Portions of this file are based on pieces of Yahoo User Interface Library
2895 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2896 * YUI licensed under the BSD License:
2897 * http://developer.yahoo.net/yui/license.txt
2898 * <script type="text/javascript">
2905 scroll : function(el, args, duration, easing, cb, scope) {
2906 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
2909 motion : function(el, args, duration, easing, cb, scope) {
2910 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
2913 color : function(el, args, duration, easing, cb, scope) {
2914 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
2917 run : function(el, args, duration, easing, cb, scope, type) {
2918 type = type || Roo.lib.AnimBase;
2919 if (typeof easing == "string") {
2920 easing = Roo.lib.Easing[easing];
2922 var anim = new type(el, args, duration, easing);
2923 anim.animateX(function() {
2924 Roo.callback(cb, scope);
2930 * Portions of this file are based on pieces of Yahoo User Interface Library
2931 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2932 * YUI licensed under the BSD License:
2933 * http://developer.yahoo.net/yui/license.txt
2934 * <script type="text/javascript">
2942 if (!libFlyweight) {
2943 libFlyweight = new Roo.Element.Flyweight();
2945 libFlyweight.dom = el;
2946 return libFlyweight;
2949 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
2953 Roo.lib.AnimBase = function(el, attributes, duration, method) {
2955 this.init(el, attributes, duration, method);
2959 Roo.lib.AnimBase.fly = fly;
2963 Roo.lib.AnimBase.prototype = {
2965 toString: function() {
2966 var el = this.getEl();
2967 var id = el.id || el.tagName;
2968 return ("Anim " + id);
2972 noNegatives: /width|height|opacity|padding/i,
2973 offsetAttribute: /^((width|height)|(top|left))$/,
2974 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
2975 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
2979 doMethod: function(attr, start, end) {
2980 return this.method(this.currentFrame, start, end - start, this.totalFrames);
2984 setAttribute: function(attr, val, unit) {
2985 if (this.patterns.noNegatives.test(attr)) {
2986 val = (val > 0) ? val : 0;
2989 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
2993 getAttribute: function(attr) {
2994 var el = this.getEl();
2995 var val = fly(el).getStyle(attr);
2997 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
2998 return parseFloat(val);
3001 var a = this.patterns.offsetAttribute.exec(attr) || [];
3002 var pos = !!( a[3] );
3003 var box = !!( a[2] );
3006 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3007 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3016 getDefaultUnit: function(attr) {
3017 if (this.patterns.defaultUnit.test(attr)) {
3024 animateX : function(callback, scope) {
3025 var f = function() {
3026 this.onComplete.removeListener(f);
3027 if (typeof callback == "function") {
3028 callback.call(scope || this, this);
3031 this.onComplete.addListener(f, this);
3036 setRuntimeAttribute: function(attr) {
3039 var attributes = this.attributes;
3041 this.runtimeAttributes[attr] = {};
3043 var isset = function(prop) {
3044 return (typeof prop !== 'undefined');
3047 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3051 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3054 if (isset(attributes[attr]['to'])) {
3055 end = attributes[attr]['to'];
3056 } else if (isset(attributes[attr]['by'])) {
3057 if (start.constructor == Array) {
3059 for (var i = 0, len = start.length; i < len; ++i) {
3060 end[i] = start[i] + attributes[attr]['by'][i];
3063 end = start + attributes[attr]['by'];
3067 this.runtimeAttributes[attr].start = start;
3068 this.runtimeAttributes[attr].end = end;
3071 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3075 init: function(el, attributes, duration, method) {
3077 var isAnimated = false;
3080 var startTime = null;
3083 var actualFrames = 0;
3086 el = Roo.getDom(el);
3089 this.attributes = attributes || {};
3092 this.duration = duration || 1;
3095 this.method = method || Roo.lib.Easing.easeNone;
3098 this.useSeconds = true;
3101 this.currentFrame = 0;
3104 this.totalFrames = Roo.lib.AnimMgr.fps;
3107 this.getEl = function() {
3112 this.isAnimated = function() {
3117 this.getStartTime = function() {
3121 this.runtimeAttributes = {};
3124 this.animate = function() {
3125 if (this.isAnimated()) {
3129 this.currentFrame = 0;
3131 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3133 Roo.lib.AnimMgr.registerElement(this);
3137 this.stop = function(finish) {
3139 this.currentFrame = this.totalFrames;
3140 this._onTween.fire();
3142 Roo.lib.AnimMgr.stop(this);
3145 var onStart = function() {
3146 this.onStart.fire();
3148 this.runtimeAttributes = {};
3149 for (var attr in this.attributes) {
3150 this.setRuntimeAttribute(attr);
3155 startTime = new Date();
3159 var onTween = function() {
3161 duration: new Date() - this.getStartTime(),
3162 currentFrame: this.currentFrame
3165 data.toString = function() {
3167 'duration: ' + data.duration +
3168 ', currentFrame: ' + data.currentFrame
3172 this.onTween.fire(data);
3174 var runtimeAttributes = this.runtimeAttributes;
3176 for (var attr in runtimeAttributes) {
3177 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3183 var onComplete = function() {
3184 var actual_duration = (new Date() - startTime) / 1000 ;
3187 duration: actual_duration,
3188 frames: actualFrames,
3189 fps: actualFrames / actual_duration
3192 data.toString = function() {
3194 'duration: ' + data.duration +
3195 ', frames: ' + data.frames +
3196 ', fps: ' + data.fps
3202 this.onComplete.fire(data);
3206 this._onStart = new Roo.util.Event(this);
3207 this.onStart = new Roo.util.Event(this);
3208 this.onTween = new Roo.util.Event(this);
3209 this._onTween = new Roo.util.Event(this);
3210 this.onComplete = new Roo.util.Event(this);
3211 this._onComplete = new Roo.util.Event(this);
3212 this._onStart.addListener(onStart);
3213 this._onTween.addListener(onTween);
3214 this._onComplete.addListener(onComplete);
3219 * Portions of this file are based on pieces of Yahoo User Interface Library
3220 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3221 * YUI licensed under the BSD License:
3222 * http://developer.yahoo.net/yui/license.txt
3223 * <script type="text/javascript">
3227 Roo.lib.AnimMgr = new function() {
3244 this.registerElement = function(tween) {
3245 queue[queue.length] = tween;
3247 tween._onStart.fire();
3252 this.unRegister = function(tween, index) {
3253 tween._onComplete.fire();
3254 index = index || getIndex(tween);
3256 queue.splice(index, 1);
3260 if (tweenCount <= 0) {
3266 this.start = function() {
3267 if (thread === null) {
3268 thread = setInterval(this.run, this.delay);
3273 this.stop = function(tween) {
3275 clearInterval(thread);
3277 for (var i = 0, len = queue.length; i < len; ++i) {
3278 if (queue[0].isAnimated()) {
3279 this.unRegister(queue[0], 0);
3288 this.unRegister(tween);
3293 this.run = function() {
3294 for (var i = 0, len = queue.length; i < len; ++i) {
3295 var tween = queue[i];
3296 if (!tween || !tween.isAnimated()) {
3300 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3302 tween.currentFrame += 1;
3304 if (tween.useSeconds) {
3305 correctFrame(tween);
3307 tween._onTween.fire();
3310 Roo.lib.AnimMgr.stop(tween, i);
3315 var getIndex = function(anim) {
3316 for (var i = 0, len = queue.length; i < len; ++i) {
3317 if (queue[i] == anim) {
3325 var correctFrame = function(tween) {
3326 var frames = tween.totalFrames;
3327 var frame = tween.currentFrame;
3328 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3329 var elapsed = (new Date() - tween.getStartTime());
3332 if (elapsed < tween.duration * 1000) {
3333 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3335 tweak = frames - (frame + 1);
3337 if (tweak > 0 && isFinite(tweak)) {
3338 if (tween.currentFrame + tweak >= frames) {
3339 tweak = frames - (frame + 1);
3342 tween.currentFrame += tweak;
3346 * Portions of this file are based on pieces of Yahoo User Interface Library
3347 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3348 * YUI licensed under the BSD License:
3349 * http://developer.yahoo.net/yui/license.txt
3350 * <script type="text/javascript">
3353 Roo.lib.Bezier = new function() {
3355 this.getPosition = function(points, t) {
3356 var n = points.length;
3359 for (var i = 0; i < n; ++i) {
3360 tmp[i] = [points[i][0], points[i][1]];
3363 for (var j = 1; j < n; ++j) {
3364 for (i = 0; i < n - j; ++i) {
3365 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3366 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3370 return [ tmp[0][0], tmp[0][1] ];
3374 * Portions of this file are based on pieces of Yahoo User Interface Library
3375 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3376 * YUI licensed under the BSD License:
3377 * http://developer.yahoo.net/yui/license.txt
3378 * <script type="text/javascript">
3383 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3384 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3387 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3389 var fly = Roo.lib.AnimBase.fly;
3391 var superclass = Y.ColorAnim.superclass;
3392 var proto = Y.ColorAnim.prototype;
3394 proto.toString = function() {
3395 var el = this.getEl();
3396 var id = el.id || el.tagName;
3397 return ("ColorAnim " + id);
3400 proto.patterns.color = /color$/i;
3401 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3402 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3403 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3404 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3407 proto.parseColor = function(s) {
3408 if (s.length == 3) {
3412 var c = this.patterns.hex.exec(s);
3413 if (c && c.length == 4) {
3414 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3417 c = this.patterns.rgb.exec(s);
3418 if (c && c.length == 4) {
3419 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3422 c = this.patterns.hex3.exec(s);
3423 if (c && c.length == 4) {
3424 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3429 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3430 proto.getAttribute = function(attr) {
3431 var el = this.getEl();
3432 if (this.patterns.color.test(attr)) {
3433 var val = fly(el).getStyle(attr);
3435 if (this.patterns.transparent.test(val)) {
3436 var parent = el.parentNode;
3437 val = fly(parent).getStyle(attr);
3439 while (parent && this.patterns.transparent.test(val)) {
3440 parent = parent.parentNode;
3441 val = fly(parent).getStyle(attr);
3442 if (parent.tagName.toUpperCase() == 'HTML') {
3448 val = superclass.getAttribute.call(this, attr);
3453 proto.getAttribute = function(attr) {
3454 var el = this.getEl();
3455 if (this.patterns.color.test(attr)) {
3456 var val = fly(el).getStyle(attr);
3458 if (this.patterns.transparent.test(val)) {
3459 var parent = el.parentNode;
3460 val = fly(parent).getStyle(attr);
3462 while (parent && this.patterns.transparent.test(val)) {
3463 parent = parent.parentNode;
3464 val = fly(parent).getStyle(attr);
3465 if (parent.tagName.toUpperCase() == 'HTML') {
3471 val = superclass.getAttribute.call(this, attr);
3477 proto.doMethod = function(attr, start, end) {
3480 if (this.patterns.color.test(attr)) {
3482 for (var i = 0, len = start.length; i < len; ++i) {
3483 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3486 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3489 val = superclass.doMethod.call(this, attr, start, end);
3495 proto.setRuntimeAttribute = function(attr) {
3496 superclass.setRuntimeAttribute.call(this, attr);
3498 if (this.patterns.color.test(attr)) {
3499 var attributes = this.attributes;
3500 var start = this.parseColor(this.runtimeAttributes[attr].start);
3501 var end = this.parseColor(this.runtimeAttributes[attr].end);
3503 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3504 end = this.parseColor(attributes[attr].by);
3506 for (var i = 0, len = start.length; i < len; ++i) {
3507 end[i] = start[i] + end[i];
3511 this.runtimeAttributes[attr].start = start;
3512 this.runtimeAttributes[attr].end = end;
3518 * Portions of this file are based on pieces of Yahoo User Interface Library
3519 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3520 * YUI licensed under the BSD License:
3521 * http://developer.yahoo.net/yui/license.txt
3522 * <script type="text/javascript">
3528 easeNone: function (t, b, c, d) {
3529 return c * t / d + b;
3533 easeIn: function (t, b, c, d) {
3534 return c * (t /= d) * t + b;
3538 easeOut: function (t, b, c, d) {
3539 return -c * (t /= d) * (t - 2) + b;
3543 easeBoth: function (t, b, c, d) {
3544 if ((t /= d / 2) < 1) {
3545 return c / 2 * t * t + b;
3548 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3552 easeInStrong: function (t, b, c, d) {
3553 return c * (t /= d) * t * t * t + b;
3557 easeOutStrong: function (t, b, c, d) {
3558 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3562 easeBothStrong: function (t, b, c, d) {
3563 if ((t /= d / 2) < 1) {
3564 return c / 2 * t * t * t * t + b;
3567 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3572 elasticIn: function (t, b, c, d, a, p) {
3576 if ((t /= d) == 1) {
3583 if (!a || a < Math.abs(c)) {
3588 var s = p / (2 * Math.PI) * Math.asin(c / a);
3591 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3595 elasticOut: function (t, b, c, d, a, p) {
3599 if ((t /= d) == 1) {
3606 if (!a || a < Math.abs(c)) {
3611 var s = p / (2 * Math.PI) * Math.asin(c / a);
3614 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3618 elasticBoth: function (t, b, c, d, a, p) {
3623 if ((t /= d / 2) == 2) {
3631 if (!a || a < Math.abs(c)) {
3636 var s = p / (2 * Math.PI) * Math.asin(c / a);
3640 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3641 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3643 return a * Math.pow(2, -10 * (t -= 1)) *
3644 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3649 backIn: function (t, b, c, d, s) {
3650 if (typeof s == 'undefined') {
3653 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3657 backOut: function (t, b, c, d, s) {
3658 if (typeof s == 'undefined') {
3661 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3665 backBoth: function (t, b, c, d, s) {
3666 if (typeof s == 'undefined') {
3670 if ((t /= d / 2 ) < 1) {
3671 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3673 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3677 bounceIn: function (t, b, c, d) {
3678 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3682 bounceOut: function (t, b, c, d) {
3683 if ((t /= d) < (1 / 2.75)) {
3684 return c * (7.5625 * t * t) + b;
3685 } else if (t < (2 / 2.75)) {
3686 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3687 } else if (t < (2.5 / 2.75)) {
3688 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3690 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3694 bounceBoth: function (t, b, c, d) {
3696 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3698 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3701 * Portions of this file are based on pieces of Yahoo User Interface Library
3702 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3703 * YUI licensed under the BSD License:
3704 * http://developer.yahoo.net/yui/license.txt
3705 * <script type="text/javascript">
3709 Roo.lib.Motion = function(el, attributes, duration, method) {
3711 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3715 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3719 var superclass = Y.Motion.superclass;
3720 var proto = Y.Motion.prototype;
3722 proto.toString = function() {
3723 var el = this.getEl();
3724 var id = el.id || el.tagName;
3725 return ("Motion " + id);
3728 proto.patterns.points = /^points$/i;
3730 proto.setAttribute = function(attr, val, unit) {
3731 if (this.patterns.points.test(attr)) {
3732 unit = unit || 'px';
3733 superclass.setAttribute.call(this, 'left', val[0], unit);
3734 superclass.setAttribute.call(this, 'top', val[1], unit);
3736 superclass.setAttribute.call(this, attr, val, unit);
3740 proto.getAttribute = function(attr) {
3741 if (this.patterns.points.test(attr)) {
3743 superclass.getAttribute.call(this, 'left'),
3744 superclass.getAttribute.call(this, 'top')
3747 val = superclass.getAttribute.call(this, attr);
3753 proto.doMethod = function(attr, start, end) {
3756 if (this.patterns.points.test(attr)) {
3757 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3758 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3760 val = superclass.doMethod.call(this, attr, start, end);
3765 proto.setRuntimeAttribute = function(attr) {
3766 if (this.patterns.points.test(attr)) {
3767 var el = this.getEl();
3768 var attributes = this.attributes;
3770 var control = attributes['points']['control'] || [];
3774 if (control.length > 0 && !(control[0] instanceof Array)) {
3775 control = [control];
3778 for (i = 0,len = control.length; i < len; ++i) {
3779 tmp[i] = control[i];
3784 Roo.fly(el).position();
3786 if (isset(attributes['points']['from'])) {
3787 Roo.lib.Dom.setXY(el, attributes['points']['from']);
3790 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3793 start = this.getAttribute('points');
3796 if (isset(attributes['points']['to'])) {
3797 end = translateValues.call(this, attributes['points']['to'], start);
3799 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3800 for (i = 0,len = control.length; i < len; ++i) {
3801 control[i] = translateValues.call(this, control[i], start);
3805 } else if (isset(attributes['points']['by'])) {
3806 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3808 for (i = 0,len = control.length; i < len; ++i) {
3809 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3813 this.runtimeAttributes[attr] = [start];
3815 if (control.length > 0) {
3816 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3819 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
3822 superclass.setRuntimeAttribute.call(this, attr);
3826 var translateValues = function(val, start) {
3827 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3828 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
3833 var isset = function(prop) {
3834 return (typeof prop !== 'undefined');
3838 * Portions of this file are based on pieces of Yahoo User Interface Library
3839 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3840 * YUI licensed under the BSD License:
3841 * http://developer.yahoo.net/yui/license.txt
3842 * <script type="text/javascript">
3846 Roo.lib.Scroll = function(el, attributes, duration, method) {
3848 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
3852 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
3856 var superclass = Y.Scroll.superclass;
3857 var proto = Y.Scroll.prototype;
3859 proto.toString = function() {
3860 var el = this.getEl();
3861 var id = el.id || el.tagName;
3862 return ("Scroll " + id);
3865 proto.doMethod = function(attr, start, end) {
3868 if (attr == 'scroll') {
3870 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
3871 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
3875 val = superclass.doMethod.call(this, attr, start, end);
3880 proto.getAttribute = function(attr) {
3882 var el = this.getEl();
3884 if (attr == 'scroll') {
3885 val = [ el.scrollLeft, el.scrollTop ];
3887 val = superclass.getAttribute.call(this, attr);
3893 proto.setAttribute = function(attr, val, unit) {
3894 var el = this.getEl();
3896 if (attr == 'scroll') {
3897 el.scrollLeft = val[0];
3898 el.scrollTop = val[1];
3900 superclass.setAttribute.call(this, attr, val, unit);
3906 * Ext JS Library 1.1.1
3907 * Copyright(c) 2006-2007, Ext JS, LLC.
3909 * Originally Released Under LGPL - original licence link has changed is not relivant.
3912 * <script type="text/javascript">
3917 * @class Roo.DomHelper
3918 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
3919 * 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>.
3922 Roo.DomHelper = function(){
3923 var tempTableEl = null;
3924 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
3925 var tableRe = /^table|tbody|tr|td$/i;
3927 // build as innerHTML where available
3929 var createHtml = function(o){
3930 if(typeof o == 'string'){
3939 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
3940 if(attr == "style"){
3942 if(typeof s == "function"){
3945 if(typeof s == "string"){
3946 b += ' style="' + s + '"';
3947 }else if(typeof s == "object"){
3950 if(typeof s[key] != "function"){
3951 b += key + ":" + s[key] + ";";
3958 b += ' class="' + o["cls"] + '"';
3959 }else if(attr == "htmlFor"){
3960 b += ' for="' + o["htmlFor"] + '"';
3962 b += " " + attr + '="' + o[attr] + '"';
3966 if(emptyTags.test(o.tag)){
3970 var cn = o.children || o.cn;
3972 //http://bugs.kde.org/show_bug.cgi?id=71506
3973 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
3974 for(var i = 0, len = cn.length; i < len; i++) {
3975 b += createHtml(cn[i], b);
3978 b += createHtml(cn, b);
3984 b += "</" + o.tag + ">";
3991 var createDom = function(o, parentNode){
3993 // defininition craeted..
3995 if (o.ns && o.ns != 'html') {
3997 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
3998 xmlns[o.ns] = o.xmlns;
4001 if (typeof(xmlns[o.ns]) == 'undefined') {
4002 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4008 if (typeof(o) == 'string') {
4009 return parentNode.appendChild(document.createTextNode(o));
4011 o.tag = o.tag || div;
4012 if (o.ns && Roo.isIE) {
4014 o.tag = o.ns + ':' + o.tag;
4017 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4018 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4021 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4022 attr == "style" || typeof o[attr] == "function") continue;
4024 if(attr=="cls" && Roo.isIE){
4025 el.className = o["cls"];
4027 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4028 else el[attr] = o[attr];
4031 Roo.DomHelper.applyStyles(el, o.style);
4032 var cn = o.children || o.cn;
4034 //http://bugs.kde.org/show_bug.cgi?id=71506
4035 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4036 for(var i = 0, len = cn.length; i < len; i++) {
4037 createDom(cn[i], el);
4044 el.innerHTML = o.html;
4047 parentNode.appendChild(el);
4052 var ieTable = function(depth, s, h, e){
4053 tempTableEl.innerHTML = [s, h, e].join('');
4054 var i = -1, el = tempTableEl;
4061 // kill repeat to save bytes
4065 tbe = '</tbody>'+te,
4071 * Nasty code for IE's broken table implementation
4073 var insertIntoTable = function(tag, where, el, html){
4075 tempTableEl = document.createElement('div');
4080 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4083 if(where == 'beforebegin'){
4087 before = el.nextSibling;
4090 node = ieTable(4, trs, html, tre);
4092 else if(tag == 'tr'){
4093 if(where == 'beforebegin'){
4096 node = ieTable(3, tbs, html, tbe);
4097 } else if(where == 'afterend'){
4098 before = el.nextSibling;
4100 node = ieTable(3, tbs, html, tbe);
4101 } else{ // INTO a TR
4102 if(where == 'afterbegin'){
4103 before = el.firstChild;
4105 node = ieTable(4, trs, html, tre);
4107 } else if(tag == 'tbody'){
4108 if(where == 'beforebegin'){
4111 node = ieTable(2, ts, html, te);
4112 } else if(where == 'afterend'){
4113 before = el.nextSibling;
4115 node = ieTable(2, ts, html, te);
4117 if(where == 'afterbegin'){
4118 before = el.firstChild;
4120 node = ieTable(3, tbs, html, tbe);
4123 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4126 if(where == 'afterbegin'){
4127 before = el.firstChild;
4129 node = ieTable(2, ts, html, te);
4131 el.insertBefore(node, before);
4136 /** True to force the use of DOM instead of html fragments @type Boolean */
4140 * Returns the markup for the passed Element(s) config
4141 * @param {Object} o The Dom object spec (and children)
4144 markup : function(o){
4145 return createHtml(o);
4149 * Applies a style specification to an element
4150 * @param {String/HTMLElement} el The element to apply styles to
4151 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4152 * a function which returns such a specification.
4154 applyStyles : function(el, styles){
4157 if(typeof styles == "string"){
4158 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4160 while ((matches = re.exec(styles)) != null){
4161 el.setStyle(matches[1], matches[2]);
4163 }else if (typeof styles == "object"){
4164 for (var style in styles){
4165 el.setStyle(style, styles[style]);
4167 }else if (typeof styles == "function"){
4168 Roo.DomHelper.applyStyles(el, styles.call());
4174 * Inserts an HTML fragment into the Dom
4175 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4176 * @param {HTMLElement} el The context element
4177 * @param {String} html The HTML fragmenet
4178 * @return {HTMLElement} The new node
4180 insertHtml : function(where, el, html){
4181 where = where.toLowerCase();
4182 if(el.insertAdjacentHTML){
4183 if(tableRe.test(el.tagName)){
4185 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4191 el.insertAdjacentHTML('BeforeBegin', html);
4192 return el.previousSibling;
4194 el.insertAdjacentHTML('AfterBegin', html);
4195 return el.firstChild;
4197 el.insertAdjacentHTML('BeforeEnd', html);
4198 return el.lastChild;
4200 el.insertAdjacentHTML('AfterEnd', html);
4201 return el.nextSibling;
4203 throw 'Illegal insertion point -> "' + where + '"';
4205 var range = el.ownerDocument.createRange();
4209 range.setStartBefore(el);
4210 frag = range.createContextualFragment(html);
4211 el.parentNode.insertBefore(frag, el);
4212 return el.previousSibling;
4215 range.setStartBefore(el.firstChild);
4216 frag = range.createContextualFragment(html);
4217 el.insertBefore(frag, el.firstChild);
4218 return el.firstChild;
4220 el.innerHTML = html;
4221 return el.firstChild;
4225 range.setStartAfter(el.lastChild);
4226 frag = range.createContextualFragment(html);
4227 el.appendChild(frag);
4228 return el.lastChild;
4230 el.innerHTML = html;
4231 return el.lastChild;
4234 range.setStartAfter(el);
4235 frag = range.createContextualFragment(html);
4236 el.parentNode.insertBefore(frag, el.nextSibling);
4237 return el.nextSibling;
4239 throw 'Illegal insertion point -> "' + where + '"';
4243 * Creates new Dom element(s) and inserts them before el
4244 * @param {String/HTMLElement/Element} el The context element
4245 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4246 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4247 * @return {HTMLElement/Roo.Element} The new node
4249 insertBefore : function(el, o, returnElement){
4250 return this.doInsert(el, o, returnElement, "beforeBegin");
4254 * Creates new Dom element(s) and inserts them after el
4255 * @param {String/HTMLElement/Element} el The context element
4256 * @param {Object} o The Dom object spec (and children)
4257 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4258 * @return {HTMLElement/Roo.Element} The new node
4260 insertAfter : function(el, o, returnElement){
4261 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4265 * Creates new Dom element(s) and inserts them as the first child of el
4266 * @param {String/HTMLElement/Element} el The context element
4267 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4268 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4269 * @return {HTMLElement/Roo.Element} The new node
4271 insertFirst : function(el, o, returnElement){
4272 return this.doInsert(el, o, returnElement, "afterBegin");
4276 doInsert : function(el, o, returnElement, pos, sibling){
4277 el = Roo.getDom(el);
4279 if(this.useDom || o.ns){
4280 newNode = createDom(o, null);
4281 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4283 var html = createHtml(o);
4284 newNode = this.insertHtml(pos, el, html);
4286 return returnElement ? Roo.get(newNode, true) : newNode;
4290 * Creates new Dom element(s) and appends them to el
4291 * @param {String/HTMLElement/Element} el The context element
4292 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4293 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4294 * @return {HTMLElement/Roo.Element} The new node
4296 append : function(el, o, returnElement){
4297 el = Roo.getDom(el);
4299 if(this.useDom || o.ns){
4300 newNode = createDom(o, null);
4301 el.appendChild(newNode);
4303 var html = createHtml(o);
4304 newNode = this.insertHtml("beforeEnd", el, html);
4306 return returnElement ? Roo.get(newNode, true) : newNode;
4310 * Creates new Dom element(s) and overwrites the contents of el with them
4311 * @param {String/HTMLElement/Element} el The context element
4312 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4313 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4314 * @return {HTMLElement/Roo.Element} The new node
4316 overwrite : function(el, o, returnElement){
4317 el = Roo.getDom(el);
4320 while (el.childNodes.length) {
4321 el.removeChild(el.firstChild);
4325 el.innerHTML = createHtml(o);
4328 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4332 * Creates a new Roo.DomHelper.Template from the Dom object spec
4333 * @param {Object} o The Dom object spec (and children)
4334 * @return {Roo.DomHelper.Template} The new template
4336 createTemplate : function(o){
4337 var html = createHtml(o);
4338 return new Roo.Template(html);
4344 * Ext JS Library 1.1.1
4345 * Copyright(c) 2006-2007, Ext JS, LLC.
4347 * Originally Released Under LGPL - original licence link has changed is not relivant.
4350 * <script type="text/javascript">
4354 * @class Roo.Template
4355 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4356 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4359 var t = new Roo.Template(
4360 '<div name="{id}">',
4361 '<span class="{cls}">{name:trim} {value:ellipsis(10)}</span>',
4364 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4366 * 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>.
4368 * @param {String/Array} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4370 Roo.Template = function(html){
4371 if(html instanceof Array){
4372 html = html.join("");
4373 }else if(arguments.length > 1){
4374 html = Array.prototype.join.call(arguments, "");
4380 Roo.Template.prototype = {
4382 * Returns an HTML fragment of this template with the specified values applied.
4383 * @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'})
4384 * @return {String} The HTML fragment
4386 applyTemplate : function(values){
4388 return this.compiled(values);
4390 var useF = this.disableFormats !== true;
4391 var fm = Roo.util.Format, tpl = this;
4392 var fn = function(m, name, format, args){
4394 if(format.substr(0, 5) == "this."){
4395 return tpl.call(format.substr(5), values[name], values);
4398 // quoted values are required for strings in compiled templates,
4399 // but for non compiled we need to strip them
4400 // quoted reversed for jsmin
4401 var re = /^\s*['"](.*)["']\s*$/;
4402 args = args.split(',');
4403 for(var i = 0, len = args.length; i < len; i++){
4404 args[i] = args[i].replace(re, "$1");
4406 args = [values[name]].concat(args);
4408 args = [values[name]];
4410 return fm[format].apply(fm, args);
4413 return values[name] !== undefined ? values[name] : "";
4416 return this.html.replace(this.re, fn);
4420 * Sets the HTML used as the template and optionally compiles it.
4421 * @param {String} html
4422 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4423 * @return {Roo.Template} this
4425 set : function(html, compile){
4427 this.compiled = null;
4435 * True to disable format functions (defaults to false)
4438 disableFormats : false,
4441 * The regular expression used to match template variables
4445 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4448 * Compiles the template into an internal function, eliminating the RegEx overhead.
4449 * @return {Roo.Template} this
4451 compile : function(){
4452 var fm = Roo.util.Format;
4453 var useF = this.disableFormats !== true;
4454 var sep = Roo.isGecko ? "+" : ",";
4455 var fn = function(m, name, format, args){
4457 args = args ? ',' + args : "";
4458 if(format.substr(0, 5) != "this."){
4459 format = "fm." + format + '(';
4461 format = 'this.call("'+ format.substr(5) + '", ';
4465 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4467 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4470 // branched to use + in gecko and [].join() in others
4472 body = "this.compiled = function(values){ return '" +
4473 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4476 body = ["this.compiled = function(values){ return ['"];
4477 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4478 body.push("'].join('');};");
4479 body = body.join('');
4489 // private function used to call members
4490 call : function(fnName, value, allValues){
4491 return this[fnName](value, allValues);
4495 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4496 * @param {String/HTMLElement/Roo.Element} el The context element
4497 * @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'})
4498 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4499 * @return {HTMLElement/Roo.Element} The new node or Element
4501 insertFirst: function(el, values, returnElement){
4502 return this.doInsert('afterBegin', el, values, returnElement);
4506 * Applies the supplied values to the template and inserts the new node(s) before el.
4507 * @param {String/HTMLElement/Roo.Element} el The context element
4508 * @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'})
4509 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4510 * @return {HTMLElement/Roo.Element} The new node or Element
4512 insertBefore: function(el, values, returnElement){
4513 return this.doInsert('beforeBegin', el, values, returnElement);
4517 * Applies the supplied values to the template and inserts the new node(s) after el.
4518 * @param {String/HTMLElement/Roo.Element} el The context element
4519 * @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'})
4520 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4521 * @return {HTMLElement/Roo.Element} The new node or Element
4523 insertAfter : function(el, values, returnElement){
4524 return this.doInsert('afterEnd', el, values, returnElement);
4528 * Applies the supplied values to the template and appends the new node(s) to el.
4529 * @param {String/HTMLElement/Roo.Element} el The context element
4530 * @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'})
4531 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4532 * @return {HTMLElement/Roo.Element} The new node or Element
4534 append : function(el, values, returnElement){
4535 return this.doInsert('beforeEnd', el, values, returnElement);
4538 doInsert : function(where, el, values, returnEl){
4539 el = Roo.getDom(el);
4540 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4541 return returnEl ? Roo.get(newNode, true) : newNode;
4545 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4546 * @param {String/HTMLElement/Roo.Element} el The context element
4547 * @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'})
4548 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4549 * @return {HTMLElement/Roo.Element} The new node or Element
4551 overwrite : function(el, values, returnElement){
4552 el = Roo.getDom(el);
4553 el.innerHTML = this.applyTemplate(values);
4554 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4558 * Alias for {@link #applyTemplate}
4561 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4564 Roo.DomHelper.Template = Roo.Template;
4567 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4568 * @param {String/HTMLElement} el A DOM element or its id
4569 * @returns {Roo.Template} The created template
4572 Roo.Template.from = function(el){
4573 el = Roo.getDom(el);
4574 return new Roo.Template(el.value || el.innerHTML);
4577 * Ext JS Library 1.1.1
4578 * Copyright(c) 2006-2007, Ext JS, LLC.
4580 * Originally Released Under LGPL - original licence link has changed is not relivant.
4583 * <script type="text/javascript">
4588 * This is code is also distributed under MIT license for use
4589 * with jQuery and prototype JavaScript libraries.
4592 * @class Roo.DomQuery
4593 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).
4595 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>
4598 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.
4600 <h4>Element Selectors:</h4>
4602 <li> <b>*</b> any element</li>
4603 <li> <b>E</b> an element with the tag E</li>
4604 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4605 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4606 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4607 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4609 <h4>Attribute Selectors:</h4>
4610 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4612 <li> <b>E[foo]</b> has an attribute "foo"</li>
4613 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4614 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4615 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4616 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4617 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4618 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4620 <h4>Pseudo Classes:</h4>
4622 <li> <b>E:first-child</b> E is the first child of its parent</li>
4623 <li> <b>E:last-child</b> E is the last child of its parent</li>
4624 <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>
4625 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4626 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4627 <li> <b>E:only-child</b> E is the only child of its parent</li>
4628 <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>
4629 <li> <b>E:first</b> the first E in the resultset</li>
4630 <li> <b>E:last</b> the last E in the resultset</li>
4631 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4632 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4633 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4634 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4635 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4636 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4637 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4638 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4639 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4641 <h4>CSS Value Selectors:</h4>
4643 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4644 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4645 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4646 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4647 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4648 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4652 Roo.DomQuery = function(){
4653 var cache = {}, simpleCache = {}, valueCache = {};
4654 var nonSpace = /\S/;
4655 var trimRe = /^\s+|\s+$/g;
4656 var tplRe = /\{(\d+)\}/g;
4657 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4658 var tagTokenRe = /^(#)?([\w-\*]+)/;
4659 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4661 function child(p, index){
4663 var n = p.firstChild;
4665 if(n.nodeType == 1){
4676 while((n = n.nextSibling) && n.nodeType != 1);
4681 while((n = n.previousSibling) && n.nodeType != 1);
4685 function children(d){
4686 var n = d.firstChild, ni = -1;
4688 var nx = n.nextSibling;
4689 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4699 function byClassName(c, a, v){
4703 var r = [], ri = -1, cn;
4704 for(var i = 0, ci; ci = c[i]; i++){
4705 if((' '+ci.className+' ').indexOf(v) != -1){
4712 function attrValue(n, attr){
4713 if(!n.tagName && typeof n.length != "undefined"){
4722 if(attr == "class" || attr == "className"){
4725 return n.getAttribute(attr) || n[attr];
4729 function getNodes(ns, mode, tagName){
4730 var result = [], ri = -1, cs;
4734 tagName = tagName || "*";
4735 if(typeof ns.getElementsByTagName != "undefined"){
4739 for(var i = 0, ni; ni = ns[i]; i++){
4740 cs = ni.getElementsByTagName(tagName);
4741 for(var j = 0, ci; ci = cs[j]; j++){
4745 }else if(mode == "/" || mode == ">"){
4746 var utag = tagName.toUpperCase();
4747 for(var i = 0, ni, cn; ni = ns[i]; i++){
4748 cn = ni.children || ni.childNodes;
4749 for(var j = 0, cj; cj = cn[j]; j++){
4750 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
4755 }else if(mode == "+"){
4756 var utag = tagName.toUpperCase();
4757 for(var i = 0, n; n = ns[i]; i++){
4758 while((n = n.nextSibling) && n.nodeType != 1);
4759 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
4763 }else if(mode == "~"){
4764 for(var i = 0, n; n = ns[i]; i++){
4765 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
4774 function concat(a, b){
4778 for(var i = 0, l = b.length; i < l; i++){
4784 function byTag(cs, tagName){
4785 if(cs.tagName || cs == document){
4791 var r = [], ri = -1;
4792 tagName = tagName.toLowerCase();
4793 for(var i = 0, ci; ci = cs[i]; i++){
4794 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
4801 function byId(cs, attr, id){
4802 if(cs.tagName || cs == document){
4808 var r = [], ri = -1;
4809 for(var i = 0,ci; ci = cs[i]; i++){
4810 if(ci && ci.id == id){
4818 function byAttribute(cs, attr, value, op, custom){
4819 var r = [], ri = -1, st = custom=="{";
4820 var f = Roo.DomQuery.operators[op];
4821 for(var i = 0, ci; ci = cs[i]; i++){
4824 a = Roo.DomQuery.getStyle(ci, attr);
4826 else if(attr == "class" || attr == "className"){
4828 }else if(attr == "for"){
4830 }else if(attr == "href"){
4831 a = ci.getAttribute("href", 2);
4833 a = ci.getAttribute(attr);
4835 if((f && f(a, value)) || (!f && a)){
4842 function byPseudo(cs, name, value){
4843 return Roo.DomQuery.pseudos[name](cs, value);
4846 // This is for IE MSXML which does not support expandos.
4847 // IE runs the same speed using setAttribute, however FF slows way down
4848 // and Safari completely fails so they need to continue to use expandos.
4849 var isIE = window.ActiveXObject ? true : false;
4851 // this eval is stop the compressor from
4852 // renaming the variable to something shorter
4854 /** eval:var:batch */
4859 function nodupIEXml(cs){
4861 cs[0].setAttribute("_nodup", d);
4863 for(var i = 1, len = cs.length; i < len; i++){
4865 if(!c.getAttribute("_nodup") != d){
4866 c.setAttribute("_nodup", d);
4870 for(var i = 0, len = cs.length; i < len; i++){
4871 cs[i].removeAttribute("_nodup");
4880 var len = cs.length, c, i, r = cs, cj, ri = -1;
4881 if(!len || typeof cs.nodeType != "undefined" || len == 1){
4884 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
4885 return nodupIEXml(cs);
4889 for(i = 1; c = cs[i]; i++){
4894 for(var j = 0; j < i; j++){
4897 for(j = i+1; cj = cs[j]; j++){
4909 function quickDiffIEXml(c1, c2){
4911 for(var i = 0, len = c1.length; i < len; i++){
4912 c1[i].setAttribute("_qdiff", d);
4915 for(var i = 0, len = c2.length; i < len; i++){
4916 if(c2[i].getAttribute("_qdiff") != d){
4917 r[r.length] = c2[i];
4920 for(var i = 0, len = c1.length; i < len; i++){
4921 c1[i].removeAttribute("_qdiff");
4926 function quickDiff(c1, c2){
4927 var len1 = c1.length;
4931 if(isIE && c1[0].selectSingleNode){
4932 return quickDiffIEXml(c1, c2);
4935 for(var i = 0; i < len1; i++){
4939 for(var i = 0, len = c2.length; i < len; i++){
4940 if(c2[i]._qdiff != d){
4941 r[r.length] = c2[i];
4947 function quickId(ns, mode, root, id){
4949 var d = root.ownerDocument || root;
4950 return d.getElementById(id);
4952 ns = getNodes(ns, mode, "*");
4953 return byId(ns, null, id);
4957 getStyle : function(el, name){
4958 return Roo.fly(el).getStyle(name);
4961 * Compiles a selector/xpath query into a reusable function. The returned function
4962 * takes one parameter "root" (optional), which is the context node from where the query should start.
4963 * @param {String} selector The selector/xpath query
4964 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
4965 * @return {Function}
4967 compile : function(path, type){
4968 type = type || "select";
4970 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
4971 var q = path, mode, lq;
4972 var tk = Roo.DomQuery.matchers;
4973 var tklen = tk.length;
4976 // accept leading mode switch
4977 var lmode = q.match(modeRe);
4978 if(lmode && lmode[1]){
4979 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
4980 q = q.replace(lmode[1], "");
4982 // strip leading slashes
4983 while(path.substr(0, 1)=="/"){
4984 path = path.substr(1);
4987 while(q && lq != q){
4989 var tm = q.match(tagTokenRe);
4990 if(type == "select"){
4993 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
4995 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
4997 q = q.replace(tm[0], "");
4998 }else if(q.substr(0, 1) != '@'){
4999 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5004 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5006 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5008 q = q.replace(tm[0], "");
5011 while(!(mm = q.match(modeRe))){
5012 var matched = false;
5013 for(var j = 0; j < tklen; j++){
5015 var m = q.match(t.re);
5017 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5020 q = q.replace(m[0], "");
5025 // prevent infinite loop on bad selector
5027 throw 'Error parsing selector, parsing failed at "' + q + '"';
5031 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5032 q = q.replace(mm[1], "");
5035 fn[fn.length] = "return nodup(n);\n}";
5038 * list of variables that need from compression as they are used by eval.
5048 * eval:var:byClassName
5050 * eval:var:byAttribute
5051 * eval:var:attrValue
5059 * Selects a group of elements.
5060 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5061 * @param {Node} root (optional) The start of the query (defaults to document).
5064 select : function(path, root, type){
5065 if(!root || root == document){
5068 if(typeof root == "string"){
5069 root = document.getElementById(root);
5071 var paths = path.split(",");
5073 for(var i = 0, len = paths.length; i < len; i++){
5074 var p = paths[i].replace(trimRe, "");
5076 cache[p] = Roo.DomQuery.compile(p);
5078 throw p + " is not a valid selector";
5081 var result = cache[p](root);
5082 if(result && result != document){
5083 results = results.concat(result);
5086 if(paths.length > 1){
5087 return nodup(results);
5093 * Selects a single element.
5094 * @param {String} selector The selector/xpath query
5095 * @param {Node} root (optional) The start of the query (defaults to document).
5098 selectNode : function(path, root){
5099 return Roo.DomQuery.select(path, root)[0];
5103 * Selects the value of a node, optionally replacing null with the defaultValue.
5104 * @param {String} selector The selector/xpath query
5105 * @param {Node} root (optional) The start of the query (defaults to document).
5106 * @param {String} defaultValue
5108 selectValue : function(path, root, defaultValue){
5109 path = path.replace(trimRe, "");
5110 if(!valueCache[path]){
5111 valueCache[path] = Roo.DomQuery.compile(path, "select");
5113 var n = valueCache[path](root);
5114 n = n[0] ? n[0] : n;
5115 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5116 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5120 * Selects the value of a node, parsing integers and floats.
5121 * @param {String} selector The selector/xpath query
5122 * @param {Node} root (optional) The start of the query (defaults to document).
5123 * @param {Number} defaultValue
5126 selectNumber : function(path, root, defaultValue){
5127 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5128 return parseFloat(v);
5132 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5133 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5134 * @param {String} selector The simple selector to test
5137 is : function(el, ss){
5138 if(typeof el == "string"){
5139 el = document.getElementById(el);
5141 var isArray = (el instanceof Array);
5142 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5143 return isArray ? (result.length == el.length) : (result.length > 0);
5147 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5148 * @param {Array} el An array of elements to filter
5149 * @param {String} selector The simple selector to test
5150 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5151 * the selector instead of the ones that match
5154 filter : function(els, ss, nonMatches){
5155 ss = ss.replace(trimRe, "");
5156 if(!simpleCache[ss]){
5157 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5159 var result = simpleCache[ss](els);
5160 return nonMatches ? quickDiff(result, els) : result;
5164 * Collection of matching regular expressions and code snippets.
5168 select: 'n = byClassName(n, null, " {1} ");'
5170 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5171 select: 'n = byPseudo(n, "{1}", "{2}");'
5173 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5174 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5177 select: 'n = byId(n, null, "{1}");'
5180 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5185 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5186 * 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, > <.
5189 "=" : function(a, v){
5192 "!=" : function(a, v){
5195 "^=" : function(a, v){
5196 return a && a.substr(0, v.length) == v;
5198 "$=" : function(a, v){
5199 return a && a.substr(a.length-v.length) == v;
5201 "*=" : function(a, v){
5202 return a && a.indexOf(v) !== -1;
5204 "%=" : function(a, v){
5205 return (a % v) == 0;
5207 "|=" : function(a, v){
5208 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5210 "~=" : function(a, v){
5211 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5216 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5217 * and the argument (if any) supplied in the selector.
5220 "first-child" : function(c){
5221 var r = [], ri = -1, n;
5222 for(var i = 0, ci; ci = n = c[i]; i++){
5223 while((n = n.previousSibling) && n.nodeType != 1);
5231 "last-child" : function(c){
5232 var r = [], ri = -1, n;
5233 for(var i = 0, ci; ci = n = c[i]; i++){
5234 while((n = n.nextSibling) && n.nodeType != 1);
5242 "nth-child" : function(c, a) {
5243 var r = [], ri = -1;
5244 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5245 var f = (m[1] || 1) - 0, l = m[2] - 0;
5246 for(var i = 0, n; n = c[i]; i++){
5247 var pn = n.parentNode;
5248 if (batch != pn._batch) {
5250 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5251 if(cn.nodeType == 1){
5258 if (l == 0 || n.nodeIndex == l){
5261 } else if ((n.nodeIndex + l) % f == 0){
5269 "only-child" : function(c){
5270 var r = [], ri = -1;;
5271 for(var i = 0, ci; ci = c[i]; i++){
5272 if(!prev(ci) && !next(ci)){
5279 "empty" : function(c){
5280 var r = [], ri = -1;
5281 for(var i = 0, ci; ci = c[i]; i++){
5282 var cns = ci.childNodes, j = 0, cn, empty = true;
5285 if(cn.nodeType == 1 || cn.nodeType == 3){
5297 "contains" : function(c, v){
5298 var r = [], ri = -1;
5299 for(var i = 0, ci; ci = c[i]; i++){
5300 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5307 "nodeValue" : function(c, v){
5308 var r = [], ri = -1;
5309 for(var i = 0, ci; ci = c[i]; i++){
5310 if(ci.firstChild && ci.firstChild.nodeValue == v){
5317 "checked" : function(c){
5318 var r = [], ri = -1;
5319 for(var i = 0, ci; ci = c[i]; i++){
5320 if(ci.checked == true){
5327 "not" : function(c, ss){
5328 return Roo.DomQuery.filter(c, ss, true);
5331 "odd" : function(c){
5332 return this["nth-child"](c, "odd");
5335 "even" : function(c){
5336 return this["nth-child"](c, "even");
5339 "nth" : function(c, a){
5340 return c[a-1] || [];
5343 "first" : function(c){
5347 "last" : function(c){
5348 return c[c.length-1] || [];
5351 "has" : function(c, ss){
5352 var s = Roo.DomQuery.select;
5353 var r = [], ri = -1;
5354 for(var i = 0, ci; ci = c[i]; i++){
5355 if(s(ss, ci).length > 0){
5362 "next" : function(c, ss){
5363 var is = Roo.DomQuery.is;
5364 var r = [], ri = -1;
5365 for(var i = 0, ci; ci = c[i]; i++){
5374 "prev" : function(c, ss){
5375 var is = Roo.DomQuery.is;
5376 var r = [], ri = -1;
5377 for(var i = 0, ci; ci = c[i]; i++){
5390 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5391 * @param {String} path The selector/xpath query
5392 * @param {Node} root (optional) The start of the query (defaults to document).
5397 Roo.query = Roo.DomQuery.select;
5400 * Ext JS Library 1.1.1
5401 * Copyright(c) 2006-2007, Ext JS, LLC.
5403 * Originally Released Under LGPL - original licence link has changed is not relivant.
5406 * <script type="text/javascript">
5410 * @class Roo.util.Observable
5411 * Base class that provides a common interface for publishing events. Subclasses are expected to
5412 * to have a property "events" with all the events defined.<br>
5415 Employee = function(name){
5422 Roo.extend(Employee, Roo.util.Observable);
5424 * @param {Object} config properties to use (incuding events / listeners)
5427 Roo.util.Observable = function(cfg){
5430 this.addEvents(cfg.events || {});
5432 delete cfg.events; // make sure
5435 Roo.apply(this, cfg);
5438 this.on(this.listeners);
5439 delete this.listeners;
5442 Roo.util.Observable.prototype = {
5444 * @cfg {Object} listeners list of events and functions to call for this object,
5448 'click' : function(e) {
5458 * Fires the specified event with the passed parameters (minus the event name).
5459 * @param {String} eventName
5460 * @param {Object...} args Variable number of parameters are passed to handlers
5461 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5463 fireEvent : function(){
5464 var ce = this.events[arguments[0].toLowerCase()];
5465 if(typeof ce == "object"){
5466 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5473 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5476 * Appends an event handler to this component
5477 * @param {String} eventName The type of event to listen for
5478 * @param {Function} handler The method the event invokes
5479 * @param {Object} scope (optional) The scope in which to execute the handler
5480 * function. The handler function's "this" context.
5481 * @param {Object} options (optional) An object containing handler configuration
5482 * properties. This may contain any of the following properties:<ul>
5483 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5484 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5485 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5486 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5487 * by the specified number of milliseconds. If the event fires again within that time, the original
5488 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5491 * <b>Combining Options</b><br>
5492 * Using the options argument, it is possible to combine different types of listeners:<br>
5494 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5496 el.on('click', this.onClick, this, {
5503 * <b>Attaching multiple handlers in 1 call</b><br>
5504 * The method also allows for a single argument to be passed which is a config object containing properties
5505 * which specify multiple handlers.
5514 fn: this.onMouseOver,
5518 fn: this.onMouseOut,
5524 * Or a shorthand syntax which passes the same scope object to all handlers:
5527 'click': this.onClick,
5528 'mouseover': this.onMouseOver,
5529 'mouseout': this.onMouseOut,
5534 addListener : function(eventName, fn, scope, o){
5535 if(typeof eventName == "object"){
5538 if(this.filterOptRe.test(e)){
5541 if(typeof o[e] == "function"){
5543 this.addListener(e, o[e], o.scope, o);
5545 // individual options
5546 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5551 o = (!o || typeof o == "boolean") ? {} : o;
5552 eventName = eventName.toLowerCase();
5553 var ce = this.events[eventName] || true;
5554 if(typeof ce == "boolean"){
5555 ce = new Roo.util.Event(this, eventName);
5556 this.events[eventName] = ce;
5558 ce.addListener(fn, scope, o);
5562 * Removes a listener
5563 * @param {String} eventName The type of event to listen for
5564 * @param {Function} handler The handler to remove
5565 * @param {Object} scope (optional) The scope (this object) for the handler
5567 removeListener : function(eventName, fn, scope){
5568 var ce = this.events[eventName.toLowerCase()];
5569 if(typeof ce == "object"){
5570 ce.removeListener(fn, scope);
5575 * Removes all listeners for this object
5577 purgeListeners : function(){
5578 for(var evt in this.events){
5579 if(typeof this.events[evt] == "object"){
5580 this.events[evt].clearListeners();
5585 relayEvents : function(o, events){
5586 var createHandler = function(ename){
5588 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5591 for(var i = 0, len = events.length; i < len; i++){
5592 var ename = events[i];
5593 if(!this.events[ename]){ this.events[ename] = true; };
5594 o.on(ename, createHandler(ename), this);
5599 * Used to define events on this Observable
5600 * @param {Object} object The object with the events defined
5602 addEvents : function(o){
5606 Roo.applyIf(this.events, o);
5610 * Checks to see if this object has any listeners for a specified event
5611 * @param {String} eventName The name of the event to check for
5612 * @return {Boolean} True if the event is being listened for, else false
5614 hasListener : function(eventName){
5615 var e = this.events[eventName];
5616 return typeof e == "object" && e.listeners.length > 0;
5620 * Appends an event handler to this element (shorthand for addListener)
5621 * @param {String} eventName The type of event to listen for
5622 * @param {Function} handler The method the event invokes
5623 * @param {Object} scope (optional) The scope in which to execute the handler
5624 * function. The handler function's "this" context.
5625 * @param {Object} options (optional)
5628 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5630 * Removes a listener (shorthand for removeListener)
5631 * @param {String} eventName The type of event to listen for
5632 * @param {Function} handler The handler to remove
5633 * @param {Object} scope (optional) The scope (this object) for the handler
5636 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5639 * Starts capture on the specified Observable. All events will be passed
5640 * to the supplied function with the event name + standard signature of the event
5641 * <b>before</b> the event is fired. If the supplied function returns false,
5642 * the event will not fire.
5643 * @param {Observable} o The Observable to capture
5644 * @param {Function} fn The function to call
5645 * @param {Object} scope (optional) The scope (this object) for the fn
5648 Roo.util.Observable.capture = function(o, fn, scope){
5649 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5653 * Removes <b>all</b> added captures from the Observable.
5654 * @param {Observable} o The Observable to release
5657 Roo.util.Observable.releaseCapture = function(o){
5658 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5663 var createBuffered = function(h, o, scope){
5664 var task = new Roo.util.DelayedTask();
5666 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5670 var createSingle = function(h, e, fn, scope){
5672 e.removeListener(fn, scope);
5673 return h.apply(scope, arguments);
5677 var createDelayed = function(h, o, scope){
5679 var args = Array.prototype.slice.call(arguments, 0);
5680 setTimeout(function(){
5681 h.apply(scope, args);
5686 Roo.util.Event = function(obj, name){
5689 this.listeners = [];
5692 Roo.util.Event.prototype = {
5693 addListener : function(fn, scope, options){
5694 var o = options || {};
5695 scope = scope || this.obj;
5696 if(!this.isListening(fn, scope)){
5697 var l = {fn: fn, scope: scope, options: o};
5700 h = createDelayed(h, o, scope);
5703 h = createSingle(h, this, fn, scope);
5706 h = createBuffered(h, o, scope);
5709 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5710 this.listeners.push(l);
5712 this.listeners = this.listeners.slice(0);
5713 this.listeners.push(l);
5718 findListener : function(fn, scope){
5719 scope = scope || this.obj;
5720 var ls = this.listeners;
5721 for(var i = 0, len = ls.length; i < len; i++){
5723 if(l.fn == fn && l.scope == scope){
5730 isListening : function(fn, scope){
5731 return this.findListener(fn, scope) != -1;
5734 removeListener : function(fn, scope){
5736 if((index = this.findListener(fn, scope)) != -1){
5738 this.listeners.splice(index, 1);
5740 this.listeners = this.listeners.slice(0);
5741 this.listeners.splice(index, 1);
5748 clearListeners : function(){
5749 this.listeners = [];
5753 var ls = this.listeners, scope, len = ls.length;
5756 var args = Array.prototype.slice.call(arguments, 0);
5757 for(var i = 0; i < len; i++){
5759 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
5760 this.firing = false;
5764 this.firing = false;
5771 * Ext JS Library 1.1.1
5772 * Copyright(c) 2006-2007, Ext JS, LLC.
5774 * Originally Released Under LGPL - original licence link has changed is not relivant.
5777 * <script type="text/javascript">
5781 * @class Roo.EventManager
5782 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
5783 * several useful events directly.
5784 * See {@link Roo.EventObject} for more details on normalized event objects.
5787 Roo.EventManager = function(){
5788 var docReadyEvent, docReadyProcId, docReadyState = false;
5789 var resizeEvent, resizeTask, textEvent, textSize;
5790 var E = Roo.lib.Event;
5791 var D = Roo.lib.Dom;
5794 var fireDocReady = function(){
5796 docReadyState = true;
5799 clearInterval(docReadyProcId);
5801 if(Roo.isGecko || Roo.isOpera) {
5802 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
5805 var defer = document.getElementById("ie-deferred-loader");
5807 defer.onreadystatechange = null;
5808 defer.parentNode.removeChild(defer);
5812 docReadyEvent.fire();
5813 docReadyEvent.clearListeners();
5818 var initDocReady = function(){
5819 docReadyEvent = new Roo.util.Event();
5820 if(Roo.isGecko || Roo.isOpera) {
5821 document.addEventListener("DOMContentLoaded", fireDocReady, false);
5823 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
5824 var defer = document.getElementById("ie-deferred-loader");
5825 defer.onreadystatechange = function(){
5826 if(this.readyState == "complete"){
5830 }else if(Roo.isSafari){
5831 docReadyProcId = setInterval(function(){
5832 var rs = document.readyState;
5833 if(rs == "complete") {
5838 // no matter what, make sure it fires on load
5839 E.on(window, "load", fireDocReady);
5842 var createBuffered = function(h, o){
5843 var task = new Roo.util.DelayedTask(h);
5845 // create new event object impl so new events don't wipe out properties
5846 e = new Roo.EventObjectImpl(e);
5847 task.delay(o.buffer, h, null, [e]);
5851 var createSingle = function(h, el, ename, fn){
5853 Roo.EventManager.removeListener(el, ename, fn);
5858 var createDelayed = function(h, o){
5860 // create new event object impl so new events don't wipe out properties
5861 e = new Roo.EventObjectImpl(e);
5862 setTimeout(function(){
5868 var listen = function(element, ename, opt, fn, scope){
5869 var o = (!opt || typeof opt == "boolean") ? {} : opt;
5870 fn = fn || o.fn; scope = scope || o.scope;
5871 var el = Roo.getDom(element);
5873 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
5875 var h = function(e){
5876 e = Roo.EventObject.setEvent(e);
5879 t = e.getTarget(o.delegate, el);
5886 if(o.stopEvent === true){
5889 if(o.preventDefault === true){
5892 if(o.stopPropagation === true){
5893 e.stopPropagation();
5896 if(o.normalized === false){
5900 fn.call(scope || el, e, t, o);
5903 h = createDelayed(h, o);
5906 h = createSingle(h, el, ename, fn);
5909 h = createBuffered(h, o);
5911 fn._handlers = fn._handlers || [];
5912 fn._handlers.push([Roo.id(el), ename, h]);
5915 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
5916 el.addEventListener("DOMMouseScroll", h, false);
5917 E.on(window, 'unload', function(){
5918 el.removeEventListener("DOMMouseScroll", h, false);
5921 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
5922 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
5927 var stopListening = function(el, ename, fn){
5928 var id = Roo.id(el), hds = fn._handlers, hd = fn;
5930 for(var i = 0, len = hds.length; i < len; i++){
5932 if(h[0] == id && h[1] == ename){
5939 E.un(el, ename, hd);
5940 el = Roo.getDom(el);
5941 if(ename == "mousewheel" && el.addEventListener){
5942 el.removeEventListener("DOMMouseScroll", hd, false);
5944 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
5945 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
5949 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
5956 * @scope Roo.EventManager
5961 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
5962 * object with a Roo.EventObject
5963 * @param {Function} fn The method the event invokes
5964 * @param {Object} scope An object that becomes the scope of the handler
5965 * @param {boolean} override If true, the obj passed in becomes
5966 * the execution scope of the listener
5967 * @return {Function} The wrapped function
5970 wrap : function(fn, scope, override){
5972 Roo.EventObject.setEvent(e);
5973 fn.call(override ? scope || window : window, Roo.EventObject, scope);
5978 * Appends an event handler to an element (shorthand for addListener)
5979 * @param {String/HTMLElement} element The html element or id to assign the
5980 * @param {String} eventName The type of event to listen for
5981 * @param {Function} handler The method the event invokes
5982 * @param {Object} scope (optional) The scope in which to execute the handler
5983 * function. The handler function's "this" context.
5984 * @param {Object} options (optional) An object containing handler configuration
5985 * properties. This may contain any of the following properties:<ul>
5986 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5987 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
5988 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
5989 * <li>preventDefault {Boolean} True to prevent the default action</li>
5990 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
5991 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
5992 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5993 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5994 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5995 * by the specified number of milliseconds. If the event fires again within that time, the original
5996 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5999 * <b>Combining Options</b><br>
6000 * Using the options argument, it is possible to combine different types of listeners:<br>
6002 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6004 el.on('click', this.onClick, this, {
6011 * <b>Attaching multiple handlers in 1 call</b><br>
6012 * The method also allows for a single argument to be passed which is a config object containing properties
6013 * which specify multiple handlers.
6023 fn: this.onMouseOver
6032 * Or a shorthand syntax:<br>
6035 'click' : this.onClick,
6036 'mouseover' : this.onMouseOver,
6037 'mouseout' : this.onMouseOut
6041 addListener : function(element, eventName, fn, scope, options){
6042 if(typeof eventName == "object"){
6048 if(typeof o[e] == "function"){
6050 listen(element, e, o, o[e], o.scope);
6052 // individual options
6053 listen(element, e, o[e]);
6058 return listen(element, eventName, options, fn, scope);
6062 * Removes an event handler
6064 * @param {String/HTMLElement} element The id or html element to remove the
6066 * @param {String} eventName The type of event
6067 * @param {Function} fn
6068 * @return {Boolean} True if a listener was actually removed
6070 removeListener : function(element, eventName, fn){
6071 return stopListening(element, eventName, fn);
6075 * Fires when the document is ready (before onload and before images are loaded). Can be
6076 * accessed shorthanded Roo.onReady().
6077 * @param {Function} fn The method the event invokes
6078 * @param {Object} scope An object that becomes the scope of the handler
6079 * @param {boolean} options
6081 onDocumentReady : function(fn, scope, options){
6082 if(docReadyState){ // if it already fired
6083 docReadyEvent.addListener(fn, scope, options);
6084 docReadyEvent.fire();
6085 docReadyEvent.clearListeners();
6091 docReadyEvent.addListener(fn, scope, options);
6095 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6096 * @param {Function} fn The method the event invokes
6097 * @param {Object} scope An object that becomes the scope of the handler
6098 * @param {boolean} options
6100 onWindowResize : function(fn, scope, options){
6102 resizeEvent = new Roo.util.Event();
6103 resizeTask = new Roo.util.DelayedTask(function(){
6104 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6106 E.on(window, "resize", function(){
6108 resizeTask.delay(50);
6110 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6114 resizeEvent.addListener(fn, scope, options);
6118 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6119 * @param {Function} fn The method the event invokes
6120 * @param {Object} scope An object that becomes the scope of the handler
6121 * @param {boolean} options
6123 onTextResize : function(fn, scope, options){
6125 textEvent = new Roo.util.Event();
6126 var textEl = new Roo.Element(document.createElement('div'));
6127 textEl.dom.className = 'x-text-resize';
6128 textEl.dom.innerHTML = 'X';
6129 textEl.appendTo(document.body);
6130 textSize = textEl.dom.offsetHeight;
6131 setInterval(function(){
6132 if(textEl.dom.offsetHeight != textSize){
6133 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6135 }, this.textResizeInterval);
6137 textEvent.addListener(fn, scope, options);
6141 * Removes the passed window resize listener.
6142 * @param {Function} fn The method the event invokes
6143 * @param {Object} scope The scope of handler
6145 removeResizeListener : function(fn, scope){
6147 resizeEvent.removeListener(fn, scope);
6152 fireResize : function(){
6154 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6158 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6162 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6164 textResizeInterval : 50
6169 * @scopeAlias pub=Roo.EventManager
6173 * Appends an event handler to an element (shorthand for addListener)
6174 * @param {String/HTMLElement} element The html element or id to assign the
6175 * @param {String} eventName The type of event to listen for
6176 * @param {Function} handler The method the event invokes
6177 * @param {Object} scope (optional) The scope in which to execute the handler
6178 * function. The handler function's "this" context.
6179 * @param {Object} options (optional) An object containing handler configuration
6180 * properties. This may contain any of the following properties:<ul>
6181 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6182 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6183 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6184 * <li>preventDefault {Boolean} True to prevent the default action</li>
6185 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6186 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6187 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6188 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6189 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6190 * by the specified number of milliseconds. If the event fires again within that time, the original
6191 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6194 * <b>Combining Options</b><br>
6195 * Using the options argument, it is possible to combine different types of listeners:<br>
6197 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6199 el.on('click', this.onClick, this, {
6206 * <b>Attaching multiple handlers in 1 call</b><br>
6207 * The method also allows for a single argument to be passed which is a config object containing properties
6208 * which specify multiple handlers.
6218 fn: this.onMouseOver
6227 * Or a shorthand syntax:<br>
6230 'click' : this.onClick,
6231 'mouseover' : this.onMouseOver,
6232 'mouseout' : this.onMouseOut
6236 pub.on = pub.addListener;
6237 pub.un = pub.removeListener;
6239 pub.stoppedMouseDownEvent = new Roo.util.Event();
6243 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6244 * @param {Function} fn The method the event invokes
6245 * @param {Object} scope An object that becomes the scope of the handler
6246 * @param {boolean} override If true, the obj passed in becomes
6247 * the execution scope of the listener
6251 Roo.onReady = Roo.EventManager.onDocumentReady;
6253 Roo.onReady(function(){
6254 var bd = Roo.get(document.body);
6259 : Roo.isGecko ? "roo-gecko"
6260 : Roo.isOpera ? "roo-opera"
6261 : Roo.isSafari ? "roo-safari" : ""];
6264 cls.push("roo-mac");
6267 cls.push("roo-linux");
6269 if(Roo.isBorderBox){
6270 cls.push('roo-border-box');
6272 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6273 var p = bd.dom.parentNode;
6275 p.className += ' roo-strict';
6278 bd.addClass(cls.join(' '));
6282 * @class Roo.EventObject
6283 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6284 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6287 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6289 var target = e.getTarget();
6292 var myDiv = Roo.get("myDiv");
6293 myDiv.on("click", handleClick);
6295 Roo.EventManager.on("myDiv", 'click', handleClick);
6296 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6300 Roo.EventObject = function(){
6302 var E = Roo.lib.Event;
6304 // safari keypress events for special keys return bad keycodes
6307 63235 : 39, // right
6310 63276 : 33, // page up
6311 63277 : 34, // page down
6312 63272 : 46, // delete
6317 // normalize button clicks
6318 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6319 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6321 Roo.EventObjectImpl = function(e){
6323 this.setEvent(e.browserEvent || e);
6326 Roo.EventObjectImpl.prototype = {
6328 * Used to fix doc tools.
6329 * @scope Roo.EventObject.prototype
6335 /** The normal browser event */
6336 browserEvent : null,
6337 /** The button pressed in a mouse event */
6339 /** True if the shift key was down during the event */
6341 /** True if the control key was down during the event */
6343 /** True if the alt key was down during the event */
6402 setEvent : function(e){
6403 if(e == this || (e && e.browserEvent)){ // already wrapped
6406 this.browserEvent = e;
6408 // normalize buttons
6409 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6410 if(e.type == 'click' && this.button == -1){
6414 this.shiftKey = e.shiftKey;
6415 // mac metaKey behaves like ctrlKey
6416 this.ctrlKey = e.ctrlKey || e.metaKey;
6417 this.altKey = e.altKey;
6418 // in getKey these will be normalized for the mac
6419 this.keyCode = e.keyCode;
6420 // keyup warnings on firefox.
6421 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6422 // cache the target for the delayed and or buffered events
6423 this.target = E.getTarget(e);
6425 this.xy = E.getXY(e);
6428 this.shiftKey = false;
6429 this.ctrlKey = false;
6430 this.altKey = false;
6440 * Stop the event (preventDefault and stopPropagation)
6442 stopEvent : function(){
6443 if(this.browserEvent){
6444 if(this.browserEvent.type == 'mousedown'){
6445 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6447 E.stopEvent(this.browserEvent);
6452 * Prevents the browsers default handling of the event.
6454 preventDefault : function(){
6455 if(this.browserEvent){
6456 E.preventDefault(this.browserEvent);
6461 isNavKeyPress : function(){
6462 var k = this.keyCode;
6463 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6464 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6467 isSpecialKey : function(){
6468 var k = this.keyCode;
6469 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6470 (k == 16) || (k == 17) ||
6471 (k >= 18 && k <= 20) ||
6472 (k >= 33 && k <= 35) ||
6473 (k >= 36 && k <= 39) ||
6474 (k >= 44 && k <= 45);
6477 * Cancels bubbling of the event.
6479 stopPropagation : function(){
6480 if(this.browserEvent){
6481 if(this.type == 'mousedown'){
6482 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6484 E.stopPropagation(this.browserEvent);
6489 * Gets the key code for the event.
6492 getCharCode : function(){
6493 return this.charCode || this.keyCode;
6497 * Returns a normalized keyCode for the event.
6498 * @return {Number} The key code
6500 getKey : function(){
6501 var k = this.keyCode || this.charCode;
6502 return Roo.isSafari ? (safariKeys[k] || k) : k;
6506 * Gets the x coordinate of the event.
6509 getPageX : function(){
6514 * Gets the y coordinate of the event.
6517 getPageY : function(){
6522 * Gets the time of the event.
6525 getTime : function(){
6526 if(this.browserEvent){
6527 return E.getTime(this.browserEvent);
6533 * Gets the page coordinates of the event.
6534 * @return {Array} The xy values like [x, y]
6541 * Gets the target for the event.
6542 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6543 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6544 search as a number or element (defaults to 10 || document.body)
6545 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6546 * @return {HTMLelement}
6548 getTarget : function(selector, maxDepth, returnEl){
6549 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6552 * Gets the related target.
6553 * @return {HTMLElement}
6555 getRelatedTarget : function(){
6556 if(this.browserEvent){
6557 return E.getRelatedTarget(this.browserEvent);
6563 * Normalizes mouse wheel delta across browsers
6564 * @return {Number} The delta
6566 getWheelDelta : function(){
6567 var e = this.browserEvent;
6569 if(e.wheelDelta){ /* IE/Opera. */
6570 delta = e.wheelDelta/120;
6571 }else if(e.detail){ /* Mozilla case. */
6572 delta = -e.detail/3;
6578 * Returns true if the control, meta, shift or alt key was pressed during this event.
6581 hasModifier : function(){
6582 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6586 * Returns true if the target of this event equals el or is a child of el
6587 * @param {String/HTMLElement/Element} el
6588 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6591 within : function(el, related){
6592 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6593 return t && Roo.fly(el).contains(t);
6596 getPoint : function(){
6597 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6601 return new Roo.EventObjectImpl();
6606 * Ext JS Library 1.1.1
6607 * Copyright(c) 2006-2007, Ext JS, LLC.
6609 * Originally Released Under LGPL - original licence link has changed is not relivant.
6612 * <script type="text/javascript">
6616 // was in Composite Element!??!?!
6619 var D = Roo.lib.Dom;
6620 var E = Roo.lib.Event;
6621 var A = Roo.lib.Anim;
6623 // local style camelizing for speed
6625 var camelRe = /(-[a-z])/gi;
6626 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6627 var view = document.defaultView;
6630 * @class Roo.Element
6631 * Represents an Element in the DOM.<br><br>
6634 var el = Roo.get("my-div");
6637 var el = getEl("my-div");
6639 // or with a DOM element
6640 var el = Roo.get(myDivElement);
6642 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6643 * each call instead of constructing a new one.<br><br>
6644 * <b>Animations</b><br />
6645 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6646 * should either be a boolean (true) or an object literal with animation options. The animation options are:
6648 Option Default Description
6649 --------- -------- ---------------------------------------------
6650 duration .35 The duration of the animation in seconds
6651 easing easeOut The YUI easing method
6652 callback none A function to execute when the anim completes
6653 scope this The scope (this) of the callback function
6655 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6656 * manipulate the animation. Here's an example:
6658 var el = Roo.get("my-div");
6663 // default animation
6664 el.setWidth(100, true);
6666 // animation with some options set
6673 // using the "anim" property to get the Anim object
6679 el.setWidth(100, opt);
6681 if(opt.anim.isAnimated()){
6685 * <b> Composite (Collections of) Elements</b><br />
6686 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6687 * @constructor Create a new Element directly.
6688 * @param {String/HTMLElement} element
6689 * @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).
6691 Roo.Element = function(element, forceNew){
6692 var dom = typeof element == "string" ?
6693 document.getElementById(element) : element;
6694 if(!dom){ // invalid id/element
6698 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6699 return Roo.Element.cache[id];
6709 * The DOM element ID
6712 this.id = id || Roo.id(dom);
6715 var El = Roo.Element;
6719 * The element's default display mode (defaults to "")
6722 originalDisplay : "",
6726 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6731 * Sets the element's visibility mode. When setVisible() is called it
6732 * will use this to determine whether to set the visibility or the display property.
6733 * @param visMode Element.VISIBILITY or Element.DISPLAY
6734 * @return {Roo.Element} this
6736 setVisibilityMode : function(visMode){
6737 this.visibilityMode = visMode;
6741 * Convenience method for setVisibilityMode(Element.DISPLAY)
6742 * @param {String} display (optional) What to set display to when visible
6743 * @return {Roo.Element} this
6745 enableDisplayMode : function(display){
6746 this.setVisibilityMode(El.DISPLAY);
6747 if(typeof display != "undefined") this.originalDisplay = display;
6752 * 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)
6753 * @param {String} selector The simple selector to test
6754 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6755 search as a number or element (defaults to 10 || document.body)
6756 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6757 * @return {HTMLElement} The matching DOM node (or null if no match was found)
6759 findParent : function(simpleSelector, maxDepth, returnEl){
6760 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
6761 maxDepth = maxDepth || 50;
6762 if(typeof maxDepth != "number"){
6763 stopEl = Roo.getDom(maxDepth);
6766 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
6767 if(dq.is(p, simpleSelector)){
6768 return returnEl ? Roo.get(p) : p;
6778 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
6779 * @param {String} selector The simple selector to test
6780 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6781 search as a number or element (defaults to 10 || document.body)
6782 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6783 * @return {HTMLElement} The matching DOM node (or null if no match was found)
6785 findParentNode : function(simpleSelector, maxDepth, returnEl){
6786 var p = Roo.fly(this.dom.parentNode, '_internal');
6787 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
6791 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
6792 * This is a shortcut for findParentNode() that always returns an Roo.Element.
6793 * @param {String} selector The simple selector to test
6794 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6795 search as a number or element (defaults to 10 || document.body)
6796 * @return {Roo.Element} The matching DOM node (or null if no match was found)
6798 up : function(simpleSelector, maxDepth){
6799 return this.findParentNode(simpleSelector, maxDepth, true);
6805 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
6806 * @param {String} selector The simple selector to test
6807 * @return {Boolean} True if this element matches the selector, else false
6809 is : function(simpleSelector){
6810 return Roo.DomQuery.is(this.dom, simpleSelector);
6814 * Perform animation on this element.
6815 * @param {Object} args The YUI animation control args
6816 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
6817 * @param {Function} onComplete (optional) Function to call when animation completes
6818 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
6819 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
6820 * @return {Roo.Element} this
6822 animate : function(args, duration, onComplete, easing, animType){
6823 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
6828 * @private Internal animation call
6830 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
6831 animType = animType || 'run';
6833 var anim = Roo.lib.Anim[animType](
6835 (opt.duration || defaultDur) || .35,
6836 (opt.easing || defaultEase) || 'easeOut',
6838 Roo.callback(cb, this);
6839 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
6847 // private legacy anim prep
6848 preanim : function(a, i){
6849 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
6853 * Removes worthless text nodes
6854 * @param {Boolean} forceReclean (optional) By default the element
6855 * keeps track if it has been cleaned already so
6856 * you can call this over and over. However, if you update the element and
6857 * need to force a reclean, you can pass true.
6859 clean : function(forceReclean){
6860 if(this.isCleaned && forceReclean !== true){
6864 var d = this.dom, n = d.firstChild, ni = -1;
6866 var nx = n.nextSibling;
6867 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
6874 this.isCleaned = true;
6879 calcOffsetsTo : function(el){
6882 var restorePos = false;
6883 if(el.getStyle('position') == 'static'){
6884 el.position('relative');
6889 while(op && op != d && op.tagName != 'HTML'){
6892 op = op.offsetParent;
6895 el.position('static');
6901 * Scrolls this element into view within the passed container.
6902 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
6903 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
6904 * @return {Roo.Element} this
6906 scrollIntoView : function(container, hscroll){
6907 var c = Roo.getDom(container) || document.body;
6910 var o = this.calcOffsetsTo(c),
6913 b = t+el.offsetHeight,
6914 r = l+el.offsetWidth;
6916 var ch = c.clientHeight;
6917 var ct = parseInt(c.scrollTop, 10);
6918 var cl = parseInt(c.scrollLeft, 10);
6920 var cr = cl + c.clientWidth;
6928 if(hscroll !== false){
6932 c.scrollLeft = r-c.clientWidth;
6939 scrollChildIntoView : function(child, hscroll){
6940 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
6944 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
6945 * the new height may not be available immediately.
6946 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
6947 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
6948 * @param {Function} onComplete (optional) Function to call when animation completes
6949 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
6950 * @return {Roo.Element} this
6952 autoHeight : function(animate, duration, onComplete, easing){
6953 var oldHeight = this.getHeight();
6955 this.setHeight(1); // force clipping
6956 setTimeout(function(){
6957 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
6959 this.setHeight(height);
6961 if(typeof onComplete == "function"){
6965 this.setHeight(oldHeight); // restore original height
6966 this.setHeight(height, animate, duration, function(){
6968 if(typeof onComplete == "function") onComplete();
6969 }.createDelegate(this), easing);
6971 }.createDelegate(this), 0);
6976 * Returns true if this element is an ancestor of the passed element
6977 * @param {HTMLElement/String} el The element to check
6978 * @return {Boolean} True if this element is an ancestor of el, else false
6980 contains : function(el){
6981 if(!el){return false;}
6982 return D.isAncestor(this.dom, el.dom ? el.dom : el);
6986 * Checks whether the element is currently visible using both visibility and display properties.
6987 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
6988 * @return {Boolean} True if the element is currently visible, else false
6990 isVisible : function(deep) {
6991 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
6992 if(deep !== true || !vis){
6995 var p = this.dom.parentNode;
6996 while(p && p.tagName.toLowerCase() != "body"){
6997 if(!Roo.fly(p, '_isVisible').isVisible()){
7006 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7007 * @param {String} selector The CSS selector
7008 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7009 * @return {CompositeElement/CompositeElementLite} The composite element
7011 select : function(selector, unique){
7012 return El.select(selector, unique, this.dom);
7016 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7017 * @param {String} selector The CSS selector
7018 * @return {Array} An array of the matched nodes
7020 query : function(selector, unique){
7021 return Roo.DomQuery.select(selector, this.dom);
7025 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7026 * @param {String} selector The CSS selector
7027 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7028 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7030 child : function(selector, returnDom){
7031 var n = Roo.DomQuery.selectNode(selector, this.dom);
7032 return returnDom ? n : Roo.get(n);
7036 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7037 * @param {String} selector The CSS selector
7038 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7039 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7041 down : function(selector, returnDom){
7042 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7043 return returnDom ? n : Roo.get(n);
7047 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7048 * @param {String} group The group the DD object is member of
7049 * @param {Object} config The DD config object
7050 * @param {Object} overrides An object containing methods to override/implement on the DD object
7051 * @return {Roo.dd.DD} The DD object
7053 initDD : function(group, config, overrides){
7054 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7055 return Roo.apply(dd, overrides);
7059 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7060 * @param {String} group The group the DDProxy object is member of
7061 * @param {Object} config The DDProxy config object
7062 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7063 * @return {Roo.dd.DDProxy} The DDProxy object
7065 initDDProxy : function(group, config, overrides){
7066 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7067 return Roo.apply(dd, overrides);
7071 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7072 * @param {String} group The group the DDTarget object is member of
7073 * @param {Object} config The DDTarget config object
7074 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7075 * @return {Roo.dd.DDTarget} The DDTarget object
7077 initDDTarget : function(group, config, overrides){
7078 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7079 return Roo.apply(dd, overrides);
7083 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7084 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7085 * @param {Boolean} visible Whether the element is visible
7086 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7087 * @return {Roo.Element} this
7089 setVisible : function(visible, animate){
7091 if(this.visibilityMode == El.DISPLAY){
7092 this.setDisplayed(visible);
7095 this.dom.style.visibility = visible ? "visible" : "hidden";
7098 // closure for composites
7100 var visMode = this.visibilityMode;
7102 this.setOpacity(.01);
7103 this.setVisible(true);
7105 this.anim({opacity: { to: (visible?1:0) }},
7106 this.preanim(arguments, 1),
7107 null, .35, 'easeIn', function(){
7109 if(visMode == El.DISPLAY){
7110 dom.style.display = "none";
7112 dom.style.visibility = "hidden";
7114 Roo.get(dom).setOpacity(1);
7122 * Returns true if display is not "none"
7125 isDisplayed : function() {
7126 return this.getStyle("display") != "none";
7130 * Toggles the element's visibility or display, depending on visibility mode.
7131 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7132 * @return {Roo.Element} this
7134 toggle : function(animate){
7135 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7140 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7141 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7142 * @return {Roo.Element} this
7144 setDisplayed : function(value) {
7145 if(typeof value == "boolean"){
7146 value = value ? this.originalDisplay : "none";
7148 this.setStyle("display", value);
7153 * Tries to focus the element. Any exceptions are caught and ignored.
7154 * @return {Roo.Element} this
7156 focus : function() {
7164 * Tries to blur the element. Any exceptions are caught and ignored.
7165 * @return {Roo.Element} this
7175 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7176 * @param {String/Array} className The CSS class to add, or an array of classes
7177 * @return {Roo.Element} this
7179 addClass : function(className){
7180 if(className instanceof Array){
7181 for(var i = 0, len = className.length; i < len; i++) {
7182 this.addClass(className[i]);
7185 if(className && !this.hasClass(className)){
7186 this.dom.className = this.dom.className + " " + className;
7193 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7194 * @param {String/Array} className The CSS class to add, or an array of classes
7195 * @return {Roo.Element} this
7197 radioClass : function(className){
7198 var siblings = this.dom.parentNode.childNodes;
7199 for(var i = 0; i < siblings.length; i++) {
7200 var s = siblings[i];
7201 if(s.nodeType == 1){
7202 Roo.get(s).removeClass(className);
7205 this.addClass(className);
7210 * Removes one or more CSS classes from the element.
7211 * @param {String/Array} className The CSS class to remove, or an array of classes
7212 * @return {Roo.Element} this
7214 removeClass : function(className){
7215 if(!className || !this.dom.className){
7218 if(className instanceof Array){
7219 for(var i = 0, len = className.length; i < len; i++) {
7220 this.removeClass(className[i]);
7223 if(this.hasClass(className)){
7224 var re = this.classReCache[className];
7226 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7227 this.classReCache[className] = re;
7229 this.dom.className =
7230 this.dom.className.replace(re, " ");
7240 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7241 * @param {String} className The CSS class to toggle
7242 * @return {Roo.Element} this
7244 toggleClass : function(className){
7245 if(this.hasClass(className)){
7246 this.removeClass(className);
7248 this.addClass(className);
7254 * Checks if the specified CSS class exists on this element's DOM node.
7255 * @param {String} className The CSS class to check for
7256 * @return {Boolean} True if the class exists, else false
7258 hasClass : function(className){
7259 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7263 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7264 * @param {String} oldClassName The CSS class to replace
7265 * @param {String} newClassName The replacement CSS class
7266 * @return {Roo.Element} this
7268 replaceClass : function(oldClassName, newClassName){
7269 this.removeClass(oldClassName);
7270 this.addClass(newClassName);
7275 * Returns an object with properties matching the styles requested.
7276 * For example, el.getStyles('color', 'font-size', 'width') might return
7277 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7278 * @param {String} style1 A style name
7279 * @param {String} style2 A style name
7280 * @param {String} etc.
7281 * @return {Object} The style object
7283 getStyles : function(){
7284 var a = arguments, len = a.length, r = {};
7285 for(var i = 0; i < len; i++){
7286 r[a[i]] = this.getStyle(a[i]);
7292 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7293 * @param {String} property The style property whose value is returned.
7294 * @return {String} The current value of the style property for this element.
7296 getStyle : function(){
7297 return view && view.getComputedStyle ?
7299 var el = this.dom, v, cs, camel;
7300 if(prop == 'float'){
7303 if(el.style && (v = el.style[prop])){
7306 if(cs = view.getComputedStyle(el, "")){
7307 if(!(camel = propCache[prop])){
7308 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7315 var el = this.dom, v, cs, camel;
7316 if(prop == 'opacity'){
7317 if(typeof el.style.filter == 'string'){
7318 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7320 var fv = parseFloat(m[1]);
7322 return fv ? fv / 100 : 0;
7327 }else if(prop == 'float'){
7328 prop = "styleFloat";
7330 if(!(camel = propCache[prop])){
7331 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7333 if(v = el.style[camel]){
7336 if(cs = el.currentStyle){
7344 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7345 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7346 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7347 * @return {Roo.Element} this
7349 setStyle : function(prop, value){
7350 if(typeof prop == "string"){
7352 if(!(camel = propCache[prop])){
7353 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7355 if(camel == 'opacity') {
7356 this.setOpacity(value);
7358 this.dom.style[camel] = value;
7361 for(var style in prop){
7362 if(typeof prop[style] != "function"){
7363 this.setStyle(style, prop[style]);
7371 * More flexible version of {@link #setStyle} for setting style properties.
7372 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7373 * a function which returns such a specification.
7374 * @return {Roo.Element} this
7376 applyStyles : function(style){
7377 Roo.DomHelper.applyStyles(this.dom, style);
7382 * 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).
7383 * @return {Number} The X position of the element
7386 return D.getX(this.dom);
7390 * 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).
7391 * @return {Number} The Y position of the element
7394 return D.getY(this.dom);
7398 * 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).
7399 * @return {Array} The XY position of the element
7402 return D.getXY(this.dom);
7406 * 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).
7407 * @param {Number} The X position of the element
7408 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7409 * @return {Roo.Element} this
7411 setX : function(x, animate){
7413 D.setX(this.dom, x);
7415 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7421 * 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).
7422 * @param {Number} The Y position of the element
7423 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7424 * @return {Roo.Element} this
7426 setY : function(y, animate){
7428 D.setY(this.dom, y);
7430 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7436 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7437 * @param {String} left The left CSS property value
7438 * @return {Roo.Element} this
7440 setLeft : function(left){
7441 this.setStyle("left", this.addUnits(left));
7446 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7447 * @param {String} top The top CSS property value
7448 * @return {Roo.Element} this
7450 setTop : function(top){
7451 this.setStyle("top", this.addUnits(top));
7456 * Sets the element's CSS right style.
7457 * @param {String} right The right CSS property value
7458 * @return {Roo.Element} this
7460 setRight : function(right){
7461 this.setStyle("right", this.addUnits(right));
7466 * Sets the element's CSS bottom style.
7467 * @param {String} bottom The bottom CSS property value
7468 * @return {Roo.Element} this
7470 setBottom : function(bottom){
7471 this.setStyle("bottom", this.addUnits(bottom));
7476 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7477 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7478 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7479 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7480 * @return {Roo.Element} this
7482 setXY : function(pos, animate){
7484 D.setXY(this.dom, pos);
7486 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7492 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7493 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7494 * @param {Number} x X value for new position (coordinates are page-based)
7495 * @param {Number} y Y value for new position (coordinates are page-based)
7496 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7497 * @return {Roo.Element} this
7499 setLocation : function(x, y, animate){
7500 this.setXY([x, y], this.preanim(arguments, 2));
7505 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7506 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7507 * @param {Number} x X value for new position (coordinates are page-based)
7508 * @param {Number} y Y value for new position (coordinates are page-based)
7509 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7510 * @return {Roo.Element} this
7512 moveTo : function(x, y, animate){
7513 this.setXY([x, y], this.preanim(arguments, 2));
7518 * Returns the region of the given element.
7519 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7520 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7522 getRegion : function(){
7523 return D.getRegion(this.dom);
7527 * Returns the offset height of the element
7528 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7529 * @return {Number} The element's height
7531 getHeight : function(contentHeight){
7532 var h = this.dom.offsetHeight || 0;
7533 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7537 * Returns the offset width of the element
7538 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7539 * @return {Number} The element's width
7541 getWidth : function(contentWidth){
7542 var w = this.dom.offsetWidth || 0;
7543 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7547 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7548 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7549 * if a height has not been set using CSS.
7552 getComputedHeight : function(){
7553 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7555 h = parseInt(this.getStyle('height'), 10) || 0;
7556 if(!this.isBorderBox()){
7557 h += this.getFrameWidth('tb');
7564 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7565 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7566 * if a width has not been set using CSS.
7569 getComputedWidth : function(){
7570 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7572 w = parseInt(this.getStyle('width'), 10) || 0;
7573 if(!this.isBorderBox()){
7574 w += this.getFrameWidth('lr');
7581 * Returns the size of the element.
7582 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7583 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7585 getSize : function(contentSize){
7586 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7590 * Returns the width and height of the viewport.
7591 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7593 getViewSize : function(){
7594 var d = this.dom, doc = document, aw = 0, ah = 0;
7595 if(d == doc || d == doc.body){
7596 return {width : D.getViewWidth(), height: D.getViewHeight()};
7599 width : d.clientWidth,
7600 height: d.clientHeight
7606 * Returns the value of the "value" attribute
7607 * @param {Boolean} asNumber true to parse the value as a number
7608 * @return {String/Number}
7610 getValue : function(asNumber){
7611 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7615 adjustWidth : function(width){
7616 if(typeof width == "number"){
7617 if(this.autoBoxAdjust && !this.isBorderBox()){
7618 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7628 adjustHeight : function(height){
7629 if(typeof height == "number"){
7630 if(this.autoBoxAdjust && !this.isBorderBox()){
7631 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7641 * Set the width of the element
7642 * @param {Number} width The new width
7643 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7644 * @return {Roo.Element} this
7646 setWidth : function(width, animate){
7647 width = this.adjustWidth(width);
7649 this.dom.style.width = this.addUnits(width);
7651 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7657 * Set the height of the element
7658 * @param {Number} height The new height
7659 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7660 * @return {Roo.Element} this
7662 setHeight : function(height, animate){
7663 height = this.adjustHeight(height);
7665 this.dom.style.height = this.addUnits(height);
7667 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7673 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7674 * @param {Number} width The new width
7675 * @param {Number} height The new height
7676 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7677 * @return {Roo.Element} this
7679 setSize : function(width, height, animate){
7680 if(typeof width == "object"){ // in case of object from getSize()
7681 height = width.height; width = width.width;
7683 width = this.adjustWidth(width); height = this.adjustHeight(height);
7685 this.dom.style.width = this.addUnits(width);
7686 this.dom.style.height = this.addUnits(height);
7688 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7694 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7695 * @param {Number} x X value for new position (coordinates are page-based)
7696 * @param {Number} y Y value for new position (coordinates are page-based)
7697 * @param {Number} width The new width
7698 * @param {Number} height The new height
7699 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7700 * @return {Roo.Element} this
7702 setBounds : function(x, y, width, height, animate){
7704 this.setSize(width, height);
7705 this.setLocation(x, y);
7707 width = this.adjustWidth(width); height = this.adjustHeight(height);
7708 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7709 this.preanim(arguments, 4), 'motion');
7715 * 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.
7716 * @param {Roo.lib.Region} region The region to fill
7717 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7718 * @return {Roo.Element} this
7720 setRegion : function(region, animate){
7721 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7726 * Appends an event handler
7728 * @param {String} eventName The type of event to append
7729 * @param {Function} fn The method the event invokes
7730 * @param {Object} scope (optional) The scope (this object) of the fn
7731 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
7733 addListener : function(eventName, fn, scope, options){
7734 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
7738 * Removes an event handler from this element
7739 * @param {String} eventName the type of event to remove
7740 * @param {Function} fn the method the event invokes
7741 * @return {Roo.Element} this
7743 removeListener : function(eventName, fn){
7744 Roo.EventManager.removeListener(this.dom, eventName, fn);
7749 * Removes all previous added listeners from this element
7750 * @return {Roo.Element} this
7752 removeAllListeners : function(){
7753 E.purgeElement(this.dom);
7757 relayEvent : function(eventName, observable){
7758 this.on(eventName, function(e){
7759 observable.fireEvent(eventName, e);
7764 * Set the opacity of the element
7765 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
7766 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7767 * @return {Roo.Element} this
7769 setOpacity : function(opacity, animate){
7771 var s = this.dom.style;
7774 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
7775 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
7777 s.opacity = opacity;
7780 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
7786 * Gets the left X coordinate
7787 * @param {Boolean} local True to get the local css position instead of page coordinate
7790 getLeft : function(local){
7794 return parseInt(this.getStyle("left"), 10) || 0;
7799 * Gets the right X coordinate of the element (element X position + element width)
7800 * @param {Boolean} local True to get the local css position instead of page coordinate
7803 getRight : function(local){
7805 return this.getX() + this.getWidth();
7807 return (this.getLeft(true) + this.getWidth()) || 0;
7812 * Gets the top Y coordinate
7813 * @param {Boolean} local True to get the local css position instead of page coordinate
7816 getTop : function(local) {
7820 return parseInt(this.getStyle("top"), 10) || 0;
7825 * Gets the bottom Y coordinate of the element (element Y position + element height)
7826 * @param {Boolean} local True to get the local css position instead of page coordinate
7829 getBottom : function(local){
7831 return this.getY() + this.getHeight();
7833 return (this.getTop(true) + this.getHeight()) || 0;
7838 * Initializes positioning on this element. If a desired position is not passed, it will make the
7839 * the element positioned relative IF it is not already positioned.
7840 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
7841 * @param {Number} zIndex (optional) The zIndex to apply
7842 * @param {Number} x (optional) Set the page X position
7843 * @param {Number} y (optional) Set the page Y position
7845 position : function(pos, zIndex, x, y){
7847 if(this.getStyle('position') == 'static'){
7848 this.setStyle('position', 'relative');
7851 this.setStyle("position", pos);
7854 this.setStyle("z-index", zIndex);
7856 if(x !== undefined && y !== undefined){
7858 }else if(x !== undefined){
7860 }else if(y !== undefined){
7866 * Clear positioning back to the default when the document was loaded
7867 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
7868 * @return {Roo.Element} this
7870 clearPositioning : function(value){
7878 "position" : "static"
7884 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
7885 * snapshot before performing an update and then restoring the element.
7888 getPositioning : function(){
7889 var l = this.getStyle("left");
7890 var t = this.getStyle("top");
7892 "position" : this.getStyle("position"),
7894 "right" : l ? "" : this.getStyle("right"),
7896 "bottom" : t ? "" : this.getStyle("bottom"),
7897 "z-index" : this.getStyle("z-index")
7902 * Gets the width of the border(s) for the specified side(s)
7903 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
7904 * passing lr would get the border (l)eft width + the border (r)ight width.
7905 * @return {Number} The width of the sides passed added together
7907 getBorderWidth : function(side){
7908 return this.addStyles(side, El.borders);
7912 * Gets the width of the padding(s) for the specified side(s)
7913 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
7914 * passing lr would get the padding (l)eft + the padding (r)ight.
7915 * @return {Number} The padding of the sides passed added together
7917 getPadding : function(side){
7918 return this.addStyles(side, El.paddings);
7922 * Set positioning with an object returned by getPositioning().
7923 * @param {Object} posCfg
7924 * @return {Roo.Element} this
7926 setPositioning : function(pc){
7927 this.applyStyles(pc);
7928 if(pc.right == "auto"){
7929 this.dom.style.right = "";
7931 if(pc.bottom == "auto"){
7932 this.dom.style.bottom = "";
7938 fixDisplay : function(){
7939 if(this.getStyle("display") == "none"){
7940 this.setStyle("visibility", "hidden");
7941 this.setStyle("display", this.originalDisplay); // first try reverting to default
7942 if(this.getStyle("display") == "none"){ // if that fails, default to block
7943 this.setStyle("display", "block");
7949 * Quick set left and top adding default units
7950 * @param {String} left The left CSS property value
7951 * @param {String} top The top CSS property value
7952 * @return {Roo.Element} this
7954 setLeftTop : function(left, top){
7955 this.dom.style.left = this.addUnits(left);
7956 this.dom.style.top = this.addUnits(top);
7961 * Move this element relative to its current position.
7962 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
7963 * @param {Number} distance How far to move the element in pixels
7964 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7965 * @return {Roo.Element} this
7967 move : function(direction, distance, animate){
7968 var xy = this.getXY();
7969 direction = direction.toLowerCase();
7973 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
7977 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
7982 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
7987 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
7994 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
7995 * @return {Roo.Element} this
7998 if(!this.isClipped){
7999 this.isClipped = true;
8000 this.originalClip = {
8001 "o": this.getStyle("overflow"),
8002 "x": this.getStyle("overflow-x"),
8003 "y": this.getStyle("overflow-y")
8005 this.setStyle("overflow", "hidden");
8006 this.setStyle("overflow-x", "hidden");
8007 this.setStyle("overflow-y", "hidden");
8013 * Return clipping (overflow) to original clipping before clip() was called
8014 * @return {Roo.Element} this
8016 unclip : function(){
8018 this.isClipped = false;
8019 var o = this.originalClip;
8020 if(o.o){this.setStyle("overflow", o.o);}
8021 if(o.x){this.setStyle("overflow-x", o.x);}
8022 if(o.y){this.setStyle("overflow-y", o.y);}
8029 * Gets the x,y coordinates specified by the anchor position on the element.
8030 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8031 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8032 * {width: (target width), height: (target height)} (defaults to the element's current size)
8033 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8034 * @return {Array} [x, y] An array containing the element's x and y coordinates
8036 getAnchorXY : function(anchor, local, s){
8037 //Passing a different size is useful for pre-calculating anchors,
8038 //especially for anchored animations that change the el size.
8040 var w, h, vp = false;
8043 if(d == document.body || d == document){
8045 w = D.getViewWidth(); h = D.getViewHeight();
8047 w = this.getWidth(); h = this.getHeight();
8050 w = s.width; h = s.height;
8052 var x = 0, y = 0, r = Math.round;
8053 switch((anchor || "tl").toLowerCase()){
8095 var sc = this.getScroll();
8096 return [x + sc.left, y + sc.top];
8098 //Add the element's offset xy
8099 var o = this.getXY();
8100 return [x+o[0], y+o[1]];
8104 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8105 * supported position values.
8106 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8107 * @param {String} position The position to align to.
8108 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8109 * @return {Array} [x, y]
8111 getAlignToXY : function(el, p, o){
8115 throw "Element.alignTo with an element that doesn't exist";
8117 var c = false; //constrain to viewport
8118 var p1 = "", p2 = "";
8125 }else if(p.indexOf("-") == -1){
8128 p = p.toLowerCase();
8129 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8131 throw "Element.alignTo with an invalid alignment " + p;
8133 p1 = m[1]; p2 = m[2]; c = !!m[3];
8135 //Subtract the aligned el's internal xy from the target's offset xy
8136 //plus custom offset to get the aligned el's new offset xy
8137 var a1 = this.getAnchorXY(p1, true);
8138 var a2 = el.getAnchorXY(p2, false);
8139 var x = a2[0] - a1[0] + o[0];
8140 var y = a2[1] - a1[1] + o[1];
8142 //constrain the aligned el to viewport if necessary
8143 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8144 // 5px of margin for ie
8145 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8147 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8148 //perpendicular to the vp border, allow the aligned el to slide on that border,
8149 //otherwise swap the aligned el to the opposite border of the target.
8150 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8151 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8152 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8153 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8156 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8157 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8159 if((x+w) > dw + scrollX){
8160 x = swapX ? r.left-w : dw+scrollX-w;
8163 x = swapX ? r.right : scrollX;
8165 if((y+h) > dh + scrollY){
8166 y = swapY ? r.top-h : dh+scrollY-h;
8169 y = swapY ? r.bottom : scrollY;
8176 getConstrainToXY : function(){
8177 var os = {top:0, left:0, bottom:0, right: 0};
8179 return function(el, local, offsets, proposedXY){
8181 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8183 var vw, vh, vx = 0, vy = 0;
8184 if(el.dom == document.body || el.dom == document){
8185 vw = Roo.lib.Dom.getViewWidth();
8186 vh = Roo.lib.Dom.getViewHeight();
8188 vw = el.dom.clientWidth;
8189 vh = el.dom.clientHeight;
8191 var vxy = el.getXY();
8197 var s = el.getScroll();
8199 vx += offsets.left + s.left;
8200 vy += offsets.top + s.top;
8202 vw -= offsets.right;
8203 vh -= offsets.bottom;
8208 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8209 var x = xy[0], y = xy[1];
8210 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8212 // only move it if it needs it
8215 // first validate right/bottom
8224 // then make sure top/left isn't negative
8233 return moved ? [x, y] : false;
8238 adjustForConstraints : function(xy, parent, offsets){
8239 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8243 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8244 * document it aligns it to the viewport.
8245 * The position parameter is optional, and can be specified in any one of the following formats:
8247 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8248 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8249 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8250 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8251 * <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
8252 * element's anchor point, and the second value is used as the target's anchor point.</li>
8254 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8255 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8256 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8257 * that specified in order to enforce the viewport constraints.
8258 * Following are all of the supported anchor positions:
8261 ----- -----------------------------
8262 tl The top left corner (default)
8263 t The center of the top edge
8264 tr The top right corner
8265 l The center of the left edge
8266 c In the center of the element
8267 r The center of the right edge
8268 bl The bottom left corner
8269 b The center of the bottom edge
8270 br The bottom right corner
8274 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8275 el.alignTo("other-el");
8277 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8278 el.alignTo("other-el", "tr?");
8280 // align the bottom right corner of el with the center left edge of other-el
8281 el.alignTo("other-el", "br-l?");
8283 // align the center of el with the bottom left corner of other-el and
8284 // adjust the x position by -6 pixels (and the y position by 0)
8285 el.alignTo("other-el", "c-bl", [-6, 0]);
8287 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8288 * @param {String} position The position to align to.
8289 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8290 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8291 * @return {Roo.Element} this
8293 alignTo : function(element, position, offsets, animate){
8294 var xy = this.getAlignToXY(element, position, offsets);
8295 this.setXY(xy, this.preanim(arguments, 3));
8300 * Anchors an element to another element and realigns it when the window is resized.
8301 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8302 * @param {String} position The position to align to.
8303 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8304 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8305 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8306 * is a number, it is used as the buffer delay (defaults to 50ms).
8307 * @param {Function} callback The function to call after the animation finishes
8308 * @return {Roo.Element} this
8310 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8311 var action = function(){
8312 this.alignTo(el, alignment, offsets, animate);
8313 Roo.callback(callback, this);
8315 Roo.EventManager.onWindowResize(action, this);
8316 var tm = typeof monitorScroll;
8317 if(tm != 'undefined'){
8318 Roo.EventManager.on(window, 'scroll', action, this,
8319 {buffer: tm == 'number' ? monitorScroll : 50});
8321 action.call(this); // align immediately
8325 * Clears any opacity settings from this element. Required in some cases for IE.
8326 * @return {Roo.Element} this
8328 clearOpacity : function(){
8329 if (window.ActiveXObject) {
8330 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8331 this.dom.style.filter = "";
8334 this.dom.style.opacity = "";
8335 this.dom.style["-moz-opacity"] = "";
8336 this.dom.style["-khtml-opacity"] = "";
8342 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8343 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8344 * @return {Roo.Element} this
8346 hide : function(animate){
8347 this.setVisible(false, this.preanim(arguments, 0));
8352 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8353 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8354 * @return {Roo.Element} this
8356 show : function(animate){
8357 this.setVisible(true, this.preanim(arguments, 0));
8362 * @private Test if size has a unit, otherwise appends the default
8364 addUnits : function(size){
8365 return Roo.Element.addUnits(size, this.defaultUnit);
8369 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8370 * @return {Roo.Element} this
8372 beginMeasure : function(){
8374 if(el.offsetWidth || el.offsetHeight){
8375 return this; // offsets work already
8378 var p = this.dom, b = document.body; // start with this element
8379 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8380 var pe = Roo.get(p);
8381 if(pe.getStyle('display') == 'none'){
8382 changed.push({el: p, visibility: pe.getStyle("visibility")});
8383 p.style.visibility = "hidden";
8384 p.style.display = "block";
8388 this._measureChanged = changed;
8394 * Restores displays to before beginMeasure was called
8395 * @return {Roo.Element} this
8397 endMeasure : function(){
8398 var changed = this._measureChanged;
8400 for(var i = 0, len = changed.length; i < len; i++) {
8402 r.el.style.visibility = r.visibility;
8403 r.el.style.display = "none";
8405 this._measureChanged = null;
8411 * Update the innerHTML of this element, optionally searching for and processing scripts
8412 * @param {String} html The new HTML
8413 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8414 * @param {Function} callback For async script loading you can be noticed when the update completes
8415 * @return {Roo.Element} this
8417 update : function(html, loadScripts, callback){
8418 if(typeof html == "undefined"){
8421 if(loadScripts !== true){
8422 this.dom.innerHTML = html;
8423 if(typeof callback == "function"){
8431 html += '<span id="' + id + '"></span>';
8433 E.onAvailable(id, function(){
8434 var hd = document.getElementsByTagName("head")[0];
8435 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8436 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8437 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8440 while(match = re.exec(html)){
8441 var attrs = match[1];
8442 var srcMatch = attrs ? attrs.match(srcRe) : false;
8443 if(srcMatch && srcMatch[2]){
8444 var s = document.createElement("script");
8445 s.src = srcMatch[2];
8446 var typeMatch = attrs.match(typeRe);
8447 if(typeMatch && typeMatch[2]){
8448 s.type = typeMatch[2];
8451 }else if(match[2] && match[2].length > 0){
8452 if(window.execScript) {
8453 window.execScript(match[2]);
8461 window.eval(match[2]);
8465 var el = document.getElementById(id);
8466 if(el){el.parentNode.removeChild(el);}
8467 if(typeof callback == "function"){
8471 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8476 * Direct access to the UpdateManager update() method (takes the same parameters).
8477 * @param {String/Function} url The url for this request or a function to call to get the url
8478 * @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}
8479 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8480 * @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.
8481 * @return {Roo.Element} this
8484 var um = this.getUpdateManager();
8485 um.update.apply(um, arguments);
8490 * Gets this element's UpdateManager
8491 * @return {Roo.UpdateManager} The UpdateManager
8493 getUpdateManager : function(){
8494 if(!this.updateManager){
8495 this.updateManager = new Roo.UpdateManager(this);
8497 return this.updateManager;
8501 * Disables text selection for this element (normalized across browsers)
8502 * @return {Roo.Element} this
8504 unselectable : function(){
8505 this.dom.unselectable = "on";
8506 this.swallowEvent("selectstart", true);
8507 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8508 this.addClass("x-unselectable");
8513 * Calculates the x, y to center this element on the screen
8514 * @return {Array} The x, y values [x, y]
8516 getCenterXY : function(){
8517 return this.getAlignToXY(document, 'c-c');
8521 * Centers the Element in either the viewport, or another Element.
8522 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8524 center : function(centerIn){
8525 this.alignTo(centerIn || document, 'c-c');
8530 * Tests various css rules/browsers to determine if this element uses a border box
8533 isBorderBox : function(){
8534 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8538 * Return a box {x, y, width, height} that can be used to set another elements
8539 * size/location to match this element.
8540 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8541 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8542 * @return {Object} box An object in the format {x, y, width, height}
8544 getBox : function(contentBox, local){
8549 var left = parseInt(this.getStyle("left"), 10) || 0;
8550 var top = parseInt(this.getStyle("top"), 10) || 0;
8553 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8555 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8557 var l = this.getBorderWidth("l")+this.getPadding("l");
8558 var r = this.getBorderWidth("r")+this.getPadding("r");
8559 var t = this.getBorderWidth("t")+this.getPadding("t");
8560 var b = this.getBorderWidth("b")+this.getPadding("b");
8561 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)};
8563 bx.right = bx.x + bx.width;
8564 bx.bottom = bx.y + bx.height;
8569 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8570 for more information about the sides.
8571 * @param {String} sides
8574 getFrameWidth : function(sides, onlyContentBox){
8575 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8579 * 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.
8580 * @param {Object} box The box to fill {x, y, width, height}
8581 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8582 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8583 * @return {Roo.Element} this
8585 setBox : function(box, adjust, animate){
8586 var w = box.width, h = box.height;
8587 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8588 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8589 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8591 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8596 * Forces the browser to repaint this element
8597 * @return {Roo.Element} this
8599 repaint : function(){
8601 this.addClass("x-repaint");
8602 setTimeout(function(){
8603 Roo.get(dom).removeClass("x-repaint");
8609 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8610 * then it returns the calculated width of the sides (see getPadding)
8611 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8612 * @return {Object/Number}
8614 getMargins : function(side){
8617 top: parseInt(this.getStyle("margin-top"), 10) || 0,
8618 left: parseInt(this.getStyle("margin-left"), 10) || 0,
8619 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8620 right: parseInt(this.getStyle("margin-right"), 10) || 0
8623 return this.addStyles(side, El.margins);
8628 addStyles : function(sides, styles){
8630 for(var i = 0, len = sides.length; i < len; i++){
8631 v = this.getStyle(styles[sides.charAt(i)]);
8633 w = parseInt(v, 10);
8641 * Creates a proxy element of this element
8642 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8643 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8644 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8645 * @return {Roo.Element} The new proxy element
8647 createProxy : function(config, renderTo, matchBox){
8649 renderTo = Roo.getDom(renderTo);
8651 renderTo = document.body;
8653 config = typeof config == "object" ?
8654 config : {tag : "div", cls: config};
8655 var proxy = Roo.DomHelper.append(renderTo, config, true);
8657 proxy.setBox(this.getBox());
8663 * Puts a mask over this element to disable user interaction. Requires core.css.
8664 * This method can only be applied to elements which accept child nodes.
8665 * @param {String} msg (optional) A message to display in the mask
8666 * @param {String} msgCls (optional) A css class to apply to the msg element
8667 * @return {Element} The mask element
8669 mask : function(msg, msgCls){
8670 if(this.getStyle("position") == "static"){
8671 this.setStyle("position", "relative");
8674 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8676 this.addClass("x-masked");
8677 this._mask.setDisplayed(true);
8678 if(typeof msg == 'string'){
8680 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8682 var mm = this._maskMsg;
8683 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8684 mm.dom.firstChild.innerHTML = msg;
8685 mm.setDisplayed(true);
8688 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8689 this._mask.setHeight(this.getHeight());
8695 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8696 * it is cached for reuse.
8698 unmask : function(removeEl){
8700 if(removeEl === true){
8701 this._mask.remove();
8704 this._maskMsg.remove();
8705 delete this._maskMsg;
8708 this._mask.setDisplayed(false);
8710 this._maskMsg.setDisplayed(false);
8714 this.removeClass("x-masked");
8718 * Returns true if this element is masked
8721 isMasked : function(){
8722 return this._mask && this._mask.isVisible();
8726 * Creates an iframe shim for this element to keep selects and other windowed objects from
8728 * @return {Roo.Element} The new shim element
8730 createShim : function(){
8731 var el = document.createElement('iframe');
8732 el.frameBorder = 'no';
8733 el.className = 'roo-shim';
8734 if(Roo.isIE && Roo.isSecure){
8735 el.src = Roo.SSL_SECURE_URL;
8737 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
8738 shim.autoBoxAdjust = false;
8743 * Removes this element from the DOM and deletes it from the cache
8745 remove : function(){
8746 if(this.dom.parentNode){
8747 this.dom.parentNode.removeChild(this.dom);
8749 delete El.cache[this.dom.id];
8753 * Sets up event handlers to add and remove a css class when the mouse is over this element
8754 * @param {String} className
8755 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
8756 * mouseout events for children elements
8757 * @return {Roo.Element} this
8759 addClassOnOver : function(className, preventFlicker){
8760 this.on("mouseover", function(){
8761 Roo.fly(this, '_internal').addClass(className);
8763 var removeFn = function(e){
8764 if(preventFlicker !== true || !e.within(this, true)){
8765 Roo.fly(this, '_internal').removeClass(className);
8768 this.on("mouseout", removeFn, this.dom);
8773 * Sets up event handlers to add and remove a css class when this element has the focus
8774 * @param {String} className
8775 * @return {Roo.Element} this
8777 addClassOnFocus : function(className){
8778 this.on("focus", function(){
8779 Roo.fly(this, '_internal').addClass(className);
8781 this.on("blur", function(){
8782 Roo.fly(this, '_internal').removeClass(className);
8787 * 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)
8788 * @param {String} className
8789 * @return {Roo.Element} this
8791 addClassOnClick : function(className){
8793 this.on("mousedown", function(){
8794 Roo.fly(dom, '_internal').addClass(className);
8795 var d = Roo.get(document);
8796 var fn = function(){
8797 Roo.fly(dom, '_internal').removeClass(className);
8798 d.removeListener("mouseup", fn);
8800 d.on("mouseup", fn);
8806 * Stops the specified event from bubbling and optionally prevents the default action
8807 * @param {String} eventName
8808 * @param {Boolean} preventDefault (optional) true to prevent the default action too
8809 * @return {Roo.Element} this
8811 swallowEvent : function(eventName, preventDefault){
8812 var fn = function(e){
8813 e.stopPropagation();
8818 if(eventName instanceof Array){
8819 for(var i = 0, len = eventName.length; i < len; i++){
8820 this.on(eventName[i], fn);
8824 this.on(eventName, fn);
8831 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
8834 * Sizes this element to its parent element's dimensions performing
8835 * neccessary box adjustments.
8836 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
8837 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
8838 * @return {Roo.Element} this
8840 fitToParent : function(monitorResize, targetParent) {
8841 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
8842 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
8843 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
8846 var p = Roo.get(targetParent || this.dom.parentNode);
8847 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
8848 if (monitorResize === true) {
8849 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
8850 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
8856 * Gets the next sibling, skipping text nodes
8857 * @return {HTMLElement} The next sibling or null
8859 getNextSibling : function(){
8860 var n = this.dom.nextSibling;
8861 while(n && n.nodeType != 1){
8868 * Gets the previous sibling, skipping text nodes
8869 * @return {HTMLElement} The previous sibling or null
8871 getPrevSibling : function(){
8872 var n = this.dom.previousSibling;
8873 while(n && n.nodeType != 1){
8874 n = n.previousSibling;
8881 * Appends the passed element(s) to this element
8882 * @param {String/HTMLElement/Array/Element/CompositeElement} el
8883 * @return {Roo.Element} this
8885 appendChild: function(el){
8892 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
8893 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
8894 * automatically generated with the specified attributes.
8895 * @param {HTMLElement} insertBefore (optional) a child element of this element
8896 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
8897 * @return {Roo.Element} The new child element
8899 createChild: function(config, insertBefore, returnDom){
8900 config = config || {tag:'div'};
8902 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
8904 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
8908 * Appends this element to the passed element
8909 * @param {String/HTMLElement/Element} el The new parent element
8910 * @return {Roo.Element} this
8912 appendTo: function(el){
8913 el = Roo.getDom(el);
8914 el.appendChild(this.dom);
8919 * Inserts this element before the passed element in the DOM
8920 * @param {String/HTMLElement/Element} el The element to insert before
8921 * @return {Roo.Element} this
8923 insertBefore: function(el){
8924 el = Roo.getDom(el);
8925 el.parentNode.insertBefore(this.dom, el);
8930 * Inserts this element after the passed element in the DOM
8931 * @param {String/HTMLElement/Element} el The element to insert after
8932 * @return {Roo.Element} this
8934 insertAfter: function(el){
8935 el = Roo.getDom(el);
8936 el.parentNode.insertBefore(this.dom, el.nextSibling);
8941 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
8942 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
8943 * @return {Roo.Element} The new child
8945 insertFirst: function(el, returnDom){
8947 if(typeof el == 'object' && !el.nodeType){ // dh config
8948 return this.createChild(el, this.dom.firstChild, returnDom);
8950 el = Roo.getDom(el);
8951 this.dom.insertBefore(el, this.dom.firstChild);
8952 return !returnDom ? Roo.get(el) : el;
8957 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
8958 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
8959 * @param {String} where (optional) 'before' or 'after' defaults to before
8960 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
8961 * @return {Roo.Element} the inserted Element
8963 insertSibling: function(el, where, returnDom){
8964 where = where ? where.toLowerCase() : 'before';
8966 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
8968 if(typeof el == 'object' && !el.nodeType){ // dh config
8969 if(where == 'after' && !this.dom.nextSibling){
8970 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
8972 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
8976 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
8977 where == 'before' ? this.dom : this.dom.nextSibling);
8986 * Creates and wraps this element with another element
8987 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
8988 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
8989 * @return {HTMLElement/Element} The newly created wrapper element
8991 wrap: function(config, returnDom){
8993 config = {tag: "div"};
8995 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
8996 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9001 * Replaces the passed element with this element
9002 * @param {String/HTMLElement/Element} el The element to replace
9003 * @return {Roo.Element} this
9005 replace: function(el){
9007 this.insertBefore(el);
9013 * Inserts an html fragment into this element
9014 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9015 * @param {String} html The HTML fragment
9016 * @param {Boolean} returnEl True to return an Roo.Element
9017 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9019 insertHtml : function(where, html, returnEl){
9020 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9021 return returnEl ? Roo.get(el) : el;
9025 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9026 * @param {Object} o The object with the attributes
9027 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9028 * @return {Roo.Element} this
9030 set : function(o, useSet){
9032 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9034 if(attr == "style" || typeof o[attr] == "function") continue;
9036 el.className = o["cls"];
9038 if(useSet) el.setAttribute(attr, o[attr]);
9039 else el[attr] = o[attr];
9043 Roo.DomHelper.applyStyles(el, o.style);
9049 * Convenience method for constructing a KeyMap
9050 * @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:
9051 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9052 * @param {Function} fn The function to call
9053 * @param {Object} scope (optional) The scope of the function
9054 * @return {Roo.KeyMap} The KeyMap created
9056 addKeyListener : function(key, fn, scope){
9058 if(typeof key != "object" || key instanceof Array){
9074 return new Roo.KeyMap(this, config);
9078 * Creates a KeyMap for this element
9079 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9080 * @return {Roo.KeyMap} The KeyMap created
9082 addKeyMap : function(config){
9083 return new Roo.KeyMap(this, config);
9087 * Returns true if this element is scrollable.
9090 isScrollable : function(){
9092 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9096 * 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().
9097 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9098 * @param {Number} value The new scroll value
9099 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9100 * @return {Element} this
9103 scrollTo : function(side, value, animate){
9104 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9106 this.dom[prop] = value;
9108 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9109 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9115 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9116 * within this element's scrollable range.
9117 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9118 * @param {Number} distance How far to scroll the element in pixels
9119 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9120 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9121 * was scrolled as far as it could go.
9123 scroll : function(direction, distance, animate){
9124 if(!this.isScrollable()){
9128 var l = el.scrollLeft, t = el.scrollTop;
9129 var w = el.scrollWidth, h = el.scrollHeight;
9130 var cw = el.clientWidth, ch = el.clientHeight;
9131 direction = direction.toLowerCase();
9132 var scrolled = false;
9133 var a = this.preanim(arguments, 2);
9138 var v = Math.min(l + distance, w-cw);
9139 this.scrollTo("left", v, a);
9146 var v = Math.max(l - distance, 0);
9147 this.scrollTo("left", v, a);
9155 var v = Math.max(t - distance, 0);
9156 this.scrollTo("top", v, a);
9164 var v = Math.min(t + distance, h-ch);
9165 this.scrollTo("top", v, a);
9174 * Translates the passed page coordinates into left/top css values for this element
9175 * @param {Number/Array} x The page x or an array containing [x, y]
9176 * @param {Number} y The page y
9177 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9179 translatePoints : function(x, y){
9180 if(typeof x == 'object' || x instanceof Array){
9183 var p = this.getStyle('position');
9184 var o = this.getXY();
9186 var l = parseInt(this.getStyle('left'), 10);
9187 var t = parseInt(this.getStyle('top'), 10);
9190 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9193 t = (p == "relative") ? 0 : this.dom.offsetTop;
9196 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9200 * Returns the current scroll position of the element.
9201 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9203 getScroll : function(){
9204 var d = this.dom, doc = document;
9205 if(d == doc || d == doc.body){
9206 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9207 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9208 return {left: l, top: t};
9210 return {left: d.scrollLeft, top: d.scrollTop};
9215 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9216 * are convert to standard 6 digit hex color.
9217 * @param {String} attr The css attribute
9218 * @param {String} defaultValue The default value to use when a valid color isn't found
9219 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9222 getColor : function(attr, defaultValue, prefix){
9223 var v = this.getStyle(attr);
9224 if(!v || v == "transparent" || v == "inherit") {
9225 return defaultValue;
9227 var color = typeof prefix == "undefined" ? "#" : prefix;
9228 if(v.substr(0, 4) == "rgb("){
9229 var rvs = v.slice(4, v.length -1).split(",");
9230 for(var i = 0; i < 3; i++){
9231 var h = parseInt(rvs[i]).toString(16);
9238 if(v.substr(0, 1) == "#"){
9240 for(var i = 1; i < 4; i++){
9241 var c = v.charAt(i);
9244 }else if(v.length == 7){
9245 color += v.substr(1);
9249 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9253 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9254 * gradient background, rounded corners and a 4-way shadow.
9255 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9256 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9257 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9258 * @return {Roo.Element} this
9260 boxWrap : function(cls){
9261 cls = cls || 'x-box';
9262 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9263 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9268 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9269 * @param {String} namespace The namespace in which to look for the attribute
9270 * @param {String} name The attribute name
9271 * @return {String} The attribute value
9273 getAttributeNS : Roo.isIE ? function(ns, name){
9275 var type = typeof d[ns+":"+name];
9276 if(type != 'undefined' && type != 'unknown'){
9277 return d[ns+":"+name];
9280 } : function(ns, name){
9282 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9286 var ep = El.prototype;
9289 * Appends an event handler (Shorthand for addListener)
9290 * @param {String} eventName The type of event to append
9291 * @param {Function} fn The method the event invokes
9292 * @param {Object} scope (optional) The scope (this object) of the fn
9293 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9296 ep.on = ep.addListener;
9298 ep.mon = ep.addListener;
9301 * Removes an event handler from this element (shorthand for removeListener)
9302 * @param {String} eventName the type of event to remove
9303 * @param {Function} fn the method the event invokes
9304 * @return {Roo.Element} this
9307 ep.un = ep.removeListener;
9310 * true to automatically adjust width and height settings for box-model issues (default to true)
9312 ep.autoBoxAdjust = true;
9315 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9318 El.addUnits = function(v, defaultUnit){
9319 if(v === "" || v == "auto"){
9322 if(v === undefined){
9325 if(typeof v == "number" || !El.unitPattern.test(v)){
9326 return v + (defaultUnit || 'px');
9331 // special markup used throughout Roo when box wrapping elements
9332 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>';
9334 * Visibility mode constant - Use visibility to hide element
9340 * Visibility mode constant - Use display to hide element
9346 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9347 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9348 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9360 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9361 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9362 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9363 * @return {Element} The Element object
9366 El.get = function(el){
9368 if(!el){ return null; }
9369 if(typeof el == "string"){ // element id
9370 if(!(elm = document.getElementById(el))){
9373 if(ex = El.cache[el]){
9376 ex = El.cache[el] = new El(elm);
9379 }else if(el.tagName){ // dom element
9383 if(ex = El.cache[id]){
9386 ex = El.cache[id] = new El(el);
9389 }else if(el instanceof El){
9391 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9392 // catch case where it hasn't been appended
9393 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9396 }else if(el.isComposite){
9398 }else if(el instanceof Array){
9399 return El.select(el);
9400 }else if(el == document){
9401 // create a bogus element object representing the document object
9403 var f = function(){};
9404 f.prototype = El.prototype;
9406 docEl.dom = document;
9414 El.uncache = function(el){
9415 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9417 delete El.cache[a[i].id || a[i]];
9423 // Garbage collection - uncache elements/purge listeners on orphaned elements
9424 // so we don't hold a reference and cause the browser to retain them
9425 El.garbageCollect = function(){
9426 if(!Roo.enableGarbageCollector){
9427 clearInterval(El.collectorThread);
9430 for(var eid in El.cache){
9431 var el = El.cache[eid], d = el.dom;
9432 // -------------------------------------------------------
9433 // Determining what is garbage:
9434 // -------------------------------------------------------
9436 // dom node is null, definitely garbage
9437 // -------------------------------------------------------
9439 // no parentNode == direct orphan, definitely garbage
9440 // -------------------------------------------------------
9441 // !d.offsetParent && !document.getElementById(eid)
9442 // display none elements have no offsetParent so we will
9443 // also try to look it up by it's id. However, check
9444 // offsetParent first so we don't do unneeded lookups.
9445 // This enables collection of elements that are not orphans
9446 // directly, but somewhere up the line they have an orphan
9448 // -------------------------------------------------------
9449 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9450 delete El.cache[eid];
9451 if(d && Roo.enableListenerCollection){
9457 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9461 El.Flyweight = function(dom){
9464 El.Flyweight.prototype = El.prototype;
9466 El._flyweights = {};
9468 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9469 * the dom node can be overwritten by other code.
9470 * @param {String/HTMLElement} el The dom node or id
9471 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9472 * prevent conflicts (e.g. internally Roo uses "_internal")
9474 * @return {Element} The shared Element object
9476 El.fly = function(el, named){
9477 named = named || '_global';
9478 el = Roo.getDom(el);
9482 if(!El._flyweights[named]){
9483 El._flyweights[named] = new El.Flyweight();
9485 El._flyweights[named].dom = el;
9486 return El._flyweights[named];
9490 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9491 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9492 * Shorthand of {@link Roo.Element#get}
9493 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9494 * @return {Element} The Element object
9500 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9501 * the dom node can be overwritten by other code.
9502 * Shorthand of {@link Roo.Element#fly}
9503 * @param {String/HTMLElement} el The dom node or id
9504 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9505 * prevent conflicts (e.g. internally Roo uses "_internal")
9507 * @return {Element} The shared Element object
9513 // speedy lookup for elements never to box adjust
9514 var noBoxAdjust = Roo.isStrict ? {
9517 input:1, select:1, textarea:1
9519 if(Roo.isIE || Roo.isGecko){
9520 noBoxAdjust['button'] = 1;
9524 Roo.EventManager.on(window, 'unload', function(){
9526 delete El._flyweights;
9534 Roo.Element.selectorFunction = Roo.DomQuery.select;
9537 Roo.Element.select = function(selector, unique, root){
9539 if(typeof selector == "string"){
9540 els = Roo.Element.selectorFunction(selector, root);
9541 }else if(selector.length !== undefined){
9544 throw "Invalid selector";
9546 if(unique === true){
9547 return new Roo.CompositeElement(els);
9549 return new Roo.CompositeElementLite(els);
9553 * Selects elements based on the passed CSS selector to enable working on them as 1.
9554 * @param {String/Array} selector The CSS selector or an array of elements
9555 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9556 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9557 * @return {CompositeElementLite/CompositeElement}
9561 Roo.select = Roo.Element.select;
9578 * Ext JS Library 1.1.1
9579 * Copyright(c) 2006-2007, Ext JS, LLC.
9581 * Originally Released Under LGPL - original licence link has changed is not relivant.
9584 * <script type="text/javascript">
9589 //Notifies Element that fx methods are available
9590 Roo.enableFx = true;
9594 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
9595 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9596 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
9597 * Element effects to work.</p><br/>
9599 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9600 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9601 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9602 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
9603 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9604 * expected results and should be done with care.</p><br/>
9606 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9607 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
9610 ----- -----------------------------
9611 tl The top left corner
9612 t The center of the top edge
9613 tr The top right corner
9614 l The center of the left edge
9615 r The center of the right edge
9616 bl The bottom left corner
9617 b The center of the bottom edge
9618 br The bottom right corner
9620 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9621 * below are common options that can be passed to any Fx method.</b>
9622 * @cfg {Function} callback A function called when the effect is finished
9623 * @cfg {Object} scope The scope of the effect function
9624 * @cfg {String} easing A valid Easing value for the effect
9625 * @cfg {String} afterCls A css class to apply after the effect
9626 * @cfg {Number} duration The length of time (in seconds) that the effect should last
9627 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9628 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
9629 * effects that end with the element being visually hidden, ignored otherwise)
9630 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9631 * a function which returns such a specification that will be applied to the Element after the effect finishes
9632 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9633 * @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
9634 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9638 * Slides the element into view. An anchor point can be optionally passed to set the point of
9639 * origin for the slide effect. This function automatically handles wrapping the element with
9640 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9643 // default: slide the element in from the top
9646 // custom: slide the element in from the right with a 2-second duration
9647 el.slideIn('r', { duration: 2 });
9649 // common config options shown with default values
9655 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9656 * @param {Object} options (optional) Object literal with any of the Fx config options
9657 * @return {Roo.Element} The Element
9659 slideIn : function(anchor, o){
9660 var el = this.getFxEl();
9663 el.queueFx(o, function(){
9665 anchor = anchor || "t";
9667 // fix display to visibility
9670 // restore values after effect
9671 var r = this.getFxRestore();
9672 var b = this.getBox();
9673 // fixed size for slide
9677 var wrap = this.fxWrap(r.pos, o, "hidden");
9679 var st = this.dom.style;
9680 st.visibility = "visible";
9681 st.position = "absolute";
9683 // clear out temp styles after slide and unwrap
9684 var after = function(){
9685 el.fxUnwrap(wrap, r.pos, o);
9687 st.height = r.height;
9690 // time to calc the positions
9691 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
9693 switch(anchor.toLowerCase()){
9695 wrap.setSize(b.width, 0);
9696 st.left = st.bottom = "0";
9700 wrap.setSize(0, b.height);
9701 st.right = st.top = "0";
9705 wrap.setSize(0, b.height);
9707 st.left = st.top = "0";
9708 a = {width: bw, points: pt};
9711 wrap.setSize(b.width, 0);
9712 wrap.setY(b.bottom);
9713 st.left = st.top = "0";
9714 a = {height: bh, points: pt};
9718 st.right = st.bottom = "0";
9719 a = {width: bw, height: bh};
9723 wrap.setY(b.y+b.height);
9724 st.right = st.top = "0";
9725 a = {width: bw, height: bh, points: pt};
9729 wrap.setXY([b.right, b.bottom]);
9730 st.left = st.top = "0";
9731 a = {width: bw, height: bh, points: pt};
9735 wrap.setX(b.x+b.width);
9736 st.left = st.bottom = "0";
9737 a = {width: bw, height: bh, points: pt};
9740 this.dom.style.visibility = "visible";
9743 arguments.callee.anim = wrap.fxanim(a,
9753 * Slides the element out of view. An anchor point can be optionally passed to set the end point
9754 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
9755 * 'hidden') but block elements will still take up space in the document. The element must be removed
9756 * from the DOM using the 'remove' config option if desired. This function automatically handles
9757 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9760 // default: slide the element out to the top
9763 // custom: slide the element out to the right with a 2-second duration
9764 el.slideOut('r', { duration: 2 });
9766 // common config options shown with default values
9774 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9775 * @param {Object} options (optional) Object literal with any of the Fx config options
9776 * @return {Roo.Element} The Element
9778 slideOut : function(anchor, o){
9779 var el = this.getFxEl();
9782 el.queueFx(o, function(){
9784 anchor = anchor || "t";
9786 // restore values after effect
9787 var r = this.getFxRestore();
9789 var b = this.getBox();
9790 // fixed size for slide
9794 var wrap = this.fxWrap(r.pos, o, "visible");
9796 var st = this.dom.style;
9797 st.visibility = "visible";
9798 st.position = "absolute";
9802 var after = function(){
9804 el.setDisplayed(false);
9809 el.fxUnwrap(wrap, r.pos, o);
9812 st.height = r.height;
9817 var a, zero = {to: 0};
9818 switch(anchor.toLowerCase()){
9820 st.left = st.bottom = "0";
9824 st.right = st.top = "0";
9828 st.left = st.top = "0";
9829 a = {width: zero, points: {to:[b.right, b.y]}};
9832 st.left = st.top = "0";
9833 a = {height: zero, points: {to:[b.x, b.bottom]}};
9836 st.right = st.bottom = "0";
9837 a = {width: zero, height: zero};
9840 st.right = st.top = "0";
9841 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
9844 st.left = st.top = "0";
9845 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
9848 st.left = st.bottom = "0";
9849 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
9853 arguments.callee.anim = wrap.fxanim(a,
9863 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
9864 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
9865 * The element must be removed from the DOM using the 'remove' config option if desired.
9871 // common config options shown with default values
9879 * @param {Object} options (optional) Object literal with any of the Fx config options
9880 * @return {Roo.Element} The Element
9883 var el = this.getFxEl();
9886 el.queueFx(o, function(){
9887 this.clearOpacity();
9890 // restore values after effect
9891 var r = this.getFxRestore();
9892 var st = this.dom.style;
9894 var after = function(){
9896 el.setDisplayed(false);
9903 el.setPositioning(r.pos);
9905 st.height = r.height;
9910 var width = this.getWidth();
9911 var height = this.getHeight();
9913 arguments.callee.anim = this.fxanim({
9914 width : {to: this.adjustWidth(width * 2)},
9915 height : {to: this.adjustHeight(height * 2)},
9916 points : {by: [-(width * .5), -(height * .5)]},
9918 fontSize: {to:200, unit: "%"}
9929 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
9930 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
9931 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
9937 // all config options shown with default values
9945 * @param {Object} options (optional) Object literal with any of the Fx config options
9946 * @return {Roo.Element} The Element
9948 switchOff : function(o){
9949 var el = this.getFxEl();
9952 el.queueFx(o, function(){
9953 this.clearOpacity();
9956 // restore values after effect
9957 var r = this.getFxRestore();
9958 var st = this.dom.style;
9960 var after = function(){
9962 el.setDisplayed(false);
9968 el.setPositioning(r.pos);
9970 st.height = r.height;
9975 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
9976 this.clearOpacity();
9980 points:{by:[0, this.getHeight() * .5]}
9981 }, o, 'motion', 0.3, 'easeIn', after);
9982 }).defer(100, this);
9989 * Highlights the Element by setting a color (applies to the background-color by default, but can be
9990 * changed using the "attr" config option) and then fading back to the original color. If no original
9991 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
9994 // default: highlight background to yellow
9997 // custom: highlight foreground text to blue for 2 seconds
9998 el.highlight("0000ff", { attr: 'color', duration: 2 });
10000 // common config options shown with default values
10001 el.highlight("ffff9c", {
10002 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10003 endColor: (current color) or "ffffff",
10008 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10009 * @param {Object} options (optional) Object literal with any of the Fx config options
10010 * @return {Roo.Element} The Element
10012 highlight : function(color, o){
10013 var el = this.getFxEl();
10016 el.queueFx(o, function(){
10017 color = color || "ffff9c";
10018 attr = o.attr || "backgroundColor";
10020 this.clearOpacity();
10023 var origColor = this.getColor(attr);
10024 var restoreColor = this.dom.style[attr];
10025 endColor = (o.endColor || origColor) || "ffffff";
10027 var after = function(){
10028 el.dom.style[attr] = restoreColor;
10033 a[attr] = {from: color, to: endColor};
10034 arguments.callee.anim = this.fxanim(a,
10044 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10047 // default: a single light blue ripple
10050 // custom: 3 red ripples lasting 3 seconds total
10051 el.frame("ff0000", 3, { duration: 3 });
10053 // common config options shown with default values
10054 el.frame("C3DAF9", 1, {
10055 duration: 1 //duration of entire animation (not each individual ripple)
10056 // Note: Easing is not configurable and will be ignored if included
10059 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10060 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10061 * @param {Object} options (optional) Object literal with any of the Fx config options
10062 * @return {Roo.Element} The Element
10064 frame : function(color, count, o){
10065 var el = this.getFxEl();
10068 el.queueFx(o, function(){
10069 color = color || "#C3DAF9";
10070 if(color.length == 6){
10071 color = "#" + color;
10073 count = count || 1;
10074 duration = o.duration || 1;
10077 var b = this.getBox();
10078 var animFn = function(){
10079 var proxy = this.createProxy({
10082 visbility:"hidden",
10083 position:"absolute",
10084 "z-index":"35000", // yee haw
10085 border:"0px solid " + color
10088 var scale = Roo.isBorderBox ? 2 : 1;
10090 top:{from:b.y, to:b.y - 20},
10091 left:{from:b.x, to:b.x - 20},
10092 borderWidth:{from:0, to:10},
10093 opacity:{from:1, to:0},
10094 height:{from:b.height, to:(b.height + (20*scale))},
10095 width:{from:b.width, to:(b.width + (20*scale))}
10096 }, duration, function(){
10100 animFn.defer((duration/2)*1000, this);
10111 * Creates a pause before any subsequent queued effects begin. If there are
10112 * no effects queued after the pause it will have no effect.
10117 * @param {Number} seconds The length of time to pause (in seconds)
10118 * @return {Roo.Element} The Element
10120 pause : function(seconds){
10121 var el = this.getFxEl();
10124 el.queueFx(o, function(){
10125 setTimeout(function(){
10127 }, seconds * 1000);
10133 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10134 * using the "endOpacity" config option.
10137 // default: fade in from opacity 0 to 100%
10140 // custom: fade in from opacity 0 to 75% over 2 seconds
10141 el.fadeIn({ endOpacity: .75, duration: 2});
10143 // common config options shown with default values
10145 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10150 * @param {Object} options (optional) Object literal with any of the Fx config options
10151 * @return {Roo.Element} The Element
10153 fadeIn : function(o){
10154 var el = this.getFxEl();
10156 el.queueFx(o, function(){
10157 this.setOpacity(0);
10159 this.dom.style.visibility = 'visible';
10160 var to = o.endOpacity || 1;
10161 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10162 o, null, .5, "easeOut", function(){
10164 this.clearOpacity();
10173 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10174 * using the "endOpacity" config option.
10177 // default: fade out from the element's current opacity to 0
10180 // custom: fade out from the element's current opacity to 25% over 2 seconds
10181 el.fadeOut({ endOpacity: .25, duration: 2});
10183 // common config options shown with default values
10185 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10192 * @param {Object} options (optional) Object literal with any of the Fx config options
10193 * @return {Roo.Element} The Element
10195 fadeOut : function(o){
10196 var el = this.getFxEl();
10198 el.queueFx(o, function(){
10199 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10200 o, null, .5, "easeOut", function(){
10201 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10202 this.dom.style.display = "none";
10204 this.dom.style.visibility = "hidden";
10206 this.clearOpacity();
10214 * Animates the transition of an element's dimensions from a starting height/width
10215 * to an ending height/width.
10218 // change height and width to 100x100 pixels
10219 el.scale(100, 100);
10221 // common config options shown with default values. The height and width will default to
10222 // the element's existing values if passed as null.
10225 [element's height], {
10230 * @param {Number} width The new width (pass undefined to keep the original width)
10231 * @param {Number} height The new height (pass undefined to keep the original height)
10232 * @param {Object} options (optional) Object literal with any of the Fx config options
10233 * @return {Roo.Element} The Element
10235 scale : function(w, h, o){
10236 this.shift(Roo.apply({}, o, {
10244 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10245 * Any of these properties not specified in the config object will not be changed. This effect
10246 * requires that at least one new dimension, position or opacity setting must be passed in on
10247 * the config object in order for the function to have any effect.
10250 // slide the element horizontally to x position 200 while changing the height and opacity
10251 el.shift({ x: 200, height: 50, opacity: .8 });
10253 // common config options shown with default values.
10255 width: [element's width],
10256 height: [element's height],
10257 x: [element's x position],
10258 y: [element's y position],
10259 opacity: [element's opacity],
10264 * @param {Object} options Object literal with any of the Fx config options
10265 * @return {Roo.Element} The Element
10267 shift : function(o){
10268 var el = this.getFxEl();
10270 el.queueFx(o, function(){
10271 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10272 if(w !== undefined){
10273 a.width = {to: this.adjustWidth(w)};
10275 if(h !== undefined){
10276 a.height = {to: this.adjustHeight(h)};
10278 if(x !== undefined || y !== undefined){
10280 x !== undefined ? x : this.getX(),
10281 y !== undefined ? y : this.getY()
10284 if(op !== undefined){
10285 a.opacity = {to: op};
10287 if(o.xy !== undefined){
10288 a.points = {to: o.xy};
10290 arguments.callee.anim = this.fxanim(a,
10291 o, 'motion', .35, "easeOut", function(){
10299 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10300 * ending point of the effect.
10303 // default: slide the element downward while fading out
10306 // custom: slide the element out to the right with a 2-second duration
10307 el.ghost('r', { duration: 2 });
10309 // common config options shown with default values
10317 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10318 * @param {Object} options (optional) Object literal with any of the Fx config options
10319 * @return {Roo.Element} The Element
10321 ghost : function(anchor, o){
10322 var el = this.getFxEl();
10325 el.queueFx(o, function(){
10326 anchor = anchor || "b";
10328 // restore values after effect
10329 var r = this.getFxRestore();
10330 var w = this.getWidth(),
10331 h = this.getHeight();
10333 var st = this.dom.style;
10335 var after = function(){
10337 el.setDisplayed(false);
10343 el.setPositioning(r.pos);
10344 st.width = r.width;
10345 st.height = r.height;
10350 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10351 switch(anchor.toLowerCase()){
10378 arguments.callee.anim = this.fxanim(a,
10388 * Ensures that all effects queued after syncFx is called on the element are
10389 * run concurrently. This is the opposite of {@link #sequenceFx}.
10390 * @return {Roo.Element} The Element
10392 syncFx : function(){
10393 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10402 * Ensures that all effects queued after sequenceFx is called on the element are
10403 * run in sequence. This is the opposite of {@link #syncFx}.
10404 * @return {Roo.Element} The Element
10406 sequenceFx : function(){
10407 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10409 concurrent : false,
10416 nextFx : function(){
10417 var ef = this.fxQueue[0];
10424 * Returns true if the element has any effects actively running or queued, else returns false.
10425 * @return {Boolean} True if element has active effects, else false
10427 hasActiveFx : function(){
10428 return this.fxQueue && this.fxQueue[0];
10432 * Stops any running effects and clears the element's internal effects queue if it contains
10433 * any additional effects that haven't started yet.
10434 * @return {Roo.Element} The Element
10436 stopFx : function(){
10437 if(this.hasActiveFx()){
10438 var cur = this.fxQueue[0];
10439 if(cur && cur.anim && cur.anim.isAnimated()){
10440 this.fxQueue = [cur]; // clear out others
10441 cur.anim.stop(true);
10448 beforeFx : function(o){
10449 if(this.hasActiveFx() && !o.concurrent){
10460 * Returns true if the element is currently blocking so that no other effect can be queued
10461 * until this effect is finished, else returns false if blocking is not set. This is commonly
10462 * used to ensure that an effect initiated by a user action runs to completion prior to the
10463 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10464 * @return {Boolean} True if blocking, else false
10466 hasFxBlock : function(){
10467 var q = this.fxQueue;
10468 return q && q[0] && q[0].block;
10472 queueFx : function(o, fn){
10476 if(!this.hasFxBlock()){
10477 Roo.applyIf(o, this.fxDefaults);
10479 var run = this.beforeFx(o);
10480 fn.block = o.block;
10481 this.fxQueue.push(fn);
10493 fxWrap : function(pos, o, vis){
10495 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10498 wrapXY = this.getXY();
10500 var div = document.createElement("div");
10501 div.style.visibility = vis;
10502 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10503 wrap.setPositioning(pos);
10504 if(wrap.getStyle("position") == "static"){
10505 wrap.position("relative");
10507 this.clearPositioning('auto');
10509 wrap.dom.appendChild(this.dom);
10511 wrap.setXY(wrapXY);
10518 fxUnwrap : function(wrap, pos, o){
10519 this.clearPositioning();
10520 this.setPositioning(pos);
10522 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10528 getFxRestore : function(){
10529 var st = this.dom.style;
10530 return {pos: this.getPositioning(), width: st.width, height : st.height};
10534 afterFx : function(o){
10536 this.applyStyles(o.afterStyle);
10539 this.addClass(o.afterCls);
10541 if(o.remove === true){
10544 Roo.callback(o.callback, o.scope, [this]);
10546 this.fxQueue.shift();
10552 getFxEl : function(){ // support for composite element fx
10553 return Roo.get(this.dom);
10557 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10558 animType = animType || 'run';
10560 var anim = Roo.lib.Anim[animType](
10562 (opt.duration || defaultDur) || .35,
10563 (opt.easing || defaultEase) || 'easeOut',
10565 Roo.callback(cb, this);
10574 // backwords compat
10575 Roo.Fx.resize = Roo.Fx.scale;
10577 //When included, Roo.Fx is automatically applied to Element so that all basic
10578 //effects are available directly via the Element API
10579 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10581 * Ext JS Library 1.1.1
10582 * Copyright(c) 2006-2007, Ext JS, LLC.
10584 * Originally Released Under LGPL - original licence link has changed is not relivant.
10587 * <script type="text/javascript">
10592 * @class Roo.CompositeElement
10593 * Standard composite class. Creates a Roo.Element for every element in the collection.
10595 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10596 * actions will be performed on all the elements in this collection.</b>
10598 * All methods return <i>this</i> and can be chained.
10600 var els = Roo.select("#some-el div.some-class", true);
10601 // or select directly from an existing element
10602 var el = Roo.get('some-el');
10603 el.select('div.some-class', true);
10605 els.setWidth(100); // all elements become 100 width
10606 els.hide(true); // all elements fade out and hide
10608 els.setWidth(100).hide(true);
10611 Roo.CompositeElement = function(els){
10612 this.elements = [];
10613 this.addElements(els);
10615 Roo.CompositeElement.prototype = {
10617 addElements : function(els){
10618 if(!els) return this;
10619 if(typeof els == "string"){
10620 els = Roo.Element.selectorFunction(els);
10622 var yels = this.elements;
10623 var index = yels.length-1;
10624 for(var i = 0, len = els.length; i < len; i++) {
10625 yels[++index] = Roo.get(els[i]);
10631 * Clears this composite and adds the elements returned by the passed selector.
10632 * @param {String/Array} els A string CSS selector, an array of elements or an element
10633 * @return {CompositeElement} this
10635 fill : function(els){
10636 this.elements = [];
10642 * Filters this composite to only elements that match the passed selector.
10643 * @param {String} selector A string CSS selector
10644 * @return {CompositeElement} this
10646 filter : function(selector){
10648 this.each(function(el){
10649 if(el.is(selector)){
10650 els[els.length] = el.dom;
10657 invoke : function(fn, args){
10658 var els = this.elements;
10659 for(var i = 0, len = els.length; i < len; i++) {
10660 Roo.Element.prototype[fn].apply(els[i], args);
10665 * Adds elements to this composite.
10666 * @param {String/Array} els A string CSS selector, an array of elements or an element
10667 * @return {CompositeElement} this
10669 add : function(els){
10670 if(typeof els == "string"){
10671 this.addElements(Roo.Element.selectorFunction(els));
10672 }else if(els.length !== undefined){
10673 this.addElements(els);
10675 this.addElements([els]);
10680 * Calls the passed function passing (el, this, index) for each element in this composite.
10681 * @param {Function} fn The function to call
10682 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10683 * @return {CompositeElement} this
10685 each : function(fn, scope){
10686 var els = this.elements;
10687 for(var i = 0, len = els.length; i < len; i++){
10688 if(fn.call(scope || els[i], els[i], this, i) === false) {
10696 * Returns the Element object at the specified index
10697 * @param {Number} index
10698 * @return {Roo.Element}
10700 item : function(index){
10701 return this.elements[index] || null;
10705 * Returns the first Element
10706 * @return {Roo.Element}
10708 first : function(){
10709 return this.item(0);
10713 * Returns the last Element
10714 * @return {Roo.Element}
10717 return this.item(this.elements.length-1);
10721 * Returns the number of elements in this composite
10724 getCount : function(){
10725 return this.elements.length;
10729 * Returns true if this composite contains the passed element
10732 contains : function(el){
10733 return this.indexOf(el) !== -1;
10737 * Returns true if this composite contains the passed element
10740 indexOf : function(el){
10741 return this.elements.indexOf(Roo.get(el));
10746 * Removes the specified element(s).
10747 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
10748 * or an array of any of those.
10749 * @param {Boolean} removeDom (optional) True to also remove the element from the document
10750 * @return {CompositeElement} this
10752 removeElement : function(el, removeDom){
10753 if(el instanceof Array){
10754 for(var i = 0, len = el.length; i < len; i++){
10755 this.removeElement(el[i]);
10759 var index = typeof el == 'number' ? el : this.indexOf(el);
10762 var d = this.elements[index];
10766 d.parentNode.removeChild(d);
10769 this.elements.splice(index, 1);
10775 * Replaces the specified element with the passed element.
10776 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
10778 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
10779 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
10780 * @return {CompositeElement} this
10782 replaceElement : function(el, replacement, domReplace){
10783 var index = typeof el == 'number' ? el : this.indexOf(el);
10786 this.elements[index].replaceWith(replacement);
10788 this.elements.splice(index, 1, Roo.get(replacement))
10795 * Removes all elements.
10797 clear : function(){
10798 this.elements = [];
10802 Roo.CompositeElement.createCall = function(proto, fnName){
10803 if(!proto[fnName]){
10804 proto[fnName] = function(){
10805 return this.invoke(fnName, arguments);
10809 for(var fnName in Roo.Element.prototype){
10810 if(typeof Roo.Element.prototype[fnName] == "function"){
10811 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
10817 * Ext JS Library 1.1.1
10818 * Copyright(c) 2006-2007, Ext JS, LLC.
10820 * Originally Released Under LGPL - original licence link has changed is not relivant.
10823 * <script type="text/javascript">
10827 * @class Roo.CompositeElementLite
10828 * @extends Roo.CompositeElement
10829 * Flyweight composite class. Reuses the same Roo.Element for element operations.
10831 var els = Roo.select("#some-el div.some-class");
10832 // or select directly from an existing element
10833 var el = Roo.get('some-el');
10834 el.select('div.some-class');
10836 els.setWidth(100); // all elements become 100 width
10837 els.hide(true); // all elements fade out and hide
10839 els.setWidth(100).hide(true);
10840 </code></pre><br><br>
10841 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10842 * actions will be performed on all the elements in this collection.</b>
10844 Roo.CompositeElementLite = function(els){
10845 Roo.CompositeElementLite.superclass.constructor.call(this, els);
10846 this.el = new Roo.Element.Flyweight();
10848 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
10849 addElements : function(els){
10851 if(els instanceof Array){
10852 this.elements = this.elements.concat(els);
10854 var yels = this.elements;
10855 var index = yels.length-1;
10856 for(var i = 0, len = els.length; i < len; i++) {
10857 yels[++index] = els[i];
10863 invoke : function(fn, args){
10864 var els = this.elements;
10866 for(var i = 0, len = els.length; i < len; i++) {
10868 Roo.Element.prototype[fn].apply(el, args);
10873 * Returns a flyweight Element of the dom element object at the specified index
10874 * @param {Number} index
10875 * @return {Roo.Element}
10877 item : function(index){
10878 if(!this.elements[index]){
10881 this.el.dom = this.elements[index];
10885 // fixes scope with flyweight
10886 addListener : function(eventName, handler, scope, opt){
10887 var els = this.elements;
10888 for(var i = 0, len = els.length; i < len; i++) {
10889 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
10895 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
10896 * passed is the flyweight (shared) Roo.Element instance, so if you require a
10897 * a reference to the dom node, use el.dom.</b>
10898 * @param {Function} fn The function to call
10899 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10900 * @return {CompositeElement} this
10902 each : function(fn, scope){
10903 var els = this.elements;
10905 for(var i = 0, len = els.length; i < len; i++){
10907 if(fn.call(scope || el, el, this, i) === false){
10914 indexOf : function(el){
10915 return this.elements.indexOf(Roo.getDom(el));
10918 replaceElement : function(el, replacement, domReplace){
10919 var index = typeof el == 'number' ? el : this.indexOf(el);
10921 replacement = Roo.getDom(replacement);
10923 var d = this.elements[index];
10924 d.parentNode.insertBefore(replacement, d);
10925 d.parentNode.removeChild(d);
10927 this.elements.splice(index, 1, replacement);
10932 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
10936 * Ext JS Library 1.1.1
10937 * Copyright(c) 2006-2007, Ext JS, LLC.
10939 * Originally Released Under LGPL - original licence link has changed is not relivant.
10942 * <script type="text/javascript">
10948 * @class Roo.data.Connection
10949 * @extends Roo.util.Observable
10950 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
10951 * either to a configured URL, or to a URL specified at request time.<br><br>
10953 * Requests made by this class are asynchronous, and will return immediately. No data from
10954 * the server will be available to the statement immediately following the {@link #request} call.
10955 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
10957 * Note: If you are doing a file upload, you will not get a normal response object sent back to
10958 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
10959 * The response object is created using the innerHTML of the IFRAME's document as the responseText
10960 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
10961 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
10962 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
10963 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
10964 * standard DOM methods.
10966 * @param {Object} config a configuration object.
10968 Roo.data.Connection = function(config){
10969 Roo.apply(this, config);
10972 * @event beforerequest
10973 * Fires before a network request is made to retrieve a data object.
10974 * @param {Connection} conn This Connection object.
10975 * @param {Object} options The options config object passed to the {@link #request} method.
10977 "beforerequest" : true,
10979 * @event requestcomplete
10980 * Fires if the request was successfully completed.
10981 * @param {Connection} conn This Connection object.
10982 * @param {Object} response The XHR object containing the response data.
10983 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
10984 * @param {Object} options The options config object passed to the {@link #request} method.
10986 "requestcomplete" : true,
10988 * @event requestexception
10989 * Fires if an error HTTP status was returned from the server.
10990 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
10991 * @param {Connection} conn This Connection object.
10992 * @param {Object} response The XHR object containing the response data.
10993 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
10994 * @param {Object} options The options config object passed to the {@link #request} method.
10996 "requestexception" : true
10998 Roo.data.Connection.superclass.constructor.call(this);
11001 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11003 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11006 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11007 * extra parameters to each request made by this object. (defaults to undefined)
11010 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11011 * to each request made by this object. (defaults to undefined)
11014 * @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)
11017 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11021 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11027 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11030 disableCaching: true,
11033 * Sends an HTTP request to a remote server.
11034 * @param {Object} options An object which may contain the following properties:<ul>
11035 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11036 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11037 * request, a url encoded string or a function to call to get either.</li>
11038 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11039 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11040 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11041 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11042 * <li>options {Object} The parameter to the request call.</li>
11043 * <li>success {Boolean} True if the request succeeded.</li>
11044 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11046 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11047 * The callback is passed the following parameters:<ul>
11048 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11049 * <li>options {Object} The parameter to the request call.</li>
11051 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11052 * The callback is passed the following parameters:<ul>
11053 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11054 * <li>options {Object} The parameter to the request call.</li>
11056 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11057 * for the callback function. Defaults to the browser window.</li>
11058 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11059 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11060 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11061 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11062 * params for the post data. Any params will be appended to the URL.</li>
11063 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11065 * @return {Number} transactionId
11067 request : function(o){
11068 if(this.fireEvent("beforerequest", this, o) !== false){
11071 if(typeof p == "function"){
11072 p = p.call(o.scope||window, o);
11074 if(typeof p == "object"){
11075 p = Roo.urlEncode(o.params);
11077 if(this.extraParams){
11078 var extras = Roo.urlEncode(this.extraParams);
11079 p = p ? (p + '&' + extras) : extras;
11082 var url = o.url || this.url;
11083 if(typeof url == 'function'){
11084 url = url.call(o.scope||window, o);
11088 var form = Roo.getDom(o.form);
11089 url = url || form.action;
11091 var enctype = form.getAttribute("enctype");
11092 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11093 return this.doFormUpload(o, p, url);
11095 var f = Roo.lib.Ajax.serializeForm(form);
11096 p = p ? (p + '&' + f) : f;
11099 var hs = o.headers;
11100 if(this.defaultHeaders){
11101 hs = Roo.apply(hs || {}, this.defaultHeaders);
11108 success: this.handleResponse,
11109 failure: this.handleFailure,
11111 argument: {options: o},
11112 timeout : this.timeout
11115 var method = o.method||this.method||(p ? "POST" : "GET");
11117 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11118 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11121 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11125 }else if(this.autoAbort !== false){
11129 if((method == 'GET' && p) || o.xmlData){
11130 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11133 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11134 return this.transId;
11136 Roo.callback(o.callback, o.scope, [o, null, null]);
11142 * Determine whether this object has a request outstanding.
11143 * @param {Number} transactionId (Optional) defaults to the last transaction
11144 * @return {Boolean} True if there is an outstanding request.
11146 isLoading : function(transId){
11148 return Roo.lib.Ajax.isCallInProgress(transId);
11150 return this.transId ? true : false;
11155 * Aborts any outstanding request.
11156 * @param {Number} transactionId (Optional) defaults to the last transaction
11158 abort : function(transId){
11159 if(transId || this.isLoading()){
11160 Roo.lib.Ajax.abort(transId || this.transId);
11165 handleResponse : function(response){
11166 this.transId = false;
11167 var options = response.argument.options;
11168 response.argument = options ? options.argument : null;
11169 this.fireEvent("requestcomplete", this, response, options);
11170 Roo.callback(options.success, options.scope, [response, options]);
11171 Roo.callback(options.callback, options.scope, [options, true, response]);
11175 handleFailure : function(response, e){
11176 this.transId = false;
11177 var options = response.argument.options;
11178 response.argument = options ? options.argument : null;
11179 this.fireEvent("requestexception", this, response, options, e);
11180 Roo.callback(options.failure, options.scope, [response, options]);
11181 Roo.callback(options.callback, options.scope, [options, false, response]);
11185 doFormUpload : function(o, ps, url){
11187 var frame = document.createElement('iframe');
11190 frame.className = 'x-hidden';
11192 frame.src = Roo.SSL_SECURE_URL;
11194 document.body.appendChild(frame);
11197 document.frames[id].name = id;
11200 var form = Roo.getDom(o.form);
11202 form.method = 'POST';
11203 form.enctype = form.encoding = 'multipart/form-data';
11209 if(ps){ // add dynamic params
11211 ps = Roo.urlDecode(ps, false);
11213 if(ps.hasOwnProperty(k)){
11214 hd = document.createElement('input');
11215 hd.type = 'hidden';
11218 form.appendChild(hd);
11225 var r = { // bogus response object
11230 r.argument = o ? o.argument : null;
11235 doc = frame.contentWindow.document;
11237 doc = (frame.contentDocument || window.frames[id].document);
11239 if(doc && doc.body){
11240 r.responseText = doc.body.innerHTML;
11242 if(doc && doc.XMLDocument){
11243 r.responseXML = doc.XMLDocument;
11245 r.responseXML = doc;
11252 Roo.EventManager.removeListener(frame, 'load', cb, this);
11254 this.fireEvent("requestcomplete", this, r, o);
11255 Roo.callback(o.success, o.scope, [r, o]);
11256 Roo.callback(o.callback, o.scope, [o, true, r]);
11258 setTimeout(function(){document.body.removeChild(frame);}, 100);
11261 Roo.EventManager.on(frame, 'load', cb, this);
11264 if(hiddens){ // remove dynamic params
11265 for(var i = 0, len = hiddens.length; i < len; i++){
11266 form.removeChild(hiddens[i]);
11274 * @extends Roo.data.Connection
11275 * Global Ajax request class.
11279 Roo.Ajax = new Roo.data.Connection({
11282 * @cfg {String} url @hide
11285 * @cfg {Object} extraParams @hide
11288 * @cfg {Object} defaultHeaders @hide
11291 * @cfg {String} method (Optional) @hide
11294 * @cfg {Number} timeout (Optional) @hide
11297 * @cfg {Boolean} autoAbort (Optional) @hide
11301 * @cfg {Boolean} disableCaching (Optional) @hide
11305 * @property disableCaching
11306 * True to add a unique cache-buster param to GET requests. (defaults to true)
11311 * The default URL to be used for requests to the server. (defaults to undefined)
11315 * @property extraParams
11316 * An object containing properties which are used as
11317 * extra parameters to each request made by this object. (defaults to undefined)
11321 * @property defaultHeaders
11322 * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11327 * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11331 * @property timeout
11332 * The timeout in milliseconds to be used for requests. (defaults to 30000)
11337 * @property autoAbort
11338 * Whether a new request should abort any pending requests. (defaults to false)
11344 * Serialize the passed form into a url encoded string
11345 * @param {String/HTMLElement} form
11348 serializeForm : function(form){
11349 return Roo.lib.Ajax.serializeForm(form);
11353 * Ext JS Library 1.1.1
11354 * Copyright(c) 2006-2007, Ext JS, LLC.
11356 * Originally Released Under LGPL - original licence link has changed is not relivant.
11359 * <script type="text/javascript">
11364 * @extends Roo.data.Connection
11365 * Global Ajax request class.
11367 * @instanceOf Roo.data.Connection
11369 Roo.Ajax = new Roo.data.Connection({
11378 * @cfg {String} url @hide
11381 * @cfg {Object} extraParams @hide
11384 * @cfg {Object} defaultHeaders @hide
11387 * @cfg {String} method (Optional) @hide
11390 * @cfg {Number} timeout (Optional) @hide
11393 * @cfg {Boolean} autoAbort (Optional) @hide
11397 * @cfg {Boolean} disableCaching (Optional) @hide
11401 * @property disableCaching
11402 * True to add a unique cache-buster param to GET requests. (defaults to true)
11407 * The default URL to be used for requests to the server. (defaults to undefined)
11411 * @property extraParams
11412 * An object containing properties which are used as
11413 * extra parameters to each request made by this object. (defaults to undefined)
11417 * @property defaultHeaders
11418 * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11423 * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11427 * @property timeout
11428 * The timeout in milliseconds to be used for requests. (defaults to 30000)
11433 * @property autoAbort
11434 * Whether a new request should abort any pending requests. (defaults to false)
11440 * Serialize the passed form into a url encoded string
11441 * @param {String/HTMLElement} form
11444 serializeForm : function(form){
11445 return Roo.lib.Ajax.serializeForm(form);
11449 * Ext JS Library 1.1.1
11450 * Copyright(c) 2006-2007, Ext JS, LLC.
11452 * Originally Released Under LGPL - original licence link has changed is not relivant.
11455 * <script type="text/javascript">
11460 * @class Roo.UpdateManager
11461 * @extends Roo.util.Observable
11462 * Provides AJAX-style update for Element object.<br><br>
11465 * // Get it from a Roo.Element object
11466 * var el = Roo.get("foo");
11467 * var mgr = el.getUpdateManager();
11468 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11470 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11472 * // or directly (returns the same UpdateManager instance)
11473 * var mgr = new Roo.UpdateManager("myElementId");
11474 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11475 * mgr.on("update", myFcnNeedsToKnow);
11477 // short handed call directly from the element object
11478 Roo.get("foo").load({
11482 text: "Loading Foo..."
11486 * Create new UpdateManager directly.
11487 * @param {String/HTMLElement/Roo.Element} el The element to update
11488 * @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).
11490 Roo.UpdateManager = function(el, forceNew){
11492 if(!forceNew && el.updateManager){
11493 return el.updateManager;
11496 * The Element object
11497 * @type Roo.Element
11501 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11504 this.defaultUrl = null;
11508 * @event beforeupdate
11509 * Fired before an update is made, return false from your handler and the update is cancelled.
11510 * @param {Roo.Element} el
11511 * @param {String/Object/Function} url
11512 * @param {String/Object} params
11514 "beforeupdate": true,
11517 * Fired after successful update is made.
11518 * @param {Roo.Element} el
11519 * @param {Object} oResponseObject The response Object
11524 * Fired on update failure.
11525 * @param {Roo.Element} el
11526 * @param {Object} oResponseObject The response Object
11530 var d = Roo.UpdateManager.defaults;
11532 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11535 this.sslBlankUrl = d.sslBlankUrl;
11537 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11540 this.disableCaching = d.disableCaching;
11542 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11545 this.indicatorText = d.indicatorText;
11547 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11550 this.showLoadIndicator = d.showLoadIndicator;
11552 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11555 this.timeout = d.timeout;
11558 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11561 this.loadScripts = d.loadScripts;
11564 * Transaction object of current executing transaction
11566 this.transaction = null;
11571 this.autoRefreshProcId = null;
11573 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11576 this.refreshDelegate = this.refresh.createDelegate(this);
11578 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11581 this.updateDelegate = this.update.createDelegate(this);
11583 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11586 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11590 this.successDelegate = this.processSuccess.createDelegate(this);
11594 this.failureDelegate = this.processFailure.createDelegate(this);
11596 if(!this.renderer){
11598 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11600 this.renderer = new Roo.UpdateManager.BasicRenderer();
11603 Roo.UpdateManager.superclass.constructor.call(this);
11606 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11608 * Get the Element this UpdateManager is bound to
11609 * @return {Roo.Element} The element
11611 getEl : function(){
11615 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11616 * @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:
11619 url: "your-url.php",<br/>
11620 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11621 callback: yourFunction,<br/>
11622 scope: yourObject, //(optional scope) <br/>
11623 discardUrl: false, <br/>
11624 nocache: false,<br/>
11625 text: "Loading...",<br/>
11627 scripts: false<br/>
11630 * The only required property is url. The optional properties nocache, text and scripts
11631 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11632 * @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}
11633 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11634 * @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.
11636 update : function(url, params, callback, discardUrl){
11637 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11638 var method = this.method, cfg;
11639 if(typeof url == "object"){ // must be config object
11642 params = params || cfg.params;
11643 callback = callback || cfg.callback;
11644 discardUrl = discardUrl || cfg.discardUrl;
11645 if(callback && cfg.scope){
11646 callback = callback.createDelegate(cfg.scope);
11648 if(typeof cfg.method != "undefined"){method = cfg.method;};
11649 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11650 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11651 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11652 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11654 this.showLoading();
11656 this.defaultUrl = url;
11658 if(typeof url == "function"){
11659 url = url.call(this);
11662 method = method || (params ? "POST" : "GET");
11663 if(method == "GET"){
11664 url = this.prepareUrl(url);
11667 var o = Roo.apply(cfg ||{}, {
11670 success: this.successDelegate,
11671 failure: this.failureDelegate,
11672 callback: undefined,
11673 timeout: (this.timeout*1000),
11674 argument: {"url": url, "form": null, "callback": callback, "params": params}
11677 this.transaction = Roo.Ajax.request(o);
11682 * 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.
11683 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11684 * @param {String/HTMLElement} form The form Id or form element
11685 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11686 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11687 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11689 formUpdate : function(form, url, reset, callback){
11690 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11691 if(typeof url == "function"){
11692 url = url.call(this);
11694 form = Roo.getDom(form);
11695 this.transaction = Roo.Ajax.request({
11698 success: this.successDelegate,
11699 failure: this.failureDelegate,
11700 timeout: (this.timeout*1000),
11701 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11703 this.showLoading.defer(1, this);
11708 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11709 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11711 refresh : function(callback){
11712 if(this.defaultUrl == null){
11715 this.update(this.defaultUrl, null, callback, true);
11719 * Set this element to auto refresh.
11720 * @param {Number} interval How often to update (in seconds).
11721 * @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)
11722 * @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}
11723 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11724 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11726 startAutoRefresh : function(interval, url, params, callback, refreshNow){
11728 this.update(url || this.defaultUrl, params, callback, true);
11730 if(this.autoRefreshProcId){
11731 clearInterval(this.autoRefreshProcId);
11733 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11737 * Stop auto refresh on this element.
11739 stopAutoRefresh : function(){
11740 if(this.autoRefreshProcId){
11741 clearInterval(this.autoRefreshProcId);
11742 delete this.autoRefreshProcId;
11746 isAutoRefreshing : function(){
11747 return this.autoRefreshProcId ? true : false;
11750 * Called to update the element to "Loading" state. Override to perform custom action.
11752 showLoading : function(){
11753 if(this.showLoadIndicator){
11754 this.el.update(this.indicatorText);
11759 * Adds unique parameter to query string if disableCaching = true
11762 prepareUrl : function(url){
11763 if(this.disableCaching){
11764 var append = "_dc=" + (new Date().getTime());
11765 if(url.indexOf("?") !== -1){
11766 url += "&" + append;
11768 url += "?" + append;
11777 processSuccess : function(response){
11778 this.transaction = null;
11779 if(response.argument.form && response.argument.reset){
11780 try{ // put in try/catch since some older FF releases had problems with this
11781 response.argument.form.reset();
11784 if(this.loadScripts){
11785 this.renderer.render(this.el, response, this,
11786 this.updateComplete.createDelegate(this, [response]));
11788 this.renderer.render(this.el, response, this);
11789 this.updateComplete(response);
11793 updateComplete : function(response){
11794 this.fireEvent("update", this.el, response);
11795 if(typeof response.argument.callback == "function"){
11796 response.argument.callback(this.el, true, response);
11803 processFailure : function(response){
11804 this.transaction = null;
11805 this.fireEvent("failure", this.el, response);
11806 if(typeof response.argument.callback == "function"){
11807 response.argument.callback(this.el, false, response);
11812 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
11813 * @param {Object} renderer The object implementing the render() method
11815 setRenderer : function(renderer){
11816 this.renderer = renderer;
11819 getRenderer : function(){
11820 return this.renderer;
11824 * Set the defaultUrl used for updates
11825 * @param {String/Function} defaultUrl The url or a function to call to get the url
11827 setDefaultUrl : function(defaultUrl){
11828 this.defaultUrl = defaultUrl;
11832 * Aborts the executing transaction
11834 abort : function(){
11835 if(this.transaction){
11836 Roo.Ajax.abort(this.transaction);
11841 * Returns true if an update is in progress
11842 * @return {Boolean}
11844 isUpdating : function(){
11845 if(this.transaction){
11846 return Roo.Ajax.isLoading(this.transaction);
11853 * @class Roo.UpdateManager.defaults
11854 * @static (not really - but it helps the doc tool)
11855 * The defaults collection enables customizing the default properties of UpdateManager
11857 Roo.UpdateManager.defaults = {
11859 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
11865 * True to process scripts by default (Defaults to false).
11868 loadScripts : false,
11871 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
11874 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
11876 * Whether to append unique parameter on get request to disable caching (Defaults to false).
11879 disableCaching : false,
11881 * Whether to show indicatorText when loading (Defaults to true).
11884 showLoadIndicator : true,
11886 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
11889 indicatorText : '<div class="loading-indicator">Loading...</div>'
11893 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
11895 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
11896 * @param {String/HTMLElement/Roo.Element} el The element to update
11897 * @param {String} url The url
11898 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
11899 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
11902 * @member Roo.UpdateManager
11904 Roo.UpdateManager.updateElement = function(el, url, params, options){
11905 var um = Roo.get(el, true).getUpdateManager();
11906 Roo.apply(um, options);
11907 um.update(url, params, options ? options.callback : null);
11909 // alias for backwards compat
11910 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
11912 * @class Roo.UpdateManager.BasicRenderer
11913 * Default Content renderer. Updates the elements innerHTML with the responseText.
11915 Roo.UpdateManager.BasicRenderer = function(){};
11917 Roo.UpdateManager.BasicRenderer.prototype = {
11919 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
11920 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
11921 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
11922 * @param {Roo.Element} el The element being rendered
11923 * @param {Object} response The YUI Connect response object
11924 * @param {UpdateManager} updateManager The calling update manager
11925 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
11927 render : function(el, response, updateManager, callback){
11928 el.update(response.responseText, updateManager.loadScripts, callback);
11933 * Ext JS Library 1.1.1
11934 * Copyright(c) 2006-2007, Ext JS, LLC.
11936 * Originally Released Under LGPL - original licence link has changed is not relivant.
11939 * <script type="text/javascript">
11943 * @class Roo.util.DelayedTask
11944 * Provides a convenient method of performing setTimeout where a new
11945 * timeout cancels the old timeout. An example would be performing validation on a keypress.
11946 * You can use this class to buffer
11947 * the keypress events for a certain number of milliseconds, and perform only if they stop
11948 * for that amount of time.
11949 * @constructor The parameters to this constructor serve as defaults and are not required.
11950 * @param {Function} fn (optional) The default function to timeout
11951 * @param {Object} scope (optional) The default scope of that timeout
11952 * @param {Array} args (optional) The default Array of arguments
11954 Roo.util.DelayedTask = function(fn, scope, args){
11955 var id = null, d, t;
11957 var call = function(){
11958 var now = new Date().getTime();
11962 fn.apply(scope, args || []);
11966 * Cancels any pending timeout and queues a new one
11967 * @param {Number} delay The milliseconds to delay
11968 * @param {Function} newFn (optional) Overrides function passed to constructor
11969 * @param {Object} newScope (optional) Overrides scope passed to constructor
11970 * @param {Array} newArgs (optional) Overrides args passed to constructor
11972 this.delay = function(delay, newFn, newScope, newArgs){
11973 if(id && delay != d){
11977 t = new Date().getTime();
11979 scope = newScope || scope;
11980 args = newArgs || args;
11982 id = setInterval(call, d);
11987 * Cancel the last queued timeout
11989 this.cancel = function(){
11997 * Ext JS Library 1.1.1
11998 * Copyright(c) 2006-2007, Ext JS, LLC.
12000 * Originally Released Under LGPL - original licence link has changed is not relivant.
12003 * <script type="text/javascript">
12007 Roo.util.TaskRunner = function(interval){
12008 interval = interval || 10;
12009 var tasks = [], removeQueue = [];
12011 var running = false;
12013 var stopThread = function(){
12019 var startThread = function(){
12022 id = setInterval(runTasks, interval);
12026 var removeTask = function(task){
12027 removeQueue.push(task);
12033 var runTasks = function(){
12034 if(removeQueue.length > 0){
12035 for(var i = 0, len = removeQueue.length; i < len; i++){
12036 tasks.remove(removeQueue[i]);
12039 if(tasks.length < 1){
12044 var now = new Date().getTime();
12045 for(var i = 0, len = tasks.length; i < len; ++i){
12047 var itime = now - t.taskRunTime;
12048 if(t.interval <= itime){
12049 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12050 t.taskRunTime = now;
12051 if(rt === false || t.taskRunCount === t.repeat){
12056 if(t.duration && t.duration <= (now - t.taskStartTime)){
12063 * Queues a new task.
12064 * @param {Object} task
12066 this.start = function(task){
12068 task.taskStartTime = new Date().getTime();
12069 task.taskRunTime = 0;
12070 task.taskRunCount = 0;
12075 this.stop = function(task){
12080 this.stopAll = function(){
12082 for(var i = 0, len = tasks.length; i < len; i++){
12083 if(tasks[i].onStop){
12092 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12094 * Ext JS Library 1.1.1
12095 * Copyright(c) 2006-2007, Ext JS, LLC.
12097 * Originally Released Under LGPL - original licence link has changed is not relivant.
12100 * <script type="text/javascript">
12105 * @class Roo.util.MixedCollection
12106 * @extends Roo.util.Observable
12107 * A Collection class that maintains both numeric indexes and keys and exposes events.
12109 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12110 * collection (defaults to false)
12111 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12112 * and return the key value for that item. This is used when available to look up the key on items that
12113 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12114 * equivalent to providing an implementation for the {@link #getKey} method.
12116 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12124 * Fires when the collection is cleared.
12129 * Fires when an item is added to the collection.
12130 * @param {Number} index The index at which the item was added.
12131 * @param {Object} o The item added.
12132 * @param {String} key The key associated with the added item.
12137 * Fires when an item is replaced in the collection.
12138 * @param {String} key he key associated with the new added.
12139 * @param {Object} old The item being replaced.
12140 * @param {Object} new The new item.
12145 * Fires when an item is removed from the collection.
12146 * @param {Object} o The item being removed.
12147 * @param {String} key (optional) The key associated with the removed item.
12152 this.allowFunctions = allowFunctions === true;
12154 this.getKey = keyFn;
12156 Roo.util.MixedCollection.superclass.constructor.call(this);
12159 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12160 allowFunctions : false,
12163 * Adds an item to the collection.
12164 * @param {String} key The key to associate with the item
12165 * @param {Object} o The item to add.
12166 * @return {Object} The item added.
12168 add : function(key, o){
12169 if(arguments.length == 1){
12171 key = this.getKey(o);
12173 if(typeof key == "undefined" || key === null){
12175 this.items.push(o);
12176 this.keys.push(null);
12178 var old = this.map[key];
12180 return this.replace(key, o);
12183 this.items.push(o);
12185 this.keys.push(key);
12187 this.fireEvent("add", this.length-1, o, key);
12192 * MixedCollection has a generic way to fetch keys if you implement getKey.
12195 var mc = new Roo.util.MixedCollection();
12196 mc.add(someEl.dom.id, someEl);
12197 mc.add(otherEl.dom.id, otherEl);
12201 var mc = new Roo.util.MixedCollection();
12202 mc.getKey = function(el){
12208 // or via the constructor
12209 var mc = new Roo.util.MixedCollection(false, function(el){
12215 * @param o {Object} The item for which to find the key.
12216 * @return {Object} The key for the passed item.
12218 getKey : function(o){
12223 * Replaces an item in the collection.
12224 * @param {String} key The key associated with the item to replace, or the item to replace.
12225 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12226 * @return {Object} The new item.
12228 replace : function(key, o){
12229 if(arguments.length == 1){
12231 key = this.getKey(o);
12233 var old = this.item(key);
12234 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12235 return this.add(key, o);
12237 var index = this.indexOfKey(key);
12238 this.items[index] = o;
12240 this.fireEvent("replace", key, old, o);
12245 * Adds all elements of an Array or an Object to the collection.
12246 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12247 * an Array of values, each of which are added to the collection.
12249 addAll : function(objs){
12250 if(arguments.length > 1 || objs instanceof Array){
12251 var args = arguments.length > 1 ? arguments : objs;
12252 for(var i = 0, len = args.length; i < len; i++){
12256 for(var key in objs){
12257 if(this.allowFunctions || typeof objs[key] != "function"){
12258 this.add(key, objs[key]);
12265 * Executes the specified function once for every item in the collection, passing each
12266 * item as the first and only parameter. returning false from the function will stop the iteration.
12267 * @param {Function} fn The function to execute for each item.
12268 * @param {Object} scope (optional) The scope in which to execute the function.
12270 each : function(fn, scope){
12271 var items = [].concat(this.items); // each safe for removal
12272 for(var i = 0, len = items.length; i < len; i++){
12273 if(fn.call(scope || items[i], items[i], i, len) === false){
12280 * Executes the specified function once for every key in the collection, passing each
12281 * key, and its associated item as the first two parameters.
12282 * @param {Function} fn The function to execute for each item.
12283 * @param {Object} scope (optional) The scope in which to execute the function.
12285 eachKey : function(fn, scope){
12286 for(var i = 0, len = this.keys.length; i < len; i++){
12287 fn.call(scope || window, this.keys[i], this.items[i], i, len);
12292 * Returns the first item in the collection which elicits a true return value from the
12293 * passed selection function.
12294 * @param {Function} fn The selection function to execute for each item.
12295 * @param {Object} scope (optional) The scope in which to execute the function.
12296 * @return {Object} The first item in the collection which returned true from the selection function.
12298 find : function(fn, scope){
12299 for(var i = 0, len = this.items.length; i < len; i++){
12300 if(fn.call(scope || window, this.items[i], this.keys[i])){
12301 return this.items[i];
12308 * Inserts an item at the specified index in the collection.
12309 * @param {Number} index The index to insert the item at.
12310 * @param {String} key The key to associate with the new item, or the item itself.
12311 * @param {Object} o (optional) If the second parameter was a key, the new item.
12312 * @return {Object} The item inserted.
12314 insert : function(index, key, o){
12315 if(arguments.length == 2){
12317 key = this.getKey(o);
12319 if(index >= this.length){
12320 return this.add(key, o);
12323 this.items.splice(index, 0, o);
12324 if(typeof key != "undefined" && key != null){
12327 this.keys.splice(index, 0, key);
12328 this.fireEvent("add", index, o, key);
12333 * Removed an item from the collection.
12334 * @param {Object} o The item to remove.
12335 * @return {Object} The item removed.
12337 remove : function(o){
12338 return this.removeAt(this.indexOf(o));
12342 * Remove an item from a specified index in the collection.
12343 * @param {Number} index The index within the collection of the item to remove.
12345 removeAt : function(index){
12346 if(index < this.length && index >= 0){
12348 var o = this.items[index];
12349 this.items.splice(index, 1);
12350 var key = this.keys[index];
12351 if(typeof key != "undefined"){
12352 delete this.map[key];
12354 this.keys.splice(index, 1);
12355 this.fireEvent("remove", o, key);
12360 * Removed an item associated with the passed key fom the collection.
12361 * @param {String} key The key of the item to remove.
12363 removeKey : function(key){
12364 return this.removeAt(this.indexOfKey(key));
12368 * Returns the number of items in the collection.
12369 * @return {Number} the number of items in the collection.
12371 getCount : function(){
12372 return this.length;
12376 * Returns index within the collection of the passed Object.
12377 * @param {Object} o The item to find the index of.
12378 * @return {Number} index of the item.
12380 indexOf : function(o){
12381 if(!this.items.indexOf){
12382 for(var i = 0, len = this.items.length; i < len; i++){
12383 if(this.items[i] == o) return i;
12387 return this.items.indexOf(o);
12392 * Returns index within the collection of the passed key.
12393 * @param {String} key The key to find the index of.
12394 * @return {Number} index of the key.
12396 indexOfKey : function(key){
12397 if(!this.keys.indexOf){
12398 for(var i = 0, len = this.keys.length; i < len; i++){
12399 if(this.keys[i] == key) return i;
12403 return this.keys.indexOf(key);
12408 * Returns the item associated with the passed key OR index. Key has priority over index.
12409 * @param {String/Number} key The key or index of the item.
12410 * @return {Object} The item associated with the passed key.
12412 item : function(key){
12413 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
12414 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
12418 * Returns the item at the specified index.
12419 * @param {Number} index The index of the item.
12422 itemAt : function(index){
12423 return this.items[index];
12427 * Returns the item associated with the passed key.
12428 * @param {String/Number} key The key of the item.
12429 * @return {Object} The item associated with the passed key.
12431 key : function(key){
12432 return this.map[key];
12436 * Returns true if the collection contains the passed Object as an item.
12437 * @param {Object} o The Object to look for in the collection.
12438 * @return {Boolean} True if the collection contains the Object as an item.
12440 contains : function(o){
12441 return this.indexOf(o) != -1;
12445 * Returns true if the collection contains the passed Object as a key.
12446 * @param {String} key The key to look for in the collection.
12447 * @return {Boolean} True if the collection contains the Object as a key.
12449 containsKey : function(key){
12450 return typeof this.map[key] != "undefined";
12454 * Removes all items from the collection.
12456 clear : function(){
12461 this.fireEvent("clear");
12465 * Returns the first item in the collection.
12466 * @return {Object} the first item in the collection..
12468 first : function(){
12469 return this.items[0];
12473 * Returns the last item in the collection.
12474 * @return {Object} the last item in the collection..
12477 return this.items[this.length-1];
12480 _sort : function(property, dir, fn){
12481 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
12482 fn = fn || function(a, b){
12485 var c = [], k = this.keys, items = this.items;
12486 for(var i = 0, len = items.length; i < len; i++){
12487 c[c.length] = {key: k[i], value: items[i], index: i};
12489 c.sort(function(a, b){
12490 var v = fn(a[property], b[property]) * dsc;
12492 v = (a.index < b.index ? -1 : 1);
12496 for(var i = 0, len = c.length; i < len; i++){
12497 items[i] = c[i].value;
12500 this.fireEvent("sort", this);
12504 * Sorts this collection with the passed comparison function
12505 * @param {String} direction (optional) "ASC" or "DESC"
12506 * @param {Function} fn (optional) comparison function
12508 sort : function(dir, fn){
12509 this._sort("value", dir, fn);
12513 * Sorts this collection by keys
12514 * @param {String} direction (optional) "ASC" or "DESC"
12515 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
12517 keySort : function(dir, fn){
12518 this._sort("key", dir, fn || function(a, b){
12519 return String(a).toUpperCase()-String(b).toUpperCase();
12524 * Returns a range of items in this collection
12525 * @param {Number} startIndex (optional) defaults to 0
12526 * @param {Number} endIndex (optional) default to the last item
12527 * @return {Array} An array of items
12529 getRange : function(start, end){
12530 var items = this.items;
12531 if(items.length < 1){
12534 start = start || 0;
12535 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
12538 for(var i = start; i <= end; i++) {
12539 r[r.length] = items[i];
12542 for(var i = start; i >= end; i--) {
12543 r[r.length] = items[i];
12550 * Filter the <i>objects</i> in this collection by a specific property.
12551 * Returns a new collection that has been filtered.
12552 * @param {String} property A property on your objects
12553 * @param {String/RegExp} value Either string that the property values
12554 * should start with or a RegExp to test against the property
12555 * @return {MixedCollection} The new filtered collection
12557 filter : function(property, value){
12558 if(!value.exec){ // not a regex
12559 value = String(value);
12560 if(value.length == 0){
12561 return this.clone();
12563 value = new RegExp("^" + Roo.escapeRe(value), "i");
12565 return this.filterBy(function(o){
12566 return o && value.test(o[property]);
12571 * Filter by a function. * Returns a new collection that has been filtered.
12572 * The passed function will be called with each
12573 * object in the collection. If the function returns true, the value is included
12574 * otherwise it is filtered.
12575 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
12576 * @param {Object} scope (optional) The scope of the function (defaults to this)
12577 * @return {MixedCollection} The new filtered collection
12579 filterBy : function(fn, scope){
12580 var r = new Roo.util.MixedCollection();
12581 r.getKey = this.getKey;
12582 var k = this.keys, it = this.items;
12583 for(var i = 0, len = it.length; i < len; i++){
12584 if(fn.call(scope||this, it[i], k[i])){
12585 r.add(k[i], it[i]);
12592 * Creates a duplicate of this collection
12593 * @return {MixedCollection}
12595 clone : function(){
12596 var r = new Roo.util.MixedCollection();
12597 var k = this.keys, it = this.items;
12598 for(var i = 0, len = it.length; i < len; i++){
12599 r.add(k[i], it[i]);
12601 r.getKey = this.getKey;
12606 * Returns the item associated with the passed key or index.
12608 * @param {String/Number} key The key or index of the item.
12609 * @return {Object} The item associated with the passed key.
12611 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
12613 * Ext JS Library 1.1.1
12614 * Copyright(c) 2006-2007, Ext JS, LLC.
12616 * Originally Released Under LGPL - original licence link has changed is not relivant.
12619 * <script type="text/javascript">
12622 * @class Roo.util.JSON
12623 * Modified version of Douglas Crockford"s json.js that doesn"t
12624 * mess with the Object prototype
12625 * http://www.json.org/js.html
12628 Roo.util.JSON = new (function(){
12629 var useHasOwn = {}.hasOwnProperty ? true : false;
12631 // crashes Safari in some instances
12632 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
12634 var pad = function(n) {
12635 return n < 10 ? "0" + n : n;
12648 var encodeString = function(s){
12649 if (/["\\\x00-\x1f]/.test(s)) {
12650 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
12655 c = b.charCodeAt();
12657 Math.floor(c / 16).toString(16) +
12658 (c % 16).toString(16);
12661 return '"' + s + '"';
12664 var encodeArray = function(o){
12665 var a = ["["], b, i, l = o.length, v;
12666 for (i = 0; i < l; i += 1) {
12668 switch (typeof v) {
12677 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
12685 var encodeDate = function(o){
12686 return '"' + o.getFullYear() + "-" +
12687 pad(o.getMonth() + 1) + "-" +
12688 pad(o.getDate()) + "T" +
12689 pad(o.getHours()) + ":" +
12690 pad(o.getMinutes()) + ":" +
12691 pad(o.getSeconds()) + '"';
12695 * Encodes an Object, Array or other value
12696 * @param {Mixed} o The variable to encode
12697 * @return {String} The JSON string
12699 this.encode = function(o){
12700 if(typeof o == "undefined" || o === null){
12702 }else if(o instanceof Array){
12703 return encodeArray(o);
12704 }else if(o instanceof Date){
12705 return encodeDate(o);
12706 }else if(typeof o == "string"){
12707 return encodeString(o);
12708 }else if(typeof o == "number"){
12709 return isFinite(o) ? String(o) : "null";
12710 }else if(typeof o == "boolean"){
12713 var a = ["{"], b, i, v;
12715 if(!useHasOwn || o.hasOwnProperty(i)) {
12717 switch (typeof v) {
12726 a.push(this.encode(i), ":",
12727 v === null ? "null" : this.encode(v));
12738 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
12739 * @param {String} json The JSON string
12740 * @return {Object} The resulting object
12742 this.decode = function(json){
12746 return eval("(" + json + ')');
12750 * Shorthand for {@link Roo.util.JSON#encode}
12751 * @member Roo encode
12753 Roo.encode = Roo.util.JSON.encode;
12755 * Shorthand for {@link Roo.util.JSON#decode}
12756 * @member Roo decode
12758 Roo.decode = Roo.util.JSON.decode;
12761 * Ext JS Library 1.1.1
12762 * Copyright(c) 2006-2007, Ext JS, LLC.
12764 * Originally Released Under LGPL - original licence link has changed is not relivant.
12767 * <script type="text/javascript">
12771 * @class Roo.util.Format
12772 * Reusable data formatting functions
12775 Roo.util.Format = function(){
12776 var trimRe = /^\s+|\s+$/g;
12779 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
12780 * @param {String} value The string to truncate
12781 * @param {Number} length The maximum length to allow before truncating
12782 * @return {String} The converted text
12784 ellipsis : function(value, len){
12785 if(value && value.length > len){
12786 return value.substr(0, len-3)+"...";
12792 * Checks a reference and converts it to empty string if it is undefined
12793 * @param {Mixed} value Reference to check
12794 * @return {Mixed} Empty string if converted, otherwise the original value
12796 undef : function(value){
12797 return typeof value != "undefined" ? value : "";
12801 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
12802 * @param {String} value The string to encode
12803 * @return {String} The encoded text
12805 htmlEncode : function(value){
12806 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
12810 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
12811 * @param {String} value The string to decode
12812 * @return {String} The decoded text
12814 htmlDecode : function(value){
12815 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
12819 * Trims any whitespace from either side of a string
12820 * @param {String} value The text to trim
12821 * @return {String} The trimmed text
12823 trim : function(value){
12824 return String(value).replace(trimRe, "");
12828 * Returns a substring from within an original string
12829 * @param {String} value The original text
12830 * @param {Number} start The start index of the substring
12831 * @param {Number} length The length of the substring
12832 * @return {String} The substring
12834 substr : function(value, start, length){
12835 return String(value).substr(start, length);
12839 * Converts a string to all lower case letters
12840 * @param {String} value The text to convert
12841 * @return {String} The converted text
12843 lowercase : function(value){
12844 return String(value).toLowerCase();
12848 * Converts a string to all upper case letters
12849 * @param {String} value The text to convert
12850 * @return {String} The converted text
12852 uppercase : function(value){
12853 return String(value).toUpperCase();
12857 * Converts the first character only of a string to upper case
12858 * @param {String} value The text to convert
12859 * @return {String} The converted text
12861 capitalize : function(value){
12862 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
12866 call : function(value, fn){
12867 if(arguments.length > 2){
12868 var args = Array.prototype.slice.call(arguments, 2);
12869 args.unshift(value);
12871 return /** eval:var:value */ eval(fn).apply(window, args);
12873 /** eval:var:value */
12874 return /** eval:var:value */ eval(fn).call(window, value);
12879 * Format a number as US currency
12880 * @param {Number/String} value The numeric value to format
12881 * @return {String} The formatted currency string
12883 usMoney : function(v){
12884 v = (Math.round((v-0)*100))/100;
12885 v = (v == Math.floor(v)) ? v + ".00" : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
12887 var ps = v.split('.');
12889 var sub = ps[1] ? '.'+ ps[1] : '.00';
12890 var r = /(\d+)(\d{3})/;
12891 while (r.test(whole)) {
12892 whole = whole.replace(r, '$1' + ',' + '$2');
12894 return "$" + whole + sub ;
12898 * Parse a value into a formatted date using the specified format pattern.
12899 * @param {Mixed} value The value to format
12900 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
12901 * @return {String} The formatted date string
12903 date : function(v, format){
12907 if(!(v instanceof Date)){
12908 v = new Date(Date.parse(v));
12910 return v.dateFormat(format || "m/d/Y");
12914 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
12915 * @param {String} format Any valid date format string
12916 * @return {Function} The date formatting function
12918 dateRenderer : function(format){
12919 return function(v){
12920 return Roo.util.Format.date(v, format);
12925 stripTagsRE : /<\/?[^>]+>/gi,
12928 * Strips all HTML tags
12929 * @param {Mixed} value The text from which to strip tags
12930 * @return {String} The stripped text
12932 stripTags : function(v){
12933 return !v ? v : String(v).replace(this.stripTagsRE, "");
12938 * Ext JS Library 1.1.1
12939 * Copyright(c) 2006-2007, Ext JS, LLC.
12941 * Originally Released Under LGPL - original licence link has changed is not relivant.
12944 * <script type="text/javascript">
12951 * @class Roo.MasterTemplate
12952 * @extends Roo.Template
12953 * Provides a template that can have child templates. The syntax is:
12955 var t = new Roo.MasterTemplate(
12956 '<select name="{name}">',
12957 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
12960 t.add('options', {value: 'foo', text: 'bar'});
12961 // or you can add multiple child elements in one shot
12962 t.addAll('options', [
12963 {value: 'foo', text: 'bar'},
12964 {value: 'foo2', text: 'bar2'},
12965 {value: 'foo3', text: 'bar3'}
12967 // then append, applying the master template values
12968 t.append('my-form', {name: 'my-select'});
12970 * A name attribute for the child template is not required if you have only one child
12971 * template or you want to refer to them by index.
12973 Roo.MasterTemplate = function(){
12974 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
12975 this.originalHtml = this.html;
12977 var m, re = this.subTemplateRe;
12980 while(m = re.exec(this.html)){
12981 var name = m[1], content = m[2];
12986 tpl : new Roo.Template(content)
12989 st[name] = st[subIndex];
12991 st[subIndex].tpl.compile();
12992 st[subIndex].tpl.call = this.call.createDelegate(this);
12995 this.subCount = subIndex;
12998 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13000 * The regular expression used to match sub templates
13004 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13007 * Applies the passed values to a child template.
13008 * @param {String/Number} name (optional) The name or index of the child template
13009 * @param {Array/Object} values The values to be applied to the template
13010 * @return {MasterTemplate} this
13012 add : function(name, values){
13013 if(arguments.length == 1){
13014 values = arguments[0];
13017 var s = this.subs[name];
13018 s.buffer[s.buffer.length] = s.tpl.apply(values);
13023 * Applies all the passed values to a child template.
13024 * @param {String/Number} name (optional) The name or index of the child template
13025 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13026 * @param {Boolean} reset (optional) True to reset the template first
13027 * @return {MasterTemplate} this
13029 fill : function(name, values, reset){
13031 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13039 for(var i = 0, len = values.length; i < len; i++){
13040 this.add(name, values[i]);
13046 * Resets the template for reuse
13047 * @return {MasterTemplate} this
13049 reset : function(){
13051 for(var i = 0; i < this.subCount; i++){
13057 applyTemplate : function(values){
13059 var replaceIndex = -1;
13060 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13061 return s[++replaceIndex].buffer.join("");
13063 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13066 apply : function(){
13067 return this.applyTemplate.apply(this, arguments);
13070 compile : function(){return this;}
13074 * Alias for fill().
13077 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13079 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13080 * var tpl = Roo.MasterTemplate.from('element-id');
13081 * @param {String/HTMLElement} el
13082 * @param {Object} config
13085 Roo.MasterTemplate.from = function(el, config){
13086 el = Roo.getDom(el);
13087 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13090 * Ext JS Library 1.1.1
13091 * Copyright(c) 2006-2007, Ext JS, LLC.
13093 * Originally Released Under LGPL - original licence link has changed is not relivant.
13096 * <script type="text/javascript">
13101 * @class Roo.util.CSS
13102 * Utility class for manipulating CSS rules
13105 Roo.util.CSS = function(){
13107 var doc = document;
13109 var camelRe = /(-[a-z])/gi;
13110 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13114 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13115 * tag and appended to the HEAD of the document.
13116 * @param {String} cssText The text containing the css rules
13117 * @param {String} id An id to add to the stylesheet for later removal
13118 * @return {StyleSheet}
13120 createStyleSheet : function(cssText, id){
13122 var head = doc.getElementsByTagName("head")[0];
13123 var rules = doc.createElement("style");
13124 rules.setAttribute("type", "text/css");
13126 rules.setAttribute("id", id);
13129 head.appendChild(rules);
13130 ss = rules.styleSheet;
13131 ss.cssText = cssText;
13134 rules.appendChild(doc.createTextNode(cssText));
13136 rules.cssText = cssText;
13138 head.appendChild(rules);
13139 ss = rules.styleSheet ? rules.styleSheet : (rules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13141 this.cacheStyleSheet(ss);
13146 * Removes a style or link tag by id
13147 * @param {String} id The id of the tag
13149 removeStyleSheet : function(id){
13150 var existing = doc.getElementById(id);
13152 existing.parentNode.removeChild(existing);
13157 * Dynamically swaps an existing stylesheet reference for a new one
13158 * @param {String} id The id of an existing link tag to remove
13159 * @param {String} url The href of the new stylesheet to include
13161 swapStyleSheet : function(id, url){
13162 this.removeStyleSheet(id);
13163 var ss = doc.createElement("link");
13164 ss.setAttribute("rel", "stylesheet");
13165 ss.setAttribute("type", "text/css");
13166 ss.setAttribute("id", id);
13167 ss.setAttribute("href", url);
13168 doc.getElementsByTagName("head")[0].appendChild(ss);
13172 * Refresh the rule cache if you have dynamically added stylesheets
13173 * @return {Object} An object (hash) of rules indexed by selector
13175 refreshCache : function(){
13176 return this.getRules(true);
13180 cacheStyleSheet : function(ss){
13184 try{// try catch for cross domain access issue
13185 var ssRules = ss.cssRules || ss.rules;
13186 for(var j = ssRules.length-1; j >= 0; --j){
13187 rules[ssRules[j].selectorText] = ssRules[j];
13193 * Gets all css rules for the document
13194 * @param {Boolean} refreshCache true to refresh the internal cache
13195 * @return {Object} An object (hash) of rules indexed by selector
13197 getRules : function(refreshCache){
13198 if(rules == null || refreshCache){
13200 var ds = doc.styleSheets;
13201 for(var i =0, len = ds.length; i < len; i++){
13203 this.cacheStyleSheet(ds[i]);
13211 * Gets an an individual CSS rule by selector(s)
13212 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13213 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13214 * @return {CSSRule} The CSS rule or null if one is not found
13216 getRule : function(selector, refreshCache){
13217 var rs = this.getRules(refreshCache);
13218 if(!(selector instanceof Array)){
13219 return rs[selector];
13221 for(var i = 0; i < selector.length; i++){
13222 if(rs[selector[i]]){
13223 return rs[selector[i]];
13231 * Updates a rule property
13232 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13233 * @param {String} property The css property
13234 * @param {String} value The new value for the property
13235 * @return {Boolean} true If a rule was found and updated
13237 updateRule : function(selector, property, value){
13238 if(!(selector instanceof Array)){
13239 var rule = this.getRule(selector);
13241 rule.style[property.replace(camelRe, camelFn)] = value;
13245 for(var i = 0; i < selector.length; i++){
13246 if(this.updateRule(selector[i], property, value)){
13256 * Ext JS Library 1.1.1
13257 * Copyright(c) 2006-2007, Ext JS, LLC.
13259 * Originally Released Under LGPL - original licence link has changed is not relivant.
13262 * <script type="text/javascript">
13268 * @class Roo.util.ClickRepeater
13269 * @extends Roo.util.Observable
13271 * A wrapper class which can be applied to any element. Fires a "click" event while the
13272 * mouse is pressed. The interval between firings may be specified in the config but
13273 * defaults to 10 milliseconds.
13275 * Optionally, a CSS class may be applied to the element during the time it is pressed.
13277 * @cfg {String/HTMLElement/Element} el The element to act as a button.
13278 * @cfg {Number} delay The initial delay before the repeating event begins firing.
13279 * Similar to an autorepeat key delay.
13280 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
13281 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
13282 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
13283 * "interval" and "delay" are ignored. "immediate" is honored.
13284 * @cfg {Boolean} preventDefault True to prevent the default click event
13285 * @cfg {Boolean} stopDefault True to stop the default click event
13288 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
13289 * 2007-02-02 jvs Renamed to ClickRepeater
13290 * 2007-02-03 jvs Modifications for FF Mac and Safari
13293 * @param {String/HTMLElement/Element} el The element to listen on
13294 * @param {Object} config
13296 Roo.util.ClickRepeater = function(el, config)
13298 this.el = Roo.get(el);
13299 this.el.unselectable();
13301 Roo.apply(this, config);
13306 * Fires when the mouse button is depressed.
13307 * @param {Roo.util.ClickRepeater} this
13309 "mousedown" : true,
13312 * Fires on a specified interval during the time the element is pressed.
13313 * @param {Roo.util.ClickRepeater} this
13318 * Fires when the mouse key is released.
13319 * @param {Roo.util.ClickRepeater} this
13324 this.el.on("mousedown", this.handleMouseDown, this);
13325 if(this.preventDefault || this.stopDefault){
13326 this.el.on("click", function(e){
13327 if(this.preventDefault){
13328 e.preventDefault();
13330 if(this.stopDefault){
13336 // allow inline handler
13338 this.on("click", this.handler, this.scope || this);
13341 Roo.util.ClickRepeater.superclass.constructor.call(this);
13344 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
13347 preventDefault : true,
13348 stopDefault : false,
13352 handleMouseDown : function(){
13353 clearTimeout(this.timer);
13355 if(this.pressClass){
13356 this.el.addClass(this.pressClass);
13358 this.mousedownTime = new Date();
13360 Roo.get(document).on("mouseup", this.handleMouseUp, this);
13361 this.el.on("mouseout", this.handleMouseOut, this);
13363 this.fireEvent("mousedown", this);
13364 this.fireEvent("click", this);
13366 this.timer = this.click.defer(this.delay || this.interval, this);
13370 click : function(){
13371 this.fireEvent("click", this);
13372 this.timer = this.click.defer(this.getInterval(), this);
13376 getInterval: function(){
13377 if(!this.accelerate){
13378 return this.interval;
13380 var pressTime = this.mousedownTime.getElapsed();
13381 if(pressTime < 500){
13383 }else if(pressTime < 1700){
13385 }else if(pressTime < 2600){
13387 }else if(pressTime < 3500){
13389 }else if(pressTime < 4400){
13391 }else if(pressTime < 5300){
13393 }else if(pressTime < 6200){
13401 handleMouseOut : function(){
13402 clearTimeout(this.timer);
13403 if(this.pressClass){
13404 this.el.removeClass(this.pressClass);
13406 this.el.on("mouseover", this.handleMouseReturn, this);
13410 handleMouseReturn : function(){
13411 this.el.un("mouseover", this.handleMouseReturn);
13412 if(this.pressClass){
13413 this.el.addClass(this.pressClass);
13419 handleMouseUp : function(){
13420 clearTimeout(this.timer);
13421 this.el.un("mouseover", this.handleMouseReturn);
13422 this.el.un("mouseout", this.handleMouseOut);
13423 Roo.get(document).un("mouseup", this.handleMouseUp);
13424 this.el.removeClass(this.pressClass);
13425 this.fireEvent("mouseup", this);
13429 * Ext JS Library 1.1.1
13430 * Copyright(c) 2006-2007, Ext JS, LLC.
13432 * Originally Released Under LGPL - original licence link has changed is not relivant.
13435 * <script type="text/javascript">
13440 * @class Roo.KeyNav
13441 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
13442 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
13443 * way to implement custom navigation schemes for any UI component.</p>
13444 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
13445 * pageUp, pageDown, del, home, end. Usage:</p>
13447 var nav = new Roo.KeyNav("my-element", {
13448 "left" : function(e){
13449 this.moveLeft(e.ctrlKey);
13451 "right" : function(e){
13452 this.moveRight(e.ctrlKey);
13454 "enter" : function(e){
13461 * @param {String/HTMLElement/Roo.Element} el The element to bind to
13462 * @param {Object} config The config
13464 Roo.KeyNav = function(el, config){
13465 this.el = Roo.get(el);
13466 Roo.apply(this, config);
13467 if(!this.disabled){
13468 this.disabled = true;
13473 Roo.KeyNav.prototype = {
13475 * @cfg {Boolean} disabled
13476 * True to disable this KeyNav instance (defaults to false)
13480 * @cfg {String} defaultEventAction
13481 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
13482 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
13483 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
13485 defaultEventAction: "stopEvent",
13487 * @cfg {Boolean} forceKeyDown
13488 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
13489 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
13490 * handle keydown instead of keypress.
13492 forceKeyDown : false,
13495 prepareEvent : function(e){
13496 var k = e.getKey();
13497 var h = this.keyToHandler[k];
13498 //if(h && this[h]){
13499 // e.stopPropagation();
13501 if(Roo.isSafari && h && k >= 37 && k <= 40){
13507 relay : function(e){
13508 var k = e.getKey();
13509 var h = this.keyToHandler[k];
13511 if(this.doRelay(e, this[h], h) !== true){
13512 e[this.defaultEventAction]();
13518 doRelay : function(e, h, hname){
13519 return h.call(this.scope || this, e);
13522 // possible handlers
13536 // quick lookup hash
13553 * Enable this KeyNav
13555 enable: function(){
13557 // ie won't do special keys on keypress, no one else will repeat keys with keydown
13558 // the EventObject will normalize Safari automatically
13559 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13560 this.el.on("keydown", this.relay, this);
13562 this.el.on("keydown", this.prepareEvent, this);
13563 this.el.on("keypress", this.relay, this);
13565 this.disabled = false;
13570 * Disable this KeyNav
13572 disable: function(){
13573 if(!this.disabled){
13574 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13575 this.el.un("keydown", this.relay);
13577 this.el.un("keydown", this.prepareEvent);
13578 this.el.un("keypress", this.relay);
13580 this.disabled = true;
13585 * Ext JS Library 1.1.1
13586 * Copyright(c) 2006-2007, Ext JS, LLC.
13588 * Originally Released Under LGPL - original licence link has changed is not relivant.
13591 * <script type="text/javascript">
13596 * @class Roo.KeyMap
13597 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
13598 * The constructor accepts the same config object as defined by {@link #addBinding}.
13599 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
13600 * combination it will call the function with this signature (if the match is a multi-key
13601 * combination the callback will still be called only once): (String key, Roo.EventObject e)
13602 * A KeyMap can also handle a string representation of keys.<br />
13605 // map one key by key code
13606 var map = new Roo.KeyMap("my-element", {
13607 key: 13, // or Roo.EventObject.ENTER
13612 // map multiple keys to one action by string
13613 var map = new Roo.KeyMap("my-element", {
13619 // map multiple keys to multiple actions by strings and array of codes
13620 var map = new Roo.KeyMap("my-element", [
13623 fn: function(){ alert("Return was pressed"); }
13626 fn: function(){ alert('a, b or c was pressed'); }
13631 fn: function(){ alert('Control + shift + tab was pressed.'); }
13635 * <b>Note: A KeyMap starts enabled</b>
13637 * @param {String/HTMLElement/Roo.Element} el The element to bind to
13638 * @param {Object} config The config (see {@link #addBinding})
13639 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
13641 Roo.KeyMap = function(el, config, eventName){
13642 this.el = Roo.get(el);
13643 this.eventName = eventName || "keydown";
13644 this.bindings = [];
13646 this.addBinding(config);
13651 Roo.KeyMap.prototype = {
13653 * True to stop the event from bubbling and prevent the default browser action if the
13654 * key was handled by the KeyMap (defaults to false)
13660 * Add a new binding to this KeyMap. The following config object properties are supported:
13662 Property Type Description
13663 ---------- --------------- ----------------------------------------------------------------------
13664 key String/Array A single keycode or an array of keycodes to handle
13665 shift Boolean True to handle key only when shift is pressed (defaults to false)
13666 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
13667 alt Boolean True to handle key only when alt is pressed (defaults to false)
13668 fn Function The function to call when KeyMap finds the expected key combination
13669 scope Object The scope of the callback function
13675 var map = new Roo.KeyMap(document, {
13676 key: Roo.EventObject.ENTER,
13681 //Add a new binding to the existing KeyMap later
13689 * @param {Object/Array} config A single KeyMap config or an array of configs
13691 addBinding : function(config){
13692 if(config instanceof Array){
13693 for(var i = 0, len = config.length; i < len; i++){
13694 this.addBinding(config[i]);
13698 var keyCode = config.key,
13699 shift = config.shift,
13700 ctrl = config.ctrl,
13703 scope = config.scope;
13704 if(typeof keyCode == "string"){
13706 var keyString = keyCode.toUpperCase();
13707 for(var j = 0, len = keyString.length; j < len; j++){
13708 ks.push(keyString.charCodeAt(j));
13712 var keyArray = keyCode instanceof Array;
13713 var handler = function(e){
13714 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
13715 var k = e.getKey();
13717 for(var i = 0, len = keyCode.length; i < len; i++){
13718 if(keyCode[i] == k){
13719 if(this.stopEvent){
13722 fn.call(scope || window, k, e);
13728 if(this.stopEvent){
13731 fn.call(scope || window, k, e);
13736 this.bindings.push(handler);
13740 * Shorthand for adding a single key listener
13741 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
13742 * following options:
13743 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
13744 * @param {Function} fn The function to call
13745 * @param {Object} scope (optional) The scope of the function
13747 on : function(key, fn, scope){
13748 var keyCode, shift, ctrl, alt;
13749 if(typeof key == "object" && !(key instanceof Array)){
13768 handleKeyDown : function(e){
13769 if(this.enabled){ //just in case
13770 var b = this.bindings;
13771 for(var i = 0, len = b.length; i < len; i++){
13772 b[i].call(this, e);
13778 * Returns true if this KeyMap is enabled
13779 * @return {Boolean}
13781 isEnabled : function(){
13782 return this.enabled;
13786 * Enables this KeyMap
13788 enable: function(){
13790 this.el.on(this.eventName, this.handleKeyDown, this);
13791 this.enabled = true;
13796 * Disable this KeyMap
13798 disable: function(){
13800 this.el.removeListener(this.eventName, this.handleKeyDown, this);
13801 this.enabled = false;
13806 * Ext JS Library 1.1.1
13807 * Copyright(c) 2006-2007, Ext JS, LLC.
13809 * Originally Released Under LGPL - original licence link has changed is not relivant.
13812 * <script type="text/javascript">
13817 * @class Roo.util.TextMetrics
13818 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
13819 * wide, in pixels, a given block of text will be.
13822 Roo.util.TextMetrics = function(){
13826 * Measures the size of the specified text
13827 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
13828 * that can affect the size of the rendered text
13829 * @param {String} text The text to measure
13830 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
13831 * in order to accurately measure the text height
13832 * @return {Object} An object containing the text's size {width: (width), height: (height)}
13834 measure : function(el, text, fixedWidth){
13836 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
13839 shared.setFixedWidth(fixedWidth || 'auto');
13840 return shared.getSize(text);
13844 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
13845 * the overhead of multiple calls to initialize the style properties on each measurement.
13846 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
13847 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
13848 * in order to accurately measure the text height
13849 * @return {Roo.util.TextMetrics.Instance} instance The new instance
13851 createInstance : function(el, fixedWidth){
13852 return Roo.util.TextMetrics.Instance(el, fixedWidth);
13857 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
13858 var ml = new Roo.Element(document.createElement('div'));
13859 document.body.appendChild(ml.dom);
13860 ml.position('absolute');
13861 ml.setLeftTop(-1000, -1000);
13865 ml.setWidth(fixedWidth);
13870 * Returns the size of the specified text based on the internal element's style and width properties
13871 * @param {String} text The text to measure
13872 * @return {Object} An object containing the text's size {width: (width), height: (height)}
13874 getSize : function(text){
13876 var s = ml.getSize();
13882 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
13883 * that can affect the size of the rendered text
13884 * @param {String/HTMLElement} el The element, dom node or id
13886 bind : function(el){
13888 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
13893 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
13894 * to set a fixed width in order to accurately measure the text height.
13895 * @param {Number} width The width to set on the element
13897 setFixedWidth : function(width){
13898 ml.setWidth(width);
13902 * Returns the measured width of the specified text
13903 * @param {String} text The text to measure
13904 * @return {Number} width The width in pixels
13906 getWidth : function(text){
13907 ml.dom.style.width = 'auto';
13908 return this.getSize(text).width;
13912 * Returns the measured height of the specified text. For multiline text, be sure to call
13913 * {@link #setFixedWidth} if necessary.
13914 * @param {String} text The text to measure
13915 * @return {Number} height The height in pixels
13917 getHeight : function(text){
13918 return this.getSize(text).height;
13922 instance.bind(bindTo);
13927 // backwards compat
13928 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
13930 * Ext JS Library 1.1.1
13931 * Copyright(c) 2006-2007, Ext JS, LLC.
13933 * Originally Released Under LGPL - original licence link has changed is not relivant.
13936 * <script type="text/javascript">
13940 * @class Roo.state.Provider
13941 * Abstract base class for state provider implementations. This class provides methods
13942 * for encoding and decoding <b>typed</b> variables including dates and defines the
13943 * Provider interface.
13945 Roo.state.Provider = function(){
13947 * @event statechange
13948 * Fires when a state change occurs.
13949 * @param {Provider} this This state provider
13950 * @param {String} key The state key which was changed
13951 * @param {String} value The encoded value for the state
13954 "statechange": true
13957 Roo.state.Provider.superclass.constructor.call(this);
13959 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
13961 * Returns the current value for a key
13962 * @param {String} name The key name
13963 * @param {Mixed} defaultValue A default value to return if the key's value is not found
13964 * @return {Mixed} The state data
13966 get : function(name, defaultValue){
13967 return typeof this.state[name] == "undefined" ?
13968 defaultValue : this.state[name];
13972 * Clears a value from the state
13973 * @param {String} name The key name
13975 clear : function(name){
13976 delete this.state[name];
13977 this.fireEvent("statechange", this, name, null);
13981 * Sets the value for a key
13982 * @param {String} name The key name
13983 * @param {Mixed} value The value to set
13985 set : function(name, value){
13986 this.state[name] = value;
13987 this.fireEvent("statechange", this, name, value);
13991 * Decodes a string previously encoded with {@link #encodeValue}.
13992 * @param {String} value The value to decode
13993 * @return {Mixed} The decoded value
13995 decodeValue : function(cookie){
13996 var re = /^(a|n|d|b|s|o)\:(.*)$/;
13997 var matches = re.exec(unescape(cookie));
13998 if(!matches || !matches[1]) return; // non state cookie
13999 var type = matches[1];
14000 var v = matches[2];
14003 return parseFloat(v);
14005 return new Date(Date.parse(v));
14010 var values = v.split("^");
14011 for(var i = 0, len = values.length; i < len; i++){
14012 all.push(this.decodeValue(values[i]));
14017 var values = v.split("^");
14018 for(var i = 0, len = values.length; i < len; i++){
14019 var kv = values[i].split("=");
14020 all[kv[0]] = this.decodeValue(kv[1]);
14029 * Encodes a value including type information. Decode with {@link #decodeValue}.
14030 * @param {Mixed} value The value to encode
14031 * @return {String} The encoded value
14033 encodeValue : function(v){
14035 if(typeof v == "number"){
14037 }else if(typeof v == "boolean"){
14038 enc = "b:" + (v ? "1" : "0");
14039 }else if(v instanceof Date){
14040 enc = "d:" + v.toGMTString();
14041 }else if(v instanceof Array){
14043 for(var i = 0, len = v.length; i < len; i++){
14044 flat += this.encodeValue(v[i]);
14045 if(i != len-1) flat += "^";
14048 }else if(typeof v == "object"){
14051 if(typeof v[key] != "function"){
14052 flat += key + "=" + this.encodeValue(v[key]) + "^";
14055 enc = "o:" + flat.substring(0, flat.length-1);
14059 return escape(enc);
14065 * Ext JS Library 1.1.1
14066 * Copyright(c) 2006-2007, Ext JS, LLC.
14068 * Originally Released Under LGPL - original licence link has changed is not relivant.
14071 * <script type="text/javascript">
14074 * @class Roo.state.Manager
14075 * This is the global state manager. By default all components that are "state aware" check this class
14076 * for state information if you don't pass them a custom state provider. In order for this class
14077 * to be useful, it must be initialized with a provider when your application initializes.
14079 // in your initialization function
14081 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14083 // supposed you have a {@link Roo.BorderLayout}
14084 var layout = new Roo.BorderLayout(...);
14085 layout.restoreState();
14086 // or a {Roo.BasicDialog}
14087 var dialog = new Roo.BasicDialog(...);
14088 dialog.restoreState();
14092 Roo.state.Manager = function(){
14093 var provider = new Roo.state.Provider();
14097 * Configures the default state provider for your application
14098 * @param {Provider} stateProvider The state provider to set
14100 setProvider : function(stateProvider){
14101 provider = stateProvider;
14105 * Returns the current value for a key
14106 * @param {String} name The key name
14107 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14108 * @return {Mixed} The state data
14110 get : function(key, defaultValue){
14111 return provider.get(key, defaultValue);
14115 * Sets the value for a key
14116 * @param {String} name The key name
14117 * @param {Mixed} value The state data
14119 set : function(key, value){
14120 provider.set(key, value);
14124 * Clears a value from the state
14125 * @param {String} name The key name
14127 clear : function(key){
14128 provider.clear(key);
14132 * Gets the currently configured state provider
14133 * @return {Provider} The state provider
14135 getProvider : function(){
14142 * Ext JS Library 1.1.1
14143 * Copyright(c) 2006-2007, Ext JS, LLC.
14145 * Originally Released Under LGPL - original licence link has changed is not relivant.
14148 * <script type="text/javascript">
14151 * @class Roo.state.CookieProvider
14152 * @extends Roo.state.Provider
14153 * The default Provider implementation which saves state via cookies.
14156 var cp = new Roo.state.CookieProvider({
14158 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14159 domain: "roojs.com"
14161 Roo.state.Manager.setProvider(cp);
14163 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14164 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14165 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
14166 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14167 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14168 * domain the page is running on including the 'www' like 'www.roojs.com')
14169 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14171 * Create a new CookieProvider
14172 * @param {Object} config The configuration object
14174 Roo.state.CookieProvider = function(config){
14175 Roo.state.CookieProvider.superclass.constructor.call(this);
14177 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14178 this.domain = null;
14179 this.secure = false;
14180 Roo.apply(this, config);
14181 this.state = this.readCookies();
14184 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14186 set : function(name, value){
14187 if(typeof value == "undefined" || value === null){
14191 this.setCookie(name, value);
14192 Roo.state.CookieProvider.superclass.set.call(this, name, value);
14196 clear : function(name){
14197 this.clearCookie(name);
14198 Roo.state.CookieProvider.superclass.clear.call(this, name);
14202 readCookies : function(){
14204 var c = document.cookie + ";";
14205 var re = /\s?(.*?)=(.*?);/g;
14207 while((matches = re.exec(c)) != null){
14208 var name = matches[1];
14209 var value = matches[2];
14210 if(name && name.substring(0,3) == "ys-"){
14211 cookies[name.substr(3)] = this.decodeValue(value);
14218 setCookie : function(name, value){
14219 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14220 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14221 ((this.path == null) ? "" : ("; path=" + this.path)) +
14222 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14223 ((this.secure == true) ? "; secure" : "");
14227 clearCookie : function(name){
14228 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14229 ((this.path == null) ? "" : ("; path=" + this.path)) +
14230 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14231 ((this.secure == true) ? "; secure" : "");
14235 * Ext JS Library 1.1.1
14236 * Copyright(c) 2006-2007, Ext JS, LLC.
14238 * Originally Released Under LGPL - original licence link has changed is not relivant.
14241 * <script type="text/javascript">
14247 * These classes are derivatives of the similarly named classes in the YUI Library.
14248 * The original license:
14249 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
14250 * Code licensed under the BSD License:
14251 * http://developer.yahoo.net/yui/license.txt
14256 var Event=Roo.EventManager;
14257 var Dom=Roo.lib.Dom;
14260 * @class Roo.dd.DragDrop
14261 * Defines the interface and base operation of items that that can be
14262 * dragged or can be drop targets. It was designed to be extended, overriding
14263 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
14264 * Up to three html elements can be associated with a DragDrop instance:
14266 * <li>linked element: the element that is passed into the constructor.
14267 * This is the element which defines the boundaries for interaction with
14268 * other DragDrop objects.</li>
14269 * <li>handle element(s): The drag operation only occurs if the element that
14270 * was clicked matches a handle element. By default this is the linked
14271 * element, but there are times that you will want only a portion of the
14272 * linked element to initiate the drag operation, and the setHandleElId()
14273 * method provides a way to define this.</li>
14274 * <li>drag element: this represents the element that would be moved along
14275 * with the cursor during a drag operation. By default, this is the linked
14276 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
14277 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
14280 * This class should not be instantiated until the onload event to ensure that
14281 * the associated elements are available.
14282 * The following would define a DragDrop obj that would interact with any
14283 * other DragDrop obj in the "group1" group:
14285 * dd = new Roo.dd.DragDrop("div1", "group1");
14287 * Since none of the event handlers have been implemented, nothing would
14288 * actually happen if you were to run the code above. Normally you would
14289 * override this class or one of the default implementations, but you can
14290 * also override the methods you want on an instance of the class...
14292 * dd.onDragDrop = function(e, id) {
14293 * alert("dd was dropped on " + id);
14297 * @param {String} id of the element that is linked to this instance
14298 * @param {String} sGroup the group of related DragDrop objects
14299 * @param {object} config an object containing configurable attributes
14300 * Valid properties for DragDrop:
14301 * padding, isTarget, maintainOffset, primaryButtonOnly
14303 Roo.dd.DragDrop = function(id, sGroup, config) {
14305 this.init(id, sGroup, config);
14309 Roo.dd.DragDrop.prototype = {
14312 * The id of the element associated with this object. This is what we
14313 * refer to as the "linked element" because the size and position of
14314 * this element is used to determine when the drag and drop objects have
14322 * Configuration attributes passed into the constructor
14329 * The id of the element that will be dragged. By default this is same
14330 * as the linked element , but could be changed to another element. Ex:
14332 * @property dragElId
14339 * the id of the element that initiates the drag operation. By default
14340 * this is the linked element, but could be changed to be a child of this
14341 * element. This lets us do things like only starting the drag when the
14342 * header element within the linked html element is clicked.
14343 * @property handleElId
14350 * An associative array of HTML tags that will be ignored if clicked.
14351 * @property invalidHandleTypes
14352 * @type {string: string}
14354 invalidHandleTypes: null,
14357 * An associative array of ids for elements that will be ignored if clicked
14358 * @property invalidHandleIds
14359 * @type {string: string}
14361 invalidHandleIds: null,
14364 * An indexted array of css class names for elements that will be ignored
14366 * @property invalidHandleClasses
14369 invalidHandleClasses: null,
14372 * The linked element's absolute X position at the time the drag was
14374 * @property startPageX
14381 * The linked element's absolute X position at the time the drag was
14383 * @property startPageY
14390 * The group defines a logical collection of DragDrop objects that are
14391 * related. Instances only get events when interacting with other
14392 * DragDrop object in the same group. This lets us define multiple
14393 * groups using a single DragDrop subclass if we want.
14395 * @type {string: string}
14400 * Individual drag/drop instances can be locked. This will prevent
14401 * onmousedown start drag.
14409 * Lock this instance
14412 lock: function() { this.locked = true; },
14415 * Unlock this instace
14418 unlock: function() { this.locked = false; },
14421 * By default, all insances can be a drop target. This can be disabled by
14422 * setting isTarget to false.
14429 * The padding configured for this drag and drop object for calculating
14430 * the drop zone intersection with this object.
14437 * Cached reference to the linked element
14438 * @property _domRef
14444 * Internal typeof flag
14445 * @property __ygDragDrop
14448 __ygDragDrop: true,
14451 * Set to true when horizontal contraints are applied
14452 * @property constrainX
14459 * Set to true when vertical contraints are applied
14460 * @property constrainY
14467 * The left constraint
14475 * The right constraint
14483 * The up constraint
14492 * The down constraint
14500 * Maintain offsets when we resetconstraints. Set to true when you want
14501 * the position of the element relative to its parent to stay the same
14502 * when the page changes
14504 * @property maintainOffset
14507 maintainOffset: false,
14510 * Array of pixel locations the element will snap to if we specified a
14511 * horizontal graduation/interval. This array is generated automatically
14512 * when you define a tick interval.
14519 * Array of pixel locations the element will snap to if we specified a
14520 * vertical graduation/interval. This array is generated automatically
14521 * when you define a tick interval.
14528 * By default the drag and drop instance will only respond to the primary
14529 * button click (left button for a right-handed mouse). Set to true to
14530 * allow drag and drop to start with any mouse click that is propogated
14532 * @property primaryButtonOnly
14535 primaryButtonOnly: true,
14538 * The availabe property is false until the linked dom element is accessible.
14539 * @property available
14545 * By default, drags can only be initiated if the mousedown occurs in the
14546 * region the linked element is. This is done in part to work around a
14547 * bug in some browsers that mis-report the mousedown if the previous
14548 * mouseup happened outside of the window. This property is set to true
14549 * if outer handles are defined.
14551 * @property hasOuterHandles
14555 hasOuterHandles: false,
14558 * Code that executes immediately before the startDrag event
14559 * @method b4StartDrag
14562 b4StartDrag: function(x, y) { },
14565 * Abstract method called after a drag/drop object is clicked
14566 * and the drag or mousedown time thresholds have beeen met.
14567 * @method startDrag
14568 * @param {int} X click location
14569 * @param {int} Y click location
14571 startDrag: function(x, y) { /* override this */ },
14574 * Code that executes immediately before the onDrag event
14578 b4Drag: function(e) { },
14581 * Abstract method called during the onMouseMove event while dragging an
14584 * @param {Event} e the mousemove event
14586 onDrag: function(e) { /* override this */ },
14589 * Abstract method called when this element fist begins hovering over
14590 * another DragDrop obj
14591 * @method onDragEnter
14592 * @param {Event} e the mousemove event
14593 * @param {String|DragDrop[]} id In POINT mode, the element
14594 * id this is hovering over. In INTERSECT mode, an array of one or more
14595 * dragdrop items being hovered over.
14597 onDragEnter: function(e, id) { /* override this */ },
14600 * Code that executes immediately before the onDragOver event
14601 * @method b4DragOver
14604 b4DragOver: function(e) { },
14607 * Abstract method called when this element is hovering over another
14609 * @method onDragOver
14610 * @param {Event} e the mousemove event
14611 * @param {String|DragDrop[]} id In POINT mode, the element
14612 * id this is hovering over. In INTERSECT mode, an array of dd items
14613 * being hovered over.
14615 onDragOver: function(e, id) { /* override this */ },
14618 * Code that executes immediately before the onDragOut event
14619 * @method b4DragOut
14622 b4DragOut: function(e) { },
14625 * Abstract method called when we are no longer hovering over an element
14626 * @method onDragOut
14627 * @param {Event} e the mousemove event
14628 * @param {String|DragDrop[]} id In POINT mode, the element
14629 * id this was hovering over. In INTERSECT mode, an array of dd items
14630 * that the mouse is no longer over.
14632 onDragOut: function(e, id) { /* override this */ },
14635 * Code that executes immediately before the onDragDrop event
14636 * @method b4DragDrop
14639 b4DragDrop: function(e) { },
14642 * Abstract method called when this item is dropped on another DragDrop
14644 * @method onDragDrop
14645 * @param {Event} e the mouseup event
14646 * @param {String|DragDrop[]} id In POINT mode, the element
14647 * id this was dropped on. In INTERSECT mode, an array of dd items this
14650 onDragDrop: function(e, id) { /* override this */ },
14653 * Abstract method called when this item is dropped on an area with no
14655 * @method onInvalidDrop
14656 * @param {Event} e the mouseup event
14658 onInvalidDrop: function(e) { /* override this */ },
14661 * Code that executes immediately before the endDrag event
14662 * @method b4EndDrag
14665 b4EndDrag: function(e) { },
14668 * Fired when we are done dragging the object
14670 * @param {Event} e the mouseup event
14672 endDrag: function(e) { /* override this */ },
14675 * Code executed immediately before the onMouseDown event
14676 * @method b4MouseDown
14677 * @param {Event} e the mousedown event
14680 b4MouseDown: function(e) { },
14683 * Event handler that fires when a drag/drop obj gets a mousedown
14684 * @method onMouseDown
14685 * @param {Event} e the mousedown event
14687 onMouseDown: function(e) { /* override this */ },
14690 * Event handler that fires when a drag/drop obj gets a mouseup
14691 * @method onMouseUp
14692 * @param {Event} e the mouseup event
14694 onMouseUp: function(e) { /* override this */ },
14697 * Override the onAvailable method to do what is needed after the initial
14698 * position was determined.
14699 * @method onAvailable
14701 onAvailable: function () {
14705 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
14708 defaultPadding : {left:0, right:0, top:0, bottom:0},
14711 * Initializes the drag drop object's constraints to restrict movement to a certain element.
14715 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
14716 { dragElId: "existingProxyDiv" });
14717 dd.startDrag = function(){
14718 this.constrainTo("parent-id");
14721 * Or you can initalize it using the {@link Roo.Element} object:
14723 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
14724 startDrag : function(){
14725 this.constrainTo("parent-id");
14729 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
14730 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
14731 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
14732 * an object containing the sides to pad. For example: {right:10, bottom:10}
14733 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
14735 constrainTo : function(constrainTo, pad, inContent){
14736 if(typeof pad == "number"){
14737 pad = {left: pad, right:pad, top:pad, bottom:pad};
14739 pad = pad || this.defaultPadding;
14740 var b = Roo.get(this.getEl()).getBox();
14741 var ce = Roo.get(constrainTo);
14742 var s = ce.getScroll();
14743 var c, cd = ce.dom;
14744 if(cd == document.body){
14745 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
14748 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
14752 var topSpace = b.y - c.y;
14753 var leftSpace = b.x - c.x;
14755 this.resetConstraints();
14756 this.setXConstraint(leftSpace - (pad.left||0), // left
14757 c.width - leftSpace - b.width - (pad.right||0) //right
14759 this.setYConstraint(topSpace - (pad.top||0), //top
14760 c.height - topSpace - b.height - (pad.bottom||0) //bottom
14765 * Returns a reference to the linked element
14767 * @return {HTMLElement} the html element
14769 getEl: function() {
14770 if (!this._domRef) {
14771 this._domRef = Roo.getDom(this.id);
14774 return this._domRef;
14778 * Returns a reference to the actual element to drag. By default this is
14779 * the same as the html element, but it can be assigned to another
14780 * element. An example of this can be found in Roo.dd.DDProxy
14781 * @method getDragEl
14782 * @return {HTMLElement} the html element
14784 getDragEl: function() {
14785 return Roo.getDom(this.dragElId);
14789 * Sets up the DragDrop object. Must be called in the constructor of any
14790 * Roo.dd.DragDrop subclass
14792 * @param id the id of the linked element
14793 * @param {String} sGroup the group of related items
14794 * @param {object} config configuration attributes
14796 init: function(id, sGroup, config) {
14797 this.initTarget(id, sGroup, config);
14798 Event.on(this.id, "mousedown", this.handleMouseDown, this);
14799 // Event.on(this.id, "selectstart", Event.preventDefault);
14803 * Initializes Targeting functionality only... the object does not
14804 * get a mousedown handler.
14805 * @method initTarget
14806 * @param id the id of the linked element
14807 * @param {String} sGroup the group of related items
14808 * @param {object} config configuration attributes
14810 initTarget: function(id, sGroup, config) {
14812 // configuration attributes
14813 this.config = config || {};
14815 // create a local reference to the drag and drop manager
14816 this.DDM = Roo.dd.DDM;
14817 // initialize the groups array
14820 // assume that we have an element reference instead of an id if the
14821 // parameter is not a string
14822 if (typeof id !== "string") {
14829 // add to an interaction group
14830 this.addToGroup((sGroup) ? sGroup : "default");
14832 // We don't want to register this as the handle with the manager
14833 // so we just set the id rather than calling the setter.
14834 this.handleElId = id;
14836 // the linked element is the element that gets dragged by default
14837 this.setDragElId(id);
14839 // by default, clicked anchors will not start drag operations.
14840 this.invalidHandleTypes = { A: "A" };
14841 this.invalidHandleIds = {};
14842 this.invalidHandleClasses = [];
14844 this.applyConfig();
14846 this.handleOnAvailable();
14850 * Applies the configuration parameters that were passed into the constructor.
14851 * This is supposed to happen at each level through the inheritance chain. So
14852 * a DDProxy implentation will execute apply config on DDProxy, DD, and
14853 * DragDrop in order to get all of the parameters that are available in
14855 * @method applyConfig
14857 applyConfig: function() {
14859 // configurable properties:
14860 // padding, isTarget, maintainOffset, primaryButtonOnly
14861 this.padding = this.config.padding || [0, 0, 0, 0];
14862 this.isTarget = (this.config.isTarget !== false);
14863 this.maintainOffset = (this.config.maintainOffset);
14864 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
14869 * Executed when the linked element is available
14870 * @method handleOnAvailable
14873 handleOnAvailable: function() {
14874 this.available = true;
14875 this.resetConstraints();
14876 this.onAvailable();
14880 * Configures the padding for the target zone in px. Effectively expands
14881 * (or reduces) the virtual object size for targeting calculations.
14882 * Supports css-style shorthand; if only one parameter is passed, all sides
14883 * will have that padding, and if only two are passed, the top and bottom
14884 * will have the first param, the left and right the second.
14885 * @method setPadding
14886 * @param {int} iTop Top pad
14887 * @param {int} iRight Right pad
14888 * @param {int} iBot Bot pad
14889 * @param {int} iLeft Left pad
14891 setPadding: function(iTop, iRight, iBot, iLeft) {
14892 // this.padding = [iLeft, iRight, iTop, iBot];
14893 if (!iRight && 0 !== iRight) {
14894 this.padding = [iTop, iTop, iTop, iTop];
14895 } else if (!iBot && 0 !== iBot) {
14896 this.padding = [iTop, iRight, iTop, iRight];
14898 this.padding = [iTop, iRight, iBot, iLeft];
14903 * Stores the initial placement of the linked element.
14904 * @method setInitialPosition
14905 * @param {int} diffX the X offset, default 0
14906 * @param {int} diffY the Y offset, default 0
14908 setInitPosition: function(diffX, diffY) {
14909 var el = this.getEl();
14911 if (!this.DDM.verifyEl(el)) {
14915 var dx = diffX || 0;
14916 var dy = diffY || 0;
14918 var p = Dom.getXY( el );
14920 this.initPageX = p[0] - dx;
14921 this.initPageY = p[1] - dy;
14923 this.lastPageX = p[0];
14924 this.lastPageY = p[1];
14927 this.setStartPosition(p);
14931 * Sets the start position of the element. This is set when the obj
14932 * is initialized, the reset when a drag is started.
14933 * @method setStartPosition
14934 * @param pos current position (from previous lookup)
14937 setStartPosition: function(pos) {
14938 var p = pos || Dom.getXY( this.getEl() );
14939 this.deltaSetXY = null;
14941 this.startPageX = p[0];
14942 this.startPageY = p[1];
14946 * Add this instance to a group of related drag/drop objects. All
14947 * instances belong to at least one group, and can belong to as many
14948 * groups as needed.
14949 * @method addToGroup
14950 * @param sGroup {string} the name of the group
14952 addToGroup: function(sGroup) {
14953 this.groups[sGroup] = true;
14954 this.DDM.regDragDrop(this, sGroup);
14958 * Remove's this instance from the supplied interaction group
14959 * @method removeFromGroup
14960 * @param {string} sGroup The group to drop
14962 removeFromGroup: function(sGroup) {
14963 if (this.groups[sGroup]) {
14964 delete this.groups[sGroup];
14967 this.DDM.removeDDFromGroup(this, sGroup);
14971 * Allows you to specify that an element other than the linked element
14972 * will be moved with the cursor during a drag
14973 * @method setDragElId
14974 * @param id {string} the id of the element that will be used to initiate the drag
14976 setDragElId: function(id) {
14977 this.dragElId = id;
14981 * Allows you to specify a child of the linked element that should be
14982 * used to initiate the drag operation. An example of this would be if
14983 * you have a content div with text and links. Clicking anywhere in the
14984 * content area would normally start the drag operation. Use this method
14985 * to specify that an element inside of the content div is the element
14986 * that starts the drag operation.
14987 * @method setHandleElId
14988 * @param id {string} the id of the element that will be used to
14989 * initiate the drag.
14991 setHandleElId: function(id) {
14992 if (typeof id !== "string") {
14995 this.handleElId = id;
14996 this.DDM.regHandle(this.id, id);
15000 * Allows you to set an element outside of the linked element as a drag
15002 * @method setOuterHandleElId
15003 * @param id the id of the element that will be used to initiate the drag
15005 setOuterHandleElId: function(id) {
15006 if (typeof id !== "string") {
15009 Event.on(id, "mousedown",
15010 this.handleMouseDown, this);
15011 this.setHandleElId(id);
15013 this.hasOuterHandles = true;
15017 * Remove all drag and drop hooks for this element
15020 unreg: function() {
15021 Event.un(this.id, "mousedown",
15022 this.handleMouseDown);
15023 this._domRef = null;
15024 this.DDM._remove(this);
15027 destroy : function(){
15032 * Returns true if this instance is locked, or the drag drop mgr is locked
15033 * (meaning that all drag/drop is disabled on the page.)
15035 * @return {boolean} true if this obj or all drag/drop is locked, else
15038 isLocked: function() {
15039 return (this.DDM.isLocked() || this.locked);
15043 * Fired when this object is clicked
15044 * @method handleMouseDown
15046 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
15049 handleMouseDown: function(e, oDD){
15050 if (this.primaryButtonOnly && e.button != 0) {
15054 if (this.isLocked()) {
15058 this.DDM.refreshCache(this.groups);
15060 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
15061 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
15063 if (this.clickValidator(e)) {
15065 // set the initial element position
15066 this.setStartPosition();
15069 this.b4MouseDown(e);
15070 this.onMouseDown(e);
15072 this.DDM.handleMouseDown(e, this);
15074 this.DDM.stopEvent(e);
15082 clickValidator: function(e) {
15083 var target = e.getTarget();
15084 return ( this.isValidHandleChild(target) &&
15085 (this.id == this.handleElId ||
15086 this.DDM.handleWasClicked(target, this.id)) );
15090 * Allows you to specify a tag name that should not start a drag operation
15091 * when clicked. This is designed to facilitate embedding links within a
15092 * drag handle that do something other than start the drag.
15093 * @method addInvalidHandleType
15094 * @param {string} tagName the type of element to exclude
15096 addInvalidHandleType: function(tagName) {
15097 var type = tagName.toUpperCase();
15098 this.invalidHandleTypes[type] = type;
15102 * Lets you to specify an element id for a child of a drag handle
15103 * that should not initiate a drag
15104 * @method addInvalidHandleId
15105 * @param {string} id the element id of the element you wish to ignore
15107 addInvalidHandleId: function(id) {
15108 if (typeof id !== "string") {
15111 this.invalidHandleIds[id] = id;
15115 * Lets you specify a css class of elements that will not initiate a drag
15116 * @method addInvalidHandleClass
15117 * @param {string} cssClass the class of the elements you wish to ignore
15119 addInvalidHandleClass: function(cssClass) {
15120 this.invalidHandleClasses.push(cssClass);
15124 * Unsets an excluded tag name set by addInvalidHandleType
15125 * @method removeInvalidHandleType
15126 * @param {string} tagName the type of element to unexclude
15128 removeInvalidHandleType: function(tagName) {
15129 var type = tagName.toUpperCase();
15130 // this.invalidHandleTypes[type] = null;
15131 delete this.invalidHandleTypes[type];
15135 * Unsets an invalid handle id
15136 * @method removeInvalidHandleId
15137 * @param {string} id the id of the element to re-enable
15139 removeInvalidHandleId: function(id) {
15140 if (typeof id !== "string") {
15143 delete this.invalidHandleIds[id];
15147 * Unsets an invalid css class
15148 * @method removeInvalidHandleClass
15149 * @param {string} cssClass the class of the element(s) you wish to
15152 removeInvalidHandleClass: function(cssClass) {
15153 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
15154 if (this.invalidHandleClasses[i] == cssClass) {
15155 delete this.invalidHandleClasses[i];
15161 * Checks the tag exclusion list to see if this click should be ignored
15162 * @method isValidHandleChild
15163 * @param {HTMLElement} node the HTMLElement to evaluate
15164 * @return {boolean} true if this is a valid tag type, false if not
15166 isValidHandleChild: function(node) {
15169 // var n = (node.nodeName == "#text") ? node.parentNode : node;
15172 nodeName = node.nodeName.toUpperCase();
15174 nodeName = node.nodeName;
15176 valid = valid && !this.invalidHandleTypes[nodeName];
15177 valid = valid && !this.invalidHandleIds[node.id];
15179 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
15180 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
15189 * Create the array of horizontal tick marks if an interval was specified
15190 * in setXConstraint().
15191 * @method setXTicks
15194 setXTicks: function(iStartX, iTickSize) {
15196 this.xTickSize = iTickSize;
15200 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
15202 this.xTicks[this.xTicks.length] = i;
15207 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
15209 this.xTicks[this.xTicks.length] = i;
15214 this.xTicks.sort(this.DDM.numericSort) ;
15218 * Create the array of vertical tick marks if an interval was specified in
15219 * setYConstraint().
15220 * @method setYTicks
15223 setYTicks: function(iStartY, iTickSize) {
15225 this.yTickSize = iTickSize;
15229 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
15231 this.yTicks[this.yTicks.length] = i;
15236 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
15238 this.yTicks[this.yTicks.length] = i;
15243 this.yTicks.sort(this.DDM.numericSort) ;
15247 * By default, the element can be dragged any place on the screen. Use
15248 * this method to limit the horizontal travel of the element. Pass in
15249 * 0,0 for the parameters if you want to lock the drag to the y axis.
15250 * @method setXConstraint
15251 * @param {int} iLeft the number of pixels the element can move to the left
15252 * @param {int} iRight the number of pixels the element can move to the
15254 * @param {int} iTickSize optional parameter for specifying that the
15256 * should move iTickSize pixels at a time.
15258 setXConstraint: function(iLeft, iRight, iTickSize) {
15259 this.leftConstraint = iLeft;
15260 this.rightConstraint = iRight;
15262 this.minX = this.initPageX - iLeft;
15263 this.maxX = this.initPageX + iRight;
15264 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
15266 this.constrainX = true;
15270 * Clears any constraints applied to this instance. Also clears ticks
15271 * since they can't exist independent of a constraint at this time.
15272 * @method clearConstraints
15274 clearConstraints: function() {
15275 this.constrainX = false;
15276 this.constrainY = false;
15281 * Clears any tick interval defined for this instance
15282 * @method clearTicks
15284 clearTicks: function() {
15285 this.xTicks = null;
15286 this.yTicks = null;
15287 this.xTickSize = 0;
15288 this.yTickSize = 0;
15292 * By default, the element can be dragged any place on the screen. Set
15293 * this to limit the vertical travel of the element. Pass in 0,0 for the
15294 * parameters if you want to lock the drag to the x axis.
15295 * @method setYConstraint
15296 * @param {int} iUp the number of pixels the element can move up
15297 * @param {int} iDown the number of pixels the element can move down
15298 * @param {int} iTickSize optional parameter for specifying that the
15299 * element should move iTickSize pixels at a time.
15301 setYConstraint: function(iUp, iDown, iTickSize) {
15302 this.topConstraint = iUp;
15303 this.bottomConstraint = iDown;
15305 this.minY = this.initPageY - iUp;
15306 this.maxY = this.initPageY + iDown;
15307 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
15309 this.constrainY = true;
15314 * resetConstraints must be called if you manually reposition a dd element.
15315 * @method resetConstraints
15316 * @param {boolean} maintainOffset
15318 resetConstraints: function() {
15321 // Maintain offsets if necessary
15322 if (this.initPageX || this.initPageX === 0) {
15323 // figure out how much this thing has moved
15324 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
15325 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
15327 this.setInitPosition(dx, dy);
15329 // This is the first time we have detected the element's position
15331 this.setInitPosition();
15334 if (this.constrainX) {
15335 this.setXConstraint( this.leftConstraint,
15336 this.rightConstraint,
15340 if (this.constrainY) {
15341 this.setYConstraint( this.topConstraint,
15342 this.bottomConstraint,
15348 * Normally the drag element is moved pixel by pixel, but we can specify
15349 * that it move a number of pixels at a time. This method resolves the
15350 * location when we have it set up like this.
15352 * @param {int} val where we want to place the object
15353 * @param {int[]} tickArray sorted array of valid points
15354 * @return {int} the closest tick
15357 getTick: function(val, tickArray) {
15360 // If tick interval is not defined, it is effectively 1 pixel,
15361 // so we return the value passed to us.
15363 } else if (tickArray[0] >= val) {
15364 // The value is lower than the first tick, so we return the first
15366 return tickArray[0];
15368 for (var i=0, len=tickArray.length; i<len; ++i) {
15370 if (tickArray[next] && tickArray[next] >= val) {
15371 var diff1 = val - tickArray[i];
15372 var diff2 = tickArray[next] - val;
15373 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
15377 // The value is larger than the last tick, so we return the last
15379 return tickArray[tickArray.length - 1];
15386 * @return {string} string representation of the dd obj
15388 toString: function() {
15389 return ("DragDrop " + this.id);
15397 * Ext JS Library 1.1.1
15398 * Copyright(c) 2006-2007, Ext JS, LLC.
15400 * Originally Released Under LGPL - original licence link has changed is not relivant.
15403 * <script type="text/javascript">
15408 * The drag and drop utility provides a framework for building drag and drop
15409 * applications. In addition to enabling drag and drop for specific elements,
15410 * the drag and drop elements are tracked by the manager class, and the
15411 * interactions between the various elements are tracked during the drag and
15412 * the implementing code is notified about these important moments.
15415 // Only load the library once. Rewriting the manager class would orphan
15416 // existing drag and drop instances.
15417 if (!Roo.dd.DragDropMgr) {
15420 * @class Roo.dd.DragDropMgr
15421 * DragDropMgr is a singleton that tracks the element interaction for
15422 * all DragDrop items in the window. Generally, you will not call
15423 * this class directly, but it does have helper methods that could
15424 * be useful in your DragDrop implementations.
15427 Roo.dd.DragDropMgr = function() {
15429 var Event = Roo.EventManager;
15434 * Two dimensional Array of registered DragDrop objects. The first
15435 * dimension is the DragDrop item group, the second the DragDrop
15438 * @type {string: string}
15445 * Array of element ids defined as drag handles. Used to determine
15446 * if the element that generated the mousedown event is actually the
15447 * handle and not the html element itself.
15448 * @property handleIds
15449 * @type {string: string}
15456 * the DragDrop object that is currently being dragged
15457 * @property dragCurrent
15465 * the DragDrop object(s) that are being hovered over
15466 * @property dragOvers
15474 * the X distance between the cursor and the object being dragged
15483 * the Y distance between the cursor and the object being dragged
15492 * Flag to determine if we should prevent the default behavior of the
15493 * events we define. By default this is true, but this can be set to
15494 * false if you need the default behavior (not recommended)
15495 * @property preventDefault
15499 preventDefault: true,
15502 * Flag to determine if we should stop the propagation of the events
15503 * we generate. This is true by default but you may want to set it to
15504 * false if the html element contains other features that require the
15506 * @property stopPropagation
15510 stopPropagation: true,
15513 * Internal flag that is set to true when drag and drop has been
15515 * @property initialized
15522 * All drag and drop can be disabled.
15530 * Called the first time an element is registered.
15536 this.initialized = true;
15540 * In point mode, drag and drop interaction is defined by the
15541 * location of the cursor during the drag/drop
15549 * In intersect mode, drag and drop interactio nis defined by the
15550 * overlap of two or more drag and drop objects.
15551 * @property INTERSECT
15558 * The current drag and drop mode. Default: POINT
15566 * Runs method on all drag and drop objects
15567 * @method _execOnAll
15571 _execOnAll: function(sMethod, args) {
15572 for (var i in this.ids) {
15573 for (var j in this.ids[i]) {
15574 var oDD = this.ids[i][j];
15575 if (! this.isTypeOfDD(oDD)) {
15578 oDD[sMethod].apply(oDD, args);
15584 * Drag and drop initialization. Sets up the global event handlers
15589 _onLoad: function() {
15594 Event.on(document, "mouseup", this.handleMouseUp, this, true);
15595 Event.on(document, "mousemove", this.handleMouseMove, this, true);
15596 Event.on(window, "unload", this._onUnload, this, true);
15597 Event.on(window, "resize", this._onResize, this, true);
15598 // Event.on(window, "mouseout", this._test);
15603 * Reset constraints on all drag and drop objs
15604 * @method _onResize
15608 _onResize: function(e) {
15609 this._execOnAll("resetConstraints", []);
15613 * Lock all drag and drop functionality
15617 lock: function() { this.locked = true; },
15620 * Unlock all drag and drop functionality
15624 unlock: function() { this.locked = false; },
15627 * Is drag and drop locked?
15629 * @return {boolean} True if drag and drop is locked, false otherwise.
15632 isLocked: function() { return this.locked; },
15635 * Location cache that is set for all drag drop objects when a drag is
15636 * initiated, cleared when the drag is finished.
15637 * @property locationCache
15644 * Set useCache to false if you want to force object the lookup of each
15645 * drag and drop linked element constantly during a drag.
15646 * @property useCache
15653 * The number of pixels that the mouse needs to move after the
15654 * mousedown before the drag is initiated. Default=3;
15655 * @property clickPixelThresh
15659 clickPixelThresh: 3,
15662 * The number of milliseconds after the mousedown event to initiate the
15663 * drag if we don't get a mouseup event. Default=1000
15664 * @property clickTimeThresh
15668 clickTimeThresh: 350,
15671 * Flag that indicates that either the drag pixel threshold or the
15672 * mousdown time threshold has been met
15673 * @property dragThreshMet
15678 dragThreshMet: false,
15681 * Timeout used for the click time threshold
15682 * @property clickTimeout
15687 clickTimeout: null,
15690 * The X position of the mousedown event stored for later use when a
15691 * drag threshold is met.
15700 * The Y position of the mousedown event stored for later use when a
15701 * drag threshold is met.
15710 * Each DragDrop instance must be registered with the DragDropMgr.
15711 * This is executed in DragDrop.init()
15712 * @method regDragDrop
15713 * @param {DragDrop} oDD the DragDrop object to register
15714 * @param {String} sGroup the name of the group this element belongs to
15717 regDragDrop: function(oDD, sGroup) {
15718 if (!this.initialized) { this.init(); }
15720 if (!this.ids[sGroup]) {
15721 this.ids[sGroup] = {};
15723 this.ids[sGroup][oDD.id] = oDD;
15727 * Removes the supplied dd instance from the supplied group. Executed
15728 * by DragDrop.removeFromGroup, so don't call this function directly.
15729 * @method removeDDFromGroup
15733 removeDDFromGroup: function(oDD, sGroup) {
15734 if (!this.ids[sGroup]) {
15735 this.ids[sGroup] = {};
15738 var obj = this.ids[sGroup];
15739 if (obj && obj[oDD.id]) {
15740 delete obj[oDD.id];
15745 * Unregisters a drag and drop item. This is executed in
15746 * DragDrop.unreg, use that method instead of calling this directly.
15751 _remove: function(oDD) {
15752 for (var g in oDD.groups) {
15753 if (g && this.ids[g][oDD.id]) {
15754 delete this.ids[g][oDD.id];
15757 delete this.handleIds[oDD.id];
15761 * Each DragDrop handle element must be registered. This is done
15762 * automatically when executing DragDrop.setHandleElId()
15763 * @method regHandle
15764 * @param {String} sDDId the DragDrop id this element is a handle for
15765 * @param {String} sHandleId the id of the element that is the drag
15769 regHandle: function(sDDId, sHandleId) {
15770 if (!this.handleIds[sDDId]) {
15771 this.handleIds[sDDId] = {};
15773 this.handleIds[sDDId][sHandleId] = sHandleId;
15777 * Utility function to determine if a given element has been
15778 * registered as a drag drop item.
15779 * @method isDragDrop
15780 * @param {String} id the element id to check
15781 * @return {boolean} true if this element is a DragDrop item,
15785 isDragDrop: function(id) {
15786 return ( this.getDDById(id) ) ? true : false;
15790 * Returns the drag and drop instances that are in all groups the
15791 * passed in instance belongs to.
15792 * @method getRelated
15793 * @param {DragDrop} p_oDD the obj to get related data for
15794 * @param {boolean} bTargetsOnly if true, only return targetable objs
15795 * @return {DragDrop[]} the related instances
15798 getRelated: function(p_oDD, bTargetsOnly) {
15800 for (var i in p_oDD.groups) {
15801 for (j in this.ids[i]) {
15802 var dd = this.ids[i][j];
15803 if (! this.isTypeOfDD(dd)) {
15806 if (!bTargetsOnly || dd.isTarget) {
15807 oDDs[oDDs.length] = dd;
15816 * Returns true if the specified dd target is a legal target for
15817 * the specifice drag obj
15818 * @method isLegalTarget
15819 * @param {DragDrop} the drag obj
15820 * @param {DragDrop} the target
15821 * @return {boolean} true if the target is a legal target for the
15825 isLegalTarget: function (oDD, oTargetDD) {
15826 var targets = this.getRelated(oDD, true);
15827 for (var i=0, len=targets.length;i<len;++i) {
15828 if (targets[i].id == oTargetDD.id) {
15837 * My goal is to be able to transparently determine if an object is
15838 * typeof DragDrop, and the exact subclass of DragDrop. typeof
15839 * returns "object", oDD.constructor.toString() always returns
15840 * "DragDrop" and not the name of the subclass. So for now it just
15841 * evaluates a well-known variable in DragDrop.
15842 * @method isTypeOfDD
15843 * @param {Object} the object to evaluate
15844 * @return {boolean} true if typeof oDD = DragDrop
15847 isTypeOfDD: function (oDD) {
15848 return (oDD && oDD.__ygDragDrop);
15852 * Utility function to determine if a given element has been
15853 * registered as a drag drop handle for the given Drag Drop object.
15855 * @param {String} id the element id to check
15856 * @return {boolean} true if this element is a DragDrop handle, false
15860 isHandle: function(sDDId, sHandleId) {
15861 return ( this.handleIds[sDDId] &&
15862 this.handleIds[sDDId][sHandleId] );
15866 * Returns the DragDrop instance for a given id
15867 * @method getDDById
15868 * @param {String} id the id of the DragDrop object
15869 * @return {DragDrop} the drag drop object, null if it is not found
15872 getDDById: function(id) {
15873 for (var i in this.ids) {
15874 if (this.ids[i][id]) {
15875 return this.ids[i][id];
15882 * Fired after a registered DragDrop object gets the mousedown event.
15883 * Sets up the events required to track the object being dragged
15884 * @method handleMouseDown
15885 * @param {Event} e the event
15886 * @param oDD the DragDrop object being dragged
15890 handleMouseDown: function(e, oDD) {
15892 Roo.QuickTips.disable();
15894 this.currentTarget = e.getTarget();
15896 this.dragCurrent = oDD;
15898 var el = oDD.getEl();
15900 // track start position
15901 this.startX = e.getPageX();
15902 this.startY = e.getPageY();
15904 this.deltaX = this.startX - el.offsetLeft;
15905 this.deltaY = this.startY - el.offsetTop;
15907 this.dragThreshMet = false;
15909 this.clickTimeout = setTimeout(
15911 var DDM = Roo.dd.DDM;
15912 DDM.startDrag(DDM.startX, DDM.startY);
15914 this.clickTimeThresh );
15918 * Fired when either the drag pixel threshol or the mousedown hold
15919 * time threshold has been met.
15920 * @method startDrag
15921 * @param x {int} the X position of the original mousedown
15922 * @param y {int} the Y position of the original mousedown
15925 startDrag: function(x, y) {
15926 clearTimeout(this.clickTimeout);
15927 if (this.dragCurrent) {
15928 this.dragCurrent.b4StartDrag(x, y);
15929 this.dragCurrent.startDrag(x, y);
15931 this.dragThreshMet = true;
15935 * Internal function to handle the mouseup event. Will be invoked
15936 * from the context of the document.
15937 * @method handleMouseUp
15938 * @param {Event} e the event
15942 handleMouseUp: function(e) {
15945 Roo.QuickTips.enable();
15947 if (! this.dragCurrent) {
15951 clearTimeout(this.clickTimeout);
15953 if (this.dragThreshMet) {
15954 this.fireEvents(e, true);
15964 * Utility to stop event propagation and event default, if these
15965 * features are turned on.
15966 * @method stopEvent
15967 * @param {Event} e the event as returned by this.getEvent()
15970 stopEvent: function(e){
15971 if(this.stopPropagation) {
15972 e.stopPropagation();
15975 if (this.preventDefault) {
15976 e.preventDefault();
15981 * Internal function to clean up event handlers after the drag
15982 * operation is complete
15984 * @param {Event} e the event
15988 stopDrag: function(e) {
15989 // Fire the drag end event for the item that was dragged
15990 if (this.dragCurrent) {
15991 if (this.dragThreshMet) {
15992 this.dragCurrent.b4EndDrag(e);
15993 this.dragCurrent.endDrag(e);
15996 this.dragCurrent.onMouseUp(e);
15999 this.dragCurrent = null;
16000 this.dragOvers = {};
16004 * Internal function to handle the mousemove event. Will be invoked
16005 * from the context of the html element.
16007 * @TODO figure out what we can do about mouse events lost when the
16008 * user drags objects beyond the window boundary. Currently we can
16009 * detect this in internet explorer by verifying that the mouse is
16010 * down during the mousemove event. Firefox doesn't give us the
16011 * button state on the mousemove event.
16012 * @method handleMouseMove
16013 * @param {Event} e the event
16017 handleMouseMove: function(e) {
16018 if (! this.dragCurrent) {
16022 // var button = e.which || e.button;
16024 // check for IE mouseup outside of page boundary
16025 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
16027 return this.handleMouseUp(e);
16030 if (!this.dragThreshMet) {
16031 var diffX = Math.abs(this.startX - e.getPageX());
16032 var diffY = Math.abs(this.startY - e.getPageY());
16033 if (diffX > this.clickPixelThresh ||
16034 diffY > this.clickPixelThresh) {
16035 this.startDrag(this.startX, this.startY);
16039 if (this.dragThreshMet) {
16040 this.dragCurrent.b4Drag(e);
16041 this.dragCurrent.onDrag(e);
16042 if(!this.dragCurrent.moveOnly){
16043 this.fireEvents(e, false);
16053 * Iterates over all of the DragDrop elements to find ones we are
16054 * hovering over or dropping on
16055 * @method fireEvents
16056 * @param {Event} e the event
16057 * @param {boolean} isDrop is this a drop op or a mouseover op?
16061 fireEvents: function(e, isDrop) {
16062 var dc = this.dragCurrent;
16064 // If the user did the mouse up outside of the window, we could
16065 // get here even though we have ended the drag.
16066 if (!dc || dc.isLocked()) {
16070 var pt = e.getPoint();
16072 // cache the previous dragOver array
16078 var enterEvts = [];
16080 // Check to see if the object(s) we were hovering over is no longer
16081 // being hovered over so we can fire the onDragOut event
16082 for (var i in this.dragOvers) {
16084 var ddo = this.dragOvers[i];
16086 if (! this.isTypeOfDD(ddo)) {
16090 if (! this.isOverTarget(pt, ddo, this.mode)) {
16091 outEvts.push( ddo );
16094 oldOvers[i] = true;
16095 delete this.dragOvers[i];
16098 for (var sGroup in dc.groups) {
16100 if ("string" != typeof sGroup) {
16104 for (i in this.ids[sGroup]) {
16105 var oDD = this.ids[sGroup][i];
16106 if (! this.isTypeOfDD(oDD)) {
16110 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
16111 if (this.isOverTarget(pt, oDD, this.mode)) {
16112 // look for drop interactions
16114 dropEvts.push( oDD );
16115 // look for drag enter and drag over interactions
16118 // initial drag over: dragEnter fires
16119 if (!oldOvers[oDD.id]) {
16120 enterEvts.push( oDD );
16121 // subsequent drag overs: dragOver fires
16123 overEvts.push( oDD );
16126 this.dragOvers[oDD.id] = oDD;
16134 if (outEvts.length) {
16135 dc.b4DragOut(e, outEvts);
16136 dc.onDragOut(e, outEvts);
16139 if (enterEvts.length) {
16140 dc.onDragEnter(e, enterEvts);
16143 if (overEvts.length) {
16144 dc.b4DragOver(e, overEvts);
16145 dc.onDragOver(e, overEvts);
16148 if (dropEvts.length) {
16149 dc.b4DragDrop(e, dropEvts);
16150 dc.onDragDrop(e, dropEvts);
16154 // fire dragout events
16156 for (i=0, len=outEvts.length; i<len; ++i) {
16157 dc.b4DragOut(e, outEvts[i].id);
16158 dc.onDragOut(e, outEvts[i].id);
16161 // fire enter events
16162 for (i=0,len=enterEvts.length; i<len; ++i) {
16163 // dc.b4DragEnter(e, oDD.id);
16164 dc.onDragEnter(e, enterEvts[i].id);
16167 // fire over events
16168 for (i=0,len=overEvts.length; i<len; ++i) {
16169 dc.b4DragOver(e, overEvts[i].id);
16170 dc.onDragOver(e, overEvts[i].id);
16173 // fire drop events
16174 for (i=0, len=dropEvts.length; i<len; ++i) {
16175 dc.b4DragDrop(e, dropEvts[i].id);
16176 dc.onDragDrop(e, dropEvts[i].id);
16181 // notify about a drop that did not find a target
16182 if (isDrop && !dropEvts.length) {
16183 dc.onInvalidDrop(e);
16189 * Helper function for getting the best match from the list of drag
16190 * and drop objects returned by the drag and drop events when we are
16191 * in INTERSECT mode. It returns either the first object that the
16192 * cursor is over, or the object that has the greatest overlap with
16193 * the dragged element.
16194 * @method getBestMatch
16195 * @param {DragDrop[]} dds The array of drag and drop objects
16197 * @return {DragDrop} The best single match
16200 getBestMatch: function(dds) {
16202 // Return null if the input is not what we expect
16203 //if (!dds || !dds.length || dds.length == 0) {
16205 // If there is only one item, it wins
16206 //} else if (dds.length == 1) {
16208 var len = dds.length;
16213 // Loop through the targeted items
16214 for (var i=0; i<len; ++i) {
16216 // If the cursor is over the object, it wins. If the
16217 // cursor is over multiple matches, the first one we come
16219 if (dd.cursorIsOver) {
16222 // Otherwise the object with the most overlap wins
16225 winner.overlap.getArea() < dd.overlap.getArea()) {
16236 * Refreshes the cache of the top-left and bottom-right points of the
16237 * drag and drop objects in the specified group(s). This is in the
16238 * format that is stored in the drag and drop instance, so typical
16241 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
16245 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
16247 * @TODO this really should be an indexed array. Alternatively this
16248 * method could accept both.
16249 * @method refreshCache
16250 * @param {Object} groups an associative array of groups to refresh
16253 refreshCache: function(groups) {
16254 for (var sGroup in groups) {
16255 if ("string" != typeof sGroup) {
16258 for (var i in this.ids[sGroup]) {
16259 var oDD = this.ids[sGroup][i];
16261 if (this.isTypeOfDD(oDD)) {
16262 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
16263 var loc = this.getLocation(oDD);
16265 this.locationCache[oDD.id] = loc;
16267 delete this.locationCache[oDD.id];
16268 // this will unregister the drag and drop object if
16269 // the element is not in a usable state
16278 * This checks to make sure an element exists and is in the DOM. The
16279 * main purpose is to handle cases where innerHTML is used to remove
16280 * drag and drop objects from the DOM. IE provides an 'unspecified
16281 * error' when trying to access the offsetParent of such an element
16283 * @param {HTMLElement} el the element to check
16284 * @return {boolean} true if the element looks usable
16287 verifyEl: function(el) {
16292 parent = el.offsetParent;
16295 parent = el.offsetParent;
16306 * Returns a Region object containing the drag and drop element's position
16307 * and size, including the padding configured for it
16308 * @method getLocation
16309 * @param {DragDrop} oDD the drag and drop object to get the
16311 * @return {Roo.lib.Region} a Region object representing the total area
16312 * the element occupies, including any padding
16313 * the instance is configured for.
16316 getLocation: function(oDD) {
16317 if (! this.isTypeOfDD(oDD)) {
16321 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
16324 pos= Roo.lib.Dom.getXY(el);
16332 x2 = x1 + el.offsetWidth;
16334 y2 = y1 + el.offsetHeight;
16336 t = y1 - oDD.padding[0];
16337 r = x2 + oDD.padding[1];
16338 b = y2 + oDD.padding[2];
16339 l = x1 - oDD.padding[3];
16341 return new Roo.lib.Region( t, r, b, l );
16345 * Checks the cursor location to see if it over the target
16346 * @method isOverTarget
16347 * @param {Roo.lib.Point} pt The point to evaluate
16348 * @param {DragDrop} oTarget the DragDrop object we are inspecting
16349 * @return {boolean} true if the mouse is over the target
16353 isOverTarget: function(pt, oTarget, intersect) {
16354 // use cache if available
16355 var loc = this.locationCache[oTarget.id];
16356 if (!loc || !this.useCache) {
16357 loc = this.getLocation(oTarget);
16358 this.locationCache[oTarget.id] = loc;
16366 oTarget.cursorIsOver = loc.contains( pt );
16368 // DragDrop is using this as a sanity check for the initial mousedown
16369 // in this case we are done. In POINT mode, if the drag obj has no
16370 // contraints, we are also done. Otherwise we need to evaluate the
16371 // location of the target as related to the actual location of the
16372 // dragged element.
16373 var dc = this.dragCurrent;
16374 if (!dc || !dc.getTargetCoord ||
16375 (!intersect && !dc.constrainX && !dc.constrainY)) {
16376 return oTarget.cursorIsOver;
16379 oTarget.overlap = null;
16381 // Get the current location of the drag element, this is the
16382 // location of the mouse event less the delta that represents
16383 // where the original mousedown happened on the element. We
16384 // need to consider constraints and ticks as well.
16385 var pos = dc.getTargetCoord(pt.x, pt.y);
16387 var el = dc.getDragEl();
16388 var curRegion = new Roo.lib.Region( pos.y,
16389 pos.x + el.offsetWidth,
16390 pos.y + el.offsetHeight,
16393 var overlap = curRegion.intersect(loc);
16396 oTarget.overlap = overlap;
16397 return (intersect) ? true : oTarget.cursorIsOver;
16404 * unload event handler
16405 * @method _onUnload
16409 _onUnload: function(e, me) {
16410 Roo.dd.DragDropMgr.unregAll();
16414 * Cleans up the drag and drop events and objects.
16419 unregAll: function() {
16421 if (this.dragCurrent) {
16423 this.dragCurrent = null;
16426 this._execOnAll("unreg", []);
16428 for (i in this.elementCache) {
16429 delete this.elementCache[i];
16432 this.elementCache = {};
16437 * A cache of DOM elements
16438 * @property elementCache
16445 * Get the wrapper for the DOM element specified
16446 * @method getElWrapper
16447 * @param {String} id the id of the element to get
16448 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
16450 * @deprecated This wrapper isn't that useful
16453 getElWrapper: function(id) {
16454 var oWrapper = this.elementCache[id];
16455 if (!oWrapper || !oWrapper.el) {
16456 oWrapper = this.elementCache[id] =
16457 new this.ElementWrapper(Roo.getDom(id));
16463 * Returns the actual DOM element
16464 * @method getElement
16465 * @param {String} id the id of the elment to get
16466 * @return {Object} The element
16467 * @deprecated use Roo.getDom instead
16470 getElement: function(id) {
16471 return Roo.getDom(id);
16475 * Returns the style property for the DOM element (i.e.,
16476 * document.getElById(id).style)
16478 * @param {String} id the id of the elment to get
16479 * @return {Object} The style property of the element
16480 * @deprecated use Roo.getDom instead
16483 getCss: function(id) {
16484 var el = Roo.getDom(id);
16485 return (el) ? el.style : null;
16489 * Inner class for cached elements
16490 * @class DragDropMgr.ElementWrapper
16495 ElementWrapper: function(el) {
16500 this.el = el || null;
16505 this.id = this.el && el.id;
16507 * A reference to the style property
16510 this.css = this.el && el.style;
16514 * Returns the X position of an html element
16516 * @param el the element for which to get the position
16517 * @return {int} the X coordinate
16519 * @deprecated use Roo.lib.Dom.getX instead
16522 getPosX: function(el) {
16523 return Roo.lib.Dom.getX(el);
16527 * Returns the Y position of an html element
16529 * @param el the element for which to get the position
16530 * @return {int} the Y coordinate
16531 * @deprecated use Roo.lib.Dom.getY instead
16534 getPosY: function(el) {
16535 return Roo.lib.Dom.getY(el);
16539 * Swap two nodes. In IE, we use the native method, for others we
16540 * emulate the IE behavior
16542 * @param n1 the first node to swap
16543 * @param n2 the other node to swap
16546 swapNode: function(n1, n2) {
16550 var p = n2.parentNode;
16551 var s = n2.nextSibling;
16554 p.insertBefore(n1, n2);
16555 } else if (n2 == n1.nextSibling) {
16556 p.insertBefore(n2, n1);
16558 n1.parentNode.replaceChild(n2, n1);
16559 p.insertBefore(n1, s);
16565 * Returns the current scroll position
16566 * @method getScroll
16570 getScroll: function () {
16571 var t, l, dde=document.documentElement, db=document.body;
16572 if (dde && (dde.scrollTop || dde.scrollLeft)) {
16574 l = dde.scrollLeft;
16581 return { top: t, left: l };
16585 * Returns the specified element style property
16587 * @param {HTMLElement} el the element
16588 * @param {string} styleProp the style property
16589 * @return {string} The value of the style property
16590 * @deprecated use Roo.lib.Dom.getStyle
16593 getStyle: function(el, styleProp) {
16594 return Roo.fly(el).getStyle(styleProp);
16598 * Gets the scrollTop
16599 * @method getScrollTop
16600 * @return {int} the document's scrollTop
16603 getScrollTop: function () { return this.getScroll().top; },
16606 * Gets the scrollLeft
16607 * @method getScrollLeft
16608 * @return {int} the document's scrollTop
16611 getScrollLeft: function () { return this.getScroll().left; },
16614 * Sets the x/y position of an element to the location of the
16617 * @param {HTMLElement} moveEl The element to move
16618 * @param {HTMLElement} targetEl The position reference element
16621 moveToEl: function (moveEl, targetEl) {
16622 var aCoord = Roo.lib.Dom.getXY(targetEl);
16623 Roo.lib.Dom.setXY(moveEl, aCoord);
16627 * Numeric array sort function
16628 * @method numericSort
16631 numericSort: function(a, b) { return (a - b); },
16635 * @property _timeoutCount
16642 * Trying to make the load order less important. Without this we get
16643 * an error if this file is loaded before the Event Utility.
16644 * @method _addListeners
16648 _addListeners: function() {
16649 var DDM = Roo.dd.DDM;
16650 if ( Roo.lib.Event && document ) {
16653 if (DDM._timeoutCount > 2000) {
16655 setTimeout(DDM._addListeners, 10);
16656 if (document && document.body) {
16657 DDM._timeoutCount += 1;
16664 * Recursively searches the immediate parent and all child nodes for
16665 * the handle element in order to determine wheter or not it was
16667 * @method handleWasClicked
16668 * @param node the html element to inspect
16671 handleWasClicked: function(node, id) {
16672 if (this.isHandle(id, node.id)) {
16675 // check to see if this is a text node child of the one we want
16676 var p = node.parentNode;
16679 if (this.isHandle(id, p.id)) {
16694 // shorter alias, save a few bytes
16695 Roo.dd.DDM = Roo.dd.DragDropMgr;
16696 Roo.dd.DDM._addListeners();
16700 * Ext JS Library 1.1.1
16701 * Copyright(c) 2006-2007, Ext JS, LLC.
16703 * Originally Released Under LGPL - original licence link has changed is not relivant.
16706 * <script type="text/javascript">
16711 * A DragDrop implementation where the linked element follows the
16712 * mouse cursor during a drag.
16713 * @extends Roo.dd.DragDrop
16715 * @param {String} id the id of the linked element
16716 * @param {String} sGroup the group of related DragDrop items
16717 * @param {object} config an object containing configurable attributes
16718 * Valid properties for DD:
16721 Roo.dd.DD = function(id, sGroup, config) {
16723 this.init(id, sGroup, config);
16727 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
16730 * When set to true, the utility automatically tries to scroll the browser
16731 * window wehn a drag and drop element is dragged near the viewport boundary.
16732 * Defaults to true.
16739 * Sets the pointer offset to the distance between the linked element's top
16740 * left corner and the location the element was clicked
16741 * @method autoOffset
16742 * @param {int} iPageX the X coordinate of the click
16743 * @param {int} iPageY the Y coordinate of the click
16745 autoOffset: function(iPageX, iPageY) {
16746 var x = iPageX - this.startPageX;
16747 var y = iPageY - this.startPageY;
16748 this.setDelta(x, y);
16752 * Sets the pointer offset. You can call this directly to force the
16753 * offset to be in a particular location (e.g., pass in 0,0 to set it
16754 * to the center of the object)
16756 * @param {int} iDeltaX the distance from the left
16757 * @param {int} iDeltaY the distance from the top
16759 setDelta: function(iDeltaX, iDeltaY) {
16760 this.deltaX = iDeltaX;
16761 this.deltaY = iDeltaY;
16765 * Sets the drag element to the location of the mousedown or click event,
16766 * maintaining the cursor location relative to the location on the element
16767 * that was clicked. Override this if you want to place the element in a
16768 * location other than where the cursor is.
16769 * @method setDragElPos
16770 * @param {int} iPageX the X coordinate of the mousedown or drag event
16771 * @param {int} iPageY the Y coordinate of the mousedown or drag event
16773 setDragElPos: function(iPageX, iPageY) {
16774 // the first time we do this, we are going to check to make sure
16775 // the element has css positioning
16777 var el = this.getDragEl();
16778 this.alignElWithMouse(el, iPageX, iPageY);
16782 * Sets the element to the location of the mousedown or click event,
16783 * maintaining the cursor location relative to the location on the element
16784 * that was clicked. Override this if you want to place the element in a
16785 * location other than where the cursor is.
16786 * @method alignElWithMouse
16787 * @param {HTMLElement} el the element to move
16788 * @param {int} iPageX the X coordinate of the mousedown or drag event
16789 * @param {int} iPageY the Y coordinate of the mousedown or drag event
16791 alignElWithMouse: function(el, iPageX, iPageY) {
16792 var oCoord = this.getTargetCoord(iPageX, iPageY);
16793 var fly = el.dom ? el : Roo.fly(el);
16794 if (!this.deltaSetXY) {
16795 var aCoord = [oCoord.x, oCoord.y];
16797 var newLeft = fly.getLeft(true);
16798 var newTop = fly.getTop(true);
16799 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
16801 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
16804 this.cachePosition(oCoord.x, oCoord.y);
16805 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
16810 * Saves the most recent position so that we can reset the constraints and
16811 * tick marks on-demand. We need to know this so that we can calculate the
16812 * number of pixels the element is offset from its original position.
16813 * @method cachePosition
16814 * @param iPageX the current x position (optional, this just makes it so we
16815 * don't have to look it up again)
16816 * @param iPageY the current y position (optional, this just makes it so we
16817 * don't have to look it up again)
16819 cachePosition: function(iPageX, iPageY) {
16821 this.lastPageX = iPageX;
16822 this.lastPageY = iPageY;
16824 var aCoord = Roo.lib.Dom.getXY(this.getEl());
16825 this.lastPageX = aCoord[0];
16826 this.lastPageY = aCoord[1];
16831 * Auto-scroll the window if the dragged object has been moved beyond the
16832 * visible window boundary.
16833 * @method autoScroll
16834 * @param {int} x the drag element's x position
16835 * @param {int} y the drag element's y position
16836 * @param {int} h the height of the drag element
16837 * @param {int} w the width of the drag element
16840 autoScroll: function(x, y, h, w) {
16843 // The client height
16844 var clientH = Roo.lib.Dom.getViewWidth();
16846 // The client width
16847 var clientW = Roo.lib.Dom.getViewHeight();
16849 // The amt scrolled down
16850 var st = this.DDM.getScrollTop();
16852 // The amt scrolled right
16853 var sl = this.DDM.getScrollLeft();
16855 // Location of the bottom of the element
16858 // Location of the right of the element
16861 // The distance from the cursor to the bottom of the visible area,
16862 // adjusted so that we don't scroll if the cursor is beyond the
16863 // element drag constraints
16864 var toBot = (clientH + st - y - this.deltaY);
16866 // The distance from the cursor to the right of the visible area
16867 var toRight = (clientW + sl - x - this.deltaX);
16870 // How close to the edge the cursor must be before we scroll
16871 // var thresh = (document.all) ? 100 : 40;
16874 // How many pixels to scroll per autoscroll op. This helps to reduce
16875 // clunky scrolling. IE is more sensitive about this ... it needs this
16876 // value to be higher.
16877 var scrAmt = (document.all) ? 80 : 30;
16879 // Scroll down if we are near the bottom of the visible page and the
16880 // obj extends below the crease
16881 if ( bot > clientH && toBot < thresh ) {
16882 window.scrollTo(sl, st + scrAmt);
16885 // Scroll up if the window is scrolled down and the top of the object
16886 // goes above the top border
16887 if ( y < st && st > 0 && y - st < thresh ) {
16888 window.scrollTo(sl, st - scrAmt);
16891 // Scroll right if the obj is beyond the right border and the cursor is
16892 // near the border.
16893 if ( right > clientW && toRight < thresh ) {
16894 window.scrollTo(sl + scrAmt, st);
16897 // Scroll left if the window has been scrolled to the right and the obj
16898 // extends past the left border
16899 if ( x < sl && sl > 0 && x - sl < thresh ) {
16900 window.scrollTo(sl - scrAmt, st);
16906 * Finds the location the element should be placed if we want to move
16907 * it to where the mouse location less the click offset would place us.
16908 * @method getTargetCoord
16909 * @param {int} iPageX the X coordinate of the click
16910 * @param {int} iPageY the Y coordinate of the click
16911 * @return an object that contains the coordinates (Object.x and Object.y)
16914 getTargetCoord: function(iPageX, iPageY) {
16917 var x = iPageX - this.deltaX;
16918 var y = iPageY - this.deltaY;
16920 if (this.constrainX) {
16921 if (x < this.minX) { x = this.minX; }
16922 if (x > this.maxX) { x = this.maxX; }
16925 if (this.constrainY) {
16926 if (y < this.minY) { y = this.minY; }
16927 if (y > this.maxY) { y = this.maxY; }
16930 x = this.getTick(x, this.xTicks);
16931 y = this.getTick(y, this.yTicks);
16938 * Sets up config options specific to this class. Overrides
16939 * Roo.dd.DragDrop, but all versions of this method through the
16940 * inheritance chain are called
16942 applyConfig: function() {
16943 Roo.dd.DD.superclass.applyConfig.call(this);
16944 this.scroll = (this.config.scroll !== false);
16948 * Event that fires prior to the onMouseDown event. Overrides
16951 b4MouseDown: function(e) {
16952 // this.resetConstraints();
16953 this.autoOffset(e.getPageX(),
16958 * Event that fires prior to the onDrag event. Overrides
16961 b4Drag: function(e) {
16962 this.setDragElPos(e.getPageX(),
16966 toString: function() {
16967 return ("DD " + this.id);
16970 //////////////////////////////////////////////////////////////////////////
16971 // Debugging ygDragDrop events that can be overridden
16972 //////////////////////////////////////////////////////////////////////////
16974 startDrag: function(x, y) {
16977 onDrag: function(e) {
16980 onDragEnter: function(e, id) {
16983 onDragOver: function(e, id) {
16986 onDragOut: function(e, id) {
16989 onDragDrop: function(e, id) {
16992 endDrag: function(e) {
16999 * Ext JS Library 1.1.1
17000 * Copyright(c) 2006-2007, Ext JS, LLC.
17002 * Originally Released Under LGPL - original licence link has changed is not relivant.
17005 * <script type="text/javascript">
17009 * @class Roo.dd.DDProxy
17010 * A DragDrop implementation that inserts an empty, bordered div into
17011 * the document that follows the cursor during drag operations. At the time of
17012 * the click, the frame div is resized to the dimensions of the linked html
17013 * element, and moved to the exact location of the linked element.
17015 * References to the "frame" element refer to the single proxy element that
17016 * was created to be dragged in place of all DDProxy elements on the
17019 * @extends Roo.dd.DD
17021 * @param {String} id the id of the linked html element
17022 * @param {String} sGroup the group of related DragDrop objects
17023 * @param {object} config an object containing configurable attributes
17024 * Valid properties for DDProxy in addition to those in DragDrop:
17025 * resizeFrame, centerFrame, dragElId
17027 Roo.dd.DDProxy = function(id, sGroup, config) {
17029 this.init(id, sGroup, config);
17035 * The default drag frame div id
17036 * @property Roo.dd.DDProxy.dragElId
17040 Roo.dd.DDProxy.dragElId = "ygddfdiv";
17042 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
17045 * By default we resize the drag frame to be the same size as the element
17046 * we want to drag (this is to get the frame effect). We can turn it off
17047 * if we want a different behavior.
17048 * @property resizeFrame
17054 * By default the frame is positioned exactly where the drag element is, so
17055 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
17056 * you do not have constraints on the obj is to have the drag frame centered
17057 * around the cursor. Set centerFrame to true for this effect.
17058 * @property centerFrame
17061 centerFrame: false,
17064 * Creates the proxy element if it does not yet exist
17065 * @method createFrame
17067 createFrame: function() {
17069 var body = document.body;
17071 if (!body || !body.firstChild) {
17072 setTimeout( function() { self.createFrame(); }, 50 );
17076 var div = this.getDragEl();
17079 div = document.createElement("div");
17080 div.id = this.dragElId;
17083 s.position = "absolute";
17084 s.visibility = "hidden";
17086 s.border = "2px solid #aaa";
17089 // appendChild can blow up IE if invoked prior to the window load event
17090 // while rendering a table. It is possible there are other scenarios
17091 // that would cause this to happen as well.
17092 body.insertBefore(div, body.firstChild);
17097 * Initialization for the drag frame element. Must be called in the
17098 * constructor of all subclasses
17099 * @method initFrame
17101 initFrame: function() {
17102 this.createFrame();
17105 applyConfig: function() {
17106 Roo.dd.DDProxy.superclass.applyConfig.call(this);
17108 this.resizeFrame = (this.config.resizeFrame !== false);
17109 this.centerFrame = (this.config.centerFrame);
17110 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
17114 * Resizes the drag frame to the dimensions of the clicked object, positions
17115 * it over the object, and finally displays it
17116 * @method showFrame
17117 * @param {int} iPageX X click position
17118 * @param {int} iPageY Y click position
17121 showFrame: function(iPageX, iPageY) {
17122 var el = this.getEl();
17123 var dragEl = this.getDragEl();
17124 var s = dragEl.style;
17126 this._resizeProxy();
17128 if (this.centerFrame) {
17129 this.setDelta( Math.round(parseInt(s.width, 10)/2),
17130 Math.round(parseInt(s.height, 10)/2) );
17133 this.setDragElPos(iPageX, iPageY);
17135 Roo.fly(dragEl).show();
17139 * The proxy is automatically resized to the dimensions of the linked
17140 * element when a drag is initiated, unless resizeFrame is set to false
17141 * @method _resizeProxy
17144 _resizeProxy: function() {
17145 if (this.resizeFrame) {
17146 var el = this.getEl();
17147 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
17151 // overrides Roo.dd.DragDrop
17152 b4MouseDown: function(e) {
17153 var x = e.getPageX();
17154 var y = e.getPageY();
17155 this.autoOffset(x, y);
17156 this.setDragElPos(x, y);
17159 // overrides Roo.dd.DragDrop
17160 b4StartDrag: function(x, y) {
17161 // show the drag frame
17162 this.showFrame(x, y);
17165 // overrides Roo.dd.DragDrop
17166 b4EndDrag: function(e) {
17167 Roo.fly(this.getDragEl()).hide();
17170 // overrides Roo.dd.DragDrop
17171 // By default we try to move the element to the last location of the frame.
17172 // This is so that the default behavior mirrors that of Roo.dd.DD.
17173 endDrag: function(e) {
17175 var lel = this.getEl();
17176 var del = this.getDragEl();
17178 // Show the drag frame briefly so we can get its position
17179 del.style.visibility = "";
17182 // Hide the linked element before the move to get around a Safari
17184 lel.style.visibility = "hidden";
17185 Roo.dd.DDM.moveToEl(lel, del);
17186 del.style.visibility = "hidden";
17187 lel.style.visibility = "";
17192 beforeMove : function(){
17196 afterDrag : function(){
17200 toString: function() {
17201 return ("DDProxy " + this.id);
17207 * Ext JS Library 1.1.1
17208 * Copyright(c) 2006-2007, Ext JS, LLC.
17210 * Originally Released Under LGPL - original licence link has changed is not relivant.
17213 * <script type="text/javascript">
17217 * @class Roo.dd.DDTarget
17218 * A DragDrop implementation that does not move, but can be a drop
17219 * target. You would get the same result by simply omitting implementation
17220 * for the event callbacks, but this way we reduce the processing cost of the
17221 * event listener and the callbacks.
17222 * @extends Roo.dd.DragDrop
17224 * @param {String} id the id of the element that is a drop target
17225 * @param {String} sGroup the group of related DragDrop objects
17226 * @param {object} config an object containing configurable attributes
17227 * Valid properties for DDTarget in addition to those in
17231 Roo.dd.DDTarget = function(id, sGroup, config) {
17233 this.initTarget(id, sGroup, config);
17237 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
17238 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
17239 toString: function() {
17240 return ("DDTarget " + this.id);
17245 * Ext JS Library 1.1.1
17246 * Copyright(c) 2006-2007, Ext JS, LLC.
17248 * Originally Released Under LGPL - original licence link has changed is not relivant.
17251 * <script type="text/javascript">
17256 * @class Roo.dd.ScrollManager
17257 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
17258 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
17261 Roo.dd.ScrollManager = function(){
17262 var ddm = Roo.dd.DragDropMgr;
17267 var onStop = function(e){
17272 var triggerRefresh = function(){
17273 if(ddm.dragCurrent){
17274 ddm.refreshCache(ddm.dragCurrent.groups);
17278 var doScroll = function(){
17279 if(ddm.dragCurrent){
17280 var dds = Roo.dd.ScrollManager;
17282 if(proc.el.scroll(proc.dir, dds.increment)){
17286 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
17291 var clearProc = function(){
17293 clearInterval(proc.id);
17300 var startProc = function(el, dir){
17304 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
17307 var onFire = function(e, isDrop){
17308 if(isDrop || !ddm.dragCurrent){ return; }
17309 var dds = Roo.dd.ScrollManager;
17310 if(!dragEl || dragEl != ddm.dragCurrent){
17311 dragEl = ddm.dragCurrent;
17312 // refresh regions on drag start
17313 dds.refreshCache();
17316 var xy = Roo.lib.Event.getXY(e);
17317 var pt = new Roo.lib.Point(xy[0], xy[1]);
17318 for(var id in els){
17319 var el = els[id], r = el._region;
17320 if(r && r.contains(pt) && el.isScrollable()){
17321 if(r.bottom - pt.y <= dds.thresh){
17323 startProc(el, "down");
17326 }else if(r.right - pt.x <= dds.thresh){
17328 startProc(el, "left");
17331 }else if(pt.y - r.top <= dds.thresh){
17333 startProc(el, "up");
17336 }else if(pt.x - r.left <= dds.thresh){
17338 startProc(el, "right");
17347 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
17348 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
17352 * Registers new overflow element(s) to auto scroll
17353 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
17355 register : function(el){
17356 if(el instanceof Array){
17357 for(var i = 0, len = el.length; i < len; i++) {
17358 this.register(el[i]);
17367 * Unregisters overflow element(s) so they are no longer scrolled
17368 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
17370 unregister : function(el){
17371 if(el instanceof Array){
17372 for(var i = 0, len = el.length; i < len; i++) {
17373 this.unregister(el[i]);
17382 * The number of pixels from the edge of a container the pointer needs to be to
17383 * trigger scrolling (defaults to 25)
17389 * The number of pixels to scroll in each scroll increment (defaults to 50)
17395 * The frequency of scrolls in milliseconds (defaults to 500)
17401 * True to animate the scroll (defaults to true)
17407 * The animation duration in seconds -
17408 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
17414 * Manually trigger a cache refresh.
17416 refreshCache : function(){
17417 for(var id in els){
17418 if(typeof els[id] == 'object'){ // for people extending the object prototype
17419 els[id]._region = els[id].getRegion();
17426 * Ext JS Library 1.1.1
17427 * Copyright(c) 2006-2007, Ext JS, LLC.
17429 * Originally Released Under LGPL - original licence link has changed is not relivant.
17432 * <script type="text/javascript">
17437 * @class Roo.dd.Registry
17438 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
17439 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
17442 Roo.dd.Registry = function(){
17445 var autoIdSeed = 0;
17447 var getId = function(el, autogen){
17448 if(typeof el == "string"){
17452 if(!id && autogen !== false){
17453 id = "roodd-" + (++autoIdSeed);
17461 * Register a drag drop element
17462 * @param {String/HTMLElement) element The id or DOM node to register
17463 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
17464 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
17465 * knows how to interpret, plus there are some specific properties known to the Registry that should be
17466 * populated in the data object (if applicable):
17468 Value Description<br />
17469 --------- ------------------------------------------<br />
17470 handles Array of DOM nodes that trigger dragging<br />
17471 for the element being registered<br />
17472 isHandle True if the element passed in triggers<br />
17473 dragging itself, else false
17476 register : function(el, data){
17478 if(typeof el == "string"){
17479 el = document.getElementById(el);
17482 elements[getId(el)] = data;
17483 if(data.isHandle !== false){
17484 handles[data.ddel.id] = data;
17487 var hs = data.handles;
17488 for(var i = 0, len = hs.length; i < len; i++){
17489 handles[getId(hs[i])] = data;
17495 * Unregister a drag drop element
17496 * @param {String/HTMLElement) element The id or DOM node to unregister
17498 unregister : function(el){
17499 var id = getId(el, false);
17500 var data = elements[id];
17502 delete elements[id];
17504 var hs = data.handles;
17505 for(var i = 0, len = hs.length; i < len; i++){
17506 delete handles[getId(hs[i], false)];
17513 * Returns the handle registered for a DOM Node by id
17514 * @param {String/HTMLElement} id The DOM node or id to look up
17515 * @return {Object} handle The custom handle data
17517 getHandle : function(id){
17518 if(typeof id != "string"){ // must be element?
17521 return handles[id];
17525 * Returns the handle that is registered for the DOM node that is the target of the event
17526 * @param {Event} e The event
17527 * @return {Object} handle The custom handle data
17529 getHandleFromEvent : function(e){
17530 var t = Roo.lib.Event.getTarget(e);
17531 return t ? handles[t.id] : null;
17535 * Returns a custom data object that is registered for a DOM node by id
17536 * @param {String/HTMLElement} id The DOM node or id to look up
17537 * @return {Object} data The custom data
17539 getTarget : function(id){
17540 if(typeof id != "string"){ // must be element?
17543 return elements[id];
17547 * Returns a custom data object that is registered for the DOM node that is the target of the event
17548 * @param {Event} e The event
17549 * @return {Object} data The custom data
17551 getTargetFromEvent : function(e){
17552 var t = Roo.lib.Event.getTarget(e);
17553 return t ? elements[t.id] || handles[t.id] : null;
17558 * Ext JS Library 1.1.1
17559 * Copyright(c) 2006-2007, Ext JS, LLC.
17561 * Originally Released Under LGPL - original licence link has changed is not relivant.
17564 * <script type="text/javascript">
17569 * @class Roo.dd.StatusProxy
17570 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
17571 * default drag proxy used by all Roo.dd components.
17573 * @param {Object} config
17575 Roo.dd.StatusProxy = function(config){
17576 Roo.apply(this, config);
17577 this.id = this.id || Roo.id();
17578 this.el = new Roo.Layer({
17580 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
17581 {tag: "div", cls: "x-dd-drop-icon"},
17582 {tag: "div", cls: "x-dd-drag-ghost"}
17585 shadow: !config || config.shadow !== false
17587 this.ghost = Roo.get(this.el.dom.childNodes[1]);
17588 this.dropStatus = this.dropNotAllowed;
17591 Roo.dd.StatusProxy.prototype = {
17593 * @cfg {String} dropAllowed
17594 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
17596 dropAllowed : "x-dd-drop-ok",
17598 * @cfg {String} dropNotAllowed
17599 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
17601 dropNotAllowed : "x-dd-drop-nodrop",
17604 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
17605 * over the current target element.
17606 * @param {String} cssClass The css class for the new drop status indicator image
17608 setStatus : function(cssClass){
17609 cssClass = cssClass || this.dropNotAllowed;
17610 if(this.dropStatus != cssClass){
17611 this.el.replaceClass(this.dropStatus, cssClass);
17612 this.dropStatus = cssClass;
17617 * Resets the status indicator to the default dropNotAllowed value
17618 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
17620 reset : function(clearGhost){
17621 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
17622 this.dropStatus = this.dropNotAllowed;
17624 this.ghost.update("");
17629 * Updates the contents of the ghost element
17630 * @param {String} html The html that will replace the current innerHTML of the ghost element
17632 update : function(html){
17633 if(typeof html == "string"){
17634 this.ghost.update(html);
17636 this.ghost.update("");
17637 html.style.margin = "0";
17638 this.ghost.dom.appendChild(html);
17640 // ensure float = none set?? cant remember why though.
17641 var el = this.ghost.dom.firstChild;
17643 Roo.fly(el).setStyle('float', 'none');
17648 * Returns the underlying proxy {@link Roo.Layer}
17649 * @return {Roo.Layer} el
17651 getEl : function(){
17656 * Returns the ghost element
17657 * @return {Roo.Element} el
17659 getGhost : function(){
17665 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
17667 hide : function(clear){
17675 * Stops the repair animation if it's currently running
17678 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
17684 * Displays this proxy
17691 * Force the Layer to sync its shadow and shim positions to the element
17698 * Causes the proxy to return to its position of origin via an animation. Should be called after an
17699 * invalid drop operation by the item being dragged.
17700 * @param {Array} xy The XY position of the element ([x, y])
17701 * @param {Function} callback The function to call after the repair is complete
17702 * @param {Object} scope The scope in which to execute the callback
17704 repair : function(xy, callback, scope){
17705 this.callback = callback;
17706 this.scope = scope;
17707 if(xy && this.animRepair !== false){
17708 this.el.addClass("x-dd-drag-repair");
17709 this.el.hideUnders(true);
17710 this.anim = this.el.shift({
17711 duration: this.repairDuration || .5,
17715 callback: this.afterRepair,
17719 this.afterRepair();
17724 afterRepair : function(){
17726 if(typeof this.callback == "function"){
17727 this.callback.call(this.scope || this);
17729 this.callback = null;
17734 * Ext JS Library 1.1.1
17735 * Copyright(c) 2006-2007, Ext JS, LLC.
17737 * Originally Released Under LGPL - original licence link has changed is not relivant.
17740 * <script type="text/javascript">
17744 * @class Roo.dd.DragSource
17745 * @extends Roo.dd.DDProxy
17746 * A simple class that provides the basic implementation needed to make any element draggable.
17748 * @param {String/HTMLElement/Element} el The container element
17749 * @param {Object} config
17751 Roo.dd.DragSource = function(el, config){
17752 this.el = Roo.get(el);
17753 this.dragData = {};
17755 Roo.apply(this, config);
17758 this.proxy = new Roo.dd.StatusProxy();
17761 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
17762 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
17764 this.dragging = false;
17767 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
17769 * @cfg {String} dropAllowed
17770 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
17772 dropAllowed : "x-dd-drop-ok",
17774 * @cfg {String} dropNotAllowed
17775 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
17777 dropNotAllowed : "x-dd-drop-nodrop",
17780 * Returns the data object associated with this drag source
17781 * @return {Object} data An object containing arbitrary data
17783 getDragData : function(e){
17784 return this.dragData;
17788 onDragEnter : function(e, id){
17789 var target = Roo.dd.DragDropMgr.getDDById(id);
17790 this.cachedTarget = target;
17791 if(this.beforeDragEnter(target, e, id) !== false){
17792 if(target.isNotifyTarget){
17793 var status = target.notifyEnter(this, e, this.dragData);
17794 this.proxy.setStatus(status);
17796 this.proxy.setStatus(this.dropAllowed);
17799 if(this.afterDragEnter){
17801 * An empty function by default, but provided so that you can perform a custom action
17802 * when the dragged item enters the drop target by providing an implementation.
17803 * @param {Roo.dd.DragDrop} target The drop target
17804 * @param {Event} e The event object
17805 * @param {String} id The id of the dragged element
17806 * @method afterDragEnter
17808 this.afterDragEnter(target, e, id);
17814 * An empty function by default, but provided so that you can perform a custom action
17815 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
17816 * @param {Roo.dd.DragDrop} target The drop target
17817 * @param {Event} e The event object
17818 * @param {String} id The id of the dragged element
17819 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
17821 beforeDragEnter : function(target, e, id){
17826 alignElWithMouse: function() {
17827 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
17832 onDragOver : function(e, id){
17833 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
17834 if(this.beforeDragOver(target, e, id) !== false){
17835 if(target.isNotifyTarget){
17836 var status = target.notifyOver(this, e, this.dragData);
17837 this.proxy.setStatus(status);
17840 if(this.afterDragOver){
17842 * An empty function by default, but provided so that you can perform a custom action
17843 * while the dragged item is over the drop target by providing an implementation.
17844 * @param {Roo.dd.DragDrop} target The drop target
17845 * @param {Event} e The event object
17846 * @param {String} id The id of the dragged element
17847 * @method afterDragOver
17849 this.afterDragOver(target, e, id);
17855 * An empty function by default, but provided so that you can perform a custom action
17856 * while the dragged item is over the drop target and optionally cancel the onDragOver.
17857 * @param {Roo.dd.DragDrop} target The drop target
17858 * @param {Event} e The event object
17859 * @param {String} id The id of the dragged element
17860 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
17862 beforeDragOver : function(target, e, id){
17867 onDragOut : function(e, id){
17868 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
17869 if(this.beforeDragOut(target, e, id) !== false){
17870 if(target.isNotifyTarget){
17871 target.notifyOut(this, e, this.dragData);
17873 this.proxy.reset();
17874 if(this.afterDragOut){
17876 * An empty function by default, but provided so that you can perform a custom action
17877 * after the dragged item is dragged out of the target without dropping.
17878 * @param {Roo.dd.DragDrop} target The drop target
17879 * @param {Event} e The event object
17880 * @param {String} id The id of the dragged element
17881 * @method afterDragOut
17883 this.afterDragOut(target, e, id);
17886 this.cachedTarget = null;
17890 * An empty function by default, but provided so that you can perform a custom action before the dragged
17891 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
17892 * @param {Roo.dd.DragDrop} target The drop target
17893 * @param {Event} e The event object
17894 * @param {String} id The id of the dragged element
17895 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
17897 beforeDragOut : function(target, e, id){
17902 onDragDrop : function(e, id){
17903 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
17904 if(this.beforeDragDrop(target, e, id) !== false){
17905 if(target.isNotifyTarget){
17906 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
17907 this.onValidDrop(target, e, id);
17909 this.onInvalidDrop(target, e, id);
17912 this.onValidDrop(target, e, id);
17915 if(this.afterDragDrop){
17917 * An empty function by default, but provided so that you can perform a custom action
17918 * after a valid drag drop has occurred by providing an implementation.
17919 * @param {Roo.dd.DragDrop} target The drop target
17920 * @param {Event} e The event object
17921 * @param {String} id The id of the dropped element
17922 * @method afterDragDrop
17924 this.afterDragDrop(target, e, id);
17927 delete this.cachedTarget;
17931 * An empty function by default, but provided so that you can perform a custom action before the dragged
17932 * item is dropped onto the target and optionally cancel the onDragDrop.
17933 * @param {Roo.dd.DragDrop} target The drop target
17934 * @param {Event} e The event object
17935 * @param {String} id The id of the dragged element
17936 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
17938 beforeDragDrop : function(target, e, id){
17943 onValidDrop : function(target, e, id){
17945 if(this.afterValidDrop){
17947 * An empty function by default, but provided so that you can perform a custom action
17948 * after a valid drop has occurred by providing an implementation.
17949 * @param {Object} target The target DD
17950 * @param {Event} e The event object
17951 * @param {String} id The id of the dropped element
17952 * @method afterInvalidDrop
17954 this.afterValidDrop(target, e, id);
17959 getRepairXY : function(e, data){
17960 return this.el.getXY();
17964 onInvalidDrop : function(target, e, id){
17965 this.beforeInvalidDrop(target, e, id);
17966 if(this.cachedTarget){
17967 if(this.cachedTarget.isNotifyTarget){
17968 this.cachedTarget.notifyOut(this, e, this.dragData);
17970 this.cacheTarget = null;
17972 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
17974 if(this.afterInvalidDrop){
17976 * An empty function by default, but provided so that you can perform a custom action
17977 * after an invalid drop has occurred by providing an implementation.
17978 * @param {Event} e The event object
17979 * @param {String} id The id of the dropped element
17980 * @method afterInvalidDrop
17982 this.afterInvalidDrop(e, id);
17987 afterRepair : function(){
17989 this.el.highlight(this.hlColor || "c3daf9");
17991 this.dragging = false;
17995 * An empty function by default, but provided so that you can perform a custom action after an invalid
17996 * drop has occurred.
17997 * @param {Roo.dd.DragDrop} target The drop target
17998 * @param {Event} e The event object
17999 * @param {String} id The id of the dragged element
18000 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
18002 beforeInvalidDrop : function(target, e, id){
18007 handleMouseDown : function(e){
18008 if(this.dragging) {
18011 var data = this.getDragData(e);
18012 if(data && this.onBeforeDrag(data, e) !== false){
18013 this.dragData = data;
18015 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
18020 * An empty function by default, but provided so that you can perform a custom action before the initial
18021 * drag event begins and optionally cancel it.
18022 * @param {Object} data An object containing arbitrary data to be shared with drop targets
18023 * @param {Event} e The event object
18024 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18026 onBeforeDrag : function(data, e){
18031 * An empty function by default, but provided so that you can perform a custom action once the initial
18032 * drag event has begun. The drag cannot be canceled from this function.
18033 * @param {Number} x The x position of the click on the dragged object
18034 * @param {Number} y The y position of the click on the dragged object
18036 onStartDrag : Roo.emptyFn,
18038 // private - YUI override
18039 startDrag : function(x, y){
18040 this.proxy.reset();
18041 this.dragging = true;
18042 this.proxy.update("");
18043 this.onInitDrag(x, y);
18048 onInitDrag : function(x, y){
18049 var clone = this.el.dom.cloneNode(true);
18050 clone.id = Roo.id(); // prevent duplicate ids
18051 this.proxy.update(clone);
18052 this.onStartDrag(x, y);
18057 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
18058 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
18060 getProxy : function(){
18065 * Hides the drag source's {@link Roo.dd.StatusProxy}
18067 hideProxy : function(){
18069 this.proxy.reset(true);
18070 this.dragging = false;
18074 triggerCacheRefresh : function(){
18075 Roo.dd.DDM.refreshCache(this.groups);
18078 // private - override to prevent hiding
18079 b4EndDrag: function(e) {
18082 // private - override to prevent moving
18083 endDrag : function(e){
18084 this.onEndDrag(this.dragData, e);
18088 onEndDrag : function(data, e){
18091 // private - pin to cursor
18092 autoOffset : function(x, y) {
18093 this.setDelta(-12, -20);
18097 * Ext JS Library 1.1.1
18098 * Copyright(c) 2006-2007, Ext JS, LLC.
18100 * Originally Released Under LGPL - original licence link has changed is not relivant.
18103 * <script type="text/javascript">
18108 * @class Roo.dd.DropTarget
18109 * @extends Roo.dd.DDTarget
18110 * A simple class that provides the basic implementation needed to make any element a drop target that can have
18111 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
18113 * @param {String/HTMLElement/Element} el The container element
18114 * @param {Object} config
18116 Roo.dd.DropTarget = function(el, config){
18117 this.el = Roo.get(el);
18119 Roo.apply(this, config);
18121 if(this.containerScroll){
18122 Roo.dd.ScrollManager.register(this.el);
18125 Roo.dd.DropTarget.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
18130 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
18132 * @cfg {String} overClass
18133 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
18136 * @cfg {String} dropAllowed
18137 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
18139 dropAllowed : "x-dd-drop-ok",
18141 * @cfg {String} dropNotAllowed
18142 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
18144 dropNotAllowed : "x-dd-drop-nodrop",
18150 isNotifyTarget : true,
18153 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
18154 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
18155 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
18156 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18157 * @param {Event} e The event
18158 * @param {Object} data An object containing arbitrary data supplied by the drag source
18159 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18160 * underlying {@link Roo.dd.StatusProxy} can be updated
18162 notifyEnter : function(dd, e, data){
18163 if(this.overClass){
18164 this.el.addClass(this.overClass);
18166 return this.dropAllowed;
18170 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
18171 * This method will be called on every mouse movement while the drag source is over the drop target.
18172 * This default implementation simply returns the dropAllowed config value.
18173 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18174 * @param {Event} e The event
18175 * @param {Object} data An object containing arbitrary data supplied by the drag source
18176 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18177 * underlying {@link Roo.dd.StatusProxy} can be updated
18179 notifyOver : function(dd, e, data){
18180 return this.dropAllowed;
18184 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
18185 * out of the target without dropping. This default implementation simply removes the CSS class specified by
18186 * overClass (if any) from the drop element.
18187 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18188 * @param {Event} e The event
18189 * @param {Object} data An object containing arbitrary data supplied by the drag source
18191 notifyOut : function(dd, e, data){
18192 if(this.overClass){
18193 this.el.removeClass(this.overClass);
18198 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
18199 * been dropped on it. This method has no default implementation and returns false, so you must provide an
18200 * implementation that does something to process the drop event and returns true so that the drag source's
18201 * repair action does not run.
18202 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18203 * @param {Event} e The event
18204 * @param {Object} data An object containing arbitrary data supplied by the drag source
18205 * @return {Boolean} True if the drop was valid, else false
18207 notifyDrop : function(dd, e, data){
18212 * Ext JS Library 1.1.1
18213 * Copyright(c) 2006-2007, Ext JS, LLC.
18215 * Originally Released Under LGPL - original licence link has changed is not relivant.
18218 * <script type="text/javascript">
18223 * @class Roo.dd.DragZone
18224 * @extends Roo.dd.DragSource
18225 * This class provides a container DD instance that proxies for multiple child node sources.<br />
18226 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
18228 * @param {String/HTMLElement/Element} el The container element
18229 * @param {Object} config
18231 Roo.dd.DragZone = function(el, config){
18232 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
18233 if(this.containerScroll){
18234 Roo.dd.ScrollManager.register(this.el);
18238 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
18240 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
18241 * for auto scrolling during drag operations.
18244 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
18245 * method after a failed drop (defaults to "c3daf9" - light blue)
18249 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
18250 * for a valid target to drag based on the mouse down. Override this method
18251 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
18252 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
18253 * @param {EventObject} e The mouse down event
18254 * @return {Object} The dragData
18256 getDragData : function(e){
18257 return Roo.dd.Registry.getHandleFromEvent(e);
18261 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
18262 * this.dragData.ddel
18263 * @param {Number} x The x position of the click on the dragged object
18264 * @param {Number} y The y position of the click on the dragged object
18265 * @return {Boolean} true to continue the drag, false to cancel
18267 onInitDrag : function(x, y){
18268 this.proxy.update(this.dragData.ddel.cloneNode(true));
18269 this.onStartDrag(x, y);
18274 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
18276 afterRepair : function(){
18278 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
18280 this.dragging = false;
18284 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
18285 * the XY of this.dragData.ddel
18286 * @param {EventObject} e The mouse up event
18287 * @return {Array} The xy location (e.g. [100, 200])
18289 getRepairXY : function(e){
18290 return Roo.Element.fly(this.dragData.ddel).getXY();
18294 * Ext JS Library 1.1.1
18295 * Copyright(c) 2006-2007, Ext JS, LLC.
18297 * Originally Released Under LGPL - original licence link has changed is not relivant.
18300 * <script type="text/javascript">
18303 * @class Roo.dd.DropZone
18304 * @extends Roo.dd.DropTarget
18305 * This class provides a container DD instance that proxies for multiple child node targets.<br />
18306 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
18308 * @param {String/HTMLElement/Element} el The container element
18309 * @param {Object} config
18311 Roo.dd.DropZone = function(el, config){
18312 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
18315 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
18317 * Returns a custom data object associated with the DOM node that is the target of the event. By default
18318 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
18319 * provide your own custom lookup.
18320 * @param {Event} e The event
18321 * @return {Object} data The custom data
18323 getTargetFromEvent : function(e){
18324 return Roo.dd.Registry.getTargetFromEvent(e);
18328 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
18329 * that it has registered. This method has no default implementation and should be overridden to provide
18330 * node-specific processing if necessary.
18331 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18332 * {@link #getTargetFromEvent} for this node)
18333 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18334 * @param {Event} e The event
18335 * @param {Object} data An object containing arbitrary data supplied by the drag source
18337 onNodeEnter : function(n, dd, e, data){
18342 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
18343 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
18344 * overridden to provide the proper feedback.
18345 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18346 * {@link #getTargetFromEvent} for this node)
18347 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18348 * @param {Event} e The event
18349 * @param {Object} data An object containing arbitrary data supplied by the drag source
18350 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18351 * underlying {@link Roo.dd.StatusProxy} can be updated
18353 onNodeOver : function(n, dd, e, data){
18354 return this.dropAllowed;
18358 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
18359 * the drop node without dropping. This method has no default implementation and should be overridden to provide
18360 * node-specific processing if necessary.
18361 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18362 * {@link #getTargetFromEvent} for this node)
18363 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18364 * @param {Event} e The event
18365 * @param {Object} data An object containing arbitrary data supplied by the drag source
18367 onNodeOut : function(n, dd, e, data){
18372 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
18373 * the drop node. The default implementation returns false, so it should be overridden to provide the
18374 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
18375 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18376 * {@link #getTargetFromEvent} for this node)
18377 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18378 * @param {Event} e The event
18379 * @param {Object} data An object containing arbitrary data supplied by the drag source
18380 * @return {Boolean} True if the drop was valid, else false
18382 onNodeDrop : function(n, dd, e, data){
18387 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
18388 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
18389 * it should be overridden to provide the proper feedback if necessary.
18390 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18391 * @param {Event} e The event
18392 * @param {Object} data An object containing arbitrary data supplied by the drag source
18393 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18394 * underlying {@link Roo.dd.StatusProxy} can be updated
18396 onContainerOver : function(dd, e, data){
18397 return this.dropNotAllowed;
18401 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
18402 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
18403 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
18404 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
18405 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18406 * @param {Event} e The event
18407 * @param {Object} data An object containing arbitrary data supplied by the drag source
18408 * @return {Boolean} True if the drop was valid, else false
18410 onContainerDrop : function(dd, e, data){
18415 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
18416 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
18417 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
18418 * you should override this method and provide a custom implementation.
18419 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18420 * @param {Event} e The event
18421 * @param {Object} data An object containing arbitrary data supplied by the drag source
18422 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18423 * underlying {@link Roo.dd.StatusProxy} can be updated
18425 notifyEnter : function(dd, e, data){
18426 return this.dropNotAllowed;
18430 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
18431 * This method will be called on every mouse movement while the drag source is over the drop zone.
18432 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
18433 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
18434 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
18435 * registered node, it will call {@link #onContainerOver}.
18436 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18437 * @param {Event} e The event
18438 * @param {Object} data An object containing arbitrary data supplied by the drag source
18439 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18440 * underlying {@link Roo.dd.StatusProxy} can be updated
18442 notifyOver : function(dd, e, data){
18443 var n = this.getTargetFromEvent(e);
18444 if(!n){ // not over valid drop target
18445 if(this.lastOverNode){
18446 this.onNodeOut(this.lastOverNode, dd, e, data);
18447 this.lastOverNode = null;
18449 return this.onContainerOver(dd, e, data);
18451 if(this.lastOverNode != n){
18452 if(this.lastOverNode){
18453 this.onNodeOut(this.lastOverNode, dd, e, data);
18455 this.onNodeEnter(n, dd, e, data);
18456 this.lastOverNode = n;
18458 return this.onNodeOver(n, dd, e, data);
18462 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
18463 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
18464 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
18465 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18466 * @param {Event} e The event
18467 * @param {Object} data An object containing arbitrary data supplied by the drag zone
18469 notifyOut : function(dd, e, data){
18470 if(this.lastOverNode){
18471 this.onNodeOut(this.lastOverNode, dd, e, data);
18472 this.lastOverNode = null;
18477 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
18478 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
18479 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
18480 * otherwise it will call {@link #onContainerDrop}.
18481 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18482 * @param {Event} e The event
18483 * @param {Object} data An object containing arbitrary data supplied by the drag source
18484 * @return {Boolean} True if the drop was valid, else false
18486 notifyDrop : function(dd, e, data){
18487 if(this.lastOverNode){
18488 this.onNodeOut(this.lastOverNode, dd, e, data);
18489 this.lastOverNode = null;
18491 var n = this.getTargetFromEvent(e);
18493 this.onNodeDrop(n, dd, e, data) :
18494 this.onContainerDrop(dd, e, data);
18498 triggerCacheRefresh : function(){
18499 Roo.dd.DDM.refreshCache(this.groups);
18503 * Ext JS Library 1.1.1
18504 * Copyright(c) 2006-2007, Ext JS, LLC.
18506 * Originally Released Under LGPL - original licence link has changed is not relivant.
18509 * <script type="text/javascript">
18514 * @class Roo.data.SortTypes
18516 * Defines the default sorting (casting?) comparison functions used when sorting data.
18518 Roo.data.SortTypes = {
18520 * Default sort that does nothing
18521 * @param {Mixed} s The value being converted
18522 * @return {Mixed} The comparison value
18524 none : function(s){
18529 * The regular expression used to strip tags
18533 stripTagsRE : /<\/?[^>]+>/gi,
18536 * Strips all HTML tags to sort on text only
18537 * @param {Mixed} s The value being converted
18538 * @return {String} The comparison value
18540 asText : function(s){
18541 return String(s).replace(this.stripTagsRE, "");
18545 * Strips all HTML tags to sort on text only - Case insensitive
18546 * @param {Mixed} s The value being converted
18547 * @return {String} The comparison value
18549 asUCText : function(s){
18550 return String(s).toUpperCase().replace(this.stripTagsRE, "");
18554 * Case insensitive string
18555 * @param {Mixed} s The value being converted
18556 * @return {String} The comparison value
18558 asUCString : function(s) {
18559 return String(s).toUpperCase();
18564 * @param {Mixed} s The value being converted
18565 * @return {Number} The comparison value
18567 asDate : function(s) {
18571 if(s instanceof Date){
18572 return s.getTime();
18574 return Date.parse(String(s));
18579 * @param {Mixed} s The value being converted
18580 * @return {Float} The comparison value
18582 asFloat : function(s) {
18583 var val = parseFloat(String(s).replace(/,/g, ""));
18584 if(isNaN(val)) val = 0;
18590 * @param {Mixed} s The value being converted
18591 * @return {Number} The comparison value
18593 asInt : function(s) {
18594 var val = parseInt(String(s).replace(/,/g, ""));
18595 if(isNaN(val)) val = 0;
18600 * Ext JS Library 1.1.1
18601 * Copyright(c) 2006-2007, Ext JS, LLC.
18603 * Originally Released Under LGPL - original licence link has changed is not relivant.
18606 * <script type="text/javascript">
18610 * @class Roo.data.Record
18611 * Instances of this class encapsulate both record <em>definition</em> information, and record
18612 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
18613 * to access Records cached in an {@link Roo.data.Store} object.<br>
18615 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
18616 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
18619 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
18621 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
18622 * {@link #create}. The parameters are the same.
18623 * @param {Array} data An associative Array of data values keyed by the field name.
18624 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
18625 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
18626 * not specified an integer id is generated.
18628 Roo.data.Record = function(data, id){
18629 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
18634 * Generate a constructor for a specific record layout.
18635 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
18636 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
18637 * Each field definition object may contain the following properties: <ul>
18638 * <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,
18639 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
18640 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
18641 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
18642 * is being used, then this is a string containing the javascript expression to reference the data relative to
18643 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
18644 * to the data item relative to the record element. If the mapping expression is the same as the field name,
18645 * this may be omitted.</p></li>
18646 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
18647 * <ul><li>auto (Default, implies no conversion)</li>
18652 * <li>date</li></ul></p></li>
18653 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
18654 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
18655 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
18656 * by the Reader into an object that will be stored in the Record. It is passed the
18657 * following parameters:<ul>
18658 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
18660 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
18662 * <br>usage:<br><pre><code>
18663 var TopicRecord = Roo.data.Record.create(
18664 {name: 'title', mapping: 'topic_title'},
18665 {name: 'author', mapping: 'username'},
18666 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
18667 {name: 'lastPost', mapping: 'post_time', type: 'date'},
18668 {name: 'lastPoster', mapping: 'user2'},
18669 {name: 'excerpt', mapping: 'post_text'}
18672 var myNewRecord = new TopicRecord({
18673 title: 'Do my job please',
18676 lastPost: new Date(),
18677 lastPoster: 'Animal',
18678 excerpt: 'No way dude!'
18680 myStore.add(myNewRecord);
18685 Roo.data.Record.create = function(o){
18686 var f = function(){
18687 f.superclass.constructor.apply(this, arguments);
18689 Roo.extend(f, Roo.data.Record);
18690 var p = f.prototype;
18691 p.fields = new Roo.util.MixedCollection(false, function(field){
18694 for(var i = 0, len = o.length; i < len; i++){
18695 p.fields.add(new Roo.data.Field(o[i]));
18697 f.getField = function(name){
18698 return p.fields.get(name);
18703 Roo.data.Record.AUTO_ID = 1000;
18704 Roo.data.Record.EDIT = 'edit';
18705 Roo.data.Record.REJECT = 'reject';
18706 Roo.data.Record.COMMIT = 'commit';
18708 Roo.data.Record.prototype = {
18710 * Readonly flag - true if this record has been modified.
18719 join : function(store){
18720 this.store = store;
18724 * Set the named field to the specified value.
18725 * @param {String} name The name of the field to set.
18726 * @param {Object} value The value to set the field to.
18728 set : function(name, value){
18729 if(this.data[name] == value){
18733 if(!this.modified){
18734 this.modified = {};
18736 if(typeof this.modified[name] == 'undefined'){
18737 this.modified[name] = this.data[name];
18739 this.data[name] = value;
18741 this.store.afterEdit(this);
18746 * Get the value of the named field.
18747 * @param {String} name The name of the field to get the value of.
18748 * @return {Object} The value of the field.
18750 get : function(name){
18751 return this.data[name];
18755 beginEdit : function(){
18756 this.editing = true;
18757 this.modified = {};
18761 cancelEdit : function(){
18762 this.editing = false;
18763 delete this.modified;
18767 endEdit : function(){
18768 this.editing = false;
18769 if(this.dirty && this.store){
18770 this.store.afterEdit(this);
18775 * Usually called by the {@link Roo.data.Store} which owns the Record.
18776 * Rejects all changes made to the Record since either creation, or the last commit operation.
18777 * Modified fields are reverted to their original values.
18779 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
18780 * of reject operations.
18782 reject : function(){
18783 var m = this.modified;
18785 if(typeof m[n] != "function"){
18786 this.data[n] = m[n];
18789 this.dirty = false;
18790 delete this.modified;
18791 this.editing = false;
18793 this.store.afterReject(this);
18798 * Usually called by the {@link Roo.data.Store} which owns the Record.
18799 * Commits all changes made to the Record since either creation, or the last commit operation.
18801 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
18802 * of commit operations.
18804 commit : function(){
18805 this.dirty = false;
18806 delete this.modified;
18807 this.editing = false;
18809 this.store.afterCommit(this);
18814 hasError : function(){
18815 return this.error != null;
18819 clearError : function(){
18824 * Creates a copy of this record.
18825 * @param {String} id (optional) A new record id if you don't want to use this record's id
18828 copy : function(newId) {
18829 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
18833 * Ext JS Library 1.1.1
18834 * Copyright(c) 2006-2007, Ext JS, LLC.
18836 * Originally Released Under LGPL - original licence link has changed is not relivant.
18839 * <script type="text/javascript">
18845 * @class Roo.data.Store
18846 * @extends Roo.util.Observable
18847 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
18848 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
18850 * 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
18851 * has no knowledge of the format of the data returned by the Proxy.<br>
18853 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
18854 * instances from the data object. These records are cached and made available through accessor functions.
18856 * Creates a new Store.
18857 * @param {Object} config A config object containing the objects needed for the Store to access data,
18858 * and read the data into Records.
18860 Roo.data.Store = function(config){
18861 this.data = new Roo.util.MixedCollection(false);
18862 this.data.getKey = function(o){
18865 this.baseParams = {};
18867 this.paramNames = {
18874 if(config && config.data){
18875 this.inlineData = config.data;
18876 delete config.data;
18879 Roo.apply(this, config);
18881 if(this.reader){ // reader passed
18882 this.reader = Roo.factory(this.reader, Roo.data);
18883 this.reader.xmodule = this.xmodule || false;
18884 if(!this.recordType){
18885 this.recordType = this.reader.recordType;
18887 if(this.reader.onMetaChange){
18888 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
18892 if(this.recordType){
18893 this.fields = this.recordType.prototype.fields;
18895 this.modified = [];
18899 * @event datachanged
18900 * Fires when the data cache has changed, and a widget which is using this Store
18901 * as a Record cache should refresh its view.
18902 * @param {Store} this
18904 datachanged : true,
18906 * @event metachange
18907 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
18908 * @param {Store} this
18909 * @param {Object} meta The JSON metadata
18914 * Fires when Records have been added to the Store
18915 * @param {Store} this
18916 * @param {Roo.data.Record[]} records The array of Records added
18917 * @param {Number} index The index at which the record(s) were added
18922 * Fires when a Record has been removed from the Store
18923 * @param {Store} this
18924 * @param {Roo.data.Record} record The Record that was removed
18925 * @param {Number} index The index at which the record was removed
18930 * Fires when a Record has been updated
18931 * @param {Store} this
18932 * @param {Roo.data.Record} record The Record that was updated
18933 * @param {String} operation The update operation being performed. Value may be one of:
18935 Roo.data.Record.EDIT
18936 Roo.data.Record.REJECT
18937 Roo.data.Record.COMMIT
18943 * Fires when the data cache has been cleared.
18944 * @param {Store} this
18948 * @event beforeload
18949 * Fires before a request is made for a new data object. If the beforeload handler returns false
18950 * the load action will be canceled.
18951 * @param {Store} this
18952 * @param {Object} options The loading options that were specified (see {@link #load} for details)
18957 * Fires after a new set of Records has been loaded.
18958 * @param {Store} this
18959 * @param {Roo.data.Record[]} records The Records that were loaded
18960 * @param {Object} options The loading options that were specified (see {@link #load} for details)
18964 * @event loadexception
18965 * Fires if an exception occurs in the Proxy during loading.
18966 * Called with the signature of the Proxy's "loadexception" event.
18967 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
18970 * @param {Object} return from JsonData.reader() - success, totalRecords, records
18971 * @param {Object} load options
18972 * @param {Object} jsonData from your request (normally this contains the Exception)
18974 loadexception : true
18978 this.proxy = Roo.factory(this.proxy, Roo.data);
18979 this.proxy.xmodule = this.xmodule || false;
18980 this.relayEvents(this.proxy, ["loadexception"]);
18982 this.sortToggle = {};
18984 Roo.data.Store.superclass.constructor.call(this);
18986 if(this.inlineData){
18987 this.loadData(this.inlineData);
18988 delete this.inlineData;
18991 Roo.extend(Roo.data.Store, Roo.util.Observable, {
18993 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
18994 * without a remote query - used by combo/forms at present.
18998 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
19001 * @cfg {Array} data Inline data to be loaded when the store is initialized.
19004 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
19005 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
19008 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
19009 * on any HTTP request
19012 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
19015 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
19016 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
19018 remoteSort : false,
19021 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
19022 * loaded or when a record is removed. (defaults to false).
19024 pruneModifiedRecords : false,
19027 lastOptions : null,
19030 * Add Records to the Store and fires the add event.
19031 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19033 add : function(records){
19034 records = [].concat(records);
19035 for(var i = 0, len = records.length; i < len; i++){
19036 records[i].join(this);
19038 var index = this.data.length;
19039 this.data.addAll(records);
19040 this.fireEvent("add", this, records, index);
19044 * Remove a Record from the Store and fires the remove event.
19045 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
19047 remove : function(record){
19048 var index = this.data.indexOf(record);
19049 this.data.removeAt(index);
19050 if(this.pruneModifiedRecords){
19051 this.modified.remove(record);
19053 this.fireEvent("remove", this, record, index);
19057 * Remove all Records from the Store and fires the clear event.
19059 removeAll : function(){
19061 if(this.pruneModifiedRecords){
19062 this.modified = [];
19064 this.fireEvent("clear", this);
19068 * Inserts Records to the Store at the given index and fires the add event.
19069 * @param {Number} index The start index at which to insert the passed Records.
19070 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19072 insert : function(index, records){
19073 records = [].concat(records);
19074 for(var i = 0, len = records.length; i < len; i++){
19075 this.data.insert(index, records[i]);
19076 records[i].join(this);
19078 this.fireEvent("add", this, records, index);
19082 * Get the index within the cache of the passed Record.
19083 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
19084 * @return {Number} The index of the passed Record. Returns -1 if not found.
19086 indexOf : function(record){
19087 return this.data.indexOf(record);
19091 * Get the index within the cache of the Record with the passed id.
19092 * @param {String} id The id of the Record to find.
19093 * @return {Number} The index of the Record. Returns -1 if not found.
19095 indexOfId : function(id){
19096 return this.data.indexOfKey(id);
19100 * Get the Record with the specified id.
19101 * @param {String} id The id of the Record to find.
19102 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
19104 getById : function(id){
19105 return this.data.key(id);
19109 * Get the Record at the specified index.
19110 * @param {Number} index The index of the Record to find.
19111 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
19113 getAt : function(index){
19114 return this.data.itemAt(index);
19118 * Returns a range of Records between specified indices.
19119 * @param {Number} startIndex (optional) The starting index (defaults to 0)
19120 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
19121 * @return {Roo.data.Record[]} An array of Records
19123 getRange : function(start, end){
19124 return this.data.getRange(start, end);
19128 storeOptions : function(o){
19129 o = Roo.apply({}, o);
19132 this.lastOptions = o;
19136 * Loads the Record cache from the configured Proxy using the configured Reader.
19138 * If using remote paging, then the first load call must specify the <em>start</em>
19139 * and <em>limit</em> properties in the options.params property to establish the initial
19140 * position within the dataset, and the number of Records to cache on each read from the Proxy.
19142 * <strong>It is important to note that for remote data sources, loading is asynchronous,
19143 * and this call will return before the new data has been loaded. Perform any post-processing
19144 * in a callback function, or in a "load" event handler.</strong>
19146 * @param {Object} options An object containing properties which control loading options:<ul>
19147 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
19148 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
19149 * passed the following arguments:<ul>
19150 * <li>r : Roo.data.Record[]</li>
19151 * <li>options: Options object from the load call</li>
19152 * <li>success: Boolean success indicator</li></ul></li>
19153 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
19154 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
19157 load : function(options){
19158 options = options || {};
19159 if(this.fireEvent("beforeload", this, options) !== false){
19160 this.storeOptions(options);
19161 var p = Roo.apply(options.params || {}, this.baseParams);
19162 if(this.sortInfo && this.remoteSort){
19163 var pn = this.paramNames;
19164 p[pn["sort"]] = this.sortInfo.field;
19165 p[pn["dir"]] = this.sortInfo.direction;
19167 this.proxy.load(p, this.reader, this.loadRecords, this, options);
19172 * Reloads the Record cache from the configured Proxy using the configured Reader and
19173 * the options from the last load operation performed.
19174 * @param {Object} options (optional) An object containing properties which may override the options
19175 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
19176 * the most recently used options are reused).
19178 reload : function(options){
19179 this.load(Roo.applyIf(options||{}, this.lastOptions));
19183 // Called as a callback by the Reader during a load operation.
19184 loadRecords : function(o, options, success){
19185 if(!o || success === false){
19186 if(success !== false){
19187 this.fireEvent("load", this, [], options);
19189 if(options.callback){
19190 options.callback.call(options.scope || this, [], options, false);
19194 // if data returned failure - throw an exception.
19195 if (o.success === false) {
19196 this.fireEvent("loadexception", this, o, options, this.reader.jsonData);
19199 var r = o.records, t = o.totalRecords || r.length;
19200 if(!options || options.add !== true){
19201 if(this.pruneModifiedRecords){
19202 this.modified = [];
19204 for(var i = 0, len = r.length; i < len; i++){
19208 this.data = this.snapshot;
19209 delete this.snapshot;
19212 this.data.addAll(r);
19213 this.totalLength = t;
19215 this.fireEvent("datachanged", this);
19217 this.totalLength = Math.max(t, this.data.length+r.length);
19220 this.fireEvent("load", this, r, options);
19221 if(options.callback){
19222 options.callback.call(options.scope || this, r, options, true);
19227 * Loads data from a passed data block. A Reader which understands the format of the data
19228 * must have been configured in the constructor.
19229 * @param {Object} data The data block from which to read the Records. The format of the data expected
19230 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
19231 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
19233 loadData : function(o, append){
19234 var r = this.reader.readRecords(o);
19235 this.loadRecords(r, {add: append}, true);
19239 * Gets the number of cached records.
19241 * <em>If using paging, this may not be the total size of the dataset. If the data object
19242 * used by the Reader contains the dataset size, then the getTotalCount() function returns
19243 * the data set size</em>
19245 getCount : function(){
19246 return this.data.length || 0;
19250 * Gets the total number of records in the dataset as returned by the server.
19252 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
19253 * the dataset size</em>
19255 getTotalCount : function(){
19256 return this.totalLength || 0;
19260 * Returns the sort state of the Store as an object with two properties:
19262 field {String} The name of the field by which the Records are sorted
19263 direction {String} The sort order, "ASC" or "DESC"
19266 getSortState : function(){
19267 return this.sortInfo;
19271 applySort : function(){
19272 if(this.sortInfo && !this.remoteSort){
19273 var s = this.sortInfo, f = s.field;
19274 var st = this.fields.get(f).sortType;
19275 var fn = function(r1, r2){
19276 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
19277 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
19279 this.data.sort(s.direction, fn);
19280 if(this.snapshot && this.snapshot != this.data){
19281 this.snapshot.sort(s.direction, fn);
19287 * Sets the default sort column and order to be used by the next load operation.
19288 * @param {String} fieldName The name of the field to sort by.
19289 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
19291 setDefaultSort : function(field, dir){
19292 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
19296 * Sort the Records.
19297 * If remote sorting is used, the sort is performed on the server, and the cache is
19298 * reloaded. If local sorting is used, the cache is sorted internally.
19299 * @param {String} fieldName The name of the field to sort by.
19300 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
19302 sort : function(fieldName, dir){
19303 var f = this.fields.get(fieldName);
19305 if(this.sortInfo && this.sortInfo.field == f.name){ // toggle sort dir
19306 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
19311 this.sortToggle[f.name] = dir;
19312 this.sortInfo = {field: f.name, direction: dir};
19313 if(!this.remoteSort){
19315 this.fireEvent("datachanged", this);
19317 this.load(this.lastOptions);
19322 * Calls the specified function for each of the Records in the cache.
19323 * @param {Function} fn The function to call. The Record is passed as the first parameter.
19324 * Returning <em>false</em> aborts and exits the iteration.
19325 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
19327 each : function(fn, scope){
19328 this.data.each(fn, scope);
19332 * Gets all records modified since the last commit. Modified records are persisted across load operations
19333 * (e.g., during paging).
19334 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
19336 getModifiedRecords : function(){
19337 return this.modified;
19341 createFilterFn : function(property, value, anyMatch){
19342 if(!value.exec){ // not a regex
19343 value = String(value);
19344 if(value.length == 0){
19347 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
19349 return function(r){
19350 return value.test(r.data[property]);
19355 * Sums the value of <i>property</i> for each record between start and end and returns the result.
19356 * @param {String} property A field on your records
19357 * @param {Number} start The record index to start at (defaults to 0)
19358 * @param {Number} end The last record index to include (defaults to length - 1)
19359 * @return {Number} The sum
19361 sum : function(property, start, end){
19362 var rs = this.data.items, v = 0;
19363 start = start || 0;
19364 end = (end || end === 0) ? end : rs.length-1;
19366 for(var i = start; i <= end; i++){
19367 v += (rs[i].data[property] || 0);
19373 * Filter the records by a specified property.
19374 * @param {String} field A field on your records
19375 * @param {String/RegExp} value Either a string that the field
19376 * should start with or a RegExp to test against the field
19377 * @param {Boolean} anyMatch True to match any part not just the beginning
19379 filter : function(property, value, anyMatch){
19380 var fn = this.createFilterFn(property, value, anyMatch);
19381 return fn ? this.filterBy(fn) : this.clearFilter();
19385 * Filter by a function. The specified function will be called with each
19386 * record in this data source. If the function returns true the record is included,
19387 * otherwise it is filtered.
19388 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
19389 * @param {Object} scope (optional) The scope of the function (defaults to this)
19391 filterBy : function(fn, scope){
19392 this.snapshot = this.snapshot || this.data;
19393 this.data = this.queryBy(fn, scope||this);
19394 this.fireEvent("datachanged", this);
19398 * Query the records by a specified property.
19399 * @param {String} field A field on your records
19400 * @param {String/RegExp} value Either a string that the field
19401 * should start with or a RegExp to test against the field
19402 * @param {Boolean} anyMatch True to match any part not just the beginning
19403 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
19405 query : function(property, value, anyMatch){
19406 var fn = this.createFilterFn(property, value, anyMatch);
19407 return fn ? this.queryBy(fn) : this.data.clone();
19411 * Query by a function. The specified function will be called with each
19412 * record in this data source. If the function returns true the record is included
19414 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
19415 * @param {Object} scope (optional) The scope of the function (defaults to this)
19416 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
19418 queryBy : function(fn, scope){
19419 var data = this.snapshot || this.data;
19420 return data.filterBy(fn, scope||this);
19424 * Collects unique values for a particular dataIndex from this store.
19425 * @param {String} dataIndex The property to collect
19426 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
19427 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
19428 * @return {Array} An array of the unique values
19430 collect : function(dataIndex, allowNull, bypassFilter){
19431 var d = (bypassFilter === true && this.snapshot) ?
19432 this.snapshot.items : this.data.items;
19433 var v, sv, r = [], l = {};
19434 for(var i = 0, len = d.length; i < len; i++){
19435 v = d[i].data[dataIndex];
19437 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
19446 * Revert to a view of the Record cache with no filtering applied.
19447 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
19449 clearFilter : function(suppressEvent){
19450 if(this.snapshot && this.snapshot != this.data){
19451 this.data = this.snapshot;
19452 delete this.snapshot;
19453 if(suppressEvent !== true){
19454 this.fireEvent("datachanged", this);
19460 afterEdit : function(record){
19461 if(this.modified.indexOf(record) == -1){
19462 this.modified.push(record);
19464 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
19468 afterReject : function(record){
19469 this.modified.remove(record);
19470 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
19474 afterCommit : function(record){
19475 this.modified.remove(record);
19476 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
19480 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
19481 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
19483 commitChanges : function(){
19484 var m = this.modified.slice(0);
19485 this.modified = [];
19486 for(var i = 0, len = m.length; i < len; i++){
19492 * Cancel outstanding changes on all changed records.
19494 rejectChanges : function(){
19495 var m = this.modified.slice(0);
19496 this.modified = [];
19497 for(var i = 0, len = m.length; i < len; i++){
19502 onMetaChange : function(meta, rtype, o){
19503 this.recordType = rtype;
19504 this.fields = rtype.prototype.fields;
19505 delete this.snapshot;
19506 this.sortInfo = meta.sortInfo;
19507 this.modified = [];
19508 this.fireEvent('metachange', this, this.reader.meta);
19512 * Ext JS Library 1.1.1
19513 * Copyright(c) 2006-2007, Ext JS, LLC.
19515 * Originally Released Under LGPL - original licence link has changed is not relivant.
19518 * <script type="text/javascript">
19522 * @class Roo.data.SimpleStore
19523 * @extends Roo.data.Store
19524 * Small helper class to make creating Stores from Array data easier.
19525 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
19526 * @cfg {Array} fields An array of field definition objects, or field name strings.
19527 * @cfg {Array} data The multi-dimensional array of data
19529 * @param {Object} config
19531 Roo.data.SimpleStore = function(config){
19532 Roo.data.SimpleStore.superclass.constructor.call(this, {
19534 reader: new Roo.data.ArrayReader({
19537 Roo.data.Record.create(config.fields)
19539 proxy : new Roo.data.MemoryProxy(config.data)
19543 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
19545 * Ext JS Library 1.1.1
19546 * Copyright(c) 2006-2007, Ext JS, LLC.
19548 * Originally Released Under LGPL - original licence link has changed is not relivant.
19551 * <script type="text/javascript">
19556 * @extends Roo.data.Store
19557 * @class Roo.data.JsonStore
19558 * Small helper class to make creating Stores for JSON data easier. <br/>
19560 var store = new Roo.data.JsonStore({
19561 url: 'get-images.php',
19563 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
19566 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
19567 * JsonReader and HttpProxy (unless inline data is provided).</b>
19568 * @cfg {Array} fields An array of field definition objects, or field name strings.
19570 * @param {Object} config
19572 Roo.data.JsonStore = function(c){
19573 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
19574 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
19575 reader: new Roo.data.JsonReader(c, c.fields)
19578 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
19580 * Ext JS Library 1.1.1
19581 * Copyright(c) 2006-2007, Ext JS, LLC.
19583 * Originally Released Under LGPL - original licence link has changed is not relivant.
19586 * <script type="text/javascript">
19590 Roo.data.Field = function(config){
19591 if(typeof config == "string"){
19592 config = {name: config};
19594 Roo.apply(this, config);
19597 this.type = "auto";
19600 var st = Roo.data.SortTypes;
19601 // named sortTypes are supported, here we look them up
19602 if(typeof this.sortType == "string"){
19603 this.sortType = st[this.sortType];
19606 // set default sortType for strings and dates
19607 if(!this.sortType){
19610 this.sortType = st.asUCString;
19613 this.sortType = st.asDate;
19616 this.sortType = st.none;
19621 var stripRe = /[\$,%]/g;
19623 // prebuilt conversion function for this field, instead of
19624 // switching every time we're reading a value
19626 var cv, dateFormat = this.dateFormat;
19631 cv = function(v){ return v; };
19634 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
19638 return v !== undefined && v !== null && v !== '' ?
19639 parseInt(String(v).replace(stripRe, ""), 10) : '';
19644 return v !== undefined && v !== null && v !== '' ?
19645 parseFloat(String(v).replace(stripRe, ""), 10) : '';
19650 cv = function(v){ return v === true || v === "true" || v == 1; };
19657 if(v instanceof Date){
19661 if(dateFormat == "timestamp"){
19662 return new Date(v*1000);
19664 return Date.parseDate(v, dateFormat);
19666 var parsed = Date.parse(v);
19667 return parsed ? new Date(parsed) : null;
19676 Roo.data.Field.prototype = {
19684 * Ext JS Library 1.1.1
19685 * Copyright(c) 2006-2007, Ext JS, LLC.
19687 * Originally Released Under LGPL - original licence link has changed is not relivant.
19690 * <script type="text/javascript">
19693 // Base class for reading structured data from a data source. This class is intended to be
19694 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
19697 * @class Roo.data.DataReader
19698 * Base class for reading structured data from a data source. This class is intended to be
19699 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
19702 Roo.data.DataReader = function(meta, recordType){
19706 this.recordType = recordType instanceof Array ?
19707 Roo.data.Record.create(recordType) : recordType;
19710 Roo.data.DataReader.prototype = {
19712 * Create an empty record
19713 * @param {Object} data (optional) - overlay some values
19714 * @return {Roo.data.Record} record created.
19716 newRow : function(d) {
19718 this.recordType.prototype.fields.each(function(c) {
19720 case 'int' : da[c.name] = 0; break;
19721 case 'date' : da[c.name] = new Date(); break;
19722 case 'float' : da[c.name] = 0.0; break;
19723 case 'boolean' : da[c.name] = false; break;
19724 default : da[c.name] = ""; break;
19728 return new this.recordType(Roo.apply(da, d));
19733 * Ext JS Library 1.1.1
19734 * Copyright(c) 2006-2007, Ext JS, LLC.
19736 * Originally Released Under LGPL - original licence link has changed is not relivant.
19739 * <script type="text/javascript">
19743 * @class Roo.data.DataProxy
19744 * @extends Roo.data.Observable
19745 * This class is an abstract base class for implementations which provide retrieval of
19746 * unformatted data objects.<br>
19748 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
19749 * (of the appropriate type which knows how to parse the data object) to provide a block of
19750 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
19752 * Custom implementations must implement the load method as described in
19753 * {@link Roo.data.HttpProxy#load}.
19755 Roo.data.DataProxy = function(){
19758 * @event beforeload
19759 * Fires before a network request is made to retrieve a data object.
19760 * @param {Object} This DataProxy object.
19761 * @param {Object} params The params parameter to the load function.
19766 * Fires before the load method's callback is called.
19767 * @param {Object} This DataProxy object.
19768 * @param {Object} o The data object.
19769 * @param {Object} arg The callback argument object passed to the load function.
19773 * @event loadexception
19774 * Fires if an Exception occurs during data retrieval.
19775 * @param {Object} This DataProxy object.
19776 * @param {Object} o The data object.
19777 * @param {Object} arg The callback argument object passed to the load function.
19778 * @param {Object} e The Exception.
19780 loadexception : true
19782 Roo.data.DataProxy.superclass.constructor.call(this);
19785 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
19788 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
19792 * Ext JS Library 1.1.1
19793 * Copyright(c) 2006-2007, Ext JS, LLC.
19795 * Originally Released Under LGPL - original licence link has changed is not relivant.
19798 * <script type="text/javascript">
19801 * @class Roo.data.MemoryProxy
19802 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
19803 * to the Reader when its load method is called.
19805 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
19807 Roo.data.MemoryProxy = function(data){
19811 Roo.data.MemoryProxy.superclass.constructor.call(this);
19815 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
19817 * Load data from the requested source (in this case an in-memory
19818 * data object passed to the constructor), read the data object into
19819 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
19820 * process that block using the passed callback.
19821 * @param {Object} params This parameter is not used by the MemoryProxy class.
19822 * @param {Roo.data.DataReader} reader The Reader object which converts the data
19823 * object into a block of Roo.data.Records.
19824 * @param {Function} callback The function into which to pass the block of Roo.data.records.
19825 * The function must be passed <ul>
19826 * <li>The Record block object</li>
19827 * <li>The "arg" argument from the load function</li>
19828 * <li>A boolean success indicator</li>
19830 * @param {Object} scope The scope in which to call the callback
19831 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
19833 load : function(params, reader, callback, scope, arg){
19834 params = params || {};
19837 result = reader.readRecords(this.data);
19839 this.fireEvent("loadexception", this, arg, null, e);
19840 callback.call(scope, null, arg, false);
19843 callback.call(scope, result, arg, true);
19847 update : function(params, records){
19852 * Ext JS Library 1.1.1
19853 * Copyright(c) 2006-2007, Ext JS, LLC.
19855 * Originally Released Under LGPL - original licence link has changed is not relivant.
19858 * <script type="text/javascript">
19861 * @class Roo.data.HttpProxy
19862 * @extends Roo.data.DataProxy
19863 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
19864 * configured to reference a certain URL.<br><br>
19866 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
19867 * from which the running page was served.<br><br>
19869 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
19871 * Be aware that to enable the browser to parse an XML document, the server must set
19872 * the Content-Type header in the HTTP response to "text/xml".
19874 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
19875 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
19876 * will be used to make the request.
19878 Roo.data.HttpProxy = function(conn){
19879 Roo.data.HttpProxy.superclass.constructor.call(this);
19880 // is conn a conn config or a real conn?
19882 this.useAjax = !conn || !conn.events;
19886 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
19887 // thse are take from connection...
19890 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
19893 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
19894 * extra parameters to each request made by this object. (defaults to undefined)
19897 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
19898 * to each request made by this object. (defaults to undefined)
19901 * @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)
19904 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
19907 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
19913 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
19917 * Return the {@link Roo.data.Connection} object being used by this Proxy.
19918 * @return {Connection} The Connection object. This object may be used to subscribe to events on
19919 * a finer-grained basis than the DataProxy events.
19921 getConnection : function(){
19922 return this.useAjax ? Roo.Ajax : this.conn;
19926 * Load data from the configured {@link Roo.data.Connection}, read the data object into
19927 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
19928 * process that block using the passed callback.
19929 * @param {Object} params An object containing properties which are to be used as HTTP parameters
19930 * for the request to the remote server.
19931 * @param {Roo.data.DataReader} reader The Reader object which converts the data
19932 * object into a block of Roo.data.Records.
19933 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
19934 * The function must be passed <ul>
19935 * <li>The Record block object</li>
19936 * <li>The "arg" argument from the load function</li>
19937 * <li>A boolean success indicator</li>
19939 * @param {Object} scope The scope in which to call the callback
19940 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
19942 load : function(params, reader, callback, scope, arg){
19943 if(this.fireEvent("beforeload", this, params) !== false){
19945 params : params || {},
19947 callback : callback,
19952 callback : this.loadResponse,
19956 Roo.applyIf(o, this.conn);
19957 if(this.activeRequest){
19958 Roo.Ajax.abort(this.activeRequest);
19960 this.activeRequest = Roo.Ajax.request(o);
19962 this.conn.request(o);
19965 callback.call(scope||this, null, arg, false);
19970 loadResponse : function(o, success, response){
19971 delete this.activeRequest;
19973 this.fireEvent("loadexception", this, o, response);
19974 o.request.callback.call(o.request.scope, null, o.request.arg, false);
19979 result = o.reader.read(response);
19981 this.fireEvent("loadexception", this, o, response, e);
19982 o.request.callback.call(o.request.scope, null, o.request.arg, false);
19986 this.fireEvent("load", this, o, o.request.arg);
19987 o.request.callback.call(o.request.scope, result, o.request.arg, true);
19991 update : function(dataSet){
19996 updateResponse : function(dataSet){
20001 * Ext JS Library 1.1.1
20002 * Copyright(c) 2006-2007, Ext JS, LLC.
20004 * Originally Released Under LGPL - original licence link has changed is not relivant.
20007 * <script type="text/javascript">
20011 * @class Roo.data.ScriptTagProxy
20012 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
20013 * other than the originating domain of the running page.<br><br>
20015 * <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
20016 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
20018 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
20019 * source code that is used as the source inside a <script> tag.<br><br>
20021 * In order for the browser to process the returned data, the server must wrap the data object
20022 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
20023 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
20024 * depending on whether the callback name was passed:
20027 boolean scriptTag = false;
20028 String cb = request.getParameter("callback");
20031 response.setContentType("text/javascript");
20033 response.setContentType("application/x-json");
20035 Writer out = response.getWriter();
20037 out.write(cb + "(");
20039 out.print(dataBlock.toJsonString());
20046 * @param {Object} config A configuration object.
20048 Roo.data.ScriptTagProxy = function(config){
20049 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
20050 Roo.apply(this, config);
20051 this.head = document.getElementsByTagName("head")[0];
20054 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
20056 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
20058 * @cfg {String} url The URL from which to request the data object.
20061 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
20065 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
20066 * the server the name of the callback function set up by the load call to process the returned data object.
20067 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
20068 * javascript output which calls this named function passing the data object as its only parameter.
20070 callbackParam : "callback",
20072 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
20073 * name to the request.
20078 * Load data from the configured URL, read the data object into
20079 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20080 * process that block using the passed callback.
20081 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20082 * for the request to the remote server.
20083 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20084 * object into a block of Roo.data.Records.
20085 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20086 * The function must be passed <ul>
20087 * <li>The Record block object</li>
20088 * <li>The "arg" argument from the load function</li>
20089 * <li>A boolean success indicator</li>
20091 * @param {Object} scope The scope in which to call the callback
20092 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20094 load : function(params, reader, callback, scope, arg){
20095 if(this.fireEvent("beforeload", this, params) !== false){
20097 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
20099 var url = this.url;
20100 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
20102 url += "&_dc=" + (new Date().getTime());
20104 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
20107 cb : "stcCallback"+transId,
20108 scriptId : "stcScript"+transId,
20112 callback : callback,
20118 window[trans.cb] = function(o){
20119 conn.handleResponse(o, trans);
20122 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
20124 if(this.autoAbort !== false){
20128 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
20130 var script = document.createElement("script");
20131 script.setAttribute("src", url);
20132 script.setAttribute("type", "text/javascript");
20133 script.setAttribute("id", trans.scriptId);
20134 this.head.appendChild(script);
20136 this.trans = trans;
20138 callback.call(scope||this, null, arg, false);
20143 isLoading : function(){
20144 return this.trans ? true : false;
20148 * Abort the current server request.
20150 abort : function(){
20151 if(this.isLoading()){
20152 this.destroyTrans(this.trans);
20157 destroyTrans : function(trans, isLoaded){
20158 this.head.removeChild(document.getElementById(trans.scriptId));
20159 clearTimeout(trans.timeoutId);
20161 window[trans.cb] = undefined;
20163 delete window[trans.cb];
20166 // if hasn't been loaded, wait for load to remove it to prevent script error
20167 window[trans.cb] = function(){
20168 window[trans.cb] = undefined;
20170 delete window[trans.cb];
20177 handleResponse : function(o, trans){
20178 this.trans = false;
20179 this.destroyTrans(trans, true);
20182 result = trans.reader.readRecords(o);
20184 this.fireEvent("loadexception", this, o, trans.arg, e);
20185 trans.callback.call(trans.scope||window, null, trans.arg, false);
20188 this.fireEvent("load", this, o, trans.arg);
20189 trans.callback.call(trans.scope||window, result, trans.arg, true);
20193 handleFailure : function(trans){
20194 this.trans = false;
20195 this.destroyTrans(trans, false);
20196 this.fireEvent("loadexception", this, null, trans.arg);
20197 trans.callback.call(trans.scope||window, null, trans.arg, false);
20201 * Ext JS Library 1.1.1
20202 * Copyright(c) 2006-2007, Ext JS, LLC.
20204 * Originally Released Under LGPL - original licence link has changed is not relivant.
20207 * <script type="text/javascript">
20211 * @class Roo.data.JsonReader
20212 * @extends Roo.data.DataReader
20213 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
20214 * based on mappings in a provided Roo.data.Record constructor.
20218 var RecordDef = Roo.data.Record.create([
20219 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
20220 {name: 'occupation'} // This field will use "occupation" as the mapping.
20222 var myReader = new Roo.data.JsonReader({
20223 totalProperty: "results", // The property which contains the total dataset size (optional)
20224 root: "rows", // The property which contains an Array of row objects
20225 id: "id" // The property within each row object that provides an ID for the record (optional)
20229 * This would consume a JSON file like this:
20231 { 'results': 2, 'rows': [
20232 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
20233 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
20236 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
20237 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
20238 * paged from the remote server.
20239 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
20240 * @cfg {String} root name of the property which contains the Array of row objects.
20241 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
20243 * Create a new JsonReader
20244 * @param {Object} meta Metadata configuration options
20245 * @param {Object} recordType Either an Array of field definition objects,
20246 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
20248 Roo.data.JsonReader = function(meta, recordType){
20251 // set some defaults:
20252 Roo.applyIf(meta, {
20253 totalProperty: 'total',
20254 successProperty : 'success',
20259 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
20261 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
20263 * This method is only used by a DataProxy which has retrieved data from a remote server.
20264 * @param {Object} response The XHR object which contains the JSON data in its responseText.
20265 * @return {Object} data A data block which is used by an Roo.data.Store object as
20266 * a cache of Roo.data.Records.
20268 read : function(response){
20269 var json = response.responseText;
20271 var o = eval("("+json+")");
20273 throw {message: "JsonReader.read: Json object not found"};
20278 this.meta = o.metaData;
20279 this.recordType = Roo.data.Record.create(o.metaData.fields);
20280 this.onMetaChange(this.meta, this.recordType, o);
20282 return this.readRecords(o);
20285 // private function a store will implement
20286 onMetaChange : function(meta, recordType, o){
20293 simpleAccess: function(obj, subsc) {
20300 getJsonAccessor: function(){
20302 return function(expr) {
20304 return(re.test(expr))
20305 ? new Function("obj", "return obj." + expr)
20310 return Roo.emptyFn;
20315 * Create a data block containing Roo.data.Records from an XML document.
20316 * @param {Object} o An object which contains an Array of row objects in the property specified
20317 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
20318 * which contains the total size of the dataset.
20319 * @return {Object} data A data block which is used by an Roo.data.Store object as
20320 * a cache of Roo.data.Records.
20322 readRecords : function(o){
20324 * After any data loads, the raw JSON data is available for further custom processing.
20328 var s = this.meta, Record = this.recordType,
20329 f = Record.prototype.fields, fi = f.items, fl = f.length;
20331 // Generate extraction functions for the totalProperty, the root, the id, and for each field
20333 if(s.totalProperty) {
20334 this.getTotal = this.getJsonAccessor(s.totalProperty);
20336 if(s.successProperty) {
20337 this.getSuccess = this.getJsonAccessor(s.successProperty);
20339 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
20341 var g = this.getJsonAccessor(s.id);
20342 this.getId = function(rec) {
20344 return (r === undefined || r === "") ? null : r;
20347 this.getId = function(){return null;};
20350 for(var i = 0; i < fl; i++){
20352 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
20353 this.ef[i] = this.getJsonAccessor(map);
20357 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
20358 if(s.totalProperty){
20359 var v = parseInt(this.getTotal(o), 10);
20364 if(s.successProperty){
20365 var v = this.getSuccess(o);
20366 if(v === false || v === 'false'){
20371 for(var i = 0; i < c; i++){
20374 var id = this.getId(n);
20375 for(var j = 0; j < fl; j++){
20377 var v = this.ef[j](n);
20378 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
20380 var record = new Record(values, id);
20382 records[i] = record;
20387 totalRecords : totalRecords
20392 * Ext JS Library 1.1.1
20393 * Copyright(c) 2006-2007, Ext JS, LLC.
20395 * Originally Released Under LGPL - original licence link has changed is not relivant.
20398 * <script type="text/javascript">
20402 * @class Roo.data.XmlReader
20403 * @extends Roo.data.DataReader
20404 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
20405 * based on mappings in a provided Roo.data.Record constructor.<br><br>
20407 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
20408 * header in the HTTP response must be set to "text/xml".</em>
20412 var RecordDef = Roo.data.Record.create([
20413 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
20414 {name: 'occupation'} // This field will use "occupation" as the mapping.
20416 var myReader = new Roo.data.XmlReader({
20417 totalRecords: "results", // The element which contains the total dataset size (optional)
20418 record: "row", // The repeated element which contains row information
20419 id: "id" // The element within the row that provides an ID for the record (optional)
20423 * This would consume an XML file like this:
20427 <results>2</results>
20430 <name>Bill</name>
20431 <occupation>Gardener</occupation>
20435 <name>Ben</name>
20436 <occupation>Horticulturalist</occupation>
20440 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
20441 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
20442 * paged from the remote server.
20443 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
20444 * @cfg {String} success The DomQuery path to the success attribute used by forms.
20445 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
20446 * a record identifier value.
20448 * Create a new XmlReader
20449 * @param {Object} meta Metadata configuration options
20450 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
20451 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
20452 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
20454 Roo.data.XmlReader = function(meta, recordType){
20456 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
20458 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
20460 * This method is only used by a DataProxy which has retrieved data from a remote server.
20461 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
20462 * to contain a method called 'responseXML' that returns an XML document object.
20463 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
20464 * a cache of Roo.data.Records.
20466 read : function(response){
20467 var doc = response.responseXML;
20469 throw {message: "XmlReader.read: XML Document not available"};
20471 return this.readRecords(doc);
20475 * Create a data block containing Roo.data.Records from an XML document.
20476 * @param {Object} doc A parsed XML document.
20477 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
20478 * a cache of Roo.data.Records.
20480 readRecords : function(doc){
20482 * After any data loads/reads, the raw XML Document is available for further custom processing.
20483 * @type XMLDocument
20485 this.xmlData = doc;
20486 var root = doc.documentElement || doc;
20487 var q = Roo.DomQuery;
20488 var recordType = this.recordType, fields = recordType.prototype.fields;
20489 var sid = this.meta.id;
20490 var totalRecords = 0, success = true;
20491 if(this.meta.totalRecords){
20492 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
20495 if(this.meta.success){
20496 var sv = q.selectValue(this.meta.success, root, true);
20497 success = sv !== false && sv !== 'false';
20500 var ns = q.select(this.meta.record, root);
20501 for(var i = 0, len = ns.length; i < len; i++) {
20504 var id = sid ? q.selectValue(sid, n) : undefined;
20505 for(var j = 0, jlen = fields.length; j < jlen; j++){
20506 var f = fields.items[j];
20507 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
20509 values[f.name] = v;
20511 var record = new recordType(values, id);
20513 records[records.length] = record;
20519 totalRecords : totalRecords || records.length
20524 * Ext JS Library 1.1.1
20525 * Copyright(c) 2006-2007, Ext JS, LLC.
20527 * Originally Released Under LGPL - original licence link has changed is not relivant.
20530 * <script type="text/javascript">
20534 * @class Roo.data.ArrayReader
20535 * @extends Roo.data.DataReader
20536 * Data reader class to create an Array of Roo.data.Record objects from an Array.
20537 * Each element of that Array represents a row of data fields. The
20538 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
20539 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
20543 var RecordDef = Roo.data.Record.create([
20544 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
20545 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
20547 var myReader = new Roo.data.ArrayReader({
20548 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
20552 * This would consume an Array like this:
20554 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
20556 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
20558 * Create a new JsonReader
20559 * @param {Object} meta Metadata configuration options.
20560 * @param {Object} recordType Either an Array of field definition objects
20561 * as specified to {@link Roo.data.Record#create},
20562 * or an {@link Roo.data.Record} object
20563 * created using {@link Roo.data.Record#create}.
20565 Roo.data.ArrayReader = function(meta, recordType){
20566 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
20569 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
20571 * Create a data block containing Roo.data.Records from an XML document.
20572 * @param {Object} o An Array of row objects which represents the dataset.
20573 * @return {Object} data A data block which is used by an Roo.data.Store object as
20574 * a cache of Roo.data.Records.
20576 readRecords : function(o){
20577 var sid = this.meta ? this.meta.id : null;
20578 var recordType = this.recordType, fields = recordType.prototype.fields;
20581 for(var i = 0; i < root.length; i++){
20584 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
20585 for(var j = 0, jlen = fields.length; j < jlen; j++){
20586 var f = fields.items[j];
20587 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
20588 var v = n[k] !== undefined ? n[k] : f.defaultValue;
20590 values[f.name] = v;
20592 var record = new recordType(values, id);
20594 records[records.length] = record;
20598 totalRecords : records.length
20603 * Ext JS Library 1.1.1
20604 * Copyright(c) 2006-2007, Ext JS, LLC.
20606 * Originally Released Under LGPL - original licence link has changed is not relivant.
20609 * <script type="text/javascript">
20614 * @class Roo.data.Tree
20615 * @extends Roo.util.Observable
20616 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
20617 * in the tree have most standard DOM functionality.
20619 * @param {Node} root (optional) The root node
20621 Roo.data.Tree = function(root){
20622 this.nodeHash = {};
20624 * The root node for this tree
20629 this.setRootNode(root);
20634 * Fires when a new child node is appended to a node in this tree.
20635 * @param {Tree} tree The owner tree
20636 * @param {Node} parent The parent node
20637 * @param {Node} node The newly appended node
20638 * @param {Number} index The index of the newly appended node
20643 * Fires when a child node is removed from a node in this tree.
20644 * @param {Tree} tree The owner tree
20645 * @param {Node} parent The parent node
20646 * @param {Node} node The child node removed
20651 * Fires when a node is moved to a new location in the tree
20652 * @param {Tree} tree The owner tree
20653 * @param {Node} node The node moved
20654 * @param {Node} oldParent The old parent of this node
20655 * @param {Node} newParent The new parent of this node
20656 * @param {Number} index The index it was moved to
20661 * Fires when a new child node is inserted in a node in this tree.
20662 * @param {Tree} tree The owner tree
20663 * @param {Node} parent The parent node
20664 * @param {Node} node The child node inserted
20665 * @param {Node} refNode The child node the node was inserted before
20669 * @event beforeappend
20670 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
20671 * @param {Tree} tree The owner tree
20672 * @param {Node} parent The parent node
20673 * @param {Node} node The child node to be appended
20675 "beforeappend" : true,
20677 * @event beforeremove
20678 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
20679 * @param {Tree} tree The owner tree
20680 * @param {Node} parent The parent node
20681 * @param {Node} node The child node to be removed
20683 "beforeremove" : true,
20685 * @event beforemove
20686 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
20687 * @param {Tree} tree The owner tree
20688 * @param {Node} node The node being moved
20689 * @param {Node} oldParent The parent of the node
20690 * @param {Node} newParent The new parent the node is moving to
20691 * @param {Number} index The index it is being moved to
20693 "beforemove" : true,
20695 * @event beforeinsert
20696 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
20697 * @param {Tree} tree The owner tree
20698 * @param {Node} parent The parent node
20699 * @param {Node} node The child node to be inserted
20700 * @param {Node} refNode The child node the node is being inserted before
20702 "beforeinsert" : true
20705 Roo.data.Tree.superclass.constructor.call(this);
20708 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
20709 pathSeparator: "/",
20711 proxyNodeEvent : function(){
20712 return this.fireEvent.apply(this, arguments);
20716 * Returns the root node for this tree.
20719 getRootNode : function(){
20724 * Sets the root node for this tree.
20725 * @param {Node} node
20728 setRootNode : function(node){
20730 node.ownerTree = this;
20731 node.isRoot = true;
20732 this.registerNode(node);
20737 * Gets a node in this tree by its id.
20738 * @param {String} id
20741 getNodeById : function(id){
20742 return this.nodeHash[id];
20745 registerNode : function(node){
20746 this.nodeHash[node.id] = node;
20749 unregisterNode : function(node){
20750 delete this.nodeHash[node.id];
20753 toString : function(){
20754 return "[Tree"+(this.id?" "+this.id:"")+"]";
20759 * @class Roo.data.Node
20760 * @extends Roo.util.Observable
20761 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
20762 * @cfg {String} id The id for this node. If one is not specified, one is generated.
20764 * @param {Object} attributes The attributes/config for the node
20766 Roo.data.Node = function(attributes){
20768 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
20771 this.attributes = attributes || {};
20772 this.leaf = this.attributes.leaf;
20774 * The node id. @type String
20776 this.id = this.attributes.id;
20778 this.id = Roo.id(null, "ynode-");
20779 this.attributes.id = this.id;
20782 * All child nodes of this node. @type Array
20784 this.childNodes = [];
20785 if(!this.childNodes.indexOf){ // indexOf is a must
20786 this.childNodes.indexOf = function(o){
20787 for(var i = 0, len = this.length; i < len; i++){
20788 if(this[i] == o) return i;
20794 * The parent node for this node. @type Node
20796 this.parentNode = null;
20798 * The first direct child node of this node, or null if this node has no child nodes. @type Node
20800 this.firstChild = null;
20802 * The last direct child node of this node, or null if this node has no child nodes. @type Node
20804 this.lastChild = null;
20806 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
20808 this.previousSibling = null;
20810 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
20812 this.nextSibling = null;
20817 * Fires when a new child node is appended
20818 * @param {Tree} tree The owner tree
20819 * @param {Node} this This node
20820 * @param {Node} node The newly appended node
20821 * @param {Number} index The index of the newly appended node
20826 * Fires when a child node is removed
20827 * @param {Tree} tree The owner tree
20828 * @param {Node} this This node
20829 * @param {Node} node The removed node
20834 * Fires when this node is moved to a new location in the tree
20835 * @param {Tree} tree The owner tree
20836 * @param {Node} this This node
20837 * @param {Node} oldParent The old parent of this node
20838 * @param {Node} newParent The new parent of this node
20839 * @param {Number} index The index it was moved to
20844 * Fires when a new child node is inserted.
20845 * @param {Tree} tree The owner tree
20846 * @param {Node} this This node
20847 * @param {Node} node The child node inserted
20848 * @param {Node} refNode The child node the node was inserted before
20852 * @event beforeappend
20853 * Fires before a new child is appended, return false to cancel the append.
20854 * @param {Tree} tree The owner tree
20855 * @param {Node} this This node
20856 * @param {Node} node The child node to be appended
20858 "beforeappend" : true,
20860 * @event beforeremove
20861 * Fires before a child is removed, return false to cancel the remove.
20862 * @param {Tree} tree The owner tree
20863 * @param {Node} this This node
20864 * @param {Node} node The child node to be removed
20866 "beforeremove" : true,
20868 * @event beforemove
20869 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
20870 * @param {Tree} tree The owner tree
20871 * @param {Node} this This node
20872 * @param {Node} oldParent The parent of this node
20873 * @param {Node} newParent The new parent this node is moving to
20874 * @param {Number} index The index it is being moved to
20876 "beforemove" : true,
20878 * @event beforeinsert
20879 * Fires before a new child is inserted, return false to cancel the insert.
20880 * @param {Tree} tree The owner tree
20881 * @param {Node} this This node
20882 * @param {Node} node The child node to be inserted
20883 * @param {Node} refNode The child node the node is being inserted before
20885 "beforeinsert" : true
20887 this.listeners = this.attributes.listeners;
20888 Roo.data.Node.superclass.constructor.call(this);
20891 Roo.extend(Roo.data.Node, Roo.util.Observable, {
20892 fireEvent : function(evtName){
20893 // first do standard event for this node
20894 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
20897 // then bubble it up to the tree if the event wasn't cancelled
20898 var ot = this.getOwnerTree();
20900 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
20908 * Returns true if this node is a leaf
20909 * @return {Boolean}
20911 isLeaf : function(){
20912 return this.leaf === true;
20916 setFirstChild : function(node){
20917 this.firstChild = node;
20921 setLastChild : function(node){
20922 this.lastChild = node;
20927 * Returns true if this node is the last child of its parent
20928 * @return {Boolean}
20930 isLast : function(){
20931 return (!this.parentNode ? true : this.parentNode.lastChild == this);
20935 * Returns true if this node is the first child of its parent
20936 * @return {Boolean}
20938 isFirst : function(){
20939 return (!this.parentNode ? true : this.parentNode.firstChild == this);
20942 hasChildNodes : function(){
20943 return !this.isLeaf() && this.childNodes.length > 0;
20947 * Insert node(s) as the last child node of this node.
20948 * @param {Node/Array} node The node or Array of nodes to append
20949 * @return {Node} The appended node if single append, or null if an array was passed
20951 appendChild : function(node){
20953 if(node instanceof Array){
20955 }else if(arguments.length > 1){
20958 // if passed an array or multiple args do them one by one
20960 for(var i = 0, len = multi.length; i < len; i++) {
20961 this.appendChild(multi[i]);
20964 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
20967 var index = this.childNodes.length;
20968 var oldParent = node.parentNode;
20969 // it's a move, make sure we move it cleanly
20971 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
20974 oldParent.removeChild(node);
20976 index = this.childNodes.length;
20978 this.setFirstChild(node);
20980 this.childNodes.push(node);
20981 node.parentNode = this;
20982 var ps = this.childNodes[index-1];
20984 node.previousSibling = ps;
20985 ps.nextSibling = node;
20987 node.previousSibling = null;
20989 node.nextSibling = null;
20990 this.setLastChild(node);
20991 node.setOwnerTree(this.getOwnerTree());
20992 this.fireEvent("append", this.ownerTree, this, node, index);
20994 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
21001 * Removes a child node from this node.
21002 * @param {Node} node The node to remove
21003 * @return {Node} The removed node
21005 removeChild : function(node){
21006 var index = this.childNodes.indexOf(node);
21010 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
21014 // remove it from childNodes collection
21015 this.childNodes.splice(index, 1);
21018 if(node.previousSibling){
21019 node.previousSibling.nextSibling = node.nextSibling;
21021 if(node.nextSibling){
21022 node.nextSibling.previousSibling = node.previousSibling;
21025 // update child refs
21026 if(this.firstChild == node){
21027 this.setFirstChild(node.nextSibling);
21029 if(this.lastChild == node){
21030 this.setLastChild(node.previousSibling);
21033 node.setOwnerTree(null);
21034 // clear any references from the node
21035 node.parentNode = null;
21036 node.previousSibling = null;
21037 node.nextSibling = null;
21038 this.fireEvent("remove", this.ownerTree, this, node);
21043 * Inserts the first node before the second node in this nodes childNodes collection.
21044 * @param {Node} node The node to insert
21045 * @param {Node} refNode The node to insert before (if null the node is appended)
21046 * @return {Node} The inserted node
21048 insertBefore : function(node, refNode){
21049 if(!refNode){ // like standard Dom, refNode can be null for append
21050 return this.appendChild(node);
21053 if(node == refNode){
21057 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
21060 var index = this.childNodes.indexOf(refNode);
21061 var oldParent = node.parentNode;
21062 var refIndex = index;
21064 // when moving internally, indexes will change after remove
21065 if(oldParent == this && this.childNodes.indexOf(node) < index){
21069 // it's a move, make sure we move it cleanly
21071 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
21074 oldParent.removeChild(node);
21077 this.setFirstChild(node);
21079 this.childNodes.splice(refIndex, 0, node);
21080 node.parentNode = this;
21081 var ps = this.childNodes[refIndex-1];
21083 node.previousSibling = ps;
21084 ps.nextSibling = node;
21086 node.previousSibling = null;
21088 node.nextSibling = refNode;
21089 refNode.previousSibling = node;
21090 node.setOwnerTree(this.getOwnerTree());
21091 this.fireEvent("insert", this.ownerTree, this, node, refNode);
21093 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
21099 * Returns the child node at the specified index.
21100 * @param {Number} index
21103 item : function(index){
21104 return this.childNodes[index];
21108 * Replaces one child node in this node with another.
21109 * @param {Node} newChild The replacement node
21110 * @param {Node} oldChild The node to replace
21111 * @return {Node} The replaced node
21113 replaceChild : function(newChild, oldChild){
21114 this.insertBefore(newChild, oldChild);
21115 this.removeChild(oldChild);
21120 * Returns the index of a child node
21121 * @param {Node} node
21122 * @return {Number} The index of the node or -1 if it was not found
21124 indexOf : function(child){
21125 return this.childNodes.indexOf(child);
21129 * Returns the tree this node is in.
21132 getOwnerTree : function(){
21133 // if it doesn't have one, look for one
21134 if(!this.ownerTree){
21138 this.ownerTree = p.ownerTree;
21144 return this.ownerTree;
21148 * Returns depth of this node (the root node has a depth of 0)
21151 getDepth : function(){
21154 while(p.parentNode){
21162 setOwnerTree : function(tree){
21163 // if it's move, we need to update everyone
21164 if(tree != this.ownerTree){
21165 if(this.ownerTree){
21166 this.ownerTree.unregisterNode(this);
21168 this.ownerTree = tree;
21169 var cs = this.childNodes;
21170 for(var i = 0, len = cs.length; i < len; i++) {
21171 cs[i].setOwnerTree(tree);
21174 tree.registerNode(this);
21180 * Returns the path for this node. The path can be used to expand or select this node programmatically.
21181 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
21182 * @return {String} The path
21184 getPath : function(attr){
21185 attr = attr || "id";
21186 var p = this.parentNode;
21187 var b = [this.attributes[attr]];
21189 b.unshift(p.attributes[attr]);
21192 var sep = this.getOwnerTree().pathSeparator;
21193 return sep + b.join(sep);
21197 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
21198 * function call will be the scope provided or the current node. The arguments to the function
21199 * will be the args provided or the current node. If the function returns false at any point,
21200 * the bubble is stopped.
21201 * @param {Function} fn The function to call
21202 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21203 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21205 bubble : function(fn, scope, args){
21208 if(fn.call(scope || p, args || p) === false){
21216 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
21217 * function call will be the scope provided or the current node. The arguments to the function
21218 * will be the args provided or the current node. If the function returns false at any point,
21219 * the cascade is stopped on that branch.
21220 * @param {Function} fn The function to call
21221 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21222 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21224 cascade : function(fn, scope, args){
21225 if(fn.call(scope || this, args || this) !== false){
21226 var cs = this.childNodes;
21227 for(var i = 0, len = cs.length; i < len; i++) {
21228 cs[i].cascade(fn, scope, args);
21234 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
21235 * function call will be the scope provided or the current node. The arguments to the function
21236 * will be the args provided or the current node. If the function returns false at any point,
21237 * the iteration stops.
21238 * @param {Function} fn The function to call
21239 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21240 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21242 eachChild : function(fn, scope, args){
21243 var cs = this.childNodes;
21244 for(var i = 0, len = cs.length; i < len; i++) {
21245 if(fn.call(scope || this, args || cs[i]) === false){
21252 * Finds the first child that has the attribute with the specified value.
21253 * @param {String} attribute The attribute name
21254 * @param {Mixed} value The value to search for
21255 * @return {Node} The found child or null if none was found
21257 findChild : function(attribute, value){
21258 var cs = this.childNodes;
21259 for(var i = 0, len = cs.length; i < len; i++) {
21260 if(cs[i].attributes[attribute] == value){
21268 * Finds the first child by a custom function. The child matches if the function passed
21270 * @param {Function} fn
21271 * @param {Object} scope (optional)
21272 * @return {Node} The found child or null if none was found
21274 findChildBy : function(fn, scope){
21275 var cs = this.childNodes;
21276 for(var i = 0, len = cs.length; i < len; i++) {
21277 if(fn.call(scope||cs[i], cs[i]) === true){
21285 * Sorts this nodes children using the supplied sort function
21286 * @param {Function} fn
21287 * @param {Object} scope (optional)
21289 sort : function(fn, scope){
21290 var cs = this.childNodes;
21291 var len = cs.length;
21293 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
21295 for(var i = 0; i < len; i++){
21297 n.previousSibling = cs[i-1];
21298 n.nextSibling = cs[i+1];
21300 this.setFirstChild(n);
21303 this.setLastChild(n);
21310 * Returns true if this node is an ancestor (at any point) of the passed node.
21311 * @param {Node} node
21312 * @return {Boolean}
21314 contains : function(node){
21315 return node.isAncestor(this);
21319 * Returns true if the passed node is an ancestor (at any point) of this node.
21320 * @param {Node} node
21321 * @return {Boolean}
21323 isAncestor : function(node){
21324 var p = this.parentNode;
21334 toString : function(){
21335 return "[Node"+(this.id?" "+this.id:"")+"]";
21339 * Ext JS Library 1.1.1
21340 * Copyright(c) 2006-2007, Ext JS, LLC.
21342 * Originally Released Under LGPL - original licence link has changed is not relivant.
21345 * <script type="text/javascript">
21350 * @class Roo.ComponentMgr
21351 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
21354 Roo.ComponentMgr = function(){
21355 var all = new Roo.util.MixedCollection();
21359 * Registers a component.
21360 * @param {Roo.Component} c The component
21362 register : function(c){
21367 * Unregisters a component.
21368 * @param {Roo.Component} c The component
21370 unregister : function(c){
21375 * Returns a component by id
21376 * @param {String} id The component id
21378 get : function(id){
21379 return all.get(id);
21383 * Registers a function that will be called when a specified component is added to ComponentMgr
21384 * @param {String} id The component id
21385 * @param {Funtction} fn The callback function
21386 * @param {Object} scope The scope of the callback
21388 onAvailable : function(id, fn, scope){
21389 all.on("add", function(index, o){
21391 fn.call(scope || o, o);
21392 all.un("add", fn, scope);
21399 * Ext JS Library 1.1.1
21400 * Copyright(c) 2006-2007, Ext JS, LLC.
21402 * Originally Released Under LGPL - original licence link has changed is not relivant.
21405 * <script type="text/javascript">
21409 * @class Roo.Component
21410 * @extends Roo.util.Observable
21411 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
21412 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
21413 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
21414 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
21415 * All visual components (widgets) that require rendering into a layout should subclass Component.
21417 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
21418 * element and its id used as the component id. If a string is passed, it is assumed to be the id of an existing element
21419 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
21421 Roo.Component = function(config){
21422 config = config || {};
21423 if(config.tagName || config.dom || typeof config == "string"){ // element object
21424 config = {el: config, id: config.id || config};
21426 this.initialConfig = config;
21428 Roo.apply(this, config);
21432 * Fires after the component is disabled.
21433 * @param {Roo.Component} this
21438 * Fires after the component is enabled.
21439 * @param {Roo.Component} this
21443 * @event beforeshow
21444 * Fires before the component is shown. Return false to stop the show.
21445 * @param {Roo.Component} this
21450 * Fires after the component is shown.
21451 * @param {Roo.Component} this
21455 * @event beforehide
21456 * Fires before the component is hidden. Return false to stop the hide.
21457 * @param {Roo.Component} this
21462 * Fires after the component is hidden.
21463 * @param {Roo.Component} this
21467 * @event beforerender
21468 * Fires before the component is rendered. Return false to stop the render.
21469 * @param {Roo.Component} this
21471 beforerender : true,
21474 * Fires after the component is rendered.
21475 * @param {Roo.Component} this
21479 * @event beforedestroy
21480 * Fires before the component is destroyed. Return false to stop the destroy.
21481 * @param {Roo.Component} this
21483 beforedestroy : true,
21486 * Fires after the component is destroyed.
21487 * @param {Roo.Component} this
21492 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
21494 Roo.ComponentMgr.register(this);
21495 Roo.Component.superclass.constructor.call(this);
21496 this.initComponent();
21497 if(this.renderTo){ // not supported by all components yet. use at your own risk!
21498 this.render(this.renderTo);
21499 delete this.renderTo;
21504 Roo.Component.AUTO_ID = 1000;
21506 Roo.extend(Roo.Component, Roo.util.Observable, {
21508 * @property {Boolean} hidden
21509 * true if this component is hidden. Read-only.
21513 * true if this component is disabled. Read-only.
21517 * true if this component has been rendered. Read-only.
21521 /** @cfg {String} disableClass
21522 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
21524 disabledClass : "x-item-disabled",
21525 /** @cfg {Boolean} allowDomMove
21526 * Whether the component can move the Dom node when rendering (defaults to true).
21528 allowDomMove : true,
21529 /** @cfg {String} hideMode
21530 * How this component should hidden. Supported values are
21531 * "visibility" (css visibility), "offsets" (negative offset position) and
21532 * "display" (css display) - defaults to "display".
21534 hideMode: 'display',
21537 ctype : "Roo.Component",
21539 /** @cfg {String} actionMode
21540 * which property holds the element that used for hide() / show() / disable() / enable()
21546 getActionEl : function(){
21547 return this[this.actionMode];
21550 initComponent : Roo.emptyFn,
21552 * If this is a lazy rendering component, render it to its container element.
21553 * @param {String/HTMLElement/Element} container (optional) The element this component should be rendered into. If it is being applied to existing markup, this should be left off.
21555 render : function(container, position){
21556 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
21557 if(!container && this.el){
21558 this.el = Roo.get(this.el);
21559 container = this.el.dom.parentNode;
21560 this.allowDomMove = false;
21562 this.container = Roo.get(container);
21563 this.rendered = true;
21564 if(position !== undefined){
21565 if(typeof position == 'number'){
21566 position = this.container.dom.childNodes[position];
21568 position = Roo.getDom(position);
21571 this.onRender(this.container, position || null);
21573 this.el.addClass(this.cls);
21577 this.el.applyStyles(this.style);
21580 this.fireEvent("render", this);
21581 this.afterRender(this.container);
21593 // default function is not really useful
21594 onRender : function(ct, position){
21596 this.el = Roo.get(this.el);
21597 if(this.allowDomMove !== false){
21598 ct.dom.insertBefore(this.el.dom, position);
21604 getAutoCreate : function(){
21605 var cfg = typeof this.autoCreate == "object" ?
21606 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
21607 if(this.id && !cfg.id){
21614 afterRender : Roo.emptyFn,
21617 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
21618 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
21620 destroy : function(){
21621 if(this.fireEvent("beforedestroy", this) !== false){
21622 this.purgeListeners();
21623 this.beforeDestroy();
21625 this.el.removeAllListeners();
21627 if(this.actionMode == "container"){
21628 this.container.remove();
21632 Roo.ComponentMgr.unregister(this);
21633 this.fireEvent("destroy", this);
21638 beforeDestroy : function(){
21643 onDestroy : function(){
21648 * Returns the underlying {@link Roo.Element}.
21649 * @return {Roo.Element} The element
21651 getEl : function(){
21656 * Returns the id of this component.
21659 getId : function(){
21664 * Try to focus this component.
21665 * @param {Boolean} selectText True to also select the text in this component (if applicable)
21666 * @return {Roo.Component} this
21668 focus : function(selectText){
21671 if(selectText === true){
21672 this.el.dom.select();
21687 * Disable this component.
21688 * @return {Roo.Component} this
21690 disable : function(){
21694 this.disabled = true;
21695 this.fireEvent("disable", this);
21700 onDisable : function(){
21701 this.getActionEl().addClass(this.disabledClass);
21702 this.el.dom.disabled = true;
21706 * Enable this component.
21707 * @return {Roo.Component} this
21709 enable : function(){
21713 this.disabled = false;
21714 this.fireEvent("enable", this);
21719 onEnable : function(){
21720 this.getActionEl().removeClass(this.disabledClass);
21721 this.el.dom.disabled = false;
21725 * Convenience function for setting disabled/enabled by boolean.
21726 * @param {Boolean} disabled
21728 setDisabled : function(disabled){
21729 this[disabled ? "disable" : "enable"]();
21733 * Show this component.
21734 * @return {Roo.Component} this
21737 if(this.fireEvent("beforeshow", this) !== false){
21738 this.hidden = false;
21742 this.fireEvent("show", this);
21748 onShow : function(){
21749 var ae = this.getActionEl();
21750 if(this.hideMode == 'visibility'){
21751 ae.dom.style.visibility = "visible";
21752 }else if(this.hideMode == 'offsets'){
21753 ae.removeClass('x-hidden');
21755 ae.dom.style.display = "";
21760 * Hide this component.
21761 * @return {Roo.Component} this
21764 if(this.fireEvent("beforehide", this) !== false){
21765 this.hidden = true;
21769 this.fireEvent("hide", this);
21775 onHide : function(){
21776 var ae = this.getActionEl();
21777 if(this.hideMode == 'visibility'){
21778 ae.dom.style.visibility = "hidden";
21779 }else if(this.hideMode == 'offsets'){
21780 ae.addClass('x-hidden');
21782 ae.dom.style.display = "none";
21787 * Convenience function to hide or show this component by boolean.
21788 * @param {Boolean} visible True to show, false to hide
21789 * @return {Roo.Component} this
21791 setVisible: function(visible){
21801 * Returns true if this component is visible.
21803 isVisible : function(){
21804 return this.getActionEl().isVisible();
21807 cloneConfig : function(overrides){
21808 overrides = overrides || {};
21809 var id = overrides.id || Roo.id();
21810 var cfg = Roo.applyIf(overrides, this.initialConfig);
21811 cfg.id = id; // prevent dup id
21812 return new this.constructor(cfg);
21816 * Ext JS Library 1.1.1
21817 * Copyright(c) 2006-2007, Ext JS, LLC.
21819 * Originally Released Under LGPL - original licence link has changed is not relivant.
21822 * <script type="text/javascript">
21827 * @extends Roo.Element
21828 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
21829 * automatic maintaining of shadow/shim positions.
21830 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
21831 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
21832 * you can pass a string with a CSS class name. False turns off the shadow.
21833 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
21834 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
21835 * @cfg {String} cls CSS class to add to the element
21836 * @cfg {Number} zindex Starting z-index (defaults to 11000)
21837 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
21839 * @param {Object} config An object with config options.
21840 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
21843 Roo.Layer = function(config, existingEl){
21844 config = config || {};
21845 var dh = Roo.DomHelper;
21846 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
21848 this.dom = Roo.getDom(existingEl);
21851 var o = config.dh || {tag: "div", cls: "x-layer"};
21852 this.dom = dh.append(pel, o);
21855 this.addClass(config.cls);
21857 this.constrain = config.constrain !== false;
21858 this.visibilityMode = Roo.Element.VISIBILITY;
21860 this.id = this.dom.id = config.id;
21862 this.id = Roo.id(this.dom);
21864 this.zindex = config.zindex || this.getZIndex();
21865 this.position("absolute", this.zindex);
21867 this.shadowOffset = config.shadowOffset || 4;
21868 this.shadow = new Roo.Shadow({
21869 offset : this.shadowOffset,
21870 mode : config.shadow
21873 this.shadowOffset = 0;
21875 this.useShim = config.shim !== false && Roo.useShims;
21876 this.useDisplay = config.useDisplay;
21880 var supr = Roo.Element.prototype;
21882 // shims are shared among layer to keep from having 100 iframes
21885 Roo.extend(Roo.Layer, Roo.Element, {
21887 getZIndex : function(){
21888 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
21891 getShim : function(){
21898 var shim = shims.shift();
21900 shim = this.createShim();
21901 shim.enableDisplayMode('block');
21902 shim.dom.style.display = 'none';
21903 shim.dom.style.visibility = 'visible';
21905 var pn = this.dom.parentNode;
21906 if(shim.dom.parentNode != pn){
21907 pn.insertBefore(shim.dom, this.dom);
21909 shim.setStyle('z-index', this.getZIndex()-2);
21914 hideShim : function(){
21916 this.shim.setDisplayed(false);
21917 shims.push(this.shim);
21922 disableShadow : function(){
21924 this.shadowDisabled = true;
21925 this.shadow.hide();
21926 this.lastShadowOffset = this.shadowOffset;
21927 this.shadowOffset = 0;
21931 enableShadow : function(show){
21933 this.shadowDisabled = false;
21934 this.shadowOffset = this.lastShadowOffset;
21935 delete this.lastShadowOffset;
21943 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
21944 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
21945 sync : function(doShow){
21946 var sw = this.shadow;
21947 if(!this.updating && this.isVisible() && (sw || this.useShim)){
21948 var sh = this.getShim();
21950 var w = this.getWidth(),
21951 h = this.getHeight();
21953 var l = this.getLeft(true),
21954 t = this.getTop(true);
21956 if(sw && !this.shadowDisabled){
21957 if(doShow && !sw.isVisible()){
21960 sw.realign(l, t, w, h);
21966 // fit the shim behind the shadow, so it is shimmed too
21967 var a = sw.adjusts, s = sh.dom.style;
21968 s.left = (Math.min(l, l+a.l))+"px";
21969 s.top = (Math.min(t, t+a.t))+"px";
21970 s.width = (w+a.w)+"px";
21971 s.height = (h+a.h)+"px";
21978 sh.setLeftTop(l, t);
21985 destroy : function(){
21988 this.shadow.hide();
21990 this.removeAllListeners();
21991 var pn = this.dom.parentNode;
21993 pn.removeChild(this.dom);
21995 Roo.Element.uncache(this.id);
21998 remove : function(){
22003 beginUpdate : function(){
22004 this.updating = true;
22008 endUpdate : function(){
22009 this.updating = false;
22014 hideUnders : function(negOffset){
22016 this.shadow.hide();
22022 constrainXY : function(){
22023 if(this.constrain){
22024 var vw = Roo.lib.Dom.getViewWidth(),
22025 vh = Roo.lib.Dom.getViewHeight();
22026 var s = Roo.get(document).getScroll();
22028 var xy = this.getXY();
22029 var x = xy[0], y = xy[1];
22030 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
22031 // only move it if it needs it
22033 // first validate right/bottom
22034 if((x + w) > vw+s.left){
22035 x = vw - w - this.shadowOffset;
22038 if((y + h) > vh+s.top){
22039 y = vh - h - this.shadowOffset;
22042 // then make sure top/left isn't negative
22053 var ay = this.avoidY;
22054 if(y <= ay && (y+h) >= ay){
22060 supr.setXY.call(this, xy);
22066 isVisible : function(){
22067 return this.visible;
22071 showAction : function(){
22072 this.visible = true; // track visibility to prevent getStyle calls
22073 if(this.useDisplay === true){
22074 this.setDisplayed("");
22075 }else if(this.lastXY){
22076 supr.setXY.call(this, this.lastXY);
22077 }else if(this.lastLT){
22078 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
22083 hideAction : function(){
22084 this.visible = false;
22085 if(this.useDisplay === true){
22086 this.setDisplayed(false);
22088 this.setLeftTop(-10000,-10000);
22092 // overridden Element method
22093 setVisible : function(v, a, d, c, e){
22098 var cb = function(){
22103 }.createDelegate(this);
22104 supr.setVisible.call(this, true, true, d, cb, e);
22107 this.hideUnders(true);
22116 }.createDelegate(this);
22118 supr.setVisible.call(this, v, a, d, cb, e);
22127 storeXY : function(xy){
22128 delete this.lastLT;
22132 storeLeftTop : function(left, top){
22133 delete this.lastXY;
22134 this.lastLT = [left, top];
22138 beforeFx : function(){
22139 this.beforeAction();
22140 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
22144 afterFx : function(){
22145 Roo.Layer.superclass.afterFx.apply(this, arguments);
22146 this.sync(this.isVisible());
22150 beforeAction : function(){
22151 if(!this.updating && this.shadow){
22152 this.shadow.hide();
22156 // overridden Element method
22157 setLeft : function(left){
22158 this.storeLeftTop(left, this.getTop(true));
22159 supr.setLeft.apply(this, arguments);
22163 setTop : function(top){
22164 this.storeLeftTop(this.getLeft(true), top);
22165 supr.setTop.apply(this, arguments);
22169 setLeftTop : function(left, top){
22170 this.storeLeftTop(left, top);
22171 supr.setLeftTop.apply(this, arguments);
22175 setXY : function(xy, a, d, c, e){
22177 this.beforeAction();
22179 var cb = this.createCB(c);
22180 supr.setXY.call(this, xy, a, d, cb, e);
22187 createCB : function(c){
22198 // overridden Element method
22199 setX : function(x, a, d, c, e){
22200 this.setXY([x, this.getY()], a, d, c, e);
22203 // overridden Element method
22204 setY : function(y, a, d, c, e){
22205 this.setXY([this.getX(), y], a, d, c, e);
22208 // overridden Element method
22209 setSize : function(w, h, a, d, c, e){
22210 this.beforeAction();
22211 var cb = this.createCB(c);
22212 supr.setSize.call(this, w, h, a, d, cb, e);
22218 // overridden Element method
22219 setWidth : function(w, a, d, c, e){
22220 this.beforeAction();
22221 var cb = this.createCB(c);
22222 supr.setWidth.call(this, w, a, d, cb, e);
22228 // overridden Element method
22229 setHeight : function(h, a, d, c, e){
22230 this.beforeAction();
22231 var cb = this.createCB(c);
22232 supr.setHeight.call(this, h, a, d, cb, e);
22238 // overridden Element method
22239 setBounds : function(x, y, w, h, a, d, c, e){
22240 this.beforeAction();
22241 var cb = this.createCB(c);
22243 this.storeXY([x, y]);
22244 supr.setXY.call(this, [x, y]);
22245 supr.setSize.call(this, w, h, a, d, cb, e);
22248 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
22254 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
22255 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
22256 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
22257 * @param {Number} zindex The new z-index to set
22258 * @return {this} The Layer
22260 setZIndex : function(zindex){
22261 this.zindex = zindex;
22262 this.setStyle("z-index", zindex + 2);
22264 this.shadow.setZIndex(zindex + 1);
22267 this.shim.setStyle("z-index", zindex);
22273 * Ext JS Library 1.1.1
22274 * Copyright(c) 2006-2007, Ext JS, LLC.
22276 * Originally Released Under LGPL - original licence link has changed is not relivant.
22279 * <script type="text/javascript">
22284 * @class Roo.Shadow
22285 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
22286 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
22287 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
22289 * Create a new Shadow
22290 * @param {Object} config The config object
22292 Roo.Shadow = function(config){
22293 Roo.apply(this, config);
22294 if(typeof this.mode != "string"){
22295 this.mode = this.defaultMode;
22297 var o = this.offset, a = {h: 0};
22298 var rad = Math.floor(this.offset/2);
22299 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
22305 a.l -= this.offset + rad;
22306 a.t -= this.offset + rad;
22317 a.l -= (this.offset - rad);
22318 a.t -= this.offset + rad;
22320 a.w -= (this.offset - rad)*2;
22331 a.l -= (this.offset - rad);
22332 a.t -= (this.offset - rad);
22334 a.w -= (this.offset + rad + 1);
22335 a.h -= (this.offset + rad);
22344 Roo.Shadow.prototype = {
22346 * @cfg {String} mode
22347 * The shadow display mode. Supports the following options:<br />
22348 * sides: Shadow displays on both sides and bottom only<br />
22349 * frame: Shadow displays equally on all four sides<br />
22350 * drop: Traditional bottom-right drop shadow (default)
22353 * @cfg {String} offset
22354 * The number of pixels to offset the shadow from the element (defaults to 4)
22359 defaultMode: "drop",
22362 * Displays the shadow under the target element
22363 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
22365 show : function(target){
22366 target = Roo.get(target);
22368 this.el = Roo.Shadow.Pool.pull();
22369 if(this.el.dom.nextSibling != target.dom){
22370 this.el.insertBefore(target);
22373 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
22375 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
22378 target.getLeft(true),
22379 target.getTop(true),
22383 this.el.dom.style.display = "block";
22387 * Returns true if the shadow is visible, else false
22389 isVisible : function(){
22390 return this.el ? true : false;
22394 * Direct alignment when values are already available. Show must be called at least once before
22395 * calling this method to ensure it is initialized.
22396 * @param {Number} left The target element left position
22397 * @param {Number} top The target element top position
22398 * @param {Number} width The target element width
22399 * @param {Number} height The target element height
22401 realign : function(l, t, w, h){
22405 var a = this.adjusts, d = this.el.dom, s = d.style;
22407 s.left = (l+a.l)+"px";
22408 s.top = (t+a.t)+"px";
22409 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
22410 if(s.width != sws || s.height != shs){
22414 var cn = d.childNodes;
22415 var sww = Math.max(0, (sw-12))+"px";
22416 cn[0].childNodes[1].style.width = sww;
22417 cn[1].childNodes[1].style.width = sww;
22418 cn[2].childNodes[1].style.width = sww;
22419 cn[1].style.height = Math.max(0, (sh-12))+"px";
22425 * Hides this shadow
22429 this.el.dom.style.display = "none";
22430 Roo.Shadow.Pool.push(this.el);
22436 * Adjust the z-index of this shadow
22437 * @param {Number} zindex The new z-index
22439 setZIndex : function(z){
22442 this.el.setStyle("z-index", z);
22447 // Private utility class that manages the internal Shadow cache
22448 Roo.Shadow.Pool = function(){
22450 var markup = Roo.isIE ?
22451 '<div class="x-ie-shadow"></div>' :
22452 '<div class="x-shadow"><div class="xst"><div class="xstl"></div><div class="xstc"></div><div class="xstr"></div></div><div class="xsc"><div class="xsml"></div><div class="xsmc"></div><div class="xsmr"></div></div><div class="xsb"><div class="xsbl"></div><div class="xsbc"></div><div class="xsbr"></div></div></div>';
22455 var sh = p.shift();
22457 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
22458 sh.autoBoxAdjust = false;
22463 push : function(sh){
22469 * Ext JS Library 1.1.1
22470 * Copyright(c) 2006-2007, Ext JS, LLC.
22472 * Originally Released Under LGPL - original licence link has changed is not relivant.
22475 * <script type="text/javascript">
22479 * @class Roo.BoxComponent
22480 * @extends Roo.Component
22481 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
22482 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
22483 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
22484 * layout containers.
22486 * @param {Roo.Element/String/Object} config The configuration options.
22488 Roo.BoxComponent = function(config){
22489 Roo.Component.call(this, config);
22493 * Fires after the component is resized.
22494 * @param {Roo.Component} this
22495 * @param {Number} adjWidth The box-adjusted width that was set
22496 * @param {Number} adjHeight The box-adjusted height that was set
22497 * @param {Number} rawWidth The width that was originally specified
22498 * @param {Number} rawHeight The height that was originally specified
22503 * Fires after the component is moved.
22504 * @param {Roo.Component} this
22505 * @param {Number} x The new x position
22506 * @param {Number} y The new y position
22512 Roo.extend(Roo.BoxComponent, Roo.Component, {
22513 // private, set in afterRender to signify that the component has been rendered
22515 // private, used to defer height settings to subclasses
22516 deferHeight: false,
22517 /** @cfg {Number} width
22518 * width (optional) size of component
22520 /** @cfg {Number} height
22521 * height (optional) size of component
22525 * Sets the width and height of the component. This method fires the resize event. This method can accept
22526 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
22527 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
22528 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
22529 * @return {Roo.BoxComponent} this
22531 setSize : function(w, h){
22532 // support for standard size objects
22533 if(typeof w == 'object'){
22538 if(!this.boxReady){
22544 // prevent recalcs when not needed
22545 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
22548 this.lastSize = {width: w, height: h};
22550 var adj = this.adjustSize(w, h);
22551 var aw = adj.width, ah = adj.height;
22552 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
22553 var rz = this.getResizeEl();
22554 if(!this.deferHeight && aw !== undefined && ah !== undefined){
22555 rz.setSize(aw, ah);
22556 }else if(!this.deferHeight && ah !== undefined){
22558 }else if(aw !== undefined){
22561 this.onResize(aw, ah, w, h);
22562 this.fireEvent('resize', this, aw, ah, w, h);
22568 * Gets the current size of the component's underlying element.
22569 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
22571 getSize : function(){
22572 return this.el.getSize();
22576 * Gets the current XY position of the component's underlying element.
22577 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
22578 * @return {Array} The XY position of the element (e.g., [100, 200])
22580 getPosition : function(local){
22581 if(local === true){
22582 return [this.el.getLeft(true), this.el.getTop(true)];
22584 return this.xy || this.el.getXY();
22588 * Gets the current box measurements of the component's underlying element.
22589 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
22590 * @returns {Object} box An object in the format {x, y, width, height}
22592 getBox : function(local){
22593 var s = this.el.getSize();
22595 s.x = this.el.getLeft(true);
22596 s.y = this.el.getTop(true);
22598 var xy = this.xy || this.el.getXY();
22606 * Sets the current box measurements of the component's underlying element.
22607 * @param {Object} box An object in the format {x, y, width, height}
22608 * @returns {Roo.BoxComponent} this
22610 updateBox : function(box){
22611 this.setSize(box.width, box.height);
22612 this.setPagePosition(box.x, box.y);
22617 getResizeEl : function(){
22618 return this.resizeEl || this.el;
22622 getPositionEl : function(){
22623 return this.positionEl || this.el;
22627 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
22628 * This method fires the move event.
22629 * @param {Number} left The new left
22630 * @param {Number} top The new top
22631 * @returns {Roo.BoxComponent} this
22633 setPosition : function(x, y){
22636 if(!this.boxReady){
22639 var adj = this.adjustPosition(x, y);
22640 var ax = adj.x, ay = adj.y;
22642 var el = this.getPositionEl();
22643 if(ax !== undefined || ay !== undefined){
22644 if(ax !== undefined && ay !== undefined){
22645 el.setLeftTop(ax, ay);
22646 }else if(ax !== undefined){
22648 }else if(ay !== undefined){
22651 this.onPosition(ax, ay);
22652 this.fireEvent('move', this, ax, ay);
22658 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
22659 * This method fires the move event.
22660 * @param {Number} x The new x position
22661 * @param {Number} y The new y position
22662 * @returns {Roo.BoxComponent} this
22664 setPagePosition : function(x, y){
22667 if(!this.boxReady){
22670 if(x === undefined || y === undefined){ // cannot translate undefined points
22673 var p = this.el.translatePoints(x, y);
22674 this.setPosition(p.left, p.top);
22679 onRender : function(ct, position){
22680 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
22682 this.resizeEl = Roo.get(this.resizeEl);
22684 if(this.positionEl){
22685 this.positionEl = Roo.get(this.positionEl);
22690 afterRender : function(){
22691 Roo.BoxComponent.superclass.afterRender.call(this);
22692 this.boxReady = true;
22693 this.setSize(this.width, this.height);
22694 if(this.x || this.y){
22695 this.setPosition(this.x, this.y);
22697 if(this.pageX || this.pageY){
22698 this.setPagePosition(this.pageX, this.pageY);
22703 * Force the component's size to recalculate based on the underlying element's current height and width.
22704 * @returns {Roo.BoxComponent} this
22706 syncSize : function(){
22707 delete this.lastSize;
22708 this.setSize(this.el.getWidth(), this.el.getHeight());
22713 * Called after the component is resized, this method is empty by default but can be implemented by any
22714 * subclass that needs to perform custom logic after a resize occurs.
22715 * @param {Number} adjWidth The box-adjusted width that was set
22716 * @param {Number} adjHeight The box-adjusted height that was set
22717 * @param {Number} rawWidth The width that was originally specified
22718 * @param {Number} rawHeight The height that was originally specified
22720 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
22725 * Called after the component is moved, this method is empty by default but can be implemented by any
22726 * subclass that needs to perform custom logic after a move occurs.
22727 * @param {Number} x The new x position
22728 * @param {Number} y The new y position
22730 onPosition : function(x, y){
22735 adjustSize : function(w, h){
22736 if(this.autoWidth){
22739 if(this.autoHeight){
22742 return {width : w, height: h};
22746 adjustPosition : function(x, y){
22747 return {x : x, y: y};
22751 * Ext JS Library 1.1.1
22752 * Copyright(c) 2006-2007, Ext JS, LLC.
22754 * Originally Released Under LGPL - original licence link has changed is not relivant.
22757 * <script type="text/javascript">
22762 * @class Roo.SplitBar
22763 * @extends Roo.util.Observable
22764 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
22768 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
22769 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
22770 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
22771 split.minSize = 100;
22772 split.maxSize = 600;
22773 split.animate = true;
22774 split.on('moved', splitterMoved);
22777 * Create a new SplitBar
22778 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
22779 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
22780 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
22781 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
22782 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
22783 position of the SplitBar).
22785 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
22788 this.el = Roo.get(dragElement, true);
22789 this.el.dom.unselectable = "on";
22791 this.resizingEl = Roo.get(resizingElement, true);
22795 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
22796 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
22799 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
22802 * The minimum size of the resizing element. (Defaults to 0)
22808 * The maximum size of the resizing element. (Defaults to 2000)
22811 this.maxSize = 2000;
22814 * Whether to animate the transition to the new size
22817 this.animate = false;
22820 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
22823 this.useShim = false;
22828 if(!existingProxy){
22830 this.proxy = Roo.SplitBar.createProxy(this.orientation);
22832 this.proxy = Roo.get(existingProxy).dom;
22835 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
22838 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
22841 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
22844 this.dragSpecs = {};
22847 * @private The adapter to use to positon and resize elements
22849 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
22850 this.adapter.init(this);
22852 if(this.orientation == Roo.SplitBar.HORIZONTAL){
22854 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
22855 this.el.addClass("x-splitbar-h");
22858 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
22859 this.el.addClass("x-splitbar-v");
22865 * Fires when the splitter is moved (alias for {@link #event-moved})
22866 * @param {Roo.SplitBar} this
22867 * @param {Number} newSize the new width or height
22872 * Fires when the splitter is moved
22873 * @param {Roo.SplitBar} this
22874 * @param {Number} newSize the new width or height
22878 * @event beforeresize
22879 * Fires before the splitter is dragged
22880 * @param {Roo.SplitBar} this
22882 "beforeresize" : true,
22884 "beforeapply" : true
22887 Roo.util.Observable.call(this);
22890 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
22891 onStartProxyDrag : function(x, y){
22892 this.fireEvent("beforeresize", this);
22894 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
22896 o.enableDisplayMode("block");
22897 // all splitbars share the same overlay
22898 Roo.SplitBar.prototype.overlay = o;
22900 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
22901 this.overlay.show();
22902 Roo.get(this.proxy).setDisplayed("block");
22903 var size = this.adapter.getElementSize(this);
22904 this.activeMinSize = this.getMinimumSize();;
22905 this.activeMaxSize = this.getMaximumSize();;
22906 var c1 = size - this.activeMinSize;
22907 var c2 = Math.max(this.activeMaxSize - size, 0);
22908 if(this.orientation == Roo.SplitBar.HORIZONTAL){
22909 this.dd.resetConstraints();
22910 this.dd.setXConstraint(
22911 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
22912 this.placement == Roo.SplitBar.LEFT ? c2 : c1
22914 this.dd.setYConstraint(0, 0);
22916 this.dd.resetConstraints();
22917 this.dd.setXConstraint(0, 0);
22918 this.dd.setYConstraint(
22919 this.placement == Roo.SplitBar.TOP ? c1 : c2,
22920 this.placement == Roo.SplitBar.TOP ? c2 : c1
22923 this.dragSpecs.startSize = size;
22924 this.dragSpecs.startPoint = [x, y];
22925 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
22929 * @private Called after the drag operation by the DDProxy
22931 onEndProxyDrag : function(e){
22932 Roo.get(this.proxy).setDisplayed(false);
22933 var endPoint = Roo.lib.Event.getXY(e);
22935 this.overlay.hide();
22938 if(this.orientation == Roo.SplitBar.HORIZONTAL){
22939 newSize = this.dragSpecs.startSize +
22940 (this.placement == Roo.SplitBar.LEFT ?
22941 endPoint[0] - this.dragSpecs.startPoint[0] :
22942 this.dragSpecs.startPoint[0] - endPoint[0]
22945 newSize = this.dragSpecs.startSize +
22946 (this.placement == Roo.SplitBar.TOP ?
22947 endPoint[1] - this.dragSpecs.startPoint[1] :
22948 this.dragSpecs.startPoint[1] - endPoint[1]
22951 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
22952 if(newSize != this.dragSpecs.startSize){
22953 if(this.fireEvent('beforeapply', this, newSize) !== false){
22954 this.adapter.setElementSize(this, newSize);
22955 this.fireEvent("moved", this, newSize);
22956 this.fireEvent("resize", this, newSize);
22962 * Get the adapter this SplitBar uses
22963 * @return The adapter object
22965 getAdapter : function(){
22966 return this.adapter;
22970 * Set the adapter this SplitBar uses
22971 * @param {Object} adapter A SplitBar adapter object
22973 setAdapter : function(adapter){
22974 this.adapter = adapter;
22975 this.adapter.init(this);
22979 * Gets the minimum size for the resizing element
22980 * @return {Number} The minimum size
22982 getMinimumSize : function(){
22983 return this.minSize;
22987 * Sets the minimum size for the resizing element
22988 * @param {Number} minSize The minimum size
22990 setMinimumSize : function(minSize){
22991 this.minSize = minSize;
22995 * Gets the maximum size for the resizing element
22996 * @return {Number} The maximum size
22998 getMaximumSize : function(){
22999 return this.maxSize;
23003 * Sets the maximum size for the resizing element
23004 * @param {Number} maxSize The maximum size
23006 setMaximumSize : function(maxSize){
23007 this.maxSize = maxSize;
23011 * Sets the initialize size for the resizing element
23012 * @param {Number} size The initial size
23014 setCurrentSize : function(size){
23015 var oldAnimate = this.animate;
23016 this.animate = false;
23017 this.adapter.setElementSize(this, size);
23018 this.animate = oldAnimate;
23022 * Destroy this splitbar.
23023 * @param {Boolean} removeEl True to remove the element
23025 destroy : function(removeEl){
23027 this.shim.remove();
23030 this.proxy.parentNode.removeChild(this.proxy);
23038 * @private static Create our own proxy element element. So it will be the same same size on all browsers, we won't use borders. Instead we use a background color.
23040 Roo.SplitBar.createProxy = function(dir){
23041 var proxy = new Roo.Element(document.createElement("div"));
23042 proxy.unselectable();
23043 var cls = 'x-splitbar-proxy';
23044 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
23045 document.body.appendChild(proxy.dom);
23050 * @class Roo.SplitBar.BasicLayoutAdapter
23051 * Default Adapter. It assumes the splitter and resizing element are not positioned
23052 * elements and only gets/sets the width of the element. Generally used for table based layouts.
23054 Roo.SplitBar.BasicLayoutAdapter = function(){
23057 Roo.SplitBar.BasicLayoutAdapter.prototype = {
23058 // do nothing for now
23059 init : function(s){
23063 * Called before drag operations to get the current size of the resizing element.
23064 * @param {Roo.SplitBar} s The SplitBar using this adapter
23066 getElementSize : function(s){
23067 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23068 return s.resizingEl.getWidth();
23070 return s.resizingEl.getHeight();
23075 * Called after drag operations to set the size of the resizing element.
23076 * @param {Roo.SplitBar} s The SplitBar using this adapter
23077 * @param {Number} newSize The new size to set
23078 * @param {Function} onComplete A function to be invoked when resizing is complete
23080 setElementSize : function(s, newSize, onComplete){
23081 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23083 s.resizingEl.setWidth(newSize);
23085 onComplete(s, newSize);
23088 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
23093 s.resizingEl.setHeight(newSize);
23095 onComplete(s, newSize);
23098 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
23105 *@class Roo.SplitBar.AbsoluteLayoutAdapter
23106 * @extends Roo.SplitBar.BasicLayoutAdapter
23107 * Adapter that moves the splitter element to align with the resized sizing element.
23108 * Used with an absolute positioned SplitBar.
23109 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
23110 * document.body, make sure you assign an id to the body element.
23112 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
23113 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
23114 this.container = Roo.get(container);
23117 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
23118 init : function(s){
23119 this.basic.init(s);
23122 getElementSize : function(s){
23123 return this.basic.getElementSize(s);
23126 setElementSize : function(s, newSize, onComplete){
23127 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
23130 moveSplitter : function(s){
23131 var yes = Roo.SplitBar;
23132 switch(s.placement){
23134 s.el.setX(s.resizingEl.getRight());
23137 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
23140 s.el.setY(s.resizingEl.getBottom());
23143 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
23150 * Orientation constant - Create a vertical SplitBar
23154 Roo.SplitBar.VERTICAL = 1;
23157 * Orientation constant - Create a horizontal SplitBar
23161 Roo.SplitBar.HORIZONTAL = 2;
23164 * Placement constant - The resizing element is to the left of the splitter element
23168 Roo.SplitBar.LEFT = 1;
23171 * Placement constant - The resizing element is to the right of the splitter element
23175 Roo.SplitBar.RIGHT = 2;
23178 * Placement constant - The resizing element is positioned above the splitter element
23182 Roo.SplitBar.TOP = 3;
23185 * Placement constant - The resizing element is positioned under splitter element
23189 Roo.SplitBar.BOTTOM = 4;
23192 * Ext JS Library 1.1.1
23193 * Copyright(c) 2006-2007, Ext JS, LLC.
23195 * Originally Released Under LGPL - original licence link has changed is not relivant.
23198 * <script type="text/javascript">
23203 * @extends Roo.util.Observable
23204 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
23205 * This class also supports single and multi selection modes. <br>
23206 * Create a data model bound view:
23208 var store = new Roo.data.Store(...);
23210 var view = new Roo.View("my-element",
23211 '<div id="{0}">{2} - {1}</div>', // auto create template
23213 singleSelect: true,
23214 selectedClass: "ydataview-selected",
23218 // listen for node click?
23219 view.on("click", function(vw, index, node, e){
23220 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
23224 dataModel.load("foobar.xml");
23226 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
23228 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
23229 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
23231 * Create a new View
23232 * @param {String/HTMLElement/Element} container The container element where the view is to be rendered.
23233 * @param {String/DomHelper.Template} tpl The rendering template or a string to create a template with
23234 * @param {Object} config The config object
23236 Roo.View = function(container, tpl, config){
23237 this.el = Roo.get(container);
23238 if(typeof tpl == "string"){
23239 tpl = new Roo.Template(tpl);
23243 * The template used by this View
23244 * @type {Roo.DomHelper.Template}
23248 Roo.apply(this, config);
23253 * @event beforeclick
23254 * Fires before a click is processed. Returns false to cancel the default action.
23255 * @param {Roo.View} this
23256 * @param {Number} index The index of the target node
23257 * @param {HTMLElement} node The target node
23258 * @param {Roo.EventObject} e The raw event object
23260 "beforeclick" : true,
23263 * Fires when a template node is clicked.
23264 * @param {Roo.View} this
23265 * @param {Number} index The index of the target node
23266 * @param {HTMLElement} node The target node
23267 * @param {Roo.EventObject} e The raw event object
23272 * Fires when a template node is double clicked.
23273 * @param {Roo.View} this
23274 * @param {Number} index The index of the target node
23275 * @param {HTMLElement} node The target node
23276 * @param {Roo.EventObject} e The raw event object
23280 * @event contextmenu
23281 * Fires when a template node is right clicked.
23282 * @param {Roo.View} this
23283 * @param {Number} index The index of the target node
23284 * @param {HTMLElement} node The target node
23285 * @param {Roo.EventObject} e The raw event object
23287 "contextmenu" : true,
23289 * @event selectionchange
23290 * Fires when the selected nodes change.
23291 * @param {Roo.View} this
23292 * @param {Array} selections Array of the selected nodes
23294 "selectionchange" : true,
23297 * @event beforeselect
23298 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
23299 * @param {Roo.View} this
23300 * @param {HTMLElement} node The node to be selected
23301 * @param {Array} selections Array of currently selected nodes
23303 "beforeselect" : true
23307 "click": this.onClick,
23308 "dblclick": this.onDblClick,
23309 "contextmenu": this.onContextMenu,
23313 this.selections = [];
23315 this.cmp = new Roo.CompositeElementLite([]);
23317 this.store = Roo.factory(this.store, Roo.data);
23318 this.setStore(this.store, true);
23320 Roo.View.superclass.constructor.call(this);
23323 Roo.extend(Roo.View, Roo.util.Observable, {
23325 * The css class to add to selected nodes
23326 * @type {Roo.DomHelper.Template}
23328 selectedClass : "x-view-selected",
23332 * Returns the element this view is bound to.
23333 * @return {Roo.Element}
23335 getEl : function(){
23340 * Refreshes the view.
23342 refresh : function(){
23344 this.clearSelections();
23345 this.el.update("");
23347 var records = this.store.getRange();
23348 if(records.length < 1){
23349 this.el.update(this.emptyText);
23352 for(var i = 0, len = records.length; i < len; i++){
23353 var data = this.prepareData(records[i].data, i, records[i]);
23354 html[html.length] = t.apply(data);
23356 this.el.update(html.join(""));
23357 this.nodes = this.el.dom.childNodes;
23358 this.updateIndexes(0);
23362 * Function to override to reformat the data that is sent to
23363 * the template for each node.
23364 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
23365 * a JSON object for an UpdateManager bound view).
23367 prepareData : function(data){
23371 onUpdate : function(ds, record){
23372 this.clearSelections();
23373 var index = this.store.indexOf(record);
23374 var n = this.nodes[index];
23375 this.tpl.insertBefore(n, this.prepareData(record.data));
23376 n.parentNode.removeChild(n);
23377 this.updateIndexes(index, index);
23380 onAdd : function(ds, records, index){
23381 this.clearSelections();
23382 if(this.nodes.length == 0){
23386 var n = this.nodes[index];
23387 for(var i = 0, len = records.length; i < len; i++){
23388 var d = this.prepareData(records[i].data);
23390 this.tpl.insertBefore(n, d);
23392 this.tpl.append(this.el, d);
23395 this.updateIndexes(index);
23398 onRemove : function(ds, record, index){
23399 this.clearSelections();
23400 this.el.dom.removeChild(this.nodes[index]);
23401 this.updateIndexes(index);
23405 * Refresh an individual node.
23406 * @param {Number} index
23408 refreshNode : function(index){
23409 this.onUpdate(this.store, this.store.getAt(index));
23412 updateIndexes : function(startIndex, endIndex){
23413 var ns = this.nodes;
23414 startIndex = startIndex || 0;
23415 endIndex = endIndex || ns.length - 1;
23416 for(var i = startIndex; i <= endIndex; i++){
23417 ns[i].nodeIndex = i;
23422 * Changes the data store this view uses and refresh the view.
23423 * @param {Store} store
23425 setStore : function(store, initial){
23426 if(!initial && this.store){
23427 this.store.un("datachanged", this.refresh);
23428 this.store.un("add", this.onAdd);
23429 this.store.un("remove", this.onRemove);
23430 this.store.un("update", this.onUpdate);
23431 this.store.un("clear", this.refresh);
23435 store.on("datachanged", this.refresh, this);
23436 store.on("add", this.onAdd, this);
23437 store.on("remove", this.onRemove, this);
23438 store.on("update", this.onUpdate, this);
23439 store.on("clear", this.refresh, this);
23448 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
23449 * @param {HTMLElement} node
23450 * @return {HTMLElement} The template node
23452 findItemFromChild : function(node){
23453 var el = this.el.dom;
23454 if(!node || node.parentNode == el){
23457 var p = node.parentNode;
23458 while(p && p != el){
23459 if(p.parentNode == el){
23468 onClick : function(e){
23469 var item = this.findItemFromChild(e.getTarget());
23471 var index = this.indexOf(item);
23472 if(this.onItemClick(item, index, e) !== false){
23473 this.fireEvent("click", this, index, item, e);
23476 this.clearSelections();
23481 onContextMenu : function(e){
23482 var item = this.findItemFromChild(e.getTarget());
23484 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
23489 onDblClick : function(e){
23490 var item = this.findItemFromChild(e.getTarget());
23492 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
23496 onItemClick : function(item, index, e){
23497 if(this.fireEvent("beforeclick", this, index, item, e) === false){
23500 if(this.multiSelect || this.singleSelect){
23501 if(this.multiSelect && e.shiftKey && this.lastSelection){
23502 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
23504 this.select(item, this.multiSelect && e.ctrlKey);
23505 this.lastSelection = item;
23507 e.preventDefault();
23513 * Get the number of selected nodes.
23516 getSelectionCount : function(){
23517 return this.selections.length;
23521 * Get the currently selected nodes.
23522 * @return {Array} An array of HTMLElements
23524 getSelectedNodes : function(){
23525 return this.selections;
23529 * Get the indexes of the selected nodes.
23532 getSelectedIndexes : function(){
23533 var indexes = [], s = this.selections;
23534 for(var i = 0, len = s.length; i < len; i++){
23535 indexes.push(s[i].nodeIndex);
23541 * Clear all selections
23542 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
23544 clearSelections : function(suppressEvent){
23545 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
23546 this.cmp.elements = this.selections;
23547 this.cmp.removeClass(this.selectedClass);
23548 this.selections = [];
23549 if(!suppressEvent){
23550 this.fireEvent("selectionchange", this, this.selections);
23556 * Returns true if the passed node is selected
23557 * @param {HTMLElement/Number} node The node or node index
23558 * @return {Boolean}
23560 isSelected : function(node){
23561 var s = this.selections;
23565 node = this.getNode(node);
23566 return s.indexOf(node) !== -1;
23571 * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
23572 * @param {Boolean} keepExisting (optional) true to keep existing selections
23573 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
23575 select : function(nodeInfo, keepExisting, suppressEvent){
23576 if(nodeInfo instanceof Array){
23578 this.clearSelections(true);
23580 for(var i = 0, len = nodeInfo.length; i < len; i++){
23581 this.select(nodeInfo[i], true, true);
23584 var node = this.getNode(nodeInfo);
23585 if(node && !this.isSelected(node)){
23587 this.clearSelections(true);
23589 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
23590 Roo.fly(node).addClass(this.selectedClass);
23591 this.selections.push(node);
23592 if(!suppressEvent){
23593 this.fireEvent("selectionchange", this, this.selections);
23601 * Gets a template node.
23602 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
23603 * @return {HTMLElement} The node or null if it wasn't found
23605 getNode : function(nodeInfo){
23606 if(typeof nodeInfo == "string"){
23607 return document.getElementById(nodeInfo);
23608 }else if(typeof nodeInfo == "number"){
23609 return this.nodes[nodeInfo];
23615 * Gets a range template nodes.
23616 * @param {Number} startIndex
23617 * @param {Number} endIndex
23618 * @return {Array} An array of nodes
23620 getNodes : function(start, end){
23621 var ns = this.nodes;
23622 start = start || 0;
23623 end = typeof end == "undefined" ? ns.length - 1 : end;
23626 for(var i = start; i <= end; i++){
23630 for(var i = start; i >= end; i--){
23638 * Finds the index of the passed node
23639 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
23640 * @return {Number} The index of the node or -1
23642 indexOf : function(node){
23643 node = this.getNode(node);
23644 if(typeof node.nodeIndex == "number"){
23645 return node.nodeIndex;
23647 var ns = this.nodes;
23648 for(var i = 0, len = ns.length; i < len; i++){
23658 * Ext JS Library 1.1.1
23659 * Copyright(c) 2006-2007, Ext JS, LLC.
23661 * Originally Released Under LGPL - original licence link has changed is not relivant.
23664 * <script type="text/javascript">
23668 * @class Roo.JsonView
23669 * @extends Roo.View
23670 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
23672 var view = new Roo.JsonView("my-element",
23673 '<div id="{id}">{foo} - {bar}</div>', // auto create template
23674 { multiSelect: true, jsonRoot: "data" }
23677 // listen for node click?
23678 view.on("click", function(vw, index, node, e){
23679 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
23682 // direct load of JSON data
23683 view.load("foobar.php");
23685 // Example from my blog list
23686 var tpl = new Roo.Template(
23687 '<div class="entry">' +
23688 '<a class="entry-title" href="{link}">{title}</a>' +
23689 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
23690 "</div><hr />"
23693 var moreView = new Roo.JsonView("entry-list", tpl, {
23696 moreView.on("beforerender", this.sortEntries, this);
23698 url: "/blog/get-posts.php",
23699 params: "allposts=true",
23700 text: "Loading Blog Entries..."
23704 * Create a new JsonView
23705 * @param {String/HTMLElement/Element} container The container element where the view is to be rendered.
23706 * @param {Template} tpl The rendering template
23707 * @param {Object} config The config object
23709 Roo.JsonView = function(container, tpl, config){
23710 Roo.JsonView.superclass.constructor.call(this, container, tpl, config);
23712 var um = this.el.getUpdateManager();
23713 um.setRenderer(this);
23714 um.on("update", this.onLoad, this);
23715 um.on("failure", this.onLoadException, this);
23718 * @event beforerender
23719 * Fires before rendering of the downloaded JSON data.
23720 * @param {Roo.JsonView} this
23721 * @param {Object} data The JSON data loaded
23725 * Fires when data is loaded.
23726 * @param {Roo.JsonView} this
23727 * @param {Object} data The JSON data loaded
23728 * @param {Object} response The raw Connect response object
23731 * @event loadexception
23732 * Fires when loading fails.
23733 * @param {Roo.JsonView} this
23734 * @param {Object} response The raw Connect response object
23737 'beforerender' : true,
23739 'loadexception' : true
23742 Roo.extend(Roo.JsonView, Roo.View, {
23744 * The root property in the loaded JSON object that contains the data
23750 * Refreshes the view.
23752 refresh : function(){
23753 this.clearSelections();
23754 this.el.update("");
23756 var o = this.jsonData;
23757 if(o && o.length > 0){
23758 for(var i = 0, len = o.length; i < len; i++){
23759 var data = this.prepareData(o[i], i, o);
23760 html[html.length] = this.tpl.apply(data);
23763 html.push(this.emptyText);
23765 this.el.update(html.join(""));
23766 this.nodes = this.el.dom.childNodes;
23767 this.updateIndexes(0);
23771 * Performs an async HTTP request, and loads the JSON from the response. If <i>params</i> are specified it uses POST, otherwise it uses GET.
23772 * @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:
23775 url: "your-url.php",
23776 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
23777 callback: yourFunction,
23778 scope: yourObject, //(optional scope)
23781 text: "Loading...",
23786 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
23787 * are respectively shorthand for <i>disableCaching</i>, <i>indicatorText</i>, and <i>loadScripts</i> and are used to set their associated property on this UpdateManager instance.
23788 * @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}
23789 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
23790 * @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.
23793 var um = this.el.getUpdateManager();
23794 um.update.apply(um, arguments);
23797 render : function(el, response){
23798 this.clearSelections();
23799 this.el.update("");
23802 o = Roo.util.JSON.decode(response.responseText);
23805 o = /** eval:var:o */ eval("o." + this.jsonRoot);
23810 * The current JSON data or null
23813 this.beforeRender();
23818 * Get the number of records in the current JSON dataset
23821 getCount : function(){
23822 return this.jsonData ? this.jsonData.length : 0;
23826 * Returns the JSON object for the specified node(s)
23827 * @param {HTMLElement/Array} node The node or an array of nodes
23828 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
23829 * you get the JSON object for the node
23831 getNodeData : function(node){
23832 if(node instanceof Array){
23834 for(var i = 0, len = node.length; i < len; i++){
23835 data.push(this.getNodeData(node[i]));
23839 return this.jsonData[this.indexOf(node)] || null;
23842 beforeRender : function(){
23843 this.snapshot = this.jsonData;
23845 this.sort.apply(this, this.sortInfo);
23847 this.fireEvent("beforerender", this, this.jsonData);
23850 onLoad : function(el, o){
23851 this.fireEvent("load", this, this.jsonData, o);
23854 onLoadException : function(el, o){
23855 this.fireEvent("loadexception", this, o);
23859 * Filter the data by a specific property.
23860 * @param {String} property A property on your JSON objects
23861 * @param {String/RegExp} value Either string that the property values
23862 * should start with, or a RegExp to test against the property
23864 filter : function(property, value){
23867 var ss = this.snapshot;
23868 if(typeof value == "string"){
23869 var vlen = value.length;
23871 this.clearFilter();
23874 value = value.toLowerCase();
23875 for(var i = 0, len = ss.length; i < len; i++){
23877 if(o[property].substr(0, vlen).toLowerCase() == value){
23881 } else if(value.exec){ // regex?
23882 for(var i = 0, len = ss.length; i < len; i++){
23884 if(value.test(o[property])){
23891 this.jsonData = data;
23897 * Filter by a function. The passed function will be called with each
23898 * object in the current dataset. If the function returns true the value is kept,
23899 * otherwise it is filtered.
23900 * @param {Function} fn
23901 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
23903 filterBy : function(fn, scope){
23906 var ss = this.snapshot;
23907 for(var i = 0, len = ss.length; i < len; i++){
23909 if(fn.call(scope || this, o)){
23913 this.jsonData = data;
23919 * Clears the current filter.
23921 clearFilter : function(){
23922 if(this.snapshot && this.jsonData != this.snapshot){
23923 this.jsonData = this.snapshot;
23930 * Sorts the data for this view and refreshes it.
23931 * @param {String} property A property on your JSON objects to sort on
23932 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
23933 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
23935 sort : function(property, dir, sortType){
23936 this.sortInfo = Array.prototype.slice.call(arguments, 0);
23939 var dsc = dir && dir.toLowerCase() == "desc";
23940 var f = function(o1, o2){
23941 var v1 = sortType ? sortType(o1[p]) : o1[p];
23942 var v2 = sortType ? sortType(o2[p]) : o2[p];
23945 return dsc ? +1 : -1;
23946 } else if(v1 > v2){
23947 return dsc ? -1 : +1;
23952 this.jsonData.sort(f);
23954 if(this.jsonData != this.snapshot){
23955 this.snapshot.sort(f);
23961 * Ext JS Library 1.1.1
23962 * Copyright(c) 2006-2007, Ext JS, LLC.
23964 * Originally Released Under LGPL - original licence link has changed is not relivant.
23967 * <script type="text/javascript">
23972 * @class Roo.ColorPalette
23973 * @extends Roo.Component
23974 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
23975 * Here's an example of typical usage:
23977 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
23978 cp.render('my-div');
23980 cp.on('select', function(palette, selColor){
23981 // do something with selColor
23985 * Create a new ColorPalette
23986 * @param {Object} config The config object
23988 Roo.ColorPalette = function(config){
23989 Roo.ColorPalette.superclass.constructor.call(this, config);
23993 * Fires when a color is selected
23994 * @param {ColorPalette} this
23995 * @param {String} color The 6-digit color hex code (without the # symbol)
24001 this.on("select", this.handler, this.scope, true);
24004 Roo.extend(Roo.ColorPalette, Roo.Component, {
24006 * @cfg {String} itemCls
24007 * The CSS class to apply to the containing element (defaults to "x-color-palette")
24009 itemCls : "x-color-palette",
24011 * @cfg {String} value
24012 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
24013 * the hex codes are case-sensitive.
24016 clickEvent:'click',
24018 ctype: "Roo.ColorPalette",
24021 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
24023 allowReselect : false,
24026 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
24027 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
24028 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
24029 * of colors with the width setting until the box is symmetrical.</p>
24030 * <p>You can override individual colors if needed:</p>
24032 var cp = new Roo.ColorPalette();
24033 cp.colors[0] = "FF0000"; // change the first box to red
24036 Or you can provide a custom array of your own for complete control:
24038 var cp = new Roo.ColorPalette();
24039 cp.colors = ["000000", "993300", "333300"];
24044 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
24045 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
24046 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
24047 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
24048 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
24052 onRender : function(container, position){
24053 var t = new Roo.MasterTemplate(
24054 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
24056 var c = this.colors;
24057 for(var i = 0, len = c.length; i < len; i++){
24060 var el = document.createElement("div");
24061 el.className = this.itemCls;
24063 container.dom.insertBefore(el, position);
24064 this.el = Roo.get(el);
24065 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
24066 if(this.clickEvent != 'click'){
24067 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
24072 afterRender : function(){
24073 Roo.ColorPalette.superclass.afterRender.call(this);
24075 var s = this.value;
24082 handleClick : function(e, t){
24083 e.preventDefault();
24084 if(!this.disabled){
24085 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
24086 this.select(c.toUpperCase());
24091 * Selects the specified color in the palette (fires the select event)
24092 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
24094 select : function(color){
24095 color = color.replace("#", "");
24096 if(color != this.value || this.allowReselect){
24099 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
24101 el.child("a.color-"+color).addClass("x-color-palette-sel");
24102 this.value = color;
24103 this.fireEvent("select", this, color);
24108 * Ext JS Library 1.1.1
24109 * Copyright(c) 2006-2007, Ext JS, LLC.
24111 * Originally Released Under LGPL - original licence link has changed is not relivant.
24114 * <script type="text/javascript">
24118 * @class Roo.DatePicker
24119 * @extends Roo.Component
24120 * Simple date picker class.
24122 * Create a new DatePicker
24123 * @param {Object} config The config object
24125 Roo.DatePicker = function(config){
24126 Roo.DatePicker.superclass.constructor.call(this, config);
24128 this.value = config && config.value ?
24129 config.value.clearTime() : new Date().clearTime();
24134 * Fires when a date is selected
24135 * @param {DatePicker} this
24136 * @param {Date} date The selected date
24142 this.on("select", this.handler, this.scope || this);
24144 // build the disabledDatesRE
24145 if(!this.disabledDatesRE && this.disabledDates){
24146 var dd = this.disabledDates;
24148 for(var i = 0; i < dd.length; i++){
24150 if(i != dd.length-1) re += "|";
24152 this.disabledDatesRE = new RegExp(re + ")");
24156 Roo.extend(Roo.DatePicker, Roo.Component, {
24158 * @cfg {String} todayText
24159 * The text to display on the button that selects the current date (defaults to "Today")
24161 todayText : "Today",
24163 * @cfg {String} okText
24164 * The text to display on the ok button
24166 okText : " OK ", //   to give the user extra clicking room
24168 * @cfg {String} cancelText
24169 * The text to display on the cancel button
24171 cancelText : "Cancel",
24173 * @cfg {String} todayTip
24174 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
24176 todayTip : "{0} (Spacebar)",
24178 * @cfg {Date} minDate
24179 * Minimum allowable date (JavaScript date object, defaults to null)
24183 * @cfg {Date} maxDate
24184 * Maximum allowable date (JavaScript date object, defaults to null)
24188 * @cfg {String} minText
24189 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
24191 minText : "This date is before the minimum date",
24193 * @cfg {String} maxText
24194 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
24196 maxText : "This date is after the maximum date",
24198 * @cfg {String} format
24199 * The default date format string which can be overriden for localization support. The format must be
24200 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
24204 * @cfg {Array} disabledDays
24205 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
24207 disabledDays : null,
24209 * @cfg {String} disabledDaysText
24210 * The tooltip to display when the date falls on a disabled day (defaults to "")
24212 disabledDaysText : "",
24214 * @cfg {RegExp} disabledDatesRE
24215 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
24217 disabledDatesRE : null,
24219 * @cfg {String} disabledDatesText
24220 * The tooltip text to display when the date falls on a disabled date (defaults to "")
24222 disabledDatesText : "",
24224 * @cfg {Boolean} constrainToViewport
24225 * True to constrain the date picker to the viewport (defaults to true)
24227 constrainToViewport : true,
24229 * @cfg {Array} monthNames
24230 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
24232 monthNames : Date.monthNames,
24234 * @cfg {Array} dayNames
24235 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
24237 dayNames : Date.dayNames,
24239 * @cfg {String} nextText
24240 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
24242 nextText: 'Next Month (Control+Right)',
24244 * @cfg {String} prevText
24245 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
24247 prevText: 'Previous Month (Control+Left)',
24249 * @cfg {String} monthYearText
24250 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
24252 monthYearText: 'Choose a month (Control+Up/Down to move years)',
24254 * @cfg {Number} startDay
24255 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
24259 * @cfg {Bool} showClear
24260 * Show a clear button (usefull for date form elements that can be blank.)
24266 * Sets the value of the date field
24267 * @param {Date} value The date to set
24269 setValue : function(value){
24270 var old = this.value;
24271 this.value = value.clearTime(true);
24273 this.update(this.value);
24278 * Gets the current selected value of the date field
24279 * @return {Date} The selected date
24281 getValue : function(){
24286 focus : function(){
24288 this.update(this.activeDate);
24293 onRender : function(container, position){
24295 '<table cellspacing="0">',
24296 '<tr><td class="x-date-left"><a href="#" title="', this.prevText ,'"> </a></td><td class="x-date-middle" align="center"></td><td class="x-date-right"><a href="#" title="', this.nextText ,'"> </a></td></tr>',
24297 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
24298 var dn = this.dayNames;
24299 for(var i = 0; i < 7; i++){
24300 var d = this.startDay+i;
24304 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
24306 m[m.length] = "</tr></thead><tbody><tr>";
24307 for(var i = 0; i < 42; i++) {
24308 if(i % 7 == 0 && i != 0){
24309 m[m.length] = "</tr><tr>";
24311 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
24313 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
24314 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
24316 var el = document.createElement("div");
24317 el.className = "x-date-picker";
24318 el.innerHTML = m.join("");
24320 container.dom.insertBefore(el, position);
24322 this.el = Roo.get(el);
24323 this.eventEl = Roo.get(el.firstChild);
24325 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
24326 handler: this.showPrevMonth,
24328 preventDefault:true,
24332 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
24333 handler: this.showNextMonth,
24335 preventDefault:true,
24339 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
24341 this.monthPicker = this.el.down('div.x-date-mp');
24342 this.monthPicker.enableDisplayMode('block');
24344 var kn = new Roo.KeyNav(this.eventEl, {
24345 "left" : function(e){
24347 this.showPrevMonth() :
24348 this.update(this.activeDate.add("d", -1));
24351 "right" : function(e){
24353 this.showNextMonth() :
24354 this.update(this.activeDate.add("d", 1));
24357 "up" : function(e){
24359 this.showNextYear() :
24360 this.update(this.activeDate.add("d", -7));
24363 "down" : function(e){
24365 this.showPrevYear() :
24366 this.update(this.activeDate.add("d", 7));
24369 "pageUp" : function(e){
24370 this.showNextMonth();
24373 "pageDown" : function(e){
24374 this.showPrevMonth();
24377 "enter" : function(e){
24378 e.stopPropagation();
24385 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
24387 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
24389 this.el.unselectable();
24391 this.cells = this.el.select("table.x-date-inner tbody td");
24392 this.textNodes = this.el.query("table.x-date-inner tbody span");
24394 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
24396 tooltip: this.monthYearText
24399 this.mbtn.on('click', this.showMonthPicker, this);
24400 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
24403 var today = (new Date()).dateFormat(this.format);
24405 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
24407 text: String.format(this.todayText, today),
24408 tooltip: String.format(this.todayTip, today),
24409 handler: this.selectToday,
24413 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
24416 if (this.showClear) {
24418 baseTb.add( new Roo.Toolbar.Fill());
24421 cls: 'x-btn-icon x-btn-clear',
24422 handler: function() {
24424 this.fireEvent("select", this, '');
24434 this.update(this.value);
24437 createMonthPicker : function(){
24438 if(!this.monthPicker.dom.firstChild){
24439 var buf = ['<table border="0" cellspacing="0">'];
24440 for(var i = 0; i < 6; i++){
24442 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
24443 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
24445 '<td class="x-date-mp-ybtn" align="center"><a class="x-date-mp-prev"></a></td><td class="x-date-mp-ybtn" align="center"><a class="x-date-mp-next"></a></td></tr>' :
24446 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
24450 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
24452 '</button><button type="button" class="x-date-mp-cancel">',
24454 '</button></td></tr>',
24457 this.monthPicker.update(buf.join(''));
24458 this.monthPicker.on('click', this.onMonthClick, this);
24459 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
24461 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
24462 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
24464 this.mpMonths.each(function(m, a, i){
24467 m.dom.xmonth = 5 + Math.round(i * .5);
24469 m.dom.xmonth = Math.round((i-1) * .5);
24475 showMonthPicker : function(){
24476 this.createMonthPicker();
24477 var size = this.el.getSize();
24478 this.monthPicker.setSize(size);
24479 this.monthPicker.child('table').setSize(size);
24481 this.mpSelMonth = (this.activeDate || this.value).getMonth();
24482 this.updateMPMonth(this.mpSelMonth);
24483 this.mpSelYear = (this.activeDate || this.value).getFullYear();
24484 this.updateMPYear(this.mpSelYear);
24486 this.monthPicker.slideIn('t', {duration:.2});
24489 updateMPYear : function(y){
24491 var ys = this.mpYears.elements;
24492 for(var i = 1; i <= 10; i++){
24493 var td = ys[i-1], y2;
24495 y2 = y + Math.round(i * .5);
24496 td.firstChild.innerHTML = y2;
24499 y2 = y - (5-Math.round(i * .5));
24500 td.firstChild.innerHTML = y2;
24503 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
24507 updateMPMonth : function(sm){
24508 this.mpMonths.each(function(m, a, i){
24509 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
24513 selectMPMonth: function(m){
24517 onMonthClick : function(e, t){
24519 var el = new Roo.Element(t), pn;
24520 if(el.is('button.x-date-mp-cancel')){
24521 this.hideMonthPicker();
24523 else if(el.is('button.x-date-mp-ok')){
24524 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
24525 this.hideMonthPicker();
24527 else if(pn = el.up('td.x-date-mp-month', 2)){
24528 this.mpMonths.removeClass('x-date-mp-sel');
24529 pn.addClass('x-date-mp-sel');
24530 this.mpSelMonth = pn.dom.xmonth;
24532 else if(pn = el.up('td.x-date-mp-year', 2)){
24533 this.mpYears.removeClass('x-date-mp-sel');
24534 pn.addClass('x-date-mp-sel');
24535 this.mpSelYear = pn.dom.xyear;
24537 else if(el.is('a.x-date-mp-prev')){
24538 this.updateMPYear(this.mpyear-10);
24540 else if(el.is('a.x-date-mp-next')){
24541 this.updateMPYear(this.mpyear+10);
24545 onMonthDblClick : function(e, t){
24547 var el = new Roo.Element(t), pn;
24548 if(pn = el.up('td.x-date-mp-month', 2)){
24549 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
24550 this.hideMonthPicker();
24552 else if(pn = el.up('td.x-date-mp-year', 2)){
24553 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
24554 this.hideMonthPicker();
24558 hideMonthPicker : function(disableAnim){
24559 if(this.monthPicker){
24560 if(disableAnim === true){
24561 this.monthPicker.hide();
24563 this.monthPicker.slideOut('t', {duration:.2});
24569 showPrevMonth : function(e){
24570 this.update(this.activeDate.add("mo", -1));
24574 showNextMonth : function(e){
24575 this.update(this.activeDate.add("mo", 1));
24579 showPrevYear : function(){
24580 this.update(this.activeDate.add("y", -1));
24584 showNextYear : function(){
24585 this.update(this.activeDate.add("y", 1));
24589 handleMouseWheel : function(e){
24590 var delta = e.getWheelDelta();
24592 this.showPrevMonth();
24594 } else if(delta < 0){
24595 this.showNextMonth();
24601 handleDateClick : function(e, t){
24603 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
24604 this.setValue(new Date(t.dateValue));
24605 this.fireEvent("select", this, this.value);
24610 selectToday : function(){
24611 this.setValue(new Date().clearTime());
24612 this.fireEvent("select", this, this.value);
24616 update : function(date){
24617 var vd = this.activeDate;
24618 this.activeDate = date;
24620 var t = date.getTime();
24621 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
24622 this.cells.removeClass("x-date-selected");
24623 this.cells.each(function(c){
24624 if(c.dom.firstChild.dateValue == t){
24625 c.addClass("x-date-selected");
24626 setTimeout(function(){
24627 try{c.dom.firstChild.focus();}catch(e){}
24635 var days = date.getDaysInMonth();
24636 var firstOfMonth = date.getFirstDateOfMonth();
24637 var startingPos = firstOfMonth.getDay()-this.startDay;
24639 if(startingPos <= this.startDay){
24643 var pm = date.add("mo", -1);
24644 var prevStart = pm.getDaysInMonth()-startingPos;
24646 var cells = this.cells.elements;
24647 var textEls = this.textNodes;
24648 days += startingPos;
24650 // convert everything to numbers so it's fast
24651 var day = 86400000;
24652 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
24653 var today = new Date().clearTime().getTime();
24654 var sel = date.clearTime().getTime();
24655 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
24656 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
24657 var ddMatch = this.disabledDatesRE;
24658 var ddText = this.disabledDatesText;
24659 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
24660 var ddaysText = this.disabledDaysText;
24661 var format = this.format;
24663 var setCellClass = function(cal, cell){
24665 var t = d.getTime();
24666 cell.firstChild.dateValue = t;
24668 cell.className += " x-date-today";
24669 cell.title = cal.todayText;
24672 cell.className += " x-date-selected";
24673 setTimeout(function(){
24674 try{cell.firstChild.focus();}catch(e){}
24679 cell.className = " x-date-disabled";
24680 cell.title = cal.minText;
24684 cell.className = " x-date-disabled";
24685 cell.title = cal.maxText;
24689 if(ddays.indexOf(d.getDay()) != -1){
24690 cell.title = ddaysText;
24691 cell.className = " x-date-disabled";
24694 if(ddMatch && format){
24695 var fvalue = d.dateFormat(format);
24696 if(ddMatch.test(fvalue)){
24697 cell.title = ddText.replace("%0", fvalue);
24698 cell.className = " x-date-disabled";
24704 for(; i < startingPos; i++) {
24705 textEls[i].innerHTML = (++prevStart);
24706 d.setDate(d.getDate()+1);
24707 cells[i].className = "x-date-prevday";
24708 setCellClass(this, cells[i]);
24710 for(; i < days; i++){
24711 intDay = i - startingPos + 1;
24712 textEls[i].innerHTML = (intDay);
24713 d.setDate(d.getDate()+1);
24714 cells[i].className = "x-date-active";
24715 setCellClass(this, cells[i]);
24718 for(; i < 42; i++) {
24719 textEls[i].innerHTML = (++extraDays);
24720 d.setDate(d.getDate()+1);
24721 cells[i].className = "x-date-nextday";
24722 setCellClass(this, cells[i]);
24725 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
24727 if(!this.internalRender){
24728 var main = this.el.dom.firstChild;
24729 var w = main.offsetWidth;
24730 this.el.setWidth(w + this.el.getBorderWidth("lr"));
24731 Roo.fly(main).setWidth(w);
24732 this.internalRender = true;
24733 // opera does not respect the auto grow header center column
24734 // then, after it gets a width opera refuses to recalculate
24735 // without a second pass
24736 if(Roo.isOpera && !this.secondPass){
24737 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
24738 this.secondPass = true;
24739 this.update.defer(10, this, [date]);
24745 * Ext JS Library 1.1.1
24746 * Copyright(c) 2006-2007, Ext JS, LLC.
24748 * Originally Released Under LGPL - original licence link has changed is not relivant.
24751 * <script type="text/javascript">
24754 * @class Roo.TabPanel
24755 * @extends Roo.util.Observable
24756 * A lightweight tab container.
24760 // basic tabs 1, built from existing content
24761 var tabs = new Roo.TabPanel("tabs1");
24762 tabs.addTab("script", "View Script");
24763 tabs.addTab("markup", "View Markup");
24764 tabs.activate("script");
24766 // more advanced tabs, built from javascript
24767 var jtabs = new Roo.TabPanel("jtabs");
24768 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
24770 // set up the UpdateManager
24771 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
24772 var updater = tab2.getUpdateManager();
24773 updater.setDefaultUrl("ajax1.htm");
24774 tab2.on('activate', updater.refresh, updater, true);
24776 // Use setUrl for Ajax loading
24777 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
24778 tab3.setUrl("ajax2.htm", null, true);
24781 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
24784 jtabs.activate("jtabs-1");
24787 * Create a new TabPanel.
24788 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
24789 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
24791 Roo.TabPanel = function(container, config){
24793 * The container element for this TabPanel.
24794 * @type Roo.Element
24796 this.el = Roo.get(container, true);
24798 if(typeof config == "boolean"){
24799 this.tabPosition = config ? "bottom" : "top";
24801 Roo.apply(this, config);
24804 if(this.tabPosition == "bottom"){
24805 this.bodyEl = Roo.get(this.createBody(this.el.dom));
24806 this.el.addClass("x-tabs-bottom");
24808 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
24809 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
24810 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
24812 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
24814 if(this.tabPosition != "bottom"){
24815 /** The body element that contains {@link Roo.TabPanelItem} bodies.
24816 * @type Roo.Element
24818 this.bodyEl = Roo.get(this.createBody(this.el.dom));
24819 this.el.addClass("x-tabs-top");
24823 this.bodyEl.setStyle("position", "relative");
24825 this.active = null;
24826 this.activateDelegate = this.activate.createDelegate(this);
24831 * Fires when the active tab changes
24832 * @param {Roo.TabPanel} this
24833 * @param {Roo.TabPanelItem} activePanel The new active tab
24837 * @event beforetabchange
24838 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
24839 * @param {Roo.TabPanel} this
24840 * @param {Object} e Set cancel to true on this object to cancel the tab change
24841 * @param {Roo.TabPanelItem} tab The tab being changed to
24843 "beforetabchange" : true
24846 Roo.EventManager.onWindowResize(this.onResize, this);
24847 this.cpad = this.el.getPadding("lr");
24848 this.hiddenCount = 0;
24850 Roo.TabPanel.superclass.constructor.call(this);
24853 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
24855 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
24857 tabPosition : "top",
24859 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
24861 currentTabWidth : 0,
24863 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
24867 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
24871 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
24873 preferredTabWidth : 175,
24875 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
24877 resizeTabs : false,
24879 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
24881 monitorResize : true,
24884 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
24885 * @param {String} id The id of the div to use <b>or create</b>
24886 * @param {String} text The text for the tab
24887 * @param {String} content (optional) Content to put in the TabPanelItem body
24888 * @param {Boolean} closable (optional) True to create a close icon on the tab
24889 * @return {Roo.TabPanelItem} The created TabPanelItem
24891 addTab : function(id, text, content, closable){
24892 var item = new Roo.TabPanelItem(this, id, text, closable);
24893 this.addTabItem(item);
24895 item.setContent(content);
24901 * Returns the {@link Roo.TabPanelItem} with the specified id/index
24902 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
24903 * @return {Roo.TabPanelItem}
24905 getTab : function(id){
24906 return this.items[id];
24910 * Hides the {@link Roo.TabPanelItem} with the specified id/index
24911 * @param {String/Number} id The id or index of the TabPanelItem to hide.
24913 hideTab : function(id){
24914 var t = this.items[id];
24917 this.hiddenCount++;
24918 this.autoSizeTabs();
24923 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
24924 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
24926 unhideTab : function(id){
24927 var t = this.items[id];
24929 t.setHidden(false);
24930 this.hiddenCount--;
24931 this.autoSizeTabs();
24936 * Adds an existing {@link Roo.TabPanelItem}.
24937 * @param {Roo.TabPanelItem} item The TabPanelItem to add
24939 addTabItem : function(item){
24940 this.items[item.id] = item;
24941 this.items.push(item);
24942 if(this.resizeTabs){
24943 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
24944 this.autoSizeTabs();
24951 * Removes a {@link Roo.TabPanelItem}.
24952 * @param {String/Number} id The id or index of the TabPanelItem to remove.
24954 removeTab : function(id){
24955 var items = this.items;
24956 var tab = items[id];
24958 var index = items.indexOf(tab);
24959 if(this.active == tab && items.length > 1){
24960 var newTab = this.getNextAvailable(index);
24961 if(newTab)newTab.activate();
24963 this.stripEl.dom.removeChild(tab.pnode.dom);
24964 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
24965 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
24967 items.splice(index, 1);
24968 delete this.items[tab.id];
24969 tab.fireEvent("close", tab);
24970 tab.purgeListeners();
24971 this.autoSizeTabs();
24974 getNextAvailable : function(start){
24975 var items = this.items;
24977 // look for a next tab that will slide over to
24978 // replace the one being removed
24979 while(index < items.length){
24980 var item = items[++index];
24981 if(item && !item.isHidden()){
24985 // if one isn't found select the previous tab (on the left)
24988 var item = items[--index];
24989 if(item && !item.isHidden()){
24997 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
24998 * @param {String/Number} id The id or index of the TabPanelItem to disable.
25000 disableTab : function(id){
25001 var tab = this.items[id];
25002 if(tab && this.active != tab){
25008 * Enables a {@link Roo.TabPanelItem} that is disabled.
25009 * @param {String/Number} id The id or index of the TabPanelItem to enable.
25011 enableTab : function(id){
25012 var tab = this.items[id];
25017 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
25018 * @param {String/Number} id The id or index of the TabPanelItem to activate.
25019 * @return {Roo.TabPanelItem} The TabPanelItem.
25021 activate : function(id){
25022 var tab = this.items[id];
25026 if(tab == this.active || tab.disabled){
25030 this.fireEvent("beforetabchange", this, e, tab);
25031 if(e.cancel !== true && !tab.disabled){
25033 this.active.hide();
25035 this.active = this.items[id];
25036 this.active.show();
25037 this.fireEvent("tabchange", this, this.active);
25043 * Gets the active {@link Roo.TabPanelItem}.
25044 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
25046 getActiveTab : function(){
25047 return this.active;
25051 * Updates the tab body element to fit the height of the container element
25052 * for overflow scrolling
25053 * @param {Number} targetHeight (optional) Override the starting height from the elements height
25055 syncHeight : function(targetHeight){
25056 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
25057 var bm = this.bodyEl.getMargins();
25058 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
25059 this.bodyEl.setHeight(newHeight);
25063 onResize : function(){
25064 if(this.monitorResize){
25065 this.autoSizeTabs();
25070 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
25072 beginUpdate : function(){
25073 this.updating = true;
25077 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
25079 endUpdate : function(){
25080 this.updating = false;
25081 this.autoSizeTabs();
25085 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
25087 autoSizeTabs : function(){
25088 var count = this.items.length;
25089 var vcount = count - this.hiddenCount;
25090 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
25091 var w = Math.max(this.el.getWidth() - this.cpad, 10);
25092 var availWidth = Math.floor(w / vcount);
25093 var b = this.stripBody;
25094 if(b.getWidth() > w){
25095 var tabs = this.items;
25096 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
25097 if(availWidth < this.minTabWidth){
25098 /*if(!this.sleft){ // incomplete scrolling code
25099 this.createScrollButtons();
25102 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
25105 if(this.currentTabWidth < this.preferredTabWidth){
25106 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
25112 * Returns the number of tabs in this TabPanel.
25115 getCount : function(){
25116 return this.items.length;
25120 * Resizes all the tabs to the passed width
25121 * @param {Number} The new width
25123 setTabWidth : function(width){
25124 this.currentTabWidth = width;
25125 for(var i = 0, len = this.items.length; i < len; i++) {
25126 if(!this.items[i].isHidden())this.items[i].setWidth(width);
25131 * Destroys this TabPanel
25132 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
25134 destroy : function(removeEl){
25135 Roo.EventManager.removeResizeListener(this.onResize, this);
25136 for(var i = 0, len = this.items.length; i < len; i++){
25137 this.items[i].purgeListeners();
25139 if(removeEl === true){
25140 this.el.update("");
25147 * @class Roo.TabPanelItem
25148 * @extends Roo.util.Observable
25149 * Represents an individual item (tab plus body) in a TabPanel.
25150 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
25151 * @param {String} id The id of this TabPanelItem
25152 * @param {String} text The text for the tab of this TabPanelItem
25153 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
25155 Roo.TabPanelItem = function(tabPanel, id, text, closable){
25157 * The {@link Roo.TabPanel} this TabPanelItem belongs to
25158 * @type Roo.TabPanel
25160 this.tabPanel = tabPanel;
25162 * The id for this TabPanelItem
25167 this.disabled = false;
25171 this.loaded = false;
25172 this.closable = closable;
25175 * The body element for this TabPanelItem.
25176 * @type Roo.Element
25178 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
25179 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
25180 this.bodyEl.setStyle("display", "block");
25181 this.bodyEl.setStyle("zoom", "1");
25184 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
25186 this.el = Roo.get(els.el, true);
25187 this.inner = Roo.get(els.inner, true);
25188 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
25189 this.pnode = Roo.get(els.el.parentNode, true);
25190 this.el.on("mousedown", this.onTabMouseDown, this);
25191 this.el.on("click", this.onTabClick, this);
25194 var c = Roo.get(els.close, true);
25195 c.dom.title = this.closeText;
25196 c.addClassOnOver("close-over");
25197 c.on("click", this.closeClick, this);
25203 * Fires when this tab becomes the active tab.
25204 * @param {Roo.TabPanel} tabPanel The parent TabPanel
25205 * @param {Roo.TabPanelItem} this
25209 * @event beforeclose
25210 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
25211 * @param {Roo.TabPanelItem} this
25212 * @param {Object} e Set cancel to true on this object to cancel the close.
25214 "beforeclose": true,
25217 * Fires when this tab is closed.
25218 * @param {Roo.TabPanelItem} this
25222 * @event deactivate
25223 * Fires when this tab is no longer the active tab.
25224 * @param {Roo.TabPanel} tabPanel The parent TabPanel
25225 * @param {Roo.TabPanelItem} this
25227 "deactivate" : true
25229 this.hidden = false;
25231 Roo.TabPanelItem.superclass.constructor.call(this);
25234 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
25235 purgeListeners : function(){
25236 Roo.util.Observable.prototype.purgeListeners.call(this);
25237 this.el.removeAllListeners();
25240 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
25243 this.pnode.addClass("on");
25246 this.tabPanel.stripWrap.repaint();
25248 this.fireEvent("activate", this.tabPanel, this);
25252 * Returns true if this tab is the active tab.
25253 * @return {Boolean}
25255 isActive : function(){
25256 return this.tabPanel.getActiveTab() == this;
25260 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
25263 this.pnode.removeClass("on");
25265 this.fireEvent("deactivate", this.tabPanel, this);
25268 hideAction : function(){
25269 this.bodyEl.hide();
25270 this.bodyEl.setStyle("position", "absolute");
25271 this.bodyEl.setLeft("-20000px");
25272 this.bodyEl.setTop("-20000px");
25275 showAction : function(){
25276 this.bodyEl.setStyle("position", "relative");
25277 this.bodyEl.setTop("");
25278 this.bodyEl.setLeft("");
25279 this.bodyEl.show();
25283 * Set the tooltip for the tab.
25284 * @param {String} tooltip The tab's tooltip
25286 setTooltip : function(text){
25287 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
25288 this.textEl.dom.qtip = text;
25289 this.textEl.dom.removeAttribute('title');
25291 this.textEl.dom.title = text;
25295 onTabClick : function(e){
25296 e.preventDefault();
25297 this.tabPanel.activate(this.id);
25300 onTabMouseDown : function(e){
25301 e.preventDefault();
25302 this.tabPanel.activate(this.id);
25305 getWidth : function(){
25306 return this.inner.getWidth();
25309 setWidth : function(width){
25310 var iwidth = width - this.pnode.getPadding("lr");
25311 this.inner.setWidth(iwidth);
25312 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
25313 this.pnode.setWidth(width);
25317 * Show or hide the tab
25318 * @param {Boolean} hidden True to hide or false to show.
25320 setHidden : function(hidden){
25321 this.hidden = hidden;
25322 this.pnode.setStyle("display", hidden ? "none" : "");
25326 * Returns true if this tab is "hidden"
25327 * @return {Boolean}
25329 isHidden : function(){
25330 return this.hidden;
25334 * Returns the text for this tab
25337 getText : function(){
25341 autoSize : function(){
25342 //this.el.beginMeasure();
25343 this.textEl.setWidth(1);
25344 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
25345 //this.el.endMeasure();
25349 * Sets the text for the tab (Note: this also sets the tooltip text)
25350 * @param {String} text The tab's text and tooltip
25352 setText : function(text){
25354 this.textEl.update(text);
25355 this.setTooltip(text);
25356 if(!this.tabPanel.resizeTabs){
25361 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
25363 activate : function(){
25364 this.tabPanel.activate(this.id);
25368 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
25370 disable : function(){
25371 if(this.tabPanel.active != this){
25372 this.disabled = true;
25373 this.pnode.addClass("disabled");
25378 * Enables this TabPanelItem if it was previously disabled.
25380 enable : function(){
25381 this.disabled = false;
25382 this.pnode.removeClass("disabled");
25386 * Sets the content for this TabPanelItem.
25387 * @param {String} content The content
25388 * @param {Boolean} loadScripts true to look for and load scripts
25390 setContent : function(content, loadScripts){
25391 this.bodyEl.update(content, loadScripts);
25395 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
25396 * @return {Roo.UpdateManager} The UpdateManager
25398 getUpdateManager : function(){
25399 return this.bodyEl.getUpdateManager();
25403 * Set a URL to be used to load the content for this TabPanelItem.
25404 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
25405 * @param {String/Object} params (optional) The string params for the update call or an object of the params. See {@link Roo.UpdateManager#update} for more details. (Defaults to null)
25406 * @param {Boolean} loadOnce (optional) Whether to only load the content once. If this is false it makes the Ajax call every time this TabPanelItem is activated. (Defaults to false)
25407 * @return {Roo.UpdateManager} The UpdateManager
25409 setUrl : function(url, params, loadOnce){
25410 if(this.refreshDelegate){
25411 this.un('activate', this.refreshDelegate);
25413 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
25414 this.on("activate", this.refreshDelegate);
25415 return this.bodyEl.getUpdateManager();
25419 _handleRefresh : function(url, params, loadOnce){
25420 if(!loadOnce || !this.loaded){
25421 var updater = this.bodyEl.getUpdateManager();
25422 updater.update(url, params, this._setLoaded.createDelegate(this));
25427 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
25428 * Will fail silently if the setUrl method has not been called.
25429 * This does not activate the panel, just updates its content.
25431 refresh : function(){
25432 if(this.refreshDelegate){
25433 this.loaded = false;
25434 this.refreshDelegate();
25439 _setLoaded : function(){
25440 this.loaded = true;
25444 closeClick : function(e){
25447 this.fireEvent("beforeclose", this, o);
25448 if(o.cancel !== true){
25449 this.tabPanel.removeTab(this.id);
25453 * The text displayed in the tooltip for the close icon.
25456 closeText : "Close this tab"
25460 Roo.TabPanel.prototype.createStrip = function(container){
25461 var strip = document.createElement("div");
25462 strip.className = "x-tabs-wrap";
25463 container.appendChild(strip);
25467 Roo.TabPanel.prototype.createStripList = function(strip){
25468 // div wrapper for retard IE
25469 strip.innerHTML = '<div class="x-tabs-strip-wrap"><table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr></tr></tbody></table></div>';
25470 return strip.firstChild.firstChild.firstChild.firstChild;
25473 Roo.TabPanel.prototype.createBody = function(container){
25474 var body = document.createElement("div");
25475 Roo.id(body, "tab-body");
25476 Roo.fly(body).addClass("x-tabs-body");
25477 container.appendChild(body);
25481 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
25482 var body = Roo.getDom(id);
25484 body = document.createElement("div");
25487 Roo.fly(body).addClass("x-tabs-item-body");
25488 bodyEl.insertBefore(body, bodyEl.firstChild);
25492 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
25493 var td = document.createElement("td");
25494 stripEl.appendChild(td);
25496 td.className = "x-tabs-closable";
25497 if(!this.closeTpl){
25498 this.closeTpl = new Roo.Template(
25499 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
25500 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
25501 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
25504 var el = this.closeTpl.overwrite(td, {"text": text});
25505 var close = el.getElementsByTagName("div")[0];
25506 var inner = el.getElementsByTagName("em")[0];
25507 return {"el": el, "close": close, "inner": inner};
25510 this.tabTpl = new Roo.Template(
25511 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
25512 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
25515 var el = this.tabTpl.overwrite(td, {"text": text});
25516 var inner = el.getElementsByTagName("em")[0];
25517 return {"el": el, "inner": inner};
25521 * Ext JS Library 1.1.1
25522 * Copyright(c) 2006-2007, Ext JS, LLC.
25524 * Originally Released Under LGPL - original licence link has changed is not relivant.
25527 * <script type="text/javascript">
25531 * @class Roo.Button
25532 * @extends Roo.util.Observable
25533 * Simple Button class
25534 * @cfg {String} text The button text
25535 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
25536 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
25537 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
25538 * @cfg {Object} scope The scope of the handler
25539 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
25540 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
25541 * @cfg {Boolean} hidden True to start hidden (defaults to false)
25542 * @cfg {Boolean} disabled True to start disabled (defaults to false)
25543 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
25544 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
25545 applies if enableToggle = true)
25546 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
25547 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
25548 an {@link Roo.util.ClickRepeater} config object (defaults to false).
25550 * Create a new button
25551 * @param {Object} config The config object
25553 Roo.Button = function(renderTo, config)
25557 renderTo = config.renderTo || false;
25560 Roo.apply(this, config);
25564 * Fires when this button is clicked
25565 * @param {Button} this
25566 * @param {EventObject} e The click event
25571 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
25572 * @param {Button} this
25573 * @param {Boolean} pressed
25578 * Fires when the mouse hovers over the button
25579 * @param {Button} this
25580 * @param {Event} e The event object
25582 'mouseover' : true,
25585 * Fires when the mouse exits the button
25586 * @param {Button} this
25587 * @param {Event} e The event object
25592 * Fires when the button is rendered
25593 * @param {Button} this
25598 this.menu = Roo.menu.MenuMgr.get(this.menu);
25601 this.render(renderTo);
25604 Roo.util.Observable.call(this);
25607 Roo.extend(Roo.Button, Roo.util.Observable, {
25613 * Read-only. True if this button is hidden
25618 * Read-only. True if this button is disabled
25623 * Read-only. True if this button is pressed (only if enableToggle = true)
25629 * @cfg {Number} tabIndex
25630 * The DOM tabIndex for this button (defaults to undefined)
25632 tabIndex : undefined,
25635 * @cfg {Boolean} enableToggle
25636 * True to enable pressed/not pressed toggling (defaults to false)
25638 enableToggle: false,
25640 * @cfg {Mixed} menu
25641 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
25645 * @cfg {String} menuAlign
25646 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
25648 menuAlign : "tl-bl?",
25651 * @cfg {String} iconCls
25652 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
25654 iconCls : undefined,
25656 * @cfg {String} type
25657 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
25662 menuClassTarget: 'tr',
25665 * @cfg {String} clickEvent
25666 * The type of event to map to the button's event handler (defaults to 'click')
25668 clickEvent : 'click',
25671 * @cfg {Boolean} handleMouseEvents
25672 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
25674 handleMouseEvents : true,
25677 * @cfg {String} tooltipType
25678 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
25680 tooltipType : 'qtip',
25683 * @cfg {String} cls
25684 * A CSS class to apply to the button's main element.
25688 * @cfg {Roo.Template} template (Optional)
25689 * An {@link Roo.Template} with which to create the Button's main element. This Template must
25690 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
25691 * require code modifications if required elements (e.g. a button) aren't present.
25695 render : function(renderTo){
25697 if(this.hideParent){
25698 this.parentEl = Roo.get(renderTo);
25700 if(!this.dhconfig){
25701 if(!this.template){
25702 if(!Roo.Button.buttonTemplate){
25703 // hideous table template
25704 Roo.Button.buttonTemplate = new Roo.Template(
25705 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
25706 '<td class="x-btn-left"><i> </i></td><td class="x-btn-center"><em unselectable="on"><button class="x-btn-text" type="{1}">{0}</button></em></td><td class="x-btn-right"><i> </i></td>',
25707 "</tr></tbody></table>");
25709 this.template = Roo.Button.buttonTemplate;
25711 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
25712 var btnEl = btn.child("button:first");
25713 btnEl.on('focus', this.onFocus, this);
25714 btnEl.on('blur', this.onBlur, this);
25716 btn.addClass(this.cls);
25719 btnEl.setStyle('background-image', 'url(' +this.icon +')');
25722 btnEl.addClass(this.iconCls);
25724 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
25727 if(this.tabIndex !== undefined){
25728 btnEl.dom.tabIndex = this.tabIndex;
25731 if(typeof this.tooltip == 'object'){
25732 Roo.QuickTips.tips(Roo.apply({
25736 btnEl.dom[this.tooltipType] = this.tooltip;
25740 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
25744 this.el.dom.id = this.el.id = this.id;
25747 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
25748 this.menu.on("show", this.onMenuShow, this);
25749 this.menu.on("hide", this.onMenuHide, this);
25751 btn.addClass("x-btn");
25752 if(Roo.isIE && !Roo.isIE7){
25753 this.autoWidth.defer(1, this);
25757 if(this.handleMouseEvents){
25758 btn.on("mouseover", this.onMouseOver, this);
25759 btn.on("mouseout", this.onMouseOut, this);
25760 btn.on("mousedown", this.onMouseDown, this);
25762 btn.on(this.clickEvent, this.onClick, this);
25763 //btn.on("mouseup", this.onMouseUp, this);
25770 Roo.ButtonToggleMgr.register(this);
25772 this.el.addClass("x-btn-pressed");
25775 var repeater = new Roo.util.ClickRepeater(btn,
25776 typeof this.repeat == "object" ? this.repeat : {}
25778 repeater.on("click", this.onClick, this);
25780 this.fireEvent('render', this);
25784 * Returns the button's underlying element
25785 * @return {Roo.Element} The element
25787 getEl : function(){
25792 * Destroys this Button and removes any listeners.
25794 destroy : function(){
25795 Roo.ButtonToggleMgr.unregister(this);
25796 this.el.removeAllListeners();
25797 this.purgeListeners();
25802 autoWidth : function(){
25804 this.el.setWidth("auto");
25805 if(Roo.isIE7 && Roo.isStrict){
25806 var ib = this.el.child('button');
25807 if(ib && ib.getWidth() > 20){
25809 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
25814 this.el.beginMeasure();
25816 if(this.el.getWidth() < this.minWidth){
25817 this.el.setWidth(this.minWidth);
25820 this.el.endMeasure();
25827 * Assigns this button's click handler
25828 * @param {Function} handler The function to call when the button is clicked
25829 * @param {Object} scope (optional) Scope for the function passed in
25831 setHandler : function(handler, scope){
25832 this.handler = handler;
25833 this.scope = scope;
25837 * Sets this button's text
25838 * @param {String} text The button text
25840 setText : function(text){
25843 this.el.child("td.x-btn-center button.x-btn-text").update(text);
25849 * Gets the text for this button
25850 * @return {String} The button text
25852 getText : function(){
25860 this.hidden = false;
25862 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
25870 this.hidden = true;
25872 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
25877 * Convenience function for boolean show/hide
25878 * @param {Boolean} visible True to show, false to hide
25880 setVisible: function(visible){
25889 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
25890 * @param {Boolean} state (optional) Force a particular state
25892 toggle : function(state){
25893 state = state === undefined ? !this.pressed : state;
25894 if(state != this.pressed){
25896 this.el.addClass("x-btn-pressed");
25897 this.pressed = true;
25898 this.fireEvent("toggle", this, true);
25900 this.el.removeClass("x-btn-pressed");
25901 this.pressed = false;
25902 this.fireEvent("toggle", this, false);
25904 if(this.toggleHandler){
25905 this.toggleHandler.call(this.scope || this, this, state);
25913 focus : function(){
25914 this.el.child('button:first').focus();
25918 * Disable this button
25920 disable : function(){
25922 this.el.addClass("x-btn-disabled");
25924 this.disabled = true;
25928 * Enable this button
25930 enable : function(){
25932 this.el.removeClass("x-btn-disabled");
25934 this.disabled = false;
25938 * Convenience function for boolean enable/disable
25939 * @param {Boolean} enabled True to enable, false to disable
25941 setDisabled : function(v){
25942 this[v !== true ? "enable" : "disable"]();
25946 onClick : function(e){
25948 e.preventDefault();
25953 if(!this.disabled){
25954 if(this.enableToggle){
25957 if(this.menu && !this.menu.isVisible()){
25958 this.menu.show(this.el, this.menuAlign);
25960 this.fireEvent("click", this, e);
25962 this.el.removeClass("x-btn-over");
25963 this.handler.call(this.scope || this, this, e);
25968 onMouseOver : function(e){
25969 if(!this.disabled){
25970 this.el.addClass("x-btn-over");
25971 this.fireEvent('mouseover', this, e);
25975 onMouseOut : function(e){
25976 if(!e.within(this.el, true)){
25977 this.el.removeClass("x-btn-over");
25978 this.fireEvent('mouseout', this, e);
25982 onFocus : function(e){
25983 if(!this.disabled){
25984 this.el.addClass("x-btn-focus");
25988 onBlur : function(e){
25989 this.el.removeClass("x-btn-focus");
25992 onMouseDown : function(e){
25993 if(!this.disabled && e.button == 0){
25994 this.el.addClass("x-btn-click");
25995 Roo.get(document).on('mouseup', this.onMouseUp, this);
25999 onMouseUp : function(e){
26001 this.el.removeClass("x-btn-click");
26002 Roo.get(document).un('mouseup', this.onMouseUp, this);
26006 onMenuShow : function(e){
26007 this.el.addClass("x-btn-menu-active");
26010 onMenuHide : function(e){
26011 this.el.removeClass("x-btn-menu-active");
26015 // Private utility class used by Button
26016 Roo.ButtonToggleMgr = function(){
26019 function toggleGroup(btn, state){
26021 var g = groups[btn.toggleGroup];
26022 for(var i = 0, l = g.length; i < l; i++){
26024 g[i].toggle(false);
26031 register : function(btn){
26032 if(!btn.toggleGroup){
26035 var g = groups[btn.toggleGroup];
26037 g = groups[btn.toggleGroup] = [];
26040 btn.on("toggle", toggleGroup);
26043 unregister : function(btn){
26044 if(!btn.toggleGroup){
26047 var g = groups[btn.toggleGroup];
26050 btn.un("toggle", toggleGroup);
26056 * Ext JS Library 1.1.1
26057 * Copyright(c) 2006-2007, Ext JS, LLC.
26059 * Originally Released Under LGPL - original licence link has changed is not relivant.
26062 * <script type="text/javascript">
26066 * @class Roo.SplitButton
26067 * @extends Roo.Button
26068 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
26069 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
26070 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
26071 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
26072 * @cfg {String} arrowTooltip The title attribute of the arrow
26074 * Create a new menu button
26075 * @param {String/HTMLElement/Element} renderTo The element to append the button to
26076 * @param {Object} config The config object
26078 Roo.SplitButton = function(renderTo, config){
26079 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
26081 * @event arrowclick
26082 * Fires when this button's arrow is clicked
26083 * @param {SplitButton} this
26084 * @param {EventObject} e The click event
26086 this.addEvents({"arrowclick":true});
26089 Roo.extend(Roo.SplitButton, Roo.Button, {
26090 render : function(renderTo){
26091 // this is one sweet looking template!
26092 var tpl = new Roo.Template(
26093 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
26094 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
26095 '<tr><td class="x-btn-left"><i> </i></td><td class="x-btn-center"><button class="x-btn-text" type="{1}">{0}</button></td></tr>',
26096 "</tbody></table></td><td>",
26097 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
26098 '<tr><td class="x-btn-center"><button class="x-btn-menu-arrow-el" type="button"> </button></td><td class="x-btn-right"><i> </i></td></tr>',
26099 "</tbody></table></td></tr></table>"
26101 var btn = tpl.append(renderTo, [this.text, this.type], true);
26102 var btnEl = btn.child("button");
26104 btn.addClass(this.cls);
26107 btnEl.setStyle('background-image', 'url(' +this.icon +')');
26110 btnEl.addClass(this.iconCls);
26112 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
26116 if(this.handleMouseEvents){
26117 btn.on("mouseover", this.onMouseOver, this);
26118 btn.on("mouseout", this.onMouseOut, this);
26119 btn.on("mousedown", this.onMouseDown, this);
26120 btn.on("mouseup", this.onMouseUp, this);
26122 btn.on(this.clickEvent, this.onClick, this);
26124 if(typeof this.tooltip == 'object'){
26125 Roo.QuickTips.tips(Roo.apply({
26129 btnEl.dom[this.tooltipType] = this.tooltip;
26132 if(this.arrowTooltip){
26133 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
26142 this.el.addClass("x-btn-pressed");
26144 if(Roo.isIE && !Roo.isIE7){
26145 this.autoWidth.defer(1, this);
26150 this.menu.on("show", this.onMenuShow, this);
26151 this.menu.on("hide", this.onMenuHide, this);
26153 this.fireEvent('render', this);
26157 autoWidth : function(){
26159 var tbl = this.el.child("table:first");
26160 var tbl2 = this.el.child("table:last");
26161 this.el.setWidth("auto");
26162 tbl.setWidth("auto");
26163 if(Roo.isIE7 && Roo.isStrict){
26164 var ib = this.el.child('button:first');
26165 if(ib && ib.getWidth() > 20){
26167 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
26172 this.el.beginMeasure();
26174 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
26175 tbl.setWidth(this.minWidth-tbl2.getWidth());
26178 this.el.endMeasure();
26181 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
26185 * Sets this button's click handler
26186 * @param {Function} handler The function to call when the button is clicked
26187 * @param {Object} scope (optional) Scope for the function passed above
26189 setHandler : function(handler, scope){
26190 this.handler = handler;
26191 this.scope = scope;
26195 * Sets this button's arrow click handler
26196 * @param {Function} handler The function to call when the arrow is clicked
26197 * @param {Object} scope (optional) Scope for the function passed above
26199 setArrowHandler : function(handler, scope){
26200 this.arrowHandler = handler;
26201 this.scope = scope;
26207 focus : function(){
26209 this.el.child("button:first").focus();
26214 onClick : function(e){
26215 e.preventDefault();
26216 if(!this.disabled){
26217 if(e.getTarget(".x-btn-menu-arrow-wrap")){
26218 if(this.menu && !this.menu.isVisible()){
26219 this.menu.show(this.el, this.menuAlign);
26221 this.fireEvent("arrowclick", this, e);
26222 if(this.arrowHandler){
26223 this.arrowHandler.call(this.scope || this, this, e);
26226 this.fireEvent("click", this, e);
26228 this.handler.call(this.scope || this, this, e);
26234 onMouseDown : function(e){
26235 if(!this.disabled){
26236 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
26240 onMouseUp : function(e){
26241 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
26246 // backwards compat
26247 Roo.MenuButton = Roo.SplitButton;/*
26249 * Ext JS Library 1.1.1
26250 * Copyright(c) 2006-2007, Ext JS, LLC.
26252 * Originally Released Under LGPL - original licence link has changed is not relivant.
26255 * <script type="text/javascript">
26259 * @class Roo.Toolbar
26260 * Basic Toolbar class.
26262 * Creates a new Toolbar
26263 * @param {Object} config The config object
26265 Roo.Toolbar = function(container, buttons, config)
26267 /// old consturctor format still supported..
26268 if(container instanceof Array){ // omit the container for later rendering
26269 buttons = container;
26273 if (typeof(container) == 'object' && container.xtype) {
26274 config = container;
26275 container = config.container;
26276 buttons = config.buttons; // not really - use items!!
26279 if (config && config.items) {
26280 xitems = config.items;
26281 delete config.items;
26283 Roo.apply(this, config);
26284 this.buttons = buttons;
26287 this.render(container);
26289 Roo.each(xitems, function(b) {
26295 Roo.Toolbar.prototype = {
26297 * @cfg {Roo.data.Store} items
26298 * array of button configs or elements to add
26302 * @cfg {String/HTMLElement/Element} container
26303 * The id or element that will contain the toolbar
26306 render : function(ct){
26307 this.el = Roo.get(ct);
26309 this.el.addClass(this.cls);
26311 // using a table allows for vertical alignment
26312 // 100% width is needed by Safari...
26313 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
26314 this.tr = this.el.child("tr", true);
26316 this.items = new Roo.util.MixedCollection(false, function(o){
26317 return o.id || ("item" + (++autoId));
26320 this.add.apply(this, this.buttons);
26321 delete this.buttons;
26326 * Adds element(s) to the toolbar -- this function takes a variable number of
26327 * arguments of mixed type and adds them to the toolbar.
26328 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
26330 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
26331 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
26332 * <li>Field: Any form field (equivalent to {@link #addField})</li>
26333 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
26334 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
26335 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
26336 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
26337 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
26338 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
26340 * @param {Mixed} arg2
26341 * @param {Mixed} etc.
26344 var a = arguments, l = a.length;
26345 for(var i = 0; i < l; i++){
26350 _add : function(el) {
26353 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
26356 if (el.applyTo){ // some kind of form field
26357 return this.addField(el);
26359 if (el.render){ // some kind of Toolbar.Item
26360 return this.addItem(el);
26362 if (typeof el == "string"){ // string
26363 if(el == "separator" || el == "-"){
26364 return this.addSeparator();
26367 return this.addSpacer();
26370 return this.addFill();
26372 return this.addText(el);
26375 if(el.tagName){ // element
26376 return this.addElement(el);
26378 if(typeof el == "object"){ // must be button config?
26379 return this.addButton(el);
26381 // and now what?!?!
26387 * Add an Xtype element
26388 * @param {Object} xtype Xtype Object
26389 * @return {Object} created Object
26391 addxtype : function(e){
26392 return this.add(e);
26396 * Returns the Element for this toolbar.
26397 * @return {Roo.Element}
26399 getEl : function(){
26405 * @return {Roo.Toolbar.Item} The separator item
26407 addSeparator : function(){
26408 return this.addItem(new Roo.Toolbar.Separator());
26412 * Adds a spacer element
26413 * @return {Roo.Toolbar.Spacer} The spacer item
26415 addSpacer : function(){
26416 return this.addItem(new Roo.Toolbar.Spacer());
26420 * Adds a fill element that forces subsequent additions to the right side of the toolbar
26421 * @return {Roo.Toolbar.Fill} The fill item
26423 addFill : function(){
26424 return this.addItem(new Roo.Toolbar.Fill());
26428 * Adds any standard HTML element to the toolbar
26429 * @param {String/HTMLElement/Element} el The element or id of the element to add
26430 * @return {Roo.Toolbar.Item} The element's item
26432 addElement : function(el){
26433 return this.addItem(new Roo.Toolbar.Item(el));
26436 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
26437 * @type Roo.util.MixedCollection
26442 * Adds any Toolbar.Item or subclass
26443 * @param {Roo.Toolbar.Item} item
26444 * @return {Roo.Toolbar.Item} The item
26446 addItem : function(item){
26447 var td = this.nextBlock();
26449 this.items.add(item);
26454 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
26455 * @param {Object/Array} config A button config or array of configs
26456 * @return {Roo.Toolbar.Button/Array}
26458 addButton : function(config){
26459 if(config instanceof Array){
26461 for(var i = 0, len = config.length; i < len; i++) {
26462 buttons.push(this.addButton(config[i]));
26467 if(!(config instanceof Roo.Toolbar.Button)){
26469 new Roo.Toolbar.SplitButton(config) :
26470 new Roo.Toolbar.Button(config);
26472 var td = this.nextBlock();
26479 * Adds text to the toolbar
26480 * @param {String} text The text to add
26481 * @return {Roo.Toolbar.Item} The element's item
26483 addText : function(text){
26484 return this.addItem(new Roo.Toolbar.TextItem(text));
26488 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
26489 * @param {Number} index The index where the item is to be inserted
26490 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
26491 * @return {Roo.Toolbar.Button/Item}
26493 insertButton : function(index, item){
26494 if(item instanceof Array){
26496 for(var i = 0, len = item.length; i < len; i++) {
26497 buttons.push(this.insertButton(index + i, item[i]));
26501 if (!(item instanceof Roo.Toolbar.Button)){
26502 item = new Roo.Toolbar.Button(item);
26504 var td = document.createElement("td");
26505 this.tr.insertBefore(td, this.tr.childNodes[index]);
26507 this.items.insert(index, item);
26512 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
26513 * @param {Object} config
26514 * @return {Roo.Toolbar.Item} The element's item
26516 addDom : function(config, returnEl){
26517 var td = this.nextBlock();
26518 Roo.DomHelper.overwrite(td, config);
26519 var ti = new Roo.Toolbar.Item(td.firstChild);
26521 this.items.add(ti);
26526 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
26527 * @type Roo.util.MixedCollection
26532 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc). Note: the field should not have
26533 * been rendered yet. For a field that has already been rendered, use {@link #addElement}.
26534 * @param {Roo.form.Field} field
26535 * @return {Roo.ToolbarItem}
26539 addField : function(field) {
26540 if (!this.fields) {
26542 this.fields = new Roo.util.MixedCollection(false, function(o){
26543 return o.id || ("item" + (++autoId));
26548 var td = this.nextBlock();
26550 var ti = new Roo.Toolbar.Item(td.firstChild);
26552 this.items.add(ti);
26553 this.fields.add(field);
26564 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
26565 this.el.child('div').hide();
26573 this.el.child('div').show();
26577 nextBlock : function(){
26578 var td = document.createElement("td");
26579 this.tr.appendChild(td);
26584 destroy : function(){
26585 if(this.items){ // rendered?
26586 Roo.destroy.apply(Roo, this.items.items);
26588 if(this.fields){ // rendered?
26589 Roo.destroy.apply(Roo, this.fields.items);
26591 Roo.Element.uncache(this.el, this.tr);
26596 * @class Roo.Toolbar.Item
26597 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
26599 * Creates a new Item
26600 * @param {HTMLElement} el
26602 Roo.Toolbar.Item = function(el){
26603 this.el = Roo.getDom(el);
26604 this.id = Roo.id(this.el);
26605 this.hidden = false;
26608 Roo.Toolbar.Item.prototype = {
26611 * Get this item's HTML Element
26612 * @return {HTMLElement}
26614 getEl : function(){
26619 render : function(td){
26621 td.appendChild(this.el);
26625 * Removes and destroys this item.
26627 destroy : function(){
26628 this.td.parentNode.removeChild(this.td);
26635 this.hidden = false;
26636 this.td.style.display = "";
26643 this.hidden = true;
26644 this.td.style.display = "none";
26648 * Convenience function for boolean show/hide.
26649 * @param {Boolean} visible true to show/false to hide
26651 setVisible: function(visible){
26660 * Try to focus this item.
26662 focus : function(){
26663 Roo.fly(this.el).focus();
26667 * Disables this item.
26669 disable : function(){
26670 Roo.fly(this.td).addClass("x-item-disabled");
26671 this.disabled = true;
26672 this.el.disabled = true;
26676 * Enables this item.
26678 enable : function(){
26679 Roo.fly(this.td).removeClass("x-item-disabled");
26680 this.disabled = false;
26681 this.el.disabled = false;
26687 * @class Roo.Toolbar.Separator
26688 * @extends Roo.Toolbar.Item
26689 * A simple toolbar separator class
26691 * Creates a new Separator
26693 Roo.Toolbar.Separator = function(){
26694 var s = document.createElement("span");
26695 s.className = "ytb-sep";
26696 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
26698 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
26699 enable:Roo.emptyFn,
26700 disable:Roo.emptyFn,
26705 * @class Roo.Toolbar.Spacer
26706 * @extends Roo.Toolbar.Item
26707 * A simple element that adds extra horizontal space to a toolbar.
26709 * Creates a new Spacer
26711 Roo.Toolbar.Spacer = function(){
26712 var s = document.createElement("div");
26713 s.className = "ytb-spacer";
26714 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
26716 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
26717 enable:Roo.emptyFn,
26718 disable:Roo.emptyFn,
26723 * @class Roo.Toolbar.Fill
26724 * @extends Roo.Toolbar.Spacer
26725 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
26727 * Creates a new Spacer
26729 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
26731 render : function(td){
26732 td.style.width = '100%';
26733 Roo.Toolbar.Fill.superclass.render.call(this, td);
26738 * @class Roo.Toolbar.TextItem
26739 * @extends Roo.Toolbar.Item
26740 * A simple class that renders text directly into a toolbar.
26742 * Creates a new TextItem
26743 * @param {String} text
26745 Roo.Toolbar.TextItem = function(text){
26746 if (typeof(text) == 'object') {
26749 var s = document.createElement("span");
26750 s.className = "ytb-text";
26751 s.innerHTML = text;
26752 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
26754 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
26755 enable:Roo.emptyFn,
26756 disable:Roo.emptyFn,
26761 * @class Roo.Toolbar.Button
26762 * @extends Roo.Button
26763 * A button that renders into a toolbar.
26765 * Creates a new Button
26766 * @param {Object} config A standard {@link Roo.Button} config object
26768 Roo.Toolbar.Button = function(config){
26769 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
26771 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
26772 render : function(td){
26774 Roo.Toolbar.Button.superclass.render.call(this, td);
26778 * Removes and destroys this button
26780 destroy : function(){
26781 Roo.Toolbar.Button.superclass.destroy.call(this);
26782 this.td.parentNode.removeChild(this.td);
26786 * Shows this button
26789 this.hidden = false;
26790 this.td.style.display = "";
26794 * Hides this button
26797 this.hidden = true;
26798 this.td.style.display = "none";
26802 * Disables this item
26804 disable : function(){
26805 Roo.fly(this.td).addClass("x-item-disabled");
26806 this.disabled = true;
26810 * Enables this item
26812 enable : function(){
26813 Roo.fly(this.td).removeClass("x-item-disabled");
26814 this.disabled = false;
26817 // backwards compat
26818 Roo.ToolbarButton = Roo.Toolbar.Button;
26821 * @class Roo.Toolbar.SplitButton
26822 * @extends Roo.SplitButton
26823 * A menu button that renders into a toolbar.
26825 * Creates a new SplitButton
26826 * @param {Object} config A standard {@link Roo.SplitButton} config object
26828 Roo.Toolbar.SplitButton = function(config){
26829 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
26831 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
26832 render : function(td){
26834 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
26838 * Removes and destroys this button
26840 destroy : function(){
26841 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
26842 this.td.parentNode.removeChild(this.td);
26846 * Shows this button
26849 this.hidden = false;
26850 this.td.style.display = "";
26854 * Hides this button
26857 this.hidden = true;
26858 this.td.style.display = "none";
26862 // backwards compat
26863 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
26865 * Ext JS Library 1.1.1
26866 * Copyright(c) 2006-2007, Ext JS, LLC.
26868 * Originally Released Under LGPL - original licence link has changed is not relivant.
26871 * <script type="text/javascript">
26875 * @class Roo.PagingToolbar
26876 * @extends Roo.Toolbar
26877 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
26879 * Create a new PagingToolbar
26880 * @param {Object} config The config object
26882 Roo.PagingToolbar = function(el, ds, config)
26884 // old args format still supported... - xtype is prefered..
26885 if (typeof(el) == 'object' && el.xtype) {
26886 // created from xtype...
26888 ds = el.dataSource;
26889 el = config.container;
26893 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
26896 this.renderButtons(this.el);
26900 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
26902 * @cfg {Roo.data.Store} dataSource
26903 * The underlying data store providing the paged data
26906 * @cfg {String/HTMLElement/Element} container
26907 * container The id or element that will contain the toolbar
26910 * @cfg {Boolean} displayInfo
26911 * True to display the displayMsg (defaults to false)
26914 * @cfg {Number} pageSize
26915 * The number of records to display per page (defaults to 20)
26919 * @cfg {String} displayMsg
26920 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
26922 displayMsg : 'Displaying {0} - {1} of {2}',
26924 * @cfg {String} emptyMsg
26925 * The message to display when no records are found (defaults to "No data to display")
26927 emptyMsg : 'No data to display',
26929 * Customizable piece of the default paging text (defaults to "Page")
26932 beforePageText : "Page",
26934 * Customizable piece of the default paging text (defaults to "of %0")
26937 afterPageText : "of {0}",
26939 * Customizable piece of the default paging text (defaults to "First Page")
26942 firstText : "First Page",
26944 * Customizable piece of the default paging text (defaults to "Previous Page")
26947 prevText : "Previous Page",
26949 * Customizable piece of the default paging text (defaults to "Next Page")
26952 nextText : "Next Page",
26954 * Customizable piece of the default paging text (defaults to "Last Page")
26957 lastText : "Last Page",
26959 * Customizable piece of the default paging text (defaults to "Refresh")
26962 refreshText : "Refresh",
26965 renderButtons : function(el){
26966 Roo.PagingToolbar.superclass.render.call(this, el);
26967 this.first = this.addButton({
26968 tooltip: this.firstText,
26969 cls: "x-btn-icon x-grid-page-first",
26971 handler: this.onClick.createDelegate(this, ["first"])
26973 this.prev = this.addButton({
26974 tooltip: this.prevText,
26975 cls: "x-btn-icon x-grid-page-prev",
26977 handler: this.onClick.createDelegate(this, ["prev"])
26979 this.addSeparator();
26980 this.add(this.beforePageText);
26981 this.field = Roo.get(this.addDom({
26986 cls: "x-grid-page-number"
26988 this.field.on("keydown", this.onPagingKeydown, this);
26989 this.field.on("focus", function(){this.dom.select();});
26990 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
26991 this.field.setHeight(18);
26992 this.addSeparator();
26993 this.next = this.addButton({
26994 tooltip: this.nextText,
26995 cls: "x-btn-icon x-grid-page-next",
26997 handler: this.onClick.createDelegate(this, ["next"])
26999 this.last = this.addButton({
27000 tooltip: this.lastText,
27001 cls: "x-btn-icon x-grid-page-last",
27003 handler: this.onClick.createDelegate(this, ["last"])
27005 this.addSeparator();
27006 this.loading = this.addButton({
27007 tooltip: this.refreshText,
27008 cls: "x-btn-icon x-grid-loading",
27009 handler: this.onClick.createDelegate(this, ["refresh"])
27012 if(this.displayInfo){
27013 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
27018 updateInfo : function(){
27019 if(this.displayEl){
27020 var count = this.ds.getCount();
27021 var msg = count == 0 ?
27025 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
27027 this.displayEl.update(msg);
27032 onLoad : function(ds, r, o){
27033 this.cursor = o.params ? o.params.start : 0;
27034 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
27036 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
27037 this.field.dom.value = ap;
27038 this.first.setDisabled(ap == 1);
27039 this.prev.setDisabled(ap == 1);
27040 this.next.setDisabled(ap == ps);
27041 this.last.setDisabled(ap == ps);
27042 this.loading.enable();
27047 getPageData : function(){
27048 var total = this.ds.getTotalCount();
27051 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
27052 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
27057 onLoadError : function(){
27058 this.loading.enable();
27062 onPagingKeydown : function(e){
27063 var k = e.getKey();
27064 var d = this.getPageData();
27066 var v = this.field.dom.value, pageNum;
27067 if(!v || isNaN(pageNum = parseInt(v, 10))){
27068 this.field.dom.value = d.activePage;
27071 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
27072 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27075 else if(k == e.HOME || (k == e.UP && e.ctrlKey) || (k == e.PAGEUP && e.ctrlKey) || (k == e.RIGHT && e.ctrlKey) || k == e.END || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey))
27077 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
27078 this.field.dom.value = pageNum;
27079 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
27082 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27084 var v = this.field.dom.value, pageNum;
27085 var increment = (e.shiftKey) ? 10 : 1;
27086 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27088 if(!v || isNaN(pageNum = parseInt(v, 10))) {
27089 this.field.dom.value = d.activePage;
27092 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
27094 this.field.dom.value = parseInt(v, 10) + increment;
27095 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
27096 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27103 beforeLoad : function(){
27105 this.loading.disable();
27110 onClick : function(which){
27114 ds.load({params:{start: 0, limit: this.pageSize}});
27117 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
27120 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
27123 var total = ds.getTotalCount();
27124 var extra = total % this.pageSize;
27125 var lastStart = extra ? (total - extra) : total-this.pageSize;
27126 ds.load({params:{start: lastStart, limit: this.pageSize}});
27129 ds.load({params:{start: this.cursor, limit: this.pageSize}});
27135 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
27136 * @param {Roo.data.Store} store The data store to unbind
27138 unbind : function(ds){
27139 ds.un("beforeload", this.beforeLoad, this);
27140 ds.un("load", this.onLoad, this);
27141 ds.un("loadexception", this.onLoadError, this);
27142 ds.un("remove", this.updateInfo, this);
27143 ds.un("add", this.updateInfo, this);
27144 this.ds = undefined;
27148 * Binds the paging toolbar to the specified {@link Roo.data.Store}
27149 * @param {Roo.data.Store} store The data store to bind
27151 bind : function(ds){
27152 ds.on("beforeload", this.beforeLoad, this);
27153 ds.on("load", this.onLoad, this);
27154 ds.on("loadexception", this.onLoadError, this);
27155 ds.on("remove", this.updateInfo, this);
27156 ds.on("add", this.updateInfo, this);